Actual source code: ls.c

  1: #define PETSCSNES_DLL

 3:  #include src/snes/impls/ls/ls.h

  5: /*
  6:      Checks if J^T F = 0 which implies we've found a local minimum of the function,
  7:     but not a zero. In the case when one cannot compute J^T F we use the fact that
  8:     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More 
  9:     for this trick.
 10: */
 13: PetscErrorCode SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin)
 14: {
 15:   PetscReal      a1;
 17:   PetscTruth     hastranspose;

 20:   *ismin = PETSC_FALSE;
 21:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
 22:   if (hastranspose) {
 23:     /* Compute || J^T F|| */
 24:     MatMultTranspose(A,F,W);
 25:     VecNorm(W,NORM_2,&a1);
 26:     PetscInfo1(0,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);
 27:     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
 28:   } else {
 29:     Vec         work;
 30:     PetscScalar result;
 31:     PetscReal   wnorm;

 33:     VecSetRandom(W,PETSC_NULL);
 34:     VecNorm(W,NORM_2,&wnorm);
 35:     VecDuplicate(W,&work);
 36:     MatMult(A,W,work);
 37:     VecDot(F,work,&result);
 38:     VecDestroy(work);
 39:     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
 40:     PetscInfo1(0,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);
 41:     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
 42:   }
 43:   return(0);
 44: }

 46: /*
 47:      Checks if J^T(F - J*X) = 0 
 48: */
 51: PetscErrorCode SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2)
 52: {
 53:   PetscReal      a1,a2;
 55:   PetscTruth     hastranspose;

 58:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
 59:   if (hastranspose) {
 60:     MatMult(A,X,W1);
 61:     VecAXPY(W1,-1.0,F);

 63:     /* Compute || J^T W|| */
 64:     MatMultTranspose(A,W1,W2);
 65:     VecNorm(W1,NORM_2,&a1);
 66:     VecNorm(W2,NORM_2,&a2);
 67:     if (a1) {
 68:       PetscInfo1(0,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);
 69:     }
 70:   }
 71:   return(0);
 72: }

 74: /*  -------------------------------------------------------------------- 

 76:      This file implements a truncated Newton method with a line search,
 77:      for solving a system of nonlinear equations, using the KSP, Vec, 
 78:      and Mat interfaces for linear solvers, vectors, and matrices, 
 79:      respectively.

 81:      The following basic routines are required for each nonlinear solver:
 82:           SNESCreate_XXX()          - Creates a nonlinear solver context
 83:           SNESSetFromOptions_XXX()  - Sets runtime options
 84:           SNESSolve_XXX()           - Solves the nonlinear system
 85:           SNESDestroy_XXX()         - Destroys the nonlinear solver context
 86:      The suffix "_XXX" denotes a particular implementation, in this case
 87:      we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
 88:      systems of nonlinear equations with a line search (LS) method.
 89:      These routines are actually called via the common user interface
 90:      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and 
 91:      SNESDestroy(), so the application code interface remains identical 
 92:      for all nonlinear solvers.

 94:      Another key routine is:
 95:           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
 96:      by setting data structures and options.   The interface routine SNESSetUp()
 97:      is not usually called directly by the user, but instead is called by
 98:      SNESSolve() if necessary.

100:      Additional basic routines are:
101:           SNESView_XXX()            - Prints details of runtime options that
102:                                       have actually been used.
103:      These are called by application codes via the interface routines
104:      SNESView().

106:      The various types of solvers (preconditioners, Krylov subspace methods,
107:      nonlinear solvers, timesteppers) are all organized similarly, so the
108:      above description applies to these categories also.  

110:     -------------------------------------------------------------------- */
111: /*
112:    SNESSolve_LS - Solves a nonlinear system with a truncated Newton
113:    method with a line search.

115:    Input Parameters:
116: .  snes - the SNES context

118:    Output Parameter:
119: .  outits - number of iterations until termination

121:    Application Interface Routine: SNESSolve()

123:    Notes:
124:    This implements essentially a truncated Newton method with a
125:    line search.  By default a cubic backtracking line search 
126:    is employed, as described in the text "Numerical Methods for
127:    Unconstrained Optimization and Nonlinear Equations" by Dennis 
128:    and Schnabel.
129: */
132: PetscErrorCode SNESSolve_LS(SNES snes)
133: {
134:   SNES_LS            *neP = (SNES_LS*)snes->data;
135:   PetscErrorCode     ierr;
136:   PetscInt           maxits,i,lits;
137:   PetscTruth         lssucceed;
138:   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
139:   PetscReal          fnorm,gnorm,xnorm,ynorm;
140:   Vec                Y,X,F,G,W,TMP;
141:   KSPConvergedReason kspreason;

144:   snes->numFailures            = 0;
145:   snes->numLinearSolveFailures = 0;
146:   snes->reason                 = SNES_CONVERGED_ITERATING;

148:   maxits        = snes->max_its;        /* maximum number of iterations */
149:   X                = snes->vec_sol;        /* solution vector */
150:   F                = snes->vec_func;        /* residual vector */
151:   Y                = snes->work[0];        /* work vectors */
152:   G                = snes->work[1];
153:   W                = snes->work[2];

155:   PetscObjectTakeAccess(snes);
156:   snes->iter = 0;
157:   PetscObjectGrantAccess(snes);
158:   SNESComputeFunction(snes,X,F);
159:   VecNorm(F,NORM_2,&fnorm);        /* fnorm <- ||F||  */
160:   if (fnorm != fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
161:   PetscObjectTakeAccess(snes);
162:   snes->norm = fnorm;
163:   PetscObjectGrantAccess(snes);
164:   SNESLogConvHistory(snes,fnorm,0);
165:   SNESMonitor(snes,0,fnorm);

167:   /* set parameter for default relative tolerance convergence test */
168:   snes->ttol = fnorm*snes->rtol;
169:   if (snes->ops->converged) {
170:     (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
171:   }
172:   if (snes->reason) return(0);

174:   for (i=0; i<maxits; i++) {

176:     /* Call general purpose update function */
177:     if (snes->ops->update) {
178:       (*snes->ops->update)(snes, snes->iter);
179:     }

181:     /* Solve J Y = F, where J is Jacobian matrix */
182:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
183:     KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
184:     SNES_KSPSolve(snes,snes->ksp,F,Y);
185:     KSPGetConvergedReason(snes->ksp,&kspreason);
186:     if (kspreason < 0) {
187:       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
188:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
189:         return(0);
190:       }
191:     }
192:     KSPGetIterationNumber(snes->ksp,&lits);
193:     snes->linear_its += lits;
194:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);

196:     if (neP->precheckstep) {
197:       PetscTruth changed_y = PETSC_FALSE;
198:       (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);
199:     }

201:     if (PetscLogPrintInfo){
202:       SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);
203:     }

205:     /* Compute a (scaled) negative update in the line search routine: 
206:          Y <- X - lambda*Y 
207:        and evaluate G = function(Y) (depends on the line search). 
208:     */
209:     VecCopy(Y,snes->vec_sol_update_always);
210:     ynorm = 1; gnorm = fnorm;
211:     (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);
212:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
213:     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
214:     TMP = X; X = W; snes->vec_sol_always = X;  W = TMP;
215:     fnorm = gnorm;
216:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;

218:     PetscObjectTakeAccess(snes);
219:     snes->iter = i+1;
220:     snes->norm = fnorm;
221:     PetscObjectGrantAccess(snes);
222:     SNESLogConvHistory(snes,fnorm,lits);
223:     SNESMonitor(snes,i+1,fnorm);

225:     if (!lssucceed) {
226:       PetscTruth ismin;
227:       if (++snes->numFailures >= snes->maxFailures) {
228:         snes->reason = SNES_DIVERGED_LS_FAILURE;
229:         SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);
230:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
231:         break;
232:       }
233:     }

