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: }