xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 42f4f86d694fb53cb4294575ec6d71954f75b2e7)
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;
1619653cdaSPeter Brune   ierr = VecDestroyVecs(ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
1719653cdaSPeter 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;
32cac108bcSPeter Brune     ierr = PetscFree5(ngmres->h, ngmres->beta, ngmres->xi, ngmres->r_norms, 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,
6019653cdaSPeter Brune 		      msize,PetscReal,&ngmres->r_norms,
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);
66087dfb9eSxuemin 
6719653cdaSPeter Brune   ierr = PetscMemzero(ngmres->h,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6819653cdaSPeter Brune   ierr = PetscMemzero(ngmres->q,hsize*sizeof(PetscScalar));CHKERRQ(ierr);
6919653cdaSPeter Brune   ierr = PetscMemzero(ngmres->xi,msize*sizeof(PetscScalar));CHKERRQ(ierr);
7019653cdaSPeter Brune   ierr = PetscMemzero(ngmres->beta,msize*sizeof(PetscScalar));CHKERRQ(ierr);
71211b2d39SPeter Brune 
7219653cdaSPeter Brune   ngmres->lwork = 12*msize;
7319653cdaSPeter Brune #if PETSC_USE_COMPLEX
7419653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscReal)*ngmres->lwork,&ngmres->rwork);
7519653cdaSPeter Brune #endif
7619653cdaSPeter Brune   ierr = PetscMalloc(sizeof(PetscScalar)*ngmres->lwork,&ngmres->work);
77211b2d39SPeter Brune 
7819653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->xdot);CHKERRQ(ierr);
7919653cdaSPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->rdot);CHKERRQ(ierr);
80732c72c5SBarry Smith   ierr = SNESDefaultGetWork(snes, 3);CHKERRQ(ierr);
81a312c225SMatthew G Knepley   PetscFunctionReturn(0);
82a312c225SMatthew G Knepley }
83a312c225SMatthew G Knepley 
84a312c225SMatthew G Knepley #undef __FUNCT__
85a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
86a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
87a312c225SMatthew G Knepley {
88a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
89a312c225SMatthew G Knepley   PetscErrorCode ierr;
90dfbf837cSBarry Smith   PetscBool      debug;
91a312c225SMatthew G Knepley 
92a312c225SMatthew G Knepley   PetscFunctionBegin;
93a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
9419653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
9519653cdaSPeter Brune   ierr = PetscOptionsInt("-snes_ngmres_restart", "Maximum iterations before restart.", "SNES", ngmres->k_rmax, &ngmres->k_rmax, PETSC_NULL);CHKERRQ(ierr);
96dfbf837cSBarry Smith   ierr = PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE: PETSC_FALSE, &debug, PETSC_NULL);CHKERRQ(ierr);
97dfbf837cSBarry Smith   if (debug) {
98dfbf837cSBarry Smith     ngmres->monitor = PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);CHKERRQ(ierr);
99dfbf837cSBarry Smith   }
1006a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, PETSC_NULL);CHKERRQ(ierr);
1016a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, PETSC_NULL);CHKERRQ(ierr);
1026a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, PETSC_NULL);CHKERRQ(ierr);
1036a7cf640SPeter Brune   ierr = PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, PETSC_NULL);CHKERRQ(ierr);
104a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1056a7cf640SPeter Brune   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
106a312c225SMatthew G Knepley   PetscFunctionReturn(0);
107a312c225SMatthew G Knepley }
108a312c225SMatthew G Knepley 
109a312c225SMatthew G Knepley #undef __FUNCT__
110a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
111a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
112a312c225SMatthew G Knepley {
113a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
114a312c225SMatthew G Knepley   PetscBool      iascii;
115a312c225SMatthew G Knepley   PetscErrorCode ierr;
116a312c225SMatthew G Knepley 
117a312c225SMatthew G Knepley   PetscFunctionBegin;
118a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
119a312c225SMatthew G Knepley   if (iascii) {
120a312c225SMatthew G Knepley     ierr = PetscViewerASCIIPrintf(viewer, "  Size of space %d\n", ngmres->msize);CHKERRQ(ierr);
121cac108bcSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer, "  Maximum iterations before restart %d\n", ngmres->k_rmax);CHKERRQ(ierr);
122a312c225SMatthew G Knepley   }
123a312c225SMatthew G Knepley   PetscFunctionReturn(0);
124a312c225SMatthew G Knepley }
125a312c225SMatthew G Knepley 
12619653cdaSPeter Brune 
127a312c225SMatthew G Knepley #undef __FUNCT__
128a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
129211b2d39SPeter Brune 
130a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
131a312c225SMatthew G Knepley {
1324a0c5b0cSMatthew G Knepley   SNES               pc;
133087dfb9eSxuemin   SNES_NGMRES        *ngmres = (SNES_NGMRES *) snes->data;
13419653cdaSPeter Brune 
13598b3e84cSPeter Brune   /* present solution, residual, and preconditioned residual */
136c878e8e6SPeter Brune   Vec                 x, r, b, d;
13719653cdaSPeter Brune   Vec                 x_A, r_A;
13819653cdaSPeter Brune 
13998b3e84cSPeter Brune   /* previous iterations to construct the subspace */
14019653cdaSPeter Brune   Vec                 *rdot = ngmres->rdot;
14119653cdaSPeter Brune   Vec                 *xdot = ngmres->xdot;
14219653cdaSPeter Brune 
14398b3e84cSPeter Brune   /* coefficients and RHS to the minimization problem */
14419653cdaSPeter Brune   PetscScalar         *beta = ngmres->beta;
14519653cdaSPeter Brune   PetscScalar         *xi = ngmres->xi;
14619653cdaSPeter Brune   PetscReal           r_norm, r_A_norm;
14719653cdaSPeter Brune   PetscReal           nu;
14819653cdaSPeter Brune   PetscScalar         alph_total = 0.;
14919653cdaSPeter Brune   PetscScalar         qentry;
15019653cdaSPeter Brune   PetscInt            i, j, k, k_restart, l, ivec;
15119653cdaSPeter Brune 
15298b3e84cSPeter Brune   /* solution selection data */
15319653cdaSPeter Brune   PetscBool           selectA, selectRestart;
15419653cdaSPeter Brune   PetscReal           d_norm, d_min_norm, d_cur_norm;
15519653cdaSPeter Brune   PetscReal           r_min_norm;
15619653cdaSPeter Brune 
1571e633543SBarry Smith   SNESConvergedReason reason;
158a312c225SMatthew G Knepley   PetscErrorCode      ierr;
159a312c225SMatthew G Knepley 
160a312c225SMatthew G Knepley   PetscFunctionBegin;
16198b3e84cSPeter Brune   /* variable initialization */
162a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
16319653cdaSPeter Brune   x             = snes->vec_sol;
16419653cdaSPeter Brune   r             = snes->vec_func;
16519653cdaSPeter Brune   b             = snes->vec_rhs;
16619653cdaSPeter Brune   x_A           = snes->vec_sol_update;
167c878e8e6SPeter Brune   r_A           = snes->work[0];
168c878e8e6SPeter Brune   d             = snes->work[1];
169732c72c5SBarry Smith   r             = snes->work[2];
170a312c225SMatthew G Knepley 
1714a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &pc);CHKERRQ(ierr);
172a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
173a312c225SMatthew G Knepley   snes->iter = 0;
174a312c225SMatthew G Knepley   snes->norm = 0.;
175a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
17619653cdaSPeter Brune 
17798b3e84cSPeter Brune   /* initialization */
17819653cdaSPeter Brune 
17998b3e84cSPeter Brune   /* r = F(x) */
18098b3e84cSPeter Brune   ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);
181a312c225SMatthew G Knepley   if (snes->domainerror) {
182a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
183a312c225SMatthew G Knepley     PetscFunctionReturn(0);
184a312c225SMatthew G Knepley   }
18519653cdaSPeter Brune 
18698b3e84cSPeter Brune   /* nu = (r, r) */
18719653cdaSPeter Brune   ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
18819653cdaSPeter Brune   r_min_norm = r_norm;
18919653cdaSPeter Brune   nu = r_norm*r_norm;
190dfbf837cSBarry Smith   if (PetscIsInfOrNanReal(r_norm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in function evaluation");
19119653cdaSPeter Brune 
19298b3e84cSPeter Brune   /* q_{00} = nu  */
19319653cdaSPeter Brune   Q(0,0) = nu;
19419653cdaSPeter Brune   ngmres->r_norms[0] = r_norm;
19598b3e84cSPeter Brune   /* rdot[0] = r */
19619653cdaSPeter Brune   ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
19719653cdaSPeter Brune   ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
198087dfb9eSxuemin 
199a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
20019653cdaSPeter Brune   snes->norm = r_norm;
201a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
20219653cdaSPeter Brune   SNESLogConvHistory(snes, r_norm, 0);
20319653cdaSPeter Brune   ierr = SNESMonitor(snes, 0, r_norm);CHKERRQ(ierr);
20419653cdaSPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
205a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
206a312c225SMatthew G Knepley 
20719653cdaSPeter Brune   k_restart = 1;
20819653cdaSPeter Brune   l = 1;
20919653cdaSPeter Brune   for (k=1; k<snes->max_its; k++) {
210087dfb9eSxuemin 
21198b3e84cSPeter Brune     /* select which vector of the stored subspace will be updated */
21298b3e84cSPeter Brune     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
21319653cdaSPeter Brune 
21498b3e84cSPeter Brune     /* Computation of x^M */
21519653cdaSPeter Brune     ierr = SNESSolve(pc, b, x);CHKERRQ(ierr);
2161e633543SBarry Smith     ierr = SNESGetConvergedReason(pc,&reason);CHKERRQ(ierr);
2171e633543SBarry Smith     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
2181e633543SBarry Smith       snes->reason = SNES_DIVERGED_INNER;
2191e633543SBarry Smith       PetscFunctionReturn(0);
2201e633543SBarry Smith     }
2211e633543SBarry Smith 
22298b3e84cSPeter Brune     /* r = F(x) */
22319653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x, r);CHKERRQ(ierr);
22419653cdaSPeter Brune     ierr = VecNorm(r, NORM_2, &r_norm);CHKERRQ(ierr);
22598b3e84cSPeter Brune     /* nu = (r, r) */
22619653cdaSPeter Brune     ngmres->r_norms[ivec] = r_norm;
22719653cdaSPeter Brune     nu = r_norm*r_norm;
22898b3e84cSPeter Brune     if (r_min_norm > r_norm) r_min_norm = r_norm;  /* the minimum norm is now of r^M */
22919653cdaSPeter Brune 
23098b3e84cSPeter Brune     /* construct the right hand side and xi factors */
23119653cdaSPeter Brune     for (i = 0; i < l; i++) {
2321e633543SBarry Smith       ierr = VecDot(rdot[i], r, &xi[i]);CHKERRQ(ierr);
23319653cdaSPeter Brune       beta[i] = nu - xi[i];
23419653cdaSPeter Brune     }
23519653cdaSPeter Brune 
23698b3e84cSPeter Brune     /* construct h */
23719653cdaSPeter Brune     for (j = 0; j < l; j++) {
23819653cdaSPeter Brune       for (i = 0; i < l; i++) {
23919653cdaSPeter Brune 	H(i, j) = Q(i, j) - xi[i] - xi[j] + nu;
24019653cdaSPeter Brune       }
24119653cdaSPeter Brune     }
24219653cdaSPeter Brune #ifdef PETSC_MISSING_LAPACK_GELSS
24319653cdaSPeter Brune     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "NGMRES with LS requires the LAPACK GELSS routine.");
2444a0c5b0cSMatthew G Knepley #else
24519653cdaSPeter Brune     ngmres->m = PetscBLASIntCast(l);
24619653cdaSPeter Brune     ngmres->n = PetscBLASIntCast(l);
24719653cdaSPeter Brune     ngmres->info = PetscBLASIntCast(0);
24819653cdaSPeter Brune     ngmres->rcond = -1.;
24919653cdaSPeter Brune #ifdef PETSC_USE_COMPLEX
25019653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
25119653cdaSPeter Brune 		 &ngmres->n,
25219653cdaSPeter Brune 		 &ngmres->nrhs,
25319653cdaSPeter Brune 		 ngmres->h,
25419653cdaSPeter Brune 		 &ngmres->lda,
25519653cdaSPeter Brune 		 ngmres->beta,
25619653cdaSPeter Brune 		 &ngmres->ldb,
25719653cdaSPeter Brune 		 ngmres->s,
25819653cdaSPeter Brune 		 &ngmres->rcond,
25919653cdaSPeter Brune 		 &ngmres->rank,
26019653cdaSPeter Brune 		 ngmres->work,
26119653cdaSPeter Brune 		 &ngmres->lwork,
26219653cdaSPeter Brune 		 ngmres->rwork,
26319653cdaSPeter Brune 		 &ngmres->info);
26419653cdaSPeter Brune #else
26519653cdaSPeter Brune     LAPACKgelss_(&ngmres->m,
26619653cdaSPeter Brune 		 &ngmres->n,
26719653cdaSPeter Brune 		 &ngmres->nrhs,
26819653cdaSPeter Brune 		 ngmres->h,
26919653cdaSPeter Brune 		 &ngmres->lda,
27019653cdaSPeter Brune 		 ngmres->beta,
27119653cdaSPeter Brune 		 &ngmres->ldb,
27219653cdaSPeter Brune 		 ngmres->s,
27319653cdaSPeter Brune 		 &ngmres->rcond,
27419653cdaSPeter Brune 		 &ngmres->rank,
27519653cdaSPeter Brune 		 ngmres->work,
27619653cdaSPeter Brune 		 &ngmres->lwork,
27719653cdaSPeter Brune 		 &ngmres->info);
27819653cdaSPeter Brune #endif
27919653cdaSPeter Brune     if (ngmres->info < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELSS");
28019653cdaSPeter Brune     if (ngmres->info > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SVD failed to converge");
281a312c225SMatthew G Knepley #endif
282a312c225SMatthew G Knepley 
28319653cdaSPeter Brune     alph_total = 0.;
28419653cdaSPeter Brune     for (i = 0; i < l; i++) {
28519653cdaSPeter Brune       alph_total += beta[i];
286c0bbabecSxuemin     }
28719653cdaSPeter Brune     ierr = VecCopy(x, x_A);CHKERRQ(ierr);
28819653cdaSPeter Brune     ierr = VecScale(x_A, 1. - alph_total);CHKERRQ(ierr);
289087dfb9eSxuemin 
29019653cdaSPeter Brune     for(i=0;i<l;i++){
29119653cdaSPeter Brune       ierr= VecAXPY(x_A, beta[i], xdot[i]);CHKERRQ(ierr);
29219653cdaSPeter Brune     }
29319653cdaSPeter Brune     ierr = SNESComputeFunction(snes, x_A, r_A);CHKERRQ(ierr);
29419653cdaSPeter Brune     ierr = VecNorm(r_A, NORM_2, &r_A_norm);CHKERRQ(ierr);
29519653cdaSPeter Brune 
29619653cdaSPeter Brune     selectA = PETSC_TRUE;
29798b3e84cSPeter Brune     /* Conditions for choosing the accelerated answer */
29819653cdaSPeter Brune 
29998b3e84cSPeter Brune     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
30019653cdaSPeter Brune     if (r_A_norm >= ngmres->gammaA*r_min_norm) {
30119653cdaSPeter Brune       selectA = PETSC_FALSE;
302a312c225SMatthew G Knepley     }
303087dfb9eSxuemin 
30498b3e84cSPeter Brune     /* Criterion B -- the choice of x^A isn't too close to some other choice */
30519653cdaSPeter Brune     ierr=VecCopy(x_A,d);CHKERRQ(ierr);
30619653cdaSPeter Brune     ierr=VecAXPY(d,-1,x);CHKERRQ(ierr);
30719653cdaSPeter Brune     ierr=VecNorm(d,NORM_2,&d_norm);CHKERRQ(ierr);
3089261d27aSPeter Brune     d_min_norm = -1.0;
30919653cdaSPeter Brune     for(i=0;i<l;i++) {
31019653cdaSPeter Brune       ierr=VecCopy(x_A,d);CHKERRQ(ierr);
31119653cdaSPeter Brune       ierr=VecAXPY(d,-1,xdot[i]);CHKERRQ(ierr);
31219653cdaSPeter Brune       ierr=VecNorm(d,NORM_2,&d_cur_norm);CHKERRQ(ierr);
3139261d27aSPeter Brune       if((d_cur_norm < d_min_norm) || (d_min_norm < 0.0)) d_min_norm = d_cur_norm;
31419653cdaSPeter Brune     }
31519653cdaSPeter Brune     if (ngmres->epsilonB*d_norm<d_min_norm || sqrt(r_norm)<ngmres->deltaB*sqrt(r_min_norm)) {
31619653cdaSPeter Brune     } else {
31719653cdaSPeter Brune       selectA=PETSC_FALSE;
31819653cdaSPeter Brune     }
319211b2d39SPeter Brune 
320087dfb9eSxuemin 
32119653cdaSPeter Brune     if (selectA) {
322dfbf837cSBarry Smith       if (ngmres->monitor) {
323dfbf837cSBarry Smith 	ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked r_A, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);CHKERRQ(ierr);
324dfbf837cSBarry Smith       }
32598b3e84cSPeter Brune       /* copy it over */
32619653cdaSPeter Brune       r_norm = r_A_norm;
32719653cdaSPeter Brune       nu = r_norm*r_norm;
32819653cdaSPeter Brune       ierr = VecCopy(r_A, r);CHKERRQ(ierr);
32919653cdaSPeter Brune       ierr = VecCopy(x_A, x);CHKERRQ(ierr);
33019653cdaSPeter Brune     } else {
331dfbf837cSBarry Smith       if (ngmres->monitor) {
332dfbf837cSBarry Smith 	ierr = PetscViewerASCIIPrintf(ngmres->monitor, "picked r_M, ||r_A||_2 = %e, ||r_M||_2 = %e\n", r_A_norm, r_norm);CHKERRQ(ierr);
333dfbf837cSBarry Smith       }
33419653cdaSPeter Brune     }
335211b2d39SPeter Brune 
33619653cdaSPeter Brune     selectRestart = PETSC_FALSE;
33719653cdaSPeter Brune 
33898b3e84cSPeter Brune     /* maximum iteration criterion */
33919653cdaSPeter Brune     if (k_restart > ngmres->k_rmax) {
34019653cdaSPeter Brune       selectRestart = PETSC_TRUE;
34119653cdaSPeter Brune     }
34219653cdaSPeter Brune 
34398b3e84cSPeter Brune     /* difference stagnation restart */
344dfbf837cSBarry Smith     if 	((ngmres->epsilonB*d_norm > d_min_norm) && (sqrt(r_A_norm) > ngmres->deltaB*sqrt(r_min_norm))) {
345dfbf837cSBarry Smith       if (ngmres->monitor) {
346dfbf837cSBarry Smith 	ierr = PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", ngmres->epsilonB*d_norm, d_min_norm);CHKERRQ(ierr);
347dfbf837cSBarry Smith       }
34819653cdaSPeter Brune       selectRestart = PETSC_TRUE;
34919653cdaSPeter Brune     }
35019653cdaSPeter Brune 
35198b3e84cSPeter Brune     /* residual stagnation restart */
35219653cdaSPeter Brune     if (sqrt(r_A_norm) > ngmres->gammaC*sqrt(r_min_norm)) {
353dfbf837cSBarry Smith       if (ngmres->monitor) {
354dfbf837cSBarry Smith 	ierr = PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", sqrt(r_A_norm), ngmres->gammaC*sqrt(r_min_norm));CHKERRQ(ierr);
355dfbf837cSBarry Smith       }
35619653cdaSPeter Brune       selectRestart = PETSC_TRUE;
35719653cdaSPeter Brune     }
35819653cdaSPeter Brune 
35919653cdaSPeter Brune     if (selectRestart) {
360dfbf837cSBarry Smith       if (ngmres->monitor){
361dfbf837cSBarry Smith 	ierr = PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %d\n", k_restart);CHKERRQ(ierr);
362dfbf837cSBarry Smith       }
36319653cdaSPeter Brune       k_restart = 1;
36419653cdaSPeter Brune       l = 1;
36598b3e84cSPeter Brune       /* q_{00} = nu */
36619653cdaSPeter Brune       ngmres->r_norms[0] = r_norm;
36719653cdaSPeter Brune       nu = r_norm*r_norm;
36819653cdaSPeter Brune       Q(0,0) = nu;
36998b3e84cSPeter Brune       /* rdot[0] = r */
37019653cdaSPeter Brune       ierr = VecCopy(x, xdot[0]);CHKERRQ(ierr);
37119653cdaSPeter Brune       ierr = VecCopy(r, rdot[0]);CHKERRQ(ierr);
37219653cdaSPeter Brune     } else {
37398b3e84cSPeter Brune       /* select the current size of the subspace */
3741e633543SBarry Smith       if (l < ngmres->msize) l++;
37519653cdaSPeter Brune       k_restart++;
37698b3e84cSPeter Brune       /* place the current entry in the list of previous entries */
37719653cdaSPeter Brune       ierr = VecCopy(r, rdot[ivec]);CHKERRQ(ierr);
37819653cdaSPeter Brune       ierr = VecCopy(x, xdot[ivec]);CHKERRQ(ierr);
37919653cdaSPeter Brune       ngmres->r_norms[ivec] = r_norm;
38098b3e84cSPeter Brune       if (r_min_norm > r_norm) r_min_norm = r_norm;  /* the minimum norm is now of r^A */
38119653cdaSPeter Brune       for (i = 0; i < l; i++) {
3821e633543SBarry Smith 	ierr = VecDot(r, rdot[i], &qentry);CHKERRQ(ierr);
38319653cdaSPeter Brune 	Q(i, ivec) = qentry;
38419653cdaSPeter Brune 	Q(ivec, i) = qentry;
38519653cdaSPeter Brune       }
38619653cdaSPeter Brune     }
38719653cdaSPeter Brune 
38819653cdaSPeter Brune     SNESLogConvHistory(snes, r_norm, k);
38919653cdaSPeter Brune     ierr = SNESMonitor(snes, k, r_norm);CHKERRQ(ierr);
39019653cdaSPeter Brune 
391087dfb9eSxuemin     snes->iter =k;
39219653cdaSPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,r_norm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
393087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
394a312c225SMatthew G Knepley   }
395a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
396a312c225SMatthew G Knepley   PetscFunctionReturn(0);
397a312c225SMatthew G Knepley }
398a312c225SMatthew G Knepley 
399dfbf837cSBarry Smith /*MC
400dfbf837cSBarry Smith   SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio.
401a312c225SMatthew G Knepley 
402dfbf837cSBarry Smith    Level: beginner
403dfbf837cSBarry Smith 
404dfbf837cSBarry Smith    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
405dfbf837cSBarry Smith    SIAM Journal on Scientific Computing, 21(5), 2000.
406dfbf837cSBarry Smith 
407dfbf837cSBarry Smith    This is also the same as the algorithm called Anderson acceleration introduced in "D. G. Anderson. Iterative procedures for nonlinear integral equations.
408dfbf837cSBarry Smith    J. Assoc. Comput. Mach., 12:547–560, 1965."
409dfbf837cSBarry Smith 
410dfbf837cSBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
411dfbf837cSBarry Smith M*/
412a312c225SMatthew G Knepley 
413a312c225SMatthew G Knepley EXTERN_C_BEGIN
414a312c225SMatthew G Knepley #undef __FUNCT__
415a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
416a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
417a312c225SMatthew G Knepley {
418a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
419a312c225SMatthew G Knepley   PetscErrorCode ierr;
420a312c225SMatthew G Knepley 
421a312c225SMatthew G Knepley   PetscFunctionBegin;
422a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
423a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
424a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
425a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
426a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
427a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
428a312c225SMatthew G Knepley 
429*42f4f86dSBarry Smith   snes->usespc          = PETSC_TRUE;
4302c155ee1SBarry Smith   snes->usesksp         = PETSC_FALSE;
4312c155ee1SBarry Smith 
432a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
433a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
43419653cdaSPeter Brune   ngmres->msize = 10;
43519653cdaSPeter Brune 
43619653cdaSPeter Brune   ngmres->gammaA   = 2.;
43719653cdaSPeter Brune   ngmres->gammaC   = 2.;
438cac108bcSPeter Brune   ngmres->deltaB   = 0.9;
439cac108bcSPeter Brune   ngmres->epsilonB = 0.1;
440cac108bcSPeter Brune   ngmres->k_rmax   = 200;
4414a0c5b0cSMatthew G Knepley 
4421e633543SBarry Smith   if (!snes->pc) {
4434a0c5b0cSMatthew G Knepley     ierr = SNESGetPC(snes, &snes->pc);CHKERRQ(ierr);
444*42f4f86dSBarry Smith     ierr = SNESSetType(snes->pc,SNESRICHARDSON);CHKERRQ(ierr);
4451e633543SBarry Smith   }
446a312c225SMatthew G Knepley   PetscFunctionReturn(0);
447a312c225SMatthew G Knepley }
448a312c225SMatthew G Knepley EXTERN_C_END
449