Date: 2025-03-29T05:58:26+00:00

Actual source code: pipebcgs.c

      1: /*
      2:     This file implements pipelined BiCGStab (pipe-BiCGStab).
      3: */
      4: #include <../src/ksp/ksp/impls/bcgs/bcgsimpl.h>

      6: static PetscErrorCode KSPSetUp_PIPEBCGS(KSP ksp)
      7: {
      8:   PetscFunctionBegin;
      9:   PetscCall(KSPSetWorkVecs(ksp, 15));
     10:   PetscFunctionReturn(PETSC_SUCCESS);
     11: }

     13: /* Only need a few hacks from KSPSolve_BCGS */
     14: #include <petsc/private/pcimpl.h>
     15: static PetscErrorCode KSPSolve_PIPEBCGS(KSP ksp)
     16: {
     17:   PetscInt    i;
     18:   PetscScalar rho, rhoold, alpha, beta, omega = 0.0, d1, d2, d3;
     19:   Vec         X, B, S, R, RP, Y, Q, P2, Q2, R2, S2, W, Z, W2, Z2, T, V;
     20:   PetscReal   dp   = 0.0;
     21:   KSP_BCGS   *bcgs = (KSP_BCGS *)ksp->data;
     22:   PC          pc;

     24:   PetscFunctionBegin;
     25:   X  = ksp->vec_sol;
     26:   B  = ksp->vec_rhs;
     27:   R  = ksp->work[0];
     28:   RP = ksp->work[1];
     29:   S  = ksp->work[2];
     30:   Y  = ksp->work[3];
     31:   Q  = ksp->work[4];
     32:   Q2 = ksp->work[5];
     33:   P2 = ksp->work[6];
     34:   R2 = ksp->work[7];
     35:   S2 = ksp->work[8];
     36:   W  = ksp->work[9];
     37:   Z  = ksp->work[10];
     38:   W2 = ksp->work[11];
     39:   Z2 = ksp->work[12];
     40:   T  = ksp->work[13];
     41:   V  = ksp->work[14];

     43:   if (!ksp->guess_zero) {
     44:     if (!bcgs->guess) PetscCall(VecDuplicate(X, &bcgs->guess));
     45:     PetscCall(VecCopy(X, bcgs->guess));
     46:   } else {
     47:     PetscCall(VecSet(X, 0.0));
     48:   }

     50:   /* Compute initial residual */
     51:   PetscCall(KSPGetPC(ksp, &pc));
     52:   if (!ksp->guess_zero) {
     53:     PetscCall(KSP_MatMult(ksp, pc->mat, X, Q2));
     54:     PetscCall(VecCopy(B, R));
     55:     PetscCall(VecAXPY(R, -1.0, Q2));
     56:   } else {
     57:     PetscCall(VecCopy(B, R));
     58:   }

     60:   /* Test for nothing to do */
     61:   if (ksp->normtype != KSP_NORM_NONE) {
     62:     PetscCall(VecNorm(R, NORM_2, &dp));
     63:   } else dp = 0.0;
     64:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
     65:   ksp->its   = 0;
     66:   ksp->rnorm = dp;
     67:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
     68:   PetscCall(KSPLogResidualHistory(ksp, dp));
     69:   PetscCall(KSPMonitor(ksp, 0, dp));
     70:   PetscCall((*ksp->converged)(ksp, 0, dp, &ksp->reason, ksp->cnvP));
     71:   if (ksp->reason) PetscFunctionReturn(PETSC_SUCCESS);

     73:   /* Initialize */
     74:   PetscCall(VecCopy(R, RP)); /* rp <- r */

     76:   PetscCall(VecDotBegin(R, RP, &rho)); /* rho <- (r,rp) */
     77:   PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)R)));
     78:   PetscCall(KSP_PCApply(ksp, R, R2));          /* r2 <- K r */
     79:   PetscCall(KSP_MatMult(ksp, pc->mat, R2, W)); /* w <- A r2 */
     80:   PetscCall(VecDotEnd(R, RP, &rho));

     82:   PetscCall(VecDotBegin(W, RP, &d2)); /* d2 <- (w,rp) */
     83:   PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)W)));
     84:   PetscCall(KSP_PCApply(ksp, W, W2));          /* w2 <- K w */
     85:   PetscCall(KSP_MatMult(ksp, pc->mat, W2, T)); /* t <- A w2 */
     86:   PetscCall(VecDotEnd(W, RP, &d2));

     88:   alpha = rho / d2;
     89:   beta  = 0.0;

     91:   /* Main loop */
     92:   i = 0;
     93:   do {
     94:     if (i == 0) {
     95:       PetscCall(VecCopy(R2, P2)); /* p2 <- r2 */
     96:       PetscCall(VecCopy(W, S));   /* s  <- w  */
     97:       PetscCall(VecCopy(W2, S2)); /* s2 <- w2 */
     98:       PetscCall(VecCopy(T, Z));   /* z  <- t  */
     99:     } else {
    100:       PetscCall(VecAXPBYPCZ(P2, 1.0, -beta * omega, beta, R2, S2)); /* p2 <- beta * p2 + r2 - beta * omega * s2 */
    101:       PetscCall(VecAXPBYPCZ(S, 1.0, -beta * omega, beta, W, Z));    /* s  <- beta * s  + w  - beta * omega * z  */
    102:       PetscCall(VecAXPBYPCZ(S2, 1.0, -beta * omega, beta, W2, Z2)); /* s2 <- beta * s2 + w2 - beta * omega * z2 */
    103:       PetscCall(VecAXPBYPCZ(Z, 1.0, -beta * omega, beta, T, V));    /* z  <- beta * z  + t  - beta * omega * v  */
    104:     }
    105:     PetscCall(VecWAXPY(Q, -alpha, S, R));    /* q  <- r  - alpha s  */
    106:     PetscCall(VecWAXPY(Q2, -alpha, S2, R2)); /* q2 <- r2 - alpha s2 */
    107:     PetscCall(VecWAXPY(Y, -alpha, Z, W));    /* y  <- w  - alpha z  */

    109:     PetscCall(VecDotBegin(Q, Y, &d1)); /* d1 <- (q,y) */
    110:     PetscCall(VecDotBegin(Y, Y, &d2)); /* d2 <- (y,y) */

    112:     PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)Q)));
    113:     PetscCall(KSP_PCApply(ksp, Z, Z2));          /* z2 <- K z */
    114:     PetscCall(KSP_MatMult(ksp, pc->mat, Z2, V)); /* v <- A z2 */

    116:     PetscCall(VecDotEnd(Q, Y, &d1));
    117:     PetscCall(VecDotEnd(Y, Y, &d2));

    119:     if (d2 == 0.0) {
    120:       /* y is 0. if q is 0, then alpha s == r, and hence alpha p may be our solution. Give it a try? */
    121:       PetscCall(VecDot(Q, Q, &d1));
    122:       if (d1 != 0.0) {
    123:         ksp->reason = KSP_DIVERGED_BREAKDOWN;
    124:         break;
    125:       }
    126:       PetscCall(VecAXPY(X, alpha, P2)); /* x <- x + alpha p2 */
    127:       PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
    128:       ksp->its++;
    129:       ksp->rnorm  = 0.0;
    130:       ksp->reason = KSP_CONVERGED_RTOL;
    131:       PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
    132:       PetscCall(KSPLogResidualHistory(ksp, dp));
    133:       PetscCall(KSPMonitor(ksp, i + 1, 0.0));
    134:       break;
    135:     }
    136:     omega = d1 / d2;                                      /* omega <- (y'q) / (y'y) */
    137:     PetscCall(VecAXPBYPCZ(X, alpha, omega, 1.0, P2, Q2)); /* x <- alpha * p2 + omega * q2 + x */
    138:     PetscCall(VecWAXPY(R, -omega, Y, Q));                 /* r <- q - omega y */
    139:     PetscCall(VecWAXPY(R2, -alpha, Z2, W2));              /* r2 <- w2 - alpha z2 */
    140:     PetscCall(VecAYPX(R2, -omega, Q2));                   /* r2 <- q2 - omega r2 */
    141:     PetscCall(VecWAXPY(W, -alpha, V, T));                 /* w <- t - alpha v */
    142:     PetscCall(VecAYPX(W, -omega, Y));                     /* w <- y - omega w */
    143:     rhoold = rho;

    145:     if (ksp->normtype != KSP_NORM_NONE && ksp->chknorm < i + 2) { PetscCall(VecNormBegin(R, NORM_2, &dp)); /* dp <- norm(r) */ }
    146:     PetscCall(VecDotBegin(R, RP, &rho)); /* rho <- (r,rp) */
    147:     PetscCall(VecDotBegin(S, RP, &d1));  /* d1 <- (s,rp) */
    148:     PetscCall(VecDotBegin(W, RP, &d2));  /* d2 <- (w,rp) */
    149:     PetscCall(VecDotBegin(Z, RP, &d3));  /* d3 <- (z,rp) */

    151:     PetscCall(PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)R)));
    152:     PetscCall(KSP_PCApply(ksp, W, W2));          /* w2 <- K w */
    153:     PetscCall(KSP_MatMult(ksp, pc->mat, W2, T)); /* t <- A w2 */

    155:     if (ksp->normtype != KSP_NORM_NONE && ksp->chknorm < i + 2) PetscCall(VecNormEnd(R, NORM_2, &dp));
    156:     PetscCall(VecDotEnd(R, RP, &rho));
    157:     PetscCall(VecDotEnd(S, RP, &d1));
    158:     PetscCall(VecDotEnd(W, RP, &d2));
    159:     PetscCall(VecDotEnd(Z, RP, &d3));

    161:     PetscCheck(d2 + beta * d1 - beta * omega * d3 != 0.0, PetscObjectComm((PetscObject)ksp), PETSC_ERR_PLIB, "Divide by zero");

    163:     beta  = (rho / rhoold) * (alpha / omega);
    164:     alpha = rho / (d2 + beta * d1 - beta * omega * d3); /* alpha <- rho / (d2 + beta * d1 - beta * omega * d3) */

    166:     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
    167:     ksp->its++;

    169:     /* Residual replacement step  */
    170:     if (i > 0 && i % 100 == 0 && i < 1001) {
    171:       PetscCall(KSP_MatMult(ksp, pc->mat, X, R));
    172:       PetscCall(VecAYPX(R, -1.0, B));              /* r  <- b - Ax */
    173:       PetscCall(KSP_PCApply(ksp, R, R2));          /* r2 <- K r */
    174:       PetscCall(KSP_MatMult(ksp, pc->mat, R2, W)); /* w  <- A r2 */
    175:       PetscCall(KSP_PCApply(ksp, W, W2));          /* w2 <- K w */
    176:       PetscCall(KSP_MatMult(ksp, pc->mat, W2, T)); /* t  <- A w2 */
    177:       PetscCall(KSP_MatMult(ksp, pc->mat, P2, S)); /* s  <- A p2 */
    178:       PetscCall(KSP_PCApply(ksp, S, S2));          /* s2 <- K s */
    179:       PetscCall(KSP_MatMult(ksp, pc->mat, S2, Z)); /* z  <- A s2 */
    180:       PetscCall(KSP_PCApply(ksp, Z, Z2));          /* z2 <- K z */
    181:       PetscCall(KSP_MatMult(ksp, pc->mat, Z2, V)); /* v  <- A z2 */
    182:     }

    184:     ksp->rnorm = dp;
    185:     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
    186:     PetscCall(KSPLogResidualHistory(ksp, dp));
    187:     PetscCall(KSPMonitor(ksp, i + 1, dp));
    188:     PetscCall((*ksp->converged)(ksp, i + 1, dp, &ksp->reason, ksp->cnvP));
    189:     if (ksp->reason) break;
    190:     if (rho == 0.0) {
    191:       ksp->reason = KSP_DIVERGED_BREAKDOWN;
    192:       break;
    193:     }
    194:     i++;
    195:   } while (i < ksp->max_it);

    197:   if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
    198:   PetscFunctionReturn(PETSC_SUCCESS);
    199: }

    201: /*MC
    202:     KSPPIPEBCGS - Implements a pipelined BiCGStab method. [](sec_pipelineksp)

    204:     Level: intermediate

    206:     Notes:
    207:     This method has only two non-blocking reductions per iteration, compared to 3 blocking for standard `KSPFBCGS`.  The
    208:     non-blocking reductions are overlapped by matrix-vector products and preconditioner applications.

    210:     Periodic residual replacement may be used to increase robustness and maximal attainable accuracy.

    212:     Like `KSPFBCGS`, the `KSPPIPEBCGS` implementation only allows for right preconditioning.

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

    217:     Contributed by:
    218:     Siegfried Cools, Universiteit Antwerpen, {cite}`cools2017communication`
    219:     EXA2CT European Project on EXascale Algorithms and Advanced Computational Techniques, 2016.

    221: .seealso: [](ch_ksp), `KSPFBCGS`, `KSPFBCGSR`, `KSPBCGS`, `KSPBCGSL`, `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPBICG`, `KSPFBCGS`, `KSPSetPCSide()`,
    222:            [](sec_pipelineksp), [](doc_faq_pipelined)
    223: M*/
    224: PETSC_EXTERN PetscErrorCode KSPCreate_PIPEBCGS(KSP ksp)
    225: {
    226:   KSP_BCGS *bcgs;

    228:   PetscFunctionBegin;
    229:   PetscCall(PetscNew(&bcgs));

    231:   ksp->data                = bcgs;
    232:   ksp->ops->setup          = KSPSetUp_PIPEBCGS;
    233:   ksp->ops->solve          = KSPSolve_PIPEBCGS;
    234:   ksp->ops->destroy        = KSPDestroy_BCGS;
    235:   ksp->ops->reset          = KSPReset_BCGS;
    236:   ksp->ops->buildresidual  = KSPBuildResidualDefault;
    237:   ksp->ops->setfromoptions = KSPSetFromOptions_BCGS;

    239:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_RIGHT, 2));
    240:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_RIGHT, 1));
    241:   PetscFunctionReturn(PETSC_SUCCESS);
    242: }