xref: /petsc/src/snes/impls/ls/ls.c (revision c8dd0c0d1465a0be5d606d0075fe0d07d9b5cf5f)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: ls.c,v 1.125 1999/03/14 17:17:00 curfman Exp curfman $";
3 #endif
4 
5 #include "src/snes/impls/ls/ls.h"
6 
7 /*  --------------------------------------------------------------------
8 
9      This file implements a truncated Newton method with a line search,
10      for solving a system of nonlinear equations, using the SLES, Vec,
11      and Mat interfaces for linear solvers, vectors, and matrices,
12      respectively.
13 
14      The following basic routines are required for each nonlinear solver:
15           SNESCreate_XXX()          - Creates a nonlinear solver context
16           SNESSetFromOptions_XXX()  - Sets runtime options
17           SNESSolve_XXX()           - Solves the nonlinear system
18           SNESDestroy_XXX()         - Destroys the nonlinear solver context
19      The suffix "_XXX" denotes a particular implementation, in this case
20      we use _EQ_LS (e.g., SNESCreate_EQ_LS, SNESSolve_EQ_LS) for solving
21      systems of nonlinear equations (EQ) with a line search (LS) method.
22      These routines are actually called via the common user interface
23      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
24      SNESDestroy(), so the application code interface remains identical
25      for all nonlinear solvers.
26 
27      Another key routine is:
28           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
29      by setting data structures and options.   The interface routine SNESSetUp()
30      is not usually called directly by the user, but instead is called by
31      SNESSolve() if necessary.
32 
33      Additional basic routines are:
34           SNESPrintHelp_XXX()       - Prints nonlinear solver runtime options
35           SNESView_XXX()            - Prints details of runtime options that
36                                       have actually been used.
37      These are called by application codes via the interface routines
38      SNESPrintHelp() and SNESView().
39 
40      The various types of solvers (preconditioners, Krylov subspace methods,
41      nonlinear solvers, timesteppers) are all organized similarly, so the
42      above description applies to these categories also.
43 
44     -------------------------------------------------------------------- */
45 /*
46    SNESSolve_EQ_LS - Solves a nonlinear system with a truncated Newton
47    method with a line search.
48 
49    Input Parameters:
50 .  snes - the SNES context
51 
52    Output Parameter:
53 .  outits - number of iterations until termination
54 
55    Application Interface Routine: SNESSolve()
56 
57    Notes:
58    This implements essentially a truncated Newton method with a
59    line search.  By default a cubic backtracking line search
60    is employed, as described in the text "Numerical Methods for
61    Unconstrained Optimization and Nonlinear Equations" by Dennis
62    and Schnabel.
63 */
64 #undef __FUNC__
65 #define __FUNC__ "SNESSolve_EQ_LS"
66 int SNESSolve_EQ_LS(SNES snes,int *outits)
67 {
68   SNES_LS       *neP = (SNES_LS *) snes->data;
69   int           maxits, i, ierr, lits, lsfail;
70   MatStructure  flg = DIFFERENT_NONZERO_PATTERN;
71   double        fnorm, gnorm, xnorm, ynorm;
72   Vec           Y, X, F, G, W, TMP;
73 
74   PetscFunctionBegin;
75   maxits	= snes->max_its;	/* maximum number of iterations */
76   X		= snes->vec_sol;	/* solution vector */
77   F		= snes->vec_func;	/* residual vector */
78   Y		= snes->work[0];	/* work vectors */
79   G		= snes->work[1];
80   W		= snes->work[2];
81 
82   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);  /*  F(X)      */
83   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	/* fnorm <- ||F||  */
84   PetscAMSTakeAccess(snes);
85   snes->iter = 0;
86   snes->norm = fnorm;
87   PetscAMSGrantAccess(snes);
88   SNESLogConvHistory(snes,fnorm,0);
89   SNESMonitor(snes,0,fnorm);
90 
91   if (fnorm < snes->atol) {*outits = 0; PetscFunctionReturn(0);}
92 
93   /* set parameter for default relative tolerance convergence test */
94   snes->ttol = fnorm*snes->rtol;
95 
96   for ( i=0; i<maxits; i++ ) {
97 
98     /* Solve J Y = F, where J is Jacobian matrix */
99     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr);
100     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
101     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
102     snes->linear_its += PetscAbsInt(lits);
103     PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
104 
105     /* Compute a (scaled) negative update in the line search routine:
106          Y <- X - lambda*Y
107        and evaluate G(Y) = function(Y))
108     */
109     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
110     ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr);
111     PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
112     if (lsfail) snes->nfailures++;
113 
114     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
115     TMP = X; X = Y; snes->vec_sol_always = X;  Y = TMP;
116     fnorm = gnorm;
117 
118     PetscAMSTakeAccess(snes);
119     snes->iter = i+1;
120     snes->norm = fnorm;
121     PetscAMSGrantAccess(snes);
122     SNESLogConvHistory(snes,fnorm,lits);
123     SNESMonitor(snes,i+1,fnorm);
124 
125     /* Test for convergence */
126     if (snes->converged) {
127       ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
128       if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
129         break;
130       }
131     }
132   }
133   if (X != snes->vec_sol) {
134     ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
135     snes->vec_sol_always  = snes->vec_sol;
136     snes->vec_func_always = snes->vec_func;
137   }
138   if (i == maxits) {
139     PLogInfo(snes,"SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
140     i--;
141   }
142   *outits = i+1;
143   PetscFunctionReturn(0);
144 }
145 /* -------------------------------------------------------------------------- */
146 /*
147    SNESSetUp_EQ_LS - Sets up the internal data structures for the later use
148    of the SNES_EQ_LS nonlinear solver.
149 
150    Input Parameter:
151 .  snes - the SNES context
152 .  x - the solution vector
153 
154    Application Interface Routine: SNESSetUp()
155 
156    Notes:
157    For basic use of the SNES solvers the user need not explicitly call
158    SNESSetUp(), since these actions will automatically occur during
159    the call to SNESSolve().
160  */
161 #undef __FUNC__
162 #define __FUNC__ "SNESSetUp_EQ_LS"
163 int SNESSetUp_EQ_LS(SNES snes)
164 {
165   int ierr;
166 
167   PetscFunctionBegin;
168   snes->nwork = 4;
169   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
170   PLogObjectParents(snes,snes->nwork,snes->work);
171   snes->vec_sol_update_always = snes->work[3];
172   PetscFunctionReturn(0);
173 }
174 /* -------------------------------------------------------------------------- */
175 /*
176    SNESDestroy_EQ_LS - Destroys the private SNES_LS context that was created
177    with SNESCreate_EQ_LS().
178 
179    Input Parameter:
180 .  snes - the SNES context
181 
182    Application Interface Routine: SNESDestroy()
183  */
184 #undef __FUNC__
185 #define __FUNC__ "SNESDestroy_EQ_LS"
186 int SNESDestroy_EQ_LS(SNES snes)
187 {
188   int  ierr;
189 
190   PetscFunctionBegin;
191   if (snes->nwork) {
192     ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
193   }
194   PetscFree(snes->data);
195   PetscFunctionReturn(0);
196 }
197 /* -------------------------------------------------------------------------- */
198 #undef __FUNC__
199 #define __FUNC__ "SNESNoLineSearch"
200 
201 /*@C
202    SNESNoLineSearch - This routine is not a line search at all;
203    it simply uses the full Newton step.  Thus, this routine is intended
204    to serve as a template and is not recommended for general use.
205 
206    Collective on SNES and Vec
207 
208    Input Parameters:
209 +  snes - nonlinear context
210 .  lsctx - optional context for line search (not used here)
211 .  x - current iterate
212 .  f - residual evaluated at x
213 .  y - search direction (contains new iterate on output)
214 .  w - work vector
215 -  fnorm - 2-norm of f
216 
217    Output Parameters:
218 +  g - residual evaluated at new iterate y
219 .  y - new iterate (contains search direction on input)
220 .  gnorm - 2-norm of g
221 .  ynorm - 2-norm of search length
222 -  flag - set to 0, indicating a successful line search
223 
224    Options Database Key:
225 .  -snes_eq_ls basic - Activates SNESNoLineSearch()
226 
227    Level: advanced
228 
229 .keywords: SNES, nonlinear, line search, cubic
230 
231 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
232           SNESSetLineSearch(), SNESNoLineSearchNoNorms()
233 @*/
234 int SNESNoLineSearch(SNES snes, void *lsctx, Vec x, Vec f, Vec g, Vec y, Vec w,
235                      double fnorm, double *ynorm, double *gnorm,int *flag )
236 {
237   int    ierr;
238   Scalar mone = -1.0;
239 
240   PetscFunctionBegin;
241   *flag = 0;
242   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
243   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);       /* ynorm = || y || */
244   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
245   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
246   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);       /* gnorm = || g || */
247   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
248   PetscFunctionReturn(0);
249 }
250 /* -------------------------------------------------------------------------- */
251 #undef __FUNC__
252 #define __FUNC__ "SNESNoLineSearchNoNorms"
253 
254 /*@C
255    SNESNoLineSearchNoNorms - This routine is not a line search at
256    all; it simply uses the full Newton step. This version does not
257    even compute the norm of the function or search direction; this
258    is intended only when you know the full step is fine and are
259    not checking for convergence of the nonlinear iteration (for
260    example, you are running always for a fixed number of Newton steps).
261 
262    Collective on SNES and Vec
263 
264    Input Parameters:
265 +  snes - nonlinear context
266 .  lsctx - optional context for line search (not used here)
267 .  x - current iterate
268 .  f - residual evaluated at x
269 .  y - search direction (contains new iterate on output)
270 .  w - work vector
271 -  fnorm - 2-norm of f
272 
273    Output Parameters:
274 +  g - residual evaluated at new iterate y
275 .  gnorm - not changed
276 .  ynorm - not changed
277 -  flag - set to 0, indicating a successful line search
278 
279    Options Database Key:
280 .  -snes_eq_ls basicnonorms - Activates SNESNoLineSearchNoNorms()
281 
282    Level: advanced
283 
284 .keywords: SNES, nonlinear, line search, cubic
285 
286 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
287           SNESSetLineSearch(), SNESNoLineSearch()
288 @*/
289 int SNESNoLineSearchNoNorms(SNES snes, void *lsctx, Vec x, Vec f, Vec g, Vec y, Vec w,
290                      double fnorm, double *ynorm, double *gnorm,int *flag )
291 {
292   int    ierr;
293   Scalar mone = -1.0;
294 
295   PetscFunctionBegin;
296   *flag = 0;
297   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
298   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);            /* y <- y - x      */
299   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y)    */
300   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
301   PetscFunctionReturn(0);
302 }
303 /* -------------------------------------------------------------------------- */
304 #undef __FUNC__
305 #define __FUNC__ "SNESCubicLineSearch"
306 /*@C
307    SNESCubicLineSearch - Performs a cubic line search (default line search method).
308 
309    Collective on SNES
310 
311    Input Parameters:
312 +  snes - nonlinear context
313 .  lsctx - optional context for line search (not used here)
314 .  x - current iterate
315 .  f - residual evaluated at x
316 .  y - search direction (contains new iterate on output)
317 .  w - work vector
318 -  fnorm - 2-norm of f
319 
320    Output Parameters:
321 +  g - residual evaluated at new iterate y
322 .  y - new iterate (contains search direction on input)
323 .  gnorm - 2-norm of g
324 .  ynorm - 2-norm of search length
325 -  flag - 0 if line search succeeds; -1 on failure.
326 
327    Options Database Key:
328 $  -snes_eq_ls cubic - Activates SNESCubicLineSearch()
329 
330    Notes:
331    This line search is taken from "Numerical Methods for Unconstrained
332    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
333 
334    Level: advanced
335 
336 .keywords: SNES, nonlinear, line search, cubic
337 
338 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
339 @*/
340 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
341                         double fnorm,double *ynorm,double *gnorm,int *flag)
342 {
343   /*
344      Note that for line search purposes we work with with the related
345      minimization problem:
346         min  z(x):  R^n -> R,
347      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
348    */
349 
350   double  steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2;
351   double  maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg;
352 #if defined(USE_PETSC_COMPLEX)
353   Scalar  cinitslope, clambda;
354 #endif
355   int     ierr, count;
356   SNES_LS *neP = (SNES_LS *) snes->data;
357   Scalar  mone = -1.0,scale;
358 
359   PetscFunctionBegin;
360   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
361   *flag   = 0;
362   alpha   = neP->alpha;
363   maxstep = neP->maxstep;
364   steptol = neP->steptol;
365 
366   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
367   if (*ynorm < snes->atol) {
368     PLogInfo(snes,"SNESCubicLineSearch: Search direction and size are nearly 0\n");
369     *gnorm = fnorm;
370     ierr = VecCopy(x,y); CHKERRQ(ierr);
371     ierr = VecCopy(f,g); CHKERRQ(ierr);
372     goto theend1;
373   }
374   if (*ynorm > maxstep) {	/* Step too big, so scale back */
375     scale = maxstep/(*ynorm);
376 #if defined(USE_PETSC_COMPLEX)
377     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",PetscReal(scale));
378 #else
379     PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
380 #endif
381     ierr = VecScale(&scale,y); CHKERRQ(ierr);
382     *ynorm = maxstep;
383   }
384   minlambda = steptol/(*ynorm);
385   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
386 #if defined(USE_PETSC_COMPLEX)
387   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
388   initslope = PetscReal(cinitslope);
389 #else
390   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
391 #endif
392   if (initslope > 0.0) initslope = -initslope;
393   if (initslope == 0.0) initslope = -1.0;
394 
395   ierr = VecCopy(y,w); CHKERRQ(ierr);
396   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
397   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
398   ierr = VecNorm(g,NORM_2,gnorm);
399   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */
400     ierr = VecCopy(w,y); CHKERRQ(ierr);
401     PLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
402     goto theend1;
403   }
404 
405   /* Fit points with quadratic */
406   lambda = 1.0; count = 0;
407   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
408   lambdaprev = lambda;
409   gnormprev = *gnorm;
410   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
411   else lambda = lambdatemp;
412   ierr   = VecCopy(x,w); CHKERRQ(ierr);
413   lambdaneg = -lambda;
414 #if defined(USE_PETSC_COMPLEX)
415   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
416 #else
417   ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
418 #endif
419   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
420   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
421   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */
422     ierr = VecCopy(w,y); CHKERRQ(ierr);
423     PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
424     goto theend1;
425   }
426 
427   /* Fit points with cubic */
428   count = 1;
429   while (1) {
430     if (lambda <= minlambda) { /* bad luck; use full step */
431       PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
432       PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
433                fnorm,*gnorm,*ynorm,lambda,initslope);
434       ierr = VecCopy(w,y); CHKERRQ(ierr);
435       *flag = -1; break;
436     }
437     t1 = ((*gnorm)*(*gnorm) - fnorm*fnorm)*0.5 - lambda*initslope;
438     t2 = (gnormprev*gnormprev  - fnorm*fnorm)*0.5 - lambdaprev*initslope;
439     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
440     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
441     d  = b*b - 3*a*initslope;
442     if (d < 0.0) d = 0.0;
443     if (a == 0.0) {
444       lambdatemp = -initslope/(2.0*b);
445     } else {
446       lambdatemp = (-b + sqrt(d))/(3.0*a);
447     }
448     if (lambdatemp > .5*lambda) {
449       lambdatemp = .5*lambda;
450     }
451     lambdaprev = lambda;
452     gnormprev = *gnorm;
453     if (lambdatemp <= .1*lambda) {
454       lambda = .1*lambda;
455     }
456     else lambda = lambdatemp;
457     ierr = VecCopy( x, w ); CHKERRQ(ierr);
458     lambdaneg = -lambda;
459 #if defined(USE_PETSC_COMPLEX)
460     clambda = lambdaneg;
461     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
462 #else
463     ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr);
464 #endif
465     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
466     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
467     if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* is reduction enough? */
468       ierr = VecCopy(w,y); CHKERRQ(ierr);
469       PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
470       goto theend1;
471     } else {
472       PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%g\n",lambda);
473     }
474     count++;
475   }
476   theend1:
477   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
478   PetscFunctionReturn(0);
479 }
480 /* -------------------------------------------------------------------------- */
481 #undef __FUNC__
482 #define __FUNC__ "SNESQuadraticLineSearch"
483 /*@C
484    SNESQuadraticLineSearch - Performs a quadratic line search.
485 
486    Collective on SNES and Vec
487 
488    Input Parameters:
489 +  snes - the SNES context
490 .  lsctx - optional context for line search (not used here)
491 .  x - current iterate
492 .  f - residual evaluated at x
493 .  y - search direction (contains new iterate on output)
494 .  w - work vector
495 -  fnorm - 2-norm of f
496 
497    Output Parameters:
498 +  g - residual evaluated at new iterate y
499 .  y - new iterate (contains search direction on input)
500 .  gnorm - 2-norm of g
501 .  ynorm - 2-norm of search length
502 -  flag - 0 if line search succeeds; -1 on failure.
503 
504    Options Database Key:
505 .  -snes_eq_ls quadratic - Activates SNESQuadraticLineSearch()
506 
507    Notes:
508    Use SNESSetLineSearch() to set this routine within the SNES_EQ_LS method.
509 
510    Level: advanced
511 
512 .keywords: SNES, nonlinear, quadratic, line search
513 
514 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
515 @*/
516 int SNESQuadraticLineSearch(SNES snes, void *lsctx, Vec x, Vec f, Vec g, Vec y, Vec w,
517                            double fnorm, double *ynorm, double *gnorm,int *flag)
518 {
519   /*
520      Note that for line search purposes we work with with the related
521      minimization problem:
522         min  z(x):  R^n -> R,
523      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
524    */
525   double  steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp;
526 #if defined(USE_PETSC_COMPLEX)
527   Scalar  cinitslope,clambda;
528 #endif
529   int     ierr,count;
530   SNES_LS *neP = (SNES_LS *) snes->data;
531   Scalar  mone = -1.0,scale;
532 
533   PetscFunctionBegin;
534   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
535   *flag   = 0;
536   alpha   = neP->alpha;
537   maxstep = neP->maxstep;
538   steptol = neP->steptol;
539 
540   VecNorm(y, NORM_2,ynorm );
541   if (*ynorm < snes->atol) {
542     PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
543     *gnorm = fnorm;
544     ierr = VecCopy(x,y); CHKERRQ(ierr);
545     ierr = VecCopy(f,g); CHKERRQ(ierr);
546     goto theend2;
547   }
548   if (*ynorm > maxstep) {	/* Step too big, so scale back */
549     scale = maxstep/(*ynorm);
550     ierr = VecScale(&scale,y); CHKERRQ(ierr);
551     *ynorm = maxstep;
552   }
553   minlambda = steptol/(*ynorm);
554   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
555 #if defined(USE_PETSC_COMPLEX)
556   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
557   initslope = PetscReal(cinitslope);
558 #else
559   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
560 #endif
561   if (initslope > 0.0) initslope = -initslope;
562   if (initslope == 0.0) initslope = -1.0;
563 
564   ierr = VecCopy(y,w); CHKERRQ(ierr);
565   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
566   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
567   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
568   if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */
569     ierr = VecCopy(w,y); CHKERRQ(ierr);
570     PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
571     goto theend2;
572   }
573 
574   /* Fit points with quadratic */
575   lambda = 1.0; count = 0;
576   count = 1;
577   while (1) {
578     if (lambda <= minlambda) { /* bad luck; use full step */
579       PLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
580       PLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",
581                fnorm,*gnorm,*ynorm,lambda,initslope);
582       ierr = VecCopy(w,y); CHKERRQ(ierr);
583       *flag = -1; break;
584     }
585     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
586     if (lambdatemp <= .1*lambda) {
587       lambda = .1*lambda;
588     } else lambda = lambdatemp;
589     ierr = VecCopy(x,w); CHKERRQ(ierr);
590     lambda = -lambda;
591 #if defined(USE_PETSC_COMPLEX)
592     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
593 #else
594     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
595 #endif
596     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
597     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
598     if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */
599       ierr = VecCopy(w,y); CHKERRQ(ierr);
600       PLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
601       break;
602     }
603     count++;
604   }
605   theend2:
606   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
607   PetscFunctionReturn(0);
608 }
609 /* -------------------------------------------------------------------------- */
610 #undef __FUNC__
611 #define __FUNC__ "SNESSetLineSearch"
612 /*@C
613    SNESSetLineSearch - Sets the line search routine to be used
614    by the method SNES_EQ_LS.
615 
616    Input Parameters:
617 +  snes - nonlinear context obtained from SNESCreate()
618 .  lsctx - optional user-defined context for use by line search
619 -  func - pointer to int function
620 
621    Collective on SNES
622 
623    Available Routines:
624 +  SNESCubicLineSearch() - default line search
625 .  SNESQuadraticLineSearch() - quadratic line search
626 .  SNESNoLineSearch() - the full Newton step (actually not a line search)
627 -  SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
628 
629     Options Database Keys:
630 +   -snes_eq_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
631 .   -snes_eq_ls_alpha <alpha> - Sets alpha
632 .   -snes_eq_ls_maxstep <max> - Sets maxstep
633 -   -snes_eq_ls_steptol <steptol> - Sets steptol
634 
635    Calling sequence of func:
636 .vb
637    func (SNES snes, void *lsctx, Vec x, Vec f, Vec g, Vec y, Vec w,
638          double fnorm, double *ynorm, double *gnorm, *flag)
639 .ve
640 
641     Input parameters for func:
642 +   snes - nonlinear context
643 .   lsctx - optional user-defined context for line search
644 .   x - current iterate
645 .   f - residual evaluated at x
646 .   y - search direction (contains new iterate on output)
647 .   w - work vector
648 -   fnorm - 2-norm of f
649 
650     Output parameters for func:
651 +   g - residual evaluated at new iterate y
652 .   y - new iterate (contains search direction on input)
653 .   gnorm - 2-norm of g
654 .   ynorm - 2-norm of search length
655 -   flag - set to 0 if the line search succeeds; a nonzero integer
656            on failure.
657 
658     Level: advanced
659 
660 .keywords: SNES, nonlinear, set, line search, routine
661 
662 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms()
663 @*/
664 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,double,double*,double*,int*),void *lsctx)
665 {
666   int ierr, (*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,double,double*,double*,int*),void*);
667 
668   PetscFunctionBegin;
669   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void **)&f);CHKERRQ(ierr);
670   if (f) {
671     ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr);
672   }
673   PetscFunctionReturn(0);
674 }
675 /* -------------------------------------------------------------------------- */
676 EXTERN_C_BEGIN
677 #undef __FUNC__
678 #define __FUNC__ "SNESSetLineSearch_LS"
679 int SNESSetLineSearch_LS(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,
680                          double,double*,double*,int*),void *lsctx)
681 {
682   PetscFunctionBegin;
683   ((SNES_LS *)(snes->data))->LineSearch = func;
684   ((SNES_LS *)(snes->data))->lsP = lsctx;
685   PetscFunctionReturn(0);
686 }
687 EXTERN_C_END
688 /* -------------------------------------------------------------------------- */
689 #undef __FUNC__
690 #define __FUNC__ "SNESSetLineSearchCheck"
691 /*@C
692    SNESSetLineSearchCheck - Sets a routine to check the step computed by the
693    line search routine in the Newton-based method SNES_EQ_LS.
694 
695    Input Parameters:
696 +  snes - nonlinear context obtained from SNESCreate()
697 .  func - pointer to int function
698 -  checkctx - optional user-defined context for use by step checking routine
699 
700    Collective on SNES
701 
702    Calling sequence of func:
703 .vb
704    func (SNES snes, void *lsctx, Vec x, int *flag)
705 .ve
706 
707     Input parameters for func:
708 +   snes - nonlinear context
709 .   checkctx - optional user-defined context for use by step checking routine
710 -   x - current iterate
711 
712     Output parameters for func:
713 +   x - current iterate (possibly modified)
714 -   flag - flag indicating whether x has been modified (either
715            PETSC_TRUE of PETSC_FALSE)
716 
717     Level: advanced
718 
719 .keywords: SNES, nonlinear, set, line search check, step check, routine
720 
721 .seealso: SNESSetLineSearch()
722 @*/
723 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,int*),void *checkctx)
724 {
725   int ierr, (*f)(SNES,int (*)(SNES,void*,Vec,int*),void*);
726 
727   PetscFunctionBegin;
728   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void **)&f);CHKERRQ(ierr);
729   if (f) {
730     ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr);
731   }
732   PetscFunctionReturn(0);
733 }
734 /* -------------------------------------------------------------------------- */
735 EXTERN_C_BEGIN
736 #undef __FUNC__
737 #define __FUNC__ "SNESSetLineSearchCheck_LS"
738 int SNESSetLineSearchCheck_LS(SNES snes,int (*func)(SNES,void*,Vec,int*),void *checkctx)
739 {
740   PetscFunctionBegin;
741   ((SNES_LS *)(snes->data))->CheckStep = func;
742   ((SNES_LS *)(snes->data))->checkP = checkctx;
743   PetscFunctionReturn(0);
744 }
745 EXTERN_C_END
746 /* -------------------------------------------------------------------------- */
747 /*
748    SNESPrintHelp_EQ_LS - Prints all options for the SNES_EQ_LS method.
749 
750    Input Parameter:
751 .  snes - the SNES context
752 
753    Application Interface Routine: SNESPrintHelp()
754 */
755 #undef __FUNC__
756 #define __FUNC__ "SNESPrintHelp_EQ_LS"
757 static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
758 {
759   SNES_LS *ls = (SNES_LS *)snes->data;
760 
761   PetscFunctionBegin;
762   (*PetscHelpPrintf)(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
763   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
764   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
765   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
766   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
767   PetscFunctionReturn(0);
768 }
769 /* -------------------------------------------------------------------------- */
770 /*
771    SNESView_EQ_LS - Prints info from the SNES_EQ_LS data structure.
772 
773    Input Parameters:
774 .  SNES - the SNES context
775 .  viewer - visualization context
776 
777    Application Interface Routine: SNESView()
778 */
779 #undef __FUNC__
780 #define __FUNC__ "SNESView_EQ_LS"
781 static int SNESView_EQ_LS(SNES snes,Viewer viewer)
782 {
783   SNES_LS    *ls = (SNES_LS *)snes->data;
784   char       *cstr;
785   int        ierr;
786   ViewerType vtype;
787 
788   PetscFunctionBegin;
789   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
790   if (PetscTypeCompare(vtype,ASCII_VIEWER)) {
791     if (ls->LineSearch == SNESNoLineSearch)             cstr = "SNESNoLineSearch";
792     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
793     else if (ls->LineSearch == SNESCubicLineSearch)     cstr = "SNESCubicLineSearch";
794     else                                                cstr = "unknown";
795     ViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);
796     ViewerASCIIPrintf(viewer,"  alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);
797   } else {
798     SETERRQ(1,1,"Viewer type not supported for this object");
799   }
800   PetscFunctionReturn(0);
801 }
802 /* -------------------------------------------------------------------------- */
803 /*
804    SNESSetFromOptions_EQ_LS - Sets various parameters for the SNES_EQ_LS method.
805 
806    Input Parameter:
807 .  snes - the SNES context
808 
809    Application Interface Routine: SNESSetFromOptions()
810 */
811 #undef __FUNC__
812 #define __FUNC__ "SNESSetFromOptions_EQ_LS"
813 static int SNESSetFromOptions_EQ_LS(SNES snes)
814 {
815   SNES_LS *ls = (SNES_LS *)snes->data;
816   char    ver[16];
817   double  tmp;
818   int     ierr,flg;
819 
820   PetscFunctionBegin;
821   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr);
822   if (flg) {
823     ls->alpha = tmp;
824   }
825   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr);
826   if (flg) {
827     ls->maxstep = tmp;
828   }
829   ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr);
830   if (flg) {
831     ls->steptol = tmp;
832   }
833   ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr);
834   if (flg) {
835     if (!PetscStrcmp(ver,"basic")) {
836       ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr);
837     } else if (!PetscStrcmp(ver,"basicnonorms")) {
838       ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
839     } else if (!PetscStrcmp(ver,"quadratic")) {
840       ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr);
841     } else if (!PetscStrcmp(ver,"cubic")) {
842       ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr);
843     }
844     else {SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown line search");}
845   }
846   PetscFunctionReturn(0);
847 }
848 /* -------------------------------------------------------------------------- */
849 /*
850    SNESCreate_EQ_LS - Creates a nonlinear solver context for the SNES_EQ_LS method,
851    SNES_LS, and sets this as the private data within the generic nonlinear solver
852    context, SNES, that was created within SNESCreate().
853 
854 
855    Input Parameter:
856 .  snes - the SNES context
857 
858    Application Interface Routine: SNESCreate()
859  */
860 EXTERN_C_BEGIN
861 #undef __FUNC__
862 #define __FUNC__ "SNESCreate_EQ_LS"
863 int SNESCreate_EQ_LS(SNES snes)
864 {
865   int     ierr;
866   SNES_LS *neP;
867 
868   PetscFunctionBegin;
869   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
870     SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only");
871   }
872 
873   snes->setup		= SNESSetUp_EQ_LS;
874   snes->solve		= SNESSolve_EQ_LS;
875   snes->destroy		= SNESDestroy_EQ_LS;
876   snes->converged	= SNESConverged_EQ_LS;
877   snes->printhelp       = SNESPrintHelp_EQ_LS;
878   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
879   snes->view            = SNESView_EQ_LS;
880   snes->nwork           = 0;
881 
882   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
883   PLogObjectMemory(snes,sizeof(SNES_LS));
884   snes->data    	= (void *) neP;
885   neP->alpha		= 1.e-4;
886   neP->maxstep		= 1.e8;
887   neP->steptol		= 1.e-12;
888   neP->LineSearch       = SNESCubicLineSearch;
889   neP->lsP              = PETSC_NULL;
890   neP->CheckStep        = PETSC_NULL;
891   neP->checkP           = PETSC_NULL;
892 
893   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",
894                     (void*)SNESSetLineSearch_LS);CHKERRQ(ierr);
895   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",
896                     (void*)SNESSetLineSearchCheck_LS);CHKERRQ(ierr);
897 
898   PetscFunctionReturn(0);
899 }
900 EXTERN_C_END
901 
902 
903 
904