xref: /petsc/src/snes/impls/ls/ls.c (revision b2da817d11b8f98ec4a15fcfa65f2fa8cfedc826)
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 EXTERN_C_BEGIN
837 #undef __FUNCT__
838 #define __FUNCT__ "SNESSetLineSearch_LS"
839 int SNESSetLineSearch_LS(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,
840                          PetscReal,PetscReal*,PetscReal*,int*),void *lsctx)
841 {
842   PetscFunctionBegin;
843   ((SNES_LS *)(snes->data))->LineSearch = func;
844   ((SNES_LS *)(snes->data))->lsP        = lsctx;
845   PetscFunctionReturn(0);
846 }
847 EXTERN_C_END
848 /* -------------------------------------------------------------------------- */
849 #undef __FUNCT__
850 #define __FUNCT__ "SNESSetLineSearchCheck"
851 /*@C
852    SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed
853    by the line search routine in the Newton-based method SNESLS.
854 
855    Input Parameters:
856 +  snes - nonlinear context obtained from SNESCreate()
857 .  func - pointer to int function
858 -  checkctx - optional user-defined context for use by step checking routine
859 
860    Collective on SNES
861 
862    Calling sequence of func:
863 .vb
864    int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag)
865 .ve
866    where func returns an error code of 0 on success and a nonzero
867    on failure.
868 
869    Input parameters for func:
870 +  snes - nonlinear context
871 .  checkctx - optional user-defined context for use by step checking routine
872 -  x - current candidate iterate
873 
874    Output parameters for func:
875 +  x - current iterate (possibly modified)
876 -  flag - flag indicating whether x has been modified (either
877            PETSC_TRUE of PETSC_FALSE)
878 
879    Level: advanced
880 
881    Notes:
882    SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new
883    iterate computed by the line search checking routine.  In particular,
884    these routines (1) compute a candidate iterate u_{i+1}, (2) pass control
885    to the checking routine, and then (3) compute the corresponding nonlinear
886    function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
887 
888    SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the
889    new iterate computed by the line search checking routine.  In particular,
890    these routines (1) compute a candidate iterate u_{i+1} as well as a
891    candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
892    routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
893    were made to the candidate iterate in the checking routine (as indicated
894    by flag=PETSC_TRUE).  The overhead of this function re-evaluation can be
895    very costly, so use this feature with caution!
896 
897 .keywords: SNES, nonlinear, set, line search check, step check, routine
898 
899 .seealso: SNESSetLineSearch()
900 @*/
901 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx)
902 {
903   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,PetscTruth*),void*);
904 
905   PetscFunctionBegin;
906   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr);
907   if (f) {
908     ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr);
909   }
910   PetscFunctionReturn(0);
911 }
912 /* -------------------------------------------------------------------------- */
913 typedef int (*FCN)(SNES,void*,Vec,PetscTruth*); /* force argument to next function to not be extern C*/
914 EXTERN_C_BEGIN
915 #undef __FUNCT__
916 #define __FUNCT__ "SNESSetLineSearchCheck_LS"
917 int SNESSetLineSearchCheck_LS(SNES snes,FCN func,void *checkctx)
918 {
919   PetscFunctionBegin;
920   ((SNES_LS *)(snes->data))->CheckStep = func;
921   ((SNES_LS *)(snes->data))->checkP    = checkctx;
922   PetscFunctionReturn(0);
923 }
924 EXTERN_C_END
925 /* -------------------------------------------------------------------------- */
926 /*
927    SNESPrintHelp_LS - Prints all options for the SNES_LS method.
928 
929    Input Parameter:
930 .  snes - the SNES context
931 
932    Application Interface Routine: SNESPrintHelp()
933 */
934 #undef __FUNCT__
935 #define __FUNCT__ "SNESPrintHelp_LS"
936 static int SNESPrintHelp_LS(SNES snes,char *p)
937 {
938   SNES_LS *ls = (SNES_LS *)snes->data;
939 
940   PetscFunctionBegin;
941   (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n");
942   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
943   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
944   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
945   (*PetscHelpPrintf)(snes->comm,"   %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol);
946   PetscFunctionReturn(0);
947 }
948 
949 /*
950    SNESView_LS - Prints info from the SNESLS data structure.
951 
952    Input Parameters:
953 .  SNES - the SNES context
954 .  viewer - visualization context
955 
956    Application Interface Routine: SNESView()
957 */
958 #undef __FUNCT__
959 #define __FUNCT__ "SNESView_LS"
960 static int SNESView_LS(SNES snes,PetscViewer viewer)
961 {
962   SNES_LS    *ls = (SNES_LS *)snes->data;
963   const char *cstr;
964   int        ierr;
965   PetscTruth isascii;
966 
967   PetscFunctionBegin;
968   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
969   if (isascii) {
970     if (ls->LineSearch == SNESNoLineSearch)             cstr = "SNESNoLineSearch";
971     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
972     else if (ls->LineSearch == SNESCubicLineSearch)     cstr = "SNESCubicLineSearch";
973     else                                                cstr = "unknown";
974     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
975     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr);
976   } else {
977     SETERRQ1(1,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
978   }
979   PetscFunctionReturn(0);
980 }
981 /* -------------------------------------------------------------------------- */
982 /*
983    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.
984 
985    Input Parameter:
986 .  snes - the SNES context
987 
988    Application Interface Routine: SNESSetFromOptions()
989 */
990 #undef __FUNCT__
991 #define __FUNCT__ "SNESSetFromOptions_LS"
992 static int SNESSetFromOptions_LS(SNES snes)
993 {
994   SNES_LS    *ls = (SNES_LS *)snes->data;
995   const char *lses[] = {"basic","basicnonorms","quadratic","cubic"};
996   int        ierr,indx;
997   PetscTruth flg;
998 
999   PetscFunctionBegin;
1000   ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr);
1001     ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr);
1002     ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr);
1003     ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr);
1004 
1005     ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr);
1006     if (flg) {
1007       switch (indx) {
1008       case 0:
1009         ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr);
1010         break;
1011       case 1:
1012         ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
1013         break;
1014       case 2:
1015         ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr);
1016         break;
1017       case 3:
1018         ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr);
1019         break;
1020       }
1021     }
1022   ierr = PetscOptionsTail();CHKERRQ(ierr);
1023   PetscFunctionReturn(0);
1024 }
1025 /* -------------------------------------------------------------------------- */
1026 /*
1027    SNESCreate_LS - Creates a nonlinear solver context for the SNESLS method,
1028    SNES_LS, and sets this as the private data within the generic nonlinear solver
1029    context, SNES, that was created within SNESCreate().
1030 
1031 
1032    Input Parameter:
1033 .  snes - the SNES context
1034 
1035    Application Interface Routine: SNESCreate()
1036  */
1037 EXTERN_C_BEGIN
1038 #undef __FUNCT__
1039 #define __FUNCT__ "SNESCreate_LS"
1040 int SNESCreate_LS(SNES snes)
1041 {
1042   int     ierr;
1043   SNES_LS *neP;
1044 
1045   PetscFunctionBegin;
1046   snes->setup		= SNESSetUp_LS;
1047   snes->solve		= SNESSolve_LS;
1048   snes->destroy		= SNESDestroy_LS;
1049   snes->converged	= SNESConverged_LS;
1050   snes->printhelp       = SNESPrintHelp_LS;
1051   snes->setfromoptions  = SNESSetFromOptions_LS;
1052   snes->view            = SNESView_LS;
1053   snes->nwork           = 0;
1054 
1055   ierr                  = PetscNew(SNES_LS,&neP);CHKERRQ(ierr);
1056   PetscLogObjectMemory(snes,sizeof(SNES_LS));
1057   snes->data    	= (void*)neP;
1058   neP->alpha		= 1.e-4;
1059   neP->maxstep		= 1.e8;
1060   neP->steptol		= 1.e-12;
1061   neP->LineSearch       = SNESCubicLineSearch;
1062   neP->lsP              = PETSC_NULL;
1063   neP->CheckStep        = PETSC_NULL;
1064   neP->checkP           = PETSC_NULL;
1065 
1066   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr);
1067   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr);
1068 
1069   PetscFunctionReturn(0);
1070 }
1071 EXTERN_C_END
1072 
1073 
1074 
1075