xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 63a3b9bc7a1f24f247904ccba9383635fe6abade)
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 
8a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
9a312c225SMatthew G Knepley {
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 
19a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
20a312c225SMatthew G Knepley {
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));
319566063dSJacob Faibussowitsch   PetscCall(PetscFree(snes->data));
32a312c225SMatthew G Knepley   PetscFunctionReturn(0);
33a312c225SMatthew G Knepley }
34a312c225SMatthew G Knepley 
35a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
36a312c225SMatthew G Knepley {
37a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
38e7058c64SPeter Brune   const char     *optionsprefix;
3919653cdaSPeter Brune   PetscInt       msize,hsize;
40fced5a79SAsbjørn Nilsen Riseth   DM             dm;
41a312c225SMatthew G Knepley 
42a312c225SMatthew G Knepley   PetscFunctionBegin;
43efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
4446159c86SPeter Brune     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function");
4546159c86SPeter Brune   }
46efd4aadfSBarry Smith   if (snes->npcside== PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
479566063dSJacob Faibussowitsch   PetscCall(SNESSetWorkVecs(snes,5));
48fced5a79SAsbjørn Nilsen Riseth 
49fced5a79SAsbjørn Nilsen Riseth   if (!snes->vec_sol) {
509566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes,&dm));
519566063dSJacob Faibussowitsch     PetscCall(DMCreateGlobalVector(dm,&snes->vec_sol));
52fced5a79SAsbjørn Nilsen Riseth   }
53fced5a79SAsbjørn Nilsen Riseth 
549566063dSJacob Faibussowitsch   if (!ngmres->Xdot) PetscCall(VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot));
559566063dSJacob Faibussowitsch   if (!ngmres->Fdot) PetscCall(VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot));
5678440776SJed Brown   if (!ngmres->setup_called) {
57087dfb9eSxuemin     msize = ngmres->msize;          /* restart size */
5819653cdaSPeter Brune     hsize = msize * msize;
59087dfb9eSxuemin 
6098b3e84cSPeter Brune     /* explicit least squares minimization solve */
619566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, hsize,&ngmres->q));
629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(msize,&ngmres->xnorms,msize,&ngmres->fnorms,msize,&ngmres->s));
6319653cdaSPeter Brune     ngmres->nrhs  = 1;
6419653cdaSPeter Brune     ngmres->lda   = msize;
6519653cdaSPeter Brune     ngmres->ldb   = msize;
6619653cdaSPeter Brune     ngmres->lwork = 12*msize;
67dd63322aSSatish Balay #if defined(PETSC_USE_COMPLEX)
689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ngmres->lwork,&ngmres->rwork));
6919653cdaSPeter Brune #endif
709566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ngmres->lwork,&ngmres->work));
7178440776SJed Brown   }
72e7058c64SPeter Brune 
73e7058c64SPeter Brune   /* linesearch setup */
749566063dSJacob Faibussowitsch   PetscCall(SNESGetOptionsPrefix(snes,&optionsprefix));
75e7058c64SPeter Brune 
7613a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
779566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch));
789566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch,snes));
79ec786807SJed Brown     if (!((PetscObject)ngmres->additive_linesearch)->type_name) {
809566063dSJacob Faibussowitsch       PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2));
81ec786807SJed Brown     }
829566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_"));
839566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix));
849566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetFromOptions(ngmres->additive_linesearch));
85e7058c64SPeter Brune   }
86e7058c64SPeter Brune 
8778440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
88a312c225SMatthew G Knepley   PetscFunctionReturn(0);
89a312c225SMatthew G Knepley }
90a312c225SMatthew G Knepley 
914416b707SBarry Smith PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptionItems *PetscOptionsObject,SNES snes)
92a312c225SMatthew G Knepley {
93a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
9494ae4db5SBarry Smith   PetscBool      debug = PETSC_FALSE;
950adebc6cSBarry Smith 
96a312c225SMatthew G Knepley   PetscFunctionBegin;
97d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"SNES NGMRES options");
98d0609cedSBarry Smith   PetscCall(PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,(PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL));
99d0609cedSBarry Smith   PetscCall(PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,(PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL));
1009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL));
1019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL));
1029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL));
1039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL));
1049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL));
1059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL));
106dfbf837cSBarry Smith   if (debug) {
1072f613bf5SBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));
108dfbf837cSBarry Smith   }
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 
120a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
121a312c225SMatthew G Knepley {
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) {
128*63a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize));
129*63a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",(double)ngmres->gammaA,(double)ngmres->gammaC));
130*63a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",(double)ngmres->epsilonB,(double)ngmres->deltaB));
131*63a3b9bcSJacob 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 
136a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
137a312c225SMatthew G Knepley {
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;
1652c71b3e2SJacob Faibussowitsch   PetscCheckFalse(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));
2129566063dSJacob Faibussowitsch   PetscCall((*snes->ops->converged)(snes,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) {
277*63a3b9bcSJacob 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) {
286dfbf837cSBarry Smith       if (ngmres->monitor) {
287*63a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %" PetscInt_FMT "\n",k_restart));
288dfbf837cSBarry Smith       }
28928ed4a04SPeter Brune       restart_count = 0;
29019653cdaSPeter Brune       k_restart     = 1;
29119653cdaSPeter Brune       l             = 1;
292b3c6a99cSPeter Brune       ivec          = 0;
29398b3e84cSPeter Brune       /* q_{00} = nu */
2949566063dSJacob Faibussowitsch       PetscCall(SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM));
295d2e16ddcSPeter Brune     } else {
29698b3e84cSPeter Brune       /* select the current size of the subspace */
2971e633543SBarry Smith       if (l < ngmres->msize) l++;
29819653cdaSPeter Brune       k_restart++;
29998b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
30038774f0aSPeter Brune       if (ngmres->candidate) {
30138774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
3029566063dSJacob Faibussowitsch         PetscCall(SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM));
303d2e16ddcSPeter Brune       } else {
30438774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
3059566063dSJacob Faibussowitsch         PetscCall(SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X));
30619653cdaSPeter Brune       }
307d2e16ddcSPeter Brune     }
30819653cdaSPeter Brune 
3099566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
310087dfb9eSxuemin     snes->iter = k;
311f109b39eSPeter Brune     snes->norm = fnorm;
3129566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
3139566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes,snes->norm,snes->iter));
3149566063dSJacob Faibussowitsch     PetscCall(SNESMonitor(snes,snes->iter,snes->norm));
3159566063dSJacob Faibussowitsch     PetscCall((*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP));
316087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
317a312c225SMatthew G Knepley   }
318a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
319a312c225SMatthew G Knepley   PetscFunctionReturn(0);
320a312c225SMatthew G Knepley }
321a312c225SMatthew G Knepley 
32223b3e82cSAsbjørn Nilsen Riseth /*@
32323b3e82cSAsbjørn Nilsen Riseth  SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M
32423b3e82cSAsbjørn Nilsen Riseth 
32523b3e82cSAsbjørn Nilsen Riseth   Input Parameters:
32623b3e82cSAsbjørn Nilsen Riseth   +  snes - the SNES context.
32723b3e82cSAsbjørn Nilsen Riseth   -  flg  - boolean value deciding whether to use the option or not
32823b3e82cSAsbjørn Nilsen Riseth 
32923b3e82cSAsbjørn Nilsen Riseth   Options Database:
33023b3e82cSAsbjørn Nilsen Riseth   + -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M
33123b3e82cSAsbjørn Nilsen Riseth 
33223b3e82cSAsbjørn Nilsen Riseth   Level: intermediate
33323b3e82cSAsbjørn Nilsen Riseth 
33423b3e82cSAsbjørn Nilsen Riseth   Notes:
33523b3e82cSAsbjø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.
33623b3e82cSAsbjørn Nilsen Riseth   To help the solver do that, reset the Krylov subspace whenever F_M increases.
33723b3e82cSAsbjørn Nilsen Riseth 
33823b3e82cSAsbjørn Nilsen Riseth   This option must be used with SNES_NGMRES_RESTART_DIFFERENCE
33923b3e82cSAsbjørn Nilsen Riseth 
34023b3e82cSAsbjørn Nilsen Riseth   The default is FALSE.
34123b3e82cSAsbjørn Nilsen Riseth   .seealso: SNES_NGMRES_RESTART_DIFFERENCE
34223b3e82cSAsbjørn Nilsen Riseth   @*/
34323b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes,PetscBool flg)
34423b3e82cSAsbjørn Nilsen Riseth {
34523b3e82cSAsbjørn Nilsen Riseth     PetscErrorCode (*f)(SNES,PetscBool);
34623b3e82cSAsbjørn Nilsen Riseth 
34723b3e82cSAsbjørn Nilsen Riseth     PetscFunctionBegin;
3489566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",&f));
3499566063dSJacob Faibussowitsch     if (f) PetscCall((f)(snes,flg));
35023b3e82cSAsbjørn Nilsen Riseth     PetscFunctionReturn(0);
35123b3e82cSAsbjørn Nilsen Riseth }
35223b3e82cSAsbjørn Nilsen Riseth 
35323b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes,PetscBool flg)
35423b3e82cSAsbjørn Nilsen Riseth {
35523b3e82cSAsbjørn Nilsen Riseth   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
35623b3e82cSAsbjørn Nilsen Riseth 
35723b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
35823b3e82cSAsbjørn Nilsen Riseth   ngmres->restart_fm_rise = flg;
35923b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
36023b3e82cSAsbjørn Nilsen Riseth }
36123b3e82cSAsbjørn Nilsen Riseth 
36223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes,PetscBool *flg)
36323b3e82cSAsbjørn Nilsen Riseth {
36423b3e82cSAsbjørn Nilsen Riseth     PetscErrorCode (*f)(SNES,PetscBool*);
36523b3e82cSAsbjørn Nilsen Riseth 
36623b3e82cSAsbjørn Nilsen Riseth     PetscFunctionBegin;
3679566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",&f));
3689566063dSJacob Faibussowitsch     if (f) PetscCall((f)(snes,flg));
36923b3e82cSAsbjørn Nilsen Riseth     PetscFunctionReturn(0);
37023b3e82cSAsbjørn Nilsen Riseth }
37123b3e82cSAsbjørn Nilsen Riseth 
37223b3e82cSAsbjørn Nilsen Riseth PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes,PetscBool *flg)
37323b3e82cSAsbjørn Nilsen Riseth {
37423b3e82cSAsbjørn Nilsen Riseth   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
37523b3e82cSAsbjørn Nilsen Riseth 
37623b3e82cSAsbjørn Nilsen Riseth   PetscFunctionBegin;
37723b3e82cSAsbjørn Nilsen Riseth   *flg = ngmres->restart_fm_rise;
37823b3e82cSAsbjørn Nilsen Riseth   PetscFunctionReturn(0);
37923b3e82cSAsbjørn Nilsen Riseth }
38023b3e82cSAsbjørn Nilsen Riseth 
38113a62661SPeter Brune /*@
38213a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
38313a62661SPeter Brune 
38413a62661SPeter Brune     Logically Collective on SNES
38513a62661SPeter Brune 
38613a62661SPeter Brune     Input Parameters:
38713a62661SPeter Brune +   snes - the iterative context
38813a62661SPeter Brune -   rtype - restart type
38913a62661SPeter Brune 
39013a62661SPeter Brune     Options Database:
39113a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3920c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
39313a62661SPeter Brune 
39413a62661SPeter Brune     Level: intermediate
39513a62661SPeter Brune 
39613a62661SPeter Brune     SNESNGMRESRestartTypes:
39713a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
39813a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
39913a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
40013a62661SPeter Brune 
40113a62661SPeter Brune     Notes:
40213a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
40313a62661SPeter Brune 
40413a62661SPeter Brune @*/
4050adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
4060adebc6cSBarry Smith {
40713a62661SPeter Brune   PetscFunctionBegin;
40813a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
409cac4c232SBarry Smith   PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));
41013a62661SPeter Brune   PetscFunctionReturn(0);
41113a62661SPeter Brune }
41213a62661SPeter Brune 
41313a62661SPeter Brune /*@
41413a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
41513a62661SPeter Brune     combined solution are used to create the next iterate.
41613a62661SPeter Brune 
41713a62661SPeter Brune     Logically Collective on SNES
41813a62661SPeter Brune 
41913a62661SPeter Brune     Input Parameters:
42013a62661SPeter Brune +   snes - the iterative context
42113a62661SPeter Brune -   stype - selection type
42213a62661SPeter Brune 
42313a62661SPeter Brune     Options Database:
42467b8a455SSatish Balay .   -snes_ngmres_select_type<difference,none,linesearch> - select type
42513a62661SPeter Brune 
42613a62661SPeter Brune     Level: intermediate
42713a62661SPeter Brune 
42813a62661SPeter Brune     SNESNGMRESSelectTypes:
42913a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
43013a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
43113a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
43213a62661SPeter Brune 
43313a62661SPeter Brune     Notes:
43413a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
43513a62661SPeter Brune 
43613a62661SPeter Brune @*/
4370adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4380adebc6cSBarry Smith {
43913a62661SPeter Brune   PetscFunctionBegin;
44013a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
441cac4c232SBarry Smith   PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));
44213a62661SPeter Brune   PetscFunctionReturn(0);
44313a62661SPeter Brune }
44413a62661SPeter Brune 
4450adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4460adebc6cSBarry Smith {
44713a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4485fd66863SKarl Rupp 
44913a62661SPeter Brune   PetscFunctionBegin;
45013a62661SPeter Brune   ngmres->select_type = stype;
45113a62661SPeter Brune   PetscFunctionReturn(0);
45213a62661SPeter Brune }
45313a62661SPeter Brune 
4540adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4550adebc6cSBarry Smith {
45613a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4575fd66863SKarl Rupp 
45813a62661SPeter Brune   PetscFunctionBegin;
45913a62661SPeter Brune   ngmres->restart_type = rtype;
46013a62661SPeter Brune   PetscFunctionReturn(0);
46113a62661SPeter Brune }
46213a62661SPeter Brune 
463dfbf837cSBarry Smith /*MC
4641867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
465a312c225SMatthew G Knepley 
466dfbf837cSBarry Smith    Level: beginner
467dfbf837cSBarry Smith 
4681867fe5bSPeter Brune    Options Database:
46913a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
47038774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
47138774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
47213a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
47313a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
47413a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
47513a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
47613a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
47713a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
47823b3e82cSAsbjørn Nilsen Riseth .  -snes_ngmres_restart_fm_rise  - Restart on residual rise from x_M step
47913a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4805c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
48113a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4821867fe5bSPeter Brune 
4831867fe5bSPeter Brune    Notes:
4841867fe5bSPeter Brune 
4851867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4861867fe5bSPeter Brune    optimization problem at each iteration.
4871867fe5bSPeter Brune 
4884f02bc6aSBarry Smith    Very similar to the SNESANDERSON algorithm.
4894f02bc6aSBarry Smith 
4901867fe5bSPeter Brune    References:
491606c0280SSatish Balay +  * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows",
492dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
493606c0280SSatish Balay -  * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
4944f02bc6aSBarry Smith    SIAM Review, 57(4), 2015
4954f02bc6aSBarry Smith 
496dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
497dfbf837cSBarry Smith M*/
498a312c225SMatthew G Knepley 
4998cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
500a312c225SMatthew G Knepley {
501a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
502d8d34be6SBarry Smith   SNESLineSearch linesearch;
503a312c225SMatthew G Knepley 
504a312c225SMatthew G Knepley   PetscFunctionBegin;
505a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
506a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
507a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
508a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
509a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
510a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
511a312c225SMatthew G Knepley 
512efd4aadfSBarry Smith   snes->usesnpc  = PETSC_TRUE;
5132c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
514efd4aadfSBarry Smith   snes->npcside  = PC_RIGHT;
5152c155ee1SBarry Smith 
5164fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
5174fc747eaSLawrence Mitchell 
5189566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(snes,&ngmres));
519a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
520d2e16ddcSPeter Brune   ngmres->msize = 30;
52119653cdaSPeter Brune 
52288976e71SPeter Brune   if (!snes->tolerancesset) {
5230e444f03SPeter Brune     snes->max_funcs = 30000;
5240e444f03SPeter Brune     snes->max_its   = 10000;
52588976e71SPeter Brune   }
5260e444f03SPeter Brune 
52738774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
528d2e16ddcSPeter Brune 
5299566063dSJacob Faibussowitsch   PetscCall(SNESGetLineSearch(snes,&linesearch));
530ec786807SJed Brown   if (!((PetscObject)linesearch)->type_name) {
5319566063dSJacob Faibussowitsch     PetscCall(SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC));
532ec786807SJed Brown   }
533d8d34be6SBarry Smith 
5340298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
535077c4231SPeter Brune   ngmres->approxfunc          = PETSC_FALSE;
53628ed4a04SPeter Brune   ngmres->restart_it          = 2;
53713a62661SPeter Brune   ngmres->restart_periodic    = 30;
538f109b39eSPeter Brune   ngmres->gammaA              = 2.0;
539f109b39eSPeter Brune   ngmres->gammaC              = 2.0;
540cac108bcSPeter Brune   ngmres->deltaB              = 0.9;
541cac108bcSPeter Brune   ngmres->epsilonB            = 0.1;
54223b3e82cSAsbjørn Nilsen Riseth   ngmres->restart_fm_rise     = PETSC_FALSE;
543e7058c64SPeter Brune 
54413a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
54513a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
54613a62661SPeter Brune 
5479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES));
5489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES));
5499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartFmRise_C",SNESNGMRESSetRestartFmRise_NGMRES));
5509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESGetRestartFmRise_C",SNESNGMRESGetRestartFmRise_NGMRES));
551a312c225SMatthew G Knepley   PetscFunctionReturn(0);
552a312c225SMatthew G Knepley }
553