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