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