Actual source code: linesearch.c

  1: #include <petsc/private/linesearchimpl.h>

  3: PetscBool         SNESLineSearchRegisterAllCalled = PETSC_FALSE;
  4: PetscFunctionList SNESLineSearchList              = NULL;

  6: PetscClassId  SNESLINESEARCH_CLASSID;
  7: PetscLogEvent SNESLINESEARCH_Apply;

  9: /*@
 10:   SNESLineSearchMonitorCancel - Clears all the monitor functions for a `SNESLineSearch` object.

 12:   Logically Collective

 14:   Input Parameter:
 15: . ls - the `SNESLineSearch` context

 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

 22:   Level: advanced

 24:   Notes:
 25:   There is no way to clear one specific monitor from a `SNESLineSearch` object.

 27:   This does not clear the monitor set with `SNESLineSearchSetDefaultMonitor()` use `SNESLineSearchSetDefaultMonitor`(`ls`,`NULL`) to cancel it
 28:   that one.

 30: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorSet()`
 31: @*/
 32: PetscErrorCode SNESLineSearchMonitorCancel(SNESLineSearch ls)
 33: {
 34:   PetscInt i;

 36:   PetscFunctionBegin;
 38:   for (i = 0; i < ls->numbermonitors; i++) {
 39:     if (ls->monitordestroy[i]) PetscCall((*ls->monitordestroy[i])(&ls->monitorcontext[i]));
 40:   }
 41:   ls->numbermonitors = 0;
 42:   PetscFunctionReturn(PETSC_SUCCESS);
 43: }

 45: /*@
 46:   SNESLineSearchMonitor - runs the user provided monitor routines, if they exist

 48:   Collective

 50:   Input Parameter:
 51: . ls - the linesearch object

 53:   Level: developer

 55:   Note:
 56:   This routine is called by the `SNESLineSearch` implementations.
 57:   It does not typically need to be called by the user.

 59: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorSet()`
 60: @*/
 61: PetscErrorCode SNESLineSearchMonitor(SNESLineSearch ls)
 62: {
 63:   PetscInt i, n = ls->numbermonitors;

 65:   PetscFunctionBegin;
 66:   for (i = 0; i < n; i++) PetscCall((*ls->monitorftns[i])(ls, ls->monitorcontext[i]));
 67:   PetscFunctionReturn(PETSC_SUCCESS);
 68: }

 70: /*@C
 71:   SNESLineSearchMonitorSet - Sets an ADDITIONAL function that is to be used at every
 72:   iteration of the nonlinear solver to display the iteration's
 73:   progress.

 75:   Logically Collective

 77:   Input Parameters:
 78: + ls             - the `SNESLineSearch` context
 79: . f              - the monitor function
 80: . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
 81: - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence

 83:   Calling sequence of `f`:
 84: + ls   - the `SNESLineSearch` context
 85: - mctx - [optional] user-defined context for private data for the monitor routine

 87:   Level: intermediate

 89:   Note:
 90:   Several different monitoring routines may be set by calling
 91:   `SNESLineSearchMonitorSet()` multiple times; all will be called in the
 92:   order in which they were set.

 94:   Fortran Note:
 95:   Only a single monitor function can be set for each `SNESLineSearch` object

 97: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorDefault()`, `SNESLineSearchMonitorCancel()`, `PetscCtxDestroyFn`
 98: @*/
 99: PetscErrorCode SNESLineSearchMonitorSet(SNESLineSearch ls, PetscErrorCode (*f)(SNESLineSearch ls, void *mctx), void *mctx, PetscCtxDestroyFn *monitordestroy)
100: {
101:   PetscInt  i;
102:   PetscBool identical;

104:   PetscFunctionBegin;
106:   for (i = 0; i < ls->numbermonitors; i++) {
107:     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))ls->monitorftns[i], ls->monitorcontext[i], ls->monitordestroy[i], &identical));
108:     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
109:   }
110:   PetscCheck(ls->numbermonitors < MAXSNESLSMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
111:   ls->monitorftns[ls->numbermonitors]      = f;
112:   ls->monitordestroy[ls->numbermonitors]   = monitordestroy;
113:   ls->monitorcontext[ls->numbermonitors++] = mctx;
114:   PetscFunctionReturn(PETSC_SUCCESS);
115: }

117: /*@C
118:   SNESLineSearchMonitorSolutionUpdate - Monitors each update of the function value the linesearch tries

120:   Collective

122:   Input Parameters:
123: + ls - the `SNESLineSearch` object
124: - vf - the context for the monitor, in this case it is an `PetscViewerAndFormat`

126:   Options Database Key:
127: . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine

129:   Level: developer

131:   This is not normally called directly but is passed to `SNESLineSearchMonitorSet()`

133: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchMonitorSet()`, `SNESMonitorSolution()`
134: @*/
135: PetscErrorCode SNESLineSearchMonitorSolutionUpdate(SNESLineSearch ls, PetscViewerAndFormat *vf)
136: {
137:   PetscViewer viewer = vf->viewer;
138:   Vec         Y, W, G;

140:   PetscFunctionBegin;
141:   PetscCall(SNESLineSearchGetVecs(ls, NULL, NULL, &Y, &W, &G));
142:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
143:   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted update to solution \n"));
144:   PetscCall(VecView(Y, viewer));
145:   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted new solution \n"));
146:   PetscCall(VecView(W, viewer));
147:   PetscCall(PetscViewerASCIIPrintf(viewer, "LineSearch attempted updated function value\n"));
148:   PetscCall(VecView(G, viewer));
149:   PetscCall(PetscViewerPopFormat(viewer));
150:   PetscFunctionReturn(PETSC_SUCCESS);
151: }

153: /*@
154:   SNESLineSearchCreate - Creates a `SNESLineSearch` context.

156:   Logically Collective

158:   Input Parameter:
159: . comm - MPI communicator for the line search (typically from the associated `SNES` context).

161:   Output Parameter:
162: . outlinesearch - the new line search context

164:   Level: developer

166:   Note:
167:   The preferred calling sequence is to use `SNESGetLineSearch()` to acquire the `SNESLineSearch` instance
168:   already associated with the `SNES`.

170: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `LineSearchDestroy()`, `SNESGetLineSearch()`
171: @*/
172: PetscErrorCode SNESLineSearchCreate(MPI_Comm comm, SNESLineSearch *outlinesearch)
173: {
174:   SNESLineSearch linesearch;

176:   PetscFunctionBegin;
177:   PetscAssertPointer(outlinesearch, 2);
178:   PetscCall(SNESInitializePackage());

180:   PetscCall(PetscHeaderCreate(linesearch, SNESLINESEARCH_CLASSID, "SNESLineSearch", "Linesearch", "SNESLineSearch", comm, SNESLineSearchDestroy, SNESLineSearchView));
181:   linesearch->vec_sol_new  = NULL;
182:   linesearch->vec_func_new = NULL;
183:   linesearch->vec_sol      = NULL;
184:   linesearch->vec_func     = NULL;
185:   linesearch->vec_update   = NULL;

187:   linesearch->lambda       = 1.0;
188:   linesearch->fnorm        = 1.0;
189:   linesearch->ynorm        = 1.0;
190:   linesearch->xnorm        = 1.0;
191:   linesearch->result       = SNES_LINESEARCH_SUCCEEDED;
192:   linesearch->norms        = PETSC_TRUE;
193:   linesearch->keeplambda   = PETSC_FALSE;
194:   linesearch->damping      = 1.0;
195:   linesearch->maxstep      = 1e8;
196:   linesearch->steptol      = 1e-12;
197:   linesearch->rtol         = 1e-8;
198:   linesearch->atol         = 1e-15;
199:   linesearch->ltol         = 1e-8;
200:   linesearch->precheckctx  = NULL;
201:   linesearch->postcheckctx = NULL;
202:   linesearch->max_its      = 1;
203:   linesearch->setupcalled  = PETSC_FALSE;
204:   linesearch->monitor      = NULL;
205:   *outlinesearch           = linesearch;
206:   PetscFunctionReturn(PETSC_SUCCESS);
207: }

