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