Actual source code: bicg.c
1: #include <petsc/private/kspimpl.h>
3: static PetscErrorCode KSPSetUp_BiCG(KSP ksp)
4: {
5: PetscFunctionBegin;
6: PetscCall(KSPSetWorkVecs(ksp, 6));
7: PetscFunctionReturn(PETSC_SUCCESS);
8: }
10: static PetscErrorCode KSPSolve_BiCG(KSP ksp)
11: {
12: PetscInt i;
13: PetscScalar dpi, a = 1.0, beta, betaold = 1.0, b, ma;
14: PetscReal dp;
15: Vec X, B, Zl, Zr, Rl, Rr, Pl, Pr;
16: Mat Amat, Pmat;
18: PetscFunctionBegin;
19: X = ksp->vec_sol;
20: B = ksp->vec_rhs;
21: Rl = ksp->work[0];
22: Zl = ksp->work[1];
23: Pl = ksp->work[2];
24: Rr = ksp->work[3];
25: Zr = ksp->work[4];
26: Pr = ksp->work[5];
28: PetscCall(PCGetOperators(ksp->pc, &Amat, &Pmat));
30: if (!ksp->guess_zero) {
31: PetscCall(KSP_MatMult(ksp, Amat, X, Rr)); /* r <- b - Ax */
32: PetscCall(VecAYPX(Rr, -1.0, B));
33: } else {
34: PetscCall(VecCopy(B, Rr)); /* r <- b (x is 0) */
35: }
36: PetscCall(VecCopy(Rr, Rl));
37: PetscCall(KSP_PCApply(ksp, Rr, Zr)); /* z <- Br */
38: PetscCall(KSP_PCApplyHermitianTranspose(ksp, Rl, Zl));
39: if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
40: PetscCall(VecNorm(Zr, NORM_2, &dp)); /* dp <- z'*z */
41: } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
42: PetscCall(VecNorm(Rr, NORM_2, &dp)); /* dp <- r'*r */
43: } else dp = 0.0;
45: KSPCheckNorm(ksp, dp);
46: PetscCall(KSPMonitor(ksp, 0, dp));
47: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
48: ksp->its = 0;
49: ksp->rnorm = dp;
50: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
51: PetscCall(KSPLogResidualHistory(ksp, dp));
52: PetscCall((*ksp->converged)(ksp, 0, dp, &ksp->reason, ksp->cnvP));
53: if (ksp->reason) PetscFunctionReturn(PETSC_SUCCESS);
55: i = 0;
56: do {
57: PetscCall(VecDot(Zr, Rl, &beta)); /* beta <- r'z */
58: KSPCheckDot(ksp, beta);
59: if (!i) {
60: if (beta == 0.0) {
61: ksp->reason = KSP_DIVERGED_BREAKDOWN_BICG;
62: PetscFunctionReturn(PETSC_SUCCESS);
63: }
64: PetscCall(VecCopy(Zr, Pr)); /* p <- z */
65: PetscCall(VecCopy(Zl, Pl));
66: } else {
67: b = beta / betaold;
68: PetscCall(VecAYPX(Pr, b, Zr)); /* p <- z + b* p */
69: b = PetscConj(b);
70: PetscCall(VecAYPX(Pl, b, Zl));
71: }
72: betaold = beta;
73: PetscCall(KSP_MatMult(ksp, Amat, Pr, Zr)); /* z <- Kp */
74: PetscCall(KSP_MatMultHermitianTranspose(ksp, Amat, Pl, Zl));
75: PetscCall(VecDot(Zr, Pl, &dpi)); /* dpi <- z'p */
76: KSPCheckDot(ksp, dpi);
77: a = beta / dpi; /* a = beta/p'z */
78: PetscCall(VecAXPY(X, a, Pr)); /* x <- x + ap */
79: ma = -a;
80: PetscCall(VecAXPY(Rr, ma, Zr));
81: ma = PetscConj(ma);
82: PetscCall(VecAXPY(Rl, ma, Zl));
83: if (ksp->normtype == KSP_NORM_PRECONDITIONED) {
84: PetscCall(KSP_PCApply(ksp, Rr, Zr)); /* z <- Br */
85: PetscCall(KSP_PCApplyHermitianTranspose(ksp, Rl, Zl));
86: PetscCall(VecNorm(Zr, NORM_2, &dp)); /* dp <- z'*z */
87: } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
88: PetscCall(VecNorm(Rr, NORM_2, &dp)); /* dp <- r'*r */
89: } else dp = 0.0;
91: KSPCheckNorm(ksp, dp);
92: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
93: ksp->its = i + 1;
94: ksp->rnorm = dp;
95: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
96: PetscCall(KSPLogResidualHistory(ksp, dp));
97: PetscCall(KSPMonitor(ksp, i + 1, dp));
98: PetscCall((*ksp->converged)(ksp, i + 1, dp, &ksp->reason, ksp->cnvP));
99: if (ksp->reason) break;
100: if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {
101: PetscCall(KSP_PCApply(ksp, Rr, Zr)); /* z <- Br */
102: PetscCall(KSP_PCApplyHermitianTranspose(ksp, Rl, Zl));
103: }
104: i++;
105: } while (i < ksp->max_it);
106: if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
107: PetscFunctionReturn(PETSC_SUCCESS);
108: }
110: /*MC
111: KSPBICG - Implements the Biconjugate gradient method (similar to running the conjugate
112: gradient on the normal equations).
114: Level: beginner
116: Notes:
117: This method requires that one be apply to apply the transpose of the preconditioner and operator
118: as well as the operator and preconditioner.
120: Supports only left preconditioning
122: See `KSPCGNE` for code that EXACTLY runs the preconditioned conjugate gradient method on the normal equations
124: See `KSPBCGS` for the famous stabilized variant of this algorithm
126: .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPBCGS`, `KSPCGNE`
127: M*/
128: PETSC_EXTERN PetscErrorCode KSPCreate_BiCG(KSP ksp)
129: {
130: PetscFunctionBegin;
131: PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 3));
132: PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_LEFT, 2));
133: PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1));
135: ksp->ops->setup = KSPSetUp_BiCG;
136: ksp->ops->solve = KSPSolve_BiCG;
137: ksp->ops->destroy = KSPDestroyDefault;
138: ksp->ops->view = NULL;
139: ksp->ops->setfromoptions = NULL;
140: ksp->ops->buildsolution = KSPBuildSolutionDefault;
141: ksp->ops->buildresidual = KSPBuildResidualDefault;
142: PetscFunctionReturn(PETSC_SUCCESS);
143: }