xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
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*9371c9d4SSatish 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 
18*9371c9d4SSatish 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 
37*9371c9d4SSatish 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*9371c9d4SSatish Balay     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 
90*9371c9d4SSatish 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));
104*9371c9d4SSatish 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 
116*9371c9d4SSatish 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 
131*9371c9d4SSatish 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*9371c9d4SSatish Balay       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   @*/
335*9371c9d4SSatish 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 
344*9371c9d4SSatish 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 
352*9371c9d4SSatish 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 
361*9371c9d4SSatish 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 @*/
393*9371c9d4SSatish 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 @*/
424*9371c9d4SSatish 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 
431*9371c9d4SSatish 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 
439*9371c9d4SSatish 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 
483*9371c9d4SSatish 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*9371c9d4SSatish Balay   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