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