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