xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 9261d27a1399e9c1f856dd2f45e8d4ae7c60f685)
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    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
1219653cdaSPeter Brune    SIAM Journal on Scientific Computing, 21(5), 2000.
1319653cdaSPeter Brune 
1419653cdaSPeter Brune .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
1519653cdaSPeter Brune M*/
16087dfb9eSxuemin 
17a312c225SMatthew G Knepley #undef __FUNCT__
18a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
19a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
20a312c225SMatthew G Knepley {
21a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
22a312c225SMatthew G Knepley   PetscErrorCode ierr;
23a312c225SMatthew G Knepley 
24a312c225SMatthew G Knepley   PetscFunctionBegin;
2519653cdaSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
2619653cdaSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->xdot);CHKERRQ(ierr);
27a312c225SMatthew G Knepley   PetscFunctionReturn(0);
28a312c225SMatthew G Knepley }
29a312c225SMatthew G Knepley 
30a312c225SMatthew G Knepley #undef __FUNCT__
31a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
32a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
33a312c225SMatthew G Knepley {
34a312c225SMatthew G Knepley   PetscErrorCode ierr;
35a312c225SMatthew G Knepley 
36a312c225SMatthew G Knepley   PetscFunctionBegin;
37a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
38a312c225SMatthew G Knepley   if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);}
3919653cdaSPeter Brune   if (snes->data) {
4019653cdaSPeter Brune     SNES_NGMRES * ngmres = (SNES_NGMRES *)snes->data;
41cac108bcSPeter Brune     ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->r_norms, ngmres->q);CHKERRQ(ierr);
4219653cdaSPeter Brune     ierr = PetscFree(ngmres->s);CHKERRQ(ierr);
4319653cdaSPeter Brune #if PETSC_USE_COMPLEX
4419653cdaSPeter Brune     ierr = PetscFree(ngmres->rwork);
4519653cdaSPeter Brune #endif
4619653cdaSPeter Brune     ierr = PetscFree(ngmres->work);
4719653cdaSPeter Brune   }
4819653cdaSPeter Brune   ierr = PetscFree(snes->data);
49a312c225SMatthew G Knepley   PetscFunctionReturn(0);
50a312c225SMatthew G Knepley }
51a312c225SMatthew G Knepley 
52a312c225SMatthew G Knepley #undef __FUNCT__
53a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
54a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
55a312c225SMatthew G Knepley {
56a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
5719653cdaSPeter Brune   PetscInt msize,hsize;
58a312c225SMatthew G Knepley   PetscErrorCode ierr;
59a312c225SMatthew G Knepley 
60a312c225SMatthew G Knepley   PetscFunctionBegin;
61087dfb9eSxuemin   msize         = ngmres->msize;  /* restart size */
6219653cdaSPeter Brune   hsize         = msize * msize;
63087dfb9eSxuemin 
64087dfb9eSxuemin 
6598b3e84cSPeter Brune   /* explicit least squares minimization solve */
6619653cdaSPeter Brune   ierr = PetscMalloc5(hsize,PetscScalar,&ngmres->h,
6719653cdaSPeter Brune 		      msize,PetscScalar,&ngmres->beta,
6819653cdaSPeter Brune 		      msize,PetscScalar,&ngmres->xi,
6919653cdaSPeter Brune 		      msize,PetscReal,&ngmres->r_norms,
7019653cdaSPeter Brune 		      hsize,PetscScalar,&ngmres->q);CHKERRQ(ierr);
7119653cdaSPeter Brune   ngmres->nrhs = 1;
7219653cdaSPeter Brune   ngmres->lda = msize;
7319653cdaSPeter Brune   ngmres->ldb = msize;
7419653cdaSPeter Brune   ierr = PetscMalloc(msize*sizeof(PetscScalar),&ngmres->s);CHKERRQ(ierr);
75087dfb9eSxuemin 
7619653cdaSPeter Brune   ierr = PetscMemzero(ngmres->h,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7719653cdaSPeter Brune   ierr = PetscMemzero(ngmres->q,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
7819653cdaSPeter Brune   ierr = PetscMemzero(ngmres->xi,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7919653cdaSPeter Brune   ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
80211b2d39SPeter Brune 
8119653cdaSPeter Brune   ngmres->lwork = 12*msize;
8219653cdaSPeter Brune #if PETSC_USE_COMPLEX
8319653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
8419653cdaSPeter Brune #endif
8519653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
86211b2d39SPeter Brune 
8719653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->xdot);CHKERRQ(ierr);
8819653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
89211b2d39SPeter Brune   ierr = SNESDefaultGetWork(snes, 3);CHKERRQ(ierr);
90a312c225SMatthew G Knepley   PetscFunctionReturn(0);
91a312c225SMatthew G Knepley }
92a312c225SMatthew G Knepley 
93a312c225SMatthew G Knepley #undef __FUNCT__
94a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
95a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
96a312c225SMatthew G Knepley {
97a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
98a312c225SMatthew G Knepley   PetscErrorCode ierr;
99a312c225SMatthew G Knepley 
100a312c225SMatthew G Knepley   PetscFunctionBegin;
101a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
10219653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
10319653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart", "Maximum iterations before restart.", "SNES", ngmres->k_rmax, &ngmres->k_rmax, PETSC_NULL);CHKERRQ(ierr);
10419653cdaSPeter Brune   ierr = PetscOptionsBool("-snes_ngmres_debug", "Debugging output for NGMRES", "SNES", ngmres->debug, &ngmres->debug, PETSC_NULL);CHKERRQ(ierr);
1056a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
1066a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
1076a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
1086a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
109a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1106a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
111a312c225SMatthew G Knepley   PetscFunctionReturn(0);
112a312c225SMatthew G Knepley }
113a312c225SMatthew G Knepley 
114a312c225SMatthew G Knepley #undef __FUNCT__
115a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
116a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
117a312c225SMatthew G Knepley {
118a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
119a312c225SMatthew G Knepley   PetscBool      iascii;
120a312c225SMatthew G Knepley   PetscErrorCode ierr;
121a312c225SMatthew G Knepley 
122a312c225SMatthew G Knepley   PetscFunctionBegin;
123a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
124a312c225SMatthew G Knepley   if (iascii) {
125a312c225SMatthew G Knepley     ierr = PetscViewerASCIIPrintf(viewer, "  Size of space %d\n", ngmres->msize);CHKERRQ(ierr);
126cac108bcSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Maximum iterations before restart %d\n", ngmres->k_rmax);CHKERRQ(ierr);
127a312c225SMatthew G Knepley   }
128a312c225SMatthew G Knepley   PetscFunctionReturn(0);
129a312c225SMatthew G Knepley }
130a312c225SMatthew G Knepley 
13119653cdaSPeter Brune 
132a312c225SMatthew G Knepley #undef __FUNCT__
133a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
134211b2d39SPeter Brune 
135a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
136a312c225SMatthew G Knepley {
1374a0c5b0cSMatthew G Knepley   SNES           pc;
138087dfb9eSxuemin   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
13919653cdaSPeter Brune 
14019653cdaSPeter Brune 
14119653cdaSPeter Brune 
14298b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
14319653cdaSPeter Brune   Vec            x, r, f, b, d;
14419653cdaSPeter Brune   Vec            x_A, r_A;
14519653cdaSPeter Brune 
14698b3e84cSPeter Brune   /* previous iterations to construct the subspace */
14719653cdaSPeter Brune   Vec            *rdot = ngmres->rdot;
14819653cdaSPeter Brune   Vec            *xdot = ngmres->xdot;
14919653cdaSPeter Brune 
15098b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
15119653cdaSPeter Brune   PetscScalar    *beta = ngmres->beta;
15219653cdaSPeter Brune   PetscScalar    *xi = ngmres->xi;
15319653cdaSPeter Brune   PetscReal      r_norm, r_A_norm;
15419653cdaSPeter Brune   PetscReal      nu;
15519653cdaSPeter Brune   PetscScalar    alph_total = 0.;
15619653cdaSPeter Brune   PetscScalar    qentry;
15719653cdaSPeter Brune   PetscInt       i, j, k, k_restart, l, ivec;
15819653cdaSPeter Brune 
15998b3e84cSPeter Brune   /* solution selection data */
16019653cdaSPeter Brune   PetscBool selectA, selectRestart;
16119653cdaSPeter Brune   PetscReal d_norm, d_min_norm, d_cur_norm;
16219653cdaSPeter Brune   PetscReal r_min_norm;
16319653cdaSPeter Brune 
164a312c225SMatthew G Knepley   PetscErrorCode ierr;
165a312c225SMatthew G Knepley 
166a312c225SMatthew G Knepley   PetscFunctionBegin;
16798b3e84cSPeter Brune   /* variable initialization */
168a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
16919653cdaSPeter Brune   x             = snes->vec_sol;
17019653cdaSPeter Brune   r             = snes->vec_func;
17119653cdaSPeter Brune   f             = snes->work[0];
17219653cdaSPeter Brune   b             = snes->vec_rhs;
17319653cdaSPeter Brune   x_A           = snes->vec_sol_update;
17419653cdaSPeter Brune   r_A           = snes->work[1];
17519653cdaSPeter Brune   d             = snes->work[2];
17619653cdaSPeter Brune   ierr = VecDuplicate(x,&r);CHKERRQ(ierr);
177a312c225SMatthew G Knepley 
1784a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &pc);CHKERRQ(ierr);
179a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
180a312c225SMatthew G Knepley   snes->iter = 0;
181a312c225SMatthew G Knepley   snes->norm = 0.;
182a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
18319653cdaSPeter Brune 
18498b3e84cSPeter Brune   /* initialization */
18519653cdaSPeter Brune 
18698b3e84cSPeter Brune   /* r = F(x) */
18798b3e84cSPeter Brune   ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);
188a312c225SMatthew G Knepley   if (snes->domainerror) {
189a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
190a312c225SMatthew G Knepley     PetscFunctionReturn(0);
191a312c225SMatthew G Knepley   }
19219653cdaSPeter Brune 
19398b3e84cSPeter Brune   /* nu = (r, r) */
19419653cdaSPeter Brune   ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
19519653cdaSPeter Brune   r_min_norm = r_norm;
19619653cdaSPeter Brune   nu = r_norm*r_norm;
19719653cdaSPeter Brune   if (PetscIsInfOrNanReal(r_norm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
19819653cdaSPeter Brune 
19998b3e84cSPeter Brune   /* q_{00} = nu  */
20019653cdaSPeter Brune   Q(0,0) = nu;
20119653cdaSPeter Brune   ngmres->r_norms[0] = r_norm;
20298b3e84cSPeter Brune   /* rdot[0] = r */
20319653cdaSPeter Brune   ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
20419653cdaSPeter Brune   ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
205087dfb9eSxuemin 
206a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
20719653cdaSPeter Brune   snes->norm = r_norm;
208a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
20919653cdaSPeter Brune   SNESLogConvHistory(snes, r_norm, 0);
21019653cdaSPeter Brune   ierr = SNESMonitor(snes, 0, r_norm);CHKERRQ(ierr);
21119653cdaSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
212a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
213a312c225SMatthew G Knepley 
21419653cdaSPeter Brune   k_restart = 1;
21519653cdaSPeter Brune   l = 1;
21619653cdaSPeter Brune   for (k=1; k<snes->max_its; k++) {
217087dfb9eSxuemin 
21898b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
21998b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
22019653cdaSPeter Brune 
22119653cdaSPeter Brune 
22298b3e84cSPeter Brune     /* Computation of x^M */
22319653cdaSPeter Brune     ierr = SNESSolve(pc, b, x);CHKERRQ(ierr);
22498b3e84cSPeter Brune     /* r = F(x) */
22519653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);
22619653cdaSPeter Brune     ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
22798b3e84cSPeter Brune     /* nu = (r, r) */
22819653cdaSPeter Brune     ngmres->r_norms[ivec] = r_norm;
22919653cdaSPeter Brune     nu = r_norm*r_norm;
23098b3e84cSPeter Brune     if (r_min_norm > r_norm) r_min_norm = r_norm;  /* the minimum norm is now of r^M */
23119653cdaSPeter Brune 
23298b3e84cSPeter Brune     /* construct the right hand side and xi factors */
23319653cdaSPeter Brune     for (i = 0; i < l; i++) {
23419653cdaSPeter Brune       VecDot(rdot[i], r, &xi[i]);
23519653cdaSPeter Brune       beta[i] = nu - xi[i];
23619653cdaSPeter Brune     }
23719653cdaSPeter Brune 
23898b3e84cSPeter Brune     /* construct h */
23919653cdaSPeter Brune     for (j = 0; j < l; j++) {
24019653cdaSPeter Brune       for (i = 0; i < l; i++) {
24119653cdaSPeter Brune 	H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
24219653cdaSPeter Brune       }
24319653cdaSPeter Brune     }
24419653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
24519653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2464a0c5b0cSMatthew G Knepley #else
24719653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
24819653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
24919653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
25019653cdaSPeter Brune     ngmres->rcond = -1.;
25119653cdaSPeter Brune     ngmres->nrhs = 1;
25219653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
25319653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
25419653cdaSPeter Brune 		 &ngmres->n,
25519653cdaSPeter Brune 		 &ngmres->nrhs,
25619653cdaSPeter Brune 		 ngmres->h,
25719653cdaSPeter Brune 		 &ngmres->lda,
25819653cdaSPeter Brune 		 ngmres->beta,
25919653cdaSPeter Brune 		 &ngmres->ldb,
26019653cdaSPeter Brune 		 ngmres->s,
26119653cdaSPeter Brune 		 &ngmres->rcond,
26219653cdaSPeter Brune 		 &ngmres->rank,
26319653cdaSPeter Brune 		 ngmres->work,
26419653cdaSPeter Brune 		 &ngmres->lwork,
26519653cdaSPeter Brune 		 ngmres->rwork,
26619653cdaSPeter Brune 		 &ngmres->info);
26719653cdaSPeter Brune #else
26819653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
26919653cdaSPeter Brune 		 &ngmres->n,
27019653cdaSPeter Brune 		 &ngmres->nrhs,
27119653cdaSPeter Brune 		 ngmres->h,
27219653cdaSPeter Brune 		 &ngmres->lda,
27319653cdaSPeter Brune 		 ngmres->beta,
27419653cdaSPeter Brune 		 &ngmres->ldb,
27519653cdaSPeter Brune 		 ngmres->s,
27619653cdaSPeter Brune 		 &ngmres->rcond,
27719653cdaSPeter Brune 		 &ngmres->rank,
27819653cdaSPeter Brune 		 ngmres->work,
27919653cdaSPeter Brune 		 &ngmres->lwork,
28019653cdaSPeter Brune 		 &ngmres->info);
28119653cdaSPeter Brune #endif
28219653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
28319653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
284a312c225SMatthew G Knepley #endif
285a312c225SMatthew G Knepley 
28619653cdaSPeter Brune     alph_total = 0.;
28719653cdaSPeter Brune     for (i = 0; i < l; i++) {
28819653cdaSPeter Brune       alph_total += beta[i];
289c0bbabecSxuemin     }
29019653cdaSPeter Brune     ierr = VecCopy(x, x_A);CHKERRQ(ierr);
29119653cdaSPeter Brune     ierr = VecScale(x_A, 1. - alph_total);CHKERRQ(ierr);
292087dfb9eSxuemin 
29319653cdaSPeter Brune     for(i=0;i<l;i++){
29419653cdaSPeter Brune       ierr= VecAXPY(x_A, beta[i], xdot[i]);CHKERRQ(ierr);
29519653cdaSPeter Brune     }
29619653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x_A, r_A);CHKERRQ(ierr);
29719653cdaSPeter Brune     ierr = VecNorm(r_A, NORM_2, &r_A_norm);CHKERRQ(ierr);
29819653cdaSPeter Brune 
29919653cdaSPeter Brune     selectA = PETSC_TRUE;
30098b3e84cSPeter Brune     /* Conditions for choosing the accelerated answer */
30119653cdaSPeter Brune 
30298b3e84cSPeter Brune     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
30319653cdaSPeter Brune     if (r_A_norm >= ngmres->gammaA*r_min_norm) {
30419653cdaSPeter Brune       selectA = PETSC_FALSE;
305a312c225SMatthew G Knepley     }
306087dfb9eSxuemin 
30798b3e84cSPeter Brune     /* Criterion B -- the choice of x^A isn't too close to some other choice */
30819653cdaSPeter Brune     ierr=VecCopy(x_A,d);CHKERRQ(ierr);
30919653cdaSPeter Brune     ierr=VecAXPY(d,-1,x);CHKERRQ(ierr);
31019653cdaSPeter Brune     ierr=VecNorm(d,NORM_2,&d_norm);CHKERRQ(ierr);
311*9261d27aSPeter Brune     d_min_norm = -1.0;
31219653cdaSPeter Brune     for(i=0;i<l;i++) {
31319653cdaSPeter Brune       ierr=VecCopy(x_A,d);CHKERRQ(ierr);
31419653cdaSPeter Brune       ierr=VecAXPY(d,-1,xdot[i]);CHKERRQ(ierr);
31519653cdaSPeter Brune       ierr=VecNorm(d,NORM_2,&d_cur_norm);CHKERRQ(ierr);
316*9261d27aSPeter Brune       if((d_cur_norm < d_min_norm) || (d_min_norm < 0.0)) d_min_norm = d_cur_norm;
31719653cdaSPeter Brune     }
31819653cdaSPeter Brune     if (ngmres->epsilonB*d_norm<d_min_norm || sqrt(r_norm)<ngmres->deltaB*sqrt(r_min_norm)) {
31919653cdaSPeter Brune     } else {
32019653cdaSPeter Brune       selectA=PETSC_FALSE;
32119653cdaSPeter Brune     }
322211b2d39SPeter Brune 
323087dfb9eSxuemin 
32419653cdaSPeter Brune     if (selectA) {
32519653cdaSPeter Brune       if (ngmres->debug)
32619653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "picked r_A, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);
32798b3e84cSPeter Brune       /* copy it over */
32819653cdaSPeter Brune       r_norm = r_A_norm;
32919653cdaSPeter Brune       nu = r_norm*r_norm;
33019653cdaSPeter Brune       ierr = VecCopy(r_A, r);CHKERRQ(ierr);
33119653cdaSPeter Brune       ierr = VecCopy(x_A, x);CHKERRQ(ierr);
33219653cdaSPeter Brune     } else {
33319653cdaSPeter Brune       if(ngmres->debug)
33419653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "picked r_M, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);
33519653cdaSPeter Brune     }
336211b2d39SPeter Brune 
33719653cdaSPeter Brune     selectRestart = PETSC_FALSE;
33819653cdaSPeter Brune 
33998b3e84cSPeter Brune     /* maximum iteration criterion */
34019653cdaSPeter Brune     if (k_restart > ngmres->k_rmax) {
34119653cdaSPeter Brune       selectRestart = PETSC_TRUE;
34219653cdaSPeter Brune     }
34319653cdaSPeter Brune 
34498b3e84cSPeter Brune     /* difference stagnation restart */
34519653cdaSPeter Brune     if 	((ngmres->epsilonB*d_norm > d_min_norm) &&
34619653cdaSPeter Brune 	 (sqrt(r_A_norm) > ngmres->deltaB*sqrt(r_min_norm))) {
34719653cdaSPeter Brune       if (ngmres->debug)
34819653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "difference restart: %e > %e\n", ngmres->epsilonB*d_norm, d_min_norm);
34919653cdaSPeter Brune       selectRestart = PETSC_TRUE;
35019653cdaSPeter Brune     }
35119653cdaSPeter Brune 
35298b3e84cSPeter Brune     /* residual stagnation restart */
35319653cdaSPeter Brune     if (sqrt(r_A_norm) > ngmres->gammaC*sqrt(r_min_norm)) {
35419653cdaSPeter Brune       if (ngmres->debug)
35519653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "residual restart: %e > %e\n", sqrt(r_A_norm), ngmres->gammaC*sqrt(r_min_norm));
35619653cdaSPeter Brune       selectRestart = PETSC_TRUE;
35719653cdaSPeter Brune     }
35819653cdaSPeter Brune 
35919653cdaSPeter Brune     if (selectRestart) {
36019653cdaSPeter Brune       if (ngmres->debug)
36119653cdaSPeter Brune 	PetscPrintf(PETSC_COMM_WORLD, "Restarted at iteration %d\n", k_restart);
36219653cdaSPeter Brune       k_restart = 1;
36319653cdaSPeter Brune       l = 1;
36498b3e84cSPeter Brune       /* q_{00} = nu */
36519653cdaSPeter Brune       ngmres->r_norms[0] = r_norm;
36619653cdaSPeter Brune       nu = r_norm*r_norm;
36719653cdaSPeter Brune       Q(0,0) = nu;
36898b3e84cSPeter Brune       /* rdot[0] = r */
36919653cdaSPeter Brune       ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
37019653cdaSPeter Brune       ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
37119653cdaSPeter Brune     } else {
37298b3e84cSPeter Brune       /* select the current size of the subspace */
37319653cdaSPeter Brune       if (l < ngmres->msize) {
37419653cdaSPeter Brune 	l++;
37519653cdaSPeter Brune       }
37619653cdaSPeter Brune       k_restart++;
37798b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
37819653cdaSPeter Brune       ierr = VecCopy(r, rdot[ivec]);CHKERRQ(ierr);
37919653cdaSPeter Brune       ierr = VecCopy(x, xdot[ivec]);CHKERRQ(ierr);
38019653cdaSPeter Brune       ngmres->r_norms[ivec] = r_norm;
38198b3e84cSPeter Brune       if (r_min_norm > r_norm) r_min_norm = r_norm;  /* the minimum norm is now of r^A */
38219653cdaSPeter Brune       for (i = 0; i < l; i++) {
38319653cdaSPeter Brune 	VecDot(r, rdot[i], &qentry);
38419653cdaSPeter Brune 	Q(i, ivec) = qentry;
38519653cdaSPeter Brune 	Q(ivec, i) = qentry;
38619653cdaSPeter Brune       }
38719653cdaSPeter Brune     }
38819653cdaSPeter Brune 
38919653cdaSPeter Brune     SNESLogConvHistory(snes, r_norm, k);
39019653cdaSPeter Brune     ierr = SNESMonitor(snes, k, r_norm);CHKERRQ(ierr);
39119653cdaSPeter Brune 
392087dfb9eSxuemin     snes->iter =k;
39319653cdaSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
394087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
395a312c225SMatthew G Knepley   }
396a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
397a312c225SMatthew G Knepley   PetscFunctionReturn(0);
398a312c225SMatthew G Knepley }
399a312c225SMatthew G Knepley 
400a312c225SMatthew G Knepley 
401a312c225SMatthew G Knepley 
402a312c225SMatthew G Knepley EXTERN_C_BEGIN
403a312c225SMatthew G Knepley #undef __FUNCT__
404a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
405a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
406a312c225SMatthew G Knepley {
407a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
408a312c225SMatthew G Knepley   PetscErrorCode ierr;
409a312c225SMatthew G Knepley 
410a312c225SMatthew G Knepley   PetscFunctionBegin;
411a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
412a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
413a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
414a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
415a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
416a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
417a312c225SMatthew G Knepley 
418a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
419a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
42019653cdaSPeter Brune   ngmres->msize = 10;
42119653cdaSPeter Brune   ngmres->debug = PETSC_FALSE;
42219653cdaSPeter Brune 
42319653cdaSPeter Brune   ngmres->gammaA = 2.;
42419653cdaSPeter Brune   ngmres->gammaC = 2.;
425cac108bcSPeter Brune   ngmres->deltaB = 0.9;
426cac108bcSPeter Brune   ngmres->epsilonB = 0.1;
427cac108bcSPeter Brune   ngmres->k_rmax = 200;
4284a0c5b0cSMatthew G Knepley 
4294a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &snes->pc);CHKERRQ(ierr);
430a312c225SMatthew G Knepley   PetscFunctionReturn(0);
431a312c225SMatthew G Knepley }
432a312c225SMatthew G Knepley EXTERN_C_END
433