Actual source code: taosolver.c

      1: #include <petsc/private/taoimpl.h>
      2: #include <petsc/private/snesimpl.h>

      4: PetscBool         TaoRegisterAllCalled = PETSC_FALSE;
      5: PetscFunctionList TaoList              = NULL;

      7: PetscClassId TAO_CLASSID;

      9: PetscLogEvent TAO_Solve;
     10: PetscLogEvent TAO_ObjectiveEval;
     11: PetscLogEvent TAO_GradientEval;
     12: PetscLogEvent TAO_ObjGradEval;
     13: PetscLogEvent TAO_HessianEval;
     14: PetscLogEvent TAO_JacobianEval;
     15: PetscLogEvent TAO_ConstraintsEval;

     17: const char *TaoSubSetTypes[] = {"subvec", "mask", "matrixfree", "TaoSubSetType", "TAO_SUBSET_", NULL};

     19: struct _n_TaoMonitorDrawCtx {
     20:   PetscViewer viewer;
     21:   PetscInt    howoften; /* when > 0 uses iteration % howoften, when negative only final solution plotted */
     22: };

     24: static PetscErrorCode KSPPreSolve_TAOEW_Private(KSP ksp, Vec b, Vec x, void *ctx)
     25: {
     26:   Tao  tao          = (Tao)ctx;
     27:   SNES snes_ewdummy = tao->snes_ewdummy;

     29:   PetscFunctionBegin;
     30:   if (!snes_ewdummy) PetscFunctionReturn(PETSC_SUCCESS);
     31:   /* populate snes_ewdummy struct values used in KSPPreSolve_SNESEW */
     32:   snes_ewdummy->vec_func = b;
     33:   snes_ewdummy->rtol     = tao->gttol;
     34:   snes_ewdummy->iter     = tao->niter;
     35:   PetscCall(VecNorm(b, NORM_2, &snes_ewdummy->norm));
     36:   PetscCall(KSPPreSolve_SNESEW(ksp, b, x, snes_ewdummy));
     37:   snes_ewdummy->vec_func = NULL;
     38:   PetscFunctionReturn(PETSC_SUCCESS);
     39: }

     41: static PetscErrorCode KSPPostSolve_TAOEW_Private(KSP ksp, Vec b, Vec x, void *ctx)
     42: {
     43:   Tao  tao          = (Tao)ctx;
     44:   SNES snes_ewdummy = tao->snes_ewdummy;

     46:   PetscFunctionBegin;
     47:   if (!snes_ewdummy) PetscFunctionReturn(PETSC_SUCCESS);
     48:   PetscCall(KSPPostSolve_SNESEW(ksp, b, x, snes_ewdummy));
     49:   PetscFunctionReturn(PETSC_SUCCESS);
     50: }

     52: static PetscErrorCode TaoSetUpEW_Private(Tao tao)
     53: {
     54:   SNESKSPEW  *kctx;
     55:   const char *ewprefix;

     57:   PetscFunctionBegin;
     58:   if (!tao->ksp) PetscFunctionReturn(PETSC_SUCCESS);
     59:   if (tao->ksp_ewconv) {
     60:     if (!tao->snes_ewdummy) PetscCall(SNESCreate(PetscObjectComm((PetscObject)tao), &tao->snes_ewdummy));
     61:     tao->snes_ewdummy->ksp_ewconv = PETSC_TRUE;
     62:     PetscCall(KSPSetPreSolve(tao->ksp, KSPPreSolve_TAOEW_Private, tao));
     63:     PetscCall(KSPSetPostSolve(tao->ksp, KSPPostSolve_TAOEW_Private, tao));

     65:     PetscCall(KSPGetOptionsPrefix(tao->ksp, &ewprefix));
     66:     kctx = (SNESKSPEW *)tao->snes_ewdummy->kspconvctx;
     67:     PetscCall(SNESEWSetFromOptions_Private(kctx, PETSC_FALSE, PetscObjectComm((PetscObject)tao), ewprefix));
     68:   } else PetscCall(SNESDestroy(&tao->snes_ewdummy));
     69:   PetscFunctionReturn(PETSC_SUCCESS);
     70: }

     72: /*@
     73:   TaoParametersInitialize - Sets all the parameters in `tao` to their default value (when `TaoCreate()` was called) if they
     74:   currently contain default values. Default values are the parameter values when the object's type is set.

     76:   Collective

     78:   Input Parameter:
     79: . tao - the `Tao` object

     81:   Level: developer

     83:   Developer Note:
     84:   This is called by all the `TaoCreate_XXX()` routines.

     86: .seealso: [](ch_snes), `Tao`, `TaoSolve()`, `TaoDestroy()`,
     87:           `PetscObjectParameterSetDefault()`
     88: @*/
     89: PetscErrorCode TaoParametersInitialize(Tao tao)
     90: {
     91:   PetscObjectParameterSetDefault(tao, max_it, 10000);
     92:   PetscObjectParameterSetDefault(tao, max_funcs, PETSC_UNLIMITED);
     93:   PetscObjectParameterSetDefault(tao, gatol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
     94:   PetscObjectParameterSetDefault(tao, grtol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
     95:   PetscObjectParameterSetDefault(tao, crtol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
     96:   PetscObjectParameterSetDefault(tao, catol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
     97:   PetscObjectParameterSetDefault(tao, gttol, 0.0);
     98:   PetscObjectParameterSetDefault(tao, steptol, 0.0);
     99:   PetscObjectParameterSetDefault(tao, fmin, PETSC_NINFINITY);
    100:   PetscObjectParameterSetDefault(tao, trust0, PETSC_INFINITY);
    101:   return PETSC_SUCCESS;
    102: }

    104: /*@
    105:   TaoCreate - Creates a Tao solver

    107:   Collective

    109:   Input Parameter:
    110: . comm - MPI communicator

    112:   Output Parameter:
    113: . newtao - the new `Tao` context

    115:   Options Database Key:
    116: . -tao_type - select which method Tao should use

    118:   Level: beginner

    120: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoDestroy()`, `TaoSetFromOptions()`, `TaoSetType()`
    121: @*/
    122: PetscErrorCode TaoCreate(MPI_Comm comm, Tao *newtao)
    123: {
    124:   Tao tao;

    126:   PetscFunctionBegin;
    127:   PetscAssertPointer(newtao, 2);
    128:   PetscCall(TaoInitializePackage());
    129:   PetscCall(TaoLineSearchInitializePackage());

    131:   PetscCall(PetscHeaderCreate(tao, TAO_CLASSID, "Tao", "Optimization solver", "Tao", comm, TaoDestroy, TaoView));
    132:   tao->ops->convergencetest = TaoDefaultConvergenceTest;

    134:   tao->hist_reset = PETSC_TRUE;
    135:   PetscCall(TaoResetStatistics(tao));
    136:   *newtao = tao;
    137:   PetscFunctionReturn(PETSC_SUCCESS);
    138: }

    140: /*@
    141:   TaoSolve - Solves an optimization problem min F(x) s.t. l <= x <= u

    143:   Collective

    145:   Input Parameter:
    146: . tao - the `Tao` context

    148:   Level: beginner

    150:   Notes:
    151:   The user must set up the `Tao` object  with calls to `TaoSetSolution()`, `TaoSetObjective()`, `TaoSetGradient()`, and (if using 2nd order method) `TaoSetHessian()`.

    153:   You should call `TaoGetConvergedReason()` or run with `-tao_converged_reason` to determine if the optimization algorithm actually succeeded or
    154:   why it failed.

    156: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSetObjective()`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoGetConvergedReason()`, `TaoSetUp()`
    157:  @*/
    158: PetscErrorCode TaoSolve(Tao tao)
    159: {
    160:   static PetscBool set = PETSC_FALSE;

    162:   PetscFunctionBegin;
    164:   PetscCall(PetscCitationsRegister("@TechReport{tao-user-ref,\n"
    165:                                    "title   = {Toolkit for Advanced Optimization (TAO) Users Manual},\n"
    166:                                    "author  = {Todd Munson and Jason Sarich and Stefan Wild and Steve Benson and Lois Curfman McInnes},\n"
    167:                                    "Institution = {Argonne National Laboratory},\n"
    168:                                    "Year   = 2014,\n"
    169:                                    "Number = {ANL/MCS-TM-322 - Revision 3.5},\n"
    170:                                    "url    = {https://www.mcs.anl.gov/research/projects/tao/}\n}\n",
    171:                                    &set));
    172:   tao->header_printed = PETSC_FALSE;
    173:   PetscCall(TaoSetUp(tao));
    174:   PetscCall(TaoResetStatistics(tao));
    175:   if (tao->linesearch) PetscCall(TaoLineSearchReset(tao->linesearch));

    177:   PetscCall(PetscLogEventBegin(TAO_Solve, tao, 0, 0, 0));
    178:   PetscTryTypeMethod(tao, solve);
    179:   PetscCall(PetscLogEventEnd(TAO_Solve, tao, 0, 0, 0));

    181:   PetscCall(VecViewFromOptions(tao->solution, (PetscObject)tao, "-tao_view_solution"));

    183:   tao->ntotalits += tao->niter;

    185:   if (tao->printreason) {
    186:     PetscViewer viewer = PETSC_VIEWER_STDOUT_(((PetscObject)tao)->comm);
    187:     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)tao)->tablevel));
    188:     if (tao->reason > 0) {
    189:       PetscCall(PetscViewerASCIIPrintf(viewer, "  TAO %s solve converged due to %s iterations %" PetscInt_FMT "\n", ((PetscObject)tao)->prefix ? ((PetscObject)tao)->prefix : "", TaoConvergedReasons[tao->reason], tao->niter));
    190:     } else {
    191:       PetscCall(PetscViewerASCIIPrintf(viewer, "  TAO %s solve did not converge due to %s iteration %" PetscInt_FMT "\n", ((PetscObject)tao)->prefix ? ((PetscObject)tao)->prefix : "", TaoConvergedReasons[tao->reason], tao->niter));
    192:     }
    193:     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)tao)->tablevel));
    194:   }
    195:   PetscCall(TaoViewFromOptions(tao, NULL, "-tao_view"));
    196:   PetscFunctionReturn(PETSC_SUCCESS);
    197: }

    199: /*@
    200:   TaoSetUp - Sets up the internal data structures for the later use
    201:   of a Tao solver

    203:   Collective

    205:   Input Parameter:
    206: . tao - the `Tao` context

    208:   Level: advanced

    210:   Note:
    211:   The user will not need to explicitly call `TaoSetUp()`, as it will
    212:   automatically be called in `TaoSolve()`.  However, if the user
    213:   desires to call it explicitly, it should come after `TaoCreate()`
    214:   and any TaoSetSomething() routines, but before `TaoSolve()`.

    216: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
    217: @*/
    218: PetscErrorCode TaoSetUp(Tao tao)
    219: {
    220:   PetscFunctionBegin;
    222:   if (tao->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
    223:   PetscCall(TaoSetUpEW_Private(tao));
    224:   PetscCheck(tao->solution, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Must call TaoSetSolution");
    225:   PetscTryTypeMethod(tao, setup);
    226:   tao->setupcalled = PETSC_TRUE;
    227:   PetscFunctionReturn(PETSC_SUCCESS);
    228: }

    230: /*@
    231:   TaoDestroy - Destroys the `Tao` context that was created with `TaoCreate()`

    233:   Collective

    235:   Input Parameter:
    236: . tao - the `Tao` context

    238:   Level: beginner

    240: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
    241: @*/
    242: PetscErrorCode TaoDestroy(Tao *tao)
    243: {
    244:   PetscFunctionBegin;
    245:   if (!*tao) PetscFunctionReturn(PETSC_SUCCESS);
    247:   if (--((PetscObject)*tao)->refct > 0) {
    248:     *tao = NULL;
    249:     PetscFunctionReturn(PETSC_SUCCESS);
    250:   }

    252:   PetscTryTypeMethod(*tao, destroy);
    253:   PetscCall(KSPDestroy(&(*tao)->ksp));
    254:   PetscCall(SNESDestroy(&(*tao)->snes_ewdummy));
    255:   PetscCall(TaoLineSearchDestroy(&(*tao)->linesearch));

    257:   if ((*tao)->ops->convergencedestroy) {
    258:     PetscCall((*(*tao)->ops->convergencedestroy)((*tao)->cnvP));
    259:     if ((*tao)->jacobian_state_inv) PetscCall(MatDestroy(&(*tao)->jacobian_state_inv));
    260:   }
    261:   PetscCall(VecDestroy(&(*tao)->solution));
    262:   PetscCall(VecDestroy(&(*tao)->gradient));
    263:   PetscCall(VecDestroy(&(*tao)->ls_res));

    265:   if ((*tao)->gradient_norm) {
    266:     PetscCall(PetscObjectDereference((PetscObject)(*tao)->gradient_norm));
    267:     PetscCall(VecDestroy(&(*tao)->gradient_norm_tmp));
    268:   }

    270:   PetscCall(VecDestroy(&(*tao)->XL));
    271:   PetscCall(VecDestroy(&(*tao)->XU));
    272:   PetscCall(VecDestroy(&(*tao)->IL));
    273:   PetscCall(VecDestroy(&(*tao)->IU));
    274:   PetscCall(VecDestroy(&(*tao)->DE));
    275:   PetscCall(VecDestroy(&(*tao)->DI));
    276:   PetscCall(VecDestroy(&(*tao)->constraints));
    277:   PetscCall(VecDestroy(&(*tao)->constraints_equality));
    278:   PetscCall(VecDestroy(&(*tao)->constraints_inequality));
    279:   PetscCall(VecDestroy(&(*tao)->stepdirection));
    280:   PetscCall(MatDestroy(&(*tao)->hessian_pre));
    281:   PetscCall(MatDestroy(&(*tao)->hessian));
    282:   PetscCall(MatDestroy(&(*tao)->ls_jac));
    283:   PetscCall(MatDestroy(&(*tao)->ls_jac_pre));
    284:   PetscCall(MatDestroy(&(*tao)->jacobian_pre));
    285:   PetscCall(MatDestroy(&(*tao)->jacobian));
    286:   PetscCall(MatDestroy(&(*tao)->jacobian_state_pre));
    287:   PetscCall(MatDestroy(&(*tao)->jacobian_state));
    288:   PetscCall(MatDestroy(&(*tao)->jacobian_state_inv));
    289:   PetscCall(MatDestroy(&(*tao)->jacobian_design));
    290:   PetscCall(MatDestroy(&(*tao)->jacobian_equality));
    291:   PetscCall(MatDestroy(&(*tao)->jacobian_equality_pre));
    292:   PetscCall(MatDestroy(&(*tao)->jacobian_inequality));
    293:   PetscCall(MatDestroy(&(*tao)->jacobian_inequality_pre));
    294:   PetscCall(ISDestroy(&(*tao)->state_is));
    295:   PetscCall(ISDestroy(&(*tao)->design_is));
    296:   PetscCall(VecDestroy(&(*tao)->res_weights_v));
    297:   PetscCall(TaoMonitorCancel(*tao));
    298:   if ((*tao)->hist_malloc) PetscCall(PetscFree4((*tao)->hist_obj, (*tao)->hist_resid, (*tao)->hist_cnorm, (*tao)->hist_lits));
    299:   if ((*tao)->res_weights_n) {
    300:     PetscCall(PetscFree((*tao)->res_weights_rows));
    301:     PetscCall(PetscFree((*tao)->res_weights_cols));
    302:     PetscCall(PetscFree((*tao)->res_weights_w));
    303:   }
    304:   PetscCall(PetscHeaderDestroy(tao));
    305:   PetscFunctionReturn(PETSC_SUCCESS);
    306: }

    308: /*@
    309:   TaoKSPSetUseEW - Sets `SNES` to use Eisenstat-Walker method {cite}`ew96`for computing relative tolerance for linear solvers.

    311:   Logically Collective

    313:   Input Parameters:
    314: + tao  - Tao context
    315: - flag - `PETSC_TRUE` or `PETSC_FALSE`

    317:   Level: advanced

    319:   Note:
    320:   See `SNESKSPSetUseEW()` for customization details.

    322: .seealso: [](ch_tao), `Tao`, `SNESKSPSetUseEW()`
    323: @*/
    324: PetscErrorCode TaoKSPSetUseEW(Tao tao, PetscBool flag)
    325: {
    326:   PetscFunctionBegin;
    329:   tao->ksp_ewconv = flag;
    330:   PetscFunctionReturn(PETSC_SUCCESS);
    331: }

    333: /*@
    334:   TaoSetFromOptions - Sets various Tao parameters from the options database

    336:   Collective

    338:   Input Parameter:
    339: . tao - the `Tao` solver context

    341:   Options Database Keys:
    342: + -tao_type <type>             - The algorithm that Tao uses (lmvm, nls, etc.)
    343: . -tao_gatol <gatol>           - absolute error tolerance for ||gradient||
    344: . -tao_grtol <grtol>           - relative error tolerance for ||gradient||
    345: . -tao_gttol <gttol>           - reduction of ||gradient|| relative to initial gradient
    346: . -tao_max_it <max>            - sets maximum number of iterations
    347: . -tao_max_funcs <max>         - sets maximum number of function evaluations
    348: . -tao_fmin <fmin>             - stop if function value reaches fmin
    349: . -tao_steptol <tol>           - stop if trust region radius less than <tol>
    350: . -tao_trust0 <t>              - initial trust region radius
    351: . -tao_view_solution           - view the solution at the end of the optimization process
    352: . -tao_monitor                 - prints function value and residual norm at each iteration
    353: . -tao_monitor_short           - same as `-tao_monitor`, but truncates very small values
    354: . -tao_monitor_constraint_norm - prints objective value, gradient, and constraint norm at each iteration
    355: . -tao_monitor_globalization   - prints information about the globalization at each iteration
    356: . -tao_monitor_solution        - prints solution vector at each iteration
    357: . -tao_monitor_ls_residual     - prints least-squares residual vector at each iteration
    358: . -tao_monitor_step            - prints step vector at each iteration
    359: . -tao_monitor_gradient        - prints gradient vector at each iteration
    360: . -tao_monitor_solution_draw   - graphically view solution vector at each iteration
    361: . -tao_monitor_step_draw       - graphically view step vector at each iteration
    362: . -tao_monitor_gradient_draw   - graphically view gradient at each iteration
    363: . -tao_monitor_cancel          - cancels all monitors (except those set with command line)
    364: . -tao_fd_gradient             - use gradient computed with finite differences
    365: . -tao_fd_hessian              - use hessian computed with finite differences
    366: . -tao_mf_hessian              - use matrix-free Hessian computed with finite differences
    367: . -tao_view                    - prints information about the Tao after solving
    368: - -tao_converged_reason        - prints the reason Tao stopped iterating

    370:   Level: beginner

    372:   Note:
    373:   To see all options, run your program with the `-help` option or consult the
    374:   user's manual. Should be called after `TaoCreate()` but before `TaoSolve()`

    376: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
    377: @*/
    378: PetscErrorCode TaoSetFromOptions(Tao tao)
    379: {
    380:   TaoType     default_type = TAOLMVM;
    381:   char        type[256], monfilename[PETSC_MAX_PATH_LEN];
    382:   PetscViewer monviewer;
    383:   PetscBool   flg, found;
    384:   MPI_Comm    comm;
    385:   PetscReal   catol, crtol, gatol, grtol, gttol;

    387:   PetscFunctionBegin;
    389:   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));

    391:   if (((PetscObject)tao)->type_name) default_type = ((PetscObject)tao)->type_name;

    393:   PetscObjectOptionsBegin((PetscObject)tao);
    394:   /* Check for type from options */
    395:   PetscCall(PetscOptionsFList("-tao_type", "Tao Solver type", "TaoSetType", TaoList, default_type, type, 256, &flg));
    396:   if (flg) {
    397:     PetscCall(TaoSetType(tao, type));
    398:   } else if (!((PetscObject)tao)->type_name) {
    399:     PetscCall(TaoSetType(tao, default_type));
    400:   }

    402:   /* Tao solvers do not set the prefix, set it here if not yet done
    403:      We do it after SetType since solver may have been changed */
    404:   if (tao->linesearch) {
    405:     const char *prefix;
    406:     PetscCall(TaoLineSearchGetOptionsPrefix(tao->linesearch, &prefix));
    407:     if (!prefix) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, ((PetscObject)tao)->prefix));
    408:   }

    410:   catol = tao->catol;
    411:   crtol = tao->crtol;
    412:   PetscCall(PetscOptionsReal("-tao_catol", "Stop if constraints violations within", "TaoSetConstraintTolerances", tao->catol, &catol, NULL));
    413:   PetscCall(PetscOptionsReal("-tao_crtol", "Stop if relative constraint violations within", "TaoSetConstraintTolerances", tao->crtol, &crtol, NULL));
    414:   PetscCall(TaoSetConstraintTolerances(tao, catol, crtol));

    416:   gatol = tao->gatol;
    417:   grtol = tao->grtol;
    418:   gttol = tao->gttol;
    419:   PetscCall(PetscOptionsReal("-tao_gatol", "Stop if norm of gradient less than", "TaoSetTolerances", tao->gatol, &gatol, NULL));
    420:   PetscCall(PetscOptionsReal("-tao_grtol", "Stop if norm of gradient divided by the function value is less than", "TaoSetTolerances", tao->grtol, &grtol, NULL));
    421:   PetscCall(PetscOptionsReal("-tao_gttol", "Stop if the norm of the gradient is less than the norm of the initial gradient times tol", "TaoSetTolerances", tao->gttol, &gttol, NULL));
    422:   PetscCall(TaoSetTolerances(tao, gatol, grtol, gttol));

    424:   PetscCall(PetscOptionsInt("-tao_max_it", "Stop if iteration number exceeds", "TaoSetMaximumIterations", tao->max_it, &tao->max_it, &flg));
    425:   if (flg) PetscCall(TaoSetMaximumIterations(tao, tao->max_it));

    427:   PetscCall(PetscOptionsInt("-tao_max_funcs", "Stop if number of function evaluations exceeds", "TaoSetMaximumFunctionEvaluations", tao->max_funcs, &tao->max_funcs, &flg));
    428:   if (flg) PetscCall(TaoSetMaximumFunctionEvaluations(tao, tao->max_funcs));

    430:   PetscCall(PetscOptionsReal("-tao_fmin", "Stop if function less than", "TaoSetFunctionLowerBound", tao->fmin, &tao->fmin, NULL));
    431:   PetscCall(PetscOptionsBoundedReal("-tao_steptol", "Stop if step size or trust region radius less than", "", tao->steptol, &tao->steptol, NULL, 0));
    432:   PetscCall(PetscOptionsReal("-tao_trust0", "Initial trust region radius", "TaoSetInitialTrustRegionRadius", tao->trust0, &tao->trust0, &flg));
    433:   if (flg) PetscCall(TaoSetInitialTrustRegionRadius(tao, tao->trust0));

    435:   PetscCall(PetscOptionsDeprecated("-tao_solution_monitor", "-tao_monitor_solution", "3.21", NULL));
    436:   PetscCall(PetscOptionsDeprecated("-tao_gradient_monitor", "-tao_monitor_gradient", "3.21", NULL));
    437:   PetscCall(PetscOptionsDeprecated("-tao_stepdirection_monitor", "-tao_monitor_step", "3.21", NULL));
    438:   PetscCall(PetscOptionsDeprecated("-tao_residual_monitor", "-tao_monitor_residual", "3.21", NULL));
    439:   PetscCall(PetscOptionsDeprecated("-tao_smonitor", "-tao_monitor_short", "3.21", NULL));
    440:   PetscCall(PetscOptionsDeprecated("-tao_cmonitor", "-tao_monitor_constraint_norm", "3.21", NULL));
    441:   PetscCall(PetscOptionsDeprecated("-tao_gmonitor", "-tao_monitor_globalization", "3.21", NULL));
    442:   PetscCall(PetscOptionsDeprecated("-tao_draw_solution", "-tao_monitor_solution_draw", "3.21", NULL));
    443:   PetscCall(PetscOptionsDeprecated("-tao_draw_gradient", "-tao_monitor_gradient_draw", "3.21", NULL));
    444:   PetscCall(PetscOptionsDeprecated("-tao_draw_step", "-tao_monitor_step_draw", "3.21", NULL));

    446:   PetscCall(PetscOptionsString("-tao_monitor_solution", "View solution vector after each iteration", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    447:   if (flg) {
    448:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    449:     PetscCall(TaoMonitorSet(tao, TaoMonitorSolution, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    450:   }

    452:   PetscCall(PetscOptionsBool("-tao_converged_reason", "Print reason for Tao converged", "TaoSolve", tao->printreason, &tao->printreason, NULL));
    453:   PetscCall(PetscOptionsString("-tao_monitor_gradient", "View gradient vector for each iteration", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    454:   if (flg) {
    455:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    456:     PetscCall(TaoMonitorSet(tao, TaoMonitorGradient, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    457:   }

    459:   PetscCall(PetscOptionsString("-tao_monitor_step", "View step vector after each iteration", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    460:   if (flg) {
    461:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    462:     PetscCall(TaoMonitorSet(tao, TaoMonitorStep, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    463:   }

    465:   PetscCall(PetscOptionsString("-tao_monitor_residual", "View least-squares residual vector after each iteration", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    466:   if (flg) {
    467:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    468:     PetscCall(TaoMonitorSet(tao, TaoMonitorResidual, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    469:   }

    471:   PetscCall(PetscOptionsString("-tao_monitor", "Use the default convergence monitor", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    472:   if (flg) {
    473:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    474:     PetscCall(TaoMonitorSet(tao, TaoMonitorDefault, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    475:   }

    477:   PetscCall(PetscOptionsString("-tao_monitor_globalization", "Use the convergence monitor with extra globalization info", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    478:   if (flg) {
    479:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    480:     PetscCall(TaoMonitorSet(tao, TaoMonitorGlobalization, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    481:   }

    483:   PetscCall(PetscOptionsString("-tao_monitor_short", "Use the short convergence monitor", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    484:   if (flg) {
    485:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    486:     PetscCall(TaoMonitorSet(tao, TaoMonitorDefaultShort, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    487:   }

    489:   PetscCall(PetscOptionsString("-tao_monitor_constraint_norm", "Use the default convergence monitor with constraint norm", "TaoMonitorSet", "stdout", monfilename, sizeof(monfilename), &flg));
    490:   if (flg) {
    491:     PetscCall(PetscViewerASCIIOpen(comm, monfilename, &monviewer));
    492:     PetscCall(TaoMonitorSet(tao, TaoMonitorConstraintNorm, monviewer, (PetscErrorCode (*)(void **))PetscViewerDestroy));
    493:   }

    495:   flg = PETSC_FALSE;
    496:   PetscCall(PetscOptionsDeprecated("-tao_cancelmonitors", "-tao_monitor_cancel", "3.21", NULL));
    497:   PetscCall(PetscOptionsBool("-tao_monitor_cancel", "cancel all monitors and call any registered destroy routines", "TaoMonitorCancel", flg, &flg, NULL));
    498:   if (flg) PetscCall(TaoMonitorCancel(tao));

    500:   flg = PETSC_FALSE;
    501:   PetscCall(PetscOptionsBool("-tao_monitor_solution_draw", "Plot solution vector at each iteration", "TaoMonitorSet", flg, &flg, NULL));
    502:   if (flg) {
    503:     TaoMonitorDrawCtx drawctx;
    504:     PetscInt          howoften = 1;
    505:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
    506:     PetscCall(TaoMonitorSet(tao, TaoMonitorSolutionDraw, drawctx, (PetscErrorCode (*)(void **))TaoMonitorDrawCtxDestroy));
    507:   }

    509:   flg = PETSC_FALSE;
    510:   PetscCall(PetscOptionsBool("-tao_monitor_step_draw", "Plots step at each iteration", "TaoMonitorSet", flg, &flg, NULL));
    511:   if (flg) PetscCall(TaoMonitorSet(tao, TaoMonitorStepDraw, NULL, NULL));

    513:   flg = PETSC_FALSE;
    514:   PetscCall(PetscOptionsBool("-tao_monitor_gradient_draw", "plots gradient at each iteration", "TaoMonitorSet", flg, &flg, NULL));
    515:   if (flg) {
    516:     TaoMonitorDrawCtx drawctx;
    517:     PetscInt          howoften = 1;
    518:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
    519:     PetscCall(TaoMonitorSet(tao, TaoMonitorGradientDraw, drawctx, (PetscErrorCode (*)(void **))TaoMonitorDrawCtxDestroy));
    520:   }
    521:   flg = PETSC_FALSE;
    522:   PetscCall(PetscOptionsBool("-tao_fd_gradient", "compute gradient using finite differences", "TaoDefaultComputeGradient", flg, &flg, NULL));
    523:   if (flg) PetscCall(TaoSetGradient(tao, NULL, TaoDefaultComputeGradient, NULL));
    524:   flg = PETSC_FALSE;
    525:   PetscCall(PetscOptionsBool("-tao_fd_hessian", "compute Hessian using finite differences", "TaoDefaultComputeHessian", flg, &flg, NULL));
    526:   if (flg) {
    527:     Mat H;

    529:     PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &H));
    530:     PetscCall(MatSetType(H, MATAIJ));
    531:     PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessian, NULL));
    532:     PetscCall(MatDestroy(&H));
    533:   }
    534:   flg = PETSC_FALSE;
    535:   PetscCall(PetscOptionsBool("-tao_mf_hessian", "compute matrix-free Hessian using finite differences", "TaoDefaultComputeHessianMFFD", flg, &flg, NULL));
    536:   if (flg) {
    537:     Mat H;

    539:     PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &H));
    540:     PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessianMFFD, NULL));
    541:     PetscCall(MatDestroy(&H));
    542:   }
    543:   PetscCall(PetscOptionsBool("-tao_recycle_history", "enable recycling/re-using information from the previous TaoSolve() call for some algorithms", "TaoSetRecycleHistory", flg, &flg, &found));
    544:   if (found) PetscCall(TaoSetRecycleHistory(tao, flg));
    545:   PetscCall(PetscOptionsEnum("-tao_subset_type", "subset type", "", TaoSubSetTypes, (PetscEnum)tao->subset_type, (PetscEnum *)&tao->subset_type, NULL));

    547:   if (tao->ksp) {
    548:     PetscCall(PetscOptionsBool("-tao_ksp_ew", "Use Eisentat-Walker linear system convergence test", "TaoKSPSetUseEW", tao->ksp_ewconv, &tao->ksp_ewconv, NULL));
    549:     PetscCall(TaoKSPSetUseEW(tao, tao->ksp_ewconv));
    550:   }

    552:   PetscTryTypeMethod(tao, setfromoptions, PetscOptionsObject);

    554:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    555:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tao, PetscOptionsObject));
    556:   PetscOptionsEnd();

    558:   if (tao->linesearch) PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
    559:   PetscFunctionReturn(PETSC_SUCCESS);
    560: }

    562: /*@
    563:   TaoViewFromOptions - View a `Tao` object based on values in the options database

    565:   Collective

    567:   Input Parameters:
    568: + A    - the  `Tao` context
    569: . obj  - Optional object that provides the prefix for the options database
    570: - name - command line option

    572:   Level: intermediate

    574: .seealso: [](ch_tao), `Tao`, `TaoView`, `PetscObjectViewFromOptions()`, `TaoCreate()`
    575: @*/
    576: PetscErrorCode TaoViewFromOptions(Tao A, PetscObject obj, const char name[])
    577: {
    578:   PetscFunctionBegin;
    580:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
    581:   PetscFunctionReturn(PETSC_SUCCESS);
    582: }

    584: /*@
    585:   TaoView - Prints information about the `Tao` object

    587:   Collective

    589:   Input Parameters:
    590: + tao    - the `Tao` context
    591: - viewer - visualization context

    593:   Options Database Key:
    594: . -tao_view - Calls `TaoView()` at the end of `TaoSolve()`

    596:   Level: beginner

    598:   Notes:
    599:   The available visualization contexts include
    600: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
    601: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
    602:   output where only the first processor opens
    603:   the file.  All other processors send their
    604:   data to the first processor to print.

    606: .seealso: [](ch_tao), `Tao`, `PetscViewerASCIIOpen()`
    607: @*/
    608: PetscErrorCode TaoView(Tao tao, PetscViewer viewer)
    609: {
    610:   PetscBool isascii, isstring;
    611:   TaoType   type;

    613:   PetscFunctionBegin;
    615:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(((PetscObject)tao)->comm, &viewer));
    617:   PetscCheckSameComm(tao, 1, viewer, 2);

    619:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    620:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
    621:   if (isascii) {
    622:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tao, viewer));

    624:     PetscCall(PetscViewerASCIIPushTab(viewer));
    625:     PetscTryTypeMethod(tao, view, viewer);
    626:     if (tao->linesearch) PetscCall(TaoLineSearchView(tao->linesearch, viewer));
    627:     if (tao->ksp) {
    628:       PetscCall(KSPView(tao->ksp, viewer));
    629:       PetscCall(PetscViewerASCIIPrintf(viewer, "total KSP iterations: %" PetscInt_FMT "\n", tao->ksp_tot_its));
    630:     }

    632:     if (tao->XL || tao->XU) PetscCall(PetscViewerASCIIPrintf(viewer, "Active Set subset type: %s\n", TaoSubSetTypes[tao->subset_type]));

    634:     PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: gatol=%g,", (double)tao->gatol));
    635:     PetscCall(PetscViewerASCIIPrintf(viewer, " grtol=%g,", (double)tao->grtol));
    636:     PetscCall(PetscViewerASCIIPrintf(viewer, " steptol=%g,", (double)tao->steptol));
    637:     PetscCall(PetscViewerASCIIPrintf(viewer, " gttol=%g\n", (double)tao->gttol));
    638:     PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Function/Gradient:=%g\n", (double)tao->residual));

    640:     if (tao->constrained) {
    641:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances:"));
    642:       PetscCall(PetscViewerASCIIPrintf(viewer, " catol=%g,", (double)tao->catol));
    643:       PetscCall(PetscViewerASCIIPrintf(viewer, " crtol=%g\n", (double)tao->crtol));
    644:       PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Constraints:=%g\n", (double)tao->cnorm));
    645:     }

    647:     if (tao->trust < tao->steptol) {
    648:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: steptol=%g\n", (double)tao->steptol));
    649:       PetscCall(PetscViewerASCIIPrintf(viewer, "Final trust region radius:=%g\n", (double)tao->trust));
    650:     }

    652:     if (tao->fmin > -1.e25) PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: function minimum=%g\n", (double)tao->fmin));
    653:     PetscCall(PetscViewerASCIIPrintf(viewer, "Objective value=%g\n", (double)tao->fc));

    655:     PetscCall(PetscViewerASCIIPrintf(viewer, "total number of iterations=%" PetscInt_FMT ",          ", tao->niter));
    656:     PetscCall(PetscViewerASCIIPrintf(viewer, "              (max: %" PetscInt_FMT ")\n", tao->max_it));

    658:     if (tao->nfuncs > 0) {
    659:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function evaluations=%" PetscInt_FMT ",", tao->nfuncs));
    660:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
    661:       else PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: %" PetscInt_FMT ")\n", tao->max_funcs));
    662:     }
    663:     if (tao->ngrads > 0) {
    664:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of gradient evaluations=%" PetscInt_FMT ",", tao->ngrads));
    665:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
    666:       else PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: %" PetscInt_FMT ")\n", tao->max_funcs));
    667:     }
    668:     if (tao->nfuncgrads > 0) {
    669:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function/gradient evaluations=%" PetscInt_FMT ",", tao->nfuncgrads));
    670:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: unlimited)\n"));
    671:       else PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: %" PetscInt_FMT ")\n", tao->max_funcs));
    672:     }
    673:     if (tao->nhess > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Hessian evaluations=%" PetscInt_FMT "\n", tao->nhess));
    674:     if (tao->nconstraints > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of constraint function evaluations=%" PetscInt_FMT "\n", tao->nconstraints));
    675:     if (tao->njac > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Jacobian evaluations=%" PetscInt_FMT "\n", tao->njac));

    677:     if (tao->reason > 0) {
    678:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solution converged: "));
    679:       switch (tao->reason) {
    680:       case TAO_CONVERGED_GATOL:
    681:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)|| <= gatol\n"));
    682:         break;
    683:       case TAO_CONVERGED_GRTOL:
    684:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/|f(X)| <= grtol\n"));
    685:         break;
    686:       case TAO_CONVERGED_GTTOL:
    687:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/||g(X0)|| <= gttol\n"));
    688:         break;
    689:       case TAO_CONVERGED_STEPTOL:
    690:         PetscCall(PetscViewerASCIIPrintf(viewer, " Steptol -- step size small\n"));
    691:         break;
    692:       case TAO_CONVERGED_MINF:
    693:         PetscCall(PetscViewerASCIIPrintf(viewer, " Minf --  f < fmin\n"));
    694:         break;
    695:       case TAO_CONVERGED_USER:
    696:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
    697:         break;
    698:       default:
    699:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
    700:         break;
    701:       }
    702:     } else if (tao->reason == TAO_CONTINUE_ITERATING) {
    703:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver never run\n"));
    704:     } else {
    705:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver failed: "));
    706:       switch (tao->reason) {
    707:       case TAO_DIVERGED_MAXITS:
    708:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Iterations\n"));
    709:         break;
    710:       case TAO_DIVERGED_NAN:
    711:         PetscCall(PetscViewerASCIIPrintf(viewer, " NAN or Inf encountered\n"));
    712:         break;
    713:       case TAO_DIVERGED_MAXFCN:
    714:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Function Evaluations\n"));
    715:         break;
    716:       case TAO_DIVERGED_LS_FAILURE:
    717:         PetscCall(PetscViewerASCIIPrintf(viewer, " Line Search Failure\n"));
    718:         break;
    719:       case TAO_DIVERGED_TR_REDUCTION:
    720:         PetscCall(PetscViewerASCIIPrintf(viewer, " Trust Region too small\n"));
    721:         break;
    722:       case TAO_DIVERGED_USER:
    723:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
    724:         break;
    725:       default:
    726:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
    727:         break;
    728:       }
    729:     }
    730:     PetscCall(PetscViewerASCIIPopTab(viewer));
    731:   } else if (isstring) {
    732:     PetscCall(TaoGetType(tao, &type));
    733:     PetscCall(PetscViewerStringSPrintf(viewer, " %-3.3s", type));
    734:   }
    735:   PetscFunctionReturn(PETSC_SUCCESS);
    736: }

    738: /*@
    739:   TaoSetRecycleHistory - Sets the boolean flag to enable/disable re-using
    740:   iterate information from the previous `TaoSolve()`. This feature is disabled by
    741:   default.

    743:   Logically Collective

    745:   Input Parameters:
    746: + tao     - the `Tao` context
    747: - recycle - boolean flag

    749:   Options Database Key:
    750: . -tao_recycle_history <true,false> - reuse the history

    752:   Level: intermediate

    754:   Notes:
    755:   For conjugate gradient methods (`TAOBNCG`), this re-uses the latest search direction
    756:   from the previous `TaoSolve()` call when computing the first search direction in a
    757:   new solution. By default, CG methods set the first search direction to the
    758:   negative gradient.

    760:   For quasi-Newton family of methods (`TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`), this re-uses
    761:   the accumulated quasi-Newton Hessian approximation from the previous `TaoSolve()`
    762:   call. By default, QN family of methods reset the initial Hessian approximation to
    763:   the identity matrix.

    765:   For any other algorithm, this setting has no effect.

    767: .seealso: [](ch_tao), `Tao`, `TaoGetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
    768: @*/
    769: PetscErrorCode TaoSetRecycleHistory(Tao tao, PetscBool recycle)
    770: {
    771:   PetscFunctionBegin;
    774:   tao->recycle = recycle;
    775:   PetscFunctionReturn(PETSC_SUCCESS);
    776: }

    778: /*@
    779:   TaoGetRecycleHistory - Retrieve the boolean flag for re-using iterate information
    780:   from the previous `TaoSolve()`. This feature is disabled by default.

    782:   Logically Collective

    784:   Input Parameter:
    785: . tao - the `Tao` context

    787:   Output Parameter:
    788: . recycle - boolean flag

    790:   Level: intermediate

    792: .seealso: [](ch_tao), `Tao`, `TaoSetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
    793: @*/
    794: PetscErrorCode TaoGetRecycleHistory(Tao tao, PetscBool *recycle)
    795: {
    796:   PetscFunctionBegin;
    798:   PetscAssertPointer(recycle, 2);
    799:   *recycle = tao->recycle;
    800:   PetscFunctionReturn(PETSC_SUCCESS);
    801: }

    803: /*@
    804:   TaoSetTolerances - Sets parameters used in `TaoSolve()` convergence tests

    806:   Logically Collective

    808:   Input Parameters:
    809: + tao   - the `Tao` context
    810: . gatol - stop if norm of gradient is less than this
    811: . grtol - stop if relative norm of gradient is less than this
    812: - gttol - stop if norm of gradient is reduced by this factor

    814:   Options Database Keys:
    815: + -tao_gatol <gatol> - Sets gatol
    816: . -tao_grtol <grtol> - Sets grtol
    817: - -tao_gttol <gttol> - Sets gttol

    819:   Stopping Criteria\:
    820: .vb
    821:   ||g(X)||                            <= gatol
    822:   ||g(X)|| / |f(X)|                   <= grtol
    823:   ||g(X)|| / ||g(X0)||                <= gttol
    824: .ve

    826:   Level: beginner

    828:   Notes:
    829:   Use `PETSC_CURRENT` to leave one or more tolerances unchanged.

    831:   Use `PETSC_DETERMINE` to set one or more tolerances to their values when the `tao`object's type was set

    833:   Fortran Note:
    834:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

    836: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`
    837: @*/
    838: PetscErrorCode TaoSetTolerances(Tao tao, PetscReal gatol, PetscReal grtol, PetscReal gttol)
    839: {
    840:   PetscFunctionBegin;

    846:   if (gatol == (PetscReal)PETSC_DETERMINE) {
    847:     tao->gatol = tao->default_gatol;
    848:   } else if (gatol != (PetscReal)PETSC_CURRENT) {
    849:     PetscCheck(gatol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gatol not allowed");
    850:     tao->gatol = gatol;
    851:   }

    853:   if (grtol == (PetscReal)PETSC_DETERMINE) {
    854:     tao->grtol = tao->default_grtol;
    855:   } else if (grtol != (PetscReal)PETSC_CURRENT) {
    856:     PetscCheck(grtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative grtol not allowed");
    857:     tao->grtol = grtol;
    858:   }

    860:   if (gttol == (PetscReal)PETSC_DETERMINE) {
    861:     tao->gttol = tao->default_gttol;
    862:   } else if (gttol != (PetscReal)PETSC_CURRENT) {
    863:     PetscCheck(gttol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gttol not allowed");
    864:     tao->gttol = gttol;
    865:   }
    866:   PetscFunctionReturn(PETSC_SUCCESS);
    867: }

    869: /*@
    870:   TaoSetConstraintTolerances - Sets constraint tolerance parameters used in `TaoSolve()` convergence tests

    872:   Logically Collective

    874:   Input Parameters:
    875: + tao   - the `Tao` context
    876: . catol - absolute constraint tolerance, constraint norm must be less than `catol` for used for `gatol` convergence criteria
    877: - crtol - relative constraint tolerance, constraint norm must be less than `crtol` for used for `gatol`, `gttol` convergence criteria

    879:   Options Database Keys:
    880: + -tao_catol <catol> - Sets catol
    881: - -tao_crtol <crtol> - Sets crtol

    883:   Level: intermediate

    885:   Notes:
    886:   Use `PETSC_CURRENT` to leave one or tolerance unchanged.

    888:   Use `PETSC_DETERMINE` to set one or more tolerances to their values when the `tao` object's type was set

    890:   Fortran Note:
    891:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

    893: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`, `TaoGetConstraintTolerances()`, `TaoSetTolerances()`
    894: @*/
    895: PetscErrorCode TaoSetConstraintTolerances(Tao tao, PetscReal catol, PetscReal crtol)
    896: {
    897:   PetscFunctionBegin;

    902:   if (catol == (PetscReal)PETSC_DETERMINE) {
    903:     tao->catol = tao->default_catol;
    904:   } else if (catol != (PetscReal)PETSC_CURRENT) {
    905:     PetscCheck(catol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative catol not allowed");
    906:     tao->catol = catol;
    907:   }

    909:   if (crtol == (PetscReal)PETSC_DETERMINE) {
    910:     tao->crtol = tao->default_crtol;
    911:   } else if (crtol != (PetscReal)PETSC_CURRENT) {
    912:     PetscCheck(crtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative crtol not allowed");
    913:     tao->crtol = crtol;
    914:   }
    915:   PetscFunctionReturn(PETSC_SUCCESS);
    916: }

    918: /*@
    919:   TaoGetConstraintTolerances - Gets constraint tolerance parameters used in `TaoSolve()` convergence tests

    921:   Not Collective

    923:   Input Parameter:
    924: . tao - the `Tao` context

    926:   Output Parameters:
    927: + catol - absolute constraint tolerance, constraint norm must be less than `catol` for used for `gatol` convergence criteria
    928: - crtol - relative constraint tolerance, constraint norm must be less than `crtol` for used for `gatol`, `gttol` convergence criteria

    930:   Level: intermediate

    932: .seealso: [](ch_tao), `Tao`, `TaoConvergedReasons`,`TaoGetTolerances()`, `TaoSetTolerances()`, `TaoSetConstraintTolerances()`
    933: @*/
    934: PetscErrorCode TaoGetConstraintTolerances(Tao tao, PetscReal *catol, PetscReal *crtol)
    935: {
    936:   PetscFunctionBegin;
    938:   if (catol) *catol = tao->catol;
    939:   if (crtol) *crtol = tao->crtol;
    940:   PetscFunctionReturn(PETSC_SUCCESS);
    941: }

    943: /*@
    944:   TaoSetFunctionLowerBound - Sets a bound on the solution objective value.
    945:   When an approximate solution with an objective value below this number
    946:   has been found, the solver will terminate.

    948:   Logically Collective

    950:   Input Parameters:
    951: + tao  - the Tao solver context
    952: - fmin - the tolerance

    954:   Options Database Key:
    955: . -tao_fmin <fmin> - sets the minimum function value

    957:   Level: intermediate

    959: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetTolerances()`
    960: @*/
    961: PetscErrorCode TaoSetFunctionLowerBound(Tao tao, PetscReal fmin)
    962: {
    963:   PetscFunctionBegin;
    966:   tao->fmin = fmin;
    967:   PetscFunctionReturn(PETSC_SUCCESS);
    968: }

    970: /*@
    971:   TaoGetFunctionLowerBound - Gets the bound on the solution objective value.
    972:   When an approximate solution with an objective value below this number
    973:   has been found, the solver will terminate.

    975:   Not Collective

    977:   Input Parameter:
    978: . tao - the `Tao` solver context

    980:   Output Parameter:
    981: . fmin - the minimum function value

    983:   Level: intermediate

    985: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetFunctionLowerBound()`
    986: @*/
    987: PetscErrorCode TaoGetFunctionLowerBound(Tao tao, PetscReal *fmin)
    988: {
    989:   PetscFunctionBegin;
    991:   PetscAssertPointer(fmin, 2);
    992:   *fmin = tao->fmin;
    993:   PetscFunctionReturn(PETSC_SUCCESS);
    994: }

    996: /*@
    997:   TaoSetMaximumFunctionEvaluations - Sets a maximum number of function evaluations allowed for a `TaoSolve()`.

    999:   Logically Collective

    1001:   Input Parameters:
    1002: + tao  - the `Tao` solver context
    1003: - nfcn - the maximum number of function evaluations (>=0), use `PETSC_UNLIMITED` to have no bound

    1005:   Options Database Key:
    1006: . -tao_max_funcs <nfcn> - sets the maximum number of function evaluations

    1008:   Level: intermediate

    1010:   Note:
    1011:   Use `PETSC_DETERMINE` to use the default maximum number of function evaluations that was set when the object type was set.

    1013:   Developer Note:
    1014:   Deprecated support for an unlimited number of function evaluations by passing a negative value.

    1016: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumIterations()`
    1017: @*/
    1018: PetscErrorCode TaoSetMaximumFunctionEvaluations(Tao tao, PetscInt nfcn)
    1019: {
    1020:   PetscFunctionBegin;
    1023:   if (nfcn == PETSC_DETERMINE) {
    1024:     tao->max_funcs = tao->default_max_funcs;
    1025:   } else if (nfcn == PETSC_UNLIMITED || nfcn < 0) {
    1026:     tao->max_funcs = PETSC_UNLIMITED;
    1027:   } else {
    1028:     PetscCheck(nfcn >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of function evaluations  must be positive");
    1029:     tao->max_funcs = nfcn;
    1030:   }
    1031:   PetscFunctionReturn(PETSC_SUCCESS);
    1032: }

    1034: /*@
    1035:   TaoGetMaximumFunctionEvaluations - Gets a maximum number of function evaluations allowed for a `TaoSolve()`

    1037:   Logically Collective

    1039:   Input Parameter:
    1040: . tao - the `Tao` solver context

    1042:   Output Parameter:
    1043: . nfcn - the maximum number of function evaluations

    1045:   Level: intermediate

    1047: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
    1048: @*/
    1049: PetscErrorCode TaoGetMaximumFunctionEvaluations(Tao tao, PetscInt *nfcn)
    1050: {
    1051:   PetscFunctionBegin;
    1053:   PetscAssertPointer(nfcn, 2);
    1054:   *nfcn = tao->max_funcs;
    1055:   PetscFunctionReturn(PETSC_SUCCESS);
    1056: }

    1058: /*@
    1059:   TaoGetCurrentFunctionEvaluations - Get current number of function evaluations used by a `Tao` object

    1061:   Not Collective

    1063:   Input Parameter:
    1064: . tao - the `Tao` solver context

    1066:   Output Parameter:
    1067: . nfuncs - the current number of function evaluations (maximum between gradient and function evaluations)

    1069:   Level: intermediate

    1071: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
    1072: @*/
    1073: PetscErrorCode TaoGetCurrentFunctionEvaluations(Tao tao, PetscInt *nfuncs)
    1074: {
    1075:   PetscFunctionBegin;
    1077:   PetscAssertPointer(nfuncs, 2);
    1078:   *nfuncs = PetscMax(tao->nfuncs, tao->nfuncgrads);
    1079:   PetscFunctionReturn(PETSC_SUCCESS);
    1080: }

    1082: /*@
    1083:   TaoSetMaximumIterations - Sets a maximum number of iterates to be used in `TaoSolve()`

    1085:   Logically Collective

    1087:   Input Parameters:
    1088: + tao    - the `Tao` solver context
    1089: - maxits - the maximum number of iterates (>=0), use `PETSC_UNLIMITED` to have no bound

    1091:   Options Database Key:
    1092: . -tao_max_it <its> - sets the maximum number of iterations

    1094:   Level: intermediate

    1096:   Note:
    1097:   Use `PETSC_DETERMINE` to use the default maximum number of iterations that was set when the object's type was set.

    1099:   Developer Note:
    1100:   DeprAlso accepts the deprecated negative values to indicate no limit

    1102: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumFunctionEvaluations()`
    1103: @*/
    1104: PetscErrorCode TaoSetMaximumIterations(Tao tao, PetscInt maxits)
    1105: {
    1106:   PetscFunctionBegin;
    1109:   if (maxits == PETSC_DETERMINE) {
    1110:     tao->max_it = tao->default_max_it;
    1111:   } else if (maxits == PETSC_UNLIMITED) {
    1112:     tao->max_it = PETSC_INT_MAX;
    1113:   } else {
    1114:     PetscCheck(maxits > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations must be positive");
    1115:     tao->max_it = maxits;
    1116:   }
    1117:   PetscFunctionReturn(PETSC_SUCCESS);
    1118: }

    1120: /*@
    1121:   TaoGetMaximumIterations - Gets a maximum number of iterates that will be used

    1123:   Not Collective

    1125:   Input Parameter:
    1126: . tao - the `Tao` solver context

    1128:   Output Parameter:
    1129: . maxits - the maximum number of iterates

    1131:   Level: intermediate

    1133: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumIterations()`, `TaoGetMaximumFunctionEvaluations()`
    1134: @*/
    1135: PetscErrorCode TaoGetMaximumIterations(Tao tao, PetscInt *maxits)
    1136: {
    1137:   PetscFunctionBegin;
    1139:   PetscAssertPointer(maxits, 2);
    1140:   *maxits = tao->max_it;
    1141:   PetscFunctionReturn(PETSC_SUCCESS);
    1142: }

    1144: /*@
    1145:   TaoSetInitialTrustRegionRadius - Sets the initial trust region radius.

    1147:   Logically Collective

    1149:   Input Parameters:
    1150: + tao    - a `Tao` optimization solver
    1151: - radius - the trust region radius

    1153:   Options Database Key:
    1154: . -tao_trust0 <t0> - sets initial trust region radius

    1156:   Level: intermediate

    1158:   Note:
    1159:   Use `PETSC_DETERMINE` to use the default radius that was set when the object's type was set.

    1161: .seealso: [](ch_tao), `Tao`, `TaoGetTrustRegionRadius()`, `TaoSetTrustRegionTolerance()`, `TAONTR`
    1162: @*/
    1163: PetscErrorCode TaoSetInitialTrustRegionRadius(Tao tao, PetscReal radius)
    1164: {
    1165:   PetscFunctionBegin;
    1168:   if (radius == PETSC_DETERMINE) {
    1169:     tao->trust0 = tao->default_trust0;
    1170:   } else {
    1171:     PetscCheck(radius > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Radius must be positive");
    1172:     tao->trust0 = radius;
    1173:   }
    1174:   PetscFunctionReturn(PETSC_SUCCESS);
    1175: }

    1177: /*@
    1178:   TaoGetInitialTrustRegionRadius - Gets the initial trust region radius.

    1180:   Not Collective

    1182:   Input Parameter:
    1183: . tao - a `Tao` optimization solver

    1185:   Output Parameter:
    1186: . radius - the trust region radius

    1188:   Level: intermediate

    1190: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetCurrentTrustRegionRadius()`, `TAONTR`
    1191: @*/
    1192: PetscErrorCode TaoGetInitialTrustRegionRadius(Tao tao, PetscReal *radius)
    1193: {
    1194:   PetscFunctionBegin;
    1196:   PetscAssertPointer(radius, 2);
    1197:   *radius = tao->trust0;
    1198:   PetscFunctionReturn(PETSC_SUCCESS);
    1199: }

    1201: /*@
    1202:   TaoGetCurrentTrustRegionRadius - Gets the current trust region radius.

    1204:   Not Collective

    1206:   Input Parameter:
    1207: . tao - a `Tao` optimization solver

    1209:   Output Parameter:
    1210: . radius - the trust region radius

    1212:   Level: intermediate

    1214: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetInitialTrustRegionRadius()`, `TAONTR`
    1215: @*/
    1216: PetscErrorCode TaoGetCurrentTrustRegionRadius(Tao tao, PetscReal *radius)
    1217: {
    1218:   PetscFunctionBegin;
    1220:   PetscAssertPointer(radius, 2);
    1221:   *radius = tao->trust;
    1222:   PetscFunctionReturn(PETSC_SUCCESS);
    1223: }

    1225: /*@
    1226:   TaoGetTolerances - gets the current values of some tolerances used for the convergence testing of `TaoSolve()`

    1228:   Not Collective

    1230:   Input Parameter:
    1231: . tao - the `Tao` context

    1233:   Output Parameters:
    1234: + gatol - stop if norm of gradient is less than this
    1235: . grtol - stop if relative norm of gradient is less than this
    1236: - gttol - stop if norm of gradient is reduced by a this factor

    1238:   Level: intermediate

    1240:   Note:
    1241:   `NULL` can be used as an argument if not all tolerances values are needed

    1243: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`
    1244: @*/
    1245: PetscErrorCode TaoGetTolerances(Tao tao, PetscReal *gatol, PetscReal *grtol, PetscReal *gttol)
    1246: {
    1247:   PetscFunctionBegin;
    1249:   if (gatol) *gatol = tao->gatol;
    1250:   if (grtol) *grtol = tao->grtol;
    1251:   if (gttol) *gttol = tao->gttol;
    1252:   PetscFunctionReturn(PETSC_SUCCESS);
    1253: }

    1255: /*@
    1256:   TaoGetKSP - Gets the linear solver used by the optimization solver.

    1258:   Not Collective

    1260:   Input Parameter:
    1261: . tao - the `Tao` solver

    1263:   Output Parameter:
    1264: . ksp - the `KSP` linear solver used in the optimization solver

    1266:   Level: intermediate

    1268: .seealso: [](ch_tao), `Tao`, `KSP`
    1269: @*/
    1270: PetscErrorCode TaoGetKSP(Tao tao, KSP *ksp)
    1271: {
    1272:   PetscFunctionBegin;
    1274:   PetscAssertPointer(ksp, 2);
    1275:   *ksp = tao->ksp;
    1276:   PetscFunctionReturn(PETSC_SUCCESS);
    1277: }

    1279: /*@
    1280:   TaoGetLinearSolveIterations - Gets the total number of linear iterations
    1281:   used by the `Tao` solver

    1283:   Not Collective

    1285:   Input Parameter:
    1286: . tao - the `Tao` context

    1288:   Output Parameter:
    1289: . lits - number of linear iterations

    1291:   Level: intermediate

    1293:   Note:
    1294:   This counter is reset to zero for each successive call to `TaoSolve()`

    1296: .seealso: [](ch_tao), `Tao`, `TaoGetKSP()`
    1297: @*/
    1298: PetscErrorCode TaoGetLinearSolveIterations(Tao tao, PetscInt *lits)
    1299: {
    1300:   PetscFunctionBegin;
    1302:   PetscAssertPointer(lits, 2);
    1303:   *lits = tao->ksp_tot_its;
    1304:   PetscFunctionReturn(PETSC_SUCCESS);
    1305: }

    1307: /*@
    1308:   TaoGetLineSearch - Gets the line search used by the optimization solver.

    1310:   Not Collective

    1312:   Input Parameter:
    1313: . tao - the `Tao` solver

    1315:   Output Parameter:
    1316: . ls - the line search used in the optimization solver

    1318:   Level: intermediate

    1320: .seealso: [](ch_tao), `Tao`, `TaoLineSearch`, `TaoLineSearchType`
    1321: @*/
    1322: PetscErrorCode TaoGetLineSearch(Tao tao, TaoLineSearch *ls)
    1323: {
    1324:   PetscFunctionBegin;
    1326:   PetscAssertPointer(ls, 2);
    1327:   *ls = tao->linesearch;
    1328:   PetscFunctionReturn(PETSC_SUCCESS);
    1329: }

    1331: /*@
    1332:   TaoAddLineSearchCounts - Adds the number of function evaluations spent
    1333:   in the line search to the running total.

    1335:   Input Parameters:
    1336: . tao - the `Tao` solver

    1338:   Level: developer

    1340: .seealso: [](ch_tao), `Tao`, `TaoGetLineSearch()`, `TaoLineSearchApply()`
    1341: @*/
    1342: PetscErrorCode TaoAddLineSearchCounts(Tao tao)
    1343: {
    1344:   PetscBool flg;
    1345:   PetscInt  nfeval, ngeval, nfgeval;

    1347:   PetscFunctionBegin;
    1349:   if (tao->linesearch) {
    1350:     PetscCall(TaoLineSearchIsUsingTaoRoutines(tao->linesearch, &flg));
    1351:     if (!flg) {
    1352:       PetscCall(TaoLineSearchGetNumberFunctionEvaluations(tao->linesearch, &nfeval, &ngeval, &nfgeval));
    1353:       tao->nfuncs += nfeval;
    1354:       tao->ngrads += ngeval;
    1355:       tao->nfuncgrads += nfgeval;
    1356:     }
    1357:   }
    1358:   PetscFunctionReturn(PETSC_SUCCESS);
    1359: }

    1361: /*@
    1362:   TaoGetSolution - Returns the vector with the current solution from the `Tao` object

    1364:   Not Collective

    1366:   Input Parameter:
    1367: . tao - the `Tao` context

    1369:   Output Parameter:
    1370: . X - the current solution

    1372:   Level: intermediate

    1374:   Note:
    1375:   The returned vector will be the same object that was passed into `TaoSetSolution()`

    1377: .seealso: [](ch_tao), `Tao`, `TaoSetSolution()`, `TaoSolve()`
    1378: @*/
    1379: PetscErrorCode TaoGetSolution(Tao tao, Vec *X)
    1380: {
    1381:   PetscFunctionBegin;
    1383:   PetscAssertPointer(X, 2);
    1384:   *X = tao->solution;
    1385:   PetscFunctionReturn(PETSC_SUCCESS);
    1386: }

    1388: /*@
    1389:   TaoResetStatistics - Initialize the statistics collected by the `Tao` object.
    1390:   These statistics include the iteration number, residual norms, and convergence status.
    1391:   This routine gets called before solving each optimization problem.

    1393:   Collective

    1395:   Input Parameter:
    1396: . tao - the `Tao` context

    1398:   Level: developer

    1400: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
    1401: @*/
    1402: PetscErrorCode TaoResetStatistics(Tao tao)
    1403: {
    1404:   PetscFunctionBegin;
    1406:   tao->niter        = 0;
    1407:   tao->nfuncs       = 0;
    1408:   tao->nfuncgrads   = 0;
    1409:   tao->ngrads       = 0;
    1410:   tao->nhess        = 0;
    1411:   tao->njac         = 0;
    1412:   tao->nconstraints = 0;
    1413:   tao->ksp_its      = 0;
    1414:   tao->ksp_tot_its  = 0;
    1415:   tao->reason       = TAO_CONTINUE_ITERATING;
    1416:   tao->residual     = 0.0;
    1417:   tao->cnorm        = 0.0;
    1418:   tao->step         = 0.0;
    1419:   tao->lsflag       = PETSC_FALSE;
    1420:   if (tao->hist_reset) tao->hist_len = 0;
    1421:   PetscFunctionReturn(PETSC_SUCCESS);
    1422: }

    1424: /*@C
    1425:   TaoSetUpdate - Sets the general-purpose update function called
    1426:   at the beginning of every iteration of the optimization algorithm. Called after the new solution and the gradient
    1427:   is determined, but before the Hessian is computed (if applicable).

    1429:   Logically Collective

    1431:   Input Parameters:
    1432: + tao  - The `Tao` solver
    1433: . func - The function
    1434: - ctx  - The update function context

    1436:   Calling sequence of `func`:
    1437: + tao - The optimizer context
    1438: . it  - The current iteration index
    1439: - ctx - The update context

    1441:   Level: advanced

    1443:   Notes:
    1444:   Users can modify the gradient direction or any other vector associated to the specific solver used.
    1445:   The objective function value is always recomputed after a call to the update hook.

    1447: .seealso: [](ch_tao), `Tao`, `TaoSolve()`
    1448: @*/
    1449: PetscErrorCode TaoSetUpdate(Tao tao, PetscErrorCode (*func)(Tao tao, PetscInt it, void *ctx), void *ctx)
    1450: {
    1451:   PetscFunctionBegin;
    1453:   tao->ops->update = func;
    1454:   tao->user_update = ctx;
    1455:   PetscFunctionReturn(PETSC_SUCCESS);
    1456: }

    1458: /*@C
    1459:   TaoSetConvergenceTest - Sets the function that is to be used to test
    1460:   for convergence of the iterative minimization solution.  The new convergence
    1461:   testing routine will replace Tao's default convergence test.

    1463:   Logically Collective

    1465:   Input Parameters:
    1466: + tao  - the `Tao` object
    1467: . conv - the routine to test for convergence
    1468: - ctx  - [optional] context for private data for the convergence routine
    1469:         (may be `NULL`)

    1471:   Calling sequence of `conv`:
    1472: + tao - the `Tao` object
    1473: - ctx - [optional] convergence context

    1475:   Level: advanced

    1477:   Note:
    1478:   The new convergence testing routine should call `TaoSetConvergedReason()`.

    1480: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergedReason()`, `TaoGetSolutionStatus()`, `TaoGetTolerances()`, `TaoMonitorSet()`
    1481: @*/
    1482: PetscErrorCode TaoSetConvergenceTest(Tao tao, PetscErrorCode (*conv)(Tao, void *), void *ctx)
    1483: {
    1484:   PetscFunctionBegin;
    1486:   tao->ops->convergencetest = conv;
    1487:   tao->cnvP                 = ctx;
    1488:   PetscFunctionReturn(PETSC_SUCCESS);
    1489: }

    1491: /*@C
    1492:   TaoMonitorSet - Sets an additional function that is to be used at every
    1493:   iteration of the solver to display the iteration's
    1494:   progress.

    1496:   Logically Collective

    1498:   Input Parameters:
    1499: + tao  - the `Tao` solver context
    1500: . func - monitoring routine
    1501: . ctx  - [optional] user-defined context for private data for the monitor routine (may be `NULL`)
    1502: - dest - [optional] function to destroy the context when the `Tao` is destroyed

    1504:   Calling sequence of `func`:
    1505: + tao - the `Tao` solver context
    1506: - ctx - [optional] monitoring context

    1508:   Calling sequence of `dest`:
    1509: . ctx - monitoring context

    1511:   Level: intermediate

    1513:   Notes:
    1514:   See `TaoSetFromOptions()` for a monitoring options.

    1516:   Several different monitoring routines may be set by calling
    1517:   `TaoMonitorSet()` multiple times; all will be called in the
    1518:   order in which they were set.

    1520:   Fortran Notes:
    1521:   Only one monitor function may be set

    1523: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoMonitorDefault()`, `TaoMonitorCancel()`, `TaoSetDestroyRoutine()`, `TaoView()`
    1524: @*/
    1525: PetscErrorCode TaoMonitorSet(Tao tao, PetscErrorCode (*func)(Tao, void *), void *ctx, PetscErrorCode (*dest)(void **))
    1526: {
    1527:   PetscInt  i;
    1528:   PetscBool identical;

    1530:   PetscFunctionBegin;
    1532:   PetscCheck(tao->numbermonitors < MAXTAOMONITORS, PetscObjectComm((PetscObject)tao), PETSC_ERR_SUP, "Cannot attach another monitor -- max=%d", MAXTAOMONITORS);

    1534:   for (i = 0; i < tao->numbermonitors; i++) {
    1535:     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))func, ctx, dest, (PetscErrorCode (*)(void))tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i], &identical));
    1536:     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
    1537:   }
    1538:   tao->monitor[tao->numbermonitors]        = func;
    1539:   tao->monitorcontext[tao->numbermonitors] = (void *)ctx;
    1540:   tao->monitordestroy[tao->numbermonitors] = dest;
    1541:   ++tao->numbermonitors;
    1542:   PetscFunctionReturn(PETSC_SUCCESS);
    1543: }

    1545: /*@
    1546:   TaoMonitorCancel - Clears all the monitor functions for a `Tao` object.

    1548:   Logically Collective

    1550:   Input Parameter:
    1551: . tao - the `Tao` solver context

    1553:   Options Database Key:
    1554: . -tao_monitor_cancel - cancels all monitors that have been hardwired
    1555:     into a code by calls to `TaoMonitorSet()`, but does not cancel those
    1556:     set via the options database

    1558:   Level: advanced

    1560:   Note:
    1561:   There is no way to clear one specific monitor from a `Tao` object.

    1563: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
    1564: @*/
    1565: PetscErrorCode TaoMonitorCancel(Tao tao)
    1566: {
    1567:   PetscInt i;

    1569:   PetscFunctionBegin;
    1571:   for (i = 0; i < tao->numbermonitors; i++) {
    1572:     if (tao->monitordestroy[i]) PetscCall((*tao->monitordestroy[i])(&tao->monitorcontext[i]));
    1573:   }
    1574:   tao->numbermonitors = 0;
    1575:   PetscFunctionReturn(PETSC_SUCCESS);
    1576: }

    1578: /*@
    1579:   TaoMonitorDefault - Default routine for monitoring progress of `TaoSolve()`

    1581:   Collective

    1583:   Input Parameters:
    1584: + tao - the `Tao` context
    1585: - ctx - `PetscViewer` context or `NULL`

    1587:   Options Database Key:
    1588: . -tao_monitor - turn on default monitoring

    1590:   Level: advanced

    1592:   Note:
    1593:   This monitor prints the function value and gradient
    1594:   norm at each iteration.

    1596: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1597: @*/
    1598: PetscErrorCode TaoMonitorDefault(Tao tao, void *ctx)
    1599: {
    1600:   PetscInt    its, tabs;
    1601:   PetscReal   fct, gnorm;
    1602:   PetscViewer viewer = (PetscViewer)ctx;

    1604:   PetscFunctionBegin;
    1607:   its   = tao->niter;
    1608:   fct   = tao->fc;
    1609:   gnorm = tao->residual;
    1610:   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
    1611:   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
    1612:   if (its == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
    1613:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
    1614:     tao->header_printed = PETSC_TRUE;
    1615:   }
    1616:   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", its));
    1617:   PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)fct));
    1618:   if (gnorm >= PETSC_INFINITY) {
    1619:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: Inf \n"));
    1620:   } else {
    1621:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g \n", (double)gnorm));
    1622:   }
    1623:   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
    1624:   PetscFunctionReturn(PETSC_SUCCESS);
    1625: }

    1627: /*@
    1628:   TaoMonitorGlobalization - Default routine for monitoring progress of `TaoSolve()` with extra detail on the globalization method.

    1630:   Collective

    1632:   Input Parameters:
    1633: + tao - the `Tao` context
    1634: - ctx - `PetscViewer` context or `NULL`

    1636:   Options Database Key:
    1637: . -tao_monitor_globalization - turn on monitoring with globalization information

    1639:   Level: advanced

    1641:   Note:
    1642:   This monitor prints the function value and gradient norm at each
    1643:   iteration, as well as the step size and trust radius. Note that the
    1644:   step size and trust radius may be the same for some algorithms.

    1646: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1647: @*/
    1648: PetscErrorCode TaoMonitorGlobalization(Tao tao, void *ctx)
    1649: {
    1650:   PetscInt    its, tabs;
    1651:   PetscReal   fct, gnorm, stp, tr;
    1652:   PetscViewer viewer = (PetscViewer)ctx;

    1654:   PetscFunctionBegin;
    1657:   its   = tao->niter;
    1658:   fct   = tao->fc;
    1659:   gnorm = tao->residual;
    1660:   stp   = tao->step;
    1661:   tr    = tao->trust;
    1662:   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
    1663:   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
    1664:   if (its == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
    1665:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
    1666:     tao->header_printed = PETSC_TRUE;
    1667:   }
    1668:   PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", its));
    1669:   PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)fct));
    1670:   if (gnorm >= PETSC_INFINITY) {
    1671:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: Inf,"));
    1672:   } else {
    1673:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g,", (double)gnorm));
    1674:   }
    1675:   PetscCall(PetscViewerASCIIPrintf(viewer, "  Step: %g,  Trust: %g\n", (double)stp, (double)tr));
    1676:   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
    1677:   PetscFunctionReturn(PETSC_SUCCESS);
    1678: }

    1680: /*@
    1681:   TaoMonitorDefaultShort - Routine for monitoring progress of `TaoSolve()` that displays fewer digits than `TaoMonitorDefault()`

    1683:   Collective

    1685:   Input Parameters:
    1686: + tao - the `Tao` context
    1687: - ctx - `PetscViewer` context of type `PETSCVIEWERASCII`

    1689:   Options Database Key:
    1690: . -tao_monitor_short - turn on default short monitoring

    1692:   Level: advanced

    1694:   Note:
    1695:   Same as `TaoMonitorDefault()` except
    1696:   it prints fewer digits of the residual as the residual gets smaller.
    1697:   This is because the later digits are meaningless and are often
    1698:   different on different machines; by using this routine different
    1699:   machines will usually generate the same output.

    1701: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
    1702: @*/
    1703: PetscErrorCode TaoMonitorDefaultShort(Tao tao, void *ctx)
    1704: {
    1705:   PetscInt    its, tabs;
    1706:   PetscReal   fct, gnorm;
    1707:   PetscViewer viewer = (PetscViewer)ctx;

    1709:   PetscFunctionBegin;
    1712:   its   = tao->niter;
    1713:   fct   = tao->fc;
    1714:   gnorm = tao->residual;
    1715:   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
    1716:   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
    1717:   PetscCall(PetscViewerASCIIPrintf(viewer, "iter = %3" PetscInt_FMT ",", its));
    1718:   PetscCall(PetscViewerASCIIPrintf(viewer, " Function value %g,", (double)fct));
    1719:   if (gnorm >= PETSC_INFINITY) {
    1720:     PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: Inf \n"));
    1721:   } else if (gnorm > 1.e-6) {
    1722:     PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: %g \n", (double)gnorm));
    1723:   } else if (gnorm > 1.e-11) {
    1724:     PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: < 1.0e-6 \n"));
    1725:   } else {
    1726:     PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: < 1.0e-11 \n"));
    1727:   }
    1728:   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
    1729:   PetscFunctionReturn(PETSC_SUCCESS);
    1730: }

    1732: /*@
    1733:   TaoMonitorConstraintNorm - same as `TaoMonitorDefault()` except
    1734:   it prints the norm of the constraint function.

    1736:   Collective

    1738:   Input Parameters:
    1739: + tao - the `Tao` context
    1740: - ctx - `PetscViewer` context or `NULL`

    1742:   Options Database Key:
    1743: . -tao_monitor_constraint_norm - monitor the constraints

    1745:   Level: advanced

    1747: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
    1748: @*/
    1749: PetscErrorCode TaoMonitorConstraintNorm(Tao tao, void *ctx)
    1750: {
    1751:   PetscInt    its, tabs;
    1752:   PetscReal   fct, gnorm;
    1753:   PetscViewer viewer = (PetscViewer)ctx;

    1755:   PetscFunctionBegin;
    1758:   its   = tao->niter;
    1759:   fct   = tao->fc;
    1760:   gnorm = tao->residual;
    1761:   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
    1762:   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
    1763:   PetscCall(PetscViewerASCIIPrintf(viewer, "iter = %" PetscInt_FMT ",", its));
    1764:   PetscCall(PetscViewerASCIIPrintf(viewer, " Function value: %g,", (double)fct));
    1765:   PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g ", (double)gnorm));
    1766:   PetscCall(PetscViewerASCIIPrintf(viewer, "  Constraint: %g \n", (double)tao->cnorm));
    1767:   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
    1768:   PetscFunctionReturn(PETSC_SUCCESS);
    1769: }

    1771: /*@C
    1772:   TaoMonitorSolution - Views the solution at each iteration of `TaoSolve()`

    1774:   Collective

    1776:   Input Parameters:
    1777: + tao - the `Tao` context
    1778: - ctx - `PetscViewer` context or `NULL`

    1780:   Options Database Key:
    1781: . -tao_monitor_solution - view the solution

    1783:   Level: advanced

    1785: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1786: @*/
    1787: PetscErrorCode TaoMonitorSolution(Tao tao, void *ctx)
    1788: {
    1789:   PetscViewer viewer = (PetscViewer)ctx;

    1791:   PetscFunctionBegin;
    1794:   PetscCall(VecView(tao->solution, viewer));
    1795:   PetscFunctionReturn(PETSC_SUCCESS);
    1796: }

    1798: /*@C
    1799:   TaoMonitorGradient - Views the gradient at each iteration of `TaoSolve()`

    1801:   Collective

    1803:   Input Parameters:
    1804: + tao - the `Tao` context
    1805: - ctx - `PetscViewer` context or `NULL`

    1807:   Options Database Key:
    1808: . -tao_monitor_gradient - view the gradient at each iteration

    1810:   Level: advanced

    1812: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1813: @*/
    1814: PetscErrorCode TaoMonitorGradient(Tao tao, void *ctx)
    1815: {
    1816:   PetscViewer viewer = (PetscViewer)ctx;

    1818:   PetscFunctionBegin;
    1821:   PetscCall(VecView(tao->gradient, viewer));
    1822:   PetscFunctionReturn(PETSC_SUCCESS);
    1823: }

    1825: /*@C
    1826:   TaoMonitorStep - Views the step-direction at each iteration of `TaoSolve()`

    1828:   Collective

    1830:   Input Parameters:
    1831: + tao - the `Tao` context
    1832: - ctx - `PetscViewer` context or `NULL`

    1834:   Options Database Key:
    1835: . -tao_monitor_step - view the step vector at each iteration

    1837:   Level: advanced

    1839: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1840: @*/
    1841: PetscErrorCode TaoMonitorStep(Tao tao, void *ctx)
    1842: {
    1843:   PetscViewer viewer = (PetscViewer)ctx;

    1845:   PetscFunctionBegin;
    1848:   PetscCall(VecView(tao->stepdirection, viewer));
    1849:   PetscFunctionReturn(PETSC_SUCCESS);
    1850: }

    1852: /*@C
    1853:   TaoMonitorSolutionDraw - Plots the solution at each iteration of `TaoSolve()`

    1855:   Collective

    1857:   Input Parameters:
    1858: + tao - the `Tao` context
    1859: - ctx - `TaoMonitorDraw` context

    1861:   Options Database Key:
    1862: . -tao_monitor_solution_draw - draw the solution at each iteration

    1864:   Level: advanced

    1866:   Note:
    1867:   The context created by `TaoMonitorDrawCtxCreate()`, along with `TaoMonitorSolutionDraw()`, and `TaoMonitorDrawCtxDestroy()`
    1868:   are passed to `TaoMonitorSet()` to monitor the solution graphically.

    1870: .seealso: [](ch_tao), `Tao`, `TaoMonitorSolution()`, `TaoMonitorSet()`, `TaoMonitorGradientDraw()`, `TaoMonitorDrawCtxCreate()`,
    1871:           `TaoMonitorDrawCtxDestroy()`
    1872: @*/
    1873: PetscErrorCode TaoMonitorSolutionDraw(Tao tao, void *ctx)
    1874: {
    1875:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

    1877:   PetscFunctionBegin;
    1879:   if (!(((ictx->howoften > 0) && (!(tao->niter % ictx->howoften))) || ((ictx->howoften == -1) && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
    1880:   PetscCall(VecView(tao->solution, ictx->viewer));
    1881:   PetscFunctionReturn(PETSC_SUCCESS);
    1882: }

    1884: /*@C
    1885:   TaoMonitorGradientDraw - Plots the gradient at each iteration of `TaoSolve()`

    1887:   Collective

    1889:   Input Parameters:
    1890: + tao - the `Tao` context
    1891: - ctx - `PetscViewer` context

    1893:   Options Database Key:
    1894: . -tao_monitor_gradient_draw - draw the gradient at each iteration

    1896:   Level: advanced

    1898: .seealso: [](ch_tao), `Tao`, `TaoMonitorGradient()`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw()`
    1899: @*/
    1900: PetscErrorCode TaoMonitorGradientDraw(Tao tao, void *ctx)
    1901: {
    1902:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

    1904:   PetscFunctionBegin;
    1906:   if (!(((ictx->howoften > 0) && (!(tao->niter % ictx->howoften))) || ((ictx->howoften == -1) && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
    1907:   PetscCall(VecView(tao->gradient, ictx->viewer));
    1908:   PetscFunctionReturn(PETSC_SUCCESS);
    1909: }

    1911: /*@C
    1912:   TaoMonitorStepDraw - Plots the step direction at each iteration of `TaoSolve()`

    1914:   Collective

    1916:   Input Parameters:
    1917: + tao - the `Tao` context
    1918: - ctx - the `PetscViewer` context

    1920:   Options Database Key:
    1921: . -tao_monitor_step_draw - draw the step direction at each iteration

    1923:   Level: advanced

    1925: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw`
    1926: @*/
    1927: PetscErrorCode TaoMonitorStepDraw(Tao tao, void *ctx)
    1928: {
    1929:   PetscViewer viewer = (PetscViewer)ctx;

    1931:   PetscFunctionBegin;
    1934:   PetscCall(VecView(tao->stepdirection, viewer));
    1935:   PetscFunctionReturn(PETSC_SUCCESS);
    1936: }

    1938: /*@C
    1939:   TaoMonitorResidual - Views the least-squares residual at each iteration of `TaoSolve()`

    1941:   Collective

    1943:   Input Parameters:
    1944: + tao - the `Tao` context
    1945: - ctx - the `PetscViewer` context or `NULL`

    1947:   Options Database Key:
    1948: . -tao_monitor_ls_residual - view the residual at each iteration

    1950:   Level: advanced

    1952: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
    1953: @*/
    1954: PetscErrorCode TaoMonitorResidual(Tao tao, void *ctx)
    1955: {
    1956:   PetscViewer viewer = (PetscViewer)ctx;

    1958:   PetscFunctionBegin;
    1961:   PetscCall(VecView(tao->ls_res, viewer));
    1962:   PetscFunctionReturn(PETSC_SUCCESS);
    1963: }

    1965: /*@
    1966:   TaoDefaultConvergenceTest - Determines whether the solver should continue iterating
    1967:   or terminate.

    1969:   Collective

    1971:   Input Parameters:
    1972: + tao   - the `Tao` context
    1973: - dummy - unused dummy context

    1975:   Level: developer

    1977:   Notes:
    1978:   This routine checks the residual in the optimality conditions, the
    1979:   relative residual in the optimity conditions, the number of function
    1980:   evaluations, and the function value to test convergence.  Some
    1981:   solvers may use different convergence routines.

    1983: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoGetConvergedReason()`, `TaoSetConvergedReason()`
    1984: @*/
    1985: PetscErrorCode TaoDefaultConvergenceTest(Tao tao, void *dummy)
    1986: {
    1987:   PetscInt           niter = tao->niter, nfuncs = PetscMax(tao->nfuncs, tao->nfuncgrads);
    1988:   PetscInt           max_funcs = tao->max_funcs;
    1989:   PetscReal          gnorm = tao->residual, gnorm0 = tao->gnorm0;
    1990:   PetscReal          f = tao->fc, steptol = tao->steptol, trradius = tao->step;
    1991:   PetscReal          gatol = tao->gatol, grtol = tao->grtol, gttol = tao->gttol;
    1992:   PetscReal          catol = tao->catol, crtol = tao->crtol;
    1993:   PetscReal          fmin = tao->fmin, cnorm = tao->cnorm;
    1994:   TaoConvergedReason reason = tao->reason;

    1996:   PetscFunctionBegin;
    1998:   if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);

    2000:   if (PetscIsInfOrNanReal(f)) {
    2001:     PetscCall(PetscInfo(tao, "Failed to converged, function value is Inf or NaN\n"));
    2002:     reason = TAO_DIVERGED_NAN;
    2003:   } else if (f <= fmin && cnorm <= catol) {
    2004:     PetscCall(PetscInfo(tao, "Converged due to function value %g < minimum function value %g\n", (double)f, (double)fmin));
    2005:     reason = TAO_CONVERGED_MINF;
    2006:   } else if (gnorm <= gatol && cnorm <= catol) {
    2007:     PetscCall(PetscInfo(tao, "Converged due to residual norm ||g(X)||=%g < %g\n", (double)gnorm, (double)gatol));
    2008:     reason = TAO_CONVERGED_GATOL;
    2009:   } else if (f != 0 && PetscAbsReal(gnorm / f) <= grtol && cnorm <= crtol) {
    2010:     PetscCall(PetscInfo(tao, "Converged due to residual ||g(X)||/|f(X)| =%g < %g\n", (double)(gnorm / f), (double)grtol));
    2011:     reason = TAO_CONVERGED_GRTOL;
    2012:   } else if (gnorm0 != 0 && ((gttol == 0 && gnorm == 0) || gnorm / gnorm0 < gttol) && cnorm <= crtol) {
    2013:     PetscCall(PetscInfo(tao, "Converged due to relative residual norm ||g(X)||/||g(X0)|| = %g < %g\n", (double)(gnorm / gnorm0), (double)gttol));
    2014:     reason = TAO_CONVERGED_GTTOL;
    2015:   } else if (max_funcs != PETSC_UNLIMITED && nfuncs > max_funcs) {
    2016:     PetscCall(PetscInfo(tao, "Exceeded maximum number of function evaluations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", nfuncs, max_funcs));
    2017:     reason = TAO_DIVERGED_MAXFCN;
    2018:   } else if (tao->lsflag != 0) {
    2019:     PetscCall(PetscInfo(tao, "Tao Line Search failure.\n"));
    2020:     reason = TAO_DIVERGED_LS_FAILURE;
    2021:   } else if (trradius < steptol && niter > 0) {
    2022:     PetscCall(PetscInfo(tao, "Trust region/step size too small: %g < %g\n", (double)trradius, (double)steptol));
    2023:     reason = TAO_CONVERGED_STEPTOL;
    2024:   } else if (niter >= tao->max_it) {
    2025:     PetscCall(PetscInfo(tao, "Exceeded maximum number of iterations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", niter, tao->max_it));
    2026:     reason = TAO_DIVERGED_MAXITS;
    2027:   } else {
    2028:     reason = TAO_CONTINUE_ITERATING;
    2029:   }
    2030:   tao->reason = reason;
    2031:   PetscFunctionReturn(PETSC_SUCCESS);
    2032: }

    2034: /*@
    2035:   TaoSetOptionsPrefix - Sets the prefix used for searching for all
    2036:   Tao options in the database.

    2038:   Logically Collective

    2040:   Input Parameters:
    2041: + tao - the `Tao` context
    2042: - p   - the prefix string to prepend to all Tao option requests

    2044:   Level: advanced

    2046:   Notes:
    2047:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    2048:   The first character of all runtime options is AUTOMATICALLY the hyphen.

    2050:   For example, to distinguish between the runtime options for two
    2051:   different Tao solvers, one could call
    2052: .vb
    2053:       TaoSetOptionsPrefix(tao1,"sys1_")
    2054:       TaoSetOptionsPrefix(tao2,"sys2_")
    2055: .ve

    2057:   This would enable use of different options for each system, such as
    2058: .vb
    2059:       -sys1_tao_method blmvm -sys1_tao_grtol 1.e-3
    2060:       -sys2_tao_method lmvm  -sys2_tao_grtol 1.e-4
    2061: .ve

    2063: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoAppendOptionsPrefix()`, `TaoGetOptionsPrefix()`
    2064: @*/
    2065: PetscErrorCode TaoSetOptionsPrefix(Tao tao, const char p[])
    2066: {
    2067:   PetscFunctionBegin;
    2069:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao, p));
    2070:   if (tao->linesearch) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, p));
    2071:   if (tao->ksp) PetscCall(KSPSetOptionsPrefix(tao->ksp, p));
    2072:   PetscFunctionReturn(PETSC_SUCCESS);
    2073: }

    2075: /*@
    2076:   TaoAppendOptionsPrefix - Appends to the prefix used for searching for all Tao options in the database.

    2078:   Logically Collective

    2080:   Input Parameters:
    2081: + tao - the `Tao` solver context
    2082: - p   - the prefix string to prepend to all `Tao` option requests

    2084:   Level: advanced

    2086:   Note:
    2087:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    2088:   The first character of all runtime options is automatically the hyphen.

    2090: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoGetOptionsPrefix()`
    2091: @*/
    2092: PetscErrorCode TaoAppendOptionsPrefix(Tao tao, const char p[])
    2093: {
    2094:   PetscFunctionBegin;
    2096:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao, p));
    2097:   if (tao->linesearch) PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->linesearch, p));
    2098:   if (tao->ksp) PetscCall(KSPAppendOptionsPrefix(tao->ksp, p));
    2099:   PetscFunctionReturn(PETSC_SUCCESS);
    2100: }

    2102: /*@
    2103:   TaoGetOptionsPrefix - Gets the prefix used for searching for all
    2104:   Tao options in the database

    2106:   Not Collective

    2108:   Input Parameter:
    2109: . tao - the `Tao` context

    2111:   Output Parameter:
    2112: . p - pointer to the prefix string used is returned

    2114:   Fortran Notes:
    2115:   Pass in a string 'prefix' of sufficient length to hold the prefix.

    2117:   Level: advanced

    2119: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoAppendOptionsPrefix()`
    2120: @*/
    2121: PetscErrorCode TaoGetOptionsPrefix(Tao tao, const char *p[])
    2122: {
    2123:   PetscFunctionBegin;
    2125:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao, p));
    2126:   PetscFunctionReturn(PETSC_SUCCESS);
    2127: }

    2129: /*@
    2130:   TaoSetType - Sets the `TaoType` for the minimization solver.

    2132:   Collective

    2134:   Input Parameters:
    2135: + tao  - the `Tao` solver context
    2136: - type - a known method

    2138:   Options Database Key:
    2139: . -tao_type <type> - Sets the method; use -help for a list
    2140:    of available methods (for instance, "-tao_type lmvm" or "-tao_type tron")

    2142:   Level: intermediate

    2144: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoGetType()`, `TaoType`
    2145: @*/
    2146: PetscErrorCode TaoSetType(Tao tao, TaoType type)
    2147: {
    2148:   PetscErrorCode (*create_xxx)(Tao);
    2149:   PetscBool issame;

    2151:   PetscFunctionBegin;

    2154:   PetscCall(PetscObjectTypeCompare((PetscObject)tao, type, &issame));
    2155:   if (issame) PetscFunctionReturn(PETSC_SUCCESS);

    2157:   PetscCall(PetscFunctionListFind(TaoList, type, (void (**)(void))&create_xxx));
    2158:   PetscCheck(create_xxx, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Tao type %s", type);

    2160:   /* Destroy the existing solver information */
    2161:   PetscTryTypeMethod(tao, destroy);
    2162:   PetscCall(KSPDestroy(&tao->ksp));
    2163:   PetscCall(TaoLineSearchDestroy(&tao->linesearch));
    2164:   tao->ops->setup          = NULL;
    2165:   tao->ops->solve          = NULL;
    2166:   tao->ops->view           = NULL;
    2167:   tao->ops->setfromoptions = NULL;
    2168:   tao->ops->destroy        = NULL;

    2170:   tao->setupcalled = PETSC_FALSE;

    2172:   PetscCall((*create_xxx)(tao));
    2173:   PetscCall(PetscObjectChangeTypeName((PetscObject)tao, type));
    2174:   PetscFunctionReturn(PETSC_SUCCESS);
    2175: }

    2177: /*@C
    2178:   TaoRegister - Adds a method to the Tao package for minimization.

    2180:   Not Collective, No Fortran Support

    2182:   Input Parameters:
    2183: + sname - name of a new user-defined solver
    2184: - func  - routine to Create method context

    2186:   Example Usage:
    2187: .vb
    2188:    TaoRegister("my_solver", MySolverCreate);
    2189: .ve

    2191:   Then, your solver can be chosen with the procedural interface via
    2192: $     TaoSetType(tao, "my_solver")
    2193:   or at runtime via the option
    2194: $     -tao_type my_solver

    2196:   Level: advanced

    2198:   Note:
    2199:   `TaoRegister()` may be called multiple times to add several user-defined solvers.

    2201: .seealso: [](ch_tao), `Tao`, `TaoSetType()`, `TaoRegisterAll()`, `TaoRegisterDestroy()`
    2202: @*/
    2203: PetscErrorCode TaoRegister(const char sname[], PetscErrorCode (*func)(Tao))
    2204: {
    2205:   PetscFunctionBegin;
    2206:   PetscCall(TaoInitializePackage());
    2207:   PetscCall(PetscFunctionListAdd(&TaoList, sname, (void (*)(void))func));
    2208:   PetscFunctionReturn(PETSC_SUCCESS);
    2209: }

    2211: /*@C
    2212:   TaoRegisterDestroy - Frees the list of minimization solvers that were
    2213:   registered by `TaoRegister()`.

    2215:   Not Collective

    2217:   Level: advanced

    2219: .seealso: [](ch_tao), `Tao`, `TaoRegisterAll()`, `TaoRegister()`
    2220: @*/
    2221: PetscErrorCode TaoRegisterDestroy(void)
    2222: {
    2223:   PetscFunctionBegin;
    2224:   PetscCall(PetscFunctionListDestroy(&TaoList));
    2225:   TaoRegisterAllCalled = PETSC_FALSE;
    2226:   PetscFunctionReturn(PETSC_SUCCESS);
    2227: }

    2229: /*@
    2230:   TaoGetIterationNumber - Gets the number of `TaoSolve()` iterations completed
    2231:   at this time.

    2233:   Not Collective

    2235:   Input Parameter:
    2236: . tao - the `Tao` context

    2238:   Output Parameter:
    2239: . iter - iteration number

    2241:   Notes:
    2242:   For example, during the computation of iteration 2 this would return 1.

    2244:   Level: intermediate

    2246: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetResidualNorm()`, `TaoGetObjective()`
    2247: @*/
    2248: PetscErrorCode TaoGetIterationNumber(Tao tao, PetscInt *iter)
    2249: {
    2250:   PetscFunctionBegin;
    2252:   PetscAssertPointer(iter, 2);
    2253:   *iter = tao->niter;
    2254:   PetscFunctionReturn(PETSC_SUCCESS);
    2255: }

    2257: /*@
    2258:   TaoGetResidualNorm - Gets the current value of the norm of the residual (gradient)
    2259:   at this time.

    2261:   Not Collective

    2263:   Input Parameter:
    2264: . tao - the `Tao` context

    2266:   Output Parameter:
    2267: . value - the current value

    2269:   Level: intermediate

    2271:   Developer Notes:
    2272:   This is the 2-norm of the residual, we cannot use `TaoGetGradientNorm()` because that has
    2273:   a different meaning. For some reason `Tao` sometimes calls the gradient the residual.

    2275: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetIterationNumber()`, `TaoGetObjective()`
    2276: @*/
    2277: PetscErrorCode TaoGetResidualNorm(Tao tao, PetscReal *value)
    2278: {
    2279:   PetscFunctionBegin;
    2281:   PetscAssertPointer(value, 2);
    2282:   *value = tao->residual;
    2283:   PetscFunctionReturn(PETSC_SUCCESS);
    2284: }

    2286: /*@
    2287:   TaoSetIterationNumber - Sets the current iteration number.

    2289:   Logically Collective

    2291:   Input Parameters:
    2292: + tao  - the `Tao` context
    2293: - iter - iteration number

    2295:   Level: developer

    2297: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
    2298: @*/
    2299: PetscErrorCode TaoSetIterationNumber(Tao tao, PetscInt iter)
    2300: {
    2301:   PetscFunctionBegin;
    2304:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
    2305:   tao->niter = iter;
    2306:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
    2307:   PetscFunctionReturn(PETSC_SUCCESS);
    2308: }

    2310: /*@
    2311:   TaoGetTotalIterationNumber - Gets the total number of `TaoSolve()` iterations
    2312:   completed. This number keeps accumulating if multiple solves
    2313:   are called with the `Tao` object.

    2315:   Not Collective

    2317:   Input Parameter:
    2318: . tao - the `Tao` context

    2320:   Output Parameter:
    2321: . iter - number of iterations

    2323:   Level: intermediate

    2325:   Note:
    2326:   The total iteration count is updated after each solve, if there is a current
    2327:   `TaoSolve()` in progress then those iterations are not included in the count

    2329: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
    2330: @*/
    2331: PetscErrorCode TaoGetTotalIterationNumber(Tao tao, PetscInt *iter)
    2332: {
    2333:   PetscFunctionBegin;
    2335:   PetscAssertPointer(iter, 2);
    2336:   *iter = tao->ntotalits;
    2337:   PetscFunctionReturn(PETSC_SUCCESS);
    2338: }

    2340: /*@
    2341:   TaoSetTotalIterationNumber - Sets the current total iteration number.

    2343:   Logically Collective

    2345:   Input Parameters:
    2346: + tao  - the `Tao` context
    2347: - iter - the iteration number

    2349:   Level: developer

    2351: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
    2352: @*/
    2353: PetscErrorCode TaoSetTotalIterationNumber(Tao tao, PetscInt iter)
    2354: {
    2355:   PetscFunctionBegin;
    2358:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
    2359:   tao->ntotalits = iter;
    2360:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
    2361:   PetscFunctionReturn(PETSC_SUCCESS);
    2362: }

    2364: /*@
    2365:   TaoSetConvergedReason - Sets the termination flag on a `Tao` object

    2367:   Logically Collective

    2369:   Input Parameters:
    2370: + tao    - the `Tao` context
    2371: - reason - the `TaoConvergedReason`

    2373:   Level: intermediate

    2375: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`
    2376: @*/
    2377: PetscErrorCode TaoSetConvergedReason(Tao tao, TaoConvergedReason reason)
    2378: {
    2379:   PetscFunctionBegin;
    2382:   tao->reason = reason;
    2383:   PetscFunctionReturn(PETSC_SUCCESS);
    2384: }

    2386: /*@
    2387:   TaoGetConvergedReason - Gets the reason the `TaoSolve()` was stopped.

    2389:   Not Collective

    2391:   Input Parameter:
    2392: . tao - the `Tao` solver context

    2394:   Output Parameter:
    2395: . reason - value of `TaoConvergedReason`

    2397:   Level: intermediate

    2399: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetConvergenceTest()`, `TaoSetTolerances()`
    2400: @*/
    2401: PetscErrorCode TaoGetConvergedReason(Tao tao, TaoConvergedReason *reason)
    2402: {
    2403:   PetscFunctionBegin;
    2405:   PetscAssertPointer(reason, 2);
    2406:   *reason = tao->reason;
    2407:   PetscFunctionReturn(PETSC_SUCCESS);
    2408: }

    2410: /*@
    2411:   TaoGetSolutionStatus - Get the current iterate, objective value,
    2412:   residual, infeasibility, and termination from a `Tao` object

    2414:   Not Collective

    2416:   Input Parameter:
    2417: . tao - the `Tao` context

    2419:   Output Parameters:
    2420: + its    - the current iterate number (>=0)
    2421: . f      - the current function value
    2422: . gnorm  - the square of the gradient norm, duality gap, or other measure indicating distance from optimality.
    2423: . cnorm  - the infeasibility of the current solution with regard to the constraints.
    2424: . xdiff  - the step length or trust region radius of the most recent iterate.
    2425: - reason - The termination reason, which can equal `TAO_CONTINUE_ITERATING`

    2427:   Level: intermediate

    2429:   Notes:
    2430:   Tao returns the values set by the solvers in the routine `TaoMonitor()`.

    2432:   If any of the output arguments are set to `NULL`, no corresponding value will be returned.

    2434: .seealso: [](ch_tao), `TaoMonitor()`, `TaoGetConvergedReason()`
    2435: @*/
    2436: PetscErrorCode TaoGetSolutionStatus(Tao tao, PetscInt *its, PetscReal *f, PetscReal *gnorm, PetscReal *cnorm, PetscReal *xdiff, TaoConvergedReason *reason)
    2437: {
    2438:   PetscFunctionBegin;
    2440:   if (its) *its = tao->niter;
    2441:   if (f) *f = tao->fc;
    2442:   if (gnorm) *gnorm = tao->residual;
    2443:   if (cnorm) *cnorm = tao->cnorm;
    2444:   if (reason) *reason = tao->reason;
    2445:   if (xdiff) *xdiff = tao->step;
    2446:   PetscFunctionReturn(PETSC_SUCCESS);
    2447: }

    2449: /*@
    2450:   TaoGetType - Gets the current `TaoType` being used in the `Tao` object

    2452:   Not Collective

    2454:   Input Parameter:
    2455: . tao - the `Tao` solver context

    2457:   Output Parameter:
    2458: . type - the `TaoType`

    2460:   Level: intermediate

    2462: .seealso: [](ch_tao), `Tao`, `TaoType`, `TaoSetType()`
    2463: @*/
    2464: PetscErrorCode TaoGetType(Tao tao, TaoType *type)
    2465: {
    2466:   PetscFunctionBegin;
    2468:   PetscAssertPointer(type, 2);
    2469:   *type = ((PetscObject)tao)->type_name;
    2470:   PetscFunctionReturn(PETSC_SUCCESS);
    2471: }

    2473: /*@C
    2474:   TaoMonitor - Monitor the solver and the current solution.  This
    2475:   routine will record the iteration number and residual statistics,
    2476:   and call any monitors specified by the user.

    2478:   Input Parameters:
    2479: + tao        - the `Tao` context
    2480: . its        - the current iterate number (>=0)
    2481: . f          - the current objective function value
    2482: . res        - the gradient norm, square root of the duality gap, or other measure indicating distance from optimality.  This measure will be recorded and
    2483:           used for some termination tests.
    2484: . cnorm      - the infeasibility of the current solution with regard to the constraints.
    2485: - steplength - multiple of the step direction added to the previous iterate.

    2487:   Options Database Key:
    2488: . -tao_monitor - Use the default monitor, which prints statistics to standard output

    2490:   Level: developer

    2492: .seealso: [](ch_tao), `Tao`, `TaoGetConvergedReason()`, `TaoMonitorDefault()`, `TaoMonitorSet()`
    2493: @*/
    2494: PetscErrorCode TaoMonitor(Tao tao, PetscInt its, PetscReal f, PetscReal res, PetscReal cnorm, PetscReal steplength)
    2495: {
    2496:   PetscInt i;

    2498:   PetscFunctionBegin;
    2500:   tao->fc       = f;
    2501:   tao->residual = res;
    2502:   tao->cnorm    = cnorm;
    2503:   tao->step     = steplength;
    2504:   if (!its) {
    2505:     tao->cnorm0 = cnorm;
    2506:     tao->gnorm0 = res;
    2507:   }
    2508:   PetscCall(VecLockReadPush(tao->solution));
    2509:   for (i = 0; i < tao->numbermonitors; i++) PetscCall((*tao->monitor[i])(tao, tao->monitorcontext[i]));
    2510:   PetscCall(VecLockReadPop(tao->solution));
    2511:   PetscFunctionReturn(PETSC_SUCCESS);
    2512: }

    2514: /*@
    2515:   TaoSetConvergenceHistory - Sets the array used to hold the convergence history.

    2517:   Logically Collective

    2519:   Input Parameters:
    2520: + tao   - the `Tao` solver context
    2521: . obj   - array to hold objective value history
    2522: . resid - array to hold residual history
    2523: . cnorm - array to hold constraint violation history
    2524: . lits  - integer array holds the number of linear iterations for each Tao iteration
    2525: . na    - size of `obj`, `resid`, and `cnorm`
    2526: - reset - `PETSC_TRUE` indicates each new minimization resets the history counter to zero,
    2527:            else it continues storing new values for new minimizations after the old ones

    2529:   Level: intermediate

    2531:   Notes:
    2532:   If set, `Tao` will fill the given arrays with the indicated
    2533:   information at each iteration.  If 'obj','resid','cnorm','lits' are
    2534:   *all* `NULL` then space (using size `na`, or 1000 if `na` is `PETSC_DECIDE`) is allocated for the history.
    2535:   If not all are `NULL`, then only the non-`NULL` information categories
    2536:   will be stored, the others will be ignored.

    2538:   Any convergence information after iteration number 'na' will not be stored.

    2540:   This routine is useful, e.g., when running a code for purposes
    2541:   of accurate performance monitoring, when no I/O should be done
    2542:   during the section of code that is being timed.

    2544: .seealso: [](ch_tao), `TaoGetConvergenceHistory()`
    2545: @*/
    2546: PetscErrorCode TaoSetConvergenceHistory(Tao tao, PetscReal obj[], PetscReal resid[], PetscReal cnorm[], PetscInt lits[], PetscInt na, PetscBool reset)
    2547: {
    2548:   PetscFunctionBegin;
    2550:   if (obj) PetscAssertPointer(obj, 2);
    2551:   if (resid) PetscAssertPointer(resid, 3);
    2552:   if (cnorm) PetscAssertPointer(cnorm, 4);
    2553:   if (lits) PetscAssertPointer(lits, 5);

    2555:   if (na == PETSC_DECIDE || na == PETSC_CURRENT) na = 1000;
    2556:   if (!obj && !resid && !cnorm && !lits) {
    2557:     PetscCall(PetscCalloc4(na, &obj, na, &resid, na, &cnorm, na, &lits));
    2558:     tao->hist_malloc = PETSC_TRUE;
    2559:   }

    2561:   tao->hist_obj   = obj;
    2562:   tao->hist_resid = resid;
    2563:   tao->hist_cnorm = cnorm;
    2564:   tao->hist_lits  = lits;
    2565:   tao->hist_max   = na;
    2566:   tao->hist_reset = reset;
    2567:   tao->hist_len   = 0;
    2568:   PetscFunctionReturn(PETSC_SUCCESS);
    2569: }

    2571: /*@C
    2572:   TaoGetConvergenceHistory - Gets the arrays used that hold the convergence history.

    2574:   Collective

    2576:   Input Parameter:
    2577: . tao - the `Tao` context

    2579:   Output Parameters:
    2580: + obj   - array used to hold objective value history
    2581: . resid - array used to hold residual history
    2582: . cnorm - array used to hold constraint violation history
    2583: . lits  - integer array used to hold linear solver iteration count
    2584: - nhist - size of `obj`, `resid`, `cnorm`, and `lits`

    2586:   Level: advanced

    2588:   Notes:
    2589:   This routine must be preceded by calls to `TaoSetConvergenceHistory()`
    2590:   and `TaoSolve()`, otherwise it returns useless information.

    2592:   This routine is useful, e.g., when running a code for purposes
    2593:   of accurate performance monitoring, when no I/O should be done
    2594:   during the section of code that is being timed.

    2596:   Fortran Notes:
    2597:   The calling sequence is
    2598: .vb
    2599:    call TaoGetConvergenceHistory(Tao tao, PetscInt nhist, PetscErrorCode ierr)
    2600: .ve
    2601:   In other words this gets the current number of entries in the history. Access the history through the array you passed to `TaoSetConvergenceHistory()`

    2603: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergenceHistory()`
    2604: @*/
    2605: PetscErrorCode TaoGetConvergenceHistory(Tao tao, PetscReal **obj, PetscReal **resid, PetscReal **cnorm, PetscInt **lits, PetscInt *nhist)
    2606: {
    2607:   PetscFunctionBegin;
    2609:   if (obj) *obj = tao->hist_obj;
    2610:   if (cnorm) *cnorm = tao->hist_cnorm;
    2611:   if (resid) *resid = tao->hist_resid;
    2612:   if (lits) *lits = tao->hist_lits;
    2613:   if (nhist) *nhist = tao->hist_len;
    2614:   PetscFunctionReturn(PETSC_SUCCESS);
    2615: }

    2617: /*@
    2618:   TaoSetApplicationContext - Sets the optional user-defined context for a `Tao` solver.

    2620:   Logically Collective

    2622:   Input Parameters:
    2623: + tao  - the `Tao` context
    2624: - usrP - optional user context

    2626:   Level: intermediate

    2628: .seealso: [](ch_tao), `Tao`, `TaoGetApplicationContext()`
    2629: @*/
    2630: PetscErrorCode TaoSetApplicationContext(Tao tao, void *usrP)
    2631: {
    2632:   PetscFunctionBegin;
    2634:   tao->user = usrP;
    2635:   PetscFunctionReturn(PETSC_SUCCESS);
    2636: }

    2638: /*@
    2639:   TaoGetApplicationContext - Gets the user-defined context for a `Tao` solver

    2641:   Not Collective

    2643:   Input Parameter:
    2644: . tao - the `Tao` context

    2646:   Output Parameter:
    2647: . usrP - user context

    2649:   Level: intermediate

    2651: .seealso: [](ch_tao), `Tao`, `TaoSetApplicationContext()`
    2652: @*/
    2653: PetscErrorCode TaoGetApplicationContext(Tao tao, void *usrP)
    2654: {
    2655:   PetscFunctionBegin;
    2657:   PetscAssertPointer(usrP, 2);
    2658:   *(void **)usrP = tao->user;
    2659:   PetscFunctionReturn(PETSC_SUCCESS);
    2660: }

    2662: /*@
    2663:   TaoSetGradientNorm - Sets the matrix used to define the norm that measures the size of the gradient in some of the `Tao` algorithms

    2665:   Collective

    2667:   Input Parameters:
    2668: + tao - the `Tao` context
    2669: - M   - matrix that defines the norm

    2671:   Level: beginner

    2673: .seealso: [](ch_tao), `Tao`, `TaoGetGradientNorm()`, `TaoGradientNorm()`
    2674: @*/
    2675: PetscErrorCode TaoSetGradientNorm(Tao tao, Mat M)
    2676: {
    2677:   PetscFunctionBegin;
    2680:   PetscCall(PetscObjectReference((PetscObject)M));
    2681:   PetscCall(MatDestroy(&tao->gradient_norm));
    2682:   PetscCall(VecDestroy(&tao->gradient_norm_tmp));
    2683:   tao->gradient_norm = M;
    2684:   PetscCall(MatCreateVecs(M, NULL, &tao->gradient_norm_tmp));
    2685:   PetscFunctionReturn(PETSC_SUCCESS);
    2686: }

    2688: /*@
    2689:   TaoGetGradientNorm - Returns the matrix used to define the norm used for measuring the size of the gradient in some of the `Tao` algorithms

    2691:   Not Collective

    2693:   Input Parameter:
    2694: . tao - the `Tao` context

    2696:   Output Parameter:
    2697: . M - gradient norm

    2699:   Level: beginner

    2701: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGradientNorm()`
    2702: @*/
    2703: PetscErrorCode TaoGetGradientNorm(Tao tao, Mat *M)
    2704: {
    2705:   PetscFunctionBegin;
    2707:   PetscAssertPointer(M, 2);
    2708:   *M = tao->gradient_norm;
    2709:   PetscFunctionReturn(PETSC_SUCCESS);
    2710: }

    2712: /*@
    2713:   TaoGradientNorm - Compute the norm using the `NormType`, the user has selected

    2715:   Collective

    2717:   Input Parameters:
    2718: + tao      - the `Tao` context
    2719: . gradient - the gradient
    2720: - type     - the norm type

    2722:   Output Parameter:
    2723: . gnorm - the gradient norm

    2725:   Level: advanced

    2727:   Note:
    2728:   If `TaoSetGradientNorm()` has been set and `type` is `NORM_2` then the norm provided with `TaoSetGradientNorm()` is used.

    2730:   Developer Notes:
    2731:   Should be named `TaoComputeGradientNorm()`.

    2733:   The usage is a bit confusing, with `TaoSetGradientNorm()` plus `NORM_2` resulting in the computation of the user provided
    2734:   norm, perhaps a refactorization is in order.

    2736: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGetGradientNorm()`
    2737: @*/
    2738: PetscErrorCode TaoGradientNorm(Tao tao, Vec gradient, NormType type, PetscReal *gnorm)
    2739: {
    2740:   PetscFunctionBegin;
    2744:   PetscAssertPointer(gnorm, 4);
    2745:   if (tao->gradient_norm) {
    2746:     PetscScalar gnorms;

    2748:     PetscCheck(type == NORM_2, PetscObjectComm((PetscObject)gradient), PETSC_ERR_ARG_WRONG, "Norm type must be NORM_2 if an inner product for the gradient norm is set.");
    2749:     PetscCall(MatMult(tao->gradient_norm, gradient, tao->gradient_norm_tmp));
    2750:     PetscCall(VecDot(gradient, tao->gradient_norm_tmp, &gnorms));
    2751:     *gnorm = PetscRealPart(PetscSqrtScalar(gnorms));
    2752:   } else {
    2753:     PetscCall(VecNorm(gradient, type, gnorm));
    2754:   }
    2755:   PetscFunctionReturn(PETSC_SUCCESS);
    2756: }

    2758: /*@C
    2759:   TaoMonitorDrawCtxCreate - Creates the monitor context for `TaoMonitorSolutionDraw()`

    2761:   Collective

    2763:   Input Parameters:
    2764: + comm     - the communicator to share the context
    2765: . host     - the name of the X Windows host that will display the monitor
    2766: . label    - the label to put at the top of the display window
    2767: . x        - the horizontal coordinate of the lower left corner of the window to open
    2768: . y        - the vertical coordinate of the lower left corner of the window to open
    2769: . m        - the width of the window
    2770: . n        - the height of the window
    2771: - howoften - how many `Tao` iterations between displaying the monitor information

    2773:   Output Parameter:
    2774: . ctx - the monitor context

    2776:   Options Database Keys:
    2777: + -tao_monitor_solution_draw - use `TaoMonitorSolutionDraw()` to monitor the solution
    2778: - -tao_draw_solution_initial - show initial guess as well as current solution

    2780:   Level: intermediate

    2782:   Note:
    2783:   The context this creates, along with `TaoMonitorSolutionDraw()`, and `TaoMonitorDrawCtxDestroy()`
    2784:   are passed to `TaoMonitorSet()`.

    2786: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorDrawCtx()`
    2787: @*/
    2788: PetscErrorCode TaoMonitorDrawCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TaoMonitorDrawCtx *ctx)
    2789: {
    2790:   PetscFunctionBegin;
    2791:   PetscCall(PetscNew(ctx));
    2792:   PetscCall(PetscViewerDrawOpen(comm, host, label, x, y, m, n, &(*ctx)->viewer));
    2793:   PetscCall(PetscViewerSetFromOptions((*ctx)->viewer));
    2794:   (*ctx)->howoften = howoften;
    2795:   PetscFunctionReturn(PETSC_SUCCESS);
    2796: }

    2798: /*@C
    2799:   TaoMonitorDrawCtxDestroy - Destroys the monitor context for `TaoMonitorSolutionDraw()`

    2801:   Collective

    2803:   Input Parameter:
    2804: . ictx - the monitor context

    2806:   Level: intermediate

    2808:   Note:
    2809:   This is passed to `TaoMonitorSet()` as the final argument, along with `TaoMonitorSolutionDraw()`, and the context
    2810:   obtained with `TaoMonitorDrawCtxCreate()`.

    2812: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorSolutionDraw()`
    2813: @*/
    2814: PetscErrorCode TaoMonitorDrawCtxDestroy(TaoMonitorDrawCtx *ictx)
    2815: {
    2816:   PetscFunctionBegin;
    2817:   PetscCall(PetscViewerDestroy(&(*ictx)->viewer));
    2818:   PetscCall(PetscFree(*ictx));
    2819:   PetscFunctionReturn(PETSC_SUCCESS);
    2820: }