Actual source code: bicg.c


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

  4: static PetscErrorCode KSPSetUp_BiCG(KSP ksp)
  5: {
  6:   KSPSetWorkVecs(ksp, 6);
  7:   return 0;
  8: }

 10: static PetscErrorCode KSPSolve_BiCG(KSP ksp)
 11: {
 12:   PetscInt    i;
 13:   PetscBool   diagonalscale;
 14:   PetscScalar dpi, a = 1.0, beta, betaold = 1.0, b, ma;
 15:   PetscReal   dp;
 16:   Vec         X, B, Zl, Zr, Rl, Rr, Pl, Pr;
 17:   Mat         Amat, Pmat;

 19:   PCGetDiagonalScale(ksp->pc, &diagonalscale);

 22:   X  = ksp->vec_sol;
 23:   B  = ksp->vec_rhs;
 24:   Rl = ksp->work[0];
 25:   Zl = ksp->work[1];
 26:   Pl = ksp->work[2];
 27:   Rr = ksp->work[3];
 28:   Zr = ksp->work[4];
 29:   Pr = ksp->work[5];

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

 33:   if (!ksp->guess_zero) {
 34:     KSP_MatMult(ksp, Amat, X, Rr); /*   r <- b - Ax       */
 35:     VecAYPX(Rr, -1.0, B);
 36:   } else {
 37:     VecCopy(B, Rr); /*     r <- b (x is 0) */
 38:   }
 39:   VecCopy(Rr, Rl);
 40:   KSP_PCApply(ksp, Rr, Zr); /*     z <- Br         */
 41:   KSP_PCApplyHermitianTranspose(ksp, Rl, Zl);
 42:   if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
 43:     VecNorm(Zr, NORM_2, &dp); /*    dp <- z'*z       */
 44:   } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
 45:     VecNorm(Rr, NORM_2, &dp); /*    dp <- r'*r       */
 46:   } else dp = 0.0;

 48:   KSPCheckNorm(ksp, dp);
 49:   KSPMonitor(ksp, 0, dp);
 50:   PetscObjectSAWsTakeAccess((PetscObject)ksp);
 51:   ksp->its   = 0;
 52:   ksp->rnorm = dp;
 53:   PetscObjectSAWsGrantAccess((PetscObject)ksp);
 54:   KSPLogResidualHistory(ksp, dp);
 55:   (*ksp->converged)(ksp, 0, dp, &ksp->reason, ksp->cnvP);
 56:   if (ksp->reason) return 0;

 58:   i = 0;
 59:   do {
 60:     VecDot(Zr, Rl, &beta); /*     beta <- r'z     */
 61:     KSPCheckDot(ksp, beta);
 62:     if (!i) {
 63:       if (beta == 0.0) {
 64:         ksp->reason = KSP_DIVERGED_BREAKDOWN_BICG;
 65:         return 0;
 66:       }
 67:       VecCopy(Zr, Pr); /*     p <- z          */
 68:       VecCopy(Zl, Pl);
 69:     } else {
 70:       b = beta / betaold;
 71:       VecAYPX(Pr, b, Zr); /*     p <- z + b* p   */
 72:       b = PetscConj(b);
 73:       VecAYPX(Pl, b, Zl);
 74:     }
 75:     betaold = beta;
 76:     KSP_MatMult(ksp, Amat, Pr, Zr); /*     z <- Kp         */
 77:     KSP_MatMultHermitianTranspose(ksp, Amat, Pl, Zl);
 78:     VecDot(Zr, Pl, &dpi); /*     dpi <- z'p      */
 79:     KSPCheckDot(ksp, dpi);
 80:     a = beta / dpi;               /*     a = beta/p'z    */
 81:     VecAXPY(X, a, Pr); /*     x <- x + ap     */
 82:     ma = -a;
 83:     VecAXPY(Rr, ma, Zr);
 84:     ma = PetscConj(ma);
 85:     VecAXPY(Rl, ma, Zl);
 86:     if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
 87:       KSP_PCApply(ksp, Rr, Zr); /*     z <- Br         */
 88:       KSP_PCApplyHermitianTranspose(ksp, Rl, Zl);
 89:       VecNorm(Zr, NORM_2, &dp); /*    dp <- z'*z       */
 90:     } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
 91:       VecNorm(Rr, NORM_2, &dp); /*    dp <- r'*r       */
 92:     } else dp = 0.0;

 94:     KSPCheckNorm(ksp, dp);
 95:     PetscObjectSAWsTakeAccess((PetscObject)ksp);
 96:     ksp->its   = i + 1;
 97:     ksp->rnorm = dp;
 98:     PetscObjectSAWsGrantAccess((PetscObject)ksp);
 99:     KSPLogResidualHistory(ksp, dp);
100:     KSPMonitor(ksp, i + 1, dp);
101:     (*ksp->converged)(ksp, i + 1, dp, &ksp->reason, ksp->cnvP);
102:     if (ksp->reason) break;
103:     if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
104:       KSP_PCApply(ksp, Rr, Zr); /* z <- Br  */
105:       KSP_PCApplyHermitianTranspose(ksp, Rl, Zl);
106:     }
107:     i++;
108:   } while (i < ksp->max_it);
109:   if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
110:   return 0;
111: }

113: /*MC
114:      KSPBICG - Implements the Biconjugate gradient method (similar to running the conjugate
115:          gradient on the normal equations).

117:    Level: beginner

119:    Notes:
120:    This method requires that one be apply to apply the transpose of the preconditioner and operator
121:    as well as the operator and preconditioner.

123:    Supports only left preconditioning

125:    See `KSPCGNE` for code that EXACTLY runs the preconditioned conjugate gradient method on the normal equations

127:    See `KSPBCGS` for the famous stabilized variant of this algorithm

129: .seealso: [](chapter_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPBCGS`, `KSPCGNE`
130: M*/
131: PETSC_EXTERN PetscErrorCode KSPCreate_BiCG(KSP ksp)
132: {
133:   KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 3);
134:   KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_LEFT, 2);
135:   KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1);

137:   ksp->ops->setup          = KSPSetUp_BiCG;
138:   ksp->ops->solve          = KSPSolve_BiCG;
139:   ksp->ops->destroy        = KSPDestroyDefault;
140:   ksp->ops->view           = NULL;
141:   ksp->ops->setfromoptions = NULL;
142:   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
143:   ksp->ops->buildresidual  = KSPBuildResidualDefault;
144:   return 0;
145: }