Actual source code: cheby.c
2: #include <private/kspimpl.h> /*I "petscksp.h" I*/
3: #include <../src/ksp/ksp/impls/cheby/chebychevimpl.h>
7: PetscErrorCode KSPSetUp_Chebychev(KSP ksp)
8: {
9: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
13: KSPDefaultGetWork(ksp,3);
14: cheb->estimate_current = PETSC_FALSE;
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(((PetscObject)ksp)->comm,PETSC_ERR_ARG_INCOMP,"Maximum eigenvalue must be larger than minimum: max %g min %G",emax,emin);
27: if (emax*emin <= 0.0) SETERRQ2(((PetscObject)ksp)->comm,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: }
37: PetscErrorCode KSPChebychevSetEstimateEigenvalues_Chebychev(KSP ksp,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
38: {
39: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
43: if (a != 0.0 || b != 0.0 || c != 0.0 || d != 0.0) {
44: if (!cheb->kspest) {
45: PetscBool nonzero;
47: KSPCreate(((PetscObject)ksp)->comm,&cheb->kspest);
49: KSPGetPC(cheb->kspest,&cheb->pcnone);
50: PetscObjectReference((PetscObject)cheb->pcnone);
51: PCSetType(cheb->pcnone,PCNONE);
52: KSPSetPC(cheb->kspest,ksp->pc);
54: KSPGetInitialGuessNonzero(ksp,&nonzero);
55: KSPSetInitialGuessNonzero(cheb->kspest,nonzero);
56: KSPSetComputeSingularValues(cheb->kspest,PETSC_TRUE);
58: /* Estimate with a fixed number of iterations */
59: KSPSetConvergenceTest(cheb->kspest,KSPSkipConverged,0,0);
60: KSPSetNormType(cheb->kspest,KSP_NORM_NONE);
61: KSPSetTolerances(cheb->kspest,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,5);
63: if (a >= 0) cheb->tform[0] = a;
64: if (b >= 0) cheb->tform[1] = b;
65: if (c >= 0) cheb->tform[2] = c;
66: if (d >= 0) cheb->tform[3] = d;
67: }
68: } else {
69: KSPDestroy(&cheb->kspest);
70: PCDestroy(&cheb->pcnone);
71: }
72: return(0);
73: }
78: /*@
79: KSPChebychevSetEigenvalues - Sets estimates for the extreme eigenvalues
80: of the preconditioned problem.
82: Logically Collective on KSP
84: Input Parameters:
85: + ksp - the Krylov space context
86: - emax, emin - the eigenvalue estimates
88: Options Database:
89: . -ksp_chebychev_eigenvalues emin,emax
91: Note: If you run with the Krylov method of KSPCG with the option -ksp_monitor_singular_value it will
92: for that given matrix and preconditioner an estimate of the extreme eigenvalues.
94: Level: intermediate
96: .keywords: KSP, Chebyshev, set, eigenvalues
97: @*/
98: PetscErrorCode KSPChebychevSetEigenvalues(KSP ksp,PetscReal emax,PetscReal emin)
99: {
106: PetscTryMethod(ksp,"KSPChebychevSetEigenvalues_C",(KSP,PetscReal,PetscReal),(ksp,emax,emin));
107: return(0);
108: }
112: /*@
113: KSPChebychevSetEstimateEigenvalues - Automatically estimate the eigenvalues to use for Chebychev
115: Logically Collective on KSP
117: Input Parameters:
118: + ksp - the Krylov space context
119: . a - multiple of min eigenvalue estimate to use for min Chebychev bound (or PETSC_DECIDE)
120: . b - multiple of max eigenvalue estimate to use for min Chebychev bound (or PETSC_DECIDE)
121: . c - multiple of min eigenvalue estimate to use for max Chebychev bound (or PETSC_DECIDE)
122: - d - multiple of max eigenvalue estimate to use for max Chebychev bound (or PETSC_DECIDE)
124: Options Database:
125: . -ksp_chebychev_estimate_eigenvalues a,b,c,d
127: Notes:
128: The Chebychev bounds are estimated using
129: .vb
130: minbound = a*minest + b*maxest
131: maxbound = c*minest + d*maxest
132: .ve
133: The default configuration targets the upper part of the spectrum for use as a multigrid smoother, so only the maximum eigenvalue estimate is used.
134: The minimum eigenvalue estimate obtained by Krylov iteration is typically not accurate until the method has converged.
136: If 0.0 is passed for all transform arguments (a,b,c,d), eigenvalue estimation is disabled.
138: Level: intermediate
140: .keywords: KSP, Chebyshev, set, eigenvalues
141: @*/
142: PetscErrorCode KSPChebychevSetEstimateEigenvalues(KSP ksp,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
143: {
152: PetscTryMethod(ksp,"KSPChebychevSetEstimateEigenvalues_C",(KSP,PetscReal,PetscReal,PetscReal,PetscReal),(ksp,a,b,c,d));
153: return(0);
154: }
158: PetscErrorCode KSPSetFromOptions_Chebychev(KSP ksp)
159: {
160: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
162: PetscInt two = 2,four = 4;
163: PetscReal tform[4] = {PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE};
164: PetscBool flg;
167: PetscOptionsHead("KSP Chebychev Options");
168: PetscOptionsRealArray("-ksp_chebychev_eigenvalues","extreme eigenvalues","KSPChebychevSetEigenvalues",&cheb->emin,&two,0);
169: PetscOptionsRealArray("-ksp_chebychev_estimate_eigenvalues","estimate eigenvalues using a Krylov method, then use this transform for Chebychev eigenvalue bounds","KSPChebychevSetEstimateEigenvalues",tform,&four,&flg);
170: if (flg) {KSPChebychevSetEstimateEigenvalues(ksp,tform[0],tform[1],tform[2],tform[3]);}
171: if (cheb->kspest) {
172: /* Mask the PC so that PCSetFromOptions does not do anything */
173: KSPSetPC(cheb->kspest,cheb->pcnone);
174: KSPSetOptionsPrefix(cheb->kspest,((PetscObject)ksp)->prefix);
175: KSPAppendOptionsPrefix(cheb->kspest,"est_");
176: if (!((PetscObject)cheb->kspest)->type_name) {
177: KSPSetType(cheb->kspest,KSPGMRES);
178: }
179: KSPSetFromOptions(cheb->kspest);
180: KSPSetPC(cheb->kspest,ksp->pc);
181: }
182: PetscOptionsTail();
183: return(0);
184: }
188: PetscErrorCode KSPSolve_Chebychev(KSP ksp)
189: {
190: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
192: PetscInt k,kp1,km1,maxit,ktmp,i;
193: PetscScalar alpha,omegaprod,mu,omega,Gamma,c[3],scale;
194: PetscReal rnorm = 0.0;
195: Vec x,b,p[3],r;
196: Mat Amat,Pmat;
197: MatStructure pflag;
198: PetscBool diagonalscale;
201: PCGetDiagonalScale(ksp->pc,&diagonalscale);
202: if (diagonalscale) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
204: if (cheb->kspest && !cheb->estimate_current) {
205: PetscReal max,min;
206: PetscBool nonzero;
207: Vec X = ksp->vec_sol;
208: KSPGetInitialGuessNonzero(ksp,&nonzero);
209: if (nonzero) {VecDuplicate(ksp->vec_sol,&X);}
210: KSPSolve(cheb->kspest,ksp->vec_rhs,X);
211: if (nonzero) {VecDestroy(&X);}
212: else {VecZeroEntries(X);}
213: KSPComputeExtremeSingularValues(cheb->kspest,&max,&min);
214: cheb->emin = cheb->tform[0]*min + cheb->tform[1]*max;
215: cheb->emax = cheb->tform[2]*min + cheb->tform[3]*max;
216: cheb->estimate_current = PETSC_TRUE;
217: }
219: ksp->its = 0;
220: PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
221: maxit = ksp->max_it;
223: /* These three point to the three active solutions, we
224: rotate these three at each solution update */
225: km1 = 0; k = 1; kp1 = 2;
226: x = ksp->vec_sol;
227: b = ksp->vec_rhs;
228: p[km1] = x;
229: p[k] = ksp->work[0];
230: p[kp1] = ksp->work[1];
231: r = ksp->work[2];
233: /* use scale*B as our preconditioner */
234: scale = 2.0/(cheb->emax + cheb->emin);
236: /* -alpha <= scale*lambda(B^{-1}A) <= alpha */
237: alpha = 1.0 - scale*(cheb->emin); ;
238: Gamma = 1.0;
239: mu = 1.0/alpha;
240: omegaprod = 2.0/alpha;
242: c[km1] = 1.0;
243: c[k] = mu;
245: if (!ksp->guess_zero) {
246: KSP_MatMult(ksp,Amat,x,r); /* r = b - Ax */
247: VecAYPX(r,-1.0,b);
248: } else {
249: VecCopy(b,r);
250: }
251:
252: KSP_PCApply(ksp,r,p[k]); /* p[k] = scale B^{-1}r + x */
253: VecAYPX(p[k],scale,x);
255: for (i=0; i<maxit; i++) {
256: PetscObjectTakeAccess(ksp);
257: ksp->its++;
258: PetscObjectGrantAccess(ksp);
259: c[kp1] = 2.0*mu*c[k] - c[km1];
260: omega = omegaprod*c[k]/c[kp1];
262: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
263: VecAYPX(r,-1.0,b);
264: KSP_PCApply(ksp,r,p[kp1]); /* p[kp1] = B^{-1}z */
266: /* calculate residual norm if requested */
267: if (ksp->normtype != KSP_NORM_NONE) {
268: if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {VecNorm(r,NORM_2,&rnorm);}
269: else {VecNorm(p[kp1],NORM_2,&rnorm);}
270: PetscObjectTakeAccess(ksp);
271: ksp->rnorm = rnorm;
272: PetscObjectGrantAccess(ksp);
273: ksp->vec_sol = p[k];
274: KSPLogResidualHistory(ksp,rnorm);
275: KSPMonitor(ksp,i,rnorm);
276: (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
277: if (ksp->reason) break;
278: }
280: /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */
281: VecScale(p[kp1],omega*Gamma*scale);
282: VecAXPY(p[kp1],1.0-omega,p[km1]);
283: VecAXPY(p[kp1],omega,p[k]);
285: ktmp = km1;
286: km1 = k;
287: k = kp1;
288: kp1 = ktmp;
289: }
290: if (!ksp->reason) {
291: if (ksp->normtype != KSP_NORM_NONE) {
292: KSP_MatMult(ksp,Amat,p[k],r); /* r = b - Ap[k] */
293: VecAYPX(r,-1.0,b);
294: if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
295: VecNorm(r,NORM_2,&rnorm);
296: } else {
297: KSP_PCApply(ksp,r,p[kp1]); /* p[kp1] = B^{-1}z */
298: VecNorm(p[kp1],NORM_2,&rnorm);
299: }
300: PetscObjectTakeAccess(ksp);
301: ksp->rnorm = rnorm;
302: PetscObjectGrantAccess(ksp);
303: ksp->vec_sol = p[k];
304: KSPLogResidualHistory(ksp,rnorm);
305: KSPMonitor(ksp,i,rnorm);
306: }
307: if (ksp->its >= ksp->max_it) {
308: if (ksp->normtype != KSP_NORM_NONE) {
309: (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);
310: if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
311: } else {
312: ksp->reason = KSP_CONVERGED_ITS;
313: }
314: }
315: }
317: /* make sure solution is in vector x */
318: ksp->vec_sol = x;
319: if (k) {
320: VecCopy(p[k],x);
321: }
322: return(0);
323: }
327: PetscErrorCode KSPView_Chebychev(KSP ksp,PetscViewer viewer)
328: {
329: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
331: PetscBool iascii;
334: PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
335: if (iascii) {
336: PetscViewerASCIIPrintf(viewer," Chebychev: eigenvalue estimates: min = %G, max = %G\n",cheb->emin,cheb->emax);
337: if (cheb->kspest) {
338: PetscViewerASCIIPushTab(viewer);
339: KSPView(cheb->kspest,viewer);
340: PetscViewerASCIIPopTab(viewer);
341: }
342: } else {
343: SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for KSP Chebychev",((PetscObject)viewer)->type_name);
344: }
345: return(0);
346: }
350: PetscErrorCode KSPDestroy_Chebychev(KSP ksp)
351: {
352: KSP_Chebychev *cheb = (KSP_Chebychev*)ksp->data;
356: KSPDestroy(&cheb->kspest);
357: PCDestroy(&cheb->pcnone);
358: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C","",PETSC_NULL);
359: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEstimateEigenvalues_C","",PETSC_NULL);
360: KSPDefaultDestroy(ksp);
361: return(0);
362: }
364: /*MC
365: KSPCHEBYCHEV - The preconditioned Chebychev iterative method
367: Options Database Keys:
368: + -ksp_chebychev_eigenvalues <emin,emax> - set approximations to the smallest and largest eigenvalues
369: of the preconditioned operator. If these are accurate you will get much faster convergence.
370: - -ksp_chebychev_estimate_eigenvalues <a,b,c,d> - estimate eigenvalues using a Krylov method, then use this
371: transform for Chebychev eigenvalue bounds (KSPChebychevSetEstimateEigenvalues)
374: Level: beginner
376: Notes: The Chebychev method requires both the matrix and preconditioner to
377: be symmetric positive (semi) definite.
378: Only support for left preconditioning.
380: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
381: KSPChebychevSetEigenvalues(), KSPRICHARDSON, KSPCG
383: M*/
388: PetscErrorCode KSPCreate_Chebychev(KSP ksp)
389: {
391: KSP_Chebychev *chebychevP;
394: PetscNewLog(ksp,KSP_Chebychev,&chebychevP);
396: ksp->data = (void*)chebychevP;
397: KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2);
398: KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);
400: chebychevP->emin = 1.e-2;
401: chebychevP->emax = 1.e+2;
403: chebychevP->tform[0] = 0.0;
404: chebychevP->tform[1] = 0.02;
405: chebychevP->tform[1] = 0;
406: chebychevP->tform[2] = 1.1;
408: ksp->ops->setup = KSPSetUp_Chebychev;
409: ksp->ops->solve = KSPSolve_Chebychev;
410: ksp->ops->destroy = KSPDestroy_Chebychev;
411: ksp->ops->buildsolution = KSPDefaultBuildSolution;
412: ksp->ops->buildresidual = KSPDefaultBuildResidual;
413: ksp->ops->setfromoptions = KSPSetFromOptions_Chebychev;
414: ksp->ops->view = KSPView_Chebychev;
416: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEigenvalues_C",
417: "KSPChebychevSetEigenvalues_Chebychev",
418: KSPChebychevSetEigenvalues_Chebychev);
419: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPChebychevSetEstimateEigenvalues_C",
420: "KSPChebychevSetEstimateEigenvalues_Chebychev",
421: KSPChebychevSetEstimateEigenvalues_Chebychev);
422: return(0);
423: }