235:     /* Test for convergence */
236:     if (snes->ops->converged) {
237:       VecNorm(X,NORM_2,&xnorm);        /* xnorm = || X || */
238:       (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
239:       if (snes->reason) break;
240:     }
241:   }
242:   if (X != snes->vec_sol) {
243:     VecCopy(X,snes->vec_sol);
244:   }
245:   if (F != snes->vec_func) {
246:     VecCopy(F,snes->vec_func);
247:   }
248:   snes->vec_sol_always  = snes->vec_sol;
249:   snes->vec_func_always = snes->vec_func;
250:   if (i == maxits) {
251:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
252:     snes->reason = SNES_DIVERGED_MAX_IT;
253:   }
254:   return(0);
255: }
256: /* -------------------------------------------------------------------------- */
257: /*
258:    SNESSetUp_LS - Sets up the internal data structures for the later use
259:    of the SNESLS nonlinear solver.

261:    Input Parameter:
262: .  snes - the SNES context
263: .  x - the solution vector

265:    Application Interface Routine: SNESSetUp()

267:    Notes:
268:    For basic use of the SNES solvers, the user need not explicitly call
269:    SNESSetUp(), since these actions will automatically occur during
270:    the call to SNESSolve().
271:  */
274: PetscErrorCode SNESSetUp_LS(SNES snes)
275: {

279:   if (!snes->work) {
280:     snes->nwork = 4;
281:     VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
282:     PetscLogObjectParents(snes,snes->nwork,snes->work);
283:     snes->vec_sol_update_always = snes->work[3];
284:   }
285:   return(0);
286: }
287: /* -------------------------------------------------------------------------- */
288: /*
289:    SNESDestroy_LS - Destroys the private SNES_LS context that was created
290:    with SNESCreate_LS().

292:    Input Parameter:
293: .  snes - the SNES context

295:    Application Interface Routine: SNESDestroy()
296:  */
299: PetscErrorCode SNESDestroy_LS(SNES snes)
300: {

304:   if (snes->nwork) {
305:     VecDestroyVecs(snes->work,snes->nwork);
306:   }
307:   PetscFree(snes->data);

309:   /* clear composed functions */
310:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);
311:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","",PETSC_NULL);
312:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","",PETSC_NULL);

