xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision fced5a79f641b28174cc1f1ef5e329f9f9a60666)
113a62661SPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
219653cdaSPeter Brune #include <petscblaslapack.h>
3*fced5a79SAsbjørn Nilsen Riseth #include <petscdm.h>
4a312c225SMatthew G Knepley 
56a6fc655SJed Brown const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0};
66a6fc655SJed Brown const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",0};
713a62661SPeter Brune 
8a312c225SMatthew G Knepley #undef __FUNCT__
9a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
10a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
11a312c225SMatthew G Knepley {
12a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
13a312c225SMatthew G Knepley   PetscErrorCode ierr;
14a312c225SMatthew G Knepley 
15a312c225SMatthew G Knepley   PetscFunctionBegin;
16f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);
17f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);
18f1c6b773SPeter Brune   ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr);
19a312c225SMatthew G Knepley   PetscFunctionReturn(0);
20a312c225SMatthew G Knepley }
21a312c225SMatthew G Knepley 
22a312c225SMatthew G Knepley #undef __FUNCT__
23a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
24a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
25a312c225SMatthew G Knepley {
26a312c225SMatthew G Knepley   PetscErrorCode ierr;
2778440776SJed Brown   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;
28a312c225SMatthew G Knepley 
29a312c225SMatthew G Knepley   PetscFunctionBegin;
30a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
31f109b39eSPeter Brune   ierr = PetscFree5(ngmres->h,ngmres->beta,ngmres->xi,ngmres->fnorms,ngmres->q);CHKERRQ(ierr);
3219653cdaSPeter Brune   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
3318aa0c0cSPeter Brune   ierr = PetscFree(ngmres->xnorms);CHKERRQ(ierr);
3419653cdaSPeter Brune #if PETSC_USE_COMPLEX
3522d28d08SBarry Smith   ierr = PetscFree(ngmres->rwork);CHKERRQ(ierr);
3619653cdaSPeter Brune #endif
3722d28d08SBarry Smith   ierr = PetscFree(ngmres->work);CHKERRQ(ierr);
3822d28d08SBarry Smith   ierr = PetscFree(snes->data);CHKERRQ(ierr);
39a312c225SMatthew G Knepley   PetscFunctionReturn(0);
40a312c225SMatthew G Knepley }
41a312c225SMatthew G Knepley 
42a312c225SMatthew G Knepley #undef __FUNCT__
43a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
44a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
45a312c225SMatthew G Knepley {
46a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
47e7058c64SPeter Brune   const char     *optionsprefix;
4819653cdaSPeter Brune   PetscInt       msize,hsize;
49a312c225SMatthew G Knepley   PetscErrorCode ierr;
50*fced5a79SAsbjørn Nilsen Riseth   DM             dm;
51a312c225SMatthew G Knepley 
52a312c225SMatthew G Knepley   PetscFunctionBegin;
5346159c86SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
5446159c86SPeter Brune     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function");
5546159c86SPeter Brune   }
566c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
57fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr);
58*fced5a79SAsbjørn Nilsen Riseth 
59*fced5a79SAsbjørn Nilsen Riseth   if (!snes->vec_sol) {
60*fced5a79SAsbjørn Nilsen Riseth     ierr             = SNESGetDM(snes,&dm);CHKERRQ(ierr);
61*fced5a79SAsbjørn Nilsen Riseth     ierr             = DMCreateGlobalVector(dm,&snes->vec_sol);CHKERRQ(ierr);
62*fced5a79SAsbjørn Nilsen Riseth   }
63*fced5a79SAsbjørn Nilsen Riseth 
6478440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
6578440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
6678440776SJed Brown   if (!ngmres->setup_called) {
67087dfb9eSxuemin     msize = ngmres->msize;          /* restart size */
6819653cdaSPeter Brune     hsize = msize * msize;
69087dfb9eSxuemin 
7098b3e84cSPeter Brune     /* explicit least squares minimization solve */
71dcca6d9dSJed Brown     ierr = PetscMalloc5(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, msize,&ngmres->fnorms, hsize,&ngmres->q);CHKERRQ(ierr);
72785e854fSJed Brown     ierr = PetscMalloc1(msize,&ngmres->xnorms);CHKERRQ(ierr);
7319653cdaSPeter Brune     ngmres->nrhs  = 1;
7419653cdaSPeter Brune     ngmres->lda   = msize;
7519653cdaSPeter Brune     ngmres->ldb   = msize;
76785e854fSJed Brown     ierr          = PetscMalloc1(msize,&ngmres->s);CHKERRQ(ierr);
7719653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7819653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7919653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
8019653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
8119653cdaSPeter Brune     ngmres->lwork = 12*msize;
8219653cdaSPeter Brune #if PETSC_USE_COMPLEX
83854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
8419653cdaSPeter Brune #endif
85854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
8678440776SJed Brown   }
87e7058c64SPeter Brune 
88e7058c64SPeter Brune   /* linesearch setup */
89e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
90e7058c64SPeter Brune 
9113a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
92ce94432eSBarry Smith     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
93f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
941a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
95f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
96f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
97f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
98e7058c64SPeter Brune   }
99e7058c64SPeter Brune 
10078440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
101a312c225SMatthew G Knepley   PetscFunctionReturn(0);
102a312c225SMatthew G Knepley }
103a312c225SMatthew G Knepley 
104a312c225SMatthew G Knepley #undef __FUNCT__
105a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
1068c34d3f5SBarry Smith PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptions *PetscOptionsObject,SNES snes)
107a312c225SMatthew G Knepley {
108a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
109a312c225SMatthew G Knepley   PetscErrorCode ierr;
11094ae4db5SBarry Smith   PetscBool      debug = PETSC_FALSE;
111f1c6b773SPeter Brune   SNESLineSearch linesearch;
1120adebc6cSBarry Smith 
113a312c225SMatthew G Knepley   PetscFunctionBegin;
114e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNES NGMRES options");CHKERRQ(ierr);
11513a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
1160298fd71SBarry Smith                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
11713a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
1180298fd71SBarry Smith                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
1190298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
120077c4231SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
1210298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
1220298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
1230298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
1240298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
125dfbf837cSBarry Smith   if (debug) {
126ce94432eSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
127dfbf837cSBarry Smith   }
1280298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
1290298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
1300298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
1310298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
1320298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
133a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1346a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1359e764e56SPeter Brune 
1369e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1379e764e56SPeter Brune   if (!snes->linesearch) {
1387601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1391a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1409e764e56SPeter Brune   }
141a312c225SMatthew G Knepley   PetscFunctionReturn(0);
142a312c225SMatthew G Knepley }
143a312c225SMatthew G Knepley 
144a312c225SMatthew G Knepley #undef __FUNCT__
145a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
146a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
147a312c225SMatthew G Knepley {
148a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
149a312c225SMatthew G Knepley   PetscBool      iascii;
150a312c225SMatthew G Knepley   PetscErrorCode ierr;
151a312c225SMatthew G Knepley 
152a312c225SMatthew G Knepley   PetscFunctionBegin;
153251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
154a312c225SMatthew G Knepley   if (iascii) {
155f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
156f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
157f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
158a312c225SMatthew G Knepley   }
159a312c225SMatthew G Knepley   PetscFunctionReturn(0);
160a312c225SMatthew G Knepley }
161a312c225SMatthew G Knepley 
162a312c225SMatthew G Knepley #undef __FUNCT__
163a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
164a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
165a312c225SMatthew G Knepley {
166087dfb9eSxuemin   SNES_NGMRES          *ngmres = (SNES_NGMRES*) snes->data;
16798b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1689f425c49SPeter Brune   Vec                  X,F,B,D,Y;
169f109b39eSPeter Brune 
170f109b39eSPeter Brune   /* candidate linear combination answers */
171ddd40ce5SPeter Brune   Vec                  XA,FA,XM,FM;
17219653cdaSPeter Brune 
17398b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
17418aa0c0cSPeter Brune   PetscReal            fnorm,fMnorm,fAnorm;
175b3c6a99cSPeter Brune   PetscReal            xnorm,xMnorm,xAnorm;
176b3c6a99cSPeter Brune   PetscReal            ynorm,yMnorm,yAnorm;
17738774f0aSPeter Brune   PetscInt             k,k_restart,l,ivec,restart_count = 0;
17819653cdaSPeter Brune 
17998b3e84cSPeter Brune   /* solution selection data */
18038774f0aSPeter Brune   PetscBool            selectRestart;
18138774f0aSPeter Brune   PetscReal            dnorm,dminnorm = 0.0;
182b3c6a99cSPeter Brune   PetscReal            fminnorm;
18319653cdaSPeter Brune 
1841e633543SBarry Smith   SNESConvergedReason  reason;
185422a814eSBarry Smith   SNESLineSearchReason lssucceed;
186a312c225SMatthew G Knepley   PetscErrorCode       ierr;
187a312c225SMatthew G Knepley 
188a312c225SMatthew G Knepley   PetscFunctionBegin;
189c579b300SPatrick Farrell 
190c579b300SPatrick Farrell   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
191c579b300SPatrick Farrell     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
192c579b300SPatrick Farrell   }
193c579b300SPatrick Farrell 
194fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
19598b3e84cSPeter Brune   /* variable initialization */
196a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
197f109b39eSPeter Brune   X            = snes->vec_sol;
198f109b39eSPeter Brune   F            = snes->vec_func;
199f109b39eSPeter Brune   B            = snes->vec_rhs;
200f109b39eSPeter Brune   XA           = snes->vec_sol_update;
201f109b39eSPeter Brune   FA           = snes->work[0];
202f109b39eSPeter Brune   D            = snes->work[1];
203f109b39eSPeter Brune 
204f109b39eSPeter Brune   /* work for the line search */
205f109b39eSPeter Brune   Y  = snes->work[2];
2069f425c49SPeter Brune   XM = snes->work[3];
2079f425c49SPeter Brune   FM = snes->work[4];
208a312c225SMatthew G Knepley 
209e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
210a312c225SMatthew G Knepley   snes->iter = 0;
211a312c225SMatthew G Knepley   snes->norm = 0.;
212e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
21319653cdaSPeter Brune 
21498b3e84cSPeter Brune   /* initialization */
21519653cdaSPeter Brune 
2163a2ae377SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT) {
217be95d8f1SBarry Smith     ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr);
2183a2ae377SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2193a2ae377SPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
2203a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
2213a2ae377SPeter Brune       PetscFunctionReturn(0);
2223a2ae377SPeter Brune     }
2233a2ae377SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
2243a2ae377SPeter Brune   } else {
225e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
226f109b39eSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
2271aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
228c1c75074SPeter Brune 
229f109b39eSPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
230422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
2313a2ae377SPeter Brune   }
232e4ed7901SPeter Brune   fminnorm = fnorm;
23319653cdaSPeter Brune 
234e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
235f109b39eSPeter Brune   snes->norm = fnorm;
236e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
237a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
238f109b39eSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
239f109b39eSPeter Brune   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
240a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
241b3c6a99cSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
242a312c225SMatthew G Knepley 
24319653cdaSPeter Brune   k_restart = 1;
24419653cdaSPeter Brune   l         = 1;
245b3c6a99cSPeter Brune   ivec      = 0;
24609c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
24798b3e84cSPeter Brune     /* Computation of x^M */
248c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2499f425c49SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
250e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
25163e7833aSPeter Brune 
25263e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2539f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
25463e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
25563e7833aSPeter Brune 
2568cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2578cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2588cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2598cc86e31SPeter Brune         PetscFunctionReturn(0);
2608cc86e31SPeter Brune       }
261be95d8f1SBarry Smith       ierr = SNESGetNPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr);
2628cc86e31SPeter Brune     } else {
263f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
264f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
265e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
266e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
2671aa26658SKarl Rupp 
268e7058c64SPeter Brune       fMnorm = fnorm;
2691aa26658SKarl Rupp 
270f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
271422a814eSBarry Smith       ierr = SNESLineSearchGetReason(snes->linesearch,&lssucceed);CHKERRQ(ierr);
272422a814eSBarry Smith       if (lssucceed) {
273f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
274f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
275f109b39eSPeter Brune           PetscFunctionReturn(0);
276f109b39eSPeter Brune         }
277f109b39eSPeter Brune       }
2786634f59bSPeter Brune     }
279b3c6a99cSPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
28098b3e84cSPeter Brune     /* r = F(x) */
2819f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
28219653cdaSPeter Brune 
2839f425c49SPeter Brune     /* differences for selection and restart */
28413a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
285b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
28613a62661SPeter Brune     } else {
287b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
28813a62661SPeter Brune     }
289422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
2901aa26658SKarl Rupp 
2919f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
292b3c6a99cSPeter 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);
29319653cdaSPeter Brune     selectRestart = PETSC_FALSE;
29413a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
29521687c63SPeter Brune       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
29628ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
2971aa26658SKarl Rupp       if (selectRestart) restart_count++;
2981aa26658SKarl Rupp       else restart_count = 0;
29913a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
30013a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
30113a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
30213a62661SPeter Brune         restart_count = ngmres->restart_it;
30313a62661SPeter Brune       }
30413a62661SPeter Brune     }
305b3c6a99cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
30628ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
30728ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
308dfbf837cSBarry Smith       if (ngmres->monitor) {
309dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
310dfbf837cSBarry Smith       }
31128ed4a04SPeter Brune       restart_count = 0;
31219653cdaSPeter Brune       k_restart     = 1;
31319653cdaSPeter Brune       l             = 1;
314b3c6a99cSPeter Brune       ivec          = 0;
31598b3e84cSPeter Brune       /* q_{00} = nu */
316fa8c639aSPeter Brune       ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
317d2e16ddcSPeter Brune     } else {
31898b3e84cSPeter Brune       /* select the current size of the subspace */
3191e633543SBarry Smith       if (l < ngmres->msize) l++;
32019653cdaSPeter Brune       k_restart++;
32198b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
32238774f0aSPeter Brune       if (ngmres->candidate) {
32338774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
324fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
325d2e16ddcSPeter Brune       } else {
32638774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
327fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
32819653cdaSPeter Brune       }
329d2e16ddcSPeter Brune     }
33019653cdaSPeter Brune 
331e04113cfSBarry Smith     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
332087dfb9eSxuemin     snes->iter = k;
333f109b39eSPeter Brune     snes->norm = fnorm;
334e04113cfSBarry Smith     ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
335a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
3368409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
337b3c6a99cSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
338087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
339a312c225SMatthew G Knepley   }
340a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
341a312c225SMatthew G Knepley   PetscFunctionReturn(0);
342a312c225SMatthew G Knepley }
343a312c225SMatthew G Knepley 
34413a62661SPeter Brune #undef __FUNCT__
34513a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
34613a62661SPeter Brune /*@
34713a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
34813a62661SPeter Brune 
34913a62661SPeter Brune     Logically Collective on SNES
35013a62661SPeter Brune 
35113a62661SPeter Brune     Input Parameters:
35213a62661SPeter Brune +   snes - the iterative context
35313a62661SPeter Brune -   rtype - restart type
35413a62661SPeter Brune 
35513a62661SPeter Brune     Options Database:
35613a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3570c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
35813a62661SPeter Brune 
35913a62661SPeter Brune     Level: intermediate
36013a62661SPeter Brune 
36113a62661SPeter Brune     SNESNGMRESRestartTypes:
36213a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
36313a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
36413a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
36513a62661SPeter Brune 
36613a62661SPeter Brune     Notes:
36713a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
36813a62661SPeter Brune 
36913a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
37013a62661SPeter Brune @*/
3710adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3720adebc6cSBarry Smith {
37313a62661SPeter Brune   PetscErrorCode ierr;
3745fd66863SKarl Rupp 
37513a62661SPeter Brune   PetscFunctionBegin;
37613a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
37713a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
37813a62661SPeter Brune   PetscFunctionReturn(0);
37913a62661SPeter Brune }
38013a62661SPeter Brune 
38113a62661SPeter Brune #undef __FUNCT__
38213a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
38313a62661SPeter Brune /*@
38413a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
38513a62661SPeter Brune     combined solution are used to create the next iterate.
38613a62661SPeter Brune 
38713a62661SPeter Brune     Logically Collective on SNES
38813a62661SPeter Brune 
38913a62661SPeter Brune     Input Parameters:
39013a62661SPeter Brune +   snes - the iterative context
39113a62661SPeter Brune -   stype - selection type
39213a62661SPeter Brune 
39313a62661SPeter Brune     Options Database:
39413a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
39513a62661SPeter Brune 
39613a62661SPeter Brune     Level: intermediate
39713a62661SPeter Brune 
39813a62661SPeter Brune     SNESNGMRESSelectTypes:
39913a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
40013a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
40113a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
40213a62661SPeter Brune 
40313a62661SPeter Brune     Notes:
40413a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
40513a62661SPeter Brune 
40613a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
40713a62661SPeter Brune @*/
4080adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4090adebc6cSBarry Smith {
41013a62661SPeter Brune   PetscErrorCode ierr;
4115fd66863SKarl Rupp 
41213a62661SPeter Brune   PetscFunctionBegin;
41313a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
41413a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
41513a62661SPeter Brune   PetscFunctionReturn(0);
41613a62661SPeter Brune }
41713a62661SPeter Brune 
41813a62661SPeter Brune #undef __FUNCT__
41913a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4200adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4210adebc6cSBarry Smith {
42213a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4235fd66863SKarl Rupp 
42413a62661SPeter Brune   PetscFunctionBegin;
42513a62661SPeter Brune   ngmres->select_type = stype;
42613a62661SPeter Brune   PetscFunctionReturn(0);
42713a62661SPeter Brune }
42813a62661SPeter Brune 
42913a62661SPeter Brune #undef __FUNCT__
43013a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4310adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4320adebc6cSBarry Smith {
43313a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4345fd66863SKarl Rupp 
43513a62661SPeter Brune   PetscFunctionBegin;
43613a62661SPeter Brune   ngmres->restart_type = rtype;
43713a62661SPeter Brune   PetscFunctionReturn(0);
43813a62661SPeter Brune }
43913a62661SPeter Brune 
440dfbf837cSBarry Smith /*MC
4411867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
442a312c225SMatthew G Knepley 
443dfbf837cSBarry Smith    Level: beginner
444dfbf837cSBarry Smith 
4451867fe5bSPeter Brune    Options Database:
44613a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
44738774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
44838774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
44913a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
45013a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
45113a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
45213a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
45313a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
45413a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
45513a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4565c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
45713a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4581867fe5bSPeter Brune 
4591867fe5bSPeter Brune    Notes:
4601867fe5bSPeter Brune 
4611867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4621867fe5bSPeter Brune    optimization problem at each iteration.
4631867fe5bSPeter Brune 
4641867fe5bSPeter Brune    References:
4651867fe5bSPeter Brune 
466dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
467dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
468dfbf837cSBarry Smith 
469dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
470dfbf837cSBarry Smith M*/
471a312c225SMatthew G Knepley 
472a312c225SMatthew G Knepley #undef __FUNCT__
473a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
4748cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
475a312c225SMatthew G Knepley {
476a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
477a312c225SMatthew G Knepley   PetscErrorCode ierr;
478a312c225SMatthew G Knepley 
479a312c225SMatthew G Knepley   PetscFunctionBegin;
480a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
481a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
482a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
483a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
484a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
485a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
486a312c225SMatthew G Knepley 
48742f4f86dSBarry Smith   snes->usespc   = PETSC_TRUE;
4882c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
48946159c86SPeter Brune   snes->pcside   = PC_RIGHT;
4902c155ee1SBarry Smith 
491b00a9115SJed Brown   ierr          = PetscNewLog(snes,&ngmres);CHKERRQ(ierr);
492a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
493d2e16ddcSPeter Brune   ngmres->msize = 30;
49419653cdaSPeter Brune 
49588976e71SPeter Brune   if (!snes->tolerancesset) {
4960e444f03SPeter Brune     snes->max_funcs = 30000;
4970e444f03SPeter Brune     snes->max_its   = 10000;
49888976e71SPeter Brune   }
4990e444f03SPeter Brune 
50038774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
501d2e16ddcSPeter Brune 
5020298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
503077c4231SPeter Brune   ngmres->approxfunc       = PETSC_FALSE;
50428ed4a04SPeter Brune   ngmres->restart_it       = 2;
50513a62661SPeter Brune   ngmres->restart_periodic = 30;
506f109b39eSPeter Brune   ngmres->gammaA           = 2.0;
507f109b39eSPeter Brune   ngmres->gammaC           = 2.0;
508cac108bcSPeter Brune   ngmres->deltaB           = 0.9;
509cac108bcSPeter Brune   ngmres->epsilonB         = 0.1;
510e7058c64SPeter Brune 
51113a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
51213a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
51313a62661SPeter Brune 
514bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
515bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
516a312c225SMatthew G Knepley   PetscFunctionReturn(0);
517a312c225SMatthew G Knepley }
518