xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 0e444f0362714c3f04cd28fb8b36878ffa678f04)
1a312c225SMatthew G Knepley /* Defines the basic SNES object */
219653cdaSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h>
319653cdaSPeter Brune #include <petscblaslapack.h>
4a312c225SMatthew G Knepley 
5a312c225SMatthew G Knepley #undef __FUNCT__
6a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
7a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
8a312c225SMatthew G Knepley {
9a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
10a312c225SMatthew G Knepley   PetscErrorCode ierr;
11a312c225SMatthew G Knepley 
12a312c225SMatthew G Knepley   PetscFunctionBegin;
13f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr);
14f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr);
15a312c225SMatthew G Knepley   PetscFunctionReturn(0);
16a312c225SMatthew G Knepley }
17a312c225SMatthew G Knepley 
18a312c225SMatthew G Knepley #undef __FUNCT__
19a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
20a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
21a312c225SMatthew G Knepley {
22a312c225SMatthew G Knepley   PetscErrorCode ierr;
2378440776SJed Brown   SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
24a312c225SMatthew G Knepley 
25a312c225SMatthew G Knepley   PetscFunctionBegin;
26a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
27f109b39eSPeter Brune   ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->fnorms, ngmres->q);CHKERRQ(ierr);
2819653cdaSPeter Brune   ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
2919653cdaSPeter Brune #if PETSC_USE_COMPLEX
3019653cdaSPeter Brune   ierr = PetscFree(ngmres->rwork);
3119653cdaSPeter Brune #endif
3219653cdaSPeter Brune   ierr = PetscFree(ngmres->work);
3319653cdaSPeter Brune   ierr = PetscFree(snes->data);
34a312c225SMatthew G Knepley   PetscFunctionReturn(0);
35a312c225SMatthew G Knepley }
36a312c225SMatthew G Knepley 
37a312c225SMatthew G Knepley #undef __FUNCT__
38a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
39a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
40a312c225SMatthew G Knepley {
41a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES *) snes->data;
4219653cdaSPeter Brune   PetscInt       msize,hsize;
43a312c225SMatthew G Knepley   PetscErrorCode ierr;
44a312c225SMatthew G Knepley 
45a312c225SMatthew G Knepley   PetscFunctionBegin;
4678440776SJed Brown   ierr = SNESDefaultGetWork(snes,5);CHKERRQ(ierr);
4778440776SJed Brown   if (!ngmres->Xdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Xdot);CHKERRQ(ierr);}
4878440776SJed Brown   if (!ngmres->Fdot) {ierr = VecDuplicateVecs(snes->vec_sol,ngmres->msize,&ngmres->Fdot);CHKERRQ(ierr);}
4978440776SJed Brown   if (!ngmres->setup_called) {
50087dfb9eSxuemin     msize         = ngmres->msize;  /* restart size */
5119653cdaSPeter Brune     hsize         = msize * msize;
52087dfb9eSxuemin 
5398b3e84cSPeter Brune     /* explicit least squares minimization solve */
5419653cdaSPeter Brune     ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
5519653cdaSPeter Brune                         msize,PetscScalar,&ngmres->beta,
5619653cdaSPeter Brune                         msize,PetscScalar,&ngmres->xi,
57f109b39eSPeter Brune                         msize,PetscReal,  &ngmres->fnorms,
5819653cdaSPeter Brune                         hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
5919653cdaSPeter Brune     ngmres->nrhs = 1;
6019653cdaSPeter Brune     ngmres->lda = msize;
6119653cdaSPeter Brune     ngmres->ldb = msize;
6219653cdaSPeter Brune     ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
6319653cdaSPeter Brune     ierr = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6419653cdaSPeter Brune     ierr = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6519653cdaSPeter Brune     ierr = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
6619653cdaSPeter Brune     ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
6719653cdaSPeter Brune     ngmres->lwork = 12*msize;
6819653cdaSPeter Brune #if PETSC_USE_COMPLEX
6919653cdaSPeter Brune     ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
7019653cdaSPeter Brune #endif
7119653cdaSPeter Brune     ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
7278440776SJed Brown   }
7378440776SJed Brown   ngmres->setup_called = PETSC_TRUE;
74a312c225SMatthew G Knepley   PetscFunctionReturn(0);
75a312c225SMatthew G Knepley }
76a312c225SMatthew G Knepley 
77a312c225SMatthew G Knepley #undef __FUNCT__
78a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
79a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
80a312c225SMatthew G Knepley {
81a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
82a312c225SMatthew G Knepley   PetscErrorCode ierr;
83dfbf837cSBarry Smith   PetscBool      debug;
84a312c225SMatthew G Knepley 
85a312c225SMatthew G Knepley   PetscFunctionBegin;
86a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
879f425c49SPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_additive", "Use additive variant vs. choice",    "SNES", ngmres->additive,  &ngmres->additive, PETSC_NULL);CHKERRQ(ierr);
8819653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m",         "Number of directions",               "SNES", ngmres->msize,  &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
8928ed4a04SPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart_it","Tolerance iterations before restart","SNES", ngmres->restart_it,  &ngmres->restart_it, PETSC_NULL);CHKERRQ(ierr);
90dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor",  "Monitor actions of NGMRES",          "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr);
91dfbf837cSBarry Smith   if (debug) {
92dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
93dfbf837cSBarry Smith   }
946a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA",   "Residual selection constant",   "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
956a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "  Residual restart constant",     "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
966a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
976a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB",   "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
98a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
996a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
100a312c225SMatthew G Knepley   PetscFunctionReturn(0);
101a312c225SMatthew G Knepley }
102a312c225SMatthew G Knepley 
103a312c225SMatthew G Knepley #undef __FUNCT__
104a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
105a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
106a312c225SMatthew G Knepley {
107a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
108a312c225SMatthew G Knepley   PetscBool      iascii;
109f109b39eSPeter Brune   const char     *cstr;
110a312c225SMatthew G Knepley   PetscErrorCode ierr;
111a312c225SMatthew G Knepley 
112a312c225SMatthew G Knepley   PetscFunctionBegin;
113a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
114a312c225SMatthew G Knepley   if (iascii) {
115f109b39eSPeter Brune     cstr = SNESLineSearchTypeName(snes->ls_type);
116f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  line search variant: %s\n",cstr);CHKERRQ(ierr);
117f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
118f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr);
119f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr);
120a312c225SMatthew G Knepley   }
121a312c225SMatthew G Knepley   PetscFunctionReturn(0);
122a312c225SMatthew G Knepley }
123a312c225SMatthew G Knepley 
124f109b39eSPeter Brune EXTERN_C_BEGIN
125f109b39eSPeter Brune #undef __FUNCT__
126f109b39eSPeter Brune #define __FUNCT__ "SNESLineSearchSetType_NGMRES"
127f109b39eSPeter Brune PetscErrorCode  SNESLineSearchSetType_NGMRES(SNES snes, SNESLineSearchType type)
128f109b39eSPeter Brune {
129f109b39eSPeter Brune   PetscErrorCode ierr;
130f109b39eSPeter Brune   PetscFunctionBegin;
131f109b39eSPeter Brune 
132f109b39eSPeter Brune   switch (type) {
133f109b39eSPeter Brune   case SNES_LS_BASIC:
134f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr);
135f109b39eSPeter Brune     break;
136f109b39eSPeter Brune   case SNES_LS_BASIC_NONORMS:
137f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
138f109b39eSPeter Brune     break;
139f109b39eSPeter Brune   case SNES_LS_QUADRATIC:
140f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr);
141f109b39eSPeter Brune     break;
142f109b39eSPeter Brune   default:
143f109b39eSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type.");
144f109b39eSPeter Brune     break;
145f109b39eSPeter Brune   }
146f109b39eSPeter Brune   snes->ls_type = type;
147f109b39eSPeter Brune   PetscFunctionReturn(0);
148f109b39eSPeter Brune }
149f109b39eSPeter Brune EXTERN_C_END
150f109b39eSPeter Brune 
15119653cdaSPeter Brune 
152a312c225SMatthew G Knepley #undef __FUNCT__
153a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
154211b2d39SPeter Brune 
155a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
156a312c225SMatthew G Knepley {
157087dfb9eSxuemin   SNES_NGMRES        *ngmres = (SNES_NGMRES *) snes->data;
15898b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
1599f425c49SPeter Brune   Vec                 X, F, B, D, Y;
160f109b39eSPeter Brune 
161f109b39eSPeter Brune   /* candidate linear combination answers */
1624b32a720SPeter Brune   Vec                 XA, FA, XM, FM, FPC;
16319653cdaSPeter Brune 
16498b3e84cSPeter Brune   /* previous iterations to construct the subspace */
165f109b39eSPeter Brune   Vec                 *Fdot = ngmres->Fdot;
166f109b39eSPeter Brune   Vec                 *Xdot = ngmres->Xdot;
16719653cdaSPeter Brune 
16898b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
16919653cdaSPeter Brune   PetscScalar         *beta = ngmres->beta;
17019653cdaSPeter Brune   PetscScalar         *xi   = ngmres->xi;
1719f425c49SPeter Brune   PetscReal           fnorm, fMnorm, fAnorm, ynorm, xnorm = 0.0;
17219653cdaSPeter Brune   PetscReal           nu;
17319653cdaSPeter Brune   PetscScalar         alph_total = 0.;
17419653cdaSPeter Brune   PetscScalar         qentry;
17528ed4a04SPeter Brune   PetscInt            i, j, k, k_restart, l, ivec, restart_count = 0;
17619653cdaSPeter Brune 
17798b3e84cSPeter Brune   /* solution selection data */
17819653cdaSPeter Brune   PetscBool           selectA, selectRestart;
179f109b39eSPeter Brune   PetscReal           dnorm, dminnorm, dcurnorm;
180f109b39eSPeter Brune   PetscReal           fminnorm;
18119653cdaSPeter Brune 
1821e633543SBarry Smith   SNESConvergedReason reason;
183f109b39eSPeter Brune   PetscBool           lssucceed;
184a312c225SMatthew G Knepley   PetscErrorCode      ierr;
185a312c225SMatthew G Knepley 
186a312c225SMatthew G Knepley   PetscFunctionBegin;
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 
201a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
202a312c225SMatthew G Knepley   snes->iter = 0;
203a312c225SMatthew G Knepley   snes->norm = 0.;
204a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
20519653cdaSPeter Brune 
20698b3e84cSPeter Brune   /* initialization */
20719653cdaSPeter Brune 
20898b3e84cSPeter Brune   /* r = F(x) */
209f109b39eSPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
210a312c225SMatthew G Knepley   if (snes->domainerror) {
211a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
212a312c225SMatthew G Knepley     PetscFunctionReturn(0);
213a312c225SMatthew G Knepley   }
21419653cdaSPeter Brune 
21598b3e84cSPeter Brune   /* nu = (r, r) */
216f109b39eSPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
217f109b39eSPeter Brune   fminnorm = fnorm;
218f109b39eSPeter Brune   nu = fnorm*fnorm;
219f109b39eSPeter Brune   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
22019653cdaSPeter Brune 
22198b3e84cSPeter Brune   /* q_{00} = nu  */
22219653cdaSPeter Brune   Q(0,0) = nu;
223f109b39eSPeter Brune   ngmres->fnorms[0] = fnorm;
224f109b39eSPeter Brune   /* Fdot[0] = F */
225f109b39eSPeter Brune   ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
226f109b39eSPeter Brune   ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
227087dfb9eSxuemin 
228a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
229f109b39eSPeter Brune   snes->norm = fnorm;
230a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
231f109b39eSPeter Brune   SNESLogConvHistory(snes, fnorm, 0);
232f109b39eSPeter Brune   ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr);
233f109b39eSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
234a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
235a312c225SMatthew G Knepley 
23619653cdaSPeter Brune   k_restart = 1;
23719653cdaSPeter Brune   l = 1;
23809c08436SPeter Brune   for (k=1; k < snes->max_its+1; k++) {
23998b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
24098b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
24119653cdaSPeter Brune 
24298b3e84cSPeter Brune     /* Computation of x^M */
2438cc86e31SPeter Brune     if (snes->pc) {
2449f425c49SPeter Brune       ierr = VecCopy(X, XM);CHKERRQ(ierr);
2459f425c49SPeter Brune       ierr = SNESSolve(snes->pc, B, XM);CHKERRQ(ierr);
2468cc86e31SPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2478cc86e31SPeter Brune       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2488cc86e31SPeter Brune         snes->reason = SNES_DIVERGED_INNER;
2498cc86e31SPeter Brune         PetscFunctionReturn(0);
2508cc86e31SPeter Brune       }
2514b32a720SPeter Brune       ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
2524b32a720SPeter Brune       ierr = VecCopy(FPC, FM);CHKERRQ(ierr);
2534b32a720SPeter Brune       ierr = SNESGetFunctionNorm(snes->pc, &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);
2579f425c49SPeter Brune       ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,FM,XM,&ynorm,&fMnorm,&lssucceed);CHKERRQ(ierr);
258f109b39eSPeter Brune       if (!lssucceed) {
259f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
260f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
261f109b39eSPeter Brune           PetscFunctionReturn(0);
262f109b39eSPeter Brune         }
263f109b39eSPeter Brune       }
2646634f59bSPeter Brune     }
2651e633543SBarry Smith 
26698b3e84cSPeter Brune     /* r = F(x) */
2679f425c49SPeter Brune     nu = fMnorm*fMnorm;
2689f425c49SPeter Brune     if (fminnorm > fMnorm) fminnorm = fMnorm;  /* the minimum norm is now of F^M */
26919653cdaSPeter Brune 
27098b3e84cSPeter Brune     /* construct the right hand side and xi factors */
2718c09b6b7SPeter Brune     ierr = VecMDot(FM, l, Fdot, xi);CHKERRQ(ierr);
2728c09b6b7SPeter Brune 
27319653cdaSPeter Brune     for (i = 0; i < l; i++) {
27419653cdaSPeter Brune       beta[i] = nu - xi[i];
27519653cdaSPeter Brune     }
27619653cdaSPeter Brune 
27798b3e84cSPeter Brune     /* construct h */
27819653cdaSPeter Brune     for (j = 0; j < l; j++) {
27919653cdaSPeter Brune       for (i = 0; i < l; i++) {
28019653cdaSPeter Brune         H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
28119653cdaSPeter Brune       }
28219653cdaSPeter Brune     }
283f109b39eSPeter Brune 
284f109b39eSPeter Brune     if(l == 1) {
285f109b39eSPeter Brune       /* simply set alpha[0] = beta[0] / H[0, 0] */
286f109b39eSPeter Brune       beta[0] = beta[0] / H(0, 0);
287f109b39eSPeter Brune     } else {
28819653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
28919653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2904a0c5b0cSMatthew G Knepley #else
29119653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
29219653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
29319653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
29419653cdaSPeter Brune     ngmres->rcond = -1.;
29519653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
29619653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
29719653cdaSPeter Brune                  &ngmres->n,
29819653cdaSPeter Brune                  &ngmres->nrhs,
29919653cdaSPeter Brune                  ngmres->h,
30019653cdaSPeter Brune                  &ngmres->lda,
30119653cdaSPeter Brune                  ngmres->beta,
30219653cdaSPeter Brune                  &ngmres->ldb,
30319653cdaSPeter Brune                  ngmres->s,
30419653cdaSPeter Brune                  &ngmres->rcond,
30519653cdaSPeter Brune                  &ngmres->rank,
30619653cdaSPeter Brune                  ngmres->work,
30719653cdaSPeter Brune                  &ngmres->lwork,
30819653cdaSPeter Brune                  ngmres->rwork,
30919653cdaSPeter Brune                  &ngmres->info);
31019653cdaSPeter Brune #else
31119653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
31219653cdaSPeter Brune                  &ngmres->n,
31319653cdaSPeter Brune                  &ngmres->nrhs,
31419653cdaSPeter Brune                  ngmres->h,
31519653cdaSPeter Brune                  &ngmres->lda,
31619653cdaSPeter Brune                  ngmres->beta,
31719653cdaSPeter Brune                  &ngmres->ldb,
31819653cdaSPeter Brune                  ngmres->s,
31919653cdaSPeter Brune                  &ngmres->rcond,
32019653cdaSPeter Brune                  &ngmres->rank,
32119653cdaSPeter Brune                  ngmres->work,
32219653cdaSPeter Brune                  &ngmres->lwork,
32319653cdaSPeter Brune                  &ngmres->info);
32419653cdaSPeter Brune #endif
32519653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
32619653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
327a312c225SMatthew G Knepley #endif
328f109b39eSPeter Brune     }
329a312c225SMatthew G Knepley 
33019653cdaSPeter Brune     alph_total = 0.;
33119653cdaSPeter Brune     for (i = 0; i < l; i++) {
33219653cdaSPeter Brune       alph_total += beta[i];
333c0bbabecSxuemin     }
334f109b39eSPeter Brune 
3359f425c49SPeter Brune     ierr = VecCopy(XM, XA);CHKERRQ(ierr);
336f109b39eSPeter Brune     ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr);
337087dfb9eSxuemin 
3388c09b6b7SPeter Brune     ierr = VecMAXPY(XA, l, beta, Xdot);CHKERRQ(ierr);
339f109b39eSPeter Brune     ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr);
340f109b39eSPeter Brune     ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
34119653cdaSPeter Brune 
3429f425c49SPeter Brune     /* differences for selection and restart */
343f109b39eSPeter Brune     ierr=VecCopy(XA, D);CHKERRQ(ierr);
344f109b39eSPeter Brune     ierr=VecAXPY(D, -1.0, X);CHKERRQ(ierr);
345f109b39eSPeter Brune     ierr=VecNorm(D, NORM_2, &dnorm);CHKERRQ(ierr);
346f109b39eSPeter Brune     dminnorm = -1.0;
34719653cdaSPeter Brune     for(i=0;i<l;i++) {
348f109b39eSPeter Brune       ierr=VecCopy(XA, D);CHKERRQ(ierr);
349f109b39eSPeter Brune       ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr);
350f109b39eSPeter Brune       ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr);
351f109b39eSPeter Brune       if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm;
35219653cdaSPeter Brune     }
3539f425c49SPeter Brune 
3549f425c49SPeter Brune     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
3559f425c49SPeter Brune     if (ngmres->additive) {
3569f425c49SPeter Brune       /* X = X + \lambda(XA - X) */
3579f425c49SPeter Brune       if (ngmres->monitor) {
3589f425c49SPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fMnorm);CHKERRQ(ierr);
3599f425c49SPeter Brune       }
3609f425c49SPeter Brune       ierr = VecCopy(XA, Y);CHKERRQ(ierr);
361eb1825c3SPeter Brune       ierr = VecAYPX(Y, -1.0, X);CHKERRQ(ierr);
3629f425c49SPeter Brune       ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,FA,XA,&ynorm,&fnorm,&lssucceed);CHKERRQ(ierr);
3639f425c49SPeter Brune       if (!lssucceed) {
3649f425c49SPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
3659f425c49SPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
3669f425c49SPeter Brune           PetscFunctionReturn(0);
3679f425c49SPeter Brune         }
3689f425c49SPeter Brune       }
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) {
388f109b39eSPeter Brune           ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);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 */
439f109b39eSPeter Brune       ngmres->fnorms[0] = fnorm;
440f109b39eSPeter Brune       nu = fnorm*fnorm;
44119653cdaSPeter Brune       Q(0,0) = nu;
442f109b39eSPeter Brune       /* Fdot[0] = F */
443f109b39eSPeter Brune       ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
444f109b39eSPeter Brune       ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
44519653cdaSPeter Brune     } else {
44698b3e84cSPeter Brune       /* select the current size of the subspace */
4471e633543SBarry Smith       if (l < ngmres->msize) l++;
44819653cdaSPeter Brune       k_restart++;
44998b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
450f109b39eSPeter Brune       ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr);
451f109b39eSPeter Brune       ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr);
452f109b39eSPeter Brune       ngmres->fnorms[ivec] = fnorm;
453f109b39eSPeter Brune       if (fminnorm > fnorm) fminnorm = fnorm;  /* the minimum norm is now of r^A */
45419653cdaSPeter Brune       for (i = 0; i < l; i++) {
455f109b39eSPeter Brune         ierr = VecDot(F, Fdot[i], &qentry);CHKERRQ(ierr);
45619653cdaSPeter Brune         Q(i, ivec) = qentry;
45719653cdaSPeter Brune         Q(ivec, i) = qentry;
45819653cdaSPeter Brune       }
45919653cdaSPeter Brune     }
46019653cdaSPeter Brune 
4618409ca45SMatthew G Knepley     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
462087dfb9eSxuemin     snes->iter = k;
463f109b39eSPeter Brune     snes->norm = fnorm;
4648409ca45SMatthew G Knepley     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
4658409ca45SMatthew G Knepley     SNESLogConvHistory(snes, snes->norm, snes->iter);
4668409ca45SMatthew G Knepley     ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr);
4678409ca45SMatthew G Knepley 
468f109b39eSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
469087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
470a312c225SMatthew G Knepley   }
471a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
472a312c225SMatthew G Knepley   PetscFunctionReturn(0);
473a312c225SMatthew G Knepley }
474a312c225SMatthew G Knepley 
475dfbf837cSBarry Smith /*MC
476dfbf837cSBarry Smith   SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio.
477a312c225SMatthew G Knepley 
478dfbf837cSBarry Smith    Level: beginner
479dfbf837cSBarry Smith 
480dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
481dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
482dfbf837cSBarry Smith 
483dfbf837cSBarry Smith    This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations.
484dfbf837cSBarry Smith    J. Assoc. Comput. Mach., 12:547–560, 1965."
485dfbf837cSBarry Smith 
486dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
487dfbf837cSBarry Smith M*/
488a312c225SMatthew G Knepley 
489a312c225SMatthew G Knepley EXTERN_C_BEGIN
490a312c225SMatthew G Knepley #undef __FUNCT__
491a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
492a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
493a312c225SMatthew G Knepley {
494a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
495a312c225SMatthew G Knepley   PetscErrorCode ierr;
496a312c225SMatthew G Knepley 
497a312c225SMatthew G Knepley   PetscFunctionBegin;
498a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
499a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
500a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
501a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
502a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
503a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
504a312c225SMatthew G Knepley 
50542f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
5062c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
5072c155ee1SBarry Smith 
508a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
509a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
51019653cdaSPeter Brune   ngmres->msize = 10;
51119653cdaSPeter Brune 
512*0e444f03SPeter Brune   snes->max_funcs = 30000;
513*0e444f03SPeter Brune   snes->max_its   = 10000;
514*0e444f03SPeter Brune 
51528ed4a04SPeter Brune   ngmres->restart_it = 2;
516f109b39eSPeter Brune   ngmres->gammaA     = 2.0;
517f109b39eSPeter Brune   ngmres->gammaC     = 2.0;
518cac108bcSPeter Brune   ngmres->deltaB     = 0.9;
519cac108bcSPeter Brune   ngmres->epsilonB   = 0.1;
520f109b39eSPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_NGMRES",SNESLineSearchSetType_NGMRES);CHKERRQ(ierr);
521f109b39eSPeter Brune   ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr);
522a312c225SMatthew G Knepley   PetscFunctionReturn(0);
523a312c225SMatthew G Knepley }
524a312c225SMatthew G Knepley EXTERN_C_END
525