209: /*@
210:   SNESLineSearchSetUp - Prepares the line search for being applied by allocating
211:   any required vectors.

213:   Collective

215:   Input Parameter:
216: . linesearch - The `SNESLineSearch` instance.

218:   Level: advanced

220:   Note:
221:   For most cases, this needn't be called by users or outside of `SNESLineSearchApply()`.
222:   The only current case where this is called outside of this is for the VI
223:   solvers, which modify the solution and work vectors before the first call
224:   of `SNESLineSearchApply()`, requiring the `SNESLineSearch` work vectors to be
225:   allocated upfront.

227: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchReset()`
228: @*/
229: PetscErrorCode SNESLineSearchSetUp(SNESLineSearch linesearch)
230: {
231:   PetscFunctionBegin;
232:   if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
233:   if (!linesearch->setupcalled) {
234:     if (!linesearch->vec_sol_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_sol_new));
235:     if (!linesearch->vec_func_new) PetscCall(VecDuplicate(linesearch->vec_sol, &linesearch->vec_func_new));
236:     PetscTryTypeMethod(linesearch, setup);
237:     if (!linesearch->ops->snesfunc) PetscCall(SNESLineSearchSetFunction(linesearch, SNESComputeFunction));
238:     linesearch->lambda      = linesearch->damping;
239:     linesearch->setupcalled = PETSC_TRUE;
240:   }
241:   PetscFunctionReturn(PETSC_SUCCESS);
242: }

244: /*@
245:   SNESLineSearchReset - Undoes the `SNESLineSearchSetUp()` and deletes any `Vec`s or `Mat`s allocated by the line search.

247:   Collective

249:   Input Parameter:
250: . linesearch - The `SNESLineSearch` instance.

252:   Level: developer

254:   Note:
255:   Usually only called by `SNESReset()`

257: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetUp()`
258: @*/
259: PetscErrorCode SNESLineSearchReset(SNESLineSearch linesearch)
260: {
261:   PetscFunctionBegin;
262:   PetscTryTypeMethod(linesearch, reset);

264:   PetscCall(VecDestroy(&linesearch->vec_sol_new));
265:   PetscCall(VecDestroy(&linesearch->vec_func_new));

267:   PetscCall(VecDestroyVecs(linesearch->nwork, &linesearch->work));

269:   linesearch->nwork       = 0;
270:   linesearch->setupcalled = PETSC_FALSE;
271:   PetscFunctionReturn(PETSC_SUCCESS);
272: }

274: /*@C
275:   SNESLineSearchSetFunction - Sets the function evaluation used by the `SNES` line search
276:   `

278:   Input Parameters:
279: + linesearch - the `SNESLineSearch` context
280: - func       - function evaluation routine, this is usually the function provided with `SNESSetFunction()`

282:   Calling sequence of `func`:
283: + snes - the `SNES` with which the `SNESLineSearch` context is associated with
284: . x    - the input vector
285: - f    - the computed value of the function

287:   Level: developer

289:   Note:
290:   By default the `SNESLineSearch` uses the function provided by `SNESSetFunction()` so this is rarely needed

292: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESSetFunction()`
293: @*/
294: PetscErrorCode SNESLineSearchSetFunction(SNESLineSearch linesearch, PetscErrorCode (*func)(SNES snes, Vec x, Vec f))
295: {
296:   PetscFunctionBegin;
298:   linesearch->ops->snesfunc = func;
299:   PetscFunctionReturn(PETSC_SUCCESS);
300: }

302: /*@C
303:   SNESLineSearchSetPreCheck - Sets a function that is called after the initial search direction has been computed but
304:   before the line search routine has been applied. Allows adjusting the result of (usually a linear solve) that
305:   determined the search direction.

307:   Logically Collective

309:   Input Parameters:
310: + linesearch - the `SNESLineSearch` context
311: . func       - [optional] function evaluation routine
312: - ctx        - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)

314:   Calling sequence of `func`:
315: + ls        - the `SNESLineSearch` context
316: . x         - the current solution
317: . d         - the current search direction
318: . changed_d - indicates if the search direction has been changed
319: - ctx       - the context passed to `SNESLineSearchSetPreCheck()`

321:   Level: intermediate

323:   Note:
324:   Use `SNESLineSearchSetPostCheck()` to change the step after the line search is complete.

326:   Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.

328: .seealso: [](ch_snes), `SNES`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
329:           `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`

331: @*/
332: PetscErrorCode SNESLineSearchSetPreCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch ls, Vec x, Vec d, PetscBool *changed_d, void *ctx), void *ctx)
333: {
334:   PetscFunctionBegin;
336:   if (func) linesearch->ops->precheck = func;
337:   if (ctx) linesearch->precheckctx = ctx;
338:   PetscFunctionReturn(PETSC_SUCCESS);
339: }

341: /*@C
342:   SNESLineSearchGetPreCheck - Gets the pre-check function for the line search routine.

344:   Input Parameter:
345: . linesearch - the `SNESLineSearch` context

347:   Output Parameters:
348: + func - [optional] function evaluation routine,  for calling sequence see `SNESLineSearchSetPreCheck()`
349: - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)

351:   Level: intermediate

353: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
354: @*/
355: PetscErrorCode SNESLineSearchGetPreCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, PetscBool *, void *), void **ctx)
356: {
357:   PetscFunctionBegin;
359:   if (func) *func = linesearch->ops->precheck;
360:   if (ctx) *ctx = linesearch->precheckctx;
361:   PetscFunctionReturn(PETSC_SUCCESS);
362: }

364: /*@C
365:   SNESLineSearchSetPostCheck - Sets a user function that is called after the line search has been applied to determine the step
366:   direction and length. Allows the user a chance to change or override the decision of the line search routine

368:   Logically Collective

370:   Input Parameters:
371: + linesearch - the `SNESLineSearch` context
372: . func       - [optional] function evaluation routine
373: - ctx        - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)

375:   Calling sequence of `func`:
376: + ls        - the `SNESLineSearch` context
377: . x         - the current solution
378: . d         - the current search direction
379: . w         - $ w = x + lambda*d $ for some lambda
380: . changed_d - indicates if the search direction `d` has been changed
381: . changed_w - indicates `w` has been changed
382: - ctx       - the context passed to `SNESLineSearchSetPreCheck()`

384:   Level: intermediate

386:   Notes:
387:   Use `SNESLineSearchSetPreCheck()` to change the step before the line search is completed.
388:   The calling sequence of the callback does not contain the current scaling factor. To access the value, use `SNESLineSearchGetLambda()`.

390:   Use `SNESVISetVariableBounds()` and `SNESVISetComputeVariableBounds()` to cause `SNES` to automatically control the ranges of variables allowed.

392: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchGetPostCheck()`,
393:           `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`
394: @*/
395: PetscErrorCode SNESLineSearchSetPostCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch ls, Vec x, Vec d, Vec w, PetscBool *changed_d, PetscBool *changed_w, void *ctx), void *ctx)
396: {
397:   PetscFunctionBegin;
399:   if (func) linesearch->ops->postcheck = func;
400:   if (ctx) linesearch->postcheckctx = ctx;
401:   PetscFunctionReturn(PETSC_SUCCESS);
402: }

404: /*@C
405:   SNESLineSearchGetPostCheck - Gets the post-check function for the line search routine.

407:   Input Parameter:
408: . linesearch - the `SNESLineSearch` context

410:   Output Parameters:
411: + func - [optional] function evaluation routine, see for the calling sequence `SNESLineSearchSetPostCheck()`
412: - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)

414:   Level: intermediate

416: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`
417: @*/
418: PetscErrorCode SNESLineSearchGetPostCheck(SNESLineSearch linesearch, PetscErrorCode (**func)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx)
419: {
420:   PetscFunctionBegin;
422:   if (func) *func = linesearch->ops->postcheck;
423:   if (ctx) *ctx = linesearch->postcheckctx;
424:   PetscFunctionReturn(PETSC_SUCCESS);
425: }

