xref: /petsc/src/snes/impls/tr/tr.c (revision acba1f639723d2c96d17150f46c667032d36792e)
1c6db04a5SJed Brown #include <../src/snes/impls/tr/trimpl.h> /*I   "petscsnes.h"   I*/
24800dd8cSBarry Smith 
3971273eeSBarry Smith typedef struct {
4971273eeSBarry Smith   SNES snes;
5df8705c3SBarry Smith   PetscErrorCode (*convtest)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *);
6df8705c3SBarry Smith   PetscErrorCode (*convdestroy)(void *);
7df8705c3SBarry Smith   void *convctx;
8971273eeSBarry Smith } SNES_TR_KSPConverged_Ctx;
9971273eeSBarry Smith 
104a221d59SStefano Zampini const char *const SNESNewtonTRFallbackTypes[] = {"NEWTON", "CAUCHY", "DOGLEG", "SNESNewtonTRFallbackType", "SNES_TR_FALLBACK_", NULL};
1124fb275aSStefano Zampini const char *const SNESNewtonTRQNTypes[]       = {"NONE", "SAME", "DIFFERENT", "SNESNewtonTRQNType", "SNES_TR_QN_", NULL};
1224fb275aSStefano Zampini 
1324fb275aSStefano Zampini static PetscErrorCode SNESComputeJacobian_MATLMVM(SNES snes, Vec X, Mat J, Mat B, void *dummy)
1424fb275aSStefano Zampini {
1524fb275aSStefano Zampini   PetscFunctionBegin;
1624fb275aSStefano Zampini   // PetscCall(MatLMVMSymBroydenSetDelta(B, _some_delta));
1724fb275aSStefano Zampini   PetscCall(MatLMVMUpdate(B, X, snes->vec_func));
1824fb275aSStefano Zampini   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1924fb275aSStefano Zampini   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2024fb275aSStefano Zampini   if (J != B) {
2124fb275aSStefano Zampini     // PetscCall(MatLMVMSymBroydenSetDelta(J, _some_delta));
2224fb275aSStefano Zampini     PetscCall(MatLMVMUpdate(J, X, snes->vec_func));
2324fb275aSStefano Zampini     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2424fb275aSStefano Zampini     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
2524fb275aSStefano Zampini   }
2624fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2724fb275aSStefano Zampini }
284a221d59SStefano Zampini 
29d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTR_KSPConverged_Private(KSP ksp, PetscInt n, PetscReal rnorm, KSPConvergedReason *reason, void *cctx)
30d71ae5a4SJacob Faibussowitsch {
31971273eeSBarry Smith   SNES_TR_KSPConverged_Ctx *ctx  = (SNES_TR_KSPConverged_Ctx *)cctx;
32971273eeSBarry Smith   SNES                      snes = ctx->snes;
3304d7464bSBarry Smith   SNES_NEWTONTR            *neP  = (SNES_NEWTONTR *)snes->data;
34df60cc22SBarry Smith   Vec                       x;
35064f8208SBarry Smith   PetscReal                 nrm;
36df60cc22SBarry Smith 
373a40ed3dSBarry Smith   PetscFunctionBegin;
389566063dSJacob Faibussowitsch   PetscCall((*ctx->convtest)(ksp, n, rnorm, reason, ctx->convctx));
3948a46eb9SPierre Jolivet   if (*reason) PetscCall(PetscInfo(snes, "Default or user provided convergence test KSP iterations=%" PetscInt_FMT ", rnorm=%g\n", n, (double)rnorm));
40a935fc98SLois Curfman McInnes   /* Determine norm of solution */
419566063dSJacob Faibussowitsch   PetscCall(KSPBuildSolution(ksp, NULL, &x));
4224fb275aSStefano Zampini   PetscCall(VecNorm(x, neP->norm, &nrm));
43064f8208SBarry Smith   if (nrm >= neP->delta) {
449566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Ending linear iteration early, delta=%g, length=%g\n", (double)neP->delta, (double)nrm));
45329f5518SBarry Smith     *reason = KSP_CONVERGED_STEP_LENGTH;
46df60cc22SBarry Smith   }
473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48df60cc22SBarry Smith }
4982bf6240SBarry Smith 
50d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTR_KSPConverged_Destroy(void *cctx)
51d71ae5a4SJacob Faibussowitsch {
52971273eeSBarry Smith   SNES_TR_KSPConverged_Ctx *ctx = (SNES_TR_KSPConverged_Ctx *)cctx;
53971273eeSBarry Smith 
54971273eeSBarry Smith   PetscFunctionBegin;
559566063dSJacob Faibussowitsch   PetscCall((*ctx->convdestroy)(ctx->convctx));
569566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58971273eeSBarry Smith }
59971273eeSBarry Smith 
60d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTR_Converged_Private(SNES snes, PetscInt it, PetscReal xnorm, PetscReal pnorm, PetscReal fnorm, SNESConvergedReason *reason, void *dummy)
61d71ae5a4SJacob Faibussowitsch {
6204d7464bSBarry Smith   SNES_NEWTONTR *neP = (SNES_NEWTONTR *)snes->data;
6385385478SLisandro Dalcin 
6485385478SLisandro Dalcin   PetscFunctionBegin;
6585385478SLisandro Dalcin   *reason = SNES_CONVERGED_ITERATING;
664a221d59SStefano Zampini   if (neP->delta < snes->deltatol) {
674a221d59SStefano Zampini     PetscCall(PetscInfo(snes, "Diverged due to too small a trust region %g<%g\n", (double)neP->delta, (double)snes->deltatol));
681c6b2ff8SBarry Smith     *reason = SNES_DIVERGED_TR_DELTA;
69e71169deSBarry Smith   } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
7063a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Exceeded maximum number of function evaluations: %" PetscInt_FMT "\n", snes->max_funcs));
7185385478SLisandro Dalcin     *reason = SNES_DIVERGED_FUNCTION_COUNT;
7285385478SLisandro Dalcin   }
733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7485385478SLisandro Dalcin }
7585385478SLisandro Dalcin 
764a221d59SStefano Zampini /*@
7724fb275aSStefano Zampini   SNESNewtonTRSetNormType - Specify the type of norm to use for the computation of the trust region.
7824fb275aSStefano Zampini 
7924fb275aSStefano Zampini   Input Parameters:
8024fb275aSStefano Zampini + snes - the nonlinear solver object
8124fb275aSStefano Zampini - norm - the norm type
8224fb275aSStefano Zampini 
8324fb275aSStefano Zampini   Level: intermediate
8424fb275aSStefano Zampini 
8524fb275aSStefano Zampini .seealso: `SNESNEWTONTR`, `NormType`
8624fb275aSStefano Zampini @*/
8724fb275aSStefano Zampini PetscErrorCode SNESNewtonTRSetNormType(SNES snes, NormType norm)
8824fb275aSStefano Zampini {
8924fb275aSStefano Zampini   PetscBool flg;
9024fb275aSStefano Zampini 
9124fb275aSStefano Zampini   PetscFunctionBegin;
9224fb275aSStefano Zampini   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
9324fb275aSStefano Zampini   PetscValidLogicalCollectiveEnum(snes, norm, 2);
9424fb275aSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
9524fb275aSStefano Zampini   if (flg) {
9624fb275aSStefano Zampini     SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
9724fb275aSStefano Zampini 
9824fb275aSStefano Zampini     tr->norm = norm;
9924fb275aSStefano Zampini   }
10024fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
10124fb275aSStefano Zampini }
10224fb275aSStefano Zampini 
10324fb275aSStefano Zampini /*@
10424fb275aSStefano Zampini   SNESNewtonTRSetQNType - Specify to use a quasi-Newton model.
10524fb275aSStefano Zampini 
10624fb275aSStefano Zampini   Input Parameters:
10724fb275aSStefano Zampini + snes - the nonlinear solver object
10824fb275aSStefano Zampini - use  - the type of approximations to be used
10924fb275aSStefano Zampini 
11024fb275aSStefano Zampini   Level: intermediate
11124fb275aSStefano Zampini 
11224fb275aSStefano Zampini   Notes:
11324fb275aSStefano Zampini   Options for the approximations can be set with the snes_tr_qn_ and snes_tr_qn_pre_ prefixes.
11424fb275aSStefano Zampini 
11524fb275aSStefano Zampini .seealso: `SNESNEWTONTR`, `SNESNewtonTRQNType`, `MATLMVM`
11624fb275aSStefano Zampini @*/
11724fb275aSStefano Zampini PetscErrorCode SNESNewtonTRSetQNType(SNES snes, SNESNewtonTRQNType use)
11824fb275aSStefano Zampini {
11924fb275aSStefano Zampini   PetscBool flg;
12024fb275aSStefano Zampini 
12124fb275aSStefano Zampini   PetscFunctionBegin;
12224fb275aSStefano Zampini   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
12324fb275aSStefano Zampini   PetscValidLogicalCollectiveEnum(snes, use, 2);
12424fb275aSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
12524fb275aSStefano Zampini   if (flg) {
12624fb275aSStefano Zampini     SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
12724fb275aSStefano Zampini 
12824fb275aSStefano Zampini     tr->qn = use;
12924fb275aSStefano Zampini   }
13024fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
13124fb275aSStefano Zampini }
13224fb275aSStefano Zampini 
13324fb275aSStefano Zampini /*@
134420bcc1bSBarry Smith   SNESNewtonTRSetFallbackType - Set the type of fallback to use if the solution of the trust region subproblem is outside the radius
1354a221d59SStefano Zampini 
1364a221d59SStefano Zampini   Input Parameters:
1374a221d59SStefano Zampini + snes  - the nonlinear solver object
1384a221d59SStefano Zampini - ftype - the fallback type, see `SNESNewtonTRFallbackType`
1394a221d59SStefano Zampini 
1404a221d59SStefano Zampini   Level: intermediate
1414a221d59SStefano Zampini 
142420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRPreCheck()`, `SNESNewtonTRGetPreCheck()`, `SNESNewtonTRSetPreCheck()`,
1434a221d59SStefano Zampini           `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRGetPostCheck()`
1444a221d59SStefano Zampini @*/
1454a221d59SStefano Zampini PetscErrorCode SNESNewtonTRSetFallbackType(SNES snes, SNESNewtonTRFallbackType ftype)
1464a221d59SStefano Zampini {
1474a221d59SStefano Zampini   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
1484a221d59SStefano Zampini   PetscBool      flg;
1494a221d59SStefano Zampini 
1504a221d59SStefano Zampini   PetscFunctionBegin;
1514a221d59SStefano Zampini   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1524a221d59SStefano Zampini   PetscValidLogicalCollectiveEnum(snes, ftype, 2);
1534a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
1544a221d59SStefano Zampini   if (flg) tr->fallback = ftype;
1554a221d59SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1564a221d59SStefano Zampini }
1574a221d59SStefano Zampini 
1587cb011f5SBarry Smith /*@C
159c9368356SGlenn Hammond   SNESNewtonTRSetPreCheck - Sets a user function that is called before the search step has been determined.
1604a221d59SStefano Zampini   Allows the user a chance to change or override the trust region decision.
161f6dfbefdSBarry Smith 
162c3339decSBarry Smith   Logically Collective
163c9368356SGlenn Hammond 
164c9368356SGlenn Hammond   Input Parameters:
165c9368356SGlenn Hammond + snes - the nonlinear solver object
16620f4b53cSBarry Smith . func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRPreCheck()`
16720f4b53cSBarry Smith - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
168c9368356SGlenn Hammond 
169*acba1f63SStefano Zampini   Level: intermediate
170c9368356SGlenn Hammond 
171f6dfbefdSBarry Smith   Note:
1724a221d59SStefano Zampini   This function is called BEFORE the function evaluation within the solver.
173c9368356SGlenn Hammond 
174420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRPreCheck()`, `SNESNewtonTRGetPreCheck()`, `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRGetPostCheck()`,
175c9368356SGlenn Hammond @*/
176d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRSetPreCheck(SNES snes, PetscErrorCode (*func)(SNES, Vec, Vec, PetscBool *, void *), void *ctx)
177d71ae5a4SJacob Faibussowitsch {
178c9368356SGlenn Hammond   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
1794a221d59SStefano Zampini   PetscBool      flg;
180c9368356SGlenn Hammond 
181c9368356SGlenn Hammond   PetscFunctionBegin;
182c9368356SGlenn Hammond   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1834a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
1844a221d59SStefano Zampini   if (flg) {
185c9368356SGlenn Hammond     if (func) tr->precheck = func;
186c9368356SGlenn Hammond     if (ctx) tr->precheckctx = ctx;
1874a221d59SStefano Zampini   }
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
189c9368356SGlenn Hammond }
190c9368356SGlenn Hammond 
191c9368356SGlenn Hammond /*@C
192c9368356SGlenn Hammond   SNESNewtonTRGetPreCheck - Gets the pre-check function
193c9368356SGlenn Hammond 
19420f4b53cSBarry Smith   Not Collective
195c9368356SGlenn Hammond 
196c9368356SGlenn Hammond   Input Parameter:
197c9368356SGlenn Hammond . snes - the nonlinear solver context
198c9368356SGlenn Hammond 
199c9368356SGlenn Hammond   Output Parameters:
20020f4b53cSBarry Smith + func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRPreCheck()`
20120f4b53cSBarry Smith - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
202c9368356SGlenn Hammond 
203*acba1f63SStefano Zampini   Level: intermediate
204c9368356SGlenn Hammond 
205420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRPreCheck()`
206c9368356SGlenn Hammond @*/
207d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRGetPreCheck(SNES snes, PetscErrorCode (**func)(SNES, Vec, Vec, PetscBool *, void *), void **ctx)
208d71ae5a4SJacob Faibussowitsch {
209c9368356SGlenn Hammond   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
2104a221d59SStefano Zampini   PetscBool      flg;
211c9368356SGlenn Hammond 
212c9368356SGlenn Hammond   PetscFunctionBegin;
213c9368356SGlenn Hammond   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2144a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
2154a221d59SStefano Zampini   PetscAssert(flg, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Not for type %s", ((PetscObject)snes)->type_name);
216c9368356SGlenn Hammond   if (func) *func = tr->precheck;
217c9368356SGlenn Hammond   if (ctx) *ctx = tr->precheckctx;
2183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
219c9368356SGlenn Hammond }
220c9368356SGlenn Hammond 
221c9368356SGlenn Hammond /*@C
2227cb011f5SBarry Smith   SNESNewtonTRSetPostCheck - Sets a user function that is called after the search step has been determined but before the next
2234a221d59SStefano Zampini   function evaluation. Allows the user a chance to change or override the internal decision of the solver
224f6dfbefdSBarry Smith 
225c3339decSBarry Smith   Logically Collective
2267cb011f5SBarry Smith 
2277cb011f5SBarry Smith   Input Parameters:
2287cb011f5SBarry Smith + snes - the nonlinear solver object
22920f4b53cSBarry Smith . func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRPostCheck()`
23020f4b53cSBarry Smith - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
2317cb011f5SBarry Smith 
232*acba1f63SStefano Zampini   Level: intermediate
2337cb011f5SBarry Smith 
234f6dfbefdSBarry Smith   Note:
2354a221d59SStefano Zampini   This function is called BEFORE the function evaluation within the solver while the function set in
236f6dfbefdSBarry Smith   `SNESLineSearchSetPostCheck()` is called AFTER the function evaluation.
2377cb011f5SBarry Smith 
238420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRPostCheck()`, `SNESNewtonTRGetPostCheck()`, `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRGetPreCheck()`
2397cb011f5SBarry Smith @*/
240d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRSetPostCheck(SNES snes, PetscErrorCode (*func)(SNES, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void *ctx)
241d71ae5a4SJacob Faibussowitsch {
2427cb011f5SBarry Smith   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
2434a221d59SStefano Zampini   PetscBool      flg;
2447cb011f5SBarry Smith 
2457cb011f5SBarry Smith   PetscFunctionBegin;
2467cb011f5SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2474a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
2484a221d59SStefano Zampini   if (flg) {
2497cb011f5SBarry Smith     if (func) tr->postcheck = func;
2507cb011f5SBarry Smith     if (ctx) tr->postcheckctx = ctx;
2514a221d59SStefano Zampini   }
2523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2537cb011f5SBarry Smith }
2547cb011f5SBarry Smith 
2557cb011f5SBarry Smith /*@C
2567cb011f5SBarry Smith   SNESNewtonTRGetPostCheck - Gets the post-check function
2577cb011f5SBarry Smith 
25820f4b53cSBarry Smith   Not Collective
2597cb011f5SBarry Smith 
2607cb011f5SBarry Smith   Input Parameter:
2617cb011f5SBarry Smith . snes - the nonlinear solver context
2627cb011f5SBarry Smith 
2637cb011f5SBarry Smith   Output Parameters:
26420f4b53cSBarry Smith + func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRPostCheck()`
26520f4b53cSBarry Smith - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
2667cb011f5SBarry Smith 
2677cb011f5SBarry Smith   Level: intermediate
2687cb011f5SBarry Smith 
269420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRPostCheck()`
2707cb011f5SBarry Smith @*/
271d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRGetPostCheck(SNES snes, PetscErrorCode (**func)(SNES, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx)
272d71ae5a4SJacob Faibussowitsch {
2737cb011f5SBarry Smith   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
2744a221d59SStefano Zampini   PetscBool      flg;
2757cb011f5SBarry Smith 
2767cb011f5SBarry Smith   PetscFunctionBegin;
2777cb011f5SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2784a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
2794a221d59SStefano Zampini   PetscAssert(flg, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Not for type %s", ((PetscObject)snes)->type_name);
2807cb011f5SBarry Smith   if (func) *func = tr->postcheck;
2817cb011f5SBarry Smith   if (ctx) *ctx = tr->postcheckctx;
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2837cb011f5SBarry Smith }
2847cb011f5SBarry Smith 
2857cb011f5SBarry Smith /*@C
2864a221d59SStefano Zampini   SNESNewtonTRPreCheck - Runs the precheck routine
287c9368356SGlenn Hammond 
288c3339decSBarry Smith   Logically Collective
289c9368356SGlenn Hammond 
290c9368356SGlenn Hammond   Input Parameters:
291c9368356SGlenn Hammond + snes - the solver
292c9368356SGlenn Hammond . X    - The last solution
293c9368356SGlenn Hammond - Y    - The step direction
294c9368356SGlenn Hammond 
2952fe279fdSBarry Smith   Output Parameter:
2962fe279fdSBarry Smith . changed_Y - Indicator that the step direction `Y` has been changed.
297c9368356SGlenn Hammond 
2984a221d59SStefano Zampini   Level: intermediate
299c9368356SGlenn Hammond 
300420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRGetPreCheck()`, `SNESNewtonTRPostCheck()`
301c9368356SGlenn Hammond @*/
3024a221d59SStefano Zampini PetscErrorCode SNESNewtonTRPreCheck(SNES snes, Vec X, Vec Y, PetscBool *changed_Y)
303d71ae5a4SJacob Faibussowitsch {
304c9368356SGlenn Hammond   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
3054a221d59SStefano Zampini   PetscBool      flg;
306c9368356SGlenn Hammond 
307c9368356SGlenn Hammond   PetscFunctionBegin;
3084a221d59SStefano Zampini   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3094a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
3104a221d59SStefano Zampini   PetscAssert(flg, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Not for type %s", ((PetscObject)snes)->type_name);
311c9368356SGlenn Hammond   *changed_Y = PETSC_FALSE;
312c9368356SGlenn Hammond   if (tr->precheck) {
3139566063dSJacob Faibussowitsch     PetscCall((*tr->precheck)(snes, X, Y, changed_Y, tr->precheckctx));
314c9368356SGlenn Hammond     PetscValidLogicalCollectiveBool(snes, *changed_Y, 4);
315c9368356SGlenn Hammond   }
3163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
317c9368356SGlenn Hammond }
318c9368356SGlenn Hammond 
319c9368356SGlenn Hammond /*@C
3204a221d59SStefano Zampini   SNESNewtonTRPostCheck - Runs the postcheck routine
3217cb011f5SBarry Smith 
322c3339decSBarry Smith   Logically Collective
3237cb011f5SBarry Smith 
3247cb011f5SBarry Smith   Input Parameters:
3256b867d5aSJose E. Roman + snes - the solver
3266b867d5aSJose E. Roman . X    - The last solution
3277cb011f5SBarry Smith . Y    - The full step direction
3283312a946SBarry Smith - W    - The updated solution, W = X - Y
3297cb011f5SBarry Smith 
3307cb011f5SBarry Smith   Output Parameters:
3313312a946SBarry Smith + changed_Y - indicator if step has been changed
3323312a946SBarry Smith - changed_W - Indicator if the new candidate solution W has been changed.
3337cb011f5SBarry Smith 
334f6dfbefdSBarry Smith   Note:
3353312a946SBarry Smith   If Y is changed then W is recomputed as X - Y
3367cb011f5SBarry Smith 
3374a221d59SStefano Zampini   Level: intermediate
3387cb011f5SBarry Smith 
339420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESNEWTONTR`, `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRGetPostCheck()`, `SNESNewtonTRPreCheck()`
3407cb011f5SBarry Smith @*/
3414a221d59SStefano Zampini PetscErrorCode SNESNewtonTRPostCheck(SNES snes, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W)
342d71ae5a4SJacob Faibussowitsch {
3437cb011f5SBarry Smith   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
3444a221d59SStefano Zampini   PetscBool      flg;
3457cb011f5SBarry Smith 
3467cb011f5SBarry Smith   PetscFunctionBegin;
3474a221d59SStefano Zampini   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3484a221d59SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
3494a221d59SStefano Zampini   PetscAssert(flg, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Not for type %s", ((PetscObject)snes)->type_name);
350c9368356SGlenn Hammond   *changed_Y = PETSC_FALSE;
3517cb011f5SBarry Smith   *changed_W = PETSC_FALSE;
3527cb011f5SBarry Smith   if (tr->postcheck) {
3539566063dSJacob Faibussowitsch     PetscCall((*tr->postcheck)(snes, X, Y, W, changed_Y, changed_W, tr->postcheckctx));
354c9368356SGlenn Hammond     PetscValidLogicalCollectiveBool(snes, *changed_Y, 5);
3557cb011f5SBarry Smith     PetscValidLogicalCollectiveBool(snes, *changed_W, 6);
3567cb011f5SBarry Smith   }
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3587cb011f5SBarry Smith }
35985385478SLisandro Dalcin 
36024fb275aSStefano Zampini /* stable implementation of roots of a*x^2 + b*x + c = 0 */
3614a221d59SStefano Zampini static inline void PetscQuadraticRoots(PetscReal a, PetscReal b, PetscReal c, PetscReal *xm, PetscReal *xp)
3624a221d59SStefano Zampini {
3634a221d59SStefano Zampini   PetscReal temp = -0.5 * (b + PetscCopysignReal(1.0, b) * PetscSqrtReal(b * b - 4 * a * c));
3644a221d59SStefano Zampini   PetscReal x1   = temp / a;
3654a221d59SStefano Zampini   PetscReal x2   = c / temp;
3664a221d59SStefano Zampini   *xm            = PetscMin(x1, x2);
3674a221d59SStefano Zampini   *xp            = PetscMax(x1, x2);
3684a221d59SStefano Zampini }
3694a221d59SStefano Zampini 
3707aa289d8SStefano Zampini /* Computes the quadratic model difference */
37124fb275aSStefano Zampini static PetscErrorCode SNESNewtonTRQuadraticDelta(SNES snes, Mat J, PetscBool has_objective, Vec Y, Vec GradF, Vec W, PetscReal *yTHy_, PetscReal *gTy_, PetscReal *deltaqm)
3727aa289d8SStefano Zampini {
37324fb275aSStefano Zampini   PetscReal yTHy, gTy;
37424fb275aSStefano Zampini 
3757aa289d8SStefano Zampini   PetscFunctionBegin;
37624fb275aSStefano Zampini   PetscCall(MatMult(J, Y, W));
37724fb275aSStefano Zampini   if (has_objective) PetscCall(VecDotRealPart(Y, W, &yTHy));
37824fb275aSStefano Zampini   else PetscCall(VecDotRealPart(W, W, &yTHy)); /* Gauss-Newton approximation J^t * J */
37924fb275aSStefano Zampini   PetscCall(VecDotRealPart(GradF, Y, &gTy));
38024fb275aSStefano Zampini   *deltaqm = -(-(gTy) + 0.5 * (yTHy)); /* difference in quadratic model, -gTy because SNES solves it this way */
38124fb275aSStefano Zampini   if (yTHy_) *yTHy_ = yTHy;
38224fb275aSStefano Zampini   if (gTy_) *gTy_ = gTy;
38324fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
38424fb275aSStefano Zampini }
38524fb275aSStefano Zampini 
38624fb275aSStefano Zampini /* Computes the new objective given X = Xk, Y = direction
38724fb275aSStefano Zampini    W work vector, on output W = X - Y
38824fb275aSStefano Zampini    G work vector, on output G = SNESFunction(W) */
38924fb275aSStefano Zampini static PetscErrorCode SNESNewtonTRObjective(SNES snes, PetscBool has_objective, Vec X, Vec Y, Vec W, Vec G, PetscReal *gnorm, PetscReal *fkp1)
39024fb275aSStefano Zampini {
39124fb275aSStefano Zampini   PetscBool changed_y, changed_w;
39224fb275aSStefano Zampini 
39324fb275aSStefano Zampini   PetscFunctionBegin;
39424fb275aSStefano Zampini   /* TODO: we can add a linesearch here */
39524fb275aSStefano Zampini   PetscCall(SNESNewtonTRPreCheck(snes, X, Y, &changed_y));
39624fb275aSStefano Zampini   PetscCall(VecWAXPY(W, -1.0, Y, X)); /* Xkp1 */
39724fb275aSStefano Zampini   PetscCall(SNESNewtonTRPostCheck(snes, X, Y, W, &changed_y, &changed_w));
39824fb275aSStefano Zampini   if (changed_y && !changed_w) PetscCall(VecWAXPY(W, -1.0, Y, X));
39924fb275aSStefano Zampini 
40024fb275aSStefano Zampini   PetscCall(SNESComputeFunction(snes, W, G)); /*  F(Xkp1) = G */
40124fb275aSStefano Zampini   PetscCall(VecNorm(G, NORM_2, gnorm));
40224fb275aSStefano Zampini   if (has_objective) PetscCall(SNESComputeObjective(snes, W, fkp1));
40324fb275aSStefano Zampini   else *fkp1 = 0.5 * PetscSqr(*gnorm);
40424fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
40524fb275aSStefano Zampini }
40624fb275aSStefano Zampini 
40724fb275aSStefano Zampini static PetscErrorCode SNESSetUpQN_NEWTONTR(SNES snes)
40824fb275aSStefano Zampini {
40924fb275aSStefano Zampini   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
41024fb275aSStefano Zampini 
41124fb275aSStefano Zampini   PetscFunctionBegin;
41224fb275aSStefano Zampini   PetscCall(MatDestroy(&tr->qnB));
41324fb275aSStefano Zampini   PetscCall(MatDestroy(&tr->qnB_pre));
41424fb275aSStefano Zampini   if (tr->qn) {
41524fb275aSStefano Zampini     PetscInt    n, N;
41624fb275aSStefano Zampini     const char *optionsprefix;
41724fb275aSStefano Zampini     Mat         B;
41824fb275aSStefano Zampini 
41924fb275aSStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)snes), &B));
42024fb275aSStefano Zampini     PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
42124fb275aSStefano Zampini     PetscCall(MatSetOptionsPrefix(B, "snes_tr_qn_"));
42224fb275aSStefano Zampini     PetscCall(MatAppendOptionsPrefix(B, optionsprefix));
42324fb275aSStefano Zampini     PetscCall(MatSetType(B, MATLMVMBFGS));
42424fb275aSStefano Zampini     PetscCall(VecGetLocalSize(snes->vec_sol, &n));
42524fb275aSStefano Zampini     PetscCall(VecGetSize(snes->vec_sol, &N));
42624fb275aSStefano Zampini     PetscCall(MatSetSizes(B, n, n, N, N));
42724fb275aSStefano Zampini     PetscCall(MatSetUp(B));
42824fb275aSStefano Zampini     PetscCall(MatSetFromOptions(B));
42924fb275aSStefano Zampini     PetscCall(MatLMVMAllocate(B, snes->vec_sol, snes->vec_func));
43024fb275aSStefano Zampini     tr->qnB = B;
43124fb275aSStefano Zampini     if (tr->qn == SNES_TR_QN_DIFFERENT) {
43224fb275aSStefano Zampini       PetscCall(MatCreate(PetscObjectComm((PetscObject)snes), &B));
43324fb275aSStefano Zampini       PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
43424fb275aSStefano Zampini       PetscCall(MatSetOptionsPrefix(B, "snes_tr_qn_pre_"));
43524fb275aSStefano Zampini       PetscCall(MatAppendOptionsPrefix(B, optionsprefix));
43624fb275aSStefano Zampini       PetscCall(MatSetType(B, MATLMVMBFGS));
43724fb275aSStefano Zampini       PetscCall(MatSetSizes(B, n, n, N, N));
43824fb275aSStefano Zampini       PetscCall(MatSetUp(B));
43924fb275aSStefano Zampini       PetscCall(MatSetFromOptions(B));
44024fb275aSStefano Zampini       PetscCall(MatLMVMAllocate(B, snes->vec_sol, snes->vec_func));
44124fb275aSStefano Zampini       tr->qnB_pre = B;
44224fb275aSStefano Zampini     } else {
44324fb275aSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)tr->qnB));
44424fb275aSStefano Zampini       tr->qnB_pre = tr->qnB;
44524fb275aSStefano Zampini     }
44624fb275aSStefano Zampini   }
4477aa289d8SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
4487aa289d8SStefano Zampini }
4497aa289d8SStefano Zampini 
450df60cc22SBarry Smith /*
4514a221d59SStefano Zampini    SNESSolve_NEWTONTR - Implements Newton's Method with trust-region subproblem and adds dogleg Cauchy
4524a221d59SStefano Zampini    (Steepest Descent direction) step and direction if the trust region is not satisfied for solving system of
4534a221d59SStefano Zampini    nonlinear equations
4544800dd8cSBarry Smith 
4554800dd8cSBarry Smith */
456d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSolve_NEWTONTR(SNES snes)
457d71ae5a4SJacob Faibussowitsch {
45804d7464bSBarry Smith   SNES_NEWTONTR            *neP = (SNES_NEWTONTR *)snes->data;
45924fb275aSStefano Zampini   Vec                       X, F, Y, G, W, GradF, YU, Yc;
4604a221d59SStefano Zampini   PetscInt                  maxits, lits;
4614b0a5c37SStefano Zampini   PetscReal                 rho, fnorm, gnorm = 0.0, xnorm = 0.0, delta, ynorm;
46224fb275aSStefano Zampini   PetscReal                 deltaM, fk, fkp1, deltaqm = 0.0, gTy = 0.0, yTHy = 0.0;
46324fb275aSStefano Zampini   PetscReal                 auk, tauk, gfnorm, gfnorm_k, ycnorm, gTBg, objmin = 0.0, beta_k = 1.0;
464a0254a93SStefano Zampini   PC                        pc;
46524fb275aSStefano Zampini   Mat                       J, Jp;
46624fb275aSStefano Zampini   PetscBool                 already_done = PETSC_FALSE, on_boundary;
4677aa289d8SStefano Zampini   PetscBool                 clear_converged_test, rho_satisfied, has_objective;
468df8705c3SBarry Smith   SNES_TR_KSPConverged_Ctx *ctx;
4695e28bcb6Sprj-   void                     *convctx;
47024fb275aSStefano Zampini 
4714a221d59SStefano Zampini   PetscErrorCode (*convtest)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *), (*convdestroy)(void *);
4724a221d59SStefano Zampini   PetscErrorCode (*objective)(SNES, Vec, PetscReal *, void *);
4734800dd8cSBarry Smith 
4743a40ed3dSBarry Smith   PetscFunctionBegin;
4754a221d59SStefano Zampini   PetscCall(SNESGetObjective(snes, &objective, NULL));
4767aa289d8SStefano Zampini   has_objective = objective ? PETSC_TRUE : PETSC_FALSE;
477c579b300SPatrick Farrell 
478fbe28522SBarry Smith   maxits = snes->max_its;                                   /* maximum number of iterations */
479fbe28522SBarry Smith   X      = snes->vec_sol;                                   /* solution vector */
48039e2f89bSBarry Smith   F      = snes->vec_func;                                  /* residual vector */
4814a221d59SStefano Zampini   Y      = snes->vec_sol_update;                            /* update vector */
4824a221d59SStefano Zampini   G      = snes->work[0];                                   /* updated residual */
4834a221d59SStefano Zampini   W      = snes->work[1];                                   /* temporary vector */
4847aa289d8SStefano Zampini   GradF  = !has_objective ? snes->work[2] : snes->vec_func; /* grad f = J^T F */
4854a221d59SStefano Zampini   YU     = snes->work[3];                                   /* work vector for dogleg method */
48624fb275aSStefano Zampini   Yc     = snes->work[4];                                   /* Cauchy point */
4874a221d59SStefano Zampini 
4884a221d59SStefano Zampini   PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
4894800dd8cSBarry Smith 
4909566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
4914c49b128SBarry Smith   snes->iter = 0;
4929566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
4934800dd8cSBarry Smith 
49424fb275aSStefano Zampini   /* setup QN matrices if needed */
49524fb275aSStefano Zampini   PetscCall(SNESSetUpQN_NEWTONTR(snes));
49624fb275aSStefano Zampini 
4974a221d59SStefano Zampini   /* Set the linear stopping criteria to use the More' trick if needed */
4984a221d59SStefano Zampini   clear_converged_test = PETSC_FALSE;
499a0254a93SStefano Zampini   PetscCall(SNESGetKSP(snes, &snes->ksp));
500a0254a93SStefano Zampini   PetscCall(KSPGetConvergenceTest(snes->ksp, &convtest, &convctx, &convdestroy));
501fcc61681SStefano Zampini   if (convtest != SNESTR_KSPConverged_Private) {
5024a221d59SStefano Zampini     clear_converged_test = PETSC_TRUE;
5039566063dSJacob Faibussowitsch     PetscCall(PetscNew(&ctx));
504df8705c3SBarry Smith     ctx->snes = snes;
505a0254a93SStefano Zampini     PetscCall(KSPGetAndClearConvergenceTest(snes->ksp, &ctx->convtest, &ctx->convctx, &ctx->convdestroy));
506a0254a93SStefano Zampini     PetscCall(KSPSetConvergenceTest(snes->ksp, SNESTR_KSPConverged_Private, ctx, SNESTR_KSPConverged_Destroy));
5079566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Using Krylov convergence test SNESTR_KSPConverged_Private\n"));
508df8705c3SBarry Smith   }
509df8705c3SBarry Smith 
510e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
5119566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, X, F)); /* F(X) */
5121aa26658SKarl Rupp   } else snes->vec_func_init_set = PETSC_FALSE;
513e4ed7901SPeter Brune 
5149566063dSJacob Faibussowitsch   PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- || F || */
515422a814eSBarry Smith   SNESCheckFunctionNorm(snes, fnorm);
5169566063dSJacob Faibussowitsch   PetscCall(VecNorm(X, NORM_2, &xnorm)); /* xnorm <- || X || */
5174a221d59SStefano Zampini 
5189566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
519fbe28522SBarry Smith   snes->norm = fnorm;
5209566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
5214a221d59SStefano Zampini   delta      = neP->delta0;
5224a221d59SStefano Zampini   deltaM     = neP->deltaM;
5234800dd8cSBarry Smith   neP->delta = delta;
5249566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
525b37302c6SLois Curfman McInnes 
52685385478SLisandro Dalcin   /* test convergence */
5274a221d59SStefano Zampini   rho_satisfied = PETSC_FALSE;
5282d157150SStefano Zampini   PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm));
5292d157150SStefano Zampini   PetscCall(SNESMonitor(snes, 0, fnorm));
5303ba16761SJacob Faibussowitsch   if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
5313f149594SLisandro Dalcin 
5327aa289d8SStefano Zampini   if (has_objective) PetscCall(SNESComputeObjective(snes, X, &fk));
5334a221d59SStefano Zampini   else fk = 0.5 * PetscSqr(fnorm); /* obj(x) = 0.5 * ||F(x)||^2 */
53499a96b7cSMatthew Knepley 
535a0254a93SStefano Zampini   /* hook state vector to BFGS preconditioner */
536a0254a93SStefano Zampini   PetscCall(KSPGetPC(snes->ksp, &pc));
537a0254a93SStefano Zampini   PetscCall(PCLMVMSetUpdateVec(pc, X));
538a0254a93SStefano Zampini 
53924fb275aSStefano Zampini   if (neP->kmdc) PetscCall(KSPSetComputeEigenvalues(snes->ksp, PETSC_TRUE));
5406b5873e3SBarry Smith 
54124fb275aSStefano Zampini   while (snes->iter < maxits) {
54212d0050eSStefano Zampini     /* calculating Jacobian and GradF of minimization function only once */
5434a221d59SStefano Zampini     if (!already_done) {
54412d0050eSStefano Zampini       /* Call general purpose update function */
54512d0050eSStefano Zampini       PetscTryTypeMethod(snes, update, snes->iter);
54612d0050eSStefano Zampini 
5474b0a5c37SStefano Zampini       /* apply the nonlinear preconditioner */
5484b0a5c37SStefano Zampini       if (snes->npc && snes->npcside == PC_RIGHT) {
5494b0a5c37SStefano Zampini         SNESConvergedReason reason;
5504b0a5c37SStefano Zampini 
5514b0a5c37SStefano Zampini         PetscCall(SNESSetInitialFunction(snes->npc, F));
5524b0a5c37SStefano Zampini         PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, X, snes->vec_rhs, 0));
5534b0a5c37SStefano Zampini         PetscCall(SNESSolve(snes->npc, snes->vec_rhs, X));
5544b0a5c37SStefano Zampini         PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, X, snes->vec_rhs, 0));
5554b0a5c37SStefano Zampini         PetscCall(SNESGetConvergedReason(snes->npc, &reason));
5564b0a5c37SStefano Zampini         if (reason < 0 && reason != SNES_DIVERGED_MAX_IT && reason != SNES_DIVERGED_TR_DELTA) {
5574b0a5c37SStefano Zampini           snes->reason = SNES_DIVERGED_INNER;
5584b0a5c37SStefano Zampini           PetscFunctionReturn(PETSC_SUCCESS);
5594b0a5c37SStefano Zampini         }
5604b0a5c37SStefano Zampini         // XXX
5614b0a5c37SStefano Zampini         PetscCall(SNESGetNPCFunction(snes, F, &fnorm));
5624b0a5c37SStefano Zampini       } else if (snes->ops->update) { /* if update is present, recompute objective function and function norm */
56312d0050eSStefano Zampini         PetscCall(SNESComputeFunction(snes, X, F));
56412d0050eSStefano Zampini       }
56512d0050eSStefano Zampini 
56612d0050eSStefano Zampini       /* Jacobian */
56724fb275aSStefano Zampini       J  = NULL;
56824fb275aSStefano Zampini       Jp = NULL;
56924fb275aSStefano Zampini       if (!neP->qnB) {
5704a221d59SStefano Zampini         PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
57124fb275aSStefano Zampini         J  = snes->jacobian;
57224fb275aSStefano Zampini         Jp = snes->jacobian_pre;
57324fb275aSStefano Zampini       } else { /* QN model */
57424fb275aSStefano Zampini         PetscCall(SNESComputeJacobian_MATLMVM(snes, X, neP->qnB, neP->qnB_pre, NULL));
57524fb275aSStefano Zampini         J  = neP->qnB;
57624fb275aSStefano Zampini         Jp = neP->qnB_pre;
57724fb275aSStefano Zampini       }
5784a221d59SStefano Zampini       SNESCheckJacobianDomainerror(snes);
57912d0050eSStefano Zampini 
58024fb275aSStefano Zampini       /* objective function */
58124fb275aSStefano Zampini       PetscCall(VecNorm(F, NORM_2, &fnorm));
58224fb275aSStefano Zampini       if (has_objective) PetscCall(SNESComputeObjective(snes, X, &fk));
58324fb275aSStefano Zampini       else fk = 0.5 * PetscSqr(fnorm); /* obj(x) = 0.5 * ||F(x)||^2 */
58424fb275aSStefano Zampini 
58512d0050eSStefano Zampini       /* GradF */
5867aa289d8SStefano Zampini       if (has_objective) gfnorm = fnorm;
5877aa289d8SStefano Zampini       else {
58824fb275aSStefano Zampini         PetscCall(MatMultTranspose(J, F, GradF)); /* grad f = J^T F */
5897aa289d8SStefano Zampini         PetscCall(VecNorm(GradF, NORM_2, &gfnorm));
590fbe28522SBarry Smith       }
59124fb275aSStefano Zampini       PetscCall(VecNorm(GradF, neP->norm, &gfnorm_k));
5927aa289d8SStefano Zampini     }
5937aa289d8SStefano Zampini     already_done = PETSC_TRUE;
5947aa289d8SStefano Zampini 
5954b0a5c37SStefano Zampini     /* solve trust-region subproblem */
5964b0a5c37SStefano Zampini 
59724fb275aSStefano Zampini     /* first compute Cauchy Point */
59824fb275aSStefano Zampini     PetscCall(MatMult(J, GradF, W));
59924fb275aSStefano Zampini     if (has_objective) PetscCall(VecDotRealPart(GradF, W, &gTBg));
60024fb275aSStefano Zampini     else PetscCall(VecDotRealPart(W, W, &gTBg)); /* B = J^t * J */
60124fb275aSStefano Zampini     /* Eqs 4.11 and 4.12 in Nocedal and Wright 2nd Edition (4.7 and 4.8 in 1st Edition) */
60224fb275aSStefano Zampini     auk = delta / gfnorm_k;
60324fb275aSStefano Zampini     if (gTBg < 0.0) tauk = 1.0;
60424fb275aSStefano Zampini     else tauk = PetscMin(gfnorm * gfnorm * gfnorm_k / (delta * gTBg), 1);
60524fb275aSStefano Zampini     auk *= tauk;
60624fb275aSStefano Zampini     ycnorm = auk * gfnorm;
60724fb275aSStefano Zampini     PetscCall(VecAXPBY(Yc, auk, 0.0, GradF));
60824fb275aSStefano Zampini 
60924fb275aSStefano Zampini     on_boundary = PETSC_FALSE;
61024fb275aSStefano Zampini     if (tauk != 1.0) {
61124fb275aSStefano Zampini       KSPConvergedReason reason;
61224fb275aSStefano Zampini 
6134b0a5c37SStefano Zampini       /* sufficient decrease (see 6.3.27 in Conn, Gould, Toint "Trust Region Methods")
61424fb275aSStefano Zampini          beta_k the largest eigenvalue of the Hessian. Here we use the previous estimated value */
61524fb275aSStefano Zampini       objmin = -neP->kmdc * gnorm * PetscMin(gnorm / beta_k, delta);
616fb01098fSStefano Zampini       PetscCall(KSPCGSetObjectiveTarget(snes->ksp, objmin));
6174b0a5c37SStefano Zampini 
61824fb275aSStefano Zampini       /* specify radius if looking for Newton step and trust region norm is the l2 norm */
61924fb275aSStefano Zampini       PetscCall(KSPCGSetRadius(snes->ksp, neP->fallback == SNES_TR_FALLBACK_NEWTON && neP->norm == NORM_2 ? delta : 0.0));
62024fb275aSStefano Zampini       PetscCall(KSPSetOperators(snes->ksp, J, Jp));
6214a221d59SStefano Zampini       PetscCall(KSPSolve(snes->ksp, F, Y));
6224a221d59SStefano Zampini       SNESCheckKSPSolve(snes);
6234a221d59SStefano Zampini       PetscCall(KSPGetIterationNumber(snes->ksp, &lits));
62424fb275aSStefano Zampini       PetscCall(KSPGetConvergedReason(snes->ksp, &reason));
62524fb275aSStefano Zampini       on_boundary = (PetscBool)(reason == KSP_CONVERGED_STEP_LENGTH);
6264b0a5c37SStefano Zampini       PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits));
62724fb275aSStefano Zampini       if (neP->kmdc) { /* update estimated Hessian largest eigenvalue */
62824fb275aSStefano Zampini         PetscReal emax, emin;
62924fb275aSStefano Zampini         PetscCall(KSPComputeExtremeSingularValues(snes->ksp, &emax, &emin));
63024fb275aSStefano Zampini         if (emax > 0.0) beta_k = emax + 1;
63124fb275aSStefano Zampini       }
63224fb275aSStefano Zampini     } else { /* Cauchy point is on the boundary, accept it */
63324fb275aSStefano Zampini       on_boundary = PETSC_TRUE;
63424fb275aSStefano Zampini       PetscCall(VecCopy(Yc, Y));
63524fb275aSStefano Zampini       PetscCall(PetscInfo(snes, "CP evaluated on boundary. delta: %g, ycnorm: %g, gTBg: %g\n", (double)delta, (double)ycnorm, (double)gTBg));
63624fb275aSStefano Zampini     }
63724fb275aSStefano Zampini     PetscCall(VecNorm(Y, neP->norm, &ynorm));
6384800dd8cSBarry Smith 
6394a221d59SStefano Zampini     /* decide what to do when the update is outside of trust region */
6405ec2728bSStefano Zampini     if (ynorm > delta || ynorm == 0.0) {
6415ec2728bSStefano Zampini       SNESNewtonTRFallbackType fallback = ynorm > 0.0 ? neP->fallback : SNES_TR_FALLBACK_CAUCHY;
6425ec2728bSStefano Zampini 
64324fb275aSStefano Zampini       PetscCheck(neP->norm == NORM_2 || fallback != SNES_TR_FALLBACK_DOGLEG, PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "DOGLEG without l2 norm not implemented");
6445ec2728bSStefano Zampini       switch (fallback) {
6454a221d59SStefano Zampini       case SNES_TR_FALLBACK_NEWTON:
6464a221d59SStefano Zampini         auk = delta / ynorm;
6474a221d59SStefano Zampini         PetscCall(VecScale(Y, auk));
6484b0a5c37SStefano Zampini         PetscCall(PetscInfo(snes, "SN evaluated. delta: %g, ynorm: %g\n", (double)delta, (double)ynorm));
6494a221d59SStefano Zampini         break;
6504a221d59SStefano Zampini       case SNES_TR_FALLBACK_CAUCHY:
6514a221d59SStefano Zampini       case SNES_TR_FALLBACK_DOGLEG:
6525ec2728bSStefano Zampini         if (fallback == SNES_TR_FALLBACK_CAUCHY || gTBg <= 0.0) {
65324fb275aSStefano Zampini           PetscCall(VecCopy(Yc, Y));
6544a221d59SStefano Zampini           PetscCall(PetscInfo(snes, "CP evaluated. delta: %g, ynorm: %g, ycnorm: %g, gTBg: %g\n", (double)delta, (double)ynorm, (double)ycnorm, (double)gTBg));
6554a221d59SStefano Zampini         } else { /* take linear combination of Cauchy and Newton direction and step */
65624fb275aSStefano Zampini           auk = gfnorm * gfnorm / gTBg;
65724fb275aSStefano Zampini           if (gfnorm_k * auk >= delta) { /* first leg: Cauchy point outside of trust region */
65824fb275aSStefano Zampini             PetscCall(VecAXPBY(Y, delta / gfnorm_k, 0.0, GradF));
65924fb275aSStefano Zampini             PetscCall(PetscInfo(snes, "CP evaluated (outside region). delta: %g, ynorm: %g, ycnorm: %g\n", (double)delta, (double)ynorm, (double)ycnorm));
66024fb275aSStefano Zampini           } else { /* second leg */
6614a221d59SStefano Zampini             PetscReal c0, c1, c2, tau = 0.0, tpos, tneg;
6624a221d59SStefano Zampini             PetscBool noroots;
663284fb49fSHeeho Park 
66424fb275aSStefano Zampini             /* Find solutions of (Eq. 4.16 in Nocedal and Wright)
66524fb275aSStefano Zampini                  ||p_U + lambda * (p_B - p_U)||^2 - delta^2 = 0,
66624fb275aSStefano Zampini                where p_U  the Cauchy direction, p_B the Newton direction */
6674a221d59SStefano Zampini             PetscCall(VecAXPBY(YU, auk, 0.0, GradF));
6684a221d59SStefano Zampini             PetscCall(VecAXPY(Y, -1.0, YU));
6694a221d59SStefano Zampini             PetscCall(VecNorm(Y, NORM_2, &c0));
6704a221d59SStefano Zampini             PetscCall(VecDotRealPart(YU, Y, &c1));
6714a221d59SStefano Zampini             c0 = PetscSqr(c0);
6724a221d59SStefano Zampini             c2 = PetscSqr(ycnorm) - PetscSqr(delta);
67324fb275aSStefano Zampini             PetscQuadraticRoots(c0, 2 * c1, c2, &tneg, &tpos);
6744a221d59SStefano Zampini 
67524fb275aSStefano Zampini             /* In principle the DL strategy as a unique solution in [0,1]
67624fb275aSStefano Zampini                here we check that for some reason we numerically failed
67724fb275aSStefano Zampini                to compute it. In that case, we use the Cauchy point */
6784a221d59SStefano Zampini             noroots = PetscIsInfOrNanReal(tneg);
67924fb275aSStefano Zampini             if (!noroots) {
68024fb275aSStefano Zampini               if (tpos > 1) {
68124fb275aSStefano Zampini                 if (tneg >= 0 && tneg <= 1) {
68224fb275aSStefano Zampini                   tau = tneg;
68324fb275aSStefano Zampini                 } else noroots = PETSC_TRUE;
68424fb275aSStefano Zampini               } else if (tpos >= 0) {
68524fb275aSStefano Zampini                 tau = tpos;
68624fb275aSStefano Zampini               } else noroots = PETSC_TRUE;
68724fb275aSStefano Zampini             }
6884a221d59SStefano Zampini             if (noroots) { /* No roots, select Cauchy point */
68924fb275aSStefano Zampini               PetscCall(VecCopy(Yc, Y));
6904a221d59SStefano Zampini             } else {
69124fb275aSStefano Zampini               PetscCall(VecAXPBY(Y, 1.0, tau, YU));
6924a221d59SStefano Zampini             }
69324fb275aSStefano Zampini             PetscCall(PetscInfo(snes, "%s evaluated. roots: (%g, %g), tau %g, ynorm: %g, ycnorm: %g, gTBg: %g\n", noroots ? "CP" : "DL", (double)tneg, (double)tpos, (double)tau, (double)ynorm, (double)ycnorm, (double)gTBg));
6944a221d59SStefano Zampini           }
6954a221d59SStefano Zampini         }
6964a221d59SStefano Zampini         break;
6974a221d59SStefano Zampini       default:
6984a221d59SStefano Zampini         SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Unknown fallback mode");
699454a90a3SBarry Smith         break;
70052392280SLois Curfman McInnes       }
7014800dd8cSBarry Smith     }
7024a221d59SStefano Zampini 
7037aa289d8SStefano Zampini     /* compute the quadratic model difference */
70424fb275aSStefano Zampini     PetscCall(SNESNewtonTRQuadraticDelta(snes, J, has_objective, Y, GradF, W, &yTHy, &gTy, &deltaqm));
7054a221d59SStefano Zampini 
7064a221d59SStefano Zampini     /* Compute new objective function */
70724fb275aSStefano Zampini     PetscCall(SNESNewtonTRObjective(snes, has_objective, X, Y, W, G, &gnorm, &fkp1));
70824fb275aSStefano Zampini     if (PetscIsInfOrNanReal(fkp1)) rho = neP->eta1;
70924fb275aSStefano Zampini     else {
7104a221d59SStefano Zampini       if (deltaqm > 0.0) rho = (fk - fkp1) / deltaqm; /* actual improvement over predicted improvement */
71124fb275aSStefano Zampini       else rho = neP->eta1;                           /*  no reduction in quadratic model, step must be rejected */
71224fb275aSStefano Zampini     }
7134a221d59SStefano Zampini 
71424fb275aSStefano Zampini     PetscCall(VecNorm(Y, neP->norm, &ynorm));
71524fb275aSStefano Zampini     PetscCall(PetscInfo(snes, "rho=%g, delta=%g, fk=%g, fkp1=%g, deltaqm=%g, gTy=%g, yTHy=%g, ynormk=%g\n", (double)rho, (double)delta, (double)fk, (double)fkp1, (double)deltaqm, (double)gTy, (double)yTHy, (double)ynorm));
71624fb275aSStefano Zampini 
71724fb275aSStefano Zampini     /* update the size of the trust region */
7184a221d59SStefano Zampini     if (rho < neP->eta2) delta *= neP->t1;                     /* shrink the region */
71924fb275aSStefano Zampini     else if (rho > neP->eta3 && on_boundary) delta *= neP->t2; /* expand the region */
7204a221d59SStefano Zampini     delta = PetscMin(delta, deltaM);                           /* but not greater than deltaM */
7214a221d59SStefano Zampini 
72224fb275aSStefano Zampini     /* log 2-norm of update for moniroting routines */
72324fb275aSStefano Zampini     PetscCall(VecNorm(Y, NORM_2, &ynorm));
72424fb275aSStefano Zampini 
72524fb275aSStefano Zampini     /* decide on new step */
7264a221d59SStefano Zampini     neP->delta = delta;
72724fb275aSStefano Zampini     if (rho > neP->eta1) {
7284a221d59SStefano Zampini       rho_satisfied = PETSC_TRUE;
7294a221d59SStefano Zampini     } else {
7304a221d59SStefano Zampini       rho_satisfied = PETSC_FALSE;
7314a221d59SStefano Zampini       PetscCall(PetscInfo(snes, "Trying again in smaller region\n"));
7324a221d59SStefano Zampini       /* check to see if progress is hopeless */
7334a221d59SStefano Zampini       PetscCall(SNESTR_Converged_Private(snes, snes->iter, xnorm, ynorm, fnorm, &snes->reason, snes->cnvP));
7342d157150SStefano Zampini       if (!snes->reason) PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm));
7354b0a5c37SStefano Zampini       if (snes->reason == SNES_CONVERGED_SNORM_RELATIVE) snes->reason = SNES_DIVERGED_TR_DELTA;
7364a221d59SStefano Zampini       snes->numFailures++;
7374a221d59SStefano Zampini       /* We're not progressing, so return with the current iterate */
7384a221d59SStefano Zampini       if (snes->reason) break;
7394a221d59SStefano Zampini     }
7404a221d59SStefano Zampini     if (rho_satisfied) {
7414a221d59SStefano Zampini       /* Update function values */
7424a221d59SStefano Zampini       already_done = PETSC_FALSE;
7434800dd8cSBarry Smith       fnorm        = gnorm;
7444a221d59SStefano Zampini       fk           = fkp1;
7454a221d59SStefano Zampini 
7464a221d59SStefano Zampini       /* New residual and linearization point */
7479566063dSJacob Faibussowitsch       PetscCall(VecCopy(G, F));
7489566063dSJacob Faibussowitsch       PetscCall(VecCopy(W, X));
7494a221d59SStefano Zampini 
75085385478SLisandro Dalcin       /* Monitor convergence */
7519566063dSJacob Faibussowitsch       PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
7524a221d59SStefano Zampini       snes->iter++;
753fbe28522SBarry Smith       snes->norm  = fnorm;
754c1e67a49SFande Kong       snes->xnorm = xnorm;
755c1e67a49SFande Kong       snes->ynorm = ynorm;
7569566063dSJacob Faibussowitsch       PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
7579566063dSJacob Faibussowitsch       PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits));
7584a221d59SStefano Zampini 
75985385478SLisandro Dalcin       /* Test for convergence, xnorm = || X || */
7604a221d59SStefano Zampini       PetscCall(VecNorm(X, NORM_2, &xnorm));
7612d157150SStefano Zampini       PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm));
7622d157150SStefano Zampini       PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
7634a221d59SStefano Zampini       if (snes->reason) break;
7644a221d59SStefano Zampini     }
76538442cffSBarry Smith   }
766284fb49fSHeeho Park 
7674a221d59SStefano Zampini   if (clear_converged_test) {
768a0254a93SStefano Zampini     PetscCall(KSPGetAndClearConvergenceTest(snes->ksp, &ctx->convtest, &ctx->convctx, &ctx->convdestroy));
7699566063dSJacob Faibussowitsch     PetscCall(PetscFree(ctx));
770a0254a93SStefano Zampini     PetscCall(KSPSetConvergenceTest(snes->ksp, convtest, convctx, convdestroy));
7715e28bcb6Sprj-   }
7723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7734800dd8cSBarry Smith }
774284fb49fSHeeho Park 
775d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetUp_NEWTONTR(SNES snes)
776d71ae5a4SJacob Faibussowitsch {
7773a40ed3dSBarry Smith   PetscFunctionBegin;
77824fb275aSStefano Zampini   PetscCall(SNESSetWorkVecs(snes, 5));
7799566063dSJacob Faibussowitsch   PetscCall(SNESSetUpMatrices(snes));
7803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7814800dd8cSBarry Smith }
7826b8b9a38SLisandro Dalcin 
78324fb275aSStefano Zampini static PetscErrorCode SNESReset_NEWTONTR(SNES snes)
78424fb275aSStefano Zampini {
78524fb275aSStefano Zampini   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
78624fb275aSStefano Zampini 
78724fb275aSStefano Zampini   PetscFunctionBegin;
78824fb275aSStefano Zampini   PetscCall(MatDestroy(&tr->qnB));
78924fb275aSStefano Zampini   PetscCall(MatDestroy(&tr->qnB_pre));
79024fb275aSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
79124fb275aSStefano Zampini }
79224fb275aSStefano Zampini 
793d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESDestroy_NEWTONTR(SNES snes)
794d71ae5a4SJacob Faibussowitsch {
7953a40ed3dSBarry Smith   PetscFunctionBegin;
79624fb275aSStefano Zampini   PetscCall(SNESReset_NEWTONTR(snes));
7979566063dSJacob Faibussowitsch   PetscCall(PetscFree(snes->data));
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7994800dd8cSBarry Smith }
8004800dd8cSBarry Smith 
801d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetFromOptions_NEWTONTR(SNES snes, PetscOptionItems *PetscOptionsObject)
802d71ae5a4SJacob Faibussowitsch {
80304d7464bSBarry Smith   SNES_NEWTONTR           *ctx = (SNES_NEWTONTR *)snes->data;
80424fb275aSStefano Zampini   SNESNewtonTRQNType       qn;
80524fb275aSStefano Zampini   SNESNewtonTRFallbackType fallback;
80624fb275aSStefano Zampini   NormType                 norm;
80724fb275aSStefano Zampini   PetscReal                deltatol;
80824fb275aSStefano Zampini   PetscBool                flg;
8094800dd8cSBarry Smith 
8103a40ed3dSBarry Smith   PetscFunctionBegin;
811d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "SNES trust region options for nonlinear equations");
8124a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_eta1", "eta1", "None", ctx->eta1, &ctx->eta1, NULL));
8134a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_eta2", "eta2", "None", ctx->eta2, &ctx->eta2, NULL));
8144a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_eta3", "eta3", "None", ctx->eta3, &ctx->eta3, NULL));
8154a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_t1", "t1", "None", ctx->t1, &ctx->t1, NULL));
8164a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_t2", "t2", "None", ctx->t2, &ctx->t2, NULL));
8174a221d59SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_deltaM", "deltaM", "None", ctx->deltaM, &ctx->deltaM, NULL));
8189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_tr_delta0", "delta0", "None", ctx->delta0, &ctx->delta0, NULL));
8194b0a5c37SStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_kmdc", "sufficient decrease parameter", "None", ctx->kmdc, &ctx->kmdc, NULL));
82024fb275aSStefano Zampini 
82124fb275aSStefano Zampini   deltatol = snes->deltatol;
82224fb275aSStefano Zampini   PetscCall(PetscOptionsReal("-snes_tr_tol", "Trust region tolerance", "SNESSetTrustRegionTolerance", deltatol, &deltatol, &flg));
82324fb275aSStefano Zampini   if (flg) PetscCall(SNESSetTrustRegionTolerance(snes, deltatol));
82424fb275aSStefano Zampini 
82524fb275aSStefano Zampini   fallback = ctx->fallback;
82624fb275aSStefano Zampini   PetscCall(PetscOptionsEnum("-snes_tr_fallback_type", "Type of fallback if subproblem solution is outside of the trust region", "SNESNewtonTRSetFallbackType", SNESNewtonTRFallbackTypes, (PetscEnum)fallback, (PetscEnum *)&fallback, &flg));
82724fb275aSStefano Zampini   if (flg) PetscCall(SNESNewtonTRSetFallbackType(snes, fallback));
82824fb275aSStefano Zampini 
82924fb275aSStefano Zampini   qn = ctx->qn;
83024fb275aSStefano Zampini   PetscCall(PetscOptionsEnum("-snes_tr_qn", "Use Quasi-Newton approximations for the model", "SNESNewtonTRSetQNType", SNESNewtonTRQNTypes, (PetscEnum)qn, (PetscEnum *)&qn, &flg));
83124fb275aSStefano Zampini   if (flg) PetscCall(SNESNewtonTRSetQNType(snes, qn));
83224fb275aSStefano Zampini 
83324fb275aSStefano Zampini   norm = ctx->norm;
83424fb275aSStefano Zampini   PetscCall(PetscOptionsEnum("-snes_tr_norm_type", "Type of norm for trust region bounds", "SNESNewtonTRSetNormType", NormTypes, (PetscEnum)norm, (PetscEnum *)&norm, &flg));
83524fb275aSStefano Zampini   if (flg) PetscCall(SNESNewtonTRSetNormType(snes, norm));
83624fb275aSStefano Zampini 
837d0609cedSBarry Smith   PetscOptionsHeadEnd();
8383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8394800dd8cSBarry Smith }
8404800dd8cSBarry Smith 
841d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_NEWTONTR(SNES snes, PetscViewer viewer)
842d71ae5a4SJacob Faibussowitsch {
84304d7464bSBarry Smith   SNES_NEWTONTR *tr = (SNES_NEWTONTR *)snes->data;
844ace3abfcSBarry Smith   PetscBool      iascii;
845a935fc98SLois Curfman McInnes 
8463a40ed3dSBarry Smith   PetscFunctionBegin;
8479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
84832077d6dSBarry Smith   if (iascii) {
8494a221d59SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  Trust region tolerance %g\n", (double)snes->deltatol));
8504a221d59SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  eta1=%g, eta2=%g, eta3=%g\n", (double)tr->eta1, (double)tr->eta2, (double)tr->eta3));
8514a221d59SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  delta0=%g, t1=%g, t2=%g, deltaM=%g\n", (double)tr->delta0, (double)tr->t1, (double)tr->t2, (double)tr->deltaM));
8524b0a5c37SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  kmdc=%g\n", (double)tr->kmdc));
8534a221d59SStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "  fallback=%s\n", SNESNewtonTRFallbackTypes[tr->fallback]));
85424fb275aSStefano Zampini     if (tr->qn) PetscCall(PetscViewerASCIIPrintf(viewer, "  qn=%s\n", SNESNewtonTRQNTypes[tr->qn]));
85524fb275aSStefano Zampini     if (tr->norm != NORM_2) PetscCall(PetscViewerASCIIPrintf(viewer, "  norm=%s\n", NormTypes[tr->norm]));
85619bcc07fSBarry Smith   }
8573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
858a935fc98SLois Curfman McInnes }
859f6dfbefdSBarry Smith 
860ebe3b25bSBarry Smith /*MC
8611d27aa22SBarry Smith    SNESNEWTONTR - Newton based nonlinear solver that uses trust-region dogleg method with Cauchy direction {cite}`nocedal2006numerical`
862f6dfbefdSBarry Smith 
863f6dfbefdSBarry Smith    Options Database Keys:
8644a221d59SStefano Zampini +  -snes_tr_tol <tol>                            - trust region tolerance
86524fb275aSStefano Zampini .  -snes_tr_eta1 <eta1>                          - trust region parameter eta1 <= eta2, rho > eta1 breaks out of the inner iteration (default: eta1=0.001)
86624fb275aSStefano Zampini .  -snes_tr_eta2 <eta2>                          - trust region parameter, rho <= eta2 shrinks the trust region (default: eta2=0.25)
8674a221d59SStefano Zampini .  -snes_tr_eta3 <eta3>                          - trust region parameter eta3 > eta2, rho >= eta3 expands the trust region (default: eta3=0.75)
8684a221d59SStefano Zampini .  -snes_tr_t1 <t1>                              - trust region parameter, shrinking factor of trust region (default: 0.25)
8694a221d59SStefano Zampini .  -snes_tr_t2 <t2>                              - trust region parameter, expanding factor of trust region (default: 2.0)
8704a221d59SStefano Zampini .  -snes_tr_deltaM <deltaM>                      - trust region parameter, max size of trust region (default: MAX_REAL)
8714a221d59SStefano Zampini .  -snes_tr_delta0 <delta0>                      - trust region parameter, initial size of trust region (default: 0.2)
8724a221d59SStefano Zampini -  -snes_tr_fallback_type <newton,cauchy,dogleg> - Solution strategy to test reduction when step is outside of trust region. Can use scaled Newton direction, Cauchy point (Steepest Descent direction) or dogleg method.
873*acba1f63SStefano Zampini 
874*acba1f63SStefano Zampini    Level: beginner
875b3113221SBarry Smith 
876420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONLS`, `SNESSetTrustRegionTolerance()`,
8774a221d59SStefano Zampini           `SNESNewtonTRPreCheck()`, `SNESNewtonTRGetPreCheck()`, `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRGetPostCheck()`,
87824fb275aSStefano Zampini           `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRSetFallbackType()`, `SNESNewtonTRSetQNType()`
879ebe3b25bSBarry Smith M*/
880d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONTR(SNES snes)
881d71ae5a4SJacob Faibussowitsch {
88204d7464bSBarry Smith   SNES_NEWTONTR *neP;
8834800dd8cSBarry Smith 
8843a40ed3dSBarry Smith   PetscFunctionBegin;
88504d7464bSBarry Smith   snes->ops->setup          = SNESSetUp_NEWTONTR;
88604d7464bSBarry Smith   snes->ops->solve          = SNESSolve_NEWTONTR;
88724fb275aSStefano Zampini   snes->ops->reset          = SNESReset_NEWTONTR;
88804d7464bSBarry Smith   snes->ops->destroy        = SNESDestroy_NEWTONTR;
88904d7464bSBarry Smith   snes->ops->setfromoptions = SNESSetFromOptions_NEWTONTR;
89004d7464bSBarry Smith   snes->ops->view           = SNESView_NEWTONTR;
891fbe28522SBarry Smith 
8921a58d6d3SStefano Zampini   snes->stol    = 0.0;
89342f4f86dSBarry Smith   snes->usesksp = PETSC_TRUE;
8944b0a5c37SStefano Zampini   snes->npcside = PC_RIGHT;
8954b0a5c37SStefano Zampini   snes->usesnpc = PETSC_TRUE;
89642f4f86dSBarry Smith 
8974fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
8984fc747eaSLawrence Mitchell 
8994dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&neP));
900fbe28522SBarry Smith   snes->data    = (void *)neP;
901fbe28522SBarry Smith   neP->delta    = 0.0;
902fbe28522SBarry Smith   neP->delta0   = 0.2;
9034a221d59SStefano Zampini   neP->eta1     = 0.001;
9044a221d59SStefano Zampini   neP->eta2     = 0.25;
9054a221d59SStefano Zampini   neP->eta3     = 0.75;
9064a221d59SStefano Zampini   neP->t1       = 0.25;
9074a221d59SStefano Zampini   neP->t2       = 2.0;
9084a221d59SStefano Zampini   neP->deltaM   = 1.e10;
90924fb275aSStefano Zampini   neP->norm     = NORM_2;
9104a221d59SStefano Zampini   neP->fallback = SNES_TR_FALLBACK_NEWTON;
9114b0a5c37SStefano Zampini   neP->kmdc     = 0.0; /* by default do not use sufficient decrease */
9123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9134800dd8cSBarry Smith }
914