xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision f109b39eb9ae46831d990244e4589cb6c24f65e0)
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 
5087dfb9eSxuemin 
6087dfb9eSxuemin 
7087dfb9eSxuemin 
8a312c225SMatthew G Knepley #undef __FUNCT__
9a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
10a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
11a312c225SMatthew G Knepley {
12a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
13a312c225SMatthew G Knepley   PetscErrorCode ierr;
14a312c225SMatthew G Knepley 
15a312c225SMatthew G Knepley   PetscFunctionBegin;
16*f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr);
17*f109b39eSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr);
18732c72c5SBarry Smith   if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);}
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;
27a312c225SMatthew G Knepley 
28a312c225SMatthew G Knepley   PetscFunctionBegin;
29a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
3019653cdaSPeter Brune   if (snes->data) {
3119653cdaSPeter Brune     SNES_NGMRES * ngmres = (SNES_NGMRES *)snes->data;
32*f109b39eSPeter Brune     ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->fnorms, ngmres->q);CHKERRQ(ierr);
3319653cdaSPeter Brune     ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
3419653cdaSPeter Brune #if PETSC_USE_COMPLEX
3519653cdaSPeter Brune     ierr = PetscFree(ngmres->rwork);
3619653cdaSPeter Brune #endif
3719653cdaSPeter Brune     ierr = PetscFree(ngmres->work);
3819653cdaSPeter Brune   }
3919653cdaSPeter Brune   ierr = PetscFree(snes->data);
40a312c225SMatthew G Knepley   PetscFunctionReturn(0);
41a312c225SMatthew G Knepley }
42a312c225SMatthew G Knepley 
43a312c225SMatthew G Knepley #undef __FUNCT__
44a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
45a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
46a312c225SMatthew G Knepley {
47a312c225SMatthew G Knepley   SNES_NGMRES    *ngmres = (SNES_NGMRES *) snes->data;
4819653cdaSPeter Brune   PetscInt       msize,hsize;
49a312c225SMatthew G Knepley   PetscErrorCode ierr;
50a312c225SMatthew G Knepley 
51a312c225SMatthew G Knepley   PetscFunctionBegin;
52087dfb9eSxuemin   msize         = ngmres->msize;  /* restart size */
5319653cdaSPeter Brune   hsize         = msize * msize;
54087dfb9eSxuemin 
55087dfb9eSxuemin 
5698b3e84cSPeter Brune   /* explicit least squares minimization solve */
5719653cdaSPeter Brune   ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
5819653cdaSPeter Brune                       msize,PetscScalar,&ngmres->beta,
5919653cdaSPeter Brune                       msize,PetscScalar,&ngmres->xi,
60*f109b39eSPeter Brune                       msize,PetscReal,  &ngmres->fnorms,
6119653cdaSPeter Brune                       hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
6219653cdaSPeter Brune   ngmres->nrhs = 1;
6319653cdaSPeter Brune   ngmres->lda = msize;
6419653cdaSPeter Brune   ngmres->ldb = msize;
6519653cdaSPeter Brune   ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
6619653cdaSPeter Brune   ierr = PetscMemzero(ngmres->h,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6719653cdaSPeter Brune   ierr = PetscMemzero(ngmres->q,   hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6819653cdaSPeter Brune   ierr = PetscMemzero(ngmres->xi,  msize*sizeof(PetscScalar));CHKERRQ(ierr);
6919653cdaSPeter Brune   ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7019653cdaSPeter Brune   ngmres->lwork = 12*msize;
7119653cdaSPeter Brune #if PETSC_USE_COMPLEX
7219653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
7319653cdaSPeter Brune #endif
7419653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
75211b2d39SPeter Brune 
76*f109b39eSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Xdot);CHKERRQ(ierr);
77*f109b39eSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Fdot);CHKERRQ(ierr);
78*f109b39eSPeter Brune   ierr = SNESDefaultGetWork(snes, 5);CHKERRQ(ierr);
79a312c225SMatthew G Knepley   PetscFunctionReturn(0);
80a312c225SMatthew G Knepley }
81a312c225SMatthew G Knepley 
82a312c225SMatthew G Knepley #undef __FUNCT__
83a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
84a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
85a312c225SMatthew G Knepley {
86a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
87a312c225SMatthew G Knepley   PetscErrorCode ierr;
88dfbf837cSBarry Smith   PetscBool      debug;
89a312c225SMatthew G Knepley 
90a312c225SMatthew G Knepley   PetscFunctionBegin;
91a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
9219653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m",        "Number of directions",               "SNES", ngmres->msize,  &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
9319653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart",  "Maximum iterations before restart.", "SNES", ngmres->k_rmax, &ngmres->k_rmax, PETSC_NULL);CHKERRQ(ierr);
94dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES",          "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr);
95dfbf837cSBarry Smith   if (debug) {
96dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
97dfbf837cSBarry Smith   }
986a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA",   "Residual selection constant",   "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
996a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "  Residual restart constant",     "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
1006a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
1016a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB",   "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
102a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1036a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
104a312c225SMatthew G Knepley   PetscFunctionReturn(0);
105a312c225SMatthew G Knepley }
106a312c225SMatthew G Knepley 
107a312c225SMatthew G Knepley #undef __FUNCT__
108a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
109a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
110a312c225SMatthew G Knepley {
111a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
112a312c225SMatthew G Knepley   PetscBool      iascii;
113*f109b39eSPeter Brune   const char     *cstr;
114a312c225SMatthew G Knepley   PetscErrorCode ierr;
115a312c225SMatthew G Knepley 
116a312c225SMatthew G Knepley   PetscFunctionBegin;
117a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
118a312c225SMatthew G Knepley   if (iascii) {
119*f109b39eSPeter Brune     cstr = SNESLineSearchTypeName(snes->ls_type);
120*f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
121*f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %d\n", ngmres->msize);CHKERRQ(ierr);
122*f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Maximum iterations before total restart: %d\n", ngmres->k_rmax);CHKERRQ(ierr);
123*f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", ngmres->gammaA, ngmres->gammaC);CHKERRQ(ierr);
124*f109b39eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", ngmres->epsilonB, ngmres->deltaB);CHKERRQ(ierr);
125a312c225SMatthew G Knepley   }
126a312c225SMatthew G Knepley   PetscFunctionReturn(0);
127a312c225SMatthew G Knepley }
128a312c225SMatthew G Knepley 
129*f109b39eSPeter Brune EXTERN_C_BEGIN
130*f109b39eSPeter Brune #undef __FUNCT__
131*f109b39eSPeter Brune #define __FUNCT__ "SNESLineSearchSetType_NGMRES"
132*f109b39eSPeter Brune PetscErrorCode  SNESLineSearchSetType_NGMRES(SNES snes, SNESLineSearchType type)
133*f109b39eSPeter Brune {
134*f109b39eSPeter Brune   PetscErrorCode ierr;
135*f109b39eSPeter Brune   PetscFunctionBegin;
136*f109b39eSPeter Brune 
137*f109b39eSPeter Brune   switch (type) {
138*f109b39eSPeter Brune   case SNES_LS_BASIC:
139*f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr);
140*f109b39eSPeter Brune     break;
141*f109b39eSPeter Brune   case SNES_LS_BASIC_NONORMS:
142*f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr);
143*f109b39eSPeter Brune     break;
144*f109b39eSPeter Brune   case SNES_LS_QUADRATIC:
145*f109b39eSPeter Brune     ierr = SNESLineSearchSet(snes,SNESLineSearchQuadraticSecant,PETSC_NULL);CHKERRQ(ierr);
146*f109b39eSPeter Brune     break;
147*f109b39eSPeter Brune   default:
148*f109b39eSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,"Unknown line search type.");
149*f109b39eSPeter Brune     break;
150*f109b39eSPeter Brune   }
151*f109b39eSPeter Brune   snes->ls_type = type;
152*f109b39eSPeter Brune   PetscFunctionReturn(0);
153*f109b39eSPeter Brune }
154*f109b39eSPeter Brune EXTERN_C_END
155*f109b39eSPeter Brune 
15619653cdaSPeter Brune 
157a312c225SMatthew G Knepley #undef __FUNCT__
158a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
159211b2d39SPeter Brune 
160a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
161a312c225SMatthew G Knepley {
162087dfb9eSxuemin   SNES_NGMRES        *ngmres = (SNES_NGMRES *) snes->data;
16398b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
164*f109b39eSPeter Brune   Vec                 X, F, B, D, G, W, Y;
165*f109b39eSPeter Brune 
166*f109b39eSPeter Brune   /* candidate linear combination answers */
167*f109b39eSPeter Brune   Vec                 XA, FA;
16819653cdaSPeter Brune 
16998b3e84cSPeter Brune   /* previous iterations to construct the subspace */
170*f109b39eSPeter Brune   Vec                 *Fdot = ngmres->Fdot;
171*f109b39eSPeter Brune   Vec                 *Xdot = ngmres->Xdot;
17219653cdaSPeter Brune 
17398b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
17419653cdaSPeter Brune   PetscScalar         *beta = ngmres->beta;
17519653cdaSPeter Brune   PetscScalar         *xi   = ngmres->xi;
176*f109b39eSPeter Brune   PetscReal           fnorm, fAnorm, gnorm, ynorm, xnorm = 0.0;
17719653cdaSPeter Brune   PetscReal           nu;
17819653cdaSPeter Brune   PetscScalar         alph_total = 0.;
17919653cdaSPeter Brune   PetscScalar         qentry;
18019653cdaSPeter Brune   PetscInt            i, j, k, k_restart, l, ivec;
18119653cdaSPeter Brune 
18298b3e84cSPeter Brune   /* solution selection data */
18319653cdaSPeter Brune   PetscBool           selectA, selectRestart;
184*f109b39eSPeter Brune   PetscReal           dnorm, dminnorm, dcurnorm;
185*f109b39eSPeter Brune   PetscReal           fminnorm;
18619653cdaSPeter Brune 
1871e633543SBarry Smith   SNESConvergedReason reason;
188*f109b39eSPeter Brune   PetscBool           lssucceed;
189a312c225SMatthew G Knepley   PetscErrorCode      ierr;
190a312c225SMatthew G Knepley 
191a312c225SMatthew G Knepley   PetscFunctionBegin;
19298b3e84cSPeter Brune   /* variable initialization */
193a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
194*f109b39eSPeter Brune   X             = snes->vec_sol;
195*f109b39eSPeter Brune   F             = snes->vec_func;
196*f109b39eSPeter Brune   B             = snes->vec_rhs;
197*f109b39eSPeter Brune   XA            = snes->vec_sol_update;
198*f109b39eSPeter Brune   FA            = snes->work[0];
199*f109b39eSPeter Brune   D             = snes->work[1];
200*f109b39eSPeter Brune 
201*f109b39eSPeter Brune   /* work for the line search */
202*f109b39eSPeter Brune   Y             = snes->work[2];
203*f109b39eSPeter Brune   G             = snes->work[3];
204*f109b39eSPeter Brune   W             = snes->work[4];
205a312c225SMatthew G Knepley 
206a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
207a312c225SMatthew G Knepley   snes->iter = 0;
208a312c225SMatthew G Knepley   snes->norm = 0.;
209a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
21019653cdaSPeter Brune 
21198b3e84cSPeter Brune   /* initialization */
21219653cdaSPeter Brune 
21398b3e84cSPeter Brune   /* r = F(x) */
214*f109b39eSPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
215a312c225SMatthew G Knepley   if (snes->domainerror) {
216a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
217a312c225SMatthew G Knepley     PetscFunctionReturn(0);
218a312c225SMatthew G Knepley   }
21919653cdaSPeter Brune 
22098b3e84cSPeter Brune   /* nu = (r, r) */
221*f109b39eSPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
222*f109b39eSPeter Brune   fminnorm = fnorm;
223*f109b39eSPeter Brune   nu = fnorm*fnorm;
224*f109b39eSPeter Brune   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
22519653cdaSPeter Brune 
22698b3e84cSPeter Brune   /* q_{00} = nu  */
22719653cdaSPeter Brune   Q(0,0) = nu;
228*f109b39eSPeter Brune   ngmres->fnorms[0] = fnorm;
229*f109b39eSPeter Brune   /* Fdot[0] = F */
230*f109b39eSPeter Brune   ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
231*f109b39eSPeter Brune   ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
232087dfb9eSxuemin 
233a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
234*f109b39eSPeter Brune   snes->norm = fnorm;
235a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
236*f109b39eSPeter Brune   SNESLogConvHistory(snes, fnorm, 0);
237*f109b39eSPeter Brune   ierr = SNESMonitor(snes, 0, fnorm);CHKERRQ(ierr);
238*f109b39eSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
239a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
240a312c225SMatthew G Knepley 
24119653cdaSPeter Brune   k_restart = 1;
24219653cdaSPeter Brune   l = 1;
24319653cdaSPeter Brune   for (k=1; k<snes->max_its; k++) {
24498b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
24598b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
24619653cdaSPeter Brune 
24798b3e84cSPeter Brune     /* Computation of x^M */
2486634f59bSPeter Brune     if (!snes->pc) {
249*f109b39eSPeter Brune       /* no preconditioner -- just take gradient descent with line search */
250*f109b39eSPeter Brune       ierr = VecCopy(F, Y);CHKERRQ(ierr);
251*f109b39eSPeter Brune       ierr = VecScale(Y, -1.0);CHKERRQ(ierr);
252*f109b39eSPeter Brune       ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,F,Y,fnorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
253*f109b39eSPeter Brune       if (!lssucceed) {
254*f109b39eSPeter Brune         if (++snes->numFailures >= snes->maxFailures) {
255*f109b39eSPeter Brune           snes->reason = SNES_DIVERGED_LINE_SEARCH;
256*f109b39eSPeter Brune           PetscFunctionReturn(0);
257*f109b39eSPeter Brune         }
258*f109b39eSPeter Brune       }
259*f109b39eSPeter Brune       fnorm = gnorm;
260*f109b39eSPeter Brune       ierr = VecCopy(G, F);CHKERRQ(ierr);
261*f109b39eSPeter Brune       ierr = VecCopy(W, X);CHKERRQ(ierr);
2626634f59bSPeter Brune     } else {
263*f109b39eSPeter Brune       ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr);
2646634f59bSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
2651e633543SBarry Smith       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2661e633543SBarry Smith         snes->reason = SNES_DIVERGED_INNER;
2671e633543SBarry Smith         PetscFunctionReturn(0);
2681e633543SBarry Smith       }
269*f109b39eSPeter Brune       ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
270*f109b39eSPeter Brune       ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
2716634f59bSPeter Brune     }
2721e633543SBarry Smith 
27398b3e84cSPeter Brune     /* r = F(x) */
274*f109b39eSPeter Brune     nu = fnorm*fnorm;
275*f109b39eSPeter Brune     if (fminnorm > fnorm) fminnorm = fnorm;  /* the minimum norm is now of F^M */
27619653cdaSPeter Brune 
27798b3e84cSPeter Brune     /* construct the right hand side and xi factors */
27819653cdaSPeter Brune     for (i = 0; i < l; i++) {
279*f109b39eSPeter Brune       ierr = VecDot(Fdot[i], F, &xi[i]);CHKERRQ(ierr);
28019653cdaSPeter Brune       beta[i] = nu - xi[i];
28119653cdaSPeter Brune     }
28219653cdaSPeter Brune 
28398b3e84cSPeter Brune     /* construct h */
28419653cdaSPeter Brune     for (j = 0; j < l; j++) {
28519653cdaSPeter Brune       for (i = 0; i < l; i++) {
28619653cdaSPeter Brune         H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
28719653cdaSPeter Brune       }
28819653cdaSPeter Brune     }
289*f109b39eSPeter Brune 
290*f109b39eSPeter Brune     if(l == 1) {
291*f109b39eSPeter Brune       /* simply set alpha[0] = beta[0] / H[0, 0] */
292*f109b39eSPeter Brune       beta[0] = beta[0] / H(0, 0);
293*f109b39eSPeter Brune     } else {
29419653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
29519653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2964a0c5b0cSMatthew G Knepley #else
29719653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
29819653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
29919653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
30019653cdaSPeter Brune     ngmres->rcond = -1.;
30119653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
30219653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
30319653cdaSPeter Brune                  &ngmres->n,
30419653cdaSPeter Brune                  &ngmres->nrhs,
30519653cdaSPeter Brune                  ngmres->h,
30619653cdaSPeter Brune                  &ngmres->lda,
30719653cdaSPeter Brune                  ngmres->beta,
30819653cdaSPeter Brune                  &ngmres->ldb,
30919653cdaSPeter Brune                  ngmres->s,
31019653cdaSPeter Brune                  &ngmres->rcond,
31119653cdaSPeter Brune                  &ngmres->rank,
31219653cdaSPeter Brune                  ngmres->work,
31319653cdaSPeter Brune                  &ngmres->lwork,
31419653cdaSPeter Brune                  ngmres->rwork,
31519653cdaSPeter Brune                  &ngmres->info);
31619653cdaSPeter Brune #else
31719653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
31819653cdaSPeter Brune                  &ngmres->n,
31919653cdaSPeter Brune                  &ngmres->nrhs,
32019653cdaSPeter Brune                  ngmres->h,
32119653cdaSPeter Brune                  &ngmres->lda,
32219653cdaSPeter Brune                  ngmres->beta,
32319653cdaSPeter Brune                  &ngmres->ldb,
32419653cdaSPeter Brune                  ngmres->s,
32519653cdaSPeter Brune                  &ngmres->rcond,
32619653cdaSPeter Brune                  &ngmres->rank,
32719653cdaSPeter Brune                  ngmres->work,
32819653cdaSPeter Brune                  &ngmres->lwork,
32919653cdaSPeter Brune                  &ngmres->info);
33019653cdaSPeter Brune #endif
33119653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
33219653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
333a312c225SMatthew G Knepley #endif
334*f109b39eSPeter Brune     }
335a312c225SMatthew G Knepley 
33619653cdaSPeter Brune     alph_total = 0.;
33719653cdaSPeter Brune     for (i = 0; i < l; i++) {
33819653cdaSPeter Brune       alph_total += beta[i];
339c0bbabecSxuemin     }
340*f109b39eSPeter Brune 
341*f109b39eSPeter Brune     ierr = VecCopy(X, XA);CHKERRQ(ierr);
342*f109b39eSPeter Brune     ierr = VecScale(XA, 1. - alph_total);CHKERRQ(ierr);
343087dfb9eSxuemin 
34419653cdaSPeter Brune     for(i=0;i<l;i++){
345*f109b39eSPeter Brune       ierr= VecAXPY(XA, beta[i], Xdot[i]);CHKERRQ(ierr);
34619653cdaSPeter Brune     }
347*f109b39eSPeter Brune     ierr = SNESComputeFunction(snes, XA, FA);CHKERRQ(ierr);
348*f109b39eSPeter Brune     ierr = VecNorm(FA, NORM_2, &fAnorm);CHKERRQ(ierr);
34919653cdaSPeter Brune 
35019653cdaSPeter Brune     selectA = PETSC_TRUE;
35198b3e84cSPeter Brune     /* Conditions for choosing the accelerated answer */
35219653cdaSPeter Brune 
35398b3e84cSPeter Brune     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
354*f109b39eSPeter Brune     if (fAnorm >= ngmres->gammaA*fminnorm) {
35519653cdaSPeter Brune       selectA = PETSC_FALSE;
356a312c225SMatthew G Knepley     }
357087dfb9eSxuemin 
35898b3e84cSPeter Brune     /* Criterion B -- the choice of x^A isn't too close to some other choice */
359*f109b39eSPeter Brune     ierr=VecCopy(XA, D);CHKERRQ(ierr);
360*f109b39eSPeter Brune     ierr=VecAXPY(D, -1.0, X);CHKERRQ(ierr);
361*f109b39eSPeter Brune     ierr=VecNorm(D, NORM_2, &dnorm);CHKERRQ(ierr);
362*f109b39eSPeter Brune     dminnorm = -1.0;
36319653cdaSPeter Brune     for(i=0;i<l;i++) {
364*f109b39eSPeter Brune       ierr=VecCopy(XA, D);CHKERRQ(ierr);
365*f109b39eSPeter Brune       ierr=VecAXPY(D, -1.0, Xdot[i]);CHKERRQ(ierr);
366*f109b39eSPeter Brune       ierr=VecNorm(D, NORM_2, &dcurnorm);CHKERRQ(ierr);
367*f109b39eSPeter Brune       if((dcurnorm < dminnorm) || (dminnorm < 0.0)) dminnorm = dcurnorm;
36819653cdaSPeter Brune     }
369*f109b39eSPeter Brune     if (ngmres->epsilonB*dnorm<dminnorm || sqrt(fnorm)<ngmres->deltaB*sqrt(fminnorm)) {
37019653cdaSPeter Brune     } else {
37119653cdaSPeter Brune       selectA=PETSC_FALSE;
37219653cdaSPeter Brune     }
373211b2d39SPeter Brune 
374087dfb9eSxuemin 
37519653cdaSPeter Brune     if (selectA) {
376dfbf837cSBarry Smith       if (ngmres->monitor) {
377*f109b39eSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr);
378dfbf837cSBarry Smith       }
37998b3e84cSPeter Brune       /* copy it over */
380*f109b39eSPeter Brune       fnorm = fAnorm;
381*f109b39eSPeter Brune       nu = fnorm*fnorm;
382*f109b39eSPeter Brune       ierr = VecCopy(FA, F);CHKERRQ(ierr);
383*f109b39eSPeter Brune       ierr = VecCopy(XA, X);CHKERRQ(ierr);
38419653cdaSPeter Brune     } else {
385dfbf837cSBarry Smith       if (ngmres->monitor) {
386*f109b39eSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", fAnorm, fnorm);CHKERRQ(ierr);
387dfbf837cSBarry Smith       }
38819653cdaSPeter Brune     }
389211b2d39SPeter Brune 
39019653cdaSPeter Brune     selectRestart = PETSC_FALSE;
39119653cdaSPeter Brune 
39298b3e84cSPeter Brune     /* maximum iteration criterion */
39319653cdaSPeter Brune     if (k_restart > ngmres->k_rmax) {
39419653cdaSPeter Brune       selectRestart = PETSC_TRUE;
39519653cdaSPeter Brune     }
39619653cdaSPeter Brune 
39798b3e84cSPeter Brune     /* difference stagnation restart */
398*f109b39eSPeter Brune     if((ngmres->epsilonB*dnorm > dminnorm) && (sqrt(fAnorm) > ngmres->deltaB*sqrt(fminnorm))) {
399dfbf837cSBarry Smith       if (ngmres->monitor) {
400*f109b39eSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*dnorm, dminnorm);CHKERRQ(ierr);
401dfbf837cSBarry Smith       }
40219653cdaSPeter Brune       selectRestart = PETSC_TRUE;
40319653cdaSPeter Brune     }
40498b3e84cSPeter Brune     /* residual stagnation restart */
405*f109b39eSPeter Brune     if (sqrt(fAnorm) > ngmres->gammaC*sqrt(fminnorm)) {
406dfbf837cSBarry Smith       if (ngmres->monitor) {
407*f109b39eSPeter Brune         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", sqrt(fAnorm), ngmres->gammaC*sqrt(fminnorm));CHKERRQ(ierr);
408dfbf837cSBarry Smith       }
40919653cdaSPeter Brune       selectRestart = PETSC_TRUE;
41019653cdaSPeter Brune     }
41119653cdaSPeter Brune 
41219653cdaSPeter Brune     if (selectRestart) {
413dfbf837cSBarry Smith       if (ngmres->monitor){
414dfbf837cSBarry Smith         ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr);
415dfbf837cSBarry Smith       }
41619653cdaSPeter Brune       k_restart = 1;
41719653cdaSPeter Brune       l = 1;
41898b3e84cSPeter Brune       /* q_{00} = nu */
419*f109b39eSPeter Brune       ngmres->fnorms[0] = fnorm;
420*f109b39eSPeter Brune       nu = fnorm*fnorm;
42119653cdaSPeter Brune       Q(0,0) = nu;
422*f109b39eSPeter Brune       /* Fdot[0] = F */
423*f109b39eSPeter Brune       ierr = VecCopy(X, Xdot[0]);CHKERRQ(ierr);
424*f109b39eSPeter Brune       ierr = VecCopy(F, Fdot[0]);CHKERRQ(ierr);
42519653cdaSPeter Brune     } else {
42698b3e84cSPeter Brune       /* select the current size of the subspace */
4271e633543SBarry Smith       if (l < ngmres->msize) l++;
42819653cdaSPeter Brune       k_restart++;
42998b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
430*f109b39eSPeter Brune       ierr = VecCopy(F, Fdot[ivec]);CHKERRQ(ierr);
431*f109b39eSPeter Brune       ierr = VecCopy(X, Xdot[ivec]);CHKERRQ(ierr);
432*f109b39eSPeter Brune       ngmres->fnorms[ivec] = fnorm;
433*f109b39eSPeter Brune       if (fminnorm > fnorm) fminnorm = fnorm;  /* the minimum norm is now of r^A */
43419653cdaSPeter Brune       for (i = 0; i < l; i++) {
435*f109b39eSPeter Brune         ierr = VecDot(F, Fdot[i], &qentry);CHKERRQ(ierr);
43619653cdaSPeter Brune         Q(i, ivec) = qentry;
43719653cdaSPeter Brune         Q(ivec, i) = qentry;
43819653cdaSPeter Brune       }
43919653cdaSPeter Brune     }
44019653cdaSPeter Brune 
4418409ca45SMatthew G Knepley     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
442087dfb9eSxuemin     snes->iter = k;
443*f109b39eSPeter Brune     snes->norm = fnorm;
4448409ca45SMatthew G Knepley     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
4458409ca45SMatthew G Knepley     SNESLogConvHistory(snes, snes->norm, snes->iter);
4468409ca45SMatthew G Knepley     ierr = SNESMonitor(snes, snes->iter, snes->norm);CHKERRQ(ierr);
4478409ca45SMatthew G Knepley 
448*f109b39eSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
449087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
450a312c225SMatthew G Knepley   }
451a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
452a312c225SMatthew G Knepley   PetscFunctionReturn(0);
453a312c225SMatthew G Knepley }
454a312c225SMatthew G Knepley 
455dfbf837cSBarry Smith /*MC
456dfbf837cSBarry Smith   SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio.
457a312c225SMatthew G Knepley 
458dfbf837cSBarry Smith    Level: beginner
459dfbf837cSBarry Smith 
460dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
461dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
462dfbf837cSBarry Smith 
463dfbf837cSBarry Smith    This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations.
464dfbf837cSBarry Smith    J. Assoc. Comput. Mach., 12:547–560, 1965."
465dfbf837cSBarry Smith 
466dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
467dfbf837cSBarry Smith M*/
468a312c225SMatthew G Knepley 
469a312c225SMatthew G Knepley EXTERN_C_BEGIN
470a312c225SMatthew G Knepley #undef __FUNCT__
471a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
472a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
473a312c225SMatthew G Knepley {
474a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
475a312c225SMatthew G Knepley   PetscErrorCode ierr;
476a312c225SMatthew G Knepley 
477a312c225SMatthew G Knepley   PetscFunctionBegin;
478a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
479a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
480a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
481a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
482a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
483a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
484a312c225SMatthew G Knepley 
48542f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
4862c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
4872c155ee1SBarry Smith 
488a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
489a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
49019653cdaSPeter Brune   ngmres->msize = 10;
49119653cdaSPeter Brune 
492*f109b39eSPeter Brune   ngmres->gammaA   = 2.0;
493*f109b39eSPeter Brune   ngmres->gammaC   = 2.0;
494cac108bcSPeter Brune   ngmres->deltaB   = 0.9;
495cac108bcSPeter Brune   ngmres->epsilonB = 0.1;
496cac108bcSPeter Brune   ngmres->k_rmax   = 200;
497*f109b39eSPeter Brune   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_NGMRES",SNESLineSearchSetType_NGMRES);CHKERRQ(ierr);
498*f109b39eSPeter Brune   ierr = SNESLineSearchSetType(snes, SNES_LS_QUADRATIC);CHKERRQ(ierr);
499a312c225SMatthew G Knepley   PetscFunctionReturn(0);
500a312c225SMatthew G Knepley }
501a312c225SMatthew G Knepley EXTERN_C_END
502