Actual source code: jacobi.c
2: /* --------------------------------------------------------------------
4: This file implements a Jacobi preconditioner in PETSc as part of PC.
5: You can use this as a starting point for implementing your own
6: preconditioner that is not provided with PETSc. (You might also consider
7: just using PCSHELL)
9: The following basic routines are required for each preconditioner.
10: PCCreate_XXX() - Creates a preconditioner context
11: PCSetFromOptions_XXX() - Sets runtime options
12: PCApply_XXX() - Applies the preconditioner
13: PCDestroy_XXX() - Destroys the preconditioner context
14: where the suffix "_XXX" denotes a particular implementation, in
15: this case we use _Jacobi (e.g., PCCreate_Jacobi, PCApply_Jacobi).
16: These routines are actually called via the common user interface
17: routines PCCreate(), PCSetFromOptions(), PCApply(), and PCDestroy(),
18: so the application code interface remains identical for all
19: preconditioners.
21: Another key routine is:
22: PCSetUp_XXX() - Prepares for the use of a preconditioner
23: by setting data structures and options. The interface routine PCSetUp()
24: is not usually called directly by the user, but instead is called by
25: PCApply() if necessary.
27: Additional basic routines are:
28: PCView_XXX() - Prints details of runtime options that
29: have actually been used.
30: These are called by application codes via the interface routines
31: PCView().
33: The various types of solvers (preconditioners, Krylov subspace methods,
34: nonlinear solvers, timesteppers) are all organized similarly, so the
35: above description applies to these categories also. One exception is
36: that the analogues of PCApply() for these components are KSPSolve(),
37: SNESSolve(), and TSSolve().
39: Additional optional functionality unique to preconditioners is left and
40: right symmetric preconditioner application via PCApplySymmetricLeft()
41: and PCApplySymmetricRight(). The Jacobi implementation is
42: PCApplySymmetricLeftOrRight_Jacobi().
44: -------------------------------------------------------------------- */
46: /*
47: Include files needed for the Jacobi preconditioner:
48: pcimpl.h - private include file intended for use by all preconditioners
49: */
51: #include <petsc/private/pcimpl.h>
53: const char *const PCJacobiTypes[] = {"DIAGONAL", "ROWMAX", "ROWSUM", "PCJacobiType", "PC_JACOBI_", NULL};
55: /*
56: Private context (data structure) for the Jacobi preconditioner.
57: */
58: typedef struct {
59: Vec diag; /* vector containing the reciprocals of the diagonal elements of the preconditioner matrix */
60: Vec diagsqrt; /* vector containing the reciprocals of the square roots of
61: the diagonal elements of the preconditioner matrix (used
62: only for symmetric preconditioner application) */
63: PetscBool userowmax; /* set with PCJacobiSetType() */
64: PetscBool userowsum;
65: PetscBool useabs; /* use the absolute values of the diagonal entries */
66: PetscBool fixdiag; /* fix zero diagonal terms */
67: } PC_Jacobi;
69: static PetscErrorCode PCJacobiSetType_Jacobi(PC pc, PCJacobiType type)
70: {
71: PC_Jacobi *j = (PC_Jacobi *)pc->data;
73: j->userowmax = PETSC_FALSE;
74: j->userowsum = PETSC_FALSE;
75: if (type == PC_JACOBI_ROWMAX) {
76: j->userowmax = PETSC_TRUE;
77: } else if (type == PC_JACOBI_ROWSUM) {
78: j->userowsum = PETSC_TRUE;
79: }
80: return 0;
81: }
83: static PetscErrorCode PCJacobiGetType_Jacobi(PC pc, PCJacobiType *type)
84: {
85: PC_Jacobi *j = (PC_Jacobi *)pc->data;
87: if (j->userowmax) {
88: *type = PC_JACOBI_ROWMAX;
89: } else if (j->userowsum) {
90: *type = PC_JACOBI_ROWSUM;
91: } else {
92: *type = PC_JACOBI_DIAGONAL;
93: }
94: return 0;
95: }
97: static PetscErrorCode PCJacobiSetUseAbs_Jacobi(PC pc, PetscBool flg)
98: {
99: PC_Jacobi *j = (PC_Jacobi *)pc->data;
101: j->useabs = flg;
102: return 0;
103: }
105: static PetscErrorCode PCJacobiGetUseAbs_Jacobi(PC pc, PetscBool *flg)
106: {
107: PC_Jacobi *j = (PC_Jacobi *)pc->data;
109: *flg = j->useabs;
110: return 0;
111: }
113: static PetscErrorCode PCJacobiSetFixDiagonal_Jacobi(PC pc, PetscBool flg)
114: {
115: PC_Jacobi *j = (PC_Jacobi *)pc->data;
117: j->fixdiag = flg;
118: return 0;
119: }
121: static PetscErrorCode PCJacobiGetFixDiagonal_Jacobi(PC pc, PetscBool *flg)
122: {
123: PC_Jacobi *j = (PC_Jacobi *)pc->data;
125: *flg = j->fixdiag;
126: return 0;
127: }
129: /*
130: PCSetUp_Jacobi - Prepares for the use of the Jacobi preconditioner
131: by setting data structures and options.
133: Input Parameter:
134: . pc - the preconditioner context
136: Application Interface Routine: PCSetUp()
138: Note:
139: The interface routine PCSetUp() is not usually called directly by
140: the user, but instead is called by PCApply() if necessary.
141: */
142: static PetscErrorCode PCSetUp_Jacobi(PC pc)
143: {
144: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
145: Vec diag, diagsqrt;
146: PetscInt n, i;
147: PetscScalar *x;
148: PetscBool zeroflag = PETSC_FALSE;
150: /*
151: For most preconditioners the code would begin here something like
153: if (pc->setupcalled == 0) { allocate space the first time this is ever called
154: MatCreateVecs(pc->mat,&jac->diag);
155: }
157: But for this preconditioner we want to support use of both the matrix' diagonal
158: elements (for left or right preconditioning) and square root of diagonal elements
159: (for symmetric preconditioning). Hence we do not allocate space here, since we
160: don't know at this point which will be needed (diag and/or diagsqrt) until the user
161: applies the preconditioner, and we don't want to allocate BOTH unless we need
162: them both. Thus, the diag and diagsqrt are allocated in PCSetUp_Jacobi_NonSymmetric()
163: and PCSetUp_Jacobi_Symmetric(), respectively.
164: */
166: /*
167: Here we set up the preconditioner; that is, we copy the diagonal values from
168: the matrix and put them into a format to make them quick to apply as a preconditioner.
169: */
170: diag = jac->diag;
171: diagsqrt = jac->diagsqrt;
173: if (diag) {
174: PetscBool isset, isspd;
176: if (jac->userowmax) {
177: MatGetRowMaxAbs(pc->pmat, diag, NULL);
178: } else if (jac->userowsum) {
179: MatGetRowSum(pc->pmat, diag);
180: } else {
181: MatGetDiagonal(pc->pmat, diag);
182: }
183: VecReciprocal(diag);
184: if (jac->useabs) VecAbs(diag);
185: MatIsSPDKnown(pc->pmat, &isset, &isspd);
186: if (jac->fixdiag && (!isset || !isspd)) {
187: VecGetLocalSize(diag, &n);
188: VecGetArray(diag, &x);
189: for (i = 0; i < n; i++) {
190: if (x[i] == 0.0) {
191: x[i] = 1.0;
192: zeroflag = PETSC_TRUE;
193: }
194: }
195: VecRestoreArray(diag, &x);
196: }
197: }
198: if (diagsqrt) {
199: if (jac->userowmax) {
200: MatGetRowMaxAbs(pc->pmat, diagsqrt, NULL);
201: } else if (jac->userowsum) {
202: MatGetRowSum(pc->pmat, diagsqrt);
203: } else {
204: MatGetDiagonal(pc->pmat, diagsqrt);
205: }
206: VecGetLocalSize(diagsqrt, &n);
207: VecGetArray(diagsqrt, &x);
208: for (i = 0; i < n; i++) {
209: if (x[i] != 0.0) x[i] = 1.0 / PetscSqrtReal(PetscAbsScalar(x[i]));
210: else {
211: x[i] = 1.0;
212: zeroflag = PETSC_TRUE;
213: }
214: }
215: VecRestoreArray(diagsqrt, &x);
216: }
217: if (zeroflag) PetscInfo(pc, "Zero detected in diagonal of matrix, using 1 at those locations\n");
218: return 0;
219: }
221: /*
222: PCSetUp_Jacobi_Symmetric - Allocates the vector needed to store the
223: inverse of the square root of the diagonal entries of the matrix. This
224: is used for symmetric application of the Jacobi preconditioner.
226: Input Parameter:
227: . pc - the preconditioner context
228: */
229: static PetscErrorCode PCSetUp_Jacobi_Symmetric(PC pc)
230: {
231: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
233: MatCreateVecs(pc->pmat, &jac->diagsqrt, NULL);
234: PCSetUp_Jacobi(pc);
235: return 0;
236: }
238: /*
239: PCSetUp_Jacobi_NonSymmetric - Allocates the vector needed to store the
240: inverse of the diagonal entries of the matrix. This is used for left of
241: right application of the Jacobi preconditioner.
243: Input Parameter:
244: . pc - the preconditioner context
245: */
246: static PetscErrorCode PCSetUp_Jacobi_NonSymmetric(PC pc)
247: {
248: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
250: MatCreateVecs(pc->pmat, &jac->diag, NULL);
251: PCSetUp_Jacobi(pc);
252: return 0;
253: }
255: /*
256: PCApply_Jacobi - Applies the Jacobi preconditioner to a vector.
258: Input Parameters:
259: . pc - the preconditioner context
260: . x - input vector
262: Output Parameter:
263: . y - output vector
265: Application Interface Routine: PCApply()
266: */
267: static PetscErrorCode PCApply_Jacobi(PC pc, Vec x, Vec y)
268: {
269: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
271: if (!jac->diag) PCSetUp_Jacobi_NonSymmetric(pc);
272: VecPointwiseMult(y, x, jac->diag);
273: return 0;
274: }
276: /*
277: PCApplySymmetricLeftOrRight_Jacobi - Applies the left or right part of a
278: symmetric preconditioner to a vector.
280: Input Parameters:
281: . pc - the preconditioner context
282: . x - input vector
284: Output Parameter:
285: . y - output vector
287: Application Interface Routines: PCApplySymmetricLeft(), PCApplySymmetricRight()
288: */
289: static PetscErrorCode PCApplySymmetricLeftOrRight_Jacobi(PC pc, Vec x, Vec y)
290: {
291: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
293: if (!jac->diagsqrt) PCSetUp_Jacobi_Symmetric(pc);
294: VecPointwiseMult(y, x, jac->diagsqrt);
295: return 0;
296: }
298: static PetscErrorCode PCReset_Jacobi(PC pc)
299: {
300: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
302: VecDestroy(&jac->diag);
303: VecDestroy(&jac->diagsqrt);
304: return 0;
305: }
307: /*
308: PCDestroy_Jacobi - Destroys the private context for the Jacobi preconditioner
309: that was created with PCCreate_Jacobi().
311: Input Parameter:
312: . pc - the preconditioner context
314: Application Interface Routine: PCDestroy()
315: */
316: static PetscErrorCode PCDestroy_Jacobi(PC pc)
317: {
318: PCReset_Jacobi(pc);
319: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetType_C", NULL);
320: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetType_C", NULL);
321: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetUseAbs_C", NULL);
322: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetUseAbs_C", NULL);
323: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetFixDiagonal_C", NULL);
324: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetFixDiagonal_C", NULL);
326: /*
327: Free the private data structure that was hanging off the PC
328: */
329: PetscFree(pc->data);
330: return 0;
331: }
333: static PetscErrorCode PCSetFromOptions_Jacobi(PC pc, PetscOptionItems *PetscOptionsObject)
334: {
335: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
336: PetscBool flg;
337: PCJacobiType deflt, type;
339: PCJacobiGetType(pc, &deflt);
340: PetscOptionsHeadBegin(PetscOptionsObject, "Jacobi options");
341: PetscOptionsEnum("-pc_jacobi_type", "How to construct diagonal matrix", "PCJacobiSetType", PCJacobiTypes, (PetscEnum)deflt, (PetscEnum *)&type, &flg);
342: if (flg) PCJacobiSetType(pc, type);
343: PetscOptionsBool("-pc_jacobi_abs", "Use absolute values of diagonal entries", "PCJacobiSetUseAbs", jac->useabs, &jac->useabs, NULL);
344: PetscOptionsBool("-pc_jacobi_fixdiagonal", "Fix null terms on diagonal", "PCJacobiSetFixDiagonal", jac->fixdiag, &jac->fixdiag, NULL);
345: PetscOptionsHeadEnd();
346: return 0;
347: }
349: static PetscErrorCode PCView_Jacobi(PC pc, PetscViewer viewer)
350: {
351: PC_Jacobi *jac = (PC_Jacobi *)pc->data;
352: PetscBool iascii;
354: PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
355: if (iascii) {
356: PCJacobiType type;
357: PetscBool useAbs, fixdiag;
358: PetscViewerFormat format;
360: PCJacobiGetType(pc, &type);
361: PCJacobiGetUseAbs(pc, &useAbs);
362: PCJacobiGetFixDiagonal(pc, &fixdiag);
363: PetscViewerASCIIPrintf(viewer, " type %s%s%s\n", PCJacobiTypes[type], useAbs ? ", using absolute value of entries" : "", !fixdiag ? ", not checking null diagonal entries" : "");
364: PetscViewerGetFormat(viewer, &format);
365: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) VecView(jac->diag, viewer);
366: }
367: return 0;
368: }
370: /*
371: PCCreate_Jacobi - Creates a Jacobi preconditioner context, PC_Jacobi,
372: and sets this as the private data within the generic preconditioning
373: context, PC, that was created within PCCreate().
375: Input Parameter:
376: . pc - the preconditioner context
378: Application Interface Routine: PCCreate()
379: */
381: /*MC
382: PCJACOBI - Jacobi (i.e. diagonal scaling preconditioning)
384: Options Database Keys:
385: + -pc_jacobi_type <diagonal,rowmax,rowsum> - approach for forming the preconditioner
386: . -pc_jacobi_abs - use the absolute value of the diagonal entry
387: - -pc_jacobi_fixdiag - fix for zero diagonal terms by placing 1.0 in those locations
389: Level: beginner
391: Notes:
392: By using `KSPSetPCSide`(ksp,`PC_SYMMETRIC`) or -ksp_pc_side symmetric
393: can scale each side of the matrix by the square root of the diagonal entries.
395: Zero entries along the diagonal are replaced with the value 1.0
397: See `PCPBJACOBI` for fixed-size point block, `PCVPBJACOBI` for variable-sized point block, and `PCBJACOBI` for large size blocks
399: .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
400: `PCJacobiSetType()`, `PCJacobiSetUseAbs()`, `PCJacobiGetUseAbs()`, `PCASM`,
401: `PCJacobiSetFixDiagonal()`, `PCJacobiGetFixDiagonal()`
402: `PCJacobiSetType()`, `PCJacobiSetUseAbs()`, `PCJacobiGetUseAbs()`, `PCPBJACOBI`, `PCBJACOBI`, `PCVPBJACOBI`
403: M*/
405: PETSC_EXTERN PetscErrorCode PCCreate_Jacobi(PC pc)
406: {
407: PC_Jacobi *jac;
409: /*
410: Creates the private data structure for this preconditioner and
411: attach it to the PC object.
412: */
413: PetscNew(&jac);
414: pc->data = (void *)jac;
416: /*
417: Initialize the pointers to vectors to ZERO; these will be used to store
418: diagonal entries of the matrix for fast preconditioner application.
419: */
420: jac->diag = NULL;
421: jac->diagsqrt = NULL;
422: jac->userowmax = PETSC_FALSE;
423: jac->userowsum = PETSC_FALSE;
424: jac->useabs = PETSC_FALSE;
425: jac->fixdiag = PETSC_TRUE;
427: /*
428: Set the pointers for the functions that are provided above.
429: Now when the user-level routines (such as PCApply(), PCDestroy(), etc.)
430: are called, they will automatically call these functions. Note we
431: choose not to provide a couple of these functions since they are
432: not needed.
433: */
434: pc->ops->apply = PCApply_Jacobi;
435: pc->ops->applytranspose = PCApply_Jacobi;
436: pc->ops->setup = PCSetUp_Jacobi;
437: pc->ops->reset = PCReset_Jacobi;
438: pc->ops->destroy = PCDestroy_Jacobi;
439: pc->ops->setfromoptions = PCSetFromOptions_Jacobi;
440: pc->ops->view = PCView_Jacobi;
441: pc->ops->applyrichardson = NULL;
442: pc->ops->applysymmetricleft = PCApplySymmetricLeftOrRight_Jacobi;
443: pc->ops->applysymmetricright = PCApplySymmetricLeftOrRight_Jacobi;
445: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetType_C", PCJacobiSetType_Jacobi);
446: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetType_C", PCJacobiGetType_Jacobi);
447: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetUseAbs_C", PCJacobiSetUseAbs_Jacobi);
448: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetUseAbs_C", PCJacobiGetUseAbs_Jacobi);
449: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiSetFixDiagonal_C", PCJacobiSetFixDiagonal_Jacobi);
450: PetscObjectComposeFunction((PetscObject)pc, "PCJacobiGetFixDiagonal_C", PCJacobiGetFixDiagonal_Jacobi);
451: return 0;
452: }
454: /*@
455: PCJacobiSetUseAbs - Causes the Jacobi preconditioner `PCJACOBI` to use the
456: absolute values of the diagonal divisors in the preconditioner
458: Logically Collective
460: Input Parameters:
461: + pc - the preconditioner context
462: - flg - whether to use absolute values or not
464: Options Database Key:
465: . -pc_jacobi_abs <bool> - use absolute values
467: Note:
468: This takes affect at the next construction of the preconditioner
470: Level: intermediate
472: .seealso: `PCJACOBI`, `PCJacobiaSetType()`, `PCJacobiGetUseAbs()`
473: @*/
474: PetscErrorCode PCJacobiSetUseAbs(PC pc, PetscBool flg)
475: {
477: PetscTryMethod(pc, "PCJacobiSetUseAbs_C", (PC, PetscBool), (pc, flg));
478: return 0;
479: }
481: /*@
482: PCJacobiGetUseAbs - Determines if the Jacobi preconditioner `PCJACOBI` uses the
483: absolute values of the diagonal divisors in the preconditioner
485: Logically Collective
487: Input Parameter:
488: . pc - the preconditioner context
490: Output Parameter:
491: . flg - whether to use absolute values or not
493: Level: intermediate
495: .seealso: `PCJACOBI`, `PCJacobiaSetType()`, `PCJacobiSetUseAbs()`, `PCJacobiGetType()`
496: @*/
497: PetscErrorCode PCJacobiGetUseAbs(PC pc, PetscBool *flg)
498: {
500: PetscUseMethod(pc, "PCJacobiGetUseAbs_C", (PC, PetscBool *), (pc, flg));
501: return 0;
502: }
504: /*@
505: PCJacobiSetFixDiagonal - Check for zero values on the diagonal and replace them with 1.0
507: Logically Collective
509: Input Parameters:
510: + pc - the preconditioner context
511: - flg - the boolean flag
513: Options Database Key:
514: . -pc_jacobi_fixdiagonal <bool> - check for zero values on the diagonal
516: Note:
517: This takes affect at the next construction of the preconditioner
519: Level: intermediate
521: .seealso: `PCJACOBI`, `PCJacobiSetType()`, `PCJacobiGetFixDiagonal()`, `PCJacobiSetUseAbs()`
522: @*/
523: PetscErrorCode PCJacobiSetFixDiagonal(PC pc, PetscBool flg)
524: {
526: PetscTryMethod(pc, "PCJacobiSetFixDiagonal_C", (PC, PetscBool), (pc, flg));
527: return 0;
528: }
530: /*@
531: PCJacobiGetFixDiagonal - Determines if the Jacobi preconditioner `PCJACOBI` checks for zero diagonal terms
533: Logically Collective
535: Input Parameter:
536: . pc - the preconditioner context
538: Output Parameter:
539: . flg - the boolean flag
541: Options Database Key:
542: . -pc_jacobi_fixdiagonal <bool> - Fix 0 terms on diagonal by using 1
544: Level: intermediate
546: .seealso: `PCJACOBI`, `PCJacobiSetType()`, `PCJacobiSetFixDiagonal()`
547: @*/
548: PetscErrorCode PCJacobiGetFixDiagonal(PC pc, PetscBool *flg)
549: {
551: PetscUseMethod(pc, "PCJacobiGetFixDiagonal_C", (PC, PetscBool *), (pc, flg));
552: return 0;
553: }
555: /*@
556: PCJacobiSetType - Causes the Jacobi preconditioner to use either the diagonal, the maximum entry in each row,
557: of the sum of rows entries for the diagonal preconditioner
559: Logically Collective
561: Input Parameters:
562: + pc - the preconditioner context
563: - type - `PC_JACOBI_DIAGONAL`, `PC_JACOBI_ROWMAX`, `PC_JACOBI_ROWSUM`
565: Options Database Key:
566: . -pc_jacobi_type <diagonal,rowmax,rowsum> - the type of diagonal matrix to use for Jacobi
568: Level: intermediate
570: Developer Note:
571: Why is there a separate function for using the absolute value?
573: .seealso: `PCJACOBI`, `PCJacobiSetUseAbs()`, `PCJacobiGetType()`
574: @*/
575: PetscErrorCode PCJacobiSetType(PC pc, PCJacobiType type)
576: {
578: PetscTryMethod(pc, "PCJacobiSetType_C", (PC, PCJacobiType), (pc, type));
579: return 0;
580: }
582: /*@
583: PCJacobiGetType - Gets how the diagonal matrix is produced for the preconditioner
585: Not Collective
587: Input Parameter:
588: . pc - the preconditioner context
590: Output Parameter:
591: . type - `PC_JACOBI_DIAGONAL`, `PC_JACOBI_ROWMAX`, `PC_JACOBI_ROWSUM`
593: Level: intermediate
595: .seealso: `PCJACOBI`, `PCJacobiaUseAbs()`, `PCJacobiSetType()`
596: @*/
597: PetscErrorCode PCJacobiGetType(PC pc, PCJacobiType *type)
598: {
600: PetscUseMethod(pc, "PCJacobiGetType_C", (PC, PCJacobiType *), (pc, type));
601: return 0;
602: }