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