xref: /petsc/src/snes/impls/ls/ls.c (revision 8eb2139f285127b90816fa224279e30dd84c25c8)
1 /*$Id: ls.c,v 1.172 2001/08/07 03:04:11 balay Exp $*/
2 
3 #include "src/snes/impls/ls/ls.h"
4 
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 */
11 #undef __FUNCT__
12 #define __FUNCT__ "SNESLSCheckLocalMin_Private"
13 int SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin)
14 {
15   PetscReal  a1;
16   int        ierr;
17   PetscTruth hastranspose;
18 
19   PetscFunctionBegin;
20   *ismin = PETSC_FALSE;
21   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
22   if (hastranspose) {
23     /* Compute || J^T F|| */
24     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
25     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
26     PetscLogInfo(0,"SNESSolve_LS: || J^T F|| %g near zero implies found a local minimum\n",a1/fnorm);
27     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
28   } else {
29     Vec       work;
30     PetscScalar    result;
31     PetscReal wnorm;
32 
33     ierr = VecSetRandom(PETSC_NULL,W);CHKERRQ(ierr);
34     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
35     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
36     ierr = MatMult(A,W,work);CHKERRQ(ierr);
37     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
38     ierr = VecDestroy(work);CHKERRQ(ierr);
39     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
40     PetscLogInfo(0,"SNESSolve_LS: (F^T J random)/(|| F ||*||random|| %g near zero implies found a local minimum\n",a1);
41     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 /*
47      Checks if J^T(F - J*X) = 0
48 */
49 #undef __FUNCT__
50 #define __FUNCT__ "SNESLSCheckResidual_Private"
51 int SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2)
52 {
53   PetscReal     a1,a2;
54   int           ierr;
55   PetscTruth    hastranspose;
56   PetscScalar   mone = -1.0;
57 
58   PetscFunctionBegin;
59   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
60   if (hastranspose) {
61     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
62     ierr = VecAXPY(&mone,F,W1);CHKERRQ(ierr);
63 
64     /* Compute || J^T W|| */
65     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
66     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
67     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
68     if (a1 != 0) {
69       PetscLogInfo(0,"SNESSolve_LS: ||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",a2/a1);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 /*  --------------------------------------------------------------------
76 
77      This file implements a truncated Newton method with a line search,
78      for solving a system of nonlinear equations, using the KSP, Vec,
79      and Mat interfaces for linear solvers, vectors, and matrices,
80      respectively.
81 
82      The following basic routines are required for each nonlinear solver:
83           SNESCreate_XXX()          - Creates a nonlinear solver context
84           SNESSetFromOptions_XXX()  - Sets runtime options
85           SNESSolve_XXX()           - Solves the nonlinear system
86           SNESDestroy_XXX()         - Destroys the nonlinear solver context
87      The suffix "_XXX" denotes a particular implementation, in this case
88      we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
89      systems of nonlinear equations with a line search (LS) method.
90      These routines are actually called via the common user interface
91      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
92      SNESDestroy(), so the application code interface remains identical
93      for all nonlinear solvers.
94 
95      Another key routine is:
96           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
97      by setting data structures and options.   The interface routine SNESSetUp()
98      is not usually called directly by the user, but instead is called by
99      SNESSolve() if necessary.
100 
101      Additional basic routines are:
102           SNESView_XXX()            - Prints details of runtime options that
103                                       have actually been used.
104      These are called by application codes via the interface routines
105      SNESView().
106 
107      The various types of solvers (preconditioners, Krylov subspace methods,
108      nonlinear solvers, timesteppers) are all organized similarly, so the
109      above description applies to these categories also.
110 
111     -------------------------------------------------------------------- */
112 /*
113    SNESSolve_LS - Solves a nonlinear system with a truncated Newton
114    method with a line search.
115 
116    Input Parameters:
117 .  snes - the SNES context
118 
119    Output Parameter:
120 .  outits - number of iterations until termination
121 
122    Application Interface Routine: SNESSolve()
123 
124    Notes:
125    This implements essentially a truncated Newton method with a
126    line search.  By default a cubic backtracking line search
127    is employed, as described in the text "Numerical Methods for
128    Unconstrained Optimization and Nonlinear Equations" by Dennis
129    and Schnabel.
130 */
131 #undef __FUNCT__
132 #define __FUNCT__ "SNESSolve_LS"
133 int SNESSolve_LS(SNES snes)
134 {
135   SNES_LS      *neP = (SNES_LS*)snes->data;
136   int          maxits,i,ierr,lits,lsfail;
137   MatStructure flg = DIFFERENT_NONZERO_PATTERN;
138   PetscReal    fnorm,gnorm,xnorm,ynorm;
139   Vec          Y,X,F,G,W,TMP;
140   KSP          ksp;
141 
142   PetscFunctionBegin;
143   ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr);
144   snes->reason  = SNES_CONVERGED_ITERATING;
145 
146   maxits	= snes->max_its;	/* maximum number of iterations */
147   X		= snes->vec_sol;	/* solution vector */
148   F		= snes->vec_func;	/* residual vector */
149   Y		= snes->work[0];	/* work vectors */
150   G		= snes->work[1];
151   W		= snes->work[2];
152 
153   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
154   snes->iter = 0;
155   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
156   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);  /*  F(X)      */
157   ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);	/* fnorm <- ||F||  */
158   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
159   snes->norm = fnorm;
160   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
161   SNESLogConvHistory(snes,fnorm,0);
162   SNESMonitor(snes,0,fnorm);
163 
164   if (fnorm < snes->atol) {snes->reason = SNES_CONVERGED_FNORM_ABS; PetscFunctionReturn(0);}
165 
166   /* set parameter for default relative tolerance convergence test */
167   snes->ttol = fnorm*snes->rtol;
168 
169   for (i=0; i<maxits; i++) {
170 
171     /* Call general purpose update function */
172     if (snes->update != PETSC_NULL) {
173       ierr = (*snes->update)(snes, snes->iter);CHKERRQ(ierr);
174     }
175 
176     /* Solve J Y = F, where J is Jacobian matrix */
177     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
178     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
179     ierr = KSPSetRhs(snes->ksp,F);CHKERRQ(ierr);
180     ierr = KSPSetSolution(snes->ksp,Y);CHKERRQ(ierr);
181     ierr = KSPSolve(snes->ksp);CHKERRQ(ierr);
182     ierr = KSPGetIterationNumber(ksp,&lits);CHKERRQ(ierr);
183 
184     if (PetscLogPrintInfo){
185       ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
186     }
187 
188     /* should check what happened to the linear solve? */
189     snes->linear_its += lits;
190     PetscLogInfo(snes,"SNESSolve_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
191 
192     /* Compute a (scaled) negative update in the line search routine:
193          Y <- X - lambda*Y
194        and evaluate G(Y) = function(Y))
195     */
196     ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr);
197     ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
198     PetscLogInfo(snes,"SNESSolve_LS: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
199 
200     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
201     TMP = X; X = Y; snes->vec_sol_always = X;  Y = TMP;
202     fnorm = gnorm;
203 
204     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
205     snes->iter = i+1;
206     snes->norm = fnorm;
207     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
208     SNESLogConvHistory(snes,fnorm,lits);
209     SNESMonitor(snes,i+1,fnorm);
210 
211     if (lsfail) {
212       PetscTruth ismin;
213 
214       if (++snes->numFailures >= snes->maxFailures) {
215         snes->reason = SNES_DIVERGED_LS_FAILURE;
216         ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr);
217         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
218         break;
219       }
220     }
221 
222     /* Test for convergence */
223     if (snes->converged) {
224       ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm = || X || */
225       ierr = (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
226       if (snes->reason) {
227         break;
228       }
229     }
230   }
231   if (X != snes->vec_sol) {
232     ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr);
233   }
234   if (F != snes->vec_func) {
235     ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr);
236   }
237   snes->vec_sol_always  = snes->vec_sol;
238   snes->vec_func_always = snes->vec_func;
239   if (i == maxits) {
240     PetscLogInfo(snes,"SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits);
241     snes->reason = SNES_DIVERGED_MAX_IT;
242   }
243   PetscFunctionReturn(0);
244 }
245 /* -------------------------------------------------------------------------- */
246 /*
247    SNESSetUp_LS - Sets up the internal data structures for the later use
248    of the SNESLS nonlinear solver.
249 
250    Input Parameter:
251 .  snes - the SNES context
252 .  x - the solution vector
253 
254    Application Interface Routine: SNESSetUp()
255 
256    Notes:
257    For basic use of the SNES solvers, the user need not explicitly call
258    SNESSetUp(), since these actions will automatically occur during
259    the call to SNESSolve().
260  */
261 #undef __FUNCT__
262 #define __FUNCT__ "SNESSetUp_LS"
263 int SNESSetUp_LS(SNES snes)
264 {
265   int ierr;
266 
267   PetscFunctionBegin;
268   snes->nwork = 4;
269   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
270   PetscLogObjectParents(snes,snes->nwork,snes->work);
271   snes->vec_sol_update_always = snes->work[3];
272   PetscFunctionReturn(0);
273 }
274 /* -------------------------------------------------------------------------- */
275 /*
276    SNESDestroy_LS - Destroys the private SNES_LS context that was created
277    with SNESCreate_LS().
278 
279    Input Parameter:
280 .  snes - the SNES context
281 
282    Application Interface Routine: SNESDestroy()
283  */
284 #undef __FUNCT__
285 #define __FUNCT__ "SNESDestroy_LS"
286 int SNESDestroy_LS(SNES snes)
287 {
288   int  ierr;
289 
290   PetscFunctionBegin;
291   if (snes->nwork) {
292     ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr);
293   }
294   ierr = PetscFree(snes->data);CHKERRQ(ierr);
295   PetscFunctionReturn(0);
296 }
297 /* -------------------------------------------------------------------------- */
298 #undef __FUNCT__
299 #define __FUNCT__ "SNESNoLineSearch"
300 
301 /*@C
302    SNESNoLineSearch - This routine is not a line search at all;
303    it simply uses the full Newton step.  Thus, this routine is intended
304    to serve as a template and is not recommended for general use.
305 
306    Collective on SNES and Vec
307 
308    Input Parameters:
309 +  snes - nonlinear context
310 .  lsctx - optional context for line search (not used here)
311 .  x - current iterate
312 .  f - residual evaluated at x
313 .  y - search direction (contains new iterate on output)
314 .  w - work vector
315 -  fnorm - 2-norm of f
316 
317    Output Parameters:
318 +  g - residual evaluated at new iterate y
319 .  y - new iterate (contains search direction on input)
320 .  gnorm - 2-norm of g
321 .  ynorm - 2-norm of search length
322 -  flag - set to 0, indicating a successful line search
323 
324    Options Database Key:
325 .  -snes_ls basic - Activates SNESNoLineSearch()
326 
327    Level: advanced
328 
329 .keywords: SNES, nonlinear, line search, cubic
330 
331 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
332           SNESSetLineSearch(), SNESNoLineSearchNoNorms()
333 @*/
334 int SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
335 {
336   int         ierr;
337   PetscScalar mone = -1.0;
338   SNES_LS     *neP = (SNES_LS*)snes->data;
339   PetscTruth  change_y = PETSC_FALSE;
340 
341   PetscFunctionBegin;
342   *flag = 0;
343   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
344   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);  /* ynorm = || y || */
345   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
346   if (neP->CheckStep) {
347    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
348   }
349   ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
350   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
351   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
352   PetscFunctionReturn(0);
353 }
354 /* -------------------------------------------------------------------------- */
355 #undef __FUNCT__
356 #define __FUNCT__ "SNESNoLineSearchNoNorms"
357 
358 /*@C
359    SNESNoLineSearchNoNorms - This routine is not a line search at
360    all; it simply uses the full Newton step. This version does not
361    even compute the norm of the function or search direction; this
362    is intended only when you know the full step is fine and are
363    not checking for convergence of the nonlinear iteration (for
364    example, you are running always for a fixed number of Newton steps).
365 
366    Collective on SNES and Vec
367 
368    Input Parameters:
369 +  snes - nonlinear context
370 .  lsctx - optional context for line search (not used here)
371 .  x - current iterate
372 .  f - residual evaluated at x
373 .  y - search direction (contains new iterate on output)
374 .  w - work vector
375 -  fnorm - 2-norm of f
376 
377    Output Parameters:
378 +  g - residual evaluated at new iterate y
379 .  gnorm - not changed
380 .  ynorm - not changed
381 -  flag - set to 0, indicating a successful line search
382 
383    Options Database Key:
384 .  -snes_ls basicnonorms - Activates SNESNoLineSearchNoNorms()
385 
386    Notes:
387    SNESNoLineSearchNoNorms() must be used in conjunction with
388    either the options
389 $     -snes_no_convergence_test -snes_max_it <its>
390    or alternatively a user-defined custom test set via
391    SNESSetConvergenceTest(); or a -snes_max_it of 1,
392    otherwise, the SNES solver will generate an error.
393 
394    During the final iteration this will not evaluate the function at
395    the solution point. This is to save a function evaluation while
396    using pseudo-timestepping.
397 
398    The residual norms printed by monitoring routines such as
399    SNESDefaultMonitor() (as activated via -snes_monitor) will not be
400    correct, since they are not computed.
401 
402    Level: advanced
403 
404 .keywords: SNES, nonlinear, line search, cubic
405 
406 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
407           SNESSetLineSearch(), SNESNoLineSearch()
408 @*/
409 int SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
410 {
411   int         ierr;
412   PetscScalar mone = -1.0;
413   SNES_LS     *neP = (SNES_LS*)snes->data;
414   PetscTruth  change_y = PETSC_FALSE;
415 
416   PetscFunctionBegin;
417   *flag = 0;
418   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
419   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
420   if (neP->CheckStep) {
421    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
422   }
423 
424   /* don't evaluate function the last time through */
425   if (snes->iter < snes->max_its-1) {
426     ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
427   }
428   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
429   PetscFunctionReturn(0);
430 }
431 /* -------------------------------------------------------------------------- */
432 #undef __FUNCT__
433 #define __FUNCT__ "SNESCubicLineSearch"
434 /*@C
435    SNESCubicLineSearch - Performs a cubic line search (default line search method).
436 
437    Collective on SNES
438 
439    Input Parameters:
440 +  snes - nonlinear context
441 .  lsctx - optional context for line search (not used here)
442 .  x - current iterate
443 .  f - residual evaluated at x
444 .  y - search direction (contains new iterate on output)
445 .  w - work vector
446 -  fnorm - 2-norm of f
447 
448    Output Parameters:
449 +  g - residual evaluated at new iterate y
450 .  y - new iterate (contains search direction on input)
451 .  gnorm - 2-norm of g
452 .  ynorm - 2-norm of search length
453 -  flag - 0 if line search succeeds; -1 on failure.
454 
455    Options Database Key:
456 $  -snes_ls cubic - Activates SNESCubicLineSearch()
457 
458    Notes:
459    This line search is taken from "Numerical Methods for Unconstrained
460    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
461 
462    Level: advanced
463 
464 .keywords: SNES, nonlinear, line search, cubic
465 
466 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
467 @*/
468 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
469 {
470   /*
471      Note that for line search purposes we work with with the related
472      minimization problem:
473         min  z(x):  R^n -> R,
474      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
475    */
476 
477   PetscReal   steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
478   PetscReal   maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg;
479 #if defined(PETSC_USE_COMPLEX)
480   PetscScalar cinitslope,clambda;
481 #endif
482   int         ierr,count;
483   SNES_LS     *neP = (SNES_LS*)snes->data;
484   PetscScalar mone = -1.0,scale;
485   PetscTruth  change_y = PETSC_FALSE;
486 
487   PetscFunctionBegin;
488   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
489   *flag   = 0;
490   alpha   = neP->alpha;
491   maxstep = neP->maxstep;
492   steptol = neP->steptol;
493 
494   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
495   if (*ynorm == 0.0) {
496     PetscLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n");
497     *gnorm = fnorm;
498     ierr   = VecCopy(x,y);CHKERRQ(ierr);
499     ierr   = VecCopy(f,g);CHKERRQ(ierr);
500     *flag  = -1;
501     goto theend1;
502   }
503   if (*ynorm > maxstep) {	/* Step too big, so scale back */
504     scale = maxstep/(*ynorm);
505 #if defined(PETSC_USE_COMPLEX)
506     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm);
507 #else
508     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",scale,*ynorm);
509 #endif
510     ierr = VecScale(&scale,y);CHKERRQ(ierr);
511     *ynorm = maxstep;
512   }
513   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
514   minlambda = steptol/rellength;
515   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
516 #if defined(PETSC_USE_COMPLEX)
517   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
518   initslope = PetscRealPart(cinitslope);
519 #else
520   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
521 #endif
522   if (initslope > 0.0) initslope = -initslope;
523   if (initslope == 0.0) initslope = -1.0;
524 
525   ierr = VecCopy(y,w);CHKERRQ(ierr);
526   ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr);
527   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
528   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
529   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
530     ierr = VecCopy(w,y);CHKERRQ(ierr);
531     PetscLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
532     goto theend1;
533   }
534 
535   /* Fit points with quadratic */
536   lambda = 1.0;
537   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
538   lambdaprev = lambda;
539   gnormprev = *gnorm;
540   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
541   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
542   else                         lambda = lambdatemp;
543   ierr   = VecCopy(x,w);CHKERRQ(ierr);
544   lambdaneg = -lambda;
545 #if defined(PETSC_USE_COMPLEX)
546   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
547 #else
548   ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
549 #endif
550   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
551   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
552   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
553     ierr = VecCopy(w,y);CHKERRQ(ierr);
554     PetscLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%18.16e\n",lambda);
555     goto theend1;
556   }
557 
558   /* Fit points with cubic */
559   count = 1;
560   while (count < 10000) {
561     if (lambda <= minlambda) { /* bad luck; use full step */
562       PetscLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
563       PetscLogInfo(snes,"SNESCubicLineSearch:fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);
564       ierr = VecCopy(x,y);CHKERRQ(ierr);
565       *flag = -1; break;
566     }
567     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
568     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
569     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
570     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
571     d  = b*b - 3*a*initslope;
572     if (d < 0.0) d = 0.0;
573     if (a == 0.0) {
574       lambdatemp = -initslope/(2.0*b);
575     } else {
576       lambdatemp = (-b + sqrt(d))/(3.0*a);
577     }
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;
583     ierr = VecCopy(x,w);CHKERRQ(ierr);
584     lambdaneg = -lambda;
585 #if defined(PETSC_USE_COMPLEX)
586     clambda = lambdaneg;
587     ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
588 #else
589     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
590 #endif
591     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
592     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
593     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
594       ierr = VecCopy(w,y);CHKERRQ(ierr);
595       PetscLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%18.16e\n",lambda);
596       goto theend1;
597     } else {
598       PetscLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%18.16e\n",lambda);
599     }
600     count++;
601   }
602   if (count >= 10000) {
603     SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation");
604   }
605   theend1:
606   /* Optional user-defined check for line search step validity */
607   if (neP->CheckStep) {
608     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
609     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
610       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
611       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
612       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
613       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
614       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
615     }
616   }
617   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
618   PetscFunctionReturn(0);
619 }
620 /* -------------------------------------------------------------------------- */
621 #undef __FUNCT__
622 #define __FUNCT__ "SNESQuadraticLineSearch"
623 /*@C
624    SNESQuadraticLineSearch - Performs a quadratic line search.
625 
626    Collective on SNES and Vec
627 
628    Input Parameters:
629 +  snes - the SNES context
630 .  lsctx - optional context for line search (not used here)
631 .  x - current iterate
632 .  f - residual evaluated at x
633 .  y - search direction (contains new iterate on output)
634 .  w - work vector
635 -  fnorm - 2-norm of f
636 
637    Output Parameters:
638 +  g - residual evaluated at new iterate y
639 .  y - new iterate (contains search direction on input)
640 .  gnorm - 2-norm of g
641 .  ynorm - 2-norm of search length
642 -  flag - 0 if line search succeeds; -1 on failure.
643 
644    Options Database Key:
645 .  -snes_ls quadratic - Activates SNESQuadraticLineSearch()
646 
647    Notes:
648    Use SNESSetLineSearch() to set this routine within the SNESLS method.
649 
650    Level: advanced
651 
652 .keywords: SNES, nonlinear, quadratic, line search
653 
654 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
655 @*/
656 int SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
657 {
658   /*
659      Note that for line search purposes we work with with the related
660      minimization problem:
661         min  z(x):  R^n -> R,
662      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
663    */
664   PetscReal   steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength;
665 #if defined(PETSC_USE_COMPLEX)
666   PetscScalar cinitslope,clambda;
667 #endif
668   int         ierr,count;
669   SNES_LS     *neP = (SNES_LS*)snes->data;
670   PetscScalar mone = -1.0,scale;
671   PetscTruth  change_y = PETSC_FALSE;
672 
673   PetscFunctionBegin;
674   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
675   *flag   = 0;
676   alpha   = neP->alpha;
677   maxstep = neP->maxstep;
678   steptol = neP->steptol;
679 
680   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
681   if (*ynorm == 0.0) {
682     PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
683     *gnorm = fnorm;
684     ierr   = VecCopy(x,y);CHKERRQ(ierr);
685     ierr   = VecCopy(f,g);CHKERRQ(ierr);
686     *flag  = -1;
687     goto theend2;
688   }
689   if (*ynorm > maxstep) {	/* Step too big, so scale back */
690     scale = maxstep/(*ynorm);
691     ierr = VecScale(&scale,y);CHKERRQ(ierr);
692     *ynorm = maxstep;
693   }
694   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
695   minlambda = steptol/rellength;
696   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
697 #if defined(PETSC_USE_COMPLEX)
698   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
699   initslope = PetscRealPart(cinitslope);
700 #else
701   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
702 #endif
703   if (initslope > 0.0) initslope = -initslope;
704   if (initslope == 0.0) initslope = -1.0;
705 
706   ierr = VecCopy(y,w);CHKERRQ(ierr);
707   ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr);
708   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
709   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
710   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
711     ierr = VecCopy(w,y);CHKERRQ(ierr);
712     PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
713     goto theend2;
714   }
715 
716   /* Fit points with quadratic */
717   lambda = 1.0;
718   count = 1;
719   while (PETSC_TRUE) {
720     if (lambda <= minlambda) { /* bad luck; use full step */
721       PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
722       PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
723       ierr = VecCopy(x,y);CHKERRQ(ierr);
724       *flag = -1; break;
725     }
726     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
727     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
728     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
729     else                         lambda     = lambdatemp;
730     ierr = VecCopy(x,w);CHKERRQ(ierr);
731     lambdaneg = -lambda;
732 #if defined(PETSC_USE_COMPLEX)
733     clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
734 #else
735     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
736 #endif
737     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
738     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
739     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
740       ierr = VecCopy(w,y);CHKERRQ(ierr);
741       PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
742       break;
743     }
744     count++;
745   }
746   theend2:
747   /* Optional user-defined check for line search step validity */
748   if (neP->CheckStep) {
749     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
750     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
751       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
752       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
753       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
754       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
755       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
756     }
757   }
758   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
759   PetscFunctionReturn(0);
760 }
761 
762 /* -------------------------------------------------------------------------- */
763 #undef __FUNCT__
764 #define __FUNCT__ "SNESSetLineSearch"
765 /*@C
766    SNESSetLineSearch - Sets the line search routine to be used
767    by the method SNESLS.
768 
769    Input Parameters:
770 +  snes - nonlinear context obtained from SNESCreate()
771 .  lsctx - optional user-defined context for use by line search
772 -  func - pointer to int function
773 
774    Collective on SNES
775 
776    Available Routines:
777 +  SNESCubicLineSearch() - default line search
778 .  SNESQuadraticLineSearch() - quadratic line search
779 .  SNESNoLineSearch() - the full Newton step (actually not a line search)
780 -  SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
781 
782     Options Database Keys:
783 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
784 .   -snes_ls_alpha <alpha> - Sets alpha
785 .   -snes_ls_maxstep <max> - Sets maxstep
786 -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
787                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
788                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
789 
790    Calling sequence of func:
791 .vb
792    func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
793          PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,*flag)
794 .ve
795 
796     Input parameters for func:
797 +   snes - nonlinear context
798 .   lsctx - optional user-defined context for line search
799 .   x - current iterate
800 .   f - residual evaluated at x
801 .   y - search direction (contains new iterate on output)
802 .   w - work vector
803 -   fnorm - 2-norm of f
804 
805     Output parameters for func:
806 +   g - residual evaluated at new iterate y
807 .   y - new iterate (contains search direction on input)
808 .   gnorm - 2-norm of g
809 .   ynorm - 2-norm of search length
810 -   flag - set to 0 if the line search succeeds; a nonzero integer
811            on failure.
812 
813     Level: advanced
814 
815 .keywords: SNES, nonlinear, set, line search, routine
816 
817 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms(),
818           SNESSetLineSearchCheck(), SNESSetLineSearchParams(), SNESGetLineSearchParams()
819 @*/
820 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void *lsctx)
821 {
822   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void*);
823 
824   PetscFunctionBegin;
825   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void (**)(void))&f);CHKERRQ(ierr);
826   if (f) {
827     ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr);
828   }
829   PetscFunctionReturn(0);
830 }
831 
832 typedef int (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*); /* force argument to next function to not be extern C*/
833 /* -------------------------------------------------------------------------- */
834 EXTERN_C_BEGIN
835 #undef __FUNCT__
836 #define __FUNCT__ "SNESSetLineSearch_LS"
837 int SNESSetLineSearch_LS(SNES snes,FCN2 func,void *lsctx)
838 {
839   PetscFunctionBegin;
840   ((SNES_LS *)(snes->data))->LineSearch = func;
841   ((SNES_LS *)(snes->data))->lsP        = lsctx;
842   PetscFunctionReturn(0);
843 }
844 EXTERN_C_END
845 /* -------------------------------------------------------------------------- */
846 #undef __FUNCT__
847 #define __FUNCT__ "SNESSetLineSearchCheck"
848 /*@C
849    SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed
850    by the line search routine in the Newton-based method SNESLS.
851 
852    Input Parameters:
853 +  snes - nonlinear context obtained from SNESCreate()
854 .  func - pointer to int function
855 -  checkctx - optional user-defined context for use by step checking routine
856 
857    Collective on SNES
858 
859    Calling sequence of func:
860 .vb
861    int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag)
862 .ve
863    where func returns an error code of 0 on success and a nonzero
864    on failure.
865 
866    Input parameters for func:
867 +  snes - nonlinear context
868 .  checkctx - optional user-defined context for use by step checking routine
869 -  x - current candidate iterate
870 
871    Output parameters for func:
872 +  x - current iterate (possibly modified)
873 -  flag - flag indicating whether x has been modified (either
874            PETSC_TRUE of PETSC_FALSE)
875 
876    Level: advanced
877 
878    Notes:
879    SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new
880    iterate computed by the line search checking routine.  In particular,
881    these routines (1) compute a candidate iterate u_{i+1}, (2) pass control
882    to the checking routine, and then (3) compute the corresponding nonlinear
883    function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
884 
885    SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the
886    new iterate computed by the line search checking routine.  In particular,
887    these routines (1) compute a candidate iterate u_{i+1} as well as a
888    candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
889    routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
890    were made to the candidate iterate in the checking routine (as indicated
891    by flag=PETSC_TRUE).  The overhead of this function re-evaluation can be
892    very costly, so use this feature with caution!
893 
894 .keywords: SNES, nonlinear, set, line search check, step check, routine
895 
896 .seealso: SNESSetLineSearch()
897 @*/
898 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx)
899 {
900   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,PetscTruth*),void*);
901 
902   PetscFunctionBegin;
903   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr);
904   if (f) {
905     ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr);
906   }
907   PetscFunctionReturn(0);
908 }
909 /* -------------------------------------------------------------------------- */
910 typedef int (*FCN)(SNES,void*,Vec,PetscTruth*); /* force argument to next function to not be extern C*/
911 EXTERN_C_BEGIN
912 #undef __FUNCT__
913 #define __FUNCT__ "SNESSetLineSearchCheck_LS"
914 int SNESSetLineSearchCheck_LS(SNES snes,FCN func,void *checkctx)
915 {
916   PetscFunctionBegin;
917   ((SNES_LS *)(snes->data))->CheckStep = func;
918   ((SNES_LS *)(snes->data))->checkP    = checkctx;
919   PetscFunctionReturn(0);
920 }
921 EXTERN_C_END
922 /* -------------------------------------------------------------------------- */
923 /*
924    SNESPrintHelp_LS - Prints all options for the SNES_LS method.
925 
926    Input Parameter:
927 .  snes - the SNES context
928 
929    Application Interface Routine: SNESPrintHelp()
930 */
931 #undef __FUNCT__
932 #define __FUNCT__ "SNESPrintHelp_LS"
933 static int SNESPrintHelp_LS(SNES snes,char *p)
934 {
935   SNES_LS *ls = (SNES_LS *)snes->data;
936 
937   PetscFunctionBegin;
938   (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n");
939   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
940   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
941   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
942   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol);
943   PetscFunctionReturn(0);
944 }
945 
946 /*
947    SNESView_LS - Prints info from the SNESLS data structure.
948 
949    Input Parameters:
950 .  SNES - the SNES context
951 .  viewer - visualization context
952 
953    Application Interface Routine: SNESView()
954 */
955 #undef __FUNCT__
956 #define __FUNCT__ "SNESView_LS"
957 static int SNESView_LS(SNES snes,PetscViewer viewer)
958 {
959   SNES_LS    *ls = (SNES_LS *)snes->data;
960   const char *cstr;
961   int        ierr;
962   PetscTruth isascii;
963 
964   PetscFunctionBegin;
965   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
966   if (isascii) {
967     if (ls->LineSearch == SNESNoLineSearch)             cstr = "SNESNoLineSearch";
968     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
969     else if (ls->LineSearch == SNESCubicLineSearch)     cstr = "SNESCubicLineSearch";
970     else                                                cstr = "unknown";
971     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
972     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr);
973   } else {
974     SETERRQ1(1,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
975   }
976   PetscFunctionReturn(0);
977 }
978 /* -------------------------------------------------------------------------- */
979 /*
980    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
981 
982    Input Parameter:
983 .  snes - the SNES context
984 
985    Application Interface Routine: SNESSetFromOptions()
986 */
987 #undef __FUNCT__
988 #define __FUNCT__ "SNESSetFromOptions_LS"
989 static int SNESSetFromOptions_LS(SNES snes)
990 {
991   SNES_LS    *ls = (SNES_LS *)snes->data;
992   const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
993   int        ierr,indx;
994   PetscTruth flg;
995 
996   PetscFunctionBegin;
997   ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr);
998     ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr);
999     ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr);
1000     ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr);
1001 
1002     ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr);
1003     if (flg) {
1004       switch (indx) {
1005       case 0:
1006         ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr);
1007         break;
1008       case 1:
1009         ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
1010         break;
1011       case 2:
1012         ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr);
1013         break;
1014       case 3:
1015         ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr);
1016         break;
1017       }
1018     }
1019   ierr = PetscOptionsTail();CHKERRQ(ierr);
1020   PetscFunctionReturn(0);
1021 }
1022 /* -------------------------------------------------------------------------- */
1023 /*MC
1024       SNESLS - Newton based nonlinear solver that uses a line search
1025 
1026    Options Database:
1027 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
1028 .   -snes_ls_alpha <alpha> - Sets alpha
1029 .   -snes_ls_maxstep <max> - Sets maxstep
1030 -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
1031                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
1032                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
1033 
1034     Notes: This is the default nonlinear solver in SNES
1035 
1036 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESSetLineSearch(),
1037            SNESSetLineSearchCheck(), SNESNoLineSearch(), SNESCubicLineSearch(), SNESQuadraticLineSearch(),
1038           SNESSetLineSearch(), SNESNoLineSearchNoNorms()
1039 
1040 M*/
1041 EXTERN_C_BEGIN
1042 #undef __FUNCT__
1043 #define __FUNCT__ "SNESCreate_LS"
1044 int SNESCreate_LS(SNES snes)
1045 {
1046   int     ierr;
1047   SNES_LS *neP;
1048 
1049   PetscFunctionBegin;
1050   snes->setup		= SNESSetUp_LS;
1051   snes->solve		= SNESSolve_LS;
1052   snes->destroy		= SNESDestroy_LS;
1053   snes->converged	= SNESConverged_LS;
1054   snes->printhelp       = SNESPrintHelp_LS;
1055   snes->setfromoptions  = SNESSetFromOptions_LS;
1056   snes->view            = SNESView_LS;
1057   snes->nwork           = 0;
1058 
1059   ierr                  = PetscNew(SNES_LS,&neP);CHKERRQ(ierr);
1060   PetscLogObjectMemory(snes,sizeof(SNES_LS));
1061   snes->data    	= (void*)neP;
1062   neP->alpha		= 1.e-4;
1063   neP->maxstep		= 1.e8;
1064   neP->steptol		= 1.e-12;
1065   neP->LineSearch       = SNESCubicLineSearch;
1066   neP->lsP              = PETSC_NULL;
1067   neP->CheckStep        = PETSC_NULL;
1068   neP->checkP           = PETSC_NULL;
1069 
1070   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr);
1071   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr);
1072 
1073   PetscFunctionReturn(0);
1074 }
1075 EXTERN_C_END
1076 
1077 
1078 
1079