427: /*@
428:   SNESLineSearchPreCheck - Prepares the line search for being applied.

430:   Logically Collective

432:   Input Parameters:
433: + linesearch - The linesearch instance.
434: . X          - The current solution
435: - Y          - The step direction

437:   Output Parameter:
438: . changed - Indicator that the precheck routine has changed `Y`

440:   Level: advanced

442:   Note:
443:   This calls any function provided with `SNESLineSearchSetPreCheck()` and is called automatically inside the line search routines

445:   Developer Note:
446:   The use of `PetscObjectGetState()` would eliminate the need for the `changed` argument to be provided

448: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`, `SNESLineSearchSetPostCheck()`,
449:           `SNESLineSearchGetPostCheck()`
450: @*/
451: PetscErrorCode SNESLineSearchPreCheck(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed)
452: {
453:   PetscFunctionBegin;
454:   *changed = PETSC_FALSE;
455:   if (linesearch->ops->precheck) {
456:     PetscUseTypeMethod(linesearch, precheck, X, Y, changed, linesearch->precheckctx);
458:   }
459:   PetscFunctionReturn(PETSC_SUCCESS);
460: }

462: /*@
463:   SNESLineSearchPostCheck - Hook to modify step direction or updated solution after a successful linesearch

465:   Logically Collective

467:   Input Parameters:
468: + linesearch - The line search context
469: . X          - The last solution
470: . Y          - The step direction
471: - W          - The updated solution, `W = X - lambda * Y` for some lambda

473:   Output Parameters:
474: + changed_Y - Indicator if the direction `Y` has been changed.
475: - changed_W - Indicator if the new candidate solution `W` has been changed.

477:   Level: developer

479:   Note:
480:   This calls any function provided with `SNESLineSearchSetPostCheck()` and is called automatically inside the line search routines

482:   Developer Note:
483:   The use of `PetscObjectGetState()` would eliminate the need for the `changed_Y` and `changed_W` arguments to be provided

485: .seealso: [](ch_snes), `SNES`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPrecheck()`, `SNESLineSearchGetPrecheck()`
486: @*/
487: PetscErrorCode SNESLineSearchPostCheck(SNESLineSearch linesearch, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W)
488: {
489:   PetscFunctionBegin;
490:   *changed_Y = PETSC_FALSE;
491:   *changed_W = PETSC_FALSE;
492:   if (linesearch->ops->postcheck) {
493:     PetscUseTypeMethod(linesearch, postcheck, X, Y, W, changed_Y, changed_W, linesearch->postcheckctx);
496:   }
497:   PetscFunctionReturn(PETSC_SUCCESS);
498: }

500: /*@C
501:   SNESLineSearchPreCheckPicard - Implements a correction that is sometimes useful to improve the convergence rate of Picard iteration {cite}`hindmarsh1996time`

503:   Logically Collective

505:   Input Parameters:
506: + linesearch - the line search context
507: . X          - base state for this step
508: - ctx        - context for this function

510:   Input/Output Parameter:
511: . Y - correction, possibly modified

513:   Output Parameter:
514: . changed - flag indicating that `Y` was modified

516:   Options Database Keys:
517: + -snes_linesearch_precheck_picard       - activate this routine
518: - -snes_linesearch_precheck_picard_angle - angle

520:   Level: advanced

522:   Notes:
523:   This function should be passed to `SNESLineSearchSetPreCheck()`

525:   The justification for this method involves the linear convergence of a Picard iteration
526:   so the Picard linearization should be provided in place of the "Jacobian"  {cite}`hindmarsh1996time`. This correction
527:   is generally not useful when using a Newton linearization.

529:   Developer Note:
530:   The use of `PetscObjectGetState()` would eliminate the need for the `changed` argument to be provided

532: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESSetPicard()`, `SNESGetLineSearch()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
533: @*/
534: PetscErrorCode SNESLineSearchPreCheckPicard(SNESLineSearch linesearch, Vec X, Vec Y, PetscBool *changed, void *ctx)
535: {
536:   PetscReal   angle = *(PetscReal *)linesearch->precheckctx;
537:   Vec         Ylast;
538:   PetscScalar dot;
539:   PetscInt    iter;
540:   PetscReal   ynorm, ylastnorm, theta, angle_radians;
541:   SNES        snes;

543:   PetscFunctionBegin;
544:   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
545:   PetscCall(PetscObjectQuery((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject *)&Ylast));
546:   if (!Ylast) {
547:     PetscCall(VecDuplicate(Y, &Ylast));
548:     PetscCall(PetscObjectCompose((PetscObject)snes, "SNESLineSearchPreCheckPicard_Ylast", (PetscObject)Ylast));
549:     PetscCall(PetscObjectDereference((PetscObject)Ylast));
550:   }
551:   PetscCall(SNESGetIterationNumber(snes, &iter));
552:   if (iter < 2) {
553:     PetscCall(VecCopy(Y, Ylast));
554:     *changed = PETSC_FALSE;
555:     PetscFunctionReturn(PETSC_SUCCESS);
556:   }

558:   PetscCall(VecDot(Y, Ylast, &dot));
559:   PetscCall(VecNorm(Y, NORM_2, &ynorm));
560:   PetscCall(VecNorm(Ylast, NORM_2, &ylastnorm));
561:   /* Compute the angle between the vectors Y and Ylast, clip to keep inside the domain of acos() */
562:   theta         = PetscAcosReal((PetscReal)PetscClipInterval(PetscAbsScalar(dot) / (ynorm * ylastnorm), -1.0, 1.0));
563:   angle_radians = angle * PETSC_PI / 180.;
564:   if (PetscAbsReal(theta) < angle_radians || PetscAbsReal(theta - PETSC_PI) < angle_radians) {
565:     /* Modify the step Y */
566:     PetscReal alpha, ydiffnorm;
567:     PetscCall(VecAXPY(Ylast, -1.0, Y));
568:     PetscCall(VecNorm(Ylast, NORM_2, &ydiffnorm));
569:     alpha = (ydiffnorm > .001 * ylastnorm) ? ylastnorm / ydiffnorm : 1000.0;
570:     PetscCall(VecCopy(Y, Ylast));
571:     PetscCall(VecScale(Y, alpha));
572:     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));
573:     *changed = PETSC_TRUE;
574:   } else {
575:     PetscCall(PetscInfo(snes, "Angle %14.12e degrees exceeds threshold %14.12e, no correction applied\n", (double)(theta * 180 / PETSC_PI), (double)angle));
576:     PetscCall(VecCopy(Y, Ylast));
577:     *changed = PETSC_FALSE;
578:   }
579:   PetscFunctionReturn(PETSC_SUCCESS);
580: }