314:   return(0);
315: }
316: /* -------------------------------------------------------------------------- */

320: /*@C
321:    SNESLineSearchNo - This routine is not a line search at all; 
322:    it simply uses the full Newton step.  Thus, this routine is intended 
323:    to serve as a template and is not recommended for general use.  

325:    Collective on SNES and Vec

327:    Input Parameters:
328: +  snes - nonlinear context
329: .  lsctx - optional context for line search (not used here)
330: .  x - current iterate
331: .  f - residual evaluated at x
332: .  y - search direction 
333: .  w - work vector
334: -  fnorm - 2-norm of f

336:    Output Parameters:
337: +  g - residual evaluated at new iterate y
338: .  w - new iterate 
339: .  gnorm - 2-norm of g
340: .  ynorm - 2-norm of search length
341: -  flag - PETSC_TRUE on success, PETSC_FALSE on failure

343:    Options Database Key:
344: .  -snes_ls basic - Activates SNESLineSearchNo()

346:    Level: advanced

348: .keywords: SNES, nonlinear, line search, cubic

350: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
351:           SNESLineSearchSet(), SNESLineSearchNoNorms()
352: @*/
353: PetscErrorCode  SNESLineSearchNo(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
354: {
356:   SNES_LS        *neP = (SNES_LS*)snes->data;
357:   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

360:   *flag = PETSC_TRUE;
362:   VecNorm(y,NORM_2,ynorm);         /* ynorm = || y || */
363:   VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
364:   if (neP->postcheckstep) {
365:    (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
366:   }
367:   if (changed_y) {
368:     VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
369:   }
370:   SNESComputeFunction(snes,w,g);
371:   if (PetscExceptionValue(ierr)) {
373:   }
374: 

376:   VecNorm(g,NORM_2,gnorm);  /* gnorm = || g || */
377:   if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
379:   return(0);
380: }
381: /* -------------------------------------------------------------------------- */

385: /*@C
386:    SNESLineSearchNoNorms - This routine is not a line search at 
387:    all; it simply uses the full Newton step. This version does not
388:    even compute the norm of the function or search direction; this
389:    is intended only when you know the full step is fine and are
390:    not checking for convergence of the nonlinear iteration (for
391:    example, you are running always for a fixed number of Newton steps).

393:    Collective on SNES and Vec

395:    Input Parameters:
396: +  snes - nonlinear context
397: .  lsctx - optional context for line search (not used here)
398: .  x - current iterate
399: .  f - residual evaluated at x
400: .  y - search direction 
401: .  w - work vector
402: -  fnorm - 2-norm of f

404:    Output Parameters:
405: +  g - residual evaluated at new iterate y
406: .  w - new iterate
407: .  gnorm - not changed
408: .  ynorm - not changed
409: -  flag - set to PETSC_TRUE indicating a successful line search

411:    Options Database Key:
412: .  -snes_ls basicnonorms - Activates SNESLineSearchNoNorms()

414:    Notes:
415:    SNESLineSearchNoNorms() must be used in conjunction with
416:    either the options
417: $     -snes_no_convergence_test -snes_max_it <its>
418:    or alternatively a user-defined custom test set via
419:    SNESSetConvergenceTest(); or a -snes_max_it of 1, 
420:    otherwise, the SNES solver will generate an error.

422:    During the final iteration this will not evaluate the function at
423:    the solution point. This is to save a function evaluation while
424:    using pseudo-timestepping.

426:    The residual norms printed by monitoring routines such as
427:    SNESMonitorDefault() (as activated via -snes_monitor) will not be 
428:    correct, since they are not computed.

430:    Level: advanced

432: .keywords: SNES, nonlinear, line search, cubic

434: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
435:           SNESLineSearchSet(), SNESLineSearchNo()
436: @*/
437: PetscErrorCode  SNESLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
438: {
440:   SNES_LS        *neP = (SNES_LS*)snes->data;
441:   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

444:   *flag = PETSC_TRUE;
446:   VecWAXPY(w,-1.0,y,x);            /* w <- x - y      */
447:   if (neP->postcheckstep) {
448:    (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
449:   }
450:   if (changed_y) {
451:     VecWAXPY(w,-1.0,y,x);            /* w <- x - y   */
452:   }
453: 
454:   /* don't evaluate function the last time through */
455:   if (snes->iter < snes->max_its-1) {
456:     SNESComputeFunction(snes,w,g);
457:     if (PetscExceptionValue(ierr)) {
459:     }
460: 
461:   }
463:   return(0);
464: }
465: /* -------------------------------------------------------------------------- */
468: /*@C
469:    SNESLineSearchCubic - Performs a cubic line search (default line search method).

471:    Collective on SNES

473:    Input Parameters:
474: +  snes - nonlinear context
475: .  lsctx - optional context for line search (not used here)
476: .  x - current iterate
477: .  f - residual evaluated at x
478: .  y - search direction 
479: .  w - work vector
480: -  fnorm - 2-norm of f

482:    Output Parameters:
483: +  g - residual evaluated at new iterate y
484: .  w - new iterate 
485: .  gnorm - 2-norm of g
486: .  ynorm - 2-norm of search length
487: -  flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.

489:    Options Database Key:
490: $  -snes_ls cubic - Activates SNESLineSearchCubic()

492:    Notes:
493:    This line search is taken from "Numerical Methods for Unconstrained 
494:    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.

496:    Level: advanced

498: .keywords: SNES, nonlinear, line search, cubic

500: .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
501: @*/
502: PetscErrorCode  SNESLineSearchCubic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
503: {
504:   /* 
505:      Note that for line search purposes we work with with the related
506:      minimization problem:
507:         min  z(x):  R^n -> R,
508:      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
509:    */
510: 
511:   PetscReal      steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
512:   PetscReal      maxstep,minlambda,alpha,lambda,lambdatemp;
513: #if defined(PETSC_USE_COMPLEX)
514:   PetscScalar    cinitslope,clambda;
515: #endif
517:   PetscInt       count;
518:   SNES_LS        *neP = (SNES_LS*)snes->data;
519:   PetscScalar    scale;
520:   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

524:   *flag   = PETSC_TRUE;
525:   alpha   = neP->alpha;
526:   maxstep = neP->maxstep;
527:   steptol = neP->steptol;

529:   VecNorm(y,NORM_2,ynorm);
530:   if (!*ynorm) {
531:     PetscInfo(snes,"Search direction and size is 0\n");
532:     *gnorm = fnorm;
533:     VecCopy(x,w);
534:     VecCopy(f,g);
535:     *flag  = PETSC_FALSE;
536:     goto theend1;
537:   }
538:   if (*ynorm > maxstep) {        /* Step too big, so scale back */
539:     scale = maxstep/(*ynorm);
540:     PetscInfo2(snes,"Scaling step by %G old ynorm %G\n",PetscRealPart(scale),*ynorm);
541:     VecScale(y,scale);
542:     *ynorm = maxstep;
543:   }
544:   VecMaxPointwiseDivide(y,x,&rellength);
545:   minlambda = steptol/rellength;
546:   MatMult(snes->jacobian,y,w);
547: #if defined(PETSC_USE_COMPLEX)
548:   VecDot(f,w,&cinitslope);
549:   initslope = PetscRealPart(cinitslope);
550: #else
551:   VecDot(f,w,&initslope);
552: #endif
553:   if (initslope > 0.0)  initslope = -initslope;
554:   if (initslope == 0.0) initslope = -1.0;

556:   VecWAXPY(w,-1.0,y,x);
557:   if (snes->nfuncs >= snes->max_funcs) {
558:     PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
559:     *flag = PETSC_FALSE;
560:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
561:     goto theend1;
562:   }
563:   SNESComputeFunction(snes,w,g);
564:   if (PetscExceptionValue(ierr)) {
566:   }
567: 
568:   VecNorm(g,NORM_2,gnorm);
569:   if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
570:   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
571:     PetscInfo(snes,"Using full step\n");
572:     goto theend1;
573:   }

575:   /* Fit points with quadratic */
576:   lambda     = 1.0;
577:   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
578:   lambdaprev = lambda;
579:   gnormprev  = *gnorm;
580:   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
581:   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
582:   else                         lambda = lambdatemp;

584: #if defined(PETSC_USE_COMPLEX)
585:   clambda   = lambda; VecWAXPY(w,-clambda,y,x);
586: #else
587:   VecWAXPY(w,-lambda,y,x);
588: #endif
589:   if (snes->nfuncs >= snes->max_funcs) {
590:     PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);
591:     *flag = PETSC_FALSE;
592:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
593:     goto theend1;
594:   }
595:   SNESComputeFunction(snes,w,g);
596:   if (PetscExceptionValue(ierr)) {
598:   }
599: 
600:   VecNorm(g,NORM_2,gnorm);
601:   if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
602:   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
603:     PetscInfo1(snes,"Quadratically determined step, lambda=%18.16e\n",lambda);
604:     goto theend1;
605:   }

607:   /* Fit points with cubic */
608:   count = 1;
609:   while (count < 10000) {
610:     if (lambda <= minlambda) { /* bad luck; use full step */
611:       PetscInfo1(snes,"Unable to find good step length! %D \n",count);
612:       PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
613:       *flag = PETSC_FALSE;
614:       break;
615:     }
616:     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
617:     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
618:     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
619:     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
620:     d  = b*b - 3*a*initslope;
621:     if (d < 0.0) d = 0.0;
622:     if (a == 0.0) {
623:       lambdatemp = -initslope/(2.0*b);
624:     } else {
625:       lambdatemp = (-b + sqrt(d))/(3.0*a);
626:     }
627:     lambdaprev = lambda;
628:     gnormprev  = *gnorm;
629:     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
630:     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
631:     else                         lambda     = lambdatemp;
632: #if defined(PETSC_USE_COMPLEX)
633:     clambda   = lambda;
634:     VecWAXPY(w,-clambda,y,x);
635: #else
636:     VecWAXPY(w,-lambda,y,x);
637: #endif
638:     if (snes->nfuncs >= snes->max_funcs) {
639:       PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
640:       PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
641:       *flag = PETSC_FALSE;
642:       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
643:       break;
644:     }
645:     SNESComputeFunction(snes,w,g);
646:     if (PetscExceptionValue(ierr)) {
648:     }
649: 
650:     VecNorm(g,NORM_2,gnorm);
651:     if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
652:     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
653:       PetscInfo1(snes,"Cubically determined step, lambda=%18.16e\n",lambda);
654:       break;
655:     } else {
656:       PetscInfo1(snes,"Cubic step no good, shrinking lambda,  lambda=%18.16e\n",lambda);
657:     }
658:     count++;
659:   }
660:   if (count >= 10000) {
661:     SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation");
662:   }
663:   theend1:
664:   /* Optional user-defined check for line search step validity */
665:   if (neP->postcheckstep && *flag) {
666:     (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
667:     if (changed_y) {
668:       VecWAXPY(w,-1.0,y,x);
669:     }
670:     if (changed_y || changed_w) { /* recompute the function if the step has changed */
671:       SNESComputeFunction(snes,w,g);
672:       if (PetscExceptionValue(ierr)) {
674:       }
675: 
676:       VecNormBegin(g,NORM_2,gnorm);
677:       if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
678:       VecNormBegin(w,NORM_2,ynorm);
679:       VecNormEnd(g,NORM_2,gnorm);
680:       VecNormEnd(w,NORM_2,ynorm);
681:     }
682:   }
684:   return(0);
685: }
686: /* -------------------------------------------------------------------------- */
689: /*@C
690:    SNESLineSearchQuadratic - Performs a quadratic line search.

692:    Collective on SNES and Vec

694:    Input Parameters:
695: +  snes - the SNES context
696: .  lsctx - optional context for line search (not used here)
697: .  x - current iterate
698: .  f - residual evaluated at x
699: .  y - search direction 
700: .  w - work vector
701: -  fnorm - 2-norm of f

703:    Output Parameters:
704: +  g - residual evaluated at new iterate w
705: .  w - new iterate (x + alpha*y)
706: .  gnorm - 2-norm of g
707: .  ynorm - 2-norm of search length
708: -  flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure.

710:    Options Database Keys:
711: +  -snes_ls quadratic - Activates SNESLineSearchQuadratic()
712: .   -snes_ls_alpha <alpha> - Sets alpha
713: .   -snes_ls_maxstep <max> - Sets maxstep
714: -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
715:                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
716:                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
717:    Notes:
718:    Use SNESLineSearchSet() to set this routine within the SNESLS method.  

720:    Level: advanced

722: .keywords: SNES, nonlinear, quadratic, line search

724: .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms()
725: @*/
726: PetscErrorCode  SNESLineSearchQuadratic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
727: {
728:   /* 
729:      Note that for line search purposes we work with with the related
730:      minimization problem:
731:         min  z(x):  R^n -> R,
732:      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
733:    */
734:   PetscReal      steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,rellength;
735: #if defined(PETSC_USE_COMPLEX)
736:   PetscScalar    cinitslope,clambda;
737: #endif
739:   PetscInt       count;
740:   SNES_LS        *neP = (SNES_LS*)snes->data;
741:   PetscScalar    scale;
742:   PetscTruth     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;

746:   *flag   = PETSC_TRUE;
747:   alpha   = neP->alpha;
748:   maxstep = neP->maxstep;
749:   steptol = neP->steptol;

751:   VecNorm(y,NORM_2,ynorm);
752:   if (*ynorm == 0.0) {
753:     PetscInfo(snes,"Search direction and size is 0\n");
754:     *gnorm = fnorm;
755:     VecCopy(x,w);
756:     VecCopy(f,g);
757:     *flag  = PETSC_FALSE;
758:     goto theend2;
759:   }
760:   if (*ynorm > maxstep) {        /* Step too big, so scale back */
761:     scale  = maxstep/(*ynorm);
762:     VecScale(y,scale);
763:     *ynorm = maxstep;
764:   }
765:   VecMaxPointwiseDivide(y,x,&rellength);
766:   minlambda = steptol/rellength;
767:   MatMult(snes->jacobian,y,w);
768: #if defined(PETSC_USE_COMPLEX)
769:   VecDot(f,w,&cinitslope);
770:   initslope = PetscRealPart(cinitslope);
771: #else
772:   VecDot(f,w,&initslope);
773: #endif
774:   if (initslope > 0.0)  initslope = -initslope;
775:   if (initslope == 0.0) initslope = -1.0;

777:   VecWAXPY(w,-1.0,y,x);
778:   if (snes->nfuncs >= snes->max_funcs) {
779:     PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");
780:     *flag = PETSC_FALSE;
781:     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
782:     goto theend2;
783:   }
784:   SNESComputeFunction(snes,w,g);
785:   if (PetscExceptionValue(ierr)) {
787:   }
788: 
789:   VecNorm(g,NORM_2,gnorm);
790:   if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
791:   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
792:     PetscInfo(snes,"Using full step\n");
793:     goto theend2;
794:   }

