xref: /petsc/src/ksp/pc/impls/jacobi/jacobi.c (revision a06653b4217a6b7095655997faad757ca7c559a5)
1 
2 /*  --------------------------------------------------------------------
3 
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)
8 
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.
20 
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.
26 
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().
32 
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().
38 
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().
43 
44     -------------------------------------------------------------------- */
45 
46 /*
47    Include files needed for the Jacobi preconditioner:
48      pcimpl.h - private include file intended for use by all preconditioners
49 */
50 
51 #include <private/pcimpl.h>   /*I "petscpc.h" I*/
52 
53 /*
54    Private context (data structure) for the Jacobi preconditioner.
55 */
56 typedef struct {
57   Vec        diag;               /* vector containing the reciprocals of the diagonal elements
58                                     of the preconditioner matrix */
59   Vec        diagsqrt;           /* vector containing the reciprocals of the square roots of
60                                     the diagonal elements of the preconditioner matrix (used
61                                     only for symmetric preconditioner application) */
62   PetscBool  userowmax;
63   PetscBool  userowsum;
64   PetscBool  useabs;             /* use the absolute values of the diagonal entries */
65 } PC_Jacobi;
66 
67 EXTERN_C_BEGIN
68 #undef __FUNCT__
69 #define __FUNCT__ "PCJacobiSetUseRowMax_Jacobi"
70 PetscErrorCode  PCJacobiSetUseRowMax_Jacobi(PC pc)
71 {
72   PC_Jacobi *j;
73 
74   PetscFunctionBegin;
75   j            = (PC_Jacobi*)pc->data;
76   j->userowmax = PETSC_TRUE;
77   PetscFunctionReturn(0);
78 }
79 EXTERN_C_END
80 
81 EXTERN_C_BEGIN
82 #undef __FUNCT__
83 #define __FUNCT__ "PCJacobiSetUseRowSum_Jacobi"
84 PetscErrorCode  PCJacobiSetUseRowSum_Jacobi(PC pc)
85 {
86   PC_Jacobi *j;
87 
88   PetscFunctionBegin;
89   j            = (PC_Jacobi*)pc->data;
90   j->userowsum = PETSC_TRUE;
91   PetscFunctionReturn(0);
92 }
93 EXTERN_C_END
94 
95 EXTERN_C_BEGIN
96 #undef __FUNCT__
97 #define __FUNCT__ "PCJacobiSetUseAbs_Jacobi"
98 PetscErrorCode  PCJacobiSetUseAbs_Jacobi(PC pc)
99 {
100   PC_Jacobi *j;
101 
102   PetscFunctionBegin;
103   j         = (PC_Jacobi*)pc->data;
104   j->useabs = PETSC_TRUE;
105   PetscFunctionReturn(0);
106 }
107 EXTERN_C_END
108 
109 /* -------------------------------------------------------------------------- */
110 /*
111    PCSetUp_Jacobi - Prepares for the use of the Jacobi preconditioner
112                     by setting data structures and options.
113 
114    Input Parameter:
115 .  pc - the preconditioner context
116 
117    Application Interface Routine: PCSetUp()
118 
119    Notes:
120    The interface routine PCSetUp() is not usually called directly by
121    the user, but instead is called by PCApply() if necessary.
122 */
123 #undef __FUNCT__
124 #define __FUNCT__ "PCSetUp_Jacobi"
125 static PetscErrorCode PCSetUp_Jacobi(PC pc)
126 {
127   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
128   Vec            diag,diagsqrt;
129   PetscErrorCode ierr;
130   PetscInt       n,i;
131   PetscScalar    *x;
132   PetscBool      zeroflag = PETSC_FALSE;
133 
134   PetscFunctionBegin;
135   /*
136        For most preconditioners the code would begin here something like
137 
138   if (pc->setupcalled == 0) { allocate space the first time this is ever called
139     ierr = MatGetVecs(pc->mat,&jac->diag);CHKERRQ(ierr);
140     PetscLogObjectParent(pc,jac->diag);
141   }
142 
143     But for this preconditioner we want to support use of both the matrix' diagonal
144     elements (for left or right preconditioning) and square root of diagonal elements
145     (for symmetric preconditioning).  Hence we do not allocate space here, since we
146     don't know at this point which will be needed (diag and/or diagsqrt) until the user
147     applies the preconditioner, and we don't want to allocate BOTH unless we need
148     them both.  Thus, the diag and diagsqrt are allocated in PCSetUp_Jacobi_NonSymmetric()
149     and PCSetUp_Jacobi_Symmetric(), respectively.
150   */
151 
152   /*
153     Here we set up the preconditioner; that is, we copy the diagonal values from
154     the matrix and put them into a format to make them quick to apply as a preconditioner.
155   */
156   diag     = jac->diag;
157   diagsqrt = jac->diagsqrt;
158 
159   if (diag) {
160     if (jac->userowmax) {
161       ierr = MatGetRowMaxAbs(pc->pmat,diag,PETSC_NULL);CHKERRQ(ierr);
162     } else if (jac->userowsum) {
163       ierr = MatGetRowSum(pc->pmat,diag);CHKERRQ(ierr);
164     } else {
165       ierr = MatGetDiagonal(pc->pmat,diag);CHKERRQ(ierr);
166     }
167     ierr = VecReciprocal(diag);CHKERRQ(ierr);
168     ierr = VecGetLocalSize(diag,&n);CHKERRQ(ierr);
169     ierr = VecGetArray(diag,&x);CHKERRQ(ierr);
170     if (jac->useabs) {
171       for (i=0; i<n; i++) {
172         x[i]     = PetscAbsScalar(x[i]);
173       }
174     }
175     for (i=0; i<n; i++) {
176       if (x[i] == 0.0) {
177         x[i]     = 1.0;
178         zeroflag = PETSC_TRUE;
179       }
180     }
181     ierr = VecRestoreArray(diag,&x);CHKERRQ(ierr);
182   }
183   if (diagsqrt) {
184     if (jac->userowmax) {
185       ierr = MatGetRowMaxAbs(pc->pmat,diagsqrt,PETSC_NULL);CHKERRQ(ierr);
186     } else if (jac->userowsum) {
187       ierr = MatGetRowSum(pc->pmat,diagsqrt);CHKERRQ(ierr);
188     } else {
189       ierr = MatGetDiagonal(pc->pmat,diagsqrt);CHKERRQ(ierr);
190     }
191     ierr = VecGetLocalSize(diagsqrt,&n);CHKERRQ(ierr);
192     ierr = VecGetArray(diagsqrt,&x);CHKERRQ(ierr);
193     for (i=0; i<n; i++) {
194       if (x[i] != 0.0) x[i] = 1.0/sqrt(PetscAbsScalar(x[i]));
195       else {
196         x[i]     = 1.0;
197         zeroflag = PETSC_TRUE;
198       }
199     }
200     ierr = VecRestoreArray(diagsqrt,&x);CHKERRQ(ierr);
201   }
202   if (zeroflag) {
203     ierr = PetscInfo(pc,"Zero detected in diagonal of matrix, using 1 at those locations\n");CHKERRQ(ierr);
204   }
205   PetscFunctionReturn(0);
206 }
207 /* -------------------------------------------------------------------------- */
208 /*
209    PCSetUp_Jacobi_Symmetric - Allocates the vector needed to store the
210    inverse of the square root of the diagonal entries of the matrix.  This
211    is used for symmetric application of the Jacobi preconditioner.
212 
213    Input Parameter:
214 .  pc - the preconditioner context
215 */
216 #undef __FUNCT__
217 #define __FUNCT__ "PCSetUp_Jacobi_Symmetric"
218 static PetscErrorCode PCSetUp_Jacobi_Symmetric(PC pc)
219 {
220   PetscErrorCode ierr;
221   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
222 
223   PetscFunctionBegin;
224   ierr = MatGetVecs(pc->pmat,&jac->diagsqrt,0);CHKERRQ(ierr);
225   ierr = PetscLogObjectParent(pc,jac->diagsqrt);CHKERRQ(ierr);
226   ierr = PCSetUp_Jacobi(pc);CHKERRQ(ierr);
227   PetscFunctionReturn(0);
228 }
229 /* -------------------------------------------------------------------------- */
230 /*
231    PCSetUp_Jacobi_NonSymmetric - Allocates the vector needed to store the
232    inverse of the diagonal entries of the matrix.  This is used for left of
233    right application of the Jacobi preconditioner.
234 
235    Input Parameter:
236 .  pc - the preconditioner context
237 */
238 #undef __FUNCT__
239 #define __FUNCT__ "PCSetUp_Jacobi_NonSymmetric"
240 static PetscErrorCode PCSetUp_Jacobi_NonSymmetric(PC pc)
241 {
242   PetscErrorCode ierr;
243   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
244 
245   PetscFunctionBegin;
246   ierr = MatGetVecs(pc->pmat,&jac->diag,0);CHKERRQ(ierr);
247   ierr = PetscLogObjectParent(pc,jac->diag);CHKERRQ(ierr);
248   ierr = PCSetUp_Jacobi(pc);CHKERRQ(ierr);
249   PetscFunctionReturn(0);
250 }
251 /* -------------------------------------------------------------------------- */
252 /*
253    PCApply_Jacobi - Applies the Jacobi preconditioner to a vector.
254 
255    Input Parameters:
256 .  pc - the preconditioner context
257 .  x - input vector
258 
259    Output Parameter:
260 .  y - output vector
261 
262    Application Interface Routine: PCApply()
263  */
264 #undef __FUNCT__
265 #define __FUNCT__ "PCApply_Jacobi"
266 static PetscErrorCode PCApply_Jacobi(PC pc,Vec x,Vec y)
267 {
268   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   if (!jac->diag) {
273     ierr = PCSetUp_Jacobi_NonSymmetric(pc);CHKERRQ(ierr);
274   }
275   ierr = VecPointwiseMult(y,x,jac->diag);CHKERRQ(ierr);
276   PetscFunctionReturn(0);
277 }
278 /* -------------------------------------------------------------------------- */
279 /*
280    PCApplySymmetricLeftOrRight_Jacobi - Applies the left or right part of a
281    symmetric preconditioner to a vector.
282 
283    Input Parameters:
284 .  pc - the preconditioner context
285 .  x - input vector
286 
287    Output Parameter:
288 .  y - output vector
289 
290    Application Interface Routines: PCApplySymmetricLeft(), PCApplySymmetricRight()
291 */
292 #undef __FUNCT__
293 #define __FUNCT__ "PCApplySymmetricLeftOrRight_Jacobi"
294 static PetscErrorCode PCApplySymmetricLeftOrRight_Jacobi(PC pc,Vec x,Vec y)
295 {
296   PetscErrorCode ierr;
297   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
298 
299   PetscFunctionBegin;
300   if (!jac->diagsqrt) {
301     ierr = PCSetUp_Jacobi_Symmetric(pc);CHKERRQ(ierr);
302   }
303   VecPointwiseMult(y,x,jac->diagsqrt);
304   PetscFunctionReturn(0);
305 }
306 /* -------------------------------------------------------------------------- */
307 #undef __FUNCT__
308 #define __FUNCT__ "PCReset_Jacobi"
309 static PetscErrorCode PCReset_Jacobi(PC pc)
310 {
311   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
312   PetscErrorCode ierr;
313 
314   PetscFunctionBegin;
315   if (jac->diag)     {ierr = VecDestroy(jac->diag);CHKERRQ(ierr);}
316   if (jac->diagsqrt) {ierr = VecDestroy(jac->diagsqrt);CHKERRQ(ierr);}
317   PetscFunctionReturn(0);
318 }
319 
320 /*
321    PCDestroy_Jacobi - Destroys the private context for the Jacobi preconditioner
322    that was created with PCCreate_Jacobi().
323 
324    Input Parameter:
325 .  pc - the preconditioner context
326 
327    Application Interface Routine: PCDestroy()
328 */
329 #undef __FUNCT__
330 #define __FUNCT__ "PCDestroy_Jacobi"
331 static PetscErrorCode PCDestroy_Jacobi(PC pc)
332 {
333   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
334   PetscErrorCode ierr;
335 
336   PetscFunctionBegin;
337   ierr = PCReset_Jacobi(pc);CHKERRQ(ierr);
338 
339   /*
340       Free the private data structure that was hanging off the PC
341   */
342   ierr = PetscFree(pc->data);CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "PCSetFromOptions_Jacobi"
348 static PetscErrorCode PCSetFromOptions_Jacobi(PC pc)
349 {
350   PC_Jacobi      *jac = (PC_Jacobi*)pc->data;
351   PetscErrorCode ierr;
352 
353   PetscFunctionBegin;
354   ierr = PetscOptionsHead("Jacobi options");CHKERRQ(ierr);
355     ierr = PetscOptionsBool("-pc_jacobi_rowmax","Use row maximums for diagonal","PCJacobiSetUseRowMax",jac->userowmax,
356                           &jac->userowmax,PETSC_NULL);CHKERRQ(ierr);
357     ierr = PetscOptionsBool("-pc_jacobi_rowsum","Use row sums for diagonal","PCJacobiSetUseRowSum",jac->userowsum,
358                           &jac->userowsum,PETSC_NULL);CHKERRQ(ierr);
359     ierr = PetscOptionsBool("-pc_jacobi_abs","Use absolute values of diagaonal entries","PCJacobiSetUseAbs",jac->useabs,
360                           &jac->useabs,PETSC_NULL);CHKERRQ(ierr);
361   ierr = PetscOptionsTail();CHKERRQ(ierr);
362   PetscFunctionReturn(0);
363 }
364 
365 /* -------------------------------------------------------------------------- */
366 /*
367    PCCreate_Jacobi - Creates a Jacobi preconditioner context, PC_Jacobi,
368    and sets this as the private data within the generic preconditioning
369    context, PC, that was created within PCCreate().
370 
371    Input Parameter:
372 .  pc - the preconditioner context
373 
374    Application Interface Routine: PCCreate()
375 */
376 
377 /*MC
378      PCJACOBI - Jacobi (i.e. diagonal scaling preconditioning)
379 
380    Options Database Key:
381 +    -pc_jacobi_rowmax - use the maximum absolute value in each row as the scaling factor,
382                         rather than the diagonal
383 .    -pc_jacobi_rowsum - use the maximum absolute value in each row as the scaling factor,
384                         rather than the diagonal
385 -    -pc_jacobi_abs - use the absolute value of the diagaonl entry
386 
387    Level: beginner
388 
389   Concepts: Jacobi, diagonal scaling, preconditioners
390 
391   Notes: By using KSPSetPCSide(ksp,PC_SYMMETRIC) or -ksp_pc_side symmetric
392          can scale each side of the matrix by the squareroot of the diagonal entries.
393 
394          Zero entries along the diagonal are replaced with the value 1.0
395 
396 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
397            PCJacobiSetUseRowMax(), PCJacobiSetUseRowSum(), PCJacobiSetUseAbs()
398 M*/
399 
400 EXTERN_C_BEGIN
401 #undef __FUNCT__
402 #define __FUNCT__ "PCCreate_Jacobi"
403 PetscErrorCode  PCCreate_Jacobi(PC pc)
404 {
405   PC_Jacobi      *jac;
406   PetscErrorCode ierr;
407 
408   PetscFunctionBegin;
409   /*
410      Creates the private data structure for this preconditioner and
411      attach it to the PC object.
412   */
413   ierr      = PetscNewLog(pc,PC_Jacobi,&jac);CHKERRQ(ierr);
414   pc->data  = (void*)jac;
415 
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          = 0;
421   jac->diagsqrt      = 0;
422   jac->userowmax     = PETSC_FALSE;
423   jac->userowsum     = PETSC_FALSE;
424   jac->useabs        = PETSC_FALSE;
425 
426   /*
427       Set the pointers for the functions that are provided above.
428       Now when the user-level routines (such as PCApply(), PCDestroy(), etc.)
429       are called, they will automatically call these functions.  Note we
430       choose not to provide a couple of these functions since they are
431       not needed.
432   */
433   pc->ops->apply               = PCApply_Jacobi;
434   pc->ops->applytranspose      = PCApply_Jacobi;
435   pc->ops->setup               = PCSetUp_Jacobi;
436   pc->ops->reset               = PCReset_Jacobi;
437   pc->ops->destroy             = PCDestroy_Jacobi;
438   pc->ops->setfromoptions      = PCSetFromOptions_Jacobi;
439   pc->ops->view                = 0;
440   pc->ops->applyrichardson     = 0;
441   pc->ops->applysymmetricleft  = PCApplySymmetricLeftOrRight_Jacobi;
442   pc->ops->applysymmetricright = PCApplySymmetricLeftOrRight_Jacobi;
443   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCJacobiSetUseRowMax_C","PCJacobiSetUseRowMax_Jacobi",PCJacobiSetUseRowMax_Jacobi);CHKERRQ(ierr);
444   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCJacobiSetUseRowSum_C","PCJacobiSetUseRowSum_Jacobi",PCJacobiSetUseRowSum_Jacobi);CHKERRQ(ierr);
445   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCJacobiSetUseAbs_C","PCJacobiSetUseAbs_Jacobi",PCJacobiSetUseAbs_Jacobi);CHKERRQ(ierr);
446   PetscFunctionReturn(0);
447 }
448 EXTERN_C_END
449 
450 
451 #undef __FUNCT__
452 #define __FUNCT__ "PCJacobiSetUseAbs"
453 /*@
454    PCJacobiSetUseAbs - Causes the Jacobi preconditioner to use the
455       absolute value of the diagonal to for the preconditioner
456 
457    Logically Collective on PC
458 
459    Input Parameters:
460 .  pc - the preconditioner context
461 
462 
463    Options Database Key:
464 .  -pc_jacobi_abs
465 
466    Level: intermediate
467 
468    Concepts: Jacobi preconditioner
469 
470 .seealso: PCJacobiaUseRowMax(), PCJacobiaUseRowSum()
471 
472 @*/
473 PetscErrorCode  PCJacobiSetUseAbs(PC pc)
474 {
475   PetscErrorCode ierr;
476 
477   PetscFunctionBegin;
478   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
479   ierr = PetscTryMethod(pc,"PCJacobiSetUseAbs_C",(PC),(pc));CHKERRQ(ierr);
480   PetscFunctionReturn(0);
481 }
482 
483 #undef __FUNCT__
484 #define __FUNCT__ "PCJacobiSetUseRowMax"
485 /*@
486    PCJacobiSetUseRowMax - Causes the Jacobi preconditioner to use the
487       maximum entry in each row as the diagonal preconditioner, instead of
488       the diagonal entry
489 
490    Logically Collective on PC
491 
492    Input Parameters:
493 .  pc - the preconditioner context
494 
495 
496    Options Database Key:
497 .  -pc_jacobi_rowmax
498 
499    Level: intermediate
500 
501    Concepts: Jacobi preconditioner
502 
503 .seealso: PCJacobiaUseAbs()
504 @*/
505 PetscErrorCode  PCJacobiSetUseRowMax(PC pc)
506 {
507   PetscErrorCode ierr;
508 
509   PetscFunctionBegin;
510   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
511   ierr = PetscTryMethod(pc,"PCJacobiSetUseRowMax_C",(PC),(pc));CHKERRQ(ierr);
512   PetscFunctionReturn(0);
513 }
514 
515 #undef __FUNCT__
516 #define __FUNCT__ "PCJacobiSetUseRowSum"
517 /*@
518    PCJacobiSetUseRowSum - Causes the Jacobi preconditioner to use the
519       sum of each row as the diagonal preconditioner, instead of
520       the diagonal entry
521 
522    Logical Collective on PC
523 
524    Input Parameters:
525 .  pc - the preconditioner context
526 
527 
528    Options Database Key:
529 .  -pc_jacobi_rowsum
530 
531    Level: intermediate
532 
533    Concepts: Jacobi preconditioner
534 
535 .seealso: PCJacobiaUseAbs(), PCJacobiaUseRowSum()
536 @*/
537 PetscErrorCode  PCJacobiSetUseRowSum(PC pc)
538 {
539   PetscErrorCode ierr;
540 
541   PetscFunctionBegin;
542   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
543   ierr = PetscTryMethod(pc,"PCJacobiSetUseRowSum_C",(PC),(pc));CHKERRQ(ierr);
544   PetscFunctionReturn(0);
545 }
546 
547