CHROMA
eoprec_slic_linop_w.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Even-odd preconditioned clover linear operator
3  */
4 
6 
7 using namespace QDP::Hints;
8 
9 /*
10  Notes on SLIC
11 
12 The idea is you want *two* optimized dslash calls of the form
13 
14 dslash(0.5*U + 0.5*U',PLUS)*psi
15 dslash(0.5*U - 0.5*U',MINUS)*psi
16 
17 If you work this out, you'll find the cross terms cancel, and
18 you are left with
19 
20 Dslash' psi(x) = sum_mu [ gamma_mu U_mu(x) - U'_mu(x) ] psi(x + mu)
21  - [ gamma_mu U^\dag_mu(x - mu) + U'^\dag_mu(x - mu) ] psi(x-mu)
22 
23 The point is the "MINUS" in the dslash call (the dagger) flips the
24 sign and changes gamma_mu*U - U' -> gamma_mu*U + U'
25 
26 So, two copies of the gauge fields are needed beyond
27 holding the fat and the thin links, namely
28 
29 U_1 = 0.5*U_thin + 0.5*U_fat
30 U_2 = 0.5*U_thin - 0.5*U_fat
31 
32 and then one does (in pseudo-code)
33 
34 chi = dslash(U_1,PLUS)*psi
35 chi += dslash(U_2,MINUS)*psi
36 
37 So, to reiterate. The existing optimized codes can be used. You
38 get the projector trick. You need 2 dslash calls, so SLIC (or SLRC)
39 is twice the cost of normal Wilson ferms that are fully fattened
40 or not fattened at all. However, this factor of two is better than
41 the naive cost of *four* which would come from doing a full
42 3x3(gauge) * 3x4(full spinor) . The spin projector trick allows us
43 to reduce the actual work to
44 3x3(gauge) * 3x2(half spinor)
45 
46 This factor of 2 overhead is what Waseem advertises as the normal
47 cost of SLIC.
48 */
49 
50 
51 namespace Chroma
52 {
53 
54  //! Full constructor
55  EvenOddPrecSLICLinOp::EvenOddPrecSLICLinOp(Handle< FermState<T,P,Q> > fs,
56  const CloverFermActParams& param_) : slic_fs(fs)
57  {
58  create(fs, param_);
59  }
60 
61 
62 
63  //! Creation routine with Anisotropy
64  /*!
65  * \param u_ gauge field (Read)
66  * \param param_ fermion kappa (Read)
67  */
69  const CloverFermActParams& param_)
70  {
71  START_CODE();
72 
73  param = param_;
74 
75  multi1d<LatticeColorMatrix> u_pl(Nd);
76  multi1d<LatticeColorMatrix> u_mn(Nd);
77 
78  for(int mu=0; mu < Nd; ++mu)
79  {
80  u_pl[mu] = (fs.cast<SLICFermState<T,P,Q> >())->getThinLinks()[mu]
81  + (fs.cast<SLICFermState<T,P,Q> >())->getLinks()[mu];
82 
83  u_mn[mu] = (fs.cast<SLICFermState<T,P,Q> >())->getThinLinks()[mu]
84  - (fs.cast<SLICFermState<T,P,Q> >())->getLinks()[mu];
85 
86  u_pl[mu] *= Real(0.5);
87  u_mn[mu] *= Real(0.5);
88  }
89 
90  // Need to make sure that fs is a stout ferm state
91  clov.create(fs, param);
92 
93  invclov.create(fs,param,clov); // make a copy
94  invclov.choles(0); // invert the cb=0 part
95 
96  // Create the two dslashs
97  //
98  // WARNING: there are factor of 1/2 floating around. Need to fix this in the
99  // derivatives below.
100  //
101  fs_pl = new SimpleFermState<T,P,Q>(fs->getFermBC(), u_pl);
102  fs_mn = new SimpleFermState<T,P,Q>(fs->getFermBC(), u_mn);
103 
106 
107  END_CODE();
108  }
109 
110  //! Apply the the odd-odd block onto a source std::vector
111  void
112  EvenOddPrecSLICLinOp::oddOddLinOp(LatticeFermion& chi, const LatticeFermion& psi,
113  enum PlusMinus isign) const
114  {
115  clov.apply(chi, psi, isign, 1);
116  }
117 
118 
119  //! Apply the the even-even block onto a source std::vector
120  void
121  EvenOddPrecSLICLinOp::evenEvenLinOp(LatticeFermion& chi, const LatticeFermion& psi,
122  enum PlusMinus isign) const
123  {
124  // Nuke for testing
125  clov.apply(chi, psi, isign, 0);
126  }
127 
128  //! Apply the inverse of the even-even block onto a source std::vector
129  void
130  EvenOddPrecSLICLinOp::evenEvenInvLinOp(LatticeFermion& chi, const LatticeFermion& psi,
131  enum PlusMinus isign) const
132  {
133  invclov.apply(chi, psi, isign, 0);
134  }
135 
136 
137  //! Apply even-odd linop component
138  /*!
139  * The operator acts on the entire even sublattice
140  *
141  * \param chi Pseudofermion field (Write)
142  * \param psi Pseudofermion field (Read)
143  * \param isign Flag ( PLUS | MINUS ) (Read)
144  */
145  void
147  const LatticeFermion& psi,
148  enum PlusMinus isign) const
149  {
150  START_CODE();
151 
152  enum PlusMinus msign = (isign == PLUS) ? MINUS : PLUS;
153  Real mhalf = -0.5;
154 
155  LatticeFermion tmp;
156  D_pl.apply(chi, psi, isign, 0);
157  D_mn.apply(tmp, psi, msign, 0);
158  chi[rb[0]] += tmp;
159  chi[rb[0]] *= mhalf;
160 
161  END_CODE();
162  }
163 
164  //! Apply odd-even linop component
165  /*!
166  * The operator acts on the entire odd sublattice
167  *
168  * \param chi Pseudofermion field (Write)
169  * \param psi Pseudofermion field (Read)
170  * \param isign Flag ( PLUS | MINUS ) (Read)
171  */
172  void
174  const LatticeFermion& psi,
175  enum PlusMinus isign) const
176  {
177  START_CODE();
178 
179  enum PlusMinus msign = (isign == PLUS) ? MINUS : PLUS;
180  Real mhalf = -0.5;
181 
182  LatticeFermion tmp;
183  D_pl.apply(chi, psi, isign, 1);
184  D_mn.apply(tmp, psi, msign, 1);
185  chi[rb[1]] += tmp;
186  chi[rb[1]] *= mhalf;
187 
188  END_CODE();
189  }
190 
191 
192  //! Apply even-odd preconditioned Clover fermion linear operator
193  /*!
194  * \param chi Pseudofermion field (Write)
195  * \param psi Pseudofermion field (Read)
196  * \param isign Flag ( PLUS | MINUS ) (Read)
197  */
198  void EvenOddPrecSLICLinOp::operator()(LatticeFermion & chi,
199  const LatticeFermion& psi,
200  enum PlusMinus isign) const
201  {
202  START_CODE();
203 
204  enum PlusMinus msign = (isign == PLUS) ? MINUS : PLUS;
205 
206  LatticeFermion tmp1; moveToFastMemoryHint(tmp1);
207  LatticeFermion tmp2; moveToFastMemoryHint(tmp2);
208  LatticeFermion tmp3; moveToFastMemoryHint(tmp3);
209  Real mquarter = -0.25;
210 
211  // tmp1_o = D_oe A^(-1)_ee D_eo psi_o
212  D_pl.apply(tmp1, psi, isign, 0);
213  D_mn.apply(tmp3, psi, msign, 0);
214  tmp1[rb[0]] += tmp3;
215  invclov.apply(tmp2, tmp1, isign, 0);
216  D_pl.apply(tmp1, tmp2, isign, 1);
217  D_mn.apply(tmp3, tmp2, msign, 1);
218  tmp1[rb[1]] += tmp3;
219 
220  // chi_o = A_oo psi_o - tmp1_o
221  clov.apply(chi, psi, isign, 1);
222 
223  chi[rb[1]] += mquarter*tmp1;
224 
225  END_CODE();
226  }
227 
228 
229  //! Apply the even-even block onto a source std::vector
230  void
231  EvenOddPrecSLICLinOp::derivEvenEvenLinOp(multi1d<LatticeColorMatrix>& ds_u,
232  const LatticeFermion& chi, const LatticeFermion& psi,
233  enum PlusMinus isign) const
234  {
235  START_CODE();
236 
237  //
238  //
239  // WARNING: these derivatives are not correct
240  //
241  //
242  std::cerr << __func__ << ": need to fix up SLIC derivatives\n";
243  QDP_abort(1);
244 
245 
246  multi1d<LatticeColorMatrix> ds_tmp(Nd);
247  ds_u.resize(Nd);
248 
249  clov.deriv(ds_tmp, chi, psi, isign, 0);
250  SLICFermState<T,P,Q>& sfs = dynamic_cast<SLICFermState<T,P,Q>& >(*slic_fs);
251 
252  sfs.fatForceToThin(ds_tmp,ds_u);
253 
254  END_CODE();
255  }
256 
257  //! Apply the even-even block onto a source std::vector
258  void
259  EvenOddPrecSLICLinOp::derivLogDetEvenEvenLinOp(multi1d<LatticeColorMatrix>& ds_u,
260  enum PlusMinus isign) const
261  {
262  START_CODE();
263 
264  // Testing Odd Odd Term - get nothing from even even term
265  multi1d<LatticeColorMatrix> ds_tmp(Nd);
266  ds_u.resize(Nd);
267 
268  invclov.derivTrLn(ds_tmp, isign, 0);
269  SLICFermState<T,P,Q>& sfs = dynamic_cast<SLICFermState<T,P,Q>& >(*slic_fs);
270 
271  sfs.fatForceToThin(ds_tmp,ds_u);
272 
273  END_CODE();
274  }
275 
276  //! Apply the the even-odd block onto a source std::vector
277  void
278  EvenOddPrecSLICLinOp::derivEvenOddLinOp(multi1d<LatticeColorMatrix>& ds_u,
279  const LatticeFermion& chi, const LatticeFermion& psi,
280  enum PlusMinus isign) const
281  {
282  START_CODE();
283 
284  ds_u.resize(Nd);
285  D_pl.deriv(ds_u, chi, psi, isign, 0);
286 // D_mn.deriv(ds_u, chi, psi, isign, 0);
287 
288  // Undo ferm boundaries on ds_U
289  slic_fs->getFermBC()->modify(ds_u);
290 
291  // But reinforce gauge boundaries
292  slic_fs->getFermBC()->zero(ds_u);
293 
294  for(int mu=0; mu < Nd; mu++) {
295  ds_u[mu] *= Real(-0.5);
296  }
297  END_CODE();
298  }
299 
300  //! Apply the the odd-even block onto a source std::vector
301  void
302  EvenOddPrecSLICLinOp::derivOddEvenLinOp(multi1d<LatticeColorMatrix>& ds_u,
303  const LatticeFermion& chi, const LatticeFermion& psi,
304  enum PlusMinus isign) const
305  {
306  START_CODE();
307  ds_u.resize(Nd);
308 
309  D_pl.deriv(ds_u, chi, psi, isign, 1);
310 // D_mn.deriv(ds_u, chi, psi, isign, 1);
311 
312  // Undo ferm boundaries on ds_U
313  slic_fs->getFermBC()->modify(ds_u);
314 
315  // But reinforce gauge boundaries
316  slic_fs->getFermBC()->zero(ds_u);
317 
318  for(int mu=0; mu < Nd; mu++) {
319  ds_u[mu] *= Real(-0.5);
320  }
321  END_CODE();
322  }
323 
324  // Inherit this
325  //! Apply the the odd-odd block onto a source std::vector
326  void
327  EvenOddPrecSLICLinOp::derivOddOddLinOp(multi1d<LatticeColorMatrix>& ds_u,
328  const LatticeFermion& chi, const LatticeFermion& psi,
329  enum PlusMinus isign) const
330  {
331  START_CODE();
332 
333  ds_u.resize(Nd);
334  multi1d<LatticeColorMatrix> ds_tmp(Nd);
335  clov.deriv(ds_tmp, chi, psi, isign, 1);
336  SLICFermState<T,P,Q>& sfs = dynamic_cast< SLICFermState<T,P,Q>& >(*slic_fs);
337  sfs.fatForceToThin(ds_tmp,ds_u);
338 
339  END_CODE();
340  }
341 
342 
343  //! Return flops performed by the operator()
344  unsigned long EvenOddPrecSLICLinOp::nFlops() const
345  {
346  unsigned long cbsite_flops = 2*2*D_pl.nFlops()+2*clov.nFlops()+4*Nc*Ns;
347  return cbsite_flops*(Layout::sitesOnNode()/2);
348  }
349 
350  //! Get the log det of the even even part
351  // BUt for now, return zero for testing.
353  return invclov.cholesDet(0);
354  }
355 } // End Namespace Chroma
unsigned long nFlops() const
Return flops performed by the operator()
void derivTrLn(multi1d< U > &ds_u, enum PlusMinus isign, int cb) const
Take derivative of TrLn D.
void deriv(multi1d< U > &ds_u, const T &chi, const T &psi, enum PlusMinus isign) const
Take deriv of D.
Handle< FermState< T, P, Q > > fs_mn
void operator()(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply even-odd preconditioned Clover fermion linear operator.
void derivOddOddLinOp(multi1d< LatticeColorMatrix > &ds_u, const LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the odd-odd block onto a source std::vector.
Double logDetEvenEvenLinOp(void) const
Get the log det of the even even part.
void derivLogDetEvenEvenLinOp(multi1d< LatticeColorMatrix > &ds_u, enum PlusMinus isign) const
Apply the even-even block onto a source std::vector.
void evenEvenLinOp(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the even-even block onto a source std::vector.
void derivOddEvenLinOp(multi1d< LatticeColorMatrix > &ds_u, const LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the odd-even block onto a source std::vector.
void derivEvenEvenLinOp(multi1d< LatticeColorMatrix > &ds_u, const LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the even-even block onto a source std::vector.
void derivEvenOddLinOp(multi1d< LatticeColorMatrix > &ds_u, const LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the even-odd block onto a source std::vector.
void oddEvenLinOp(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the odd-even block onto a source std::vector.
void create(Handle< FermState< T, P, Q > > fs, const CloverFermActParams &param_)
Creation routine.
Handle< FermState< T, P, Q > > fs_pl
void evenEvenInvLinOp(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the inverse of the even-even block onto a source std::vector.
void evenOddLinOp(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the even-odd block onto a source std::vector.
void oddOddLinOp(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the the odd-odd block onto a source std::vector.
Handle< FermState< T, P, Q > > slic_fs
unsigned long nFlops() const
Return flops performed by the operator()
Support class for fermion actions and linear operators.
Definition: state.h:94
Class for counted reference semantics.
Definition: handle.h:33
void create(Handle< FermState< T, multi1d< U >, multi1d< U > > > fs, const CloverFermActParams &param_)
Creation routine.
Double cholesDet(int cb) const
Computes the inverse of the term on cb using Cholesky.
void apply(T &chi, const T &psi, enum PlusMinus isign, int cb) const
void choles(int cb)
Computes the inverse of the term on cb using Cholesky.
void create(Handle< FermState< T, P, Q > > state)
Creation routine.
Definition: lwldslash_w.h:161
SLIC (Stout Link Irrelevant Clover ferm connection state.
Simple version of FermState.
void fatForceToThin(const P &F_fat, P &F_thin) const
virtual void deriv(P &ds_u, const T &chi, const T &psi, enum PlusMinus isign) const
Take deriv of D.
unsigned long nFlops() const
Return flops performed by the operator()
int mu
Definition: cool.cc:24
Even-odd preconditioned Clover fermion linear operator.
void apply(T &chi, const T &psi, enum PlusMinus isign, int cb) const
General Wilson-Dirac dslash.
Definition: lwldslash_w.h:228
Nd
Definition: meslate.cc:74
Double tmp2
Definition: mesq.cc:30
Double tmp3
Definition: mesq.cc:31
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
START_CODE()
FloatingPoint< double > Double
Definition: gtest.h:7351
Params for clover ferm acts.