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`)

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

     87:   Calling sequence of `monitordestroy`:
     88: . mctx - [optional] user-defined context for private data for the monitor routine

     90:   Level: intermediate

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

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

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

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

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

    123:   Collective

    125:   Input Parameters:
    126: + ls - the `SNESLineSearch` object
    127: - vf - the context for the monitor, in this case it is an `PetscViewerAndFormat`

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

    132:   Level: developer

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

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

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

    156: /*@
    157:   SNESLineSearchCreate - Creates a `SNESLineSearch` context.

    159:   Logically Collective

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

    164:   Output Parameter:
    165: . outlinesearch - the new line search context

    167:   Level: developer

    169:   Note:
    170:   The preferred calling sequence is to use `SNESGetLineSearch()` to acquire the `SNESLineSearch` instance
    171:   already associated with the `SNES`.

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

    179:   PetscFunctionBegin;
    180:   PetscAssertPointer(outlinesearch, 2);
    181:   PetscCall(SNESInitializePackage());

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

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

    212: /*@
    213:   SNESLineSearchSetUp - Prepares the line search for being applied by allocating
    214:   any required vectors.

    216:   Collective

    218:   Input Parameter:
    219: . linesearch - The `SNESLineSearch` instance.

    221:   Level: advanced

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

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

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

    250:   Collective

    252:   Input Parameter:
    253: . linesearch - The `SNESLineSearch` instance.

    255:   Level: developer

    257:   Note:
    258:   Usually only called by `SNESReset()`

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

    267:   PetscCall(VecDestroy(&linesearch->vec_sol_new));
    268:   PetscCall(VecDestroy(&linesearch->vec_func_new));

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

    272:   linesearch->nwork       = 0;
    273:   linesearch->setupcalled = PETSC_FALSE;
    274:   PetscFunctionReturn(PETSC_SUCCESS);
    275: }

    277: /*@C
    278:   SNESLineSearchSetFunction - Sets the function evaluation used by the `SNES` line search
    279:   `

    281:   Input Parameters:
    282: + linesearch - the `SNESLineSearch` context
    283: - func       - function evaluation routine, this is usually the function provided with `SNESSetFunction()`

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

    290:   Level: developer

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

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

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

    310:   Logically Collective

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

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

    324:   Level: intermediate

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

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

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

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

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

    347:   Input Parameter:
    348: . linesearch - the `SNESLineSearch` context

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

    354:   Level: intermediate

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

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

    371:   Logically Collective

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

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

    387:   Level: intermediate

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

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

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

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

    410:   Input Parameter:
    411: . linesearch - the `SNESLineSearch` context

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

    417:   Level: intermediate

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

    430: /*@
    431:   SNESLineSearchPreCheck - Prepares the line search for being applied.

    433:   Logically Collective

    435:   Input Parameters:
    436: + linesearch - The linesearch instance.
    437: . X          - The current solution
    438: - Y          - The step direction

    440:   Output Parameter:
    441: . changed - Indicator that the precheck routine has changed `Y`

    443:   Level: advanced

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

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

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

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

    468:   Logically Collective

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

    476:   Output Parameters:
    477: + changed_Y - Indicator if the direction `Y` has been changed.
    478: - changed_W - Indicator if the new candidate solution `W` has been changed.

    480:   Level: developer

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

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

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

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

    506:   Logically Collective

    508:   Input Parameters:
    509: + linesearch - the line search context
    510: . X          - base state for this step
    511: - ctx        - context for this function

    513:   Input/Output Parameter:
    514: . Y - correction, possibly modified

    516:   Output Parameter:
    517: . changed - flag indicating that `Y` was modified

    519:   Options Database Keys:
    520: + -snes_linesearch_precheck_picard       - activate this routine
    521: - -snes_linesearch_precheck_picard_angle - angle

    523:   Level: advanced

    525:   Notes:
    526:   This function should be passed to `SNESLineSearchSetPreCheck()`

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

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

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

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

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

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

    588:   Collective

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

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

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

    607:   Level: intermediate

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

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

    628:   linesearch->result = SNES_LINESEARCH_SUCCEEDED;

    630:   linesearch->vec_sol    = X;
    631:   linesearch->vec_update = Y;
    632:   linesearch->vec_func   = F;

    634:   PetscCall(SNESLineSearchSetUp(linesearch));

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

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

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

    643:   PetscUseTypeMethod(linesearch, apply);

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

    647:   if (fnorm) *fnorm = linesearch->fnorm;
    648:   PetscFunctionReturn(PETSC_SUCCESS);
    649: }

    651: /*@
    652:   SNESLineSearchDestroy - Destroys the line search instance.

    654:   Collective

    656:   Input Parameter:
    657: . linesearch - The line search context

    659:   Level: developer

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

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

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

    687:   Logically Collective

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

    693:   Options Database Key:
    694: . -snes_linesearch_monitor [:filename] - enables the monitor

    696:   Level: intermediate

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

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

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

    717:   Logically Collective

    719:   Input Parameter:
    720: . linesearch - the line search context

    722:   Output Parameter:
    723: . monitor - monitor context

    725:   Level: intermediate

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

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

    740:   Collective

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

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

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

    758:   Level: advanced

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

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

    786: /*@
    787:   SNESLineSearchSetFromOptions - Sets options for the line search

    789:   Logically Collective

    791:   Input Parameter:
    792: . linesearch - a `SNESLineSearch` line search context

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

    811:   Level: intermediate

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

    823:   PetscFunctionBegin;
    824:   PetscCall(SNESLineSearchRegisterAll());

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

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

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

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

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

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

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

    867:   PetscTryTypeMethod(linesearch, setfromoptions, PetscOptionsObject);

    869:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)linesearch, PetscOptionsObject));
    870:   PetscOptionsEnd();
    871:   PetscFunctionReturn(PETSC_SUCCESS);
    872: }

    874: /*@
    875:   SNESLineSearchView - Prints useful information about the line search

    877:   Logically Collective

    879:   Input Parameters:
    880: + linesearch - line search context
    881: - viewer     - the `PetscViewer` to display the line search information to

    883:   Level: intermediate

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

    891:   PetscFunctionBegin;
    893:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)linesearch), &viewer));
    895:   PetscCheckSameComm(linesearch, 1, viewer, 2);

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

    918: /*@
    919:   SNESLineSearchGetType - Gets the `SNESLinesearchType` of a `SNESLineSearch`

    921:   Logically Collective

    923:   Input Parameter:
    924: . linesearch - the line search context

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

    929:   Level: intermediate

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

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

    945:   Logically Collective

    947:   Input Parameters:
    948: + linesearch - the line search context
    949: - type       - The type of line search to be used, see `SNESLineSearchType`

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

    954:   Level: intermediate

    956:   Note:
    957:   The `SNESLineSearch` object is generally obtained with `SNESGetLineSearch()`

    959: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`, `SNESLineSearchGetType()`,
    960:           `SNESGetLineSearch()`
    961: @*/
    962: PetscErrorCode SNESLineSearchSetType(SNESLineSearch linesearch, SNESLineSearchType type)
    963: {
    964:   PetscBool match;
    965:   PetscErrorCode (*r)(SNESLineSearch);

    967:   PetscFunctionBegin;
    969:   PetscAssertPointer(type, 2);

    971:   PetscCall(PetscObjectTypeCompare((PetscObject)linesearch, type, &match));
    972:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

    974:   PetscCall(PetscFunctionListFind(SNESLineSearchList, type, &r));
    975:   PetscCheck(r, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Line Search type %s", type);
    976:   /* Destroy the previous private line search context */
    977:   PetscTryTypeMethod(linesearch, destroy);
    978:   linesearch->ops->destroy = NULL;
    979:   /* Reinitialize function pointers in SNESLineSearchOps structure */
    980:   linesearch->ops->apply          = NULL;
    981:   linesearch->ops->view           = NULL;
    982:   linesearch->ops->setfromoptions = NULL;
    983:   linesearch->ops->destroy        = NULL;

    985:   PetscCall(PetscObjectChangeTypeName((PetscObject)linesearch, type));
    986:   PetscCall((*r)(linesearch));
    987:   PetscFunctionReturn(PETSC_SUCCESS);
    988: }

    990: /*@
    991:   SNESLineSearchSetSNES - Sets the `SNES` for the linesearch for function evaluation.

    993:   Input Parameters:
    994: + linesearch - the line search context
    995: - snes       - The `SNES` instance

    997:   Level: developer

    999:   Note:
    1000:   This happens automatically when the line search is obtained/created with
    1001:   `SNESGetLineSearch()`.  This routine is therefore mainly called within `SNES`
    1002:   implementations.

    1004: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetSNES()`, `SNESLineSearchSetVecs()`
    1005: @*/
    1006: PetscErrorCode SNESLineSearchSetSNES(SNESLineSearch linesearch, SNES snes)
    1007: {
    1008:   PetscFunctionBegin;
    1011:   linesearch->snes = snes;
    1012:   PetscFunctionReturn(PETSC_SUCCESS);
    1013: }

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

    1018:   Not Collective

    1020:   Input Parameter:
    1021: . linesearch - the line search context

    1023:   Output Parameter:
    1024: . snes - The `SNES` instance

    1026:   Level: developer

    1028: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESType`, `SNESLineSearchSetVecs()`
    1029: @*/
    1030: PetscErrorCode SNESLineSearchGetSNES(SNESLineSearch linesearch, SNES *snes)
    1031: {
    1032:   PetscFunctionBegin;
    1034:   PetscAssertPointer(snes, 2);
    1035:   *snes = linesearch->snes;
    1036:   PetscFunctionReturn(PETSC_SUCCESS);
    1037: }

    1039: /*@
    1040:   SNESLineSearchGetLambda - Gets the last line search steplength used

    1042:   Not Collective

    1044:   Input Parameter:
    1045: . linesearch - the line search context

    1047:   Output Parameter:
    1048: . lambda - The last steplength computed during `SNESLineSearchApply()`

    1050:   Level: advanced

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

    1058: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetLambda()`, `SNESLineSearchGetDamping()`, `SNESLineSearchApply()`
    1059: @*/
    1060: PetscErrorCode SNESLineSearchGetLambda(SNESLineSearch linesearch, PetscReal *lambda)
    1061: {
    1062:   PetscFunctionBegin;
    1064:   PetscAssertPointer(lambda, 2);
    1065:   *lambda = linesearch->lambda;
    1066:   PetscFunctionReturn(PETSC_SUCCESS);
    1067: }

    1069: /*@
    1070:   SNESLineSearchSetLambda - Sets the line search steplength

    1072:   Input Parameters:
    1073: + linesearch - line search context
    1074: - lambda     - The steplength to use

    1076:   Level: advanced

    1078:   Note:
    1079:   This routine is typically used within implementations of `SNESLineSearchApply()`
    1080:   to set the final steplength.  This routine (and `SNESLineSearchGetLambda()`) were
    1081:   added in order to facilitate Quasi-Newton methods that use the previous steplength
    1082:   as an inner scaling parameter.

    1084: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetLambda()`
    1085: @*/
    1086: PetscErrorCode SNESLineSearchSetLambda(SNESLineSearch linesearch, PetscReal lambda)
    1087: {
    1088:   PetscFunctionBegin;
    1090:   linesearch->lambda = lambda;
    1091:   PetscFunctionReturn(PETSC_SUCCESS);
    1092: }

    1094: /*@
    1095:   SNESLineSearchGetTolerances - Gets the tolerances for the line search.

    1097:   Not Collective

    1099:   Input Parameter:
    1100: . linesearch - the line search context

    1102:   Output Parameters:
    1103: + steptol - The minimum steplength
    1104: . maxstep - The maximum steplength
    1105: . rtol    - The relative tolerance for iterative line searches
    1106: . atol    - The absolute tolerance for iterative line searches
    1107: . ltol    - The change in lambda tolerance for iterative line searches
    1108: - max_its - The maximum number of iterations of the line search

    1110:   Level: intermediate

    1112:   Note:
    1113:   Different line searches may implement these parameters slightly differently as
    1114:   the type requires.

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

    1149: /*@
    1150:   SNESLineSearchSetTolerances -  Sets the tolerances for the linesearch.

    1152:   Collective

    1154:   Input Parameters:
    1155: + linesearch - the line search context
    1156: . steptol    - The minimum steplength
    1157: . maxstep    - The maximum steplength
    1158: . rtol       - The relative tolerance for iterative line searches
    1159: . atol       - The absolute tolerance for iterative line searches
    1160: . ltol       - The change in lambda tolerance for iterative line searches
    1161: - max_it     - The maximum number of iterations of the line search

    1163:   Options Database Keys:
    1164: + -snes_linesearch_minlambda - The minimum step length
    1165: . -snes_linesearch_maxstep   - The maximum step size
    1166: . -snes_linesearch_rtol      - Relative tolerance for iterative line searches
    1167: . -snes_linesearch_atol      - Absolute tolerance for iterative line searches
    1168: . -snes_linesearch_ltol      - Change in lambda tolerance for iterative line searches
    1169: - -snes_linesearch_max_it    - The number of iterations for iterative line searches

    1171:   Level: intermediate

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

    1176: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetTolerances()`
    1177: @*/
    1178: PetscErrorCode SNESLineSearchSetTolerances(SNESLineSearch linesearch, PetscReal steptol, PetscReal maxstep, PetscReal rtol, PetscReal atol, PetscReal ltol, PetscInt max_it)
    1179: {
    1180:   PetscFunctionBegin;

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

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

    1199:   if (rtol != (PetscReal)PETSC_DEFAULT) {
    1200:     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);
    1201:     linesearch->rtol = rtol;
    1202:   }

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

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

    1214:   if (max_it != PETSC_DEFAULT) {
    1215:     PetscCheck(max_it >= 0, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", max_it);
    1216:     linesearch->max_its = max_it;
    1217:   }
    1218:   PetscFunctionReturn(PETSC_SUCCESS);
    1219: }

    1221: /*@
    1222:   SNESLineSearchGetDamping - Gets the line search damping parameter.

    1224:   Input Parameter:
    1225: . linesearch - the line search context

    1227:   Output Parameter:
    1228: . damping - The damping parameter

    1230:   Level: advanced

    1232: .seealso: [](ch_snes), `SNES`, `SNESLineSearchGetStepTolerance()`, `SNESQN`
    1233: @*/
    1234: PetscErrorCode SNESLineSearchGetDamping(SNESLineSearch linesearch, PetscReal *damping)
    1235: {
    1236:   PetscFunctionBegin;
    1238:   PetscAssertPointer(damping, 2);
    1239:   *damping = linesearch->damping;
    1240:   PetscFunctionReturn(PETSC_SUCCESS);
    1241: }

    1243: /*@
    1244:   SNESLineSearchSetDamping - Sets the line search damping parameter.

    1246:   Input Parameters:
    1247: + linesearch - the line search context
    1248: - damping    - The damping parameter

    1250:   Options Database Key:
    1251: . -snes_linesearch_damping <damping> - the damping value

    1253:   Level: intermediate

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

    1262: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetDamping()`
    1263: @*/
    1264: PetscErrorCode SNESLineSearchSetDamping(SNESLineSearch linesearch, PetscReal damping)
    1265: {
    1266:   PetscFunctionBegin;
    1268:   linesearch->damping = damping;
    1269:   PetscFunctionReturn(PETSC_SUCCESS);
    1270: }

    1272: /*@
    1273:   SNESLineSearchGetOrder - Gets the line search approximation order.

    1275:   Input Parameter:
    1276: . linesearch - the line search context

    1278:   Output Parameter:
    1279: . order - The order

    1281:   Level: intermediate

    1283: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetOrder()`
    1284: @*/
    1285: PetscErrorCode SNESLineSearchGetOrder(SNESLineSearch linesearch, PetscInt *order)
    1286: {
    1287:   PetscFunctionBegin;
    1289:   PetscAssertPointer(order, 2);
    1290:   *order = linesearch->order;
    1291:   PetscFunctionReturn(PETSC_SUCCESS);
    1292: }

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

    1297:   Input Parameters:
    1298: + linesearch - the line search context
    1299: - order      - The order

    1301:   Level: intermediate

    1303:   Values for `order`\:
    1304: +  1 or `SNES_LINESEARCH_ORDER_LINEAR` - linear order
    1305: .  2 or `SNES_LINESEARCH_ORDER_QUADRATIC` - quadratic order
    1306: -  3 or `SNES_LINESEARCH_ORDER_CUBIC` - cubic order

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

    1311:   Note:
    1312:   These orders are supported by `SNESLINESEARCHBT` and `SNESLINESEARCHCP`

    1314: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetOrder()`, `SNESLineSearchSetDamping()`
    1315: @*/
    1316: PetscErrorCode SNESLineSearchSetOrder(SNESLineSearch linesearch, PetscInt order)
    1317: {
    1318:   PetscFunctionBegin;
    1320:   linesearch->order = order;
    1321:   PetscFunctionReturn(PETSC_SUCCESS);
    1322: }

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

    1327:   Not Collective

    1329:   Input Parameter:
    1330: . linesearch - the line search context

    1332:   Output Parameters:
    1333: + xnorm - The norm of the current solution
    1334: . fnorm - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution.
    1335: - ynorm - The norm of the current update (after scaling by the linesearch computed lambda)

    1337:   Level: developer

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

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

    1345: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
    1346: @*/
    1347: PetscErrorCode SNESLineSearchGetNorms(SNESLineSearch linesearch, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm)
    1348: {
    1349:   PetscFunctionBegin;
    1351:   if (xnorm) *xnorm = linesearch->xnorm;
    1352:   if (fnorm) *fnorm = linesearch->fnorm;
    1353:   if (ynorm) *ynorm = linesearch->ynorm;
    1354:   PetscFunctionReturn(PETSC_SUCCESS);
    1355: }

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

    1360:   Collective

    1362:   Input Parameters:
    1363: + linesearch - the line search context
    1364: . xnorm      - The norm of the current solution
    1365: . fnorm      - The norm of the current function, this is the `norm(function(X))` where `X` is the current solution
    1366: - ynorm      - The norm of the current update (after scaling by the linesearch computed lambda)

    1368:   Level: developer

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

    1373: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetVecs()`
    1374: @*/
    1375: PetscErrorCode SNESLineSearchSetNorms(SNESLineSearch linesearch, PetscReal xnorm, PetscReal fnorm, PetscReal ynorm)
    1376: {
    1377:   PetscFunctionBegin;
    1379:   linesearch->xnorm = xnorm;
    1380:   linesearch->fnorm = fnorm;
    1381:   linesearch->ynorm = ynorm;
    1382:   PetscFunctionReturn(PETSC_SUCCESS);
    1383: }

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

    1388:   Input Parameter:
    1389: . linesearch - the line search context

    1391:   Options Database Key:
    1392: . -snes_linesearch_norms - turn norm computation on or off

    1394:   Level: intermediate

    1396:   Developer Note:
    1397:   The options database key is misnamed. It should be -snes_linesearch_compute_norms

    1399: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms`, `SNESLineSearchSetNorms()`, `SNESLineSearchSetComputeNorms()`
    1400: @*/
    1401: PetscErrorCode SNESLineSearchComputeNorms(SNESLineSearch linesearch)
    1402: {
    1403:   SNES snes;

    1405:   PetscFunctionBegin;
    1406:   if (linesearch->norms) {
    1407:     if (linesearch->ops->vinorm) {
    1408:       PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
    1409:       PetscCall(VecNorm(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1410:       PetscCall(VecNorm(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1411:       PetscCall((*linesearch->ops->vinorm)(snes, linesearch->vec_func, linesearch->vec_sol, &linesearch->fnorm));
    1412:     } else {
    1413:       PetscCall(VecNormBegin(linesearch->vec_func, NORM_2, &linesearch->fnorm));
    1414:       PetscCall(VecNormBegin(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1415:       PetscCall(VecNormBegin(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1416:       PetscCall(VecNormEnd(linesearch->vec_func, NORM_2, &linesearch->fnorm));
    1417:       PetscCall(VecNormEnd(linesearch->vec_sol, NORM_2, &linesearch->xnorm));
    1418:       PetscCall(VecNormEnd(linesearch->vec_update, NORM_2, &linesearch->ynorm));
    1419:     }
    1420:   }
    1421:   PetscFunctionReturn(PETSC_SUCCESS);
    1422: }

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

    1427:   Input Parameters:
    1428: + linesearch - the line search context
    1429: - flg        - indicates whether or not to compute norms

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

    1434:   Level: intermediate

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

    1439:   Developer Note:
    1440:   The options database key is misnamed. It should be -snes_linesearch_compute_norms

    1442: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetNorms()`, `SNESLineSearchSetNorms()`, `SNESLineSearchComputeNorms()`, `SNESLINESEARCHBASIC`
    1443: @*/
    1444: PetscErrorCode SNESLineSearchSetComputeNorms(SNESLineSearch linesearch, PetscBool flg)
    1445: {
    1446:   PetscFunctionBegin;
    1447:   linesearch->norms = flg;
    1448:   PetscFunctionReturn(PETSC_SUCCESS);
    1449: }

    1451: /*@
    1452:   SNESLineSearchGetVecs - Gets the vectors from the `SNESLineSearch` context

    1454:   Not Collective but the vectors are parallel

    1456:   Input Parameter:
    1457: . linesearch - the line search context

    1459:   Output Parameters:
    1460: + X - Solution vector
    1461: . F - Function vector
    1462: . Y - Search direction vector
    1463: . W - Solution work vector
    1464: - G - Function work vector

    1466:   Level: advanced

    1468:   Notes:
    1469:   At the beginning of a line search application, `X` should contain a
    1470:   solution and the vector `F` the function computed at `X`.  At the end of the
    1471:   line search application, `X` should contain the new solution, and `F` the
    1472:   function evaluated at the new solution.

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

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

    1505: /*@
    1506:   SNESLineSearchSetVecs - Sets the vectors on the `SNESLineSearch` context

    1508:   Logically Collective

    1510:   Input Parameters:
    1511: + linesearch - the line search context
    1512: . X          - Solution vector
    1513: . F          - Function vector
    1514: . Y          - Search direction vector
    1515: . W          - Solution work vector
    1516: - G          - Function work vector

    1518:   Level: developer

    1520: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetNorms()`, `SNESLineSearchGetVecs()`
    1521: @*/
    1522: PetscErrorCode SNESLineSearchSetVecs(SNESLineSearch linesearch, Vec X, Vec F, Vec Y, Vec W, Vec G)
    1523: {
    1524:   PetscFunctionBegin;
    1526:   if (X) {
    1528:     linesearch->vec_sol = X;
    1529:   }
    1530:   if (F) {
    1532:     linesearch->vec_func = F;
    1533:   }
    1534:   if (Y) {
    1536:     linesearch->vec_update = Y;
    1537:   }
    1538:   if (W) {
    1540:     linesearch->vec_sol_new = W;
    1541:   }
    1542:   if (G) {
    1544:     linesearch->vec_func_new = G;
    1545:   }
    1546:   PetscFunctionReturn(PETSC_SUCCESS);
    1547: }

    1549: /*@
    1550:   SNESLineSearchAppendOptionsPrefix - Appends to the prefix used for searching for all
    1551:   `SNESLineSearch` options in the database.

    1553:   Logically Collective

    1555:   Input Parameters:
    1556: + linesearch - the `SNESLineSearch` context
    1557: - prefix     - the prefix to prepend to all option names

    1559:   Level: advanced

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

    1565: .seealso: [](ch_snes), `SNES`, `SNESLineSearch()`, `SNESLineSearchSetFromOptions()`, `SNESGetOptionsPrefix()`
    1566: @*/
    1567: PetscErrorCode SNESLineSearchAppendOptionsPrefix(SNESLineSearch linesearch, const char prefix[])
    1568: {
    1569:   PetscFunctionBegin;
    1571:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)linesearch, prefix));
    1572:   PetscFunctionReturn(PETSC_SUCCESS);
    1573: }

    1575: /*@
    1576:   SNESLineSearchGetOptionsPrefix - Gets the prefix used for searching for all
    1577:   SNESLineSearch options in the database.

    1579:   Not Collective

    1581:   Input Parameter:
    1582: . linesearch - the `SNESLineSearch` context

    1584:   Output Parameter:
    1585: . prefix - pointer to the prefix string used

    1587:   Level: advanced

    1589:   Fortran Notes:
    1590:   The user should pass in a string 'prefix' of
    1591:   sufficient length to hold the prefix.

    1593: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESAppendOptionsPrefix()`
    1594: @*/
    1595: PetscErrorCode SNESLineSearchGetOptionsPrefix(SNESLineSearch linesearch, const char *prefix[])
    1596: {
    1597:   PetscFunctionBegin;
    1599:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)linesearch, prefix));
    1600:   PetscFunctionReturn(PETSC_SUCCESS);
    1601: }

    1603: /*@C
    1604:   SNESLineSearchSetWorkVecs - Sets work vectors for the line search.

    1606:   Input Parameters:
    1607: + linesearch - the `SNESLineSearch` context
    1608: - nwork      - the number of work vectors

    1610:   Level: developer

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

    1615: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESSetWorkVecs()`
    1616: @*/
    1617: PetscErrorCode SNESLineSearchSetWorkVecs(SNESLineSearch linesearch, PetscInt nwork)
    1618: {
    1619:   PetscFunctionBegin;
    1620:   PetscCheck(linesearch->vec_sol, PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "Cannot get linesearch work-vectors without setting a solution vec!");
    1621:   PetscCall(VecDuplicateVecs(linesearch->vec_sol, nwork, &linesearch->work));
    1622:   PetscFunctionReturn(PETSC_SUCCESS);
    1623: }

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

    1628:   Input Parameter:
    1629: . linesearch - the line search context

    1631:   Output Parameter:
    1632: . result - The success or failure status

    1634:   Level: developer

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

    1640: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetReason()`, `SNESLineSearchReason`
    1641: @*/
    1642: PetscErrorCode SNESLineSearchGetReason(SNESLineSearch linesearch, SNESLineSearchReason *result)
    1643: {
    1644:   PetscFunctionBegin;
    1646:   PetscAssertPointer(result, 2);
    1647:   *result = linesearch->result;
    1648:   PetscFunctionReturn(PETSC_SUCCESS);
    1649: }

    1651: /*@
    1652:   SNESLineSearchSetReason - Sets the success/failure status of the line search application

    1654:   Logically Collective; No Fortran Support

    1656:   Input Parameters:
    1657: + linesearch - the line search context
    1658: - result     - The success or failure status

    1660:   Level: developer

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

    1666: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchReason`, `SNESLineSearchGetSResult()`
    1667: @*/
    1668: PetscErrorCode SNESLineSearchSetReason(SNESLineSearch linesearch, SNESLineSearchReason result)
    1669: {
    1670:   PetscFunctionBegin;
    1672:   linesearch->result = result;
    1673:   PetscFunctionReturn(PETSC_SUCCESS);
    1674: }

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

    1680:   Logically Collective

    1682:   Input Parameters:
    1683: + linesearch  - the linesearch object
    1684: . projectfunc - function for projecting the function to the bounds, see `SNESLineSearchVIProjectFn` for calling sequence
    1685: - normfunc    - function for computing the norm of an active set, see `SNESLineSearchVINormFn` for calling sequence

    1687:   Level: advanced

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

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

    1695: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchGetVIFunctions()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()`,
    1696:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`
    1697: @*/
    1698: PetscErrorCode SNESLineSearchSetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn *projectfunc, SNESLineSearchVINormFn *normfunc)
    1699: {
    1700:   PetscFunctionBegin;
    1702:   if (projectfunc) linesearch->ops->viproject = projectfunc;
    1703:   if (normfunc) linesearch->ops->vinorm = normfunc;
    1704:   PetscFunctionReturn(PETSC_SUCCESS);
    1705: }

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

    1710:   Not Collective

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

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

    1719:   Level: advanced

    1721: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchSetVIFunctions()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchGetPreCheck()`,
    1722:           `SNESLineSearchVIProjectFn`, `SNESLineSearchVINormFn`
    1723: @*/
    1724: PetscErrorCode SNESLineSearchGetVIFunctions(SNESLineSearch linesearch, SNESLineSearchVIProjectFn **projectfunc, SNESLineSearchVINormFn **normfunc)
    1725: {
    1726:   PetscFunctionBegin;
    1727:   if (projectfunc) *projectfunc = linesearch->ops->viproject;
    1728:   if (normfunc) *normfunc = linesearch->ops->vinorm;
    1729:   PetscFunctionReturn(PETSC_SUCCESS);
    1730: }

    1732: /*@C
    1733:   SNESLineSearchRegister - register a line search type `SNESLineSearchType`

    1735:   Logically Collective, No Fortran Support

    1737:   Input Parameters:
    1738: + sname    - name of the `SNESLineSearchType()`
    1739: - function - the creation function for that type

    1741:   Calling sequence of `function`:
    1742: . ls - the line search context

    1744:   Level: advanced

    1746: .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESLineSearchType`, `SNESLineSearchSetType()`
    1747: @*/
    1748: PetscErrorCode SNESLineSearchRegister(const char sname[], PetscErrorCode (*function)(SNESLineSearch ls))
    1749: {
    1750:   PetscFunctionBegin;
    1751:   PetscCall(SNESInitializePackage());
    1752:   PetscCall(PetscFunctionListAdd(&SNESLineSearchList, sname, function));
    1753:   PetscFunctionReturn(PETSC_SUCCESS);
    1754: }