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