582: /*@
583:   SNESLineSearchApply - Computes the line-search update.

585:   Collective

587:   Input Parameter:
588: . linesearch - The line search context

590:   Input/Output Parameters:
591: + X     - The current solution, on output the new solution
592: . F     - The current function value, on output the new function value at the solution value `X`
593: . fnorm - The current norm of `F`, on output the new norm of `F`
594: - Y     - The current search direction, on output the direction determined by the linesearch, i.e. Xnew = Xold - lambda*Y

596:   Options Database Keys:
597: + -snes_linesearch_type                - basic (or equivalently none), bt, l2, cp, nleqerr, bisection, shell
598: . -snes_linesearch_monitor [:filename] - Print progress of line searches
599: . -snes_linesearch_damping             - The linesearch damping parameter, default is 1.0 (no damping)
600: . -snes_linesearch_norms               - Turn on/off the linesearch norms computation (SNESLineSearchSetComputeNorms())
601: . -snes_linesearch_keeplambda          - Keep the previous search length as the initial guess
602: - -snes_linesearch_max_it              - The number of iterations for iterative line searches

604:   Level: intermediate

606:   Notes:
607:   This is typically called from within a `SNESSolve()` implementation in order to
608:   help with convergence of the nonlinear method.  Various `SNES` types use line searches
609:   in different ways, but the overarching theme is that a line search is used to determine
610:   an optimal damping parameter of a step at each iteration of the method.  Each
611:   application of the line search may invoke `SNESComputeFunction()` several times, and
612:   therefore may be fairly expensive.

614: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchGetLambda()`, `SNESLineSearchPreCheck()`, `SNESLineSearchPostCheck()`, `SNESSolve()`, `SNESComputeFunction()`, `SNESLineSearchSetComputeNorms()`,
615:           `SNESLineSearchType`, `SNESLineSearchSetType()`
616: @*/
617: PetscErrorCode SNESLineSearchApply(SNESLineSearch linesearch, Vec X, Vec F, PetscReal *fnorm, Vec Y)
618: {
619:   PetscFunctionBegin;

625:   linesearch->result = SNES_LINESEARCH_SUCCEEDED;

627:   linesearch->vec_sol    = X;
628:   linesearch->vec_update = Y;
629:   linesearch->vec_func   = F;

631:   PetscCall(SNESLineSearchSetUp(linesearch));

633:   if (!linesearch->keeplambda) linesearch->lambda = linesearch->damping; /* set the initial guess to lambda */

635:   if (fnorm) linesearch->fnorm = *fnorm;
636:   else PetscCall(VecNorm(F, NORM_2, &linesearch->fnorm));

638:   PetscCall(PetscLogEventBegin(SNESLINESEARCH_Apply, linesearch, X, F, Y));

640:   PetscUseTypeMethod(linesearch, apply);

642:   PetscCall(PetscLogEventEnd(SNESLINESEARCH_Apply, linesearch, X, F, Y));

644:   if (fnorm) *fnorm = linesearch->fnorm;
645:   PetscFunctionReturn(PETSC_SUCCESS);
646: }

648: /*@
649:   SNESLineSearchDestroy - Destroys the line search instance.

651:   Collective

653:   Input Parameter:
654: . linesearch - The line search context

656:   Level: developer

658:   Note:
659:   The line search in `SNES` is automatically called on `SNESDestroy()` so this call is rarely needed

661: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchReset()`, `SNESDestroy()`
662: @*/
663: PetscErrorCode SNESLineSearchDestroy(SNESLineSearch *linesearch)
664: {
665:   PetscFunctionBegin;
666:   if (!*linesearch) PetscFunctionReturn(PETSC_SUCCESS);
668:   if (--((PetscObject)*linesearch)->refct > 0) {
669:     *linesearch = NULL;
670:     PetscFunctionReturn(PETSC_SUCCESS);
671:   }
672:   PetscCall(PetscObjectSAWsViewOff((PetscObject)*linesearch));
673:   PetscCall(SNESLineSearchReset(*linesearch));
674:   PetscTryTypeMethod(*linesearch, destroy);
675:   PetscCall(PetscViewerDestroy(&(*linesearch)->monitor));
676:   PetscCall(SNESLineSearchMonitorCancel(*linesearch));
677:   PetscCall(PetscHeaderDestroy(linesearch));
678:   PetscFunctionReturn(PETSC_SUCCESS);
679: }

681: /*@
682:   SNESLineSearchSetDefaultMonitor - Turns on/off printing useful information and debugging output about the line search.

684:   Logically Collective

686:   Input Parameters:
687: + linesearch - the linesearch object
688: - viewer     - an `PETSCVIEWERASCII` `PetscViewer` or `NULL` to turn off monitor

690:   Options Database Key:
691: . -snes_linesearch_monitor [:filename] - enables the monitor

693:   Level: intermediate

695:   Developer Notes:
696:   This monitor is implemented differently than the other line search monitors that are set with
697:   `SNESLineSearchMonitorSet()` since it is called in many locations of the line search routines to display aspects of the
698:   line search that are not visible to the other monitors.

700: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `PETSCVIEWERASCII`, `SNESGetLineSearch()`, `SNESLineSearchGetDefaultMonitor()`, `PetscViewer`, `SNESLineSearchSetMonitor()`,
701:           `SNESLineSearchMonitorSetFromOptions()`
702: @*/
703: PetscErrorCode SNESLineSearchSetDefaultMonitor(SNESLineSearch linesearch, PetscViewer viewer)
704: {
705:   PetscFunctionBegin;
706:   PetscCall(PetscViewerDestroy(&linesearch->monitor));
707:   linesearch->monitor = viewer;
708:   PetscFunctionReturn(PETSC_SUCCESS);
709: }

711: /*@
712:   SNESLineSearchGetDefaultMonitor - Gets the `PetscViewer` instance for the default line search monitor that is turned on with `SNESLineSearchSetDefaultMonitor()`

714:   Logically Collective

716:   Input Parameter:
717: . linesearch - the line search context

719:   Output Parameter:
720: . monitor - monitor context

722:   Level: intermediate

724: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetDefaultMonitor()`, `PetscViewer`
725: @*/
726: PetscErrorCode SNESLineSearchGetDefaultMonitor(SNESLineSearch linesearch, PetscViewer *monitor)
727: {
728:   PetscFunctionBegin;
730:   *monitor = linesearch->monitor;
731:   PetscFunctionReturn(PETSC_SUCCESS);
732: }

734: /*@C
735:   SNESLineSearchMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated in the options database

737:   Collective

739:   Input Parameters:
740: + ls           - `SNESLineSearch` object to monitor
741: . name         - the monitor type
742: . help         - message indicating what monitoring is done
743: . manual       - manual page for the monitor
744: . monitor      - the monitor function, must use `PetscViewerAndFormat` as its context
745: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `SNESLineSearch` or `PetscViewer`

747:   Calling sequence of `monitor`:
748: + ls - `SNESLineSearch` object being monitored
749: - vf - a `PetscViewerAndFormat` struct that provides the `PetscViewer` and `PetscViewerFormat` being used

751:   Calling sequence of `monitorsetup`:
752: + ls - `SNESLineSearch` object being monitored
753: - vf - a `PetscViewerAndFormat` struct that provides the `PetscViewer` and `PetscViewerFormat` being used

755:   Level: advanced

757: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetMonitor()`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
758:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
759:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
760:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
761:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
762:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
763:           `PetscOptionsFList()`, `PetscOptionsEList()`
764: @*/
765: PetscErrorCode SNESLineSearchMonitorSetFromOptions(SNESLineSearch ls, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(SNESLineSearch ls, PetscViewerAndFormat *vf), PetscErrorCode (*monitorsetup)(SNESLineSearch ls, PetscViewerAndFormat *vf))
766: {
767:   PetscViewer       viewer;
768:   PetscViewerFormat format;
769:   PetscBool         flg;

771:   PetscFunctionBegin;
772:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)ls), ((PetscObject)ls)->options, ((PetscObject)ls)->prefix, name, &viewer, &format, &flg));
773:   if (flg) {
774:     PetscViewerAndFormat *vf;
775:     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
776:     PetscCall(PetscViewerDestroy(&viewer));
777:     if (monitorsetup) PetscCall((*monitorsetup)(ls, vf));
778:     PetscCall(SNESLineSearchMonitorSet(ls, (PetscErrorCode (*)(SNESLineSearch, void *))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
779:   }
780:   PetscFunctionReturn(PETSC_SUCCESS);
781: }

783: /*@
784:   SNESLineSearchSetFromOptions - Sets options for the line search

786:   Logically Collective

788:   Input Parameter:
789: . linesearch - a `SNESLineSearch` line search context

791:   Options Database Keys:
792: + -snes_linesearch_type <type>                                      - basic (or equivalently none), bt, l2, cp, nleqerr, bisection, shell
793: . -snes_linesearch_order <order>                                    - 1, 2, 3.  Most types only support certain orders (bt supports 2 or 3)
794: . -snes_linesearch_norms                                            - Turn on/off the linesearch norms for the basic linesearch typem (`SNESLineSearchSetComputeNorms()`)
795: . -snes_linesearch_minlambda                                        - The minimum step length
796: . -snes_linesearch_maxstep                                          - The maximum step size
797: . -snes_linesearch_rtol                                             - Relative tolerance for iterative line searches
798: . -snes_linesearch_atol                                             - Absolute tolerance for iterative line searches
799: . -snes_linesearch_ltol                                             - Change in lambda tolerance for iterative line searches
800: . -snes_linesearch_max_it                                           - The number of iterations for iterative line searches
801: . -snes_linesearch_monitor [:filename]                              - Print progress of line searches
802: . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine
803: . -snes_linesearch_damping                                          - The linesearch damping parameter
804: . -snes_linesearch_keeplambda                                       - Keep the previous search length as the initial guess.
805: . -snes_linesearch_precheck_picard                                  - Use precheck that speeds up convergence of picard method
806: - -snes_linesearch_precheck_picard_angle                            - Angle used in Picard precheck method

808:   Level: intermediate

810: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchCreate()`, `SNESLineSearchSetOrder()`, `SNESLineSearchSetType()`, `SNESLineSearchSetTolerances()`, `SNESLineSearchSetDamping()`, `SNESLineSearchPreCheckPicard()`,
811:           `SNESLineSearchType`, `SNESLineSearchSetComputeNorms()`
812: @*/
813: PetscErrorCode SNESLineSearchSetFromOptions(SNESLineSearch linesearch)
814: {
815:   const char *deft = SNESLINESEARCHBASIC;
816:   char        type[256];
817:   PetscBool   flg, set;
818:   PetscViewer viewer;

820:   PetscFunctionBegin;
821:   PetscCall(SNESLineSearchRegisterAll());

823:   PetscObjectOptionsBegin((PetscObject)linesearch);
824:   if (((PetscObject)linesearch)->type_name) deft = ((PetscObject)linesearch)->type_name;
825:   PetscCall(PetscOptionsFList("-snes_linesearch_type", "Linesearch type", "SNESLineSearchSetType", SNESLineSearchList, deft, type, 256, &flg));
826:   if (flg) {
827:     PetscCall(SNESLineSearchSetType(linesearch, type));
828:   } else if (!((PetscObject)linesearch)->type_name) {
829:     PetscCall(SNESLineSearchSetType(linesearch, deft));
830:   }

832:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)linesearch), ((PetscObject)linesearch)->options, ((PetscObject)linesearch)->prefix, "-snes_linesearch_monitor", &viewer, NULL, &set));
833:   if (set) PetscCall(SNESLineSearchSetDefaultMonitor(linesearch, viewer));
834:   PetscCall(SNESLineSearchMonitorSetFromOptions(linesearch, "-snes_linesearch_monitor_solution_update", "View correction at each iteration", "SNESLineSearchMonitorSolutionUpdate", SNESLineSearchMonitorSolutionUpdate, NULL));

