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