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 norm of the function,
7: || F(u) ||_2 but not a zero, F(u) = 0. 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. One assumes that the probability that W is in the null space of J is very, very small.
10: */
13: PetscErrorCode SNESLSCheckLocalMin_Private(SNES snes,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(snes,"|| 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(snes,"(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(SNES snes,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(snes,"||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=0,ynorm;
140: Vec Y,X,F,G,W;
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: snes->norm = 0;
158: PetscObjectGrantAccess(snes);
159: SNESComputeFunction(snes,X,F);
160: if (snes->domainerror) {
161: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
162: return(0);
163: }
164: VecNormBegin(F,NORM_2,&fnorm); /* fnorm <- ||F|| */
165: VecNormBegin(X,NORM_2,&xnorm); /* xnorm <- ||x|| */
166: VecNormEnd(F,NORM_2,&fnorm);
167: VecNormEnd(X,NORM_2,&xnorm);
168: if PetscIsInfOrNanReal(fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
169: PetscObjectTakeAccess(snes);
170: snes->norm = fnorm;
171: PetscObjectGrantAccess(snes);
172: SNESLogConvHistory(snes,fnorm,0);
173: SNESMonitor(snes,0,fnorm);
175: /* set parameter for default relative tolerance convergence test */
176: snes->ttol = fnorm*snes->rtol;
177: /* test convergence */
178: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
179: if (snes->reason) return(0);
181: for (i=0; i<maxits; i++) {
183: /* Call general purpose update function */
184: if (snes->ops->update) {
185: (*snes->ops->update)(snes, snes->iter);
186: }
188: /* Solve J Y = F, where J is Jacobian matrix */
189: SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
190: KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
191: SNES_KSPSolve(snes,snes->ksp,F,Y);
192: KSPGetConvergedReason(snes->ksp,&kspreason);
193: if (kspreason < 0) {
194: if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
195: PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
196: snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
197: break;
198: }
199: }
200: KSPGetIterationNumber(snes->ksp,&lits);
201: snes->linear_its += lits;
202: PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
204: if (neP->precheckstep) {
205: PetscTruth changed_y = PETSC_FALSE;
206: (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);
207: }
209: if (PetscLogPrintInfo){
210: SNESLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
211: }
213: /* Compute a (scaled) negative update in the line search routine:
214: Y <- X - lambda*Y
215: and evaluate G = function(Y) (depends on the line search).
216: */
217: VecCopy(Y,snes->vec_sol_update);
218: ynorm = 1; gnorm = fnorm;
219: (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);
220: PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
221: if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
222: if (snes->domainerror) {
223: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
224: return(0);
225: }
226: if (!lssucceed) {
227: if (++snes->numFailures >= snes->maxFailures) {
228: PetscTruth ismin;
229: snes->reason = SNES_DIVERGED_LS_FAILURE;
230: SNESLSCheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);
231: if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
232: break;
233: }
234: }
235: /* Update function and solution vectors */
236: fnorm = gnorm;
237: VecCopy(G,F);
238: VecCopy(W,X);
239: /* Monitor convergence */
240: PetscObjectTakeAccess(snes);
241: snes->iter = i+1;
242: snes->norm = fnorm;
243: PetscObjectGrantAccess(snes);
244: SNESLogConvHistory(snes,snes->norm,lits);
245: SNESMonitor(snes,snes->iter,snes->norm);
246: /* Test for convergence, xnorm = || X || */
247: if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
248: (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
249: if (snes->reason) break;
250: }
251: if (i == maxits) {
252: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
253: if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
254: }
255: return(0);
256: }
257: /* -------------------------------------------------------------------------- */
258: /*
259: SNESSetUp_LS - Sets up the internal data structures for the later use
260: of the SNESLS nonlinear solver.
262: Input Parameter:
263: . snes - the SNES context
264: . x - the solution vector
266: Application Interface Routine: SNESSetUp()
268: Notes:
269: For basic use of the SNES solvers, the user need not explicitly call
270: SNESSetUp(), since these actions will automatically occur during
271: the call to SNESSolve().
272: */
275: PetscErrorCode SNESSetUp_LS(SNES snes)
276: {
280: if (!snes->vec_sol_update) {
281: VecDuplicate(snes->vec_sol,&snes->vec_sol_update);
282: PetscLogObjectParent(snes,snes->vec_sol_update);
283: }
284: if (!snes->work) {
285: snes->nwork = 3;
286: VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
287: PetscLogObjectParents(snes,snes->nwork,snes->work);
288: }
289: return(0);
290: }
291: /* -------------------------------------------------------------------------- */
292: /*
293: SNESDestroy_LS - Destroys the private SNES_LS context that was created
294: with SNESCreate_LS().
296: Input Parameter:
297: . snes - the SNES context
299: Application Interface Routine: SNESDestroy()
300: */
303: PetscErrorCode SNESDestroy_LS(SNES snes)
304: {
308: if (snes->vec_sol_update) {
309: VecDestroy(snes->vec_sol_update);
310: snes->vec_sol_update = PETSC_NULL;
311: }
312: if (snes->nwork) {
313: VecDestroyVecs(snes->work,snes->nwork);
314: snes->nwork = 0;
315: snes->work = PETSC_NULL;
316: }
317: PetscFree(snes->data);
319: /* clear composed functions */
320: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);
321: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","",PETSC_NULL);
322: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","",PETSC_NULL);
324: return(0);
325: }
326: /* -------------------------------------------------------------------------- */
330: /*@C
331: SNESLineSearchNo - This routine is not a line search at all;
332: it simply uses the full Newton step. Thus, this routine is intended
333: to serve as a template and is not recommended for general use.
335: Collective on SNES and Vec
337: Input Parameters:
338: + snes - nonlinear context
339: . lsctx - optional context for line search (not used here)
340: . x - current iterate
341: . f - residual evaluated at x
342: . y - search direction
343: . w - work vector
344: . fnorm - 2-norm of f
345: - xnorm - norm of x if known, otherwise 0
347: Output Parameters:
348: + g - residual evaluated at new iterate y
349: . w - new iterate
350: . gnorm - 2-norm of g
351: . ynorm - 2-norm of search length
352: - flag - PETSC_TRUE on success, PETSC_FALSE on failure
354: Options Database Key:
355: . -snes_ls basic - Activates SNESLineSearchNo()
357: Level: advanced
359: .keywords: SNES, nonlinear, line search, cubic
361: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
362: SNESLineSearchSet(), SNESLineSearchNoNorms()
363: @*/
364: PetscErrorCode SNESLineSearchNo(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
365: {
367: SNES_LS *neP = (SNES_LS*)snes->data;
368: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
371: *flag = PETSC_TRUE;
372: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
373: VecNorm(y,NORM_2,ynorm); /* ynorm = || y || */
374: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
375: if (neP->postcheckstep) {
376: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
377: }
378: if (changed_y) {
379: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
380: }
381: SNESComputeFunction(snes,w,g);
382: if (!snes->domainerror) {
383: VecNorm(g,NORM_2,gnorm); /* gnorm = || g || */
384: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
385: }
386: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
387: return(0);
388: }
389: /* -------------------------------------------------------------------------- */
393: /*@C
394: SNESLineSearchNoNorms - This routine is not a line search at
395: all; it simply uses the full Newton step. This version does not
396: even compute the norm of the function or search direction; this
397: is intended only when you know the full step is fine and are
398: not checking for convergence of the nonlinear iteration (for
399: example, you are running always for a fixed number of Newton steps).
401: Collective on SNES and Vec
403: Input Parameters:
404: + snes - nonlinear context
405: . lsctx - optional context for line search (not used here)
406: . x - current iterate
407: . f - residual evaluated at x
408: . y - search direction
409: . w - work vector
410: . fnorm - 2-norm of f
411: - xnorm - norm of x if known, otherwise 0
413: Output Parameters:
414: + g - residual evaluated at new iterate y
415: . w - new iterate
416: . gnorm - not changed
417: . ynorm - not changed
418: - flag - set to PETSC_TRUE indicating a successful line search
420: Options Database Key:
421: . -snes_ls basicnonorms - Activates SNESLineSearchNoNorms()
423: Notes:
424: SNESLineSearchNoNorms() must be used in conjunction with
425: either the options
426: $ -snes_no_convergence_test -snes_max_it <its>
427: or alternatively a user-defined custom test set via
428: SNESSetConvergenceTest(); or a -snes_max_it of 1,
429: otherwise, the SNES solver will generate an error.
431: During the final iteration this will not evaluate the function at
432: the solution point. This is to save a function evaluation while
433: using pseudo-timestepping.
435: The residual norms printed by monitoring routines such as
436: SNESMonitorDefault() (as activated via -snes_monitor) will not be
437: correct, since they are not computed.
439: Level: advanced
441: .keywords: SNES, nonlinear, line search, cubic
443: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
444: SNESLineSearchSet(), SNESLineSearchNo()
445: @*/
446: PetscErrorCode SNESLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
447: {
449: SNES_LS *neP = (SNES_LS*)snes->data;
450: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
453: *flag = PETSC_TRUE;
454: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
455: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
456: if (neP->postcheckstep) {
457: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
458: }
459: if (changed_y) {
460: VecWAXPY(w,-1.0,y,x); /* w <- x - y */
461: }
462:
463: /* don't evaluate function the last time through */
464: if (snes->iter < snes->max_its-1) {
465: SNESComputeFunction(snes,w,g);
466: }
467: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
468: return(0);
469: }
470: /* -------------------------------------------------------------------------- */
473: /*@C
474: SNESLineSearchCubic - Performs a cubic line search (default line search method).
476: Collective on SNES
478: Input Parameters:
479: + snes - nonlinear context
480: . lsctx - optional context for line search (not used here)
481: . x - current iterate
482: . f - residual evaluated at x
483: . y - search direction
484: . w - work vector
485: . fnorm - 2-norm of f
486: - xnorm - norm of x if known, otherwise 0
488: Output Parameters:
489: + g - residual evaluated at new iterate y
490: . w - new iterate
491: . gnorm - 2-norm of g
492: . ynorm - 2-norm of search length
493: - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
495: Options Database Key:
496: $ -snes_ls cubic - Activates SNESLineSearchCubic()
498: Notes:
499: This line search is taken from "Numerical Methods for Unconstrained
500: Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
502: Level: advanced
504: .keywords: SNES, nonlinear, line search, cubic
506: .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
507: @*/
508: PetscErrorCode SNESLineSearchCubic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
509: {
510: /*
511: Note that for line search purposes we work with with the related
512: minimization problem:
513: min z(x): R^n -> R,
514: where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
515: */
516:
517: PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
518: PetscReal maxstep,minlambda,alpha,lambda,lambdatemp;
519: #if defined(PETSC_USE_COMPLEX)
520: PetscScalar cinitslope;
521: #endif
523: PetscInt count;
524: SNES_LS *neP = (SNES_LS*)snes->data;
525: PetscScalar scale;
526: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
529: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
530: *flag = PETSC_TRUE;
531: alpha = neP->alpha;
532: maxstep = neP->maxstep;
533: steptol = snes->xtol;
535: VecNorm(y,NORM_2,ynorm);
536: if (!*ynorm) {
537: PetscInfo(snes,"Search direction and size is 0\n");
538: *gnorm = fnorm;
539: VecCopy(x,w);
540: VecCopy(f,g);
541: *flag = PETSC_FALSE;
542: goto theend1;
543: }
544: if (*ynorm > maxstep) { /* Step too big, so scale back */
545: scale = maxstep/(*ynorm);
546: PetscInfo2(snes,"Scaling step by %G old ynorm %G\n",PetscRealPart(scale),*ynorm);
547: VecScale(y,scale);
548: *ynorm = maxstep;
549: }
550: VecMaxPointwiseDivide(y,x,&rellength);
551: minlambda = steptol/rellength;
552: MatMult(snes->jacobian,y,w);
553: #if defined(PETSC_USE_COMPLEX)
554: VecDot(f,w,&cinitslope);
555: initslope = PetscRealPart(cinitslope);
556: #else
557: VecDot(f,w,&initslope);
558: #endif
559: if (initslope > 0.0) initslope = -initslope;
560: if (initslope == 0.0) initslope = -1.0;
562: VecWAXPY(w,-1.0,y,x);
563: if (snes->nfuncs >= snes->max_funcs) {
564: PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
565: *flag = PETSC_FALSE;
566: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
567: goto theend1;
568: }
569: SNESComputeFunction(snes,w,g);
570: if (snes->domainerror) {
571: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
572: return(0);
573: }
574: VecNorm(g,NORM_2,gnorm);
575: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
576: PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);
577: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
578: PetscInfo2(snes,"Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);
579: goto theend1;
580: }
581: if (*ynorm < xnorm*snes->xtol) {
582: PetscInfo3(snes,"Using full step: because ynorm %G < xnorm %G * steptol %G (i.e. Newton step is below tolerance)\n",*ynorm,xnorm,snes->xtol);
583: *flag = PETSC_TRUE;
584: goto theend1;
585: }
588: /* Fit points with quadratic */
589: lambda = 1.0;
590: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
591: lambdaprev = lambda;
592: gnormprev = *gnorm;
593: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
594: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
595: else lambda = lambdatemp;
597: VecWAXPY(w,-lambda,y,x);
598: if (snes->nfuncs >= snes->max_funcs) {
599: PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);
600: *flag = PETSC_FALSE;
601: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
602: goto theend1;
603: }
604: SNESComputeFunction(snes,w,g);
605: if (snes->domainerror) {
606: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
607: return(0);
608: }
609: VecNorm(g,NORM_2,gnorm);
610: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
611: PetscInfo1(snes,"gnorm after quadratic fit %G\n",*gnorm);
612: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
613: PetscInfo1(snes,"Quadratically determined step, lambda=%18.16e\n",lambda);
614: goto theend1;
615: }
617: /* Fit points with cubic */
618: count = 1;
619: while (PETSC_TRUE) {
620: if (lambda <= minlambda) {
621: PetscInfo1(snes,"Unable to find good step length! After %D tries \n",count);
622: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
623: *flag = PETSC_FALSE;
624: break;
625: }
626: t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
627: t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope;
628: a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
629: b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
630: d = b*b - 3*a*initslope;
631: if (d < 0.0) d = 0.0;
632: if (a == 0.0) {
633: lambdatemp = -initslope/(2.0*b);
634: } else {
635: lambdatemp = (-b + sqrt(d))/(3.0*a);
636: }
637: lambdaprev = lambda;
638: gnormprev = *gnorm;
639: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
640: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
641: else lambda = lambdatemp;
642: VecWAXPY(w,-lambda,y,x);
643: if (snes->nfuncs >= snes->max_funcs) {
644: PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
645: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
646: *flag = PETSC_FALSE;
647: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
648: break;
649: }
650: SNESComputeFunction(snes,w,g);
651: if (snes->domainerror) {
652: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
653: return(0);
654: }
655: VecNorm(g,NORM_2,gnorm);
656: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
657: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
658: PetscInfo2(snes,"Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);
659: break;
660: } else {
661: PetscInfo2(snes,"Cubic step no good, shrinking lambda, current gnorem %G lambda=%18.16e\n",*gnorm,lambda);
662: }
663: count++;
664: }
665: theend1:
666: /* Optional user-defined check for line search step validity */
667: if (neP->postcheckstep && *flag) {
668: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
669: if (changed_y) {
670: VecWAXPY(w,-1.0,y,x);
671: }
672: if (changed_y || changed_w) { /* recompute the function if the step has changed */
673: SNESComputeFunction(snes,w,g);
674: if (snes->domainerror) {
675: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
676: return(0);
677: }
678: VecNormBegin(g,NORM_2,gnorm);
679: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
680: VecNormBegin(y,NORM_2,ynorm);
681: VecNormEnd(g,NORM_2,gnorm);
682: VecNormEnd(y,NORM_2,ynorm);
683: }
684: }
685: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
686: return(0);
687: }
688: /* -------------------------------------------------------------------------- */
691: /*@C
692: SNESLineSearchQuadratic - Performs a quadratic line search.
694: Collective on SNES and Vec
696: Input Parameters:
697: + snes - the SNES context
698: . lsctx - optional context for line search (not used here)
699: . x - current iterate
700: . f - residual evaluated at x
701: . y - search direction
702: . w - work vector
703: . fnorm - 2-norm of f
704: - xnorm - norm of x if known, otherwise 0
706: Output Parameters:
707: + g - residual evaluated at new iterate w
708: . w - new iterate (x + alpha*y)
709: . gnorm - 2-norm of g
710: . ynorm - 2-norm of search length
711: - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
713: Options Database Keys:
714: + -snes_ls quadratic - Activates SNESLineSearchQuadratic()
715: . -snes_ls_alpha <alpha> - Sets alpha
716: . -snes_ls_maxstep <max> - Sets maxstep
717: - -snes_stol <steptol> - Sets steptol, this is the minimum step size that the line search code
718: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
719: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
720: Notes:
721: Use SNESLineSearchSet() to set this routine within the SNESLS method.
723: Level: advanced
725: .keywords: SNES, nonlinear, quadratic, line search
727: .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
728: @*/
729: PetscErrorCode SNESLineSearchQuadratic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
730: {
731: /*
732: Note that for line search purposes we work with with the related
733: minimization problem:
734: min z(x): R^n -> R,
735: where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
736: */
737: PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,rellength;
738: #if defined(PETSC_USE_COMPLEX)
739: PetscScalar cinitslope;
740: #endif
742: PetscInt count;
743: SNES_LS *neP = (SNES_LS*)snes->data;
744: PetscScalar scale;
745: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
748: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
749: *flag = PETSC_TRUE;
750: alpha = neP->alpha;
751: maxstep = neP->maxstep;
752: steptol = snes->xtol;
754: VecNorm(y,NORM_2,ynorm);
755: if (*ynorm == 0.0) {
756: PetscInfo(snes,"Search direction and size is 0\n");
757: *gnorm = fnorm;
758: VecCopy(x,w);
759: VecCopy(f,g);
760: *flag = PETSC_FALSE;
761: goto theend2;
762: }
763: if (*ynorm > maxstep) { /* Step too big, so scale back */
764: scale = maxstep/(*ynorm);
765: VecScale(y,scale);
766: *ynorm = maxstep;
767: }
768: VecMaxPointwiseDivide(y,x,&rellength);
769: minlambda = steptol/rellength;
770: MatMult(snes->jacobian,y,w);
771: #if defined(PETSC_USE_COMPLEX)
772: VecDot(f,w,&cinitslope);
773: initslope = PetscRealPart(cinitslope);
774: #else
775: VecDot(f,w,&initslope);
776: #endif
777: if (initslope > 0.0) initslope = -initslope;
778: if (initslope == 0.0) initslope = -1.0;
779: PetscInfo1(snes,"Initslope %G \n",initslope);
781: VecWAXPY(w,-1.0,y,x);
782: if (snes->nfuncs >= snes->max_funcs) {
783: PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
784: *flag = PETSC_FALSE;
785: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
786: goto theend2;
787: }
788: SNESComputeFunction(snes,w,g);
789: if (snes->domainerror) {
790: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
791: return(0);
792: }
793: VecNorm(g,NORM_2,gnorm);
794: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
795: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
796: PetscInfo(snes,"Using full step\n");
797: goto theend2;
798: }
799: if (*ynorm < xnorm*snes->xtol) {
800: PetscInfo3(snes,"Using full step: because ynorm %G < xnorm %G * steptol %G (i.e. Newton step is below tolerance)\n",*ynorm,xnorm,snes->xtol);
801: *flag = PETSC_TRUE;
802: goto theend2;
803: }
805: /* Fit points with quadratic */
806: lambda = 1.0;
807: count = 1;
808: while (PETSC_TRUE) {
809: if (lambda <= minlambda) { /* bad luck; use full step */
810: PetscInfo1(snes,"Unable to find good step length! %D \n",count);
811: PetscInfo5(snes,"fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);
812: VecCopy(x,w);
813: *flag = PETSC_FALSE;
814: break;
815: }
816: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
817: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
818: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
819: else lambda = lambdatemp;
820:
821: VecWAXPY(w,-lambda,y,x);
822: if (snes->nfuncs >= snes->max_funcs) {
823: PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
824: PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
825: *flag = PETSC_FALSE;
826: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
827: break;
828: }
829: SNESComputeFunction(snes,w,g);
830: if (snes->domainerror) {
831: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
832: return(0);
833: }
834: VecNorm(g,NORM_2,gnorm);
835: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
836: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
837: PetscInfo1(snes,"Quadratically determined step, lambda=%G\n",lambda);
838: break;
839: }
840: count++;
841: }
842: theend2:
843: /* Optional user-defined check for line search step validity */
844: if (neP->postcheckstep) {
845: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
846: if (changed_y) {
847: VecWAXPY(w,-1.0,y,x);
848: }
849: if (changed_y || changed_w) { /* recompute the function if the step has changed */
850: SNESComputeFunction(snes,w,g);
851: if (snes->domainerror) {
852: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
853: return(0);
854: }
855: VecNormBegin(g,NORM_2,gnorm);
856: VecNormBegin(y,NORM_2,ynorm);
857: VecNormEnd(g,NORM_2,gnorm);
858: VecNormEnd(y,NORM_2,ynorm);
859: if PetscIsInfOrNanReal(*gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
860: }
861: }
862: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
863: return(0);
864: }
866: /* -------------------------------------------------------------------------- */
869: /*@C
870: SNESLineSearchSet - Sets the line search routine to be used
871: by the method SNESLS.
873: Input Parameters:
874: + snes - nonlinear context obtained from SNESCreate()
875: . lsctx - optional user-defined context for use by line search
876: - func - pointer to int function
878: Collective on SNES
880: Available Routines:
881: + SNESLineSearchCubic() - default line search
882: . SNESLineSearchQuadratic() - quadratic line search
883: . SNESLineSearchNo() - the full Newton step (actually not a line search)
884: - SNESLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
886: Options Database Keys:
887: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
888: . -snes_ls_alpha <alpha> - Sets alpha
889: . -snes_ls_maxstep <max> - Sets maxstep
890: - -snes_xtol <steptol> - Sets steptol, this is the minimum step size that the line search code. This is the same as the minimum step length
891: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
893: Calling sequence of func:
894: .vb
895: func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
896: .ve
898: Input parameters for func:
899: + snes - nonlinear context
900: . lsctx - optional user-defined context for line search
901: . x - current iterate
902: . f - residual evaluated at x
903: . y - search direction
904: . w - work vector
905: - fnorm - 2-norm of f
907: Output parameters for func:
908: + g - residual evaluated at new iterate y
909: . w - new iterate
910: . gnorm - 2-norm of g
911: . ynorm - 2-norm of search length
912: - flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure.
914: Level: advanced
916: .keywords: SNES, nonlinear, set, line search, routine
918: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchNoNorms(),
919: SNESLineSearchSetPostCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams(), SNESLineSearchSetPreCheck()
920: @*/
921: PetscErrorCode SNESLineSearchSet(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx)
922: {
923: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*);
926: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSet_C",(void (**)(void))&f);
927: if (f) {
928: (*f)(snes,func,lsctx);
929: }
930: return(0);
931: }
934: /* -------------------------------------------------------------------------- */
938: PetscErrorCode SNESLineSearchSet_LS(SNES snes,FCN2 func,void *lsctx)
939: {
941: ((SNES_LS *)(snes->data))->LineSearch = func;
942: ((SNES_LS *)(snes->data))->lsP = lsctx;
943: return(0);
944: }
946: /* -------------------------------------------------------------------------- */
949: /*@C
950: SNESLineSearchSetPostCheck - Sets a routine to check the validity of new iterate computed
951: by the line search routine in the Newton-based method SNESLS.
953: Input Parameters:
954: + snes - nonlinear context obtained from SNESCreate()
955: . func - pointer to function
956: - checkctx - optional user-defined context for use by step checking routine
958: Collective on SNES
960: Calling sequence of func:
961: .vb
962: int func (SNES snes, Vec x,Vec y,Vec w,void *checkctx, PetscTruth *changed_y,PetscTruth *changed_w)
963: .ve
964: where func returns an error code of 0 on success and a nonzero
965: on failure.
967: Input parameters for func:
968: + snes - nonlinear context
969: . checkctx - optional user-defined context for use by step checking routine
970: . x - previous iterate
971: . y - new search direction and length
972: - w - current candidate iterate
974: Output parameters for func:
975: + y - search direction (possibly changed)
976: . w - current iterate (possibly modified)
977: . changed_y - indicates search direction was changed by this routine
978: - changed_w - indicates current iterate was changed by this routine
980: Level: advanced
982: Notes: All line searches accept the new iterate computed by the line search checking routine.
984: Only one of changed_y and changed_w can be PETSC_TRUE
986: On input w = x + y
988: SNESLineSearchNo() and SNESLineSearchNoNorms() (1) compute a candidate iterate u_{i+1}, (2) pass control
989: to the checking routine, and then (3) compute the corresponding nonlinear
990: function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
992: SNESLineSearchQuadratic() and SNESLineSearchCubic() (1) compute a candidate iterate u_{i+1} as well as a
993: candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
994: routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
995: were made to the candidate iterate in the checking routine (as indicated
996: by flag=PETSC_TRUE). The overhead of this extra function re-evaluation can be
997: very costly, so use this feature with caution!
999: .keywords: SNES, nonlinear, set, line search check, step check, routine
1001: .seealso: SNESLineSearchSet(), SNESLineSearchSetPreCheck()
1002: @*/
1003: PetscErrorCode SNESLineSearchSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void *checkctx)
1004: {
1005: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void*);
1008: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPostCheck_C",(void (**)(void))&f);
1009: if (f) {
1010: (*f)(snes,func,checkctx);
1011: }
1012: return(0);
1013: }
1016: /*@C
1017: SNESLineSearchSetPreCheck - Sets a routine to check the validity of a new direction given by the linear solve
1018: before the line search is called.
1020: Input Parameters:
1021: + snes - nonlinear context obtained from SNESCreate()
1022: . func - pointer to function
1023: - checkctx - optional user-defined context for use by step checking routine
1025: Collective on SNES
1027: Calling sequence of func:
1028: .vb
1029: int func (SNES snes, Vec x,Vec y,void *checkctx, PetscTruth *changed_y)
1030: .ve
1031: where func returns an error code of 0 on success and a nonzero
1032: on failure.
1034: Input parameters for func:
1035: + snes - nonlinear context
1036: . checkctx - optional user-defined context for use by step checking routine
1037: . x - previous iterate
1038: - y - new search direction and length
1040: Output parameters for func:
1041: + y - search direction (possibly changed)
1042: - changed_y - indicates search direction was changed by this routine
1044: Level: advanced
1046: Notes: All line searches accept the new iterate computed by the line search checking routine.
1048: .keywords: SNES, nonlinear, set, line search check, step check, routine
1050: .seealso: SNESLineSearchSet(), SNESLineSearchSetPostCheck(), SNESSetUpdate()
1051: @*/
1052: PetscErrorCode SNESLineSearchSetPreCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,void*,PetscTruth*),void *checkctx)
1053: {
1054: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,void*,PetscTruth*),void*);
1057: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPreCheck_C",(void (**)(void))&f);
1058: if (f) {
1059: (*f)(snes,func,checkctx);
1060: }
1061: return(0);
1062: }
1064: /* -------------------------------------------------------------------------- */
1070: PetscErrorCode SNESLineSearchSetPostCheck_LS(SNES snes,FCN1 func,void *checkctx)
1071: {
1073: ((SNES_LS *)(snes->data))->postcheckstep = func;
1074: ((SNES_LS *)(snes->data))->postcheck = checkctx;
1075: return(0);
1076: }
1082: PetscErrorCode SNESLineSearchSetPreCheck_LS(SNES snes,FCN3 func,void *checkctx)
1083: {
1085: ((SNES_LS *)(snes->data))->precheckstep = func;
1086: ((SNES_LS *)(snes->data))->precheck = checkctx;
1087: return(0);
1088: }
1091: /*
1092: SNESView_LS - Prints info from the SNESLS data structure.
1094: Input Parameters:
1095: . SNES - the SNES context
1096: . viewer - visualization context
1098: Application Interface Routine: SNESView()
1099: */
1102: static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
1103: {
1104: SNES_LS *ls = (SNES_LS *)snes->data;
1105: const char *cstr;
1107: PetscTruth iascii;
1110: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
1111: if (iascii) {
1112: if (ls->LineSearch == SNESLineSearchNo) cstr = "SNESLineSearchNo";
1113: else if (ls->LineSearch == SNESLineSearchQuadratic) cstr = "SNESLineSearchQuadratic";
1114: else if (ls->LineSearch == SNESLineSearchCubic) cstr = "SNESLineSearchCubic";
1115: else cstr = "unknown";
1116: PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);
1117: PetscViewerASCIIPrintf(viewer," alpha=%G, maxstep=%G\n",ls->alpha,ls->maxstep);
1118: } else {
1119: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
1120: }
1121: return(0);
1122: }
1123: /* -------------------------------------------------------------------------- */
1124: /*
1125: SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
1127: Input Parameter:
1128: . snes - the SNES context
1130: Application Interface Routine: SNESSetFromOptions()
1131: */
1134: static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
1135: {
1136: SNES_LS *ls = (SNES_LS *)snes->data;
1137: const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1139: PetscInt indx;
1140: PetscTruth flg;
1143: PetscOptionsHead("SNES Line search options");
1144: PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);
1145: PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);
1147: PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
1148: if (flg) {
1149: switch (indx) {
1150: case 0:
1151: SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
1152: break;
1153: case 1:
1154: SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);
1155: break;
1156: case 2:
1157: SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);
1158: break;
1159: case 3:
1160: SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);
1161: break;
1162: }
1163: }
1164: PetscOptionsTail();
1165: return(0);
1166: }
1167: /* -------------------------------------------------------------------------- */
1168: /*MC
1169: SNESLS - Newton based nonlinear solver that uses a line search
1171: Options Database:
1172: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1173: . -snes_ls_alpha <alpha> - Sets alpha
1174: . -snes_ls_maxstep <max> - Sets maxstep
1175: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
1176: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
1177: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
1179: Notes: This is the default nonlinear solver in SNES
1181: Level: beginner
1183: .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1184: SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1185: SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck()
1187: M*/
1191: PetscErrorCode SNESCreate_LS(SNES snes)
1192: {
1194: SNES_LS *neP;
1197: snes->ops->setup = SNESSetUp_LS;
1198: snes->ops->solve = SNESSolve_LS;
1199: snes->ops->destroy = SNESDestroy_LS;
1200: snes->ops->setfromoptions = SNESSetFromOptions_LS;
1201: snes->ops->view = SNESView_LS;
1203: PetscNewLog(snes,SNES_LS,&neP);
1204: snes->data = (void*)neP;
1205: neP->alpha = 1.e-4;
1206: neP->maxstep = 1.e8;
1207: neP->LineSearch = SNESLineSearchCubic;
1208: neP->lsP = PETSC_NULL;
1209: neP->postcheckstep = PETSC_NULL;
1210: neP->postcheck = PETSC_NULL;
1211: neP->precheckstep = PETSC_NULL;
1212: neP->precheck = PETSC_NULL;
1214: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C",
1215: "SNESLineSearchSet_LS",
1216: SNESLineSearchSet_LS);
1217: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C",
1218: "SNESLineSearchSetPostCheck_LS",
1219: SNESLineSearchSetPostCheck_LS);
1220: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C",
1221: "SNESLineSearchSetPreCheck_LS",
1222: SNESLineSearchSetPreCheck_LS);
1224: return(0);
1225: }