836:   /* tolerances */
837:   PetscCall(PetscOptionsReal("-snes_linesearch_minlambda", "Minimum step length", "SNESLineSearchSetTolerances", linesearch->steptol, &linesearch->steptol, NULL));
838:   PetscCall(PetscOptionsReal("-snes_linesearch_maxstep", "Maximum step size", "SNESLineSearchSetTolerances", linesearch->maxstep, &linesearch->maxstep, NULL));
839:   PetscCall(PetscOptionsReal("-snes_linesearch_rtol", "Relative tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->rtol, &linesearch->rtol, NULL));
840:   PetscCall(PetscOptionsReal("-snes_linesearch_atol", "Absolute tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->atol, &linesearch->atol, NULL));
841:   PetscCall(PetscOptionsReal("-snes_linesearch_ltol", "Change in lambda tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->ltol, &linesearch->ltol, NULL));
842:   PetscCall(PetscOptionsInt("-snes_linesearch_max_it", "Maximum iterations for iterative line searches", "SNESLineSearchSetTolerances", linesearch->max_its, &linesearch->max_its, NULL));

844:   /* damping parameters */
845:   PetscCall(PetscOptionsReal("-snes_linesearch_damping", "Line search damping and initial step guess", "SNESLineSearchSetDamping", linesearch->damping, &linesearch->damping, NULL));

847:   PetscCall(PetscOptionsBool("-snes_linesearch_keeplambda", "Use previous lambda as damping", "SNESLineSearchSetKeepLambda", linesearch->keeplambda, &linesearch->keeplambda, NULL));

849:   /* precheck */
850:   PetscCall(PetscOptionsBool("-snes_linesearch_precheck_picard", "Use a correction that sometimes improves convergence of Picard iteration", "SNESLineSearchPreCheckPicard", flg, &flg, &set));
851:   if (set) {
852:     if (flg) {
853:       linesearch->precheck_picard_angle = 10.; /* correction only active if angle is less than 10 degrees */

855:       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));
856:       PetscCall(SNESLineSearchSetPreCheck(linesearch, SNESLineSearchPreCheckPicard, &linesearch->precheck_picard_angle));
857:     } else {
858:       PetscCall(SNESLineSearchSetPreCheck(linesearch, NULL, NULL));
859:     }
860:   }
861:   PetscCall(PetscOptionsInt("-snes_linesearch_order", "Order of approximation used in the line search", "SNESLineSearchSetOrder", linesearch->order, &linesearch->order, NULL));
862:   PetscCall(PetscOptionsBool("-snes_linesearch_norms", "Compute final norms in line search", "SNESLineSearchSetComputeNorms", linesearch->norms, &linesearch->norms, NULL));

864:   PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);

866:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
867:   PetscOptionsEnd();
868:   PetscFunctionReturn(PETSC_SUCCESS);
869: }

871: /*@
872:   SNESLineSearchView - Prints useful information about the line search

874:   Logically Collective

876:   Input Parameters:
877: + linesearch - line search context
878: - viewer     - the `PetscViewer` to display the line search information to

880:   Level: intermediate

882: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `PetscViewer`, `SNESLineSearchCreate()`
883: @*/
884: PetscErrorCode SNESLineSearchView(SNESLineSearch linesearch, PetscViewer viewer)
885: {
886:   PetscBool iascii;

888:   PetscFunctionBegin;
890:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
892:   PetscCheckSameComm(linesearch, 1, viewer, 2);

894:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
895:   if (iascii) {
896:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)linesearch, viewer));
897:     PetscCall(PetscViewerASCIIPushTab(viewer));
898:     PetscTryTypeMethod(linesearch, view, viewer);
899:     PetscCall(PetscViewerASCIIPopTab(viewer));
900:     PetscCall(PetscViewerASCIIPrintf(viewer, "  maxstep=%e, minlambda=%e\n", (double)linesearch->maxstep, (double)linesearch->steptol));
901:     PetscCall(PetscViewerASCIIPrintf(viewer, "  tolerances: relative=%e, absolute=%e, lambda=%e\n", (double)linesearch->rtol, (double)linesearch->atol, (double)linesearch->ltol));
902:     PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum iterations=%" PetscInt_FMT "\n", linesearch->max_its));
903:     if (linesearch->ops->precheck) {
904:       if (linesearch->ops->precheck == SNESLineSearchPreCheckPicard) {
905:         PetscCall(PetscViewerASCIIPrintf(viewer, "  using precheck step to speed up Picard convergence\n"));
906:       } else {
907:         PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined precheck step\n"));
908:       }
909:     }
910:     if (linesearch->ops->postcheck) PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined postcheck step\n"));
911:   }
912:   PetscFunctionReturn(PETSC_SUCCESS);
913: }

915: /*@
916:   SNESLineSearchGetType - Gets the `SNESLinesearchType` of a `SNESLineSearch`

918:   Logically Collective

920:   Input Parameter:
921: . linesearch - the line search context

923:   Output Parameter:
924: . type - The type of line search, or `NULL` if not set

926:   Level: intermediate

928: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchSetType()`
929: @*/
930: PetscErrorCode SNESLineSearchGetType(SNESLineSearch linesearch, SNESLineSearchType *type)
931: {
932:   PetscFunctionBegin;
934:   PetscAssertPointer(type, 2);
935:   *type = ((PetscObject)linesearch)->type_name;
936:   PetscFunctionReturn(PETSC_SUCCESS);
937: }

