xref: /petsc/src/snes/impls/ls/ls.c (revision 4482741e5b2e2bbc854fb1f8dba65221386520f2)
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,int *outits)
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) {*outits = 0; 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     i--;
242     snes->reason = SNES_DIVERGED_MAX_IT;
243   }
244   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
245   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
246   *outits = i+1;
247   PetscFunctionReturn(0);
248 }
249 /* -------------------------------------------------------------------------- */
250 /*
251    SNESSetUp_LS - Sets up the internal data structures for the later use
252    of the SNESLS nonlinear solver.
253 
254    Input Parameter:
255 .  snes - the SNES context
256 .  x - the solution vector
257 
258    Application Interface Routine: SNESSetUp()
259 
260    Notes:
261    For basic use of the SNES solvers, the user need not explicitly call
262    SNESSetUp(), since these actions will automatically occur during
263    the call to SNESSolve().
264  */
265 #undef __FUNCT__
266 #define __FUNCT__ "SNESSetUp_LS"
267 int SNESSetUp_LS(SNES snes)
268 {
269   int ierr;
270 
271   PetscFunctionBegin;
272   snes->nwork = 4;
273   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
274   PetscLogObjectParents(snes,snes->nwork,snes->work);
275   snes->vec_sol_update_always = snes->work[3];
276   PetscFunctionReturn(0);
277 }
278 /* -------------------------------------------------------------------------- */
279 /*
280    SNESDestroy_LS - Destroys the private SNES_LS context that was created
281    with SNESCreate_LS().
282 
283    Input Parameter:
284 .  snes - the SNES context
285 
286    Application Interface Routine: SNESDestroy()
287  */
288 #undef __FUNCT__
289 #define __FUNCT__ "SNESDestroy_LS"
290 int SNESDestroy_LS(SNES snes)
291 {
292   int  ierr;
293 
294   PetscFunctionBegin;
295   if (snes->nwork) {
296     ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr);
297   }
298   ierr = PetscFree(snes->data);CHKERRQ(ierr);
299   PetscFunctionReturn(0);
300 }
301 /* -------------------------------------------------------------------------- */
302 #undef __FUNCT__
303 #define __FUNCT__ "SNESNoLineSearch"
304 
305 /*@C
306    SNESNoLineSearch - This routine is not a line search at all;
307    it simply uses the full Newton step.  Thus, this routine is intended
308    to serve as a template and is not recommended for general use.
309 
310    Collective on SNES and Vec
311 
312    Input Parameters:
313 +  snes - nonlinear context
314 .  lsctx - optional context for line search (not used here)
315 .  x - current iterate
316 .  f - residual evaluated at x
317 .  y - search direction (contains new iterate on output)
318 .  w - work vector
319 -  fnorm - 2-norm of f
320 
321    Output Parameters:
322 +  g - residual evaluated at new iterate y
323 .  y - new iterate (contains search direction on input)
324 .  gnorm - 2-norm of g
325 .  ynorm - 2-norm of search length
326 -  flag - set to 0, indicating a successful line search
327 
328    Options Database Key:
329 .  -snes_ls basic - Activates SNESNoLineSearch()
330 
331    Level: advanced
332 
333 .keywords: SNES, nonlinear, line search, cubic
334 
335 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
336           SNESSetLineSearch(), SNESNoLineSearchNoNorms()
337 @*/
338 int SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
339 {
340   int         ierr;
341   PetscScalar mone = -1.0;
342   SNES_LS     *neP = (SNES_LS*)snes->data;
343   PetscTruth  change_y = PETSC_FALSE;
344 
345   PetscFunctionBegin;
346   *flag = 0;
347   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
348   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);  /* ynorm = || y || */
349   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
350   if (neP->CheckStep) {
351    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
352   }
353   ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
354   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
355   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
356   PetscFunctionReturn(0);
357 }
358 /* -------------------------------------------------------------------------- */
359 #undef __FUNCT__
360 #define __FUNCT__ "SNESNoLineSearchNoNorms"
361 
362 /*@C
363    SNESNoLineSearchNoNorms - This routine is not a line search at
364    all; it simply uses the full Newton step. This version does not
365    even compute the norm of the function or search direction; this
366    is intended only when you know the full step is fine and are
367    not checking for convergence of the nonlinear iteration (for
368    example, you are running always for a fixed number of Newton steps).
369 
370    Collective on SNES and Vec
371 
372    Input Parameters:
373 +  snes - nonlinear context
374 .  lsctx - optional context for line search (not used here)
375 .  x - current iterate
376 .  f - residual evaluated at x
377 .  y - search direction (contains new iterate on output)
378 .  w - work vector
379 -  fnorm - 2-norm of f
380 
381    Output Parameters:
382 +  g - residual evaluated at new iterate y
383 .  gnorm - not changed
384 .  ynorm - not changed
385 -  flag - set to 0, indicating a successful line search
386 
387    Options Database Key:
388 .  -snes_ls basicnonorms - Activates SNESNoLineSearchNoNorms()
389 
390    Notes:
391    SNESNoLineSearchNoNorms() must be used in conjunction with
392    either the options
393 $     -snes_no_convergence_test -snes_max_it <its>
394    or alternatively a user-defined custom test set via
395    SNESSetConvergenceTest(); or a -snes_max_it of 1,
396    otherwise, the SNES solver will generate an error.
397 
398    During the final iteration this will not evaluate the function at
399    the solution point. This is to save a function evaluation while
400    using pseudo-timestepping.
401 
402    The residual norms printed by monitoring routines such as
403    SNESDefaultMonitor() (as activated via -snes_monitor) will not be
404    correct, since they are not computed.
405 
406    Level: advanced
407 
408 .keywords: SNES, nonlinear, line search, cubic
409 
410 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
411           SNESSetLineSearch(), SNESNoLineSearch()
412 @*/
413 int SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
414 {
415   int         ierr;
416   PetscScalar mone = -1.0;
417   SNES_LS     *neP = (SNES_LS*)snes->data;
418   PetscTruth  change_y = PETSC_FALSE;
419 
420   PetscFunctionBegin;
421   *flag = 0;
422   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
423   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
424   if (neP->CheckStep) {
425    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
426   }
427 
428   /* don't evaluate function the last time through */
429   if (snes->iter < snes->max_its-1) {
430     ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
431   }
432   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
433   PetscFunctionReturn(0);
434 }
435 /* -------------------------------------------------------------------------- */
436 #undef __FUNCT__
437 #define __FUNCT__ "SNESCubicLineSearch"
438 /*@C
439    SNESCubicLineSearch - Performs a cubic line search (default line search method).
440 
441    Collective on SNES
442 
443    Input Parameters:
444 +  snes - nonlinear context
445 .  lsctx - optional context for line search (not used here)
446 .  x - current iterate
447 .  f - residual evaluated at x
448 .  y - search direction (contains new iterate on output)
449 .  w - work vector
450 -  fnorm - 2-norm of f
451 
452    Output Parameters:
453 +  g - residual evaluated at new iterate y
454 .  y - new iterate (contains search direction on input)
455 .  gnorm - 2-norm of g
456 .  ynorm - 2-norm of search length
457 -  flag - 0 if line search succeeds; -1 on failure.
458 
459    Options Database Key:
460 $  -snes_ls cubic - Activates SNESCubicLineSearch()
461 
462    Notes:
463    This line search is taken from "Numerical Methods for Unconstrained
464    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
465 
466    Level: advanced
467 
468 .keywords: SNES, nonlinear, line search, cubic
469 
470 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
471 @*/
472 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
473 {
474   /*
475      Note that for line search purposes we work with with the related
476      minimization problem:
477         min  z(x):  R^n -> R,
478      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
479    */
480 
481   PetscReal   steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
482   PetscReal   maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg;
483 #if defined(PETSC_USE_COMPLEX)
484   PetscScalar cinitslope,clambda;
485 #endif
486   int         ierr,count;
487   SNES_LS     *neP = (SNES_LS*)snes->data;
488   PetscScalar mone = -1.0,scale;
489   PetscTruth  change_y = PETSC_FALSE;
490 
491   PetscFunctionBegin;
492   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
493   *flag   = 0;
494   alpha   = neP->alpha;
495   maxstep = neP->maxstep;
496   steptol = neP->steptol;
497 
498   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
499   if (*ynorm == 0.0) {
500     PetscLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n");
501     *gnorm = fnorm;
502     ierr   = VecCopy(x,y);CHKERRQ(ierr);
503     ierr   = VecCopy(f,g);CHKERRQ(ierr);
504     *flag  = -1;
505     goto theend1;
506   }
507   if (*ynorm > maxstep) {	/* Step too big, so scale back */
508     scale = maxstep/(*ynorm);
509 #if defined(PETSC_USE_COMPLEX)
510     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm);
511 #else
512     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",scale,*ynorm);
513 #endif
514     ierr = VecScale(&scale,y);CHKERRQ(ierr);
515     *ynorm = maxstep;
516   }
517   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
518   minlambda = steptol/rellength;
519   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
520 #if defined(PETSC_USE_COMPLEX)
521   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
522   initslope = PetscRealPart(cinitslope);
523 #else
524   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
525 #endif
526   if (initslope > 0.0) initslope = -initslope;
527   if (initslope == 0.0) initslope = -1.0;
528 
529   ierr = VecCopy(y,w);CHKERRQ(ierr);
530   ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr);
531   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
532   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
533   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
534     ierr = VecCopy(w,y);CHKERRQ(ierr);
535     PetscLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
536     goto theend1;
537   }
538 
539   /* Fit points with quadratic */
540   lambda = 1.0;
541   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
542   lambdaprev = lambda;
543   gnormprev = *gnorm;
544   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
545   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
546   else                         lambda = lambdatemp;
547   ierr   = VecCopy(x,w);CHKERRQ(ierr);
548   lambdaneg = -lambda;
549 #if defined(PETSC_USE_COMPLEX)
550   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
551 #else
552   ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
553 #endif
554   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
555   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
556   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
557     ierr = VecCopy(w,y);CHKERRQ(ierr);
558     PetscLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%18.16e\n",lambda);
559     goto theend1;
560   }
561 
562   /* Fit points with cubic */
563   count = 1;
564   while (count < 10000) {
565     if (lambda <= minlambda) { /* bad luck; use full step */
566       PetscLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
567       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);
568       ierr = VecCopy(x,y);CHKERRQ(ierr);
569       *flag = -1; break;
570     }
571     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
572     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
573     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
574     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
575     d  = b*b - 3*a*initslope;
576     if (d < 0.0) d = 0.0;
577     if (a == 0.0) {
578       lambdatemp = -initslope/(2.0*b);
579     } else {
580       lambdatemp = (-b + sqrt(d))/(3.0*a);
581     }
582     lambdaprev = lambda;
583     gnormprev  = *gnorm;
584     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
585     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
586     else                         lambda     = lambdatemp;
587     ierr = VecCopy(x,w);CHKERRQ(ierr);
588     lambdaneg = -lambda;
589 #if defined(PETSC_USE_COMPLEX)
590     clambda = lambdaneg;
591     ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
592 #else
593     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
594 #endif
595     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
596     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
597     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
598       ierr = VecCopy(w,y);CHKERRQ(ierr);
599       PetscLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%18.16e\n",lambda);
600       goto theend1;
601     } else {
602       PetscLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%18.16e\n",lambda);
603     }
604     count++;
605   }
606   if (count >= 10000) {
607     SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation");
608   }
609   theend1:
610   /* Optional user-defined check for line search step validity */
611   if (neP->CheckStep) {
612     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
613     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
614       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
615       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
616       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
617       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
618       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
619     }
620   }
621   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
622   PetscFunctionReturn(0);
623 }
624 /* -------------------------------------------------------------------------- */
625 #undef __FUNCT__
626 #define __FUNCT__ "SNESQuadraticLineSearch"
627 /*@C
628    SNESQuadraticLineSearch - Performs a quadratic line search.
629 
630    Collective on SNES and Vec
631 
632    Input Parameters:
633 +  snes - the SNES context
634 .  lsctx - optional context for line search (not used here)
635 .  x - current iterate
636 .  f - residual evaluated at x
637 .  y - search direction (contains new iterate on output)
638 .  w - work vector
639 -  fnorm - 2-norm of f
640 
641    Output Parameters:
642 +  g - residual evaluated at new iterate y
643 .  y - new iterate (contains search direction on input)
644 .  gnorm - 2-norm of g
645 .  ynorm - 2-norm of search length
646 -  flag - 0 if line search succeeds; -1 on failure.
647 
648    Options Database Key:
649 .  -snes_ls quadratic - Activates SNESQuadraticLineSearch()
650 
651    Notes:
652    Use SNESSetLineSearch() to set this routine within the SNESLS method.
653 
654    Level: advanced
655 
656 .keywords: SNES, nonlinear, quadratic, line search
657 
658 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
659 @*/
660 int SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
661 {
662   /*
663      Note that for line search purposes we work with with the related
664      minimization problem:
665         min  z(x):  R^n -> R,
666      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
667    */
668   PetscReal   steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength;
669 #if defined(PETSC_USE_COMPLEX)
670   PetscScalar cinitslope,clambda;
671 #endif
672   int         ierr,count;
673   SNES_LS     *neP = (SNES_LS*)snes->data;
674   PetscScalar mone = -1.0,scale;
675   PetscTruth  change_y = PETSC_FALSE;
676 
677   PetscFunctionBegin;
678   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
679   *flag   = 0;
680   alpha   = neP->alpha;
681   maxstep = neP->maxstep;
682   steptol = neP->steptol;
683 
684   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
685   if (*ynorm == 0.0) {
686     PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
687     *gnorm = fnorm;
688     ierr   = VecCopy(x,y);CHKERRQ(ierr);
689     ierr   = VecCopy(f,g);CHKERRQ(ierr);
690     *flag  = -1;
691     goto theend2;
692   }
693   if (*ynorm > maxstep) {	/* Step too big, so scale back */
694     scale = maxstep/(*ynorm);
695     ierr = VecScale(&scale,y);CHKERRQ(ierr);
696     *ynorm = maxstep;
697   }
698   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
699   minlambda = steptol/rellength;
700   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
701 #if defined(PETSC_USE_COMPLEX)
702   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
703   initslope = PetscRealPart(cinitslope);
704 #else
705   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
706 #endif
707   if (initslope > 0.0) initslope = -initslope;
708   if (initslope == 0.0) initslope = -1.0;
709 
710   ierr = VecCopy(y,w);CHKERRQ(ierr);
711   ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr);
712   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
713   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
714   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
715     ierr = VecCopy(w,y);CHKERRQ(ierr);
716     PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
717     goto theend2;
718   }
719 
720   /* Fit points with quadratic */
721   lambda = 1.0;
722   count = 1;
723   while (PETSC_TRUE) {
724     if (lambda <= minlambda) { /* bad luck; use full step */
725       PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
726       PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
727       ierr = VecCopy(x,y);CHKERRQ(ierr);
728       *flag = -1; break;
729     }
730     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
731     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
732     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
733     else                         lambda     = lambdatemp;
734     ierr = VecCopy(x,w);CHKERRQ(ierr);
735     lambdaneg = -lambda;
736 #if defined(PETSC_USE_COMPLEX)
737     clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
738 #else
739     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
740 #endif
741     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
742     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
743     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
744       ierr = VecCopy(w,y);CHKERRQ(ierr);
745       PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
746       break;
747     }
748     count++;
749   }
750   theend2:
751   /* Optional user-defined check for line search step validity */
752   if (neP->CheckStep) {
753     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
754     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
755       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
756       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
757       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
758       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
759       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
760     }
761   }
762   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
763   PetscFunctionReturn(0);
764 }
765 
766 /* -------------------------------------------------------------------------- */
767 #undef __FUNCT__
768 #define __FUNCT__ "SNESSetLineSearch"
769 /*@C
770    SNESSetLineSearch - Sets the line search routine to be used
771    by the method SNESLS.
772 
773    Input Parameters:
774 +  snes - nonlinear context obtained from SNESCreate()
775 .  lsctx - optional user-defined context for use by line search
776 -  func - pointer to int function
777 
778    Collective on SNES
779 
780    Available Routines:
781 +  SNESCubicLineSearch() - default line search
782 .  SNESQuadraticLineSearch() - quadratic line search
783 .  SNESNoLineSearch() - the full Newton step (actually not a line search)
784 -  SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
785 
786     Options Database Keys:
787 +   -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
788 .   -snes_ls_alpha <alpha> - Sets alpha
789 .   -snes_ls_maxstep <max> - Sets maxstep
790 -   -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code
791                    will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length
792                    the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x)
793 
794    Calling sequence of func:
795 .vb
796    func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
797          PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,*flag)
798 .ve
799 
800     Input parameters for func:
801 +   snes - nonlinear context
802 .   lsctx - optional user-defined context for line search
803 .   x - current iterate
804 .   f - residual evaluated at x
805 .   y - search direction (contains new iterate on output)
806 .   w - work vector
807 -   fnorm - 2-norm of f
808 
809     Output parameters for func:
810 +   g - residual evaluated at new iterate y
811 .   y - new iterate (contains search direction on input)
812 .   gnorm - 2-norm of g
813 .   ynorm - 2-norm of search length
814 -   flag - set to 0 if the line search succeeds; a nonzero integer
815            on failure.
816 
817     Level: advanced
818 
819 .keywords: SNES, nonlinear, set, line search, routine
820 
821 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms(),
822           SNESSetLineSearchCheck(), SNESSetLineSearchParams(), SNESGetLineSearchParams()
823 @*/
824 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void *lsctx)
825 {
826   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void*);
827 
828   PetscFunctionBegin;
829   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void (**)(void))&f);CHKERRQ(ierr);
830   if (f) {
831     ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr);
832   }
833   PetscFunctionReturn(0);
834 }
835 
836 typedef int (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*); /* force argument to next function to not be extern C*/
837 /* -------------------------------------------------------------------------- */
838 EXTERN_C_BEGIN
839 #undef __FUNCT__
840 #define __FUNCT__ "SNESSetLineSearch_LS"
841 int SNESSetLineSearch_LS(SNES snes,FCN2 func,void *lsctx)
842 {
843   PetscFunctionBegin;
844   ((SNES_LS *)(snes->data))->LineSearch = func;
845   ((SNES_LS *)(snes->data))->lsP        = lsctx;
846   PetscFunctionReturn(0);
847 }
848 EXTERN_C_END
849 /* -------------------------------------------------------------------------- */
850 #undef __FUNCT__
851 #define __FUNCT__ "SNESSetLineSearchCheck"
852 /*@C
853    SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed
854    by the line search routine in the Newton-based method SNESLS.
855 
856    Input Parameters:
857 +  snes - nonlinear context obtained from SNESCreate()
858 .  func - pointer to int function
859 -  checkctx - optional user-defined context for use by step checking routine
860 
861    Collective on SNES
862 
863    Calling sequence of func:
864 .vb
865    int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag)
866 .ve
867    where func returns an error code of 0 on success and a nonzero
868    on failure.
869 
870    Input parameters for func:
871 +  snes - nonlinear context
872 .  checkctx - optional user-defined context for use by step checking routine
873 -  x - current candidate iterate
874 
875    Output parameters for func:
876 +  x - current iterate (possibly modified)
877 -  flag - flag indicating whether x has been modified (either
878            PETSC_TRUE of PETSC_FALSE)
879 
880    Level: advanced
881 
882    Notes:
883    SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new
884    iterate computed by the line search checking routine.  In particular,
885    these routines (1) compute a candidate iterate u_{i+1}, (2) pass control
886    to the checking routine, and then (3) compute the corresponding nonlinear
887    function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
888 
889    SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the
890    new iterate computed by the line search checking routine.  In particular,
891    these routines (1) compute a candidate iterate u_{i+1} as well as a
892    candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
893    routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
894    were made to the candidate iterate in the checking routine (as indicated
895    by flag=PETSC_TRUE).  The overhead of this function re-evaluation can be
896    very costly, so use this feature with caution!
897 
898 .keywords: SNES, nonlinear, set, line search check, step check, routine
899 
900 .seealso: SNESSetLineSearch()
901 @*/
902 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx)
903 {
904   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,PetscTruth*),void*);
905 
906   PetscFunctionBegin;
907   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr);
908   if (f) {
909     ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr);
910   }
911   PetscFunctionReturn(0);
912 }
913 /* -------------------------------------------------------------------------- */
914 typedef int (*FCN)(SNES,void*,Vec,PetscTruth*); /* force argument to next function to not be extern C*/
915 EXTERN_C_BEGIN
916 #undef __FUNCT__
917 #define __FUNCT__ "SNESSetLineSearchCheck_LS"
918 int SNESSetLineSearchCheck_LS(SNES snes,FCN func,void *checkctx)
919 {
920   PetscFunctionBegin;
921   ((SNES_LS *)(snes->data))->CheckStep = func;
922   ((SNES_LS *)(snes->data))->checkP    = checkctx;
923   PetscFunctionReturn(0);
924 }
925 EXTERN_C_END
926 /* -------------------------------------------------------------------------- */
927 /*
928    SNESPrintHelp_LS - Prints all options for the SNES_LS method.
929 
930    Input Parameter:
931 .  snes - the SNES context
932 
933    Application Interface Routine: SNESPrintHelp()
934 */
935 #undef __FUNCT__
936 #define __FUNCT__ "SNESPrintHelp_LS"
937 static int SNESPrintHelp_LS(SNES snes,char *p)
938 {
939   SNES_LS *ls = (SNES_LS *)snes->data;
940 
941   PetscFunctionBegin;
942   (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n");
943   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
944   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
945   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
946   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol);
947   PetscFunctionReturn(0);
948 }
949 
950 /*
951    SNESView_LS - Prints info from the SNESLS data structure.
952 
953    Input Parameters:
954 .  SNES - the SNES context
955 .  viewer - visualization context
956 
957    Application Interface Routine: SNESView()
958 */
959 #undef __FUNCT__
960 #define __FUNCT__ "SNESView_LS"
961 static int SNESView_LS(SNES snes,PetscViewer viewer)
962 {
963   SNES_LS    *ls = (SNES_LS *)snes->data;
964   const char *cstr;
965   int        ierr;
966   PetscTruth isascii;
967 
968   PetscFunctionBegin;
969   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
970   if (isascii) {
971     if (ls->LineSearch == SNESNoLineSearch)             cstr = "SNESNoLineSearch";
972     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
973     else if (ls->LineSearch == SNESCubicLineSearch)     cstr = "SNESCubicLineSearch";
974     else                                                cstr = "unknown";
975     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
976     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr);
977   } else {
978     SETERRQ1(1,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
979   }
980   PetscFunctionReturn(0);
981 }
982 /* -------------------------------------------------------------------------- */
983 /*
984    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
985 
986    Input Parameter:
987 .  snes - the SNES context
988 
989    Application Interface Routine: SNESSetFromOptions()
990 */
991 #undef __FUNCT__
992 #define __FUNCT__ "SNESSetFromOptions_LS"
993 static int SNESSetFromOptions_LS(SNES snes)
994 {
995   SNES_LS    *ls = (SNES_LS *)snes->data;
996   const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
997   int        ierr,indx;
998   PetscTruth flg;
999 
1000   PetscFunctionBegin;
1001   ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr);
1002     ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr);
1003     ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr);
1004     ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr);
1005 
1006     ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr);
1007     if (flg) {
1008       switch (indx) {
1009       case 0:
1010         ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr);
1011         break;
1012       case 1:
1013         ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
1014         break;
1015       case 2:
1016         ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr);
1017         break;
1018       case 3:
1019         ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr);
1020         break;
1021       }
1022     }
1023   ierr = PetscOptionsTail();CHKERRQ(ierr);
1024   PetscFunctionReturn(0);
1025 }
1026 /* -------------------------------------------------------------------------- */
1027 /*
1028    SNESCreate_LS - Creates a nonlinear solver context for the SNESLS method,
1029    SNES_LS, and sets this as the private data within the generic nonlinear solver
1030    context, SNES, that was created within SNESCreate().
1031 
1032 
1033    Input Parameter:
1034 .  snes - the SNES context
1035 
1036    Application Interface Routine: SNESCreate()
1037  */
1038 EXTERN_C_BEGIN
1039 #undef __FUNCT__
1040 #define __FUNCT__ "SNESCreate_LS"
1041 int SNESCreate_LS(SNES snes)
1042 {
1043   int     ierr;
1044   SNES_LS *neP;
1045 
1046   PetscFunctionBegin;
1047   snes->setup		= SNESSetUp_LS;
1048   snes->solve		= SNESSolve_LS;
1049   snes->destroy		= SNESDestroy_LS;
1050   snes->converged	= SNESConverged_LS;
1051   snes->printhelp       = SNESPrintHelp_LS;
1052   snes->setfromoptions  = SNESSetFromOptions_LS;
1053   snes->view            = SNESView_LS;
1054   snes->nwork           = 0;
1055 
1056   ierr                  = PetscNew(SNES_LS,&neP);CHKERRQ(ierr);
1057   PetscLogObjectMemory(snes,sizeof(SNES_LS));
1058   snes->data    	= (void*)neP;
1059   neP->alpha		= 1.e-4;
1060   neP->maxstep		= 1.e8;
1061   neP->steptol		= 1.e-12;
1062   neP->LineSearch       = SNESCubicLineSearch;
1063   neP->lsP              = PETSC_NULL;
1064   neP->CheckStep        = PETSC_NULL;
1065   neP->checkP           = PETSC_NULL;
1066 
1067   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr);
1068   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr);
1069 
1070   PetscFunctionReturn(0);
1071 }
1072 EXTERN_C_END
1073 
1074 
1075 
1076