xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 21687c63ff693cd32f35bd2361cfeaae024c1a36)
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;
5178440776SJed Brown   ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr);
5278440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5378440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
5478440776SJed Brown   if (!ngmres->setup_called) {
55087dfb9eSxuemin     msize         = ngmres->msize;  /* restart size */
5619653cdaSPeter Brune     hsize         = msize * msize;
57087dfb9eSxuemin 
5898b3e84cSPeter Brune     /* explicit least squares minimization solve */
5919653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6019653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
6119653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
62f109b39eSPeter Brune                         msize,PetscReal, &ngmres->fnorms,
6319653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6418aa0c0cSPeter Brune     if (ngmres->singlereduction) {
6518aa0c0cSPeter Brune       ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr);
6618aa0c0cSPeter Brune     }
6719653cdaSPeter Brune     ngmres->nrhs = 1;
6819653cdaSPeter Brune     ngmres->lda = msize;
6919653cdaSPeter Brune     ngmres->ldb = msize;
7019653cdaSPeter Brune     ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
7119653cdaSPeter Brune     ierr = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7219653cdaSPeter Brune     ierr = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7319653cdaSPeter Brune     ierr = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7419653cdaSPeter Brune     ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7519653cdaSPeter Brune     ngmres->lwork = 12*msize;
7619653cdaSPeter Brune #if PETSC_USE_COMPLEX
7722d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
7819653cdaSPeter Brune #endif
7922d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
8078440776SJed Brown   }
81e7058c64SPeter Brune 
82e7058c64SPeter Brune   /* linesearch setup */
83e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
84e7058c64SPeter Brune 
8513a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
86f1c6b773SPeter Brune     ierr = SNESLineSearchCreate(((PetscObject)snes)->comm,&ngmres->additive_linesearch);CHKERRQ(ierr);
87f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
881a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
89f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
90f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
91f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
92e7058c64SPeter Brune   }
93e7058c64SPeter Brune 
9478440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
95a312c225SMatthew G Knepley   PetscFunctionReturn(0);
96a312c225SMatthew G Knepley }
97a312c225SMatthew G Knepley 
98a312c225SMatthew G Knepley #undef __FUNCT__
99a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
100a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
101a312c225SMatthew G Knepley {
102a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
103a312c225SMatthew G Knepley   PetscErrorCode ierr;
104dfbf837cSBarry Smith   PetscBool      debug;
105f1c6b773SPeter Brune   SNESLineSearch linesearch;
1060adebc6cSBarry Smith 
107a312c225SMatthew G Knepley   PetscFunctionBegin;
108a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
10913a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
11013a62661SPeter Brune                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,PETSC_NULL);CHKERRQ(ierr);
11113a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
11213a62661SPeter Brune                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,PETSC_NULL);CHKERRQ(ierr);
11338774f0aSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_candidate","Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,PETSC_NULL);CHKERRQ(ierr);
11419653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m",         "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,PETSC_NULL);CHKERRQ(ierr);
1150c777b0cSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart",   "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,PETSC_NULL);CHKERRQ(ierr);
11628ed4a04SPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,PETSC_NULL);CHKERRQ(ierr);
117dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",  "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE: PETSC_FALSE,&debug,PETSC_NULL);CHKERRQ(ierr);
118dfbf837cSBarry Smith   if (debug) {
119dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
120dfbf837cSBarry Smith   }
1216a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA",   "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,PETSC_NULL);CHKERRQ(ierr);
1226a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "  Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,PETSC_NULL);CHKERRQ(ierr);
1236a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,PETSC_NULL);CHKERRQ(ierr);
1246a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB",   "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,PETSC_NULL);CHKERRQ(ierr);
1254d116c7dSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,PETSC_NULL);CHKERRQ(ierr);
126a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1276a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1289e764e56SPeter Brune 
1299e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1309e764e56SPeter Brune   if (!snes->linesearch) {
131f1c6b773SPeter Brune     ierr = SNESGetSNESLineSearch(snes,&linesearch);CHKERRQ(ierr);
1321a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1339e764e56SPeter Brune   }
134a312c225SMatthew G Knepley   PetscFunctionReturn(0);
135a312c225SMatthew G Knepley }
136a312c225SMatthew G Knepley 
137a312c225SMatthew G Knepley #undef __FUNCT__
138a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
139a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
140a312c225SMatthew G Knepley {
141a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
142a312c225SMatthew G Knepley   PetscBool      iascii;
143a312c225SMatthew G Knepley   PetscErrorCode ierr;
144a312c225SMatthew G Knepley 
145a312c225SMatthew G Knepley   PetscFunctionBegin;
146251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
147a312c225SMatthew G Knepley   if (iascii) {
148f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
149f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
150f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
151a312c225SMatthew G Knepley   }
152a312c225SMatthew G Knepley   PetscFunctionReturn(0);
153a312c225SMatthew G Knepley }
154a312c225SMatthew G Knepley 
155a312c225SMatthew G Knepley #undef __FUNCT__
156a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
157a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
158a312c225SMatthew G Knepley {
15938774f0aSPeter Brune 
160087dfb9eSxuemin   SNES_NGMRES        *ngmres = (SNES_NGMRES *) snes->data;
16198b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1629f425c49SPeter Brune   Vec                 X,F,B,D,Y;
163f109b39eSPeter Brune 
164f109b39eSPeter Brune   /* candidate linear combination answers */
1654b32a720SPeter Brune   Vec                 XA,FA,XM,FM,FPC;
16619653cdaSPeter Brune 
16798b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
16818aa0c0cSPeter Brune   PetscReal           fnorm,fMnorm,fAnorm;
16938774f0aSPeter Brune   PetscInt            k,k_restart,l,ivec,restart_count = 0;
17019653cdaSPeter Brune 
17198b3e84cSPeter Brune   /* solution selection data */
17238774f0aSPeter Brune   PetscBool           selectRestart;
17338774f0aSPeter Brune   PetscReal           dnorm,dminnorm = 0.0;
174d484d688SPeter Brune   PetscReal           fminnorm,xnorm,ynorm;
17519653cdaSPeter Brune 
1761e633543SBarry Smith   SNESConvergedReason reason;
17738774f0aSPeter Brune   PetscBool           lssucceed;
178a312c225SMatthew G Knepley   PetscErrorCode      ierr;
179a312c225SMatthew G Knepley 
180a312c225SMatthew G Knepley   PetscFunctionBegin;
18198b3e84cSPeter Brune   /* variable initialization */
182a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
183f109b39eSPeter Brune   X             = snes->vec_sol;
184f109b39eSPeter Brune   F             = snes->vec_func;
185f109b39eSPeter Brune   B             = snes->vec_rhs;
186f109b39eSPeter Brune   XA            = snes->vec_sol_update;
187f109b39eSPeter Brune   FA            = snes->work[0];
188f109b39eSPeter Brune   D             = snes->work[1];
189f109b39eSPeter Brune 
190f109b39eSPeter Brune   /* work for the line search */
191f109b39eSPeter Brune   Y             = snes->work[2];
1929f425c49SPeter Brune   XM            = snes->work[3];
1939f425c49SPeter Brune   FM            = snes->work[4];
194a312c225SMatthew G Knepley 
195a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
196a312c225SMatthew G Knepley   snes->iter = 0;
197a312c225SMatthew G Knepley   snes->norm = 0.;
198a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
19919653cdaSPeter Brune 
20098b3e84cSPeter Brune   /* initialization */
20119653cdaSPeter Brune 
20298b3e84cSPeter Brune   /* r = F(x) */
203e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
204f109b39eSPeter Brune     ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
205a312c225SMatthew G Knepley     if (snes->domainerror) {
206a312c225SMatthew G Knepley       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
207a312c225SMatthew G Knepley       PetscFunctionReturn(0);
208a312c225SMatthew G Knepley     }
209e4ed7901SPeter Brune   } else {
210e4ed7901SPeter Brune     snes->vec_func_init_set = PETSC_FALSE;
211e4ed7901SPeter Brune   }
21219653cdaSPeter Brune 
213e4ed7901SPeter Brune   if (!snes->norm_init_set) {
214f109b39eSPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
215b707f0f7SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in function evaluation");
216e4ed7901SPeter Brune   } else {
217e4ed7901SPeter Brune     fnorm = snes->norm_init;
218e4ed7901SPeter Brune     snes->norm_init_set = PETSC_FALSE;
219e4ed7901SPeter Brune   }
220e4ed7901SPeter Brune   fminnorm = fnorm;
22119653cdaSPeter Brune 
22298b3e84cSPeter Brune   /* q_{00} = nu  */
22338774f0aSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
224087dfb9eSxuemin 
225a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
226f109b39eSPeter Brune   snes->norm = fnorm;
227a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
228f109b39eSPeter Brune   SNESLogConvHistory(snes,fnorm,0);
229f109b39eSPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
230f109b39eSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
231a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
232a312c225SMatthew G Knepley 
23319653cdaSPeter Brune   k_restart = 1;
23419653cdaSPeter Brune   l = 1;
23509c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
23698b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
23798b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
23819653cdaSPeter Brune 
23998b3e84cSPeter Brune     /* Computation of x^M */
240c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2419f425c49SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
242e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr);
243e4ed7901SPeter Brune       ierr = SNESSetInitialFunctionNorm(snes->pc,fnorm);CHKERRQ(ierr);
24463e7833aSPeter Brune 
24563e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2469f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
24763e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
24863e7833aSPeter Brune 
2498cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2508cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2518cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2528cc86e31SPeter Brune         PetscFunctionReturn(0);
2538cc86e31SPeter Brune       }
2544b32a720SPeter Brune       ierr = SNESGetFunction(snes->pc,&FPC,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
2554b32a720SPeter Brune       ierr = VecCopy(FPC,FM);CHKERRQ(ierr);
2564b32a720SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc,&fMnorm);CHKERRQ(ierr);
2578cc86e31SPeter Brune     } else {
258f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
259f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
260e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
261e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
262e7058c64SPeter Brune       fMnorm = fnorm;
263f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
264f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch,&lssucceed);CHKERRQ(ierr);
265f109b39eSPeter Brune       if (!lssucceed) {
266f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
267f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
268f109b39eSPeter Brune           PetscFunctionReturn(0);
269f109b39eSPeter Brune         }
270f109b39eSPeter Brune       }
2716634f59bSPeter Brune     }
27238774f0aSPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,l,XM,FM,fMnorm,X,XA,FA);
27398b3e84cSPeter Brune     /* r = F(x) */
2749f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
27519653cdaSPeter Brune 
2769f425c49SPeter Brune     /* differences for selection and restart */
27713a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
278fa8c639aSPeter Brune       ierr = SNESNGMRESCalculateDifferences_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&fAnorm);CHKERRQ(ierr);
27913a62661SPeter Brune     } else {
28013a62661SPeter Brune       ierr = VecNorm(FA,NORM_2,&fAnorm);CHKERRQ(ierr);
28113a62661SPeter Brune     }
282b707f0f7SPeter Brune     if (PetscIsInfOrNanReal(fAnorm)) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in function evaluation");
2839f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
284fa8c639aSPeter Brune     ierr = SNESNGMRESSelect_Private(snes,k_restart,XM,FM,fMnorm,XA,FA,fAnorm,dnorm,fminnorm,dminnorm,X,F,Y,&fnorm);CHKERRQ(ierr);
28519653cdaSPeter Brune     selectRestart = PETSC_FALSE;
28613a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
287*21687c63SPeter Brune       ierr = SNESNGMRESSelectRestart_Private(snes,l,fAnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr);
28828ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
28919653cdaSPeter Brune       if (selectRestart) {
29028ed4a04SPeter Brune         restart_count++;
29128ed4a04SPeter Brune       } else {
29228ed4a04SPeter Brune         restart_count = 0;
29328ed4a04SPeter Brune       }
29413a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
29513a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
29613a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
29713a62661SPeter Brune         restart_count = ngmres->restart_it;
29813a62661SPeter Brune       }
29913a62661SPeter Brune     }
30028ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
30128ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
302dfbf837cSBarry Smith       if (ngmres->monitor) {
303dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
304dfbf837cSBarry Smith       }
30528ed4a04SPeter Brune       restart_count = 0;
30619653cdaSPeter Brune       k_restart = 1;
30719653cdaSPeter Brune       l = 1;
30898b3e84cSPeter Brune       /* q_{00} = nu */
30938774f0aSPeter Brune       if (ngmres->candidate) {
310fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
311d2e16ddcSPeter Brune       } else {
312fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fMnorm,X);CHKERRQ(ierr);
313d2e16ddcSPeter Brune       }
31419653cdaSPeter Brune     } else {
31598b3e84cSPeter Brune       /* select the current size of the subspace */
3161e633543SBarry Smith       if (l < ngmres->msize) l++;
31719653cdaSPeter Brune       k_restart++;
31898b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
31938774f0aSPeter Brune       if (ngmres->candidate) {
32038774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
321fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
322d2e16ddcSPeter Brune       } else {
32338774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
324fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
32519653cdaSPeter Brune       }
326d2e16ddcSPeter Brune     }
32719653cdaSPeter Brune 
3288409ca45SMatthew G Knepley     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
329087dfb9eSxuemin     snes->iter = k;
330f109b39eSPeter Brune     snes->norm = fnorm;
3318409ca45SMatthew G Knepley     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
3328409ca45SMatthew G Knepley     SNESLogConvHistory(snes,snes->norm,snes->iter);
3338409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
334d484d688SPeter Brune     ierr = VecNormBegin(Y,NORM_2,&ynorm);CHKERRQ(ierr);
335d484d688SPeter Brune     ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);
336d484d688SPeter Brune     ierr = VecNormEnd(Y,NORM_2,&ynorm);CHKERRQ(ierr);
337d484d688SPeter Brune     ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
338d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
339087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
340a312c225SMatthew G Knepley   }
341a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
342a312c225SMatthew G Knepley   PetscFunctionReturn(0);
343a312c225SMatthew G Knepley }
344a312c225SMatthew G Knepley 
34513a62661SPeter Brune #undef __FUNCT__
34613a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
34713a62661SPeter Brune /*@
34813a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
34913a62661SPeter Brune 
35013a62661SPeter Brune     Logically Collective on SNES
35113a62661SPeter Brune 
35213a62661SPeter Brune     Input Parameters:
35313a62661SPeter Brune +   snes - the iterative context
35413a62661SPeter Brune -   rtype - restart type
35513a62661SPeter Brune 
35613a62661SPeter Brune     Options Database:
35713a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3580c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
35913a62661SPeter Brune 
36013a62661SPeter Brune     Level: intermediate
36113a62661SPeter Brune 
36213a62661SPeter Brune     SNESNGMRESRestartTypes:
36313a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
36413a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
36513a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
36613a62661SPeter Brune 
36713a62661SPeter Brune     Notes:
36813a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
36913a62661SPeter Brune 
37013a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
37113a62661SPeter Brune @*/
3720adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3730adebc6cSBarry Smith {
37413a62661SPeter Brune   PetscErrorCode ierr;
3755fd66863SKarl Rupp 
37613a62661SPeter Brune   PetscFunctionBegin;
37713a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
37813a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
37913a62661SPeter Brune   PetscFunctionReturn(0);
38013a62661SPeter Brune }
38113a62661SPeter Brune 
38213a62661SPeter Brune #undef __FUNCT__
38313a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
38413a62661SPeter Brune /*@
38513a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
38613a62661SPeter Brune     combined solution are used to create the next iterate.
38713a62661SPeter Brune 
38813a62661SPeter Brune     Logically Collective on SNES
38913a62661SPeter Brune 
39013a62661SPeter Brune     Input Parameters:
39113a62661SPeter Brune +   snes - the iterative context
39213a62661SPeter Brune -   stype - selection type
39313a62661SPeter Brune 
39413a62661SPeter Brune     Options Database:
39513a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
39613a62661SPeter Brune 
39713a62661SPeter Brune     Level: intermediate
39813a62661SPeter Brune 
39913a62661SPeter Brune     SNESNGMRESSelectTypes:
40013a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
40113a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
40213a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
40313a62661SPeter Brune 
40413a62661SPeter Brune     Notes:
40513a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
40613a62661SPeter Brune 
40713a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
40813a62661SPeter Brune @*/
4090adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4100adebc6cSBarry Smith {
41113a62661SPeter Brune   PetscErrorCode ierr;
4125fd66863SKarl Rupp 
41313a62661SPeter Brune   PetscFunctionBegin;
41413a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
41513a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
41613a62661SPeter Brune   PetscFunctionReturn(0);
41713a62661SPeter Brune }
41813a62661SPeter Brune 
41913a62661SPeter Brune EXTERN_C_BEGIN
42013a62661SPeter Brune #undef __FUNCT__
42113a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4220adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4230adebc6cSBarry Smith {
42413a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
4255fd66863SKarl Rupp 
42613a62661SPeter Brune   PetscFunctionBegin;
42713a62661SPeter Brune   ngmres->select_type = stype;
42813a62661SPeter Brune   PetscFunctionReturn(0);
42913a62661SPeter Brune }
43013a62661SPeter Brune 
43113a62661SPeter Brune #undef __FUNCT__
43213a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4330adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4340adebc6cSBarry Smith {
43513a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
4365fd66863SKarl Rupp 
43713a62661SPeter Brune   PetscFunctionBegin;
43813a62661SPeter Brune   ngmres->restart_type = rtype;
43913a62661SPeter Brune   PetscFunctionReturn(0);
44013a62661SPeter Brune }
44113a62661SPeter Brune EXTERN_C_END
44213a62661SPeter Brune 
443dfbf837cSBarry Smith /*MC
4441867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
445a312c225SMatthew G Knepley 
446dfbf837cSBarry Smith    Level: beginner
447dfbf837cSBarry Smith 
4481867fe5bSPeter Brune    Options Database:
44913a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
45038774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
45138774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
45213a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
45313a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
45413a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
45513a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
45613a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
45713a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
45813a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
45913a62661SPeter Brune .  -snes_linesearch_type <basic,basicnonorms,quadratic,critical> - Line search type used for the default smoother
46013a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4611867fe5bSPeter Brune 
4621867fe5bSPeter Brune    Notes:
4631867fe5bSPeter Brune 
4641867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4651867fe5bSPeter Brune    optimization problem at each iteration.
4661867fe5bSPeter Brune 
4671867fe5bSPeter Brune    References:
4681867fe5bSPeter Brune 
469dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
470dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
471dfbf837cSBarry Smith 
472dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
473dfbf837cSBarry Smith M*/
474a312c225SMatthew G Knepley 
475a312c225SMatthew G Knepley EXTERN_C_BEGIN
476a312c225SMatthew G Knepley #undef __FUNCT__
477a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
478a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
479a312c225SMatthew G Knepley {
480a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
481a312c225SMatthew G Knepley   PetscErrorCode ierr;
482a312c225SMatthew G Knepley 
483a312c225SMatthew G Knepley   PetscFunctionBegin;
484a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
485a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
486a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
487a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
488a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
489a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
490a312c225SMatthew G Knepley 
49142f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
4922c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
4932c155ee1SBarry Smith 
494a312c225SMatthew G Knepley   ierr = PetscNewLog(snes,SNES_NGMRES,&ngmres);CHKERRQ(ierr);
495a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
496d2e16ddcSPeter Brune   ngmres->msize = 30;
49719653cdaSPeter Brune 
49888976e71SPeter Brune   if (!snes->tolerancesset) {
4990e444f03SPeter Brune     snes->max_funcs = 30000;
5000e444f03SPeter Brune     snes->max_its   = 10000;
50188976e71SPeter Brune   }
5020e444f03SPeter Brune 
50338774f0aSPeter Brune   ngmres->candidate   = PETSC_FALSE;
504d2e16ddcSPeter Brune 
505e7058c64SPeter Brune   ngmres->additive_linesearch = PETSC_NULL;
506e7058c64SPeter Brune 
50728ed4a04SPeter Brune   ngmres->restart_it = 2;
50813a62661SPeter Brune   ngmres->restart_periodic = 30;
509f109b39eSPeter Brune   ngmres->gammaA     = 2.0;
510f109b39eSPeter Brune   ngmres->gammaC     = 2.0;
511cac108bcSPeter Brune   ngmres->deltaB     = 0.9;
512cac108bcSPeter Brune   ngmres->epsilonB   = 0.1;
513e7058c64SPeter Brune 
51413a62661SPeter Brune   ngmres->restart_type   = SNES_NGMRES_RESTART_DIFFERENCE;
51513a62661SPeter Brune   ngmres->select_type    = SNES_NGMRES_SELECT_DIFFERENCE;
51613a62661SPeter Brune 
51713a62661SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetSelectType_C","SNESNGMRESSetSelectType_NGMRES",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
51813a62661SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetRestartType_C","SNESNGMRESSetRestartType_NGMRES",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
519a312c225SMatthew G Knepley   PetscFunctionReturn(0);
520a312c225SMatthew G Knepley }
521a312c225SMatthew G Knepley EXTERN_C_END
522