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(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:   VecNorm(F,NORM_2,&fnorm);        /* fnorm <- ||F||  */
161:   if (fnorm != fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
162:   PetscObjectTakeAccess(snes);
163:   snes->norm = fnorm;
164:   PetscObjectGrantAccess(snes);
165:   SNESLogConvHistory(snes,fnorm,0);
166:   SNESMonitor(snes,0,fnorm);

168:   /* set parameter for default relative tolerance convergence test */
169:   snes->ttol = fnorm*snes->rtol;
170:   /* test convergence */
171:   (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
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:         PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
189:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
190:         break;
191:       }
192:     }
193:     KSPGetIterationNumber(snes->ksp,&lits);
194:     snes->linear_its += lits;
195:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);

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

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

206:     /* Compute a (scaled) negative update in the line search routine: 
207:          Y <- X - lambda*Y 
208:        and evaluate G = function(Y) (depends on the line search). 
209:     */
210:     VecCopy(Y,snes->vec_sol_update);
211:     ynorm = 1; gnorm = fnorm;
212:     (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);
213:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);
214:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
215:     if (!lssucceed) {
216:       if (++snes->numFailures >= snes->maxFailures) {
217:         PetscTruth ismin;
218:         snes->reason = SNES_DIVERGED_LS_FAILURE;
219:         SNESLSCheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);
220:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
221:         break;
222:       }
223:     }
224:     /* Update function and solution vectors */
225:     fnorm = gnorm;
226:     VecCopy(G,F);
227:     VecCopy(W,X);
228:     /* Monitor convergence */
229:     PetscObjectTakeAccess(snes);
230:     snes->iter = i+1;
231:     snes->norm = fnorm;
232:     PetscObjectGrantAccess(snes);
233:     SNESLogConvHistory(snes,snes->norm,lits);
234:     SNESMonitor(snes,snes->iter,snes->norm);
235:     /* Test for convergence, xnorm = || X || */
236:     if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
237:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
238:     if (snes->reason) break;
239:   }
240:   if (i == maxits) {
241:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
242:     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
243:   }
244:   return(0);
245: }
246: /* -------------------------------------------------------------------------- */
247: /*
248:    SNESSetUp_LS - Sets up the internal data structures for the later use
249:    of the SNESLS nonlinear solver.

251:    Input Parameter:
252: .  snes - the SNES context
253: .  x - the solution vector

255:    Application Interface Routine: SNESSetUp()

257:    Notes:
258:    For basic use of the SNES solvers, the user need not explicitly call
259:    SNESSetUp(), since these actions will automatically occur during
260:    the call to SNESSolve().
261:  */
264: PetscErrorCode SNESSetUp_LS(SNES snes)
265: {

269:   if (!snes->vec_sol_update) {
270:     VecDuplicate(snes->vec_sol,&snes->vec_sol_update);
271:     PetscLogObjectParent(snes,snes->vec_sol_update);
272:   }
273:   if (!snes->work) {
274:     snes->nwork = 3;
275:     VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
276:     PetscLogObjectParents(snes,snes->nwork,snes->work);
277:   }
278:   return(0);
279: }
280: /* -------------------------------------------------------------------------- */
281: /*
282:    SNESDestroy_LS - Destroys the private SNES_LS context that was created
283:    with SNESCreate_LS().

285:    Input Parameter:
286: .  snes - the SNES context

288:    Application Interface Routine: SNESDestroy()
289:  */
292: PetscErrorCode SNESDestroy_LS(SNES snes)
293: {

297:   if (snes->vec_sol_update) {
298:     VecDestroy(snes->vec_sol_update);
299:     snes->vec_sol_update = PETSC_NULL;
300:   }
301:   if (snes->nwork) {
302:     VecDestroyVecs(snes->work,snes->nwork);
303:     snes->nwork = 0;
304:     snes->work  = PETSC_NULL;
305:   }
306:   PetscFree(snes->data);

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

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

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

324:    Collective on SNES and Vec

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

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

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

345:    Level: advanced

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

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

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

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

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

392:    Collective on SNES and Vec

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

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

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

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

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

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

429:    Level: advanced

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

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

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

470:    Collective on SNES

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

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

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

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

495:    Level: advanced

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

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

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

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

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

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

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

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

691:    Collective on SNES and Vec

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

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

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

719:    Level: advanced

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

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

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

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

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

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

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

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

872:    Collective on SNES

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

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

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

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

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

910:     Level: advanced

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

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

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

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

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

954:    Collective on SNES

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

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

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

976:    Level: advanced

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

980:    Only one of changed_y and changed_w can  be PETSC_TRUE

982:    On input w = x + y

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

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

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

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

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

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

1021:    Collective on SNES

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

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

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

1040:    Level: advanced

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

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

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

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

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

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

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

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

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

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

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

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

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

1144:     PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);
1145:     if (flg) {
1146:       switch (indx) {
1147:       case 0:
1148:         SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
1149:         break;
1150:       case 1:
1151:         SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);
1152:         break;
1153:       case 2:
1154:         SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);
1155:         break;
1156:       case 3:
1157:         SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);
1158:         break;
1159:       }
1160:     }
1161:   PetscOptionsTail();
1162:   return(0);
1163: }
1164: /* -------------------------------------------------------------------------- */
1165: /*MC
1166:       SNESLS - Newton based nonlinear solver that uses a line search

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

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

1178:    Level: beginner

1180: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 
1181:            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
1182:           SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck()

1184: M*/
1188: PetscErrorCode  SNESCreate_LS(SNES snes)
1189: {
1191:   SNES_LS        *neP;

1194:   snes->ops->setup             = SNESSetUp_LS;
1195:   snes->ops->solve             = SNESSolve_LS;
1196:   snes->ops->destroy             = SNESDestroy_LS;
1197:   snes->ops->setfromoptions  = SNESSetFromOptions_LS;
1198:   snes->ops->view            = SNESView_LS;

1200:   PetscNewLog(snes,SNES_LS,&neP);
1201:   snes->data            = (void*)neP;
1202:   neP->alpha                = 1.e-4;
1203:   neP->maxstep                = 1.e8;
1204:   neP->steptol                = 1.e-12;
1205:   neP->LineSearch       = SNESLineSearchCubic;
1206:   neP->lsP              = PETSC_NULL;
1207:   neP->postcheckstep    = PETSC_NULL;
1208:   neP->postcheck        = PETSC_NULL;
1209:   neP->precheckstep     = PETSC_NULL;
1210:   neP->precheck         = PETSC_NULL;

1212:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C",
1213:                                            "SNESLineSearchSet_LS",
1214:                                            SNESLineSearchSet_LS);
1215:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C",
1216:                                            "SNESLineSearchSetPostCheck_LS",
1217:                                            SNESLineSearchSetPostCheck_LS);
1218:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C",
1219:                                            "SNESLineSearchSetPreCheck_LS",
1220:                                            SNESLineSearchSetPreCheck_LS);

1222:   return(0);
1223: }