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