Actual source code: cheby.c

  1: #define PETSCKSP_DLL

 3:  #include private/kspimpl.h
 4:  #include ../src/ksp/ksp/impls/cheby/chebctx.h

  8: PetscErrorCode KSPSetUp_Chebychev(KSP ksp)
  9: {

 13:   if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(PETSC_ERR_SUP,"no symmetric preconditioning for KSPCHEBYCHEV");
 14:   KSPDefaultGetWork(ksp,3);
 15:   return(0);
 16: }

 21: PetscErrorCode  KSPChebychevSetEigenvalues_Chebychev(KSP ksp,PetscReal emax,PetscReal emin)
 22: {
 23:   KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;

 26:   if (emax <= emin) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Maximum eigenvalue must be larger than minimum: max %g min %G",emax,emin);
 27:   if (emax*emin <= 0.0) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Both eigenvalues must be of the same sign: max %G min %G",emax,emin);
 28:   chebychevP->emax = emax;
 29:   chebychevP->emin = emin;
 30:   return(0);
 31: }

 36: /*@
 37:    KSPChebychevSetEigenvalues - Sets estimates for the extreme eigenvalues
 38:    of the preconditioned problem.

 40:    Collective on KSP

 42:    Input Parameters:
 43: +  ksp - the Krylov space context
 44: -  emax, emin - the eigenvalue estimates

 46:   Options Database:
 47: .  -ksp_chebychev_eigenvalues emin,emax

 49:    Note: If you run with the Krylov method of KSPCG with the option -ksp_monitor_singular_value it will 
 50:     for that given matrix and preconditioner an estimate of the extreme eigenvalues.

 52:    Level: intermediate

 54: .keywords: KSP, Chebyshev, set, eigenvalues
 55: @*/
 56: PetscErrorCode  KSPChebychevSetEigenvalues(KSP ksp,PetscReal emax,PetscReal emin)
 57: {
 58:   PetscErrorCode 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: PetscErrorCode KSPSetFromOptions_Chebychev(KSP ksp)
 72: {
 73:   KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
 75:   PetscInt       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: PetscErrorCode KSPSolve_Chebychev(KSP ksp)
 87: {
 89:   PetscInt       k,kp1,km1,maxit,ktmp,i;
 90:   PetscScalar    alpha,omegaprod,mu,omega,Gamma,c[3],scale;
 91:   PetscReal      rnorm = 0.0;
 92:   Vec            x,b,p[3],r;
 93:   KSP_Chebychev  *chebychevP = (KSP_Chebychev*)ksp->data;
 94:   Mat            Amat,Pmat;
 95:   MatStructure   pflag;
 96:   PetscTruth     diagonalscale;

 99:   if (ksp->normtype == KSP_NORM_NATURAL) SETERRQ(PETSC_ERR_SUP,"Cannot use natural residual norm with KSPCHEBYCHEV");

101:   PCDiagonalScale(ksp->pc,&diagonalscale);
102:   if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);

104:   ksp->its = 0;
105:   PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
106:   maxit    = ksp->max_it;

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

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

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

127:   c[km1] = 1.0;
128:   c[k]   = mu;

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

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

147:     KSP_MatMult(ksp,Amat,p[k],r);                 /*  r = b - Ap[k]    */
148:     VecAYPX(r,-1.0,b);
149:     KSP_PCApply(ksp,r,p[kp1]);             /*  p[kp1] = B^{-1}z  */

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

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

170:     ktmp = km1;
171:     km1  = k;
172:     k    = kp1;
173:     kp1  = ktmp;
174:   }
175:   if (!ksp->reason) {
176:     if (ksp->normtype != KSP_NORM_NO) {
177:       KSP_MatMult(ksp,Amat,p[k],r);       /*  r = b - Ap[k]    */
178:       VecAYPX(r,-1.0,b);
179:       if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
180:         VecNorm(r,NORM_2,&rnorm);
181:       } else {
182:         KSP_PCApply(ksp,r,p[kp1]); /* p[kp1] = B^{-1}z */
183:         VecNorm(p[kp1],NORM_2,&rnorm);
184:       }
185:       PetscObjectTakeAccess(ksp);
186:       ksp->rnorm = rnorm;
187:       PetscObjectGrantAccess(ksp);
188:       ksp->vec_sol = p[k];
189:       KSPLogResidualHistory(ksp,rnorm);
190:       KSPMonitor(ksp,i,rnorm);
191:     }
192:     if (ksp->its >= ksp->max_it) {
193:       if (ksp->normtype != KSP_NORM_NO) {
194:         (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
195:         if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
196:       } else {
197:         ksp->reason = KSP_CONVERGED_ITS;
198:       }
199:     }
200:   }

202:   /* make sure solution is in vector x */
203:   ksp->vec_sol = x;
204:   if (k) {
205:     VecCopy(p[k],x);
206:   }
207:   return(0);
208: }

212: PetscErrorCode KSPView_Chebychev(KSP ksp,PetscViewer viewer)
213: {
214:   KSP_Chebychev  *cheb = (KSP_Chebychev*)ksp->data;
216:   PetscTruth     iascii;

219:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
220:   if (iascii) {
221:     PetscViewerASCIIPrintf(viewer,"  Chebychev: eigenvalue estimates:  min = %G, max = %G\n",cheb->emin,cheb->emax);
222:   } else {
223:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
224:   }
225:   return(0);
226: }

230: PetscErrorCode KSPDestroy_Chebychev(KSP ksp)
231: {

235:   KSPDefaultDestroy(ksp);
236:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C","",PETSC_NULL);
237:   return(0);
238: }

240: /*MC
241:      KSPCHEBYCHEV - The preconditioned Chebychev iterative method

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

247:    Level: beginner

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

252: .seealso:  KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
253:            KSPChebychevSetEigenvalues(), KSPRICHARDSON, KSPCG

255: M*/

260: PetscErrorCode  KSPCreate_Chebychev(KSP ksp)
261: {
263:   KSP_Chebychev  *chebychevP;

266:   PetscNewLog(ksp,KSP_Chebychev,&chebychevP);

268:   ksp->data                      = (void*)chebychevP;
269:   ksp->pc_side                   = PC_LEFT;

271:   chebychevP->emin               = 1.e-2;
272:   chebychevP->emax               = 1.e+2;

274:   ksp->ops->setup                = KSPSetUp_Chebychev;
275:   ksp->ops->solve                = KSPSolve_Chebychev;
276:   ksp->ops->destroy              = KSPDestroy_Chebychev;
277:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
278:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;
279:   ksp->ops->setfromoptions       = KSPSetFromOptions_Chebychev;
280:   ksp->ops->view                 = KSPView_Chebychev;

282:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
283:                                     "KSPChebychevSetEigenvalues_Chebychev",
284:                                     KSPChebychevSetEigenvalues_Chebychev);
285:   return(0);
286: }