xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 63e7833ae58c359c2a0b3235ce285a042bc82d50)
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);
189e764e56SPeter Brune 
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;
50a312c225SMatthew G Knepley 
51a312c225SMatthew G Knepley   PetscFunctionBegin;
5278440776SJed Brown   ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr);
5378440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5478440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
5578440776SJed Brown   if (!ngmres->setup_called) {
56087dfb9eSxuemin     msize         = ngmres->msize;  /* restart size */
5719653cdaSPeter Brune     hsize         = msize * msize;
58087dfb9eSxuemin 
5998b3e84cSPeter Brune     /* explicit least squares minimization solve */
6019653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6119653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
6219653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
63f109b39eSPeter Brune                         msize,PetscReal,  &ngmres->fnorms,
6419653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6518aa0c0cSPeter Brune     if (ngmres->singlereduction) {
6618aa0c0cSPeter Brune       ierr = PetscMalloc(msize*sizeof(PetscReal),&ngmres->xnorms);CHKERRQ(ierr);
6718aa0c0cSPeter Brune     }
6819653cdaSPeter Brune     ngmres->nrhs = 1;
6919653cdaSPeter Brune     ngmres->lda = msize;
7019653cdaSPeter Brune     ngmres->ldb = msize;
7119653cdaSPeter Brune     ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
7219653cdaSPeter Brune     ierr = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7319653cdaSPeter Brune     ierr = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7419653cdaSPeter Brune     ierr = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
7519653cdaSPeter Brune     ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7619653cdaSPeter Brune     ngmres->lwork = 12*msize;
7719653cdaSPeter Brune #if PETSC_USE_COMPLEX
7822d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);CHKERRQ(ierr);
7919653cdaSPeter Brune #endif
8022d28d08SBarry Smith     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);CHKERRQ(ierr);
8178440776SJed Brown   }
82e7058c64SPeter Brune 
83e7058c64SPeter Brune   /* linesearch setup */
84e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
85e7058c64SPeter Brune 
8613a62661SPeter Brune   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
87f1c6b773SPeter Brune     ierr = SNESLineSearchCreate(((PetscObject)snes)->comm, &ngmres->additive_linesearch);CHKERRQ(ierr);
88f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch, snes);CHKERRQ(ierr);
891a4f838cSPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
90f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_");CHKERRQ(ierr);
91f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix);CHKERRQ(ierr);
92f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
93e7058c64SPeter Brune   }
94e7058c64SPeter Brune 
9578440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
96a312c225SMatthew G Knepley   PetscFunctionReturn(0);
97a312c225SMatthew G Knepley }
98a312c225SMatthew G Knepley 
99a312c225SMatthew G Knepley #undef __FUNCT__
100a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
101a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
102a312c225SMatthew G Knepley {
103a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
104a312c225SMatthew G Knepley   PetscErrorCode ierr;
105dfbf837cSBarry Smith   PetscBool      debug;
106f1c6b773SPeter Brune   SNESLineSearch linesearch;
1070adebc6cSBarry Smith 
108a312c225SMatthew G Knepley   PetscFunctionBegin;
109a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
11013a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_select_type","Select type","SNESNGMRESSetSelectType",SNESNGMRESSelectTypes,
11113a62661SPeter Brune                           (PetscEnum)ngmres->select_type,(PetscEnum*)&ngmres->select_type,PETSC_NULL);CHKERRQ(ierr);
11213a62661SPeter Brune   ierr = PetscOptionsEnum("-snes_ngmres_restart_type","Restart type","SNESNGMRESSetRestartType",SNESNGMRESRestartTypes,
11313a62661SPeter Brune                           (PetscEnum)ngmres->restart_type,(PetscEnum*)&ngmres->restart_type,PETSC_NULL);CHKERRQ(ierr);
114d2e16ddcSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_anderson", "Use Anderson mixing storage",        "SNES", ngmres->anderson,  &ngmres->anderson, PETSC_NULL);CHKERRQ(ierr);
11519653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m",         "Number of directions",               "SNES", ngmres->msize,  &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
1160c777b0cSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart",   "Iterations before forced restart",   "SNES", ngmres->restart_periodic,  &ngmres->restart_periodic, PETSC_NULL);CHKERRQ(ierr);
11728ed4a04SPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES", ngmres->restart_it,  &ngmres->restart_it, PETSC_NULL);CHKERRQ(ierr);
118dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",  "Monitor actions of NGMRES",          "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr);
119dfbf837cSBarry Smith   if (debug) {
120dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
121dfbf837cSBarry Smith   }
1226a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA",   "Residual selection constant",   "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
1236a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "  Residual restart constant",     "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
1246a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
1256a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB",   "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
1264d116c7dSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions",  "SNES", ngmres->singlereduction, &ngmres->singlereduction, PETSC_NULL);CHKERRQ(ierr);
127a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1286a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1299e764e56SPeter Brune 
1309e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1319e764e56SPeter Brune   if (!snes->linesearch) {
132f1c6b773SPeter Brune     ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
1331a4f838cSPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr);
1349e764e56SPeter Brune   }
135a312c225SMatthew G Knepley   PetscFunctionReturn(0);
136a312c225SMatthew G Knepley }
137a312c225SMatthew G Knepley 
138a312c225SMatthew G Knepley #undef __FUNCT__
139a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
140a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
141a312c225SMatthew G Knepley {
142a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
143a312c225SMatthew G Knepley   PetscBool      iascii;
144a312c225SMatthew G Knepley   PetscErrorCode ierr;
145a312c225SMatthew G Knepley 
146a312c225SMatthew G Knepley   PetscFunctionBegin;
147251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
148a312c225SMatthew G Knepley   if (iascii) {
149f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
150f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr);
151f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr);
152a312c225SMatthew G Knepley   }
153a312c225SMatthew G Knepley   PetscFunctionReturn(0);
154a312c225SMatthew G Knepley }
155a312c225SMatthew G Knepley 
156a312c225SMatthew G Knepley #undef __FUNCT__
157a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
158a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
159a312c225SMatthew G Knepley {
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   /* previous iterations to construct the subspace */
168f109b39eSPeter Brune   Vec                 *Fdot = ngmres->Fdot;
169f109b39eSPeter Brune   Vec                 *Xdot = ngmres->Xdot;
17019653cdaSPeter Brune 
17198b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
17219653cdaSPeter Brune   PetscScalar         *beta = ngmres->beta;
17319653cdaSPeter Brune   PetscScalar         *xi   = ngmres->xi;
17418aa0c0cSPeter Brune   PetscReal           fnorm, fMnorm, fAnorm;
17519653cdaSPeter Brune   PetscReal           nu;
17619653cdaSPeter Brune   PetscScalar         alph_total = 0.;
17728ed4a04SPeter Brune   PetscInt            i, j, k, k_restart, l, ivec, restart_count = 0;
17819653cdaSPeter Brune 
17998b3e84cSPeter Brune   /* solution selection data */
18019653cdaSPeter Brune   PetscBool           selectA, selectRestart;
18174b542b2SMatthew G Knepley   PetscReal           dnorm, dminnorm = 0.0, dcurnorm;
182d484d688SPeter Brune   PetscReal           fminnorm,xnorm,ynorm;
18319653cdaSPeter Brune 
1841e633543SBarry Smith   SNESConvergedReason reason;
1856e733865SPeter Brune   PetscBool           lssucceed,changed_y,changed_w;
186a312c225SMatthew G Knepley   PetscErrorCode      ierr;
187a312c225SMatthew G Knepley 
188a312c225SMatthew G Knepley   PetscFunctionBegin;
18998b3e84cSPeter Brune   /* variable initialization */
190a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
191f109b39eSPeter Brune   X             = snes->vec_sol;
192f109b39eSPeter Brune   F             = snes->vec_func;
193f109b39eSPeter Brune   B             = snes->vec_rhs;
194f109b39eSPeter Brune   XA            = snes->vec_sol_update;
195f109b39eSPeter Brune   FA            = snes->work[0];
196f109b39eSPeter Brune   D             = snes->work[1];
197f109b39eSPeter Brune 
198f109b39eSPeter Brune   /* work for the line search */
199f109b39eSPeter Brune   Y             = snes->work[2];
2009f425c49SPeter Brune   XM            = snes->work[3];
2019f425c49SPeter Brune   FM            = snes->work[4];
202a312c225SMatthew G Knepley 
203a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
204a312c225SMatthew G Knepley   snes->iter = 0;
205a312c225SMatthew G Knepley   snes->norm = 0.;
206a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
20719653cdaSPeter Brune 
20898b3e84cSPeter Brune   /* initialization */
20919653cdaSPeter Brune 
21098b3e84cSPeter Brune   /* r = F(x) */
211e4ed7901SPeter Brune   if (!snes->vec_func_init_set) {
212f109b39eSPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
213a312c225SMatthew G Knepley     if (snes->domainerror) {
214a312c225SMatthew G Knepley       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
215a312c225SMatthew G Knepley       PetscFunctionReturn(0);
216a312c225SMatthew G Knepley     }
217e4ed7901SPeter Brune   } else {
218e4ed7901SPeter Brune     snes->vec_func_init_set = PETSC_FALSE;
219e4ed7901SPeter Brune   }
22019653cdaSPeter Brune 
221e4ed7901SPeter Brune   if (!snes->norm_init_set) {
222f109b39eSPeter Brune     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
223b707f0f7SPeter Brune     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
224e4ed7901SPeter Brune   } else {
225e4ed7901SPeter Brune     fnorm = snes->norm_init;
226e4ed7901SPeter Brune     snes->norm_init_set = PETSC_FALSE;
227e4ed7901SPeter Brune   }
228e4ed7901SPeter Brune   fminnorm = fnorm;
229e4ed7901SPeter Brune   /* nu = (r, r) */
230e4ed7901SPeter Brune   nu = fnorm*fnorm;
23119653cdaSPeter Brune 
23298b3e84cSPeter Brune   /* q_{00} = nu  */
23319653cdaSPeter Brune   Q(0,0) = nu;
234f109b39eSPeter Brune   ngmres->fnorms[0] = fnorm;
235f109b39eSPeter Brune   /* Fdot[0] = F */
236f109b39eSPeter Brune   ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
237f109b39eSPeter Brune   ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
238087dfb9eSxuemin 
239a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
240f109b39eSPeter Brune   snes->norm = fnorm;
241a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
242f109b39eSPeter Brune   SNESLogConvHistory(snes, fnorm, 0);
243f109b39eSPeter Brune   ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr);
244f109b39eSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
245a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
246a312c225SMatthew G Knepley 
24719653cdaSPeter Brune   k_restart = 1;
24819653cdaSPeter Brune   l = 1;
24909c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
25098b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
25198b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
25219653cdaSPeter Brune 
25398b3e84cSPeter Brune     /* Computation of x^M */
254c40d0f55SPeter Brune     if (snes->pc && snes->pcside == PC_RIGHT) {
2559f425c49SPeter Brune       ierr = VecCopy(X, XM);CHKERRQ(ierr);
256e4ed7901SPeter Brune       ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr);
257e4ed7901SPeter Brune       ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr);
258*63e7833aSPeter Brune 
259*63e7833aSPeter Brune       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
2609f425c49SPeter Brune       ierr = SNESSolve(snes->pc, B, XM);CHKERRQ(ierr);
261*63e7833aSPeter Brune       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr);
262*63e7833aSPeter Brune 
2638cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2648cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2658cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2668cc86e31SPeter Brune         PetscFunctionReturn(0);
2678cc86e31SPeter Brune       }
2684b32a720SPeter Brune       ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
2694b32a720SPeter Brune       ierr = VecCopy(FPC, FM);CHKERRQ(ierr);
2704b32a720SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc, &fMnorm);CHKERRQ(ierr);
2718cc86e31SPeter Brune     } else {
272f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
273f109b39eSPeter Brune       ierr = VecCopy(F, Y);CHKERRQ(ierr);
274e7058c64SPeter Brune       ierr = VecCopy(F, FM);CHKERRQ(ierr);
275e7058c64SPeter Brune       ierr = VecCopy(X, XM);CHKERRQ(ierr);
276e7058c64SPeter Brune       fMnorm = fnorm;
277f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
278f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
279f109b39eSPeter Brune       if (!lssucceed) {
280f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
281f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
282f109b39eSPeter Brune           PetscFunctionReturn(0);
283f109b39eSPeter Brune         }
284f109b39eSPeter Brune       }
2856634f59bSPeter Brune     }
2861e633543SBarry Smith 
28798b3e84cSPeter Brune     /* r = F(x) */
2889f425c49SPeter Brune     nu = fMnorm*fMnorm;
2899f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
29019653cdaSPeter Brune 
29198b3e84cSPeter Brune     /* construct the right hand side and xi factors */
2928c09b6b7SPeter Brune     ierr = VecMDot(FM, l, Fdot, xi);CHKERRQ(ierr);
2938c09b6b7SPeter Brune 
29419653cdaSPeter Brune     for (i = 0; i < l; i++) {
29519653cdaSPeter Brune       beta[i] = nu - xi[i];
29619653cdaSPeter Brune     }
29719653cdaSPeter Brune 
29898b3e84cSPeter Brune     /* construct h */
29919653cdaSPeter Brune     for (j = 0; j < l; j++) {
30019653cdaSPeter Brune       for (i = 0; i < l; i++) {
30119653cdaSPeter Brune         H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
30219653cdaSPeter Brune       }
30319653cdaSPeter Brune     }
304f109b39eSPeter Brune 
305f109b39eSPeter Brune     if (l == 1) {
306f109b39eSPeter Brune       /* simply set alpha[0] = beta[0] / H[0, 0] */
307bf08dd53SPeter Brune       if (H(0, 0) != 0.) {
308f109b39eSPeter Brune         beta[0] = beta[0] / H(0, 0);
309f109b39eSPeter Brune       } else {
310bf08dd53SPeter Brune         beta[0] = 0.;
311bf08dd53SPeter Brune       }
312bf08dd53SPeter Brune     } else {
313519f805aSKarl Rupp #if defined(PETSC_MISSING_LAPACK_GELSS)
314b707f0f7SPeter Brune       SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
3154a0c5b0cSMatthew G Knepley #else
31619653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
31719653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
31819653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
31919653cdaSPeter Brune     ngmres->rcond = -1.;
3208e57ea43SSatish Balay     ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
321519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX)
32219653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
32319653cdaSPeter Brune                  &ngmres->n,
32419653cdaSPeter Brune                  &ngmres->nrhs,
32519653cdaSPeter Brune                  ngmres->h,
32619653cdaSPeter Brune                  &ngmres->lda,
32719653cdaSPeter Brune                  ngmres->beta,
32819653cdaSPeter Brune                  &ngmres->ldb,
32919653cdaSPeter Brune                  ngmres->s,
33019653cdaSPeter Brune                  &ngmres->rcond,
33119653cdaSPeter Brune                  &ngmres->rank,
33219653cdaSPeter Brune                  ngmres->work,
33319653cdaSPeter Brune                  &ngmres->lwork,
33419653cdaSPeter Brune                  ngmres->rwork,
33519653cdaSPeter Brune                  &ngmres->info);
33619653cdaSPeter Brune #else
33719653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
33819653cdaSPeter Brune                  &ngmres->n,
33919653cdaSPeter Brune                  &ngmres->nrhs,
34019653cdaSPeter Brune                  ngmres->h,
34119653cdaSPeter Brune                  &ngmres->lda,
34219653cdaSPeter Brune                  ngmres->beta,
34319653cdaSPeter Brune                  &ngmres->ldb,
34419653cdaSPeter Brune                  ngmres->s,
34519653cdaSPeter Brune                  &ngmres->rcond,
34619653cdaSPeter Brune                  &ngmres->rank,
34719653cdaSPeter Brune                  ngmres->work,
34819653cdaSPeter Brune                  &ngmres->lwork,
34919653cdaSPeter Brune                  &ngmres->info);
35019653cdaSPeter Brune #endif
3518e57ea43SSatish Balay     ierr = PetscFPTrapPop();CHKERRQ(ierr);
352b707f0f7SPeter Brune     if (ngmres->info < 0) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_LIB,"Bad argument to GELSS");
353b707f0f7SPeter Brune     if (ngmres->info > 0) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_LIB,"SVD failed to converge");
354a312c225SMatthew G Knepley #endif
355f109b39eSPeter Brune     }
356a312c225SMatthew G Knepley 
357b707f0f7SPeter Brune     for (i=0;i<l;i++) {
358b707f0f7SPeter Brune       if (PetscIsInfOrNanScalar(beta[i])) {
359b707f0f7SPeter Brune         SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_LIB,"SVD generated inconsistent output");
360b707f0f7SPeter Brune       }
361b707f0f7SPeter Brune     }
362b707f0f7SPeter Brune 
36319653cdaSPeter Brune     alph_total = 0.;
36419653cdaSPeter Brune     for (i = 0; i < l; i++) {
36519653cdaSPeter Brune       alph_total += beta[i];
366c0bbabecSxuemin     }
367f109b39eSPeter Brune 
3689f425c49SPeter Brune     ierr = VecCopy(XM, XA);CHKERRQ(ierr);
369f109b39eSPeter Brune     ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr);
370087dfb9eSxuemin 
3718c09b6b7SPeter Brune     ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr);
3726e733865SPeter Brune 
3736e733865SPeter Brune     /* check the validity of the step */
374f89ba88eSPeter Brune     ierr = VecCopy(XA,Y);CHKERRQ(ierr);
3756e733865SPeter Brune     ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr);
3766e733865SPeter Brune     ierr = SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);CHKERRQ(ierr);
377f109b39eSPeter Brune     ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr);
37819653cdaSPeter Brune 
3799f425c49SPeter Brune     /* differences for selection and restart */
38013a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
38118aa0c0cSPeter Brune       if (ngmres->singlereduction) {
38218aa0c0cSPeter Brune         dminnorm = -1.0;
383f109b39eSPeter Brune         ierr=VecCopy(XA, D);CHKERRQ(ierr);
38418aa0c0cSPeter Brune         ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr);
38518aa0c0cSPeter Brune         for (i=0;i<l;i++) {
38618aa0c0cSPeter Brune           ierr=VecAXPY(Xdot[i],-1.0,XA);CHKERRQ(ierr);
38718aa0c0cSPeter Brune         }
38818aa0c0cSPeter Brune         ierr = VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
38918aa0c0cSPeter Brune         ierr = VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr);
39018aa0c0cSPeter Brune         for (i=0;i<l;i++) {
39118aa0c0cSPeter Brune           ierr = VecNormBegin(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr);
39218aa0c0cSPeter Brune         }
39318aa0c0cSPeter Brune         ierr = VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
39418aa0c0cSPeter Brune         ierr = VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr);
39518aa0c0cSPeter Brune         for (i=0;i<l;i++) {
39618aa0c0cSPeter Brune           ierr = VecNormEnd(Xdot[i], NORM_2, &ngmres->xnorms[i]);CHKERRQ(ierr);
39718aa0c0cSPeter Brune         }
39818aa0c0cSPeter Brune         for (i=0;i<l;i++) {
39918aa0c0cSPeter Brune           dcurnorm = ngmres->xnorms[i];
40018aa0c0cSPeter Brune           if ((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm;
40118aa0c0cSPeter Brune           ierr=VecAXPY(Xdot[i],1.0,XA);CHKERRQ(ierr);
40218aa0c0cSPeter Brune         }
40318aa0c0cSPeter Brune       } else {
40418aa0c0cSPeter Brune         ierr=VecCopy(XA, D);CHKERRQ(ierr);
40518aa0c0cSPeter Brune         ierr=VecAXPY(D, -1.0, XM);CHKERRQ(ierr);
40618aa0c0cSPeter Brune         ierr=VecNormBegin(D, NORM_2, &dnorm);CHKERRQ(ierr);
40718aa0c0cSPeter Brune         ierr=VecNormBegin(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
40818aa0c0cSPeter Brune         ierr=VecNormEnd(D, NORM_2, &dnorm);CHKERRQ(ierr);
40918aa0c0cSPeter Brune         ierr=VecNormEnd(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
410f109b39eSPeter Brune         dminnorm = -1.0;
41119653cdaSPeter Brune         for (i=0;i<l;i++) {
412f109b39eSPeter Brune           ierr=VecCopy(XA, D);CHKERRQ(ierr);
413f109b39eSPeter Brune           ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr);
414f109b39eSPeter Brune           ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr);
415f109b39eSPeter Brune           if ((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm;
41619653cdaSPeter Brune         }
41718aa0c0cSPeter Brune       }
41813a62661SPeter Brune     } else {
41913a62661SPeter Brune       ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
42013a62661SPeter Brune     }
421b707f0f7SPeter Brune     if (PetscIsInfOrNanReal(fAnorm)) SETERRQ(((PetscObject)snes)->comm, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
4229f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
42313a62661SPeter Brune     if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
4249f425c49SPeter Brune       /* X = X + \lambda(XA - X) */
4259f425c49SPeter Brune       if (ngmres->monitor) {
4269f425c49SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
4279f425c49SPeter Brune       }
42813a62661SPeter Brune       ierr = VecCopy(FM, F);CHKERRQ(ierr);
42913a62661SPeter Brune       ierr = VecCopy(XM, X);CHKERRQ(ierr);
4309f425c49SPeter Brune       ierr = VecCopy(XA, Y);CHKERRQ(ierr);
431eb1825c3SPeter Brune       ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr);
432d484d688SPeter Brune       fnorm = fMnorm;
433f1c6b773SPeter Brune       ierr = SNESLineSearchApply(ngmres->additive_linesearch,X,F,&fnorm,Y);CHKERRQ(ierr);
434f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(ngmres->additive_linesearch, &lssucceed);CHKERRQ(ierr);
4359f425c49SPeter Brune       if (!lssucceed) {
4369f425c49SPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
4379f425c49SPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
4389f425c49SPeter Brune           PetscFunctionReturn(0);
4399f425c49SPeter Brune         }
4409f425c49SPeter Brune       }
4419f425c49SPeter Brune       if (ngmres->monitor) {
4429f425c49SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", fnorm);CHKERRQ(ierr);
4439f425c49SPeter Brune       }
44413a62661SPeter Brune     } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
4459f425c49SPeter Brune       selectA = PETSC_TRUE;
4469f425c49SPeter Brune       /* Conditions for choosing the accelerated answer */
4479f425c49SPeter Brune       /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
4489f425c49SPeter Brune       if (fAnorm >= ngmres->gammaA*fminnorm) {
4499f425c49SPeter Brune         selectA = PETSC_FALSE;
4509f425c49SPeter Brune       }
4519f425c49SPeter Brune       /* Criterion B -- the choice of x^A isn't too close to some other choice */
452cf22de31SPeter Brune       if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) {
45319653cdaSPeter Brune       } else {
45419653cdaSPeter Brune         selectA=PETSC_FALSE;
45519653cdaSPeter Brune       }
45619653cdaSPeter Brune       if (selectA) {
457dfbf837cSBarry Smith         if (ngmres->monitor) {
4589e764e56SPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
459dfbf837cSBarry Smith         }
46098b3e84cSPeter Brune         /* copy it over */
461f109b39eSPeter Brune         fnorm = fAnorm;
462f109b39eSPeter Brune         nu = fnorm*fnorm;
463f109b39eSPeter Brune         ierr = VecCopy(FA, F);CHKERRQ(ierr);
464f109b39eSPeter Brune         ierr = VecCopy(XA, X);CHKERRQ(ierr);
46519653cdaSPeter Brune       } else {
466dfbf837cSBarry Smith         if (ngmres->monitor) {
4675b0d26cfSPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
468dfbf837cSBarry Smith         }
4699f425c49SPeter Brune         fnorm = fMnorm;
4709f425c49SPeter Brune         nu = fnorm*fnorm;
471d484d688SPeter Brune         ierr = VecCopy(XM, Y);CHKERRQ(ierr);
472d484d688SPeter Brune         ierr = VecAXPY(Y,-1.0,X);CHKERRQ(ierr);
4739f425c49SPeter Brune         ierr = VecCopy(FM, F);CHKERRQ(ierr);
4749f425c49SPeter Brune         ierr = VecCopy(XM, X);CHKERRQ(ierr);
4759f425c49SPeter Brune       }
47613a62661SPeter Brune     } else { /* none */
47713a62661SPeter Brune       fnorm = fAnorm;
47813a62661SPeter Brune       nu = fnorm*fnorm;
47913a62661SPeter Brune       ierr = VecCopy(FA, F);CHKERRQ(ierr);
48013a62661SPeter Brune       ierr = VecCopy(XA, X);CHKERRQ(ierr);
48119653cdaSPeter Brune     }
482211b2d39SPeter Brune 
48319653cdaSPeter Brune     selectRestart = PETSC_FALSE;
48413a62661SPeter Brune     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
48598b3e84cSPeter Brune       /* difference stagnation restart */
486cf22de31SPeter Brune       if ((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm))) {
487dfbf837cSBarry Smith         if (ngmres->monitor) {
488f109b39eSPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr);
489dfbf837cSBarry Smith         }
49019653cdaSPeter Brune         selectRestart = PETSC_TRUE;
49119653cdaSPeter Brune       }
49298b3e84cSPeter Brune       /* residual stagnation restart */
493cf22de31SPeter Brune       if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
494dfbf837cSBarry Smith         if (ngmres->monitor) {
495cf22de31SPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", PetscSqrtReal(fAnorm), ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr);
496dfbf837cSBarry Smith         }
49719653cdaSPeter Brune         selectRestart = PETSC_TRUE;
49819653cdaSPeter Brune       }
49928ed4a04SPeter Brune       /* if the restart conditions persist for more than restart_it iterations, restart. */
50019653cdaSPeter Brune       if (selectRestart) {
50128ed4a04SPeter Brune         restart_count++;
50228ed4a04SPeter Brune       } else {
50328ed4a04SPeter Brune         restart_count = 0;
50428ed4a04SPeter Brune       }
50513a62661SPeter Brune     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
50613a62661SPeter Brune       if (k_restart > ngmres->restart_periodic) {
50713a62661SPeter Brune         if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %D iterations\n", k_restart);CHKERRQ(ierr);
50813a62661SPeter Brune         restart_count = ngmres->restart_it;
50913a62661SPeter Brune       }
51013a62661SPeter Brune     }
51128ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
51228ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
513dfbf837cSBarry Smith       if (ngmres->monitor) {
514dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr);
515dfbf837cSBarry Smith       }
51628ed4a04SPeter Brune       restart_count = 0;
51719653cdaSPeter Brune       k_restart = 1;
51819653cdaSPeter Brune       l = 1;
51998b3e84cSPeter Brune       /* q_{00} = nu */
520d2e16ddcSPeter Brune       if (ngmres->anderson) {
521d2e16ddcSPeter Brune         ngmres->fnorms[0] = fMnorm;
522d2e16ddcSPeter Brune         nu = fMnorm*fMnorm;
523d2e16ddcSPeter Brune         Q(0,0) = nu;
524d2e16ddcSPeter Brune         /* Fdot[0] = F */
525d2e16ddcSPeter Brune         ierr = VecCopy(XM, Xdot[0]);CHKERRQ(ierr);
526d2e16ddcSPeter Brune         ierr = VecCopy(FM, Fdot[0]);CHKERRQ(ierr);
527d2e16ddcSPeter Brune       } else {
528f109b39eSPeter Brune         ngmres->fnorms[0] = fnorm;
529f109b39eSPeter Brune         nu = fnorm*fnorm;
53019653cdaSPeter Brune         Q(0,0) = nu;
531f109b39eSPeter Brune         /* Fdot[0] = F */
532f109b39eSPeter Brune         ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
533f109b39eSPeter Brune         ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
534d2e16ddcSPeter Brune       }
53519653cdaSPeter Brune     } else {
53698b3e84cSPeter Brune       /* select the current size of the subspace */
5371e633543SBarry Smith       if (l < ngmres->msize) l++;
53819653cdaSPeter Brune       k_restart++;
53998b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
540d2e16ddcSPeter Brune       if (ngmres->anderson) {
541d2e16ddcSPeter Brune         ierr = VecCopy(FM, Fdot[ivec]);CHKERRQ(ierr);
542d2e16ddcSPeter Brune         ierr = VecCopy(XM, Xdot[ivec]);CHKERRQ(ierr);
543d2e16ddcSPeter Brune         ngmres->fnorms[ivec] = fMnorm;
544d2e16ddcSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of FM */
54518aa0c0cSPeter Brune         xi[ivec] = fMnorm*fMnorm;
546d2e16ddcSPeter Brune         for (i = 0; i < l; i++) {
54718aa0c0cSPeter Brune           Q(i, ivec) = xi[i];
54818aa0c0cSPeter Brune           Q(ivec, i) = xi[i];
549d2e16ddcSPeter Brune         }
550d2e16ddcSPeter Brune       } else {
551f109b39eSPeter Brune         ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr);
552f109b39eSPeter Brune         ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr);
553f109b39eSPeter Brune         ngmres->fnorms[ivec] = fnorm;
554d2e16ddcSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;  /* the minimum norm is now of FA */
55518aa0c0cSPeter Brune         ierr = VecMDot(F, l, Fdot, xi);CHKERRQ(ierr);
55619653cdaSPeter Brune         for (i = 0; i < l; i++) {
55718aa0c0cSPeter Brune           Q(i, ivec) = xi[i];
55818aa0c0cSPeter Brune           Q(ivec, i) = xi[i];
55919653cdaSPeter Brune         }
56019653cdaSPeter Brune       }
561d2e16ddcSPeter Brune     }
56219653cdaSPeter Brune 
5638409ca45SMatthew G Knepley     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
564087dfb9eSxuemin     snes->iter = k;
565f109b39eSPeter Brune     snes->norm = fnorm;
5668409ca45SMatthew G Knepley     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
5678409ca45SMatthew G Knepley     SNESLogConvHistory(snes, snes->norm, snes->iter);
5688409ca45SMatthew G Knepley     ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr);
569d484d688SPeter Brune     ierr = VecNormBegin(Y,NORM_2,&ynorm);CHKERRQ(ierr);
570d484d688SPeter Brune     ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);
571d484d688SPeter Brune     ierr = VecNormEnd(Y,NORM_2,&ynorm);CHKERRQ(ierr);
572d484d688SPeter Brune     ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
573d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
574087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
575a312c225SMatthew G Knepley   }
576a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
577a312c225SMatthew G Knepley   PetscFunctionReturn(0);
578a312c225SMatthew G Knepley }
579a312c225SMatthew G Knepley 
58013a62661SPeter Brune #undef __FUNCT__
58113a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType"
58213a62661SPeter Brune /*@
58313a62661SPeter Brune     SNESNGMRESSetRestartType - Sets the restart type for SNESNGMRES.
58413a62661SPeter Brune 
58513a62661SPeter Brune     Logically Collective on SNES
58613a62661SPeter Brune 
58713a62661SPeter Brune     Input Parameters:
58813a62661SPeter Brune +   snes - the iterative context
58913a62661SPeter Brune -   rtype - restart type
59013a62661SPeter Brune 
59113a62661SPeter Brune     Options Database:
59213a62661SPeter Brune +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
5930c777b0cSPeter Brune -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic
59413a62661SPeter Brune 
59513a62661SPeter Brune     Level: intermediate
59613a62661SPeter Brune 
59713a62661SPeter Brune     SNESNGMRESRestartTypes:
59813a62661SPeter Brune +   SNES_NGMRES_RESTART_NONE - never restart
59913a62661SPeter Brune .   SNES_NGMRES_RESTART_DIFFERENCE - restart based upon difference criteria
60013a62661SPeter Brune -   SNES_NGMRES_RESTART_PERIODIC - restart after a fixed number of iterations
60113a62661SPeter Brune 
60213a62661SPeter Brune     Notes:
60313a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
60413a62661SPeter Brune 
60513a62661SPeter Brune .keywords: SNES, SNESNGMRES, restart, type, set SNESLineSearch
60613a62661SPeter Brune @*/
6070adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype)
6080adebc6cSBarry Smith {
60913a62661SPeter Brune   PetscErrorCode ierr;
61013a62661SPeter Brune   PetscFunctionBegin;
61113a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
61213a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetRestartType_C",(SNES,SNESNGMRESRestartType),(snes,rtype));CHKERRQ(ierr);
61313a62661SPeter Brune   PetscFunctionReturn(0);
61413a62661SPeter Brune }
61513a62661SPeter Brune 
61613a62661SPeter Brune #undef __FUNCT__
61713a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType"
61813a62661SPeter Brune /*@
61913a62661SPeter Brune     SNESNGMRESSetSelectType - Sets the selection type for SNESNGMRES.  This determines how the candidate solution and
62013a62661SPeter Brune     combined solution are used to create the next iterate.
62113a62661SPeter Brune 
62213a62661SPeter Brune     Logically Collective on SNES
62313a62661SPeter Brune 
62413a62661SPeter Brune     Input Parameters:
62513a62661SPeter Brune +   snes - the iterative context
62613a62661SPeter Brune -   stype - selection type
62713a62661SPeter Brune 
62813a62661SPeter Brune     Options Database:
62913a62661SPeter Brune .   -snes_ngmres_select_type<difference,none,linesearch>
63013a62661SPeter Brune 
63113a62661SPeter Brune     Level: intermediate
63213a62661SPeter Brune 
63313a62661SPeter Brune     SNESNGMRESSelectTypes:
63413a62661SPeter Brune +   SNES_NGMRES_SELECT_NONE - choose the combined solution all the time
63513a62661SPeter Brune .   SNES_NGMRES_SELECT_DIFFERENCE - choose based upon the selection criteria
63613a62661SPeter Brune -   SNES_NGMRES_SELECT_LINESEARCH - choose based upon line search combination
63713a62661SPeter Brune 
63813a62661SPeter Brune     Notes:
63913a62661SPeter Brune     The default line search used is the L2 line search and it requires two additional function evaluations.
64013a62661SPeter Brune 
64113a62661SPeter Brune .keywords: SNES, SNESNGMRES, selection, type, set SNESLineSearch
64213a62661SPeter Brune @*/
6430adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype)
6440adebc6cSBarry Smith {
64513a62661SPeter Brune   PetscErrorCode ierr;
64613a62661SPeter Brune   PetscFunctionBegin;
64713a62661SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
64813a62661SPeter Brune   ierr = PetscTryMethod(snes,"SNESNGMRESSetSelectType_C",(SNES,SNESNGMRESSelectType),(snes,stype));CHKERRQ(ierr);
64913a62661SPeter Brune   PetscFunctionReturn(0);
65013a62661SPeter Brune }
65113a62661SPeter Brune 
65213a62661SPeter Brune EXTERN_C_BEGIN
65313a62661SPeter Brune #undef __FUNCT__
65413a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetSelectType_NGMRES"
6550adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype)
6560adebc6cSBarry Smith {
65713a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
65813a62661SPeter Brune   PetscFunctionBegin;
65913a62661SPeter Brune   ngmres->select_type = stype;
66013a62661SPeter Brune   PetscFunctionReturn(0);
66113a62661SPeter Brune }
66213a62661SPeter Brune 
66313a62661SPeter Brune #undef __FUNCT__
66413a62661SPeter Brune #define __FUNCT__ "SNESNGMRESSetRestartType_NGMRES"
6650adebc6cSBarry Smith PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype)
6660adebc6cSBarry Smith {
66713a62661SPeter Brune   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
66813a62661SPeter Brune   PetscFunctionBegin;
66913a62661SPeter Brune   ngmres->restart_type = rtype;
67013a62661SPeter Brune   PetscFunctionReturn(0);
67113a62661SPeter Brune }
67213a62661SPeter Brune EXTERN_C_END
67313a62661SPeter Brune 
674dfbf837cSBarry Smith /*MC
6751867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
676a312c225SMatthew G Knepley 
677dfbf837cSBarry Smith    Level: beginner
678dfbf837cSBarry Smith 
6791867fe5bSPeter Brune    Options Database:
68013a62661SPeter Brune +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
68113a62661SPeter Brune +  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
68213a62661SPeter Brune .  -snes_ngmres_anderson         - Use Anderson mixing NGMRES variant which combines candidate solutions instead of actual solutions
68313a62661SPeter Brune .  -snes_ngmres_m                - Number of stored previous solutions and residuals
68413a62661SPeter Brune .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
68513a62661SPeter Brune .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
68613a62661SPeter Brune .  -snes_ngmres_gammaC           - Residual tolerance for restart
68713a62661SPeter Brune .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
68813a62661SPeter Brune .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
68913a62661SPeter Brune .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
69013a62661SPeter Brune .  -snes_linesearch_type <basic,basicnonorms,quadratic,critical> - Line search type used for the default smoother
69113a62661SPeter Brune -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type
6921867fe5bSPeter Brune 
6931867fe5bSPeter Brune    Notes:
6941867fe5bSPeter Brune 
6951867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
6961867fe5bSPeter Brune    optimization problem at each iteration.
6971867fe5bSPeter Brune 
6981867fe5bSPeter Brune    References:
6991867fe5bSPeter Brune 
700dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
701dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
702dfbf837cSBarry Smith 
703dfbf837cSBarry Smith    This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations.
704dfbf837cSBarry Smith    J. Assoc. Comput. Mach., 12:547–560, 1965."
705dfbf837cSBarry Smith 
706dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
707dfbf837cSBarry Smith M*/
708a312c225SMatthew G Knepley 
709a312c225SMatthew G Knepley EXTERN_C_BEGIN
710a312c225SMatthew G Knepley #undef __FUNCT__
711a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
712a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
713a312c225SMatthew G Knepley {
714a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
715a312c225SMatthew G Knepley   PetscErrorCode ierr;
716a312c225SMatthew G Knepley 
717a312c225SMatthew G Knepley   PetscFunctionBegin;
718a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
719a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
720a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
721a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
722a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
723a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
724a312c225SMatthew G Knepley 
72542f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
7262c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
7272c155ee1SBarry Smith 
728a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
729a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
730d2e16ddcSPeter Brune   ngmres->msize = 30;
73119653cdaSPeter Brune 
73288976e71SPeter Brune   if (!snes->tolerancesset) {
7330e444f03SPeter Brune     snes->max_funcs = 30000;
7340e444f03SPeter Brune     snes->max_its   = 10000;
73588976e71SPeter Brune   }
7360e444f03SPeter Brune 
737d2e16ddcSPeter Brune   ngmres->anderson   = PETSC_FALSE;
738d2e16ddcSPeter Brune 
739e7058c64SPeter Brune   ngmres->additive_linesearch = PETSC_NULL;
740e7058c64SPeter Brune 
74128ed4a04SPeter Brune   ngmres->restart_it = 2;
74213a62661SPeter Brune   ngmres->restart_periodic = 30;
743f109b39eSPeter Brune   ngmres->gammaA     = 2.0;
744f109b39eSPeter Brune   ngmres->gammaC     = 2.0;
745cac108bcSPeter Brune   ngmres->deltaB     = 0.9;
746cac108bcSPeter Brune   ngmres->epsilonB   = 0.1;
747e7058c64SPeter Brune 
74813a62661SPeter Brune   ngmres->restart_type   = SNES_NGMRES_RESTART_DIFFERENCE;
74913a62661SPeter Brune   ngmres->select_type    = SNES_NGMRES_SELECT_DIFFERENCE;
75013a62661SPeter Brune 
75113a62661SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetSelectType_C","SNESNGMRESSetSelectType_NGMRES", SNESNGMRESSetSelectType_NGMRES);CHKERRQ(ierr);
75213a62661SPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESNGMRESSetRestartType_C","SNESNGMRESSetRestartType_NGMRES", SNESNGMRESSetRestartType_NGMRES);CHKERRQ(ierr);
75313a62661SPeter Brune 
754a312c225SMatthew G Knepley   PetscFunctionReturn(0);
755a312c225SMatthew G Knepley }
756a312c225SMatthew G Knepley EXTERN_C_END
757