113a62661SPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 219653cdaSPeter Brune #include <petscblaslapack.h> 3fced5a79SAsbjørn Nilsen Riseth #include <petscdm.h> 4a312c225SMatthew G Knepley 59e5d0892SLisandro Dalcin const char *const SNESNGMRESRestartTypes[] = {"NONE", "PERIODIC", "DIFFERENCE", "SNESNGMRESRestartType", "SNES_NGMRES_RESTART_", NULL}; 69e5d0892SLisandro Dalcin const char *const SNESNGMRESSelectTypes[] = {"NONE", "DIFFERENCE", "LINESEARCH", "SNESNGMRESSelectType", "SNES_NGMRES_SELECT_", NULL}; 713a62661SPeter Brune 89371c9d4SSatish Balay PetscErrorCode SNESReset_NGMRES(SNES snes) { 9a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 10a312c225SMatthew G Knepley 11a312c225SMatthew G Knepley PetscFunctionBegin; 129566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Fdot)); 139566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Xdot)); 149566063dSJacob Faibussowitsch PetscCall(SNESLineSearchDestroy(&ngmres->additive_linesearch)); 15a312c225SMatthew G Knepley PetscFunctionReturn(0); 16a312c225SMatthew G Knepley } 17a312c225SMatthew G Knepley 189371c9d4SSatish Balay PetscErrorCode SNESDestroy_NGMRES(SNES snes) { 1978440776SJed Brown SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 20a312c225SMatthew G Knepley 21a312c225SMatthew G Knepley PetscFunctionBegin; 229566063dSJacob Faibussowitsch PetscCall(SNESReset_NGMRES(snes)); 239566063dSJacob Faibussowitsch PetscCall(PetscFree4(ngmres->h, ngmres->beta, ngmres->xi, ngmres->q)); 249566063dSJacob Faibussowitsch PetscCall(PetscFree3(ngmres->xnorms, ngmres->fnorms, ngmres->s)); 25dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX) 269566063dSJacob Faibussowitsch PetscCall(PetscFree(ngmres->rwork)); 2719653cdaSPeter Brune #endif 289566063dSJacob Faibussowitsch PetscCall(PetscFree(ngmres->work)); 292e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", NULL)); 302e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", NULL)); 312e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", NULL)); 322e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", NULL)); 339566063dSJacob Faibussowitsch PetscCall(PetscFree(snes->data)); 34a312c225SMatthew G Knepley PetscFunctionReturn(0); 35a312c225SMatthew G Knepley } 36a312c225SMatthew G Knepley 379371c9d4SSatish Balay PetscErrorCode SNESSetUp_NGMRES(SNES snes) { 38a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 39e7058c64SPeter Brune const char *optionsprefix; 4019653cdaSPeter Brune PetscInt msize, hsize; 41fced5a79SAsbjørn Nilsen Riseth DM dm; 42a312c225SMatthew G Knepley 43a312c225SMatthew G Knepley PetscFunctionBegin; 44efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { 4546159c86SPeter Brune SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNGMRES does not support left preconditioning with unpreconditioned function"); 4646159c86SPeter Brune } 47efd4aadfSBarry Smith if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED; 489566063dSJacob Faibussowitsch PetscCall(SNESSetWorkVecs(snes, 5)); 49fced5a79SAsbjørn Nilsen Riseth 50fced5a79SAsbjørn Nilsen Riseth if (!snes->vec_sol) { 519566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 529566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(dm, &snes->vec_sol)); 53fced5a79SAsbjørn Nilsen Riseth } 54fced5a79SAsbjørn Nilsen Riseth 559566063dSJacob Faibussowitsch if (!ngmres->Xdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Xdot)); 569566063dSJacob Faibussowitsch if (!ngmres->Fdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Fdot)); 5778440776SJed Brown if (!ngmres->setup_called) { 58087dfb9eSxuemin msize = ngmres->msize; /* restart size */ 5919653cdaSPeter Brune hsize = msize * msize; 60087dfb9eSxuemin 6198b3e84cSPeter Brune /* explicit least squares minimization solve */ 629566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(hsize, &ngmres->h, msize, &ngmres->beta, msize, &ngmres->xi, hsize, &ngmres->q)); 639566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(msize, &ngmres->xnorms, msize, &ngmres->fnorms, msize, &ngmres->s)); 6419653cdaSPeter Brune ngmres->nrhs = 1; 6519653cdaSPeter Brune ngmres->lda = msize; 6619653cdaSPeter Brune ngmres->ldb = msize; 6719653cdaSPeter Brune ngmres->lwork = 12 * msize; 68dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX) 699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->rwork)); 7019653cdaSPeter Brune #endif 719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->work)); 7278440776SJed Brown } 73e7058c64SPeter Brune 74e7058c64SPeter Brune /* linesearch setup */ 759566063dSJacob Faibussowitsch PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix)); 76e7058c64SPeter Brune 7713a62661SPeter Brune if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 789566063dSJacob Faibussowitsch PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &ngmres->additive_linesearch)); 799566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch, snes)); 8048a46eb9SPierre Jolivet if (!((PetscObject)ngmres->additive_linesearch)->type_name) PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2)); 819566063dSJacob Faibussowitsch PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_")); 829566063dSJacob Faibussowitsch PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix)); 839566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetFromOptions(ngmres->additive_linesearch)); 84e7058c64SPeter Brune } 85e7058c64SPeter Brune 8678440776SJed Brown ngmres->setup_called = PETSC_TRUE; 87a312c225SMatthew G Knepley PetscFunctionReturn(0); 88a312c225SMatthew G Knepley } 89a312c225SMatthew G Knepley 909371c9d4SSatish Balay PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes, PetscOptionItems *PetscOptionsObject) { 91a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 9294ae4db5SBarry Smith PetscBool debug = PETSC_FALSE; 930adebc6cSBarry Smith 94a312c225SMatthew G Knepley PetscFunctionBegin; 95d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "SNES NGMRES options"); 96d0609cedSBarry Smith PetscCall(PetscOptionsEnum("-snes_ngmres_select_type", "Select type", "SNESNGMRESSetSelectType", SNESNGMRESSelectTypes, (PetscEnum)ngmres->select_type, (PetscEnum *)&ngmres->select_type, NULL)); 97d0609cedSBarry Smith PetscCall(PetscOptionsEnum("-snes_ngmres_restart_type", "Restart type", "SNESNGMRESSetRestartType", SNESNGMRESRestartTypes, (PetscEnum)ngmres->restart_type, (PetscEnum *)&ngmres->restart_type, NULL)); 989566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES", ngmres->candidate, &ngmres->candidate, NULL)); 999566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_approxfunc", "Linearly approximate the function", "SNES", ngmres->approxfunc, &ngmres->approxfunc, NULL)); 1009566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, NULL)); 1019566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES", ngmres->restart_periodic, &ngmres->restart_periodic, NULL)); 1029566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart", "SNES", ngmres->restart_it, &ngmres->restart_it, NULL)); 1039566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL)); 104ad540459SPierre Jolivet if (debug) ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes)); 1059566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, NULL)); 1069566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, NULL)); 1079566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, NULL)); 1089566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, NULL)); 1099566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES", ngmres->singlereduction, &ngmres->singlereduction, NULL)); 1109566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise", ngmres->restart_fm_rise, &ngmres->restart_fm_rise, NULL)); 111d0609cedSBarry Smith PetscOptionsHeadEnd(); 1126a7cf640SPeter Brune if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA; 113a312c225SMatthew G Knepley PetscFunctionReturn(0); 114a312c225SMatthew G Knepley } 115a312c225SMatthew G Knepley 1169371c9d4SSatish Balay PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer) { 117a312c225SMatthew G Knepley SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 118a312c225SMatthew G Knepley PetscBool iascii; 119a312c225SMatthew G Knepley 120a312c225SMatthew G Knepley PetscFunctionBegin; 1219566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 122a312c225SMatthew G Knepley if (iascii) { 12363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize)); 12463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", (double)ngmres->gammaA, (double)ngmres->gammaC)); 12563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", (double)ngmres->epsilonB, (double)ngmres->deltaB)); 12663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Restart on F_M residual increase: %s\n", PetscBools[ngmres->restart_fm_rise])); 127a312c225SMatthew G Knepley } 128a312c225SMatthew G Knepley PetscFunctionReturn(0); 129a312c225SMatthew G Knepley } 130a312c225SMatthew G Knepley 1319371c9d4SSatish Balay PetscErrorCode SNESSolve_NGMRES(SNES snes) { 132087dfb9eSxuemin SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 13398b3e84cSPeter Brune /* present solution, residual, and preconditioned residual */ 1349f425c49SPeter Brune Vec X, F, B, D, Y; 135f109b39eSPeter Brune 136f109b39eSPeter Brune /* candidate linear combination answers */ 137ddd40ce5SPeter Brune Vec XA, FA, XM, FM; 13819653cdaSPeter Brune 13998b3e84cSPeter Brune /* coefficients and RHS to the minimization problem */ 14018aa0c0cSPeter Brune PetscReal fnorm, fMnorm, fAnorm; 141b3c6a99cSPeter Brune PetscReal xnorm, xMnorm, xAnorm; 142b3c6a99cSPeter Brune PetscReal ynorm, yMnorm, yAnorm; 14338774f0aSPeter Brune PetscInt k, k_restart, l, ivec, restart_count = 0; 14419653cdaSPeter Brune 14598b3e84cSPeter Brune /* solution selection data */ 14638774f0aSPeter Brune PetscBool selectRestart; 14761ba4676SBarry Smith /* 14861ba4676SBarry Smith These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed 14961ba4676SBarry Smith to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case 15061ba4676SBarry Smith so the code is correct as written. 15161ba4676SBarry Smith */ 15261ba4676SBarry Smith PetscReal dnorm = 0.0, dminnorm = 0.0; 153b3c6a99cSPeter Brune PetscReal fminnorm; 15419653cdaSPeter Brune 1551e633543SBarry Smith SNESConvergedReason reason; 156422a814eSBarry Smith SNESLineSearchReason lssucceed; 157a312c225SMatthew G Knepley 158a312c225SMatthew G Knepley PetscFunctionBegin; 1590b121fc5SBarry 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); 160c579b300SPatrick Farrell 1619566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite)); 16298b3e84cSPeter Brune /* variable initialization */ 163a312c225SMatthew G Knepley snes->reason = SNES_CONVERGED_ITERATING; 164f109b39eSPeter Brune X = snes->vec_sol; 165f109b39eSPeter Brune F = snes->vec_func; 166f109b39eSPeter Brune B = snes->vec_rhs; 167f109b39eSPeter Brune XA = snes->vec_sol_update; 168f109b39eSPeter Brune FA = snes->work[0]; 169f109b39eSPeter Brune D = snes->work[1]; 170f109b39eSPeter Brune 171f109b39eSPeter Brune /* work for the line search */ 172f109b39eSPeter Brune Y = snes->work[2]; 1739f425c49SPeter Brune XM = snes->work[3]; 1749f425c49SPeter Brune FM = snes->work[4]; 175a312c225SMatthew G Knepley 1769566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 177a312c225SMatthew G Knepley snes->iter = 0; 178a312c225SMatthew G Knepley snes->norm = 0.; 1799566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 18019653cdaSPeter Brune 18198b3e84cSPeter Brune /* initialization */ 18219653cdaSPeter Brune 183efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT) { 1849566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes, X, NULL, F)); 1859566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 1863a2ae377SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 1873a2ae377SPeter Brune snes->reason = SNES_DIVERGED_INNER; 1883a2ae377SPeter Brune PetscFunctionReturn(0); 1893a2ae377SPeter Brune } 1909566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); 1913a2ae377SPeter Brune } else { 192e4ed7901SPeter Brune if (!snes->vec_func_init_set) { 1939566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, X, F)); 1941aa26658SKarl Rupp } else snes->vec_func_init_set = PETSC_FALSE; 195c1c75074SPeter Brune 1969566063dSJacob Faibussowitsch PetscCall(VecNorm(F, NORM_2, &fnorm)); 197422a814eSBarry Smith SNESCheckFunctionNorm(snes, fnorm); 1983a2ae377SPeter Brune } 199e4ed7901SPeter Brune fminnorm = fnorm; 20019653cdaSPeter Brune 2019566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 202f109b39eSPeter Brune snes->norm = fnorm; 2039566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 2049566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0)); 2059566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, 0, fnorm)); 206dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP); 207a312c225SMatthew G Knepley if (snes->reason) PetscFunctionReturn(0); 208b3c6a99cSPeter Brune SNESNGMRESUpdateSubspace_Private(snes, 0, 0, F, fnorm, X); 209a312c225SMatthew G Knepley 21019653cdaSPeter Brune k_restart = 1; 21119653cdaSPeter Brune l = 1; 212b3c6a99cSPeter Brune ivec = 0; 21309c08436SPeter Brune for (k = 1; k < snes->max_its + 1; k++) { 21498b3e84cSPeter Brune /* Computation of x^M */ 215efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_RIGHT) { 2169566063dSJacob Faibussowitsch PetscCall(VecCopy(X, XM)); 2179566063dSJacob Faibussowitsch PetscCall(SNESSetInitialFunction(snes->npc, F)); 21863e7833aSPeter Brune 2199566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, XM, B, 0)); 2209566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes->npc, B, XM)); 2219566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, XM, B, 0)); 22263e7833aSPeter Brune 2239566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 2248cc86e31SPeter Brune if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { 2258cc86e31SPeter Brune snes->reason = SNES_DIVERGED_INNER; 2268cc86e31SPeter Brune PetscFunctionReturn(0); 2278cc86e31SPeter Brune } 2289566063dSJacob Faibussowitsch PetscCall(SNESGetNPCFunction(snes, FM, &fMnorm)); 2298cc86e31SPeter Brune } else { 230f109b39eSPeter Brune /* no preconditioner -- just take gradient descent with line search */ 2319566063dSJacob Faibussowitsch PetscCall(VecCopy(F, Y)); 2329566063dSJacob Faibussowitsch PetscCall(VecCopy(F, FM)); 2339566063dSJacob Faibussowitsch PetscCall(VecCopy(X, XM)); 2341aa26658SKarl Rupp 235e7058c64SPeter Brune fMnorm = fnorm; 2361aa26658SKarl Rupp 2379566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, XM, FM, &fMnorm, Y)); 2389566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 239422a814eSBarry Smith if (lssucceed) { 240f109b39eSPeter Brune if (++snes->numFailures >= snes->maxFailures) { 241f109b39eSPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 242f109b39eSPeter Brune PetscFunctionReturn(0); 243f109b39eSPeter Brune } 244f109b39eSPeter Brune } 2456634f59bSPeter Brune } 24623b3e82cSAsbjørn Nilsen Riseth 2479566063dSJacob Faibussowitsch PetscCall(SNESNGMRESFormCombinedSolution_Private(snes, ivec, l, XM, FM, fMnorm, X, XA, FA)); 24898b3e84cSPeter Brune /* r = F(x) */ 2499f425c49SPeter Brune if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */ 25019653cdaSPeter Brune 2519f425c49SPeter Brune /* differences for selection and restart */ 25213a62661SPeter Brune if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 2539566063dSJacob Faibussowitsch PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, &dnorm, &dminnorm, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm)); 25413a62661SPeter Brune } else { 2559566063dSJacob Faibussowitsch PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, NULL, NULL, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm)); 25613a62661SPeter Brune } 257422a814eSBarry Smith SNESCheckFunctionNorm(snes, fnorm); 2581aa26658SKarl Rupp 2599f425c49SPeter Brune /* combination (additive) or selection (multiplicative) of the N-GMRES solution */ 2609566063dSJacob Faibussowitsch PetscCall(SNESNGMRESSelect_Private(snes, k_restart, XM, FM, xMnorm, fMnorm, yMnorm, XA, FA, xAnorm, fAnorm, yAnorm, dnorm, fminnorm, dminnorm, X, F, Y, &xnorm, &fnorm, &ynorm)); 26119653cdaSPeter Brune selectRestart = PETSC_FALSE; 26223b3e82cSAsbjørn Nilsen Riseth 26313a62661SPeter Brune if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { 2649566063dSJacob Faibussowitsch PetscCall(SNESNGMRESSelectRestart_Private(snes, l, fMnorm, fAnorm, dnorm, fminnorm, dminnorm, &selectRestart)); 26523b3e82cSAsbjørn Nilsen Riseth 26628ed4a04SPeter Brune /* if the restart conditions persist for more than restart_it iterations, restart. */ 2671aa26658SKarl Rupp if (selectRestart) restart_count++; 2681aa26658SKarl Rupp else restart_count = 0; 26913a62661SPeter Brune } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { 27013a62661SPeter Brune if (k_restart > ngmres->restart_periodic) { 27163a3b9bcSJacob Faibussowitsch if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %" PetscInt_FMT " iterations\n", k_restart)); 27213a62661SPeter Brune restart_count = ngmres->restart_it; 27313a62661SPeter Brune } 27413a62661SPeter Brune } 27523b3e82cSAsbjørn Nilsen Riseth 276b3c6a99cSPeter Brune ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */ 27723b3e82cSAsbjørn Nilsen Riseth 27828ed4a04SPeter Brune /* restart after restart conditions have persisted for a fixed number of iterations */ 27928ed4a04SPeter Brune if (restart_count >= ngmres->restart_it) { 28048a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %" PetscInt_FMT "\n", k_restart)); 28128ed4a04SPeter Brune restart_count = 0; 28219653cdaSPeter Brune k_restart = 1; 28319653cdaSPeter Brune l = 1; 284b3c6a99cSPeter Brune ivec = 0; 28598b3e84cSPeter Brune /* q_{00} = nu */ 2869566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes, 0, 0, FM, fMnorm, XM)); 287d2e16ddcSPeter Brune } else { 28898b3e84cSPeter Brune /* select the current size of the subspace */ 2891e633543SBarry Smith if (l < ngmres->msize) l++; 29019653cdaSPeter Brune k_restart++; 29198b3e84cSPeter Brune /* place the current entry in the list of previous entries */ 29238774f0aSPeter Brune if (ngmres->candidate) { 29338774f0aSPeter Brune if (fminnorm > fMnorm) fminnorm = fMnorm; 2949566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, FM, fMnorm, XM)); 295d2e16ddcSPeter Brune } else { 29638774f0aSPeter Brune if (fminnorm > fnorm) fminnorm = fnorm; 2979566063dSJacob Faibussowitsch PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, F, fnorm, X)); 29819653cdaSPeter Brune } 299d2e16ddcSPeter Brune } 30019653cdaSPeter Brune 3019566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 302087dfb9eSxuemin snes->iter = k; 303f109b39eSPeter Brune snes->norm = fnorm; 3049566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 3059566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes, snes->norm, snes->iter)); 3069566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 307dbbe0bcdSBarry Smith PetscUseTypeMethod(snes, converged, snes->iter, 0, 0, fnorm, &snes->reason, snes->cnvP); 308087dfb9eSxuemin if (snes->reason) PetscFunctionReturn(0); 309a312c225SMatthew G Knepley } 310a312c225SMatthew G Knepley snes->reason = SNES_DIVERGED_MAX_IT; 311a312c225SMatthew G Knepley PetscFunctionReturn(0); 312a312c225SMatthew G Knepley } 313a312c225SMatthew G Knepley 31423b3e82cSAsbjørn Nilsen Riseth /*@ 31523b3e82cSAsbjørn Nilsen Riseth SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M 31623b3e82cSAsbjørn Nilsen Riseth 31723b3e82cSAsbjørn Nilsen Riseth Input Parameters: 318f6dfbefdSBarry Smith + snes - the `SNES` context. 319f6dfbefdSBarry Smith - flg - boolean value deciding whether to use the option or not, default is `PETSC_FALSE` 32023b3e82cSAsbjørn Nilsen Riseth 321f6dfbefdSBarry Smith Options Database Key: 322f6dfbefdSBarry Smith . -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M 32323b3e82cSAsbjørn Nilsen Riseth 32423b3e82cSAsbjørn Nilsen Riseth Level: intermediate 32523b3e82cSAsbjørn Nilsen Riseth 32623b3e82cSAsbjørn Nilsen Riseth Notes: 32723b3e82cSAsbjørn Nilsen Riseth If the proposed step x_M increases the residual F_M, it might be trying to get out of a stagnation area. 32823b3e82cSAsbjørn Nilsen Riseth To help the solver do that, reset the Krylov subspace whenever F_M increases. 32923b3e82cSAsbjørn Nilsen Riseth 330f6dfbefdSBarry Smith This option must be used with the `SNESNGMRES` `SNESNGMRESRestartType` of `SNES_NGMRES_RESTART_DIFFERENCE` 33123b3e82cSAsbjørn Nilsen Riseth 332f6dfbefdSBarry Smith .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartType()` 33323b3e82cSAsbjørn Nilsen Riseth @*/ 3349371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes, PetscBool flg) { 33523b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES, PetscBool); 33623b3e82cSAsbjørn Nilsen Riseth 33723b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3389566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", &f)); 3399566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes, flg)); 34023b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 34123b3e82cSAsbjørn Nilsen Riseth } 34223b3e82cSAsbjørn Nilsen Riseth 3439371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes, PetscBool flg) { 34423b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 34523b3e82cSAsbjørn Nilsen Riseth 34623b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 34723b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = flg; 34823b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 34923b3e82cSAsbjørn Nilsen Riseth } 35023b3e82cSAsbjørn Nilsen Riseth 3519371c9d4SSatish Balay PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes, PetscBool *flg) { 35223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES, PetscBool *); 35323b3e82cSAsbjørn Nilsen Riseth 35423b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3559566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", &f)); 3569566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes, flg)); 35723b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 35823b3e82cSAsbjørn Nilsen Riseth } 35923b3e82cSAsbjørn Nilsen Riseth 3609371c9d4SSatish Balay PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes, PetscBool *flg) { 36123b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 36223b3e82cSAsbjørn Nilsen Riseth 36323b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 36423b3e82cSAsbjørn Nilsen Riseth *flg = ngmres->restart_fm_rise; 36523b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 36623b3e82cSAsbjørn Nilsen Riseth } 36723b3e82cSAsbjørn Nilsen Riseth 36813a62661SPeter Brune /*@ 369f6dfbefdSBarry Smith SNESNGMRESSetRestartType - Sets the restart type for `SNESNGMRES`. 37013a62661SPeter Brune 371f6dfbefdSBarry Smith Logically Collective on snes 37213a62661SPeter Brune 37313a62661SPeter Brune Input Parameters: 37413a62661SPeter Brune + snes - the iterative context 37513a62661SPeter Brune - rtype - restart type 37613a62661SPeter Brune 377f6dfbefdSBarry Smith Options Databas Keys: 37813a62661SPeter Brune + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 3790c777b0cSPeter Brune - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 38013a62661SPeter Brune 381f6dfbefdSBarry Smith `SNESNGMRESRestartType`s: 382f6dfbefdSBarry Smith + `SNES_NGMRES_RESTART_NONE` - never restart 383f6dfbefdSBarry Smith . `SNES_NGMRES_RESTART_DIFFERENCE` - restart based upon difference criteria 384f6dfbefdSBarry Smith - `SNES_NGMRES_RESTART_PERIODIC` - restart after a fixed number of iterations 385f6dfbefdSBarry Smith 38613a62661SPeter Brune Level: intermediate 38713a62661SPeter Brune 388f6dfbefdSBarry Smith .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartFmRise()` 38913a62661SPeter Brune @*/ 3909371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype) { 39113a62661SPeter Brune PetscFunctionBegin; 39213a62661SPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 393cac4c232SBarry Smith PetscTryMethod(snes, "SNESNGMRESSetRestartType_C", (SNES, SNESNGMRESRestartType), (snes, rtype)); 39413a62661SPeter Brune PetscFunctionReturn(0); 39513a62661SPeter Brune } 39613a62661SPeter Brune 39713a62661SPeter Brune /*@ 398f6dfbefdSBarry Smith SNESNGMRESSetSelectType - Sets the selection type for `SNESNGMRES`. This determines how the candidate solution and 39913a62661SPeter Brune combined solution are used to create the next iterate. 40013a62661SPeter Brune 401f6dfbefdSBarry Smith Logically Collective on snes 40213a62661SPeter Brune 40313a62661SPeter Brune Input Parameters: 40413a62661SPeter Brune + snes - the iterative context 40513a62661SPeter Brune - stype - selection type 40613a62661SPeter Brune 407f6dfbefdSBarry Smith Options Database Key: 40867b8a455SSatish Balay . -snes_ngmres_select_type<difference,none,linesearch> - select type 40913a62661SPeter Brune 41013a62661SPeter Brune Level: intermediate 41113a62661SPeter Brune 412f6dfbefdSBarry Smith `SNESNGMRESSelectType`s: 413f6dfbefdSBarry Smith + `SNES_NGMRES_SELECT_NONE` - choose the combined solution all the time 414f6dfbefdSBarry Smith . `SNES_NGMRES_SELECT_DIFFERENCE` - choose based upon the selection criteria 415f6dfbefdSBarry Smith - `SNES_NGMRES_SELECT_LINESEARCH` - choose based upon line search combination 41613a62661SPeter Brune 417f6dfbefdSBarry Smith Note: 418f6dfbefdSBarry Smith The default line search used is the `SNESLINESEARCHL2` line search and it requires two additional function evaluations. 41913a62661SPeter Brune 420f6dfbefdSBarry Smith .seealso: `SNESNGMRESSelectType()`, `SNES_NGMRES_SELECT_NONE`, `SNES_NGMRES_SELECT_DIFFERENCE`, `SNES_NGMRES_SELECT_LINESEARCH` 42113a62661SPeter Brune @*/ 4229371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype) { 42313a62661SPeter Brune PetscFunctionBegin; 42413a62661SPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 425cac4c232SBarry Smith PetscTryMethod(snes, "SNESNGMRESSetSelectType_C", (SNES, SNESNGMRESSelectType), (snes, stype)); 42613a62661SPeter Brune PetscFunctionReturn(0); 42713a62661SPeter Brune } 42813a62661SPeter Brune 4299371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype) { 43013a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 4315fd66863SKarl Rupp 43213a62661SPeter Brune PetscFunctionBegin; 43313a62661SPeter Brune ngmres->select_type = stype; 43413a62661SPeter Brune PetscFunctionReturn(0); 43513a62661SPeter Brune } 43613a62661SPeter Brune 4379371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype) { 43813a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 4395fd66863SKarl Rupp 44013a62661SPeter Brune PetscFunctionBegin; 44113a62661SPeter Brune ngmres->restart_type = rtype; 44213a62661SPeter Brune PetscFunctionReturn(0); 44313a62661SPeter Brune } 44413a62661SPeter Brune 445dfbf837cSBarry Smith /*MC 4461867fe5bSPeter Brune SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 447a312c225SMatthew G Knepley 448dfbf837cSBarry Smith Level: beginner 449dfbf837cSBarry Smith 450f6dfbefdSBarry Smith Options Database Keys: 45113a62661SPeter Brune + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 45238774f0aSPeter Brune . -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 453f6dfbefdSBarry Smith . -snes_ngmres_candidate - Use `SNESNGMRES` variant which combines candidate solutions instead of actual solutions 45413a62661SPeter Brune . -snes_ngmres_m - Number of stored previous solutions and residuals 45513a62661SPeter Brune . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 45613a62661SPeter Brune . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 45713a62661SPeter Brune . -snes_ngmres_gammaC - Residual tolerance for restart 45813a62661SPeter Brune . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 45913a62661SPeter Brune . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 46023b3e82cSAsbjørn Nilsen Riseth . -snes_ngmres_restart_fm_rise - Restart on residual rise from x_M step 46113a62661SPeter Brune . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 4625c3e6ab7SPeter Brune . -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother 46313a62661SPeter Brune - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 4641867fe5bSPeter Brune 4651867fe5bSPeter Brune Notes: 4661867fe5bSPeter Brune The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 4671867fe5bSPeter Brune optimization problem at each iteration. 4681867fe5bSPeter Brune 469f6dfbefdSBarry Smith Very similar to the `SNESANDERSON` algorithm. 4704f02bc6aSBarry Smith 4711867fe5bSPeter Brune References: 472606c0280SSatish Balay + * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", 473dfbf837cSBarry Smith SIAM Journal on Scientific Computing, 21(5), 2000. 474606c0280SSatish Balay - * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 4754f02bc6aSBarry Smith SIAM Review, 57(4), 2015 4764f02bc6aSBarry Smith 477f6dfbefdSBarry Smith .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESANDERSON`, `SNESNGMRESSetSelectType()`, `SNESNGMRESSetRestartType()`, 478f6dfbefdSBarry Smith `SNESNGMRESSetRestartFmRise()` 479dfbf837cSBarry Smith M*/ 480a312c225SMatthew G Knepley 4819371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes) { 482a312c225SMatthew G Knepley SNES_NGMRES *ngmres; 483d8d34be6SBarry Smith SNESLineSearch linesearch; 484a312c225SMatthew G Knepley 485a312c225SMatthew G Knepley PetscFunctionBegin; 486a312c225SMatthew G Knepley snes->ops->destroy = SNESDestroy_NGMRES; 487a312c225SMatthew G Knepley snes->ops->setup = SNESSetUp_NGMRES; 488a312c225SMatthew G Knepley snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 489a312c225SMatthew G Knepley snes->ops->view = SNESView_NGMRES; 490a312c225SMatthew G Knepley snes->ops->solve = SNESSolve_NGMRES; 491a312c225SMatthew G Knepley snes->ops->reset = SNESReset_NGMRES; 492a312c225SMatthew G Knepley 493efd4aadfSBarry Smith snes->usesnpc = PETSC_TRUE; 4942c155ee1SBarry Smith snes->usesksp = PETSC_FALSE; 495efd4aadfSBarry Smith snes->npcside = PC_RIGHT; 4962c155ee1SBarry Smith 4974fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 4984fc747eaSLawrence Mitchell 499*4dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&ngmres)); 500a312c225SMatthew G Knepley snes->data = (void *)ngmres; 501d2e16ddcSPeter Brune ngmres->msize = 30; 50219653cdaSPeter Brune 50388976e71SPeter Brune if (!snes->tolerancesset) { 5040e444f03SPeter Brune snes->max_funcs = 30000; 5050e444f03SPeter Brune snes->max_its = 10000; 50688976e71SPeter Brune } 5070e444f03SPeter Brune 50838774f0aSPeter Brune ngmres->candidate = PETSC_FALSE; 509d2e16ddcSPeter Brune 5109566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 51148a46eb9SPierre Jolivet if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC)); 512d8d34be6SBarry Smith 5130298fd71SBarry Smith ngmres->additive_linesearch = NULL; 514077c4231SPeter Brune ngmres->approxfunc = PETSC_FALSE; 51528ed4a04SPeter Brune ngmres->restart_it = 2; 51613a62661SPeter Brune ngmres->restart_periodic = 30; 517f109b39eSPeter Brune ngmres->gammaA = 2.0; 518f109b39eSPeter Brune ngmres->gammaC = 2.0; 519cac108bcSPeter Brune ngmres->deltaB = 0.9; 520cac108bcSPeter Brune ngmres->epsilonB = 0.1; 52123b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = PETSC_FALSE; 522e7058c64SPeter Brune 52313a62661SPeter Brune ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 52413a62661SPeter Brune ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 52513a62661SPeter Brune 5269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", SNESNGMRESSetSelectType_NGMRES)); 5279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", SNESNGMRESSetRestartType_NGMRES)); 5289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", SNESNGMRESSetRestartFmRise_NGMRES)); 5299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", SNESNGMRESGetRestartFmRise_NGMRES)); 530a312c225SMatthew G Knepley PetscFunctionReturn(0); 531a312c225SMatthew G Knepley } 532