796:   /* Fit points with quadratic */
797:   lambda = 1.0;
798:   count = 1;
799:   while (PETSC_TRUE) {
800:     if (lambda <= minlambda) { /* bad luck; use full step */
801:       PetscInfo1(snes,"Unable to find good step length! %D \n",count);
802:       PetscInfo5(snes,"fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);
803:       VecCopy(x,w);
804:       *flag = PETSC_FALSE;
805:       break;
806:     }
807:     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
808:     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
809:     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
810:     else                         lambda     = lambdatemp;
811: 
812: #if defined(PETSC_USE_COMPLEX)
813:     clambda   = lambda; VecWAXPY(w,-clambda,y,x);
814: #else
815:     VecWAXPY(w,-lambda,y,x);
816: #endif
817:     if (snes->nfuncs >= snes->max_funcs) {
818:       PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);
819:       PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
820:       *flag = PETSC_FALSE;
821:       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
822:       break;
823:     }
824:     SNESComputeFunction(snes,w,g);
825:     if (PetscExceptionValue(ierr)) {
827:     }
828: 
829:     VecNorm(g,NORM_2,gnorm);
830:     if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
831:     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
832:       PetscInfo1(snes,"Quadratically determined step, lambda=%G\n",lambda);
833:       break;
834:     }
835:     count++;
836:   }
837:   theend2:
838:   /* Optional user-defined check for line search step validity */
839:   if (neP->postcheckstep) {
840:     (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);
841:     if (changed_y) {
842:       VecWAXPY(w,-1.0,y,x);
843:     }
844:     if (changed_y || changed_w) { /* recompute the function if the step has changed */
845:       SNESComputeFunction(snes,w,g);
846:       if (PetscExceptionValue(ierr)) {
848:       }
849: 
850:       VecNormBegin(g,NORM_2,gnorm);
851:       VecNormBegin(w,NORM_2,ynorm);
852:       VecNormEnd(g,NORM_2,gnorm);
853:       VecNormEnd(w,NORM_2,ynorm);
854:       if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
855:     }
856:   }
858:   return(0);
859: }

