xref: /petsc/src/ksp/pc/impls/factor/ilu/ilu.c (revision 503c0ea9b45bcfbcebbb1ea5341243bbc69f0bea)
1 
2 /*
3    Defines a ILU factorization preconditioner for any Mat implementation
4 */
5 #include <../src/ksp/pc/impls/factor/ilu/ilu.h>     /*I "petscpc.h"  I*/
6 
7 PetscErrorCode  PCFactorReorderForNonzeroDiagonal_ILU(PC pc,PetscReal z)
8 {
9   PC_ILU *ilu = (PC_ILU*)pc->data;
10 
11   PetscFunctionBegin;
12   ilu->nonzerosalongdiagonal = PETSC_TRUE;
13   if (z == PETSC_DECIDE) ilu->nonzerosalongdiagonaltol = 1.e-10;
14   else ilu->nonzerosalongdiagonaltol = z;
15   PetscFunctionReturn(0);
16 }
17 
18 PetscErrorCode PCReset_ILU(PC pc)
19 {
20   PC_ILU         *ilu = (PC_ILU*)pc->data;
21 
22   PetscFunctionBegin;
23   if (!ilu->hdr.inplace) PetscCall(MatDestroy(&((PC_Factor*)ilu)->fact));
24   if (ilu->row && ilu->col && ilu->row != ilu->col) PetscCall(ISDestroy(&ilu->row));
25   PetscCall(ISDestroy(&ilu->col));
26   PetscFunctionReturn(0);
27 }
28 
29 PetscErrorCode  PCFactorSetDropTolerance_ILU(PC pc,PetscReal dt,PetscReal dtcol,PetscInt dtcount)
30 {
31   PC_ILU *ilu = (PC_ILU*)pc->data;
32 
33   PetscFunctionBegin;
34   if (pc->setupcalled && (((PC_Factor*)ilu)->info.dt != dt || ((PC_Factor*)ilu)->info.dtcol != dtcol || ((PC_Factor*)ilu)->info.dtcount != dtcount)) {
35     SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot change drop tolerance after using PC");
36   }
37   ((PC_Factor*)ilu)->info.dt      = dt;
38   ((PC_Factor*)ilu)->info.dtcol   = dtcol;
39   ((PC_Factor*)ilu)->info.dtcount = dtcount;
40   ((PC_Factor*)ilu)->info.usedt   = 1.0;
41   PetscFunctionReturn(0);
42 }
43 
44 static PetscErrorCode PCSetFromOptions_ILU(PetscOptionItems *PetscOptionsObject,PC pc)
45 {
46   PetscInt       itmp;
47   PetscBool      flg,set;
48   PC_ILU         *ilu = (PC_ILU*)pc->data;
49   PetscReal      tol;
50 
51   PetscFunctionBegin;
52   PetscCall(PetscOptionsHead(PetscOptionsObject,"ILU Options"));
53   PetscCall(PCSetFromOptions_Factor(PetscOptionsObject,pc));
54 
55   PetscCall(PetscOptionsInt("-pc_factor_levels","levels of fill","PCFactorSetLevels",(PetscInt)((PC_Factor*)ilu)->info.levels,&itmp,&flg));
56   if (flg) ((PC_Factor*)ilu)->info.levels = itmp;
57 
58   PetscCall(PetscOptionsBool("-pc_factor_diagonal_fill","Allow fill into empty diagonal entry","PCFactorSetAllowDiagonalFill",((PC_Factor*)ilu)->info.diagonal_fill ? PETSC_TRUE : PETSC_FALSE,&flg,&set));
59   if (set) ((PC_Factor*)ilu)->info.diagonal_fill = (PetscReal) flg;
60   PetscCall(PetscOptionsName("-pc_factor_nonzeros_along_diagonal","Reorder to remove zeros from diagonal","PCFactorReorderForNonzeroDiagonal",&flg));
61   if (flg) {
62     tol  = PETSC_DECIDE;
63     PetscCall(PetscOptionsReal("-pc_factor_nonzeros_along_diagonal","Reorder to remove zeros from diagonal","PCFactorReorderForNonzeroDiagonal",ilu->nonzerosalongdiagonaltol,&tol,NULL));
64     PetscCall(PCFactorReorderForNonzeroDiagonal(pc,tol));
65   }
66 
67   PetscCall(PetscOptionsTail());
68   PetscFunctionReturn(0);
69 }
70 
71 static PetscErrorCode PCSetUp_ILU(PC pc)
72 {
73   PC_ILU                 *ilu = (PC_ILU*)pc->data;
74   MatInfo                info;
75   PetscBool              flg;
76   MatSolverType          stype;
77   MatFactorError         err;
78 
79   PetscFunctionBegin;
80   pc->failedreason = PC_NOERROR;
81   /* ugly hack to change default, since it is not support by some matrix types */
82   if (((PC_Factor*)ilu)->info.shifttype == (PetscReal)MAT_SHIFT_NONZERO) {
83     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATSEQAIJ,&flg));
84     if (!flg) {
85       PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATMPIAIJ,&flg));
86       if (!flg) {
87         ((PC_Factor*)ilu)->info.shifttype = (PetscReal)MAT_SHIFT_INBLOCKS;
88         PetscCall(PetscInfo(pc,"Changing shift type from NONZERO to INBLOCKS because block matrices do not support NONZERO\n"));
89       }
90     }
91   }
92 
93   PetscCall(MatSetErrorIfFailure(pc->pmat,pc->erroriffailure));
94   if (ilu->hdr.inplace) {
95     if (!pc->setupcalled) {
96 
97       /* In-place factorization only makes sense with the natural ordering,
98          so we only need to get the ordering once, even if nonzero structure changes */
99       /* Should not get the ordering if the factorization routine does not use it, but do not yet have access to the factor matrix */
100       PetscCall(PCFactorSetDefaultOrdering_Factor(pc));
101       PetscCall(MatDestroy(&((PC_Factor*)ilu)->fact));
102       PetscCall(MatGetOrdering(pc->pmat,((PC_Factor*)ilu)->ordering,&ilu->row,&ilu->col));
103       if (ilu->row) PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->row));
104       if (ilu->col) PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->col));
105     }
106 
107     /* In place ILU only makes sense with fill factor of 1.0 because
108        cannot have levels of fill */
109     ((PC_Factor*)ilu)->info.fill          = 1.0;
110     ((PC_Factor*)ilu)->info.diagonal_fill = 0.0;
111 
112     PetscCall(MatILUFactor(pc->pmat,ilu->row,ilu->col,&((PC_Factor*)ilu)->info));
113     PetscCall(MatFactorGetError(pc->pmat,&err));
114     if (err) { /* Factor() fails */
115       pc->failedreason = (PCFailedReason)err;
116       PetscFunctionReturn(0);
117     }
118 
119     ((PC_Factor*)ilu)->fact = pc->pmat;
120     /* must update the pc record of the matrix state or the PC will attempt to run PCSetUp() yet again */
121     PetscCall(PetscObjectStateGet((PetscObject)pc->pmat,&pc->matstate));
122   } else {
123     if (!pc->setupcalled) {
124       /* first time in so compute reordering and symbolic factorization */
125       PetscBool canuseordering;
126       if (!((PC_Factor*)ilu)->fact) {
127         PetscCall(MatGetFactor(pc->pmat,((PC_Factor*)ilu)->solvertype,MAT_FACTOR_ILU,&((PC_Factor*)ilu)->fact));
128         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)((PC_Factor*)ilu)->fact));
129       }
130       PetscCall(MatFactorGetCanUseOrdering(((PC_Factor*)ilu)->fact,&canuseordering));
131       if (canuseordering) {
132         PetscCall(PCFactorSetDefaultOrdering_Factor(pc));
133         PetscCall(MatGetOrdering(pc->pmat,((PC_Factor*)ilu)->ordering,&ilu->row,&ilu->col));
134         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->row));
135         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->col));
136         /*  Remove zeros along diagonal?     */
137         if (ilu->nonzerosalongdiagonal) {
138           PetscCall(MatReorderForNonzeroDiagonal(pc->pmat,ilu->nonzerosalongdiagonaltol,ilu->row,ilu->col));
139         }
140       }
141       PetscCall(MatILUFactorSymbolic(((PC_Factor*)ilu)->fact,pc->pmat,ilu->row,ilu->col,&((PC_Factor*)ilu)->info));
142       PetscCall(MatGetInfo(((PC_Factor*)ilu)->fact,MAT_LOCAL,&info));
143       ilu->hdr.actualfill = info.fill_ratio_needed;
144     } else if (pc->flag != SAME_NONZERO_PATTERN) {
145       if (!ilu->hdr.reuseordering) {
146         PetscBool canuseordering;
147         PetscCall(MatDestroy(&((PC_Factor*)ilu)->fact));
148         PetscCall(MatGetFactor(pc->pmat,((PC_Factor*)ilu)->solvertype,MAT_FACTOR_ILU,&((PC_Factor*)ilu)->fact));
149         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)((PC_Factor*)ilu)->fact));
150         PetscCall(MatFactorGetCanUseOrdering(((PC_Factor*)ilu)->fact,&canuseordering));
151         if (canuseordering) {
152           /* compute a new ordering for the ILU */
153           PetscCall(ISDestroy(&ilu->row));
154           PetscCall(ISDestroy(&ilu->col));
155           PetscCall(PCFactorSetDefaultOrdering_Factor(pc));
156           PetscCall(MatGetOrdering(pc->pmat,((PC_Factor*)ilu)->ordering,&ilu->row,&ilu->col));
157           PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->row));
158           PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)ilu->col));
159           /*  Remove zeros along diagonal?     */
160           if (ilu->nonzerosalongdiagonal) {
161             PetscCall(MatReorderForNonzeroDiagonal(pc->pmat,ilu->nonzerosalongdiagonaltol,ilu->row,ilu->col));
162           }
163         }
164       }
165       PetscCall(MatILUFactorSymbolic(((PC_Factor*)ilu)->fact,pc->pmat,ilu->row,ilu->col,&((PC_Factor*)ilu)->info));
166       PetscCall(MatGetInfo(((PC_Factor*)ilu)->fact,MAT_LOCAL,&info));
167       ilu->hdr.actualfill = info.fill_ratio_needed;
168     }
169     PetscCall(MatFactorGetError(((PC_Factor*)ilu)->fact,&err));
170     if (err) { /* FactorSymbolic() fails */
171       pc->failedreason = (PCFailedReason)err;
172       PetscFunctionReturn(0);
173     }
174 
175     PetscCall(MatLUFactorNumeric(((PC_Factor*)ilu)->fact,pc->pmat,&((PC_Factor*)ilu)->info));
176     PetscCall(MatFactorGetError(((PC_Factor*)ilu)->fact,&err));
177     if (err) { /* FactorNumeric() fails */
178       pc->failedreason = (PCFailedReason)err;
179     }
180   }
181 
182   PetscCall(PCFactorGetMatSolverType(pc,&stype));
183   if (!stype) {
184     MatSolverType solverpackage;
185     PetscCall(MatFactorGetSolverType(((PC_Factor*)ilu)->fact,&solverpackage));
186     PetscCall(PCFactorSetMatSolverType(pc,solverpackage));
187   }
188   PetscFunctionReturn(0);
189 }
190 
191 static PetscErrorCode PCDestroy_ILU(PC pc)
192 {
193   PC_ILU         *ilu = (PC_ILU*)pc->data;
194 
195   PetscFunctionBegin;
196   PetscCall(PCReset_ILU(pc));
197   PetscCall(PetscFree(((PC_Factor*)ilu)->solvertype));
198   PetscCall(PetscFree(((PC_Factor*)ilu)->ordering));
199   PetscCall(PetscFree(pc->data));
200   PetscFunctionReturn(0);
201 }
202 
203 static PetscErrorCode PCApply_ILU(PC pc,Vec x,Vec y)
204 {
205   PC_ILU         *ilu = (PC_ILU*)pc->data;
206 
207   PetscFunctionBegin;
208   PetscCall(MatSolve(((PC_Factor*)ilu)->fact,x,y));
209   PetscFunctionReturn(0);
210 }
211 
212 static PetscErrorCode PCMatApply_ILU(PC pc,Mat X,Mat Y)
213 {
214   PC_ILU         *ilu = (PC_ILU*)pc->data;
215 
216   PetscFunctionBegin;
217   PetscCall(MatMatSolve(((PC_Factor*)ilu)->fact,X,Y));
218   PetscFunctionReturn(0);
219 }
220 
221 static PetscErrorCode PCApplyTranspose_ILU(PC pc,Vec x,Vec y)
222 {
223   PC_ILU         *ilu = (PC_ILU*)pc->data;
224 
225   PetscFunctionBegin;
226   PetscCall(MatSolveTranspose(((PC_Factor*)ilu)->fact,x,y));
227   PetscFunctionReturn(0);
228 }
229 
230 static PetscErrorCode PCApplySymmetricLeft_ILU(PC pc,Vec x,Vec y)
231 {
232   PC_ILU         *icc = (PC_ILU*)pc->data;
233 
234   PetscFunctionBegin;
235   PetscCall(MatForwardSolve(((PC_Factor*)icc)->fact,x,y));
236   PetscFunctionReturn(0);
237 }
238 
239 static PetscErrorCode PCApplySymmetricRight_ILU(PC pc,Vec x,Vec y)
240 {
241   PC_ILU         *icc = (PC_ILU*)pc->data;
242 
243   PetscFunctionBegin;
244   PetscCall(MatBackwardSolve(((PC_Factor*)icc)->fact,x,y));
245   PetscFunctionReturn(0);
246 }
247 
248 /*MC
249      PCILU - Incomplete factorization preconditioners.
250 
251    Options Database Keys:
252 +  -pc_factor_levels <k> - number of levels of fill for ILU(k)
253 .  -pc_factor_in_place - only for ILU(0) with natural ordering, reuses the space of the matrix for
254                       its factorization (overwrites original matrix)
255 .  -pc_factor_diagonal_fill - fill in a zero diagonal even if levels of fill indicate it wouldn't be fill
256 .  -pc_factor_reuse_ordering - reuse ordering of factorized matrix from previous factorization
257 .  -pc_factor_fill <nfill> - expected amount of fill in factored matrix compared to original matrix, nfill > 1
258 .  -pc_factor_nonzeros_along_diagonal - reorder the matrix before factorization to remove zeros from the diagonal,
259                                    this decreases the chance of getting a zero pivot
260 .  -pc_factor_mat_ordering_type <natural,nd,1wd,rcm,qmd> - set the row/column ordering of the factored matrix
261 -  -pc_factor_pivot_in_blocks - for block ILU(k) factorization, i.e. with BAIJ matrices with block size larger
262                              than 1 the diagonal blocks are factored with partial pivoting (this increases the
263                              stability of the ILU factorization
264 
265    Level: beginner
266 
267    Notes:
268     Only implemented for some matrix formats. (for parallel see PCHYPRE for hypre's ILU)
269 
270           For BAIJ matrices this implements a point block ILU
271 
272           The "symmetric" application of this preconditioner is not actually symmetric since L is not transpose(U)
273           even when the matrix is not symmetric since the U stores the diagonals of the factorization.
274 
275           If you are using MATSEQAIJCUSPARSE matrices (or MATMPIAIJCUSPARSE matrices with block Jacobi), factorization
276           is never done on the GPU).
277 
278    References:
279 +  * - T. Dupont, R. Kendall, and H. Rachford. An approximate factorization procedure for solving
280    self adjoint elliptic difference equations. SIAM J. Numer. Anal., 5, 1968.
281 .  * -  T.A. Oliphant. An implicit numerical method for solving two dimensional timedependent diffusion problems. Quart. Appl. Math., 19, 1961.
282 -  * -  TONY F. CHAN AND HENK A. VAN DER VORST, APPROXIMATE AND INCOMPLETE FACTORIZATIONS,
283       Chapter in Parallel Numerical
284       Algorithms, edited by D. Keyes, A. Semah, V. Venkatakrishnan, ICASE/LaRC Interdisciplinary Series in
285       Science and Engineering, Kluwer.
286 
287 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCSOR, MatOrderingType,
288            PCFactorSetZeroPivot(), PCFactorSetShiftSetType(), PCFactorSetAmount(),
289            PCFactorSetDropTolerance(),PCFactorSetFill(), PCFactorSetMatOrderingType(), PCFactorSetReuseOrdering(),
290            PCFactorSetLevels(), PCFactorSetUseInPlace(), PCFactorSetAllowDiagonalFill(), PCFactorSetPivotInBlocks(),
291            PCFactorGetAllowDiagonalFill(), PCFactorGetUseInPlace()
292 
293 M*/
294 
295 PETSC_EXTERN PetscErrorCode PCCreate_ILU(PC pc)
296 {
297   PC_ILU         *ilu;
298 
299   PetscFunctionBegin;
300   PetscCall(PetscNewLog(pc,&ilu));
301   pc->data = (void*)ilu;
302   PetscCall(PCFactorInitialize(pc,MAT_FACTOR_ILU));
303 
304   ((PC_Factor*)ilu)->info.levels        = 0.;
305   ((PC_Factor*)ilu)->info.fill          = 1.0;
306   ilu->col                              = NULL;
307   ilu->row                              = NULL;
308   ((PC_Factor*)ilu)->info.dt            = PETSC_DEFAULT;
309   ((PC_Factor*)ilu)->info.dtcount       = PETSC_DEFAULT;
310   ((PC_Factor*)ilu)->info.dtcol         = PETSC_DEFAULT;
311 
312   pc->ops->reset               = PCReset_ILU;
313   pc->ops->destroy             = PCDestroy_ILU;
314   pc->ops->apply               = PCApply_ILU;
315   pc->ops->matapply            = PCMatApply_ILU;
316   pc->ops->applytranspose      = PCApplyTranspose_ILU;
317   pc->ops->setup               = PCSetUp_ILU;
318   pc->ops->setfromoptions      = PCSetFromOptions_ILU;
319   pc->ops->view                = PCView_Factor;
320   pc->ops->applysymmetricleft  = PCApplySymmetricLeft_ILU;
321   pc->ops->applysymmetricright = PCApplySymmetricRight_ILU;
322   pc->ops->applyrichardson     = NULL;
323   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCFactorSetDropTolerance_C",PCFactorSetDropTolerance_ILU));
324   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCFactorReorderForNonzeroDiagonal_C",PCFactorReorderForNonzeroDiagonal_ILU));
325   PetscFunctionReturn(0);
326 }
327