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, <ype)); 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