CHROMA
unprec_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 
11 
14 
15 #include "io/enum_io/enum_io.h"
16 #include "io/overlap_state_info.h"
18 
20 
21 namespace Chroma
22 {
23  //! Hooks to register the class with the fermact factory
24  namespace UnprecOvExtFermActArrayEnv
25  {
26  //! Callback function
27  WilsonTypeFermAct5D<LatticeFermion,
28  multi1d<LatticeColorMatrix>,
29  multi1d<LatticeColorMatrix> >* createFermAct5D(XMLReader& xml_in,
30  const std::string& path)
31  {
32  return new UnprecOvExtFermActArray(CreateFermStateEnv::reader(xml_in, path),
33  UnprecOvExtFermActArrayParams(xml_in, path));
34  }
35 
36  //! Callback function
37  /*! Differs in return type */
38  FermionAction<LatticeFermion,
39  multi1d<LatticeColorMatrix>,
40  multi1d<LatticeColorMatrix> >* createFermAct(XMLReader& xml_in,
41  const std::string& path)
42  {
43  return createFermAct5D(xml_in, path);
44  }
45 
46  //! Name to be used
47  const std::string name = "UNPRECONDITIONED_OVEXT";
48 
49  //! Local registration flag
50  static bool registered = false;
51 
52  //! Register all the factories
53  bool registerAll()
54  {
55  bool success = true;
56  if (! registered)
57  {
58  success &= Chroma::TheFermionActionFactory::Instance().registerObject(name, createFermAct);
60  registered = true;
61  }
62  return success;
63  }
64  }
65 
66 
67  //! Read parameters
69  const std::string& path)
70  {
71  try {
72 
73  XMLReader paramtop(xml, path);
74 
75  // Read the stuff for the action
76  read(paramtop, "OverMass", OverMass);
77  read(paramtop, "b5", b5);
78  read(paramtop, "c5", c5);
79  read(paramtop, "Mass", Mass);
80  read(paramtop, "RatPolyDeg", RatPolyDeg);
81  read(paramtop, "ApproximationType", approximation_type);
83  read(paramtop, "ApproxMin", ApproxMin);
84  read(paramtop, "ApproxMax", ApproxMax);
85  }
86  else {
87  ApproxMin = ApproxMax = 0.0;
88  }
89 
90  XMLReader tuning_strategy_reader(paramtop, "TuningStrategy");
91  std::ostringstream os;
92  tuning_strategy_reader.print(os);
93  tuning_strategy_xml = os.str();
94  }
95  catch( const std::string& e) {
96  QDPIO::cout << "Caught Exception while reading XML: " << e << std::endl;
97  QDP_abort(1);
98  }
99  }
100 
101 
102  //! Read parameters
103  void read(XMLReader& xml, const std::string& path, UnprecOvExtFermActArrayParams& param)
104  {
106  param = tmp;
107  }
108 
109  void write(XMLWriter& xml, const std::string& path, const UnprecOvExtFermActArrayParams& p) {
110  push(xml, path);
111  write(xml, "OverMass", p.OverMass);
112  write(xml, "b5" , p.b5);
113  write(xml, "c5" , p.c5);
114  write(xml, "Mass", p.Mass);
115  write(xml, "RatPolyDeg", p.RatPolyDeg);
116  write(xml, "ApproximationType", p.approximation_type);
117  if (p.approximation_type == COEFF_TYPE_ZOLOTAREV) {
118  write(xml, "ApproxMin", p.ApproxMin);
119  write(xml, "ApproxMax", p.ApproxMax);
120  }
121 
122  // This may be broken here...
123  QDP::write(xml, "TuningStrategy", p.tuning_strategy_xml);
124  pop(xml);
125  }
126 
127 
128  //! General FermBC
130  const UnprecOvExtFermActArrayParams& param_) :
131  cfs(cfs_), param(param_)
132  {
133 
134  // Get the betas according to the tuning strategy
135  std::istringstream ts_is(param.tuning_strategy_xml);
136  XMLReader tuning_xml(ts_is);
137  std::string strategy_name;
138  try {
139  read(tuning_xml, "/TuningStrategy/Name", strategy_name);
140  }
141  catch(const std::string& e) {
142  QDPIO::cerr << "Caught exception processing TuningStrategy: " << e << std::endl;
143  }
144 
145  theTuningStrategy = TheAbsOvExtTuningStrategyFactory::Instance().createObject(strategy_name, tuning_xml, "/TuningStrategy");
146  }
147 
148 
149  //! Initializer
151  {
152  // Type 0 and Tanh approximations:
153 
154  // If RatPolyDeg is even: => 2*(RatPolyDeg/2) + 1 = RatPolyDeg+1
155  // If RatPolyDeg is odd: => 2*((RatPolyDeg-1)/2 + 1 = RatPolyDeg
156  if( RatPolyDeg % 2 == 0 ) {
157  return RatPolyDeg+1;
158  }
159  else {
160  return RatPolyDeg;
161  }
162  }
163 
164 
165  //! Get the rational approximation coefficients
166  void UnprecOvExtFermActArray::init(int& Npoles,
167  Real& coeffP,
168  multi1d<Real>& resP,
169  multi1d<Real>& rootQ) const
170 
171  {
172  /* A scale factor which should bring the spectrum of the hermitian
173  Wilson Dirac operator H into |H| < 1. */
174  Real scale_fac;
175 
176  /* Contains all the data necessary for Zolotarev partial fraction */
177  /* -------------------------------------------------------------- */
178  zolotarev_data *rdata ;
179  /* The lower (positive) interval bound for the approximation
180  interval [-1,-eps] U [eps,1] */
181 
182  Real eps;
183  /* The type of the approximation R(x):
184  type = 0 -> R(x) = 0 at x = 0
185  type = 1 -> R(x) = infinity at x = 0 */
186 
187  int type;
188  /* The maximal error of the approximation in the interval
189  [-1,-eps] U [eps,1]*/
190 
191  Real maxerr;
192 
193 
194  /* Hermitian 4D overlap operator 1/2 ( 1 + Mass + (1 - Mass) gamma5 * sgn(H))
195  using a partial fraction expansion of the optimal rational function
196  approximation to sgn. Here, H = 1/2 * gamma_5 * (1/kappa - D').
197  The coefficients are computed by Zolotarev's formula. */
198 
199  switch(param.approximation_type) {
201  {
202  // Rescale approximation: (approxMin, approxMax)
203  // ->(alpha*approxMin, alpha*approxMax)
204  scale_fac = Real(1) / (param.ApproxMax);
206 
207  QDPIO::cout << "Initing Linop with Zolotarev Coefficients" << std::endl;
208 
209  /* Below, when we fill in the coefficents for the partial fraction,
210  we include this factor, say t, appropriately, i.e.
211  R(x) = alpha[da] * t * x + sum(alpha[j] * t * x / (t^2 * x^2 - ap[j]),
212  j = 0 .. da-1)
213  = (alpha[da] + + sum(alpha[j] / (x^2 - ap[j] / t^2) ) / t^2 ) * t * x
214  */
215 
216  /* ZOLOTAREV_4D uses Zolotarev's formula for the coefficients.
217  The coefficents produced are for an optimal uniform approximation
218  to the sign-function in the interval [-1,-eps] U [eps,1] and of order n.
219  type can be set to 0 or 1 corresponding to an approximation which is
220  is zero or infinite at x = 0, respectively.
221  Here we are interested in the partial fraction form
222 
223  R(x) = alpha[da] * x + sum(alpha[j] * x / (x^2 - ap[j]), j = 0 .. da-1)
224 
225  where da = dd for type 0 and da = dd + 1 with ap[dd] = 0 for type 1.
226  */
227  type = 0;
228  rdata = zolotarev(toFloat(eps), param.RatPolyDeg, type);
229  if( rdata == 0x0 ) {
230  QDPIO::cerr << "Failed to get Zolo Coeffs" << std::endl;
231  QDP_abort(1);
232  }
233  }
234  break;
235 
237  {
238  scale_fac = Real(1) ;
239  eps = param.ApproxMin;
240 
241  QDPIO::cout << "Initing Linop with Unscaled Higham Rep tanh Coefficients" << std::endl;
242 
243  /* Below, when we fill in the coefficents for the partial fraction,
244  we include this factor, say t, appropriately, i.e.
245  R(x) = alpha[da] * t * x + sum(alpha[j] * t * x / (t^2 * x^2 - ap[j]),
246  j = 0 .. da-1)
247  = (alpha[da] + + sum(alpha[j] / (x^2 - ap[j] / t^2) ) / t^2 ) * t * x
248  */
249 
250  /* use the tanh formula (Higham Rep) for the coefficients.
251  The coefficents produced are for the tanh approximation
252  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)
253  where da = dd for type 0 and da = dd + 1 with ap[dd] = 0 for type 1.
254  */
255  rdata = higham(toFloat(eps), param.RatPolyDeg);
256  }
257  break;
258 
259  default:
260  // The std::map system should ensure that we never get here but
261  // just for style
262  QDPIO::cerr << "Unknown coefficient type: " << param.approximation_type
263  << std::endl;
264  QDP_abort(1);
265  }
266 
267  maxerr = (Real)(rdata -> Delta);
268  QDPIO::cout << "Maxerr " << maxerr << std::flush << std::endl;
269 
270  /* The number of residuals and poles */
271  /* Allocate the roots and residua */
272  Npoles = rdata -> dd;
273 
274  if ( (2*Npoles+1) != getN5FromRatPolyDeg(param.RatPolyDeg)) {
275  QDPIO::cout << "Oops. 2Npoles+1 = " << (2*Npoles+1)
276  << " but N5=" << getN5FromRatPolyDeg(param.RatPolyDeg)
277  << " this is inconsitent" << std::endl;
278  QDP_abort(1);
279  }
280 
281 
282  /* The roots, i.e., the shifts in the partial fraction expansion */
283  rootQ.resize(Npoles);
284  /* The residuals in the partial fraction expansion */
285  resP.resize(Npoles);
286 
287  /* The coefficients from the partial fraction.
288  -- reverse order so biggest is near the physical field */
289 
290  /* Fill in alpha[0] = alpha[da] if it is not zero*/
291  coeffP = rdata -> alpha[rdata -> da - 1] * scale_fac;
292  /* Fill in the coefficients for the roots and the residua */
293  /* Make sure that the smallest shift is in the last value rootQ(Npoles-1)*/
294  Real t = Real(1) / (scale_fac * scale_fac);
295  for(int n=0; n < Npoles; ++n) {
296 
297  resP[Npoles-1-n] = rdata -> alpha[n] / scale_fac;
298  rootQ[Npoles-1-n] = rdata -> ap[n];
299  rootQ[Npoles-1-n] = -(rootQ[Npoles-1-n] * t);
300  }
301 
302  QDPIO::cout << "PartFracApprox n=" << param.RatPolyDeg
303  <<" scale=" << scale_fac
304  <<" Mass=" << param.Mass
305  << std::endl;
306 
307  QDPIO::cout << "Approximation on [-1,-eps] U [eps,1] with eps = " << eps <<
308  std::endl;
309  QDPIO::cout << "Maximum error |R(x) - sqn(x)| <= " << maxerr << std::endl;
310 
311  switch( param.approximation_type) {
313  QDPIO::cout << "Coefficients from Zolotarev" << std::endl;
314 
315  if(type == 0) {
316  QDPIO::cout << "Approximation type " << type << " with R(0) = 0"
317  << std::endl;
318  }
319  else {
320  QDPIO::cout << "Approximation type " << type << " with R(0) = infinity" << std::endl;
321  }
322 
323  break;
324 
326  QDPIO::cout << "Coefficients from Unscaled Higham Tanh representation" << std::endl;
327  break;
328 
329  default:
330  QDPIO::cerr << "Unknown coefficient type " << param.approximation_type
331  << std::endl;
332  break;
333  }
334 
335  QDPIO::cout << "Number of poles= " << Npoles << std::endl;
336  QDPIO::cout << "Overall Factor= " << coeffP << std::endl;
337  QDPIO::cout << "Numerator coefficients:" << std::endl;
338  for(int n=0; n < Npoles; n++) {
339  QDPIO::cout <<" resP[" << n << "]= " << resP[n] << std::endl;
340  }
341  QDPIO::cout << "Denominator roots: " << std::endl;
342  for(int n=0; n < Npoles; n++) {
343  QDPIO::cout <<" rootQ[" << n<< "]= " << rootQ[n] << std::endl;
344  }
345 
346  // Free the arrays allocate by Tony's zolo
347  zolotarev_free(rdata);
348  }
349 
350 
351  //! Produce a linear operator for this action
352  /*!
353  * The operator acts on the entire lattice
354  *
355  * \param state gauge field (Read)
356  */
357  UnprecLinearOperatorArray<LatticeFermion,
358  multi1d<LatticeColorMatrix>,
359  multi1d<LatticeColorMatrix> >*
361  {
362 
363  int Npoles;
364  Real coeffP;
365  multi1d<Real> resP;
366  multi1d<Real> rootQ;
367 
368  // Get the coefficients
369  init(Npoles, coeffP, resP, rootQ);
370 
371 
372  // Get the betas according to the tuning strategy
373  std::istringstream ts_is(param.tuning_strategy_xml);
374  XMLReader tuning_xml(ts_is);
375  std::string strategy_name;
376  try {
377  read(tuning_xml, "/TuningStrategy/Name", strategy_name);
378  }
379  catch(const std::string& e) {
380  QDPIO::cerr << "Caught exception processing TuningStrategy: " << e << std::endl;
381  }
382 
383 
384  Handle< AbsOvExtTuningStrategy > theStrategy(TheAbsOvExtTuningStrategyFactory::Instance().createObject(strategy_name, tuning_xml, "/TuningStrategy"));
385 
386  multi1d<Real> beta(Npoles);
387 
388  (*theTuningStrategy)(beta, coeffP, resP, rootQ, param.Mass);
389 
390  return new UnprecOvExtLinOpArray(state,
391  Npoles,
392  coeffP,
393  resP,
394  rootQ,
395  beta,
396  param.OverMass,
397  param.Mass,
398  param.b5,
399  param.c5);
400 
401  }
402 
403 
404  //! Propagator of an un-preconditioned Extended-Overlap linear operator
405  /*! \ingroup qprop
406  *
407  * Propagator solver for Extended overlap fermions
408  */
409  template<typename T>
410  class OvExt5DQprop : public SystemSolver<T>
411  {
412  public:
413  //! Constructor
414  /*!
415  * \param A_ Linear operator ( Read )
416  * \param Mass_ quark mass ( Read )
417  */
419  Handle< LinearOperator<T> > Dw_,
420  const Real& Mass_,
421  const Real& a5_,
422  const SysSolverCGParams& invParam_) :
423  A(A_), Dw(Dw_), Mass(Mass_), a5(a5_), invParam(invParam_) {}
424 
425  //! Destructor is automatic
427 
428  //! Return the subset on which the operator acts
429  const Subset& subset() const {return all;}
430 
431  //! Solver the linear system
432  /*!
433  * \param psi quark propagator ( Modify )
434  * \param chi source ( Read )
435  * \return number of CG iterations
436  */
438  {
439  START_CODE();
440 
442  const int N5 = A->size(); // array size better match
443 
444  int G5 = Ns*Ns - 1;
445 
446  // Initialize the 5D fields
447  multi1d<LatticeFermion> chi5(N5);
448  multi1d<LatticeFermion> psi5(N5);
449  psi5 = zero;
450  chi5 = zero;
451 
452 // if( invType == "CG_INVERTER")
453  {
454  psi5[N5-1] = Gamma(G5)*chi;
455  (*A)(chi5, psi5, MINUS);
456  psi5[N5-1] = psi;
457 
458  // psi5 = (H_o)^(-2) chi5
459  res = InvCG2(*A, chi5, psi5, invParam.RsdCG, invParam.MaxCG);
460  }
461 // else
462 // {
463 // QDPIO::cerr << UnprecOvExtFermActArrayEnv::name
464 // << "Unsupported inverter type =" << invType << std::endl;
465 // QDP_abort(1);
466 // }
467 
468  if ( res.n_count == invParam.MaxCG )
469  QDP_error_exit("no convergence in the inverter", res.n_count);
470 
471  // Compute residual
472  {
473  multi1d<T> r(N5);
474  (*A)(r, psi5, PLUS);
475  chi5 = zero;
476  chi5[N5-1] = Gamma(G5)*chi;
477  r -= chi5;
478  res.resid = sqrt(norm2(r));
479  }
480 
481  // Need to multiply chi[N5-1] by (2 + a5 Dw)
482  // reuse chi[0] here
483  (*Dw)(chi5[0], psi5[N5-1], PLUS);
484  psi5[N5-1] *= Real(2);
485  psi5[N5-1] += a5*chi5[0];
486 
487 
488 
489  // Return to (1/2)(1+mu + 1-mu ... ) normalisation
490  psi5[N5-1] *= Real(2)/(Real(1)-Mass);
491 
492  // Remove contact term
493  psi = psi5[N5-1] - chi;
494 
495  // Overall normalization
496  Real ftmp1 = Real(1) / (Real(1) - Mass);
497  psi *= ftmp1;
498 
499  END_CODE();
500 
501  return res;
502  }
503 
504  private:
505  // Hide default constructor
507 
510  Real Mass;
511  Real a5;
513  };
514 
515 
516  //! Propagator of an un-preconditioned Extended-Overlap linear operator
519  const GroupXML_t& invParam) const
520  {
521  Real a5 = param.b5- param.c5;
523 
524  std::istringstream is(invParam.xml);
525  XMLReader paramtop(is);
526 
528  D_w,
529  getQuarkMass(),
530  a5,
531  SysSolverCGParams(paramtop,invParam.path));
532  }
533 
534 
535 
536 }
Primary include file for CHROMA library code.
Create a fermion connection state.
Definition: create_state.h:69
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 to arrays.
Definition: linearop.h:61
Linear Operator.
Definition: linearop.h:27
Propagator of an un-preconditioned Extended-Overlap linear operator.
OvExt5DQprop(Handle< LinearOperatorArray< T > > A_, Handle< LinearOperator< T > > Dw_, const Real &Mass_, const Real &a5_, const SysSolverCGParams &invParam_)
Constructor.
~OvExt5DQprop()
Destructor is automatic.
Handle< LinearOperator< T > > Dw
const Subset & subset() const
Return the subset on which the operator acts.
SystemSolverResults_t operator()(T &psi, const T &chi) const
Solver the linear system.
Handle< LinearOperatorArray< T > > A
static T & Instance()
Definition: singleton.h:432
Linear system solvers.
Definition: syssolver.h:34
Unpreconditioned linear operator including derivatives.
Definition: linearop.h:203
Unpreconditioned Extended-Overlap (N&N) linear operator.
int getN5FromRatPolyDeg(const int &RatPolyDeg) const
Initializer.
UnprecLinearOperatorArray< T, P, Q > * linOp(Handle< FermState< T, P, Q > > state) const
Produce a linear operator for this action.
Real getQuarkMass() const
Return the quark mass.
void init(int &Npoles, Real &coeffP, multi1d< Real > &resP, multi1d< Real > &rootQ) const
Get the rational approximation coefficients.
Handle< AbsOvExtTuningStrategy > theTuningStrategy
SystemSolver< LatticeFermion > * qprop(Handle< FermState< T, P, Q > > state, const GroupXML_t &invParam) const
Compute quark propagator over base type.
Unpreconditioned Extended-Overlap (N&N) linear operator.
Unpreconditioned Wilson-Dirac operator.
Wilson-like fermion actions.
Definition: fermact.orig.h:403
int RatPolyDeg
Enums.
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.
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
FermionAction< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > * createFermAct(XMLReader &xml_in, const std::string &path)
Callback function.
static bool registered
Local registration flag.
bool registerAll()
Register all the factories.
WilsonTypeFermAct5D< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > * createFermAct5D(XMLReader &xml_in, const std::string &path)
Callback function.
const std::string name
Name to be used.
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
void write(XMLWriter &xml, const std::string &path, const UnprecOvExtFermActArrayParams &p)
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
pop(xml_out)
START_CODE()
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 extended-Overlap (5D) (Naryanan&Neuberger) action.
Unpreconditioned extended-Overlap (5D) (Naryanan&Neuberger) 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)