/* Defines a (S)SOR preconditioner for any Mat implementation */ #include /*I "petscpc.h" I*/ typedef struct { PetscInt its; /* inner iterations, number of sweeps */ PetscInt lits; /* local inner iterations, number of sweeps applied by the local matrix mat->A */ MatSORType sym; /* forward, reverse, symmetric etc. */ PetscReal omega; PetscReal fshift; } PC_SOR; static PetscErrorCode PCDestroy_SOR(PC pc) { PetscFunctionBegin; PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetSymmetric_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetOmega_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetIterations_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetSymmetric_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetOmega_C", NULL)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetIterations_C", NULL)); PetscCall(PetscFree(pc->data)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCApply_SOR(PC pc, Vec x, Vec y) { PC_SOR *jac = (PC_SOR *)pc->data; PetscInt flag = jac->sym | SOR_ZERO_INITIAL_GUESS; PetscFunctionBegin; PetscCall(MatSOR(pc->pmat, x, jac->omega, (MatSORType)flag, jac->fshift, jac->its, jac->lits, y)); PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCApplyTranspose_SOR(PC pc, Vec x, Vec y) { PC_SOR *jac = (PC_SOR *)pc->data; PetscInt flag = jac->sym | SOR_ZERO_INITIAL_GUESS; PetscBool set, sym; PetscFunctionBegin; PetscCall(MatIsSymmetricKnown(pc->pmat, &set, &sym)); 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"); PetscCall(MatSOR(pc->pmat, x, jac->omega, (MatSORType)flag, jac->fshift, jac->its, jac->lits, y)); PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); PetscFunctionReturn(PETSC_SUCCESS); } 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) { PC_SOR *jac = (PC_SOR *)pc->data; MatSORType stype = jac->sym; PetscFunctionBegin; if (guesszero) stype = (MatSORType)(stype | SOR_ZERO_INITIAL_GUESS); PetscCall(MatSOR(pc->pmat, b, jac->omega, stype, jac->fshift, its * jac->its, jac->lits, y)); PetscCall(MatFactorGetError(pc->pmat, (MatFactorError *)&pc->failedreason)); *outits = its; *reason = PCRICHARDSON_CONVERGED_ITS; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSetFromOptions_SOR(PC pc, PetscOptionItems PetscOptionsObject) { PC_SOR *jac = (PC_SOR *)pc->data; PetscBool flg; PetscReal omega; PetscFunctionBegin; PetscOptionsHeadBegin(PetscOptionsObject, "(S)SOR options"); PetscCall(PetscOptionsReal("-pc_sor_omega", "relaxation factor (0 < omega < 2)", "PCSORSetOmega", jac->omega, &omega, &flg)); if (flg) PetscCall(PCSORSetOmega(pc, omega)); PetscCall(PetscOptionsReal("-pc_sor_diagonal_shift", "Add to the diagonal entries", "", jac->fshift, &jac->fshift, NULL)); PetscCall(PetscOptionsInt("-pc_sor_its", "number of inner SOR iterations", "PCSORSetIterations", jac->its, &jac->its, NULL)); PetscCall(PetscOptionsInt("-pc_sor_lits", "number of local inner SOR iterations", "PCSORSetIterations", jac->lits, &jac->lits, NULL)); PetscCall(PetscOptionsBoolGroupBegin("-pc_sor_symmetric", "SSOR, not SOR", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_SYMMETRIC_SWEEP)); PetscCall(PetscOptionsBoolGroup("-pc_sor_backward", "use backward sweep instead of forward", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_BACKWARD_SWEEP)); PetscCall(PetscOptionsBoolGroup("-pc_sor_forward", "use forward sweep", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_FORWARD_SWEEP)); PetscCall(PetscOptionsBoolGroup("-pc_sor_local_symmetric", "use SSOR separately on each processor", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_SYMMETRIC_SWEEP)); PetscCall(PetscOptionsBoolGroup("-pc_sor_local_backward", "use backward sweep locally", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_BACKWARD_SWEEP)); PetscCall(PetscOptionsBoolGroupEnd("-pc_sor_local_forward", "use forward sweep locally", "PCSORSetSymmetric", &flg)); if (flg) PetscCall(PCSORSetSymmetric(pc, SOR_LOCAL_FORWARD_SWEEP)); PetscOptionsHeadEnd(); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCView_SOR(PC pc, PetscViewer viewer) { PC_SOR *jac = (PC_SOR *)pc->data; MatSORType sym = jac->sym; const char *sortype; PetscBool isascii; PetscFunctionBegin; PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); if (isascii) { if (sym & SOR_ZERO_INITIAL_GUESS) PetscCall(PetscViewerASCIIPrintf(viewer, " zero initial guess\n")); if (sym == SOR_APPLY_UPPER) sortype = "apply_upper"; else if (sym == SOR_APPLY_LOWER) sortype = "apply_lower"; else if (sym & SOR_EISENSTAT) sortype = "Eisenstat"; else if ((sym & SOR_SYMMETRIC_SWEEP) == SOR_SYMMETRIC_SWEEP) sortype = "symmetric"; else if (sym & SOR_BACKWARD_SWEEP) sortype = "backward"; else if (sym & SOR_FORWARD_SWEEP) sortype = "forward"; else if ((sym & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) sortype = "local_symmetric"; else if (sym & SOR_LOCAL_FORWARD_SWEEP) sortype = "local_forward"; else if (sym & SOR_LOCAL_BACKWARD_SWEEP) sortype = "local_backward"; else sortype = "unknown"; PetscCall(PetscViewerASCIIPrintf(viewer, " type = %s, iterations = %" PetscInt_FMT ", local iterations = %" PetscInt_FMT ", omega = %g\n", sortype, jac->its, jac->lits, (double)jac->omega)); } PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORSetSymmetric_SOR(PC pc, MatSORType flag) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; jac->sym = flag; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORSetOmega_SOR(PC pc, PetscReal omega) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; PetscCheck(omega > 0.0 && omega < 2.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Relaxation out of range"); jac->omega = omega; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORSetIterations_SOR(PC pc, PetscInt its, PetscInt lits) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; jac->its = its; jac->lits = lits; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORGetSymmetric_SOR(PC pc, MatSORType *flag) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; *flag = jac->sym; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORGetOmega_SOR(PC pc, PetscReal *omega) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; *omega = jac->omega; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode PCSORGetIterations_SOR(PC pc, PetscInt *its, PetscInt *lits) { PC_SOR *jac = (PC_SOR *)pc->data; PetscFunctionBegin; if (its) *its = jac->its; if (lits) *lits = jac->lits; PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORGetSymmetric - Gets the form the SOR preconditioner is using; backward, or forward relaxation. The local variants perform SOR on each processor. By default forward relaxation is used. Logically Collective Input Parameter: . pc - the preconditioner context Output Parameter: . flag - one of the following .vb SOR_FORWARD_SWEEP SOR_BACKWARD_SWEEP SOR_SYMMETRIC_SWEEP SOR_LOCAL_FORWARD_SWEEP SOR_LOCAL_BACKWARD_SWEEP SOR_LOCAL_SYMMETRIC_SWEEP .ve Options Database Keys: + -pc_sor_symmetric - Activates symmetric version . -pc_sor_backward - Activates backward version . -pc_sor_local_forward - Activates local forward version . -pc_sor_local_symmetric - Activates local symmetric version - -pc_sor_local_backward - Activates local backward version Note: To use the Eisenstat trick with SSOR, employ the `PCEISENSTAT` preconditioner, which can be chosen with the option . -pc_type eisenstat - Activates Eisenstat trick Level: intermediate .seealso: [](ch_ksp), `PCSOR`, `PCEisenstatSetOmega()`, `PCSORSetIterations()`, `PCSORSetOmega()`, `PCSORSetSymmetric()` @*/ PetscErrorCode PCSORGetSymmetric(PC pc, MatSORType *flag) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscUseMethod(pc, "PCSORGetSymmetric_C", (PC, MatSORType *), (pc, flag)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORGetOmega - Gets the SOR relaxation coefficient, omega (where omega = 1.0 by default). Logically Collective Input Parameter: . pc - the preconditioner context Output Parameter: . omega - relaxation coefficient (0 < omega < 2). Options Database Key: . -pc_sor_omega - Sets omega Level: intermediate .seealso: [](ch_ksp), `PCSOR`, `PCSORSetSymmetric()`, `PCSORSetIterations()`, `PCEisenstatSetOmega()`, `PCSORSetOmega()` @*/ PetscErrorCode PCSORGetOmega(PC pc, PetscReal *omega) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscUseMethod(pc, "PCSORGetOmega_C", (PC, PetscReal *), (pc, omega)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORGetIterations - Gets the number of inner iterations to be used by the SOR preconditioner. The default is 1. Logically Collective Input Parameter: . pc - the preconditioner context Output Parameters: + lits - number of local iterations, smoothings over just variables on processor - its - number of parallel iterations to use; each parallel iteration has lits local iterations Options Database Keys: + -pc_sor_its - Sets number of iterations - -pc_sor_lits - Sets number of local iterations Level: intermediate Note: When run on one processor the number of smoothings is lits*its .seealso: [](ch_ksp), `PCSOR`, `PCSORSetOmega()`, `PCSORSetSymmetric()`, `PCSORSetIterations()` @*/ PetscErrorCode PCSORGetIterations(PC pc, PetscInt *its, PetscInt *lits) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscUseMethod(pc, "PCSORGetIterations_C", (PC, PetscInt *, PetscInt *), (pc, its, lits)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORSetSymmetric - Sets the SOR preconditioner to use symmetric (SSOR), backward, or forward relaxation. The local variants perform SOR on each processor. By default forward relaxation is used. Logically Collective Input Parameters: + pc - the preconditioner context - flag - one of the following .vb SOR_FORWARD_SWEEP SOR_BACKWARD_SWEEP SOR_SYMMETRIC_SWEEP SOR_LOCAL_FORWARD_SWEEP SOR_LOCAL_BACKWARD_SWEEP SOR_LOCAL_SYMMETRIC_SWEEP .ve Options Database Keys: + -pc_sor_symmetric - Activates symmetric version . -pc_sor_backward - Activates backward version . -pc_sor_local_forward - Activates local forward version . -pc_sor_local_symmetric - Activates local symmetric version - -pc_sor_local_backward - Activates local backward version Note: To use the Eisenstat trick with SSOR, employ the PCEISENSTAT preconditioner, which can be chosen with the option . -pc_type eisenstat - Activates Eisenstat trick Level: intermediate .seealso: [](ch_ksp), `PCSOR`, `PCEisenstatSetOmega()`, `PCSORSetIterations()`, `PCSORSetOmega()` @*/ PetscErrorCode PCSORSetSymmetric(PC pc, MatSORType flag) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscValidLogicalCollectiveEnum(pc, flag, 2); PetscTryMethod(pc, "PCSORSetSymmetric_C", (PC, MatSORType), (pc, flag)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORSetOmega - Sets the SOR relaxation coefficient, omega (where omega = 1.0 by default). Logically Collective Input Parameters: + pc - the preconditioner context - omega - relaxation coefficient (0 < omega < 2). Options Database Key: . -pc_sor_omega - Sets omega Level: intermediate Note: If omega != 1, you will need to set the `MAT_USE_INODE`S option to `PETSC_FALSE` on the matrix. .seealso: [](ch_ksp), `PCSOR`, `PCSORSetSymmetric()`, `PCSORSetIterations()`, `PCEisenstatSetOmega()`, `MatSetOption()` @*/ PetscErrorCode PCSORSetOmega(PC pc, PetscReal omega) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscValidLogicalCollectiveReal(pc, omega, 2); PetscTryMethod(pc, "PCSORSetOmega_C", (PC, PetscReal), (pc, omega)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PCSORSetIterations - Sets the number of inner iterations to be used by the SOR preconditioner. The default is 1. Logically Collective Input Parameters: + pc - the preconditioner context . lits - number of local iterations, smoothings over just variables on processor - its - number of parallel iterations to use; each parallel iteration has lits local iterations Options Database Keys: + -pc_sor_its - Sets number of iterations - -pc_sor_lits - Sets number of local iterations Level: intermediate Note: When run on one processor the number of smoothings is lits*its .seealso: [](ch_ksp), `PCSOR`, `PCSORSetOmega()`, `PCSORSetSymmetric()` @*/ PetscErrorCode PCSORSetIterations(PC pc, PetscInt its, PetscInt lits) { PetscFunctionBegin; PetscValidHeaderSpecific(pc, PC_CLASSID, 1); PetscValidLogicalCollectiveInt(pc, its, 2); PetscTryMethod(pc, "PCSORSetIterations_C", (PC, PetscInt, PetscInt), (pc, its, lits)); PetscFunctionReturn(PETSC_SUCCESS); } /*MC PCSOR - (S)SOR (successive over relaxation, Gauss-Seidel) preconditioning Options Database Keys: + -pc_sor_symmetric - Activates symmetric version . -pc_sor_backward - Activates backward version . -pc_sor_forward - Activates forward version . -pc_sor_local_forward - Activates local forward version . -pc_sor_local_symmetric - Activates local symmetric version (default version) . -pc_sor_local_backward - Activates local backward version . -pc_sor_omega - Sets omega . -pc_sor_diagonal_shift - shift the diagonal entries; useful if the matrix has zeros on the diagonal . -pc_sor_its - Sets number of iterations (default 1) - -pc_sor_lits - Sets number of local iterations (default 1) Level: beginner Notes: Only implemented for the `MATAIJ` and `MATSEQBAIJ` matrix formats. Not a true parallel SOR, in parallel this implementation corresponds to block Jacobi with SOR on each block. For `MATAIJ` matrices if a diagonal entry is zero (and the diagonal shift is zero) then by default the inverse of that zero will be used and hence the `KSPSolve()` will terminate with `KSP_DIVERGED_NANORINF`. If the option `KSPSetErrorIfNotConverged()` or -ksp_error_if_not_converged the code will terminate as soon as it detects the zero pivot. For `MATSEQBAIJ` matrices this implements point-block SOR, but the omega, its, lits options are not supported. For `MATSEQBAIJ` the diagonal blocks are inverted using dense LU with partial pivoting. If a zero pivot is detected the computation is stopped with an error If used with `KSPRICHARDSON` and no monitors the convergence test is skipped to improve speed, thus it always iterates the maximum number of iterations you've selected for `KSP`. It is usually used in this mode as a smoother for multigrid. If omega != 1, you will need to set the `MAT_USE_INODES` option to `PETSC_FALSE` on the matrix. .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCJACOBI`, `PCSORSetIterations()`, `PCSORSetSymmetric()`, `PCSORSetOmega()`, `PCEISENSTAT`, `MatSetOption()` M*/ PETSC_EXTERN PetscErrorCode PCCreate_SOR(PC pc) { PC_SOR *jac; PetscFunctionBegin; PetscCall(PetscNew(&jac)); pc->ops->apply = PCApply_SOR; pc->ops->applytranspose = PCApplyTranspose_SOR; pc->ops->applyrichardson = PCApplyRichardson_SOR; pc->ops->setfromoptions = PCSetFromOptions_SOR; pc->ops->setup = NULL; pc->ops->view = PCView_SOR; pc->ops->destroy = PCDestroy_SOR; pc->data = (void *)jac; jac->sym = SOR_LOCAL_SYMMETRIC_SWEEP; jac->omega = 1.0; jac->fshift = 0.0; jac->its = 1; jac->lits = 1; PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetSymmetric_C", PCSORSetSymmetric_SOR)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetOmega_C", PCSORSetOmega_SOR)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORSetIterations_C", PCSORSetIterations_SOR)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetSymmetric_C", PCSORGetSymmetric_SOR)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetOmega_C", PCSORGetOmega_SOR)); PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSORGetIterations_C", PCSORGetIterations_SOR)); PetscFunctionReturn(PETSC_SUCCESS); }