CHROMA
eoprec_ovext_fermact_array_w.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Unpreconditioned extended-Overlap (5D) (Naryanan&Neuberger) action
3  */
4 
5 #include "chromabase.h"
9 
12 
13 #include "io/enum_io/enum_io.h"
14 #include "io/overlap_state_info.h"
16 
19 
21 
22 namespace Chroma
23 {
24  //! Hooks to register the class with the fermact factory
25  namespace EvenOddPrecOvExtFermActArrayEnv
26  {
27  //! Callback function
28  WilsonTypeFermAct5D<LatticeFermion,
29  multi1d<LatticeColorMatrix>,
30  multi1d<LatticeColorMatrix> >* createFermAct5D(XMLReader& xml_in,
31  const std::string& path)
32  {
35  }
36 
37  //! Callback function
38  /*! Differs in return type */
39  FermionAction<LatticeFermion,
40  multi1d<LatticeColorMatrix>,
41  multi1d<LatticeColorMatrix> >* createFermAct(XMLReader& xml_in,
42  const std::string& path)
43  {
44  return createFermAct5D(xml_in, path);
45  }
46 
47  //! Name to be used
48  const std::string name = "OVEXT";
49 
50  //! Local registration flag
51  static bool registered = false;
52 
53  //! Register all the factories
54  bool registerAll()
55  {
56  bool success = true;
57  if (! registered)
58  {
59  success &= Chroma::TheFermionActionFactory::Instance().registerObject(name, createFermAct);
61  registered = true;
62  }
63  return success;
64  }
65  }
66 
67 
68  //! Read parameters
70  const std::string& path)
71  {
72  try
73  {
74  XMLReader paramtop(xml, path);
75 
76  // Read the stuff for the action
77  read(paramtop, "OverMass", OverMass);
78  read(paramtop, "b5", b5);
79  read(paramtop, "c5", c5);
80  read(paramtop, "Mass", Mass);
81  read(paramtop, "RatPolyDeg", RatPolyDeg);
82  read(paramtop, "ApproximationType", approximation_type);
84  read(paramtop, "ApproxMin", ApproxMin);
85  read(paramtop, "ApproxMax", ApproxMax);
86  }
87  else {
88  ApproxMin = ApproxMax = 0.0;
89  }
90 
91  XMLReader tuning_strategy_reader(paramtop, "TuningStrategy");
92  std::ostringstream os;
93  tuning_strategy_reader.print(os);
94  tuning_strategy_xml = os.str();
95  }
96  catch( const std::string& e) {
97  QDPIO::cout << "Caught Exception while reading XML: " << e << std::endl;
98  QDP_abort(1);
99  }
100  }
101 
102 
103  //! Read parameters
104  void read(XMLReader& xml, const std::string& path, EvenOddPrecOvExtFermActArrayParams& param)
105  {
107  param = tmp;
108  }
109 
110  void write(XMLWriter& xml, const std::string& path, const EvenOddPrecOvExtFermActArrayParams& p)
111  {
112  push(xml, path);
113  write(xml, "OverMass", p.OverMass);
114  write(xml, "b5" , p.b5);
115  write(xml, "c5" , p.c5);
116  write(xml, "Mass", p.Mass);
117  write(xml, "RatPolyDeg", p.RatPolyDeg);
118  write(xml, "ApproximationType", p.approximation_type);
119  if (p.approximation_type == COEFF_TYPE_ZOLOTAREV) {
120  write(xml, "ApproxMin", p.ApproxMin);
121  write(xml, "ApproxMax", p.ApproxMax);
122  }
123 
124  // This may be broken here...
125  QDP::write(xml, "TuningStrategy", p.tuning_strategy_xml);
126 
127  pop(xml);
128  }
129 
130 
131  // General constructor
133  const EvenOddPrecOvExtFermActArrayParams& param_) :
134  cfs(cfs_), param(param_)
135  {
136  // Set up the strategy for tuning the betas
137  std::istringstream ts_is(param.tuning_strategy_xml);
138  XMLReader tuning_xml(ts_is);
139  std::string strategy_name;
140  try {
141  read(tuning_xml, "/TuningStrategy/Name", strategy_name);
142  }
143  catch(const std::string& e) {
144  QDPIO::cerr << "Caught exception processing TuningStrategy: " << e << std::endl;
145  }
146 
147 
148  theTuningStrategy = TheAbsOvExtTuningStrategyFactory::Instance().createObject(strategy_name, tuning_xml, "/TuningStrategy");
149  }
150 
151 
152  // Initializer
154  {
155  // Type 0 and Tanh approximations:
156 
157  // If RatPolyDeg is even: => 2*(RatPolyDeg/2) + 1 = RatPolyDeg+1
158  // If RatPolyDeg is odd: => 2*((RatPolyDeg-1)/2 + 1 = RatPolyDeg
159  if( RatPolyDeg % 2 == 0 ) {
160  return RatPolyDeg+1;
161  }
162  else {
163  return RatPolyDeg;
164  }
165  }
166 
167 
168  //! Get the rational approximation coefficients
170  Real& coeffP,
171  multi1d<Real>& resP,
172  multi1d<Real>& rootQ) const
173  {
174  /* A scale factor which should bring the spectrum of the hermitian
175  Wilson Dirac operator H into |H| < 1. */
176  Real scale_fac;
177 
178  /* Contains all the data necessary for Zolotarev partial fraction */
179  /* -------------------------------------------------------------- */
180  zolotarev_data *rdata ;
181  /* The lower (positive) interval bound for the approximation
182  interval [-1,-eps] U [eps,1] */
183 
184  Real eps;
185  /* The type of the approximation R(x):
186  type = 0 -> R(x) = 0 at x = 0
187  type = 1 -> R(x) = infinity at x = 0 */
188 
189  int type;
190  /* The maximal error of the approximation in the interval
191  [-1,-eps] U [eps,1]*/
192 
193  Real maxerr;
194 
195 
196  /* Hermitian 4D overlap operator 1/2 ( 1 + Mass + (1 - Mass) gamma5 * sgn(H))
197  using a partial fraction expansion of the optimal rational function
198  approximation to sgn. Here, H = 1/2 * gamma_5 * (1/kappa - D').
199  The coefficients are computed by Zolotarev's formula. */
200 
201  switch(param.approximation_type) {
203  {
204  // Rescale approximation: (approxMin, approxMax)
205  // ->(alpha*approxMin, alpha*approxMax)
206  scale_fac = Real(1) / (param.ApproxMax);
208 
209  QDPIO::cout << "Initing Linop with Zolotarev Coefficients" << std::endl;
210 
211  /* Below, when we fill in the coefficents for the partial fraction,
212  we include this factor, say t, appropriately, i.e.
213  R(x) = alpha[da] * t * x + sum(alpha[j] * t * x / (t^2 * x^2 - ap[j]),
214  j = 0 .. da-1)
215  = (alpha[da] + + sum(alpha[j] / (x^2 - ap[j] / t^2) ) / t^2 ) * t * x
216  */
217 
218  /* ZOLOTAREV_4D uses Zolotarev's formula for the coefficients.
219  The coefficents produced are for an optimal uniform approximation
220  to the sign-function in the interval [-1,-eps] U [eps,1] and of order n.
221  type can be set to 0 or 1 corresponding to an approximation which is
222  is zero or infinite at x = 0, respectively.
223  Here we are interested in the partial fraction form
224 
225  R(x) = alpha[da] * x + sum(alpha[j] * x / (x^2 - ap[j]), j = 0 .. da-1)
226 
227  where da = dd for type 0 and da = dd + 1 with ap[dd] = 0 for type 1.
228  */
229  type = 0;
230  rdata = zolotarev(toFloat(eps), param.RatPolyDeg, type);
231  if( rdata == 0x0 ) {
232  QDPIO::cerr << "Failed to get Zolo Coeffs" << std::endl;
233  QDP_abort(1);
234  }
235  }
236  break;
237 
239  {
240  scale_fac = Real(1) ;
241  eps = param.ApproxMin;
242 
243  QDPIO::cout << "Initing Linop with Unscaled Higham Rep tanh Coefficients" << std::endl;
244 
245  /* Below, when we fill in the coefficents for the partial fraction,
246  we include this factor, say t, appropriately, i.e.
247  R(x) = alpha[da] * t * x + sum(alpha[j] * t * x / (t^2 * x^2 - ap[j]),
248  j = 0 .. da-1)
249  = (alpha[da] + + sum(alpha[j] / (x^2 - ap[j] / t^2) ) / t^2 ) * t * x
250  */
251 
252  /* use the tanh formula (Higham Rep) for the coefficients.
253  The coefficents produced are for the tanh approximation
254  to the sign-function in the interval [-1,-eps] U [eps,1] and of order n. R(x) = alpha[da] * x + sum(alpha[j] * x / (x^2 - ap[j]), j = 0 .. da-1)
255  where da = dd for type 0 and da = dd + 1 with ap[dd] = 0 for type 1.
256  */
257  rdata = higham(toFloat(eps), param.RatPolyDeg);
258  }
259  break;
260 
261  default:
262  // The std::map system should ensure that we never get here but
263  // just for style
264  QDPIO::cerr << "Unknown coefficient type: " << param.approximation_type
265  << std::endl;
266  QDP_abort(1);
267  }
268 
269  maxerr = (Real)(rdata -> Delta);
270  QDPIO::cout << "Maxerr " << maxerr << std::flush << std::endl;
271 
272  /* The number of residuals and poles */
273  /* Allocate the roots and residua */
274  Npoles = rdata -> dd;
275 
276  if ( (2*Npoles+1) != getN5FromRatPolyDeg(param.RatPolyDeg)) {
277  QDPIO::cout << "Oops. 2Npoles+1 = " << (2*Npoles+1)
278  << " but N5=" << getN5FromRatPolyDeg(param.RatPolyDeg)
279  << " this is inconsitent" << std::endl;
280  QDP_abort(1);
281  }
282 
283 
284  /* The roots, i.e., the shifts in the partial fraction expansion */
285  rootQ.resize(Npoles);
286  /* The residuals in the partial fraction expansion */
287  resP.resize(Npoles);
288 
289  /* The coefficients from the partial fraction.
290  -- reverse order so biggest is near the physical field */
291 
292  /* Fill in alpha[0] = alpha[da] if it is not zero*/
293  coeffP = rdata -> alpha[rdata -> da - 1] * scale_fac;
294  /* Fill in the coefficients for the roots and the residua */
295  /* Make sure that the smallest shift is in the last value rootQ(Npoles-1)*/
296  Real t = Real(1) / (scale_fac * scale_fac);
297  for(int n=0; n < Npoles; ++n) {
298 
299  resP[Npoles-1-n] = rdata -> alpha[n] / scale_fac;
300  rootQ[Npoles-1-n] = rdata -> ap[n];
301  rootQ[Npoles-1-n] = -(rootQ[Npoles-1-n] * t);
302  }
303 
304  QDPIO::cout << "PartFracApprox n=" << param.RatPolyDeg
305  <<" scale=" << scale_fac
306  <<" Mass=" << param.Mass
307  << std::endl;
308 
309  QDPIO::cout << "Approximation on [-1,-eps] U [eps,1] with eps = " << eps <<
310  std::endl;
311  QDPIO::cout << "Maximum error |R(x) - sqn(x)| <= " << maxerr << std::endl;
312 
313  switch( param.approximation_type) {
315  QDPIO::cout << "Coefficients from Zolotarev" << std::endl;
316 
317  if(type == 0) {
318  QDPIO::cout << "Approximation type " << type << " with R(0) = 0"
319  << std::endl;
320  }
321  else {
322  QDPIO::cout << "Approximation type " << type << " with R(0) = infinity" << std::endl;
323  }
324 
325  break;
326 
328  QDPIO::cout << "Coefficients from Unscaled Higham Tanh representation" << std::endl;
329  break;
330 
331  default:
332  QDPIO::cerr << "Unknown coefficient type " << param.approximation_type
333  << std::endl;
334  break;
335  }
336 
337  QDPIO::cout << "Number of poles= " << Npoles << std::endl;
338  QDPIO::cout << "Overall Factor= " << coeffP << std::endl;
339  QDPIO::cout << "Numerator coefficients:" << std::endl;
340  for(int n=0; n < Npoles; n++) {
341  QDPIO::cout <<" resP[" << n << "]= " << resP[n] << std::endl;
342  }
343  QDPIO::cout << "Denominator roots: " << std::endl;
344  for(int n=0; n < Npoles; n++) {
345  QDPIO::cout <<" rootQ[" << n<< "]= " << rootQ[n] << std::endl;
346  }
347 
348  // Free the arrays allocate by Tony's zolo
349  zolotarev_free(rdata);
350  }
351 
352 
353  //! Produce a linear operator for this action
354  /*!
355  * The operator acts on the entire lattice
356  *
357  * \param state gauge field (Read)
358  */
360  multi1d<LatticeColorMatrix>,
361  multi1d<LatticeColorMatrix> >*
363  {
364  int Npoles;
365  Real coeffP;
366  multi1d<Real> resP;
367  multi1d<Real> rootQ;
368 
369  // Get the coefficients
370 
371  init(Npoles, coeffP, resP, rootQ);
372 
373  multi1d<Real> beta(Npoles);
374  (*theTuningStrategy)(beta, coeffP, resP, rootQ, param.Mass);
375 
377  Npoles,
378  coeffP,
379  resP,
380  rootQ,
381  beta,
382  param.OverMass,
383  param.Mass,
384  param.b5,
385  param.c5);
386 
387  }
388 
389 
390  //! Propagator of an un-preconditioned Extended-Overlap linear operator
391  /*! \ingroup qprop
392  *
393  * Propagator solver for Extended overlap fermions
394  */
395  template<typename T, typename P, typename Q>
396  class PrecOvExt5DQprop : public SystemSolver<T>
397  {
398  public:
399  //! Constructor
400  /*!
401  * \param A_ Linear operator ( Read )
402  * \param Mass_ quark mass ( Read )
403  */
405  Handle< LinearOperator<T> > D_denum_,
406  const Real& Mass_,
407  const SysSolverCGParams& invParam_) :
408  A(A_), D_denum(D_denum_), Mass(Mass_), invParam(invParam_) {}
409 
410  //! Destructor is automatic
412 
413  //! Return the subset on which the operator acts
414  const Subset& subset() const {return all;}
415 
416  //! Solver the linear system
417  /*!
418  * \param psi quark propagator ( Modify )
419  * \param chi source ( Read )
420  * \return number of CG iterations
421  */
423  {
424  START_CODE();
425 
427  const int N5 = A->size();
428 
429  int G5 = Ns*Ns - 1;
430 
431  // Initialize the 5D fields
432  multi1d<T> chi5(N5);
433  multi1d<T> psi5(N5);
434 
435 // if( invType == "CG_INVERTER")
436  {
437  multi1d<T> tmp5_1(N5);
438  {
439  multi1d<T> tmp5_2(N5);
440  multi1d<T> tmp5_3(N5);
441 
442  chi5 = zero;
443  psi5 = zero;
444  tmp5_1 = zero;
445 
446  // Need to prepare the source
447  psi5[N5-1] = Gamma(G5)*chi;
448 
449  A->evenEvenInvLinOp(tmp5_2, psi5, PLUS);
450  A->oddEvenLinOp(tmp5_3, tmp5_2, PLUS);
451 
452 
453  // chi5_e = S_e
454  // chi5_o = S_o - QoeQee^{-1} S_e
455  for(int i=0; i < N5; i++) {
456  chi5[i][rb[0]] = psi5[i];
457  chi5[i][rb[1]] = psi5[i] - tmp5_3[i];
458  }
459  } // tmp5_2 and tmp5_3 go away
460 
461 
462  // CGNE tmp5_1 holds source
463  (*A)(tmp5_1, chi5, MINUS);
464 
465  // Initial guess
466  psi5[N5-1][rb[1]] = psi;
467 
468  // Solve M^{+}M psi = M^{+} chi
469  res = InvCG2(*A, tmp5_1, psi5, invParam.RsdCG, invParam.MaxCG);
470 
471  // psi[N5-1]_odd now holds the desired piece.
472 
473  // Reconstruct psi[N5-1]_e = Q_ee^{-1} S_e - Q_ee^{-1}Q_eo psi[N5-1]_o
474  // = Q_ee^{-1} ( S_e - Q_eo psi_o )
475  {
476 
477  // Dont need to initialise as the parts I use
478  // will be over written the other parts I ignore
479  multi1d<T> tmp5_2(N5);
480  multi1d<T> tmp5_3(N5);
481 
482  // tmp5_2_e = Qeo psi_o
483  A->evenOddLinOp(tmp5_2, psi5, PLUS);
484  for(int i=0; i < N5; i++) {
485 
486  // tmp5_3_e = S_e - Qeo psi_o
487  // = - tmp5_2_e
488  tmp5_3[i][rb[0]] = chi5[i] - tmp5_2[i];
489 
490  }
491 
492  // tmp5_1_e = Qee^{-1} ( S_e - Qeo psi_o )
493  A->evenEvenInvLinOp(tmp5_1, tmp5_3, PLUS);
494 
495  // psi5_e = tmp5_1
496  for(int i=0; i < N5; i++) {
497  psi5[i][rb[0]] = tmp5_1[i];
498  }
499  } // tmp5_2, tmp5_3 disappear
500  } // tmp5_1 disappears
501 // else
502 // {
503 // QDPIO::cerr << EvenOddPrecOvExtFermActArrayEnv::name
504 // << "Unsupported inverter type =" << invParam.invType << std::endl;
505 // QDP_abort(1);
506 // }
507 
508  if ( res.n_count == invParam.MaxCG )
509  QDP_error_exit("no convergence in the inverter", res.n_count);
510 
511  // Need to compute residual someday...
512  res.resid = zero;
513 
514  // Solution now lives in psi5
515  {
516  LatticeFermion tmp4;
517 
518  // Take care of H_t scaling
519  (*D_denum)(tmp4, psi5[N5-1], PLUS);
520  psi5[N5-1] = tmp4;
521  }
522 
523  // Multiply back in factor 2/(1-m) to return to
524  // (1/2)( 1 + m + (1-m) gamma_5 epsilon )
525  // normalisation
526  psi5[N5-1] *= Real(2)/(Real(1)-Mass);
527 
528  // Remove contact term
529  psi = psi5[N5-1] - chi;
530 
531  // Overall normalization
532  Real ftmp1 = Real(1) / (Real(1) - Mass);
533  psi *= ftmp1;
534 
535  END_CODE();
536 
537  return res;
538  }
539 
540  private:
541  // Hide default constructor
543 
546  Real Mass;
548  };
549 
550 
551  //! Propagator of an un-preconditioned Extended-Overlap linear operator
554  const GroupXML_t& invParam) const
555  {
556  Real a5 = param.b5- param.c5;
557 
561 
562  std::istringstream is(invParam.xml);
563  XMLReader paramtop(is);
564 
565  return new PrecOvExt5DQprop<T,P,Q>(A, D_denum, param.Mass, SysSolverCGParams(paramtop,invParam.path));
566  }
567 
568 }
Primary include file for CHROMA library code.
Create a fermion connection state.
Definition: create_state.h:69
Even-odd preconditioned linear operator including derivatives for arrays.
EvenOddPreconditioned Extended-Overlap (N&N) linear operator.
void init(int &Npoles, Real &coeffP, multi1d< Real > &resP, multi1d< Real > &rootQ) const
Get the rational approximation coefficients.
SystemSolver< LatticeFermion > * qprop(Handle< FermState< T, P, Q > > state, const GroupXML_t &invParam) const
Compute quark propagator over base type.
EvenOddPrecOvExtFermActArrayParams param
int getN5FromRatPolyDeg(const int &RatPolyDeg) const
Part of initializer.
Handle< AbsOvExtTuningStrategy > theTuningStrategy
EvenOddPrecConstDetLinearOperatorArray< T, P, Q > * linOp(Handle< FermState< T, P, Q > > state) const
Produce a linear operator for this action.
EvenOddPreconditioned Extended-Overlap (N&N) linear operator.
Support class for fermion actions and linear operators.
Definition: state.h:94
Base class for quadratic matter actions (e.g., fermions)
Definition: fermact.h:53
Class for counted reference semantics.
Definition: handle.h:33
Linear Operator.
Definition: linearop.h:27
Propagator of an un-preconditioned Extended-Overlap linear operator.
SystemSolverResults_t operator()(T &psi, const T &chi) const
Solver the linear system.
Handle< LinearOperator< T > > D_denum
Handle< EvenOddPrecConstDetLinearOperatorArray< T, P, Q > > A
PrecOvExt5DQprop(Handle< EvenOddPrecConstDetLinearOperatorArray< T, P, Q > > A_, Handle< LinearOperator< T > > D_denum_, const Real &Mass_, const SysSolverCGParams &invParam_)
Constructor.
const Subset & subset() const
Return the subset on which the operator acts.
~PrecOvExt5DQprop()
Destructor is automatic.
static T & Instance()
Definition: singleton.h:432
Linear system solvers.
Definition: syssolver.h:34
Operator to apply the denominator.
Unpreconditioned Wilson-Dirac operator.
Wilson-like fermion actions.
Definition: fermact.orig.h:403
int RatPolyDeg
Enums.
Unpreconditioned extended-Overlap (5D) (Naryanan&Neuberger) action.
Unpreconditioned extended-Overlap (5D) (Naryanan&Neuberger) linear operator.
All ferm create-state method.
Fermion action factories.
void read(XMLReader &xml, const std::string &path, AsqtadFermActParams &param)
Read parameters.
void write(XMLWriter &xml, const std::string &path, const AsqtadFermActParams &param)
Writer parameters.
SystemSolverResults_t InvCG2(const LinearOperator< LatticeFermionF > &M, const LatticeFermionF &chi, LatticeFermionF &psi, const Real &RsdCG, int MaxCG)
Conjugate-Gradient (CGNE) algorithm for a generic Linear Operator.
Definition: invcg2.cc:240
@ COEFF_TYPE_ZOLOTAREV
@ COEFF_TYPE_TANH_UNSCALED
Conjugate-Gradient algorithm for a generic Linear Operator.
unsigned n
Definition: ldumul_w.cc:36
int t
Definition: meslate.cc:37
Handle< CreateFermState< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > > reader(XMLReader &xml_in, const std::string &path)
Helper function for the CreateFermState readers.
FermionAction< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > * createFermAct(XMLReader &xml_in, const std::string &path)
Callback function.
static bool registered
Local registration flag.
WilsonTypeFermAct5D< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > * createFermAct5D(XMLReader &xml_in, const std::string &path)
Callback function.
static const LatticeInteger & beta(const int dim)
Definition: stag_phases_s.h:47
static const LatticeInteger & alpha(const int dim)
Definition: stag_phases_s.h:43
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
QDP_error_exit("too many BiCG iterations", n_count, rsd_sq, cp, c, re_rvr, im_rvr, re_a, im_a, re_b, im_b)
int G5
Definition: pbg5p_w.cc:57
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
push(xml_out,"Condensates")
LinOpSysSolverMGProtoClover::T T
int i
Definition: pbg5p_w.cc:55
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
pop(xml_out)
void write(XMLWriter &xml, const std::string &path, const EvenOddPrecOvExtFermActArrayParams &p)
START_CODE()
A(A, psi, r, Ncb, PLUS)
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > state
Definition: pbg5p_w.cc:28
Double zero
Definition: invbicg.cc:106
::std::string string
Definition: gtest.h:1979
Hold group xml and type id.
Params for CG inverter.
Holds return info from SystemSolver call.
Definition: syssolver.h:17
Solve a CG1 system.
Double ftmp1
Definition: topol.cc:29
Unpreconditioned Wilson fermion linear operator.
Unpreconditioned Wilson fermion linear operator.
void zolotarev_free(ZOLOTAREV_DATA *f)
ZOLOTAREV_DATA * higham(PRECISION epsilon, int n)
ZOLOTAREV_DATA * zolotarev(PRECISION epsilon, int n, int type)