Actual source code: ngmres.c
2: #include <../src/ksp/ksp/impls/ngmres/ngmresimpl.h> /*I "petscksp.h" I*/
4: static PetscErrorCode BuildNGmresSoln(PetscScalar*,Vec,KSP,PetscInt,PetscInt);
5: /*
6: KSPSetUp_NGMRES - Sets up the workspace needed by the NGMRES method.
8: This is called once, usually automatically by KSPSolve() or KSPSetUp()
9: */
12: PetscErrorCode KSPSetUp_NGMRES(KSP ksp)
13: {
15: PetscInt hh;
16: PetscInt msize;
17: KSP_NGMRES *ngmres = (KSP_NGMRES*)ksp->data;
19: PetscBool diagonalscale;
22: /*
23: This implementation of NGMRES only handles left preconditioning
24: so generate an error otherwise.
25: */
26: if (ksp->pc_side == PC_RIGHT) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"No right preconditioning for KSPNGMRES");
27: else if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"No symmetric preconditioning for KSPNGMRES");
28: PCGetDiagonalScale(ksp->pc,&diagonalscale);
29: if (diagonalscale) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
30: ngmres->beta = 1.0;
31: msize = ngmres->msize; /* restart size */
32: hh = msize * msize;
33:
34: /* PetscMalloc1(hh,PetscScalar,&ngmres->hh_origin,bb,PetscScalar,&ngmres->bb_origin,rs,PetscScalar,&ngmres->rs_origin,cc,PetscScalar,&ngmres->cc_origin,cc,PetscScalar,&ngmres->ss_origin); */
35: PetscMalloc2(hh,PetscScalar,&ngmres->hh_origin,msize,PetscScalar,&ngmres->nrs);
37: PetscMemzero(ngmres->hh_origin,hh*sizeof(PetscScalar));
38: PetscMemzero(ngmres->nrs,msize*sizeof(PetscScalar));
40: PetscLogObjectMemory(ksp,(hh+msize)*sizeof(PetscScalar));
42: KSPGetVecs(ksp,ngmres->msize,&ngmres->v,ngmres->msize*2,&ngmres->w);
43: VecDuplicateVecs(ngmres->w[0], ngmres->msize, &ngmres->q);
44:
45: KSPDefaultGetWork(ksp,3);
46: return(0);
47: }
49: /*
50: KSPSolve_NGMRES - This routine actually applies the method
53: Input Parameter:
54: . ksp - the Krylov space object that was set to use conjugate gradient, by, for
55: example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPNGMRES);
56: */
59: PetscErrorCode KSPSolve_NGMRES(KSP ksp)
60: {
62: PetscInt i,ivec,j,k,l,flag,it;
63: KSP_NGMRES *ngmres = (KSP_NGMRES*)ksp->data;
64: Mat Amat;
65: /* Vec X,F,R, B,Fold, Xold,temp,*dX = ngmres->w,*dF = ngmres->w+ngmres->msize; */
66: Vec X,F,R, B,Fold, Xold,temp,*dX = ngmres->w,*dF = ngmres->w+ngmres->msize;
67: PetscScalar *nrs=ngmres->nrs;
68: PetscReal gnorm;
69:
72: X = ksp->vec_sol;
73: B = ksp->vec_rhs;
74: F = ksp->work[0];
75: Fold = ksp->work[1];
76: R = ksp->work[2];
77: VecDuplicate(X,&Fold);
78: VecDuplicate(X,&Xold);
79: VecDuplicate(X,&temp);
82: PCGetOperators(ksp->pc,&Amat,PETSC_NULL,PETSC_NULL);
84: if (!ksp->guess_zero) {
85: KSP_MatMult(ksp,Amat,X,R); /* r <- b - Ax */
86: VecAYPX(R,-1.0,B);
87: } else {
88: VecCopy(B,R); /* r <- b (x is 0) */
89: }
90: PCApply(ksp->pc,R,F); /* F = B r */
91: if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
92: VecNorm(R,NORM_2,&gnorm);
93: } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
94: VecNorm(F,NORM_2,&gnorm);
95: } else SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"NormType not supported");
96: KSPLogResidualHistory(ksp,gnorm);
97: KSPMonitor(ksp,0,gnorm);
98: (*ksp->converged)(ksp,0,gnorm,&ksp->reason,ksp->cnvP);
101: /* for k=0 */
103: k=0;
104: ierr= VecCopy(X,Xold); /* Xbar_0= X_0 */
105: ierr= VecCopy(F,Fold); /* Fbar_0 = f_0= B(b-Ax_0) */
106: ierr= VecWAXPY(X, ngmres->beta, Fold, Xold); /*X_1 = X_bar + beta * Fbar */
108: /* to calculate f_1 */
109: KSP_MatMult(ksp,Amat,X,R); /* r <- b - Ax */
110: VecAYPX(R,-1.0,B);
111: PCApply(ksp->pc,R,F); /* F= f_1 = B(b-Ax) */
113: /* calculate dX and dF for k=0 */
114: ierr= VecWAXPY(dX[k],-1.0, Xold, X); /* dX= X_1 - X_0 */
115: ierr= VecWAXPY(dF[k],-1.0, Fold, F); /* dF= f_1 - f_0 */
116:
117:
118: ierr= VecCopy(X,Xold); /* Xbar_0= X_0 */
119: ierr= VecCopy(F,Fold); /* Fbar_0 = f_0= B(b-Ax_0) */
121: flag=0;
123: for (k=1; k<ksp->max_it; k += 1) { /* begin the iteration */
124: l=ngmres->msize;
125: if(k<l) {
126: l=k;
127: ivec=l;
128: }else{
129: ivec=l-1;
130: }
131: it=l-1;
132: BuildNGmresSoln(nrs,Fold,ksp,it,flag);
133:
134: /* to obtain the solution at k+1 step */
135: ierr= VecCopy(Xold,X); /* X=Xold+Fold-(dX + dF) *nrd */
136: ierr= VecAXPY(X,1.0,Fold); /* X= Xold+Fold */
137: for(i=0;i<l;i++){ /*X= Xold+Fold- (dX+dF*beta) *innerb */
138: ierr= VecAXPY(X,-nrs[i], dX[i]);
139: ierr= VecAXPY(X,-nrs[i]*ngmres->beta, dF[i]);
140: }
143: /* to test with GMRES */
144: #if 0
145: ierr= VecCopy(Xold,temp); /* X=Xold-(dX ) *nrd */
146: for(i=0;i<l;i++){
147: ierr= VecAXPY(temp,-nrs[i], dX[i]);
148: }
149: KSP_MatMult(ksp,Amat,temp,R);
150: VecAYPX(R,-1.0,B);
151: PCApply(ksp->pc,R,F);
152: VecNorm(R,NORM_2,&gnorm);
153: printf("gmres residual norm=%g\n",gnorm);
154: #endif
156: /* to calculate f_k+1 */
157: KSP_MatMult(ksp,Amat,X,R); /* r <- b - Ax */
158: VecAYPX(R,-1.0,B);
159: PCApply(ksp->pc,R,F); /* F= f_1 = B(b-Ax) */
160:
162: /* check the convegence */
163:
164: if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
165: VecNorm(R,NORM_2,&gnorm);
166: } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
167: VecNorm(F,NORM_2,&gnorm);
168: } else SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"NormType not supported");
169: KSPLogResidualHistory(ksp,gnorm);
171: KSPMonitor(ksp,k,gnorm);
172: ksp->its=k;
173: (*ksp->converged)(ksp,k,gnorm,&ksp->reason,ksp->cnvP);
174: if (ksp->reason) return(0);
177: /* calculate dX and dF for k=0 */
178: if( k>ivec) {/* we need to replace the old vectors */
179: flag=1;
180: for(i=0;i<it;i++){
181: ierr= VecCopy(dX[i+1],dX[i]); /* X=Xold+Fold-(dX + dF) *nrd */
182: ierr= VecCopy(dF[i+1],dF[i]); /* X=Xold+Fold-(dX + dF) *nrd */
183: for(j=0;j<l;j++)
184: *HH(j,i)=*HH(j,i+1);
185: }
186: }
187: ierr= VecWAXPY(dX[ivec],-1.0, Xold, X); /* dX= X_1 - X_0 */
188: ierr= VecWAXPY(dF[ivec],-1.0, Fold, F); /* dF= f_1 - f_0 */
189: ierr= VecCopy(X,Xold);
190: ierr= VecCopy(F,Fold);
191:
192: }
193: ksp->reason = KSP_DIVERGED_ITS;
194: return(0);
195: }
198: PetscErrorCode KSPReset_NGMRES(KSP ksp)
199: {
200: KSP_NGMRES *ngmres = (KSP_NGMRES*)ksp->data;
204: VecDestroyVecs(ngmres->msize,&ngmres->v);
205: VecDestroyVecs(ngmres->msize,&ngmres->w);
206: VecDestroyVecs(ngmres->msize,&ngmres->q);
207: return(0);
208: }
210: /*
211: KSPDestroy_NGMRES - Frees all memory space used by the Krylov method
213: */
216: PetscErrorCode KSPDestroy_NGMRES(KSP ksp)
217: {
221: KSPReset_NGMRES(ksp);
222: KSPDefaultDestroy(ksp);
223: return(0);
224: }
226: /*
227: KSPView_NGMRES - Prints information about the current Krylov method being used
229: Currently this only prints information to a file (or stdout) about the
230: symmetry of the problem. If your Krylov method has special options or
231: flags that information should be printed here.
233: */
236: PetscErrorCode KSPView_NGMRES(KSP ksp,PetscViewer viewer)
237: {
238: KSP_NGMRES *ngmres = (KSP_NGMRES *)ksp->data;
240: PetscBool iascii;
243: PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
244: if (iascii) {
245: PetscViewerASCIIPrintf(viewer," Size of space %d\n",ngmres->msize);
246: } else {
247: SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for KSP ngmres",((PetscObject)viewer)->type_name);
248: }
249: return(0);
250: }
252: /*
253: KSPSetFromOptions_NGMRES - Checks the options database for options related to the method
254: */
257: PetscErrorCode KSPSetFromOptions_NGMRES(KSP ksp)
258: {
260: KSP_NGMRES *ngmres = (KSP_NGMRES *)ksp->data;
263: PetscOptionsHead("KSP NGMRES options");
264: PetscOptionsInt("-ksp_ngmres_restart","Number of directions","None",ngmres->msize,&ngmres->msize,PETSC_NULL);
265: PetscOptionsTail();
266: return(0);
267: }
269: /*
270: KSPCreate_NGMRES - Creates the data structure for the Krylov method NGMRES and sets the
271: function pointers for all the routines it needs to call (KSPSolve_NGMRES() etc)
274: */
275: /*MC
276: KSPNGMRES - The nonlinear generalized minimum residual (NGMRES) iterative method
278: Level: beginner
280: Notes: Supports only left preconditioning
282: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP
284: M*/
288: PetscErrorCode KSPCreate_NGMRES(KSP ksp)
289: {
291: KSP_NGMRES *ngmres;
294: PetscNewLog(ksp,KSP_NGMRES,&ngmres);
295: ksp->data = (void*)ngmres;
296: ngmres->msize = 30;
297: ngmres->csize = 0;
299: KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2);
300: KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);
302: /*
303: Sets the functions that are associated with this data structure
304: (in C++ this is the same as defining virtual functions)
305: */
306: ksp->ops->setup = KSPSetUp_NGMRES;
307: ksp->ops->solve = KSPSolve_NGMRES;
308: ksp->ops->reset = KSPReset_NGMRES;
309: ksp->ops->destroy = KSPDestroy_NGMRES;
310: ksp->ops->view = KSPView_NGMRES;
311: ksp->ops->setfromoptions = KSPSetFromOptions_NGMRES;
312: ksp->ops->buildsolution = KSPDefaultBuildSolution;
313: ksp->ops->buildresidual = KSPDefaultBuildResidual;
314: return(0);
315: }
321: /*
322: BuildNGmresSoln - create the solution of the least square problem to determine the coefficients
324: Input parameters:
325: nrs - the solution
326: Fold - the RHS vector
327: flag - =1, we need to replace the old vector by new one, =0, we still add new vector
328: This is an internal routine that knows about the NGMRES internals.
329: */
332: static PetscErrorCode BuildNGmresSoln(PetscScalar* nrs, Vec Fold, KSP ksp,PetscInt it, PetscInt flag)
333: {
334: PetscScalar tt,temps;
336: PetscInt i,ii,j,l;
337: KSP_NGMRES *ngmres = (KSP_NGMRES *)(ksp->data);
338: /* Vec *dF=ngmres->w+ngmres->msize, *Q=ngmres->w+ngmres->msize*2,temp; */
339: Vec *dF=ngmres->w+ngmres->msize,*Q=ngmres->q,temp;
340: PetscReal gam,areal;
341: PetscScalar a,b,c,s;
342:
344: VecDuplicate(Fold,&temp);
345: l=it+1;
346:
347: /* Solve for solution vector that minimizes the residual */
349: if(flag==1) { /* we need to replace the old vector and need to modify the QR factors, use Givens rotation */
350: for(i=0;i<it;i++){
351: /* calculate the Givens rotation */
352: a=*HH(i,i);
353: b=*HH(i+1,i);
354: gam=1.0/PetscRealPart(PetscSqrtScalar(PetscConj(a)*a + PetscConj(b)*b));
355: c= a*gam;
356: s= b*gam;
357:
358: #if defined(PETSC_USE_COMPLEX)
359: /* update the Q factor */
360: ierr= VecCopy(Q[i],temp);
361: VecAXPBY(temp,s,PetscConj(c),Q[i+1]); /*temp= c*Q[i]+s*Q[i+1] */
362: VecAXPBY(Q[i+1],-s,c,Q[i]); /* Q[i+1]= -s*Q[i] + c*Q[i+1] */
363: ierr= VecCopy(temp,Q[i]); /* Q[i]= c*Q[i] + s*Q[i+1] */
364: /* update the R factor */
365: for(j=0;j<l;j++){
366: a= *HH(i,j);
367: b=*HH(i+1,j);
368: temps=PetscConj(c)* a+s* b;
369: *HH(i+1,j)=-s*a+c*b;
370: *HH(i,j)=temps;
371: }
372: #else
373: /* update the Q factor */
374: ierr= VecCopy(Q[i],temp);
375: VecAXPBY(temp,s,c,Q[i+1]); /*temp= c*Q[i]+s*Q[i+1] */
376: VecAXPBY(Q[i+1],-s,c,Q[i]); /* Q[i+1]= -s*Q[i] + c*Q[i+1] */
377: ierr= VecCopy(temp,Q[i]); /* Q[i]= c*Q[i] + s*Q[i+1] */
378: /* update the R factor */
379: for(j=0;j<l;j++){
380: a= *HH(i,j);
381: b=*HH(i+1,j);
382: temps=c* a+s* b;
383: *HH(i+1,j)=-s*a+c*b;
384: *HH(i,j)=temps;
385: }
386: #endif
387: }
388: }
390: /* add a new vector, use modified Gram-Schmidt */
391: ierr= VecCopy(dF[it],temp);
392: for(i=0;i<it;i++){
393: ierr=VecDot(temp,Q[i],HH(i,it)); /* h(i,l-1)= dF[l-1]'*Q[i] */
394: VecAXPBY(temp,-*HH(i,it),1.0,Q[i]); /* temp= temp- h(i,l-1)*Q[i] */
395: }
396: ierr=VecCopy(temp,Q[it]);
397: ierr=VecNormalize(Q[it],&areal);
398: *HH(it,it) = areal;
399:
402: /* modify the RHS with Q'*Fold*/
403:
404: for(i=0;i<l;i++)
405: ierr=VecDot(Fold,Q[i],ngmres->nrs+i); /* nrs= Fold'*Q[i] */
406:
407: /* start backsubstitution to solve the least square problem */
409: if (*HH(it,it) != 0.0) {
410: nrs[it] = nrs[it]/ *HH(it,it);
411: } else {
412: ksp->reason = KSP_DIVERGED_BREAKDOWN;
413: PetscInfo2(ksp,"Likely your matrix or preconditioner is singular. HH(it,it) is identically zero; it = %D nrs(it) = %G",it,10);
414: return(0);
415: }
416: for (ii=1; ii<=it; ii++) {
417: i = it - ii;
418: tt = nrs[i];
419: for (j=i+1; j<=it; j++) tt = tt - *HH(i,j) * nrs[j];
420: if (*HH(i,i) == 0.0) {
421: ksp->reason = KSP_DIVERGED_BREAKDOWN;
422: PetscInfo1(ksp,"Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; i = %D",i);
423: return(0);
424: }
425: nrs[i] = tt / *HH(i,i);
426: }
428:
429: return(0);
430: }