xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision b3c6a99c2dfbbcbe6c384ebbf17f2aa81f303822)
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 */
6319653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6419653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
6519653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
66f109b39eSPeter Brune                         msize,PetscReal, &ngmres->fnorms,
6719653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6818aa0c0cSPeter Brune     ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr);
6919653cdaSPeter Brune     ngmres->nrhs  = 1;
7019653cdaSPeter Brune     ngmres->lda   = msize;
7119653cdaSPeter Brune     ngmres->ldb   = msize;
7219653cdaSPeter Brune     ierr          = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
7319653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7419653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7519653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7619653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7719653cdaSPeter Brune     ngmres->lwork = 12*msize;
7819653cdaSPeter Brune #if PETSC_USE_COMPLEX
7922d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
8019653cdaSPeter Brune #endif
8122d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
8278440776SJed Brown   }
83e7058c64SPeter Brune 
84e7058c64SPeter Brune   /* linesearch setup */
85e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
86e7058c64SPeter Brune 
8713a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
88ce94432eSBarry Smith     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
89f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
901a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
91f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
92f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
93f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
94e7058c64SPeter Brune   }
95e7058c64SPeter Brune 
9678440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
97a312c225SMatthew G Knepley   PetscFunctionReturn(0);
98a312c225SMatthew G Knepley }
99a312c225SMatthew G Knepley 
100a312c225SMatthew G Knepley #undef __FUNCT__
101a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
102a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
103a312c225SMatthew G Knepley {
104a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
105a312c225SMatthew G Knepley   PetscErrorCode ierr;
106dfbf837cSBarry Smith   PetscBool      debug;
107f1c6b773SPeter Brune   SNESLineSearch linesearch;
1080adebc6cSBarry Smith 
109a312c225SMatthew G Knepley   PetscFunctionBegin;
110a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
11113a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
1120298fd71SBarry Smith                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
11313a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
1140298fd71SBarry Smith                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
1150298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
116077c4231SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
1170298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
1180298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
1190298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
1200298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
121dfbf837cSBarry Smith   if (debug) {
122ce94432eSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
123dfbf837cSBarry Smith   }
1240298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
1250298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
1260298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
1270298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
1280298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
129a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1306a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1319e764e56SPeter Brune 
1329e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1339e764e56SPeter Brune   if (!snes->linesearch) {
1347601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1351a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1369e764e56SPeter Brune   }
137a312c225SMatthew G Knepley   PetscFunctionReturn(0);
138a312c225SMatthew G Knepley }
139a312c225SMatthew G Knepley 
140a312c225SMatthew G Knepley #undef __FUNCT__
141a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
142a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
143a312c225SMatthew G Knepley {
144a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
145a312c225SMatthew G Knepley   PetscBool      iascii;
146a312c225SMatthew G Knepley   PetscErrorCode ierr;
147a312c225SMatthew G Knepley 
148a312c225SMatthew G Knepley   PetscFunctionBegin;
149251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
150a312c225SMatthew G Knepley   if (iascii) {
151f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
152f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
153f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
154a312c225SMatthew G Knepley   }
155a312c225SMatthew G Knepley   PetscFunctionReturn(0);
156a312c225SMatthew G Knepley }
157a312c225SMatthew G Knepley 
158a312c225SMatthew G Knepley #undef __FUNCT__
159a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
160a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
161a312c225SMatthew G Knepley {
16238774f0aSPeter Brune 
163087dfb9eSxuemin   SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
16498b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1659f425c49SPeter Brune   Vec X,F,B,D,Y;
166f109b39eSPeter Brune 
167f109b39eSPeter Brune   /* candidate linear combination answers */
168ddd40ce5SPeter Brune   Vec XA,FA,XM,FM;
16919653cdaSPeter Brune 
17098b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
17118aa0c0cSPeter Brune   PetscReal fnorm,fMnorm,fAnorm;
172*b3c6a99cSPeter Brune   PetscReal xnorm,xMnorm,xAnorm;
173*b3c6a99cSPeter Brune   PetscReal ynorm,yMnorm,yAnorm;
17438774f0aSPeter Brune   PetscInt  k,k_restart,l,ivec,restart_count = 0;
17519653cdaSPeter Brune 
17698b3e84cSPeter Brune   /* solution selection data */
17738774f0aSPeter Brune   PetscBool selectRestart;
17838774f0aSPeter Brune   PetscReal dnorm,dminnorm = 0.0;
179*b3c6a99cSPeter Brune   PetscReal fminnorm;
18019653cdaSPeter Brune 
1811e633543SBarry Smith   SNESConvergedReason reason;
18238774f0aSPeter Brune   PetscBool           lssucceed;
183a312c225SMatthew G Knepley   PetscErrorCode      ierr;
184a312c225SMatthew G Knepley 
185a312c225SMatthew G Knepley   PetscFunctionBegin;
18698b3e84cSPeter Brune   /* variable initialization */
187a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
188f109b39eSPeter Brune   X            = snes->vec_sol;
189f109b39eSPeter Brune   F            = snes->vec_func;
190f109b39eSPeter Brune   B            = snes->vec_rhs;
191f109b39eSPeter Brune   XA           = snes->vec_sol_update;
192f109b39eSPeter Brune   FA           = snes->work[0];
193f109b39eSPeter Brune   D            = snes->work[1];
194f109b39eSPeter Brune 
195f109b39eSPeter Brune   /* work for the line search */
196f109b39eSPeter Brune   Y  = snes->work[2];
1979f425c49SPeter Brune   XM = snes->work[3];
1989f425c49SPeter Brune   FM = snes->work[4];
199a312c225SMatthew G Knepley 
200ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
201a312c225SMatthew G Knepley   snes->iter = 0;
202a312c225SMatthew G Knepley   snes->norm = 0.;
203ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
20419653cdaSPeter Brune 
20598b3e84cSPeter Brune   /* initialization */
20619653cdaSPeter Brune 
2073a2ae377SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT) {
2083a2ae377SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,F);CHKERRQ(ierr);
2093a2ae377SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2103a2ae377SPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
2113a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
2123a2ae377SPeter Brune       PetscFunctionReturn(0);
2133a2ae377SPeter Brune     }
2143a2ae377SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
2153a2ae377SPeter Brune   } else {
216e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
217f109b39eSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
218a312c225SMatthew G Knepley       if (snes->domainerror) {
219a312c225SMatthew G Knepley         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
220a312c225SMatthew G Knepley         PetscFunctionReturn(0);
221a312c225SMatthew G Knepley       }
2221aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
223e4ed7901SPeter Brune     if (!snes->norm_init_set) {
2243a2ae377SPeter Brune       /* convergence test */
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       }
230e4ed7901SPeter Brune     } else {
231e4ed7901SPeter Brune       fnorm               = snes->norm_init;
232e4ed7901SPeter Brune       snes->norm_init_set = PETSC_FALSE;
233e4ed7901SPeter Brune     }
2343a2ae377SPeter Brune   }
235e4ed7901SPeter Brune   fminnorm = fnorm;
23619653cdaSPeter Brune 
237ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
238f109b39eSPeter Brune   snes->norm = fnorm;
239ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
240a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
241f109b39eSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
242f109b39eSPeter Brune   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
243a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
244*b3c6a99cSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
245a312c225SMatthew G Knepley 
24619653cdaSPeter Brune   k_restart = 1;
24719653cdaSPeter Brune   l         = 1;
248*b3c6a99cSPeter Brune   ivec      = 0;
24909c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
25098b3e84cSPeter Brune     /* Computation of x^M */
251c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2529f425c49SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
253e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
254e4ed7901SPeter Brune       ierr = SNESSetInitialFunctionNorm(snes->pc,fnorm);CHKERRQ(ierr);
25563e7833aSPeter Brune 
25663e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2579f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
25863e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
25963e7833aSPeter Brune 
2608cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2618cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2628cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2638cc86e31SPeter Brune         PetscFunctionReturn(0);
2648cc86e31SPeter Brune       }
265ddd40ce5SPeter Brune       ierr = SNESGetPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr);
2668cc86e31SPeter Brune     } else {
267f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
268f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
269e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
270e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
2711aa26658SKarl Rupp 
272e7058c64SPeter Brune       fMnorm = fnorm;
2731aa26658SKarl Rupp 
274f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
275f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch,&lssucceed);CHKERRQ(ierr);
276f109b39eSPeter Brune       if (!lssucceed) {
277f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
278f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
279f109b39eSPeter Brune           PetscFunctionReturn(0);
280f109b39eSPeter Brune         }
281f109b39eSPeter Brune       }
2826634f59bSPeter Brune     }
283*b3c6a99cSPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
28498b3e84cSPeter Brune     /* r = F(x) */
2859f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
28619653cdaSPeter Brune 
2879f425c49SPeter Brune     /* differences for selection and restart */
28813a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
289*b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
29013a62661SPeter Brune     } else {
291*b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
29213a62661SPeter Brune     }
293189a9710SBarry Smith     if (PetscIsInfOrNanReal(fAnorm)) {
294189a9710SBarry Smith       snes->reason = SNES_DIVERGED_FNORM_NAN;
295189a9710SBarry Smith       PetscFunctionReturn(0);
296189a9710SBarry Smith     }
2971aa26658SKarl Rupp 
2989f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
299*b3c6a99cSPeter 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);
30019653cdaSPeter Brune     selectRestart = PETSC_FALSE;
30113a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
30221687c63SPeter Brune       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
30328ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
3041aa26658SKarl Rupp       if (selectRestart) restart_count++;
3051aa26658SKarl Rupp       else restart_count = 0;
30613a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
30713a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
30813a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
30913a62661SPeter Brune         restart_count = ngmres->restart_it;
31013a62661SPeter Brune       }
31113a62661SPeter Brune     }
312*b3c6a99cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
31328ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
31428ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
315dfbf837cSBarry Smith       if (ngmres->monitor) {
316dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
317dfbf837cSBarry Smith       }
31828ed4a04SPeter Brune       restart_count = 0;
31919653cdaSPeter Brune       k_restart     = 1;
32019653cdaSPeter Brune       l             = 1;
321*b3c6a99cSPeter Brune       ivec          = 0;
32298b3e84cSPeter Brune       /* q_{00} = nu */
323fa8c639aSPeter Brune       ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
324d2e16ddcSPeter Brune     } else {
32598b3e84cSPeter Brune       /* select the current size of the subspace */
3261e633543SBarry Smith       if (l < ngmres->msize) l++;
32719653cdaSPeter Brune       k_restart++;
32898b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
32938774f0aSPeter Brune       if (ngmres->candidate) {
33038774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
331fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
332d2e16ddcSPeter Brune       } else {
33338774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
334fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
33519653cdaSPeter Brune       }
336d2e16ddcSPeter Brune     }
33719653cdaSPeter Brune 
338ce8c27fbSBarry Smith     ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
339087dfb9eSxuemin     snes->iter = k;
340f109b39eSPeter Brune     snes->norm = fnorm;
341ce8c27fbSBarry Smith     ierr = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
342a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
3438409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
344*b3c6a99cSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
345087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
346a312c225SMatthew G Knepley   }
347a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
348a312c225SMatthew G Knepley   PetscFunctionReturn(0);
349a312c225SMatthew G Knepley }
350a312c225SMatthew G Knepley 
35113a62661SPeter Brune #undef __FUNCT__
35213a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
35313a62661SPeter Brune /*@
35413a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
35513a62661SPeter Brune 
35613a62661SPeter Brune     Logically Collective on SNES
35713a62661SPeter Brune 
35813a62661SPeter Brune     Input Parameters:
35913a62661SPeter Brune +   snes - the iterative context
36013a62661SPeter Brune -   rtype - restart type
36113a62661SPeter Brune 
36213a62661SPeter Brune     Options Database:
36313a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3640c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
36513a62661SPeter Brune 
36613a62661SPeter Brune     Level: intermediate
36713a62661SPeter Brune 
36813a62661SPeter Brune     SNESNGMRESRestartTypes:
36913a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
37013a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
37113a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
37213a62661SPeter Brune 
37313a62661SPeter Brune     Notes:
37413a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
37513a62661SPeter Brune 
37613a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
37713a62661SPeter Brune @*/
3780adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3790adebc6cSBarry Smith {
38013a62661SPeter Brune   PetscErrorCode ierr;
3815fd66863SKarl Rupp 
38213a62661SPeter Brune   PetscFunctionBegin;
38313a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
38413a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
38513a62661SPeter Brune   PetscFunctionReturn(0);
38613a62661SPeter Brune }
38713a62661SPeter Brune 
38813a62661SPeter Brune #undef __FUNCT__
38913a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
39013a62661SPeter Brune /*@
39113a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
39213a62661SPeter Brune     combined solution are used to create the next iterate.
39313a62661SPeter Brune 
39413a62661SPeter Brune     Logically Collective on SNES
39513a62661SPeter Brune 
39613a62661SPeter Brune     Input Parameters:
39713a62661SPeter Brune +   snes - the iterative context
39813a62661SPeter Brune -   stype - selection type
39913a62661SPeter Brune 
40013a62661SPeter Brune     Options Database:
40113a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
40213a62661SPeter Brune 
40313a62661SPeter Brune     Level: intermediate
40413a62661SPeter Brune 
40513a62661SPeter Brune     SNESNGMRESSelectTypes:
40613a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
40713a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
40813a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
40913a62661SPeter Brune 
41013a62661SPeter Brune     Notes:
41113a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
41213a62661SPeter Brune 
41313a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
41413a62661SPeter Brune @*/
4150adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4160adebc6cSBarry Smith {
41713a62661SPeter Brune   PetscErrorCode ierr;
4185fd66863SKarl Rupp 
41913a62661SPeter Brune   PetscFunctionBegin;
42013a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
42113a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
42213a62661SPeter Brune   PetscFunctionReturn(0);
42313a62661SPeter Brune }
42413a62661SPeter Brune 
42513a62661SPeter Brune #undef __FUNCT__
42613a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4270adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4280adebc6cSBarry Smith {
42913a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4305fd66863SKarl Rupp 
43113a62661SPeter Brune   PetscFunctionBegin;
43213a62661SPeter Brune   ngmres->select_type = stype;
43313a62661SPeter Brune   PetscFunctionReturn(0);
43413a62661SPeter Brune }
43513a62661SPeter Brune 
43613a62661SPeter Brune #undef __FUNCT__
43713a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4380adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4390adebc6cSBarry Smith {
44013a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4415fd66863SKarl Rupp 
44213a62661SPeter Brune   PetscFunctionBegin;
44313a62661SPeter Brune   ngmres->restart_type = rtype;
44413a62661SPeter Brune   PetscFunctionReturn(0);
44513a62661SPeter Brune }
44613a62661SPeter Brune 
447dfbf837cSBarry Smith /*MC
4481867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
449a312c225SMatthew G Knepley 
450dfbf837cSBarry Smith    Level: beginner
451dfbf837cSBarry Smith 
4521867fe5bSPeter Brune    Options Database:
45313a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
45438774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
45538774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
45613a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
45713a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
45813a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
45913a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
46013a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
46113a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
46213a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4635c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
46413a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4651867fe5bSPeter Brune 
4661867fe5bSPeter Brune    Notes:
4671867fe5bSPeter Brune 
4681867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4691867fe5bSPeter Brune    optimization problem at each iteration.
4701867fe5bSPeter Brune 
4711867fe5bSPeter Brune    References:
4721867fe5bSPeter Brune 
473dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
474dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
475dfbf837cSBarry Smith 
476dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
477dfbf837cSBarry Smith M*/
478a312c225SMatthew G Knepley 
479a312c225SMatthew G Knepley #undef __FUNCT__
480a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
4818cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
482a312c225SMatthew G Knepley {
483a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
484a312c225SMatthew G Knepley   PetscErrorCode ierr;
485a312c225SMatthew G Knepley 
486a312c225SMatthew G Knepley   PetscFunctionBegin;
487a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
488a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
489a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
490a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
491a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
492a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
493a312c225SMatthew G Knepley 
49442f4f86dSBarry Smith   snes->usespc   = PETSC_TRUE;
4952c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
49646159c86SPeter Brune   snes->pcside   = PC_RIGHT;
4972c155ee1SBarry Smith 
498a312c225SMatthew G Knepley   ierr          = PetscNewLog(snes,SNES_NGMRES,&ngmres);CHKERRQ(ierr);
499a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
500d2e16ddcSPeter Brune   ngmres->msize = 30;
50119653cdaSPeter Brune 
50288976e71SPeter Brune   if (!snes->tolerancesset) {
5030e444f03SPeter Brune     snes->max_funcs = 30000;
5040e444f03SPeter Brune     snes->max_its   = 10000;
50588976e71SPeter Brune   }
5060e444f03SPeter Brune 
50738774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
508d2e16ddcSPeter Brune 
5090298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
510077c4231SPeter Brune   ngmres->approxfunc       = PETSC_FALSE;
51128ed4a04SPeter Brune   ngmres->restart_it       = 2;
51213a62661SPeter Brune   ngmres->restart_periodic = 30;
513f109b39eSPeter Brune   ngmres->gammaA           = 2.0;
514f109b39eSPeter Brune   ngmres->gammaC           = 2.0;
515cac108bcSPeter Brune   ngmres->deltaB           = 0.9;
516cac108bcSPeter Brune   ngmres->epsilonB         = 0.1;
517e7058c64SPeter Brune 
51813a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
51913a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
52013a62661SPeter Brune 
521bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
522bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
523a312c225SMatthew G Knepley   PetscFunctionReturn(0);
524a312c225SMatthew G Knepley }
52599e0435eSBarry Smith 
526