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