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/sles/ksp/kspimpl.h
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 (**)(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: PetscScalar 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 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;
77: /* These three point to the three active solutions, we
78: rotate these three at each solution update */
79: km1 = 0; k = 1; kp1 = 2;
80: x = ksp->vec_sol;
81: b = ksp->vec_rhs;
82: p[km1] = x;
83: p[k] = ksp->work[0];
84: p[kp1] = ksp->work[1];
85: r = ksp->work[2];
87: /* use scale*B as our preconditioner */
88: scale = 2.0/(chebychevP->emax + chebychevP->emin);
90: /* -alpha <= scale*lambda(B^{-1}A) <= alpha */
91: alpha = 1.0 - scale*(chebychevP->emin); ;
92: Gamma = 1.0;
93: mu = 1.0/alpha;
94: omegaprod = 2.0/alpha;
96: c[km1] = 1.0;
97: c[k] = mu;
99: if (!ksp->guess_zero) {
100: KSP_MatMult(ksp,Amat,x,r); /* r = b - Ax */
101: VecAYPX(&mone,b,r);
102: } else {
103: VecCopy(b,r);
104: }
105:
106: KSP_PCApply(ksp,ksp->B,r,p[k]); /* p[k] = scale B^{-1}r + x */
107: VecAYPX(&scale,x,p[k]);
109: for (i=0; i<maxit; i++) {
110: PetscObjectTakeAccess(ksp);
111: ksp->its++;
112: PetscObjectGrantAccess(ksp);
113: c[kp1] = 2.0*mu*c[k] - c[km1];
114: omega = omegaprod*c[k]/c[kp1];
116: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
117: VecAYPX(&mone,b,r);
118: KSP_PCApply(ksp,ksp->B,r,p[kp1]); /* p[kp1] = B^{-1}z */
120: /* calculate residual norm if requested */
121: if (ksp->normtype != KSP_NO_NORM) {
122: if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
123: else {VecNorm(p[kp1],NORM_2,&rnorm);}
124: PetscObjectTakeAccess(ksp);
125: ksp->rnorm = rnorm;
126: PetscObjectGrantAccess(ksp);
127: ksp->vec_sol = p[k];
128: KSPLogResidualHistory(ksp,rnorm);
129: KSPMonitor(ksp,i,rnorm);
130: (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
131: if (ksp->reason) break;
132: }
134: /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */
135: tmp = omega*Gamma*scale;
136: VecScale(&tmp,p[kp1]);
137: tmp = 1.0-omega; VecAXPY(&tmp,p[km1],p[kp1]);
138: VecAXPY(&omega,p[k],p[kp1]);
140: ktmp = km1;
141: km1 = k;
142: k = kp1;
143: kp1 = ktmp;
144: }
145: if (!ksp->reason && ksp->normtype != KSP_NO_NORM) {
146: ksp->reason = KSP_DIVERGED_ITS;
147: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
148: VecAYPX(&mone,b,r);
149: if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {VecNorm(r,NORM_2,&rnorm);}
150: else {
151: KSP_PCApply(ksp,ksp->B,r,p[kp1]); /* p[kp1] = B^{-1}z */
152: VecNorm(p[kp1],NORM_2,&rnorm);
153: }
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: }
162: /* make sure solution is in vector x */
163: ksp->vec_sol = x;
164: if (k) {
165: VecCopy(p[k],x);
166: }
167: *its = ksp->its;
168: return(0);
169: }
171: int KSPView_Chebychev(KSP ksp,PetscViewer viewer)
172: {
173: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
174: int ierr;
175: PetscTruth isascii;
178: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
179: if (isascii) {
180: PetscViewerASCIIPrintf(viewer," Chebychev: eigenvalue estimates: min = %g, max = %gn",cheb->emin,cheb->emax);
181: } else {
182: SETERRQ1(1,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
183: }
184: return(0);
185: }
187: EXTERN_C_BEGIN
188: int KSPCreate_Chebychev(KSP ksp)
189: {
190: int ierr;
191: KSP_Chebychev *chebychevP;
194: PetscNew(KSP_Chebychev,&chebychevP);
195: PetscLogObjectMemory(ksp,sizeof(KSP_Chebychev));
197: ksp->data = (void*)chebychevP;
198: ksp->pc_side = PC_LEFT;
200: chebychevP->emin = 1.e-2;
201: chebychevP->emax = 1.e+2;
203: ksp->ops->setup = KSPSetUp_Chebychev;
204: ksp->ops->solve = KSPSolve_Chebychev;
205: ksp->ops->destroy = KSPDefaultDestroy;
206: ksp->ops->buildsolution = KSPDefaultBuildSolution;
207: ksp->ops->buildresidual = KSPDefaultBuildResidual;
208: ksp->ops->setfromoptions = 0;
209: ksp->ops->view = KSPView_Chebychev;
211: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
212: "KSPChebychevSetEigenvalues_Chebychev",
213: KSPChebychevSetEigenvalues_Chebychev);
214: return(0);
215: }
216: EXTERN_C_END