Actual source code: cheby.c
1: /*$Id: cheby.c,v 1.93 2001/04/10 19:36:33 bsmith Exp $*/
2: /*
3: This is a first attempt at a Chebychev routine, it is not
4: necessarily well optimized.
5: */
6: #include "src/sles/ksp/kspimpl.h" /*I "petscksp.h" I*/
7: #include "src/sles/ksp/impls/cheby/chebctx.h"
9: int KSPSetUp_Chebychev(KSP ksp)
10: {
14: if (ksp->pc_side == PC_SYMMETRIC) SETERRQ(2,"no symmetric preconditioning for KSPCHEBYCHEV");
15: KSPDefaultGetWork(ksp,3);
16: return(0);
17: }
19: EXTERN_C_BEGIN
20: int KSPChebychevSetEigenvalues_Chebychev(KSP ksp,PetscReal emax,PetscReal emin)
21: {
22: KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;
25: chebychevP->emax = emax;
26: chebychevP->emin = emin;
27: return(0);
28: }
29: EXTERN_C_END
31: /*@
32: KSPChebychevSetEigenvalues - Sets estimates for the extreme eigenvalues
33: of the preconditioned problem.
35: Collective on KSP
37: Input Parameters:
38: + ksp - the Krylov space context
39: - emax, emin - the eigenvalue estimates
41: Level: intermediate
43: .keywords: KSP, Chebyshev, set, eigenvalues
44: @*/
45: int KSPChebychevSetEigenvalues(KSP ksp,PetscReal emax,PetscReal emin)
46: {
47: int ierr,(*f)(KSP,PetscReal,PetscReal);
51: PetscObjectQueryFunction((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",(void (**)())&f);
52: if (f) {
53: (*f)(ksp,emax,emin);
54: }
55: return(0);
56: }
58: int KSPSolve_Chebychev(KSP ksp,int *its)
59: {
60: int k,kp1,km1,maxit,ktmp,i,ierr;
61: Scalar alpha,omegaprod,mu,omega,Gamma,c[3],scale,mone = -1.0,tmp;
62: PetscReal rnorm;
63: Vec x,b,p[3],r;
64: KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data;
65: Mat Amat,Pmat;
66: MatStructure pflag;
67: PetscTruth pres,diagonalscale;
70: ierr = PCDiagonalScale(ksp->B,&diagonalscale);
71: if (diagonalscale) SETERRQ1(1,"Krylov method %s does not support diagonal scaling",ksp->type_name);
73: ksp->its = 0;
74: ierr = PCGetOperators(ksp->B,&Amat,&Pmat,&pflag);
75: maxit = ksp->max_it;
76: pres = ksp->use_pres;
78: /* These three point to the three active solutions, we
79: rotate these three at each solution update */
80: km1 = 0; k = 1; kp1 = 2;
81: x = ksp->vec_sol;
82: b = ksp->vec_rhs;
83: p[km1] = x;
84: p[k] = ksp->work[0];
85: p[kp1] = ksp->work[1];
86: r = ksp->work[2];
88: /* use scale*B as our preconditioner */
89: scale = 2.0/(chebychevP->emax + chebychevP->emin);
91: /* -alpha <= scale*lambda(B^{-1}A) <= alpha */
92: alpha = 1.0 - scale*(chebychevP->emin); ;
93: Gamma = 1.0;
94: mu = 1.0/alpha;
95: omegaprod = 2.0/alpha;
97: c[km1] = 1.0;
98: c[k] = mu;
100: if (!ksp->guess_zero) {
101: KSP_MatMult(ksp,Amat,x,r); /* r = b - Ax */
102: VecAYPX(&mone,b,r);
103: } else {
104: VecCopy(b,r);
105: }
106:
107: KSP_PCApply(ksp,ksp->B,r,p[k]); /* p[k] = scale B^{-1}r + x */
108: VecAYPX(&scale,x,p[k]);
110: for (i=0; i<maxit; i++) {
111: PetscObjectTakeAccess(ksp);
112: ksp->its++;
113: PetscObjectGrantAccess(ksp);
114: c[kp1] = 2.0*mu*c[k] - c[km1];
115: omega = omegaprod*c[k]/c[kp1];
117: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
118: VecAYPX(&mone,b,r);
119: KSP_PCApply(ksp,ksp->B,r,p[kp1]); /* p[kp1] = B^{-1}z */
121: /* calculate residual norm if requested */
122: if (ksp->calc_res) {
123: if (!pres) {VecNorm(r,NORM_2,&rnorm);}
124: else {VecNorm(p[kp1],NORM_2,&rnorm);}
125: PetscObjectTakeAccess(ksp);
126: ksp->rnorm = rnorm;
127: PetscObjectGrantAccess(ksp);
128: ksp->vec_sol = p[k];
129: KSPLogResidualHistory(ksp,rnorm);
130: KSPMonitor(ksp,i,rnorm);
131: (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
132: if (ksp->reason) break;
133: }
135: /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */
136: tmp = omega*Gamma*scale;
137: VecScale(&tmp,p[kp1]);
138: tmp = 1.0-omega; VecAXPY(&tmp,p[km1],p[kp1]);
139: VecAXPY(&omega,p[k],p[kp1]);
141: ktmp = km1;
142: km1 = k;
143: k = kp1;
144: kp1 = ktmp;
145: }
146: if (!ksp->reason && ksp->calc_res) {
147: ksp->reason = KSP_DIVERGED_ITS;
148: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
149: VecAYPX(&mone,b,r);
150: if (!pres) {VecNorm(r,NORM_2,&rnorm);}
151: else {
152: KSP_PCApply(ksp,ksp->B,r,p[kp1]); /* p[kp1] = B^{-1}z */
153: VecNorm(p[kp1],NORM_2,&rnorm);
154: }
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: }
163: /* make sure solution is in vector x */
164: ksp->vec_sol = x;
165: if (k) {
166: VecCopy(p[k],x);
167: }
168: *its = ksp->its;
169: return(0);
170: }
172: int KSPView_Chebychev(KSP ksp,PetscViewer viewer)
173: {
174: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
175: int ierr;
176: PetscTruth isascii;
179: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
180: if (isascii) {
181: PetscViewerASCIIPrintf(viewer," Chebychev: eigenvalue estimates: min = %g, max = %gn",cheb->emin,cheb->emax);
182: } else {
183: SETERRQ1(1,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
184: }
185: return(0);
186: }
188: EXTERN_C_BEGIN
189: int KSPCreate_Chebychev(KSP ksp)
190: {
191: int ierr;
192: KSP_Chebychev *chebychevP;
195: PetscNew(KSP_Chebychev,&chebychevP);
196: PetscLogObjectMemory(ksp,sizeof(KSP_Chebychev));
198: ksp->data = (void*)chebychevP;
199: ksp->pc_side = PC_LEFT;
200: ksp->calc_res = PETSC_TRUE;
202: chebychevP->emin = 1.e-2;
203: chebychevP->emax = 1.e+2;
205: ksp->ops->setup = KSPSetUp_Chebychev;
206: ksp->ops->solve = KSPSolve_Chebychev;
207: ksp->ops->destroy = KSPDefaultDestroy;
208: ksp->ops->buildsolution = KSPDefaultBuildSolution;
209: ksp->ops->buildresidual = KSPDefaultBuildResidual;
210: ksp->ops->setfromoptions = 0;
211: ksp->ops->view = KSPView_Chebychev;
213: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
214: "KSPChebychevSetEigenvalues_Chebychev",
215: KSPChebychevSetEigenvalues_Chebychev);
216: return(0);
217: }
218: EXTERN_C_END