xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 3a2ae377b6b37e222133c3129a95818911ad2fb2)
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   }
54fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr);
5578440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5678440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
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 */
6219653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6319653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
6419653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
65f109b39eSPeter Brune                         msize,PetscReal, &ngmres->fnorms,
6619653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6718aa0c0cSPeter Brune     if (ngmres->singlereduction) {
6818aa0c0cSPeter Brune       ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr);
6918aa0c0cSPeter Brune     }
7019653cdaSPeter Brune     ngmres->nrhs  = 1;
7119653cdaSPeter Brune     ngmres->lda   = msize;
7219653cdaSPeter Brune     ngmres->ldb   = msize;
7319653cdaSPeter Brune     ierr          = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
7419653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7519653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7619653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7719653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7819653cdaSPeter Brune     ngmres->lwork = 12*msize;
7919653cdaSPeter Brune #if PETSC_USE_COMPLEX
8022d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
8119653cdaSPeter Brune #endif
8222d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
8378440776SJed Brown   }
84e7058c64SPeter Brune 
85e7058c64SPeter Brune   /* linesearch setup */
86e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
87e7058c64SPeter Brune 
8813a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
89ce94432eSBarry Smith     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
90f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
911a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
92f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
93f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
94f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
95e7058c64SPeter Brune   }
96e7058c64SPeter Brune 
9778440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
98a312c225SMatthew G Knepley   PetscFunctionReturn(0);
99a312c225SMatthew G Knepley }
100a312c225SMatthew G Knepley 
101a312c225SMatthew G Knepley #undef __FUNCT__
102a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
103a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
104a312c225SMatthew G Knepley {
105a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
106a312c225SMatthew G Knepley   PetscErrorCode ierr;
107dfbf837cSBarry Smith   PetscBool      debug;
108f1c6b773SPeter Brune   SNESLineSearch linesearch;
1090adebc6cSBarry Smith 
110a312c225SMatthew G Knepley   PetscFunctionBegin;
111a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
11213a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
1130298fd71SBarry Smith                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
11413a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
1150298fd71SBarry Smith                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
1160298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
117077c4231SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
1180298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
1190298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
1200298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
1210298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
122dfbf837cSBarry Smith   if (debug) {
123ce94432eSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
124dfbf837cSBarry Smith   }
1250298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
1260298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
1270298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
1280298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
1290298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
130a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1316a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1329e764e56SPeter Brune 
1339e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1349e764e56SPeter Brune   if (!snes->linesearch) {
1357601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1361a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1379e764e56SPeter Brune   }
138a312c225SMatthew G Knepley   PetscFunctionReturn(0);
139a312c225SMatthew G Knepley }
140a312c225SMatthew G Knepley 
141a312c225SMatthew G Knepley #undef __FUNCT__
142a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
143a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
144a312c225SMatthew G Knepley {
145a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
146a312c225SMatthew G Knepley   PetscBool      iascii;
147a312c225SMatthew G Knepley   PetscErrorCode ierr;
148a312c225SMatthew G Knepley 
149a312c225SMatthew G Knepley   PetscFunctionBegin;
150251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
151a312c225SMatthew G Knepley   if (iascii) {
152f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
153f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
154f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
155a312c225SMatthew G Knepley   }
156a312c225SMatthew G Knepley   PetscFunctionReturn(0);
157a312c225SMatthew G Knepley }
158a312c225SMatthew G Knepley 
159a312c225SMatthew G Knepley #undef __FUNCT__
160a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
161a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
162a312c225SMatthew G Knepley {
16338774f0aSPeter Brune 
164087dfb9eSxuemin   SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
16598b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1669f425c49SPeter Brune   Vec X,F,B,D,Y;
167f109b39eSPeter Brune 
168f109b39eSPeter Brune   /* candidate linear combination answers */
1694b32a720SPeter Brune   Vec XA,FA,XM,FM,FPC;
17019653cdaSPeter Brune 
17198b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
17218aa0c0cSPeter Brune   PetscReal fnorm,fMnorm,fAnorm;
17338774f0aSPeter Brune   PetscInt  k,k_restart,l,ivec,restart_count = 0;
17419653cdaSPeter Brune 
17598b3e84cSPeter Brune   /* solution selection data */
17638774f0aSPeter Brune   PetscBool selectRestart;
17738774f0aSPeter Brune   PetscReal dnorm,dminnorm = 0.0;
178d484d688SPeter Brune   PetscReal fminnorm,xnorm,ynorm;
17919653cdaSPeter Brune 
1801e633543SBarry Smith   SNESConvergedReason reason;
18138774f0aSPeter Brune   PetscBool           lssucceed;
182a312c225SMatthew G Knepley   PetscErrorCode      ierr;
183a312c225SMatthew G Knepley 
184a312c225SMatthew G Knepley   PetscFunctionBegin;
18598b3e84cSPeter Brune   /* variable initialization */
186a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
187f109b39eSPeter Brune   X            = snes->vec_sol;
188f109b39eSPeter Brune   F            = snes->vec_func;
189f109b39eSPeter Brune   B            = snes->vec_rhs;
190f109b39eSPeter Brune   XA           = snes->vec_sol_update;
191f109b39eSPeter Brune   FA           = snes->work[0];
192f109b39eSPeter Brune   D            = snes->work[1];
193f109b39eSPeter Brune 
194f109b39eSPeter Brune   /* work for the line search */
195f109b39eSPeter Brune   Y  = snes->work[2];
1969f425c49SPeter Brune   XM = snes->work[3];
1979f425c49SPeter Brune   FM = snes->work[4];
198a312c225SMatthew G Knepley 
199ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
200a312c225SMatthew G Knepley   snes->iter = 0;
201a312c225SMatthew G Knepley   snes->norm = 0.;
202ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
20319653cdaSPeter Brune 
20498b3e84cSPeter Brune   /* initialization */
20519653cdaSPeter Brune 
206*3a2ae377SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT) {
207*3a2ae377SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
208*3a2ae377SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
209*3a2ae377SPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
210*3a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
211*3a2ae377SPeter Brune       PetscFunctionReturn(0);
212*3a2ae377SPeter Brune     }
213*3a2ae377SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
214*3a2ae377SPeter Brune   } else {
215e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
216f109b39eSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
217a312c225SMatthew G Knepley       if (snes->domainerror) {
218a312c225SMatthew G Knepley         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
219a312c225SMatthew G Knepley         PetscFunctionReturn(0);
220a312c225SMatthew G Knepley       }
2211aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
222e4ed7901SPeter Brune     if (!snes->norm_init_set) {
223*3a2ae377SPeter Brune       /* convergence test */
224f109b39eSPeter Brune       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
225189a9710SBarry Smith       if (PetscIsInfOrNanReal(fnorm)) {
226189a9710SBarry Smith         snes->reason = SNES_DIVERGED_FNORM_NAN;
227189a9710SBarry Smith         PetscFunctionReturn(0);
228189a9710SBarry Smith       }
229e4ed7901SPeter Brune     } else {
230e4ed7901SPeter Brune       fnorm               = snes->norm_init;
231e4ed7901SPeter Brune       snes->norm_init_set = PETSC_FALSE;
232e4ed7901SPeter Brune     }
233*3a2ae377SPeter Brune   }
234e4ed7901SPeter Brune   fminnorm = fnorm;
23519653cdaSPeter Brune 
23698b3e84cSPeter Brune   /* q_{00} = nu  */
23738774f0aSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
238087dfb9eSxuemin 
239ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
240f109b39eSPeter Brune   snes->norm = fnorm;
241ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
242a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
243f109b39eSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
244f109b39eSPeter Brune   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
245a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
246a312c225SMatthew G Knepley 
24719653cdaSPeter Brune   k_restart = 1;
24819653cdaSPeter Brune   l         = 1;
24909c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
25098b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
25198b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
25219653cdaSPeter Brune 
25398b3e84cSPeter Brune     /* Computation of x^M */
254c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2559f425c49SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
256e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
257e4ed7901SPeter Brune       ierr = SNESSetInitialFunctionNorm(snes->pc,fnorm);CHKERRQ(ierr);
25863e7833aSPeter Brune 
25963e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2609f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
26163e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
26263e7833aSPeter Brune 
2638cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2648cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2658cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2668cc86e31SPeter Brune         PetscFunctionReturn(0);
2678cc86e31SPeter Brune       }
2680298fd71SBarry Smith       ierr = SNESGetFunction(snes->pc,&FPC,NULL,NULL);CHKERRQ(ierr);
2694b32a720SPeter Brune       ierr = VecCopy(FPC,FM);CHKERRQ(ierr);
2704b32a720SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc,&fMnorm);CHKERRQ(ierr);
2718cc86e31SPeter Brune     } else {
272f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
273f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
274e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
275e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
2761aa26658SKarl Rupp 
277e7058c64SPeter Brune       fMnorm = fnorm;
2781aa26658SKarl Rupp 
279f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
280f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch,&lssucceed);CHKERRQ(ierr);
281f109b39eSPeter Brune       if (!lssucceed) {
282f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
283f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
284f109b39eSPeter Brune           PetscFunctionReturn(0);
285f109b39eSPeter Brune         }
286f109b39eSPeter Brune       }
2876634f59bSPeter Brune     }
288f6408107SPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
28998b3e84cSPeter Brune     /* r = F(x) */
2909f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
29119653cdaSPeter Brune 
2929f425c49SPeter Brune     /* differences for selection and restart */
29313a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
294fa8c639aSPeter Brune       ierr = SNESNGMRESCalculateDifferences_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&fAnorm);CHKERRQ(ierr);
29513a62661SPeter Brune     } else {
29613a62661SPeter Brune       ierr = VecNorm(FA,NORM_2,&fAnorm);CHKERRQ(ierr);
29713a62661SPeter Brune     }
298189a9710SBarry Smith     if (PetscIsInfOrNanReal(fAnorm)) {
299189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
300189a9710SBarry Smith       PetscFunctionReturn(0);
301189a9710SBarry Smith     }
3021aa26658SKarl Rupp 
3039f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
304fa8c639aSPeter Brune     ierr          = SNESNGMRESSelect_Private(snes,k_restart,XM,FM,fMnorm,XA,FA,fAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&fnorm);CHKERRQ(ierr);
30519653cdaSPeter Brune     selectRestart = PETSC_FALSE;
30613a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
30721687c63SPeter Brune       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
30828ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
3091aa26658SKarl Rupp       if (selectRestart) restart_count++;
3101aa26658SKarl Rupp       else restart_count = 0;
31113a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
31213a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
31313a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
31413a62661SPeter Brune         restart_count = ngmres->restart_it;
31513a62661SPeter Brune       }
31613a62661SPeter Brune     }
31728ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
31828ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
319dfbf837cSBarry Smith       if (ngmres->monitor) {
320dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
321dfbf837cSBarry Smith       }
32228ed4a04SPeter Brune       restart_count = 0;
32319653cdaSPeter Brune       k_restart     = 1;
32419653cdaSPeter Brune       l             = 1;
32598b3e84cSPeter Brune       /* q_{00} = nu */
32638774f0aSPeter Brune       if (ngmres->candidate) {
327fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
328d2e16ddcSPeter Brune       } else {
329fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fMnorm,X);CHKERRQ(ierr);
330d2e16ddcSPeter Brune       }
33119653cdaSPeter Brune     } else {
33298b3e84cSPeter Brune       /* select the current size of the subspace */
3331e633543SBarry Smith       if (l < ngmres->msize) l++;
33419653cdaSPeter Brune       k_restart++;
33598b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
33638774f0aSPeter Brune       if (ngmres->candidate) {
33738774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
338fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
339d2e16ddcSPeter Brune       } else {
34038774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
341fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
34219653cdaSPeter Brune       }
343d2e16ddcSPeter Brune     }
34419653cdaSPeter Brune 
345ce8c27fbSBarry Smith     ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
346087dfb9eSxuemin     snes->iter = k;
347f109b39eSPeter Brune     snes->norm = fnorm;
348ce8c27fbSBarry Smith     ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
349a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
3508409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
351d484d688SPeter Brune     ierr = VecNormBegin(Y,NORM_2,&ynorm);CHKERRQ(ierr);
352d484d688SPeter Brune     ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);
353d484d688SPeter Brune     ierr = VecNormEnd(Y,NORM_2,&ynorm);CHKERRQ(ierr);
354d484d688SPeter Brune     ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
355d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
356087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
357a312c225SMatthew G Knepley   }
358a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
359a312c225SMatthew G Knepley   PetscFunctionReturn(0);
360a312c225SMatthew G Knepley }
361a312c225SMatthew G Knepley 
36213a62661SPeter Brune #undef __FUNCT__
36313a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
36413a62661SPeter Brune /*@
36513a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
36613a62661SPeter Brune 
36713a62661SPeter Brune     Logically Collective on SNES
36813a62661SPeter Brune 
36913a62661SPeter Brune     Input Parameters:
37013a62661SPeter Brune +   snes - the iterative context
37113a62661SPeter Brune -   rtype - restart type
37213a62661SPeter Brune 
37313a62661SPeter Brune     Options Database:
37413a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3750c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
37613a62661SPeter Brune 
37713a62661SPeter Brune     Level: intermediate
37813a62661SPeter Brune 
37913a62661SPeter Brune     SNESNGMRESRestartTypes:
38013a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
38113a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
38213a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
38313a62661SPeter Brune 
38413a62661SPeter Brune     Notes:
38513a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
38613a62661SPeter Brune 
38713a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
38813a62661SPeter Brune @*/
3890adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3900adebc6cSBarry Smith {
39113a62661SPeter Brune   PetscErrorCode ierr;
3925fd66863SKarl Rupp 
39313a62661SPeter Brune   PetscFunctionBegin;
39413a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
39513a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
39613a62661SPeter Brune   PetscFunctionReturn(0);
39713a62661SPeter Brune }
39813a62661SPeter Brune 
39913a62661SPeter Brune #undef __FUNCT__
40013a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
40113a62661SPeter Brune /*@
40213a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
40313a62661SPeter Brune     combined solution are used to create the next iterate.
40413a62661SPeter Brune 
40513a62661SPeter Brune     Logically Collective on SNES
40613a62661SPeter Brune 
40713a62661SPeter Brune     Input Parameters:
40813a62661SPeter Brune +   snes - the iterative context
40913a62661SPeter Brune -   stype - selection type
41013a62661SPeter Brune 
41113a62661SPeter Brune     Options Database:
41213a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
41313a62661SPeter Brune 
41413a62661SPeter Brune     Level: intermediate
41513a62661SPeter Brune 
41613a62661SPeter Brune     SNESNGMRESSelectTypes:
41713a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
41813a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
41913a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
42013a62661SPeter Brune 
42113a62661SPeter Brune     Notes:
42213a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
42313a62661SPeter Brune 
42413a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
42513a62661SPeter Brune @*/
4260adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4270adebc6cSBarry Smith {
42813a62661SPeter Brune   PetscErrorCode ierr;
4295fd66863SKarl Rupp 
43013a62661SPeter Brune   PetscFunctionBegin;
43113a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
43213a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
43313a62661SPeter Brune   PetscFunctionReturn(0);
43413a62661SPeter Brune }
43513a62661SPeter Brune 
43613a62661SPeter Brune #undef __FUNCT__
43713a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4380adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4390adebc6cSBarry Smith {
44013a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4415fd66863SKarl Rupp 
44213a62661SPeter Brune   PetscFunctionBegin;
44313a62661SPeter Brune   ngmres->select_type = stype;
44413a62661SPeter Brune   PetscFunctionReturn(0);
44513a62661SPeter Brune }
44613a62661SPeter Brune 
44713a62661SPeter Brune #undef __FUNCT__
44813a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4490adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4500adebc6cSBarry Smith {
45113a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4525fd66863SKarl Rupp 
45313a62661SPeter Brune   PetscFunctionBegin;
45413a62661SPeter Brune   ngmres->restart_type = rtype;
45513a62661SPeter Brune   PetscFunctionReturn(0);
45613a62661SPeter Brune }
45713a62661SPeter Brune 
458dfbf837cSBarry Smith /*MC
4591867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
460a312c225SMatthew G Knepley 
461dfbf837cSBarry Smith    Level: beginner
462dfbf837cSBarry Smith 
4631867fe5bSPeter Brune    Options Database:
46413a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
46538774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
46638774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
46713a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
46813a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
46913a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
47013a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
47113a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
47213a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
47313a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4745c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
47513a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4761867fe5bSPeter Brune 
4771867fe5bSPeter Brune    Notes:
4781867fe5bSPeter Brune 
4791867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4801867fe5bSPeter Brune    optimization problem at each iteration.
4811867fe5bSPeter Brune 
4821867fe5bSPeter Brune    References:
4831867fe5bSPeter Brune 
484dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
485dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
486dfbf837cSBarry Smith 
487dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
488dfbf837cSBarry Smith M*/
489a312c225SMatthew G Knepley 
490a312c225SMatthew G Knepley #undef __FUNCT__
491a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
4928cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
493a312c225SMatthew G Knepley {
494a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
495a312c225SMatthew G Knepley   PetscErrorCode ierr;
496a312c225SMatthew G Knepley 
497a312c225SMatthew G Knepley   PetscFunctionBegin;
498a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
499a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
500a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
501a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
502a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
503a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
504a312c225SMatthew G Knepley 
50542f4f86dSBarry Smith   snes->usespc   = PETSC_TRUE;
5062c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
50746159c86SPeter Brune   snes->pcside   = PC_RIGHT;
50846159c86SPeter Brune   snes->functype = SNES_FUNCTION_PRECONDITIONED;
5092c155ee1SBarry Smith 
510a312c225SMatthew G Knepley   ierr          = PetscNewLog(snes,SNES_NGMRES,&ngmres);CHKERRQ(ierr);
511a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
512d2e16ddcSPeter Brune   ngmres->msize = 30;
51319653cdaSPeter Brune 
51488976e71SPeter Brune   if (!snes->tolerancesset) {
5150e444f03SPeter Brune     snes->max_funcs = 30000;
5160e444f03SPeter Brune     snes->max_its   = 10000;
51788976e71SPeter Brune   }
5180e444f03SPeter Brune 
51938774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
520d2e16ddcSPeter Brune 
5210298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
522077c4231SPeter Brune   ngmres->approxfunc       = PETSC_FALSE;
52328ed4a04SPeter Brune   ngmres->restart_it       = 2;
52413a62661SPeter Brune   ngmres->restart_periodic = 30;
525f109b39eSPeter Brune   ngmres->gammaA           = 2.0;
526f109b39eSPeter Brune   ngmres->gammaC           = 2.0;
527cac108bcSPeter Brune   ngmres->deltaB           = 0.9;
528cac108bcSPeter Brune   ngmres->epsilonB         = 0.1;
529e7058c64SPeter Brune 
53013a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
53113a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
53213a62661SPeter Brune 
533bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
534bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
535a312c225SMatthew G Knepley   PetscFunctionReturn(0);
536a312c225SMatthew G Knepley }
53799e0435eSBarry Smith 
538