Actual source code: cheby.c
1: #define PETSCKSP_DLL
3: /*
4: This is a first attempt at a Chebychev routine, it is not
5: necessarily well optimized.
6: */
7: #include src/ksp/ksp/kspimpl.h
8: #include src/ksp/ksp/impls/cheby/chebctx.h
12: PetscErrorCode KSPSetUp_Chebychev(KSP ksp)
13: {
17: if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(PETSC_ERR_SUP,"no symmetric preconditioning for KSPCHEBYCHEV");
18: KSPDefaultGetWork(ksp,3);
19: return(0);
20: }
25: PetscErrorCode PETSCKSP_DLLEXPORT KSPChebychevSetEigenvalues_Chebychev(KSP ksp,PetscReal emax,PetscReal emin)
26: {
27: KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;
30: if (emax <= emin) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Maximum eigenvalue must be larger than minimum: max %g min %G",emax,emin);
31: if (emax*emin <= 0.0) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Both eigenvalues must be of the same sign: max %G min %G",emax,emin);
32: chebychevP->emax = emax;
33: chebychevP->emin = emin;
34: return(0);
35: }
40: /*@
41: KSPChebychevSetEigenvalues - Sets estimates for the extreme eigenvalues
42: of the preconditioned problem.
44: Collective on KSP
46: Input Parameters:
47: + ksp - the Krylov space context
48: - emax, emin - the eigenvalue estimates
50: Options Database:
51: . -ksp_chebychev_eigenvalues emin,emax
53: Level: intermediate
55: .keywords: KSP, Chebyshev, set, eigenvalues
56: @*/
57: PetscErrorCode PETSCKSP_DLLEXPORT KSPChebychevSetEigenvalues(KSP ksp,PetscReal emax,PetscReal emin)
58: {
59: PetscErrorCode ierr,(*f)(KSP,PetscReal,PetscReal);
63: PetscObjectQueryFunction((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",(void (**)(void))&f);
64: if (f) {
65: (*f)(ksp,emax,emin);
66: }
67: return(0);
68: }
72: PetscErrorCode KSPSetFromOptions_Chebychev(KSP ksp)
73: {
74: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
76: PetscInt two = 2;
79: PetscOptionsHead("KSP Chebychev Options");
80: PetscOptionsRealArray("-ksp_chebychev_eigenvalues","extreme eigenvalues","KSPChebychevSetEigenvalues",&cheb->emin,&two,0);
81: PetscOptionsTail();
82: return(0);
83: }
87: PetscErrorCode KSPSolve_Chebychev(KSP ksp)
88: {
90: PetscInt k,kp1,km1,maxit,ktmp,i;
91: PetscScalar alpha,omegaprod,mu,omega,Gamma,c[3],scale;
92: PetscReal rnorm;
93: Vec x,b,p[3],r;
94: KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;
95: Mat Amat,Pmat;
96: MatStructure pflag;
97: PetscTruth diagonalscale;
100: PCDiagonalScale(ksp->pc,&diagonalscale);
101: if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",ksp->type_name);
103: ksp->its = 0;
104: PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
105: maxit = ksp->max_it;
107: /* These three point to the three active solutions, we
108: rotate these three at each solution update */
109: km1 = 0; k = 1; kp1 = 2;
110: x = ksp->vec_sol;
111: b = ksp->vec_rhs;
112: p[km1] = x;
113: p[k] = ksp->work[0];
114: p[kp1] = ksp->work[1];
115: r = ksp->work[2];
117: /* use scale*B as our preconditioner */
118: scale = 2.0/(chebychevP->emax + chebychevP->emin);
120: /* -alpha <= scale*lambda(B^{-1}A) <= alpha */
121: alpha = 1.0 - scale*(chebychevP->emin); ;
122: Gamma = 1.0;
123: mu = 1.0/alpha;
124: omegaprod = 2.0/alpha;
126: c[km1] = 1.0;
127: c[k] = mu;
129: if (!ksp->guess_zero) {
130: KSP_MatMult(ksp,Amat,x,r); /* r = b - Ax */
131: VecAYPX(r,-1.0,b);
132: } else {
133: VecCopy(b,r);
134: }
135:
136: KSP_PCApply(ksp,r,p[k]); /* p[k] = scale B^{-1}r + x */
137: VecAYPX(p[k],scale,x);
139: for (i=0; i<maxit; i++) {
140: PetscObjectTakeAccess(ksp);
141: ksp->its++;
142: PetscObjectGrantAccess(ksp);
143: c[kp1] = 2.0*mu*c[k] - c[km1];
144: omega = omegaprod*c[k]/c[kp1];
146: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
147: VecAYPX(r,-1.0,b);
148: KSP_PCApply(ksp,r,p[kp1]); /* p[kp1] = B^{-1}z */
150: /* calculate residual norm if requested */
151: if (ksp->normtype != KSP_NO_NORM) {
152: if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
153: else {VecNorm(p[kp1],NORM_2,&rnorm);}
154: PetscObjectTakeAccess(ksp);
155: ksp->rnorm = rnorm;
156: PetscObjectGrantAccess(ksp);
157: ksp->vec_sol = p[k];
158: KSPLogResidualHistory(ksp,rnorm);
159: KSPMonitor(ksp,i,rnorm);
160: (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
161: if (ksp->reason) break;
162: }
164: /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */
165: VecScale(p[kp1],omega*Gamma*scale);
166: VecAXPY(p[kp1],1.0-omega,p[km1]);
167: VecAXPY(p[kp1],omega,p[k]);
169: ktmp = km1;
170: km1 = k;
171: k = kp1;
172: kp1 = ktmp;
173: }
174: if (!ksp->reason && ksp->normtype != KSP_NO_NORM) {
175: ksp->reason = KSP_DIVERGED_ITS;
176: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
177: VecAYPX(r,-1.0,b);
178: if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
179: else {
180: KSP_PCApply(ksp,r,p[kp1]); /* p[kp1] = B^{-1}z */
181: VecNorm(p[kp1],NORM_2,&rnorm);
182: }
183: PetscObjectTakeAccess(ksp);
184: ksp->rnorm = rnorm;
185: PetscObjectGrantAccess(ksp);
186: ksp->vec_sol = p[k];
187: KSPLogResidualHistory(ksp,rnorm);
188: KSPMonitor(ksp,i,rnorm);
189: }
191: /* make sure solution is in vector x */
192: ksp->vec_sol = x;
193: if (k) {
194: VecCopy(p[k],x);
195: }
196: return(0);
197: }
201: PetscErrorCode KSPView_Chebychev(KSP ksp,PetscViewer viewer)
202: {
203: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
205: PetscTruth iascii;
208: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
209: if (iascii) {
210: PetscViewerASCIIPrintf(viewer," Chebychev: eigenvalue estimates: min = %G, max = %G\n",cheb->emin,cheb->emax);
211: } else {
212: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
213: }
214: return(0);
215: }
217: /*MC
218: KSPCHEBYCHEV - The preconditioned Chebychev iterative method
220: Options Database Keys:
221: . -ksp_chebychev_eigenvalues <emin,emax> - set approximations to the smallest and largest eigenvalues
222: of the preconditioned operator. If these are accurate you will get much faster convergence.
224: Level: beginner
226: Notes: The Chebychev method requires both the matrix and preconditioner to
227: be symmetric positive (semi) definite
229: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
230: KSPChebychevSetEigenvalues()
232: M*/
237: PetscErrorCode PETSCKSP_DLLEXPORT KSPCreate_Chebychev(KSP ksp)
238: {
240: KSP_Chebychev *chebychevP;
243: PetscNew(KSP_Chebychev,&chebychevP);
244: PetscLogObjectMemory(ksp,sizeof(KSP_Chebychev));
246: ksp->data = (void*)chebychevP;
247: ksp->pc_side = PC_LEFT;
249: chebychevP->emin = 1.e-2;
250: chebychevP->emax = 1.e+2;
252: ksp->ops->setup = KSPSetUp_Chebychev;
253: ksp->ops->solve = KSPSolve_Chebychev;
254: ksp->ops->destroy = KSPDefaultDestroy;
255: ksp->ops->buildsolution = KSPDefaultBuildSolution;
256: ksp->ops->buildresidual = KSPDefaultBuildResidual;
257: ksp->ops->setfromoptions = KSPSetFromOptions_Chebychev;
258: ksp->ops->view = KSPView_Chebychev;
260: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
261: "KSPChebychevSetEigenvalues_Chebychev",
262: KSPChebychevSetEigenvalues_Chebychev);
263: return(0);
264: }