xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
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