xref: /petsc/src/ksp/ksp/impls/symmlq/symmlq.c (revision b122ec5aa1bd4469eb4e0673542fb7de3f411254)
1 
2 #include <petsc/private/kspimpl.h>
3 
4 typedef struct {
5   PetscReal haptol;
6 } KSP_SYMMLQ;
7 
8 PetscErrorCode KSPSetUp_SYMMLQ(KSP ksp)
9 {
10   PetscFunctionBegin;
11   CHKERRQ(KSPSetWorkVecs(ksp,9));
12   PetscFunctionReturn(0);
13 }
14 
15 PetscErrorCode  KSPSolve_SYMMLQ(KSP ksp)
16 {
17   PetscInt       i;
18   PetscScalar    alpha,beta,ibeta,betaold,beta1,ceta = 0,ceta_oold = 0.0, ceta_old = 0.0,ceta_bar;
19   PetscScalar    c  = 1.0,cold=1.0,s=0.0,sold=0.0,coold,soold,rho0,rho1,rho2,rho3;
20   PetscScalar    dp = 0.0;
21   PetscReal      np = 0.0,s_prod;
22   Vec            X,B,R,Z,U,V,W,UOLD,VOLD,Wbar;
23   Mat            Amat,Pmat;
24   KSP_SYMMLQ     *symmlq = (KSP_SYMMLQ*)ksp->data;
25   PetscBool      diagonalscale;
26 
27   PetscFunctionBegin;
28   CHKERRQ(PCGetDiagonalScale(ksp->pc,&diagonalscale));
29   PetscCheck(!diagonalscale,PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
30 
31   X    = ksp->vec_sol;
32   B    = ksp->vec_rhs;
33   R    = ksp->work[0];
34   Z    = ksp->work[1];
35   U    = ksp->work[2];
36   V    = ksp->work[3];
37   W    = ksp->work[4];
38   UOLD = ksp->work[5];
39   VOLD = ksp->work[6];
40   Wbar = ksp->work[7];
41 
42   CHKERRQ(PCGetOperators(ksp->pc,&Amat,&Pmat));
43 
44   ksp->its = 0;
45 
46   CHKERRQ(VecSet(UOLD,0.0));           /* u_old <- zeros;  */
47   CHKERRQ(VecCopy(UOLD,VOLD));          /* v_old <- u_old;  */
48   CHKERRQ(VecCopy(UOLD,W));             /* w     <- u_old;  */
49   CHKERRQ(VecCopy(UOLD,Wbar));          /* w_bar <- u_old;  */
50   if (!ksp->guess_zero) {
51     CHKERRQ(KSP_MatMult(ksp,Amat,X,R)); /*     r <- b - A*x */
52     CHKERRQ(VecAYPX(R,-1.0,B));
53   } else {
54     CHKERRQ(VecCopy(B,R));              /*     r <- b (x is 0) */
55   }
56 
57   CHKERRQ(KSP_PCApply(ksp,R,Z)); /* z  <- B*r       */
58   CHKERRQ(VecDot(R,Z,&dp));             /* dp = r'*z;      */
59   KSPCheckDot(ksp,dp);
60   if (PetscAbsScalar(dp) < symmlq->haptol) {
61     CHKERRQ(PetscInfo(ksp,"Detected happy breakdown %g tolerance %g\n",(double)PetscAbsScalar(dp),(double)symmlq->haptol));
62     ksp->rnorm  = 0.0;  /* what should we really put here? */
63     ksp->reason = KSP_CONVERGED_HAPPY_BREAKDOWN;  /* bugfix proposed by Lourens (lourens.vanzanen@shell.com) */
64     PetscFunctionReturn(0);
65   }
66 
67 #if !defined(PETSC_USE_COMPLEX)
68   if (dp < 0.0) {
69     ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
70     PetscFunctionReturn(0);
71   }
72 #endif
73   dp     = PetscSqrtScalar(dp);
74   beta   = dp;                         /*  beta <- sqrt(r'*z)  */
75   beta1  = beta;
76   s_prod = PetscAbsScalar(beta1);
77 
78   CHKERRQ(VecCopy(R,V)); /* v <- r; */
79   CHKERRQ(VecCopy(Z,U)); /* u <- z; */
80   ibeta = 1.0 / beta;
81   CHKERRQ(VecScale(V,ibeta));    /* v <- ibeta*v; */
82   CHKERRQ(VecScale(U,ibeta));    /* u <- ibeta*u; */
83   CHKERRQ(VecCopy(U,Wbar));       /* w_bar <- u;   */
84   if (ksp->normtype != KSP_NORM_NONE) {
85     CHKERRQ(VecNorm(Z,NORM_2,&np));     /*   np <- ||z||        */
86     KSPCheckNorm(ksp,np);
87   }
88   CHKERRQ(KSPLogResidualHistory(ksp,np));
89   CHKERRQ(KSPMonitor(ksp,0,np));
90   ksp->rnorm = np;
91   CHKERRQ((*ksp->converged)(ksp,0,np,&ksp->reason,ksp->cnvP)); /* test for convergence */
92   if (ksp->reason) PetscFunctionReturn(0);
93 
94   i = 0; ceta = 0.;
95   do {
96     ksp->its = i+1;
97 
98     /*    Update    */
99     if (ksp->its > 1) {
100       CHKERRQ(VecCopy(V,VOLD));  /* v_old <- v; */
101       CHKERRQ(VecCopy(U,UOLD));  /* u_old <- u; */
102 
103       CHKERRQ(VecCopy(R,V));
104       CHKERRQ(VecScale(V,1.0/beta)); /* v <- ibeta*r; */
105       CHKERRQ(VecCopy(Z,U));
106       CHKERRQ(VecScale(U,1.0/beta)); /* u <- ibeta*z; */
107 
108       CHKERRQ(VecCopy(Wbar,W));
109       CHKERRQ(VecScale(W,c));
110       CHKERRQ(VecAXPY(W,s,U));   /* w  <- c*w_bar + s*u;    (w_k) */
111       CHKERRQ(VecScale(Wbar,-s));
112       CHKERRQ(VecAXPY(Wbar,c,U)); /* w_bar <- -s*w_bar + c*u; (w_bar_(k+1)) */
113       CHKERRQ(VecAXPY(X,ceta,W)); /* x <- x + ceta * w;       (xL_k)  */
114 
115       ceta_oold = ceta_old;
116       ceta_old  = ceta;
117     }
118 
119     /*   Lanczos  */
120     CHKERRQ(KSP_MatMult(ksp,Amat,U,R));   /*  r     <- Amat*u; */
121     CHKERRQ(VecDot(U,R,&alpha));          /*  alpha <- u'*r;   */
122     CHKERRQ(KSP_PCApply(ksp,R,Z)); /*      z <- B*r;    */
123 
124     CHKERRQ(VecAXPY(R,-alpha,V));   /*  r <- r - alpha* v;  */
125     CHKERRQ(VecAXPY(Z,-alpha,U));   /*  z <- z - alpha* u;  */
126     CHKERRQ(VecAXPY(R,-beta,VOLD)); /*  r <- r - beta * v_old; */
127     CHKERRQ(VecAXPY(Z,-beta,UOLD)); /*  z <- z - beta * u_old; */
128     betaold = beta;                                /* beta_k                  */
129     CHKERRQ(VecDot(R,Z,&dp));       /* dp <- r'*z;             */
130     KSPCheckDot(ksp,dp);
131     if (PetscAbsScalar(dp) < symmlq->haptol) {
132       CHKERRQ(PetscInfo(ksp,"Detected happy breakdown %g tolerance %g\n",(double)PetscAbsScalar(dp),(double)symmlq->haptol));
133       dp   = 0.0;
134     }
135 
136 #if !defined(PETSC_USE_COMPLEX)
137     if (dp < 0.0) {
138       ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
139       break;
140     }
141 #endif
142     beta = PetscSqrtScalar(dp);                    /*  beta = sqrt(dp); */
143 
144     /*    QR factorization    */
145     coold = cold; cold = c; soold = sold; sold = s;
146     rho0  = cold * alpha - coold * sold * betaold;   /* gamma_bar */
147     rho1  = PetscSqrtScalar(rho0*rho0 + beta*beta);  /* gamma     */
148     rho2  = sold * alpha + coold * cold * betaold;   /* delta     */
149     rho3  = soold * betaold;                         /* epsilon   */
150 
151     /* Givens rotation: [c -s; s c] (different from the Reference!) */
152     c = rho0 / rho1; s = beta / rho1;
153 
154     if (ksp->its==1) ceta = beta1/rho1;
155     else ceta = -(rho2*ceta_old + rho3*ceta_oold)/rho1;
156 
157     s_prod = s_prod*PetscAbsScalar(s);
158     if (c == 0.0) np = s_prod*1.e16;
159     else np = s_prod/PetscAbsScalar(c);       /* residual norm for xc_k (CGNORM) */
160 
161     if (ksp->normtype != KSP_NORM_NONE) ksp->rnorm = np;
162     else ksp->rnorm = 0.0;
163     CHKERRQ(KSPLogResidualHistory(ksp,ksp->rnorm));
164     CHKERRQ(KSPMonitor(ksp,i+1,ksp->rnorm));
165     CHKERRQ((*ksp->converged)(ksp,i+1,ksp->rnorm,&ksp->reason,ksp->cnvP)); /* test for convergence */
166     if (ksp->reason) break;
167     i++;
168   } while (i<ksp->max_it);
169 
170   /* move to the CG point: xc_(k+1) */
171   if (c == 0.0) ceta_bar = ceta*1.e15;
172   else ceta_bar = ceta/c;
173 
174   CHKERRQ(VecAXPY(X,ceta_bar,Wbar)); /* x <- x + ceta_bar*w_bar */
175 
176   if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
177   PetscFunctionReturn(0);
178 }
179 
180 /*MC
181      KSPSYMMLQ -  This code implements the SYMMLQ method.
182 
183    Options Database Keys:
184     see KSPSolve()
185 
186    Level: beginner
187 
188    Notes:
189     The operator and the preconditioner must be symmetric for this method. The
190           preconditioner must be POSITIVE-DEFINITE.
191 
192           Supports only left preconditioning.
193 
194    Reference: Paige & Saunders, 1975.
195 
196 .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP
197 M*/
198 PETSC_EXTERN PetscErrorCode KSPCreate_SYMMLQ(KSP ksp)
199 {
200   KSP_SYMMLQ     *symmlq;
201 
202   PetscFunctionBegin;
203   CHKERRQ(KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,3));
204   CHKERRQ(KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1));
205 
206   CHKERRQ(PetscNewLog(ksp,&symmlq));
207   symmlq->haptol = 1.e-18;
208   ksp->data      = (void*)symmlq;
209 
210   /*
211        Sets the functions that are associated with this data structure
212        (in C++ this is the same as defining virtual functions)
213   */
214   ksp->ops->setup          = KSPSetUp_SYMMLQ;
215   ksp->ops->solve          = KSPSolve_SYMMLQ;
216   ksp->ops->destroy        = KSPDestroyDefault;
217   ksp->ops->setfromoptions = NULL;
218   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
219   ksp->ops->buildresidual  = KSPBuildResidualDefault;
220   PetscFunctionReturn(0);
221 }
222