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