861: /* -------------------------------------------------------------------------- */
864: /*@C
865:    SNESLineSearchSet - Sets the line search routine to be used
866:    by the method SNESLS.

868:    Input Parameters:
869: +  snes - nonlinear context obtained from SNESCreate()
870: .  lsctx - optional user-defined context for use by line search 
871: -  func - pointer to int function

873:    Collective on SNES

875:    Available Routines:
876: +  SNESLineSearchCubic() - default line search
877: .  SNESLineSearchQuadratic() - quadratic line search
878: .  SNESLineSearchNo() - the full Newton step (actually not a line search)
879: -  SNESLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)

881:     Options Database Keys:
882: +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
883: .   -snes_ls_alpha <alpha> - Sets alpha
884: .   -snes_ls_maxstep <max> - Sets maxstep
885: -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
886:                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
887:                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)

889:    Calling sequence of func:
890: .vb
891:    func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
892:          PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag)
893: .ve

895:     Input parameters for func:
896: +   snes - nonlinear context
897: .   lsctx - optional user-defined context for line search
898: .   x - current iterate
899: .   f - residual evaluated at x
900: .   y - search direction 
901: .   w - work vector
902: -   fnorm - 2-norm of f

904:     Output parameters for func:
905: +   g - residual evaluated at new iterate y
906: .   w - new iterate 
907: .   gnorm - 2-norm of g
908: .   ynorm - 2-norm of search length
909: -   flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure.

911:     Level: advanced

913: .keywords: SNES, nonlinear, set, line search, routine

915: .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchNoNorms(), 
916:           SNESLineSearchSetPostCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams(), SNESLineSearchSetPreCheck()
917: @*/
918: PetscErrorCode  SNESLineSearchSet(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx)
919: {
920:   PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*);

