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: }