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