923:   PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSet_C",(void (**)(void))&f);
924:   if (f) {
925:     (*f)(snes,func,lsctx);
926:   }
927:   return(0);
928: }

931: /* -------------------------------------------------------------------------- */
935: PetscErrorCode  SNESLineSearchSet_LS(SNES snes,FCN2 func,void *lsctx)
936: {
938:   ((SNES_LS *)(snes->data))->LineSearch = func;
939:   ((SNES_LS *)(snes->data))->lsP        = lsctx;
940:   return(0);
941: }
943: /* -------------------------------------------------------------------------- */
946: /*@C
947:    SNESLineSearchSetPostCheck - Sets a routine to check the validity of new iterate computed
948:    by the line search routine in the Newton-based method SNESLS.

950:    Input Parameters:
951: +  snes - nonlinear context obtained from SNESCreate()
952: .  func - pointer to function
953: -  checkctx - optional user-defined context for use by step checking routine 

955:    Collective on SNES

957:    Calling sequence of func:
958: .vb
959:    int func (SNES snes, Vec x,Vec y,Vec w,void *checkctx, PetscTruth *changed_y,PetscTruth *changed_w)
960: .ve
961:    where func returns an error code of 0 on success and a nonzero
962:    on failure.

964:    Input parameters for func:
965: +  snes - nonlinear context
966: .  checkctx - optional user-defined context for use by step checking routine 
967: .  x - previous iterate
968: .  y - new search direction and length
969: -  w - current candidate iterate

971:    Output parameters for func:
972: +  y - search direction (possibly changed)
973: .  w - current iterate (possibly modified)
974: .  changed_y - indicates search direction was changed by this routine
975: -  changed_w - indicates current iterate was changed by this routine

977:    Level: advanced

979:    Notes: All line searches accept the new iterate computed by the line search checking routine.

981:    Only one of changed_y and changed_w can  be PETSC_TRUE

983:    On input w = x + y

985:    SNESLineSearchNo() and SNESLineSearchNoNorms() (1) compute a candidate iterate u_{i+1}, (2) pass control 
986:    to the checking routine, and then (3) compute the corresponding nonlinear
987:    function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.

989:    SNESLineSearchQuadratic() and SNESLineSearchCubic() (1) compute a candidate iterate u_{i+1} as well as a
990:    candidate nonlinear function f(u_{i+1}), (2) pass control to the checking 
991:    routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes 
992:    were made to the candidate iterate in the checking routine (as indicated 
993:    by flag=PETSC_TRUE).  The overhead of this extra function re-evaluation can be
994:    very costly, so use this feature with caution!

996: .keywords: SNES, nonlinear, set, line search check, step check, routine

998: .seealso: SNESLineSearchSet(), SNESLineSearchSetPreCheck()
999: @*/
1000: PetscErrorCode  SNESLineSearchSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void *checkctx)
1001: {
1002:   PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void*);

