xref: /petsc/src/snes/impls/ngmres/snesngmres.c (revision 211b2d39fee274fff8c94272df1f8d43476a9184)
1a312c225SMatthew G Knepley /* Defines the basic SNES object */
2a312c225SMatthew G Knepley #include <private/snesimpl.h>
3a312c225SMatthew G Knepley 
4087dfb9eSxuemin static PetscErrorCode    BuildNGmresSoln(PetscScalar*,Vec,SNES,PetscInt,PetscInt);
5087dfb9eSxuemin 
6a312c225SMatthew G Knepley /* Private structure for the Anderson mixing method aka nonlinear Krylov */
7a312c225SMatthew G Knepley typedef struct {
8087dfb9eSxuemin   PetscScalar *hh_origin;
9087dfb9eSxuemin   Vec       *v, *w, *q;
10a312c225SMatthew G Knepley   PetscReal *f2;    /* 2-norms of function (residual) at each stage */
11a312c225SMatthew G Knepley   PetscInt   msize; /* maximum size of space */
12a312c225SMatthew G Knepley   PetscInt   csize; /* current size of space */
13087dfb9eSxuemin   PetscScalar beta; /* relaxation parameter */
14087dfb9eSxuemin   PetscScalar *nrs;            /* temp that holds the coefficients of the Krylov vectors that form the minimum residual solution */
15087dfb9eSxuemin 
16a312c225SMatthew G Knepley } SNES_NGMRES;
17a312c225SMatthew G Knepley 
18087dfb9eSxuemin #define HH(a,b)  (ngmres->hh_origin + (a)*(ngmres->msize)+(b))
19087dfb9eSxuemin 
20a312c225SMatthew G Knepley #undef __FUNCT__
21a312c225SMatthew G Knepley #define __FUNCT__ "SNESReset_NGMRES"
22a312c225SMatthew G Knepley PetscErrorCode SNESReset_NGMRES(SNES snes)
23a312c225SMatthew G Knepley {
24a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES*) snes->data;
25a312c225SMatthew G Knepley   PetscErrorCode ierr;
26a312c225SMatthew G Knepley 
27a312c225SMatthew G Knepley   PetscFunctionBegin;
28a312c225SMatthew G Knepley   ierr = VecDestroyVecs(ngmres->msize, &ngmres->v);CHKERRQ(ierr);
29a312c225SMatthew G Knepley   ierr = VecDestroyVecs(ngmres->msize, &ngmres->w);CHKERRQ(ierr);
30c0bbabecSxuemin   ierr = VecDestroyVecs(ngmres->msize, &ngmres->q);CHKERRQ(ierr);
31a312c225SMatthew G Knepley   PetscFunctionReturn(0);
32a312c225SMatthew G Knepley }
33a312c225SMatthew G Knepley 
34a312c225SMatthew G Knepley #undef __FUNCT__
35a312c225SMatthew G Knepley #define __FUNCT__ "SNESDestroy_NGMRES"
36a312c225SMatthew G Knepley PetscErrorCode SNESDestroy_NGMRES(SNES snes)
37a312c225SMatthew G Knepley {
38a312c225SMatthew G Knepley   PetscErrorCode ierr;
39a312c225SMatthew G Knepley 
40a312c225SMatthew G Knepley   PetscFunctionBegin;
41a312c225SMatthew G Knepley   ierr = SNESReset_NGMRES(snes);CHKERRQ(ierr);
42a312c225SMatthew G Knepley   if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);}
43a312c225SMatthew G Knepley   PetscFunctionReturn(0);
44a312c225SMatthew G Knepley }
45a312c225SMatthew G Knepley 
46a312c225SMatthew G Knepley #undef __FUNCT__
47a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetUp_NGMRES"
48a312c225SMatthew G Knepley PetscErrorCode SNESSetUp_NGMRES(SNES snes)
49a312c225SMatthew G Knepley {
50a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
51087dfb9eSxuemin   PetscInt msize,hh;
52a312c225SMatthew G Knepley   PetscErrorCode ierr;
53a312c225SMatthew G Knepley 
54a312c225SMatthew G Knepley   PetscFunctionBegin;
55a312c225SMatthew G Knepley #if 0
56a312c225SMatthew G Knepley   if (snes->pc_side != PC_LEFT) {SETERRQ(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Only left preconditioning allowed for SNESNGMRES");}
57a312c225SMatthew G Knepley #endif
58087dfb9eSxuemin   ngmres->beta  = 1.0;
59087dfb9eSxuemin   msize         = ngmres->msize;  /* restart size */
60087dfb9eSxuemin   hh            = msize * msize;
61087dfb9eSxuemin   ierr = PetscMalloc2(hh,PetscScalar,&ngmres->hh_origin,msize,PetscScalar,&ngmres->nrs);CHKERRQ(ierr);
62087dfb9eSxuemin 
63087dfb9eSxuemin   ierr = PetscMemzero(ngmres->hh_origin,hh*sizeof(PetscScalar));CHKERRQ(ierr);
64087dfb9eSxuemin   ierr = PetscMemzero(ngmres->nrs,msize*sizeof(PetscScalar));CHKERRQ(ierr);
65087dfb9eSxuemin 
66087dfb9eSxuemin   //  ierr = PetscLogObjectMemory(ksp,(hh+msize)*sizeof(PetscScalar));CHKERRQ(ierr);
67087dfb9eSxuemin 
68*211b2d39SPeter Brune   ierr = PetscLogObjectMemory(snes,(hh+msize)*sizeof(PetscScalar));CHKERRQ(ierr);
69*211b2d39SPeter Brune 
70*211b2d39SPeter Brune   //ierr = SNESGetVecs(snes,ngmres->msize,&ngmres->v,ngmres->msize*2,&ngmres->w);CHKERRQ(ierr);
71*211b2d39SPeter Brune   //ierr = VecDuplicate(snes->vec_sol, ngmres->w);CHKERRQ(ierr);
72*211b2d39SPeter Brune   //ierr = VecDuplicateVecs(ngmres->w[0], ngmres->msize, &ngmres->q);CHKERRQ(ierr);
73*211b2d39SPeter Brune 
74a312c225SMatthew G Knepley   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->v);CHKERRQ(ierr);
75*211b2d39SPeter Brune   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize*2, &ngmres->w);CHKERRQ(ierr);
76087dfb9eSxuemin   ierr = VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->q);CHKERRQ(ierr);
77*211b2d39SPeter Brune   ierr = SNESDefaultGetWork(snes, 3);CHKERRQ(ierr);
78a312c225SMatthew G Knepley   PetscFunctionReturn(0);
79a312c225SMatthew G Knepley }
80a312c225SMatthew G Knepley 
81a312c225SMatthew G Knepley #undef __FUNCT__
82a312c225SMatthew G Knepley #define __FUNCT__ "SNESSetFromOptions_NGMRES"
83a312c225SMatthew G Knepley PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes)
84a312c225SMatthew G Knepley {
85a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
86a312c225SMatthew G Knepley   PetscErrorCode ierr;
87a312c225SMatthew G Knepley 
88a312c225SMatthew G Knepley   PetscFunctionBegin;
89a312c225SMatthew G Knepley   ierr = PetscOptionsHead("SNES NGMRES options");CHKERRQ(ierr);
90c0bbabecSxuemin     ierr = PetscOptionsInt("-snes_ngmres_restart", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, PETSC_NULL);CHKERRQ(ierr);
91a312c225SMatthew G Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
92a312c225SMatthew G Knepley   PetscFunctionReturn(0);
93a312c225SMatthew G Knepley }
94a312c225SMatthew G Knepley 
95a312c225SMatthew G Knepley #undef __FUNCT__
96a312c225SMatthew G Knepley #define __FUNCT__ "SNESView_NGMRES"
97a312c225SMatthew G Knepley PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
98a312c225SMatthew G Knepley {
99a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
100a312c225SMatthew G Knepley   PetscBool      iascii;
101a312c225SMatthew G Knepley   PetscErrorCode ierr;
102a312c225SMatthew G Knepley 
103a312c225SMatthew G Knepley   PetscFunctionBegin;
104a312c225SMatthew G Knepley   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
105a312c225SMatthew G Knepley   if (iascii) {
106a312c225SMatthew G Knepley     ierr = PetscViewerASCIIPrintf(viewer, "  Size of space %d\n", ngmres->msize);CHKERRQ(ierr);
107a312c225SMatthew G Knepley   }
108a312c225SMatthew G Knepley   PetscFunctionReturn(0);
109a312c225SMatthew G Knepley }
110a312c225SMatthew G Knepley 
111a312c225SMatthew G Knepley #undef __FUNCT__
112a312c225SMatthew G Knepley #define __FUNCT__ "SNESSolve_NGMRES"
113*211b2d39SPeter Brune 
114a312c225SMatthew G Knepley PetscErrorCode SNESSolve_NGMRES(SNES snes)
115a312c225SMatthew G Knepley {
1164a0c5b0cSMatthew G Knepley   SNES           pc;
117087dfb9eSxuemin   SNES_NGMRES   *ngmres = (SNES_NGMRES *) snes->data;
118*211b2d39SPeter Brune   //Vec            X,F,R, Fold, Xold,temp,*dX = ngmres->v,*dF = ngmres->w;
119*211b2d39SPeter Brune   Vec            X,F,R,Fold, Xold,temp,*dX = ngmres->w,*dF = ngmres->w+ngmres->msize;
120087dfb9eSxuemin   PetscScalar    *nrs=ngmres->nrs;
121*211b2d39SPeter Brune   PetscReal      gnorm, xnorm, pnorm;
122c0bbabecSxuemin   PetscInt       i, j, k,ivec, l, flag, it;
123a312c225SMatthew G Knepley   PetscErrorCode ierr;
124a312c225SMatthew G Knepley 
125a312c225SMatthew G Knepley   PetscFunctionBegin;
126a312c225SMatthew G Knepley   snes->reason  = SNES_CONVERGED_ITERATING;
127a312c225SMatthew G Knepley   X             = snes->vec_sol;
128a312c225SMatthew G Knepley   F             = snes->vec_func;
129087dfb9eSxuemin   Fold          = snes->work[0];
130087dfb9eSxuemin   Xold          = snes->work[1];
131*211b2d39SPeter Brune   R             = snes->work[2];
132087dfb9eSxuemin   ierr = VecDuplicate(X,&Xold);CHKERRQ(ierr);
133087dfb9eSxuemin   ierr = VecDuplicate(X,&temp);CHKERRQ(ierr);
134*211b2d39SPeter Brune   ierr = VecDuplicate(X,&Fold);CHKERRQ(ierr);
135a312c225SMatthew G Knepley 
1364a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &pc);CHKERRQ(ierr);
137a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
138a312c225SMatthew G Knepley   snes->iter = 0;
139a312c225SMatthew G Knepley   snes->norm = 0.;
140a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
141*211b2d39SPeter Brune   ierr = SNESComputeFunction(snes, X, R);CHKERRQ(ierr);               /* r = F(x) */
142087dfb9eSxuemin #if 0
143*211b2d39SPeter Brune   ierr = SNESSolve(snes->pc, R, F);CHKERRQ(ierr);                  /* p = P(r) */
144087dfb9eSxuemin #else
145*211b2d39SPeter Brune   ierr = VecCopy(R, F);CHKERRQ(ierr);                              /* p = r    */
146087dfb9eSxuemin #endif
147a312c225SMatthew G Knepley   if (snes->domainerror) {
148a312c225SMatthew G Knepley     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
149a312c225SMatthew G Knepley     PetscFunctionReturn(0);
150a312c225SMatthew G Knepley   }
151087dfb9eSxuemin   ierr = VecNorm(F, NORM_2, &gnorm);CHKERRQ(ierr);                    /* fnorm = ||r||  */
152087dfb9eSxuemin   if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm");
153087dfb9eSxuemin 
154a312c225SMatthew G Knepley   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
155087dfb9eSxuemin   snes->norm = gnorm;
156a312c225SMatthew G Knepley   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
157087dfb9eSxuemin   SNESLogConvHistory(snes, gnorm, 0);
158087dfb9eSxuemin   ierr = SNESMonitor(snes, 0, gnorm);CHKERRQ(ierr);
159087dfb9eSxuemin   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,gnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
160a312c225SMatthew G Knepley   if (snes->reason) PetscFunctionReturn(0);
161a312c225SMatthew G Knepley 
162087dfb9eSxuemin   /* for k=0 */
163087dfb9eSxuemin 
164087dfb9eSxuemin   k=0;
165087dfb9eSxuemin   ierr= VecCopy(X,Xold); CHKERRQ(ierr); /* Xbar_0= X_0 */
166087dfb9eSxuemin   ierr= VecCopy(F,Fold); CHKERRQ(ierr); /* Fbar_0 = f_0= B(b-Ax_0) */
167087dfb9eSxuemin   ierr= VecWAXPY(X, ngmres->beta, Fold, Xold); CHKERRQ(ierr);       /*X_1 = X_bar + beta * Fbar */
168087dfb9eSxuemin 
169087dfb9eSxuemin   /* to calculate f_1 */
170*211b2d39SPeter Brune   ierr = SNESComputeFunction(snes, X, R);CHKERRQ(ierr);               /* r = F(x) */
171087dfb9eSxuemin #if 0
172087dfb9eSxuemin   ierr = SNESSolve(snes->pc, temp, F);CHKERRQ(ierr);                  /* p = P(r) */
1734a0c5b0cSMatthew G Knepley #else
174*211b2d39SPeter Brune   ierr = VecCopy(R, F);CHKERRQ(ierr);                              /* p = r    */
175a312c225SMatthew G Knepley #endif
176a312c225SMatthew G Knepley 
177087dfb9eSxuemin   /* calculate dX and dF for k=0 */
178087dfb9eSxuemin   ierr= VecWAXPY(dX[k],-1.0, Xold, X); CHKERRQ(ierr); /* dX= X_1 - X_0 */
179087dfb9eSxuemin   ierr= VecWAXPY(dF[k],-1.0, Fold, F); CHKERRQ(ierr); /* dF= f_1 - f_0 */
180087dfb9eSxuemin 
181087dfb9eSxuemin   ierr= VecCopy(X,Xold); CHKERRQ(ierr); /* Xbar_0= X_0 */
182087dfb9eSxuemin   ierr= VecCopy(F,Fold); CHKERRQ(ierr); /* Fbar_0 = f_0= B(b-Ax_0) */
183087dfb9eSxuemin 
184087dfb9eSxuemin   flag=0;
185087dfb9eSxuemin 
186087dfb9eSxuemin   for (k=1; k<snes->max_its; k += 1) {  /* begin the iteration */
187087dfb9eSxuemin     l=ngmres->msize;
188c0bbabecSxuemin 
189c0bbabecSxuemin     if(k<l) {
190c0bbabecSxuemin       l=k;
191*211b2d39SPeter Brune       ivec=l;
192c0bbabecSxuemin     }
193c0bbabecSxuemin     else{
194c0bbabecSxuemin       ivec=l-1;
195c0bbabecSxuemin     }
196087dfb9eSxuemin     it=l-1;
197087dfb9eSxuemin     ierr = BuildNGmresSoln(nrs,Fold,snes,it,flag);CHKERRQ(ierr);
198087dfb9eSxuemin 
199087dfb9eSxuemin     /* to obtain the solution at k+1 step */
200087dfb9eSxuemin     ierr= VecCopy(Xold,X); CHKERRQ(ierr); /* X=Xold+Fold-(dX + dF) *nrd */
201087dfb9eSxuemin     ierr= VecAXPY(X,1.0,Fold); CHKERRQ(ierr); /* X= Xold+Fold */
202087dfb9eSxuemin     for(i=0;i<l;i++){      /*X= Xold+Fold- (dX+dF*beta) *innerb */
203087dfb9eSxuemin       ierr= VecAXPY(X,-nrs[i], dX[i]);CHKERRQ(ierr);
204087dfb9eSxuemin       ierr= VecAXPY(X,-nrs[i]*ngmres->beta, dF[i]);CHKERRQ(ierr);
205a312c225SMatthew G Knepley     }
206087dfb9eSxuemin 
207087dfb9eSxuemin     /* to calculate f_k+1 */
208*211b2d39SPeter Brune     ierr = SNESComputeFunction(snes, X, R);CHKERRQ(ierr);               /* r = F(x) */
209*211b2d39SPeter Brune 
210087dfb9eSxuemin #if 0
211*211b2d39SPeter Brune     ierr = SNESSolve(snes->pc, R, F);CHKERRQ(ierr);                  /* p = P(r) */
212087dfb9eSxuemin #else
213*211b2d39SPeter Brune     ierr = VecCopy(R, F);CHKERRQ(ierr);                              /* p = r    */
214087dfb9eSxuemin #endif
215087dfb9eSxuemin 
216087dfb9eSxuemin     /* check the convegence */
217*211b2d39SPeter Brune 
218*211b2d39SPeter Brune     ierr = VecNorm(R, NORM_2, &gnorm);CHKERRQ(ierr);                    /* fnorm = ||r||  */
219*211b2d39SPeter Brune     ierr = VecNorm(dX[l-1], NORM_2, &pnorm);CHKERRQ(ierr);                    /* fnorm = ||r||*/
220*211b2d39SPeter Brune     ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr);                    /* fnorm = ||r||  */
221087dfb9eSxuemin     SNESLogConvHistory(snes, gnorm, k);
222087dfb9eSxuemin     ierr = SNESMonitor(snes, k, gnorm);CHKERRQ(ierr);
223087dfb9eSxuemin     snes->iter =k;
224*211b2d39SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,pnorm,gnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
225087dfb9eSxuemin     if (snes->reason) PetscFunctionReturn(0);
226087dfb9eSxuemin 
227087dfb9eSxuemin 
228087dfb9eSxuemin 
229087dfb9eSxuemin     /* calculate dX and dF for k=0 */
230c0bbabecSxuemin       if( k>ivec) {/* we need to replace the old vectors */
231087dfb9eSxuemin  	flag=1;
232c0bbabecSxuemin 	for(i=0;i<it;i++){
233087dfb9eSxuemin 	  ierr= VecCopy(dX[i+1],dX[i]); CHKERRQ(ierr); /* X=Xold+Fold-(dX + dF) *nrd */
234087dfb9eSxuemin 	  ierr= VecCopy(dF[i+1],dF[i]); CHKERRQ(ierr); /* X=Xold+Fold-(dX + dF) *nrd */
235087dfb9eSxuemin 	  for(j=0;j<l;j++)
236087dfb9eSxuemin 	    *HH(j,i)=*HH(j,i+1);
237087dfb9eSxuemin 	}
238087dfb9eSxuemin       }
239c0bbabecSxuemin 
240c0bbabecSxuemin       ierr= VecWAXPY(dX[ivec],-1.0, Xold, X); CHKERRQ(ierr); /* dX= X_1 - X_0 */
241c0bbabecSxuemin       ierr= VecWAXPY(dF[ivec],-1.0, Fold, F); CHKERRQ(ierr); /* dF= f_1 - f_0 */
242087dfb9eSxuemin       ierr= VecCopy(X,Xold); CHKERRQ(ierr);
243087dfb9eSxuemin       ierr= VecCopy(F,Fold); CHKERRQ(ierr);
244087dfb9eSxuemin 
245a312c225SMatthew G Knepley   }
246a312c225SMatthew G Knepley   snes->reason = SNES_DIVERGED_MAX_IT;
247a312c225SMatthew G Knepley   PetscFunctionReturn(0);
248a312c225SMatthew G Knepley }
249a312c225SMatthew G Knepley 
250a312c225SMatthew G Knepley /*MC
251a312c225SMatthew G Knepley   SNESNGMRES - The Nonlinear Generalized Minimum Residual (NGMRES) method of Oosterlee and Washio.
252a312c225SMatthew G Knepley 
253a312c225SMatthew G Knepley    Level: beginner
254a312c225SMatthew G Knepley 
255a312c225SMatthew G Knepley    Notes: Supports only left preconditioning
256a312c225SMatthew G Knepley 
257a312c225SMatthew G Knepley    "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows", C. W. Oosterlee and T. Washio,
258a312c225SMatthew G Knepley    SIAM Journal on Scientific Computing, 21(5), 2000.
259a312c225SMatthew G Knepley 
260a312c225SMatthew G Knepley .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types)
261a312c225SMatthew G Knepley M*/
262a312c225SMatthew G Knepley EXTERN_C_BEGIN
263a312c225SMatthew G Knepley #undef __FUNCT__
264a312c225SMatthew G Knepley #define __FUNCT__ "SNESCreate_NGMRES"
265a312c225SMatthew G Knepley PetscErrorCode SNESCreate_NGMRES(SNES snes)
266a312c225SMatthew G Knepley {
267a312c225SMatthew G Knepley   SNES_NGMRES   *ngmres;
268a312c225SMatthew G Knepley   PetscErrorCode ierr;
269a312c225SMatthew G Knepley 
270a312c225SMatthew G Knepley   PetscFunctionBegin;
271a312c225SMatthew G Knepley   snes->ops->destroy        = SNESDestroy_NGMRES;
272a312c225SMatthew G Knepley   snes->ops->setup          = SNESSetUp_NGMRES;
273a312c225SMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
274a312c225SMatthew G Knepley   snes->ops->view           = SNESView_NGMRES;
275a312c225SMatthew G Knepley   snes->ops->solve          = SNESSolve_NGMRES;
276a312c225SMatthew G Knepley   snes->ops->reset          = SNESReset_NGMRES;
277a312c225SMatthew G Knepley 
278a312c225SMatthew G Knepley   ierr = PetscNewLog(snes, SNES_NGMRES, &ngmres);CHKERRQ(ierr);
279a312c225SMatthew G Knepley   snes->data = (void*) ngmres;
280a312c225SMatthew G Knepley   ngmres->msize = 30;
281a312c225SMatthew G Knepley   ngmres->csize = 0;
2824a0c5b0cSMatthew G Knepley 
2834a0c5b0cSMatthew G Knepley   ierr = SNESGetPC(snes, &snes->pc);CHKERRQ(ierr);
284a312c225SMatthew G Knepley #if 0
285a312c225SMatthew G Knepley   if (ksp->pc_side != PC_LEFT) {ierr = PetscInfo(ksp,"WARNING! Setting PC_SIDE for NGMRES to left!\n");CHKERRQ(ierr);}
286a312c225SMatthew G Knepley   snes->pc_side = PC_LEFT;
287a312c225SMatthew G Knepley #endif
288a312c225SMatthew G Knepley   PetscFunctionReturn(0);
289a312c225SMatthew G Knepley }
290a312c225SMatthew G Knepley EXTERN_C_END
291087dfb9eSxuemin 
292087dfb9eSxuemin 
293087dfb9eSxuemin #undef __FUNCT__
294087dfb9eSxuemin #define __FUNCT__ "BuildNGmresSoln"
295087dfb9eSxuemin static PetscErrorCode BuildNGmresSoln(PetscScalar* nrs, Vec Fold, SNES snes,PetscInt it, PetscInt flag)
296087dfb9eSxuemin {
297087dfb9eSxuemin   PetscScalar    tt,temps;
298087dfb9eSxuemin   PetscErrorCode ierr;
299087dfb9eSxuemin   PetscInt       i,ii,j,l;
300087dfb9eSxuemin   SNES_NGMRES      *ngmres = (SNES_NGMRES *)(snes->data);
301*211b2d39SPeter Brune   //Vec *dF=ngmres->w+ngmres->msize, *Q=ngmres->w+ngmres->msize*2,temp;
302*211b2d39SPeter Brune   Vec *dF=ngmres->w+ngmres->msize,*Q=ngmres->q,temp;
303dadb11c9SJed Brown   PetscReal      gam,areal;
304dadb11c9SJed Brown   PetscScalar    a,b,c,s;
305087dfb9eSxuemin 
306087dfb9eSxuemin   PetscFunctionBegin;
307087dfb9eSxuemin   ierr = VecDuplicate(Fold,&temp);CHKERRQ(ierr);
308087dfb9eSxuemin   l=it+1;
309087dfb9eSxuemin 
310087dfb9eSxuemin   /* Solve for solution vector that minimizes the residual */
311087dfb9eSxuemin 
312087dfb9eSxuemin   if(flag==1) { // we need to replace the old vector and need to modify the QR factors, use Givens rotation
313087dfb9eSxuemin       for(i=0;i<it;i++){
314087dfb9eSxuemin 	/* calculate the Givens rotation */
315087dfb9eSxuemin 	a=*HH(i,i);
316087dfb9eSxuemin 	b=*HH(i+1,i);
317*211b2d39SPeter Brune         gam=1.0/PetscRealPart(PetscSqrtScalar(PetscConj(a)*a + PetscConj(b)*b));
318087dfb9eSxuemin         c= a*gam;
319087dfb9eSxuemin         s= b*gam;
320c0bbabecSxuemin 
321c0bbabecSxuemin #if defined(PETSC_USE_COMPLEX)
322c0bbabecSxuemin 	/* update the Q factor */
323c0bbabecSxuemin         ierr= VecCopy(Q[i],temp); CHKERRQ(ierr);
324c0bbabecSxuemin 	ierr = VecAXPBY(temp,s,PetscConj(c),Q[i+1]);CHKERRQ(ierr); /*temp= c*Q[i]+s*Q[i+1] */
325c0bbabecSxuemin         ierr = VecAXPBY(Q[i+1],-s,c,Q[i]);CHKERRQ(ierr); /* Q[i+1]= -s*Q[i] + c*Q[i+1] */
326c0bbabecSxuemin         ierr= VecCopy(temp,Q[i]); CHKERRQ(ierr);   /* Q[i]= c*Q[i] + s*Q[i+1] */
327c0bbabecSxuemin         /* update the R factor */
328c0bbabecSxuemin         for(j=0;j<l;j++){
329c0bbabecSxuemin           a= *HH(i,j);
330c0bbabecSxuemin           b=*HH(i+1,j);
331c0bbabecSxuemin 	  temps=PetscConj(c)* a+s* b;
332c0bbabecSxuemin           *HH(i+1,j)=-s*a+c*b;
333c0bbabecSxuemin           *HH(i,j)=temps;
334c0bbabecSxuemin         }
335c0bbabecSxuemin #else
336087dfb9eSxuemin 	/* update the Q factor */
337087dfb9eSxuemin         ierr= VecCopy(Q[i],temp); CHKERRQ(ierr);
338087dfb9eSxuemin 	ierr = VecAXPBY(temp,s,c,Q[i+1]);CHKERRQ(ierr); /*temp= c*Q[i]+s*Q[i+1] */
339087dfb9eSxuemin         ierr = VecAXPBY(Q[i+1],-s,c,Q[i]);CHKERRQ(ierr); /* Q[i+1]= -s*Q[i] + c*Q[i+1] */
340087dfb9eSxuemin         ierr= VecCopy(temp,Q[i]); CHKERRQ(ierr);   /* Q[i]= c*Q[i] + s*Q[i+1] */
341087dfb9eSxuemin         /* update the R factor */
342087dfb9eSxuemin         for(j=0;j<l;j++){
343087dfb9eSxuemin           a= *HH(i,j);
344087dfb9eSxuemin           b=*HH(i+1,j);
345087dfb9eSxuemin 	  temps=c* a+s* b;
346087dfb9eSxuemin           *HH(i+1,j)=-s*a+c*b;
347087dfb9eSxuemin           *HH(i,j)=temps;
348087dfb9eSxuemin         }
349c0bbabecSxuemin #endif
350087dfb9eSxuemin       }
351087dfb9eSxuemin     }
352087dfb9eSxuemin 
353087dfb9eSxuemin     // add a new vector, use modified Gram-Schmidt
354087dfb9eSxuemin     ierr= VecCopy(dF[it],temp); CHKERRQ(ierr);
355087dfb9eSxuemin     for(i=0;i<it;i++){
356087dfb9eSxuemin       ierr=VecDot(temp,Q[i],HH(i,it));CHKERRQ(ierr); /* h(i,l-1)= dF[l-1]'*Q[i] */
357087dfb9eSxuemin       ierr = VecAXPBY(temp,-*HH(i,it),1.0,Q[i]);CHKERRQ(ierr); /* temp= temp- h(i,l-1)*Q[i] */
358087dfb9eSxuemin     }
359c0bbabecSxuemin     ierr=VecCopy(temp,Q[it]);CHKERRQ(ierr);
360c0bbabecSxuemin     ierr=VecNormalize(Q[it],&areal);CHKERRQ(ierr);
361c0bbabecSxuemin     *HH(it,it) = areal;
362087dfb9eSxuemin 
363087dfb9eSxuemin 
364*211b2d39SPeter Brune 
365087dfb9eSxuemin     /* modify the RHS with Q'*Fold*/
366087dfb9eSxuemin 
367087dfb9eSxuemin   for(i=0;i<l;i++)
368087dfb9eSxuemin           ierr=VecDot(Fold,Q[i],ngmres->nrs+i);CHKERRQ(ierr); /* nrs= Fold'*Q[i] */
369087dfb9eSxuemin 
370087dfb9eSxuemin     /* start backsubstitution to solve the least square problem */
371087dfb9eSxuemin 
372087dfb9eSxuemin      if (*HH(it,it) != 0.0) {
373087dfb9eSxuemin       nrs[it] =  nrs[it]/ *HH(it,it);
374087dfb9eSxuemin     } else {
375087dfb9eSxuemin     snes->reason = SNES_DIVERGED_MAX_IT;
376087dfb9eSxuemin     ierr = PetscInfo2(snes,"Likely your matrix or preconditioner is singular. HH(it,it) is identically zero; it = %D nrs(it) = %G",it,10);
377087dfb9eSxuemin     PetscFunctionReturn(0);
378087dfb9eSxuemin   }
379087dfb9eSxuemin   for (ii=1; ii<=it; ii++) {
380087dfb9eSxuemin     i   = it - ii;
381087dfb9eSxuemin     tt  = nrs[i];
382087dfb9eSxuemin     for (j=i+1; j<=it; j++) tt  = tt - *HH(i,j) * nrs[j];
383087dfb9eSxuemin     if (*HH(i,i) == 0.0) {
384087dfb9eSxuemin       snes->reason = SNES_DIVERGED_MAX_IT;
385087dfb9eSxuemin       ierr = PetscInfo1(snes,"Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; i = %D",i);
386087dfb9eSxuemin       PetscFunctionReturn(0);
387087dfb9eSxuemin     }
388087dfb9eSxuemin     nrs[i]   = tt / *HH(i,i);
389087dfb9eSxuemin   }
390087dfb9eSxuemin 
391087dfb9eSxuemin 
392087dfb9eSxuemin   PetscFunctionReturn(0);
393087dfb9eSxuemin }
394