939: /*@
940:   SNESLineSearchSetType - Sets the `SNESLinesearchType` of a `SNESLineSearch`

942:   Logically Collective

944:   Input Parameters:
945: + linesearch - the line search context
946: - type       - The type of line search to be used, see `SNESLineSearchType`

948:   Options Database Key:
949: . -snes_linesearch_type <type> - basic (or equivalently none), bt, l2, cp, nleqerr, shell

951:   Level: intermediate

953: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`
954: @*/
955: PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type)
956: {
957:   PetscBool match;
958:   PetscErrorCode (*r)(SNESLineSearch);

960:   PetscFunctionBegin;
962:   PetscAssertPointer(type, 2);

964:   PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
965:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

967:   PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
968:   PetscCheck(r, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
969:   /* Destroy the previous private line search context */
970:   PetscTryTypeMethod(linesearch, destroy);
971:   linesearch->ops->destroy = NULL;
972:   /* Reinitialize function pointers in SNESLineSearchOps structure */
973:   linesearch->ops->apply          = NULL;
974:   linesearch->ops->view           = NULL;
975:   linesearch->ops->setfromoptions = NULL;
976:   linesearch->ops->destroy        = NULL;

978:   PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
979:   PetscCall((*r)(linesearch));
980:   PetscFunctionReturn(PETSC_SUCCESS);
981: }

983: /*@
984:   SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.

986:   Input Parameters:
987: + linesearch - the line search context
988: - snes       - The `SNES` instance

990:   Level: developer

992:   Note:
993:   This happens automatically when the line search is obtained/created with
994:   `SNESGetLineSearch()`.  This routine is therefore mainly called within `SNES`
995:   implementations.

997: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`
998: @*/
999: PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes)
1000: {
1001:   PetscFunctionBegin;
1004:   linesearch->snes = snes;
1005:   PetscFunctionReturn(PETSC_SUCCESS);
1006: }

1008: /*@
1009:   SNESLineSearchGetSNES - Gets the `SNES` instance associated with the line search.

1011:   Not Collective

1013:   Input Parameter:
1014: . linesearch - the line search context

1016:   Output Parameter:
1017: . snes - The `SNES` instance

1019:   Level: developer

1021: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESType`, `SNESLineSearchSetVecs()`
1022: @*/
1023: PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes)
1024: {
1025:   PetscFunctionBegin;
1027:   PetscAssertPointer(snes, 2);
1028:   *snes = linesearch->snes;
1029:   PetscFunctionReturn(PETSC_SUCCESS);
1030: }

1032: /*@
1033:   SNESLineSearchGetLambda - Gets the last line search steplength used

1035:   Not Collective

1037:   Input Parameter:
1038: . linesearch - the line search context

1040:   Output Parameter:
1041: . lambda - The last steplength computed during `SNESLineSearchApply()`

1043:   Level: advanced

1045:   Note:
1046:   This is useful in methods where the solver is ill-scaled and
1047:   requires some adaptive notion of the difference in scale between the
1048:   solution and the function.  For instance, `SNESQN` may be scaled by the
1049:   line search lambda using the argument -snes_qn_scaling ls.

1051: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
1052: @*/
1053: PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda)
1054: {
1055:   PetscFunctionBegin;
1057:   PetscAssertPointer(lambda, 2);
1058:   *lambda = linesearch->lambda;
1059:   PetscFunctionReturn(PETSC_SUCCESS);
1060: }

1062: /*@
1063:   SNESLineSearchSetLambda - Sets the line search steplength

1065:   Input Parameters:
1066: + linesearch - line search context
1067: - lambda     - The steplength to use

1069:   Level: advanced

1071:   Note:
1072:   This routine is typically used within implementations of `SNESLineSearchApply()`
1073:   to set the final steplength.  This routine (and `SNESLineSearchGetLambda()`) were
1074:   added in order to facilitate Quasi-Newton methods that use the previous steplength
1075:   as an inner scaling parameter.

1077: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetLambda()`
1078: @*/
1079: PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda)
1080: {
1081:   PetscFunctionBegin;
1083:   linesearch->lambda = lambda;
1084:   PetscFunctionReturn(PETSC_SUCCESS);
1085: }

1087: /*@
1088:   SNESLineSearchGetTolerances - Gets the tolerances for the line search.

1090:   Not Collective

1092:   Input Parameter:
1093: . linesearch - the line search context

1095:   Output Parameters:
1096: + steptol - The minimum steplength
1097: . maxstep - The maximum steplength
1098: . rtol    - The relative tolerance for iterative line searches
1099: . atol    - The absolute tolerance for iterative line searches
1100: . ltol    - The change in lambda tolerance for iterative line searches
1101: - max_its - The maximum number of iterations of the line search

1103:   Level: intermediate

1105:   Note:
1106:   Different line searches may implement these parameters slightly differently as
1107:   the type requires.

1109: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetTolerances()`
1110: @*/
1111: PetscErrorCode SNESLineSearchGetTolerances(SNESLineSearch linesearch, PetscReal *steptol, PetscReal *maxstep, PetscReal *rtol, PetscReal *atol, PetscReal *ltol, PetscInt *max_its)
1112: {
1113:   PetscFunctionBegin;
1115:   if (steptol) {
1116:     PetscAssertPointer(steptol, 2);
1117:     *steptol = linesearch->steptol;
1118:   }
1119:   if (maxstep) {
1120:     PetscAssertPointer(maxstep, 3);
1121:     *maxstep = linesearch->maxstep;
1122:   }
1123:   if (rtol) {
1124:     PetscAssertPointer(rtol, 4);
1125:     *rtol = linesearch->rtol;
1126:   }
1127:   if (atol) {
1128:     PetscAssertPointer(atol, 5);
1129:     *atol = linesearch->atol;
1130:   }
1131:   if (ltol) {
1132:     PetscAssertPointer(ltol, 6);
1133:     *ltol = linesearch->ltol;
1134:   }
1135:   if (max_its) {
1136:     PetscAssertPointer(max_its, 7);
1137:     *max_its = linesearch->max_its;
1138:   }
1139:   PetscFunctionReturn(PETSC_SUCCESS);
1140: }

