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