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, PetscCtx mctx), PetscCtx mctx, PetscCtxDestroyFn *monitordestroy)
    100: {
    101:   PetscFunctionBegin;
    103:   for (PetscInt i = 0; i < ls->numbermonitors; i++) {
    104:     PetscBool identical;

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

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

    119:   Collective

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

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

    128:   Level: developer

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

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

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

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

    155:   Logically Collective

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

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

    163:   Level: developer

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

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

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

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

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

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

    212:   Collective

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

    217:   Level: advanced

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

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

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

    246:   Collective

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

    251:   Level: developer

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

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

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

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

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

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

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

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

    286:   Level: developer

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

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

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

    306:   Logically Collective

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

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

    320:   Level: intermediate

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

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

    327: .seealso: [](ch_snes), `SNES`, `SNESGetLineSearch()`, `SNESLineSearchPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
    328:           `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESSetFunctionDomainError()`, `SNESSetJacobianDomainError()`
    329: @*/
    330: PetscErrorCode SNESLineSearchSetPreCheck(SNESLineSearch linesearch, PetscErrorCode (*func)(SNESLineSearch ls, Vec x, Vec d, PetscBool *changed_d, PetscCtx ctx), PetscCtx ctx)
    331: {
    332:   PetscFunctionBegin;
    334:   if (func) linesearch->ops->precheck = func;
    335:   if (ctx) linesearch->precheckctx = ctx;
    336:   PetscFunctionReturn(PETSC_SUCCESS);
    337: }

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

    342:   Input Parameter:
    343: . linesearch - the `SNESLineSearch` context

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

    349:   Level: intermediate

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

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

    366:   Logically Collective

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

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

    382:   Level: intermediate

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

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

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

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

    405:   Input Parameter:
    406: . linesearch - the `SNESLineSearch` context

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

    412:   Level: intermediate

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

    425: /*@
    426:   SNESLineSearchPreCheck - Prepares the line search for being applied.

    428:   Logically Collective

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

    435:   Output Parameter:
    436: . changed - Indicator that the precheck routine has changed `Y`

    438:   Level: advanced

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

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

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

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

    463:   Logically Collective

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

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

    475:   Level: developer

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

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

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

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

    501:   Logically Collective

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

    508:   Input/Output Parameter:
    509: . Y - correction, possibly modified

    511:   Output Parameter:
    512: . changed - flag indicating that `Y` was modified

    514:   Options Database Keys:
    515: + -snes_linesearch_precheck_picard (true|false) - activate this routine
    516: - -snes_linesearch_precheck_picard_angle angle  - the angle to use

    518:   Level: advanced

    520:   Notes:
    521:   This function should be passed to `SNESLineSearchSetPreCheck()`

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

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

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

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

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

    584: /*@
    585:   SNESLineSearchApply - Computes the line-search update.

    587:   Collective

    589:   Input Parameter:
    590: . linesearch - The line search context

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

    598:   Options Database Keys:
    599: + -snes_linesearch_type (none|bt|secant|cp|nleqerr|bisection|shell) - See `SNESLineSearchType`
    600: . -snes_linesearch_monitor [:filename]                              - Print progress of line searches
    601: . -snes_linesearch_damping damping                                  - The linesearch damping parameter, default is 1.0 (no damping)
    602: . -snes_linesearch_norms (true|false)                               - Turn on/off the linesearch norms computation (SNESLineSearchSetComputeNorms())
    603: . -snes_linesearch_keeplambda (true|false)                          - Keep the previous `lambda` as the initial guess
    604: - -snes_linesearch_max_it it                                        - The number of iterations for iterative line searches

    606:   Level: advanced

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

    616:   In certain situations `SNESLineSearchApply()` may directly set a `SNESConvergedReason` in the `SNES` object so one should always check
    617:   this value immediately after the call to `SNESLineSearchApply()`.

    619: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchGetLambda()`, `SNESLineSearchPreCheck()`, `SNESLineSearchPostCheck()`, `SNESSolve()`, `SNESComputeFunction()`, `SNESLineSearchSetComputeNorms()`,
    620:           `SNESLineSearchType`, `SNESLineSearchSetType()`
    621: @*/
    622: PetscErrorCode SNESLineSearchApply(SNESLineSearch linesearch, Vec X, Vec F, PetscReal *fnorm, Vec Y)
    623: {
    624:   PetscFunctionBegin;

    630:   linesearch->reason = SNES_LINESEARCH_SUCCEEDED;

    632:   linesearch->vec_sol    = X;
    633:   linesearch->vec_update = Y;
    634:   linesearch->vec_func   = F;

    636:   PetscCall(SNESLineSearchSetUp(linesearch));

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

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

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

    645:   PetscUseTypeMethod(linesearch, apply);

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

    649:   if (fnorm) *fnorm = linesearch->fnorm;
    650:   PetscFunctionReturn(PETSC_SUCCESS);
    651: }

    653: /*@
    654:   SNESLineSearchDestroy - Destroys the line search instance.

    656:   Collective

    658:   Input Parameter:
    659: . linesearch - The line search context

    661:   Level: developer

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

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

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

    689:   Logically Collective

    691:   Input Parameters:
    692: + linesearch - the linesearch object
    693: - viewer     - an `PETSCVIEWERASCII` `PetscViewer` or `NULL` to turn off monitor

    695:   Options Database Key:
    696: . -snes_linesearch_monitor [:filename] - enables the monitor

    698:   Level: intermediate

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

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

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

    719:   Logically Collective

    721:   Input Parameter:
    722: . linesearch - the line search context

    724:   Output Parameter:
    725: . monitor - monitor context

    727:   Level: intermediate

    729: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`, `SNESLineSearchSetDefaultMonitor()`, `PetscViewer`
    730: @*/
    731: PetscErrorCode SNESLineSearchGetDefaultMonitor(SNESLineSearch linesearch, PetscViewer *monitor)
    732: {
    733:   PetscFunctionBegin;
    735:   *monitor = linesearch->monitor;
    736:   PetscFunctionReturn(PETSC_SUCCESS);
    737: }

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

    742:   Collective

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

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

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

    760:   Level: advanced

    762: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetMonitor()`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
    763:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
    764:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
    765:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
    766:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
    767:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
    768:           `PetscOptionsFList()`, `PetscOptionsEList()`
    769: @*/
    770: 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))
    771: {
    772:   PetscViewer       viewer;
    773:   PetscViewerFormat format;
    774:   PetscBool         flg;

    776:   PetscFunctionBegin;
    777:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)ls), ((PetscObject)ls)->options, ((PetscObject)ls)->prefix, name, &viewer, &format, &flg));
    778:   if (flg) {
    779:     PetscViewerAndFormat *vf;
    780:     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
    781:     PetscCall(PetscViewerDestroy(&viewer));
    782:     if (monitorsetup) PetscCall((*monitorsetup)(ls, vf));
    783:     PetscCall(SNESLineSearchMonitorSet(ls, (PetscErrorCode (*)(SNESLineSearch, PetscCtx))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
    784:   }
    785:   PetscFunctionReturn(PETSC_SUCCESS);
    786: }

    788: /*@
    789:   SNESLineSearchSetFromOptions - Sets options for the line search

    791:   Logically Collective

    793:   Input Parameter:
    794: . linesearch - a `SNESLineSearch` line search context

    796:   Options Database Keys:
    797: + -snes_linesearch_type (none|bt|secant|cp|nleqerr|bisection|shell) - See `SNESLineSearchType`
    798: . -snes_linesearch_order order                                      - 1, 2, 3.  Most types only support certain orders (`bt` supports 1, 2 or 3)
    799: . -snes_linesearch_norms (true|false)                               - Turn on/off the linesearch norms for the basic linesearch typem (`SNESLineSearchSetComputeNorms()`)
    800: . -snes_linesearch_minlambda minlambda                              - The minimum `lambda`
    801: . -snes_linesearch_maxlambda maxlambda                              - The maximum `lambda`
    802: . -snes_linesearch_rtol rtol                                        - Relative tolerance for iterative line searches
    803: . -snes_linesearch_atol atol                                        - Absolute tolerance for iterative line searches
    804: . -snes_linesearch_ltol ltol                                        - Change in `lambda` tolerance for iterative line searches
    805: . -snes_linesearch_max_it max_it                                    - The number of iterations for iterative line searches
    806: . -snes_linesearch_monitor [:filename]                              - Print progress of line searches
    807: . -snes_linesearch_monitor_solution_update [viewer:filename:format] - view each update tried by line search routine
    808: . -snes_linesearch_damping damping                                  - The linesearch damping parameter
    809: . -snes_linesearch_keeplambda (true|false)                          - Keep the previous `lambda` as the initial guess.
    810: . -snes_linesearch_precheck_picard (true|false)                     - Use precheck that speeds up convergence of picard method
    811: - -snes_linesearch_precheck_picard_angle angle                      - Angle used in Picard precheck method

    813:   Level: intermediate

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

    825:   PetscFunctionBegin;
    826:   PetscCall(SNESLineSearchRegisterAll());

    828:   PetscObjectOptionsBegin((PetscObject)linesearch);
    829:   if (((PetscObject)linesearch)->type_name) deft = ((PetscObject)linesearch)->type_name;
    830:   PetscCall(PetscOptionsFList("-snes_linesearch_type", "Linesearch type", "SNESLineSearchSetType", SNESLineSearchList, deft, type, 256, &flg));
    831:   if (flg) {
    832:     PetscCall(SNESLineSearchSetType(linesearch, type));
    833:   } else if (!((PetscObject)linesearch)->type_name) {
    834:     PetscCall(SNESLineSearchSetType(linesearch, deft));
    835:   }

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

    841:   /* tolerances */
    842:   PetscCall(PetscOptionsReal("-snes_linesearch_minlambda", "Minimum lambda", "SNESLineSearchSetTolerances", linesearch->minlambda, &linesearch->minlambda, NULL));
    843:   PetscCall(PetscOptionsReal("-snes_linesearch_maxlambda", "Maximum lambda", "SNESLineSearchSetTolerances", linesearch->maxlambda, &linesearch->maxlambda, NULL));
    844:   PetscCall(PetscOptionsReal("-snes_linesearch_rtol", "Relative tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->rtol, &linesearch->rtol, NULL));
    845:   PetscCall(PetscOptionsReal("-snes_linesearch_atol", "Absolute tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->atol, &linesearch->atol, NULL));
    846:   PetscCall(PetscOptionsReal("-snes_linesearch_ltol", "Change in lambda tolerance for iterative line search", "SNESLineSearchSetTolerances", linesearch->ltol, &linesearch->ltol, NULL));
    847:   PetscCall(PetscOptionsInt("-snes_linesearch_max_it", "Maximum iterations for iterative line searches", "SNESLineSearchSetTolerances", linesearch->max_it, &linesearch->max_it, NULL));

    849:   /* deprecated options */
    850:   PetscCall(PetscOptionsDeprecated("-snes_linesearch_maxstep", "-snes_linesearch_maxlambda", "3.24.0", NULL));

    852:   /* damping parameters */
    853:   PetscCall(PetscOptionsReal("-snes_linesearch_damping", "Line search damping (and depending on chosen line search initial lambda guess)", "SNESLineSearchSetDamping", linesearch->damping, &linesearch->damping, NULL));

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

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

    863:       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));
    864:       PetscCall(SNESLineSearchSetPreCheck(linesearch, SNESLineSearchPreCheckPicard, &linesearch->precheck_picard_angle));
    865:     } else {
    866:       PetscCall(SNESLineSearchSetPreCheck(linesearch, NULL, NULL));
    867:     }
    868:   }
    869:   PetscCall(PetscOptionsInt("-snes_linesearch_order", "Order of approximation used in the line search", "SNESLineSearchSetOrder", linesearch->order, &linesearch->order, NULL));
    870:   PetscCall(PetscOptionsBool("-snes_linesearch_norms", "Compute final norms in line search", "SNESLineSearchSetComputeNorms", linesearch->norms, &linesearch->norms, NULL));

    872:   PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);

    874:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
    875:   PetscOptionsEnd();
    876:   PetscFunctionReturn(PETSC_SUCCESS);
    877: }

    879: /*@
    880:   SNESLineSearchView - Prints useful information about the line search

    882:   Logically Collective

    884:   Input Parameters:
    885: + linesearch - line search context
    886: - viewer     - the `PetscViewer` to display the line search information to

    888:   Level: intermediate

    890: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `PetscViewer`, `SNESLineSearchCreate()`
    891: @*/
    892: PetscErrorCode SNESLineSearchView(SNESLineSearch linesearch, PetscViewer viewer)
    893: {
    894:   PetscBool isascii;

    896:   PetscFunctionBegin;
    898:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
    900:   PetscCheckSameComm(linesearch, 1, viewer, 2);

    902:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    903:   if (isascii) {
    904:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)linesearch, viewer));
    905:     PetscCall(PetscViewerASCIIPushTab(viewer));
    906:     PetscTryTypeMethod(linesearch, view, viewer);
    907:     PetscCall(PetscViewerASCIIPopTab(viewer));
    908:     PetscCall(PetscViewerASCIIPrintf(viewer, "  maxlambda=%e, minlambda=%e\n", (double)linesearch->maxlambda, (double)linesearch->minlambda));
    909:     PetscCall(PetscViewerASCIIPrintf(viewer, "  tolerances: relative=%e, absolute=%e, lambda=%e\n", (double)linesearch->rtol, (double)linesearch->atol, (double)linesearch->ltol));
    910:     PetscCall(PetscViewerASCIIPrintf(viewer, "  maximum iterations=%" PetscInt_FMT "\n", linesearch->max_it));
    911:     if (linesearch->ops->precheck) {
    912:       if (linesearch->ops->precheck == SNESLineSearchPreCheckPicard) {
    913:         PetscCall(PetscViewerASCIIPrintf(viewer, "  using precheck step to speed up Picard convergence\n"));
    914:       } else {
    915:         PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined precheck step\n"));
    916:       }
    917:     }
    918:     if (linesearch->ops->postcheck) PetscCall(PetscViewerASCIIPrintf(viewer, "  using user-defined postcheck step\n"));
    919:   }
    920:   PetscFunctionReturn(PETSC_SUCCESS);
    921: }

    923: /*@
    924:   SNESLineSearchGetType - Gets the `SNESLinesearchType` of a `SNESLineSearch`

    926:   Logically Collective

    928:   Input Parameter:
    929: . linesearch - the line search context

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

    934:   Level: intermediate

    936:   Note:
    937:   `type` should not be retained for later use as it will be an invalid pointer if the `SNESLineSearchType` of `linesearch` is changed.

    939: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchSetType()`,
    940:           `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`
    941: @*/
    942: PetscErrorCode SNESLineSearchGetType(SNESLineSearch linesearch, SNESLineSearchType *type)
    943: {
    944:   PetscFunctionBegin;
    946:   PetscAssertPointer(type, 2);
    947:   *type = ((PetscObject)linesearch)->type_name;
    948:   PetscFunctionReturn(PETSC_SUCCESS);
    949: }

    951: /*@
    952:   SNESLineSearchSetType - Sets the `SNESLinesearchType` of a `SNESLineSearch` object to indicate the line search algorithm that should be used by a given `SNES` solver

    954:   Logically Collective

    956:   Input Parameters:
    957: + linesearch - the line search context
    958: - type       - The type of line search to be used, see `SNESLineSearchType`

    960:   Options Database Key:
    961: . -snes_linesearch_type (none|bt|secant|cp|nleqerr|bisection|shell) - the linesearch to use, see `SNESLineSearchType`

    963:   Level: intermediate

    965:   Note:
    966:   The `SNESLineSearch` object is generally obtained with `SNESGetLineSearch()`

    968: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`,
    969:           `SNESGetLineSearch()`
    970: @*/
    971: PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type)
    972: {
    973:   PetscBool match;
    974:   PetscErrorCode (*r)(SNESLineSearch);

    976:   PetscFunctionBegin;
    978:   PetscAssertPointer(type, 2);

    980:   PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
    981:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

    983:   PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
    984:   PetscCheck(r, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
    985:   /* Destroy the previous private line search context */
    986:   PetscTryTypeMethod(linesearch, destroy);
    987:   linesearch->ops->destroy = NULL;
    988:   /* Reinitialize function pointers in SNESLineSearchOps structure */
    989:   linesearch->ops->apply          = NULL;
    990:   linesearch->ops->view           = NULL;
    991:   linesearch->ops->setfromoptions = NULL;
    992:   linesearch->ops->destroy        = NULL;

    994:   PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
    995:   PetscCall((*r)(linesearch));
    996:   PetscFunctionReturn(PETSC_SUCCESS);
    997: }

    999: /*@
    1000:   SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.

    1002:   Input Parameters:
    1003: + linesearch - the line search context
    1004: - snes       - The `SNES` instance

    1006:   Level: developer

    1008:   Note:
    1009:   This happens automatically when the line search is obtained/created with
    1010:   `SNESGetLineSearch()`.  This routine is therefore mainly called within `SNES`
    1011:   implementations.

    1013: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`
    1014: @*/
    1015: PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes)
    1016: {
    1017:   PetscFunctionBegin;
    1020:   linesearch->snes = snes;
    1021:   PetscFunctionReturn(PETSC_SUCCESS);
    1022: }

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

    1027:   Not Collective

    1029:   Input Parameter:
    1030: . linesearch - the line search context

    1032:   Output Parameter:
    1033: . snes - The `SNES` instance

    1035:   Level: developer

    1037: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESType`, `SNESLineSearchSetVecs()`
    1038: @*/
    1039: PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes)
    1040: {
    1041:   PetscFunctionBegin;
    1043:   PetscAssertPointer(snes, 2);
    1044:   *snes = linesearch->snes;
    1045:   PetscFunctionReturn(PETSC_SUCCESS);
    1046: }

    1048: /*@
    1049:   SNESLineSearchGetLambda - Gets the last line search `lambda` used

    1051:   Not Collective

    1053:   Input Parameter:
    1054: . linesearch - the line search context

    1056:   Output Parameter:
    1057: . lambda - The last `lambda` (scaling of the solution update) computed during `SNESLineSearchApply()`

    1059:   Level: advanced

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

    1067: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
    1068: @*/
    1069: PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda)
    1070: {
    1071:   PetscFunctionBegin;
    1073:   PetscAssertPointer(lambda, 2);
    1074:   *lambda = linesearch->lambda;
    1075:   PetscFunctionReturn(PETSC_SUCCESS);
    1076: }

    1078: /*@
    1079:   SNESLineSearchSetLambda - Sets the line search `lambda` (scaling of the solution update)

    1081:   Input Parameters:
    1082: + linesearch - line search context
    1083: - lambda     - The `lambda` to use

    1085:   Level: advanced

    1087:   Note:
    1088:   This routine is typically used within implementations of `SNESLineSearchApply()`
    1089:   to set the final `lambda`.  This routine (and `SNESLineSearchGetLambda()`) were
    1090:   added to facilitate Quasi-Newton methods that use the previous `lambda`
    1091:   as an inner scaling parameter.

    1093: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetLambda()`
    1094: @*/
    1095: PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda)
    1096: {
    1097:   PetscFunctionBegin;
    1099:   linesearch->lambda = lambda;
    1100:   PetscFunctionReturn(PETSC_SUCCESS);
    1101: }

    1103: /*@
    1104:   SNESLineSearchGetTolerances - Gets the tolerances for the line search.

    1106:   Not Collective

    1108:   Input Parameter:
    1109: . linesearch - the line search context

    1111:   Output Parameters:
    1112: + minlambda - The minimum `lambda` allowed
    1113: . maxlambda - The maximum `lambda` allowed
    1114: . rtol      - The relative tolerance for iterative line searches
    1115: . atol      - The absolute tolerance for iterative line searches
    1116: . ltol      - The change in `lambda` tolerance for iterative line searches
    1117: - max_it    - The maximum number of iterations of the line search

    1119:   Level: intermediate

    1121:   Note:
    1122:   Different line searches may implement these parameters slightly differently as
    1123:   the type requires.

    1125: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetTolerances()`
    1126: @*/
    1127: PetscErrorCode SNESLineSearchGetTolerances(SNESLineSearch linesearch, PetscReal *minlambda, PetscReal *maxlambda, PetscReal *rtol, PetscReal *atol, PetscReal *ltol, PetscInt *max_it)
    1128: {
    1129:   PetscFunctionBegin;
    1131:   if (minlambda) {
    1132:     PetscAssertPointer(minlambda, 2);
    1133:     *minlambda = linesearch->minlambda;
    1134:   }
    1135:   if (maxlambda) {
    1136:     PetscAssertPointer(maxlambda, 3);
    1137:     *maxlambda = linesearch->maxlambda;
    1138:   }
    1139:   if (rtol) {
    1140:     PetscAssertPointer(rtol, 4);
    1141:     *rtol = linesearch->rtol;
    1142:   }
    1143:   if (atol) {
    1144:     PetscAssertPointer(atol, 5);
    1145:     *atol = linesearch->atol;
    1146:   }
    1147:   if (ltol) {
    1148:     PetscAssertPointer(ltol, 6);
    1149:     *ltol = linesearch->ltol;
    1150:   }
    1151:   if (max_it) {
    1152:     PetscAssertPointer(max_it, 7);
    1153:     *max_it = linesearch->max_it;
    1154:   }
    1155:   PetscFunctionReturn(PETSC_SUCCESS);
    1156: }

    1158: /*@
    1159:   SNESLineSearchSetTolerances -  Sets the tolerances for the linesearch.

    1161:   Collective

    1163:   Input Parameters:
    1164: + linesearch - the line search context
    1165: . minlambda  - The minimum `lambda` allowed
    1166: . maxlambda  - The maximum `lambda` allowed
    1167: . rtol       - The relative tolerance for iterative line searches
    1168: . atol       - The absolute tolerance for iterative line searches
    1169: . ltol       - The change in `lambda` tolerance for iterative line searches
    1170: - max_it     - The maximum number of iterations of the line search

    1172:   Options Database Keys:
    1173: + -snes_linesearch_minlambda - The minimum `lambda` allowed
    1174: . -snes_linesearch_maxlambda - The maximum `lambda` allowed
    1175: . -snes_linesearch_rtol      - Relative tolerance for iterative line searches
    1176: . -snes_linesearch_atol      - Absolute tolerance for iterative line searches
    1177: . -snes_linesearch_ltol      - Change in `lambda` tolerance for iterative line searches
    1178: - -snes_linesearch_max_it    - The number of iterations for iterative line searches

    1180:   Level: intermediate

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

    1185: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetTolerances()`
    1186: @*/
    1187: PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal minlambda, PetscReal maxlambda, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_it)
    1188: {
    1189:   PetscFunctionBegin;

    1198:   if (minlambda != (PetscReal)PETSC_DEFAULT) {
    1199:     PetscCheck(minlambda >= 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum lambda %14.12e must be non-negative", (double)minlambda);
    1200:     PetscCheck(minlambda < maxlambda, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Minimum lambda %14.12e must be smaller than maximum lambda %14.12e", (double)minlambda, (double)maxlambda);
    1201:     linesearch->minlambda = minlambda;
    1202:   }

    1204:   if (maxlambda != (PetscReal)PETSC_DEFAULT) {
    1205:     PetscCheck(maxlambda > 0.0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum lambda %14.12e must be positive", (double)maxlambda);
    1206:     linesearch->maxlambda = maxlambda;
    1207:   }

    1209:   if (rtol != (PetscReal)PETSC_DEFAULT) {
    1210:     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);
    1211:     linesearch->rtol = rtol;
    1212:   }

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

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

    1224:   if (max_it != PETSC_DEFAULT) {
    1225:     PetscCheck(max_it >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_it);
    1226:     linesearch->max_it = max_it;
    1227:   }
    1228:   PetscFunctionReturn(PETSC_SUCCESS);
    1229: }

    1231: /*@
    1232:   SNESLineSearchGetDamping - Gets the line search damping parameter.

    1234:   Input Parameter:
    1235: . linesearch - the line search context

    1237:   Output Parameter:
    1238: . damping - The damping parameter

    1240:   Level: advanced

    1242: .seealso: [](ch_snes), `SNES`, `SNESLineSearchGetStepTolerance()`, `SNESQN`
    1243: @*/
    1244: PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping)
    1245: {
    1246:   PetscFunctionBegin;
    1248:   PetscAssertPointer(damping, 2);
    1249:   *damping = linesearch->damping;
    1250:   PetscFunctionReturn(PETSC_SUCCESS);
    1251: }

    1253: /*@
    1254:   SNESLineSearchSetDamping - Sets the line search damping parameter.

    1256:   Input Parameters:
    1257: + linesearch - the line search context
    1258: - damping    - The damping parameter

    1260:   Options Database Key:
    1261: . -snes_linesearch_damping damping - the damping value

    1263:   Level: intermediate

    1265:   Note:
    1266:   The `SNESLINESEARCHNONE` line search merely takes the update step scaled by the damping parameter.
    1267:   The use of the damping parameter in the `SNESLINESEARCHSECANT` and `SNESLINESEARCHCP` line searches is much more subtle;
    1268:   it is used as a starting point for the secant method. Depending on the choice for `maxlambda`,
    1269:   the eventual `lambda` may be greater than the damping parameter however.
    1270:   For `SNESLINESEARCHBISECTION` and `SNESLINESEARCHBT` the damping is instead used as the initial guess,
    1271:   below which the line search will not go. Hence, it is the maximum possible value for `lambda`.

    1273: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetDamping()`
    1274: @*/
    1275: PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping)
    1276: {
    1277:   PetscFunctionBegin;
    1279:   linesearch->damping = damping;
    1280:   PetscFunctionReturn(PETSC_SUCCESS);
    1281: }

    1283: /*@
    1284:   SNESLineSearchGetOrder - Gets the line search approximation order.

    1286:   Input Parameter:
    1287: . linesearch - the line search context

    1289:   Output Parameter:
    1290: . order - The order

    1292:   Level: intermediate

    1294: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetOrder()`
    1295: @*/
    1296: PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order)
    1297: {
    1298:   PetscFunctionBegin;
    1300:   PetscAssertPointer(order, 2);
    1301:   *order = linesearch->order;
    1302:   PetscFunctionReturn(PETSC_SUCCESS);
    1303: }

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

    1308:   Input Parameters:
    1309: + linesearch - the line search context
    1310: - order      - The order

    1312:   Level: intermediate

    1314:   Values for `order`\:
    1315: +  1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
    1316: .  2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
    1317: -  3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order

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

    1322:   Note:
    1323:   These orders are supported by `SNESLINESEARCHBT` and `SNESLINESEARCHCP`

    1325: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
    1326: @*/
    1327: PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order)
    1328: {
    1329:   PetscFunctionBegin;
    1331:   linesearch->order = order;
    1332:   PetscFunctionReturn(PETSC_SUCCESS);
    1333: }

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

    1338:   Not Collective

    1340:   Input Parameter:
    1341: . linesearch - the line search context

    1343:   Output Parameters:
    1344: + xnorm - The norm of the current solution
    1345: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution.
    1346: - ynorm - The norm of the current update (after scaling by the linesearch computed `lambda`)

    1348:   Level: developer

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

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

    1356: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
    1357: @*/
    1358: PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
    1359: {
    1360:   PetscFunctionBegin;
    1362:   if (xnorm) *xnorm = linesearch->xnorm;
    1363:   if (fnorm) *fnorm = linesearch->fnorm;
    1364:   if (ynorm) *ynorm = linesearch->ynorm;
    1365:   PetscFunctionReturn(PETSC_SUCCESS);
    1366: }

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

    1371:   Collective

    1373:   Input Parameters:
    1374: + linesearch - the line search context
    1375: . xnorm      - The norm of the current solution
    1376: . fnorm      - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution
    1377: - ynorm      - The norm of the current update (after scaling by the linesearch computed `lambda`)

    1379:   Level: developer

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

    1384: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
    1385: @*/
    1386: PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm)
    1387: {
    1388:   PetscFunctionBegin;
    1390:   linesearch->xnorm = xnorm;
    1391:   linesearch->fnorm = fnorm;
    1392:   linesearch->ynorm = ynorm;
    1393:   PetscFunctionReturn(PETSC_SUCCESS);
    1394: }

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

    1399:   Input Parameter:
    1400: . linesearch - the line search context

    1402:   Options Database Key:
    1403: . -snes_linesearch_norms (true|false) - turn norm computation on or off

    1405:   Level: intermediate

    1407:   Developer Note:
    1408:   The options database key is misnamed. It should be `-snes_linesearch_compute_norms`

    1410: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
    1411: @*/
    1412: PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch)
    1413: {
    1414:   SNES snes;

    1416:   PetscFunctionBegin;
    1417:   if (linesearch->norms) {
    1418:     if (linesearch->ops->vinorm) {
    1419:       PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
    1420:       PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1421:       PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1422:       PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
    1423:     } else {
    1424:       PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
    1425:       PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1426:       PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1427:       PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
    1428:       PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1429:       PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1430:     }
    1431:   }
    1432:   PetscFunctionReturn(PETSC_SUCCESS);
    1433: }

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

    1438:   Input Parameters:
    1439: + linesearch - the line search context
    1440: - flg        - indicates whether or not to compute norms

    1442:   Options Database Key:
    1443: . -snes_linesearch_norms (true|false) - Turns on/off computation of the norms for basic (none) `SNESLINESEARCHBASIC` line search

    1445:   Level: intermediate

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

    1450:   Developer Note:
    1451:   The options database key is misnamed. It should be `-snes_linesearch_compute_norms`

    1453: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
    1454: @*/
    1455: PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg)
    1456: {
    1457:   PetscFunctionBegin;
    1458:   linesearch->norms = flg;
    1459:   PetscFunctionReturn(PETSC_SUCCESS);
    1460: }

    1462: /*@
    1463:   SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context

    1465:   Not Collective but the vectors are parallel

    1467:   Input Parameter:
    1468: . linesearch - the line search context

    1470:   Output Parameters:
    1471: + X - Solution vector
    1472: . F - Function vector
    1473: . Y - Search direction vector
    1474: . W - Solution work vector
    1475: - G - Function work vector

    1477:   Level: advanced

    1479:   Notes:
    1480:   At the beginning of a line search application, `X` should contain a
    1481:   solution and the vector `F` the function computed at `X`.  At the end of the
    1482:   line search application, `X` should contain the new solution, and `F` the
    1483:   function evaluated at the new solution.

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

    1487: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
    1488: @*/
    1489: PetscErrorCode SNESLineSearchGetVecs(SNESLineSearch linesearch, Vec *X, Vec *F, Vec *Y, Vec *W, Vec *G)
    1490: {
    1491:   PetscFunctionBegin;
    1493:   if (X) {
    1494:     PetscAssertPointer(X, 2);
    1495:     *X = linesearch->vec_sol;
    1496:   }
    1497:   if (F) {
    1498:     PetscAssertPointer(F, 3);
    1499:     *F = linesearch->vec_func;
    1500:   }
    1501:   if (Y) {
    1502:     PetscAssertPointer(Y, 4);
    1503:     *Y = linesearch->vec_update;
    1504:   }
    1505:   if (W) {
    1506:     PetscAssertPointer(W, 5);
    1507:     *W = linesearch->vec_sol_new;
    1508:   }
    1509:   if (G) {
    1510:     PetscAssertPointer(G, 6);
    1511:     *G = linesearch->vec_func_new;
    1512:   }
    1513:   PetscFunctionReturn(PETSC_SUCCESS);
    1514: }

    1516: /*@
    1517:   SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context

    1519:   Logically Collective

    1521:   Input Parameters:
    1522: + linesearch - the line search context
    1523: . X          - Solution vector
    1524: . F          - Function vector
    1525: . Y          - Search direction vector
    1526: . W          - Solution work vector
    1527: - G          - Function work vector

    1529:   Level: developer

    1531: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
    1532: @*/
    1533: PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G)
    1534: {
    1535:   PetscFunctionBegin;
    1537:   if (X) {
    1539:     linesearch->vec_sol = X;
    1540:   }
    1541:   if (F) {
    1543:     linesearch->vec_func = F;
    1544:   }
    1545:   if (Y) {
    1547:     linesearch->vec_update = Y;
    1548:   }
    1549:   if (W) {
    1551:     linesearch->vec_sol_new = W;
    1552:   }
    1553:   if (G) {
    1555:     linesearch->vec_func_new = G;
    1556:   }
    1557:   PetscFunctionReturn(PETSC_SUCCESS);
    1558: }

    1560: /*@
    1561:   SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
    1562:   `SNESLineSearch` options in the database.

    1564:   Logically Collective

    1566:   Input Parameters:
    1567: + linesearch - the `SNESLineSearch` context
    1568: - prefix     - the prefix to prepend to all option names

    1570:   Level: advanced

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

    1576: .seealso: [](ch_snes), `SNES`, `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
    1577: @*/
    1578: PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[])
    1579: {
    1580:   PetscFunctionBegin;
    1582:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
    1583:   PetscFunctionReturn(PETSC_SUCCESS);
    1584: }

    1586: /*@
    1587:   SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
    1588:   SNESLineSearch options in the database.

    1590:   Not Collective

    1592:   Input Parameter:
    1593: . linesearch - the `SNESLineSearch` context

    1595:   Output Parameter:
    1596: . prefix - pointer to the prefix string used

    1598:   Level: advanced

    1600: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESAppendOptionsPrefix()`
    1601: @*/
    1602: PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[])
    1603: {
    1604:   PetscFunctionBegin;
    1606:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
    1607:   PetscFunctionReturn(PETSC_SUCCESS);
    1608: }

    1610: /*@C
    1611:   SNESLineSearchSetWorkVecs - Sets work vectors for the line search.

    1613:   Input Parameters:
    1614: + linesearch - the `SNESLineSearch` context
    1615: - nwork      - the number of work vectors

    1617:   Level: developer

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

    1622: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESSetWorkVecs()`
    1623: @*/
    1624: PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork)
    1625: {
    1626:   PetscFunctionBegin;
    1627:   PetscCheck(linesearch->vec_sol, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
    1628:   PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
    1629:   PetscFunctionReturn(PETSC_SUCCESS);
    1630: }

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

    1635:   Input Parameter:
    1636: . linesearch - the line search context

    1638:   Output Parameter:
    1639: . reason - The success or failure status

    1641:   Level: developer

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

    1647: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
    1648: @*/
    1649: PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *reason)
    1650: {
    1651:   PetscFunctionBegin;
    1653:   PetscAssertPointer(reason, 2);
    1654:   *reason = linesearch->reason;
    1655:   PetscFunctionReturn(PETSC_SUCCESS);
    1656: }

    1658: /*@
    1659:   SNESLineSearchSetReason - Sets the success/failure reason of the line search application

    1661:   Logically Collective; No Fortran Support

    1663:   Input Parameters:
    1664: + linesearch - the line search context
    1665: - reason     - The success or failure reason

    1667:   Level: developer

    1669:   Notes:
    1670:   This is typically called in a `SNESLineSearchType` implementation of `SNESLineSearchApply()` or a `SNESLINESEARCHSHELL` implementation to set
    1671:   the success or failure of the line search method.

    1673:   Do not call this from callbacks provided with `SNESSetFunction()`, instead perhaps use `SNESSetFunctionDomainError()`

    1675: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`, `SNESSetFunctionDomainError()`, `SNESSetFunction()`
    1676: @*/
    1677: PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason reason)
    1678: {
    1679:   PetscFunctionBegin;
    1681:   linesearch->reason = reason;
    1682:   PetscFunctionReturn(PETSC_SUCCESS);
    1683: }

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

    1689:   Logically Collective

    1691:   Input Parameters:
    1692: + linesearch   - the linesearch object
    1693: . projectfunc  - function for projecting the function to the bounds, see `SNESLineSearchVIProjectFn` for calling sequence
    1694: . normfunc     - function for computing the norm of an active set, see `SNESLineSearchVINormFn` for calling sequence
    1695: - dirderivfunc - function for computing the directional derivative of an active set, see `SNESLineSearchVIDirDerivFn` for calling sequence

    1697:   Level: advanced

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

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

    1705:   The VI solvers further require special evaluation of the directional derivative (when assuming that there exists some $G(x)$
    1706:   for which the `SNESFunctionFn` $F(x) = grad G(x)$) such that it is only calculated on the inactive set.
    1707:   This should be implemented by `dirderivfunc`.

    1709: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`,
    1710:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`, `SNESLineSearchVIDirDerivFn`
    1711: @*/
    1712: PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn *projectfunc, SNESLineSearchVINormFn *normfunc, SNESLineSearchVIDirDerivFn *dirderivfunc)
    1713: {
    1714:   PetscFunctionBegin;
    1716:   if (projectfunc) linesearch->ops->viproject = projectfunc;
    1717:   if (normfunc) linesearch->ops->vinorm = normfunc;
    1718:   if (dirderivfunc) linesearch->ops->vidirderiv = dirderivfunc;
    1719:   PetscFunctionReturn(PETSC_SUCCESS);
    1720: }

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

    1725:   Not Collective

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

    1730:   Output Parameters:
    1731: + projectfunc  - function for projecting the function to the bounds, see `SNESLineSearchVIProjectFn` for calling sequence
    1732: . normfunc     - function for computing the norm of an active set, see `SNESLineSearchVINormFn ` for calling sequence
    1733: - dirderivfunc - function for computing the directional derivative of an active set, see `SNESLineSearchVIDirDerivFn` for calling sequence

    1735:   Level: advanced

    1737: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
    1738:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`
    1739: @*/
    1740: PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn **projectfunc, SNESLineSearchVINormFn **normfunc, SNESLineSearchVIDirDerivFn **dirderivfunc)
    1741: {
    1742:   PetscFunctionBegin;
    1743:   if (projectfunc) *projectfunc = linesearch->ops->viproject;
    1744:   if (normfunc) *normfunc = linesearch->ops->vinorm;
    1745:   if (dirderivfunc) *dirderivfunc = linesearch->ops->vidirderiv;
    1746:   PetscFunctionReturn(PETSC_SUCCESS);
    1747: }

    1749: /*@C
    1750:   SNESLineSearchRegister - register a line search type `SNESLineSearchType`

    1752:   Logically Collective, No Fortran Support

    1754:   Input Parameters:
    1755: + sname    - name of the `SNESLineSearchType()`
    1756: - function - the creation function for that type

    1758:   Calling sequence of `function`:
    1759: . ls - the line search context

    1761:   Level: advanced

    1763: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
    1764: @*/
    1765: PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch ls))
    1766: {
    1767:   PetscFunctionBegin;
    1768:   PetscCall(SNESInitializePackage());
    1769:   PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
    1770:   PetscFunctionReturn(PETSC_SUCCESS);
    1771: }