Actual source code: groppcg.c

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

  3: /*
  4:  KSPSetUp_GROPPCG - Sets up the workspace needed by the GROPPCG method.

  6:  This is called once, usually automatically by KSPSolve() or KSPSetUp()
  7:  but can be called directly by KSPSetUp()
  8: */
  9: static PetscErrorCode KSPSetUp_GROPPCG(KSP ksp)
 10: {
 11:   PetscFunctionBegin;
 12:   PetscCall(KSPSetWorkVecs(ksp, 6));
 13:   PetscFunctionReturn(PETSC_SUCCESS);
 14: }

 16: /*
 17:  KSPSolve_GROPPCG

 19:  Input Parameter:
 20:  .     ksp - the Krylov space object that was set to use conjugate gradient, by, for
 21:              example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPCG);
 22: */
 23: static PetscErrorCode KSPSolve_GROPPCG(KSP ksp)
 24: {
 25:   PetscInt    i;
 26:   PetscScalar alpha, beta = 0.0, gamma, gammaNew, t;
 27:   PetscReal   dp = 0.0;
 28:   Vec         x, b, r, p, s, S, z, Z;
 29:   Mat         Amat, Pmat;

 31:   PetscFunctionBegin;
 32:   x = ksp->vec_sol;
 33:   b = ksp->vec_rhs;
 34:   r = ksp->work[0];
 35:   p = ksp->work[1];
 36:   s = ksp->work[2];
 37:   S = ksp->work[3];
 38:   z = ksp->work[4];
 39:   Z = ksp->work[5];

 41:   PetscCall(PCGetOperators(ksp->pc, &Amat, &Pmat));

 43:   ksp->its = 0;
 44:   if (!ksp->guess_zero) {
 45:     PetscCall(KSP_MatMult(ksp, Amat, x, r)); /*     r <- b - Ax     */
 46:     PetscCall(VecAYPX(r, -1.0, b));
 47:   } else {
 48:     PetscCall(VecCopy(b, r)); /*     r <- b (x is 0) */
 49:   }

 51:   PetscCall(KSP_PCApply(ksp, r, z));    /*     z <- Br   */
 52:   PetscCall(VecCopy(z, p));             /*     p <- z    */
 53:   PetscCall(VecDotBegin(r, z, &gamma)); /*     gamma <- z'*r       */
 54:   PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)r)));
 55:   PetscCall(KSP_MatMult(ksp, Amat, p, s)); /*     s <- Ap   */
 56:   PetscCall(VecDotEnd(r, z, &gamma));      /*     gamma <- z'*r       */

 58:   switch (ksp->normtype) {
 59:   case KSP_NORM_PRECONDITIONED:
 60:     /* This could be merged with the computation of gamma above */
 61:     PetscCall(VecNorm(z, NORM_2, &dp)); /*     dp <- z'*z = e'*A'*B'*B*A'*e'     */
 62:     break;
 63:   case KSP_NORM_UNPRECONDITIONED:
 64:     /* This could be merged with the computation of gamma above */
 65:     PetscCall(VecNorm(r, NORM_2, &dp)); /*     dp <- r'*r = e'*A'*A*e            */
 66:     break;
 67:   case KSP_NORM_NATURAL:
 68:     KSPCheckDot(ksp, gamma);
 69:     dp = PetscSqrtReal(PetscAbsScalar(gamma)); /*     dp <- r'*z = r'*B*r = e'*A'*B*A*e */
 70:     break;
 71:   case KSP_NORM_NONE:
 72:     dp = 0.0;
 73:     break;
 74:   default:
 75:     SETERRQ(PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "%s", KSPNormTypes[ksp->normtype]);
 76:   }
 77:   PetscCall(KSPLogResidualHistory(ksp, dp));
 78:   PetscCall(KSPMonitor(ksp, 0, dp));
 79:   ksp->rnorm = dp;
 80:   PetscCall((*ksp->converged)(ksp, 0, dp, &ksp->reason, ksp->cnvP)); /* test for convergence */
 81:   if (ksp->reason) PetscFunctionReturn(PETSC_SUCCESS);

 83:   i = 0;
 84:   do {
 85:     ksp->its = i + 1;
 86:     i++;

 88:     PetscCall(VecDotBegin(p, s, &t));
 89:     PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)p)));

 91:     PetscCall(KSP_PCApply(ksp, s, S)); /*   S <- Bs       */

 93:     PetscCall(VecDotEnd(p, s, &t));

 95:     alpha = gamma / t;
 96:     PetscCall(VecAXPY(x, alpha, p));  /*     x <- x + alpha * p   */
 97:     PetscCall(VecAXPY(r, -alpha, s)); /*     r <- r - alpha * s   */
 98:     PetscCall(VecAXPY(z, -alpha, S)); /*     z <- z - alpha * S   */

