xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 422a814ef4a731b8529cf3a6428db526d183e312)
113a62661SPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/
219653cdaSPeter Brune #include <petscblaslapack.h>
3a312c225SMatthew G Knepley 
46a6fc655SJed Brown const char *const SNESNGMRESRestartTypes[] = {"NONE","PERIODIC","DIFFERENCE","SNESNGMRESRestartType","SNES_NGMRES_RESTART_",0};
56a6fc655SJed Brown const char *const SNESNGMRESSelectTypes[] = {"NONE","DIFFERENCE","LINESEARCH","SNESNGMRESSelectType","SNES_NGMRES_SELECT_",0};
613a62661SPeter Brune 
7a312c225SMatthew G Knepley #undef __FUNCT__
8a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
9a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
10a312c225SMatthew G Knepley {
11a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
12a312c225SMatthew G Knepley   PetscErrorCode ierr;
13a312c225SMatthew G Knepley 
14a312c225SMatthew G Knepley   PetscFunctionBegin;
15f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);
16f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);
17f1c6b773SPeter Brune   ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr);
18a312c225SMatthew G Knepley   PetscFunctionReturn(0);
19a312c225SMatthew G Knepley }
20a312c225SMatthew G Knepley 
21a312c225SMatthew G Knepley #undef __FUNCT__
22a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
23a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
24a312c225SMatthew G Knepley {
25a312c225SMatthew G Knepley   PetscErrorCode ierr;
2678440776SJed Brown   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;
27a312c225SMatthew G Knepley 
28a312c225SMatthew G Knepley   PetscFunctionBegin;
29a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
30f109b39eSPeter Brune   ierr = PetscFree5(ngmres->h,ngmres->beta,ngmres->xi,ngmres->fnorms,ngmres->q);CHKERRQ(ierr);
3119653cdaSPeter Brune   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
3218aa0c0cSPeter Brune   ierr = PetscFree(ngmres->xnorms);CHKERRQ(ierr);
3319653cdaSPeter Brune #if PETSC_USE_COMPLEX
3422d28d08SBarry Smith   ierr = PetscFree(ngmres->rwork);CHKERRQ(ierr);
3519653cdaSPeter Brune #endif
3622d28d08SBarry Smith   ierr = PetscFree(ngmres->work);CHKERRQ(ierr);
3722d28d08SBarry Smith   ierr = PetscFree(snes->data);CHKERRQ(ierr);
38a312c225SMatthew G Knepley   PetscFunctionReturn(0);
39a312c225SMatthew G Knepley }
40a312c225SMatthew G Knepley 
41a312c225SMatthew G Knepley #undef __FUNCT__
42a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
43a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
44a312c225SMatthew G Knepley {
45a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
46e7058c64SPeter Brune   const char     *optionsprefix;
4719653cdaSPeter Brune   PetscInt       msize,hsize;
48a312c225SMatthew G Knepley   PetscErrorCode ierr;
49a312c225SMatthew G Knepley 
50a312c225SMatthew G Knepley   PetscFunctionBegin;
5146159c86SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
5246159c86SPeter Brune     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNGMRES does not support left preconditioning with unpreconditioned function");
5346159c86SPeter Brune   }
546c67d002SPeter Brune   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
55fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,5);CHKERRQ(ierr);
5678440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5778440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
5878440776SJed Brown   if (!ngmres->setup_called) {
59087dfb9eSxuemin     msize = ngmres->msize;          /* restart size */
6019653cdaSPeter Brune     hsize = msize * msize;
61087dfb9eSxuemin 
6298b3e84cSPeter Brune     /* explicit least squares minimization solve */
63dcca6d9dSJed Brown     ierr = PetscMalloc5(hsize,&ngmres->h, msize,&ngmres->beta, msize,&ngmres->xi, msize,&ngmres->fnorms, hsize,&ngmres->q);CHKERRQ(ierr);
64785e854fSJed Brown     ierr = PetscMalloc1(msize,&ngmres->xnorms);CHKERRQ(ierr);
6519653cdaSPeter Brune     ngmres->nrhs  = 1;
6619653cdaSPeter Brune     ngmres->lda   = msize;
6719653cdaSPeter Brune     ngmres->ldb   = msize;
68785e854fSJed Brown     ierr          = PetscMalloc1(msize,&ngmres->s);CHKERRQ(ierr);
6919653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7019653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7119653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7219653cdaSPeter Brune     ierr          = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7319653cdaSPeter Brune     ngmres->lwork = 12*msize;
7419653cdaSPeter Brune #if PETSC_USE_COMPLEX
75854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
7619653cdaSPeter Brune #endif
77854ce69bSBarry Smith     ierr = PetscMalloc1(ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
7878440776SJed Brown   }
79e7058c64SPeter Brune 
80e7058c64SPeter Brune   /* linesearch setup */
81e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes,&optionsprefix);CHKERRQ(ierr);
82e7058c64SPeter Brune 
8313a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
84ce94432eSBarry Smith     ierr = SNESLineSearchCreate(PetscObjectComm((PetscObject)snes),&ngmres->additive_linesearch);CHKERRQ(ierr);
85f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch,snes);CHKERRQ(ierr);
861a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch,SNESLINESEARCHL2);CHKERRQ(ierr);
87f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,"additive_");CHKERRQ(ierr);
88f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch,optionsprefix);CHKERRQ(ierr);
89f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
90e7058c64SPeter Brune   }
91e7058c64SPeter Brune 
9278440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
93a312c225SMatthew G Knepley   PetscFunctionReturn(0);
94a312c225SMatthew G Knepley }
95a312c225SMatthew G Knepley 
96a312c225SMatthew G Knepley #undef __FUNCT__
97a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
988c34d3f5SBarry Smith PetscErrorCode SNESSetFromOptions_NGMRES(PetscOptions *PetscOptionsObject,SNES snes)
99a312c225SMatthew G Knepley {
100a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
101a312c225SMatthew G Knepley   PetscErrorCode ierr;
10294ae4db5SBarry Smith   PetscBool      debug = PETSC_FALSE;
103f1c6b773SPeter Brune   SNESLineSearch linesearch;
1040adebc6cSBarry Smith 
105a312c225SMatthew G Knepley   PetscFunctionBegin;
106e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNES NGMRES options");CHKERRQ(ierr);
10713a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
1080298fd71SBarry Smith                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,NULL);CHKERRQ(ierr);
10913a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
1100298fd71SBarry Smith                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,NULL);CHKERRQ(ierr);
1110298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage",              "SNES",ngmres->candidate,&ngmres->candidate,NULL);CHKERRQ(ierr);
112077c4231SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_approxfunc","Linearly approximate the function", "SNES",ngmres->approxfunc,&ngmres->approxfunc,NULL);CHKERRQ(ierr);
1130298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_m",          "Number of directions",               "SNES",ngmres->msize,&ngmres->msize,NULL);CHKERRQ(ierr);
1140298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart",    "Iterations before forced restart",   "SNES",ngmres->restart_periodic,&ngmres->restart_periodic,NULL);CHKERRQ(ierr);
1150298fd71SBarry Smith   ierr = PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart","SNES",ngmres->restart_it,&ngmres->restart_it,NULL);CHKERRQ(ierr);
1160298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",   "Monitor actions of NGMRES",          "SNES",ngmres->monitor ? PETSC_TRUE : PETSC_FALSE,&debug,NULL);CHKERRQ(ierr);
117dfbf837cSBarry Smith   if (debug) {
118ce94432eSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
119dfbf837cSBarry Smith   }
1200298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaA",    "Residual selection constant",   "SNES",ngmres->gammaA,&ngmres->gammaA,NULL);CHKERRQ(ierr);
1210298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_gammaC",    "Residual restart constant",     "SNES",ngmres->gammaC,&ngmres->gammaC,NULL);CHKERRQ(ierr);
1220298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_epsilonB",  "Difference selection constant", "SNES",ngmres->epsilonB,&ngmres->epsilonB,NULL);CHKERRQ(ierr);
1230298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_ngmres_deltaB",    "Difference residual selection constant", "SNES",ngmres->deltaB,&ngmres->deltaB,NULL);CHKERRQ(ierr);
1240298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES",ngmres->singlereduction,&ngmres->singlereduction,NULL);CHKERRQ(ierr);
125a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1266a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1279e764e56SPeter Brune 
1289e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1299e764e56SPeter Brune   if (!snes->linesearch) {
1307601faf0SJed Brown     ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
1311a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr);
1329e764e56SPeter Brune   }
133a312c225SMatthew G Knepley   PetscFunctionReturn(0);
134a312c225SMatthew G Knepley }
135a312c225SMatthew G Knepley 
136a312c225SMatthew G Knepley #undef __FUNCT__
137a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
138a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes,PetscViewer viewer)
139a312c225SMatthew G Knepley {
140a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
141a312c225SMatthew G Knepley   PetscBool      iascii;
142a312c225SMatthew G Knepley   PetscErrorCode ierr;
143a312c225SMatthew G Knepley 
144a312c225SMatthew G Knepley   PetscFunctionBegin;
145251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
146a312c225SMatthew G Knepley   if (iascii) {
147f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
148f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n",ngmres->gammaA,ngmres->gammaC);CHKERRQ(ierr);
149f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n",ngmres->epsilonB,ngmres->deltaB);CHKERRQ(ierr);
150a312c225SMatthew G Knepley   }
151a312c225SMatthew G Knepley   PetscFunctionReturn(0);
152a312c225SMatthew G Knepley }
153a312c225SMatthew G Knepley 
154a312c225SMatthew G Knepley #undef __FUNCT__
155a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
156a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
157a312c225SMatthew G Knepley {
158087dfb9eSxuemin   SNES_NGMRES          *ngmres = (SNES_NGMRES*) snes->data;
15998b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1609f425c49SPeter Brune   Vec                  X,F,B,D,Y;
161f109b39eSPeter Brune 
162f109b39eSPeter Brune   /* candidate linear combination answers */
163ddd40ce5SPeter Brune   Vec                  XA,FA,XM,FM;
16419653cdaSPeter Brune 
16598b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
16618aa0c0cSPeter Brune   PetscReal            fnorm,fMnorm,fAnorm;
167b3c6a99cSPeter Brune   PetscReal            xnorm,xMnorm,xAnorm;
168b3c6a99cSPeter Brune   PetscReal            ynorm,yMnorm,yAnorm;
16938774f0aSPeter Brune   PetscInt             k,k_restart,l,ivec,restart_count = 0;
17019653cdaSPeter Brune 
17198b3e84cSPeter Brune   /* solution selection data */
17238774f0aSPeter Brune   PetscBool            selectRestart;
17338774f0aSPeter Brune   PetscReal            dnorm,dminnorm = 0.0;
174b3c6a99cSPeter Brune   PetscReal            fminnorm;
17519653cdaSPeter Brune 
1761e633543SBarry Smith   SNESConvergedReason  reason;
177*422a814eSBarry Smith   SNESLineSearchReason lssucceed;
178a312c225SMatthew G Knepley   PetscErrorCode       ierr;
179a312c225SMatthew G Knepley 
180a312c225SMatthew G Knepley   PetscFunctionBegin;
181c579b300SPatrick Farrell 
182c579b300SPatrick Farrell   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
183c579b300SPatrick Farrell     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
184c579b300SPatrick Farrell   }
185c579b300SPatrick Farrell 
186fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
18798b3e84cSPeter Brune   /* variable initialization */
188a312c225SMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
189f109b39eSPeter Brune   X            = snes->vec_sol;
190f109b39eSPeter Brune   F            = snes->vec_func;
191f109b39eSPeter Brune   B            = snes->vec_rhs;
192f109b39eSPeter Brune   XA           = snes->vec_sol_update;
193f109b39eSPeter Brune   FA           = snes->work[0];
194f109b39eSPeter Brune   D            = snes->work[1];
195f109b39eSPeter Brune 
196f109b39eSPeter Brune   /* work for the line search */
197f109b39eSPeter Brune   Y  = snes->work[2];
1989f425c49SPeter Brune   XM = snes->work[3];
1999f425c49SPeter Brune   FM = snes->work[4];
200a312c225SMatthew G Knepley 
201e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
202a312c225SMatthew G Knepley   snes->iter = 0;
203a312c225SMatthew G Knepley   snes->norm = 0.;
204e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
20519653cdaSPeter Brune 
20698b3e84cSPeter Brune   /* initialization */
20719653cdaSPeter Brune 
2083a2ae377SPeter Brune   if (snes->pc && snes->pcside == PC_LEFT) {
209be95d8f1SBarry Smith     ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr);
2103a2ae377SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2113a2ae377SPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
2123a2ae377SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
2133a2ae377SPeter Brune       PetscFunctionReturn(0);
2143a2ae377SPeter Brune     }
2153a2ae377SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
2163a2ae377SPeter Brune   } else {
217e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
218f109b39eSPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
2191aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
220c1c75074SPeter Brune 
221f109b39eSPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
222*422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
2233a2ae377SPeter Brune   }
224e4ed7901SPeter Brune   fminnorm = fnorm;
22519653cdaSPeter Brune 
226e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
227f109b39eSPeter Brune   snes->norm = fnorm;
228e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
229a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
230f109b39eSPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
231f109b39eSPeter Brune   ierr       = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
232a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
233b3c6a99cSPeter Brune   SNESNGMRESUpdateSubspace_Private(snes,0,0,F,fnorm,X);
234a312c225SMatthew G Knepley 
23519653cdaSPeter Brune   k_restart = 1;
23619653cdaSPeter Brune   l         = 1;
237b3c6a99cSPeter Brune   ivec      = 0;
23809c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
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);
24363e7833aSPeter Brune 
24463e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2459f425c49SPeter Brune       ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr);
24663e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
24763e7833aSPeter Brune 
2488cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2498cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2508cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2518cc86e31SPeter Brune         PetscFunctionReturn(0);
2528cc86e31SPeter Brune       }
253be95d8f1SBarry Smith       ierr = SNESGetNPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr);
2548cc86e31SPeter Brune     } else {
255f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
256f109b39eSPeter Brune       ierr = VecCopy(F,Y);CHKERRQ(ierr);
257e7058c64SPeter Brune       ierr = VecCopy(F,FM);CHKERRQ(ierr);
258e7058c64SPeter Brune       ierr = VecCopy(X,XM);CHKERRQ(ierr);
2591aa26658SKarl Rupp 
260e7058c64SPeter Brune       fMnorm = fnorm;
2611aa26658SKarl Rupp 
262f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
263*422a814eSBarry Smith       ierr = SNESLineSearchGetReason(snes->linesearch,&lssucceed);CHKERRQ(ierr);
264*422a814eSBarry Smith       if (lssucceed) {
265f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
266f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
267f109b39eSPeter Brune           PetscFunctionReturn(0);
268f109b39eSPeter Brune         }
269f109b39eSPeter Brune       }
2706634f59bSPeter Brune     }
271b3c6a99cSPeter Brune     ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr);
27298b3e84cSPeter Brune     /* r = F(x) */
2739f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
27419653cdaSPeter Brune 
2759f425c49SPeter Brune     /* differences for selection and restart */
27613a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
277b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
27813a62661SPeter Brune     } else {
279b3c6a99cSPeter Brune       ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,&xMnorm,NULL,&yMnorm,&xAnorm,&fAnorm,&yAnorm);CHKERRQ(ierr);
28013a62661SPeter Brune     }
281*422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
2821aa26658SKarl Rupp 
2839f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
284b3c6a99cSPeter 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);
28519653cdaSPeter Brune     selectRestart = PETSC_FALSE;
28613a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
28721687c63SPeter 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. */
2891aa26658SKarl Rupp       if (selectRestart) restart_count++;
2901aa26658SKarl Rupp       else restart_count = 0;
29113a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
29213a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
29313a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr);
29413a62661SPeter Brune         restart_count = ngmres->restart_it;
29513a62661SPeter Brune       }
29613a62661SPeter Brune     }
297b3c6a99cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
29828ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
29928ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
300dfbf837cSBarry Smith       if (ngmres->monitor) {
301dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr);
302dfbf837cSBarry Smith       }
30328ed4a04SPeter Brune       restart_count = 0;
30419653cdaSPeter Brune       k_restart     = 1;
30519653cdaSPeter Brune       l             = 1;
306b3c6a99cSPeter Brune       ivec          = 0;
30798b3e84cSPeter Brune       /* q_{00} = nu */
308fa8c639aSPeter Brune       ierr = SNESNGMRESUpdateSubspace_Private(snes,0,0,FM,fMnorm,XM);CHKERRQ(ierr);
309d2e16ddcSPeter Brune     } else {
31098b3e84cSPeter Brune       /* select the current size of the subspace */
3111e633543SBarry Smith       if (l < ngmres->msize) l++;
31219653cdaSPeter Brune       k_restart++;
31398b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
31438774f0aSPeter Brune       if (ngmres->candidate) {
31538774f0aSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;
316fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fMnorm,XM);CHKERRQ(ierr);
317d2e16ddcSPeter Brune       } else {
31838774f0aSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;
319fa8c639aSPeter Brune         ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,F,fnorm,X);CHKERRQ(ierr);
32019653cdaSPeter Brune       }
321d2e16ddcSPeter Brune     }
32219653cdaSPeter Brune 
323e04113cfSBarry Smith     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
324087dfb9eSxuemin     snes->iter = k;
325f109b39eSPeter Brune     snes->norm = fnorm;
326e04113cfSBarry Smith     ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
327a71f0d7dSBarry Smith     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
3288409ca45SMatthew G Knepley     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
329b3c6a99cSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0,0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
330087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
331a312c225SMatthew G Knepley   }
332a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
333a312c225SMatthew G Knepley   PetscFunctionReturn(0);
334a312c225SMatthew G Knepley }
335a312c225SMatthew G Knepley 
33613a62661SPeter Brune #undef __FUNCT__
33713a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
33813a62661SPeter Brune /*@
33913a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
34013a62661SPeter Brune 
34113a62661SPeter Brune     Logically Collective on SNES
34213a62661SPeter Brune 
34313a62661SPeter Brune     Input Parameters:
34413a62661SPeter Brune +   snes - the iterative context
34513a62661SPeter Brune -   rtype - restart type
34613a62661SPeter Brune 
34713a62661SPeter Brune     Options Database:
34813a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
3490c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
35013a62661SPeter Brune 
35113a62661SPeter Brune     Level: intermediate
35213a62661SPeter Brune 
35313a62661SPeter Brune     SNESNGMRESRestartTypes:
35413a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
35513a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
35613a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
35713a62661SPeter Brune 
35813a62661SPeter Brune     Notes:
35913a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
36013a62661SPeter Brune 
36113a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
36213a62661SPeter Brune @*/
3630adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes,SNESNGMRESRestartType rtype)
3640adebc6cSBarry Smith {
36513a62661SPeter Brune   PetscErrorCode ierr;
3665fd66863SKarl Rupp 
36713a62661SPeter Brune   PetscFunctionBegin;
36813a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
36913a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
37013a62661SPeter Brune   PetscFunctionReturn(0);
37113a62661SPeter Brune }
37213a62661SPeter Brune 
37313a62661SPeter Brune #undef __FUNCT__
37413a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
37513a62661SPeter Brune /*@
37613a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
37713a62661SPeter Brune     combined solution are used to create the next iterate.
37813a62661SPeter Brune 
37913a62661SPeter Brune     Logically Collective on SNES
38013a62661SPeter Brune 
38113a62661SPeter Brune     Input Parameters:
38213a62661SPeter Brune +   snes - the iterative context
38313a62661SPeter Brune -   stype - selection type
38413a62661SPeter Brune 
38513a62661SPeter Brune     Options Database:
38613a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
38713a62661SPeter Brune 
38813a62661SPeter Brune     Level: intermediate
38913a62661SPeter Brune 
39013a62661SPeter Brune     SNESNGMRESSelectTypes:
39113a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
39213a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
39313a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
39413a62661SPeter Brune 
39513a62661SPeter Brune     Notes:
39613a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
39713a62661SPeter Brune 
39813a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
39913a62661SPeter Brune @*/
4000adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes,SNESNGMRESSelectType stype)
4010adebc6cSBarry Smith {
40213a62661SPeter Brune   PetscErrorCode ierr;
4035fd66863SKarl Rupp 
40413a62661SPeter Brune   PetscFunctionBegin;
40513a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
40613a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
40713a62661SPeter Brune   PetscFunctionReturn(0);
40813a62661SPeter Brune }
40913a62661SPeter Brune 
41013a62661SPeter Brune #undef __FUNCT__
41113a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
4120adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes,SNESNGMRESSelectType stype)
4130adebc6cSBarry Smith {
41413a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4155fd66863SKarl Rupp 
41613a62661SPeter Brune   PetscFunctionBegin;
41713a62661SPeter Brune   ngmres->select_type = stype;
41813a62661SPeter Brune   PetscFunctionReturn(0);
41913a62661SPeter Brune }
42013a62661SPeter Brune 
42113a62661SPeter Brune #undef __FUNCT__
42213a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
4230adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes,SNESNGMRESRestartType rtype)
4240adebc6cSBarry Smith {
42513a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
4265fd66863SKarl Rupp 
42713a62661SPeter Brune   PetscFunctionBegin;
42813a62661SPeter Brune   ngmres->restart_type = rtype;
42913a62661SPeter Brune   PetscFunctionReturn(0);
43013a62661SPeter Brune }
43113a62661SPeter Brune 
432dfbf837cSBarry Smith /*MC
4331867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
434a312c225SMatthew G Knepley 
435dfbf837cSBarry Smith    Level: beginner
436dfbf837cSBarry Smith 
4371867fe5bSPeter Brune    Options Database:
43813a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
43938774f0aSPeter Brune .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
44038774f0aSPeter Brune .  -snes_ngmres_candidate        - Use NGMRES variant which combines candidate solutions instead of actual solutions
44113a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
44213a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
44313a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
44413a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
44513a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
44613a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
44713a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
4485c3e6ab7SPeter Brune .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
44913a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
4501867fe5bSPeter Brune 
4511867fe5bSPeter Brune    Notes:
4521867fe5bSPeter Brune 
4531867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
4541867fe5bSPeter Brune    optimization problem at each iteration.
4551867fe5bSPeter Brune 
4561867fe5bSPeter Brune    References:
4571867fe5bSPeter Brune 
458dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
459dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
460dfbf837cSBarry Smith 
461dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
462dfbf837cSBarry Smith M*/
463a312c225SMatthew G Knepley 
464a312c225SMatthew G Knepley #undef __FUNCT__
465a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
4668cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
467a312c225SMatthew G Knepley {
468a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres;
469a312c225SMatthew G Knepley   PetscErrorCode ierr;
470a312c225SMatthew G Knepley 
471a312c225SMatthew G Knepley   PetscFunctionBegin;
472a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
473a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
474a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
475a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
476a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
477a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
478a312c225SMatthew G Knepley 
47942f4f86dSBarry Smith   snes->usespc   = PETSC_TRUE;
4802c155ee1SBarry Smith   snes->usesksp  = PETSC_FALSE;
48146159c86SPeter Brune   snes->pcside   = PC_RIGHT;
4822c155ee1SBarry Smith 
483b00a9115SJed Brown   ierr          = PetscNewLog(snes,&ngmres);CHKERRQ(ierr);
484a312c225SMatthew G Knepley   snes->data    = (void*) ngmres;
485d2e16ddcSPeter Brune   ngmres->msize = 30;
48619653cdaSPeter Brune 
48788976e71SPeter Brune   if (!snes->tolerancesset) {
4880e444f03SPeter Brune     snes->max_funcs = 30000;
4890e444f03SPeter Brune     snes->max_its   = 10000;
49088976e71SPeter Brune   }
4910e444f03SPeter Brune 
49238774f0aSPeter Brune   ngmres->candidate = PETSC_FALSE;
493d2e16ddcSPeter Brune 
4940298fd71SBarry Smith   ngmres->additive_linesearch = NULL;
495077c4231SPeter Brune   ngmres->approxfunc       = PETSC_FALSE;
49628ed4a04SPeter Brune   ngmres->restart_it       = 2;
49713a62661SPeter Brune   ngmres->restart_periodic = 30;
498f109b39eSPeter Brune   ngmres->gammaA           = 2.0;
499f109b39eSPeter Brune   ngmres->gammaC           = 2.0;
500cac108bcSPeter Brune   ngmres->deltaB           = 0.9;
501cac108bcSPeter Brune   ngmres->epsilonB         = 0.1;
502e7058c64SPeter Brune 
50313a62661SPeter Brune   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
50413a62661SPeter Brune   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;
50513a62661SPeter Brune 
506bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetSelectType_C",SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
507bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNGMRESSetRestartType_C",SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
508a312c225SMatthew G Knepley   PetscFunctionReturn(0);
509a312c225SMatthew G Knepley }
51099e0435eSBarry Smith 
511