xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision c579b30025f7481884435f5d6baf5e954044f830)
113a62661SPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
219653cdaSPeter Brune #include <petscblaslapack.h>
3a312c225SMatthew G Knepley 
46a6fc655SJed Brown const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0};
56a6fc655SJed Brown const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",0};
613a62661SPeter Brune 
7a312c225SMatthew G Knepley #undef __FUNCT__
8a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
9a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
10a312c225SMatthew G Knepley {
11a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
12a312c225SMatthew G Knepley   PetscErrorCode ierr;
13a312c225SMatthew G Knepley 
14a312c225SMatthew G Knepley   PetscFunctionBegin;
15f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);
16f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);
17f1c6b773SPeter Brune   ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr);
18a312c225SMatthew G Knepley   PetscFunctionReturn(0);
19a312c225SMatthew G Knepley }
20a312c225SMatthew G Knepley 
21a312c225SMatthew G Knepley #undef __FUNCT__
22a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
23a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
24a312c225SMatthew G Knepley {
25a312c225SMatthew G Knepley   PetscErrorCode ierr;
2678440776SJed Brown   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;
27a312c225SMatthew G Knepley 
28a312c225SMatthew G Knepley   PetscFunctionBegin;
29a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
30f109b39eSPeter Brune   ierr = PetscFree5(ngmres->h,ngmres->beta,ngmres->xi,ngmres->fnorms,ngmres->q);CHKERRQ(ierr);
3119653cdaSPeter Brune   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
3218aa0c0cSPeter Brune   ierr = PetscFree(ngmres->xnorms);CHKERRQ(ierr);
3319653cdaSPeter Brune #if PETSC_USE_COMPLEX
3422d28d08SBarry Smith   ierr = PetscFree(ngmres->rwork);CHKERRQ(ierr);
3519653cdaSPeter Brune #endif
3622d28d08SBarry Smith   ierr = PetscFree(ngmres->work);CHKERRQ(ierr);
3722d28d08SBarry Smith   ierr = PetscFree(snes->data);CHKERRQ(ierr);
38a312c225SMatthew G Knepley   PetscFunctionReturn(0);
39a312c225SMatthew G Knepley }
40a312c225SMatthew G Knepley 
41a312c225SMatthew G Knepley #undef __FUNCT__
42a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
43a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
44a312c225SMatthew G Knepley {
45a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
46e7058c64SPeter Brune   const char     *optionsprefix;
4719653cdaSPeter Brune   PetscInt       msize,hsize;
48a312c225SMatthew G Knepley   PetscErrorCode ierr;
49a312c225SMatthew G Knepley 
50a312c225SMatthew G Knepley   PetscFunctionBegin;
5146159c86SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
5246159c86SPeter Brune     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function");
5346159c86SPeter Brune   }
546c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
55fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr);
5678440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5778440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
5878440776SJed Brown   if (!ngmres->setup_called) {
59087dfb9eSxuemin     msize = ngmres->msize;          /* restart size */
6019653cdaSPeter Brune     hsize = msize * msize;
61087dfb9eSxuemin 
6298b3e84cSPeter Brune     /* explicit least squares minimization solve */
63dcca6d9dSJed Brown     ierr = PetscMalloc5(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, msize,&ngmres->fnorms, hsize,&ngmres->q);CHKERRQ(ierr);
64785e854fSJed Brown     ierr = PetscMalloc1(msize,&ngmres->xnorms);CHKERRQ(ierr);
6519653cdaSPeter Brune     ngmres->nrhs  = 1;
6619653cdaSPeter Brune     ngmres->lda   = msize;
6719653cdaSPeter Brune     ngmres->ldb   = msize;
68785e854fSJed Brown     ierr          = PetscMalloc1(msize,&ngmres->s);CHKERRQ(ierr);
6919653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7019653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7119653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7219653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7319653cdaSPeter Brune     ngmres->lwork = 12*msize;
7419653cdaSPeter Brune #if PETSC_USE_COMPLEX
75854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
7619653cdaSPeter Brune #endif
77854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
7878440776SJed Brown   }
79e7058c64SPeter Brune 
80e7058c64SPeter Brune   /* linesearch setup */
81e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
82e7058c64SPeter Brune 
8313a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
84ce94432eSBarry Smith     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
85f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
861a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
87f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
88f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
89f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
90e7058c64SPeter Brune   }
91e7058c64SPeter Brune 
9278440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
93a312c225SMatthew G Knepley   PetscFunctionReturn(0);
94a312c225SMatthew G Knepley }
95a312c225SMatthew G Knepley 
96a312c225SMatthew G Knepley #undef __FUNCT__
97a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
988c34d3f5SBarry Smith PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptions *PetscOptionsObject,SNES snes)
99a312c225SMatthew G Knepley {
100a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
101a312c225SMatthew G Knepley   PetscErrorCode ierr;
10294ae4db5SBarry Smith   PetscBool      debug = PETSC_FALSE;
103f1c6b773SPeter Brune   SNESLineSearch linesearch;
1040adebc6cSBarry Smith 
105a312c225SMatthew G Knepley   PetscFunctionBegin;
106e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNES NGMRES options");CHKERRQ(ierr);
10713a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
1080298fd71SBarry Smith                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
10913a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
1100298fd71SBarry Smith                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
1110298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
112077c4231SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
1130298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
1140298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
1150298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
1160298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
117dfbf837cSBarry Smith   if (debug) {
118ce94432eSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
119dfbf837cSBarry Smith   }
1200298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
1210298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
1220298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
1230298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
1240298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
125a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1266a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1279e764e56SPeter Brune 
1289e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1299e764e56SPeter Brune   if (!snes->linesearch) {
1307601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1311a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1329e764e56SPeter Brune   }
133a312c225SMatthew G Knepley   PetscFunctionReturn(0);
134a312c225SMatthew G Knepley }
135a312c225SMatthew G Knepley 
136a312c225SMatthew G Knepley #undef __FUNCT__
137a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
138a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
139a312c225SMatthew G Knepley {
140a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
141a312c225SMatthew G Knepley   PetscBool      iascii;
142a312c225SMatthew G Knepley   PetscErrorCode ierr;
143a312c225SMatthew G Knepley 
144a312c225SMatthew G Knepley   PetscFunctionBegin;
145251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
146a312c225SMatthew G Knepley   if (iascii) {
147f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
148f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
149f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
150a312c225SMatthew G Knepley   }
151a312c225SMatthew G Knepley   PetscFunctionReturn(0);
152a312c225SMatthew G Knepley }
153a312c225SMatthew G Knepley 
154a312c225SMatthew G Knepley #undef __FUNCT__
155a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
156a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
157a312c225SMatthew G Knepley {
158087dfb9eSxuemin   SNES_NGMRES         *ngmres = (SNES_NGMRES*) snes->data;
15998b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1609f425c49SPeter Brune   Vec                 X,F,B,D,Y;
161f109b39eSPeter Brune 
162f109b39eSPeter Brune   /* candidate linear combination answers */
163ddd40ce5SPeter Brune   Vec                 XA,FA,XM,FM;
16419653cdaSPeter Brune 
16598b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
16618aa0c0cSPeter Brune   PetscReal           fnorm,fMnorm,fAnorm;
167b3c6a99cSPeter Brune   PetscReal           xnorm,xMnorm,xAnorm;
168b3c6a99cSPeter Brune   PetscReal           ynorm,yMnorm,yAnorm;
16938774f0aSPeter Brune   PetscInt            k,k_restart,l,ivec,restart_count = 0;
17019653cdaSPeter Brune 
17198b3e84cSPeter Brune   /* solution selection data */
17238774f0aSPeter Brune   PetscBool           selectRestart;
17338774f0aSPeter Brune   PetscReal           dnorm,dminnorm = 0.0;
174b3c6a99cSPeter Brune   PetscReal           fminnorm;
17519653cdaSPeter Brune 
1761e633543SBarry Smith   SNESConvergedReason reason;
17738774f0aSPeter Brune   PetscBool           lssucceed;
178a312c225SMatthew G Knepley   PetscErrorCode      ierr;
179a312c225SMatthew G Knepley 
180a312c225SMatthew G Knepley   PetscFunctionBegin;
181*c579b300SPatrick Farrell 
182*c579b300SPatrick Farrell   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
183*c579b300SPatrick Farrell     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
184*c579b300SPatrick Farrell   }
185*c579b300SPatrick Farrell 
186fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
18798b3e84cSPeter Brune   /* variable initialization */
188a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
189f109b39eSPeter Brune   X            = snes->vec_sol;
190f109b39eSPeter Brune   F            = snes->vec_func;
191f109b39eSPeter Brune   B            = snes->vec_rhs;
192f109b39eSPeter Brune   XA           = snes->vec_sol_update;
193f109b39eSPeter Brune   FA           = snes->work[0];
194f109b39eSPeter Brune   D            = snes->work[1];
195f109b39eSPeter Brune 
196f109b39eSPeter Brune   /* work for the line search */
197f109b39eSPeter Brune   Y  = snes->work[2];
1989f425c49SPeter Brune   XM = snes->work[3];
1999f425c49SPeter Brune   FM = snes->work[4];
200a312c225SMatthew G Knepley 
201e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
202a312c225SMatthew G Knepley   snes->iter = 0;
203a312c225SMatthew G Knepley   snes->norm = 0.;
204e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
20519653cdaSPeter Brune 
20698b3e84cSPeter Brune   /* initialization */
20719653cdaSPeter Brune 
2083a2ae377SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT) {
209be95d8f1SBarry Smith     ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr);
2103a2ae377SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2113a2ae377SPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
2123a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
2133a2ae377SPeter Brune       PetscFunctionReturn(0);
2143a2ae377SPeter Brune     }
2153a2ae377SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
2163a2ae377SPeter Brune   } else {
217e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
218f109b39eSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
219a312c225SMatthew G Knepley       if (snes->domainerror) {
220a312c225SMatthew G Knepley         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
221a312c225SMatthew G Knepley         PetscFunctionReturn(0);
222a312c225SMatthew G Knepley       }
2231aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
224c1c75074SPeter Brune 
225f109b39eSPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
226189a9710SBarry Smith     if (PetscIsInfOrNanReal(fnorm)) {
227189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
228189a9710SBarry Smith       PetscFunctionReturn(0);
229189a9710SBarry Smith     }
2303a2ae377SPeter Brune   }
231e4ed7901SPeter Brune   fminnorm = fnorm;
23219653cdaSPeter Brune 
233e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
234f109b39eSPeter Brune   snes->norm = fnorm;
235e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
236a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
237f109b39eSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
238f109b39eSPeter Brune   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
239a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
240b3c6a99cSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
241a312c225SMatthew G Knepley 
24219653cdaSPeter Brune   k_restart = 1;
24319653cdaSPeter Brune   l         = 1;
244b3c6a99cSPeter Brune   ivec      = 0;
24509c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
24698b3e84cSPeter Brune     /* Computation of x^M */
247c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2489f425c49SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
249e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
25063e7833aSPeter Brune 
25163e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2529f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
25363e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
25463e7833aSPeter Brune 
2558cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2568cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2578cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2588cc86e31SPeter Brune         PetscFunctionReturn(0);
2598cc86e31SPeter Brune       }
260be95d8f1SBarry Smith       ierr = SNESGetNPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr);
2618cc86e31SPeter Brune     } else {
262f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
263f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
264e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
265e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
2661aa26658SKarl Rupp 
267e7058c64SPeter Brune       fMnorm = fnorm;
2681aa26658SKarl Rupp 
269f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
270f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch,&lssucceed);CHKERRQ(ierr);
271f109b39eSPeter Brune       if (!lssucceed) {
272f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
273f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
274f109b39eSPeter Brune           PetscFunctionReturn(0);
275f109b39eSPeter Brune         }
276f109b39eSPeter Brune       }
2776634f59bSPeter Brune     }
278b3c6a99cSPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
27998b3e84cSPeter Brune     /* r = F(x) */
2809f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
28119653cdaSPeter Brune 
2829f425c49SPeter Brune     /* differences for selection and restart */
28313a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
284b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
28513a62661SPeter Brune     } else {
286b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
28713a62661SPeter Brune     }
288189a9710SBarry Smith     if (PetscIsInfOrNanReal(fAnorm)) {
289189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
290189a9710SBarry Smith       PetscFunctionReturn(0);
291189a9710SBarry Smith     }
2921aa26658SKarl Rupp 
2939f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
294b3c6a99cSPeter Brune     ierr          = SNESNGMRESSelect_Private(snes,k_restart,XM,FM,xMnorm,fMnorm,yMnorm,XA,FA,xAnorm,fAnorm,yAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&xnorm,&fnorm,&ynorm);CHKERRQ(ierr);
29519653cdaSPeter Brune     selectRestart = PETSC_FALSE;
29613a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
29721687c63SPeter Brune       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
29828ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
2991aa26658SKarl Rupp       if (selectRestart) restart_count++;
3001aa26658SKarl Rupp       else restart_count = 0;
30113a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
30213a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
30313a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
30413a62661SPeter Brune         restart_count = ngmres->restart_it;
30513a62661SPeter Brune       }
30613a62661SPeter Brune     }
307b3c6a99cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
30828ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
30928ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
310dfbf837cSBarry Smith       if (ngmres->monitor) {
311dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
312dfbf837cSBarry Smith       }
31328ed4a04SPeter Brune       restart_count = 0;
31419653cdaSPeter Brune       k_restart     = 1;
31519653cdaSPeter Brune       l             = 1;
316b3c6a99cSPeter Brune       ivec          = 0;
31798b3e84cSPeter Brune       /* q_{00} = nu */
318fa8c639aSPeter Brune       ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
319d2e16ddcSPeter Brune     } else {
32098b3e84cSPeter Brune       /* select the current size of the subspace */
3211e633543SBarry Smith       if (l < ngmres->msize) l++;
32219653cdaSPeter Brune       k_restart++;
32398b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
32438774f0aSPeter Brune       if (ngmres->candidate) {
32538774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
326fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
327d2e16ddcSPeter Brune       } else {
32838774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
329fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
33019653cdaSPeter Brune       }
331d2e16ddcSPeter Brune     }
33219653cdaSPeter Brune 
333e04113cfSBarry Smith     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
334087dfb9eSxuemin     snes->iter = k;
335f109b39eSPeter Brune     snes->norm = fnorm;
336e04113cfSBarry Smith     ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
337a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
3388409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
339b3c6a99cSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
340087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
341a312c225SMatthew G Knepley   }
342a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
343a312c225SMatthew G Knepley   PetscFunctionReturn(0);
344a312c225SMatthew G Knepley }
345a312c225SMatthew G Knepley 
34613a62661SPeter Brune #undef __FUNCT__
34713a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
34813a62661SPeter Brune /*@
34913a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
35013a62661SPeter Brune 
35113a62661SPeter Brune     Logically Collective on SNES
35213a62661SPeter Brune 
35313a62661SPeter Brune     Input Parameters:
35413a62661SPeter Brune +   snes - the iterative context
35513a62661SPeter Brune -   rtype - restart type
35613a62661SPeter Brune 
35713a62661SPeter Brune     Options Database:
35813a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3590c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
36013a62661SPeter Brune 
36113a62661SPeter Brune     Level: intermediate
36213a62661SPeter Brune 
36313a62661SPeter Brune     SNESNGMRESRestartTypes:
36413a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
36513a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
36613a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
36713a62661SPeter Brune 
36813a62661SPeter Brune     Notes:
36913a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
37013a62661SPeter Brune 
37113a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
37213a62661SPeter Brune @*/
3730adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3740adebc6cSBarry Smith {
37513a62661SPeter Brune   PetscErrorCode ierr;
3765fd66863SKarl Rupp 
37713a62661SPeter Brune   PetscFunctionBegin;
37813a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
37913a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
38013a62661SPeter Brune   PetscFunctionReturn(0);
38113a62661SPeter Brune }
38213a62661SPeter Brune 
38313a62661SPeter Brune #undef __FUNCT__
38413a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
38513a62661SPeter Brune /*@
38613a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
38713a62661SPeter Brune     combined solution are used to create the next iterate.
38813a62661SPeter Brune 
38913a62661SPeter Brune     Logically Collective on SNES
39013a62661SPeter Brune 
39113a62661SPeter Brune     Input Parameters:
39213a62661SPeter Brune +   snes - the iterative context
39313a62661SPeter Brune -   stype - selection type
39413a62661SPeter Brune 
39513a62661SPeter Brune     Options Database:
39613a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
39713a62661SPeter Brune 
39813a62661SPeter Brune     Level: intermediate
39913a62661SPeter Brune 
40013a62661SPeter Brune     SNESNGMRESSelectTypes:
40113a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
40213a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
40313a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
40413a62661SPeter Brune 
40513a62661SPeter Brune     Notes:
40613a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
40713a62661SPeter Brune 
40813a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
40913a62661SPeter Brune @*/
4100adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4110adebc6cSBarry Smith {
41213a62661SPeter Brune   PetscErrorCode ierr;
4135fd66863SKarl Rupp 
41413a62661SPeter Brune   PetscFunctionBegin;
41513a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
41613a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
41713a62661SPeter Brune   PetscFunctionReturn(0);
41813a62661SPeter Brune }
41913a62661SPeter Brune 
42013a62661SPeter Brune #undef __FUNCT__
42113a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4220adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4230adebc6cSBarry Smith {
42413a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4255fd66863SKarl Rupp 
42613a62661SPeter Brune   PetscFunctionBegin;
42713a62661SPeter Brune   ngmres->select_type = stype;
42813a62661SPeter Brune   PetscFunctionReturn(0);
42913a62661SPeter Brune }
43013a62661SPeter Brune 
43113a62661SPeter Brune #undef __FUNCT__
43213a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4330adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4340adebc6cSBarry Smith {
43513a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4365fd66863SKarl Rupp 
43713a62661SPeter Brune   PetscFunctionBegin;
43813a62661SPeter Brune   ngmres->restart_type = rtype;
43913a62661SPeter Brune   PetscFunctionReturn(0);
44013a62661SPeter Brune }
44113a62661SPeter Brune 
442dfbf837cSBarry Smith /*MC
4431867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
444a312c225SMatthew G Knepley 
445dfbf837cSBarry Smith    Level: beginner
446dfbf837cSBarry Smith 
4471867fe5bSPeter Brune    Options Database:
44813a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
44938774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
45038774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
45113a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
45213a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
45313a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
45413a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
45513a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
45613a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
45713a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4585c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
45913a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4601867fe5bSPeter Brune 
4611867fe5bSPeter Brune    Notes:
4621867fe5bSPeter Brune 
4631867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4641867fe5bSPeter Brune    optimization problem at each iteration.
4651867fe5bSPeter Brune 
4661867fe5bSPeter Brune    References:
4671867fe5bSPeter Brune 
468dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
469dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
470dfbf837cSBarry Smith 
471dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
472dfbf837cSBarry Smith M*/
473a312c225SMatthew G Knepley 
474a312c225SMatthew G Knepley #undef __FUNCT__
475a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
4768cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
477a312c225SMatthew G Knepley {
478a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
479a312c225SMatthew G Knepley   PetscErrorCode ierr;
480a312c225SMatthew G Knepley 
481a312c225SMatthew G Knepley   PetscFunctionBegin;
482a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
483a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
484a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
485a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
486a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
487a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
488a312c225SMatthew G Knepley 
48942f4f86dSBarry Smith   snes->usespc   = PETSC_TRUE;
4902c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
49146159c86SPeter Brune   snes->pcside   = PC_RIGHT;
4922c155ee1SBarry Smith 
493b00a9115SJed Brown   ierr          = PetscNewLog(snes,&ngmres);CHKERRQ(ierr);
494a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
495d2e16ddcSPeter Brune   ngmres->msize = 30;
49619653cdaSPeter Brune 
49788976e71SPeter Brune   if (!snes->tolerancesset) {
4980e444f03SPeter Brune     snes->max_funcs = 30000;
4990e444f03SPeter Brune     snes->max_its   = 10000;
50088976e71SPeter Brune   }
5010e444f03SPeter Brune 
50238774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
503d2e16ddcSPeter Brune 
5040298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
505077c4231SPeter Brune   ngmres->approxfunc       = PETSC_FALSE;
50628ed4a04SPeter Brune   ngmres->restart_it       = 2;
50713a62661SPeter Brune   ngmres->restart_periodic = 30;
508f109b39eSPeter Brune   ngmres->gammaA           = 2.0;
509f109b39eSPeter Brune   ngmres->gammaC           = 2.0;
510cac108bcSPeter Brune   ngmres->deltaB           = 0.9;
511cac108bcSPeter Brune   ngmres->epsilonB         = 0.1;
512e7058c64SPeter Brune 
51313a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
51413a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
51513a62661SPeter Brune 
516bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
517bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
518a312c225SMatthew G Knepley   PetscFunctionReturn(0);
519a312c225SMatthew G Knepley }
52099e0435eSBarry Smith 
521