mirror of
https://github.com/paboyle/Grid.git
synced 2024-11-14 01:35:36 +00:00
183 lines
8.4 KiB
C++
183 lines
8.4 KiB
C++
/*
|
|
* Example_plaquette.cc
|
|
*
|
|
* D. Clarke
|
|
*
|
|
* Here I just want to create an incredibly simple main to get started with GRID and get used
|
|
* to its syntax. If the reader is like me, they vaguely understand something about lattice coding,
|
|
* they don't know a ton of C++, don't know much of the fine details, and certainly know nothing about GRID.
|
|
*
|
|
* Once you've made a new executable, like this one, you can bootstrap.sh again. At this point,
|
|
* the code should be able to find your new executable. You can tell that bootstrap.sh worked by
|
|
* having a look at Make.inc. You should see your executable inside there.
|
|
*
|
|
* Warning: This code illustrative only, not well tested, and not meant for production use. The best
|
|
* way to read this code is to start at the main.
|
|
*
|
|
*/
|
|
|
|
|
|
// All your mains should have this
|
|
#include <Grid/Grid.h>
|
|
using namespace Grid;
|
|
|
|
|
|
// This copies what already exists in WilsonLoops.h. The point here is to be pedagogical and explain in
|
|
// detail what everything does so we can see how GRID works.
|
|
template <class Gimpl> class WLoops : public Gimpl {
|
|
public:
|
|
// Gimpl seems to be an arbitrary class. Within this class, it is expected that certain types are
|
|
// already defined, things like Scalar and Field. This macro includes a bunch of #typedefs that
|
|
// implement this equivalence at compile time.
|
|
INHERIT_GIMPL_TYPES(Gimpl);
|
|
|
|
// Some example Gimpls can be found in GaugeImplementations.h, at the bottom. These are in turn built
|
|
// out of GaugeImplTypes, which can be found in GaugeImplTypes.h. The GaugeImplTypes contain the base
|
|
// field/vector/link/whatever types. These inherit from iScalar, iVector, and iMatrix objects, which
|
|
// are sort of the building blocks for gerenal math objects. The "i" at the beginning of these names
|
|
// indicates that they should be for internal use only. It seems like these base types have the
|
|
// acceleration, e.g. SIMD or GPU or what-have-you, abstracted away. How you accelerate these things
|
|
// appears to be controlled through a template parameter called vtype.
|
|
|
|
// The general math/physics objects, such as a color matrix, are built up by nesting these objects.
|
|
// For instance a general color matrix has two color indices, so it's built up like
|
|
// iScalar<iScalar<iMatrix<vtype ...
|
|
// where the levels going from the inside out are color, spin, then Lorentz indices. Scalars have
|
|
// no indices, so it's what we use when such an index isn't needed. Lattice objects are made by one
|
|
// higher level of indexing using iVector.
|
|
|
|
// These types will be used for U and U_mu objects, respectively.
|
|
typedef typename Gimpl::GaugeLinkField GaugeMat;
|
|
typedef typename Gimpl::GaugeField GaugeLorentz;
|
|
|
|
// U_mu_nu(x)
|
|
static void dirPlaquette(GaugeMat &plaq, const std::vector<GaugeMat> &U, const int mu, const int nu) {
|
|
// Calls like CovShiftForward and CovShiftBackward have 3 arguments, and they multiply together
|
|
// the first and last argument. (Second arg gives the shift direction.) The CovShiftIdentityBackward
|
|
// has meanwhile only two arguments; it just returns the shifted (adjoint since backward) link.
|
|
plaq = Gimpl::CovShiftForward(U[mu],mu,
|
|
// Means Link*Cshift(field,mu,1), arguments are Link, mu, field in that order.
|
|
Gimpl::CovShiftForward(U[nu],nu,
|
|
Gimpl::CovShiftBackward(U[mu],mu,
|
|
// This means Cshift(adj(Link), mu, -1)
|
|
Gimpl::CovShiftIdentityBackward(U[nu], nu))));
|
|
}
|
|
|
|
// tr U_mu_nu(x)
|
|
static void traceDirPlaquette(ComplexField &plaq, const std::vector<GaugeMat> &U, const int mu, const int nu) {
|
|
// This .Grid() syntax seems to get the pointer to the GridBase. Apparently this is needed as argument
|
|
// to instantiate a Lattice object.
|
|
GaugeMat sp(U[0].Grid());
|
|
dirPlaquette(sp, U, mu, nu);
|
|
plaq = trace(sp);
|
|
}
|
|
|
|
// sum_mu_nu tr U_mu_nu(x)
|
|
static void sitePlaquette(ComplexField &Plaq, const std::vector<GaugeMat> &U) {
|
|
ComplexField sitePlaq(U[0].Grid());
|
|
Plaq = Zero();
|
|
// Nd=4 and Nc=3 are set as global constants in QCD.h
|
|
for (int mu = 1; mu < Nd; mu++) {
|
|
for (int nu = 0; nu < mu; nu++) {
|
|
traceDirPlaquette(sitePlaq, U, mu, nu);
|
|
Plaq = Plaq + sitePlaq;
|
|
}
|
|
}
|
|
}
|
|
|
|
// sum_mu_nu_x Re tr U_mu_nu(x)
|
|
static RealD sumPlaquette(const GaugeLorentz &Umu) {
|
|
std::vector<GaugeMat> U(Nd, Umu.Grid());
|
|
for (int mu = 0; mu < Nd; mu++) {
|
|
// Umu is a GaugeLorentz object, and as such has a non-trivial Lorentz index. We can
|
|
// access the element in the mu Lorentz index with this PeekIndex syntax.
|
|
U[mu] = PeekIndex<LorentzIndex>(Umu, mu);
|
|
}
|
|
ComplexField Plaq(Umu.Grid());
|
|
sitePlaquette(Plaq, U);
|
|
// I guess this should be the line that sums over all space-time sites.
|
|
auto Tp = sum(Plaq);
|
|
// Until now, we have been working with objects inside the tensor nest. This TensorRemove gets
|
|
// rid of the tensor nest to return whatever is inside.
|
|
auto p = TensorRemove(Tp);
|
|
return p.real();
|
|
}
|
|
|
|
// < Re tr U_mu_nu(x) >
|
|
static RealD avgPlaquette(const GaugeLorentz &Umu) {
|
|
// Real double type
|
|
RealD sumplaq = sumPlaquette(Umu);
|
|
// gSites() is the number of global sites. there is also lSites() for local sites.
|
|
double vol = Umu.Grid()->gSites();
|
|
// The number of orientations. 4*3/2=6 for Nd=4, as known.
|
|
double faces = (1.0 * Nd * (Nd - 1)) / 2.0;
|
|
return sumplaq / vol / faces / Nc;
|
|
}
|
|
};
|
|
|
|
|
|
// Next we show an example of how to construct an input parameter class. We first inherit
|
|
// from Serializable. Then all class data members have to be defined using the
|
|
// GRID_SERIALIZABLE_CLASS_MEMBERS macro. This variadic macro allows for arbitrarily many
|
|
// class data members. In the below case, we make a parameter file holding the configuration
|
|
// name. Here, it expects the name to be labeled with "conf_name" in the configuration file.
|
|
struct ConfParameters: Serializable {
|
|
GRID_SERIALIZABLE_CLASS_MEMBERS(
|
|
ConfParameters,
|
|
std::string, conf_name);
|
|
|
|
template <class ReaderClass>
|
|
ConfParameters(Reader<ReaderClass>& Reader){
|
|
// If we are reading an XML file, it should be structured like:
|
|
// <grid>
|
|
// <parameters>
|
|
// <conf_name>l20t20b06498a_nersc.302500</conf_name>
|
|
// </parameters>
|
|
// </grid>
|
|
read(Reader, "parameters", *this);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// This syntax lets you pass command line arguments to main. An asterisk means that what follows is
|
|
// a pointer. Two asterisks means what follows is a pointer to an array.
|
|
int main (int argc, char **argv)
|
|
{
|
|
// This initializes Grid. Some command line options include
|
|
// --mpi n.n.n.n
|
|
// --threads n
|
|
// --grid n.n.n.n
|
|
Grid_init(&argc, &argv);
|
|
|
|
// This is where you would specify a custom lattice size, if not from the command line. Here
|
|
// Nd is a global quantity that is currently set to 4.
|
|
Coordinate simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd());
|
|
Coordinate mpi_layout = GridDefaultMpi();
|
|
Coordinate latt_size = GridDefaultLatt();
|
|
|
|
// Instantiate the spacetime Grid on which everything will be built.
|
|
GridCartesian GRID(latt_size,simd_layout,mpi_layout);
|
|
|
|
// The PeriodicGimplD type is what you want for gauge matrices. There is also a LatticeGaugeFieldD
|
|
// type that you can use, which will work perfectly with what follows.
|
|
PeriodicGimplD::Field U(&GRID);
|
|
|
|
// Here we read in the parameter file params.json to get conf_name. The last argument is what the
|
|
// top organizational level is called in the param file.
|
|
XmlReader Reader("Example_plaquette.xml",false, "grid");
|
|
ConfParameters param(Reader);
|
|
|
|
// Load a lattice from SIMULATeQCD into U. SIMULATeQCD finds plaquette = 0.6381995717
|
|
FieldMetaData header;
|
|
NerscIO::readConfiguration(U, header, param.conf_name);
|
|
|
|
// Let's see what we find.
|
|
RealD plaq = WLoops<PeriodicGimplD>::avgPlaquette(U);
|
|
|
|
// This is how you make log messages.
|
|
std::cout << GridLogMessage << std::setprecision(std::numeric_limits<Real>::digits10 + 1) << "Plaquette = " << plaq << std::endl;
|
|
|
|
// To wrap things up.
|
|
Grid_finalize();
|
|
} |