xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 6a7cf6406768ca43985ccf9c4579b439352c13e9)
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 
619653cdaSPeter Brune /*MC
719653cdaSPeter Brune   SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio.
8087dfb9eSxuemin 
919653cdaSPeter Brune    Level: beginner
10a312c225SMatthew G Knepley 
1119653cdaSPeter Brune    Notes: Supports only left preconditioning
1219653cdaSPeter Brune 
1319653cdaSPeter Brune    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
1419653cdaSPeter Brune    SIAM Journal on Scientific Computing, 21(5), 2000.
1519653cdaSPeter Brune 
1619653cdaSPeter Brune .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
1719653cdaSPeter Brune M*/
18087dfb9eSxuemin 
19a312c225SMatthew G Knepley #undef __FUNCT__
20a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
21a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
22a312c225SMatthew G Knepley {
23a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
24a312c225SMatthew G Knepley   PetscErrorCode ierr;
25a312c225SMatthew G Knepley 
26a312c225SMatthew G Knepley   PetscFunctionBegin;
2719653cdaSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
2819653cdaSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->xdot);CHKERRQ(ierr);
29a312c225SMatthew G Knepley   PetscFunctionReturn(0);
30a312c225SMatthew G Knepley }
31a312c225SMatthew G Knepley 
32a312c225SMatthew G Knepley #undef __FUNCT__
33a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
34a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
35a312c225SMatthew G Knepley {
36a312c225SMatthew G Knepley   PetscErrorCode ierr;
37a312c225SMatthew G Knepley 
38a312c225SMatthew G Knepley   PetscFunctionBegin;
39a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
40a312c225SMatthew G Knepley   if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);}
4119653cdaSPeter Brune   if (snes->data) {
4219653cdaSPeter Brune     SNES_NGMRES * ngmres = (SNES_NGMRES *)snes->data;
4319653cdaSPeter Brune     ierr = PetscFree4(ngmres->h, ngmres->beta, ngmres->xi, ngmres->q);CHKERRQ(ierr);
4419653cdaSPeter Brune     ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
4519653cdaSPeter Brune #if PETSC_USE_COMPLEX
4619653cdaSPeter Brune     ierr = PetscFree(ngmres->rwork);
4719653cdaSPeter Brune #endif
4819653cdaSPeter Brune     ierr = PetscFree(ngmres->work);
4919653cdaSPeter Brune   }
5019653cdaSPeter Brune   ierr = PetscFree(snes->data);
51a312c225SMatthew G Knepley   PetscFunctionReturn(0);
52a312c225SMatthew G Knepley }
53a312c225SMatthew G Knepley 
54a312c225SMatthew G Knepley #undef __FUNCT__
55a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
56a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
57a312c225SMatthew G Knepley {
58a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
5919653cdaSPeter Brune   PetscInt msize,hsize;
60a312c225SMatthew G Knepley   PetscErrorCode ierr;
61a312c225SMatthew G Knepley 
62a312c225SMatthew G Knepley   PetscFunctionBegin;
63087dfb9eSxuemin   msize         = ngmres->msize;  /* restart size */
6419653cdaSPeter Brune   hsize         = msize * msize;
65087dfb9eSxuemin 
66087dfb9eSxuemin 
6719653cdaSPeter Brune   //explicit least squares minimization solve
6819653cdaSPeter Brune   ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6919653cdaSPeter Brune 		      msize,PetscScalar,&ngmres->beta,
7019653cdaSPeter Brune 		      msize,PetscScalar,&ngmres->xi,
7119653cdaSPeter Brune 		      msize,PetscReal,&ngmres->r_norms,
7219653cdaSPeter Brune 		      hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
7319653cdaSPeter Brune   ngmres->nrhs = 1;
7419653cdaSPeter Brune   ngmres->lda = msize;
7519653cdaSPeter Brune   ngmres->ldb = msize;
7619653cdaSPeter Brune   ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
77087dfb9eSxuemin 
7819653cdaSPeter Brune   ierr = PetscMemzero(ngmres->h,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7919653cdaSPeter Brune   ierr = PetscMemzero(ngmres->q,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
8019653cdaSPeter Brune   ierr = PetscMemzero(ngmres->xi,msize*sizeof(PetscScalar));CHKERRQ(ierr);
8119653cdaSPeter Brune   ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
82211b2d39SPeter Brune 
8319653cdaSPeter Brune   ngmres->lwork = 12*msize;
8419653cdaSPeter Brune #if PETSC_USE_COMPLEX
8519653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
8619653cdaSPeter Brune #endif
8719653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
88211b2d39SPeter Brune 
8919653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->xdot);CHKERRQ(ierr);
9019653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
91211b2d39SPeter Brune   ierr = SNESDefaultGetWork(snes, 3);CHKERRQ(ierr);
92a312c225SMatthew G Knepley   PetscFunctionReturn(0);
93a312c225SMatthew G Knepley }
94a312c225SMatthew G Knepley 
95a312c225SMatthew G Knepley #undef __FUNCT__
96a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
97a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
98a312c225SMatthew G Knepley {
99a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
100a312c225SMatthew G Knepley   PetscErrorCode ierr;
101a312c225SMatthew G Knepley 
102a312c225SMatthew G Knepley   PetscFunctionBegin;
103a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
10419653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
10519653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart", "Maximum iterations before restart.", "SNES", ngmres->k_rmax, &ngmres->k_rmax, PETSC_NULL);CHKERRQ(ierr);
10619653cdaSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_debug", "Debugging output for NGMRES", "SNES", ngmres->debug, &ngmres->debug, PETSC_NULL);CHKERRQ(ierr);
107*6a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
108*6a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
109*6a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
110*6a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
111a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
112*6a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
113a312c225SMatthew G Knepley   PetscFunctionReturn(0);
114a312c225SMatthew G Knepley }
115a312c225SMatthew G Knepley 
116a312c225SMatthew G Knepley #undef __FUNCT__
117a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
118a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
119a312c225SMatthew G Knepley {
120a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
121a312c225SMatthew G Knepley   PetscBool      iascii;
122a312c225SMatthew G Knepley   PetscErrorCode ierr;
123a312c225SMatthew G Knepley 
124a312c225SMatthew G Knepley   PetscFunctionBegin;
125a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
126a312c225SMatthew G Knepley   if (iascii) {
127a312c225SMatthew G Knepley     ierr = PetscViewerASCIIPrintf(viewer, "  Size of space %d\n", ngmres->msize);CHKERRQ(ierr);
128a312c225SMatthew G Knepley   }
129a312c225SMatthew G Knepley   PetscFunctionReturn(0);
130a312c225SMatthew G Knepley }
131a312c225SMatthew G Knepley 
13219653cdaSPeter Brune 
133a312c225SMatthew G Knepley #undef __FUNCT__
134a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
135211b2d39SPeter Brune 
136a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
137a312c225SMatthew G Knepley {
1384a0c5b0cSMatthew G Knepley   SNES           pc;
139087dfb9eSxuemin   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
14019653cdaSPeter Brune 
14119653cdaSPeter Brune 
14219653cdaSPeter Brune 
14319653cdaSPeter Brune   //present solution, residual, and preconditioned residual
14419653cdaSPeter Brune   Vec            x, r, f, b, d;
14519653cdaSPeter Brune   Vec            x_A, r_A;
14619653cdaSPeter Brune 
14719653cdaSPeter Brune   //previous iterations to construct the subspace
14819653cdaSPeter Brune   Vec            *rdot = ngmres->rdot;
14919653cdaSPeter Brune   Vec            *xdot = ngmres->xdot;
15019653cdaSPeter Brune 
15119653cdaSPeter Brune   //coefficients and RHS to the minimization problem
15219653cdaSPeter Brune   PetscScalar    *beta = ngmres->beta;
15319653cdaSPeter Brune   PetscScalar    *xi = ngmres->xi;
15419653cdaSPeter Brune   PetscReal      r_norm, r_A_norm;
15519653cdaSPeter Brune   PetscReal      nu;
15619653cdaSPeter Brune   PetscScalar    alph_total = 0.;
15719653cdaSPeter Brune   PetscScalar    qentry;
15819653cdaSPeter Brune   PetscInt       i, j, k, k_restart, l, ivec;
15919653cdaSPeter Brune 
16019653cdaSPeter Brune   //solution selection data
16119653cdaSPeter Brune   PetscBool selectA, selectRestart;
16219653cdaSPeter Brune   PetscReal d_norm, d_min_norm, d_cur_norm;
16319653cdaSPeter Brune   PetscReal r_min_norm;
16419653cdaSPeter Brune 
165a312c225SMatthew G Knepley   PetscErrorCode ierr;
166a312c225SMatthew G Knepley 
167a312c225SMatthew G Knepley   PetscFunctionBegin;
16819653cdaSPeter Brune   //variable initialization
169a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
17019653cdaSPeter Brune   x             = snes->vec_sol;
17119653cdaSPeter Brune   r             = snes->vec_func;
17219653cdaSPeter Brune   f             = snes->work[0];
17319653cdaSPeter Brune   b             = snes->vec_rhs;
17419653cdaSPeter Brune   x_A           = snes->vec_sol_update;
17519653cdaSPeter Brune   r_A           = snes->work[1];
17619653cdaSPeter Brune   d             = snes->work[2];
17719653cdaSPeter Brune   ierr = VecDuplicate(x,&r);CHKERRQ(ierr);
178a312c225SMatthew G Knepley 
1794a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &pc);CHKERRQ(ierr);
180a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
181a312c225SMatthew G Knepley   snes->iter = 0;
182a312c225SMatthew G Knepley   snes->norm = 0.;
183a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
18419653cdaSPeter Brune 
18519653cdaSPeter Brune   //initialization --
18619653cdaSPeter Brune 
18719653cdaSPeter Brune   //r = F(u)
18819653cdaSPeter Brune   ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);               /* r = F(x) */
189a312c225SMatthew G Knepley   if (snes->domainerror) {
190a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
191a312c225SMatthew G Knepley     PetscFunctionReturn(0);
192a312c225SMatthew G Knepley   }
19319653cdaSPeter Brune 
19419653cdaSPeter Brune   //nu = (r, r);
19519653cdaSPeter Brune   ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
19619653cdaSPeter Brune   r_min_norm = r_norm;
19719653cdaSPeter Brune   nu = r_norm*r_norm;
19819653cdaSPeter Brune   if (PetscIsInfOrNanReal(r_norm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
19919653cdaSPeter Brune 
20019653cdaSPeter Brune   //q_{11} = nu
20119653cdaSPeter Brune 
20219653cdaSPeter Brune   Q(0,0) = nu;
20319653cdaSPeter Brune   ngmres->r_norms[0] = r_norm;
20419653cdaSPeter Brune   //rdot[0] = r
20519653cdaSPeter Brune   ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
20619653cdaSPeter Brune   ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
207087dfb9eSxuemin 
208a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
20919653cdaSPeter Brune   snes->norm = r_norm;
210a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
21119653cdaSPeter Brune   SNESLogConvHistory(snes, r_norm, 0);
21219653cdaSPeter Brune   ierr = SNESMonitor(snes, 0, r_norm);CHKERRQ(ierr);
21319653cdaSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
214a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
215a312c225SMatthew G Knepley 
21619653cdaSPeter Brune   k_restart = 1;
21719653cdaSPeter Brune   l = 1;
21819653cdaSPeter Brune   for (k=1; k<snes->max_its; k++) {
219087dfb9eSxuemin 
22019653cdaSPeter Brune     //
221087dfb9eSxuemin 
22219653cdaSPeter Brune     //select which vector of the stored subspace will be updated
22319653cdaSPeter Brune     ivec = k_restart % ngmres->msize; //replace the last used part of the subspace
22419653cdaSPeter Brune 
22519653cdaSPeter Brune 
22619653cdaSPeter Brune     //Computation of x^M
22719653cdaSPeter Brune     ierr = SNESSolve(pc, b, x);CHKERRQ(ierr);
22819653cdaSPeter Brune    //r = F(x)
22919653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);
23019653cdaSPeter Brune     ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
23119653cdaSPeter Brune     //nu = (r, r)
23219653cdaSPeter Brune     ngmres->r_norms[ivec] = r_norm;
23319653cdaSPeter Brune     nu = r_norm*r_norm;
23419653cdaSPeter Brune     if (r_min_norm > r_norm) r_min_norm = r_norm;  //the minimum norm is now of r^M
23519653cdaSPeter Brune 
23619653cdaSPeter Brune     //construct the right hand side and xi factors
23719653cdaSPeter Brune     for (i = 0; i < l; i++) {
23819653cdaSPeter Brune       VecDot(rdot[i], r, &xi[i]);
23919653cdaSPeter Brune       beta[i] = nu - xi[i];
24019653cdaSPeter Brune     }
24119653cdaSPeter Brune 
24219653cdaSPeter Brune     //construct h
24319653cdaSPeter Brune     for (j = 0; j < l; j++) {
24419653cdaSPeter Brune       for (i = 0; i < l; i++) {
24519653cdaSPeter Brune 	H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
24619653cdaSPeter Brune       }
24719653cdaSPeter Brune     }
24819653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
24919653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2504a0c5b0cSMatthew G Knepley #else
25119653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
25219653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
25319653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
25419653cdaSPeter Brune     ngmres->rcond = -1.;
25519653cdaSPeter Brune     ngmres->nrhs = 1;
25619653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
25719653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
25819653cdaSPeter Brune 		 &ngmres->n,
25919653cdaSPeter Brune 		 &ngmres->nrhs,
26019653cdaSPeter Brune 		 ngmres->h,
26119653cdaSPeter Brune 		 &ngmres->lda,
26219653cdaSPeter Brune 		 ngmres->beta,
26319653cdaSPeter Brune 		 &ngmres->ldb,
26419653cdaSPeter Brune 		 ngmres->s,
26519653cdaSPeter Brune 		 &ngmres->rcond,
26619653cdaSPeter Brune 		 &ngmres->rank,
26719653cdaSPeter Brune 		 ngmres->work,
26819653cdaSPeter Brune 		 &ngmres->lwork,
26919653cdaSPeter Brune 		 ngmres->rwork,
27019653cdaSPeter Brune 		 &ngmres->info);
27119653cdaSPeter Brune #else
27219653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
27319653cdaSPeter Brune 		 &ngmres->n,
27419653cdaSPeter Brune 		 &ngmres->nrhs,
27519653cdaSPeter Brune 		 ngmres->h,
27619653cdaSPeter Brune 		 &ngmres->lda,
27719653cdaSPeter Brune 		 ngmres->beta,
27819653cdaSPeter Brune 		 &ngmres->ldb,
27919653cdaSPeter Brune 		 ngmres->s,
28019653cdaSPeter Brune 		 &ngmres->rcond,
28119653cdaSPeter Brune 		 &ngmres->rank,
28219653cdaSPeter Brune 		 ngmres->work,
28319653cdaSPeter Brune 		 &ngmres->lwork,
28419653cdaSPeter Brune 		 &ngmres->info);
28519653cdaSPeter Brune #endif
28619653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
28719653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
288a312c225SMatthew G Knepley #endif
289a312c225SMatthew G Knepley 
29019653cdaSPeter Brune     alph_total = 0.;
29119653cdaSPeter Brune     for (i = 0; i < l; i++) {
29219653cdaSPeter Brune       alph_total += beta[i];
293c0bbabecSxuemin     }
29419653cdaSPeter Brune     ierr = VecCopy(x, x_A);CHKERRQ(ierr);
29519653cdaSPeter Brune     ierr = VecScale(x_A, 1. - alph_total);CHKERRQ(ierr);
296087dfb9eSxuemin 
29719653cdaSPeter Brune     for(i=0;i<l;i++){
29819653cdaSPeter Brune       ierr= VecAXPY(x_A, beta[i], xdot[i]);CHKERRQ(ierr);
29919653cdaSPeter Brune     }
30019653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x_A, r_A);CHKERRQ(ierr);
30119653cdaSPeter Brune     ierr = VecNorm(r_A, NORM_2, &r_A_norm);CHKERRQ(ierr);
30219653cdaSPeter Brune 
30319653cdaSPeter Brune     selectA = PETSC_TRUE;
30419653cdaSPeter Brune     //Conditions for choosing the accelerated answer --
30519653cdaSPeter Brune 
30619653cdaSPeter Brune     //Criterion A -- the norm of the function isn't increased above the minimum by too much
30719653cdaSPeter Brune     if (r_A_norm >= ngmres->gammaA*r_min_norm) {
30819653cdaSPeter Brune       selectA = PETSC_FALSE;
309a312c225SMatthew G Knepley     }
310087dfb9eSxuemin 
31119653cdaSPeter Brune     //Criterion B -- the choice of x^A isn't too close to some other choice
31219653cdaSPeter Brune     ierr=VecCopy(x_A,d);CHKERRQ(ierr);
31319653cdaSPeter Brune     ierr=VecAXPY(d,-1,x);CHKERRQ(ierr);
31419653cdaSPeter Brune     ierr=VecNorm(d,NORM_2,&d_norm);CHKERRQ(ierr);
31519653cdaSPeter Brune     d_min_norm=10000000;
31619653cdaSPeter Brune     for(i=0;i<l;i++) {
31719653cdaSPeter Brune       ierr=VecCopy(x_A,d);CHKERRQ(ierr);
31819653cdaSPeter Brune       ierr=VecAXPY(d,-1,xdot[i]);CHKERRQ(ierr);
31919653cdaSPeter Brune       ierr=VecNorm(d,NORM_2,&d_cur_norm);CHKERRQ(ierr);
32019653cdaSPeter Brune       if(d_cur_norm<d_min_norm) d_min_norm=d_cur_norm;
32119653cdaSPeter Brune     }
32219653cdaSPeter Brune     if (ngmres->epsilonB*d_norm<d_min_norm || sqrt(r_norm)<ngmres->deltaB*sqrt(r_min_norm)) {
32319653cdaSPeter Brune     } else {
32419653cdaSPeter Brune       selectA=PETSC_FALSE;
32519653cdaSPeter Brune     }
326211b2d39SPeter Brune 
327087dfb9eSxuemin 
32819653cdaSPeter Brune     if (selectA) {
32919653cdaSPeter Brune       if (ngmres->debug)
33019653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "picked r_A, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);
33119653cdaSPeter Brune       //copy it over
33219653cdaSPeter Brune       r_norm = r_A_norm;
33319653cdaSPeter Brune       nu = r_norm*r_norm;
33419653cdaSPeter Brune       ierr = VecCopy(r_A, r);CHKERRQ(ierr);
33519653cdaSPeter Brune       ierr = VecCopy(x_A, x);CHKERRQ(ierr);
33619653cdaSPeter Brune     } else {
33719653cdaSPeter Brune       if(ngmres->debug)
33819653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "picked r_M, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);
33919653cdaSPeter Brune     }
340211b2d39SPeter Brune 
34119653cdaSPeter Brune     selectRestart = PETSC_FALSE;
34219653cdaSPeter Brune 
34319653cdaSPeter Brune     //maximum iteration criterion
34419653cdaSPeter Brune     if (k_restart > ngmres->k_rmax) {
34519653cdaSPeter Brune       selectRestart = PETSC_TRUE;
34619653cdaSPeter Brune     }
34719653cdaSPeter Brune 
34819653cdaSPeter Brune     //difference stagnation restart
34919653cdaSPeter Brune     if 	((ngmres->epsilonB*d_norm > d_min_norm) &&
35019653cdaSPeter Brune 	 (sqrt(r_A_norm) > ngmres->deltaB*sqrt(r_min_norm))) {
35119653cdaSPeter Brune       if (ngmres->debug)
35219653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "difference restart: %e > %e\n", ngmres->epsilonB*d_norm, d_min_norm);
35319653cdaSPeter Brune       selectRestart = PETSC_TRUE;
35419653cdaSPeter Brune     }
35519653cdaSPeter Brune 
35619653cdaSPeter Brune     // residual stagnation restart
35719653cdaSPeter Brune     if (sqrt(r_A_norm) > ngmres->gammaC*sqrt(r_min_norm)) {
35819653cdaSPeter Brune       if (ngmres->debug)
35919653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "residual restart: %e > %e\n", sqrt(r_A_norm), ngmres->gammaC*sqrt(r_min_norm));
36019653cdaSPeter Brune       selectRestart = PETSC_TRUE;
36119653cdaSPeter Brune     }
36219653cdaSPeter Brune 
36319653cdaSPeter Brune     if (selectRestart) {
36419653cdaSPeter Brune       if (ngmres->debug)
36519653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "Restarted at iteration %d\n", k_restart);
36619653cdaSPeter Brune       k_restart = 1;
36719653cdaSPeter Brune       l = 1;
36819653cdaSPeter Brune       //q_{11} = nu
36919653cdaSPeter Brune       ngmres->r_norms[0] = r_norm;
37019653cdaSPeter Brune       nu = r_norm*r_norm;
37119653cdaSPeter Brune       Q(0,0) = nu;
37219653cdaSPeter Brune       //rdot[0] = r
37319653cdaSPeter Brune       ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
37419653cdaSPeter Brune       ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
37519653cdaSPeter Brune     } else {
37619653cdaSPeter Brune       //select the current size of the subspace
37719653cdaSPeter Brune       if (l < ngmres->msize) {
37819653cdaSPeter Brune 	l++;
37919653cdaSPeter Brune       }
38019653cdaSPeter Brune       k_restart++;
38119653cdaSPeter Brune       //place the current entry in the list of previous entries
38219653cdaSPeter Brune       ierr = VecCopy(r, rdot[ivec]);CHKERRQ(ierr);
38319653cdaSPeter Brune       ierr = VecCopy(x, xdot[ivec]);CHKERRQ(ierr);
38419653cdaSPeter Brune       ngmres->r_norms[ivec] = r_norm;
38519653cdaSPeter Brune       if (r_min_norm > r_norm) r_min_norm = r_norm;  //the minimum norm is now of r^A
38619653cdaSPeter Brune       for (i = 0; i < l; i++) {
38719653cdaSPeter Brune 	VecDot(r, rdot[i], &qentry);
38819653cdaSPeter Brune 	Q(i, ivec) = qentry;
38919653cdaSPeter Brune 	Q(ivec, i) = qentry;
39019653cdaSPeter Brune       }
39119653cdaSPeter Brune     }
39219653cdaSPeter Brune 
39319653cdaSPeter Brune     SNESLogConvHistory(snes, r_norm, k);
39419653cdaSPeter Brune     ierr = SNESMonitor(snes, k, r_norm);CHKERRQ(ierr);
39519653cdaSPeter Brune 
396087dfb9eSxuemin     snes->iter =k;
39719653cdaSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
398087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
399a312c225SMatthew G Knepley   }
400a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
401a312c225SMatthew G Knepley   PetscFunctionReturn(0);
402a312c225SMatthew G Knepley }
403a312c225SMatthew G Knepley 
404a312c225SMatthew G Knepley 
405a312c225SMatthew G Knepley 
406a312c225SMatthew G Knepley EXTERN_C_BEGIN
407a312c225SMatthew G Knepley #undef __FUNCT__
408a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
409a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
410a312c225SMatthew G Knepley {
411a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
412a312c225SMatthew G Knepley   PetscErrorCode ierr;
413a312c225SMatthew G Knepley 
414a312c225SMatthew G Knepley   PetscFunctionBegin;
415a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
416a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
417a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
418a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
419a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
420a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
421a312c225SMatthew G Knepley 
422a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
423a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
42419653cdaSPeter Brune   ngmres->msize = 10;
42519653cdaSPeter Brune   ngmres->debug = PETSC_FALSE;
42619653cdaSPeter Brune 
42719653cdaSPeter Brune   ngmres->gammaA = 2.;
42819653cdaSPeter Brune   ngmres->gammaC = 2.;
42919653cdaSPeter Brune   ngmres->deltaB = 0.99;
43019653cdaSPeter Brune   ngmres->epsilonB = 0.01;
43119653cdaSPeter Brune   ngmres->k_rmax = 100;
4324a0c5b0cSMatthew G Knepley 
4334a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &snes->pc);CHKERRQ(ierr);
434a312c225SMatthew G Knepley   PetscFunctionReturn(0);
435a312c225SMatthew G Knepley }
436a312c225SMatthew G Knepley EXTERN_C_END
437