xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 8e57ea438a4bc929391455041810560decd2c81e)
119653cdaSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h>
219653cdaSPeter Brune #include <petscblaslapack.h>
3a312c225SMatthew G Knepley 
4a312c225SMatthew G Knepley #undef __FUNCT__
5a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
6a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
7a312c225SMatthew G Knepley {
8a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
9a312c225SMatthew G Knepley   PetscErrorCode ierr;
10a312c225SMatthew G Knepley 
11a312c225SMatthew G Knepley   PetscFunctionBegin;
12f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr);
13f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr);
14f1c6b773SPeter Brune   ierr = SNESLineSearchDestroy(&ngmres->additive_linesearch);CHKERRQ(ierr);
159e764e56SPeter Brune 
16a312c225SMatthew G Knepley   PetscFunctionReturn(0);
17a312c225SMatthew G Knepley }
18a312c225SMatthew G Knepley 
19a312c225SMatthew G Knepley #undef __FUNCT__
20a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
21a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
22a312c225SMatthew G Knepley {
23a312c225SMatthew G Knepley   PetscErrorCode ierr;
2478440776SJed Brown   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
25a312c225SMatthew G Knepley 
26a312c225SMatthew G Knepley   PetscFunctionBegin;
27a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
28f109b39eSPeter Brune   ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->fnorms, ngmres->q);CHKERRQ(ierr);
2919653cdaSPeter Brune   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
3019653cdaSPeter Brune #if PETSC_USE_COMPLEX
3119653cdaSPeter Brune   ierr = PetscFree(ngmres->rwork);
3219653cdaSPeter Brune #endif
3319653cdaSPeter Brune   ierr = PetscFree(ngmres->work);
3419653cdaSPeter Brune   ierr = PetscFree(snes->data);
35a312c225SMatthew G Knepley   PetscFunctionReturn(0);
36a312c225SMatthew G Knepley }
37a312c225SMatthew G Knepley 
38a312c225SMatthew G Knepley #undef __FUNCT__
39a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
40a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
41a312c225SMatthew G Knepley {
42a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES *) snes->data;
43e7058c64SPeter Brune   const char     *optionsprefix;
4419653cdaSPeter Brune   PetscInt       msize,hsize;
45a312c225SMatthew G Knepley   PetscErrorCode ierr;
46a312c225SMatthew G Knepley 
47a312c225SMatthew G Knepley   PetscFunctionBegin;
4878440776SJed Brown   ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr);
4978440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
5078440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
5178440776SJed Brown   if (!ngmres->setup_called) {
52087dfb9eSxuemin     msize         = ngmres->msize;  /* restart size */
5319653cdaSPeter Brune     hsize         = msize * msize;
54087dfb9eSxuemin 
5598b3e84cSPeter Brune     /* explicit least squares minimization solve */
5619653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
5719653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
5819653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
59f109b39eSPeter Brune                         msize,PetscReal,  &ngmres->fnorms,
6019653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6119653cdaSPeter Brune     ngmres->nrhs = 1;
6219653cdaSPeter Brune     ngmres->lda = msize;
6319653cdaSPeter Brune     ngmres->ldb = msize;
6419653cdaSPeter Brune     ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
6519653cdaSPeter Brune     ierr = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6619653cdaSPeter Brune     ierr = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6719653cdaSPeter Brune     ierr = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
6819653cdaSPeter Brune     ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
6919653cdaSPeter Brune     ngmres->lwork = 12*msize;
7019653cdaSPeter Brune #if PETSC_USE_COMPLEX
7119653cdaSPeter Brune     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
7219653cdaSPeter Brune #endif
7319653cdaSPeter Brune     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
7478440776SJed Brown   }
75e7058c64SPeter Brune 
76e7058c64SPeter Brune   /* linesearch setup */
77e7058c64SPeter Brune   ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr);
78e7058c64SPeter Brune 
79e7058c64SPeter Brune   if (ngmres->additive) {
80f1c6b773SPeter Brune     ierr = SNESLineSearchCreate(((PetscObject)snes)->comm, &ngmres->additive_linesearch);CHKERRQ(ierr);
81f1c6b773SPeter Brune     ierr = SNESLineSearchSetSNES(ngmres->additive_linesearch, snes);CHKERRQ(ierr);
82f1c6b773SPeter Brune     ierr = SNESLineSearchSetType(ngmres->additive_linesearch, SNES_LINESEARCH_L2);CHKERRQ(ierr);
83f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_");CHKERRQ(ierr);
84f1c6b773SPeter Brune     ierr = SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix);CHKERRQ(ierr);
85f1c6b773SPeter Brune     ierr = SNESLineSearchSetFromOptions(ngmres->additive_linesearch);CHKERRQ(ierr);
86e7058c64SPeter Brune   }
87e7058c64SPeter Brune 
8878440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
89a312c225SMatthew G Knepley   PetscFunctionReturn(0);
90a312c225SMatthew G Knepley }
91a312c225SMatthew G Knepley 
92a312c225SMatthew G Knepley #undef __FUNCT__
93a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
94a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
95a312c225SMatthew G Knepley {
96a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
97a312c225SMatthew G Knepley   PetscErrorCode ierr;
98dfbf837cSBarry Smith   PetscBool      debug;
99f1c6b773SPeter Brune   SNESLineSearch linesearch;
100a312c225SMatthew G Knepley   PetscFunctionBegin;
101a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
1029f425c49SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_additive", "Use additive variant vs. choice",    "SNES", ngmres->additive,  &ngmres->additive, PETSC_NULL);CHKERRQ(ierr);
103d2e16ddcSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_anderson", "Use Anderson mixing storage",        "SNES", ngmres->anderson,  &ngmres->anderson, PETSC_NULL);CHKERRQ(ierr);
10419653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m",         "Number of directions",               "SNES", ngmres->msize,  &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
10528ed4a04SPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES", ngmres->restart_it,  &ngmres->restart_it, PETSC_NULL);CHKERRQ(ierr);
106dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",  "Monitor actions of NGMRES",          "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr);
107dfbf837cSBarry Smith   if (debug) {
108dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
109dfbf837cSBarry Smith   }
1106a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA",   "Residual selection constant",   "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
1116a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "  Residual restart constant",     "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
1126a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
1136a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB",   "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
114a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1156a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
1169e764e56SPeter Brune 
1179e764e56SPeter Brune   /* set the default type of the line search if the user hasn't already. */
1189e764e56SPeter Brune   if (!snes->linesearch) {
119f1c6b773SPeter Brune     ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr);
120f1c6b773SPeter Brune     ierr = SNESLineSearchSetType(linesearch, SNES_LINESEARCH_BASIC);CHKERRQ(ierr);
1219e764e56SPeter Brune   }
122a312c225SMatthew G Knepley   PetscFunctionReturn(0);
123a312c225SMatthew G Knepley }
124a312c225SMatthew G Knepley 
125a312c225SMatthew G Knepley #undef __FUNCT__
126a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
127a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
128a312c225SMatthew G Knepley {
129a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
130a312c225SMatthew G Knepley   PetscBool      iascii;
131a312c225SMatthew G Knepley   PetscErrorCode ierr;
132a312c225SMatthew G Knepley 
133a312c225SMatthew G Knepley   PetscFunctionBegin;
134a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
135a312c225SMatthew G Knepley   if (iascii) {
1369e764e56SPeter Brune 
137f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
138f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr);
139f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr);
140a312c225SMatthew G Knepley   }
141a312c225SMatthew G Knepley   PetscFunctionReturn(0);
142a312c225SMatthew G Knepley }
143a312c225SMatthew G Knepley 
144a312c225SMatthew G Knepley #undef __FUNCT__
145a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
146211b2d39SPeter Brune 
147a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
148a312c225SMatthew G Knepley {
149087dfb9eSxuemin   SNES_NGMRES        *ngmres = (SNES_NGMRES *) snes->data;
15098b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1519f425c49SPeter Brune   Vec                 X, F, B, D, Y;
152f109b39eSPeter Brune 
153f109b39eSPeter Brune   /* candidate linear combination answers */
1544b32a720SPeter Brune   Vec                 XA, FA, XM, FM, FPC;
15519653cdaSPeter Brune 
15698b3e84cSPeter Brune   /* previous iterations to construct the subspace */
157f109b39eSPeter Brune   Vec                 *Fdot = ngmres->Fdot;
158f109b39eSPeter Brune   Vec                 *Xdot = ngmres->Xdot;
15919653cdaSPeter Brune 
16098b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
16119653cdaSPeter Brune   PetscScalar         *beta = ngmres->beta;
16219653cdaSPeter Brune   PetscScalar         *xi   = ngmres->xi;
1639f425c49SPeter Brune   PetscReal           fnorm, fMnorm, fAnorm, ynorm, xnorm = 0.0;
16419653cdaSPeter Brune   PetscReal           nu;
16519653cdaSPeter Brune   PetscScalar         alph_total = 0.;
16619653cdaSPeter Brune   PetscScalar         qentry;
16728ed4a04SPeter Brune   PetscInt            i, j, k, k_restart, l, ivec, restart_count = 0;
16819653cdaSPeter Brune 
16998b3e84cSPeter Brune   /* solution selection data */
17019653cdaSPeter Brune   PetscBool           selectA, selectRestart;
171f109b39eSPeter Brune   PetscReal           dnorm, dminnorm, dcurnorm;
172f109b39eSPeter Brune   PetscReal           fminnorm;
17319653cdaSPeter Brune 
1741e633543SBarry Smith   SNESConvergedReason reason;
175f109b39eSPeter Brune   PetscBool           lssucceed;
176a312c225SMatthew G Knepley   PetscErrorCode      ierr;
177a312c225SMatthew G Knepley 
178a312c225SMatthew G Knepley   PetscFunctionBegin;
17998b3e84cSPeter Brune   /* variable initialization */
180a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
181f109b39eSPeter Brune   X             = snes->vec_sol;
182f109b39eSPeter Brune   F             = snes->vec_func;
183f109b39eSPeter Brune   B             = snes->vec_rhs;
184f109b39eSPeter Brune   XA            = snes->vec_sol_update;
185f109b39eSPeter Brune   FA            = snes->work[0];
186f109b39eSPeter Brune   D             = snes->work[1];
187f109b39eSPeter Brune 
188f109b39eSPeter Brune   /* work for the line search */
189f109b39eSPeter Brune   Y             = snes->work[2];
1909f425c49SPeter Brune   XM            = snes->work[3];
1919f425c49SPeter Brune   FM            = snes->work[4];
192a312c225SMatthew G Knepley 
193a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
194a312c225SMatthew G Knepley   snes->iter = 0;
195a312c225SMatthew G Knepley   snes->norm = 0.;
196a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
19719653cdaSPeter Brune 
19898b3e84cSPeter Brune   /* initialization */
19919653cdaSPeter Brune 
20098b3e84cSPeter Brune   /* r = F(x) */
201f109b39eSPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
202a312c225SMatthew G Knepley   if (snes->domainerror) {
203a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
204a312c225SMatthew G Knepley     PetscFunctionReturn(0);
205a312c225SMatthew G Knepley   }
20619653cdaSPeter Brune 
20798b3e84cSPeter Brune   /* nu = (r, r) */
208f109b39eSPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
209f109b39eSPeter Brune   fminnorm = fnorm;
210f109b39eSPeter Brune   nu = fnorm*fnorm;
211f109b39eSPeter Brune   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
21219653cdaSPeter Brune 
21398b3e84cSPeter Brune   /* q_{00} = nu  */
21419653cdaSPeter Brune   Q(0,0) = nu;
215f109b39eSPeter Brune   ngmres->fnorms[0] = fnorm;
216f109b39eSPeter Brune   /* Fdot[0] = F */
217f109b39eSPeter Brune   ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
218f109b39eSPeter Brune   ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
219087dfb9eSxuemin 
220a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
221f109b39eSPeter Brune   snes->norm = fnorm;
222a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
223f109b39eSPeter Brune   SNESLogConvHistory(snes, fnorm, 0);
224f109b39eSPeter Brune   ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr);
225f109b39eSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
226a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
227a312c225SMatthew G Knepley 
22819653cdaSPeter Brune   k_restart = 1;
22919653cdaSPeter Brune   l = 1;
23009c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
23198b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
23298b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
23319653cdaSPeter Brune 
23498b3e84cSPeter Brune     /* Computation of x^M */
2358cc86e31SPeter Brune     if (snes->pc) {
2369f425c49SPeter Brune       ierr = VecCopy(X, XM);CHKERRQ(ierr);
2379f425c49SPeter Brune       ierr = SNESSolve(snes->pc, B, XM);CHKERRQ(ierr);
2388cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2398cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2408cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2418cc86e31SPeter Brune         PetscFunctionReturn(0);
2428cc86e31SPeter Brune       }
2434b32a720SPeter Brune       ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
2444b32a720SPeter Brune       ierr = VecCopy(FPC, FM);CHKERRQ(ierr);
2454b32a720SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc, &fMnorm);CHKERRQ(ierr);
2468cc86e31SPeter Brune     } else {
247f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
248f109b39eSPeter Brune       ierr = VecCopy(F, Y);CHKERRQ(ierr);
249e7058c64SPeter Brune       ierr = VecCopy(F, FM);CHKERRQ(ierr);
250e7058c64SPeter Brune       ierr = VecCopy(X, XM);CHKERRQ(ierr);
251e7058c64SPeter Brune       fMnorm = fnorm;
252f1c6b773SPeter Brune       ierr = SNESLineSearchApply(snes->linesearch,XM,FM,&fMnorm,Y);CHKERRQ(ierr);
253f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr);
254f109b39eSPeter Brune       if (!lssucceed) {
255f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
256f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
257f109b39eSPeter Brune           PetscFunctionReturn(0);
258f109b39eSPeter Brune         }
259f109b39eSPeter Brune       }
2606634f59bSPeter Brune     }
2611e633543SBarry Smith 
26298b3e84cSPeter Brune     /* r = F(x) */
2639f425c49SPeter Brune     nu = fMnorm*fMnorm;
2649f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
26519653cdaSPeter Brune 
26698b3e84cSPeter Brune     /* construct the right hand side and xi factors */
2678c09b6b7SPeter Brune     ierr = VecMDot(FM, l, Fdot, xi);CHKERRQ(ierr);
2688c09b6b7SPeter Brune 
26919653cdaSPeter Brune     for (i = 0; i < l; i++) {
27019653cdaSPeter Brune       beta[i] = nu - xi[i];
27119653cdaSPeter Brune     }
27219653cdaSPeter Brune 
27398b3e84cSPeter Brune     /* construct h */
27419653cdaSPeter Brune     for (j = 0; j < l; j++) {
27519653cdaSPeter Brune       for (i = 0; i < l; i++) {
27619653cdaSPeter Brune         H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
27719653cdaSPeter Brune       }
27819653cdaSPeter Brune     }
279f109b39eSPeter Brune 
280f109b39eSPeter Brune     if(l == 1) {
281f109b39eSPeter Brune       /* simply set alpha[0] = beta[0] / H[0, 0] */
282f109b39eSPeter Brune       beta[0] = beta[0] / H(0, 0);
283f109b39eSPeter Brune     } else {
28419653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
28519653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2864a0c5b0cSMatthew G Knepley #else
28719653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
28819653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
28919653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
29019653cdaSPeter Brune     ngmres->rcond = -1.;
291*8e57ea43SSatish Balay     ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
29219653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
29319653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
29419653cdaSPeter Brune                  &ngmres->n,
29519653cdaSPeter Brune                  &ngmres->nrhs,
29619653cdaSPeter Brune                  ngmres->h,
29719653cdaSPeter Brune                  &ngmres->lda,
29819653cdaSPeter Brune                  ngmres->beta,
29919653cdaSPeter Brune                  &ngmres->ldb,
30019653cdaSPeter Brune                  ngmres->s,
30119653cdaSPeter Brune                  &ngmres->rcond,
30219653cdaSPeter Brune                  &ngmres->rank,
30319653cdaSPeter Brune                  ngmres->work,
30419653cdaSPeter Brune                  &ngmres->lwork,
30519653cdaSPeter Brune                  ngmres->rwork,
30619653cdaSPeter Brune                  &ngmres->info);
30719653cdaSPeter Brune #else
30819653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
30919653cdaSPeter Brune                  &ngmres->n,
31019653cdaSPeter Brune                  &ngmres->nrhs,
31119653cdaSPeter Brune                  ngmres->h,
31219653cdaSPeter Brune                  &ngmres->lda,
31319653cdaSPeter Brune                  ngmres->beta,
31419653cdaSPeter Brune                  &ngmres->ldb,
31519653cdaSPeter Brune                  ngmres->s,
31619653cdaSPeter Brune                  &ngmres->rcond,
31719653cdaSPeter Brune                  &ngmres->rank,
31819653cdaSPeter Brune                  ngmres->work,
31919653cdaSPeter Brune                  &ngmres->lwork,
32019653cdaSPeter Brune                  &ngmres->info);
32119653cdaSPeter Brune #endif
322*8e57ea43SSatish Balay     ierr = PetscFPTrapPop();CHKERRQ(ierr);
32319653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
32419653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
325a312c225SMatthew G Knepley #endif
326f109b39eSPeter Brune     }
327a312c225SMatthew G Knepley 
32819653cdaSPeter Brune     alph_total = 0.;
32919653cdaSPeter Brune     for (i = 0; i < l; i++) {
33019653cdaSPeter Brune       alph_total += beta[i];
331c0bbabecSxuemin     }
332f109b39eSPeter Brune 
3339f425c49SPeter Brune     ierr = VecCopy(XM, XA);CHKERRQ(ierr);
334f109b39eSPeter Brune     ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr);
335087dfb9eSxuemin 
3368c09b6b7SPeter Brune     ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr);
337f109b39eSPeter Brune     ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr);
338f109b39eSPeter Brune     ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
33919653cdaSPeter Brune 
3409f425c49SPeter Brune     /* differences for selection and restart */
341f109b39eSPeter Brune     ierr=VecCopy(XA, D);CHKERRQ(ierr);
342f109b39eSPeter Brune     ierr=VecAXPY(D, -1.0, X);CHKERRQ(ierr);
343f109b39eSPeter Brune     ierr=VecNorm(D, NORM_2, &dnorm);CHKERRQ(ierr);
344f109b39eSPeter Brune     dminnorm = -1.0;
34519653cdaSPeter Brune     for(i=0;i<l;i++) {
346f109b39eSPeter Brune       ierr=VecCopy(XA, D);CHKERRQ(ierr);
347f109b39eSPeter Brune       ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr);
348f109b39eSPeter Brune       ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr);
349f109b39eSPeter Brune       if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm;
35019653cdaSPeter Brune     }
3519f425c49SPeter Brune 
3529f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
3539f425c49SPeter Brune     if (ngmres->additive) {
3549f425c49SPeter Brune       /* X = X + \lambda(XA - X) */
3559f425c49SPeter Brune       if (ngmres->monitor) {
3569f425c49SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
3579f425c49SPeter Brune       }
3589f425c49SPeter Brune       ierr = VecCopy(XA, Y);CHKERRQ(ierr);
359eb1825c3SPeter Brune       ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr);
360f1c6b773SPeter Brune       ierr = SNESLineSearchApply(ngmres->additive_linesearch,X,F,&fnorm,Y);CHKERRQ(ierr);
361f1c6b773SPeter Brune       ierr = SNESLineSearchGetSuccess(ngmres->additive_linesearch, &lssucceed);CHKERRQ(ierr);
3629f425c49SPeter Brune       if (!lssucceed) {
3639f425c49SPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
3649f425c49SPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
3659f425c49SPeter Brune           PetscFunctionReturn(0);
3669f425c49SPeter Brune         }
3679f425c49SPeter Brune       }
368f1c6b773SPeter Brune       ierr = SNESLineSearchGetNorms(ngmres->additive_linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
3699f425c49SPeter Brune       if (ngmres->monitor) {
3709f425c49SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", fnorm);CHKERRQ(ierr);
3719f425c49SPeter Brune       }
3729f425c49SPeter Brune       ierr = VecCopy(FA, F);CHKERRQ(ierr);
3739f425c49SPeter Brune       ierr = VecCopy(XA, X);CHKERRQ(ierr);
3749f425c49SPeter Brune     } else {
3759f425c49SPeter Brune       selectA = PETSC_TRUE;
3769f425c49SPeter Brune       /* Conditions for choosing the accelerated answer */
3779f425c49SPeter Brune       /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
3789f425c49SPeter Brune       if (fAnorm >= ngmres->gammaA*fminnorm) {
3799f425c49SPeter Brune         selectA = PETSC_FALSE;
3809f425c49SPeter Brune       }
3819f425c49SPeter Brune       /* Criterion B -- the choice of x^A isn't too close to some other choice */
382cf22de31SPeter Brune      if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) {
38319653cdaSPeter Brune       } else {
38419653cdaSPeter Brune         selectA=PETSC_FALSE;
38519653cdaSPeter Brune       }
38619653cdaSPeter Brune       if (selectA) {
387dfbf837cSBarry Smith         if (ngmres->monitor) {
3889e764e56SPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
389dfbf837cSBarry Smith         }
39098b3e84cSPeter Brune         /* copy it over */
391f109b39eSPeter Brune         fnorm = fAnorm;
392f109b39eSPeter Brune         nu = fnorm*fnorm;
393f109b39eSPeter Brune         ierr = VecCopy(FA, F);CHKERRQ(ierr);
394f109b39eSPeter Brune         ierr = VecCopy(XA, X);CHKERRQ(ierr);
39519653cdaSPeter Brune       } else {
396dfbf837cSBarry Smith         if (ngmres->monitor) {
397f109b39eSPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr);
398dfbf837cSBarry Smith         }
3999f425c49SPeter Brune         fnorm = fMnorm;
4009f425c49SPeter Brune         nu = fnorm*fnorm;
4019f425c49SPeter Brune         ierr = VecCopy(FM, F);CHKERRQ(ierr);
4029f425c49SPeter Brune         ierr = VecCopy(XM, X);CHKERRQ(ierr);
4039f425c49SPeter Brune       }
40419653cdaSPeter Brune     }
405211b2d39SPeter Brune 
40619653cdaSPeter Brune     selectRestart = PETSC_FALSE;
40719653cdaSPeter Brune 
40898b3e84cSPeter Brune     /* difference stagnation restart */
409cf22de31SPeter Brune     if((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm))) {
410dfbf837cSBarry Smith       if (ngmres->monitor) {
411f109b39eSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr);
412dfbf837cSBarry Smith       }
41319653cdaSPeter Brune       selectRestart = PETSC_TRUE;
41419653cdaSPeter Brune     }
41598b3e84cSPeter Brune     /* residual stagnation restart */
416cf22de31SPeter Brune     if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
417dfbf837cSBarry Smith       if (ngmres->monitor) {
418cf22de31SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", PetscSqrtReal(fAnorm), ngmres->gammaC*PetscSqrtReal(fminnorm));CHKERRQ(ierr);
419dfbf837cSBarry Smith       }
42019653cdaSPeter Brune       selectRestart = PETSC_TRUE;
42119653cdaSPeter Brune     }
42219653cdaSPeter Brune 
42328ed4a04SPeter Brune     /* if the restart conditions persist for more than restart_it iterations, restart. */
42419653cdaSPeter Brune     if (selectRestart) {
42528ed4a04SPeter Brune       restart_count++;
42628ed4a04SPeter Brune     } else {
42728ed4a04SPeter Brune       restart_count = 0;
42828ed4a04SPeter Brune     }
42928ed4a04SPeter Brune 
43028ed4a04SPeter Brune     /* restart after restart conditions have persisted for a fixed number of iterations */
43128ed4a04SPeter Brune     if (restart_count >= ngmres->restart_it) {
432dfbf837cSBarry Smith       if (ngmres->monitor){
433dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr);
434dfbf837cSBarry Smith       }
43528ed4a04SPeter Brune       restart_count = 0;
43619653cdaSPeter Brune       k_restart = 1;
43719653cdaSPeter Brune       l = 1;
43898b3e84cSPeter Brune       /* q_{00} = nu */
439d2e16ddcSPeter Brune       if (ngmres->anderson) {
440d2e16ddcSPeter Brune         ngmres->fnorms[0] = fMnorm;
441d2e16ddcSPeter Brune         nu = fMnorm*fMnorm;
442d2e16ddcSPeter Brune         Q(0,0) = nu;
443d2e16ddcSPeter Brune         /* Fdot[0] = F */
444d2e16ddcSPeter Brune         ierr = VecCopy(XM, Xdot[0]);CHKERRQ(ierr);
445d2e16ddcSPeter Brune         ierr = VecCopy(FM, Fdot[0]);CHKERRQ(ierr);
446d2e16ddcSPeter Brune       } else {
447f109b39eSPeter Brune         ngmres->fnorms[0] = fnorm;
448f109b39eSPeter Brune         nu = fnorm*fnorm;
44919653cdaSPeter Brune         Q(0,0) = nu;
450f109b39eSPeter Brune         /* Fdot[0] = F */
451f109b39eSPeter Brune         ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
452f109b39eSPeter Brune         ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
453d2e16ddcSPeter Brune       }
45419653cdaSPeter Brune     } else {
45598b3e84cSPeter Brune       /* select the current size of the subspace */
4561e633543SBarry Smith       if (l < ngmres->msize) l++;
45719653cdaSPeter Brune       k_restart++;
45898b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
459d2e16ddcSPeter Brune       if (ngmres->anderson) {
460d2e16ddcSPeter Brune         ierr = VecCopy(FM, Fdot[ivec]);CHKERRQ(ierr);
461d2e16ddcSPeter Brune         ierr = VecCopy(XM, Xdot[ivec]);CHKERRQ(ierr);
462d2e16ddcSPeter Brune         ngmres->fnorms[ivec] = fMnorm;
463d2e16ddcSPeter Brune         if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of FM */
464d2e16ddcSPeter Brune         for (i = 0; i < l; i++) {
465d2e16ddcSPeter Brune           ierr = VecDot(FM, Fdot[i], &qentry);CHKERRQ(ierr);
466d2e16ddcSPeter Brune           Q(i, ivec) = qentry;
467d2e16ddcSPeter Brune           Q(ivec, i) = qentry;
468d2e16ddcSPeter Brune         }
469d2e16ddcSPeter Brune       } else {
470f109b39eSPeter Brune         ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr);
471f109b39eSPeter Brune         ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr);
472f109b39eSPeter Brune         ngmres->fnorms[ivec] = fnorm;
473d2e16ddcSPeter Brune         if (fminnorm > fnorm) fminnorm = fnorm;  /* the minimum norm is now of FA */
47419653cdaSPeter Brune         for (i = 0; i < l; i++) {
475f109b39eSPeter Brune           ierr = VecDot(F, Fdot[i], &qentry);CHKERRQ(ierr);
47619653cdaSPeter Brune           Q(i, ivec) = qentry;
47719653cdaSPeter Brune           Q(ivec, i) = qentry;
47819653cdaSPeter Brune         }
47919653cdaSPeter Brune       }
480d2e16ddcSPeter Brune     }
48119653cdaSPeter Brune 
4828409ca45SMatthew G Knepley     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
483087dfb9eSxuemin     snes->iter = k;
484f109b39eSPeter Brune     snes->norm = fnorm;
4858409ca45SMatthew G Knepley     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
4868409ca45SMatthew G Knepley     SNESLogConvHistory(snes, snes->norm, snes->iter);
4878409ca45SMatthew G Knepley     ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr);
4888409ca45SMatthew G Knepley 
489e7058c64SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
490087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
491a312c225SMatthew G Knepley   }
492a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
493a312c225SMatthew G Knepley   PetscFunctionReturn(0);
494a312c225SMatthew G Knepley }
495a312c225SMatthew G Knepley 
496dfbf837cSBarry Smith /*MC
4971867fe5bSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.
498a312c225SMatthew G Knepley 
499dfbf837cSBarry Smith    Level: beginner
500dfbf837cSBarry Smith 
5011867fe5bSPeter Brune    Options Database:
5021867fe5bSPeter Brune +  -snes_ngmres_additive   - Use a variant that line-searches between the candidate solution and the combined solution.
5031867fe5bSPeter Brune .  -snes_ngmres_anderson   - Use Anderson mixing NGMRES variant which combines candidate solutions instead of actual solutions.
5041867fe5bSPeter Brune .  -snes_ngmres_m          - Number of stored previous solutions and residuals.
5051867fe5bSPeter Brune .  -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart.
5061867fe5bSPeter Brune .  -snes_ngmres_gammaA     - Residual tolerance for solution selection between the candidate and combination.
5071867fe5bSPeter Brune .  -snes_ngmres_gammaC     - Residual tolerance for restart.
5081867fe5bSPeter Brune .  -snes_ngmres_epsilonB   - Difference tolerance between subsequent solutions triggering restart.
5091867fe5bSPeter Brune .  -snes_ngmres_deltaB     - Difference tolerance between residuals triggering restart.
5101867fe5bSPeter Brune .  -snes_ngmres_monitor    - Prints relevant information about the ngmres iteration.
511f3aaf736SPeter Brune -  -snes_ls <basic,basicnonorms,quadratic,critical> - Line search type.
5121867fe5bSPeter Brune 
5131867fe5bSPeter Brune    Notes:
5141867fe5bSPeter Brune 
5151867fe5bSPeter Brune    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
5161867fe5bSPeter Brune    optimization problem at each iteration.
5171867fe5bSPeter Brune 
5181867fe5bSPeter Brune    References:
5191867fe5bSPeter Brune 
520dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
521dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
522dfbf837cSBarry Smith 
523dfbf837cSBarry Smith    This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations.
524dfbf837cSBarry Smith    J. Assoc. Comput. Mach., 12:547–560, 1965."
525dfbf837cSBarry Smith 
526dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
527dfbf837cSBarry Smith M*/
528a312c225SMatthew G Knepley 
529a312c225SMatthew G Knepley EXTERN_C_BEGIN
530a312c225SMatthew G Knepley #undef __FUNCT__
531a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
532a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
533a312c225SMatthew G Knepley {
534a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
535a312c225SMatthew G Knepley   PetscErrorCode ierr;
536a312c225SMatthew G Knepley 
537a312c225SMatthew G Knepley   PetscFunctionBegin;
538a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
539a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
540a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
541a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
542a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
543a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
544a312c225SMatthew G Knepley 
54542f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
5462c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
5472c155ee1SBarry Smith 
548a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
549a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
550d2e16ddcSPeter Brune   ngmres->msize = 30;
55119653cdaSPeter Brune 
55288976e71SPeter Brune   if (!snes->tolerancesset) {
5530e444f03SPeter Brune     snes->max_funcs = 30000;
5540e444f03SPeter Brune     snes->max_its   = 10000;
55588976e71SPeter Brune   }
5560e444f03SPeter Brune 
557d2e16ddcSPeter Brune   ngmres->additive   = PETSC_FALSE;
558d2e16ddcSPeter Brune   ngmres->anderson   = PETSC_FALSE;
559d2e16ddcSPeter Brune 
560e7058c64SPeter Brune   ngmres->additive_linesearch = PETSC_NULL;
561e7058c64SPeter Brune 
56228ed4a04SPeter Brune   ngmres->restart_it = 2;
563f109b39eSPeter Brune   ngmres->gammaA     = 2.0;
564f109b39eSPeter Brune   ngmres->gammaC     = 2.0;
565cac108bcSPeter Brune   ngmres->deltaB     = 0.9;
566cac108bcSPeter Brune   ngmres->epsilonB   = 0.1;
567e7058c64SPeter Brune 
568a312c225SMatthew G Knepley   PetscFunctionReturn(0);
569a312c225SMatthew G Knepley }
570a312c225SMatthew G Knepley EXTERN_C_END
571