xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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 
8*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESReset_NGMRES(SNES snes)
9*d71ae5a4SJacob Faibussowitsch {
10a312c225SMatthew G Knepley   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
11a312c225SMatthew G Knepley 
12a312c225SMatthew G Knepley   PetscFunctionBegin;
139566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Fdot));
149566063dSJacob Faibussowitsch   PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Xdot));
159566063dSJacob Faibussowitsch   PetscCall(SNESLineSearchDestroy(&ngmres->additive_linesearch));
16a312c225SMatthew G Knepley   PetscFunctionReturn(0);
17a312c225SMatthew G Knepley }
18a312c225SMatthew G Knepley 
19*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESDestroy_NGMRES(SNES snes)
20*d71ae5a4SJacob Faibussowitsch {
2178440776SJed Brown   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
22a312c225SMatthew G Knepley 
23a312c225SMatthew G Knepley   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCall(SNESReset_NGMRES(snes));
259566063dSJacob Faibussowitsch   PetscCall(PetscFree4(ngmres->h, ngmres->beta, ngmres->xi, ngmres->q));
269566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ngmres->xnorms, ngmres->fnorms, ngmres->s));
27dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX)
289566063dSJacob Faibussowitsch   PetscCall(PetscFree(ngmres->rwork));
2919653cdaSPeter Brune #endif
309566063dSJacob Faibussowitsch   PetscCall(PetscFree(ngmres->work));
312e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", NULL));
322e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", NULL));
332e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", NULL));
342e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", NULL));
359566063dSJacob Faibussowitsch   PetscCall(PetscFree(snes->data));
36a312c225SMatthew G Knepley   PetscFunctionReturn(0);
37a312c225SMatthew G Knepley }
38a312c225SMatthew G Knepley 
39*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESSetUp_NGMRES(SNES snes)
40*d71ae5a4SJacob Faibussowitsch {
41a312c225SMatthew G Knepley   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
42e7058c64SPeter Brune   const char  *optionsprefix;
4319653cdaSPeter Brune   PetscInt     msize, hsize;
44fced5a79SAsbjørn Nilsen Riseth   DM           dm;
45a312c225SMatthew G Knepley 
46a312c225SMatthew G Knepley   PetscFunctionBegin;
47efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
4846159c86SPeter Brune     SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNGMRES does not support left preconditioning with unpreconditioned function");
4946159c86SPeter Brune   }
50efd4aadfSBarry Smith   if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
519566063dSJacob Faibussowitsch   PetscCall(SNESSetWorkVecs(snes, 5));
52fced5a79SAsbjørn Nilsen Riseth 
53fced5a79SAsbjørn Nilsen Riseth   if (!snes->vec_sol) {
549566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
559566063dSJacob Faibussowitsch     PetscCall(DMCreateGlobalVector(dm, &snes->vec_sol));
56fced5a79SAsbjørn Nilsen Riseth   }
57fced5a79SAsbjørn Nilsen Riseth 
589566063dSJacob Faibussowitsch   if (!ngmres->Xdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Xdot));
599566063dSJacob Faibussowitsch   if (!ngmres->Fdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Fdot));
6078440776SJed Brown   if (!ngmres->setup_called) {
61087dfb9eSxuemin     msize = ngmres->msize; /* restart size */
6219653cdaSPeter Brune     hsize = msize * msize;
63087dfb9eSxuemin 
6498b3e84cSPeter Brune     /* explicit least squares minimization solve */
659566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(hsize, &ngmres->h, msize, &ngmres->beta, msize, &ngmres->xi, hsize, &ngmres->q));
669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(msize, &ngmres->xnorms, msize, &ngmres->fnorms, msize, &ngmres->s));
6719653cdaSPeter Brune     ngmres->nrhs  = 1;
6819653cdaSPeter Brune     ngmres->lda   = msize;
6919653cdaSPeter Brune     ngmres->ldb   = msize;
7019653cdaSPeter Brune     ngmres->lwork = 12 * msize;
71dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX)
729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->rwork));
7319653cdaSPeter Brune #endif
749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->work));
7578440776SJed Brown   }
76e7058c64SPeter Brune 
77e7058c64SPeter Brune   /* linesearch setup */
789566063dSJacob Faibussowitsch   PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
79e7058c64SPeter Brune 
8013a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
819566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &ngmres->additive_linesearch));
829566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch, snes));
8348a46eb9SPierre Jolivet     if (!((PetscObject)ngmres->additive_linesearch)->type_name) PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2));
849566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_"));
859566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix));
869566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetFromOptions(ngmres->additive_linesearch));
87e7058c64SPeter Brune   }
88e7058c64SPeter Brune 
8978440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
90a312c225SMatthew G Knepley   PetscFunctionReturn(0);
91a312c225SMatthew G Knepley }
92a312c225SMatthew G Knepley 
93*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes, PetscOptionItems *PetscOptionsObject)
94*d71ae5a4SJacob Faibussowitsch {
95a312c225SMatthew G Knepley   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
9694ae4db5SBarry Smith   PetscBool    debug  = PETSC_FALSE;
970adebc6cSBarry Smith 
98a312c225SMatthew G Knepley   PetscFunctionBegin;
99d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "SNES NGMRES options");
100d0609cedSBarry Smith   PetscCall(PetscOptionsEnum("-snes_ngmres_select_type", "Select type", "SNESNGMRESSetSelectType", SNESNGMRESSelectTypes, (PetscEnum)ngmres->select_type, (PetscEnum *)&ngmres->select_type, NULL));
101d0609cedSBarry Smith   PetscCall(PetscOptionsEnum("-snes_ngmres_restart_type", "Restart type", "SNESNGMRESSetRestartType", SNESNGMRESRestartTypes, (PetscEnum)ngmres->restart_type, (PetscEnum *)&ngmres->restart_type, NULL));
1029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES", ngmres->candidate, &ngmres->candidate, NULL));
1039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_approxfunc", "Linearly approximate the function", "SNES", ngmres->approxfunc, &ngmres->approxfunc, NULL));
1049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, NULL));
1059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES", ngmres->restart_periodic, &ngmres->restart_periodic, NULL));
1069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart", "SNES", ngmres->restart_it, &ngmres->restart_it, NULL));
1079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL));
108ad540459SPierre Jolivet   if (debug) ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));
1099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, NULL));
1109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, NULL));
1119566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, NULL));
1129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, NULL));
1139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES", ngmres->singlereduction, &ngmres->singlereduction, NULL));
1149566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise", ngmres->restart_fm_rise, &ngmres->restart_fm_rise, NULL));
115d0609cedSBarry Smith   PetscOptionsHeadEnd();
1166a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
117a312c225SMatthew G Knepley   PetscFunctionReturn(0);
118a312c225SMatthew G Knepley }
119a312c225SMatthew G Knepley 
120*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
121*d71ae5a4SJacob Faibussowitsch {
122a312c225SMatthew G Knepley   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
123a312c225SMatthew G Knepley   PetscBool    iascii;
124a312c225SMatthew G Knepley 
125a312c225SMatthew G Knepley   PetscFunctionBegin;
1269566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
127a312c225SMatthew G Knepley   if (iascii) {
12863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize));
12963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", (double)ngmres->gammaA, (double)ngmres->gammaC));
13063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", (double)ngmres->epsilonB, (double)ngmres->deltaB));
13163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Restart on F_M residual increase: %s\n", PetscBools[ngmres->restart_fm_rise]));
132a312c225SMatthew G Knepley   }
133a312c225SMatthew G Knepley   PetscFunctionReturn(0);
134a312c225SMatthew G Knepley }
135a312c225SMatthew G Knepley 
136*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESSolve_NGMRES(SNES snes)
137*d71ae5a4SJacob Faibussowitsch {
138087dfb9eSxuemin   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
13998b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1409f425c49SPeter Brune   Vec X, F, B, D, Y;
141f109b39eSPeter Brune 
142f109b39eSPeter Brune   /* candidate linear combination answers */
143ddd40ce5SPeter Brune   Vec XA, FA, XM, FM;
14419653cdaSPeter Brune 
14598b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
14618aa0c0cSPeter Brune   PetscReal fnorm, fMnorm, fAnorm;
147b3c6a99cSPeter Brune   PetscReal xnorm, xMnorm, xAnorm;
148b3c6a99cSPeter Brune   PetscReal ynorm, yMnorm, yAnorm;
14938774f0aSPeter Brune   PetscInt  k, k_restart, l, ivec, restart_count = 0;
15019653cdaSPeter Brune 
15198b3e84cSPeter Brune   /* solution selection data */
15238774f0aSPeter Brune   PetscBool selectRestart;
15361ba4676SBarry Smith   /*
15461ba4676SBarry Smith       These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed
15561ba4676SBarry Smith       to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case
15661ba4676SBarry Smith       so the code is correct as written.
15761ba4676SBarry Smith   */
15861ba4676SBarry Smith   PetscReal dnorm = 0.0, dminnorm = 0.0;
159b3c6a99cSPeter Brune   PetscReal fminnorm;
16019653cdaSPeter Brune 
1611e633543SBarry Smith   SNESConvergedReason  reason;
162422a814eSBarry Smith   SNESLineSearchReason lssucceed;
163a312c225SMatthew G Knepley 
164a312c225SMatthew G Knepley   PetscFunctionBegin;
1650b121fc5SBarry 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);
166c579b300SPatrick Farrell 
1679566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
16898b3e84cSPeter Brune   /* variable initialization */
169a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
170f109b39eSPeter Brune   X            = snes->vec_sol;
171f109b39eSPeter Brune   F            = snes->vec_func;
172f109b39eSPeter Brune   B            = snes->vec_rhs;
173f109b39eSPeter Brune   XA           = snes->vec_sol_update;
174f109b39eSPeter Brune   FA           = snes->work[0];
175f109b39eSPeter Brune   D            = snes->work[1];
176f109b39eSPeter Brune 
177f109b39eSPeter Brune   /* work for the line search */
178f109b39eSPeter Brune   Y  = snes->work[2];
1799f425c49SPeter Brune   XM = snes->work[3];
1809f425c49SPeter Brune   FM = snes->work[4];
181a312c225SMatthew G Knepley 
1829566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
183a312c225SMatthew G Knepley   snes->iter = 0;
184a312c225SMatthew G Knepley   snes->norm = 0.;
1859566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
18619653cdaSPeter Brune 
18798b3e84cSPeter Brune   /* initialization */
18819653cdaSPeter Brune 
189efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT) {
1909566063dSJacob Faibussowitsch     PetscCall(SNESApplyNPC(snes, X, NULL, F));
1919566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes->npc, &reason));
1923a2ae377SPeter Brune     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
1933a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
1943a2ae377SPeter Brune       PetscFunctionReturn(0);
1953a2ae377SPeter Brune     }
1969566063dSJacob Faibussowitsch     PetscCall(VecNorm(F, NORM_2, &fnorm));
1973a2ae377SPeter Brune   } else {
198e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
1999566063dSJacob Faibussowitsch       PetscCall(SNESComputeFunction(snes, X, F));
2001aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
201c1c75074SPeter Brune 
2029566063dSJacob Faibussowitsch     PetscCall(VecNorm(F, NORM_2, &fnorm));
203422a814eSBarry Smith     SNESCheckFunctionNorm(snes, fnorm);
2043a2ae377SPeter Brune   }
205e4ed7901SPeter Brune   fminnorm = fnorm;
20619653cdaSPeter Brune 
2079566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
208f109b39eSPeter Brune   snes->norm = fnorm;
2099566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
2109566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
2119566063dSJacob Faibussowitsch   PetscCall(SNESMonitor(snes, 0, fnorm));
212dbbe0bcdSBarry Smith   PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
213a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
214b3c6a99cSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes, 0, 0, F, fnorm, X);
215a312c225SMatthew G Knepley 
21619653cdaSPeter Brune   k_restart = 1;
21719653cdaSPeter Brune   l         = 1;
218b3c6a99cSPeter Brune   ivec      = 0;
21909c08436SPeter Brune   for (k = 1; k < snes->max_its + 1; k++) {
22098b3e84cSPeter Brune     /* Computation of x^M */
221efd4aadfSBarry Smith     if (snes->npc && snes->npcside == PC_RIGHT) {
2229566063dSJacob Faibussowitsch       PetscCall(VecCopy(X, XM));
2239566063dSJacob Faibussowitsch       PetscCall(SNESSetInitialFunction(snes->npc, F));
22463e7833aSPeter Brune 
2259566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, XM, B, 0));
2269566063dSJacob Faibussowitsch       PetscCall(SNESSolve(snes->npc, B, XM));
2279566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, XM, B, 0));
22863e7833aSPeter Brune 
2299566063dSJacob Faibussowitsch       PetscCall(SNESGetConvergedReason(snes->npc, &reason));
2308cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2318cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2328cc86e31SPeter Brune         PetscFunctionReturn(0);
2338cc86e31SPeter Brune       }
2349566063dSJacob Faibussowitsch       PetscCall(SNESGetNPCFunction(snes, FM, &fMnorm));
2358cc86e31SPeter Brune     } else {
236f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
2379566063dSJacob Faibussowitsch       PetscCall(VecCopy(F, Y));
2389566063dSJacob Faibussowitsch       PetscCall(VecCopy(F, FM));
2399566063dSJacob Faibussowitsch       PetscCall(VecCopy(X, XM));
2401aa26658SKarl Rupp 
241e7058c64SPeter Brune       fMnorm = fnorm;
2421aa26658SKarl Rupp 
2439566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchApply(snes->linesearch, XM, FM, &fMnorm, Y));
2449566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed));
245422a814eSBarry Smith       if (lssucceed) {
246f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
247f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
248f109b39eSPeter Brune           PetscFunctionReturn(0);
249f109b39eSPeter Brune         }
250f109b39eSPeter Brune       }
2516634f59bSPeter Brune     }
25223b3e82cSAsbjørn Nilsen Riseth 
2539566063dSJacob Faibussowitsch     PetscCall(SNESNGMRESFormCombinedSolution_Private(snes, ivec, l, XM, FM, fMnorm, X, XA, FA));
25498b3e84cSPeter Brune     /* r = F(x) */
2559f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */
25619653cdaSPeter Brune 
2579f425c49SPeter Brune     /* differences for selection and restart */
25813a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
2599566063dSJacob Faibussowitsch       PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, &dnorm, &dminnorm, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm));
26013a62661SPeter Brune     } else {
2619566063dSJacob Faibussowitsch       PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, NULL, NULL, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm));
26213a62661SPeter Brune     }
263422a814eSBarry Smith     SNESCheckFunctionNorm(snes, fnorm);
2641aa26658SKarl Rupp 
2659f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
2669566063dSJacob 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));
26719653cdaSPeter Brune     selectRestart = PETSC_FALSE;
26823b3e82cSAsbjørn Nilsen Riseth 
26913a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
2709566063dSJacob Faibussowitsch       PetscCall(SNESNGMRESSelectRestart_Private(snes, l, fMnorm, fAnorm, dnorm, fminnorm, dminnorm, &selectRestart));
27123b3e82cSAsbjørn Nilsen Riseth 
27228ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
2731aa26658SKarl Rupp       if (selectRestart) restart_count++;
2741aa26658SKarl Rupp       else restart_count = 0;
27513a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
27613a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
27763a3b9bcSJacob Faibussowitsch         if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %" PetscInt_FMT " iterations\n", k_restart));
27813a62661SPeter Brune         restart_count = ngmres->restart_it;
27913a62661SPeter Brune       }
28013a62661SPeter Brune     }
28123b3e82cSAsbjørn Nilsen Riseth 
282b3c6a99cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
28323b3e82cSAsbjørn Nilsen Riseth 
28428ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
28528ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
28648a46eb9SPierre Jolivet       if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %" PetscInt_FMT "\n", k_restart));
28728ed4a04SPeter Brune       restart_count = 0;
28819653cdaSPeter Brune       k_restart     = 1;
28919653cdaSPeter Brune       l             = 1;
290b3c6a99cSPeter Brune       ivec          = 0;
29198b3e84cSPeter Brune       /* q_{00} = nu */
2929566063dSJacob Faibussowitsch       PetscCall(SNESNGMRESUpdateSubspace_Private(snes, 0, 0, FM, fMnorm, XM));
293d2e16ddcSPeter Brune     } else {
29498b3e84cSPeter Brune       /* select the current size of the subspace */
2951e633543SBarry Smith       if (l < ngmres->msize) l++;
29619653cdaSPeter Brune       k_restart++;
29798b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
29838774f0aSPeter Brune       if (ngmres->candidate) {
29938774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
3009566063dSJacob Faibussowitsch         PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, FM, fMnorm, XM));
301d2e16ddcSPeter Brune       } else {
30238774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
3039566063dSJacob Faibussowitsch         PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, F, fnorm, X));
30419653cdaSPeter Brune       }
305d2e16ddcSPeter Brune     }
30619653cdaSPeter Brune 
3079566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
308087dfb9eSxuemin     snes->iter = k;
309f109b39eSPeter Brune     snes->norm = fnorm;
3109566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
3119566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, snes->iter));
3129566063dSJacob Faibussowitsch     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
313dbbe0bcdSBarry Smith     PetscUseTypeMethod(snes, converged, snes->iter, 0, 0, fnorm, &snes->reason, snes->cnvP);
314087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
315a312c225SMatthew G Knepley   }
316a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
317a312c225SMatthew G Knepley   PetscFunctionReturn(0);
318a312c225SMatthew G Knepley }
319a312c225SMatthew G Knepley 
32023b3e82cSAsbjørn Nilsen Riseth /*@
32123b3e82cSAsbjørn Nilsen Riseth  SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M
32223b3e82cSAsbjørn Nilsen Riseth 
32323b3e82cSAsbjørn Nilsen Riseth    Input Parameters:
324f6dfbefdSBarry Smith +  snes - the `SNES` context.
325f6dfbefdSBarry Smith -  flg  - boolean value deciding whether to use the option or not, default is `PETSC_FALSE`
32623b3e82cSAsbjørn Nilsen Riseth 
327f6dfbefdSBarry Smith    Options Database Key:
328f6dfbefdSBarry Smith .   -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M
32923b3e82cSAsbjørn Nilsen Riseth 
33023b3e82cSAsbjørn Nilsen Riseth    Level: intermediate
33123b3e82cSAsbjørn Nilsen Riseth 
33223b3e82cSAsbjørn Nilsen Riseth    Notes:
33323b3e82cSAsbjø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.
33423b3e82cSAsbjørn Nilsen Riseth    To help the solver do that, reset the Krylov subspace whenever F_M increases.
33523b3e82cSAsbjørn Nilsen Riseth 
336f6dfbefdSBarry Smith    This option must be used with the `SNESNGMRES` `SNESNGMRESRestartType` of `SNES_NGMRES_RESTART_DIFFERENCE`
33723b3e82cSAsbjørn Nilsen Riseth 
338f6dfbefdSBarry Smith .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartType()`
33923b3e82cSAsbjørn Nilsen Riseth   @*/
340*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes, PetscBool flg)
341*d71ae5a4SJacob Faibussowitsch {
34223b3e82cSAsbjørn Nilsen Riseth   PetscErrorCode (*f)(SNES, PetscBool);
34323b3e82cSAsbjørn Nilsen Riseth 
34423b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
3459566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", &f));
3469566063dSJacob Faibussowitsch   if (f) PetscCall((f)(snes, flg));
34723b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
34823b3e82cSAsbjørn Nilsen Riseth }
34923b3e82cSAsbjørn Nilsen Riseth 
350*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes, PetscBool flg)
351*d71ae5a4SJacob Faibussowitsch {
35223b3e82cSAsbjørn Nilsen Riseth   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
35323b3e82cSAsbjørn Nilsen Riseth 
35423b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
35523b3e82cSAsbjørn Nilsen Riseth   ngmres->restart_fm_rise = flg;
35623b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
35723b3e82cSAsbjørn Nilsen Riseth }
35823b3e82cSAsbjørn Nilsen Riseth 
359*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes, PetscBool *flg)
360*d71ae5a4SJacob Faibussowitsch {
36123b3e82cSAsbjørn Nilsen Riseth   PetscErrorCode (*f)(SNES, PetscBool *);
36223b3e82cSAsbjørn Nilsen Riseth 
36323b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
3649566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", &f));
3659566063dSJacob Faibussowitsch   if (f) PetscCall((f)(snes, flg));
36623b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
36723b3e82cSAsbjørn Nilsen Riseth }
36823b3e82cSAsbjørn Nilsen Riseth 
369*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes, PetscBool *flg)
370*d71ae5a4SJacob Faibussowitsch {
37123b3e82cSAsbjørn Nilsen Riseth   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
37223b3e82cSAsbjørn Nilsen Riseth 
37323b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
37423b3e82cSAsbjørn Nilsen Riseth   *flg = ngmres->restart_fm_rise;
37523b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
37623b3e82cSAsbjørn Nilsen Riseth }
37723b3e82cSAsbjørn Nilsen Riseth 
37813a62661SPeter Brune /*@
379f6dfbefdSBarry Smith     SNESNGMRESSetRestartType - Sets the restart type for `SNESNGMRES`.
38013a62661SPeter Brune 
381f6dfbefdSBarry Smith     Logically Collective on snes
38213a62661SPeter Brune 
38313a62661SPeter Brune     Input Parameters:
38413a62661SPeter Brune +   snes - the iterative context
38513a62661SPeter Brune -   rtype - restart type
38613a62661SPeter Brune 
387f6dfbefdSBarry Smith     Options Databas Keys:
38813a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3890c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
39013a62661SPeter Brune 
391f6dfbefdSBarry Smith     `SNESNGMRESRestartType`s:
392f6dfbefdSBarry Smith +   `SNES_NGMRES_RESTART_NONE` - never restart
393f6dfbefdSBarry Smith .   `SNES_NGMRES_RESTART_DIFFERENCE` - restart based upon difference criteria
394f6dfbefdSBarry Smith -   `SNES_NGMRES_RESTART_PERIODIC` - restart after a fixed number of iterations
395f6dfbefdSBarry Smith 
39613a62661SPeter Brune     Level: intermediate
39713a62661SPeter Brune 
398f6dfbefdSBarry Smith .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartFmRise()`
39913a62661SPeter Brune @*/
400*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype)
401*d71ae5a4SJacob Faibussowitsch {
40213a62661SPeter Brune   PetscFunctionBegin;
40313a62661SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
404cac4c232SBarry Smith   PetscTryMethod(snes, "SNESNGMRESSetRestartType_C", (SNES, SNESNGMRESRestartType), (snes, rtype));
40513a62661SPeter Brune   PetscFunctionReturn(0);
40613a62661SPeter Brune }
40713a62661SPeter Brune 
40813a62661SPeter Brune /*@
409f6dfbefdSBarry Smith     SNESNGMRESSetSelectType - Sets the selection type for `SNESNGMRES`.  This determines how the candidate solution and
41013a62661SPeter Brune     combined solution are used to create the next iterate.
41113a62661SPeter Brune 
412f6dfbefdSBarry Smith     Logically Collective on snes
41313a62661SPeter Brune 
41413a62661SPeter Brune     Input Parameters:
41513a62661SPeter Brune +   snes - the iterative context
41613a62661SPeter Brune -   stype - selection type
41713a62661SPeter Brune 
418f6dfbefdSBarry Smith     Options Database Key:
41967b8a455SSatish Balay .   -snes_ngmres_select_type<difference,none,linesearch> - select type
42013a62661SPeter Brune 
42113a62661SPeter Brune     Level: intermediate
42213a62661SPeter Brune 
423f6dfbefdSBarry Smith     `SNESNGMRESSelectType`s:
424f6dfbefdSBarry Smith +   `SNES_NGMRES_SELECT_NONE` - choose the combined solution all the time
425f6dfbefdSBarry Smith .   `SNES_NGMRES_SELECT_DIFFERENCE` - choose based upon the selection criteria
426f6dfbefdSBarry Smith -   `SNES_NGMRES_SELECT_LINESEARCH` - choose based upon line search combination
42713a62661SPeter Brune 
428f6dfbefdSBarry Smith     Note:
429f6dfbefdSBarry Smith     The default line search used is the `SNESLINESEARCHL2` line search and it requires two additional function evaluations.
43013a62661SPeter Brune 
431f6dfbefdSBarry Smith .seealso: `SNESNGMRESSelectType()`, `SNES_NGMRES_SELECT_NONE`, `SNES_NGMRES_SELECT_DIFFERENCE`, `SNES_NGMRES_SELECT_LINESEARCH`
43213a62661SPeter Brune @*/
433*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype)
434*d71ae5a4SJacob Faibussowitsch {
43513a62661SPeter Brune   PetscFunctionBegin;
43613a62661SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
437cac4c232SBarry Smith   PetscTryMethod(snes, "SNESNGMRESSetSelectType_C", (SNES, SNESNGMRESSelectType), (snes, stype));
43813a62661SPeter Brune   PetscFunctionReturn(0);
43913a62661SPeter Brune }
44013a62661SPeter Brune 
441*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype)
442*d71ae5a4SJacob Faibussowitsch {
44313a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
4445fd66863SKarl Rupp 
44513a62661SPeter Brune   PetscFunctionBegin;
44613a62661SPeter Brune   ngmres->select_type = stype;
44713a62661SPeter Brune   PetscFunctionReturn(0);
44813a62661SPeter Brune }
44913a62661SPeter Brune 
450*d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype)
451*d71ae5a4SJacob Faibussowitsch {
45213a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
4535fd66863SKarl Rupp 
45413a62661SPeter Brune   PetscFunctionBegin;
45513a62661SPeter Brune   ngmres->restart_type = rtype;
45613a62661SPeter Brune   PetscFunctionReturn(0);
45713a62661SPeter Brune }
45813a62661SPeter Brune 
459dfbf837cSBarry Smith /*MC
4601867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
461a312c225SMatthew G Knepley 
462dfbf837cSBarry Smith    Level: beginner
463dfbf837cSBarry Smith 
464f6dfbefdSBarry Smith    Options Database Keys:
46513a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
46638774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
467f6dfbefdSBarry Smith .  -snes_ngmres_candidate        - Use `SNESNGMRES` variant which combines candidate solutions instead of actual solutions
46813a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
46913a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
47013a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
47113a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
47213a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
47313a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
47423b3e82cSAsbjørn Nilsen Riseth .  -snes_ngmres_restart_fm_rise  - Restart on residual rise from x_M step
47513a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4765c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
47713a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4781867fe5bSPeter Brune 
4791867fe5bSPeter Brune    Notes:
4801867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4811867fe5bSPeter Brune    optimization problem at each iteration.
4821867fe5bSPeter Brune 
483f6dfbefdSBarry Smith    Very similar to the `SNESANDERSON` algorithm.
4844f02bc6aSBarry Smith 
4851867fe5bSPeter Brune    References:
486606c0280SSatish Balay +  * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows",
487dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
488606c0280SSatish Balay -  * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
4894f02bc6aSBarry Smith    SIAM Review, 57(4), 2015
4904f02bc6aSBarry Smith 
491f6dfbefdSBarry Smith .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESANDERSON`, `SNESNGMRESSetSelectType()`, `SNESNGMRESSetRestartType()`,
492f6dfbefdSBarry Smith           `SNESNGMRESSetRestartFmRise()`
493dfbf837cSBarry Smith M*/
494a312c225SMatthew G Knepley 
495*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
496*d71ae5a4SJacob Faibussowitsch {
497a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
498d8d34be6SBarry Smith   SNESLineSearch linesearch;
499a312c225SMatthew G Knepley 
500a312c225SMatthew G Knepley   PetscFunctionBegin;
501a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
502a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
503a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
504a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
505a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
506a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
507a312c225SMatthew G Knepley 
508efd4aadfSBarry Smith   snes->usesnpc = PETSC_TRUE;
5092c155ee1SBarry Smith   snes->usesksp = PETSC_FALSE;
510efd4aadfSBarry Smith   snes->npcside = PC_RIGHT;
5112c155ee1SBarry Smith 
5124fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
5134fc747eaSLawrence Mitchell 
5144dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&ngmres));
515a312c225SMatthew G Knepley   snes->data    = (void *)ngmres;
516d2e16ddcSPeter Brune   ngmres->msize = 30;
51719653cdaSPeter Brune 
51888976e71SPeter Brune   if (!snes->tolerancesset) {
5190e444f03SPeter Brune     snes->max_funcs = 30000;
5200e444f03SPeter Brune     snes->max_its   = 10000;
52188976e71SPeter Brune   }
5220e444f03SPeter Brune 
52338774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
524d2e16ddcSPeter Brune 
5259566063dSJacob Faibussowitsch   PetscCall(SNESGetLineSearch(snes, &linesearch));
52648a46eb9SPierre Jolivet   if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
527d8d34be6SBarry Smith 
5280298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
529077c4231SPeter Brune   ngmres->approxfunc          = PETSC_FALSE;
53028ed4a04SPeter Brune   ngmres->restart_it          = 2;
53113a62661SPeter Brune   ngmres->restart_periodic    = 30;
532f109b39eSPeter Brune   ngmres->gammaA              = 2.0;
533f109b39eSPeter Brune   ngmres->gammaC              = 2.0;
534cac108bcSPeter Brune   ngmres->deltaB              = 0.9;
535cac108bcSPeter Brune   ngmres->epsilonB            = 0.1;
53623b3e82cSAsbjørn Nilsen Riseth   ngmres->restart_fm_rise     = PETSC_FALSE;
537e7058c64SPeter Brune 
53813a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
53913a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
54013a62661SPeter Brune 
5419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", SNESNGMRESSetSelectType_NGMRES));
5429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", SNESNGMRESSetRestartType_NGMRES));
5439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", SNESNGMRESSetRestartFmRise_NGMRES));
5449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", SNESNGMRESGetRestartFmRise_NGMRES));
545a312c225SMatthew G Knepley   PetscFunctionReturn(0);
546a312c225SMatthew G Knepley }
547