Grid 0.7.0
MobiusEOFAFermionImplementation.h
Go to the documentation of this file.
1/*************************************************************************************
2
3Grid physics library, www.github.com/paboyle/Grid
4
5Source file: ./lib/qcd/action/fermion/MobiusEOFAFermion.cc
6
7Copyright (C) 2017
8
9Author: Peter Boyle <pabobyle@ph.ed.ac.uk>
10Author: Peter Boyle <paboyle@ph.ed.ac.uk>
11Author: Peter Boyle <peterboyle@Peters-MacBook-Pro-2.local>
12Author: paboyle <paboyle@ph.ed.ac.uk>
13Author: David Murphy <dmurphy@phys.columbia.edu>
14
15This program is free software; you can redistribute it and/or modify
16it under the terms of the GNU General Public License as published by
17the Free Software Foundation; either version 2 of the License, or
18(at your option) any later version.
19
20This program is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23GNU General Public License for more details.
24
25You should have received a copy of the GNU General Public License along
26with this program; if not, write to the Free Software Foundation, Inc.,
2751 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28
29See the full license in the file "LICENSE" in the top level distribution directory
30*************************************************************************************/
31 /* END LEGAL */
32
33#pragma once
34
37
39
40template<class Impl>
42 GaugeField &_Umu,
43 GridCartesian &FiveDimGrid,
44 GridRedBlackCartesian &FiveDimRedBlackGrid,
45 GridCartesian &FourDimGrid,
46 GridRedBlackCartesian &FourDimRedBlackGrid,
47 RealD _mq1, RealD _mq2, RealD _mq3,
48 RealD _shift, int _pm, RealD _M5,
49 RealD _b, RealD _c, const ImplParams &p) :
50 AbstractEOFAFermion<Impl>(_Umu, FiveDimGrid, FiveDimRedBlackGrid,
51 FourDimGrid, FourDimRedBlackGrid, _mq1, _mq2, _mq3,
52 _shift, _pm, _M5, _b, _c, p)
53{
54 int Ls = this->Ls;
55
56 RealD eps = 1.0;
57 Approx::zolotarev_data *zdata = Approx::higham(eps, this->Ls);
58 assert(zdata->n == this->Ls);
59
60 std::cout << GridLogMessage << "MobiusEOFAFermion (b=" << _b <<
61 ",c=" << _c << ") with Ls=" << Ls << std::endl;
62 this->SetCoefficientsTanh(zdata, _b, _c);
63 std::cout << GridLogMessage << "EOFA parameters: (mq1=" << _mq1 <<
64 ",mq2=" << _mq2 << ",mq3=" << _mq3 << ",shift=" << _shift <<
65 ",pm=" << _pm << ")" << std::endl;
66
67 Approx::zolotarev_free(zdata);
68
69 if(_shift != 0.0){
71 } else {
72 Mooee_shift.resize(Ls, 0.0);
73 MooeeInv_shift_lc.resize(Ls, 0.0);
74 MooeeInv_shift_norm.resize(Ls, 0.0);
75 MooeeInvDag_shift_lc.resize(Ls, 0.0);
76 MooeeInvDag_shift_norm.resize(Ls, 0.0);
77 }
78}
79
80/****************************************************************
81 * Additional EOFA operators only called outside the inverter.
82 * Since speed is not essential, simple axpby-style
83 * implementations should be fine.
84 ***************************************************************/
85template<class Impl>
86void MobiusEOFAFermion<Impl>::Omega(const FermionField& psi, FermionField& Din, int sign, int dag)
87{
88 int Ls = this->Ls;
89 RealD alpha = this->alpha;
90
91 Din = Zero();
92 if((sign == 1) && (dag == 0)) { // \Omega_{+}
93 for(int s=0; s<Ls; ++s){
94 axpby_ssp(Din, 0.0, psi, 2.0*std::pow(1.0-alpha,Ls-s-1)/std::pow(1.0+alpha,Ls-s), psi, s, 0);
95 }
96 } else if((sign == -1) && (dag == 0)) { // \Omega_{-}
97 for(int s=0; s<Ls; ++s){
98 axpby_ssp(Din, 0.0, psi, 2.0*std::pow(1.0-alpha,s)/std::pow(1.0+alpha,s+1), psi, s, 0);
99 }
100 } else if((sign == 1 ) && (dag == 1)) { // \Omega_{+}^{\dagger}
101 for(int sp=0; sp<Ls; ++sp){
102 axpby_ssp(Din, 1.0, Din, 2.0*std::pow(1.0-alpha,Ls-sp-1)/std::pow(1.0+alpha,Ls-sp), psi, 0, sp);
103 }
104 } else if((sign == -1) && (dag == 1)) { // \Omega_{-}^{\dagger}
105 for(int sp=0; sp<Ls; ++sp){
106 axpby_ssp(Din, 1.0, Din, 2.0*std::pow(1.0-alpha,sp)/std::pow(1.0+alpha,sp+1), psi, 0, sp);
107 }
108 }
109}
110
111// This is the operator relating the usual Ddwf to TWQCD's EOFA Dirac operator (arXiv:1706.05843, Eqn. 6).
112// It also relates the preconditioned and unpreconditioned systems described in Appendix B.2.
113template<class Impl>
114void MobiusEOFAFermion<Impl>::Dtilde(const FermionField& psi, FermionField& chi)
115{
116 int Ls = this->Ls;
117 RealD b = 0.5 * ( 1.0 + this->alpha );
118 RealD c = 0.5 * ( 1.0 - this->alpha );
119 RealD mq1 = this->mq1;
120
121 for(int s=0; s<Ls; ++s){
122 if(s == 0) {
123 axpby_ssp_pminus(chi, b, psi, -c, psi, s, s+1);
124 axpby_ssp_pplus (chi, 1.0, chi, mq1*c, psi, s, Ls-1);
125 } else if(s == (Ls-1)) {
126 axpby_ssp_pminus(chi, b, psi, mq1*c, psi, s, 0);
127 axpby_ssp_pplus (chi, 1.0, chi, -c, psi, s, s-1);
128 } else {
129 axpby_ssp_pminus(chi, b, psi, -c, psi, s, s+1);
130 axpby_ssp_pplus (chi, 1.0, chi, -c, psi, s, s-1);
131 }
132 }
133}
134
135template<class Impl>
136void MobiusEOFAFermion<Impl>::DtildeInv(const FermionField& psi, FermionField& chi)
137{
138 int Ls = this->Ls;
139 RealD m = this->mq1;
140 RealD c = 0.5 * this->alpha;
141 RealD d = 0.5;
142
143 RealD DtInv_p(0.0), DtInv_m(0.0);
144 RealD N = std::pow(c+d,Ls) + m*std::pow(c-d,Ls);
145 FermionField tmp(this->FermionGrid());
146
147 for(int s=0; s<Ls; ++s){
148 for(int sp=0; sp<Ls; ++sp){
149
150 DtInv_p = m * std::pow(-1.0,s-sp+1) * std::pow(c-d,Ls+s-sp) / std::pow(c+d,s-sp+1) / N;
151 DtInv_p += (s < sp) ? 0.0 : std::pow(-1.0,s-sp) * std::pow(c-d,s-sp) / std::pow(c+d,s-sp+1);
152 DtInv_m = m * std::pow(-1.0,sp-s+1) * std::pow(c-d,Ls+sp-s) / std::pow(c+d,sp-s+1) / N;
153 DtInv_m += (s > sp) ? 0.0 : std::pow(-1.0,sp-s) * std::pow(c-d,sp-s) / std::pow(c+d,sp-s+1);
154
155 if(sp == 0){
156 axpby_ssp_pplus (tmp, 0.0, tmp, DtInv_p, psi, s, sp);
157 axpby_ssp_pminus(tmp, 0.0, tmp, DtInv_m, psi, s, sp);
158 } else {
159 axpby_ssp_pplus (tmp, 1.0, tmp, DtInv_p, psi, s, sp);
160 axpby_ssp_pminus(tmp, 1.0, tmp, DtInv_m, psi, s, sp);
161 }
162
163 }}
164}
165
166/*****************************************************************************************************/
167
168template<class Impl>
169void MobiusEOFAFermion<Impl>::M(const FermionField& psi, FermionField& chi)
170{
171 FermionField Din(psi.Grid());
172
173 this->Meooe5D(psi, Din);
174 this->DW(Din, chi, DaggerNo);
175 axpby(chi, 1.0, 1.0, chi, psi);
176 this->M5D(psi, chi);
177}
178
179template<class Impl>
180void MobiusEOFAFermion<Impl>::Mdag(const FermionField& psi, FermionField& chi)
181{
182 FermionField Din(psi.Grid());
183
184 this->DW(psi, Din, DaggerYes);
185 this->MeooeDag5D(Din, chi);
186 this->M5Ddag(psi, chi);
187 axpby(chi, 1.0, 1.0, chi, psi);
188}
189
190/********************************************************************
191 * Performance critical fermion operators called inside the inverter
192 ********************************************************************/
193
194template<class Impl>
195void MobiusEOFAFermion<Impl>::M5D(const FermionField& psi, FermionField& chi)
196{
197 int Ls = this->Ls;
198
199 std::vector<Coeff_t> diag(Ls,1.0);
200 std::vector<Coeff_t> upper(Ls,-1.0); upper[Ls-1] = this->mq1;
201 std::vector<Coeff_t> lower(Ls,-1.0); lower[0] = this->mq1;
202
203 // no shift term
204 if(this->shift == 0.0){ this->M5D(psi, chi, chi, lower, diag, upper); }
205
206 // fused M + shift operation
207 else{ this->M5D_shift(psi, chi, chi, lower, diag, upper, Mooee_shift); }
208}
209
210template<class Impl>
211void MobiusEOFAFermion<Impl>::M5Ddag(const FermionField& psi, FermionField& chi)
212{
213 int Ls = this->Ls;
214
215 std::vector<Coeff_t> diag(Ls,1.0);
216 std::vector<Coeff_t> upper(Ls,-1.0); upper[Ls-1] = this->mq1;
217 std::vector<Coeff_t> lower(Ls,-1.0); lower[0] = this->mq1;
218
219 // no shift term
220 if(this->shift == 0.0){ this->M5Ddag(psi, chi, chi, lower, diag, upper); }
221
222 // fused M + shift operation
223 else{ this->M5Ddag_shift(psi, chi, chi, lower, diag, upper, Mooee_shift); }
224}
225
226// half checkerboard operations
227template<class Impl>
228void MobiusEOFAFermion<Impl>::Mooee(const FermionField& psi, FermionField& chi)
229{
230 int Ls = this->Ls;
231
232 // coefficients of Mooee
233 std::vector<Coeff_t> diag = this->bee;
234 std::vector<Coeff_t> upper(Ls);
235 std::vector<Coeff_t> lower(Ls);
236 for(int s=0; s<Ls; s++){
237 upper[s] = -this->cee[s];
238 lower[s] = -this->cee[s];
239 }
240 upper[Ls-1] *= -this->mq1;
241 lower[0] *= -this->mq1;
242
243 // no shift term
244 if(this->shift == 0.0){ this->M5D(psi, psi, chi, lower, diag, upper); }
245
246 // fused M + shift operation
247 else { this->M5D_shift(psi, psi, chi, lower, diag, upper, Mooee_shift); }
248}
249
250template<class Impl>
251void MobiusEOFAFermion<Impl>::MooeeDag(const FermionField& psi, FermionField& chi)
252{
253 int Ls = this->Ls;
254
255 // coefficients of MooeeDag
256 std::vector<Coeff_t> diag = this->bee;
257 std::vector<Coeff_t> upper(Ls);
258 std::vector<Coeff_t> lower(Ls);
259 for(int s=0; s<Ls; s++){
260 if(s==0) {
261 upper[s] = -this->cee[s+1];
262 lower[s] = this->mq1*this->cee[Ls-1];
263 } else if(s==(Ls-1)) {
264 upper[s] = this->mq1*this->cee[0];
265 lower[s] = -this->cee[s-1];
266 } else {
267 upper[s] = -this->cee[s+1];
268 lower[s] = -this->cee[s-1];
269 }
270 }
271
272 // no shift term
273 if(this->shift == 0.0){ this->M5Ddag(psi, psi, chi, lower, diag, upper); }
274
275 // fused M + shift operation
276 else{ this->M5Ddag_shift(psi, psi, chi, lower, diag, upper, Mooee_shift); }
277}
278
279/****************************************************************************************/
280
281// Computes coefficients for applying Cayley preconditioned shift operators
282// (Mooee + \Delta) --> Mooee_shift
283// (Mooee + \Delta)^{-1} --> MooeeInv_shift_lc, MooeeInv_shift_norm
284// (Mooee + \Delta)^{-dag} --> MooeeInvDag_shift_lc, MooeeInvDag_shift_norm
285// For the latter two cases, the operation takes the form
286// [ (Mooee + \Delta)^{-1} \psi ]_{i} = Mooee_{ij} \psi_{j} +
287// ( MooeeInv_shift_norm )_{i} ( \sum_{j} [ MooeeInv_shift_lc ]_{j} P_{pm} \psi_{j} )
288template<class Impl>
290{
291 int Ls = this->Ls;
292 int pm = this->pm;
293 RealD alpha = this->alpha;
294 RealD k = this->k;
295 RealD mq1 = this->mq1;
296 RealD shift = this->shift;
297
298 // Initialize
299 Mooee_shift.resize(Ls);
300 MooeeInv_shift_lc.resize(Ls);
301 MooeeInv_shift_norm.resize(Ls);
302 MooeeInvDag_shift_lc.resize(Ls);
304
305 // Construct Mooee_shift
306 int idx(0);
307 Coeff_t N = ( (pm == 1) ? 1.0 : -1.0 ) * (2.0*shift*k) *
308 ( std::pow(alpha+1.0,Ls) + mq1*std::pow(alpha-1.0,Ls) );
309 for(int s=0; s<Ls; ++s){
310 idx = (pm == 1) ? (s) : (Ls-1-s);
311 Mooee_shift[idx] = N * std::pow(-1.0,s) * std::pow(alpha-1.0,s) / std::pow(alpha+1.0,Ls+s+1);
312 }
313
314 // Tridiagonal solve for MooeeInvDag_shift_lc
315 {
316 Coeff_t m(0.0);
317 std::vector<Coeff_t> d = Mooee_shift;
318 std::vector<Coeff_t> u(Ls,0.0);
319 std::vector<Coeff_t> y(Ls,0.0);
320 std::vector<Coeff_t> q(Ls,0.0);
321 if(pm == 1){ u[0] = 1.0; }
322 else{ u[Ls-1] = 1.0; }
323
324 // Tridiagonal matrix algorithm + Sherman-Morrison formula
325 //
326 // We solve
327 // ( Mooee' + u \otimes v ) MooeeInvDag_shift_lc = Mooee_shift
328 // where Mooee' is the tridiagonal part of Mooee_{+}, and
329 // u = (1,0,...,0) and v = (0,...,0,mq1*cee[0]) are chosen
330 // so that the outer-product u \otimes v gives the (0,Ls-1)
331 // entry of Mooee_{+}.
332 //
333 // We do this as two solves: Mooee'*y = d and Mooee'*q = u,
334 // and then construct the solution to the original system
335 // MooeeInvDag_shift_lc = y - <v,y> / ( 1 + <v,q> ) q
336 if(pm == 1){
337 for(int s=1; s<Ls; ++s){
338 m = -this->cee[s] / this->bee[s-1];
339 d[s] -= m*d[s-1];
340 u[s] -= m*u[s-1];
341 }
342 }
343 y[Ls-1] = d[Ls-1] / this->bee[Ls-1];
344 q[Ls-1] = u[Ls-1] / this->bee[Ls-1];
345 for(int s=Ls-2; s>=0; --s){
346 if(pm == 1){
347 y[s] = d[s] / this->bee[s];
348 q[s] = u[s] / this->bee[s];
349 } else {
350 y[s] = ( d[s] + this->cee[s]*y[s+1] ) / this->bee[s];
351 q[s] = ( u[s] + this->cee[s]*q[s+1] ) / this->bee[s];
352 }
353 }
354
355 // Construct MooeeInvDag_shift_lc
356 for(int s=0; s<Ls; ++s){
357 if(pm == 1){
358 MooeeInvDag_shift_lc[s] = y[s] - mq1*this->cee[0]*y[Ls-1] /
359 (1.0+mq1*this->cee[0]*q[Ls-1]) * q[s];
360 } else {
361 MooeeInvDag_shift_lc[s] = y[s] - mq1*this->cee[Ls-1]*y[0] /
362 (1.0+mq1*this->cee[Ls-1]*q[0]) * q[s];
363 }
364 }
365
366 // Compute remaining coefficients
367 N = (pm == 1) ? (1.0 + MooeeInvDag_shift_lc[Ls-1]) : (1.0 + MooeeInvDag_shift_lc[0]);
368 for(int s=0; s<Ls; ++s){
369
370 // MooeeInv_shift_lc
371 if(pm == 1){ MooeeInv_shift_lc[s] = pow(this->bee[s],s) * pow(this->cee[s],Ls-1-s); }
372 else { MooeeInv_shift_lc[s] = pow(this->bee[s],Ls-1-s) * pow(this->cee[s],s); }
373
374 // MooeeInv_shift_norm
376 ( pow(this->bee[s],Ls) + mq1*pow(this->cee[s],Ls) ) / N;
377
378 // MooeeInvDag_shift_norm
379 if(pm == 1){ MooeeInvDag_shift_norm[s] = -pow(this->bee[s],s) * pow(this->cee[s],(Ls-1-s)) /
380 ( pow(this->bee[s],Ls) + mq1*pow(this->cee[s],Ls) ) / N; }
381 else{ MooeeInvDag_shift_norm[s] = -pow(this->bee[s],(Ls-1-s)) * pow(this->cee[s],s) /
382 ( pow(this->bee[s],Ls) + mq1*pow(this->cee[s],Ls) ) / N; }
383 }
384 }
385}
386
387// Recompute coefficients for a different value of shift constant
388template<class Impl>
390{
391 this->shift = new_shift;
392 if(new_shift != 0.0){
394 } else {
395 int Ls = this->Ls;
396 Mooee_shift.resize(Ls,0.0);
397 MooeeInv_shift_lc.resize(Ls,0.0);
398 MooeeInv_shift_norm.resize(Ls,0.0);
399 MooeeInvDag_shift_lc.resize(Ls,0.0);
400 MooeeInvDag_shift_norm.resize(Ls,0.0);
401 }
402}
403
404
void axpby(Lattice< vobj > &ret, sobj a, sobj b, const Lattice< vobj > &x, const Lattice< vobj > &y)
Lattice< obj > pow(const Lattice< obj > &rhs_i, RealD y)
void axpby_ssp_pplus(Lattice< vobj > &z, Coeff a, const Lattice< vobj > &x, Coeff b, const Lattice< vobj > &y, int s, int sp)
void axpby_ssp_pminus(Lattice< vobj > &z, Coeff a, const Lattice< vobj > &x, Coeff b, const Lattice< vobj > &y, int s, int sp)
void axpby_ssp(Lattice< vobj > &z, Coeff a, const Lattice< vobj > &x, Coeff b, const Lattice< vobj > &y, int s, int sp)
Definition LinalgUtils.h:59
GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL")
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
static constexpr int DaggerYes
Definition QCD.h:70
static constexpr int DaggerNo
Definition QCD.h:69
double RealD
Definition Simd.h:61
AbstractEOFAFermion(GaugeField &_Umu, GridCartesian &FiveDimGrid, GridRedBlackCartesian &FiveDimRedBlackGrid, GridCartesian &FourDimGrid, GridRedBlackCartesian &FourDimRedBlackGrid, RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int _pm, RealD _M5, RealD _b, RealD _c, const ImplParams &p=ImplParams())
void Meooe5D(const FermionField &in, FermionField &out)
std::vector< Coeff_t > bee
void MeooeDag5D(const FermionField &in, FermionField &out)
virtual void SetCoefficientsTanh(Approx::zolotarev_data *zdata, RealD b, RealD c)
std::vector< Coeff_t > cee
virtual void DtildeInv(const FermionField &in, FermionField &out)
void M5Ddag_shift(const FermionField &psi, const FermionField &phi, FermionField &chi, std::vector< Coeff_t > &lower, std::vector< Coeff_t > &diag, std::vector< Coeff_t > &upper, std::vector< Coeff_t > &shift_coeffs)
MobiusEOFAFermion(GaugeField &_Umu, GridCartesian &FiveDimGrid, GridRedBlackCartesian &FiveDimRedBlackGrid, GridCartesian &FourDimGrid, GridRedBlackCartesian &FourDimRedBlackGrid, RealD _mq1, RealD _mq2, RealD _mq3, RealD _shift, int pm, RealD _M5, RealD _b, RealD _c, const ImplParams &p=ImplParams())
std::vector< Coeff_t > MooeeInv_shift_lc
std::vector< Coeff_t > MooeeInv_shift_norm
std::vector< Coeff_t > MooeeInvDag_shift_lc
virtual void Omega(const FermionField &in, FermionField &out, int sign, int dag)
virtual void Mooee(const FermionField &in, FermionField &out)
std::vector< Coeff_t > MooeeInvDag_shift_norm
virtual void MooeeDag(const FermionField &in, FermionField &out)
virtual void Mdag(const FermionField &in, FermionField &out)
virtual void Dtilde(const FermionField &in, FermionField &out)
virtual void RefreshShiftCoefficients(RealD new_shift)
virtual void M(const FermionField &in, FermionField &out)
virtual void M5D(const FermionField &psi, FermionField &chi)
std::vector< Coeff_t > Mooee_shift
virtual void M5Ddag(const FermionField &psi, FermionField &chi)
void M5D_shift(const FermionField &psi, const FermionField &phi, FermionField &chi, std::vector< Coeff_t > &lower, std::vector< Coeff_t > &diag, std::vector< Coeff_t > &upper, std::vector< Coeff_t > &shift_coeffs)
FermionField & tmp(void)
GridBase * FermionGrid(void)
void DW(const FermionField &in, FermionField &out, int dag)
Definition Simd.h:194