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