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)); 80*48a46eb9SPierre 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)); 1049371c9d4SSatish Balay 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) { 280*48a46eb9SPierre 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: 31823b3e82cSAsbjørn Nilsen Riseth + snes - the SNES context. 31923b3e82cSAsbjørn Nilsen Riseth - flg - boolean value deciding whether to use the option or not 32023b3e82cSAsbjørn Nilsen Riseth 32123b3e82cSAsbjørn Nilsen Riseth Options Database: 32223b3e82cSAsbjørn Nilsen Riseth + -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 33023b3e82cSAsbjørn Nilsen Riseth This option must be used with SNES_NGMRES_RESTART_DIFFERENCE 33123b3e82cSAsbjørn Nilsen Riseth 33223b3e82cSAsbjørn Nilsen Riseth The default is FALSE. 333db781477SPatrick Sanan .seealso: `SNES_NGMRES_RESTART_DIFFERENCE` 33423b3e82cSAsbjørn Nilsen Riseth @*/ 3359371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes, PetscBool flg) { 33623b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES, PetscBool); 33723b3e82cSAsbjørn Nilsen Riseth 33823b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3399566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", &f)); 3409566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes, flg)); 34123b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 34223b3e82cSAsbjørn Nilsen Riseth } 34323b3e82cSAsbjørn Nilsen Riseth 3449371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes, PetscBool flg) { 34523b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 34623b3e82cSAsbjørn Nilsen Riseth 34723b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 34823b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = flg; 34923b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 35023b3e82cSAsbjørn Nilsen Riseth } 35123b3e82cSAsbjørn Nilsen Riseth 3529371c9d4SSatish Balay PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes, PetscBool *flg) { 35323b3e82cSAsbjørn Nilsen Riseth PetscErrorCode (*f)(SNES, PetscBool *); 35423b3e82cSAsbjørn Nilsen Riseth 35523b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 3569566063dSJacob Faibussowitsch PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", &f)); 3579566063dSJacob Faibussowitsch if (f) PetscCall((f)(snes, flg)); 35823b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 35923b3e82cSAsbjørn Nilsen Riseth } 36023b3e82cSAsbjørn Nilsen Riseth 3619371c9d4SSatish Balay PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes, PetscBool *flg) { 36223b3e82cSAsbjørn Nilsen Riseth SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 36323b3e82cSAsbjørn Nilsen Riseth 36423b3e82cSAsbjørn Nilsen Riseth PetscFunctionBegin; 36523b3e82cSAsbjørn Nilsen Riseth *flg = ngmres->restart_fm_rise; 36623b3e82cSAsbjørn Nilsen Riseth PetscFunctionReturn(0); 36723b3e82cSAsbjørn Nilsen Riseth } 36823b3e82cSAsbjørn Nilsen Riseth 36913a62661SPeter Brune /*@ 37013a62661SPeter Brune SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES. 37113a62661SPeter Brune 37213a62661SPeter Brune Logically Collective on SNES 37313a62661SPeter Brune 37413a62661SPeter Brune Input Parameters: 37513a62661SPeter Brune + snes - the iterative context 37613a62661SPeter Brune - rtype - restart type 37713a62661SPeter Brune 37813a62661SPeter Brune Options Database: 37913a62661SPeter Brune + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type 3800c777b0cSPeter Brune - -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic 38113a62661SPeter Brune 38213a62661SPeter Brune Level: intermediate 38313a62661SPeter Brune 38413a62661SPeter Brune SNESNGMRESRestartTypes: 38513a62661SPeter Brune + SNES_NGMRES_RESTART_NONE - never restart 38613a62661SPeter Brune . SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria 38713a62661SPeter Brune - SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations 38813a62661SPeter Brune 38913a62661SPeter Brune Notes: 39013a62661SPeter Brune The default line search used is the L2 line search and it requires two additional function evaluations. 39113a62661SPeter Brune 39213a62661SPeter Brune @*/ 3939371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype) { 39413a62661SPeter Brune PetscFunctionBegin; 39513a62661SPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 396cac4c232SBarry Smith PetscTryMethod(snes, "SNESNGMRESSetRestartType_C", (SNES, SNESNGMRESRestartType), (snes, rtype)); 39713a62661SPeter Brune PetscFunctionReturn(0); 39813a62661SPeter Brune } 39913a62661SPeter Brune 40013a62661SPeter Brune /*@ 40113a62661SPeter Brune SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES. This determines how the candidate solution and 40213a62661SPeter Brune combined solution are used to create the next iterate. 40313a62661SPeter Brune 40413a62661SPeter Brune Logically Collective on SNES 40513a62661SPeter Brune 40613a62661SPeter Brune Input Parameters: 40713a62661SPeter Brune + snes - the iterative context 40813a62661SPeter Brune - stype - selection type 40913a62661SPeter Brune 41013a62661SPeter Brune Options Database: 41167b8a455SSatish Balay . -snes_ngmres_select_type<difference,none,linesearch> - select type 41213a62661SPeter Brune 41313a62661SPeter Brune Level: intermediate 41413a62661SPeter Brune 41513a62661SPeter Brune SNESNGMRESSelectTypes: 41613a62661SPeter Brune + SNES_NGMRES_SELECT_NONE - choose the combined solution all the time 41713a62661SPeter Brune . SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria 41813a62661SPeter Brune - SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination 41913a62661SPeter Brune 42013a62661SPeter Brune Notes: 42113a62661SPeter Brune The default line search used is the L2 line search and it requires two additional function evaluations. 42213a62661SPeter Brune 42313a62661SPeter Brune @*/ 4249371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype) { 42513a62661SPeter Brune PetscFunctionBegin; 42613a62661SPeter Brune PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 427cac4c232SBarry Smith PetscTryMethod(snes, "SNESNGMRESSetSelectType_C", (SNES, SNESNGMRESSelectType), (snes, stype)); 42813a62661SPeter Brune PetscFunctionReturn(0); 42913a62661SPeter Brune } 43013a62661SPeter Brune 4319371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype) { 43213a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 4335fd66863SKarl Rupp 43413a62661SPeter Brune PetscFunctionBegin; 43513a62661SPeter Brune ngmres->select_type = stype; 43613a62661SPeter Brune PetscFunctionReturn(0); 43713a62661SPeter Brune } 43813a62661SPeter Brune 4399371c9d4SSatish Balay PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype) { 44013a62661SPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 4415fd66863SKarl Rupp 44213a62661SPeter Brune PetscFunctionBegin; 44313a62661SPeter Brune ngmres->restart_type = rtype; 44413a62661SPeter Brune PetscFunctionReturn(0); 44513a62661SPeter Brune } 44613a62661SPeter Brune 447dfbf837cSBarry Smith /*MC 4481867fe5bSPeter Brune SNESNGMRES - The Nonlinear Generalized Minimum Residual method. 449a312c225SMatthew G Knepley 450dfbf837cSBarry Smith Level: beginner 451dfbf837cSBarry Smith 4521867fe5bSPeter Brune Options Database: 45313a62661SPeter Brune + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution 45438774f0aSPeter Brune . -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions 45538774f0aSPeter Brune . -snes_ngmres_candidate - Use NGMRES variant which combines candidate solutions instead of actual solutions 45613a62661SPeter Brune . -snes_ngmres_m - Number of stored previous solutions and residuals 45713a62661SPeter Brune . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart 45813a62661SPeter Brune . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination 45913a62661SPeter Brune . -snes_ngmres_gammaC - Residual tolerance for restart 46013a62661SPeter Brune . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart 46113a62661SPeter Brune . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart 46223b3e82cSAsbjørn Nilsen Riseth . -snes_ngmres_restart_fm_rise - Restart on residual rise from x_M step 46313a62661SPeter Brune . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration 4645c3e6ab7SPeter Brune . -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother 46513a62661SPeter Brune - -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type 4661867fe5bSPeter Brune 4671867fe5bSPeter Brune Notes: 4681867fe5bSPeter Brune 4691867fe5bSPeter Brune The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized 4701867fe5bSPeter Brune optimization problem at each iteration. 4711867fe5bSPeter Brune 4724f02bc6aSBarry Smith Very similar to the SNESANDERSON algorithm. 4734f02bc6aSBarry Smith 4741867fe5bSPeter Brune References: 475606c0280SSatish Balay + * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", 476dfbf837cSBarry Smith SIAM Journal on Scientific Computing, 21(5), 2000. 477606c0280SSatish Balay - * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 4784f02bc6aSBarry Smith SIAM Review, 57(4), 2015 4794f02bc6aSBarry Smith 480db781477SPatrick Sanan .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType` 481dfbf837cSBarry Smith M*/ 482a312c225SMatthew G Knepley 4839371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes) { 484a312c225SMatthew G Knepley SNES_NGMRES *ngmres; 485d8d34be6SBarry Smith SNESLineSearch linesearch; 486a312c225SMatthew G Knepley 487a312c225SMatthew G Knepley PetscFunctionBegin; 488a312c225SMatthew G Knepley snes->ops->destroy = SNESDestroy_NGMRES; 489a312c225SMatthew G Knepley snes->ops->setup = SNESSetUp_NGMRES; 490a312c225SMatthew G Knepley snes->ops->setfromoptions = SNESSetFromOptions_NGMRES; 491a312c225SMatthew G Knepley snes->ops->view = SNESView_NGMRES; 492a312c225SMatthew G Knepley snes->ops->solve = SNESSolve_NGMRES; 493a312c225SMatthew G Knepley snes->ops->reset = SNESReset_NGMRES; 494a312c225SMatthew G Knepley 495efd4aadfSBarry Smith snes->usesnpc = PETSC_TRUE; 4962c155ee1SBarry Smith snes->usesksp = PETSC_FALSE; 497efd4aadfSBarry Smith snes->npcside = PC_RIGHT; 4982c155ee1SBarry Smith 4994fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_TRUE; 5004fc747eaSLawrence Mitchell 5019566063dSJacob Faibussowitsch PetscCall(PetscNewLog(snes, &ngmres)); 502a312c225SMatthew G Knepley snes->data = (void *)ngmres; 503d2e16ddcSPeter Brune ngmres->msize = 30; 50419653cdaSPeter Brune 50588976e71SPeter Brune if (!snes->tolerancesset) { 5060e444f03SPeter Brune snes->max_funcs = 30000; 5070e444f03SPeter Brune snes->max_its = 10000; 50888976e71SPeter Brune } 5090e444f03SPeter Brune 51038774f0aSPeter Brune ngmres->candidate = PETSC_FALSE; 511d2e16ddcSPeter Brune 5129566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 513*48a46eb9SPierre Jolivet if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC)); 514d8d34be6SBarry Smith 5150298fd71SBarry Smith ngmres->additive_linesearch = NULL; 516077c4231SPeter Brune ngmres->approxfunc = PETSC_FALSE; 51728ed4a04SPeter Brune ngmres->restart_it = 2; 51813a62661SPeter Brune ngmres->restart_periodic = 30; 519f109b39eSPeter Brune ngmres->gammaA = 2.0; 520f109b39eSPeter Brune ngmres->gammaC = 2.0; 521cac108bcSPeter Brune ngmres->deltaB = 0.9; 522cac108bcSPeter Brune ngmres->epsilonB = 0.1; 52323b3e82cSAsbjørn Nilsen Riseth ngmres->restart_fm_rise = PETSC_FALSE; 524e7058c64SPeter Brune 52513a62661SPeter Brune ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE; 52613a62661SPeter Brune ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE; 52713a62661SPeter Brune 5289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", SNESNGMRESSetSelectType_NGMRES)); 5299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", SNESNGMRESSetRestartType_NGMRES)); 5309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", SNESNGMRESSetRestartFmRise_NGMRES)); 5319566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", SNESNGMRESGetRestartFmRise_NGMRES)); 532a312c225SMatthew G Knepley PetscFunctionReturn(0); 533a312c225SMatthew G Knepley } 534