1005:   PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPostCheck_C",(void (**)(void))&f);
1006:   if (f) {
1007:     (*f)(snes,func,checkctx);
1008:   }
1009:   return(0);
1010: }
1013: /*@C
1014:    SNESLineSearchSetPreCheck - Sets a routine to check the validity of a new direction given by the linear solve
1015:          before the line search is called.

1017:    Input Parameters:
1018: +  snes - nonlinear context obtained from SNESCreate()
1019: .  func - pointer to function
1020: -  checkctx - optional user-defined context for use by step checking routine 

1022:    Collective on SNES

1024:    Calling sequence of func:
1025: .vb
1026:    int func (SNES snes, Vec x,Vec y,void *checkctx, PetscTruth *changed_y)
1027: .ve
1028:    where func returns an error code of 0 on success and a nonzero
1029:    on failure.

1031:    Input parameters for func:
1032: +  snes - nonlinear context
1033: .  checkctx - optional user-defined context for use by step checking routine 
1034: .  x - previous iterate
1035: -  y - new search direction and length

1037:    Output parameters for func:
1038: +  y - search direction (possibly changed)
1039: -  changed_y - indicates search direction was changed by this routine

1041:    Level: advanced

1043:    Notes: All line searches accept the new iterate computed by the line search checking routine.

1045: .keywords: SNES, nonlinear, set, line search check, step check, routine

1047: .seealso: SNESLineSearchSet(), SNESLineSearchSetPostCheck(), SNESSetUpdate()
1048: @*/
1049: PetscErrorCode  SNESLineSearchSetPreCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,void*,PetscTruth*),void *checkctx)
1050: {
1051:   PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,void*,PetscTruth*),void*);

1054:   PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPreCheck_C",(void (**)(void))&f);
1055:   if (f) {
1056:     (*f)(snes,func,checkctx);
1057:   }
1058:   return(0);
1059: }

1061: /* -------------------------------------------------------------------------- */
1067: PetscErrorCode  SNESLineSearchSetPostCheck_LS(SNES snes,FCN1 func,void *checkctx)
1068: {
1070:   ((SNES_LS *)(snes->data))->postcheckstep = func;
1071:   ((SNES_LS *)(snes->data))->postcheck     = checkctx;
1072:   return(0);
1073: }

1079: PetscErrorCode  SNESLineSearchSetPreCheck_LS(SNES snes,FCN3 func,void *checkctx)
1080: {
1082:   ((SNES_LS *)(snes->data))->precheckstep = func;
1083:   ((SNES_LS *)(snes->data))->precheck     = checkctx;
1084:   return(0);
1085: }

