Actual source code: cheby.c

  1: /*$Id: cheby.c,v 1.94 2001/08/07 03:03:53 balay Exp $*/
  2: /*
  3:     This is a first attempt at a Chebychev routine, it is not 
  4:     necessarily well optimized.
  5: */
 6:  #include src/ksp/ksp/kspimpl.h
 7:  #include src/ksp/ksp/impls/cheby/chebctx.h

 11: int KSPSetUp_Chebychev(KSP ksp)
 12: {

 16:   if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(2,"no symmetric preconditioning for KSPCHEBYCHEV");
 17:   KSPDefaultGetWork(ksp,3);
 18:   return(0);
 19: }

 21: EXTERN_C_BEGIN
 24: int KSPChebychevSetEigenvalues_Chebychev(KSP ksp,PetscReal emax,PetscReal emin)
 25: {
 26:   KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;

 29:   if (emax <= emin) SETERRQ2(1,"Maximum eigenvalue must be larger than minimum: max %g min %g",emax,emin);
 30:   if (emax*emin <= 0.0) SETERRQ2(1,"Both eigenvalues must be of the same sign: max %g min %g",emax,emin);
 31:   chebychevP->emax = emax;
 32:   chebychevP->emin = emin;
 33:   return(0);
 34: }
 35: EXTERN_C_END

 39: /*@
 40:    KSPChebychevSetEigenvalues - Sets estimates for the extreme eigenvalues
 41:    of the preconditioned problem.

 43:    Collective on KSP

 45:    Input Parameters:
 46: +  ksp - the Krylov space context
 47: -  emax, emin - the eigenvalue estimates

 49:   Options Database:
 50: .  -ksp_chebychev_eigenvalues emin,emax

 52:    Level: intermediate

 54: .keywords: KSP, Chebyshev, set, eigenvalues
 55: @*/
 56: int KSPChebychevSetEigenvalues(KSP ksp,PetscReal emax,PetscReal emin)
 57: {
 58:   int ierr,(*f)(KSP,PetscReal,PetscReal);

 62:   PetscObjectQueryFunction((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",(void (**)(void))&f);
 63:   if (f) {
 64:     (*f)(ksp,emax,emin);
 65:   }
 66:   return(0);
 67: }

 71: int KSPSetFromOptions_Chebychev(KSP ksp)
 72: {
 73:   KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
 74:   int            ierr;
 75:   int            two = 2;

 78:   PetscOptionsHead("KSP Chebychev Options");
 79:     PetscOptionsRealArray("-ksp_chebychev_eigenvalues","extreme eigenvalues","KSPChebychevSetEigenvalues",&cheb->emin,&two,0);
 80:   PetscOptionsTail();
 81:   return(0);
 82: }

 86: int KSPSolve_Chebychev(KSP ksp)
 87: {
 88:   int              k,kp1,km1,maxit,ktmp,i,ierr;
 89:   PetscScalar      alpha,omegaprod,mu,omega,Gamma,c[3],scale,mone = -1.0,tmp;
 90:   PetscReal        rnorm;
 91:   Vec              x,b,p[3],r;
 92:   KSP_Chebychev    *chebychevP = (KSP_Chebychev*)ksp->data;
 93:   Mat              Amat,Pmat;
 94:   MatStructure     pflag;
 95:   PetscTruth       diagonalscale;

 98:   PCDiagonalScale(ksp->B,&diagonalscale);
 99:   if (diagonalscale) SETERRQ1(1,"Krylov method %s does not support diagonal scaling",ksp->type_name);

101:   ksp->its = 0;
102:   PCGetOperators(ksp->B,&Amat,&Pmat,&pflag);
103:   maxit    = ksp->max_it;

105:   /* These three point to the three active solutions, we
106:      rotate these three at each solution update */
107:   km1    = 0; k = 1; kp1 = 2;
108:   x      = ksp->vec_sol;
109:   b      = ksp->vec_rhs;
110:   p[km1] = x;
111:   p[k]   = ksp->work[0];
112:   p[kp1] = ksp->work[1];
113:   r      = ksp->work[2];

115:   /* use scale*B as our preconditioner */
116:   scale  = 2.0/(chebychevP->emax + chebychevP->emin);

118:   /*   -alpha <=  scale*lambda(B^{-1}A) <= alpha   */
119:   alpha  = 1.0 - scale*(chebychevP->emin); ;
120:   Gamma  = 1.0;
121:   mu     = 1.0/alpha;
122:   omegaprod = 2.0/alpha;

124:   c[km1] = 1.0;
125:   c[k]   = mu;

127:   if (!ksp->guess_zero) {
128:     KSP_MatMult(ksp,Amat,x,r);     /*  r = b - Ax     */
129:     VecAYPX(&mone,b,r);
130:   } else {
131:     VecCopy(b,r);
132:   }
133: 
134:   KSP_PCApply(ksp,ksp->B,r,p[k]);  /* p[k] = scale B^{-1}r + x */
135:   VecAYPX(&scale,x,p[k]);

137:   for (i=0; i<maxit; i++) {
138:     PetscObjectTakeAccess(ksp);
139:     ksp->its++;
140:     PetscObjectGrantAccess(ksp);
141:     c[kp1] = 2.0*mu*c[k] - c[km1];
142:     omega = omegaprod*c[k]/c[kp1];

144:     KSP_MatMult(ksp,Amat,p[k],r);                 /*  r = b - Ap[k]    */
145:     VecAYPX(&mone,b,r);
146:     KSP_PCApply(ksp,ksp->B,r,p[kp1]);             /*  p[kp1] = B^{-1}z  */

148:     /* calculate residual norm if requested */
149:     if (ksp->normtype != KSP_NO_NORM) {
150:       if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
151:       else {VecNorm(p[kp1],NORM_2,&rnorm);}
152:       PetscObjectTakeAccess(ksp);
153:       ksp->rnorm                              = rnorm;
154:       PetscObjectGrantAccess(ksp);
155:       ksp->vec_sol = p[k];
156:       KSPLogResidualHistory(ksp,rnorm);
157:       KSPMonitor(ksp,i,rnorm);
158:       (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
159:       if (ksp->reason) break;
160:     }

162:     /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */
163:     tmp  = omega*Gamma*scale;
164:     VecScale(&tmp,p[kp1]);
165:     tmp  = 1.0-omega; VecAXPY(&tmp,p[km1],p[kp1]);
166:     VecAXPY(&omega,p[k],p[kp1]);

168:     ktmp = km1;
169:     km1  = k;
170:     k    = kp1;
171:     kp1  = ktmp;
172:   }
173:   if (!ksp->reason && ksp->normtype != KSP_NO_NORM) {
174:     ksp->reason = KSP_DIVERGED_ITS;
175:     KSP_MatMult(ksp,Amat,p[k],r);       /*  r = b - Ap[k]    */
176:     VecAYPX(&mone,b,r);
177:     if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
178:     else {
179:       KSP_PCApply(ksp,ksp->B,r,p[kp1]); /* p[kp1] = B^{-1}z */
180:       VecNorm(p[kp1],NORM_2,&rnorm);
181:     }
182:     PetscObjectTakeAccess(ksp);
183:     ksp->rnorm                              = rnorm;
184:     PetscObjectGrantAccess(ksp);
185:     ksp->vec_sol = p[k];
186:     KSPLogResidualHistory(ksp,rnorm);
187:     KSPMonitor(ksp,i,rnorm);
188:   }

190:   /* make sure solution is in vector x */
191:   ksp->vec_sol = x;
192:   if (k) {
193:     VecCopy(p[k],x);
194:   }
195:   return(0);
196: }

200: int KSPView_Chebychev(KSP ksp,PetscViewer viewer)
201: {
202:   KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
203:   int           ierr;
204:   PetscTruth    isascii;

207:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
208:   if (isascii) {
209:     PetscViewerASCIIPrintf(viewer,"  Chebychev: eigenvalue estimates:  min = %g, max = %g\n",cheb->emin,cheb->emax);
210:   } else {
211:     SETERRQ1(1,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
212:   }
213:   return(0);
214: }

216: /*MC
217:      KSPCHEBYCHEV - The preconditioned Chebychev iterative method

219:    Options Database Keys:
220: .   -ksp_chebychev_eigenvalues <emin,emax> - set approximations to the smallest and largest eigenvalues
221:                   of the preconditioned operator. If these are accurate you will get much faster convergence.

223:    Level: beginner

225:    Notes: The Chebychev method requires both the matrix and preconditioner to 
226:           be symmetric positive (semi) definite

228: .seealso:  KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
229:            KSPChebychevSetEigenvalues()

231: M*/

233: EXTERN_C_BEGIN
236: int KSPCreate_Chebychev(KSP ksp)
237: {
238:   int           ierr;
239:   KSP_Chebychev *chebychevP;

242:   PetscNew(KSP_Chebychev,&chebychevP);
243:   PetscLogObjectMemory(ksp,sizeof(KSP_Chebychev));

245:   ksp->data                      = (void*)chebychevP;
246:   ksp->pc_side                   = PC_LEFT;

248:   chebychevP->emin               = 1.e-2;
249:   chebychevP->emax               = 1.e+2;

251:   ksp->ops->setup                = KSPSetUp_Chebychev;
252:   ksp->ops->solve                = KSPSolve_Chebychev;
253:   ksp->ops->destroy              = KSPDefaultDestroy;
254:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
255:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;
256:   ksp->ops->setfromoptions       = KSPSetFromOptions_Chebychev;
257:   ksp->ops->view                 = KSPView_Chebychev;

259:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
260:                                     "KSPChebychevSetEigenvalues_Chebychev",
261:                                     KSPChebychevSetEigenvalues_Chebychev);
262:   return(0);
263: }
264: EXTERN_C_END