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