1142: /*@
1143:   SNESLineSearchSetTolerances -  Sets the tolerances for the linesearch.

1145:   Collective

1147:   Input Parameters:
1148: + linesearch - the line search context
1149: . steptol    - The minimum steplength
1150: . maxstep    - The maximum steplength
1151: . rtol       - The relative tolerance for iterative line searches
1152: . atol       - The absolute tolerance for iterative line searches
1153: . ltol       - The change in lambda tolerance for iterative line searches
1154: - max_it     - The maximum number of iterations of the line search

1156:   Options Database Keys:
1157: + -snes_linesearch_minlambda - The minimum step length
1158: . -snes_linesearch_maxstep   - The maximum step size
1159: . -snes_linesearch_rtol      - Relative tolerance for iterative line searches
1160: . -snes_linesearch_atol      - Absolute tolerance for iterative line searches
1161: . -snes_linesearch_ltol      - Change in lambda tolerance for iterative line searches
1162: - -snes_linesearch_max_it    - The number of iterations for iterative line searches

1164:   Level: intermediate

1166:   Note:
1167:   The user may choose to not set any of the tolerances using `PETSC_DEFAULT` in place of an argument.

1169: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetTolerances()`
1170: @*/
1171: PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal steptol, PetscReal maxstep, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_it)
1172: {
1173:   PetscFunctionBegin;

1182:   if (steptol != (PetscReal)PETSC_DEFAULT) {
1183:     PetscCheck(steptol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum step length %14.12e must be non-negative", (double)steptol);
1184:     linesearch->steptol = steptol;
1185:   }

1187:   if (maxstep != (PetscReal)PETSC_DEFAULT) {
1188:     PetscCheck(maxstep >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum step length %14.12e must be non-negative", (double)maxstep);
1189:     linesearch->maxstep = maxstep;
1190:   }

1192:   if (rtol != (PetscReal)PETSC_DEFAULT) {
1193:     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);
1194:     linesearch->rtol = rtol;
1195:   }

1197:   if (atol != (PetscReal)PETSC_DEFAULT) {
1198:     PetscCheck(atol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %14.12e must be non-negative", (double)atol);
1199:     linesearch->atol = atol;
1200:   }

1202:   if (ltol != (PetscReal)PETSC_DEFAULT) {
1203:     PetscCheck(ltol >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Lambda tolerance %14.12e must be non-negative", (double)ltol);
1204:     linesearch->ltol = ltol;
1205:   }

1207:   if (max_it != PETSC_DEFAULT) {
1208:     PetscCheck(max_it >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_it);
1209:     linesearch->max_its = max_it;
1210:   }
1211:   PetscFunctionReturn(PETSC_SUCCESS);
1212: }

1214: /*@
1215:   SNESLineSearchGetDamping - Gets the line search damping parameter.

1217:   Input Parameter:
1218: . linesearch - the line search context

1220:   Output Parameter:
1221: . damping - The damping parameter

1223:   Level: advanced

1225: .seealso: [](ch_snes), `SNES`, `SNESLineSearchGetStepTolerance()`, `SNESQN`
1226: @*/
1227: PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping)
1228: {
1229:   PetscFunctionBegin;
1231:   PetscAssertPointer(damping, 2);
1232:   *damping = linesearch->damping;
1233:   PetscFunctionReturn(PETSC_SUCCESS);
1234: }

1236: /*@
1237:   SNESLineSearchSetDamping - Sets the line search damping parameter.

1239:   Input Parameters:
1240: + linesearch - the line search context
1241: - damping    - The damping parameter

1243:   Options Database Key:
1244: . -snes_linesearch_damping <damping> - the damping value

1246:   Level: intermediate

1248:   Note:
1249:   The `SNESLINESEARCHNONE` line search merely takes the update step scaled by the damping parameter.
1250:   The use of the damping parameter in the `SNESLINESEARCHL2` and `SNESLINESEARCHCP` line searches is much more subtle;
1251:   it is used as a starting point in calculating the secant step. However, the eventual
1252:   step may be of greater length than the damping parameter.  In the `SNESLINESEARCHBT` line search it is
1253:   used as the maximum possible step length, as the `SNESLINESEARCHBT` line search only backtracks.

1255: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetDamping()`
1256: @*/
1257: PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping)
1258: {
1259:   PetscFunctionBegin;
1261:   linesearch->damping = damping;
1262:   PetscFunctionReturn(PETSC_SUCCESS);
1263: }

1265: /*@
1266:   SNESLineSearchGetOrder - Gets the line search approximation order.

1268:   Input Parameter:
1269: . linesearch - the line search context

1271:   Output Parameter:
1272: . order - The order

1274:   Level: intermediate

1276: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetOrder()`
1277: @*/
1278: PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order)
1279: {
1280:   PetscFunctionBegin;
1282:   PetscAssertPointer(order, 2);
1283:   *order = linesearch->order;
1284:   PetscFunctionReturn(PETSC_SUCCESS);
1285: }

1287: /*@
1288:   SNESLineSearchSetOrder - Sets the maximum order of the polynomial fit used in the line search

1290:   Input Parameters:
1291: + linesearch - the line search context
1292: - order      - The order

1294:   Level: intermediate

1296:   Values for `order`\:
1297: +  1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
1298: .  2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
1299: -  3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order

1301:   Options Database Key:
1302: . -snes_linesearch_order <order> - 1, 2, 3.  Most types only support certain orders (`SNESLINESEARCHBT` supports 2 or 3)

1304:   Note:
1305:   These orders are supported by `SNESLINESEARCHBT` and `SNESLINESEARCHCP`

1307: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
1308: @*/
1309: PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order)
1310: {
1311:   PetscFunctionBegin;
1313:   linesearch->order = order;
1314:   PetscFunctionReturn(PETSC_SUCCESS);
1315: }

1317: /*@
1318:   SNESLineSearchGetNorms - Gets the norms for the current solution `X`, the current update `Y`, and the current function value `F`.

1320:   Not Collective

1322:   Input Parameter:
1323: . linesearch - the line search context

1325:   Output Parameters:
1326: + xnorm - The norm of the current solution
1327: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution.
1328: - ynorm - The norm of the current update (after scaling by the linesearch computed lambda)

1330:   Level: developer

1332:   Notes:
1333:   Some values may not be up-to-date at particular points in the code.

1335:   This, in combination with `SNESLineSearchSetNorms()`, allow the line search and the `SNESSolve_XXX()` to share
1336:   computed values.

1338: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
1339: @*/
1340: PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
1341: {
1342:   PetscFunctionBegin;
1344:   if (xnorm) *xnorm = linesearch->xnorm;
1345:   if (fnorm) *fnorm = linesearch->fnorm;
1346:   if (ynorm) *ynorm = linesearch->ynorm;
1347:   PetscFunctionReturn(PETSC_SUCCESS);
1348: }

1350: /*@
1351:   SNESLineSearchSetNorms - Sets the computed norms for the current solution `X`, the current update `Y`, and the current function value `F`.

1353:   Collective

1355:   Input Parameters:
1356: + linesearch - the line search context
1357: . xnorm      - The norm of the current solution
1358: . fnorm      - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution
1359: - ynorm      - The norm of the current update (after scaling by the linesearch computed lambda)

1361:   Level: developer

1363:   Note:
1364:   This is called by the line search routines to store the values they have just computed

1366: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1367: @*/
1368: PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm)
1369: {
1370:   PetscFunctionBegin;
1372:   linesearch->xnorm = xnorm;
1373:   linesearch->fnorm = fnorm;
1374:   linesearch->ynorm = ynorm;
1375:   PetscFunctionReturn(PETSC_SUCCESS);
1376: }

1378: /*@
1379:   SNESLineSearchComputeNorms - Explicitly computes the norms of the current solution `X`, the current update `Y`, and the current function value `F`.

1381:   Input Parameter:
1382: . linesearch - the line search context

1384:   Options Database Key:
1385: . -snes_linesearch_norms - turn norm computation on or off

1387:   Level: intermediate

1389:   Developer Note:
1390:   The options database key is misnamed. It should be -snes_linesearch_compute_norms

1392: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
1393: @*/
1394: PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch)
1395: {
1396:   SNES snes;

1398:   PetscFunctionBegin;
1399:   if (linesearch->norms) {
1400:     if (linesearch->ops->vinorm) {
1401:       PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
1402:       PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1403:       PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1404:       PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
1405:     } else {
1406:       PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1407:       PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1408:       PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1409:       PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
1410:       PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
1411:       PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
1412:     }
1413:   }
1414:   PetscFunctionReturn(PETSC_SUCCESS);
1415: }

1417: /*@
1418:   SNESLineSearchSetComputeNorms - Turns on or off the computation of final norms in the line search.

1420:   Input Parameters:
1421: + linesearch - the line search context
1422: - flg        - indicates whether or not to compute norms

1424:   Options Database Key:
1425: . -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic (none) `SNESLINESEARCHBASIC` line search

1427:   Level: intermediate

1429:   Note:
1430:   This is most relevant to the `SNESLINESEARCHBASIC` (or equivalently `SNESLINESEARCHNONE`) line search type since most line searches have a stopping criteria involving the norm.

1432:   Developer Note:
1433:   The options database key is misnamed. It should be -snes_linesearch_compute_norms

1435: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
1436: @*/
1437: PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg)
1438: {
1439:   PetscFunctionBegin;
1440:   linesearch->norms = flg;
1441:   PetscFunctionReturn(PETSC_SUCCESS);
1442: }

