1 /* 2 Defines a (S)SOR preconditioner for any Mat implementation 3 */ 4 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 5 6 typedef struct { 7 PetscInt its; /* inner iterations, number of sweeps */ 8 PetscInt lits; /* local inner iterations, number of sweeps applied by the local matrix mat->A */ 9 MatSORType sym; /* forward, reverse, symmetric etc. */ 10 PetscReal omega; 11 PetscReal fshift; 12 } PC_SOR; 13 14 static PetscErrorCode PCDestroy_SOR(PC pc) 15 { 16 PetscFunctionBegin; 17 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetSymmetric_C", NULL)); 18 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetOmega_C", NULL)); 19 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetIterations_C", NULL)); 20 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetSymmetric_C", NULL)); 21 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetOmega_C", NULL)); 22 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetIterations_C", NULL)); 23 PetscCall(PetscFree(pc->data)); 24 PetscFunctionReturn(PETSC_SUCCESS); 25 } 26 27 static PetscErrorCode PCApply_SOR(PC pc, Vec x, Vec y) 28 { 29 PC_SOR *jac = (PC_SOR *)pc->data; 30 PetscInt flag = jac->sym | SOR_ZERO_INITIAL_GUESS; 31 32 PetscFunctionBegin; 33 PetscCall(MatSOR(pc->pmat, x, jac->omega, (MatSORType)flag, jac->fshift, jac->its, jac->lits, y)); 34 PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); 35 PetscFunctionReturn(PETSC_SUCCESS); 36 } 37 38 static PetscErrorCode PCApplyTranspose_SOR(PC pc, Vec x, Vec y) 39 { 40 PC_SOR *jac = (PC_SOR *)pc->data; 41 PetscInt flag = jac->sym | SOR_ZERO_INITIAL_GUESS; 42 PetscBool set, sym; 43 44 PetscFunctionBegin; 45 PetscCall(MatIsSymmetricKnown(pc->pmat, &set, &sym)); 46 PetscCheck(set && sym && (jac->sym == SOR_SYMMETRIC_SWEEP || jac->sym == SOR_LOCAL_SYMMETRIC_SWEEP), PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Can only apply transpose of SOR if matrix is symmetric and sweep is symmetric"); 47 PetscCall(MatSOR(pc->pmat, x, jac->omega, (MatSORType)flag, jac->fshift, jac->its, jac->lits, y)); 48 PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 52 static PetscErrorCode PCApplyRichardson_SOR(PC pc, Vec b, Vec y, Vec w, PetscReal rtol, PetscReal abstol, PetscReal dtol, PetscInt its, PetscBool guesszero, PetscInt *outits, PCRichardsonConvergedReason *reason) 53 { 54 PC_SOR *jac = (PC_SOR *)pc->data; 55 MatSORType stype = jac->sym; 56 57 PetscFunctionBegin; 58 PetscCall(PetscInfo(pc, "Warning, convergence criteria ignored, using %" PetscInt_FMT " iterations\n", its)); 59 if (guesszero) stype = (MatSORType)(stype | SOR_ZERO_INITIAL_GUESS); 60 PetscCall(MatSOR(pc->pmat, b, jac->omega, stype, jac->fshift, its * jac->its, jac->lits, y)); 61 PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); 62 *outits = its; 63 *reason = PCRICHARDSON_CONVERGED_ITS; 64 PetscFunctionReturn(PETSC_SUCCESS); 65 } 66 67 PetscErrorCode PCSetFromOptions_SOR(PC pc, PetscOptionItems *PetscOptionsObject) 68 { 69 PC_SOR *jac = (PC_SOR *)pc->data; 70 PetscBool flg; 71 PetscReal omega; 72 73 PetscFunctionBegin; 74 PetscOptionsHeadBegin(PetscOptionsObject, "(S)SOR options"); 75 PetscCall(PetscOptionsReal("-pc_sor_omega", "relaxation factor (0 < omega < 2)", "PCSORSetOmega", jac->omega, &omega, &flg)); 76 if (flg) PetscCall(PCSORSetOmega(pc, omega)); 77 PetscCall(PetscOptionsReal("-pc_sor_diagonal_shift", "Add to the diagonal entries", "", jac->fshift, &jac->fshift, NULL)); 78 PetscCall(PetscOptionsInt("-pc_sor_its", "number of inner SOR iterations", "PCSORSetIterations", jac->its, &jac->its, NULL)); 79 PetscCall(PetscOptionsInt("-pc_sor_lits", "number of local inner SOR iterations", "PCSORSetIterations", jac->lits, &jac->lits, NULL)); 80 PetscCall(PetscOptionsBoolGroupBegin("-pc_sor_symmetric", "SSOR, not SOR", "PCSORSetSymmetric", &flg)); 81 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_SYMMETRIC_SWEEP)); 82 PetscCall(PetscOptionsBoolGroup("-pc_sor_backward", "use backward sweep instead of forward", "PCSORSetSymmetric", &flg)); 83 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_BACKWARD_SWEEP)); 84 PetscCall(PetscOptionsBoolGroup("-pc_sor_forward", "use forward sweep", "PCSORSetSymmetric", &flg)); 85 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_FORWARD_SWEEP)); 86 PetscCall(PetscOptionsBoolGroup("-pc_sor_local_symmetric", "use SSOR separately on each processor", "PCSORSetSymmetric", &flg)); 87 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_SYMMETRIC_SWEEP)); 88 PetscCall(PetscOptionsBoolGroup("-pc_sor_local_backward", "use backward sweep locally", "PCSORSetSymmetric", &flg)); 89 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_BACKWARD_SWEEP)); 90 PetscCall(PetscOptionsBoolGroupEnd("-pc_sor_local_forward", "use forward sweep locally", "PCSORSetSymmetric", &flg)); 91 if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_FORWARD_SWEEP)); 92 PetscOptionsHeadEnd(); 93 PetscFunctionReturn(PETSC_SUCCESS); 94 } 95 96 PetscErrorCode PCView_SOR(PC pc, PetscViewer viewer) 97 { 98 PC_SOR *jac = (PC_SOR *)pc->data; 99 MatSORType sym = jac->sym; 100 const char *sortype; 101 PetscBool iascii; 102 103 PetscFunctionBegin; 104 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 105 if (iascii) { 106 if (sym & SOR_ZERO_INITIAL_GUESS) PetscCall(PetscViewerASCIIPrintf(viewer, " zero initial guess\n")); 107 if (sym == SOR_APPLY_UPPER) sortype = "apply_upper"; 108 else if (sym == SOR_APPLY_LOWER) sortype = "apply_lower"; 109 else if (sym & SOR_EISENSTAT) sortype = "Eisenstat"; 110 else if ((sym & SOR_SYMMETRIC_SWEEP) == SOR_SYMMETRIC_SWEEP) sortype = "symmetric"; 111 else if (sym & SOR_BACKWARD_SWEEP) sortype = "backward"; 112 else if (sym & SOR_FORWARD_SWEEP) sortype = "forward"; 113 else if ((sym & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) sortype = "local_symmetric"; 114 else if (sym & SOR_LOCAL_FORWARD_SWEEP) sortype = "local_forward"; 115 else if (sym & SOR_LOCAL_BACKWARD_SWEEP) sortype = "local_backward"; 116 else sortype = "unknown"; 117 PetscCall(PetscViewerASCIIPrintf(viewer, " type = %s, iterations = %" PetscInt_FMT ", local iterations = %" PetscInt_FMT ", omega = %g\n", sortype, jac->its, jac->lits, (double)jac->omega)); 118 } 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 static PetscErrorCode PCSORSetSymmetric_SOR(PC pc, MatSORType flag) 123 { 124 PC_SOR *jac = (PC_SOR *)pc->data; 125 126 PetscFunctionBegin; 127 jac->sym = flag; 128 PetscFunctionReturn(PETSC_SUCCESS); 129 } 130 131 static PetscErrorCode PCSORSetOmega_SOR(PC pc, PetscReal omega) 132 { 133 PC_SOR *jac = (PC_SOR *)pc->data; 134 135 PetscFunctionBegin; 136 PetscCheck(omega > 0.0 && omega < 2.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Relaxation out of range"); 137 jac->omega = omega; 138 PetscFunctionReturn(PETSC_SUCCESS); 139 } 140 141 static PetscErrorCode PCSORSetIterations_SOR(PC pc, PetscInt its, PetscInt lits) 142 { 143 PC_SOR *jac = (PC_SOR *)pc->data; 144 145 PetscFunctionBegin; 146 jac->its = its; 147 jac->lits = lits; 148 PetscFunctionReturn(PETSC_SUCCESS); 149 } 150 151 static PetscErrorCode PCSORGetSymmetric_SOR(PC pc, MatSORType *flag) 152 { 153 PC_SOR *jac = (PC_SOR *)pc->data; 154 155 PetscFunctionBegin; 156 *flag = jac->sym; 157 PetscFunctionReturn(PETSC_SUCCESS); 158 } 159 160 static PetscErrorCode PCSORGetOmega_SOR(PC pc, PetscReal *omega) 161 { 162 PC_SOR *jac = (PC_SOR *)pc->data; 163 164 PetscFunctionBegin; 165 *omega = jac->omega; 166 PetscFunctionReturn(PETSC_SUCCESS); 167 } 168 169 static PetscErrorCode PCSORGetIterations_SOR(PC pc, PetscInt *its, PetscInt *lits) 170 { 171 PC_SOR *jac = (PC_SOR *)pc->data; 172 173 PetscFunctionBegin; 174 if (its) *its = jac->its; 175 if (lits) *lits = jac->lits; 176 PetscFunctionReturn(PETSC_SUCCESS); 177 } 178 179 /*@ 180 PCSORGetSymmetric - Gets the form the SOR preconditioner is using; backward, or forward relaxation. The local variants perform SOR on 181 each processor. By default forward relaxation is used. 182 183 Logically Collective 184 185 Input Parameter: 186 . pc - the preconditioner context 187 188 Output Parameter: 189 . flag - one of the following 190 .vb 191 SOR_FORWARD_SWEEP 192 SOR_BACKWARD_SWEEP 193 SOR_SYMMETRIC_SWEEP 194 SOR_LOCAL_FORWARD_SWEEP 195 SOR_LOCAL_BACKWARD_SWEEP 196 SOR_LOCAL_SYMMETRIC_SWEEP 197 .ve 198 199 Options Database Keys: 200 + -pc_sor_symmetric - Activates symmetric version 201 . -pc_sor_backward - Activates backward version 202 . -pc_sor_local_forward - Activates local forward version 203 . -pc_sor_local_symmetric - Activates local symmetric version 204 - -pc_sor_local_backward - Activates local backward version 205 206 Note: 207 To use the Eisenstat trick with SSOR, employ the `PCEISENSTAT` preconditioner, 208 which can be chosen with the option 209 . -pc_type eisenstat - Activates Eisenstat trick 210 211 Level: intermediate 212 213 .seealso: `PCSOR`, `PCEisenstatSetOmega()`, `PCSORSetIterations()`, `PCSORSetOmega()`, `PCSORSetSymmetric()` 214 @*/ 215 PetscErrorCode PCSORGetSymmetric(PC pc, MatSORType *flag) 216 { 217 PetscFunctionBegin; 218 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 219 PetscUseMethod(pc, "PCSORGetSymmetric_C", (PC, MatSORType *), (pc, flag)); 220 PetscFunctionReturn(PETSC_SUCCESS); 221 } 222 223 /*@ 224 PCSORGetOmega - Gets the SOR relaxation coefficient, omega 225 (where omega = 1.0 by default). 226 227 Logically Collective 228 229 Input Parameter: 230 . pc - the preconditioner context 231 232 Output Parameter: 233 . omega - relaxation coefficient (0 < omega < 2). 234 235 Options Database Key: 236 . -pc_sor_omega <omega> - Sets omega 237 238 Level: intermediate 239 240 .seealso: `PCSOR`, `PCSORSetSymmetric()`, `PCSORSetIterations()`, `PCEisenstatSetOmega()`, `PCSORSetOmega()` 241 @*/ 242 PetscErrorCode PCSORGetOmega(PC pc, PetscReal *omega) 243 { 244 PetscFunctionBegin; 245 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 246 PetscUseMethod(pc, "PCSORGetOmega_C", (PC, PetscReal *), (pc, omega)); 247 PetscFunctionReturn(PETSC_SUCCESS); 248 } 249 250 /*@ 251 PCSORGetIterations - Gets the number of inner iterations to 252 be used by the SOR preconditioner. The default is 1. 253 254 Logically Collective 255 256 Input Parameter: 257 . pc - the preconditioner context 258 259 Output Parameters: 260 + lits - number of local iterations, smoothings over just variables on processor 261 - its - number of parallel iterations to use; each parallel iteration has lits local iterations 262 263 Options Database Keys: 264 + -pc_sor_its <its> - Sets number of iterations 265 - -pc_sor_lits <lits> - Sets number of local iterations 266 267 Level: intermediate 268 269 Note: 270 When run on one processor the number of smoothings is lits*its 271 272 .seealso: `PCSOR`, `PCSORSetOmega()`, `PCSORSetSymmetric()`, `PCSORSetIterations()` 273 @*/ 274 PetscErrorCode PCSORGetIterations(PC pc, PetscInt *its, PetscInt *lits) 275 { 276 PetscFunctionBegin; 277 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 278 PetscUseMethod(pc, "PCSORGetIterations_C", (PC, PetscInt *, PetscInt *), (pc, its, lits)); 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 282 /*@ 283 PCSORSetSymmetric - Sets the SOR preconditioner to use symmetric (SSOR), 284 backward, or forward relaxation. The local variants perform SOR on 285 each processor. By default forward relaxation is used. 286 287 Logically Collective 288 289 Input Parameters: 290 + pc - the preconditioner context 291 - flag - one of the following 292 .vb 293 SOR_FORWARD_SWEEP 294 SOR_BACKWARD_SWEEP 295 SOR_SYMMETRIC_SWEEP 296 SOR_LOCAL_FORWARD_SWEEP 297 SOR_LOCAL_BACKWARD_SWEEP 298 SOR_LOCAL_SYMMETRIC_SWEEP 299 .ve 300 301 Options Database Keys: 302 + -pc_sor_symmetric - Activates symmetric version 303 . -pc_sor_backward - Activates backward version 304 . -pc_sor_local_forward - Activates local forward version 305 . -pc_sor_local_symmetric - Activates local symmetric version 306 - -pc_sor_local_backward - Activates local backward version 307 308 Note: 309 To use the Eisenstat trick with SSOR, employ the PCEISENSTAT preconditioner, 310 which can be chosen with the option 311 . -pc_type eisenstat - Activates Eisenstat trick 312 313 Level: intermediate 314 315 .seealso: `PCSOR`, `PCEisenstatSetOmega()`, `PCSORSetIterations()`, `PCSORSetOmega()` 316 @*/ 317 PetscErrorCode PCSORSetSymmetric(PC pc, MatSORType flag) 318 { 319 PetscFunctionBegin; 320 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 321 PetscValidLogicalCollectiveEnum(pc, flag, 2); 322 PetscTryMethod(pc, "PCSORSetSymmetric_C", (PC, MatSORType), (pc, flag)); 323 PetscFunctionReturn(PETSC_SUCCESS); 324 } 325 326 /*@ 327 PCSORSetOmega - Sets the SOR relaxation coefficient, omega 328 (where omega = 1.0 by default). 329 330 Logically Collective 331 332 Input Parameters: 333 + pc - the preconditioner context 334 - omega - relaxation coefficient (0 < omega < 2). 335 336 Options Database Key: 337 . -pc_sor_omega <omega> - Sets omega 338 339 Level: intermediate 340 341 Note: 342 If omega != 1, you will need to set the `MAT_USE_INODE`S option to `PETSC_FALSE` on the matrix. 343 344 .seealso: `PCSOR`, `PCSORSetSymmetric()`, `PCSORSetIterations()`, `PCEisenstatSetOmega()`, `MatSetOption()` 345 @*/ 346 PetscErrorCode PCSORSetOmega(PC pc, PetscReal omega) 347 { 348 PetscFunctionBegin; 349 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 350 PetscValidLogicalCollectiveReal(pc, omega, 2); 351 PetscTryMethod(pc, "PCSORSetOmega_C", (PC, PetscReal), (pc, omega)); 352 PetscFunctionReturn(PETSC_SUCCESS); 353 } 354 355 /*@ 356 PCSORSetIterations - Sets the number of inner iterations to 357 be used by the SOR preconditioner. The default is 1. 358 359 Logically Collective 360 361 Input Parameters: 362 + pc - the preconditioner context 363 . lits - number of local iterations, smoothings over just variables on processor 364 - its - number of parallel iterations to use; each parallel iteration has lits local iterations 365 366 Options Database Keys: 367 + -pc_sor_its <its> - Sets number of iterations 368 - -pc_sor_lits <lits> - Sets number of local iterations 369 370 Level: intermediate 371 372 Note: 373 When run on one processor the number of smoothings is lits*its 374 375 .seealso: `PCSOR`, `PCSORSetOmega()`, `PCSORSetSymmetric()` 376 @*/ 377 PetscErrorCode PCSORSetIterations(PC pc, PetscInt its, PetscInt lits) 378 { 379 PetscFunctionBegin; 380 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 381 PetscValidLogicalCollectiveInt(pc, its, 2); 382 PetscTryMethod(pc, "PCSORSetIterations_C", (PC, PetscInt, PetscInt), (pc, its, lits)); 383 PetscFunctionReturn(PETSC_SUCCESS); 384 } 385 386 /*MC 387 PCSOR - (S)SOR (successive over relaxation, Gauss-Seidel) preconditioning 388 389 Options Database Keys: 390 + -pc_sor_symmetric - Activates symmetric version 391 . -pc_sor_backward - Activates backward version 392 . -pc_sor_forward - Activates forward version 393 . -pc_sor_local_forward - Activates local forward version 394 . -pc_sor_local_symmetric - Activates local symmetric version (default version) 395 . -pc_sor_local_backward - Activates local backward version 396 . -pc_sor_omega <omega> - Sets omega 397 . -pc_sor_diagonal_shift <shift> - shift the diagonal entries; useful if the matrix has zeros on the diagonal 398 . -pc_sor_its <its> - Sets number of iterations (default 1) 399 - -pc_sor_lits <lits> - Sets number of local iterations (default 1) 400 401 Level: beginner 402 403 Notes: 404 Only implemented for the `MATAIJ` and `MATSEQBAIJ` matrix formats. 405 406 Not a true parallel SOR, in parallel this implementation corresponds to block 407 Jacobi with SOR on each block. 408 409 For `MATAIJ` matrices if a diagonal entry is zero (and the diagonal shift is zero) then by default the inverse of that 410 zero will be used and hence the `KSPSolve()` will terminate with `KSP_DIVERGED_NANORINF`. If the option 411 `KSPSetErrorIfNotConverged()` or -ksp_error_if_not_converged the code will terminate as soon as it detects the 412 zero pivot. 413 414 For `MATSEQBAIJ` matrices this implements point-block SOR, but the omega, its, lits options are not supported. 415 416 For `MATSEQBAIJ` the diagonal blocks are inverted using dense LU with partial pivoting. If a zero pivot is detected 417 the computation is stopped with an error 418 419 If used with `KSPRICHARDSON` and no monitors the convergence test is skipped to improve speed, thus it always iterates 420 the maximum number of iterations you've selected for `KSP`. It is usually used in this mode as a smoother for multigrid. 421 422 If omega != 1, you will need to set the `MAT_USE_INODES` option to `PETSC_FALSE` on the matrix. 423 424 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCJACOBI`, 425 `PCSORSetIterations()`, `PCSORSetSymmetric()`, `PCSORSetOmega()`, `PCEISENSTAT`, `MatSetOption()` 426 M*/ 427 428 PETSC_EXTERN PetscErrorCode PCCreate_SOR(PC pc) 429 { 430 PC_SOR *jac; 431 432 PetscFunctionBegin; 433 PetscCall(PetscNew(&jac)); 434 435 pc->ops->apply = PCApply_SOR; 436 pc->ops->applytranspose = PCApplyTranspose_SOR; 437 pc->ops->applyrichardson = PCApplyRichardson_SOR; 438 pc->ops->setfromoptions = PCSetFromOptions_SOR; 439 pc->ops->setup = NULL; 440 pc->ops->view = PCView_SOR; 441 pc->ops->destroy = PCDestroy_SOR; 442 pc->data = (void *)jac; 443 jac->sym = SOR_LOCAL_SYMMETRIC_SWEEP; 444 jac->omega = 1.0; 445 jac->fshift = 0.0; 446 jac->its = 1; 447 jac->lits = 1; 448 449 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetSymmetric_C", PCSORSetSymmetric_SOR)); 450 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetOmega_C", PCSORSetOmega_SOR)); 451 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetIterations_C", PCSORSetIterations_SOR)); 452 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetSymmetric_C", PCSORGetSymmetric_SOR)); 453 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetOmega_C", PCSORGetOmega_SOR)); 454 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetIterations_C", PCSORGetIterations_SOR)); 455 PetscFunctionReturn(PETSC_SUCCESS); 456 } 457