Actual source code: preonly.c

  1: #include <petsc/private/kspimpl.h>

  3: static PetscErrorCode KSPSetUp_PREONLY(KSP ksp)
  4: {
  5:   PetscFunctionBegin;
  6:   PetscFunctionReturn(PETSC_SUCCESS);
  7: }

  9: static PetscErrorCode KSPSolve_PREONLY(KSP ksp)
 10: {
 11:   PetscReal      norm;
 12:   PetscBool      flg;
 13:   PCFailedReason pcreason;

 15:   PetscFunctionBegin;
 16:   PetscCall(PCGetDiagonalScale(ksp->pc, &flg));
 17:   PetscCheck(!flg, PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "Krylov method %s does not support diagonal scaling", ((PetscObject)ksp)->type_name);
 18:   if (!ksp->guess_zero) {
 19:     PetscCall(PetscObjectTypeCompareAny((PetscObject)ksp->pc, &flg, PCREDISTRIBUTE, PCMPI, ""));
 20:     PetscCheck(flg, PetscObjectComm((PetscObject)ksp), PETSC_ERR_USER, "KSP of type preonly (application of preconditioner only) doesn't make sense with nonzero initial guess you probably want a KSP of type Richardson");
 21:   }
 22:   ksp->its = 0;
 23:   if (ksp->numbermonitors) {
 24:     PetscCall(VecNorm(ksp->vec_rhs, NORM_2, &norm));
 25:     PetscCall(KSPMonitor(ksp, 0, norm));
 26:   }
 27:   PetscCall(KSP_PCApply(ksp, ksp->vec_rhs, ksp->vec_sol));
 28:   PetscCall(PCReduceFailedReason(ksp->pc));
 29:   PetscCall(PCGetFailedReason(ksp->pc, &pcreason));
 30:   PetscCall(VecFlag(ksp->vec_sol, pcreason));
 31:   if (pcreason) {
 32:     PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "KSPSolve has not converged with PCFailedReason %s", PCFailedReasons[pcreason]);
 33:     ksp->reason = KSP_DIVERGED_PC_FAILED;
 34:   } else {
 35:     ksp->its    = 1;
 36:     ksp->reason = KSP_CONVERGED_ITS;
 37:   }
 38:   if (ksp->numbermonitors) {
 39:     Vec v;
 40:     Mat A;

 42:     PetscCall(VecDuplicate(ksp->vec_rhs, &v));
 43:     PetscCall(PCGetOperators(ksp->pc, &A, NULL));
 44:     PetscCall(KSP_MatMult(ksp, A, ksp->vec_sol, v));
 45:     PetscCall(VecAYPX(v, -1.0, ksp->vec_rhs));
 46:     PetscCall(VecNorm(v, NORM_2, &norm));
 47:     PetscCall(VecDestroy(&v));
 48:     PetscCall(KSPMonitor(ksp, 1, norm));
 49:   }
 50:   PetscFunctionReturn(PETSC_SUCCESS);
 51: }

 53: static PetscErrorCode KSPMatSolve_PREONLY(KSP ksp, Mat B, Mat X)
 54: {
 55:   PetscBool      diagonalscale;
 56:   PCFailedReason pcreason;

 58:   PetscFunctionBegin;
 59:   PetscCall(PCGetDiagonalScale(ksp->pc, &diagonalscale));
 60:   PetscCheck(!diagonalscale, PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "Krylov method %s does not support diagonal scaling", ((PetscObject)ksp)->type_name);
 61:   PetscCheck(ksp->guess_zero, PetscObjectComm((PetscObject)ksp), PETSC_ERR_USER, "Running KSP of preonly doesn't make sense with nonzero initial guess you probably want a KSP type of Richardson");
 62:   ksp->its = 0;
 63:   PetscCall(KSP_PCMatApply(ksp, B, X));
 64:   PetscCall(PCGetFailedReason(ksp->pc, &pcreason));
 65:   /* Note: only some ranks may have this set; this may lead to problems if the caller assumes ksp->reason is set on all processes or just uses the result */
 66:   if (pcreason) {
 67:     PetscCall(MatSetInf(X));
 68:     ksp->reason = KSP_DIVERGED_PC_FAILED;
 69:   } else {
 70:     ksp->its    = 1;
 71:     ksp->reason = KSP_CONVERGED_ITS;
 72:   }
 73:   PetscFunctionReturn(PETSC_SUCCESS);
 74: }

 76: /*MC
 77:    KSPNONE - An alias for `KSPPREONLY`

 79:    Options Database Key:
 80: .   -ksp_type none - use a single application of the preconditioner only

 82:    Level: beginner

 84:    Note:
 85:    See `KSPPREONLY` for more details

 87: .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSPPREONLY`, `KSP`, `KSPRICHARDSON`, `KSPCHEBYSHEV`, `KSPGetPC()`, `KSPSetInitialGuessNonzero()`,
 88:           `PCREDISTRIBUTE`, `PCRedistributeGetKSP()`, `KSPPREONLY`
 89: M*/

 91: /*MC
 92:    KSPPREONLY - This implements a method that applies ONLY the preconditioner exactly once.

 94:    It is commonly used with the direct solver preconditioners like `PCLU` and `PCCHOLESKY`, but it may also be used when a single iteration of the
 95:    preconditioner is needed for smoothing in multigrid, `PCMG` or `PCGAMG` or within some other nested linear solve such as `PCFIELDSPLIT` or `PCBJACOBI`.

 97:    There is an alias of this with the name `KSPNONE`.

 99:    Options Database Key:
100: .   -ksp_type preonly - use a single application of the preconditioner only

102:    Level: beginner

104:    Notes:
105:    Since this does not involve an iteration the basic `KSP` parameters such as tolerances and maximum iteration counts
106:    do not apply

108:    To apply the preconditioner multiple times in a simple iteration use `KSPRICHARDSON`

110:    This `KSPType` cannot be used with the flag `-ksp_initial_guess_nonzero` or the call `KSPSetInitialGuessNonzero()` since it simply applies
111:    the preconditioner to the given right-hand side during `KSPSolve()`. Except when the
112:    `PCType` is `PCREDISTRIBUTE`; in that situation pass the nonzero initial guess flag with `-ksp_initial_guess_nonzero` or `KSPSetInitialGuessNonzero()`
113:    both to the outer `KSP` (which is `KSPPREONLY`) and the inner `KSP` object obtained with `KSPGetPC()` followed by `PCRedistributedGetKSP()`
114:    followed by `KSPSetInitialGuessNonzero()` or the option  `-redistribute_ksp_initial_guess_nonzero`.

116:    Developer Note:
117:    Even though this method does not use any norms, the user is allowed to set the `KSPNormType` to any value.
118:    This is so the users does not have to change `KSPNormType` options when they switch from other `KSP` methods to this one.

120: .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPRICHARDSON`, `KSPCHEBYSHEV`, `KSPGetPC()`, `KSPSetInitialGuessNonzero()`,
121:           `PCREDISTRIBUTE`, `PCRedistributeGetKSP()`, `KSPNONE`
122: M*/

124: PETSC_EXTERN PetscErrorCode KSPCreate_PREONLY(KSP ksp)
125: {
126:   PetscFunctionBegin;
127:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 3));
128:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_RIGHT, 2));
129:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 2));
130:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_RIGHT, 2));
131:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_LEFT, 2));
132:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_RIGHT, 2));
133:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NATURAL, PC_LEFT, 2));

135:   ksp->data                = NULL;
136:   ksp->ops->setup          = KSPSetUp_PREONLY;
137:   ksp->ops->solve          = KSPSolve_PREONLY;
138:   ksp->ops->matsolve       = KSPMatSolve_PREONLY;
139:   ksp->ops->destroy        = KSPDestroyDefault;
140:   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
141:   ksp->ops->buildresidual  = KSPBuildResidualDefault;
142:   ksp->ops->setfromoptions = NULL;
143:   ksp->ops->view           = NULL;
144:   ksp->guess_not_read      = PETSC_TRUE; // A KSP of preonly never needs to zero the input x since PC do not use an initial guess
145:   PetscFunctionReturn(PETSC_SUCCESS);
146: }