Actual source code: minres.c
1: #define PETSCKSP_DLL
3: #include private/kspimpl.h
5: typedef struct {
6: PetscReal haptol;
7: } KSP_MINRES;
11: PetscErrorCode KSPSetUp_MINRES(KSP ksp)
12: {
16: if (ksp->pc_side == PC_RIGHT) {
17: SETERRQ(PETSC_ERR_SUP,"No right preconditioning for KSPMINRES");
18: } else if (ksp->pc_side == PC_SYMMETRIC) {
19: SETERRQ(PETSC_ERR_SUP,"No symmetric preconditioning for KSPMINRES");
20: }
21: KSPDefaultGetWork(ksp,9);
22: return(0);
23: }
28: PetscErrorCode KSPSolve_MINRES(KSP ksp)
29: {
31: PetscInt i;
32: PetscScalar alpha,beta,ibeta,betaold,eta,c=1.0,ceta,cold=1.0,coold,s=0.0,sold=0.0,soold;
33: PetscScalar rho0,rho1,irho1,rho2,mrho2,rho3,mrho3,dp = 0.0;
34: PetscReal np;
35: Vec X,B,R,Z,U,V,W,UOLD,VOLD,WOLD,WOOLD;
36: Mat Amat,Pmat;
37: MatStructure pflag;
38: KSP_MINRES *minres = (KSP_MINRES*)ksp->data;
39: PetscTruth diagonalscale;
42: if (ksp->normtype != KSP_NORM_PRECONDITIONED) SETERRQ(PETSC_ERR_SUP,"Only supports preconditioned residual norm for KSPMINRES");
44: PCDiagonalScale(ksp->pc,&diagonalscale);
45: if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
47: X = ksp->vec_sol;
48: B = ksp->vec_rhs;
49: R = ksp->work[0];
50: Z = ksp->work[1];
51: U = ksp->work[2];
52: V = ksp->work[3];
53: W = ksp->work[4];
54: UOLD = ksp->work[5];
55: VOLD = ksp->work[6];
56: WOLD = ksp->work[7];
57: WOOLD = ksp->work[8];
59: PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
61: ksp->its = 0;
63: VecSet(UOLD,0.0); /* u_old <- 0 */
64: VecCopy(UOLD,VOLD); /* v_old <- 0 */
65: VecCopy(UOLD,W); /* w <- 0 */
66: VecCopy(UOLD,WOLD); /* w_old <- 0 */
68: if (!ksp->guess_zero) {
69: KSP_MatMult(ksp,Amat,X,R); /* r <- b - A*x */
70: VecAYPX(R,-1.0,B);
71: } else {
72: VecCopy(B,R); /* r <- b (x is 0) */
73: }
75: KSP_PCApply(ksp,R,Z); /* z <- B*r */
77: VecDot(R,Z,&dp);
78: if (PetscAbsScalar(dp) < minres->haptol) {
79: PetscInfo2(ksp,"Detected happy breakdown %G tolerance %G\n",PetscAbsScalar(dp),minres->haptol);
80: dp = PetscAbsScalar(dp); /* tiny number, can't use 0.0, cause divided by below */
81: if (dp == 0.0) {
82: ksp->reason = KSP_CONVERGED_ATOL;
83: return(0);
84: }
85: }
87: #if !defined(PETSC_USE_COMPLEX)
88: if (dp < 0.0) {
89: ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
90: return(0);
91: }
92: #endif
93: dp = PetscSqrtScalar(dp);
94: beta = dp; /* beta <- sqrt(r'*z */
95: eta = beta;
97: VecCopy(R,V);
98: VecCopy(Z,U);
99: ibeta = 1.0 / beta;
100: VecScale(V,ibeta); /* v <- r / beta */
101: VecScale(U,ibeta); /* u <- z / beta */
103: VecNorm(Z,NORM_2,&np); /* np <- ||z|| */
105: KSPLogResidualHistory(ksp,np);
106: KSPMonitor(ksp,0,np); /* call any registered monitor routines */
107: ksp->rnorm = np;
108: (*ksp->converged)(ksp,0,np,&ksp->reason,ksp->cnvP); /* test for convergence */
109: if (ksp->reason) return(0);
111: i = 0;
112: do {
113: ksp->its = i+1;
115: /* Lanczos */
117: KSP_MatMult(ksp,Amat,U,R); /* r <- A*u */
118: VecDot(U,R,&alpha); /* alpha <- r'*u */
119: KSP_PCApply(ksp,R,Z); /* z <- B*r */
121: VecAXPY(R,-alpha,V); /* r <- r - alpha v */
122: VecAXPY(Z,-alpha,U); /* z <- z - alpha u */
123: VecAXPY(R,-beta,VOLD); /* r <- r - beta v_old */
124: VecAXPY(Z,-beta,UOLD); /* z <- z - beta u_old */
126: betaold = beta;
128: VecDot(R,Z,&dp);
129: if (PetscAbsScalar(dp) < minres->haptol) {
130: PetscInfo2(ksp,"Detected happy breakdown %G tolerance %G\n",PetscAbsScalar(dp),minres->haptol);
131: dp = PetscAbsScalar(dp); /* tiny number, can we use 0.0? */
132: }
134: #if !defined(PETSC_USE_COMPLEX)
135: if (dp < 0.0) {
136: ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
137: break;
138: }
140: #endif
141: beta = PetscSqrtScalar(dp); /* beta <- sqrt(r'*z) */
143: /* QR factorisation */
145: coold = cold; cold = c; soold = sold; sold = s;
147: rho0 = cold * alpha - coold * sold * betaold;
148: rho1 = PetscSqrtScalar(rho0*rho0 + beta*beta);
149: rho2 = sold * alpha + coold * cold * betaold;
150: rho3 = soold * betaold;
152: /* Givens rotation */
154: c = rho0 / rho1;
155: s = beta / rho1;
157: /* Update */
159: VecCopy(WOLD,WOOLD); /* w_oold <- w_old */
160: VecCopy(W,WOLD); /* w_old <- w */
161:
162: VecCopy(U,W); /* w <- u */
163: mrho2 = - rho2;
164: VecAXPY(W,mrho2,WOLD); /* w <- w - rho2 w_old */
165: mrho3 = - rho3;
166: VecAXPY(W,mrho3,WOOLD); /* w <- w - rho3 w_oold */
167: irho1 = 1.0 / rho1;
168: VecScale(W,irho1); /* w <- w / rho1 */
170: ceta = c * eta;
171: VecAXPY(X,ceta,W); /* x <- x + c eta w */
172: eta = - s * eta;
174: VecCopy(V,VOLD);
175: VecCopy(U,UOLD);
176: VecCopy(R,V);
177: VecCopy(Z,U);
178: ibeta = 1.0 / beta;
179: VecScale(V,ibeta); /* v <- r / beta */
180: VecScale(U,ibeta); /* u <- z / beta */
181:
182: np = ksp->rnorm * PetscAbsScalar(s);
184: ksp->rnorm = np;
185: KSPLogResidualHistory(ksp,np);
186: KSPMonitor(ksp,i+1,np);
187: (*ksp->converged)(ksp,i+1,np,&ksp->reason,ksp->cnvP); /* test for convergence */
188: if (ksp->reason) break;
189: i++;
190: } while (i<ksp->max_it);
191: if (i >= ksp->max_it) {
192: ksp->reason = KSP_DIVERGED_ITS;
193: }
194: return(0);
195: }
197: /*MC
198: KSPMINRES - This code implements the MINRES (Minimum Residual) method.
200: Options Database Keys:
201: . see KSPSolve()
203: Level: beginner
205: Contributed by: Robert Scheichl: maprs@maths.bath.ac.uk
207: Notes: The operator and the preconditioner must be symmetric and the preconditioner must
208: be positive definite for this method.
210: Reference: Paige & Saunders, 1975.
212: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP, KSPCG, KSPCR
213: M*/
217: PetscErrorCode KSPCreate_MINRES(KSP ksp)
218: {
219: KSP_MINRES *minres;
224: ksp->pc_side = PC_LEFT;
225: PetscNewLog(ksp,KSP_MINRES,&minres);
226: minres->haptol = 1.e-18;
227: ksp->data = (void*)minres;
229: /*
230: Sets the functions that are associated with this data structure
231: (in C++ this is the same as defining virtual functions)
232: */
233: ksp->ops->setup = KSPSetUp_MINRES;
234: ksp->ops->solve = KSPSolve_MINRES;
235: ksp->ops->destroy = KSPDefaultDestroy;
236: ksp->ops->setfromoptions = 0;
237: ksp->ops->buildsolution = KSPDefaultBuildSolution;
238: ksp->ops->buildresidual = KSPDefaultBuildResidual;
239: return(0);
240: }