141ba4c6cSHeeho Park #include <../src/snes/impls/ntrdc/ntrdcimpl.h> /*I "petscsnes.h" I*/ 241ba4c6cSHeeho Park 341ba4c6cSHeeho Park typedef struct { 441ba4c6cSHeeho Park SNES snes; 541ba4c6cSHeeho Park /* Information on the regular SNES convergence test; which may have been user provided 641ba4c6cSHeeho Park Copied from tr.c (maybe able to disposed, but this is a private function) - Heeho 741ba4c6cSHeeho Park Same with SNESTR_KSPConverged_Private, SNESTR_KSPConverged_Destroy, and SNESTR_Converged_Private 841ba4c6cSHeeho Park */ 941ba4c6cSHeeho Park 1041ba4c6cSHeeho Park PetscErrorCode (*convtest)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *); 1141ba4c6cSHeeho Park PetscErrorCode (*convdestroy)(void *); 1241ba4c6cSHeeho Park void *convctx; 1341ba4c6cSHeeho Park } SNES_TRDC_KSPConverged_Ctx; 1441ba4c6cSHeeho Park 15d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTRDC_KSPConverged_Private(KSP ksp, PetscInt n, PetscReal rnorm, KSPConvergedReason *reason, void *cctx) 16d71ae5a4SJacob Faibussowitsch { 1741ba4c6cSHeeho Park SNES_TRDC_KSPConverged_Ctx *ctx = (SNES_TRDC_KSPConverged_Ctx *)cctx; 1841ba4c6cSHeeho Park SNES snes = ctx->snes; 1941ba4c6cSHeeho Park SNES_NEWTONTRDC *neP = (SNES_NEWTONTRDC *)snes->data; 2041ba4c6cSHeeho Park Vec x; 2141ba4c6cSHeeho Park PetscReal nrm; 2241ba4c6cSHeeho Park 2341ba4c6cSHeeho Park PetscFunctionBegin; 249566063dSJacob Faibussowitsch PetscCall((*ctx->convtest)(ksp, n, rnorm, reason, ctx->convctx)); 2548a46eb9SPierre Jolivet if (*reason) PetscCall(PetscInfo(snes, "Default or user provided convergence test KSP iterations=%" PetscInt_FMT ", rnorm=%g\n", n, (double)rnorm)); 2641ba4c6cSHeeho Park /* Determine norm of solution */ 279566063dSJacob Faibussowitsch PetscCall(KSPBuildSolution(ksp, NULL, &x)); 289566063dSJacob Faibussowitsch PetscCall(VecNorm(x, NORM_2, &nrm)); 2941ba4c6cSHeeho Park if (nrm >= neP->delta) { 309566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Ending linear iteration early, delta=%g, length=%g\n", (double)neP->delta, (double)nrm)); 3141ba4c6cSHeeho Park *reason = KSP_CONVERGED_STEP_LENGTH; 3241ba4c6cSHeeho Park } 333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3441ba4c6cSHeeho Park } 3541ba4c6cSHeeho Park 36d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTRDC_KSPConverged_Destroy(void *cctx) 37d71ae5a4SJacob Faibussowitsch { 3841ba4c6cSHeeho Park SNES_TRDC_KSPConverged_Ctx *ctx = (SNES_TRDC_KSPConverged_Ctx *)cctx; 3941ba4c6cSHeeho Park 4041ba4c6cSHeeho Park PetscFunctionBegin; 419566063dSJacob Faibussowitsch PetscCall((*ctx->convdestroy)(ctx->convctx)); 429566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4441ba4c6cSHeeho Park } 4541ba4c6cSHeeho Park 4641ba4c6cSHeeho Park /* 4741ba4c6cSHeeho Park SNESTRDC_Converged_Private -test convergence JUST for 4841ba4c6cSHeeho Park the trust region tolerance. 4941ba4c6cSHeeho Park 5041ba4c6cSHeeho Park */ 51d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTRDC_Converged_Private(SNES snes, PetscInt it, PetscReal xnorm, PetscReal pnorm, PetscReal fnorm, SNESConvergedReason *reason, void *dummy) 52d71ae5a4SJacob Faibussowitsch { 5341ba4c6cSHeeho Park SNES_NEWTONTRDC *neP = (SNES_NEWTONTRDC *)snes->data; 5441ba4c6cSHeeho Park 5541ba4c6cSHeeho Park PetscFunctionBegin; 5641ba4c6cSHeeho Park *reason = SNES_CONVERGED_ITERATING; 5741ba4c6cSHeeho Park if (neP->delta < xnorm * snes->deltatol) { 589566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Diverged due to too small a trust region %g<%g*%g\n", (double)neP->delta, (double)xnorm, (double)snes->deltatol)); 5941ba4c6cSHeeho Park *reason = SNES_DIVERGED_TR_DELTA; 6041ba4c6cSHeeho Park } else if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) { 619566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Exceeded maximum number of function evaluations: %" PetscInt_FMT "\n", snes->max_funcs)); 6241ba4c6cSHeeho Park *reason = SNES_DIVERGED_FUNCTION_COUNT; 6341ba4c6cSHeeho Park } 643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6541ba4c6cSHeeho Park } 6641ba4c6cSHeeho Park 6741ba4c6cSHeeho Park /*@ 68f6dfbefdSBarry Smith SNESNewtonTRDCGetRhoFlag - Get whether the current solution update is within the trust-region. 6941ba4c6cSHeeho Park 7020f4b53cSBarry Smith Logically Collective 7120f4b53cSBarry Smith 72f6dfbefdSBarry Smith Input Parameter: 7341ba4c6cSHeeho Park . snes - the nonlinear solver object 7441ba4c6cSHeeho Park 75f6dfbefdSBarry Smith Output Parameter: 76420bcc1bSBarry Smith . rho_flag - `PETSC_FALSE` or `PETSC_TRUE` 7741ba4c6cSHeeho Park 7841ba4c6cSHeeho Park Level: developer 7941ba4c6cSHeeho Park 80420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCPreCheck()`, `SNESNewtonTRDCGetPreCheck()`, `SNESNewtonTRDCSetPreCheck()`, 81f6dfbefdSBarry Smith `SNESNewtonTRDCSetPostCheck()`, `SNESNewtonTRDCGetPostCheck()` 8241ba4c6cSHeeho Park @*/ 83d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRDCGetRhoFlag(SNES snes, PetscBool *rho_flag) 84d71ae5a4SJacob Faibussowitsch { 8541ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 8641ba4c6cSHeeho Park 8741ba4c6cSHeeho Park PetscFunctionBegin; 8841ba4c6cSHeeho Park PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 894f572ea9SToby Isaac PetscAssertPointer(rho_flag, 2); 9041ba4c6cSHeeho Park *rho_flag = tr->rho_satisfied; 913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9241ba4c6cSHeeho Park } 9341ba4c6cSHeeho Park 9441ba4c6cSHeeho Park /*@C 9541ba4c6cSHeeho Park SNESNewtonTRDCSetPreCheck - Sets a user function that is called before the search step has been determined. 9641ba4c6cSHeeho Park Allows the user a chance to change or override the trust region decision. 9741ba4c6cSHeeho Park 98c3339decSBarry Smith Logically Collective 9941ba4c6cSHeeho Park 10041ba4c6cSHeeho Park Input Parameters: 10141ba4c6cSHeeho Park + snes - the nonlinear solver object 10220f4b53cSBarry Smith . func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRDCPreCheck()` 10320f4b53cSBarry Smith - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`) 10441ba4c6cSHeeho Park 10541ba4c6cSHeeho Park Level: intermediate 10641ba4c6cSHeeho Park 107f6dfbefdSBarry Smith Note: 108f6dfbefdSBarry Smith This function is called BEFORE the function evaluation within the `SNESNEWTONTRDC` solver. 10941ba4c6cSHeeho Park 110420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCPreCheck()`, `SNESNewtonTRDCGetPreCheck()`, `SNESNewtonTRDCSetPostCheck()`, `SNESNewtonTRDCGetPostCheck()`, 111f6dfbefdSBarry Smith `SNESNewtonTRDCGetRhoFlag()` 11241ba4c6cSHeeho Park @*/ 113d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRDCSetPreCheck(SNES snes, PetscErrorCode (*func)(SNES, Vec, Vec, PetscBool *, void *), void *ctx) 114d71ae5a4SJacob Faibussowitsch { 11541ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 11641ba4c6cSHeeho Park 11741ba4c6cSHeeho Park PetscFunctionBegin; 11841ba4c6cSHeeho Park PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 11941ba4c6cSHeeho Park if (func) tr->precheck = func; 12041ba4c6cSHeeho Park if (ctx) tr->precheckctx = ctx; 1213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12241ba4c6cSHeeho Park } 12341ba4c6cSHeeho Park 12441ba4c6cSHeeho Park /*@C 125420bcc1bSBarry Smith SNESNewtonTRDCGetPreCheck - Gets the pre-check function optionally set with `SNESNewtonTRDCSetPreCheck()` 12641ba4c6cSHeeho Park 12720f4b53cSBarry Smith Not Collective 12841ba4c6cSHeeho Park 12941ba4c6cSHeeho Park Input Parameter: 13041ba4c6cSHeeho Park . snes - the nonlinear solver context 13141ba4c6cSHeeho Park 13241ba4c6cSHeeho Park Output Parameters: 13320f4b53cSBarry Smith + func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRDCPreCheck()` 13420f4b53cSBarry Smith - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`) 13541ba4c6cSHeeho Park 13641ba4c6cSHeeho Park Level: intermediate 13741ba4c6cSHeeho Park 138420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCSetPreCheck()`, `SNESNewtonTRDCPreCheck()` 13941ba4c6cSHeeho Park @*/ 140d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRDCGetPreCheck(SNES snes, PetscErrorCode (**func)(SNES, Vec, Vec, PetscBool *, void *), void **ctx) 141d71ae5a4SJacob Faibussowitsch { 14241ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 14341ba4c6cSHeeho Park 14441ba4c6cSHeeho Park PetscFunctionBegin; 14541ba4c6cSHeeho Park PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 14641ba4c6cSHeeho Park if (func) *func = tr->precheck; 14741ba4c6cSHeeho Park if (ctx) *ctx = tr->precheckctx; 1483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14941ba4c6cSHeeho Park } 15041ba4c6cSHeeho Park 15141ba4c6cSHeeho Park /*@C 15241ba4c6cSHeeho Park SNESNewtonTRDCSetPostCheck - Sets a user function that is called after the search step has been determined but before the next 15341ba4c6cSHeeho Park function evaluation. Allows the user a chance to change or override the decision of the line search routine 15441ba4c6cSHeeho Park 155c3339decSBarry Smith Logically Collective 15641ba4c6cSHeeho Park 15741ba4c6cSHeeho Park Input Parameters: 15841ba4c6cSHeeho Park + snes - the nonlinear solver object 15920f4b53cSBarry Smith . func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRDCPostCheck()` 16020f4b53cSBarry Smith - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`) 16141ba4c6cSHeeho Park 16241ba4c6cSHeeho Park Level: intermediate 16341ba4c6cSHeeho Park 164f6dfbefdSBarry Smith Note: 165f6dfbefdSBarry Smith This function is called BEFORE the function evaluation within the `SNESNEWTONTRDC` solver while the function set in 166f6dfbefdSBarry Smith `SNESLineSearchSetPostCheck()` is called AFTER the function evaluation. 16741ba4c6cSHeeho Park 168420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCPostCheck()`, `SNESNewtonTRDCGetPostCheck()`, `SNESNewtonTRDCSetPreCheck()`, `SNESNewtonTRDCGetPreCheck()` 16941ba4c6cSHeeho Park @*/ 170d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRDCSetPostCheck(SNES snes, PetscErrorCode (*func)(SNES, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void *ctx) 171d71ae5a4SJacob Faibussowitsch { 17241ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 17341ba4c6cSHeeho Park 17441ba4c6cSHeeho Park PetscFunctionBegin; 17541ba4c6cSHeeho Park PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 17641ba4c6cSHeeho Park if (func) tr->postcheck = func; 17741ba4c6cSHeeho Park if (ctx) tr->postcheckctx = ctx; 1783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 17941ba4c6cSHeeho Park } 18041ba4c6cSHeeho Park 18141ba4c6cSHeeho Park /*@C 182420bcc1bSBarry Smith SNESNewtonTRDCGetPostCheck - Gets the post-check function optionally set with `SNESNewtonTRDCSetPostCheck()` 18341ba4c6cSHeeho Park 18420f4b53cSBarry Smith Not Collective 18541ba4c6cSHeeho Park 18641ba4c6cSHeeho Park Input Parameter: 18741ba4c6cSHeeho Park . snes - the nonlinear solver context 18841ba4c6cSHeeho Park 18941ba4c6cSHeeho Park Output Parameters: 19020f4b53cSBarry Smith + func - [optional] function evaluation routine, for the calling sequence see `SNESNewtonTRDCPostCheck()` 19120f4b53cSBarry Smith - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`) 19241ba4c6cSHeeho Park 19341ba4c6cSHeeho Park Level: intermediate 19441ba4c6cSHeeho Park 195420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCSetPostCheck()`, `SNESNewtonTRDCPostCheck()`, `SNESNewtonTRDCSetPreCheck()`, `SNESNewtonTRDCGetPreCheck()` 19641ba4c6cSHeeho Park @*/ 197d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNewtonTRDCGetPostCheck(SNES snes, PetscErrorCode (**func)(SNES, Vec, Vec, Vec, PetscBool *, PetscBool *, void *), void **ctx) 198d71ae5a4SJacob Faibussowitsch { 19941ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 20041ba4c6cSHeeho Park 20141ba4c6cSHeeho Park PetscFunctionBegin; 20241ba4c6cSHeeho Park PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 20341ba4c6cSHeeho Park if (func) *func = tr->postcheck; 20441ba4c6cSHeeho Park if (ctx) *ctx = tr->postcheckctx; 2053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20641ba4c6cSHeeho Park } 20741ba4c6cSHeeho Park 208ceaaa498SBarry Smith // PetscClangLinter pragma disable: -fdoc-internal-linkage 20941ba4c6cSHeeho Park /*@C 210f6dfbefdSBarry Smith SNESNewtonTRDCPreCheck - Called before the step has been determined in `SNESNEWTONTRDC` 21141ba4c6cSHeeho Park 212c3339decSBarry Smith Logically Collective 21341ba4c6cSHeeho Park 21441ba4c6cSHeeho Park Input Parameters: 21541ba4c6cSHeeho Park + snes - the solver 21641ba4c6cSHeeho Park . X - The last solution 21741ba4c6cSHeeho Park - Y - The step direction 21841ba4c6cSHeeho Park 2192fe279fdSBarry Smith Output Parameter: 22020f4b53cSBarry Smith . changed_Y - Indicator that the step direction `Y` has been changed. 22141ba4c6cSHeeho Park 22241ba4c6cSHeeho Park Level: developer 22341ba4c6cSHeeho Park 224420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNewtonTRDCSetPreCheck()`, `SNESNewtonTRDCGetPreCheck()`, `SNESNewtonTRDCPostCheck()` 22541ba4c6cSHeeho Park @*/ 226d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESNewtonTRDCPreCheck(SNES snes, Vec X, Vec Y, PetscBool *changed_Y) 227d71ae5a4SJacob Faibussowitsch { 22841ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 22941ba4c6cSHeeho Park 23041ba4c6cSHeeho Park PetscFunctionBegin; 23141ba4c6cSHeeho Park *changed_Y = PETSC_FALSE; 23241ba4c6cSHeeho Park if (tr->precheck) { 2339566063dSJacob Faibussowitsch PetscCall((*tr->precheck)(snes, X, Y, changed_Y, tr->precheckctx)); 23441ba4c6cSHeeho Park PetscValidLogicalCollectiveBool(snes, *changed_Y, 4); 23541ba4c6cSHeeho Park } 2363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23741ba4c6cSHeeho Park } 23841ba4c6cSHeeho Park 239ceaaa498SBarry Smith // PetscClangLinter pragma disable: -fdoc-internal-linkage 24041ba4c6cSHeeho Park /*@C 241f6dfbefdSBarry Smith SNESNewtonTRDCPostCheck - Called after the step has been determined in `SNESNEWTONTRDC` but before the function evaluation at that step 24241ba4c6cSHeeho Park 243c3339decSBarry Smith Logically Collective 24441ba4c6cSHeeho Park 24541ba4c6cSHeeho Park Input Parameters: 246f1a722f8SMatthew G. Knepley + snes - the solver 247f1a722f8SMatthew G. Knepley . X - The last solution 24841ba4c6cSHeeho Park . Y - The full step direction 24941ba4c6cSHeeho Park - W - The updated solution, W = X - Y 25041ba4c6cSHeeho Park 25141ba4c6cSHeeho Park Output Parameters: 25241ba4c6cSHeeho Park + changed_Y - indicator if step has been changed 25320f4b53cSBarry Smith - changed_W - Indicator if the new candidate solution `W` has been changed. 25441ba4c6cSHeeho Park 2552fe279fdSBarry Smith Level: developer 2562fe279fdSBarry Smith 257f6dfbefdSBarry Smith Note: 25820f4b53cSBarry Smith If `Y` is changed then `W` is recomputed as `X` - `Y` 25941ba4c6cSHeeho Park 260420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESNEWTONTRDC`, `SNESNEWTONTRDC`, `SNESNewtonTRDCSetPostCheck()`, `SNESNewtonTRDCGetPostCheck()`, `SNESNewtonTRDCPreCheck() 26141ba4c6cSHeeho Park @*/ 262d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESNewtonTRDCPostCheck(SNES snes, Vec X, Vec Y, Vec W, PetscBool *changed_Y, PetscBool *changed_W) 263d71ae5a4SJacob Faibussowitsch { 26441ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 26541ba4c6cSHeeho Park 26641ba4c6cSHeeho Park PetscFunctionBegin; 26741ba4c6cSHeeho Park *changed_Y = PETSC_FALSE; 26841ba4c6cSHeeho Park *changed_W = PETSC_FALSE; 26941ba4c6cSHeeho Park if (tr->postcheck) { 2709566063dSJacob Faibussowitsch PetscCall((*tr->postcheck)(snes, X, Y, W, changed_Y, changed_W, tr->postcheckctx)); 27141ba4c6cSHeeho Park PetscValidLogicalCollectiveBool(snes, *changed_Y, 5); 27241ba4c6cSHeeho Park PetscValidLogicalCollectiveBool(snes, *changed_W, 6); 27341ba4c6cSHeeho Park } 2743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 27541ba4c6cSHeeho Park } 27641ba4c6cSHeeho Park 27741ba4c6cSHeeho Park /* 27841ba4c6cSHeeho Park SNESSolve_NEWTONTRDC - Implements Newton's Method with trust-region subproblem and adds dogleg Cauchy 27941ba4c6cSHeeho Park (Steepest Descent direction) step and direction if the trust region is not satisfied for solving system of 28041ba4c6cSHeeho Park nonlinear equations 28141ba4c6cSHeeho Park 28241ba4c6cSHeeho Park */ 283d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSolve_NEWTONTRDC(SNES snes) 284d71ae5a4SJacob Faibussowitsch { 28541ba4c6cSHeeho Park SNES_NEWTONTRDC *neP = (SNES_NEWTONTRDC *)snes->data; 28641ba4c6cSHeeho Park Vec X, F, Y, G, W, GradF, YNtmp; 28741ba4c6cSHeeho Park Vec YCtmp; 28841ba4c6cSHeeho Park Mat jac; 28941ba4c6cSHeeho Park PetscInt maxits, i, j, lits, inner_count, bs; 29041ba4c6cSHeeho Park PetscReal rho, fnorm, gnorm, xnorm = 0, delta, ynorm, temp_xnorm, temp_ynorm; /* TRDC inner iteration */ 29141ba4c6cSHeeho Park PetscReal inorms[99]; /* need to make it dynamic eventually, fixed max block size of 99 for now */ 29241ba4c6cSHeeho Park PetscReal deltaM, ynnorm, f0, mp, gTy, g, yTHy; /* rho calculation */ 29341ba4c6cSHeeho Park PetscReal auk, gfnorm, ycnorm, c0, c1, c2, tau, tau_pos, tau_neg, gTBg; /* Cauchy Point */ 29441ba4c6cSHeeho Park KSP ksp; 29541ba4c6cSHeeho Park SNESConvergedReason reason = SNES_CONVERGED_ITERATING; 29641ba4c6cSHeeho Park PetscBool breakout = PETSC_FALSE; 29741ba4c6cSHeeho Park SNES_TRDC_KSPConverged_Ctx *ctx; 29841ba4c6cSHeeho Park PetscErrorCode (*convtest)(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *), (*convdestroy)(void *); 29941ba4c6cSHeeho Park void *convctx; 30041ba4c6cSHeeho Park 30141ba4c6cSHeeho Park PetscFunctionBegin; 30241ba4c6cSHeeho Park maxits = snes->max_its; /* maximum number of iterations */ 30341ba4c6cSHeeho Park X = snes->vec_sol; /* solution vector */ 30441ba4c6cSHeeho Park F = snes->vec_func; /* residual vector */ 30541ba4c6cSHeeho Park Y = snes->work[0]; /* update vector */ 30641ba4c6cSHeeho Park G = snes->work[1]; /* updated residual */ 30741ba4c6cSHeeho Park W = snes->work[2]; /* temporary vector */ 30841ba4c6cSHeeho Park GradF = snes->work[3]; /* grad f = J^T F */ 30941ba4c6cSHeeho Park YNtmp = snes->work[4]; /* Newton solution */ 31041ba4c6cSHeeho Park YCtmp = snes->work[5]; /* Cauchy solution */ 31141ba4c6cSHeeho Park 3120b121fc5SBarry Smith 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); 31341ba4c6cSHeeho Park 3149566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(YNtmp, &bs)); 31541ba4c6cSHeeho Park 3169566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 31741ba4c6cSHeeho Park snes->iter = 0; 3189566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 31941ba4c6cSHeeho Park 32041ba4c6cSHeeho Park /* Set the linear stopping criteria to use the More' trick. From tr.c */ 3219566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 3229566063dSJacob Faibussowitsch PetscCall(KSPGetConvergenceTest(ksp, &convtest, &convctx, &convdestroy)); 32341ba4c6cSHeeho Park if (convtest != SNESTRDC_KSPConverged_Private) { 3249566063dSJacob Faibussowitsch PetscCall(PetscNew(&ctx)); 32541ba4c6cSHeeho Park ctx->snes = snes; 3269566063dSJacob Faibussowitsch PetscCall(KSPGetAndClearConvergenceTest(ksp, &ctx->convtest, &ctx->convctx, &ctx->convdestroy)); 3279566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(ksp, SNESTRDC_KSPConverged_Private, ctx, SNESTRDC_KSPConverged_Destroy)); 3289566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Using Krylov convergence test SNESTRDC_KSPConverged_Private\n")); 32941ba4c6cSHeeho Park } 33041ba4c6cSHeeho Park 33141ba4c6cSHeeho Park if (!snes->vec_func_init_set) { 3329566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, X, F)); /* F(X) */ 33341ba4c6cSHeeho Park } else snes->vec_func_init_set = PETSC_FALSE; 33441ba4c6cSHeeho Park 3359566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- || F || */ 33641ba4c6cSHeeho Park SNESCheckFunctionNorm(snes, fnorm); 3379566063dSJacob Faibussowitsch PetscCall(VecNorm(X, NORM_2, &xnorm)); /* xnorm <- || X || */ 33841ba4c6cSHeeho Park 3399566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 34041ba4c6cSHeeho Park snes->norm = fnorm; 3419566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 34241ba4c6cSHeeho Park delta = xnorm ? neP->delta0 * xnorm : neP->delta0; /* initial trust region size scaled by xnorm */ 34341ba4c6cSHeeho Park deltaM = xnorm ? neP->deltaM * xnorm : neP->deltaM; /* maximum trust region size scaled by xnorm */ 34441ba4c6cSHeeho Park neP->delta = delta; 3459566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0)); 3469566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, 0, fnorm)); 34741ba4c6cSHeeho Park 34841ba4c6cSHeeho Park neP->rho_satisfied = PETSC_FALSE; 34941ba4c6cSHeeho Park 35041ba4c6cSHeeho Park /* test convergence */ 351dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, snes->iter, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP); 3523ba16761SJacob Faibussowitsch if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS); 35341ba4c6cSHeeho Park 35441ba4c6cSHeeho Park for (i = 0; i < maxits; i++) { 35541ba4c6cSHeeho Park PetscBool changed_y; 35641ba4c6cSHeeho Park PetscBool changed_w; 35741ba4c6cSHeeho Park 35841ba4c6cSHeeho Park /* dogleg method */ 3599566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre)); 36041ba4c6cSHeeho Park SNESCheckJacobianDomainerror(snes); 3619566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian)); 3629566063dSJacob Faibussowitsch PetscCall(KSPSolve(snes->ksp, F, YNtmp)); /* Quasi Newton Solution */ 36341ba4c6cSHeeho Park SNESCheckKSPSolve(snes); /* this is necessary but old tr.c did not have it*/ 3649566063dSJacob Faibussowitsch PetscCall(KSPGetIterationNumber(snes->ksp, &lits)); 3659566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &jac, NULL, NULL, NULL)); 36641ba4c6cSHeeho Park 36741ba4c6cSHeeho Park /* rescale Jacobian, Newton solution update, and re-calculate delta for multiphase (multivariable) 36841ba4c6cSHeeho Park for inner iteration and Cauchy direction calculation 36941ba4c6cSHeeho Park */ 37041ba4c6cSHeeho Park if (bs > 1 && neP->auto_scale_multiphase) { 3719566063dSJacob Faibussowitsch PetscCall(VecStrideNormAll(YNtmp, NORM_INFINITY, inorms)); 37241ba4c6cSHeeho Park for (j = 0; j < bs; j++) { 37341ba4c6cSHeeho Park if (neP->auto_scale_max > 1.0) { 374ad540459SPierre Jolivet if (inorms[j] < 1.0 / neP->auto_scale_max) inorms[j] = 1.0 / neP->auto_scale_max; 37541ba4c6cSHeeho Park } 3769566063dSJacob Faibussowitsch PetscCall(VecStrideSet(W, j, inorms[j])); 3779566063dSJacob Faibussowitsch PetscCall(VecStrideScale(YNtmp, j, 1.0 / inorms[j])); 3789566063dSJacob Faibussowitsch PetscCall(VecStrideScale(X, j, 1.0 / inorms[j])); 37941ba4c6cSHeeho Park } 3809566063dSJacob Faibussowitsch PetscCall(VecNorm(X, NORM_2, &xnorm)); 38141ba4c6cSHeeho Park if (i == 0) { 38241ba4c6cSHeeho Park delta = neP->delta0 * xnorm; 38341ba4c6cSHeeho Park } else { 38441ba4c6cSHeeho Park delta = neP->delta * xnorm; 38541ba4c6cSHeeho Park } 38641ba4c6cSHeeho Park deltaM = neP->deltaM * xnorm; 387f3fa974cSJacob Faibussowitsch PetscCall(MatDiagonalScale(jac, NULL, W)); 38841ba4c6cSHeeho Park } 38941ba4c6cSHeeho Park 39041ba4c6cSHeeho Park /* calculating GradF of minimization function */ 3919566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(jac, F, GradF)); /* grad f = J^T F */ 3929566063dSJacob Faibussowitsch PetscCall(VecNorm(YNtmp, NORM_2, &ynnorm)); /* ynnorm <- || Y_newton || */ 39341ba4c6cSHeeho Park 39441ba4c6cSHeeho Park inner_count = 0; 39541ba4c6cSHeeho Park neP->rho_satisfied = PETSC_FALSE; 39641ba4c6cSHeeho Park while (1) { 39741ba4c6cSHeeho Park if (ynnorm <= delta) { /* see if the Newton solution is within the trust region */ 3989566063dSJacob Faibussowitsch PetscCall(VecCopy(YNtmp, Y)); 39941ba4c6cSHeeho Park } else if (neP->use_cauchy) { /* use Cauchy direction if enabled */ 4009566063dSJacob Faibussowitsch PetscCall(MatMult(jac, GradF, W)); 4019566063dSJacob Faibussowitsch PetscCall(VecDotRealPart(W, W, &gTBg)); /* completes GradF^T J^T J GradF */ 4029566063dSJacob Faibussowitsch PetscCall(VecNorm(GradF, NORM_2, &gfnorm)); /* grad f norm <- || grad f || */ 40341ba4c6cSHeeho Park if (gTBg <= 0.0) { 40441ba4c6cSHeeho Park auk = PETSC_MAX_REAL; 40541ba4c6cSHeeho Park } else { 40641ba4c6cSHeeho Park auk = PetscSqr(gfnorm) / gTBg; 40741ba4c6cSHeeho Park } 40841ba4c6cSHeeho Park auk = PetscMin(delta / gfnorm, auk); 4099566063dSJacob Faibussowitsch PetscCall(VecCopy(GradF, YCtmp)); /* this could be improved */ 4109566063dSJacob Faibussowitsch PetscCall(VecScale(YCtmp, auk)); /* YCtmp, Cauchy solution*/ 4119566063dSJacob Faibussowitsch PetscCall(VecNorm(YCtmp, NORM_2, &ycnorm)); /* ycnorm <- || Y_cauchy || */ 41241ba4c6cSHeeho Park if (ycnorm >= delta) { /* see if the Cauchy solution meets the criteria */ 4139566063dSJacob Faibussowitsch PetscCall(VecCopy(YCtmp, Y)); 4149566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "DL evaluated. delta: %8.4e, ynnorm: %8.4e, ycnorm: %8.4e\n", (double)delta, (double)ynnorm, (double)ycnorm)); 41541ba4c6cSHeeho Park } else { /* take ratio, tau, of Cauchy and Newton direction and step */ 4169566063dSJacob Faibussowitsch PetscCall(VecAXPY(YNtmp, -1.0, YCtmp)); /* YCtmp = A, YNtmp = B */ 4179566063dSJacob Faibussowitsch PetscCall(VecNorm(YNtmp, NORM_2, &c0)); /* this could be improved */ 41841ba4c6cSHeeho Park c0 = PetscSqr(c0); 4199566063dSJacob Faibussowitsch PetscCall(VecDotRealPart(YCtmp, YNtmp, &c1)); 42041ba4c6cSHeeho Park c1 = 2.0 * c1; 4219566063dSJacob Faibussowitsch PetscCall(VecNorm(YCtmp, NORM_2, &c2)); /* this could be improved */ 42241ba4c6cSHeeho Park c2 = PetscSqr(c2) - PetscSqr(delta); 42341ba4c6cSHeeho Park tau_pos = (c1 + PetscSqrtReal(PetscSqr(c1) - 4. * c0 * c2)) / (2. * c0); /* quadratic formula */ 42441ba4c6cSHeeho Park tau_neg = (c1 - PetscSqrtReal(PetscSqr(c1) - 4. * c0 * c2)) / (2. * c0); 42541ba4c6cSHeeho Park tau = PetscMax(tau_pos, tau_neg); /* can tau_neg > tau_pos? I don't think so, but just in case. */ 4269566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "DL evaluated. tau: %8.4e, ynnorm: %8.4e, ycnorm: %8.4e\n", (double)tau, (double)ynnorm, (double)ycnorm)); 4279566063dSJacob Faibussowitsch PetscCall(VecWAXPY(W, tau, YNtmp, YCtmp)); 4289566063dSJacob Faibussowitsch PetscCall(VecAXPY(W, -tau, YCtmp)); 4299566063dSJacob Faibussowitsch PetscCall(VecCopy(W, Y)); /* this could be improved */ 43041ba4c6cSHeeho Park } 43141ba4c6cSHeeho Park } else { 43241ba4c6cSHeeho Park /* if Cauchy is disabled, only use Newton direction */ 43341ba4c6cSHeeho Park auk = delta / ynnorm; 4349566063dSJacob Faibussowitsch PetscCall(VecScale(YNtmp, auk)); 4359566063dSJacob Faibussowitsch PetscCall(VecCopy(YNtmp, Y)); /* this could be improved (many VecCopy, VecNorm)*/ 43641ba4c6cSHeeho Park } 43741ba4c6cSHeeho Park 4389566063dSJacob Faibussowitsch PetscCall(VecNorm(Y, NORM_2, &ynorm)); /* compute the final ynorm */ 43941ba4c6cSHeeho Park f0 = 0.5 * PetscSqr(fnorm); /* minimizing function f(X) */ 4409566063dSJacob Faibussowitsch PetscCall(MatMult(jac, Y, W)); 4419566063dSJacob Faibussowitsch PetscCall(VecDotRealPart(W, W, &yTHy)); /* completes GradY^T J^T J GradY */ 4429566063dSJacob Faibussowitsch PetscCall(VecDotRealPart(GradF, Y, &gTy)); 44341ba4c6cSHeeho Park mp = f0 - gTy + 0.5 * yTHy; /* quadratic model to satisfy, -gTy because our update is X-Y*/ 44441ba4c6cSHeeho Park 44541ba4c6cSHeeho Park /* scale back solution update */ 44641ba4c6cSHeeho Park if (bs > 1 && neP->auto_scale_multiphase) { 44741ba4c6cSHeeho Park for (j = 0; j < bs; j++) { 4489566063dSJacob Faibussowitsch PetscCall(VecStrideScale(Y, j, inorms[j])); 44941ba4c6cSHeeho Park if (inner_count == 0) { 45041ba4c6cSHeeho Park /* TRDC inner algorithm does not need scaled X after calculating delta in the outer iteration */ 45141ba4c6cSHeeho Park /* need to scale back X to match Y and provide proper update to the external code */ 4529566063dSJacob Faibussowitsch PetscCall(VecStrideScale(X, j, inorms[j])); 45341ba4c6cSHeeho Park } 45441ba4c6cSHeeho Park } 4559566063dSJacob Faibussowitsch if (inner_count == 0) PetscCall(VecNorm(X, NORM_2, &temp_xnorm)); /* only in the first iteration */ 4569566063dSJacob Faibussowitsch PetscCall(VecNorm(Y, NORM_2, &temp_ynorm)); 45741ba4c6cSHeeho Park } else { 45841ba4c6cSHeeho Park temp_xnorm = xnorm; 45941ba4c6cSHeeho Park temp_ynorm = ynorm; 46041ba4c6cSHeeho Park } 46141ba4c6cSHeeho Park inner_count++; 46241ba4c6cSHeeho Park 46341ba4c6cSHeeho Park /* Evaluate the solution to meet the improvement ratio criteria */ 4649566063dSJacob Faibussowitsch PetscCall(SNESNewtonTRDCPreCheck(snes, X, Y, &changed_y)); 4659566063dSJacob Faibussowitsch PetscCall(VecWAXPY(W, -1.0, Y, X)); 4669566063dSJacob Faibussowitsch PetscCall(SNESNewtonTRDCPostCheck(snes, X, Y, W, &changed_y, &changed_w)); 4679566063dSJacob Faibussowitsch if (changed_y) PetscCall(VecWAXPY(W, -1.0, Y, X)); 4689566063dSJacob Faibussowitsch PetscCall(VecCopy(Y, snes->vec_sol_update)); 4699566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, W, G)); /* F(X-Y) = G */ 4709566063dSJacob Faibussowitsch PetscCall(VecNorm(G, NORM_2, &gnorm)); /* gnorm <- || g || */ 47141ba4c6cSHeeho Park SNESCheckFunctionNorm(snes, gnorm); 47241ba4c6cSHeeho Park g = 0.5 * PetscSqr(gnorm); /* minimizing function g(W) */ 47341ba4c6cSHeeho Park if (f0 == mp) rho = 0.0; 47441ba4c6cSHeeho Park else rho = (f0 - g) / (f0 - mp); /* actual improvement over predicted improvement */ 47541ba4c6cSHeeho Park 47641ba4c6cSHeeho Park if (rho < neP->eta2) { 47741ba4c6cSHeeho Park delta *= neP->t1; /* shrink the region */ 47841ba4c6cSHeeho Park } else if (rho > neP->eta3) { 47941ba4c6cSHeeho Park delta = PetscMin(neP->t2 * delta, deltaM); /* expand the region, but not greater than deltaM */ 48041ba4c6cSHeeho Park } 48141ba4c6cSHeeho Park 48241ba4c6cSHeeho Park neP->delta = delta; 48341ba4c6cSHeeho Park if (rho >= neP->eta1) { 48441ba4c6cSHeeho Park /* unscale delta and xnorm before going to the next outer iteration */ 48541ba4c6cSHeeho Park if (bs > 1 && neP->auto_scale_multiphase) { 48641ba4c6cSHeeho Park neP->delta = delta / xnorm; 48741ba4c6cSHeeho Park xnorm = temp_xnorm; 48841ba4c6cSHeeho Park ynorm = temp_ynorm; 48941ba4c6cSHeeho Park } 49041ba4c6cSHeeho Park neP->rho_satisfied = PETSC_TRUE; 49141ba4c6cSHeeho Park break; /* the improvement ratio is satisfactory */ 49241ba4c6cSHeeho Park } 4939566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Trying again in smaller region\n")); 49441ba4c6cSHeeho Park 49541ba4c6cSHeeho Park /* check to see if progress is hopeless */ 49641ba4c6cSHeeho Park neP->itflag = PETSC_FALSE; 49741ba4c6cSHeeho Park /* both delta, ynorm, and xnorm are either scaled or unscaled */ 4989566063dSJacob Faibussowitsch PetscCall(SNESTRDC_Converged_Private(snes, snes->iter, xnorm, ynorm, fnorm, &reason, snes->cnvP)); 49941ba4c6cSHeeho Park /* if multiphase state changes, break out inner iteration */ 50041ba4c6cSHeeho Park if (reason == SNES_BREAKOUT_INNER_ITER) { 50141ba4c6cSHeeho Park if (bs > 1 && neP->auto_scale_multiphase) { 50241ba4c6cSHeeho Park /* unscale delta and xnorm before going to the next outer iteration */ 50341ba4c6cSHeeho Park neP->delta = delta / xnorm; 50441ba4c6cSHeeho Park xnorm = temp_xnorm; 50541ba4c6cSHeeho Park ynorm = temp_ynorm; 50641ba4c6cSHeeho Park } 50741ba4c6cSHeeho Park reason = SNES_CONVERGED_ITERATING; 50841ba4c6cSHeeho Park break; 50941ba4c6cSHeeho Park } 51041ba4c6cSHeeho Park if (reason == SNES_CONVERGED_SNORM_RELATIVE) reason = SNES_DIVERGED_INNER; 51141ba4c6cSHeeho Park if (reason) { 51241ba4c6cSHeeho Park if (reason < 0) { 51341ba4c6cSHeeho Park /* We're not progressing, so return with the current iterate */ 5149566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, i + 1, fnorm)); 51541ba4c6cSHeeho Park breakout = PETSC_TRUE; 51641ba4c6cSHeeho Park break; 51741ba4c6cSHeeho Park } else if (reason > 0) { 51841ba4c6cSHeeho Park /* We're converged, so return with the current iterate and update solution */ 5199566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, i + 1, fnorm)); 52041ba4c6cSHeeho Park breakout = PETSC_FALSE; 52141ba4c6cSHeeho Park break; 52241ba4c6cSHeeho Park } 52341ba4c6cSHeeho Park } 52441ba4c6cSHeeho Park snes->numFailures++; 52541ba4c6cSHeeho Park } 52641ba4c6cSHeeho Park if (!breakout) { 52741ba4c6cSHeeho Park /* Update function and solution vectors */ 52841ba4c6cSHeeho Park fnorm = gnorm; 5299566063dSJacob Faibussowitsch PetscCall(VecCopy(G, F)); 5309566063dSJacob Faibussowitsch PetscCall(VecCopy(W, X)); 53141ba4c6cSHeeho Park /* Monitor convergence */ 5329566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 53341ba4c6cSHeeho Park snes->iter = i + 1; 53441ba4c6cSHeeho Park snes->norm = fnorm; 53541ba4c6cSHeeho Park snes->xnorm = xnorm; 53641ba4c6cSHeeho Park snes->ynorm = ynorm; 5379566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 5389566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits)); 5399566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 54041ba4c6cSHeeho Park /* Test for convergence, xnorm = || X || */ 54141ba4c6cSHeeho Park neP->itflag = PETSC_TRUE; 5429566063dSJacob Faibussowitsch if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X, NORM_2, &xnorm)); 543dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, snes->iter, xnorm, ynorm, fnorm, &reason, snes->cnvP); 54441ba4c6cSHeeho Park if (reason) break; 54541ba4c6cSHeeho Park } else break; 54641ba4c6cSHeeho Park } 54741ba4c6cSHeeho Park 5489566063dSJacob Faibussowitsch /* PetscCall(PetscFree(inorms)); */ 54941ba4c6cSHeeho Park if (i == maxits) { 5509566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", maxits)); 55141ba4c6cSHeeho Park if (!reason) reason = SNES_DIVERGED_MAX_IT; 55241ba4c6cSHeeho Park } 5539566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 55441ba4c6cSHeeho Park snes->reason = reason; 5559566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 55641ba4c6cSHeeho Park if (convtest != SNESTRDC_KSPConverged_Private) { 5579566063dSJacob Faibussowitsch PetscCall(KSPGetAndClearConvergenceTest(ksp, &ctx->convtest, &ctx->convctx, &ctx->convdestroy)); 5589566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 5599566063dSJacob Faibussowitsch PetscCall(KSPSetConvergenceTest(ksp, convtest, convctx, convdestroy)); 56041ba4c6cSHeeho Park } 5613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56241ba4c6cSHeeho Park } 56341ba4c6cSHeeho Park 564d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetUp_NEWTONTRDC(SNES snes) 565d71ae5a4SJacob Faibussowitsch { 56641ba4c6cSHeeho Park PetscFunctionBegin; 5679566063dSJacob Faibussowitsch PetscCall(SNESSetWorkVecs(snes, 6)); 5689566063dSJacob Faibussowitsch PetscCall(SNESSetUpMatrices(snes)); 5693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57041ba4c6cSHeeho Park } 57141ba4c6cSHeeho Park 57266976f2fSJacob Faibussowitsch static PetscErrorCode SNESReset_NEWTONTRDC(SNES snes) 573d71ae5a4SJacob Faibussowitsch { 57441ba4c6cSHeeho Park PetscFunctionBegin; 5753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57641ba4c6cSHeeho Park } 57741ba4c6cSHeeho Park 578d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESDestroy_NEWTONTRDC(SNES snes) 579d71ae5a4SJacob Faibussowitsch { 58041ba4c6cSHeeho Park PetscFunctionBegin; 5819566063dSJacob Faibussowitsch PetscCall(SNESReset_NEWTONTRDC(snes)); 5829566063dSJacob Faibussowitsch PetscCall(PetscFree(snes->data)); 5833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58441ba4c6cSHeeho Park } 58541ba4c6cSHeeho Park 586d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESSetFromOptions_NEWTONTRDC(SNES snes, PetscOptionItems *PetscOptionsObject) 587d71ae5a4SJacob Faibussowitsch { 58841ba4c6cSHeeho Park SNES_NEWTONTRDC *ctx = (SNES_NEWTONTRDC *)snes->data; 58941ba4c6cSHeeho Park 59041ba4c6cSHeeho Park PetscFunctionBegin; 591d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "SNES trust region options for nonlinear equations"); 5929566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_tol", "Trust region tolerance", "SNESSetTrustRegionTolerance", snes->deltatol, &snes->deltatol, NULL)); 5939566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_eta1", "eta1", "None", ctx->eta1, &ctx->eta1, NULL)); 5949566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_eta2", "eta2", "None", ctx->eta2, &ctx->eta2, NULL)); 5959566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_eta3", "eta3", "None", ctx->eta3, &ctx->eta3, NULL)); 5969566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_t1", "t1", "None", ctx->t1, &ctx->t1, NULL)); 5979566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_t2", "t2", "None", ctx->t2, &ctx->t2, NULL)); 5989566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_deltaM", "deltaM", "None", ctx->deltaM, &ctx->deltaM, NULL)); 5999566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_delta0", "delta0", "None", ctx->delta0, &ctx->delta0, NULL)); 6009566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_trdc_auto_scale_max", "auto_scale_max", "None", ctx->auto_scale_max, &ctx->auto_scale_max, NULL)); 6019566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_trdc_use_cauchy", "use_cauchy", "use Cauchy step and direction", ctx->use_cauchy, &ctx->use_cauchy, NULL)); 6029566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_trdc_auto_scale_multiphase", "auto_scale_multiphase", "Auto scaling for proper cauchy direction", ctx->auto_scale_multiphase, &ctx->auto_scale_multiphase, NULL)); 603d0609cedSBarry Smith PetscOptionsHeadEnd(); 6043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 60541ba4c6cSHeeho Park } 60641ba4c6cSHeeho Park 607d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_NEWTONTRDC(SNES snes, PetscViewer viewer) 608d71ae5a4SJacob Faibussowitsch { 60941ba4c6cSHeeho Park SNES_NEWTONTRDC *tr = (SNES_NEWTONTRDC *)snes->data; 61041ba4c6cSHeeho Park PetscBool iascii; 61141ba4c6cSHeeho Park 61241ba4c6cSHeeho Park PetscFunctionBegin; 6139566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 61441ba4c6cSHeeho Park if (iascii) { 61563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Trust region tolerance %g (-snes_trtol)\n", (double)snes->deltatol)); 6169566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " eta1=%g, eta2=%g, eta3=%g\n", (double)tr->eta1, (double)tr->eta2, (double)tr->eta3)); 6179566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " delta0=%g, t1=%g, t2=%g, deltaM=%g\n", (double)tr->delta0, (double)tr->t1, (double)tr->t2, (double)tr->deltaM)); 61841ba4c6cSHeeho Park } 6193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62041ba4c6cSHeeho Park } 621f6dfbefdSBarry Smith 62241ba4c6cSHeeho Park /*MC 62341ba4c6cSHeeho Park SNESNEWTONTRDC - Newton based nonlinear solver that uses trust-region dogleg method with Cauchy direction 62441ba4c6cSHeeho Park 625f6dfbefdSBarry Smith Options Database Keys: 62641ba4c6cSHeeho Park + -snes_trdc_tol <tol> - trust region tolerance 62741ba4c6cSHeeho Park . -snes_trdc_eta1 <eta1> - trust region parameter 0.0 <= eta1 <= eta2, rho >= eta1 breaks out of the inner iteration (default: eta1=0.001) 62841ba4c6cSHeeho Park . -snes_trdc_eta2 <eta2> - trust region parameter 0.0 <= eta1 <= eta2, rho <= eta2 shrinks the trust region (default: eta2=0.25) 62941ba4c6cSHeeho Park . -snes_trdc_eta3 <eta3> - trust region parameter eta3 > eta2, rho >= eta3 expands the trust region (default: eta3=0.75) 63041ba4c6cSHeeho Park . -snes_trdc_t1 <t1> - trust region parameter, shrinking factor of trust region (default: 0.25) 63141ba4c6cSHeeho Park . -snes_trdc_t2 <t2> - trust region parameter, expanding factor of trust region (default: 2.0) 6321d27aa22SBarry Smith . -snes_trdc_deltaM <deltaM> - trust region parameter, max size of trust region, $deltaM*norm2(x)$ (default: 0.5) 6331d27aa22SBarry Smith . -snes_trdc_delta0 <delta0> - trust region parameter, initial size of trust region, $delta0*norm2(x)$ (default: 0.1) 63441ba4c6cSHeeho Park . -snes_trdc_auto_scale_max <auto_scale_max> - used with auto_scale_multiphase, caps the maximum auto-scaling factor 63541ba4c6cSHeeho Park . -snes_trdc_use_cauchy <use_cauchy> - True uses dogleg Cauchy (Steepest Descent direction) step & direction in the trust region algorithm 63641ba4c6cSHeeho Park - -snes_trdc_auto_scale_multiphase <auto_scale_multiphase> - True turns on auto-scaling for multivariable block matrix for Cauchy and trust region 63741ba4c6cSHeeho Park 63820f4b53cSBarry Smith Level: intermediate 63920f4b53cSBarry Smith 6401d27aa22SBarry Smith Note: 6411d27aa22SBarry Smith See {cite}`park2021linear` 64241ba4c6cSHeeho Park 643420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONLS`, `SNESSetTrustRegionTolerance()`, 644f6dfbefdSBarry Smith `SNESNewtonTRDCPreCheck()`, `SNESNewtonTRDCGetPreCheck()`, `SNESNewtonTRDCSetPostCheck()`, `SNESNewtonTRDCGetPostCheck()`, 645f6dfbefdSBarry Smith `SNESNewtonTRDCGetRhoFlag()`, `SNESNewtonTRDCSetPreCheck()` 64641ba4c6cSHeeho Park M*/ 647d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONTRDC(SNES snes) 648d71ae5a4SJacob Faibussowitsch { 64941ba4c6cSHeeho Park SNES_NEWTONTRDC *neP; 65041ba4c6cSHeeho Park 65141ba4c6cSHeeho Park PetscFunctionBegin; 65241ba4c6cSHeeho Park snes->ops->setup = SNESSetUp_NEWTONTRDC; 65341ba4c6cSHeeho Park snes->ops->solve = SNESSolve_NEWTONTRDC; 65441ba4c6cSHeeho Park snes->ops->destroy = SNESDestroy_NEWTONTRDC; 65541ba4c6cSHeeho Park snes->ops->setfromoptions = SNESSetFromOptions_NEWTONTRDC; 65641ba4c6cSHeeho Park snes->ops->view = SNESView_NEWTONTRDC; 65741ba4c6cSHeeho Park snes->ops->reset = SNESReset_NEWTONTRDC; 65841ba4c6cSHeeho Park 65941ba4c6cSHeeho Park snes->usesksp = PETSC_TRUE; 66041ba4c6cSHeeho Park snes->usesnpc = PETSC_FALSE; 66141ba4c6cSHeeho Park 66241ba4c6cSHeeho Park snes->alwayscomputesfinalresidual = PETSC_TRUE; 66341ba4c6cSHeeho Park 664*77e5a1f9SBarry Smith PetscCall(SNESParametersInitialize(snes)); 665*77e5a1f9SBarry Smith PetscObjectParameterSetDefault(snes, deltatol, 1.e-12); 666*77e5a1f9SBarry Smith 6674dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&neP)); 66841ba4c6cSHeeho Park snes->data = (void *)neP; 66941ba4c6cSHeeho Park neP->delta = 0.0; 67041ba4c6cSHeeho Park neP->delta0 = 0.1; 67141ba4c6cSHeeho Park neP->eta1 = 0.001; 67241ba4c6cSHeeho Park neP->eta2 = 0.25; 67341ba4c6cSHeeho Park neP->eta3 = 0.75; 67441ba4c6cSHeeho Park neP->t1 = 0.25; 67541ba4c6cSHeeho Park neP->t2 = 2.0; 67641ba4c6cSHeeho Park neP->deltaM = 0.5; 67741ba4c6cSHeeho Park neP->sigma = 0.0001; 67841ba4c6cSHeeho Park neP->itflag = PETSC_FALSE; 67941ba4c6cSHeeho Park neP->rnorm0 = 0.0; 68041ba4c6cSHeeho Park neP->ttol = 0.0; 68141ba4c6cSHeeho Park neP->use_cauchy = PETSC_TRUE; 68241ba4c6cSHeeho Park neP->auto_scale_multiphase = PETSC_FALSE; 68341ba4c6cSHeeho Park neP->auto_scale_max = -1.0; 68441ba4c6cSHeeho Park neP->rho_satisfied = PETSC_FALSE; 68541ba4c6cSHeeho Park 68641ba4c6cSHeeho Park /* for multiphase (multivariable) scaling */ 68741ba4c6cSHeeho Park /* may be used for dynamic allocation of inorms, but it fails snes_tutorials-ex3_13 68841ba4c6cSHeeho Park on test forced DIVERGED_JACOBIAN_DOMAIN test. I will use static array for now. 6899566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(snes->work[0],&neP->bs)); 6909566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(neP->bs,&neP->inorms)); 69141ba4c6cSHeeho Park */ 6923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 69341ba4c6cSHeeho Park } 694