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