100:     if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
101:       PetscCall(VecNormBegin(r, NORM_2, &dp));
102:     } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
103:       PetscCall(VecNormBegin(z, NORM_2, &dp));
104:     }
105:     PetscCall(VecDotBegin(r, z, &gammaNew));
106:     PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)r)));

108:     PetscCall(KSP_MatMult(ksp, Amat, z, Z)); /*   Z <- Az       */

110:     if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
111:       PetscCall(VecNormEnd(r, NORM_2, &dp));
112:     } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
113:       PetscCall(VecNormEnd(z, NORM_2, &dp));
114:     }
115:     PetscCall(VecDotEnd(r, z, &gammaNew));

117:     if (ksp->normtype == KSP_NORM_NATURAL) {
118:       KSPCheckDot(ksp, gammaNew);
119:       dp = PetscSqrtReal(PetscAbsScalar(gammaNew)); /*     dp <- r'*z = r'*B*r = e'*A'*B*A*e */
120:     } else if (ksp->normtype == KSP_NORM_NONE) {
121:       dp = 0.0;
122:     }
123:     ksp->rnorm = dp;
124:     PetscCall(KSPLogResidualHistory(ksp, dp));
125:     PetscCall(KSPMonitor(ksp, i, dp));
126:     PetscCall((*ksp->converged)(ksp, i, dp, &ksp->reason, ksp->cnvP));
127:     if (ksp->reason) PetscFunctionReturn(PETSC_SUCCESS);

129:     beta  = gammaNew / gamma;
130:     gamma = gammaNew;
131:     PetscCall(VecAYPX(p, beta, z)); /*     p <- z + beta * p   */
132:     PetscCall(VecAYPX(s, beta, Z)); /*     s <- Z + beta * s   */

134:   } while (i < ksp->max_it);

136:   if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
137:   PetscFunctionReturn(PETSC_SUCCESS);
138: }

140: PETSC_INTERN PetscErrorCode KSPBuildResidual_CG(KSP, Vec, Vec, Vec *);

142: /*MC
143:    KSPGROPPCG - A pipelined conjugate gradient method developed by Bill Gropp {cite}`eller2016scalable`. [](sec_pipelineksp)

145:    Level: intermediate

147:    Notes:
148:    This method has two reductions, one of which is overlapped with the matrix-vector product and one of which is
149:    overlapped with the preconditioner.

151:    See also `KSPPIPECG`, which has only a single reduction that overlaps both the matrix-vector product and the preconditioner.

153:    MPI configuration may be necessary for reductions to make asynchronous progress, which is important for performance of pipelined methods.
154:    See [](doc_faq_pipelined)

156:    Contributed by:
157:    Pieter Ghysels, Universiteit Antwerpen, Intel Exascience lab Flanders

159: .seealso: [](ch_ksp), [](sec_pipelineksp), [](doc_faq_pipelined), `KSPCreate()`, `KSPPIPECG2()`, `KSPSetType()`, `KSPPIPECG`, `KSPPIPECR`, `KSPPGMRES`, `KSPCG`, `KSPCGUseSingleReduction()`
160: M*/

162: PETSC_EXTERN PetscErrorCode KSPCreate_GROPPCG(KSP ksp)
163: {
164:   PetscFunctionBegin;
165:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_LEFT, 2));
166:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 2));
167:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NATURAL, PC_LEFT, 2));
168:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1));

170:   ksp->ops->setup          = KSPSetUp_GROPPCG;
171:   ksp->ops->solve          = KSPSolve_GROPPCG;
172:   ksp->ops->destroy        = KSPDestroyDefault;
173:   ksp->ops->view           = NULL;
174:   ksp->ops->setfromoptions = NULL;
175:   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
176:   ksp->ops->buildresidual  = KSPBuildResidual_CG;
177:   PetscFunctionReturn(PETSC_SUCCESS);
178: }