xref: /petsc/src/snes/impls/ls/ls.c (revision 1a3481a4f86b15936ff2dcb29ec4403ee784c865)
1 #ifndef lint
2 static char vcid[] = "$Id: ls.c,v 1.33 1995/07/20 15:34:54 curfman Exp curfman $";
3 #endif
4 
5 #include <math.h>
6 #include "ls.h"
7 #include "pviewer.h"
8 #if defined(HAVE_STRING_H)
9 #include <string.h>
10 #endif
11 
12 /*
13      Implements a line search variant of Newton's Method
14     for solving systems of nonlinear equations.
15 
16     Input parameters:
17 .   snes - nonlinear context obtained from SNESCreate()
18 
19     Output Parameters:
20 .   outits  - Number of global iterations until termination.
21 
22     Notes:
23     This implements essentially a truncated Newton method with a
24     line search.  By default a cubic backtracking line search
25     is employed, as described in the text "Numerical Methods for
26     Unconstrained Optimization and Nonlinear Equations" by Dennis
27     and Schnabel.  See the examples in src/snes/examples.
28 */
29 
30 int SNESSolve_LS(SNES snes,int *outits)
31 {
32   SNES_LS      *neP = (SNES_LS *) snes->data;
33   int          maxits, i, history_len, ierr, lits, lsfail;
34   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
35   double       fnorm, gnorm, xnorm, ynorm, *history;
36   Vec          Y, X, F, G, W, TMP;
37 
38   history	= snes->conv_hist;	/* convergence history */
39   history_len	= snes->conv_hist_len;	/* convergence history length */
40   maxits	= snes->max_its;	/* maximum number of iterations */
41   X		= snes->vec_sol;	/* solution vector */
42   F		= snes->vec_func;	/* residual vector */
43   Y		= snes->work[0];	/* work vectors */
44   G		= snes->work[1];
45   W		= snes->work[2];
46 
47   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */
48   VecNorm(X,&xnorm);		                         /* xnorm = || X || */
49   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);   /* (+/-) F(X) */
50   VecNorm(F,&fnorm);	        	                 /* fnorm <- ||F|| */
51   snes->norm = fnorm;
52   if (history && history_len > 0) history[0] = fnorm;
53   if (snes->monitor)
54     {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
55 
56   for ( i=0; i<maxits; i++ ) {
57        snes->iter = i+1;
58 
59        /* Solve J Y = -F, where J is Jacobian matrix */
60        ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
61                                 &flg); CHKERRQ(ierr);
62        ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
63                                 flg); CHKERRQ(ierr);
64        ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
65        ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
66        ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);
67        if (lsfail) snes->nfailures++;
68        CHKERRQ(ierr);
69 
70        TMP = F; F = G; snes->vec_func_always = F; G = TMP;
71        TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
72        fnorm = gnorm;
73 
74        snes->norm = fnorm;
75        if (history && history_len > i+1) history[i+1] = fnorm;
76        VecNorm(X,&xnorm);		/* xnorm = || X || */
77        if (snes->monitor)
78          {(*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);}
79 
80        /* Test for convergence */
81        if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
82            if (X != snes->vec_sol) {
83              VecCopy(X,snes->vec_sol);
84              snes->vec_sol_always = snes->vec_sol;
85              snes->vec_func_always = snes->vec_func;
86            }
87            break;
88        }
89   }
90   if (i == maxits) i--;
91   *outits = i+1;
92   return 0;
93 }
94 /* ------------------------------------------------------------ */
95 int SNESSetUp_LS(SNES snes )
96 {
97   int ierr;
98   snes->nwork = 4;
99   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
100   PLogObjectParents(snes,snes->nwork,snes->work );
101   snes->vec_sol_update_always = snes->work[3];
102   return 0;
103 }
104 /* ------------------------------------------------------------ */
105 int SNESDestroy_LS(PetscObject obj)
106 {
107   SNES snes = (SNES) obj;
108   VecFreeVecs(snes->work, snes->nwork );
109   PETSCFREE(snes->data);
110   return 0;
111 }
112 /*@
113    SNESDefaultMonitor - Default SNES monitoring routine.  Prints the
114    residual norm at each iteration.
115 
116    Input Parameters:
117 .  snes - the SNES context
118 .  its - iteration number
119 .  fnorm - 2-norm residual value (may be estimated)
120 .  dummy - unused context
121 
122    Notes:
123    f is either the residual or its negative, depending on the user's
124    preference, as set with SNESSetFunction().
125 
126 .keywords: SNES, nonlinear, default, monitor, residual, norm
127 
128 .seealso: SNESSetMonitor()
129 @*/
130 int SNESDefaultMonitor(SNES snes,int its,double fnorm,void *dummy)
131 {
132   MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
133   return 0;
134 }
135 
136 int SNESDefaultSMonitor(SNES snes,int its, double fnorm,void *dummy)
137 {
138   if (fnorm > 1.e-9 || fnorm == 0.0) {
139     MPIU_printf(snes->comm, "iter = %d, Function norm %g \n",its,fnorm);
140   }
141   else if (fnorm > 1.e-11){
142     MPIU_printf(snes->comm, "iter = %d, Function norm %5.3e \n",its,fnorm);
143   }
144   else {
145     MPIU_printf(snes->comm, "iter = %d, Function norm < 1.e-11\n",its);
146   }
147   return 0;
148 }
149 
150 /*@
151    SNESDefaultConverged - Default test for monitoring the convergence
152    of the SNES solvers.
153 
154    Input Parameters:
155 .  snes - the SNES context
156 .  xnorm - 2-norm of current iterate
157 .  pnorm - 2-norm of current step
158 .  fnorm - 2-norm of residual
159 .  dummy - unused context
160 
161    Returns:
162 $  2  if  ( fnorm < atol ),
163 $  3  if  ( pnorm < xtol*xnorm ),
164 $ -2  if  ( nres > max_res ),
165 $  0  otherwise,
166 
167    where
168 $    atol    - absolute residual norm tolerance,
169 $              set with SNESSetAbsoluteTolerance()
170 $    max_res - maximum number of residual evaluations,
171 $              set with SNESSetMaxResidualEvaluations()
172 $    nres    - number of residual evaluations
173 $    xtol    - relative residual norm tolerance,
174 $              set with SNESSetRelativeTolerance()
175 
176 .keywords: SNES, nonlinear, default, converged, convergence
177 
178 .seealso: SNESSetConvergenceTest()
179 @*/
180 int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm,
181                          void *dummy)
182 {
183   if (fnorm < snes->atol) {
184     PLogInfo((PetscObject)snes,
185       "Converged due to absolute residual norm %g < %g\n",fnorm,snes->atol);
186     return 2;
187   }
188   if (pnorm < snes->xtol*(xnorm)) {
189     PLogInfo((PetscObject)snes,
190       "Converged due to small update length  %g < %g*%g\n",
191        pnorm,snes->xtol,xnorm);
192     return 3;
193   }
194   if (snes->nfuncs > snes->max_funcs) {
195     PLogInfo((PetscObject)snes,
196       "Exceeded maximum number of function evaluations: %d > %d\n",
197        snes->nfuncs, snes->max_funcs );
198     return -2;
199   }
200   return 0;
201 }
202 
203 /* ------------------------------------------------------------ */
204 /*ARGSUSED*/
205 /*@
206    SNESNoLineSearch - This routine is not a line search at all;
207    it simply uses the full Newton step.  Thus, this routine is intended
208    to serve as a template and is not recommended for general use.
209 
210    Input Parameters:
211 .  snes - nonlinear context
212 .  x - current iterate
213 .  f - residual evaluated at x
214 .  y - search direction (contains new iterate on output)
215 .  w - work vector
216 .  fnorm - 2-norm of f
217 
218    Output Parameters:
219 .  g - residual evaluated at new iterate y
220 .  y - new iterate (contains search direction on input)
221 .  gnorm - 2-norm of g
222 .  ynorm - 2-norm of search length
223 .  flag - set to 0, indicating a successful line search
224 
225    Options Database Key:
226 $  -snes_line_search basic
227 
228 .keywords: SNES, nonlinear, line search, cubic
229 
230 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
231           SNESSetLineSearchRoutine()
232 @*/
233 int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
234               double fnorm, double *ynorm, double *gnorm,int *flag )
235 {
236   int    ierr;
237   Scalar one = 1.0;
238   *flag = 0;
239   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
240   VecNorm(y,ynorm);                            /* ynorm = || y || */
241   VecAXPY(&one,x,y);	                       /* y <- x + y      */
242   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);
243   VecNorm(g,gnorm); 	                       /* gnorm = || g || */
244   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
245   return 0;
246 }
247 /* ------------------------------------------------------------------ */
248 /*@
249    SNESCubicLineSearch - This routine performs a cubic line search and
250    is the default line search method.
251 
252    Input Parameters:
253 .  snes - nonlinear context
254 .  x - current iterate
255 .  f - residual evaluated at x
256 .  y - search direction (contains new iterate on output)
257 .  w - work vector
258 .  fnorm - 2-norm of f
259 
260    Output parameters:
261 .  g - residual evaluated at new iterate y
262 .  y - new iterate (contains search direction on input)
263 .  gnorm - 2-norm of g
264 .  ynorm - 2-norm of search length
265 .  flag - 0 if line search succeeds; -1 on failure.
266 
267    Options Database Key:
268 $  -snes_line_search cubic
269 
270    Notes:
271    This line search is taken from "Numerical Methods for Unconstrained
272    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
273 
274 .keywords: SNES, nonlinear, line search, cubic
275 
276 .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
277 @*/
278 int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
279                 double fnorm, double *ynorm, double *gnorm,int *flag)
280 {
281   double  steptol, initslope;
282   double  lambdaprev, gnormprev;
283   double  a, b, d, t1, t2;
284 #if defined(PETSC_COMPLEX)
285   Scalar  cinitslope,clambda;
286 #endif
287   int     ierr,count;
288   SNES_LS *neP = (SNES_LS *) snes->data;
289   Scalar  one = 1.0,scale;
290   double  maxstep,minlambda,alpha,lambda,lambdatemp;
291 
292   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
293   *flag = 0;
294   alpha   = neP->alpha;
295   maxstep = neP->maxstep;
296   steptol = neP->steptol;
297 
298   VecNorm(y, ynorm );
299   if (*ynorm > maxstep) {	/* Step too big, so scale back */
300     scale = maxstep/(*ynorm);
301 #if defined(PETSC_COMPLEX)
302     PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale));
303 #else
304     PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale);
305 #endif
306     VecScale(&scale, y );
307     *ynorm = maxstep;
308   }
309   minlambda = steptol/(*ynorm);
310 #if defined(PETSC_COMPLEX)
311   VecDot(f, y, &cinitslope );
312   initslope = real(cinitslope);
313 #else
314   VecDot(f, y, &initslope );
315 #endif
316   if (initslope > 0.0) initslope = -initslope;
317   if (initslope == 0.0) initslope = -1.0;
318 
319   VecCopy(y, w );
320   VecAXPY(&one, x, w );
321   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
322   VecNorm(g, gnorm );
323   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
324       VecCopy(w, y );
325       PLogInfo((PetscObject)snes,"Using full step\n");
326       goto theend;
327   }
328 
329   /* Fit points with quadratic */
330   lambda = 1.0; count = 0;
331   lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
332   lambdaprev = lambda;
333   gnormprev = *gnorm;
334   if (lambdatemp <= .1*lambda) {
335       lambda = .1*lambda;
336   } else lambda = lambdatemp;
337   VecCopy(x, w );
338 #if defined(PETSC_COMPLEX)
339   clambda = lambda; VecAXPY(&clambda, y, w );
340 #else
341   VecAXPY(&lambda, y, w );
342 #endif
343   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
344   VecNorm(g, gnorm );
345   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
346       VecCopy(w, y );
347       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
348       goto theend;
349   }
350 
351   /* Fit points with cubic */
352   count = 1;
353   while (1) {
354       if (lambda <= minlambda) { /* bad luck; use full step */
355            PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
356            PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
357                    fnorm,*gnorm, *ynorm,lambda);
358            VecCopy(w, y );
359            *flag = -1; break;
360       }
361       t1 = *gnorm - fnorm - lambda*initslope;
362       t2 = gnormprev  - fnorm - lambdaprev*initslope;
363       a = (t1/(lambda*lambda) -
364                 t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
365       b = (-lambdaprev*t1/(lambda*lambda) +
366                 lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
367       d = b*b - 3*a*initslope;
368       if (d < 0.0) d = 0.0;
369       if (a == 0.0) {
370          lambdatemp = -initslope/(2.0*b);
371       } else {
372          lambdatemp = (-b + sqrt(d))/(3.0*a);
373       }
374       if (lambdatemp > .5*lambda) {
375          lambdatemp = .5*lambda;
376       }
377       lambdaprev = lambda;
378       gnormprev = *gnorm;
379       if (lambdatemp <= .1*lambda) {
380          lambda = .1*lambda;
381       }
382       else lambda = lambdatemp;
383       VecCopy( x, w );
384 #if defined(PETSC_COMPLEX)
385       VecAXPY(&clambda, y, w );
386 #else
387       VecAXPY(&lambda, y, w );
388 #endif
389       ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
390       VecNorm(g, gnorm );
391       if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
392          VecCopy(w, y );
393          PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda);
394          *flag = -1; break;
395       }
396       count++;
397    }
398   theend:
399   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
400   return 0;
401 }
402 /*@
403    SNESQuadraticLineSearch - This routine performs a cubic line search.
404 
405    Input Parameters:
406 .  snes - the SNES context
407 .  x - current iterate
408 .  f - residual evaluated at x
409 .  y - search direction (contains new iterate on output)
410 .  w - work vector
411 .  fnorm - 2-norm of f
412 
413    Output Parameters:
414 .  g - residual evaluated at new iterate y
415 .  y - new iterate (contains search direction on input)
416 .  gnorm - 2-norm of g
417 .  ynorm - 2-norm of search length
418 .  flag - 0 if line search succeeds; -1 on failure.
419 
420    Options Database Key:
421 $  -snes_line_search quadratic
422 
423    Notes:
424    Use SNESSetLineSearchRoutine()
425    to set this routine within the SNES_NLS method.
426 
427 .keywords: SNES, nonlinear, quadratic, line search
428 
429 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
430 @*/
431 int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
432                     double fnorm, double *ynorm, double *gnorm,int *flag)
433 {
434   double  steptol, initslope;
435   double  lambdaprev, gnormprev;
436 #if defined(PETSC_COMPLEX)
437   Scalar  cinitslope,clambda;
438 #endif
439   int     ierr,count;
440   SNES_LS *neP = (SNES_LS *) snes->data;
441   Scalar  one = 1.0,scale;
442   double  maxstep,minlambda,alpha,lambda,lambdatemp;
443 
444   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
445   *flag = 0;
446   alpha   = neP->alpha;
447   maxstep = neP->maxstep;
448   steptol = neP->steptol;
449 
450   VecNorm(y, ynorm );
451   if (*ynorm > maxstep) {	/* Step too big, so scale back */
452     scale = maxstep/(*ynorm);
453     VecScale(&scale, y );
454     *ynorm = maxstep;
455   }
456   minlambda = steptol/(*ynorm);
457 #if defined(PETSC_COMPLEX)
458   VecDot(f, y, &cinitslope );
459   initslope = real(cinitslope);
460 #else
461   VecDot(f, y, &initslope );
462 #endif
463   if (initslope > 0.0) initslope = -initslope;
464   if (initslope == 0.0) initslope = -1.0;
465 
466   VecCopy(y, w );
467   VecAXPY(&one, x, w );
468   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
469   VecNorm(g, gnorm );
470   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
471       VecCopy(w, y );
472       PLogInfo((PetscObject)snes,"Using full step\n");
473       goto theend;
474   }
475 
476   /* Fit points with quadratic */
477   lambda = 1.0; count = 0;
478   count = 1;
479   while (1) {
480     if (lambda <= minlambda) { /* bad luck; use full step */
481       PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count);
482       PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n",
483                    fnorm,*gnorm, *ynorm,lambda);
484       VecCopy(w, y );
485       *flag = -1; break;
486     }
487     lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope));
488     lambdaprev = lambda;
489     gnormprev = *gnorm;
490     if (lambdatemp <= .1*lambda) {
491       lambda = .1*lambda;
492     } else lambda = lambdatemp;
493     VecCopy(x, w );
494 #if defined(PETSC_COMPLEX)
495     clambda = lambda; VecAXPY(&clambda, y, w );
496 #else
497     VecAXPY(&lambda, y, w );
498 #endif
499     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
500     VecNorm(g, gnorm );
501     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
502       VecCopy(w, y );
503       PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda);
504       break;
505     }
506     count++;
507   }
508   theend:
509   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
510   return 0;
511 }
512 /* ------------------------------------------------------------ */
513 /*@
514    SNESSetLineSearchRoutine - Sets the line search routine to be used
515    by the method SNES_LS.
516 
517    Input Parameters:
518 .  snes - nonlinear context obtained from SNESCreate()
519 .  func - pointer to int function
520 
521    Available Routines:
522 .  SNESCubicLineSearch() - default line search
523 .  SNESQuadraticLineSearch() - quadratic line search
524 .  SNESNoLineSearch() - the full Newton step (actually not a line search)
525 
526     Options Database Keys:
527 $   -snes_line_search [basic,quadratic,cubic]
528 
529    Calling sequence of func:
530    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
531          Vec w, double fnorm, double *ynorm,
532          double *gnorm, *flag)
533 
534     Input parameters for func:
535 .   snes - nonlinear context
536 .   x - current iterate
537 .   f - residual evaluated at x
538 .   y - search direction (contains new iterate on output)
539 .   w - work vector
540 .   fnorm - 2-norm of f
541 
542     Output parameters for func:
543 .   g - residual evaluated at new iterate y
544 .   y - new iterate (contains search direction on input)
545 .   gnorm - 2-norm of g
546 .   ynorm - 2-norm of search length
547 .   flag - set to 0 if the line search succeeds; a nonzero integer
548            on failure.
549 
550 .keywords: SNES, nonlinear, set, line search, routine
551 
552 .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
553 @*/
554 int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
555                              double,double *,double*,int*) )
556 {
557   if ((snes)->type == SNES_NLS)
558     ((SNES_LS *)(snes->data))->LineSearch = func;
559   return 0;
560 }
561 
562 static int SNESPrintHelp_LS(SNES snes)
563 {
564   SNES_LS *ls = (SNES_LS *)snes->data;
565   MPIU_fprintf(snes->comm,stdout," method ls:\n");
566   MPIU_fprintf(snes->comm,stdout,"   -snes_line_search [basic,quadratic,cubic]\n");
567   MPIU_fprintf(snes->comm,stdout,"   -snes_line_search_alpha alpha (default %g)\n",ls->alpha);
568   MPIU_fprintf(snes->comm,stdout,"   -snes_line_search_maxstep max (default %g)\n",ls->maxstep);
569   MPIU_fprintf(snes->comm,stdout,"   -snes_line_search_steptol tol (default %g)\n",ls->steptol);
570   return 0;
571 }
572 
573 static int SNESView_LS(PetscObject obj,Viewer viewer)
574 {
575   SNES    snes = (SNES)obj;
576   SNES_LS *ls = (SNES_LS *)snes->data;
577   FILE    *fd = ViewerFileGetPointer_Private(viewer);
578   char    *cstring;
579 
580   if (ls->LineSearch == SNESNoLineSearch)
581     cstring = "SNESNoLineSearch";
582   else if (ls->LineSearch == SNESQuadraticLineSearch)
583     cstring = "SNESQuadraticLineSearch";
584   else if (ls->LineSearch == SNESCubicLineSearch)
585     cstring = "SNESCubicLineSearch";
586   else
587     cstring = "unknown";
588   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
589   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
590      ls->alpha,ls->maxstep,ls->steptol);
591   return 0;
592 }
593 
594 static int SNESSetFromOptions_LS(SNES snes)
595 {
596   SNES_LS *ls = (SNES_LS *)snes->data;
597   char    ver[16];
598   double  tmp;
599 
600   if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) {
601     ls->alpha = tmp;
602   }
603   if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) {
604     ls->maxstep = tmp;
605   }
606   if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) {
607     ls->steptol = tmp;
608   }
609   if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) {
610     if (!strcmp(ver,"basic")) {
611       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
612     }
613     else if (!strcmp(ver,"quadratic")) {
614       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
615     }
616     else if (!strcmp(ver,"cubic")) {
617       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
618     }
619     else {SETERRQ(1,"SNESSetFromOptions_LS: Unknown line search");}
620   }
621   return 0;
622 }
623 
624 /* ------------------------------------------------------------ */
625 int SNESCreate_LS(SNES  snes )
626 {
627   SNES_LS *neP;
628 
629   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,
630     "SNESCreate_LS: Valid for SNES_NONLINEAR_EQUATIONS problems only");
631   snes->type		= SNES_EQ_NLS;
632   snes->setup		= SNESSetUp_LS;
633   snes->solve		= SNESSolve_LS;
634   snes->destroy		= SNESDestroy_LS;
635   snes->converged	= SNESDefaultConverged;
636   snes->printhelp       = SNESPrintHelp_LS;
637   snes->setfromoptions  = SNESSetFromOptions_LS;
638   snes->view            = SNESView_LS;
639 
640   neP			= PETSCNEW(SNES_LS);   CHKPTRQ(neP);
641   snes->data    	= (void *) neP;
642   neP->alpha		= 1.e-4;
643   neP->maxstep		= 1.e8;
644   neP->steptol		= 1.e-12;
645   neP->LineSearch       = SNESCubicLineSearch;
646   return 0;
647 }
648 
649 
650 
651 
652