1444: /*@
1445:   SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context

1447:   Not Collective but the vectors are parallel

1449:   Input Parameter:
1450: . linesearch - the line search context

1452:   Output Parameters:
1453: + X - Solution vector
1454: . F - Function vector
1455: . Y - Search direction vector
1456: . W - Solution work vector
1457: - G - Function work vector

1459:   Level: advanced

1461:   Notes:
1462:   At the beginning of a line search application, `X` should contain a
1463:   solution and the vector `F` the function computed at `X`.  At the end of the
1464:   line search application, `X` should contain the new solution, and `F` the
1465:   function evaluated at the new solution.

1467:   These vectors are owned by the `SNESLineSearch` and should not be destroyed by the caller

1469: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
1470: @*/
1471: PetscErrorCode SNESLineSearchGetVecs(SNESLineSearch linesearch, Vec *X, Vec *F, Vec *Y, Vec *W, Vec *G)
1472: {
1473:   PetscFunctionBegin;
1475:   if (X) {
1476:     PetscAssertPointer(X, 2);
1477:     *X = linesearch->vec_sol;
1478:   }
1479:   if (F) {
1480:     PetscAssertPointer(F, 3);
1481:     *F = linesearch->vec_func;
1482:   }
1483:   if (Y) {
1484:     PetscAssertPointer(Y, 4);
1485:     *Y = linesearch->vec_update;
1486:   }
1487:   if (W) {
1488:     PetscAssertPointer(W, 5);
1489:     *W = linesearch->vec_sol_new;
1490:   }
1491:   if (G) {
1492:     PetscAssertPointer(G, 6);
1493:     *G = linesearch->vec_func_new;
1494:   }
1495:   PetscFunctionReturn(PETSC_SUCCESS);
1496: }

1498: /*@
1499:   SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context

1501:   Logically Collective

1503:   Input Parameters:
1504: + linesearch - the line search context
1505: . X          - Solution vector
1506: . F          - Function vector
1507: . Y          - Search direction vector
1508: . W          - Solution work vector
1509: - G          - Function work vector

1511:   Level: developer

1513: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
1514: @*/
1515: PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G)
1516: {
1517:   PetscFunctionBegin;
1519:   if (X) {
1521:     linesearch->vec_sol = X;
1522:   }
1523:   if (F) {
1525:     linesearch->vec_func = F;
1526:   }
1527:   if (Y) {
1529:     linesearch->vec_update = Y;
1530:   }
1531:   if (W) {
1533:     linesearch->vec_sol_new = W;
1534:   }
1535:   if (G) {
1537:     linesearch->vec_func_new = G;
1538:   }
1539:   PetscFunctionReturn(PETSC_SUCCESS);
1540: }

1542: /*@
1543:   SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
1544:   `SNESLineSearch` options in the database.

1546:   Logically Collective

1548:   Input Parameters:
1549: + linesearch - the `SNESLineSearch` context
1550: - prefix     - the prefix to prepend to all option names

1552:   Level: advanced

1554:   Note:
1555:   A hyphen (-) must NOT be given at the beginning of the prefix name.
1556:   The first character of all runtime options is AUTOMATICALLY the hyphen.

1558: .seealso: [](ch_snes), `SNES`, `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
1559: @*/
1560: PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[])
1561: {
1562:   PetscFunctionBegin;
1564:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
1565:   PetscFunctionReturn(PETSC_SUCCESS);
1566: }

1568: /*@
1569:   SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
1570:   SNESLineSearch options in the database.

1572:   Not Collective

1574:   Input Parameter:
1575: . linesearch - the `SNESLineSearch` context

1577:   Output Parameter:
1578: . prefix - pointer to the prefix string used

1580:   Level: advanced

1582:   Fortran Notes:
1583:   The user should pass in a string 'prefix' of
1584:   sufficient length to hold the prefix.

1586: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESAppendOptionsPrefix()`
1587: @*/
1588: PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[])
1589: {
1590:   PetscFunctionBegin;
1592:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
1593:   PetscFunctionReturn(PETSC_SUCCESS);
1594: }

1596: /*@C
1597:   SNESLineSearchSetWorkVecs - Sets work vectors for the line search.

1599:   Input Parameters:
1600: + linesearch - the `SNESLineSearch` context
1601: - nwork      - the number of work vectors

1603:   Level: developer

1605:   Developer Note:
1606:   This is called from within the set up routines for each of the line search types `SNESLineSearchType`

1608: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESSetWorkVecs()`
1609: @*/
1610: PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork)
1611: {
1612:   PetscFunctionBegin;
1613:   PetscCheck(linesearch->vec_sol, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
1614:   PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
1615:   PetscFunctionReturn(PETSC_SUCCESS);
1616: }

1618: /*@
1619:   SNESLineSearchGetReason - Gets the success/failure status of the last line search application

1621:   Input Parameter:
1622: . linesearch - the line search context

1624:   Output Parameter:
1625: . result - The success or failure status

1627:   Level: developer

1629:   Note:
1630:   This is typically called after `SNESLineSearchApply()` in order to determine if the line search failed
1631:   (and set into the `SNES` convergence accordingly).

1633: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
1634: @*/
1635: PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *result)
1636: {
1637:   PetscFunctionBegin;
1639:   PetscAssertPointer(result, 2);
1640:   *result = linesearch->result;
1641:   PetscFunctionReturn(PETSC_SUCCESS);
1642: }

1644: /*@
1645:   SNESLineSearchSetReason - Sets the success/failure status of the line search application

1647:   Logically Collective; No Fortran Support

1649:   Input Parameters:
1650: + linesearch - the line search context
1651: - result     - The success or failure status

1653:   Level: developer

1655:   Note:
1656:   This is typically called in a `SNESLineSearchType` implementation of `SNESLineSearchApply()` or a `SNESLINESEARCHSHELL` implementation to set
1657:   the success or failure of the line search method.

1659: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`
1660: @*/
1661: PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason result)
1662: {
1663:   PetscFunctionBegin;
1665:   linesearch->result = result;
1666:   PetscFunctionReturn(PETSC_SUCCESS);
1667: }

1669: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
1670: /*@C
1671:   SNESLineSearchSetVIFunctions - Sets VI-specific functions for line search computation.

1673:   Logically Collective

1675:   Input Parameters:
1676: + linesearch  - the linesearch object
1677: . projectfunc - function for projecting the function to the bounds, see `SNESLineSearchVIProjectFn` for calling sequence
1678: - normfunc    - function for computing the norm of an active set, see `SNESLineSearchVINormFn` for calling sequence

1680:   Level: advanced

1682:   Notes:
1683:   The VI solvers require projection of the solution to the feasible set.  `projectfunc` should implement this.

1685:   The VI solvers require special evaluation of the function norm such that the norm is only calculated
1686:   on the inactive set.  This should be implemented by `normfunc`.

1688: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`,
1689:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`
1690: @*/
1691: PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn *projectfunc, SNESLineSearchVINormFn *normfunc)
1692: {
1693:   PetscFunctionBegin;
1695:   if (projectfunc) linesearch->ops->viproject = projectfunc;
1696:   if (normfunc) linesearch->ops->vinorm = normfunc;
1697:   PetscFunctionReturn(PETSC_SUCCESS);
1698: }

1700: /*@C
1701:   SNESLineSearchGetVIFunctions - Sets VI-specific functions for line search computation.

1703:   Not Collective

1705:   Input Parameter:
1706: . linesearch - the line search context, obtain with `SNESGetLineSearch()`

1708:   Output Parameters:
1709: + projectfunc - function for projecting the function to the bounds, see `SNESLineSearchVIProjectFn` for calling sequence
1710: - normfunc    - function for computing the norm of an active set, see `SNESLineSearchVINormFn ` for calling sequence

1712:   Level: advanced

1714: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
1715:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`
1716: @*/
1717: PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn **projectfunc, SNESLineSearchVINormFn **normfunc)
1718: {
1719:   PetscFunctionBegin;
1720:   if (projectfunc) *projectfunc = linesearch->ops->viproject;
1721:   if (normfunc) *normfunc = linesearch->ops->vinorm;
1722:   PetscFunctionReturn(PETSC_SUCCESS);
1723: }

1725: /*@C
1726:   SNESLineSearchRegister - register a line search type `SNESLineSearchType`

1728:   Logically Collective, No Fortran Support

1730:   Input Parameters:
1731: + sname    - name of the `SNESLineSearchType()`
1732: - function - the creation function for that type

1734:   Calling sequence of `function`:
1735: . ls - the line search context

1737:   Level: advanced

1739: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
1740: @*/
1741: PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch ls))
1742: {
1743:   PetscFunctionBegin;
1744:   PetscCall(SNESInitializePackage());
1745:   PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
1746:   PetscFunctionReturn(PETSC_SUCCESS);
1747: }