Actual source code: ls.c
1: #define PETSCSNES_DLL
3: #include src/snes/impls/ls/ls.h
5: /*
6: Checks if J^T F = 0 which implies we've found a local minimum of the function,
7: but not a zero. In the case when one cannot compute J^T F we use the fact that
8: 0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
9: for this trick.
10: */
13: PetscErrorCode SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin)
14: {
15: PetscReal a1;
17: PetscTruth hastranspose;
20: *ismin = PETSC_FALSE;
21: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
22: if (hastranspose) {
23: /* Compute || J^T F|| */
24: MatMultTranspose(A,F,W);
25: VecNorm(W,NORM_2,&a1);
26: PetscInfo1(0,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);
27: if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
28: } else {
29: Vec work;
30: PetscScalar result;
31: PetscReal wnorm;
33: VecSetRandom(W,PETSC_NULL);
34: VecNorm(W,NORM_2,&wnorm);
35: VecDuplicate(W,&work);
36: MatMult(A,W,work);
37: VecDot(F,work,&result);
38: VecDestroy(work);
39: a1 = PetscAbsScalar(result)/(fnorm*wnorm);
40: PetscInfo1(0,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);
41: if (a1 < 1.e-4) *ismin = PETSC_TRUE;
42: }
43: return(0);
44: }
46: /*
47: Checks if J^T(F - J*X) = 0
48: */
51: PetscErrorCode SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2)
52: {
53: PetscReal a1,a2;
55: PetscTruth hastranspose;
58: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
59: if (hastranspose) {
60: MatMult(A,X,W1);
61: VecAXPY(W1,-1.0,F);
63: /* Compute || J^T W|| */
64: MatMultTranspose(A,W1,W2);
65: VecNorm(W1,NORM_2,&a1);
66: VecNorm(W2,NORM_2,&a2);
67: if (a1) {
68: PetscInfo1(0,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);
69: }
70: }
71: return(0);
72: }
74: /* --------------------------------------------------------------------
76: This file implements a truncated Newton method with a line search,
77: for solving a system of nonlinear equations, using the KSP, Vec,
78: and Mat interfaces for linear solvers, vectors, and matrices,
79: respectively.
81: The following basic routines are required for each nonlinear solver:
82: SNESCreate_XXX() - Creates a nonlinear solver context
83: SNESSetFromOptions_XXX() - Sets runtime options
84: SNESSolve_XXX() - Solves the nonlinear system
85: SNESDestroy_XXX() - Destroys the nonlinear solver context
86: The suffix "_XXX" denotes a particular implementation, in this case
87: we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
88: systems of nonlinear equations with a line search (LS) method.
89: These routines are actually called via the common user interface
90: routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
91: SNESDestroy(), so the application code interface remains identical
92: for all nonlinear solvers.
94: Another key routine is:
95: SNESSetUp_XXX() - Prepares for the use of a nonlinear solver
96: by setting data structures and options. The interface routine SNESSetUp()
97: is not usually called directly by the user, but instead is called by
98: SNESSolve() if necessary.
100: Additional basic routines are:
101: SNESView_XXX() - Prints details of runtime options that
102: have actually been used.
103: These are called by application codes via the interface routines
104: SNESView().
106: The various types of solvers (preconditioners, Krylov subspace methods,
107: nonlinear solvers, timesteppers) are all organized similarly, so the
108: above description applies to these categories also.
110: -------------------------------------------------------------------- */
111: /*
112: SNESSolve_LS - Solves a nonlinear system with a truncated Newton
113: method with a line search.
115: Input Parameters:
116: . snes - the SNES context
118: Output Parameter:
119: . outits - number of iterations until termination
121: Application Interface Routine: SNESSolve()
123: Notes:
124: This implements essentially a truncated Newton method with a
125: line search. By default a cubic backtracking line search
126: is employed, as described in the text "Numerical Methods for
127: Unconstrained Optimization and Nonlinear Equations" by Dennis
128: and Schnabel.
129: */
132: PetscErrorCode SNESSolve_LS(SNES snes)
133: {
134: SNES_LS *neP = (SNES_LS*)snes->data;
135: PetscErrorCode ierr;
136: PetscInt maxits,i,lits;
137: PetscTruth lssucceed;
138: MatStructure flg = DIFFERENT_NONZERO_PATTERN;
139: PetscReal fnorm,gnorm,xnorm,ynorm;
140: Vec Y,X,F,G,W,TMP;
141: KSPConvergedReason kspreason;
144: snes->numFailures = 0;
145: snes->numLinearSolveFailures = 0;
146: snes->reason = SNES_CONVERGED_ITERATING;
148: maxits = snes->max_its; /* maximum number of iterations */
149: X = snes->vec_sol; /* solution vector */
150: F = snes->vec_func; /* residual vector */
151: Y = snes->work[0]; /* work vectors */
152: G = snes->work[1];
153: W = snes->work[2];
155: PetscObjectTakeAccess(snes);
156: snes->iter = 0;
157: PetscObjectGrantAccess(snes);
158: SNESComputeFunction(snes,X,F);
159: VecNorm(F,NORM_2,&fnorm); /* fnorm <- ||F|| */
160: if (fnorm != fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
161: PetscObjectTakeAccess(snes);
162: snes->norm = fnorm;
163: PetscObjectGrantAccess(snes);
164: SNESLogConvHistory(snes,fnorm,0);
165: SNESMonitor(snes,0,fnorm);
167: /* set parameter for default relative tolerance convergence test */
168: snes->ttol = fnorm*snes->rtol;
169: if (snes->ops->converged) {
170: (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
171: }
172: if (snes->reason) return(0);
174: for (i=0; i<maxits; i++) {
176: /* Call general purpose update function */
177: if (snes->ops->update) {
178: (*snes->ops->update)(snes, snes->iter);
179: }
181: /* Solve J Y = F, where J is Jacobian matrix */
182: SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
183: KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
184: SNES_KSPSolve(snes,snes->ksp,F,Y);
185: KSPGetConvergedReason(snes->ksp,&kspreason);
186: if (kspreason < 0) {
187: if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
188: snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
189: return(0);
190: }
191: }
192: KSPGetIterationNumber(snes->ksp,&lits);
193: snes->linear_its += lits;
194: PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
196: if (neP->precheckstep) {
197: PetscTruth changed_y = PETSC_FALSE;
198: (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);
199: }
201: if (PetscLogPrintInfo){
202: SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);
203: }
205: /* Compute a (scaled) negative update in the line search routine:
206: Y <- X - lambda*Y
207: and evaluate G = function(Y) (depends on the line search).
208: */
209: VecCopy(Y,snes->vec_sol_update_always);
210: ynorm = 1; gnorm = fnorm;
211: (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);
212: PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
213: TMP = F; F = G; snes->vec_func_always = F; G = TMP;
214: TMP = X; X = W; snes->vec_sol_always = X; W = TMP;
215: fnorm = gnorm;
216: if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
218: PetscObjectTakeAccess(snes);
219: snes->iter = i+1;
220: snes->norm = fnorm;
221: PetscObjectGrantAccess(snes);
222: SNESLogConvHistory(snes,fnorm,lits);
223: SNESMonitor(snes,i+1,fnorm);
225: if (!lssucceed) {
226: PetscTruth ismin;
227: if (++snes->numFailures >= snes->maxFailures) {
228: snes->reason = SNES_DIVERGED_LS_FAILURE;
229: SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);
230: if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
231: break;
232: }
233: }
235: /* Test for convergence */
236: if (snes->ops->converged) {
237: VecNorm(X,NORM_2,&xnorm); /* xnorm = || X || */
238: (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
239: if (snes->reason) break;
240: }
241: }
242: if (X != snes->vec_sol) {
243: VecCopy(X,snes->vec_sol);
244: }
245: if (F != snes->vec_func) {
246: VecCopy(F,snes->vec_func);
247: }
248: snes->vec_sol_always = snes->vec_sol;
249: snes->vec_func_always = snes->vec_func;
250: if (i == maxits) {
251: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
252: snes->reason = SNES_DIVERGED_MAX_IT;
253: }
254: return(0);
255: }
256: /* -------------------------------------------------------------------------- */
257: /*
258: SNESSetUp_LS - Sets up the internal data structures for the later use
259: of the SNESLS nonlinear solver.
261: Input Parameter:
262: . snes - the SNES context
263: . x - the solution vector
265: Application Interface Routine: SNESSetUp()
267: Notes:
268: For basic use of the SNES solvers, the user need not explicitly call
269: SNESSetUp(), since these actions will automatically occur during
270: the call to SNESSolve().
271: */
274: PetscErrorCode SNESSetUp_LS(SNES snes)
275: {
279: if (!snes->work) {
280: snes->nwork = 4;
281: VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
282: PetscLogObjectParents(snes,snes->nwork,snes->work);
283: snes->vec_sol_update_always = snes->work[3];
284: }
285: return(0);
286: }
287: /* -------------------------------------------------------------------------- */
288: /*
289: SNESDestroy_LS - Destroys the private SNES_LS context that was created
290: with SNESCreate_LS().
292: Input Parameter:
293: . snes - the SNES context
295: Application Interface Routine: SNESDestroy()
296: */
299: PetscErrorCode SNESDestroy_LS(SNES snes)
300: {
304: if (snes->nwork) {
305: VecDestroyVecs(snes->work,snes->nwork);
306: }
307: PetscFree(snes->data);
309: /* clear composed functions */
310: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);
311: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","",PETSC_NULL);
312: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","",PETSC_NULL);
314: return(0);
315: }
316: /* -------------------------------------------------------------------------- */
320: /*@C
321: SNESLineSearchNo - This routine is not a line search at all;
322: it simply uses the full Newton step. Thus, this routine is intended
323: to serve as a template and is not recommended for general use.
325: Collective on SNES and Vec
327: Input Parameters:
328: + snes - nonlinear context
329: . lsctx - optional context for line search (not used here)
330: . x - current iterate
331: . f - residual evaluated at x
332: . y - search direction
333: . w - work vector
334: - fnorm - 2-norm of f
336: Output Parameters:
337: + g - residual evaluated at new iterate y
338: . w - new iterate
339: . gnorm - 2-norm of g
340: . ynorm - 2-norm of search length
341: - flag - PETSC_TRUE on success, PETSC_FALSE on failure
343: Options Database Key:
344: . -snes_ls basic - Activates SNESLineSearchNo()
346: Level: advanced
348: .keywords: SNES, nonlinear, line search, cubic
350: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
351: SNESLineSearchSet(), SNESLineSearchNoNorms()
352: @*/
353: PetscErrorCode SNESLineSearchNo(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
354: {
356: SNES_LS *neP = (SNES_LS*)snes->data;
357: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
360: *flag = PETSC_TRUE;
362: VecNorm(y,NORM_2,ynorm); /* ynorm = || y || */
363: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
364: if (neP->postcheckstep) {
365: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
366: }
367: if (changed_y) {
368: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
369: }
370: SNESComputeFunction(snes,w,g);
371: if (PetscExceptionValue(ierr)) {
373: }
374:
376: VecNorm(g,NORM_2,gnorm); /* gnorm = || g || */
377: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
379: return(0);
380: }
381: /* -------------------------------------------------------------------------- */
385: /*@C
386: SNESLineSearchNoNorms - This routine is not a line search at
387: all; it simply uses the full Newton step. This version does not
388: even compute the norm of the function or search direction; this
389: is intended only when you know the full step is fine and are
390: not checking for convergence of the nonlinear iteration (for
391: example, you are running always for a fixed number of Newton steps).
393: Collective on SNES and Vec
395: Input Parameters:
396: + snes - nonlinear context
397: . lsctx - optional context for line search (not used here)
398: . x - current iterate
399: . f - residual evaluated at x
400: . y - search direction
401: . w - work vector
402: - fnorm - 2-norm of f
404: Output Parameters:
405: + g - residual evaluated at new iterate y
406: . w - new iterate
407: . gnorm - not changed
408: . ynorm - not changed
409: - flag - set to PETSC_TRUE indicating a successful line search
411: Options Database Key:
412: . -snes_ls basicnonorms - Activates SNESLineSearchNoNorms()
414: Notes:
415: SNESLineSearchNoNorms() must be used in conjunction with
416: either the options
417: $ -snes_no_convergence_test -snes_max_it <its>
418: or alternatively a user-defined custom test set via
419: SNESSetConvergenceTest(); or a -snes_max_it of 1,
420: otherwise, the SNES solver will generate an error.
422: During the final iteration this will not evaluate the function at
423: the solution point. This is to save a function evaluation while
424: using pseudo-timestepping.
426: The residual norms printed by monitoring routines such as
427: SNESMonitorDefault() (as activated via -snes_monitor) will not be
428: correct, since they are not computed.
430: Level: advanced
432: .keywords: SNES, nonlinear, line search, cubic
434: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
435: SNESLineSearchSet(), SNESLineSearchNo()
436: @*/
437: PetscErrorCode SNESLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
438: {
440: SNES_LS *neP = (SNES_LS*)snes->data;
441: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
444: *flag = PETSC_TRUE;
446: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
447: if (neP->postcheckstep) {
448: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
449: }
450: if (changed_y) {
451: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
452: }
453:
454: /* don't evaluate function the last time through */
455: if (snes->iter < snes->max_its-1) {
456: SNESComputeFunction(snes,w,g);
457: if (PetscExceptionValue(ierr)) {
459: }
460:
461: }
463: return(0);
464: }
465: /* -------------------------------------------------------------------------- */
468: /*@C
469: SNESLineSearchCubic - Performs a cubic line search (default line search method).
471: Collective on SNES
473: Input Parameters:
474: + snes - nonlinear context
475: . lsctx - optional context for line search (not used here)
476: . x - current iterate
477: . f - residual evaluated at x
478: . y - search direction
479: . w - work vector
480: - fnorm - 2-norm of f
482: Output Parameters:
483: + g - residual evaluated at new iterate y
484: . w - new iterate
485: . gnorm - 2-norm of g
486: . ynorm - 2-norm of search length
487: - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
489: Options Database Key:
490: $ -snes_ls cubic - Activates SNESLineSearchCubic()
492: Notes:
493: This line search is taken from "Numerical Methods for Unconstrained
494: Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
496: Level: advanced
498: .keywords: SNES, nonlinear, line search, cubic
500: .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
501: @*/
502: PetscErrorCode SNESLineSearchCubic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
503: {
504: /*
505: Note that for line search purposes we work with with the related
506: minimization problem:
507: min z(x): R^n -> R,
508: where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
509: */
510:
511: PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
512: PetscReal maxstep,minlambda,alpha,lambda,lambdatemp;
513: #if defined(PETSC_USE_COMPLEX)
514: PetscScalar cinitslope,clambda;
515: #endif
517: PetscInt count;
518: SNES_LS *neP = (SNES_LS*)snes->data;
519: PetscScalar scale;
520: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
524: *flag = PETSC_TRUE;
525: alpha = neP->alpha;
526: maxstep = neP->maxstep;
527: steptol = neP->steptol;
529: VecNorm(y,NORM_2,ynorm);
530: if (!*ynorm) {
531: PetscInfo(snes,"Search direction and size is 0\n");
532: *gnorm = fnorm;
533: VecCopy(x,w);
534: VecCopy(f,g);
535: *flag = PETSC_FALSE;
536: goto theend1;
537: }
538: if (*ynorm > maxstep) { /* Step too big, so scale back */
539: scale = maxstep/(*ynorm);
540: PetscInfo2(snes,"Scaling step by %G old ynorm %G\n",PetscRealPart(scale),*ynorm);
541: VecScale(y,scale);
542: *ynorm = maxstep;
543: }
544: VecMaxPointwiseDivide(y,x,&rellength);
545: minlambda = steptol/rellength;
546: MatMult(snes->jacobian,y,w);
547: #if defined(PETSC_USE_COMPLEX)
548: VecDot(f,w,&cinitslope);
549: initslope = PetscRealPart(cinitslope);
550: #else
551: VecDot(f,w,&initslope);
552: #endif
553: if (initslope > 0.0) initslope = -initslope;
554: if (initslope == 0.0) initslope = -1.0;
556: VecWAXPY(w,-1.0,y,x);
557: if (snes->nfuncs >= snes->max_funcs) {
558: PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
559: *flag = PETSC_FALSE;
560: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
561: goto theend1;
562: }
563: SNESComputeFunction(snes,w,g);
564: if (PetscExceptionValue(ierr)) {
566: }
567:
568: VecNorm(g,NORM_2,gnorm);
569: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
570: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
571: PetscInfo(snes,"Using full step\n");
572: goto theend1;
573: }
575: /* Fit points with quadratic */
576: lambda = 1.0;
577: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
578: lambdaprev = lambda;
579: gnormprev = *gnorm;
580: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
581: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
582: else lambda = lambdatemp;
584: #if defined(PETSC_USE_COMPLEX)
585: clambda = lambda; VecWAXPY(w,-clambda,y,x);
586: #else
587: VecWAXPY(w,-lambda,y,x);
588: #endif
589: if (snes->nfuncs >= snes->max_funcs) {
590: PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);
591: *flag = PETSC_FALSE;
592: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
593: goto theend1;
594: }
595: SNESComputeFunction(snes,w,g);
596: if (PetscExceptionValue(ierr)) {
598: }
599:
600: VecNorm(g,NORM_2,gnorm);
601: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
602: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
603: PetscInfo1(snes,"Quadratically determined step, lambda=%18.16e\n",lambda);
604: goto theend1;
605: }
607: /* Fit points with cubic */
608: count = 1;
609: while (count < 10000) {
610: if (lambda <= minlambda) { /* bad luck; use full step */
611: PetscInfo1(snes,"Unable to find good step length! %D \n",count);
612: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
613: *flag = PETSC_FALSE;
614: break;
615: }
616: t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
617: t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope;
618: a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
619: b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
620: d = b*b - 3*a*initslope;
621: if (d < 0.0) d = 0.0;
622: if (a == 0.0) {
623: lambdatemp = -initslope/(2.0*b);
624: } else {
625: lambdatemp = (-b + sqrt(d))/(3.0*a);
626: }
627: lambdaprev = lambda;
628: gnormprev = *gnorm;
629: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
630: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
631: else lambda = lambdatemp;
632: #if defined(PETSC_USE_COMPLEX)
633: clambda = lambda;
634: VecWAXPY(w,-clambda,y,x);
635: #else
636: VecWAXPY(w,-lambda,y,x);
637: #endif
638: if (snes->nfuncs >= snes->max_funcs) {
639: PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
640: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
641: *flag = PETSC_FALSE;
642: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
643: break;
644: }
645: SNESComputeFunction(snes,w,g);
646: if (PetscExceptionValue(ierr)) {
648: }
649:
650: VecNorm(g,NORM_2,gnorm);
651: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
652: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
653: PetscInfo1(snes,"Cubically determined step, lambda=%18.16e\n",lambda);
654: break;
655: } else {
656: PetscInfo1(snes,"Cubic step no good, shrinking lambda, lambda=%18.16e\n",lambda);
657: }
658: count++;
659: }
660: if (count >= 10000) {
661: SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation");
662: }
663: theend1:
664: /* Optional user-defined check for line search step validity */
665: if (neP->postcheckstep && *flag) {
666: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
667: if (changed_y) {
668: VecWAXPY(w,-1.0,y,x);
669: }
670: if (changed_y || changed_w) { /* recompute the function if the step has changed */
671: SNESComputeFunction(snes,w,g);
672: if (PetscExceptionValue(ierr)) {
674: }
675:
676: VecNormBegin(g,NORM_2,gnorm);
677: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
678: VecNormBegin(w,NORM_2,ynorm);
679: VecNormEnd(g,NORM_2,gnorm);
680: VecNormEnd(w,NORM_2,ynorm);
681: }
682: }
684: return(0);
685: }
686: /* -------------------------------------------------------------------------- */
689: /*@C
690: SNESLineSearchQuadratic - Performs a quadratic line search.
692: Collective on SNES and Vec
694: Input Parameters:
695: + snes - the SNES context
696: . lsctx - optional context for line search (not used here)
697: . x - current iterate
698: . f - residual evaluated at x
699: . y - search direction
700: . w - work vector
701: - fnorm - 2-norm of f
703: Output Parameters:
704: + g - residual evaluated at new iterate w
705: . w - new iterate (x + alpha*y)
706: . gnorm - 2-norm of g
707: . ynorm - 2-norm of search length
708: - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
710: Options Database Keys:
711: + -snes_ls quadratic - Activates SNESLineSearchQuadratic()
712: . -snes_ls_alpha <alpha> - Sets alpha
713: . -snes_ls_maxstep <max> - Sets maxstep
714: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
715: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
716: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
717: Notes:
718: Use SNESLineSearchSet() to set this routine within the SNESLS method.
720: Level: advanced
722: .keywords: SNES, nonlinear, quadratic, line search
724: .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
725: @*/
726: PetscErrorCode SNESLineSearchQuadratic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
727: {
728: /*
729: Note that for line search purposes we work with with the related
730: minimization problem:
731: min z(x): R^n -> R,
732: where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
733: */
734: PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,rellength;
735: #if defined(PETSC_USE_COMPLEX)
736: PetscScalar cinitslope,clambda;
737: #endif
739: PetscInt count;
740: SNES_LS *neP = (SNES_LS*)snes->data;
741: PetscScalar scale;
742: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
746: *flag = PETSC_TRUE;
747: alpha = neP->alpha;
748: maxstep = neP->maxstep;
749: steptol = neP->steptol;
751: VecNorm(y,NORM_2,ynorm);
752: if (*ynorm == 0.0) {
753: PetscInfo(snes,"Search direction and size is 0\n");
754: *gnorm = fnorm;
755: VecCopy(x,w);
756: VecCopy(f,g);
757: *flag = PETSC_FALSE;
758: goto theend2;
759: }
760: if (*ynorm > maxstep) { /* Step too big, so scale back */
761: scale = maxstep/(*ynorm);
762: VecScale(y,scale);
763: *ynorm = maxstep;
764: }
765: VecMaxPointwiseDivide(y,x,&rellength);
766: minlambda = steptol/rellength;
767: MatMult(snes->jacobian,y,w);
768: #if defined(PETSC_USE_COMPLEX)
769: VecDot(f,w,&cinitslope);
770: initslope = PetscRealPart(cinitslope);
771: #else
772: VecDot(f,w,&initslope);
773: #endif
774: if (initslope > 0.0) initslope = -initslope;
775: if (initslope == 0.0) initslope = -1.0;
777: VecWAXPY(w,-1.0,y,x);
778: if (snes->nfuncs >= snes->max_funcs) {
779: PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
780: *flag = PETSC_FALSE;
781: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
782: goto theend2;
783: }
784: SNESComputeFunction(snes,w,g);
785: if (PetscExceptionValue(ierr)) {
787: }
788:
789: VecNorm(g,NORM_2,gnorm);
790: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
791: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
792: PetscInfo(snes,"Using full step\n");
793: goto theend2;
794: }
796: /* Fit points with quadratic */
797: lambda = 1.0;
798: count = 1;
799: while (PETSC_TRUE) {
800: if (lambda <= minlambda) { /* bad luck; use full step */
801: PetscInfo1(snes,"Unable to find good step length! %D \n",count);
802: PetscInfo5(snes,"fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);
803: VecCopy(x,w);
804: *flag = PETSC_FALSE;
805: break;
806: }
807: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
808: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
809: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
810: else lambda = lambdatemp;
811:
812: #if defined(PETSC_USE_COMPLEX)
813: clambda = lambda; VecWAXPY(w,-clambda,y,x);
814: #else
815: VecWAXPY(w,-lambda,y,x);
816: #endif
817: if (snes->nfuncs >= snes->max_funcs) {
818: PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
819: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
820: *flag = PETSC_FALSE;
821: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
822: break;
823: }
824: SNESComputeFunction(snes,w,g);
825: if (PetscExceptionValue(ierr)) {
827: }
828:
829: VecNorm(g,NORM_2,gnorm);
830: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
831: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
832: PetscInfo1(snes,"Quadratically determined step, lambda=%G\n",lambda);
833: break;
834: }
835: count++;
836: }
837: theend2:
838: /* Optional user-defined check for line search step validity */
839: if (neP->postcheckstep) {
840: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
841: if (changed_y) {
842: VecWAXPY(w,-1.0,y,x);
843: }
844: if (changed_y || changed_w) { /* recompute the function if the step has changed */
845: SNESComputeFunction(snes,w,g);
846: if (PetscExceptionValue(ierr)) {
848: }
849:
850: VecNormBegin(g,NORM_2,gnorm);
851: VecNormBegin(w,NORM_2,ynorm);
852: VecNormEnd(g,NORM_2,gnorm);
853: VecNormEnd(w,NORM_2,ynorm);
854: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
855: }
856: }
858: return(0);
859: }
861: /* -------------------------------------------------------------------------- */
864: /*@C
865: SNESLineSearchSet - Sets the line search routine to be used
866: by the method SNESLS.
868: Input Parameters:
869: + snes - nonlinear context obtained from SNESCreate()
870: . lsctx - optional user-defined context for use by line search
871: - func - pointer to int function
873: Collective on SNES
875: Available Routines:
876: + SNESLineSearchCubic() - default line search
877: . SNESLineSearchQuadratic() - quadratic line search
878: . SNESLineSearchNo() - the full Newton step (actually not a line search)
879: - SNESLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
881: Options Database Keys:
882: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
883: . -snes_ls_alpha <alpha> - Sets alpha
884: . -snes_ls_maxstep <max> - Sets maxstep
885: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
886: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
887: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
889: Calling sequence of func:
890: .vb
891: func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
892: PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
893: .ve
895: Input parameters for func:
896: + snes - nonlinear context
897: . lsctx - optional user-defined context for line search
898: . x - current iterate
899: . f - residual evaluated at x
900: . y - search direction
901: . w - work vector
902: - fnorm - 2-norm of f
904: Output parameters for func:
905: + g - residual evaluated at new iterate y
906: . w - new iterate
907: . gnorm - 2-norm of g
908: . ynorm - 2-norm of search length
909: - flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure.
911: Level: advanced
913: .keywords: SNES, nonlinear, set, line search, routine
915: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchNoNorms(),
916: SNESLineSearchSetPostCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams(), SNESLineSearchSetPreCheck()
917: @*/
918: PetscErrorCode SNESLineSearchSet(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx)
919: {
920: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*);
923: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSet_C",(void (**)(void))&f);
924: if (f) {
925: (*f)(snes,func,lsctx);
926: }
927: return(0);
928: }
931: /* -------------------------------------------------------------------------- */
935: PetscErrorCode SNESLineSearchSet_LS(SNES snes,FCN2 func,void *lsctx)
936: {
938: ((SNES_LS *)(snes->data))->LineSearch = func;
939: ((SNES_LS *)(snes->data))->lsP = lsctx;
940: return(0);
941: }
943: /* -------------------------------------------------------------------------- */
946: /*@C
947: SNESLineSearchSetPostCheck - Sets a routine to check the validity of new iterate computed
948: by the line search routine in the Newton-based method SNESLS.
950: Input Parameters:
951: + snes - nonlinear context obtained from SNESCreate()
952: . func - pointer to function
953: - checkctx - optional user-defined context for use by step checking routine
955: Collective on SNES
957: Calling sequence of func:
958: .vb
959: int func (SNES snes, Vec x,Vec y,Vec w,void *checkctx, PetscTruth *changed_y,PetscTruth *changed_w)
960: .ve
961: where func returns an error code of 0 on success and a nonzero
962: on failure.
964: Input parameters for func:
965: + snes - nonlinear context
966: . checkctx - optional user-defined context for use by step checking routine
967: . x - previous iterate
968: . y - new search direction and length
969: - w - current candidate iterate
971: Output parameters for func:
972: + y - search direction (possibly changed)
973: . w - current iterate (possibly modified)
974: . changed_y - indicates search direction was changed by this routine
975: - changed_w - indicates current iterate was changed by this routine
977: Level: advanced
979: Notes: All line searches accept the new iterate computed by the line search checking routine.
981: Only one of changed_y and changed_w can be PETSC_TRUE
983: On input w = x + y
985: SNESLineSearchNo() and SNESLineSearchNoNorms() (1) compute a candidate iterate u_{i+1}, (2) pass control
986: to the checking routine, and then (3) compute the corresponding nonlinear
987: function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
989: SNESLineSearchQuadratic() and SNESLineSearchCubic() (1) compute a candidate iterate u_{i+1} as well as a
990: candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
991: routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
992: were made to the candidate iterate in the checking routine (as indicated
993: by flag=PETSC_TRUE). The overhead of this extra function re-evaluation can be
994: very costly, so use this feature with caution!
996: .keywords: SNES, nonlinear, set, line search check, step check, routine
998: .seealso: SNESLineSearchSet(), SNESLineSearchSetPreCheck()
999: @*/
1000: PetscErrorCode SNESLineSearchSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void *checkctx)
1001: {
1002: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void*);
1005: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPostCheck_C",(void (**)(void))&f);
1006: if (f) {
1007: (*f)(snes,func,checkctx);
1008: }
1009: return(0);
1010: }
1013: /*@C
1014: SNESLineSearchSetPreCheck - Sets a routine to check the validity of a new direction given by the linear solve
1015: before the line search is called.
1017: Input Parameters:
1018: + snes - nonlinear context obtained from SNESCreate()
1019: . func - pointer to function
1020: - checkctx - optional user-defined context for use by step checking routine
1022: Collective on SNES
1024: Calling sequence of func:
1025: .vb
1026: int func (SNES snes, Vec x,Vec y,void *checkctx, PetscTruth *changed_y)
1027: .ve
1028: where func returns an error code of 0 on success and a nonzero
1029: on failure.
1031: Input parameters for func:
1032: + snes - nonlinear context
1033: . checkctx - optional user-defined context for use by step checking routine
1034: . x - previous iterate
1035: - y - new search direction and length
1037: Output parameters for func:
1038: + y - search direction (possibly changed)
1039: - changed_y - indicates search direction was changed by this routine
1041: Level: advanced
1043: Notes: All line searches accept the new iterate computed by the line search checking routine.
1045: .keywords: SNES, nonlinear, set, line search check, step check, routine
1047: .seealso: SNESLineSearchSet(), SNESLineSearchSetPostCheck(), SNESSetUpdate()
1048: @*/
1049: PetscErrorCode SNESLineSearchSetPreCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,void*,PetscTruth*),void *checkctx)
1050: {
1051: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,void*,PetscTruth*),void*);
1054: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPreCheck_C",(void (**)(void))&f);
1055: if (f) {
1056: (*f)(snes,func,checkctx);
1057: }
1058: return(0);
1059: }
1061: /* -------------------------------------------------------------------------- */
1067: PetscErrorCode SNESLineSearchSetPostCheck_LS(SNES snes,FCN1 func,void *checkctx)
1068: {
1070: ((SNES_LS *)(snes->data))->postcheckstep = func;
1071: ((SNES_LS *)(snes->data))->postcheck = checkctx;
1072: return(0);
1073: }
1079: PetscErrorCode SNESLineSearchSetPreCheck_LS(SNES snes,FCN3 func,void *checkctx)
1080: {
1082: ((SNES_LS *)(snes->data))->precheckstep = func;
1083: ((SNES_LS *)(snes->data))->precheck = checkctx;
1084: return(0);
1085: }
1088: /*
1089: SNESView_LS - Prints info from the SNESLS data structure.
1091: Input Parameters:
1092: . SNES - the SNES context
1093: . viewer - visualization context
1095: Application Interface Routine: SNESView()
1096: */
1099: static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
1100: {
1101: SNES_LS *ls = (SNES_LS *)snes->data;
1102: const char *cstr;
1104: PetscTruth iascii;
1107: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
1108: if (iascii) {
1109: if (ls->LineSearch == SNESLineSearchNo) cstr = "SNESLineSearchNo";
1110: else if (ls->LineSearch == SNESLineSearchQuadratic) cstr = "SNESLineSearchQuadratic";
1111: else if (ls->LineSearch == SNESLineSearchCubic) cstr = "SNESLineSearchCubic";
1112: else cstr = "unknown";
1113: PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);
1114: PetscViewerASCIIPrintf(viewer," alpha=%G, maxstep=%G, steptol=%G\n",ls->alpha,ls->maxstep,ls->steptol);
1115: } else {
1116: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
1117: }
1118: return(0);
1119: }
1120: /* -------------------------------------------------------------------------- */
1121: /*
1122: SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
1124: Input Parameter:
1125: . snes - the SNES context
1127: Application Interface Routine: SNESSetFromOptions()
1128: */
1131: static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
1132: {
1133: SNES_LS *ls = (SNES_LS *)snes->data;
1134: const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1136: PetscInt indx;
1137: PetscTruth flg;
1140: PetscOptionsHead("SNES Line search options");
1141: PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);
1142: PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);
1143: PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);
1145: PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
1146: if (flg) {
1147: switch (indx) {
1148: case 0:
1149: SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
1150: break;
1151: case 1:
1152: SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);
1153: break;
1154: case 2:
1155: SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);
1156: break;
1157: case 3:
1158: SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);
1159: break;
1160: }
1161: }
1162: PetscOptionsTail();
1163: return(0);
1164: }
1165: /* -------------------------------------------------------------------------- */
1168: /*@C
1169: SNESConverged_LS - Monitors the convergence of the line search
1170: method SNESLS for solving systems of nonlinear equations (default).
1172: Collective on SNES
1174: Input Parameters:
1175: + snes - the SNES context
1176: . it - the iteration (0 indicates before any Newton steps)
1177: . xnorm - 2-norm of current iterate
1178: . pnorm - 2-norm of current step
1179: . fnorm - 2-norm of function at current iterate
1180: - dummy - unused context
1182: Output Parameter:
1183: . reason - one of
1184: $ SNES_CONVERGED_FNORM_ABS - (fnorm < abstol),
1185: $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm),
1186: $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0),
1187: $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf),
1188: $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN),
1189: $ SNES_CONVERGED_ITERATING - (otherwise),
1191: where
1192: + maxf - maximum number of function evaluations,
1193: set with SNESSetTolerances()
1194: . nfct - number of function evaluations,
1195: . abstol - absolute function norm tolerance,
1196: set with SNESSetTolerances()
1197: - rtol - relative function norm tolerance, set with SNESSetTolerances()
1199: Level: intermediate
1201: .keywords: SNES, nonlinear, default, converged, convergence
1203: .seealso: SNESSetConvergenceTest()
1204: @*/
1205: PetscErrorCode SNESConverged_LS(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
1206: {
1212: SNESDefaultConverged(snes,it,xnorm,pnorm,fnorm,reason,dummy);
1213: return(0);
1214: }
1215: /* -------------------------------------------------------------------------- */
1216: /*MC
1217: SNESLS - Newton based nonlinear solver that uses a line search
1219: Options Database:
1220: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1221: . -snes_ls_alpha <alpha> - Sets alpha
1222: . -snes_ls_maxstep <max> - Sets maxstep
1223: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
1224: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
1225: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
1227: Notes: This is the default nonlinear solver in SNES
1229: Level: beginner
1231: .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1232: SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1233: SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck()
1235: M*/
1239: PetscErrorCode SNESCreate_LS(SNES snes)
1240: {
1242: SNES_LS *neP;
1245: snes->ops->setup = SNESSetUp_LS;
1246: snes->ops->solve = SNESSolve_LS;
1247: snes->ops->destroy = SNESDestroy_LS;
1248: snes->ops->converged = SNESConverged_LS;
1249: snes->ops->setfromoptions = SNESSetFromOptions_LS;
1250: snes->ops->view = SNESView_LS;
1251: snes->nwork = 0;
1253: PetscNew(SNES_LS,&neP);
1254: PetscLogObjectMemory(snes,sizeof(SNES_LS));
1255: snes->data = (void*)neP;
1256: neP->alpha = 1.e-4;
1257: neP->maxstep = 1.e8;
1258: neP->steptol = 1.e-12;
1259: neP->LineSearch = SNESLineSearchCubic;
1260: neP->lsP = PETSC_NULL;
1261: neP->postcheckstep = PETSC_NULL;
1262: neP->postcheck = PETSC_NULL;
1263: neP->precheckstep = PETSC_NULL;
1264: neP->precheck = PETSC_NULL;
1266: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C",
1267: "SNESLineSearchSet_LS",
1268: SNESLineSearchSet_LS);
1269: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C",
1270: "SNESLineSearchSetPostCheck_LS",
1271: SNESLineSearchSetPostCheck_LS);
1272: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C",
1273: "SNESLineSearchSetPreCheck_LS",
1274: SNESLineSearchSetPreCheck_LS);
1276: return(0);
1277: }