xref: /petsc/src/snes/linesearch/interface/linesearch.c (revision 127bc8d3d29cc09d2f35f7aa3a4719963c4db172)
1 #include <petsc/private/linesearchimpl.h> /*I "petscsnes.h" I*/
2 
3 PetscBool         SNESLineSearchRegisterAllCalled = PETSC_FALSE;
4 PetscFunctionList SNESLineSearchList              = NULL;
5 
6 PetscClassId  SNESLINESEARCH_CLASSID;
7 PetscLogEvent SNESLINESEARCH_Apply;
8 
9 /*@
10    SNESLineSearchMonitorCancel - Clears all the monitor functions for a `SNESLineSearch` object.
11 
12    Logically Collective on ls
13 
14    Input Parameters:
15 .  ls - the `SNESLineSearch` context
16 
17    Options Database Key:
18 .  -snes_linesearch_monitor_cancel - cancels all monitors that have been hardwired
19     into a code by calls to `SNESLineSearchMonitorSet()`, but does not cancel those
20     set via the options database
21 
22    Notes:
23    There is no way to clear one specific monitor from a `SNESLineSearch` object.
24 
25    This does not clear the monitor set with `SNESLineSearchSetDefaultMonitor()` use `SNESLineSearchSetDefaultMonitor`(ls,NULL) to cancel
26    that one.
27 
28    Level: advanced
29 
30 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorSet()`
31 @*/
32 PetscErrorCode SNESLineSearchMonitorCancel(SNESLineSearch ls) {
33   PetscInt i;
34 
35   PetscFunctionBegin;
36   PetscValidHeaderSpecific(ls, SNESLINESEARCH_CLASSID, 1);
37   for (i = 0; i < ls->numbermonitors; i++) {
38     if (ls->monitordestroy[i]) PetscCall((*ls->monitordestroy[i])(&ls->monitorcontext[i]));
39   }
40   ls->numbermonitors = 0;
41   PetscFunctionReturn(0);
42 }
43 
44 /*@
45    SNESLineSearchMonitor - runs the user provided monitor routines, if they exist
46 
47    Collective on ls
48 
49    Input Parameters:
50 .  ls - the linesearch object
51 
52    Note:
53    This routine is called by the SNES implementations.
54    It does not typically need to be called by the user.
55 
56    Level: developer
57 
58 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorSet()`
59 @*/
60 PetscErrorCode SNESLineSearchMonitor(SNESLineSearch ls) {
61   PetscInt i, n = ls->numbermonitors;
62 
63   PetscFunctionBegin;
64   for (i = 0; i < n; i++) PetscCall((*ls->monitorftns[i])(ls, ls->monitorcontext[i]));
65   PetscFunctionReturn(0);
66 }
67 
68 /*@C
69    SNESLineSearchMonitorSet - Sets an ADDITIONAL function that is to be used at every
70    iteration of the nonlinear solver to display the iteration's
71    progress.
72 
73    Logically Collective on ls
74 
75    Input Parameters:
76 +  ls - the `SNESLineSearch` context
77 .  f - the monitor function
78 .  mctx - [optional] user-defined context for private data for the
79           monitor routine (use NULL if no context is desired)
80 -  monitordestroy - [optional] routine that frees monitor context
81           (may be NULL)
82 
83    Note:
84    Several different monitoring routines may be set by calling
85    `SNESLineSearchMonitorSet()` multiple times; all will be called in the
86    order in which they were set.
87 
88    Fortran Note:
89    Only a single monitor function can be set for each `SNESLineSearch` object
90 
91    Level: intermediate
92 
93 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorCancel()`
94 @*/
95 PetscErrorCode SNESLineSearchMonitorSet(SNESLineSearch ls, PetscErrorCode (*f)(SNESLineSearch, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) {
96   PetscInt  i;
97   PetscBool identical;
98 
99   PetscFunctionBegin;
100   PetscValidHeaderSpecific(ls, SNESLINESEARCH_CLASSID, 1);
101   for (i = 0; i < ls->numbermonitors; i++) {
102     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))ls->monitorftns[i], ls->monitorcontext[i], ls->monitordestroy[i], &identical));
103     if (identical) PetscFunctionReturn(0);
104   }
105   PetscCheck(ls->numbermonitors < MAXSNESLSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
106   ls->monitorftns[ls->numbermonitors]      = f;
107   ls->monitordestroy[ls->numbermonitors]   = monitordestroy;
108   ls->monitorcontext[ls->numbermonitors++] = (void *)mctx;
109   PetscFunctionReturn(0);
110 }
111 
112 /*@C
113    SNESLineSearchMonitorSolutionUpdate - Monitors each update of the function value the linesearch tries
114 
115    Collective on ls
116 
117    Input Parameters:
118 +  ls - the `SNES` linesearch object
119 -  vf - the context for the monitor, in this case it is an `PetscViewerAndFormat`
120 
121    Level: intermediate
122 
123 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESMonitorSet()`, `SNESMonitorSolution()`
124 @*/
125 PetscErrorCode SNESLineSearchMonitorSolutionUpdate(SNESLineSearch ls, PetscViewerAndFormat *vf) {
126   PetscViewer viewer = vf->viewer;
127   Vec         Y, W, G;
128 
129   PetscFunctionBegin;
130   PetscCall(SNESLineSearchGetVecs(ls, NULL, NULL, &Y, &W, &G));
131   PetscCall(PetscViewerPushFormat(viewer, vf->format));
132   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted update to solution \n"));
133   PetscCall(VecView(Y, viewer));
134   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted new solution \n"));
135   PetscCall(VecView(W, viewer));
136   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted updated function value\n"));
137   PetscCall(VecView(G, viewer));
138   PetscCall(PetscViewerPopFormat(viewer));
139   PetscFunctionReturn(0);
140 }
141 
142 /*@
143    SNESLineSearchCreate - Creates the line search context.
144 
145    Logically Collective
146 
147    Input Parameters:
148 .  comm - MPI communicator for the line search (typically from the associated `SNES` context).
149 
150    Output Parameters:
151 .  outlinesearch - the new linesearch context
152 
153    Level: developer
154 
155    Note:
156    The preferred calling sequence for users is to use `SNESGetLineSearch()` to acquire the `SNESLineSearch` instance
157    already associated with the `SNES`.
158 
159 .seealso: `SNESLineSearch`, `LineSearchDestroy()`, `SNESGetLineSearch()`
160 @*/
161 PetscErrorCode SNESLineSearchCreate(MPI_Comm comm, SNESLineSearch *outlinesearch) {
162   SNESLineSearch linesearch;
163 
164   PetscFunctionBegin;
165   PetscValidPointer(outlinesearch, 2);
166   PetscCall(SNESInitializePackage());
167   *outlinesearch = NULL;
168 
169   PetscCall(PetscHeaderCreate(linesearch, SNESLINESEARCH_CLASSID, "SNESLineSearch", "Linesearch", "SNESLineSearch", comm, SNESLineSearchDestroy, SNESLineSearchView));
170 
171   linesearch->vec_sol_new  = NULL;
172   linesearch->vec_func_new = NULL;
173   linesearch->vec_sol      = NULL;
174   linesearch->vec_func     = NULL;
175   linesearch->vec_update   = NULL;
176 
177   linesearch->lambda       = 1.0;
178   linesearch->fnorm        = 1.0;
179   linesearch->ynorm        = 1.0;
180   linesearch->xnorm        = 1.0;
181   linesearch->result       = SNES_LINESEARCH_SUCCEEDED;
182   linesearch->norms        = PETSC_TRUE;
183   linesearch->keeplambda   = PETSC_FALSE;
184   linesearch->damping      = 1.0;
185   linesearch->maxstep      = 1e8;
186   linesearch->steptol      = 1e-12;
187   linesearch->rtol         = 1e-8;
188   linesearch->atol         = 1e-15;
189   linesearch->ltol         = 1e-8;
190   linesearch->precheckctx  = NULL;
191   linesearch->postcheckctx = NULL;
192   linesearch->max_its      = 1;
193   linesearch->setupcalled  = PETSC_FALSE;
194   linesearch->monitor      = NULL;
195   *outlinesearch           = linesearch;
196   PetscFunctionReturn(0);
197 }
198 
199 /*@
200    SNESLineSearchSetUp - Prepares the line search for being applied by allocating
201    any required vectors.
202 
203    Collective on linesearch
204 
205    Input Parameters:
206 .  linesearch - The `SNESLineSearch` instance.
207 
208    Note:
209    For most cases, this needn't be called by users or outside of `SNESLineSearchApply()`.
210    The only current case where this is called outside of this is for the VI
211    solvers, which modify the solution and work vectors before the first call
212    of `SNESLineSearchApply()`, requiring the `SNESLineSearch` work vectors to be
213    allocated upfront.
214 
215    Level: advanced
216 
217 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchReset()`
218 @*/
219 
220 PetscErrorCode SNESLineSearchSetUp(SNESLineSearch linesearch) {
221   PetscFunctionBegin;
222   if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
223   if (!linesearch->setupcalled) {
224     if (!linesearch->vec_sol_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_sol_new));
225     if (!linesearch->vec_func_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_func_new));
226     if (linesearch->ops->setup) PetscUseTypeMethod(linesearch, setup);
227     if (!linesearch->ops->snesfunc) PetscCall(SNESLineSearchSetFunction(linesearch, SNESComputeFunction));
228     linesearch->lambda      = linesearch->damping;
229     linesearch->setupcalled = PETSC_TRUE;
230   }
231   PetscFunctionReturn(0);
232 }
233 
234 /*@
235    SNESLineSearchReset - Undoes the `SNESLineSearchSetUp()` and deletes any `Vec`s or `Mat`s allocated by the line search.
236 
237    Collective on linesearch
238 
239    Input Parameters:
240 .  linesearch - The `SNESLineSearch` instance.
241 
242    Note:
243     Usually only called by `SNESReset()`
244 
245    Level: developer
246 
247 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetUp()`
248 @*/
249 
250 PetscErrorCode SNESLineSearchReset(SNESLineSearch linesearch) {
251   PetscFunctionBegin;
252   if (linesearch->ops->reset) PetscUseTypeMethod(linesearch, reset);
253 
254   PetscCall(VecDestroy(&linesearch->vec_sol_new));
255   PetscCall(VecDestroy(&linesearch->vec_func_new));
256 
257   PetscCall(VecDestroyVecs(linesearch->nwork, &linesearch->work));
258 
259   linesearch->nwork       = 0;
260   linesearch->setupcalled = PETSC_FALSE;
261   PetscFunctionReturn(0);
262 }
263 
264 /*@C
265    SNESLineSearchSetFunction - Sets the function evaluation used by the `SNES` line search
266 `
267    Input Parameters:
268 .  linesearch - the `SNESLineSearch` context
269 +  func       - function evaluation routine, this is usually the function provided with `SNESSetFunction()`
270 
271    Level: developer
272 
273 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESSetFunction()`
274 @*/
275 PetscErrorCode SNESLineSearchSetFunction(SNESLineSearch linesearch, PetscErrorCode (*func)(SNES, Vec, Vec)) {
276   PetscFunctionBegin;
277   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
278   linesearch->ops->snesfunc = func;
279   PetscFunctionReturn(0);
280 }
281 
282 /*@C
283    SNESLineSearchSetPreCheck - Sets a user function that is called after the initial search direction has been computed but
284          before the line search routine has been applied. Allows the user to adjust the result of (usually a linear solve) that
285          determined the search direction.
286 
287    Logically Collective on linesearch
288 
289    Input Parameters:
290 +  linesearch - the `SNESLineSearch` context
291 .  func - [optional] function evaluation routine, see `SNESLineSearchPreCheck()` for the calling sequence
292 -  ctx        - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
293 
294    Level: intermediate
295 
296    Note:
297    Use `SNESLineSearchSetPostCheck()` to change the step after the line search.
298    search is complete.
299 
300    Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
301 
302 .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
303           `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()
304 
305 @*/
306 PetscErrorCode SNESLineSearchSetPreCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void *ctx) {
307   PetscFunctionBegin;
308   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
309   if (func) linesearch->ops->precheck = func;
310   if (ctx) linesearch->precheckctx = ctx;
311   PetscFunctionReturn(0);
312 }
313 
314 /*@C
315    SNESLineSearchGetPreCheck - Gets the pre-check function for the line search routine.
316 
317    Input Parameter:
318 .  linesearch - the `SNESLineSearch` context
319 
320    Output Parameters:
321 +  func       - [optional] function evaluation routine, see `SNESLineSearchPreCheck` for calling sequence
322 -  ctx        - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
323 
324    Level: intermediate
325 
326 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
327 @*/
328 PetscErrorCode SNESLineSearchGetPreCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void **ctx) {
329   PetscFunctionBegin;
330   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
331   if (func) *func = linesearch->ops->precheck;
332   if (ctx) *ctx = linesearch->precheckctx;
333   PetscFunctionReturn(0);
334 }
335 
336 /*@C
337    SNESLineSearchSetPostCheck - Sets a user function that is called after the line search has been applied to determine the step
338        direction and length. Allows the user a chance to change or override the decision of the line search routine
339 
340    Logically Collective linesearch
341 
342    Input Parameters:
343 +  linesearch - the `SNESLineSearch` context
344 .  func - [optional] function evaluation routine, see `SNESLineSearchPostCheck`  for the calling sequence
345 -  ctx        - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
346 
347    Level: intermediate
348 
349    Notes:
350    Use `SNESLineSearchSetPreCheck()` to change the step before the line search.
351    search is complete.
352 
353    Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.
354 
355 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchGetPostCheck()`,
356           `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()
357 @*/
358 PetscErrorCode SNESLineSearchSetPostCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void *ctx) {
359   PetscFunctionBegin;
360   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
361   if (func) linesearch->ops->postcheck = func;
362   if (ctx) linesearch->postcheckctx = ctx;
363   PetscFunctionReturn(0);
364 }
365 
366 /*@C
367    SNESLineSearchGetPostCheck - Gets the post-check function for the line search routine.
368 
369    Input Parameter:
370 .  linesearch - the `SNESLineSearch` context
371 
372    Output Parameters:
373 +  func - [optional] function evaluation routine, see for the calling sequence `SNESLineSearchPostCheck`
374 -  ctx        - [optional] user-defined context for private data for the function evaluation routine (may be NULL)
375 
376    Level: intermediate
377 
378 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`
379 @*/
380 PetscErrorCode SNESLineSearchGetPostCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx) {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
383   if (func) *func = linesearch->ops->postcheck;
384   if (ctx) *ctx = linesearch->postcheckctx;
385   PetscFunctionReturn(0);
386 }
387 
388 /*@
389    SNESLineSearchPreCheck - Prepares the line search for being applied.
390 
391    Logically Collective on linesearch
392 
393    Input Parameters:
394 +  linesearch - The linesearch instance.
395 .  X - The current solution
396 -  Y - The step direction
397 
398    Output Parameters:
399 .  changed - Indicator that the precheck routine has changed anything
400 
401    Level: advanced
402 
403    Note:
404    This calls any function provided with `SNESLineSearchSetPreCheck()`
405 
406 .seealso: `SNESLineSearch`,  `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`,
407           `SNESLineSearchGetPostCheck()``
408 @*/
409 PetscErrorCode SNESLineSearchPreCheck(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed) {
410   PetscFunctionBegin;
411   *changed = PETSC_FALSE;
412   if (linesearch->ops->precheck) {
413     PetscUseTypeMethod(linesearch, precheck, X, Y, changed, linesearch->precheckctx);
414     PetscValidLogicalCollectiveBool(linesearch, *changed, 4);
415   }
416   PetscFunctionReturn(0);
417 }
418 
419 /*@
420    SNESLineSearchPostCheck - Hook to modify step direction or updated solution after a successful linesearch
421 
422    Logically Collective on linesearch
423 
424    Input Parameters:
425 +  linesearch - The linesearch context
426 .  X - The last solution
427 .  Y - The step direction
428 -  W - The updated solution, W = X + lambda*Y for some lambda
429 
430    Output Parameters:
431 +  changed_Y - Indicator if the direction Y has been changed.
432 -  changed_W - Indicator if the new candidate solution W has been changed.
433 
434    Note:
435    This calls any function provided with `SNESLineSearchSetPreCheck()`
436 
437    Level: developer
438 
439 .seealso: `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPrecheck()`, `SNESLineSearchGetPrecheck()`
440 @*/
441 PetscErrorCode SNESLineSearchPostCheck(SNESLineSearch linesearch, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W) {
442   PetscFunctionBegin;
443   *changed_Y = PETSC_FALSE;
444   *changed_W = PETSC_FALSE;
445   if (linesearch->ops->postcheck) {
446     PetscUseTypeMethod(linesearch, postcheck, X, Y, W, changed_Y, changed_W, linesearch->postcheckctx);
447     PetscValidLogicalCollectiveBool(linesearch, *changed_Y, 5);
448     PetscValidLogicalCollectiveBool(linesearch, *changed_W, 6);
449   }
450   PetscFunctionReturn(0);
451 }
452 
453 /*@C
454    SNESLineSearchPreCheckPicard - Implements a correction that is sometimes useful to improve the convergence rate of Picard iteration
455 
456    Logically Collective on linesearch
457 
458    Input Parameters:
459 +  linesearch - linesearch context
460 .  X - base state for this step
461 -  ctx - context for this function
462 
463    Input/Output Parameter:
464 .  Y - correction, possibly modified
465 
466    Output Parameter:
467 .  changed - flag indicating that Y was modified
468 
469    Options Database Key:
470 +  -snes_linesearch_precheck_picard - activate this routine
471 -  -snes_linesearch_precheck_picard_angle - angle
472 
473    Level: advanced
474 
475    Notes:
476    This function should be passed to `SNESLineSearchSetPreCheck()`
477 
478    The justification for this method involves the linear convergence of a Picard iteration
479    so the Picard linearization should be provided in place of the "Jacobian". This correction
480    is generally not useful when using a Newton linearization.
481 
482    Reference:
483  . - * - Hindmarsh and Payne (1996) Time step limits for stable solutions of the ice sheet equation, Annals of Glaciology.
484 
485 .seealso: `SNESLineSearch`, `SNESSetPicard()`, `SNESGetLineSearch()`, `SNESLineSearchSetPreCheck()`
486 @*/
487 PetscErrorCode SNESLineSearchPreCheckPicard(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed, void *ctx) {
488   PetscReal   angle = *(PetscReal *)linesearch->precheckctx;
489   Vec         Ylast;
490   PetscScalar dot;
491   PetscInt    iter;
492   PetscReal   ynorm, ylastnorm, theta, angle_radians;
493   SNES        snes;
494 
495   PetscFunctionBegin;
496   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
497   PetscCall(PetscObjectQuery((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject *)&Ylast));
498   if (!Ylast) {
499     PetscCall(VecDuplicate(Y, &Ylast));
500     PetscCall(PetscObjectCompose((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject)Ylast));
501     PetscCall(PetscObjectDereference((PetscObject)Ylast));
502   }
503   PetscCall(SNESGetIterationNumber(snes, &iter));
504   if (iter < 2) {
505     PetscCall(VecCopy(Y, Ylast));
506     *changed = PETSC_FALSE;
507     PetscFunctionReturn(0);
508   }
509 
510   PetscCall(VecDot(Y, Ylast, &dot));
511   PetscCall(VecNorm(Y, NORM_2, &ynorm));
512   PetscCall(VecNorm(Ylast, NORM_2, &ylastnorm));
513   /* Compute the angle between the vectors Y and Ylast, clip to keep inside the domain of acos() */
514   theta         = PetscAcosReal((PetscReal)PetscClipInterval(PetscAbsScalar(dot) / (ynorm * ylastnorm), -1.0, 1.0));
515   angle_radians = angle * PETSC_PI / 180.;
516   if (PetscAbsReal(theta) < angle_radians || PetscAbsReal(theta - PETSC_PI) < angle_radians) {
517     /* Modify the step Y */
518     PetscReal alpha, ydiffnorm;
519     PetscCall(VecAXPY(Ylast, -1.0, Y));
520     PetscCall(VecNorm(Ylast, NORM_2, &ydiffnorm));
521     alpha = (ydiffnorm > .001 * ylastnorm) ? ylastnorm / ydiffnorm : 1000.0;
522     PetscCall(VecCopy(Y, Ylast));
523     PetscCall(VecScale(Y, alpha));
524     PetscCall(PetscInfo(snes, "Angle %14.12e degrees less than threshold %14.12e, corrected step by alpha=%14.12e\n", (double)(theta * 180. / PETSC_PI), (double)angle, (double)alpha));
525     *changed = PETSC_TRUE;
526   } else {
527     PetscCall(PetscInfo(snes, "Angle %14.12e degrees exceeds threshold %14.12e, no correction applied\n", (double)(theta * 180. / PETSC_PI), (double)angle));
528     PetscCall(VecCopy(Y, Ylast));
529     *changed = PETSC_FALSE;
530   }
531   PetscFunctionReturn(0);
532 }
533 
534 /*@
535    SNESLineSearchApply - Computes the line-search update.
536 
537    Collective on linesearch
538 
539    Input Parameters:
540 +  linesearch - The linesearch context
541 -  Y - The search direction
542 
543    Input/Output Parameters:
544 +  X - The current solution, on output the new solution
545 .  F - The current function, on output the new function
546 -  fnorm - The current norm, on output the new function norm
547 
548    Options Database Keys:
549 + -snes_linesearch_type - basic (or equivalently none), bt, l2, cp, nleqerr, shell
550 . -snes_linesearch_monitor [:filename] - Print progress of line searches
551 . -snes_linesearch_damping - The linesearch damping parameter, default is 1.0 (no damping)
552 . -snes_linesearch_norms   - Turn on/off the linesearch norms computation (SNESLineSearchSetComputeNorms())
553 . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess
554 - -snes_linesearch_max_it - The number of iterations for iterative line searches
555 
556    Notes:
557    This is typically called from within a `SNESSolve()` implementation in order to
558    help with convergence of the nonlinear method.  Various `SNES` types use line searches
559    in different ways, but the overarching theme is that a line search is used to determine
560    an optimal damping parameter of a step at each iteration of the method.  Each
561    application of the line search may invoke `SNESComputeFunction()` several times, and
562    therefore may be fairly expensive.
563 
564    Level: Intermediate
565 
566 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchPreCheck()`, `SNESLineSearchPostCheck()`, `SNESSolve()`, `SNESComputeFunction()`, `SNESLineSearchSetComputeNorms()`,
567           `SNESLineSearchType`, `SNESLineSearchSetType()`
568 @*/
569 PetscErrorCode SNESLineSearchApply(SNESLineSearch linesearch, Vec X, Vec F, PetscReal *fnorm, Vec Y) {
570   PetscFunctionBegin;
571   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
572   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
573   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
574   PetscValidHeaderSpecific(Y, VEC_CLASSID, 5);
575 
576   linesearch->result = SNES_LINESEARCH_SUCCEEDED;
577 
578   linesearch->vec_sol    = X;
579   linesearch->vec_update = Y;
580   linesearch->vec_func   = F;
581 
582   PetscCall(SNESLineSearchSetUp(linesearch));
583 
584   if (!linesearch->keeplambda) linesearch->lambda = linesearch->damping; /* set the initial guess to lambda */
585 
586   if (fnorm) linesearch->fnorm = *fnorm;
587   else PetscCall(VecNorm(F, NORM_2, &linesearch->fnorm));
588 
589   PetscCall(PetscLogEventBegin(SNESLINESEARCH_Apply, linesearch, X, F, Y));
590 
591   PetscUseTypeMethod(linesearch, apply);
592 
593   PetscCall(PetscLogEventEnd(SNESLINESEARCH_Apply, linesearch, X, F, Y));
594 
595   if (fnorm) *fnorm = linesearch->fnorm;
596   PetscFunctionReturn(0);
597 }
598 
599 /*@
600    SNESLineSearchDestroy - Destroys the line search instance.
601 
602    Collective on linesearch
603 
604    Input Parameters:
605 .  linesearch - The linesearch context
606 
607    Level: developer
608 
609 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchReset()`, `SNESDestroy()`
610 @*/
611 PetscErrorCode SNESLineSearchDestroy(SNESLineSearch *linesearch) {
612   PetscFunctionBegin;
613   if (!*linesearch) PetscFunctionReturn(0);
614   PetscValidHeaderSpecific((*linesearch), SNESLINESEARCH_CLASSID, 1);
615   if (--((PetscObject)(*linesearch))->refct > 0) {
616     *linesearch = NULL;
617     PetscFunctionReturn(0);
618   }
619   PetscCall(PetscObjectSAWsViewOff((PetscObject)*linesearch));
620   PetscCall(SNESLineSearchReset(*linesearch));
621   if ((*linesearch)->ops->destroy) (*linesearch)->ops->destroy(*linesearch);
622   PetscCall(PetscViewerDestroy(&(*linesearch)->monitor));
623   PetscCall(SNESLineSearchMonitorCancel((*linesearch)));
624   PetscCall(PetscHeaderDestroy(linesearch));
625   PetscFunctionReturn(0);
626 }
627 
628 /*@
629    SNESLineSearchSetDefaultMonitor - Turns on/off printing useful information and debugging output about the line search.
630 
631    Logically Collective on linesearch
632 
633    Input Parameters:
634 +  linesearch - the linesearch object
635 -  viewer - an `PETSCVIEWERASCII` `PetscViewer` or NULL to turn off monitor
636 
637    Options Database Key:
638 .   -snes_linesearch_monitor [:filename] - enables the monitor
639 
640    Level: intermediate
641 
642    Developer Note:
643    This monitor is implemented differently than the other line search monitors that are set with
644    `SNESLineSearchMonitorSet()` since it is called in many locations of the line search routines to display aspects of the
645    line search that are not visible to the other monitors.
646 
647 .seealso: `SNESLineSearch`, `PETSCVIEWERASCII`, `SNESGetLineSearch()`, `SNESLineSearchGetDefaultMonitor()`, `PetscViewer`, `SNESLineSearchSetMonitor()`,
648           `SNESLineSearchMonitorSetFromOptions()`
649 @*/
650 PetscErrorCode SNESLineSearchSetDefaultMonitor(SNESLineSearch linesearch, PetscViewer viewer) {
651   PetscFunctionBegin;
652   if (viewer) PetscCall(PetscObjectReference((PetscObject)viewer));
653   PetscCall(PetscViewerDestroy(&linesearch->monitor));
654   linesearch->monitor = viewer;
655   PetscFunctionReturn(0);
656 }
657 
658 /*@
659    SNESLineSearchGetDefaultMonitor - Gets the `PetscViewer` instance for the line search monitor.
660 
661    Logically Collective on linsearch
662 
663    Input Parameter:
664 .  linesearch - linesearch context
665 
666    Output Parameter:
667 .  monitor - monitor context
668 
669    Level: intermediate
670 
671 .seealso: `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetDefaultMonitor()`, `PetscViewer`
672 @*/
673 PetscErrorCode SNESLineSearchGetDefaultMonitor(SNESLineSearch linesearch, PetscViewer *monitor) {
674   PetscFunctionBegin;
675   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
676   *monitor = linesearch->monitor;
677   PetscFunctionReturn(0);
678 }
679 
680 /*@C
681    SNESLineSearchMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
682 
683    Collective on ls
684 
685    Input Parameters:
686 +  ls - `SNESLineSearch` object you wish to monitor
687 .  name - the monitor type one is seeking
688 .  help - message indicating what monitoring is done
689 .  manual - manual page for the monitor
690 .  monitor - the monitor function
691 -  monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `SNESLineSearch` or `PetscViewer`
692 
693    Level: developer
694 
695 .seealso: `SNESLineSearch`, `SNESLineSearchSetMonitor()`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
696           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
697           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
698           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
699           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
700           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
701           `PetscOptionsFList()`, `PetscOptionsEList()`
702 @*/
703 PetscErrorCode SNESLineSearchMonitorSetFromOptions(SNESLineSearch ls, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(SNESLineSearch, PetscViewerAndFormat *), PetscErrorCode (*monitorsetup)(SNESLineSearch, PetscViewerAndFormat *)) {
704   PetscViewer       viewer;
705   PetscViewerFormat format;
706   PetscBool         flg;
707 
708   PetscFunctionBegin;
709   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)ls), ((PetscObject)ls)->options, ((PetscObject)ls)->prefix, name, &viewer, &format, &flg));
710   if (flg) {
711     PetscViewerAndFormat *vf;
712     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
713     PetscCall(PetscObjectDereference((PetscObject)viewer));
714     if (monitorsetup) PetscCall((*monitorsetup)(ls, vf));
715     PetscCall(SNESLineSearchMonitorSet(ls, (PetscErrorCode(*)(SNESLineSearch, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
716   }
717   PetscFunctionReturn(0);
718 }
719 
720 /*@
721    SNESLineSearchSetFromOptions - Sets options for the line search
722 
723    Logically Collective on linesearch
724 
725    Input Parameter:
726 .  linesearch - linesearch context
727 
728    Options Database Keys:
729 + -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
730 . -snes_linesearch_order <order> - 1, 2, 3.  Most types only support certain orders (bt supports 2 or 3)
731 . -snes_linesearch_norms   - Turn on/off the linesearch norms for the basic linesearch typem (`SNESLineSearchSetComputeNorms()`)
732 . -snes_linesearch_minlambda - The minimum step length
733 . -snes_linesearch_maxstep - The maximum step size
734 . -snes_linesearch_rtol - Relative tolerance for iterative line searches
735 . -snes_linesearch_atol - Absolute tolerance for iterative line searches
736 . -snes_linesearch_ltol - Change in lambda tolerance for iterative line searches
737 . -snes_linesearch_max_it - The number of iterations for iterative line searches
738 . -snes_linesearch_monitor [:filename] - Print progress of line searches
739 . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine
740 . -snes_linesearch_damping - The linesearch damping parameter
741 . -snes_linesearch_keeplambda - Keep the previous search length as the initial guess.
742 . -snes_linesearch_precheck_picard - Use precheck that speeds up convergence of picard method
743 - -snes_linesearch_precheck_picard_angle - Angle used in Picard precheck method
744 
745    Level: intermediate
746 
747 .seealso: `SNESLineSearch`, `SNESLineSearchCreate()`, `SNESLineSearchSetOrder()`, `SNESLineSearchSetType()`, `SNESLineSearchSetTolerances()`, `SNESLineSearchSetDamping()`, `SNESLineSearchPreCheckPicard()`,
748           `SNESLineSearchType`, `SNESLineSearchSetComputeNorms()`
749 @*/
750 PetscErrorCode SNESLineSearchSetFromOptions(SNESLineSearch linesearch) {
751   const char *deft = SNESLINESEARCHBASIC;
752   char        type[256];
753   PetscBool   flg, set;
754   PetscViewer viewer;
755 
756   PetscFunctionBegin;
757   PetscCall(SNESLineSearchRegisterAll());
758 
759   PetscObjectOptionsBegin((PetscObject)linesearch);
760   if (((PetscObject)linesearch)->type_name) deft = ((PetscObject)linesearch)->type_name;
761   PetscCall(PetscOptionsFList("-snes_linesearch_type", "Linesearch type", "SNESLineSearchSetType", SNESLineSearchList, deft, type, 256, &flg));
762   if (flg) {
763     PetscCall(SNESLineSearchSetType(linesearch, type));
764   } else if (!((PetscObject)linesearch)->type_name) {
765     PetscCall(SNESLineSearchSetType(linesearch, deft));
766   }
767 
768   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)linesearch), ((PetscObject)linesearch)->options, ((PetscObject)linesearch)->prefix, "-snes_linesearch_monitor", &viewer, NULL, &set));
769   if (set) {
770     PetscCall(SNESLineSearchSetDefaultMonitor(linesearch, viewer));
771     PetscCall(PetscViewerDestroy(&viewer));
772   }
773   PetscCall(SNESLineSearchMonitorSetFromOptions(linesearch, "-snes_linesearch_monitor_solution_update", "View correction at each iteration", "SNESLineSearchMonitorSolutionUpdate", SNESLineSearchMonitorSolutionUpdate, NULL));
774 
775   /* tolerances */
776   PetscCall(PetscOptionsReal("-snes_linesearch_minlambda", "Minimum step length", "SNESLineSearchSetTolerances", linesearch->steptol, &linesearch->steptol, NULL));
777   PetscCall(PetscOptionsReal("-snes_linesearch_maxstep", "Maximum step size", "SNESLineSearchSetTolerances", linesearch->maxstep, &linesearch->maxstep, NULL));
778   PetscCall(PetscOptionsReal("-snes_linesearch_rtol", "Relative tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->rtol, &linesearch->rtol, NULL));
779   PetscCall(PetscOptionsReal("-snes_linesearch_atol", "Absolute tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->atol, &linesearch->atol, NULL));
780   PetscCall(PetscOptionsReal("-snes_linesearch_ltol", "Change in lambda tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->ltol, &linesearch->ltol, NULL));
781   PetscCall(PetscOptionsInt("-snes_linesearch_max_it", "Maximum iterations for iterative line searches", "SNESLineSearchSetTolerances", linesearch->max_its, &linesearch->max_its, NULL));
782 
783   /* damping parameters */
784   PetscCall(PetscOptionsReal("-snes_linesearch_damping", "Line search damping and initial step guess", "SNESLineSearchSetDamping", linesearch->damping, &linesearch->damping, NULL));
785 
786   PetscCall(PetscOptionsBool("-snes_linesearch_keeplambda", "Use previous lambda as damping", "SNESLineSearchSetKeepLambda", linesearch->keeplambda, &linesearch->keeplambda, NULL));
787 
788   /* precheck */
789   PetscCall(PetscOptionsBool("-snes_linesearch_precheck_picard", "Use a correction that sometimes improves convergence of Picard iteration", "SNESLineSearchPreCheckPicard", flg, &flg, &set));
790   if (set) {
791     if (flg) {
792       linesearch->precheck_picard_angle = 10.; /* correction only active if angle is less than 10 degrees */
793 
794       PetscCall(PetscOptionsReal("-snes_linesearch_precheck_picard_angle", "Maximum angle at which to activate the correction", "none", linesearch->precheck_picard_angle, &linesearch->precheck_picard_angle, NULL));
795       PetscCall(SNESLineSearchSetPreCheck(linesearch, SNESLineSearchPreCheckPicard, &linesearch->precheck_picard_angle));
796     } else {
797       PetscCall(SNESLineSearchSetPreCheck(linesearch, NULL, NULL));
798     }
799   }
800   PetscCall(PetscOptionsInt("-snes_linesearch_order", "Order of approximation used in the line search", "SNESLineSearchSetOrder", linesearch->order, &linesearch->order, NULL));
801   PetscCall(PetscOptionsBool("-snes_linesearch_norms", "Compute final norms in line search", "SNESLineSearchSetComputeNorms", linesearch->norms, &linesearch->norms, NULL));
802 
803   PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);
804 
805   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
806   PetscOptionsEnd();
807   PetscFunctionReturn(0);
808 }
809 
810 /*@
811    SNESLineSearchView - Prints useful information about the line search
812 
813    Input Parameters:
814 .  linesearch - linesearch context
815 
816    Logically Collective on linesearch
817 
818    Level: intermediate
819 
820 .seealso: `SNESLineSearch`, `PetscViewer`, `SNESLineSearchCreate()`
821 @*/
822 PetscErrorCode SNESLineSearchView(SNESLineSearch linesearch, PetscViewer viewer) {
823   PetscBool iascii;
824 
825   PetscFunctionBegin;
826   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
827   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
828   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
829   PetscCheckSameComm(linesearch, 1, viewer, 2);
830 
831   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
832   if (iascii) {
833     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)linesearch, viewer));
834     PetscCall(PetscViewerASCIIPushTab(viewer));
835     PetscTryTypeMethod(linesearch, view, viewer);
836     PetscCall(PetscViewerASCIIPopTab(viewer));
837     PetscCall(PetscViewerASCIIPrintf(viewer, "  maxstep=%e, minlambda=%e\n", (double)linesearch->maxstep, (double)linesearch->steptol));
838     PetscCall(PetscViewerASCIIPrintf(viewer, "  tolerances: relative=%e, absolute=%e, lambda=%e\n", (double)linesearch->rtol, (double)linesearch->atol, (double)linesearch->ltol));
839     PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum iterations=%" PetscInt_FMT "\n", linesearch->max_its));
840     if (linesearch->ops->precheck) {
841       if (linesearch->ops->precheck == SNESLineSearchPreCheckPicard) {
842         PetscCall(PetscViewerASCIIPrintf(viewer, "  using precheck step to speed up Picard convergence\n"));
843       } else {
844         PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined precheck step\n"));
845       }
846     }
847     if (linesearch->ops->postcheck) PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined postcheck step\n"));
848   }
849   PetscFunctionReturn(0);
850 }
851 
852 /*@C
853    SNESLineSearchGetType - Gets the linesearch type
854 
855    Logically Collective on linesearch
856 
857    Input Parameters:
858 .  linesearch - linesearch context
859 
860    Output Parameters:
861 -  type - The type of line search, or NULL if not set
862 
863    Level: intermediate
864 
865 .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchType`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchSetType()`
866 @*/
867 PetscErrorCode SNESLineSearchGetType(SNESLineSearch linesearch, SNESLineSearchType *type) {
868   PetscFunctionBegin;
869   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
870   PetscValidPointer(type, 2);
871   *type = ((PetscObject)linesearch)->type_name;
872   PetscFunctionReturn(0);
873 }
874 
875 /*@C
876    SNESLineSearchSetType - Sets the linesearch type
877 
878    Logically Collective on linesearch
879 
880    Input Parameters:
881 +  linesearch - linesearch context
882 -  type - The type of line search to be used
883 
884    Available Types:
885 +  `SNESLINESEARCHBASIC` - (or equivalently `SNESLINESEARCHNONE`) Simple damping line search, defaults to using the full Newton step
886 .  `SNESLINESEARCHBT` - Backtracking line search over the L2 norm of the function
887 .  `SNESLINESEARCHL2` - Secant line search over the L2 norm of the function
888 .  `SNESLINESEARCHCP` - Critical point secant line search assuming F(x) = grad G(x) for some unknown G(x)
889 .  `SNESLINESEARCHNLEQERR` - Affine-covariant error-oriented linesearch
890 -  `SNESLINESEARCHSHELL` - User provided `SNESLineSearch` implementation
891 
892    Options Database:
893 .  -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell
894 
895    Level: intermediate
896 
897 .seealso:  `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchType`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`
898 @*/
899 PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type) {
900   PetscBool match;
901   PetscErrorCode (*r)(SNESLineSearch);
902 
903   PetscFunctionBegin;
904   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
905   PetscValidCharPointer(type, 2);
906 
907   PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
908   if (match) PetscFunctionReturn(0);
909 
910   PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
911   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
912   /* Destroy the previous private linesearch context */
913   if (linesearch->ops->destroy) {
914     PetscCall((*(linesearch)->ops->destroy)(linesearch));
915     linesearch->ops->destroy = NULL;
916   }
917   /* Reinitialize function pointers in SNESLineSearchOps structure */
918   linesearch->ops->apply          = NULL;
919   linesearch->ops->view           = NULL;
920   linesearch->ops->setfromoptions = NULL;
921   linesearch->ops->destroy        = NULL;
922 
923   PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
924   PetscCall((*r)(linesearch));
925   PetscFunctionReturn(0);
926 }
927 
928 /*@
929    SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.
930 
931    Input Parameters:
932 +  linesearch - linesearch context
933 -  snes - The snes instance
934 
935    Level: developer
936 
937    Note:
938    This happens automatically when the line search is obtained/created with
939    `SNESGetLineSearch()`.  This routine is therefore mainly called within `SNES`
940    implementations.
941 
942    Level: developer
943 
944 .seealso: `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`, `SNES`
945 @*/
946 PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes) {
947   PetscFunctionBegin;
948   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
949   PetscValidHeaderSpecific(snes, SNES_CLASSID, 2);
950   linesearch->snes = snes;
951   PetscFunctionReturn(0);
952 }
953 
954 /*@
955    SNESLineSearchGetSNES - Gets the `SNES` instance associated with the line search.
956    Having an associated `SNES` is necessary because most line search implementations must be able to
957    evaluate the function using `SNESComputeFunction()` for the associated `SNES`.  This routine
958    is used in the line search implementations when one must get this associated `SNES` instance.
959 
960    Not Collective
961 
962    Input Parameters:
963 .  linesearch - linesearch context
964 
965    Output Parameters:
966 .  snes - The snes instance
967 
968    Level: developer
969 
970 .seealso: `SNESLineSearch`, `SNESType`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`, `SNES`
971 @*/
972 PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes) {
973   PetscFunctionBegin;
974   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
975   PetscValidPointer(snes, 2);
976   *snes = linesearch->snes;
977   PetscFunctionReturn(0);
978 }
979 
980 /*@
981    SNESLineSearchGetLambda - Gets the last linesearch steplength discovered.
982 
983    Not Collective
984 
985    Input Parameters:
986 .  linesearch - linesearch context
987 
988    Output Parameters:
989 .  lambda - The last steplength computed during `SNESLineSearchApply()`
990 
991    Level: advanced
992 
993    Note:
994    This is useful in methods where the solver is ill-scaled and
995    requires some adaptive notion of the difference in scale between the
996    solution and the function.  For instance, `SNESQN` may be scaled by the
997    line search lambda using the argument -snes_qn_scaling ls.
998 
999 .seealso: `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
1000 @*/
1001 PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda) {
1002   PetscFunctionBegin;
1003   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1004   PetscValidRealPointer(lambda, 2);
1005   *lambda = linesearch->lambda;
1006   PetscFunctionReturn(0);
1007 }
1008 
1009 /*@
1010    SNESLineSearchSetLambda - Sets the linesearch steplength
1011 
1012    Input Parameters:
1013 +  linesearch - linesearch context
1014 -  lambda - The last steplength.
1015 
1016    Note:
1017    This routine is typically used within implementations of `SNESLineSearchApply()`
1018    to set the final steplength.  This routine (and `SNESLineSearchGetLambda()`) were
1019    added in order to facilitate Quasi-Newton methods that use the previous steplength
1020    as an inner scaling parameter.
1021 
1022    Level: advanced
1023 
1024 .seealso: `SNESLineSearch`, `SNESLineSearchGetLambda()`
1025 @*/
1026 PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda) {
1027   PetscFunctionBegin;
1028   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1029   linesearch->lambda = lambda;
1030   PetscFunctionReturn(0);
1031 }
1032 
1033 /*@
1034    SNESLineSearchGetTolerances - Gets the tolerances for the linesearch.  These include
1035    tolerances for the relative and absolute change in the function norm, the change
1036    in lambda for iterative line searches, the minimum steplength, the maximum steplength,
1037    and the maximum number of iterations the line search procedure may take.
1038 
1039    Not Collective
1040 
1041    Input Parameter:
1042 .  linesearch - linesearch context
1043 
1044    Output Parameters:
1045 +  steptol - The minimum steplength
1046 .  maxstep - The maximum steplength
1047 .  rtol    - The relative tolerance for iterative line searches
1048 .  atol    - The absolute tolerance for iterative line searches
1049 .  ltol    - The change in lambda tolerance for iterative line searches
1050 -  max_it  - The maximum number of iterations of the line search
1051 
1052    Level: intermediate
1053 
1054    Note:
1055    Different line searches may implement these parameters slightly differently as
1056    the type requires.
1057 
1058 .seealso: `SNESLineSearch`, `SNESLineSearchSetTolerances()`
1059 @*/
1060 PetscErrorCode SNESLineSearchGetTolerances(SNESLineSearch linesearch, PetscReal *steptol, PetscReal *maxstep, PetscReal *rtol, PetscReal *atol, PetscReal *ltol, PetscInt *max_its) {
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1063   if (steptol) {
1064     PetscValidRealPointer(steptol, 2);
1065     *steptol = linesearch->steptol;
1066   }
1067   if (maxstep) {
1068     PetscValidRealPointer(maxstep, 3);
1069     *maxstep = linesearch->maxstep;
1070   }
1071   if (rtol) {
1072     PetscValidRealPointer(rtol, 4);
1073     *rtol = linesearch->rtol;
1074   }
1075   if (atol) {
1076     PetscValidRealPointer(atol, 5);
1077     *atol = linesearch->atol;
1078   }
1079   if (ltol) {
1080     PetscValidRealPointer(ltol, 6);
1081     *ltol = linesearch->ltol;
1082   }
1083   if (max_its) {
1084     PetscValidIntPointer(max_its, 7);
1085     *max_its = linesearch->max_its;
1086   }
1087   PetscFunctionReturn(0);
1088 }
1089 
1090 /*@
1091    SNESLineSearchSetTolerances -  Gets the tolerances for the linesearch.  These include
1092    tolerances for the relative and absolute change in the function norm, the change
1093    in lambda for iterative line searches, the minimum steplength, the maximum steplength,
1094    and the maximum number of iterations the line search procedure may take.
1095 
1096    Collective
1097 
1098    Input Parameters:
1099 +  linesearch - linesearch context
1100 .  steptol - The minimum steplength
1101 .  maxstep - The maximum steplength
1102 .  rtol    - The relative tolerance for iterative line searches
1103 .  atol    - The absolute tolerance for iterative line searches
1104 .  ltol    - The change in lambda tolerance for iterative line searches
1105 -  max_it  - The maximum number of iterations of the line search
1106 
1107    Note:
1108    The user may choose to not set any of the tolerances using `PETSC_DEFAULT` in
1109    place of an argument.
1110 
1111    Level: intermediate
1112 
1113 .seealso: `SNESLineSearch`, `SNESLineSearchGetTolerances()`
1114 @*/
1115 PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal steptol, PetscReal maxstep, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_its) {
1116   PetscFunctionBegin;
1117   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1118   PetscValidLogicalCollectiveReal(linesearch, steptol, 2);
1119   PetscValidLogicalCollectiveReal(linesearch, maxstep, 3);
1120   PetscValidLogicalCollectiveReal(linesearch, rtol, 4);
1121   PetscValidLogicalCollectiveReal(linesearch, atol, 5);
1122   PetscValidLogicalCollectiveReal(linesearch, ltol, 6);
1123   PetscValidLogicalCollectiveInt(linesearch, max_its, 7);
1124 
1125   if (steptol != PETSC_DEFAULT) {
1126     PetscCheck(steptol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum step length %14.12e must be non-negative", (double)steptol);
1127     linesearch->steptol = steptol;
1128   }
1129 
1130   if (maxstep != PETSC_DEFAULT) {
1131     PetscCheck(maxstep >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum step length %14.12e must be non-negative", (double)maxstep);
1132     linesearch->maxstep = maxstep;
1133   }
1134 
1135   if (rtol != PETSC_DEFAULT) {
1136     PetscCheck(rtol >= 0.0 && rtol < 1.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Relative tolerance %14.12e must be non-negative and less than 1.0", (double)rtol);
1137     linesearch->rtol = rtol;
1138   }
1139 
1140   if (atol != PETSC_DEFAULT) {
1141     PetscCheck(atol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %14.12e must be non-negative", (double)atol);
1142     linesearch->atol = atol;
1143   }
1144 
1145   if (ltol != PETSC_DEFAULT) {
1146     PetscCheck(ltol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Lambda tolerance %14.12e must be non-negative", (double)ltol);
1147     linesearch->ltol = ltol;
1148   }
1149 
1150   if (max_its != PETSC_DEFAULT) {
1151     PetscCheck(max_its >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_its);
1152     linesearch->max_its = max_its;
1153   }
1154   PetscFunctionReturn(0);
1155 }
1156 
1157 /*@
1158    SNESLineSearchGetDamping - Gets the line search damping parameter.
1159 
1160    Input Parameters:
1161 .  linesearch - linesearch context
1162 
1163    Output Parameters:
1164 .  damping - The damping parameter
1165 
1166    Level: advanced
1167 
1168 .seealso: `SNESLineSearchGetStepTolerance()`, `SNESQN`
1169 @*/
1170 
1171 PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping) {
1172   PetscFunctionBegin;
1173   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1174   PetscValidRealPointer(damping, 2);
1175   *damping = linesearch->damping;
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 /*@
1180    SNESLineSearchSetDamping - Sets the line search damping parameter.
1181 
1182    Input Parameters:
1183 +  linesearch - linesearch context
1184 -  damping - The damping parameter
1185 
1186    Options Database Key:
1187 .   -snes_linesearch_damping <damping> - the damping value
1188 
1189    Level: intermediate
1190 
1191    Note:
1192    The `SNESLINESEARCHNONE` line search merely takes the update step scaled by the damping parameter.
1193    The use of the damping parameter in the l2 and cp line searches is much more subtle;
1194    it is used as a starting point in calculating the secant step. However, the eventual
1195    step may be of greater length than the damping parameter.  In the bt line search it is
1196    used as the maximum possible step length, as the bt line search only backtracks.
1197 
1198 .seealso: `SNESLineSearch`, `SNESLineSearchGetDamping()`
1199 @*/
1200 PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping) {
1201   PetscFunctionBegin;
1202   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1203   linesearch->damping = damping;
1204   PetscFunctionReturn(0);
1205 }
1206 
1207 /*@
1208    SNESLineSearchGetOrder - Gets the line search approximation order.
1209 
1210    Input Parameter:
1211 .  linesearch - linesearch context
1212 
1213    Output Parameter:
1214 .  order - The order
1215 
1216    Possible Values for order:
1217 +  1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1218 .  2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1219 -  3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order
1220 
1221    Level: intermediate
1222 
1223 .seealso: `SNESLineSearch`, `SNESLineSearchSetOrder()`
1224 @*/
1225 
1226 PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order) {
1227   PetscFunctionBegin;
1228   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1229   PetscValidIntPointer(order, 2);
1230   *order = linesearch->order;
1231   PetscFunctionReturn(0);
1232 }
1233 
1234 /*@
1235    SNESLineSearchSetOrder - Sets the maximum order of the polynomial fit used in the line search
1236 
1237    Input Parameters:
1238 +  linesearch - linesearch context
1239 -  order - The damping parameter
1240 
1241    Level: intermediate
1242 
1243    Possible Values for order:
1244 +  1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1245 .  2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1246 -  3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order
1247 
1248    Notes:
1249    Variable orders are supported by the following line searches:
1250 +  bt - cubic and quadratic
1251 -  cp - linear and quadratic
1252 
1253 .seealso: `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
1254 @*/
1255 PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order) {
1256   PetscFunctionBegin;
1257   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1258   linesearch->order = order;
1259   PetscFunctionReturn(0);
1260 }
1261 
1262 /*@
1263    SNESLineSearchGetNorms - Gets the norms for for X, Y, and F.
1264 
1265    Not Collective
1266 
1267    Input Parameter:
1268 .  linesearch - linesearch context
1269 
1270    Output Parameters:
1271 +  xnorm - The norm of the current solution
1272 .  fnorm - The norm of the current function
1273 -  ynorm - The norm of the current update
1274 
1275    Level: developer
1276 
1277 .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()` `SNESLineSearchGetVecs()`
1278 @*/
1279 PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm) {
1280   PetscFunctionBegin;
1281   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1282   if (xnorm) *xnorm = linesearch->xnorm;
1283   if (fnorm) *fnorm = linesearch->fnorm;
1284   if (ynorm) *ynorm = linesearch->ynorm;
1285   PetscFunctionReturn(0);
1286 }
1287 
1288 /*@
1289    SNESLineSearchSetNorms - Gets the computed norms for for X, Y, and F.
1290 
1291    Collective on linesearch
1292 
1293    Input Parameters:
1294 +  linesearch - linesearch context
1295 .  xnorm - The norm of the current solution
1296 .  fnorm - The norm of the current function
1297 -  ynorm - The norm of the current update
1298 
1299    Level: developer
1300 
1301 .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1302 @*/
1303 PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm) {
1304   PetscFunctionBegin;
1305   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1306   linesearch->xnorm = xnorm;
1307   linesearch->fnorm = fnorm;
1308   linesearch->ynorm = ynorm;
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 /*@
1313    SNESLineSearchComputeNorms - Computes the norms of X, F, and Y.
1314 
1315    Input Parameters:
1316 .  linesearch - linesearch context
1317 
1318    Options Database Keys:
1319 .   -snes_linesearch_norms - turn norm computation on or off
1320 
1321    Level: intermediate
1322 
1323 .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
1324 @*/
1325 PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch) {
1326   SNES snes;
1327 
1328   PetscFunctionBegin;
1329   if (linesearch->norms) {
1330     if (linesearch->ops->vinorm) {
1331       PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
1332       PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1333       PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1334       PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
1335     } else {
1336       PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1337       PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1338       PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1339       PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1340       PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1341       PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1342     }
1343   }
1344   PetscFunctionReturn(0);
1345 }
1346 
1347 /*@
1348    SNESLineSearchSetComputeNorms - Turns on or off the computation of final norms in the line search.
1349 
1350    Input Parameters:
1351 +  linesearch  - linesearch context
1352 -  flg  - indicates whether or not to compute norms
1353 
1354    Options Database Keys:
1355 .   -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic (none) linesearch
1356 
1357    Note:
1358    This is most relevant to the `SNESLINESEARCHBASIC` (or equivalently `SNESLINESEARCHNONE`) line search type since most line searches have a stopping criteria involving the norm.
1359 
1360    Level: intermediate
1361 
1362 .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
1363 @*/
1364 PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg) {
1365   PetscFunctionBegin;
1366   linesearch->norms = flg;
1367   PetscFunctionReturn(0);
1368 }
1369 
1370 /*@
1371    SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context
1372 
1373    Not Collective on but the vectors are parallel
1374 
1375    Input Parameter:
1376 .  linesearch - linesearch context
1377 
1378    Output Parameters:
1379 +  X - Solution vector
1380 .  F - Function vector
1381 .  Y - Search direction vector
1382 .  W - Solution work vector
1383 -  G - Function work vector
1384 
1385    Notes:
1386    At the beginning of a line search application, X should contain a
1387    solution and the vector F the function computed at X.  At the end of the
1388    line search application, X should contain the new solution, and F the
1389    function evaluated at the new solution.
1390 
1391    These vectors are owned by the `SNESLineSearch` and should not be destroyed by the caller
1392 
1393    Level: advanced
1394 
1395 .seealso: `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1396 @*/
1397 PetscErrorCode SNESLineSearchGetVecs(SNESLineSearch linesearch, Vec *X, Vec *F, Vec *Y, Vec *W, Vec *G) {
1398   PetscFunctionBegin;
1399   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1400   if (X) {
1401     PetscValidPointer(X, 2);
1402     *X = linesearch->vec_sol;
1403   }
1404   if (F) {
1405     PetscValidPointer(F, 3);
1406     *F = linesearch->vec_func;
1407   }
1408   if (Y) {
1409     PetscValidPointer(Y, 4);
1410     *Y = linesearch->vec_update;
1411   }
1412   if (W) {
1413     PetscValidPointer(W, 5);
1414     *W = linesearch->vec_sol_new;
1415   }
1416   if (G) {
1417     PetscValidPointer(G, 6);
1418     *G = linesearch->vec_func_new;
1419   }
1420   PetscFunctionReturn(0);
1421 }
1422 
1423 /*@
1424    SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context
1425 
1426    Logically Collective on linesearch
1427 
1428    Input Parameters:
1429 +  linesearch - linesearch context
1430 .  X - Solution vector
1431 .  F - Function vector
1432 .  Y - Search direction vector
1433 .  W - Solution work vector
1434 -  G - Function work vector
1435 
1436    Level: advanced
1437 
1438 .seealso: `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
1439 @*/
1440 PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G) {
1441   PetscFunctionBegin;
1442   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1443   if (X) {
1444     PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
1445     linesearch->vec_sol = X;
1446   }
1447   if (F) {
1448     PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
1449     linesearch->vec_func = F;
1450   }
1451   if (Y) {
1452     PetscValidHeaderSpecific(Y, VEC_CLASSID, 4);
1453     linesearch->vec_update = Y;
1454   }
1455   if (W) {
1456     PetscValidHeaderSpecific(W, VEC_CLASSID, 5);
1457     linesearch->vec_sol_new = W;
1458   }
1459   if (G) {
1460     PetscValidHeaderSpecific(G, VEC_CLASSID, 6);
1461     linesearch->vec_func_new = G;
1462   }
1463   PetscFunctionReturn(0);
1464 }
1465 
1466 /*@C
1467    SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
1468    `SNESLineSearch` options in the database.
1469 
1470    Logically Collective on linesearch
1471 
1472    Input Parameters:
1473 +  linesearch - the `SNESLineSearch` context
1474 -  prefix - the prefix to prepend to all option names
1475 
1476    Note:
1477    A hyphen (-) must NOT be given at the beginning of the prefix name.
1478    The first character of all runtime options is AUTOMATICALLY the hyphen.
1479 
1480    Level: advanced
1481 
1482 .seealso: `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
1483 @*/
1484 PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[]) {
1485   PetscFunctionBegin;
1486   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1487   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
1488   PetscFunctionReturn(0);
1489 }
1490 
1491 /*@C
1492    SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
1493    SNESLineSearch options in the database.
1494 
1495    Not Collective
1496 
1497    Input Parameter:
1498 .  linesearch - the `SNESLineSearch` context
1499 
1500    Output Parameter:
1501 .  prefix - pointer to the prefix string used
1502 
1503    Fortran Note:
1504    On the fortran side, the user should pass in a string 'prefix' of
1505    sufficient length to hold the prefix.
1506 
1507    Level: advanced
1508 
1509 .seealso: `SNESLineSearch`, `SNESAppendOptionsPrefix()`
1510 @*/
1511 PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[]) {
1512   PetscFunctionBegin;
1513   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1514   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 /*@C
1519    SNESLineSearchSetWorkVecs - Sets work vectors for the line search.
1520 
1521    Input Parameters:
1522 +  linesearch - the `SNESLineSearch` context
1523 -  nwork - the number of work vectors
1524 
1525    Level: developer
1526 
1527 .seealso: `SNESLineSearch`, `SNESSetWorkVecs()`
1528 @*/
1529 PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork) {
1530   PetscFunctionBegin;
1531   if (linesearch->vec_sol) {
1532     PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
1533   } else SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 /*@
1538    SNESLineSearchGetReason - Gets the success/failure status of the last line search application
1539 
1540    Input Parameters:
1541 .  linesearch - linesearch context
1542 
1543    Output Parameters:
1544 .  result - The success or failure status
1545 
1546    Note:
1547    This is typically called after `SNESLineSearchApply()` in order to determine if the line-search failed
1548    (and set the SNES convergence accordingly).
1549 
1550    Level: developer
1551 
1552 .seealso: `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
1553 @*/
1554 PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *result) {
1555   PetscFunctionBegin;
1556   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1557   PetscValidPointer(result, 2);
1558   *result = linesearch->result;
1559   PetscFunctionReturn(0);
1560 }
1561 
1562 /*@
1563    SNESLineSearchSetReason - Sets the success/failure status of the last line search application
1564 
1565    Input Parameters:
1566 +  linesearch - linesearch context
1567 -  result - The success or failure status
1568 
1569    Note:
1570    This is typically called in a `SNESLineSearchApply()` or a `SNESLINESEARCHSHELL` implementation to set
1571    the success or failure of the line search method.
1572 
1573    Level: developer
1574 
1575 .seealso: `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`
1576 @*/
1577 PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason result) {
1578   PetscFunctionBegin;
1579   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1580   linesearch->result = result;
1581   PetscFunctionReturn(0);
1582 }
1583 
1584 /*@C
1585    SNESLineSearchSetVIFunctions - Sets VI-specific functions for line search computation.
1586 
1587    Logically Collective on linesearch
1588 
1589    Input Parameters:
1590 +  snes - nonlinear context obtained from `SNESCreate()`
1591 .  projectfunc - function for projecting the function to the bounds
1592 -  normfunc - function for computing the norm of an active set
1593 
1594    Calling sequence of projectfunc:
1595 .vb
1596    projectfunc (SNES snes, Vec X)
1597 .ve
1598 
1599     Input parameters for projectfunc:
1600 +   snes - nonlinear context
1601 -   X - current solution
1602 
1603     Output parameter for projectfunc:
1604 .   X - Projected solution
1605 
1606    Calling sequence of normfunc:
1607 .vb
1608    projectfunc (SNES snes, Vec X, Vec F, PetscScalar * fnorm)
1609 .ve
1610 
1611     Input parameters for normfunc:
1612 +   snes - nonlinear context
1613 .   X - current solution
1614 -   F - current residual
1615 
1616     Output parameter for normfunc:
1617 .   fnorm - VI-specific norm of the function
1618 
1619     Note:
1620     The VI solvers require projection of the solution to the feasible set.  projectfunc should implement this.
1621 
1622     The VI solvers require special evaluation of the function norm such that the norm is only calculated
1623     on the inactive set.  This should be implemented by normfunc.
1624 
1625     Level: advanced
1626 
1627 .seealso: `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`
1628 @*/
1629 PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc projectfunc, SNESLineSearchVINormFunc normfunc) {
1630   PetscFunctionBegin;
1631   PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 1);
1632   if (projectfunc) linesearch->ops->viproject = projectfunc;
1633   if (normfunc) linesearch->ops->vinorm = normfunc;
1634   PetscFunctionReturn(0);
1635 }
1636 
1637 /*@C
1638    SNESLineSearchGetVIFunctions - Sets VI-specific functions for line search computation.
1639 
1640    Not Collective
1641 
1642    Input Parameter:
1643 .  linesearch - the line search context, obtain with `SNESGetLineSearch()`
1644 
1645    Output Parameters:
1646 +  projectfunc - function for projecting the function to the bounds
1647 -  normfunc - function for computing the norm of an active set
1648 
1649     Level: advanced
1650 
1651 .seealso: `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`
1652 @*/
1653 PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFunc *projectfunc, SNESLineSearchVINormFunc *normfunc) {
1654   PetscFunctionBegin;
1655   if (projectfunc) *projectfunc = linesearch->ops->viproject;
1656   if (normfunc) *normfunc = linesearch->ops->vinorm;
1657   PetscFunctionReturn(0);
1658 }
1659 
1660 /*@C
1661   SNESLineSearchRegister - register a line search method
1662 
1663   Level: advanced
1664 
1665 .seealso: `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
1666 @*/
1667 PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch)) {
1668   PetscFunctionBegin;
1669   PetscCall(SNESInitializePackage());
1670   PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
1671   PetscFunctionReturn(0);
1672 }
1673