xref: /petsc/src/snes/impls/ls/ls.c (revision 3b5a905bbcba14b9250de9c3c6bc067664eddbb4)
1 /*$Id: ls.c,v 1.172 2001/08/07 03:04:11 balay Exp $*/
2 
3 #include "src/snes/impls/ls/ls.h"
4 
5 
6 #undef __FUNCT__
7 #define __FUNCT__ "VecMaxScale_SNES"
8 /*
9             max { p[i]/x[i] }
10 */
11 int VecMaxScale_SNES(Vec p,Vec x,PetscReal *m)
12 {
13   int         ierr,i,n;
14   PetscScalar *pa,*xa;
15   PetscReal   t;
16   MPI_Comm    comm;
17 
18   PetscFunctionBegin;
19   ierr = VecGetLocalSize(p,&n);CHKERRQ(ierr);
20   ierr = PetscObjectGetComm((PetscObject)p,&comm);CHKERRQ(ierr);
21 
22   ierr = VecGetArray(p,&pa);CHKERRQ(ierr);
23   ierr = VecGetArray(x,&xa);CHKERRQ(ierr);
24   t = 0.0;
25   for ( i=0; i<n; i++) {
26     if (xa[i] != 0.0) {
27       t = PetscMax(PetscAbsScalar(pa[i]/xa[i]),t);
28     } else {
29       t = PetscMax(PetscAbsScalar(pa[i]),t);
30     }
31   }
32   ierr = MPI_Allreduce(&t,m,1,MPI_DOUBLE,MPI_MAX,comm);CHKERRQ(ierr);
33   ierr = VecRestoreArray(p,&pa);CHKERRQ(ierr);
34   ierr = VecRestoreArray(x,&xa);CHKERRQ(ierr);
35   PetscFunctionReturn(0);
36 }
37 
38 /*
39      Checks if J^T F = 0 which implies we've found a local minimum of the function,
40     but not a zero. In the case when one cannot compute J^T F we use the fact that
41     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
42     for this trick.
43 */
44 #undef __FUNCT__
45 #define __FUNCT__ "SNESLSCheckLocalMin_Private"
46 int SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin)
47 {
48   PetscReal  a1;
49   int        ierr;
50   PetscTruth hastranspose;
51 
52   PetscFunctionBegin;
53   *ismin = PETSC_FALSE;
54   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
55   if (hastranspose) {
56     /* Compute || J^T F|| */
57     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
58     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
59     PetscLogInfo(0,"SNESSolve_EQ_LS: || J^T F|| %g near zero implies found a local minimum\n",a1/fnorm);
60     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
61   } else {
62     Vec       work;
63     PetscScalar    result;
64     PetscReal wnorm;
65 
66     ierr = VecSetRandom(PETSC_NULL,W);CHKERRQ(ierr);
67     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
68     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
69     ierr = MatMult(A,W,work);CHKERRQ(ierr);
70     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
71     ierr = VecDestroy(work);CHKERRQ(ierr);
72     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
73     PetscLogInfo(0,"SNESSolve_EQ_LS: (F^T J random)/(|| F ||*||random|| %g near zero implies found a local minimum\n",a1);
74     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
75   }
76   PetscFunctionReturn(0);
77 }
78 
79 /*
80      Checks if J^T(F - AX) = 0
81 */
82 #undef __FUNCT__
83 #define __FUNCT__ "SNESLSCheckResidual_Private"
84 int SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2)
85 {
86   PetscReal     a1,a2;
87   int           ierr;
88   PetscTruth    hastranspose;
89   PetscScalar   mone = -1.0;
90 
91   PetscFunctionBegin;
92   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
93   if (hastranspose) {
94     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
95     ierr = VecAXPY(&mone,F,W1);CHKERRQ(ierr);
96 
97     /* Compute || J^T W|| */
98     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
99     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
100     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
101     if (a1 != 0) {
102       PetscLogInfo(0,"SNESSolve_EQ_LS: ||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",a2/a1);
103     }
104   }
105   PetscFunctionReturn(0);
106 }
107 
108 /*  --------------------------------------------------------------------
109 
110      This file implements a truncated Newton method with a line search,
111      for solving a system of nonlinear equations, using the SLES, Vec,
112      and Mat interfaces for linear solvers, vectors, and matrices,
113      respectively.
114 
115      The following basic routines are required for each nonlinear solver:
116           SNESCreate_XXX()          - Creates a nonlinear solver context
117           SNESSetFromOptions_XXX()  - Sets runtime options
118           SNESSolve_XXX()           - Solves the nonlinear system
119           SNESDestroy_XXX()         - Destroys the nonlinear solver context
120      The suffix "_XXX" denotes a particular implementation, in this case
121      we use _EQ_LS (e.g., SNESCreate_EQ_LS, SNESSolve_EQ_LS) for solving
122      systems of nonlinear equations (EQ) with a line search (LS) method.
123      These routines are actually called via the common user interface
124      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
125      SNESDestroy(), so the application code interface remains identical
126      for all nonlinear solvers.
127 
128      Another key routine is:
129           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
130      by setting data structures and options.   The interface routine SNESSetUp()
131      is not usually called directly by the user, but instead is called by
132      SNESSolve() if necessary.
133 
134      Additional basic routines are:
135           SNESView_XXX()            - Prints details of runtime options that
136                                       have actually been used.
137      These are called by application codes via the interface routines
138      SNESView().
139 
140      The various types of solvers (preconditioners, Krylov subspace methods,
141      nonlinear solvers, timesteppers) are all organized similarly, so the
142      above description applies to these categories also.
143 
144     -------------------------------------------------------------------- */
145 /*
146    SNESSolve_EQ_LS - Solves a nonlinear system with a truncated Newton
147    method with a line search.
148 
149    Input Parameters:
150 .  snes - the SNES context
151 
152    Output Parameter:
153 .  outits - number of iterations until termination
154 
155    Application Interface Routine: SNESSolve()
156 
157    Notes:
158    This implements essentially a truncated Newton method with a
159    line search.  By default a cubic backtracking line search
160    is employed, as described in the text "Numerical Methods for
161    Unconstrained Optimization and Nonlinear Equations" by Dennis
162    and Schnabel.
163 */
164 #undef __FUNCT__
165 #define __FUNCT__ "SNESSolve_EQ_LS"
166 int SNESSolve_EQ_LS(SNES snes,int *outits)
167 {
168   SNES_EQ_LS          *neP = (SNES_EQ_LS*)snes->data;
169   int                 maxits,i,ierr,lits,lsfail;
170   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
171   PetscReal           fnorm,gnorm,xnorm,ynorm;
172   Vec                 Y,X,F,G,W,TMP;
173 
174   PetscFunctionBegin;
175   snes->reason  = SNES_CONVERGED_ITERATING;
176 
177   maxits	= snes->max_its;	/* maximum number of iterations */
178   X		= snes->vec_sol;	/* solution vector */
179   F		= snes->vec_func;	/* residual vector */
180   Y		= snes->work[0];	/* work vectors */
181   G		= snes->work[1];
182   W		= snes->work[2];
183 
184   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
185   snes->iter = 0;
186   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
187   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);  /*  F(X)      */
188   ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);	/* fnorm <- ||F||  */
189   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
190   snes->norm = fnorm;
191   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
192   SNESLogConvHistory(snes,fnorm,0);
193   SNESMonitor(snes,0,fnorm);
194 
195   if (fnorm < snes->atol) {*outits = 0; snes->reason = SNES_CONVERGED_FNORM_ABS; PetscFunctionReturn(0);}
196 
197   /* set parameter for default relative tolerance convergence test */
198   snes->ttol = fnorm*snes->rtol;
199 
200   for (i=0; i<maxits; i++) {
201 
202     /* Call general purpose update function */
203     if (snes->update != PETSC_NULL) {
204       ierr = (*snes->update)(snes, snes->iter);CHKERRQ(ierr);
205     }
206 
207     /* Solve J Y = F, where J is Jacobian matrix */
208     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
209     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
210     ierr = SLESSolve(snes->sles,F,Y,&lits);CHKERRQ(ierr);
211 
212     if (PetscLogPrintInfo){
213       ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
214     }
215 
216     /* should check what happened to the linear solve? */
217     snes->linear_its += lits;
218     PetscLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits);
219 
220     /* Compute a (scaled) negative update in the line search routine:
221          Y <- X - lambda*Y
222        and evaluate G(Y) = function(Y))
223     */
224     ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr);
225     ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
226     PetscLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail);
227 
228     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
229     TMP = X; X = Y; snes->vec_sol_always = X;  Y = TMP;
230     fnorm = gnorm;
231 
232     if (lsfail) {
233       PetscTruth ismin;
234 
235       if (++snes->numFailures >= snes->maxFailures) {
236         snes->reason = SNES_DIVERGED_LS_FAILURE;
237         ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr);
238         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
239         break;
240       }
241     }
242 
243     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
244     snes->iter = i+1;
245     snes->norm = fnorm;
246     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
247     SNESLogConvHistory(snes,fnorm,lits);
248     SNESMonitor(snes,i+1,fnorm);
249 
250     /* Test for convergence */
251     if (snes->converged) {
252       ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm = || X || */
253       ierr = (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
254       if (snes->reason) {
255         break;
256       }
257     }
258   }
259   if (X != snes->vec_sol) {
260     ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr);
261   }
262   if (F != snes->vec_func) {
263     ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr);
264   }
265   snes->vec_sol_always  = snes->vec_sol;
266   snes->vec_func_always = snes->vec_func;
267   if (i == maxits) {
268     PetscLogInfo(snes,"SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits);
269     i--;
270     snes->reason = SNES_DIVERGED_MAX_IT;
271   }
272   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
273   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
274   *outits = i+1;
275   PetscFunctionReturn(0);
276 }
277 /* -------------------------------------------------------------------------- */
278 /*
279    SNESSetUp_EQ_LS - Sets up the internal data structures for the later use
280    of the SNESEQLS nonlinear solver.
281 
282    Input Parameter:
283 .  snes - the SNES context
284 .  x - the solution vector
285 
286    Application Interface Routine: SNESSetUp()
287 
288    Notes:
289    For basic use of the SNES solvers the user need not explicitly call
290    SNESSetUp(), since these actions will automatically occur during
291    the call to SNESSolve().
292  */
293 #undef __FUNCT__
294 #define __FUNCT__ "SNESSetUp_EQ_LS"
295 int SNESSetUp_EQ_LS(SNES snes)
296 {
297   int ierr;
298 
299   PetscFunctionBegin;
300   snes->nwork = 4;
301   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr);
302   PetscLogObjectParents(snes,snes->nwork,snes->work);
303   snes->vec_sol_update_always = snes->work[3];
304   PetscFunctionReturn(0);
305 }
306 /* -------------------------------------------------------------------------- */
307 /*
308    SNESDestroy_EQ_LS - Destroys the private SNESEQLS context that was created
309    with SNESCreate_EQ_LS().
310 
311    Input Parameter:
312 .  snes - the SNES context
313 
314    Application Interface Routine: SNESDestroy()
315  */
316 #undef __FUNCT__
317 #define __FUNCT__ "SNESDestroy_EQ_LS"
318 int SNESDestroy_EQ_LS(SNES snes)
319 {
320   int  ierr;
321 
322   PetscFunctionBegin;
323   if (snes->nwork) {
324     ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr);
325   }
326   ierr = PetscFree(snes->data);CHKERRQ(ierr);
327   PetscFunctionReturn(0);
328 }
329 /* -------------------------------------------------------------------------- */
330 #undef __FUNCT__
331 #define __FUNCT__ "SNESNoLineSearch"
332 
333 /*@C
334    SNESNoLineSearch - This routine is not a line search at all;
335    it simply uses the full Newton step.  Thus, this routine is intended
336    to serve as a template and is not recommended for general use.
337 
338    Collective on SNES and Vec
339 
340    Input Parameters:
341 +  snes - nonlinear context
342 .  lsctx - optional context for line search (not used here)
343 .  x - current iterate
344 .  f - residual evaluated at x
345 .  y - search direction (contains new iterate on output)
346 .  w - work vector
347 -  fnorm - 2-norm of f
348 
349    Output Parameters:
350 +  g - residual evaluated at new iterate y
351 .  y - new iterate (contains search direction on input)
352 .  gnorm - 2-norm of g
353 .  ynorm - 2-norm of search length
354 -  flag - set to 0, indicating a successful line search
355 
356    Options Database Key:
357 .  -snes_eq_ls basic - Activates SNESNoLineSearch()
358 
359    Level: advanced
360 
361 .keywords: SNES, nonlinear, line search, cubic
362 
363 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
364           SNESSetLineSearch(), SNESNoLineSearchNoNorms()
365 @*/
366 int SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
367 {
368   int           ierr;
369   PetscScalar   mone = -1.0;
370   SNES_EQ_LS    *neP = (SNES_EQ_LS*)snes->data;
371   PetscTruth    change_y = PETSC_FALSE;
372 
373   PetscFunctionBegin;
374   *flag = 0;
375   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
376   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);  /* ynorm = || y || */
377   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
378   if (neP->CheckStep) {
379    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
380   }
381   ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
382   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
383   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
384   PetscFunctionReturn(0);
385 }
386 /* -------------------------------------------------------------------------- */
387 #undef __FUNCT__
388 #define __FUNCT__ "SNESNoLineSearchNoNorms"
389 
390 /*@C
391    SNESNoLineSearchNoNorms - This routine is not a line search at
392    all; it simply uses the full Newton step. This version does not
393    even compute the norm of the function or search direction; this
394    is intended only when you know the full step is fine and are
395    not checking for convergence of the nonlinear iteration (for
396    example, you are running always for a fixed number of Newton steps).
397 
398    Collective on SNES and Vec
399 
400    Input Parameters:
401 +  snes - nonlinear context
402 .  lsctx - optional context for line search (not used here)
403 .  x - current iterate
404 .  f - residual evaluated at x
405 .  y - search direction (contains new iterate on output)
406 .  w - work vector
407 -  fnorm - 2-norm of f
408 
409    Output Parameters:
410 +  g - residual evaluated at new iterate y
411 .  gnorm - not changed
412 .  ynorm - not changed
413 -  flag - set to 0, indicating a successful line search
414 
415    Options Database Key:
416 .  -snes_eq_ls basicnonorms - Activates SNESNoLineSearchNoNorms()
417 
418    Notes:
419    SNESNoLineSearchNoNorms() must be used in conjunction with
420    either the options
421 $     -snes_no_convergence_test -snes_max_it <its>
422    or alternatively a user-defined custom test set via
423    SNESSetConvergenceTest(); or a -snes_max_it of 1,
424    otherwise, the SNES solver will generate an error.
425 
426    During the final iteration this will not evaluate the function at
427    the solution point. This is to save a function evaluation while
428    using pseudo-timestepping.
429 
430    The residual norms printed by monitoring routines such as
431    SNESDefaultMonitor() (as activated via -snes_monitor) will not be
432    correct, since they are not computed.
433 
434    Level: advanced
435 
436 .keywords: SNES, nonlinear, line search, cubic
437 
438 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
439           SNESSetLineSearch(), SNESNoLineSearch()
440 @*/
441 int SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
442 {
443   int           ierr;
444   PetscScalar   mone = -1.0;
445   SNES_EQ_LS    *neP = (SNES_EQ_LS*)snes->data;
446   PetscTruth    change_y = PETSC_FALSE;
447 
448   PetscFunctionBegin;
449   *flag = 0;
450   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
451   ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr);            /* y <- y - x      */
452   if (neP->CheckStep) {
453    ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
454   }
455 
456   /* don't evaluate function the last time through */
457   if (snes->iter < snes->max_its-1) {
458     ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y)    */
459   }
460   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
461   PetscFunctionReturn(0);
462 }
463 /* -------------------------------------------------------------------------- */
464 #undef __FUNCT__
465 #define __FUNCT__ "SNESCubicLineSearch"
466 /*@C
467    SNESCubicLineSearch - Performs a cubic line search (default line search method).
468 
469    Collective on SNES
470 
471    Input Parameters:
472 +  snes - nonlinear context
473 .  lsctx - optional context for line search (not used here)
474 .  x - current iterate
475 .  f - residual evaluated at x
476 .  y - search direction (contains new iterate on output)
477 .  w - work vector
478 -  fnorm - 2-norm of f
479 
480    Output Parameters:
481 +  g - residual evaluated at new iterate y
482 .  y - new iterate (contains search direction on input)
483 .  gnorm - 2-norm of g
484 .  ynorm - 2-norm of search length
485 -  flag - 0 if line search succeeds; -1 on failure.
486 
487    Options Database Key:
488 $  -snes_eq_ls cubic - Activates SNESCubicLineSearch()
489 
490    Notes:
491    This line search is taken from "Numerical Methods for Unconstrained
492    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
493 
494    Level: advanced
495 
496 .keywords: SNES, nonlinear, line search, cubic
497 
498 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
499 @*/
500 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
501 {
502   /*
503      Note that for line search purposes we work with with the related
504      minimization problem:
505         min  z(x):  R^n -> R,
506      where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2.
507    */
508 
509   PetscReal     steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
510   PetscReal     maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg;
511 #if defined(PETSC_USE_COMPLEX)
512   PetscScalar   cinitslope,clambda;
513 #endif
514   int           ierr,count;
515   SNES_EQ_LS    *neP = (SNES_EQ_LS*)snes->data;
516   PetscScalar   mone = -1.0,scale;
517   PetscTruth    change_y = PETSC_FALSE;
518 
519   PetscFunctionBegin;
520   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
521   *flag   = 0;
522   alpha   = neP->alpha;
523   maxstep = neP->maxstep;
524   steptol = neP->steptol;
525 
526   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
527   if (*ynorm < snes->atol) {
528     PetscLogInfo(snes,"SNESCubicLineSearch: Search direction and size are nearly 0\n");
529     *gnorm = fnorm;
530     ierr = VecCopy(x,y);CHKERRQ(ierr);
531     ierr = VecCopy(f,g);CHKERRQ(ierr);
532     goto theend1;
533   }
534   if (*ynorm > maxstep) {	/* Step too big, so scale back */
535     scale = maxstep/(*ynorm);
536 #if defined(PETSC_USE_COMPLEX)
537     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm);
538 #else
539     PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",scale,*ynorm);
540 #endif
541     ierr = VecScale(&scale,y);CHKERRQ(ierr);
542     *ynorm = maxstep;
543   }
544   ierr      = VecMaxScale_SNES(y,x,&rellength);CHKERRQ(ierr);
545   minlambda = steptol/rellength;
546   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
547 #if defined(PETSC_USE_COMPLEX)
548   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
549   initslope = PetscRealPart(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 (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
561     ierr = VecCopy(w,y);CHKERRQ(ierr);
562     PetscLogInfo(snes,"SNESCubicLineSearch: Using full step\n");
563     goto theend1;
564   }
565 
566   /* Fit points with quadratic */
567   lambda = 1.0;
568   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
569   lambdaprev = lambda;
570   gnormprev = *gnorm;
571   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
572   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
573   else                         lambda = lambdatemp;
574   ierr   = VecCopy(x,w);CHKERRQ(ierr);
575   lambdaneg = -lambda;
576 #if defined(PETSC_USE_COMPLEX)
577   clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
578 #else
579   ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
580 #endif
581   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
582   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
583   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
584     ierr = VecCopy(w,y);CHKERRQ(ierr);
585     PetscLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda);
586     goto theend1;
587   }
588 
589   /* Fit points with cubic */
590   count = 1;
591   while (PETSC_TRUE) {
592     if (lambda <= minlambda) { /* bad luck; use full step */
593       PetscLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count);
594       PetscLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
595       ierr = VecCopy(x,y);CHKERRQ(ierr);
596       *flag = -1; break;
597     }
598     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
599     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
600     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
601     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
602     d  = b*b - 3*a*initslope;
603     if (d < 0.0) d = 0.0;
604     if (a == 0.0) {
605       lambdatemp = -initslope/(2.0*b);
606     } else {
607       lambdatemp = (-b + sqrt(d))/(3.0*a);
608     }
609     lambdaprev = lambda;
610     gnormprev  = *gnorm;
611     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
612     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
613     else                         lambda     = lambdatemp;
614     ierr = VecCopy(x,w);CHKERRQ(ierr);
615     lambdaneg = -lambda;
616 #if defined(PETSC_USE_COMPLEX)
617     clambda = lambdaneg;
618     ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
619 #else
620     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
621 #endif
622     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
623     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
624     if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */
625       ierr = VecCopy(w,y);CHKERRQ(ierr);
626       PetscLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda);
627       goto theend1;
628     } else {
629       PetscLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda,  lambda=%g\n",lambda);
630     }
631     count++;
632   }
633   theend1:
634   /* Optional user-defined check for line search step validity */
635   if (neP->CheckStep) {
636     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
637     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
638       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
639       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
640       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
641       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
642       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
643     }
644   }
645   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
646   PetscFunctionReturn(0);
647 }
648 /* -------------------------------------------------------------------------- */
649 #undef __FUNCT__
650 #define __FUNCT__ "SNESQuadraticLineSearch"
651 /*@C
652    SNESQuadraticLineSearch - Performs a quadratic line search.
653 
654    Collective on SNES and Vec
655 
656    Input Parameters:
657 +  snes - the SNES context
658 .  lsctx - optional context for line search (not used here)
659 .  x - current iterate
660 .  f - residual evaluated at x
661 .  y - search direction (contains new iterate on output)
662 .  w - work vector
663 -  fnorm - 2-norm of f
664 
665    Output Parameters:
666 +  g - residual evaluated at new iterate y
667 .  y - new iterate (contains search direction on input)
668 .  gnorm - 2-norm of g
669 .  ynorm - 2-norm of search length
670 -  flag - 0 if line search succeeds; -1 on failure.
671 
672    Options Database Key:
673 .  -snes_eq_ls quadratic - Activates SNESQuadraticLineSearch()
674 
675    Notes:
676    Use SNESSetLineSearch() to set this routine within the SNESEQLS method.
677 
678    Level: advanced
679 
680 .keywords: SNES, nonlinear, quadratic, line search
681 
682 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms()
683 @*/
684 int SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag)
685 {
686   /*
687      Note that for line search purposes we work with with the related
688      minimization problem:
689         min  z(x):  R^n -> R,
690      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
691    */
692   PetscReal  steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength;
693 #if defined(PETSC_USE_COMPLEX)
694   PetscScalar    cinitslope,clambda;
695 #endif
696   int        ierr,count;
697   SNES_EQ_LS     *neP = (SNES_EQ_LS*)snes->data;
698   PetscScalar    mone = -1.0,scale;
699   PetscTruth     change_y = PETSC_FALSE;
700 
701   PetscFunctionBegin;
702   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
703   *flag   = 0;
704   alpha   = neP->alpha;
705   maxstep = neP->maxstep;
706   steptol = neP->steptol;
707 
708   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
709   if (*ynorm < snes->atol) {
710     PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n");
711     *gnorm = fnorm;
712     ierr = VecCopy(x,y);CHKERRQ(ierr);
713     ierr = VecCopy(f,g);CHKERRQ(ierr);
714     goto theend2;
715   }
716   if (*ynorm > maxstep) {	/* Step too big, so scale back */
717     scale = maxstep/(*ynorm);
718     ierr = VecScale(&scale,y);CHKERRQ(ierr);
719     *ynorm = maxstep;
720   }
721   ierr      = VecMaxScale_SNES(y,x,&rellength);CHKERRQ(ierr);
722   minlambda = steptol/rellength;
723   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
724 #if defined(PETSC_USE_COMPLEX)
725   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
726   initslope = PetscRealPart(cinitslope);
727 #else
728   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
729 #endif
730   if (initslope > 0.0) initslope = -initslope;
731   if (initslope == 0.0) initslope = -1.0;
732 
733   ierr = VecCopy(y,w);CHKERRQ(ierr);
734   ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr);
735   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
736   ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
737   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */
738     ierr = VecCopy(w,y);CHKERRQ(ierr);
739     PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n");
740     goto theend2;
741   }
742 
743   /* Fit points with quadratic */
744   lambda = 1.0;
745   count = 1;
746   while (PETSC_TRUE) {
747     if (lambda <= minlambda) { /* bad luck; use full step */
748       PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
749       PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
750       ierr = VecCopy(x,y);CHKERRQ(ierr);
751       *flag = -1; break;
752     }
753     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
754     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
755     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
756     else                         lambda     = lambdatemp;
757     ierr = VecCopy(x,w);CHKERRQ(ierr);
758     lambdaneg = -lambda;
759 #if defined(PETSC_USE_COMPLEX)
760     clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr);
761 #else
762     ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr);
763 #endif
764     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
765     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
766     if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */
767       ierr = VecCopy(w,y);CHKERRQ(ierr);
768       PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda);
769       break;
770     }
771     count++;
772   }
773   theend2:
774   /* Optional user-defined check for line search step validity */
775   if (neP->CheckStep) {
776     ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr);
777     if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */
778       ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr);
779       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
780       ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr);
781       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
782       ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr);
783     }
784   }
785   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
786   PetscFunctionReturn(0);
787 }
788 /* -------------------------------------------------------------------------- */
789 #undef __FUNCT__
790 #define __FUNCT__ "SNESSetLineSearch"
791 /*@C
792    SNESSetLineSearch - Sets the line search routine to be used
793    by the method SNESEQLS.
794 
795    Input Parameters:
796 +  snes - nonlinear context obtained from SNESCreate()
797 .  lsctx - optional user-defined context for use by line search
798 -  func - pointer to int function
799 
800    Collective on SNES
801 
802    Available Routines:
803 +  SNESCubicLineSearch() - default line search
804 .  SNESQuadraticLineSearch() - quadratic line search
805 .  SNESNoLineSearch() - the full Newton step (actually not a line search)
806 -  SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel)
807 
808     Options Database Keys:
809 +   -snes_eq_ls [cubic,quadratic,basic,basicnonorms] - Selects line search
810 .   -snes_eq_ls_alpha <alpha> - Sets alpha
811 .   -snes_eq_ls_maxstep <max> - Sets maxstep
812 -   -snes_eq_ls_steptol <steptol> - Sets steptol
813 
814    Calling sequence of func:
815 .vb
816    func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,
817          PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,*flag)
818 .ve
819 
820     Input parameters for func:
821 +   snes - nonlinear context
822 .   lsctx - optional user-defined context for line search
823 .   x - current iterate
824 .   f - residual evaluated at x
825 .   y - search direction (contains new iterate on output)
826 .   w - work vector
827 -   fnorm - 2-norm of f
828 
829     Output parameters for func:
830 +   g - residual evaluated at new iterate y
831 .   y - new iterate (contains search direction on input)
832 .   gnorm - 2-norm of g
833 .   ynorm - 2-norm of search length
834 -   flag - set to 0 if the line search succeeds; a nonzero integer
835            on failure.
836 
837     Level: advanced
838 
839 .keywords: SNES, nonlinear, set, line search, routine
840 
841 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms(),
842           SNESSetLineSearchCheck(), SNESSetLineSearchParams(), SNESGetLineSearchParams()
843 @*/
844 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void *lsctx)
845 {
846   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void*);
847 
848   PetscFunctionBegin;
849   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void (**)(void))&f);CHKERRQ(ierr);
850   if (f) {
851     ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr);
852   }
853   PetscFunctionReturn(0);
854 }
855 /* -------------------------------------------------------------------------- */
856 EXTERN_C_BEGIN
857 #undef __FUNCT__
858 #define __FUNCT__ "SNESSetLineSearch_LS"
859 int SNESSetLineSearch_LS(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,
860                          PetscReal,PetscReal*,PetscReal*,int*),void *lsctx)
861 {
862   PetscFunctionBegin;
863   ((SNES_EQ_LS *)(snes->data))->LineSearch = func;
864   ((SNES_EQ_LS *)(snes->data))->lsP        = lsctx;
865   PetscFunctionReturn(0);
866 }
867 EXTERN_C_END
868 /* -------------------------------------------------------------------------- */
869 #undef __FUNCT__
870 #define __FUNCT__ "SNESSetLineSearchCheck"
871 /*@C
872    SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed
873    by the line search routine in the Newton-based method SNESEQLS.
874 
875    Input Parameters:
876 +  snes - nonlinear context obtained from SNESCreate()
877 .  func - pointer to int function
878 -  checkctx - optional user-defined context for use by step checking routine
879 
880    Collective on SNES
881 
882    Calling sequence of func:
883 .vb
884    int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag)
885 .ve
886    where func returns an error code of 0 on success and a nonzero
887    on failure.
888 
889    Input parameters for func:
890 +  snes - nonlinear context
891 .  checkctx - optional user-defined context for use by step checking routine
892 -  x - current candidate iterate
893 
894    Output parameters for func:
895 +  x - current iterate (possibly modified)
896 -  flag - flag indicating whether x has been modified (either
897            PETSC_TRUE of PETSC_FALSE)
898 
899    Level: advanced
900 
901    Notes:
902    SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new
903    iterate computed by the line search checking routine.  In particular,
904    these routines (1) compute a candidate iterate u_{i+1}, (2) pass control
905    to the checking routine, and then (3) compute the corresponding nonlinear
906    function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}.
907 
908    SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the
909    new iterate computed by the line search checking routine.  In particular,
910    these routines (1) compute a candidate iterate u_{i+1} as well as a
911    candidate nonlinear function f(u_{i+1}), (2) pass control to the checking
912    routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes
913    were made to the candidate iterate in the checking routine (as indicated
914    by flag=PETSC_TRUE).  The overhead of this function re-evaluation can be
915    very costly, so use this feature with caution!
916 
917 .keywords: SNES, nonlinear, set, line search check, step check, routine
918 
919 .seealso: SNESSetLineSearch()
920 @*/
921 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx)
922 {
923   int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,PetscTruth*),void*);
924 
925   PetscFunctionBegin;
926   ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr);
927   if (f) {
928     ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr);
929   }
930   PetscFunctionReturn(0);
931 }
932 /* -------------------------------------------------------------------------- */
933 EXTERN_C_BEGIN
934 #undef __FUNCT__
935 #define __FUNCT__ "SNESSetLineSearchCheck_LS"
936 int SNESSetLineSearchCheck_LS(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx)
937 {
938   PetscFunctionBegin;
939   ((SNES_EQ_LS *)(snes->data))->CheckStep = func;
940   ((SNES_EQ_LS *)(snes->data))->checkP    = checkctx;
941   PetscFunctionReturn(0);
942 }
943 EXTERN_C_END
944 /* -------------------------------------------------------------------------- */
945 /*
946    SNESPrintHelp_EQ_LS - Prints all options for the SNES_EQ_LS method.
947 
948    Input Parameter:
949 .  snes - the SNES context
950 
951    Application Interface Routine: SNESPrintHelp()
952 */
953 #undef __FUNCT__
954 #define __FUNCT__ "SNESPrintHelp_EQ_LS"
955 static int SNESPrintHelp_EQ_LS(SNES snes,char *p)
956 {
957   SNES_EQ_LS *ls = (SNES_EQ_LS *)snes->data;
958 
959   PetscFunctionBegin;
960   (*PetscHelpPrintf)(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n");
961   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls [cubic,quadratic,basic,basicnonorms,...]\n",p);
962   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha);
963   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep);
964   (*PetscHelpPrintf)(snes->comm,"   %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol);
965   PetscFunctionReturn(0);
966 }
967 
968 /*
969    SNESView_EQ_LS - Prints info from the SNESEQLS data structure.
970 
971    Input Parameters:
972 .  SNES - the SNES context
973 .  viewer - visualization context
974 
975    Application Interface Routine: SNESView()
976 */
977 #undef __FUNCT__
978 #define __FUNCT__ "SNESView_EQ_LS"
979 static int SNESView_EQ_LS(SNES snes,PetscViewer viewer)
980 {
981   SNES_EQ_LS *ls = (SNES_EQ_LS *)snes->data;
982   char       *cstr;
983   int        ierr;
984   PetscTruth isascii;
985 
986   PetscFunctionBegin;
987   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
988   if (isascii) {
989     if (ls->LineSearch == SNESNoLineSearch)             cstr = "SNESNoLineSearch";
990     else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch";
991     else if (ls->LineSearch == SNESCubicLineSearch)     cstr = "SNESCubicLineSearch";
992     else                                                cstr = "unknown";
993     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
994     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr);
995   } else {
996     SETERRQ1(1,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name);
997   }
998   PetscFunctionReturn(0);
999 }
1000 /* -------------------------------------------------------------------------- */
1001 /*
1002    SNESSetFromOptions_EQ_LS - Sets various parameters for the SNESEQLS method.
1003 
1004    Input Parameter:
1005 .  snes - the SNES context
1006 
1007    Application Interface Routine: SNESSetFromOptions()
1008 */
1009 #undef __FUNCT__
1010 #define __FUNCT__ "SNESSetFromOptions_EQ_LS"
1011 static int SNESSetFromOptions_EQ_LS(SNES snes)
1012 {
1013   SNES_EQ_LS *ls = (SNES_EQ_LS *)snes->data;
1014   char       ver[16],*lses[] = {"basic","basicnonorms","quadratic","cubic"};
1015   int        ierr;
1016   PetscTruth flg;
1017 
1018   PetscFunctionBegin;
1019   ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr);
1020     ierr = PetscOptionsReal("-snes_eq_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr);
1021     ierr = PetscOptionsReal("-snes_eq_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr);
1022     ierr = PetscOptionsReal("-snes_eq_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr);
1023 
1024     ierr = PetscOptionsEList("-snes_eq_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",ver,16,&flg);CHKERRQ(ierr);
1025     if (flg) {
1026       PetscTruth isbasic,isnonorms,isquad,iscubic;
1027 
1028       ierr = PetscStrcmp(ver,lses[0],&isbasic);CHKERRQ(ierr);
1029       ierr = PetscStrcmp(ver,lses[1],&isnonorms);CHKERRQ(ierr);
1030       ierr = PetscStrcmp(ver,lses[2],&isquad);CHKERRQ(ierr);
1031       ierr = PetscStrcmp(ver,lses[3],&iscubic);CHKERRQ(ierr);
1032 
1033       if (isbasic) {
1034         ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr);
1035       } else if (isnonorms) {
1036         ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
1037       } else if (isquad) {
1038         ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr);
1039       } else if (iscubic) {
1040         ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr);
1041       }
1042       else {SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown line search");}
1043     }
1044   ierr = PetscOptionsTail();CHKERRQ(ierr);
1045   PetscFunctionReturn(0);
1046 }
1047 /* -------------------------------------------------------------------------- */
1048 /*
1049    SNESCreate_EQ_LS - Creates a nonlinear solver context for the SNESEQLS method,
1050    SNES_EQ_LS, and sets this as the private data within the generic nonlinear solver
1051    context, SNES, that was created within SNESCreate().
1052 
1053 
1054    Input Parameter:
1055 .  snes - the SNES context
1056 
1057    Application Interface Routine: SNESCreate()
1058  */
1059 EXTERN_C_BEGIN
1060 #undef __FUNCT__
1061 #define __FUNCT__ "SNESCreate_EQ_LS"
1062 int SNESCreate_EQ_LS(SNES snes)
1063 {
1064   int        ierr;
1065   SNES_EQ_LS *neP;
1066 
1067   PetscFunctionBegin;
1068   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
1069     SETERRQ(PETSC_ERR_ARG_WRONG,"For SNES_NONLINEAR_EQUATIONS only");
1070   }
1071 
1072   snes->setup		= SNESSetUp_EQ_LS;
1073   snes->solve		= SNESSolve_EQ_LS;
1074   snes->destroy		= SNESDestroy_EQ_LS;
1075   snes->converged	= SNESConverged_EQ_LS;
1076   snes->printhelp       = SNESPrintHelp_EQ_LS;
1077   snes->setfromoptions  = SNESSetFromOptions_EQ_LS;
1078   snes->view            = SNESView_EQ_LS;
1079   snes->nwork           = 0;
1080 
1081   ierr                  = PetscNew(SNES_EQ_LS,&neP);CHKERRQ(ierr);
1082   PetscLogObjectMemory(snes,sizeof(SNES_EQ_LS));
1083   snes->data    	= (void*)neP;
1084   neP->alpha		= 1.e-4;
1085   neP->maxstep		= 1.e8;
1086   neP->steptol		= 1.e-12;
1087   neP->LineSearch       = SNESCubicLineSearch;
1088   neP->lsP              = PETSC_NULL;
1089   neP->CheckStep        = PETSC_NULL;
1090   neP->checkP           = PETSC_NULL;
1091 
1092   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr);
1093   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr);
1094 
1095   PetscFunctionReturn(0);
1096 }
1097 EXTERN_C_END
1098 
1099 
1100 
1101