1
/*$Id: minres.c,v 1.18 2001/08/10 18:14:38 bsmith Exp $*/
3
This code implements the MINRES (Minimum Residual) method.
4
Reference: Paige & Saunders, 1975.
6
Contributed by: Robert Scheichl: maprs@maths.bath.ac.uk
9
#include "src/sles/ksp/kspimpl.h"
16
#define __FUNCT__ "KSPSetUp_MINRES"
17
int KSPSetUp_MINRES(KSP ksp)
23
if (ksp->pc_side == PC_RIGHT) {
24
SETERRQ(2,"No right preconditioning for KSPMINRES");
25
} else if (ksp->pc_side == PC_SYMMETRIC) {
26
SETERRQ(2,"No symmetric preconditioning for KSPMINRES");
29
ierr = KSPDefaultGetWork(ksp,9);CHKERRQ(ierr);
31
PetscFunctionReturn(0);
36
#define __FUNCT__ "KSPSolve_MINRES"
37
int KSPSolve_MINRES(KSP ksp,int *its)
40
PetscScalar alpha,malpha,beta,mbeta,ibeta,betaold,eta,c=1.0,ceta,cold=1.0,coold,s=0.0,sold=0.0,soold;
41
PetscScalar rho0,rho1,irho1,rho2,mrho2,rho3,mrho3,mone = -1.0,zero = 0.0,dp = 0.0;
43
Vec X,B,R,Z,U,V,W,UOLD,VOLD,WOLD,WOOLD;
46
KSP_MINRES *minres = (KSP_MINRES*)ksp->data;
47
PetscTruth diagonalscale;
50
ierr = PCDiagonalScale(ksp->B,&diagonalscale);CHKERRQ(ierr);
51
if (diagonalscale) SETERRQ1(1,"Krylov method %s does not support diagonal scaling",ksp->type_name);
66
ierr = PCGetOperators(ksp->B,&Amat,&Pmat,&pflag);CHKERRQ(ierr);
70
ierr = VecSet(&zero,UOLD);CHKERRQ(ierr); /* u_old <- 0 */
71
ierr = VecCopy(UOLD,VOLD);CHKERRQ(ierr); /* v_old <- 0 */
72
ierr = VecCopy(UOLD,W);CHKERRQ(ierr); /* w <- 0 */
73
ierr = VecCopy(UOLD,WOLD);CHKERRQ(ierr); /* w_old <- 0 */
75
if (!ksp->guess_zero) {
76
ierr = KSP_MatMult(ksp,Amat,X,R);CHKERRQ(ierr); /* r <- b - A*x */
77
ierr = VecAYPX(&mone,B,R);CHKERRQ(ierr);
79
ierr = VecCopy(B,R);CHKERRQ(ierr); /* r <- b (x is 0) */
82
ierr = KSP_PCApply(ksp,ksp->B,R,Z);CHKERRQ(ierr); /* z <- B*r */
84
ierr = VecDot(R,Z,&dp);CHKERRQ(ierr);
85
if (PetscAbsScalar(dp) < minres->haptol) {
86
PetscLogInfo(ksp,"KSPSolve_MINRES:Detected happy breakdown %g tolerance %g\n",PetscAbsScalar(dp),minres->haptol);
87
dp = PetscAbsScalar(dp); /* tiny number, can't use 0.0, cause divided by below */
89
ksp->reason = KSP_CONVERGED_ATOL;
91
PetscFunctionReturn(0);
95
#if !defined(PETSC_USE_COMPLEX)
96
if (dp < 0.0) SETERRQ(PETSC_ERR_KSP_BRKDWN,"Indefinite preconditioner");
98
dp = PetscSqrtScalar(dp);
99
beta = dp; /* beta <- sqrt(r'*z */
102
ierr = VecCopy(R,V);CHKERRQ(ierr);
103
ierr = VecCopy(Z,U);CHKERRQ(ierr);
105
ierr = VecScale(&ibeta,V);CHKERRQ(ierr); /* v <- r / beta */
106
ierr = VecScale(&ibeta,U);CHKERRQ(ierr); /* u <- z / beta */
108
ierr = VecNorm(Z,NORM_2,&np);CHKERRQ(ierr); /* np <- ||z|| */
110
ierr = (*ksp->converged)(ksp,0,np,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); /* test for convergence */
111
if (ksp->reason) {*its = 0; PetscFunctionReturn(0);}
112
KSPLogResidualHistory(ksp,np);
113
KSPMonitor(ksp,0,np); /* call any registered monitor routines */
116
for (i=0; i<maxit; i++) {
121
ierr = KSP_MatMult(ksp,Amat,U,R);CHKERRQ(ierr); /* r <- A*u */
122
ierr = VecDot(U,R,&alpha);CHKERRQ(ierr); /* alpha <- r'*u */
123
ierr = KSP_PCApply(ksp,ksp->B,R,Z);CHKERRQ(ierr); /* z <- B*r */
126
ierr = VecAXPY(&malpha,V,R);CHKERRQ(ierr); /* r <- r - alpha v */
127
ierr = VecAXPY(&malpha,U,Z);CHKERRQ(ierr); /* z <- z - alpha u */
129
ierr = VecAXPY(&mbeta,VOLD,R);CHKERRQ(ierr); /* r <- r - beta v_old */
130
ierr = VecAXPY(&mbeta,UOLD,Z);CHKERRQ(ierr); /* z <- z - beta u_old */
134
ierr = VecDot(R,Z,&dp);CHKERRQ(ierr);
135
if (PetscAbsScalar(dp) < minres->haptol) {
136
PetscLogInfo(ksp,"KSPSolve_MINRES:Detected happy breakdown %g tolerance %g\n",PetscAbsScalar(dp),minres->haptol);
137
dp = PetscAbsScalar(dp); /* tiny number, can we use 0.0? */
140
#if !defined(PETSC_USE_COMPLEX)
141
if (dp < 0.0) SETERRQ1(PETSC_ERR_KSP_BRKDWN,"Indefinite preconditioner R'Z = %g",dp);
143
beta = PetscSqrtScalar(dp); /* beta <- sqrt(r'*z) */
145
/* QR factorisation */
147
coold = cold; cold = c; soold = sold; sold = s;
149
rho0 = cold * alpha - coold * sold * betaold;
150
rho1 = PetscSqrtScalar(rho0*rho0 + beta*beta);
151
rho2 = sold * alpha + coold * cold * betaold;
152
rho3 = soold * betaold;
154
/* Givens rotation */
161
ierr = VecCopy(WOLD,WOOLD);CHKERRQ(ierr); /* w_oold <- w_old */
162
ierr = VecCopy(W,WOLD);CHKERRQ(ierr); /* w_old <- w */
164
ierr = VecCopy(U,W);CHKERRQ(ierr); /* w <- u */
166
ierr = VecAXPY(&mrho2,WOLD,W);CHKERRQ(ierr); /* w <- w - rho2 w_old */
168
ierr = VecAXPY(&mrho3,WOOLD,W);CHKERRQ(ierr); /* w <- w - rho3 w_oold */
170
ierr = VecScale(&irho1,W);CHKERRQ(ierr); /* w <- w / rho1 */
173
ierr = VecAXPY(&ceta,W,X);CHKERRQ(ierr); /* x <- x + c eta w */
176
ierr = VecCopy(V,VOLD);CHKERRQ(ierr);
177
ierr = VecCopy(U,UOLD);CHKERRQ(ierr);
178
ierr = VecCopy(R,V);CHKERRQ(ierr);
179
ierr = VecCopy(Z,U);CHKERRQ(ierr);
181
ierr = VecScale(&ibeta,V);CHKERRQ(ierr); /* v <- r / beta */
182
ierr = VecScale(&ibeta,U);CHKERRQ(ierr); /* u <- z / beta */
184
np = ksp->rnorm * PetscAbsScalar(s);
187
KSPLogResidualHistory(ksp,np);
188
KSPMonitor(ksp,i+1,np);
189
ierr = (*ksp->converged)(ksp,i+1,np,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); /* test for convergence */
190
if (ksp->reason) break;
193
ksp->reason = KSP_DIVERGED_ITS;
196
PetscFunctionReturn(0);
201
#define __FUNCT__ "KSPCreate_MINRES"
202
int KSPCreate_MINRES(KSP ksp)
209
ksp->pc_side = PC_LEFT;
210
ierr = PetscNew(KSP_MINRES,&minres);CHKERRQ(ierr);
211
minres->haptol = 1.e-18;
212
ksp->data = (void*)minres;
215
Sets the functions that are associated with this data structure
216
(in C++ this is the same as defining virtual functions)
218
ksp->ops->setup = KSPSetUp_MINRES;
219
ksp->ops->solve = KSPSolve_MINRES;
220
ksp->ops->destroy = KSPDefaultDestroy;
221
ksp->ops->setfromoptions = 0;
222
ksp->ops->buildsolution = KSPDefaultBuildSolution;
223
ksp->ops->buildresidual = KSPDefaultBuildResidual;
225
PetscFunctionReturn(0);