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