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: PetscLogInfo((0,"SNESSolve_LS: || 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: PetscLogInfo((0,"SNESSolve_LS: (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;
56: PetscScalar mone = -1.0;
59: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
60: if (hastranspose) {
61: MatMult(A,X,W1);
62: VecAXPY(W1,mone,F);
64: /* Compute || J^T W|| */
65: MatMultTranspose(A,W1,W2);
66: VecNorm(W1,NORM_2,&a1);
67: VecNorm(W2,NORM_2,&a2);
68: if (a1) {
69: PetscLogInfo((0,"SNESSolve_LS: ||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",a2/a1));
70: }
71: }
72: return(0);
73: }
75: /* --------------------------------------------------------------------
77: This file implements a truncated Newton method with a line search,
78: for solving a system of nonlinear equations, using the KSP, Vec,
79: and Mat interfaces for linear solvers, vectors, and matrices,
80: respectively.
82: The following basic routines are required for each nonlinear solver:
83: SNESCreate_XXX() - Creates a nonlinear solver context
84: SNESSetFromOptions_XXX() - Sets runtime options
85: SNESSolve_XXX() - Solves the nonlinear system
86: SNESDestroy_XXX() - Destroys the nonlinear solver context
87: The suffix "_XXX" denotes a particular implementation, in this case
88: we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
89: systems of nonlinear equations with a line search (LS) method.
90: These routines are actually called via the common user interface
91: routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
92: SNESDestroy(), so the application code interface remains identical
93: for all nonlinear solvers.
95: Another key routine is:
96: SNESSetUp_XXX() - Prepares for the use of a nonlinear solver
97: by setting data structures and options. The interface routine SNESSetUp()
98: is not usually called directly by the user, but instead is called by
99: SNESSolve() if necessary.
101: Additional basic routines are:
102: SNESView_XXX() - Prints details of runtime options that
103: have actually been used.
104: These are called by application codes via the interface routines
105: SNESView().
107: The various types of solvers (preconditioners, Krylov subspace methods,
108: nonlinear solvers, timesteppers) are all organized similarly, so the
109: above description applies to these categories also.
111: -------------------------------------------------------------------- */
112: /*
113: SNESSolve_LS - Solves a nonlinear system with a truncated Newton
114: method with a line search.
116: Input Parameters:
117: . snes - the SNES context
119: Output Parameter:
120: . outits - number of iterations until termination
122: Application Interface Routine: SNESSolve()
124: Notes:
125: This implements essentially a truncated Newton method with a
126: line search. By default a cubic backtracking line search
127: is employed, as described in the text "Numerical Methods for
128: Unconstrained Optimization and Nonlinear Equations" by Dennis
129: and Schnabel.
130: */
133: PetscErrorCode SNESSolve_LS(SNES snes)
134: {
135: SNES_LS *neP = (SNES_LS*)snes->data;
137: PetscInt maxits,i,lits;
138: PetscTruth lssucceed;
139: MatStructure flg = DIFFERENT_NONZERO_PATTERN;
140: PetscReal fnorm,gnorm,xnorm,ynorm;
141: Vec Y,X,F,G,W,TMP;
142: KSP ksp;
145: SNESGetKSP(snes,&ksp);
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: if (fnorm < snes->abstol) {snes->reason = SNES_CONVERGED_FNORM_ABS; return(0);}
169: /* set parameter for default relative tolerance convergence test */
170: snes->ttol = fnorm*snes->rtol;
172: for (i=0; i<maxits; i++) {
174: /* Call general purpose update function */
175: if (snes->update) {
176: (*snes->update)(snes, snes->iter);
177: }
179: /* Solve J Y = F, where J is Jacobian matrix */
180: SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
181: KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
182: KSPSolve(snes->ksp,F,Y);
183: KSPGetIterationNumber(ksp,&lits);
185: if (neP->precheckstep) {
186: PetscTruth changed_y = PETSC_FALSE;
187: (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);
188: }
190: if (PetscLogPrintInfo){
191: SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);
192: }
194: /* should check what happened to the linear solve? */
195: snes->linear_its += lits;
196: PetscLogInfo((snes,"SNESSolve_LS: iter=%D, linear solve iterations=%D\n",snes->iter,lits));
198: /* Compute a (scaled) negative update in the line search routine:
199: Y <- X - lambda*Y
200: and evaluate G(Y) = function(Y))
201: */
202: VecCopy(Y,snes->vec_sol_update_always);
203: (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);
204: PetscLogInfo((snes,"SNESSolve_LS: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed));
205: if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
207: TMP = F; F = G; snes->vec_func_always = F; G = TMP;
208: TMP = X; X = W; snes->vec_sol_always = X; W = TMP;
209: fnorm = gnorm;
211: PetscObjectTakeAccess(snes);
212: snes->iter = i+1;
213: snes->norm = fnorm;
214: PetscObjectGrantAccess(snes);
215: SNESLogConvHistory(snes,fnorm,lits);
216: SNESMonitor(snes,i+1,fnorm);
218: if (!lssucceed) {
219: PetscTruth ismin;
221: if (++snes->numFailures >= snes->maxFailures) {
222: snes->reason = SNES_DIVERGED_LS_FAILURE;
223: SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);
224: if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
225: break;
226: }
227: }
229: /* Test for convergence */
230: if (snes->converged) {
231: VecNorm(X,NORM_2,&xnorm); /* xnorm = || X || */
232: (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
233: if (snes->reason) {
234: break;
235: }
236: }
237: }
238: if (X != snes->vec_sol) {
239: VecCopy(X,snes->vec_sol);
240: }
241: if (F != snes->vec_func) {
242: VecCopy(F,snes->vec_func);
243: }
244: snes->vec_sol_always = snes->vec_sol;
245: snes->vec_func_always = snes->vec_func;
246: if (i == maxits) {
247: PetscLogInfo((snes,"SNESSolve_LS: Maximum number of iterations has been reached: %D\n",maxits));
248: snes->reason = SNES_DIVERGED_MAX_IT;
249: }
250: return(0);
251: }
252: /* -------------------------------------------------------------------------- */
253: /*
254: SNESSetUp_LS - Sets up the internal data structures for the later use
255: of the SNESLS nonlinear solver.
257: Input Parameter:
258: . snes - the SNES context
259: . x - the solution vector
261: Application Interface Routine: SNESSetUp()
263: Notes:
264: For basic use of the SNES solvers, the user need not explicitly call
265: SNESSetUp(), since these actions will automatically occur during
266: the call to SNESSolve().
267: */
270: PetscErrorCode SNESSetUp_LS(SNES snes)
271: {
275: if (!snes->work) {
276: snes->nwork = 4;
277: VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
278: PetscLogObjectParents(snes,snes->nwork,snes->work);
279: snes->vec_sol_update_always = snes->work[3];
280: }
281: return(0);
282: }
283: /* -------------------------------------------------------------------------- */
284: /*
285: SNESDestroy_LS - Destroys the private SNES_LS context that was created
286: with SNESCreate_LS().
288: Input Parameter:
289: . snes - the SNES context
291: Application Interface Routine: SNESDestroy()
292: */
295: PetscErrorCode SNESDestroy_LS(SNES snes)
296: {
300: if (snes->nwork) {
301: VecDestroyVecs(snes->work,snes->nwork);
302: }
303: PetscFree(snes->data);
304: return(0);
305: }
306: /* -------------------------------------------------------------------------- */
310: /*@C
311: SNESLineSearchNo - This routine is not a line search at all;
312: it simply uses the full Newton step. Thus, this routine is intended
313: to serve as a template and is not recommended for general use.
315: Collective on SNES and Vec
317: Input Parameters:
318: + snes - nonlinear context
319: . lsctx - optional context for line search (not used here)
320: . x - current iterate
321: . f - residual evaluated at x
322: . y - search direction
323: . w - work vector
324: - fnorm - 2-norm of f
326: Output Parameters:
327: + g - residual evaluated at new iterate y
328: . w - new iterate
329: . gnorm - 2-norm of g
330: . ynorm - 2-norm of search length
331: - flag - PETSC_TRUE on success, PETSC_FALSE on failure
333: Options Database Key:
334: . -snes_ls basic - Activates SNESLineSearchNo()
336: Level: advanced
338: .keywords: SNES, nonlinear, line search, cubic
340: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
341: SNESLineSearchSet(), SNESLineSearchNoNorms()
342: @*/
343: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchNo(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
344: {
346: PetscScalar mone = -1.0;
347: SNES_LS *neP = (SNES_LS*)snes->data;
348: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
351: *flag = PETSC_TRUE;
352: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
353: VecNorm(y,NORM_2,ynorm); /* ynorm = || y || */
354: VecWAXPY(w,mone,y,x); /* w <- x - y */
355: if (neP->postcheckstep) {
356: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
357: }
358: if (changed_y) {
359: VecWAXPY(w,mone,y,x); /* w <- x - y */
360: }
361: SNESComputeFunction(snes,w,g);
362: if (PetscExceptionValue(ierr)) {
363: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
364: }
365:
367: VecNorm(g,NORM_2,gnorm); /* gnorm = || g || */
368: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
369: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
370: return(0);
371: }
372: /* -------------------------------------------------------------------------- */
376: /*@C
377: SNESLineSearchNoNorms - This routine is not a line search at
378: all; it simply uses the full Newton step. This version does not
379: even compute the norm of the function or search direction; this
380: is intended only when you know the full step is fine and are
381: not checking for convergence of the nonlinear iteration (for
382: example, you are running always for a fixed number of Newton steps).
384: Collective on SNES and Vec
386: Input Parameters:
387: + snes - nonlinear context
388: . lsctx - optional context for line search (not used here)
389: . x - current iterate
390: . f - residual evaluated at x
391: . y - search direction
392: . w - work vector
393: - fnorm - 2-norm of f
395: Output Parameters:
396: + g - residual evaluated at new iterate y
397: . w - new iterate
398: . gnorm - not changed
399: . ynorm - not changed
400: - flag - set to PETSC_TRUE indicating a successful line search
402: Options Database Key:
403: . -snes_ls basicnonorms - Activates SNESLineSearchNoNorms()
405: Notes:
406: SNESLineSearchNoNorms() must be used in conjunction with
407: either the options
408: $ -snes_no_convergence_test -snes_max_it <its>
409: or alternatively a user-defined custom test set via
410: SNESSetConvergenceTest(); or a -snes_max_it of 1,
411: otherwise, the SNES solver will generate an error.
413: During the final iteration this will not evaluate the function at
414: the solution point. This is to save a function evaluation while
415: using pseudo-timestepping.
417: The residual norms printed by monitoring routines such as
418: SNESDefaultMonitor() (as activated via -snes_monitor) will not be
419: correct, since they are not computed.
421: Level: advanced
423: .keywords: SNES, nonlinear, line search, cubic
425: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(),
426: SNESLineSearchSet(), SNESLineSearchNo()
427: @*/
428: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
429: {
431: PetscScalar mone = -1.0;
432: SNES_LS *neP = (SNES_LS*)snes->data;
433: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
436: *flag = PETSC_TRUE;
437: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
438: VecWAXPY(w,mone,y,x); /* w <- x - y */
439: if (neP->postcheckstep) {
440: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
441: }
442: if (changed_y) {
443: VecWAXPY(w,mone,y,x); /* w <- x - y */
444: }
445:
446: /* don't evaluate function the last time through */
447: if (snes->iter < snes->max_its-1) {
448: SNESComputeFunction(snes,w,g);
449: if (PetscExceptionValue(ierr)) {
450: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
451: }
452:
453: }
454: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
455: return(0);
456: }
457: /* -------------------------------------------------------------------------- */
460: /*@C
461: SNESLineSearchCubic - Performs a cubic line search (default line search method).
463: Collective on SNES
465: Input Parameters:
466: + snes - nonlinear context
467: . lsctx - optional context for line search (not used here)
468: . x - current iterate
469: . f - residual evaluated at x
470: . y - search direction
471: . w - work vector
472: - fnorm - 2-norm of f
474: Output Parameters:
475: + g - residual evaluated at new iterate y
476: . w - new iterate
477: . gnorm - 2-norm of g
478: . ynorm - 2-norm of search length
479: - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.
481: Options Database Key:
482: $ -snes_ls cubic - Activates SNESLineSearchCubic()
484: Notes:
485: This line search is taken from "Numerical Methods for Unconstrained
486: Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
488: Level: advanced
490: .keywords: SNES, nonlinear, line search, cubic
492: .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
493: @*/
494: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchCubic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
495: {
496: /*
497: Note that for line search purposes we work with with the related
498: minimization problem:
499: min z(x): R^n -> R,
500: where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
501: */
502:
503: PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
504: PetscReal maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg;
505: #if defined(PETSC_USE_COMPLEX)
506: PetscScalar cinitslope,clambda;
507: #endif
509: PetscInt count;
510: SNES_LS *neP = (SNES_LS*)snes->data;
511: PetscScalar mone = -1.0,scale;
512: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
515: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
516: *flag = PETSC_TRUE;
517: alpha = neP->alpha;
518: maxstep = neP->maxstep;
519: steptol = neP->steptol;
521: VecNorm(y,NORM_2,ynorm);
522: if (!*ynorm) {
523: PetscLogInfo((snes,"SNESLineSearchCubic: Search direction and size is 0\n"));
524: *gnorm = fnorm;
525: VecCopy(x,w);
526: VecCopy(f,g);
527: *flag = PETSC_FALSE;
528: goto theend1;
529: }
530: if (*ynorm > maxstep) { /* Step too big, so scale back */
531: scale = maxstep/(*ynorm);
532: #if defined(PETSC_USE_COMPLEX)
533: PetscLogInfo((snes,"SNESLineSearchCubic: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm));
534: #else
535: PetscLogInfo((snes,"SNESLineSearchCubic: Scaling step by %g old ynorm %g\n",scale,*ynorm));
536: #endif
537: VecScale(y,scale);
538: *ynorm = maxstep;
539: }
540: VecMaxPointwiseDivide(y,x,&rellength);
541: minlambda = steptol/rellength;
542: MatMult(snes->jacobian,y,w);
543: #if defined(PETSC_USE_COMPLEX)
544: VecDot(f,w,&cinitslope);
545: initslope = PetscRealPart(cinitslope);
546: #else
547: VecDot(f,w,&initslope);
548: #endif
549: if (initslope > 0.0) initslope = -initslope;
550: if (initslope == 0.0) initslope = -1.0;
552: VecCopy(y,w);
553: VecAYPX(w,mone,x);
554: if (snes->nfuncs >= snes->max_funcs) {
555: PetscLogInfo((snes,"SNESLineSearchCubic:Exceeded maximum function evaluations, while checking full step length!\n"));
556: *flag = PETSC_FALSE;
557: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
558: goto theend1;
559: }
560: SNESComputeFunction(snes,w,g);
561: if (PetscExceptionValue(ierr)) {
562: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
563: }
564:
565: VecNorm(g,NORM_2,gnorm);
566: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
567: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
568: PetscLogInfo((snes,"SNESLineSearchCubic: Using full step\n"));
569: goto theend1;
570: }
572: /* Fit points with quadratic */
573: lambda = 1.0;
574: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
575: lambdaprev = lambda;
576: gnormprev = *gnorm;
577: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
578: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
579: else lambda = lambdatemp;
580: VecCopy(x,w);
581: lambdaneg = -lambda;
582: #if defined(PETSC_USE_COMPLEX)
583: clambda = lambdaneg; VecAXPY(w,clambda,y);
584: #else
585: VecAXPY(w,lambdaneg,y);
586: #endif
587: if (snes->nfuncs >= snes->max_funcs) {
588: PetscLogInfo((snes,"SNESLineSearchCubic:Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n"));
589: *flag = PETSC_FALSE;
590: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
591: goto theend1;
592: }
593: SNESComputeFunction(snes,w,g);
594: if (PetscExceptionValue(ierr)) {
595: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
596: }
597:
598: VecNorm(g,NORM_2,gnorm);
599: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
600: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
601: PetscLogInfo((snes,"SNESLineSearchCubic: Quadratically determined step, lambda=%18.16e\n",lambda));
602: goto theend1;
603: }
605: /* Fit points with cubic */
606: count = 1;
607: while (count < 10000) {
608: if (lambda <= minlambda) { /* bad luck; use full step */
609: PetscLogInfo((snes,"SNESLineSearchCubic:Unable to find good step length! %D \n",count));
610: PetscLogInfo((snes,"SNESLineSearchCubic:fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope));
611: *flag = PETSC_FALSE;
612: break;
613: }
614: t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
615: t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope;
616: a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
617: b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
618: d = b*b - 3*a*initslope;
619: if (d < 0.0) d = 0.0;
620: if (a == 0.0) {
621: lambdatemp = -initslope/(2.0*b);
622: } else {
623: lambdatemp = (-b + sqrt(d))/(3.0*a);
624: }
625: lambdaprev = lambda;
626: gnormprev = *gnorm;
627: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
628: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
629: else lambda = lambdatemp;
630: VecCopy(x,w);
631: lambdaneg = -lambda;
632: #if defined(PETSC_USE_COMPLEX)
633: clambda = lambdaneg;
634: VecAXPY(w,clambda,y);
635: #else
636: VecAXPY(w,lambdaneg,y);
637: #endif
638: if (snes->nfuncs >= snes->max_funcs) {
639: PetscLogInfo((snes,"SNESLineSearchCubic:Exceeded maximum function evaluations, while looking for good step length! %D \n",count));
640: PetscLogInfo((snes,"SNESLineSearchCubic: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)) {
647: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
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: PetscLogInfo((snes,"SNESLineSearchCubic: Cubically determined step, lambda=%18.16e\n",lambda));
654: break;
655: } else {
656: PetscLogInfo((snes,"SNESLineSearchCubic: 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,mone,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)) {
673: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
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: }
683: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
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 y
705: . w - new iterate
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 Key:
711: . -snes_ls quadratic - Activates SNESLineSearchQuadratic()
713: Notes:
714: Use SNESLineSearchSet() to set this routine within the SNESLS method.
716: Level: advanced
718: .keywords: SNES, nonlinear, quadratic, line search
720: .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
721: @*/
722: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchQuadratic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
723: {
724: /*
725: Note that for line search purposes we work with with the related
726: minimization problem:
727: min z(x): R^n -> R,
728: where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
729: */
730: PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength;
731: #if defined(PETSC_USE_COMPLEX)
732: PetscScalar cinitslope,clambda;
733: #endif
735: PetscInt count;
736: SNES_LS *neP = (SNES_LS*)snes->data;
737: PetscScalar mone = -1.0,scale;
738: PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
741: PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);
742: *flag = PETSC_TRUE;
743: alpha = neP->alpha;
744: maxstep = neP->maxstep;
745: steptol = neP->steptol;
747: VecNorm(y,NORM_2,ynorm);
748: if (*ynorm == 0.0) {
749: PetscLogInfo((snes,"SNESLineSearchQuadratic: Search direction and size is 0\n"));
750: *gnorm = fnorm;
751: VecCopy(x,y);
752: VecCopy(f,g);
753: *flag = PETSC_FALSE;
754: goto theend2;
755: }
756: if (*ynorm > maxstep) { /* Step too big, so scale back */
757: scale = maxstep/(*ynorm);
758: VecScale(y,scale);
759: *ynorm = maxstep;
760: }
761: VecMaxPointwiseDivide(y,x,&rellength);
762: minlambda = steptol/rellength;
763: MatMult(snes->jacobian,y,w);
764: #if defined(PETSC_USE_COMPLEX)
765: VecDot(f,w,&cinitslope);
766: initslope = PetscRealPart(cinitslope);
767: #else
768: VecDot(f,w,&initslope);
769: #endif
770: if (initslope > 0.0) initslope = -initslope;
771: if (initslope == 0.0) initslope = -1.0;
773: VecCopy(y,w);
774: VecAYPX(w,mone,x);
775: if (snes->nfuncs >= snes->max_funcs) {
776: PetscLogInfo((snes,"SNESLineSearchQuadratic:Exceeded maximum function evaluations, while checking full step length!\n"));
777: VecCopy(w,y);
778: *flag = PETSC_FALSE;
779: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
780: goto theend2;
781: }
782: SNESComputeFunction(snes,w,g);
783: if (PetscExceptionValue(ierr)) {
784: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
785: }
786:
787: VecNorm(g,NORM_2,gnorm);
788: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
789: if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
790: VecCopy(w,y);
791: PetscLogInfo((snes,"SNESLineSearchQuadratic: Using full step\n"));
792: goto theend2;
793: }
795: /* Fit points with quadratic */
796: lambda = 1.0;
797: count = 1;
798: while (PETSC_TRUE) {
799: if (lambda <= minlambda) { /* bad luck; use full step */
800: PetscLogInfo((snes,"SNESLineSearchQuadratic:Unable to find good step length! %D \n",count));
801: PetscLogInfo((snes,"SNESLineSearchQuadratic:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope));
802: VecCopy(x,y);
803: *flag = PETSC_FALSE;
804: break;
805: }
806: lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
807: if (lambdatemp > .5*lambda) lambdatemp = .5*lambda;
808: if (lambdatemp <= .1*lambda) lambda = .1*lambda;
809: else lambda = lambdatemp;
810: VecCopy(x,w);
811: lambdaneg = -lambda;
812: #if defined(PETSC_USE_COMPLEX)
813: clambda = lambdaneg; VecAXPY(w,clambda,y);
814: #else
815: VecAXPY(w,lambdaneg,y);
816: #endif
817: if (snes->nfuncs >= snes->max_funcs) {
818: PetscLogInfo((snes,"SNESLineSearchQuadratic:Exceeded maximum function evaluations, while looking for good step length! %D \n",count));
819: PetscLogInfo((snes,"SNESLineSearchQuadratic:fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope));
820: VecCopy(w,y);
821: *flag = PETSC_FALSE;
822: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
823: break;
824: }
825: SNESComputeFunction(snes,w,g);
826: if (PetscExceptionValue(ierr)) {
827: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
828: }
829:
830: VecNorm(g,NORM_2,gnorm);
831: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
832: if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
833: VecCopy(w,y);
834: PetscLogInfo((snes,"SNESLineSearchQuadratic:Quadratically determined step, lambda=%g\n",lambda));
835: break;
836: }
837: count++;
838: }
839: theend2:
840: /* Optional user-defined check for line search step validity */
841: if (neP->postcheckstep) {
842: (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
843: if (changed_y) {
844: VecWAXPY(w,mone,y,x);
845: }
846: if (changed_y || changed_w) { /* recompute the function if the step has changed */
847: SNESComputeFunction(snes,w,g);
848: if (PetscExceptionValue(ierr)) {
849: PetscErrorCode pPetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr);
850: }
851:
852: VecNormBegin(g,NORM_2,gnorm);
853: VecNormBegin(w,NORM_2,ynorm);
854: VecNormEnd(g,NORM_2,gnorm);
855: VecNormEnd(w,NORM_2,ynorm);
856: if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
857: }
858: }
859: PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);
860: return(0);
861: }
863: /* -------------------------------------------------------------------------- */
866: /*@C
867: SNESLineSearchSet - Sets the line search routine to be used
868: by the method SNESLS.
870: Input Parameters:
871: + snes - nonlinear context obtained from SNESCreate()
872: . lsctx - optional user-defined context for use by line search
873: - func - pointer to int function
875: Collective on SNES
877: Available Routines:
878: + SNESLineSearchCubic() - default line search
879: . SNESLineSearchQuadratic() - quadratic line search
880: . SNESLineSearchNo() - the full Newton step (actually not a line search)
881: - SNESLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
883: Options Database Keys:
884: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
885: . -snes_ls_alpha <alpha> - Sets alpha
886: . -snes_ls_maxstep <max> - Sets maxstep
887: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
888: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
889: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
891: Calling sequence of func:
892: .vb
893: func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
894: PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
895: .ve
897: Input parameters for func:
898: + snes - nonlinear context
899: . lsctx - optional user-defined context for line search
900: . x - current iterate
901: . f - residual evaluated at x
902: . y - search direction
903: . w - work vector
904: - fnorm - 2-norm of f
906: Output parameters for func:
907: + g - residual evaluated at new iterate y
908: . w - new iterate
909: . gnorm - 2-norm of g
910: . ynorm - 2-norm of search length
911: - flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure.
913: Level: advanced
915: .keywords: SNES, nonlinear, set, line search, routine
917: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchNoNorms(),
918: SNESLineSearchSetPostCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams(), SNESLineSearchSetPreCheck()
919: @*/
920: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSet(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx)
921: {
922: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*);
925: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSet_C",(void (**)(void))&f);
926: if (f) {
927: (*f)(snes,func,lsctx);
928: }
929: return(0);
930: }
933: /* -------------------------------------------------------------------------- */
937: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSet_LS(SNES snes,FCN2 func,void *lsctx)
938: {
940: ((SNES_LS *)(snes->data))->LineSearch = func;
941: ((SNES_LS *)(snes->data))->lsP = lsctx;
942: return(0);
943: }
945: /* -------------------------------------------------------------------------- */
948: /*@C
949: SNESLineSearchSetPostCheck - Sets a routine to check the validity of new iterate computed
950: by the line search routine in the Newton-based method SNESLS.
952: Input Parameters:
953: + snes - nonlinear context obtained from SNESCreate()
954: . func - pointer to function
955: - checkctx - optional user-defined context for use by step checking routine
957: Collective on SNES
959: Calling sequence of func:
960: .vb
961: int func (SNES snes, Vec x,Vec y,Vec w,void *checkctx, PetscTruth *changed_y,PetscTruth *changed_w)
962: .ve
963: where func returns an error code of 0 on success and a nonzero
964: on failure.
966: Input parameters for func:
967: + snes - nonlinear context
968: . checkctx - optional user-defined context for use by step checking routine
969: . x - previous iterate
970: . y - new search direction and length
971: - w - current candidate iterate
973: Output parameters for func:
974: + y - search direction (possibly changed)
975: . w - current iterate (possibly modified)
976: . changed_y - indicates search direction was changed by this routine
977: - changed_w - indicates current iterate was changed by this routine
979: Level: advanced
981: Notes: All line searches accept the new iterate computed by the line search checking routine.
983: Only one of changed_y and changed_w can be PETSC_TRUE
985: On input w = x + y
987: SNESLineSearchNo() and SNESLineSearchNoNorms() (1) compute a candidate iterate u_{i+1}, (2) pass control
988: to the checking routine, and then (3) compute the corresponding nonlinear
989: function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
991: SNESLineSearchQuadratic() and SNESLineSearchCubic() (1) compute a candidate iterate u_{i+1} as well as a
992: candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
993: routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
994: were made to the candidate iterate in the checking routine (as indicated
995: by flag=PETSC_TRUE). The overhead of this extra function re-evaluation can be
996: very costly, so use this feature with caution!
998: .keywords: SNES, nonlinear, set, line search check, step check, routine
1000: .seealso: SNESLineSearchSet(), SNESLineSearchSetPreCheck()
1001: @*/
1002: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void *checkctx)
1003: {
1004: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void*);
1007: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPostCheck_C",(void (**)(void))&f);
1008: if (f) {
1009: (*f)(snes,func,checkctx);
1010: }
1011: return(0);
1012: }
1015: /*@C
1016: SNESLineSearchSetPreCheck - Sets a routine to check the validity of a new direction given by the linear solve
1018: Input Parameters:
1019: + snes - nonlinear context obtained from SNESCreate()
1020: . func - pointer to function
1021: - checkctx - optional user-defined context for use by step checking routine
1023: Collective on SNES
1025: Calling sequence of func:
1026: .vb
1027: int func (SNES snes, Vec x,Vec y,,void *checkctx, PetscTruth *changed_y)
1028: .ve
1029: where func returns an error code of 0 on success and a nonzero
1030: on failure.
1032: Input parameters for func:
1033: + snes - nonlinear context
1034: . checkctx - optional user-defined context for use by step checking routine
1035: . x - previous iterate
1036: - y - new search direction and length
1038: Output parameters for func:
1039: + y - search direction (possibly changed)
1040: - changed_y - indicates search direction was changed by this routine
1042: Level: advanced
1044: Notes: All line searches accept the new iterate computed by the line search checking routine.
1046: .keywords: SNES, nonlinear, set, line search check, step check, routine
1048: .seealso: SNESLineSearchSet(), SNESLineSearchSetPostCheck()
1049: @*/
1050: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPreCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,void*,PetscTruth*),void *checkctx)
1051: {
1052: PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,void*,PetscTruth*),void*);
1055: PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPreCheck_C",(void (**)(void))&f);
1056: if (f) {
1057: (*f)(snes,func,checkctx);
1058: }
1059: return(0);
1060: }
1062: /* -------------------------------------------------------------------------- */
1068: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPostCheck_LS(SNES snes,FCN1 func,void *checkctx)
1069: {
1071: ((SNES_LS *)(snes->data))->postcheckstep = func;
1072: ((SNES_LS *)(snes->data))->postcheck = checkctx;
1073: return(0);
1074: }
1080: PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPreCheck_LS(SNES snes,FCN3 func,void *checkctx)
1081: {
1083: ((SNES_LS *)(snes->data))->precheckstep = func;
1084: ((SNES_LS *)(snes->data))->precheck = checkctx;
1085: return(0);
1086: }
1088: /* -------------------------------------------------------------------------- */
1089: /*
1090: SNESPrintHelp_LS - Prints all options for the SNES_LS method.
1092: Input Parameter:
1093: . snes - the SNES context
1095: Application Interface Routine: SNESPrintHelp()
1096: */
1099: static PetscErrorCode SNESPrintHelp_LS(SNES snes,char *p)
1100: {
1101: SNES_LS *ls = (SNES_LS *)snes->data;
1104: (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n");
1105: (*PetscHelpPrintf)(snes->comm," %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
1106: (*PetscHelpPrintf)(snes->comm," %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
1107: (*PetscHelpPrintf)(snes->comm," %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
1108: (*PetscHelpPrintf)(snes->comm," %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol);
1109: return(0);
1110: }
1112: /*
1113: SNESView_LS - Prints info from the SNESLS data structure.
1115: Input Parameters:
1116: . SNES - the SNES context
1117: . viewer - visualization context
1119: Application Interface Routine: SNESView()
1120: */
1123: static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
1124: {
1125: SNES_LS *ls = (SNES_LS *)snes->data;
1126: const char *cstr;
1128: PetscTruth iascii;
1131: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
1132: if (iascii) {
1133: if (ls->LineSearch == SNESLineSearchNo) cstr = "SNESLineSearchNo";
1134: else if (ls->LineSearch == SNESLineSearchQuadratic) cstr = "SNESLineSearchQuadratic";
1135: else if (ls->LineSearch == SNESLineSearchCubic) cstr = "SNESLineSearchCubic";
1136: else cstr = "unknown";
1137: PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);
1138: PetscViewerASCIIPrintf(viewer," alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);
1139: } else {
1140: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
1141: }
1142: return(0);
1143: }
1144: /* -------------------------------------------------------------------------- */
1145: /*
1146: SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
1148: Input Parameter:
1149: . snes - the SNES context
1151: Application Interface Routine: SNESSetFromOptions()
1152: */
1155: static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
1156: {
1157: SNES_LS *ls = (SNES_LS *)snes->data;
1158: const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1160: PetscInt indx;
1161: PetscTruth flg;
1164: PetscOptionsHead("SNES Line search options");
1165: PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);
1166: PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);
1167: PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);
1169: PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
1170: if (flg) {
1171: switch (indx) {
1172: case 0:
1173: SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
1174: break;
1175: case 1:
1176: SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);
1177: break;
1178: case 2:
1179: SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);
1180: break;
1181: case 3:
1182: SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);
1183: break;
1184: }
1185: }
1186: PetscOptionsTail();
1187: return(0);
1188: }
1189: /* -------------------------------------------------------------------------- */
1190: /*MC
1191: SNESLS - Newton based nonlinear solver that uses a line search
1193: Options Database:
1194: + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1195: . -snes_ls_alpha <alpha> - Sets alpha
1196: . -snes_ls_maxstep <max> - Sets maxstep
1197: - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
1198: will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
1199: the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
1201: Notes: This is the default nonlinear solver in SNES
1203: Level: beginner
1205: .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
1206: SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
1207: SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck()
1209: M*/
1213: PetscErrorCode PETSCSNES_DLLEXPORT SNESCreate_LS(SNES snes)
1214: {
1216: SNES_LS *neP;
1219: snes->setup = SNESSetUp_LS;
1220: snes->solve = SNESSolve_LS;
1221: snes->destroy = SNESDestroy_LS;
1222: snes->converged = SNESConverged_LS;
1223: snes->printhelp = SNESPrintHelp_LS;
1224: snes->setfromoptions = SNESSetFromOptions_LS;
1225: snes->view = SNESView_LS;
1226: snes->nwork = 0;
1228: PetscNew(SNES_LS,&neP);
1229: PetscLogObjectMemory(snes,sizeof(SNES_LS));
1230: snes->data = (void*)neP;
1231: neP->alpha = 1.e-4;
1232: neP->maxstep = 1.e8;
1233: neP->steptol = 1.e-12;
1234: neP->LineSearch = SNESLineSearchCubic;
1235: neP->lsP = PETSC_NULL;
1236: neP->postcheckstep = PETSC_NULL;
1237: neP->postcheck = PETSC_NULL;
1238: neP->precheckstep = PETSC_NULL;
1239: neP->precheck = PETSC_NULL;
1241: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_LS",SNESLineSearchSet_LS);
1242: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","SNESLineSearchSetPostCheck_LS",SNESLineSearchSetPostCheck_LS);
1243: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","SNESLineSearchSetPreCheck_LS",SNESLineSearchSetPreCheck_LS);
1245: return(0);
1246: }