1 /* 2 Defines a direct factorization preconditioner for any Mat implementation 3 Note: this need not be considered a preconditioner since it supplies 4 a direct solver. 5 */ 6 7 #include <../src/ksp/pc/impls/factor/lu/lu.h> /*I "petscpc.h" I*/ 8 9 static PetscErrorCode PCFactorReorderForNonzeroDiagonal_LU(PC pc, PetscReal z) 10 { 11 PC_LU *lu = (PC_LU *)pc->data; 12 13 PetscFunctionBegin; 14 lu->nonzerosalongdiagonal = PETSC_TRUE; 15 if (z == (PetscReal)PETSC_DECIDE) lu->nonzerosalongdiagonaltol = 1.e-10; 16 else lu->nonzerosalongdiagonaltol = z; 17 PetscFunctionReturn(PETSC_SUCCESS); 18 } 19 20 static PetscErrorCode PCSetFromOptions_LU(PC pc, PetscOptionItems PetscOptionsObject) 21 { 22 PC_LU *lu = (PC_LU *)pc->data; 23 PetscBool flg = PETSC_FALSE; 24 PetscReal tol; 25 26 PetscFunctionBegin; 27 PetscOptionsHeadBegin(PetscOptionsObject, "LU options"); 28 PetscCall(PCSetFromOptions_Factor(pc, PetscOptionsObject)); 29 30 PetscCall(PetscOptionsName("-pc_factor_nonzeros_along_diagonal", "Reorder to remove zeros from diagonal", "PCFactorReorderForNonzeroDiagonal", &flg)); 31 if (flg) { 32 tol = PETSC_DECIDE; 33 PetscCall(PetscOptionsReal("-pc_factor_nonzeros_along_diagonal", "Reorder to remove zeros from diagonal", "PCFactorReorderForNonzeroDiagonal", lu->nonzerosalongdiagonaltol, &tol, NULL)); 34 PetscCall(PCFactorReorderForNonzeroDiagonal(pc, tol)); 35 } 36 PetscOptionsHeadEnd(); 37 PetscFunctionReturn(PETSC_SUCCESS); 38 } 39 40 static PetscErrorCode PCSetUp_LU(PC pc) 41 { 42 PC_LU *dir = (PC_LU *)pc->data; 43 MatSolverType stype; 44 MatFactorError err; 45 const char *prefix; 46 47 PetscFunctionBegin; 48 pc->failedreason = PC_NOERROR; 49 if (dir->hdr.reusefill && pc->setupcalled) ((PC_Factor *)dir)->info.fill = dir->hdr.actualfill; 50 51 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 52 PetscCall(MatSetOptionsPrefixFactor(pc->pmat, prefix)); 53 54 PetscCall(MatSetErrorIfFailure(pc->pmat, pc->erroriffailure)); 55 if (dir->hdr.inplace) { 56 MatFactorType ftype; 57 58 PetscCall(MatGetFactorType(pc->pmat, &ftype)); 59 if (ftype == MAT_FACTOR_NONE) { 60 if (dir->row && dir->col && dir->row != dir->col) PetscCall(ISDestroy(&dir->row)); 61 PetscCall(ISDestroy(&dir->col)); 62 /* This should only get the ordering if needed, but since MatGetFactor() is not called we can't know if it is needed */ 63 PetscCall(PCFactorSetDefaultOrdering_Factor(pc)); 64 PetscCall(MatGetOrdering(pc->pmat, ((PC_Factor *)dir)->ordering, &dir->row, &dir->col)); 65 if (dir->row) { } 66 PetscCall(MatLUFactor(pc->pmat, dir->row, dir->col, &((PC_Factor *)dir)->info)); 67 PetscCall(MatFactorGetError(pc->pmat, &err)); 68 if (err) { /* Factor() fails */ 69 pc->failedreason = (PCFailedReason)err; 70 PetscFunctionReturn(PETSC_SUCCESS); 71 } 72 } 73 ((PC_Factor *)dir)->fact = pc->pmat; 74 } else { 75 MatInfo info; 76 77 if (!pc->setupcalled) { 78 PetscBool canuseordering; 79 80 PetscCall(PCFactorSetUpMatSolverType(pc)); 81 PetscCall(MatFactorGetCanUseOrdering(((PC_Factor *)dir)->fact, &canuseordering)); 82 if (canuseordering) { 83 PetscCall(PCFactorSetDefaultOrdering_Factor(pc)); 84 PetscCall(MatGetOrdering(pc->pmat, ((PC_Factor *)dir)->ordering, &dir->row, &dir->col)); 85 if (dir->nonzerosalongdiagonal) PetscCall(MatReorderForNonzeroDiagonal(pc->pmat, dir->nonzerosalongdiagonaltol, dir->row, dir->col)); 86 } 87 PetscCall(MatLUFactorSymbolic(((PC_Factor *)dir)->fact, pc->pmat, dir->row, dir->col, &((PC_Factor *)dir)->info)); 88 PetscCall(MatGetInfo(((PC_Factor *)dir)->fact, MAT_LOCAL, &info)); 89 dir->hdr.actualfill = info.fill_ratio_needed; 90 } else if (pc->flag != SAME_NONZERO_PATTERN) { 91 PetscBool canuseordering; 92 93 if (!dir->hdr.reuseordering) { 94 PetscCall(MatDestroy(&((PC_Factor *)dir)->fact)); 95 PetscCall(PCFactorSetUpMatSolverType(pc)); 96 PetscCall(MatFactorGetCanUseOrdering(((PC_Factor *)dir)->fact, &canuseordering)); 97 if (canuseordering) { 98 if (dir->row && dir->col && dir->row != dir->col) PetscCall(ISDestroy(&dir->row)); 99 PetscCall(ISDestroy(&dir->col)); 100 PetscCall(PCFactorSetDefaultOrdering_Factor(pc)); 101 PetscCall(MatGetOrdering(pc->pmat, ((PC_Factor *)dir)->ordering, &dir->row, &dir->col)); 102 if (dir->nonzerosalongdiagonal) PetscCall(MatReorderForNonzeroDiagonal(pc->pmat, dir->nonzerosalongdiagonaltol, dir->row, dir->col)); 103 } 104 } 105 PetscCall(MatLUFactorSymbolic(((PC_Factor *)dir)->fact, pc->pmat, dir->row, dir->col, &((PC_Factor *)dir)->info)); 106 PetscCall(MatGetInfo(((PC_Factor *)dir)->fact, MAT_LOCAL, &info)); 107 dir->hdr.actualfill = info.fill_ratio_needed; 108 } else { 109 PetscCall(MatFactorGetError(((PC_Factor *)dir)->fact, &err)); 110 if (err == MAT_FACTOR_NUMERIC_ZEROPIVOT) { 111 PetscCall(MatFactorClearError(((PC_Factor *)dir)->fact)); 112 pc->failedreason = PC_NOERROR; 113 } 114 } 115 PetscCall(MatFactorGetError(((PC_Factor *)dir)->fact, &err)); 116 if (err) { /* FactorSymbolic() fails */ 117 pc->failedreason = (PCFailedReason)err; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscCall(MatLUFactorNumeric(((PC_Factor *)dir)->fact, pc->pmat, &((PC_Factor *)dir)->info)); 122 PetscCall(MatFactorGetError(((PC_Factor *)dir)->fact, &err)); 123 if (err) { /* FactorNumeric() fails */ 124 pc->failedreason = (PCFailedReason)err; 125 } 126 } 127 128 PetscCall(PCFactorGetMatSolverType(pc, &stype)); 129 if (!stype) { 130 MatSolverType solverpackage; 131 PetscCall(MatFactorGetSolverType(((PC_Factor *)dir)->fact, &solverpackage)); 132 PetscCall(PCFactorSetMatSolverType(pc, solverpackage)); 133 } 134 PetscFunctionReturn(PETSC_SUCCESS); 135 } 136 137 static PetscErrorCode PCReset_LU(PC pc) 138 { 139 PC_LU *dir = (PC_LU *)pc->data; 140 141 PetscFunctionBegin; 142 if (!dir->hdr.inplace && ((PC_Factor *)dir)->fact) PetscCall(MatDestroy(&((PC_Factor *)dir)->fact)); 143 if (dir->row && dir->col && dir->row != dir->col) PetscCall(ISDestroy(&dir->row)); 144 PetscCall(ISDestroy(&dir->col)); 145 PetscFunctionReturn(PETSC_SUCCESS); 146 } 147 148 static PetscErrorCode PCDestroy_LU(PC pc) 149 { 150 PC_LU *dir = (PC_LU *)pc->data; 151 152 PetscFunctionBegin; 153 PetscCall(PCReset_LU(pc)); 154 PetscCall(PetscFree(((PC_Factor *)dir)->ordering)); 155 PetscCall(PetscFree(((PC_Factor *)dir)->solvertype)); 156 PetscCall(PCFactorClearComposedFunctions(pc)); 157 PetscCall(PetscFree(pc->data)); 158 PetscFunctionReturn(PETSC_SUCCESS); 159 } 160 161 static PetscErrorCode PCApply_LU(PC pc, Vec x, Vec y) 162 { 163 PC_LU *dir = (PC_LU *)pc->data; 164 165 PetscFunctionBegin; 166 if (dir->hdr.inplace) { 167 PetscCall(MatSolve(pc->pmat, x, y)); 168 } else { 169 PetscCall(MatSolve(((PC_Factor *)dir)->fact, x, y)); 170 } 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 static PetscErrorCode PCMatApply_LU(PC pc, Mat X, Mat Y) 175 { 176 PC_LU *dir = (PC_LU *)pc->data; 177 178 PetscFunctionBegin; 179 if (dir->hdr.inplace) { 180 PetscCall(MatMatSolve(pc->pmat, X, Y)); 181 } else { 182 PetscCall(MatMatSolve(((PC_Factor *)dir)->fact, X, Y)); 183 } 184 PetscFunctionReturn(PETSC_SUCCESS); 185 } 186 187 static PetscErrorCode PCApplyTranspose_LU(PC pc, Vec x, Vec y) 188 { 189 PC_LU *dir = (PC_LU *)pc->data; 190 191 PetscFunctionBegin; 192 if (dir->hdr.inplace) { 193 PetscCall(MatSolveTranspose(pc->pmat, x, y)); 194 } else { 195 PetscCall(MatSolveTranspose(((PC_Factor *)dir)->fact, x, y)); 196 } 197 PetscFunctionReturn(PETSC_SUCCESS); 198 } 199 200 static PetscErrorCode PCMatApplyTranspose_LU(PC pc, Mat X, Mat Y) 201 { 202 PC_LU *dir = (PC_LU *)pc->data; 203 204 PetscFunctionBegin; 205 if (dir->hdr.inplace) { 206 PetscCall(MatMatSolveTranspose(pc->pmat, X, Y)); 207 } else { 208 PetscCall(MatMatSolveTranspose(((PC_Factor *)dir)->fact, X, Y)); 209 } 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 /*MC 214 PCLU - Uses a direct solver, based on LU factorization, as a preconditioner 215 216 Options Database Keys: 217 + -pc_factor_reuse_ordering - Activate `PCFactorSetReuseOrdering()` 218 . -pc_factor_mat_solver_type - Actives `PCFactorSetMatSolverType()` to choose the direct solver, like superlu 219 . -pc_factor_reuse_fill - Activates `PCFactorSetReuseFill()` 220 . -pc_factor_fill <fill> - Sets fill amount 221 . -pc_factor_in_place - Activates in-place factorization 222 . -pc_factor_mat_ordering_type <nd,rcm,...> - Sets ordering routine 223 . -pc_factor_pivot_in_blocks <true,false> - allow pivoting within the small blocks during factorization (may increase 224 stability of factorization. 225 . -pc_factor_shift_type <shifttype> - Sets shift type or -1 for the default; use '-help' for a list of available types 226 . -pc_factor_shift_amount <shiftamount> - Sets shift amount or -1 for the default 227 . -pc_factor_nonzeros_along_diagonal - permutes the rows and columns to try to put nonzero value along the diagonal. 228 . -pc_factor_mat_solver_type <packagename> - use an external package for the solve, see `MatSolverType` for possibilities 229 - -mat_solvertype_optionname - options for a specific solver package, for example -mat_mumps_cntl_1 230 231 Level: beginner 232 233 Notes: 234 Not all options work for all matrix formats 235 236 Run with `-help` to see additional options for particular matrix formats or factorization algorithms 237 238 The Cholesky factorization direct solver, `PCCHOLESKY` will be more efficient than `PCLU` for symmetric positive-definite (SPD) matrices 239 240 Usually this will compute an "exact" solution in one iteration and does 241 not need a Krylov method (i.e. you can use -ksp_type preonly, or 242 `KSPSetType`(ksp,`KSPPREONLY`) for the Krylov method. 243 244 .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `MatSolverType`, `MatGetFactor()`, `PCQR`, `PCSVD`, 245 `PCILU`, `PCCHOLESKY`, `PCICC`, `PCFactorSetReuseOrdering()`, `PCFactorSetReuseFill()`, `PCFactorGetMatrix()`, 246 `PCFactorSetFill()`, `PCFactorSetUseInPlace()`, `PCFactorSetMatOrderingType()`, `PCFactorSetColumnPivot()`, 247 `PCFactorSetPivotInBlocks()`, `PCFactorSetShiftType()`, `PCFactorSetShiftAmount()` 248 `PCFactorReorderForNonzeroDiagonal()` 249 M*/ 250 251 PETSC_EXTERN PetscErrorCode PCCreate_LU(PC pc) 252 { 253 PC_LU *dir; 254 255 PetscFunctionBegin; 256 PetscCall(PetscNew(&dir)); 257 pc->data = (void *)dir; 258 PetscCall(PCFactorInitialize(pc, MAT_FACTOR_LU)); 259 dir->nonzerosalongdiagonal = PETSC_FALSE; 260 261 ((PC_Factor *)dir)->info.fill = 5.0; 262 ((PC_Factor *)dir)->info.dtcol = 1.e-6; /* default to pivoting; this is only thing PETSc LU supports */ 263 ((PC_Factor *)dir)->info.shifttype = (PetscReal)MAT_SHIFT_NONE; 264 dir->col = NULL; 265 dir->row = NULL; 266 267 pc->ops->reset = PCReset_LU; 268 pc->ops->destroy = PCDestroy_LU; 269 pc->ops->apply = PCApply_LU; 270 pc->ops->matapply = PCMatApply_LU; 271 pc->ops->applytranspose = PCApplyTranspose_LU; 272 pc->ops->matapplytranspose = PCMatApplyTranspose_LU; 273 pc->ops->setup = PCSetUp_LU; 274 pc->ops->setfromoptions = PCSetFromOptions_LU; 275 pc->ops->view = PCView_Factor; 276 pc->ops->applyrichardson = NULL; 277 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFactorReorderForNonzeroDiagonal_C", PCFactorReorderForNonzeroDiagonal_LU)); 278 PetscFunctionReturn(PETSC_SUCCESS); 279 } 280