xref: /petsc/src/ksp/pc/impls/factor/factimpl.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1 #include <../src/ksp/pc/impls/factor/factor.h> /*I "petscpc.h"  I*/
2 
3 PetscErrorCode PCFactorSetUpMatSolverType_Factor(PC pc)
4 {
5   PC_Factor *icc = (PC_Factor *)pc->data;
6 
7   PetscFunctionBegin;
8   PetscCheck(pc->pmat, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "You can only call this routine after the matrix object has been provided to the solver, for example with KSPSetOperators() or SNESSetJacobian()");
9   if (!((PC_Factor *)icc)->fact) PetscCall(MatGetFactor(pc->pmat, ((PC_Factor *)icc)->solvertype, ((PC_Factor *)icc)->factortype, &((PC_Factor *)icc)->fact));
10   PetscCheck(((PC_Factor *)icc)->fact, PetscObjectComm((PetscObject)pc->pmat), PETSC_ERR_SUP, "MatFactor type %s not supported by this matrix instance of type %s and solver type %s. Rerun with \"-info :mat | grep MatGetFactor_\" for additional information.",
11              MatFactorTypes[((PC_Factor *)icc)->factortype], ((PetscObject)pc->pmat)->type_name, ((PC_Factor *)icc)->solvertype);
12   PetscFunctionReturn(PETSC_SUCCESS);
13 }
14 
15 PetscErrorCode PCFactorSetZeroPivot_Factor(PC pc, PetscReal z)
16 {
17   PC_Factor *ilu = (PC_Factor *)pc->data;
18 
19   PetscFunctionBegin;
20   ilu->info.zeropivot = z;
21   PetscFunctionReturn(PETSC_SUCCESS);
22 }
23 
24 PetscErrorCode PCFactorSetShiftType_Factor(PC pc, MatFactorShiftType shifttype)
25 {
26   PC_Factor *dir = (PC_Factor *)pc->data;
27 
28   PetscFunctionBegin;
29   if (shifttype == (MatFactorShiftType)PETSC_DECIDE) dir->info.shifttype = (PetscReal)MAT_SHIFT_NONE;
30   else {
31     dir->info.shifttype = (PetscReal)shifttype;
32     if ((shifttype == MAT_SHIFT_NONZERO || shifttype == MAT_SHIFT_INBLOCKS) && dir->info.shiftamount == 0.0) { dir->info.shiftamount = 100.0 * PETSC_MACHINE_EPSILON; /* set default amount if user has not called PCFactorSetShiftAmount() yet */ }
33   }
34   PetscFunctionReturn(PETSC_SUCCESS);
35 }
36 
37 PetscErrorCode PCFactorSetShiftAmount_Factor(PC pc, PetscReal shiftamount)
38 {
39   PC_Factor *dir = (PC_Factor *)pc->data;
40 
41   PetscFunctionBegin;
42   if (shiftamount == (PetscReal)PETSC_DECIDE) dir->info.shiftamount = 100.0 * PETSC_MACHINE_EPSILON;
43   else dir->info.shiftamount = shiftamount;
44   PetscFunctionReturn(PETSC_SUCCESS);
45 }
46 
47 PetscErrorCode PCFactorSetDropTolerance_Factor(PC pc, PetscReal dt, PetscReal dtcol, PetscInt dtcount)
48 {
49   PC_Factor *ilu = (PC_Factor *)pc->data;
50 
51   PetscFunctionBegin;
52   if (pc->setupcalled && (!ilu->info.usedt || ((PC_Factor *)ilu)->info.dt != dt || ((PC_Factor *)ilu)->info.dtcol != dtcol || ((PC_Factor *)ilu)->info.dtcount != dtcount)) {
53     SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change tolerance after use");
54   }
55   ilu->info.usedt   = PETSC_TRUE;
56   ilu->info.dt      = dt;
57   ilu->info.dtcol   = dtcol;
58   ilu->info.dtcount = dtcount;
59   ilu->info.fill    = PETSC_DEFAULT;
60   PetscFunctionReturn(PETSC_SUCCESS);
61 }
62 
63 PetscErrorCode PCFactorSetFill_Factor(PC pc, PetscReal fill)
64 {
65   PC_Factor *dir = (PC_Factor *)pc->data;
66 
67   PetscFunctionBegin;
68   dir->info.fill = fill;
69   PetscFunctionReturn(PETSC_SUCCESS);
70 }
71 
72 PetscErrorCode PCFactorSetMatOrderingType_Factor(PC pc, MatOrderingType ordering)
73 {
74   PC_Factor *dir = (PC_Factor *)pc->data;
75   PetscBool  flg;
76 
77   PetscFunctionBegin;
78   if (!pc->setupcalled) {
79     PetscCall(PetscFree(dir->ordering));
80     PetscCall(PetscStrallocpy(ordering, (char **)&dir->ordering));
81   } else {
82     PetscCall(PetscStrcmp(dir->ordering, ordering, &flg));
83     PetscCheck(flg, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change ordering after use");
84   }
85   PetscFunctionReturn(PETSC_SUCCESS);
86 }
87 
88 PetscErrorCode PCFactorGetLevels_Factor(PC pc, PetscInt *levels)
89 {
90   PC_Factor *ilu = (PC_Factor *)pc->data;
91 
92   PetscFunctionBegin;
93   *levels = ilu->info.levels;
94   PetscFunctionReturn(PETSC_SUCCESS);
95 }
96 
97 PetscErrorCode PCFactorGetZeroPivot_Factor(PC pc, PetscReal *pivot)
98 {
99   PC_Factor *ilu = (PC_Factor *)pc->data;
100 
101   PetscFunctionBegin;
102   *pivot = ilu->info.zeropivot;
103   PetscFunctionReturn(PETSC_SUCCESS);
104 }
105 
106 PetscErrorCode PCFactorGetShiftAmount_Factor(PC pc, PetscReal *shift)
107 {
108   PC_Factor *ilu = (PC_Factor *)pc->data;
109 
110   PetscFunctionBegin;
111   *shift = ilu->info.shiftamount;
112   PetscFunctionReturn(PETSC_SUCCESS);
113 }
114 
115 PetscErrorCode PCFactorGetShiftType_Factor(PC pc, MatFactorShiftType *type)
116 {
117   PC_Factor *ilu = (PC_Factor *)pc->data;
118 
119   PetscFunctionBegin;
120   *type = (MatFactorShiftType)(int)ilu->info.shifttype;
121   PetscFunctionReturn(PETSC_SUCCESS);
122 }
123 
124 PetscErrorCode PCFactorSetLevels_Factor(PC pc, PetscInt levels)
125 {
126   PC_Factor *ilu = (PC_Factor *)pc->data;
127 
128   PetscFunctionBegin;
129   if (!pc->setupcalled) ilu->info.levels = levels;
130   else if (ilu->info.levels != levels) {
131     PetscUseTypeMethod(pc, reset); /* remove previous factored matrices */
132     pc->setupcalled  = 0;          /* force a complete rebuild of preconditioner factored matrices */
133     ilu->info.levels = levels;
134   } else PetscCheck(!ilu->info.usedt, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change levels after use with ILUdt");
135   PetscFunctionReturn(PETSC_SUCCESS);
136 }
137 
138 PetscErrorCode PCFactorSetAllowDiagonalFill_Factor(PC pc, PetscBool flg)
139 {
140   PC_Factor *dir = (PC_Factor *)pc->data;
141 
142   PetscFunctionBegin;
143   dir->info.diagonal_fill = (PetscReal)flg;
144   PetscFunctionReturn(PETSC_SUCCESS);
145 }
146 
147 PetscErrorCode PCFactorGetAllowDiagonalFill_Factor(PC pc, PetscBool *flg)
148 {
149   PC_Factor *dir = (PC_Factor *)pc->data;
150 
151   PetscFunctionBegin;
152   *flg = dir->info.diagonal_fill ? PETSC_TRUE : PETSC_FALSE;
153   PetscFunctionReturn(PETSC_SUCCESS);
154 }
155 
156 PetscErrorCode PCFactorSetPivotInBlocks_Factor(PC pc, PetscBool pivot)
157 {
158   PC_Factor *dir = (PC_Factor *)pc->data;
159 
160   PetscFunctionBegin;
161   dir->info.pivotinblocks = pivot ? 1.0 : 0.0;
162   PetscFunctionReturn(PETSC_SUCCESS);
163 }
164 
165 PetscErrorCode PCFactorGetMatrix_Factor(PC pc, Mat *mat)
166 {
167   PC_Factor *ilu = (PC_Factor *)pc->data;
168 
169   PetscFunctionBegin;
170   PetscCheck(ilu->fact, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Matrix not yet factored; call after KSPSetUp() or PCSetUp()");
171   *mat = ilu->fact;
172   PetscFunctionReturn(PETSC_SUCCESS);
173 }
174 
175 /* allow access to preallocation information */
176 #include <petsc/private/matimpl.h>
177 
178 PetscErrorCode PCFactorSetMatSolverType_Factor(PC pc, MatSolverType stype)
179 {
180   PC_Factor *lu = (PC_Factor *)pc->data;
181 
182   PetscFunctionBegin;
183   if (lu->fact && lu->fact->assembled) {
184     MatSolverType ltype;
185     PetscBool     flg;
186     PetscCall(MatFactorGetSolverType(lu->fact, &ltype));
187     PetscCall(PetscStrcmp(stype, ltype, &flg));
188     PetscCheck(flg, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change solver matrix package from %s to %s after PC has been setup or used", ltype, stype);
189   }
190 
191   PetscCall(PetscFree(lu->solvertype));
192   PetscCall(PetscStrallocpy(stype, &lu->solvertype));
193   PetscFunctionReturn(PETSC_SUCCESS);
194 }
195 
196 PetscErrorCode PCFactorGetMatSolverType_Factor(PC pc, MatSolverType *stype)
197 {
198   PC_Factor *lu = (PC_Factor *)pc->data;
199 
200   PetscFunctionBegin;
201   *stype = lu->solvertype;
202   PetscFunctionReturn(PETSC_SUCCESS);
203 }
204 
205 PetscErrorCode PCFactorSetColumnPivot_Factor(PC pc, PetscReal dtcol)
206 {
207   PC_Factor *dir = (PC_Factor *)pc->data;
208 
209   PetscFunctionBegin;
210   PetscCheck(dtcol >= 0.0 && dtcol <= 1.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Column pivot tolerance is %g must be between 0 and 1", (double)dtcol);
211   dir->info.dtcol = dtcol;
212   PetscFunctionReturn(PETSC_SUCCESS);
213 }
214 
215 PetscErrorCode PCSetFromOptions_Factor(PC pc, PetscOptionItems *PetscOptionsObject)
216 {
217   PC_Factor        *factor = (PC_Factor *)pc->data;
218   PetscBool         flg, set;
219   char              tname[256], solvertype[64];
220   PetscFunctionList ordlist;
221   PetscEnum         etmp;
222   PetscBool         inplace;
223 
224   PetscFunctionBegin;
225   PetscCall(PCFactorGetUseInPlace(pc, &inplace));
226   PetscCall(PetscOptionsBool("-pc_factor_in_place", "Form factored matrix in the same memory as the matrix", "PCFactorSetUseInPlace", inplace, &flg, &set));
227   if (set) PetscCall(PCFactorSetUseInPlace(pc, flg));
228   PetscCall(PetscOptionsReal("-pc_factor_fill", "Expected non-zeros in factored matrix", "PCFactorSetFill", ((PC_Factor *)factor)->info.fill, &((PC_Factor *)factor)->info.fill, NULL));
229 
230   PetscCall(PetscOptionsEnum("-pc_factor_shift_type", "Type of shift to add to diagonal", "PCFactorSetShiftType", MatFactorShiftTypes, (PetscEnum)(int)((PC_Factor *)factor)->info.shifttype, &etmp, &flg));
231   if (flg) PetscCall(PCFactorSetShiftType(pc, (MatFactorShiftType)etmp));
232   PetscCall(PetscOptionsReal("-pc_factor_shift_amount", "Shift added to diagonal", "PCFactorSetShiftAmount", ((PC_Factor *)factor)->info.shiftamount, &((PC_Factor *)factor)->info.shiftamount, NULL));
233 
234   PetscCall(PetscOptionsReal("-pc_factor_zeropivot", "Pivot is considered zero if less than", "PCFactorSetZeroPivot", ((PC_Factor *)factor)->info.zeropivot, &((PC_Factor *)factor)->info.zeropivot, NULL));
235   PetscCall(PetscOptionsReal("-pc_factor_column_pivot", "Column pivot tolerance (used only for some factorization)", "PCFactorSetColumnPivot", ((PC_Factor *)factor)->info.dtcol, &((PC_Factor *)factor)->info.dtcol, &flg));
236 
237   PetscCall(PetscOptionsBool("-pc_factor_pivot_in_blocks", "Pivot inside matrix dense blocks for BAIJ and SBAIJ", "PCFactorSetPivotInBlocks", ((PC_Factor *)factor)->info.pivotinblocks ? PETSC_TRUE : PETSC_FALSE, &flg, &set));
238   if (set) PetscCall(PCFactorSetPivotInBlocks(pc, flg));
239 
240   PetscCall(PetscOptionsBool("-pc_factor_reuse_fill", "Use fill from previous factorization", "PCFactorSetReuseFill", PETSC_FALSE, &flg, &set));
241   if (set) PetscCall(PCFactorSetReuseFill(pc, flg));
242   PetscCall(PetscOptionsBool("-pc_factor_reuse_ordering", "Reuse ordering from previous factorization", "PCFactorSetReuseOrdering", PETSC_FALSE, &flg, &set));
243   if (set) PetscCall(PCFactorSetReuseOrdering(pc, flg));
244 
245   PetscCall(PetscOptionsDeprecated("-pc_factor_mat_solver_package", "-pc_factor_mat_solver_type", "3.9", NULL));
246   PetscCall(PetscOptionsString("-pc_factor_mat_solver_type", "Specific direct solver to use", "MatGetFactor", ((PC_Factor *)factor)->solvertype, solvertype, sizeof(solvertype), &flg));
247   if (flg) PetscCall(PCFactorSetMatSolverType(pc, solvertype));
248   PetscCall(PCFactorSetDefaultOrdering_Factor(pc));
249   PetscCall(MatGetOrderingList(&ordlist));
250   PetscCall(PetscOptionsFList("-pc_factor_mat_ordering_type", "Reordering to reduce nonzeros in factored matrix", "PCFactorSetMatOrderingType", ordlist, ((PC_Factor *)factor)->ordering, tname, sizeof(tname), &flg));
251   if (flg) PetscCall(PCFactorSetMatOrderingType(pc, tname));
252   PetscFunctionReturn(PETSC_SUCCESS);
253 }
254 
255 PetscErrorCode PCView_Factor(PC pc, PetscViewer viewer)
256 {
257   PC_Factor        *factor = (PC_Factor *)pc->data;
258   PetscBool         isstring, iascii, canuseordering;
259   MatInfo           info;
260   MatOrderingType   ordering;
261   PetscViewerFormat format;
262 
263   PetscFunctionBegin;
264   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
265   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
266   if (iascii) {
267     if (factor->inplace) {
268       PetscCall(PetscViewerASCIIPrintf(viewer, "  in-place factorization\n"));
269     } else {
270       PetscCall(PetscViewerASCIIPrintf(viewer, "  out-of-place factorization\n"));
271     }
272 
273     if (factor->reusefill) PetscCall(PetscViewerASCIIPrintf(viewer, "  Reusing fill from past factorization\n"));
274     if (factor->reuseordering) PetscCall(PetscViewerASCIIPrintf(viewer, "  Reusing reordering from past factorization\n"));
275     if (factor->factortype == MAT_FACTOR_ILU || factor->factortype == MAT_FACTOR_ICC) {
276       if (factor->info.dt > 0) {
277         PetscCall(PetscViewerASCIIPrintf(viewer, "  drop tolerance %g\n", (double)factor->info.dt));
278         PetscCall(PetscViewerASCIIPrintf(viewer, "  max nonzeros per row %" PetscInt_FMT "\n", (PetscInt)factor->info.dtcount));
279         PetscCall(PetscViewerASCIIPrintf(viewer, "  column permutation tolerance %g\n", (double)factor->info.dtcol));
280       } else if (factor->info.levels == 1) {
281         PetscCall(PetscViewerASCIIPrintf(viewer, "  %" PetscInt_FMT " level of fill\n", (PetscInt)factor->info.levels));
282       } else {
283         PetscCall(PetscViewerASCIIPrintf(viewer, "  %" PetscInt_FMT " levels of fill\n", (PetscInt)factor->info.levels));
284       }
285     }
286 
287     PetscCall(PetscViewerASCIIPrintf(viewer, "  tolerance for zero pivot %g\n", (double)factor->info.zeropivot));
288     if (MatFactorShiftTypesDetail[(int)factor->info.shifttype]) { /* Only print when using a nontrivial shift */
289       PetscCall(PetscViewerASCIIPrintf(viewer, "  using %s [%s]\n", MatFactorShiftTypesDetail[(int)factor->info.shifttype], MatFactorShiftTypes[(int)factor->info.shifttype]));
290     }
291 
292     if (factor->fact) {
293       PetscCall(MatFactorGetCanUseOrdering(factor->fact, &canuseordering));
294       if (!canuseordering) ordering = MATORDERINGEXTERNAL;
295       else ordering = factor->ordering;
296       PetscCall(PetscViewerASCIIPrintf(viewer, "  matrix ordering: %s\n", ordering));
297       if (!factor->fact->assembled) {
298         PetscCall(PetscViewerASCIIPrintf(viewer, "  matrix solver type: %s\n", factor->fact->solvertype));
299         PetscCall(PetscViewerASCIIPrintf(viewer, "  matrix not yet factored; no additional information available\n"));
300       } else {
301         PetscCall(MatGetInfo(factor->fact, MAT_LOCAL, &info));
302         PetscCall(PetscViewerASCIIPrintf(viewer, "  factor fill ratio given %g, needed %g\n", (double)info.fill_ratio_given, (double)info.fill_ratio_needed));
303         PetscCall(PetscViewerASCIIPrintf(viewer, "    Factored matrix follows:\n"));
304         PetscCall(PetscViewerASCIIPushTab(viewer));
305         PetscCall(PetscViewerASCIIPushTab(viewer));
306         PetscCall(PetscViewerASCIIPushTab(viewer));
307         PetscCall(PetscViewerGetFormat(viewer, &format));
308         PetscCall(PetscViewerPushFormat(viewer, format != PETSC_VIEWER_ASCII_INFO_DETAIL ? PETSC_VIEWER_ASCII_INFO : PETSC_VIEWER_ASCII_INFO_DETAIL));
309         PetscCall(MatView(factor->fact, viewer));
310         PetscCall(PetscViewerPopFormat(viewer));
311         PetscCall(PetscViewerASCIIPopTab(viewer));
312         PetscCall(PetscViewerASCIIPopTab(viewer));
313         PetscCall(PetscViewerASCIIPopTab(viewer));
314       }
315     }
316 
317   } else if (isstring) {
318     MatFactorType t;
319     PetscCall(MatGetFactorType(factor->fact, &t));
320     if (t == MAT_FACTOR_ILU || t == MAT_FACTOR_ICC) PetscCall(PetscViewerStringSPrintf(viewer, " lvls=%" PetscInt_FMT ",order=%s", (PetscInt)factor->info.levels, factor->ordering));
321   }
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324