1088: /*
1089:    SNESView_LS - Prints info from the SNESLS data structure.

1091:    Input Parameters:
1092: .  SNES - the SNES context
1093: .  viewer - visualization context

1095:    Application Interface Routine: SNESView()
1096: */
1099: static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
1100: {
1101:   SNES_LS        *ls = (SNES_LS *)snes->data;
1102:   const char     *cstr;
1104:   PetscTruth     iascii;

1107:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
1108:   if (iascii) {
1109:     if (ls->LineSearch == SNESLineSearchNo)             cstr = "SNESLineSearchNo";
1110:     else if (ls->LineSearch == SNESLineSearchQuadratic) cstr = "SNESLineSearchQuadratic";
1111:     else if (ls->LineSearch == SNESLineSearchCubic)     cstr = "SNESLineSearchCubic";
1112:     else                                                cstr = "unknown";
1113:     PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);
1114:     PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, steptol=%G\n",ls->alpha,ls->maxstep,ls->steptol);
1115:   } else {
1116:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
1117:   }
1118:   return(0);
1119: }
1120: /* -------------------------------------------------------------------------- */
1121: /*
1122:    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.

1124:    Input Parameter:
1125: .  snes - the SNES context

1127:    Application Interface Routine: SNESSetFromOptions()
1128: */
1131: static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
1132: {
1133:   SNES_LS        *ls = (SNES_LS *)snes->data;
1134:   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
1136:   PetscInt       indx;
1137:   PetscTruth     flg;

1140:   PetscOptionsHead("SNES Line search options");
1141:     PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);
1142:     PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);
1143:     PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);

1145:     PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
1146:     if (flg) {
1147:       switch (indx) {
1148:       case 0:
1149:         SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
1150:         break;
1151:       case 1:
1152:         SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);
1153:         break;
1154:       case 2:
1155:         SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);
1156:         break;
1157:       case 3:
1158:         SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);
1159:         break;
1160:       }
1161:     }
1162:   PetscOptionsTail();
1163:   return(0);
1164: }
1165: /* -------------------------------------------------------------------------- */
1168: /*@C 
1169:    SNESConverged_LS - Monitors the convergence of the line search
1170:    method SNESLS for solving systems of nonlinear equations (default).

1172:    Collective on SNES

1174:    Input Parameters:
1175: +  snes - the SNES context
1176: .  it - the iteration (0 indicates before any Newton steps)
1177: .  xnorm - 2-norm of current iterate
1178: .  pnorm - 2-norm of current step 
1179: .  fnorm - 2-norm of function at current iterate
1180: -  dummy - unused context

1182:    Output Parameter:
1183: .   reason  - one of
1184: $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
1185: $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
1186: $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
1187: $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
1188: $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
1189: $  SNES_CONVERGED_ITERATING       - (otherwise),

1191:    where
1192: +    maxf - maximum number of function evaluations,
1193:             set with SNESSetTolerances()
1194: .    nfct - number of function evaluations,
1195: .    abstol - absolute function norm tolerance,
1196:             set with SNESSetTolerances()
1197: -    rtol - relative function norm tolerance, set with SNESSetTolerances()

1199:    Level: intermediate

1201: .keywords: SNES, nonlinear, default, converged, convergence

1203: .seealso: SNESSetConvergenceTest()
1204: @*/
1205: PetscErrorCode  SNESConverged_LS(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
1206: {
1212:   SNESDefaultConverged(snes,it,xnorm,pnorm,fnorm,reason,dummy);
1213:   return(0);
1214: }
1215: /* -------------------------------------------------------------------------- */
1216: /*MC
1217:       SNESLS - Newton based nonlinear solver that uses a line search

1219:    Options Database:
1220: +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1221: .   -snes_ls_alpha <alpha> - Sets alpha
1222: .   -snes_ls_maxstep <max> - Sets maxstep
1223: -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
1224:                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
1225:                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)

1227:     Notes: This is the default nonlinear solver in SNES

1229:    Level: beginner

1231: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 
1232:            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
1233:           SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck()

1235: M*/
1239: PetscErrorCode  SNESCreate_LS(SNES snes)
1240: {
1242:   SNES_LS        *neP;

1245:   snes->ops->setup             = SNESSetUp_LS;
1246:   snes->ops->solve             = SNESSolve_LS;
1247:   snes->ops->destroy             = SNESDestroy_LS;
1248:   snes->ops->converged             = SNESConverged_LS;
1249:   snes->ops->setfromoptions  = SNESSetFromOptions_LS;
1250:   snes->ops->view            = SNESView_LS;
1251:   snes->nwork                = 0;

1253:   PetscNew(SNES_LS,&neP);
1254:   PetscLogObjectMemory(snes,sizeof(SNES_LS));
1255:   snes->data            = (void*)neP;
1256:   neP->alpha                = 1.e-4;
1257:   neP->maxstep                = 1.e8;
1258:   neP->steptol                = 1.e-12;
1259:   neP->LineSearch       = SNESLineSearchCubic;
1260:   neP->lsP              = PETSC_NULL;
1261:   neP->postcheckstep    = PETSC_NULL;
1262:   neP->postcheck        = PETSC_NULL;
1263:   neP->precheckstep     = PETSC_NULL;
1264:   neP->precheck         = PETSC_NULL;

1266:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C",
1267:                                            "SNESLineSearchSet_LS",
1268:                                            SNESLineSearchSet_LS);
1269:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C",
1270:                                            "SNESLineSearchSetPostCheck_LS",
1271:                                            SNESLineSearchSetPostCheck_LS);
1272:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C",
1273:                                            "SNESLineSearchSetPreCheck_LS",
1274:                                            SNESLineSearchSetPreCheck_LS);

1276:   return(0);
1277: }