Skip to content

Commit c75b77c

Browse files
authored
Merge pull request #1414 from chaoos/feature/openqxd
Feature/openqxd
2 parents bdad358 + 9b7525d commit c75b77c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3831
-82
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,12 @@ option(QUDA_ARPACK_LOGGING "enable ARPACK logging (not available for NG)" OFF)
166166
# OpenBLAS
167167
option(QUDA_OPENBLAS "enable OpenBLAS" OFF)
168168

169+
option(QUDA_QCD_PLUS_QED "Enable QCD+QED features (builds QUDA_RECONSTRUCT_9/13 instead of 8/12 for Wilson-type operators)" OFF)
170+
169171
# Interface options
170172
option(QUDA_INTERFACE_QDP "build qdp interface" ON)
171173
option(QUDA_INTERFACE_MILC "build milc interface" ON)
174+
option(QUDA_INTERFACE_OPENQCD "build OpenQCD interface (for QCD+QED support, see QUDA_QCD_PLUS_QED)" OFF)
172175
option(QUDA_INTERFACE_CPS "build cps interface" OFF)
173176
option(QUDA_INTERFACE_QDPJIT "build qdpjit interface" OFF)
174177
option(QUDA_INTERFACE_BQCD "build bqcd interface" OFF)
@@ -306,6 +309,13 @@ if(QUDA_MPI AND QUDA_QMP)
306309
"Specifying QUDA_QMP and QUDA_MPI might result in undefined behavior. If you intend to use QMP set QUDA_MPI=OFF.")
307310
endif()
308311

312+
if(QUDA_INTERFACE_OPENQCD AND QUDA_QMP)
313+
message(SEND_ERROR "OpenQCD does not support QMP comms.")
314+
endif()
315+
316+
if(QUDA_INTERFACE_OPENQCD AND NOT (QUDA_MPI))
317+
message(SEND_ERROR "OpenQCD requires QUDA built with MPI comms.")
318+
endif()
309319

310320
if(QUDA_NVSHMEM AND NOT (QUDA_QMP OR QUDA_MPI))
311321
message(SEND_ERROR "Specifying QUDA_NVSHMEM requires either QUDA_QMP or QUDA_MPI.")

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ Advanced Scientific Computing (PASC21) [arXiv:2104.05615[hep-lat]].
265265
* Joel Giedt (Rensselaer Polytechnic Institute)
266266
* Steven Gottlieb (Indiana University)
267267
* Anthony Grebe (Fermilab)
268+
* Roman Gruber (ETH)
268269
* Kyriakos Hadjiyiannakou (Cyprus)
269270
* Ben Hoerz (Intel)
270271
* Leon Hostetler (Indiana University)

include/clover_field.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ namespace quda {
166166
inverse(param.inverse),
167167
clover(param.clover),
168168
cloverInv(param.cloverInv),
169+
csw(param.csw),
170+
coeff(param.coeff),
169171
twist_flavor(param.twist_flavor),
170172
mu2(param.mu2),
171173
epsilon2(param.epsilon2),

include/clover_field_order.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <convert.h>
1212
#include <clover_field.h>
1313
#include <complex_quda.h>
14+
#include <index_helper.cuh>
1415
#include <quda_matrix.h>
1516
#include <color_spinor.h>
1617
#include <load_store.h>
@@ -614,7 +615,11 @@ namespace quda {
614615
errorQuda("Accessor reconstruct = %d does not match field reconstruct %d", enable_reconstruct,
615616
clover.Reconstruct());
616617
if (clover.max_element(is_inverse) == 0.0 && isFixed<Float>::value)
618+
#ifdef BUILD_OPENQCD_INTERFACE
619+
warningQuda("%p max_element(%d) appears unset", &clover, is_inverse); /* ignore if the SW-field is zero */
620+
#else
617621
errorQuda("%p max_element(%d) appears unset", &clover, is_inverse);
622+
#endif
618623
if (clover.Diagonal() == 0.0 && clover.Reconstruct()) errorQuda("%p diagonal appears unset", &clover);
619624
this->clover = clover_ ? clover_ : clover.data<Float *>(is_inverse);
620625
}
@@ -983,6 +988,97 @@ namespace quda {
983988
size_t Bytes() const { return length*sizeof(Float); }
984989
};
985990

991+
/**
992+
* OpenQCD ordering for clover fields
993+
*/
994+
template <typename Float, int length = 72> struct OpenQCDOrder {
995+
static constexpr bool enable_reconstruct = false;
996+
typedef typename mapper<Float>::type RegType;
997+
Float *clover;
998+
const int volumeCB;
999+
const QudaTwistFlavorType twist_flavor;
1000+
const Float mu2;
1001+
const Float epsilon2;
1002+
const double coeff;
1003+
const double csw;
1004+
const double kappa;
1005+
const int dim[4]; // xyzt convention
1006+
const int L[4]; // txyz convention
1007+
1008+
OpenQCDOrder(const CloverField &clover, bool inverse, Float *clover_ = nullptr, void * = nullptr) :
1009+
volumeCB(clover.Stride()),
1010+
twist_flavor(clover.TwistFlavor()),
1011+
mu2(clover.Mu2()),
1012+
epsilon2(clover.Epsilon2()),
1013+
coeff(clover.Coeff()),
1014+
csw(clover.Csw()),
1015+
kappa(clover.Coeff() / clover.Csw()),
1016+
dim {clover.X()[0], clover.X()[1], clover.X()[2], clover.X()[3]}, // *local* lattice dimensions, xyzt
1017+
L {clover.X()[3], clover.X()[0], clover.X()[1], clover.X()[2]} // *local* lattice dimensions, txyz
1018+
{
1019+
if (clover.Order() != QUDA_OPENQCD_CLOVER_ORDER) {
1020+
errorQuda("Invalid clover order %d for this accessor", clover.Order());
1021+
}
1022+
this->clover = clover_ ? clover_ : clover.data<Float *>(inverse);
1023+
if (clover.Coeff() == 0.0 || clover.Csw() == 0.0) { errorQuda("Neither coeff nor csw may be zero!"); }
1024+
}
1025+
1026+
QudaTwistFlavorType TwistFlavor() const { return twist_flavor; }
1027+
Float Mu2() const { return mu2; }
1028+
Float Epsilon2() const { return epsilon2; }
1029+
1030+
/**
1031+
* @brief Gets the offset in Floats from the openQCD base pointer to
1032+
* the spinor field.
1033+
*
1034+
* @param[in] x_cb Checkerboard index coming from quda
1035+
* @param[in] parity The parity coming from quda
1036+
*
1037+
* @return The offset.
1038+
*/
1039+
__device__ __host__ inline int getCloverOffset(int x_cb, int parity) const
1040+
{
1041+
int x_quda[4], x[4];
1042+
getCoords(x_quda, x_cb, dim, parity); // x_quda contains xyzt local Carthesian corrdinates
1043+
openqcd::rotate_coords(x_quda, x); // xyzt -> txyz, x = openQCD local Carthesian lattice coordinate
1044+
return openqcd::ipt(x, L) * length;
1045+
}
1046+
1047+
/**
1048+
* @brief Load a clover field at lattice point x_cb
1049+
*
1050+
* @param v The output clover matrix in QUDA order
1051+
* @param x_cb The checkerboarded lattice site
1052+
* @param parity The parity of the lattice site
1053+
*/
1054+
__device__ __host__ inline void load(RegType v[length], int x_cb, int parity) const
1055+
{
1056+
int sign[36] = {-1, -1, -1, -1, -1, -1, // diagonals (idx 0-5)
1057+
-1, +1, -1, +1, -1, -1, -1, -1, -1, -1, // column 0 (idx 6-15)
1058+
-1, +1, -1, -1, -1, -1, -1, -1, // column 1 (idx 16-23)
1059+
-1, -1, -1, -1, -1, -1, // column 2 (idx 24-29)
1060+
-1, +1, -1, +1, // column 3 (idx 30-33)
1061+
-1, +1}; // column 4 (idx 34-35)
1062+
int map[36] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 18, 19, 24, 25, 16, 17,
1063+
12, 13, 20, 21, 26, 27, 14, 15, 22, 23, 28, 29, 30, 31, 32, 33, 34, 35};
1064+
const int M = length / 2;
1065+
int offset = getCloverOffset(x_cb, parity);
1066+
auto Ap = &clover[offset]; // A_+
1067+
auto Am = &clover[offset + M]; // A_-
1068+
1069+
#pragma unroll
1070+
for (int i = 0; i < M; i++) {
1071+
v[i] = sign[i] * (kappa * Am[map[i]] - (i < 6));
1072+
v[M + i] = sign[i] * (kappa * Ap[map[i]] - (i < 6));
1073+
}
1074+
}
1075+
1076+
// FIXME implement the save routine for OpenQCD ordered fields
1077+
__device__ __host__ inline void save(RegType[length], int, int) const { }
1078+
1079+
size_t Bytes() const { return length * sizeof(Float); }
1080+
};
1081+
9861082
} // namespace clover
9871083

9881084
// Use traits to reduce the template explosion

include/color_spinor_field.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ namespace quda
207207
} else if (inv_param.dirac_order == QUDA_TIFR_PADDED_DIRAC_ORDER) {
208208
fieldOrder = QUDA_PADDED_SPACE_SPIN_COLOR_FIELD_ORDER;
209209
siteOrder = QUDA_EVEN_ODD_SITE_ORDER;
210+
} else if (inv_param.dirac_order == QUDA_OPENQCD_DIRAC_ORDER) {
211+
fieldOrder = QUDA_OPENQCD_FIELD_ORDER;
212+
siteOrder = QUDA_EVEN_ODD_SITE_ORDER;
210213
} else {
211214
errorQuda("Dirac order %d not supported", inv_param.dirac_order);
212215
}

include/color_spinor_field_order.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,85 @@ namespace quda
17591759
size_t Bytes() const { return nParity * volumeCB * Nc * Ns * 2 * sizeof(Float); }
17601760
};
17611761

1762+
/**
1763+
* struct to define order of spinor fields in OpenQCD
1764+
*
1765+
* @tparam Float Underlying type of data (precision)
1766+
* @tparam Ns Number of spin degrees of freedom
1767+
* @tparam Nc Number of color degrees of freedom
1768+
*/
1769+
template <typename Float, int Ns, int Nc> struct OpenQCDDiracOrder {
1770+
using Accessor = OpenQCDDiracOrder<Float, Ns, Nc>;
1771+
using real = typename mapper<Float>::type;
1772+
using complex = complex<real>;
1773+
1774+
static const int length = 2 * Ns * Nc; // 12 complex (2 floats) numbers per spinor color field
1775+
Float *field;
1776+
size_t offset;
1777+
Float *ghost[8];
1778+
int volumeCB;
1779+
int faceVolumeCB[4];
1780+
int nParity;
1781+
const int dim[4]; // xyzt convention
1782+
const int L[4]; // txyz convention
1783+
1784+
OpenQCDDiracOrder(const ColorSpinorField &a, int = 1, Float *field_ = 0, float * = 0) :
1785+
field(field_ ? field_ : a.data<Float *>()),
1786+
offset(a.Bytes() / (2 * sizeof(Float))), // TODO: What's this for??
1787+
volumeCB(a.VolumeCB()),
1788+
nParity(a.SiteSubset()),
1789+
dim {a.X(0), a.X(1), a.X(2), a.X(3)}, // *local* lattice dimensions, xyzt
1790+
L {a.X(3), a.X(0), a.X(1), a.X(2)} // *local* lattice dimensions, txyz
1791+
{
1792+
if constexpr (length != 24) { errorQuda("Spinor field length %d not supported", length); }
1793+
}
1794+
1795+
/**
1796+
* @brief Gets the offset in Floats from the openQCD base pointer to
1797+
* the spinor field.
1798+
*
1799+
* @param[in] x Checkerboard index coming from quda
1800+
* @param[in] parity The parity coming from quda
1801+
*
1802+
* @return The offset.
1803+
*/
1804+
__device__ __host__ inline int getSpinorOffset(int x_cb, int parity) const
1805+
{
1806+
int x_quda[4], x[4];
1807+
getCoords(x_quda, x_cb, dim, parity); // x_quda contains xyzt local Carthesian corrdinates
1808+
openqcd::rotate_coords(x_quda, x); // xyzt -> txyz, x = openQCD local Carthesian lattice coordinate
1809+
return openqcd::ipt(x, L) * length;
1810+
}
1811+
1812+
__device__ __host__ inline void load(complex v[length / 2], int x_cb, int parity = 0) const
1813+
{
1814+
auto in = &field[getSpinorOffset(x_cb, parity)];
1815+
block_load<complex, length / 2>(v, reinterpret_cast<const complex *>(in));
1816+
}
1817+
1818+
__device__ __host__ inline void save(const complex v[length / 2], int x_cb, int parity = 0) const
1819+
{
1820+
auto out = &field[getSpinorOffset(x_cb, parity)];
1821+
block_store<complex, length / 2>(reinterpret_cast<complex *>(out), v);
1822+
}
1823+
1824+
/**
1825+
@brief This accessor routine returns a colorspinor_wrapper to this object,
1826+
allowing us to overload various operators for manipulating at
1827+
the site level interms of matrix operations.
1828+
@param[in] x_cb Checkerboarded space-time index we are requesting
1829+
@param[in] parity Parity we are requesting
1830+
@return Instance of a colorspinor_wrapper that curries in access to
1831+
this field at the above coordinates.
1832+
*/
1833+
__device__ __host__ inline auto operator()(int x_cb, int parity) const
1834+
{
1835+
return colorspinor_wrapper<real, Accessor>(*this, x_cb, parity);
1836+
}
1837+
1838+
size_t Bytes() const { return nParity * volumeCB * Nc * Ns * 2 * sizeof(Float); }
1839+
}; // openQCDDiracOrder
1840+
17621841
} // namespace colorspinor
17631842

17641843
template <typename T, int Ns, int Nc, bool project = false, bool huge_alloc = false, bool disable_ghost = false>

include/comm_quda.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ namespace quda
4949
*/
5050
int comm_dim(int dim);
5151

52+
/**
53+
Return whether the dimension dim is a C* dimension or not
54+
@param dim Dimension which we are querying
55+
@return C* dimension or nor
56+
*/
57+
bool comm_dim_cstar(int dim);
58+
5259
/**
5360
Return the global number of processes in the dimension dim
5461
@param dim Dimension which we are querying

include/communicator_quda.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace quda
4141
int (*coords)[QUDA_MAX_DIM];
4242
int my_rank;
4343
int my_coords[QUDA_MAX_DIM];
44+
int cstar; // number of C* direction as per openQxD convention
4445
// It might be worth adding communicators to allow for efficient reductions:
4546
// #if defined(MPI_COMMS)
4647
// MPI_Comm comm;
@@ -126,9 +127,26 @@ namespace quda
126127
inline int comm_rank_displaced(const Topology *topo, const int displacement[])
127128
{
128129
int coords[QUDA_MAX_DIM];
129-
130-
for (int i = 0; i < QUDA_MAX_DIM; i++) {
131-
coords[i] = (i < topo->ndim) ? mod(comm_coords(topo)[i] + displacement[i], comm_dims(topo)[i]) : 0;
130+
int shift_integer;
131+
132+
int Nx_displacement = 0;
133+
for (int i = QUDA_MAX_DIM - 1; i >= 0; i--) {
134+
// cstar shift[x] shift[y] shift[z] shift[t]
135+
// 0 0 0 0 0
136+
// 1 0 0 0 0
137+
// 2 0 1 0 0
138+
// 3 0 1 1 0
139+
if (i < topo->ndim && ((i == 1 && topo->cstar >= 2) || (i == 2 && topo->cstar >= 3))) {
140+
// if we go over the boundary and have a shifted boundary condition,
141+
// we shift Nx/2 ranks in x-direction:
142+
// shift_integer in { 0, 1, 2}
143+
// (shift_integer - 1) in {-1, 0, 1}
144+
shift_integer = (comm_coords(topo)[i] + displacement[i] + comm_dims(topo)[i]) / comm_dims(topo)[i];
145+
Nx_displacement += (shift_integer - 1) * (comm_dims(topo)[0] / 2);
146+
}
147+
coords[i] = (i < topo->ndim) ?
148+
mod(comm_coords(topo)[i] + displacement[i] + (i == 0 ? Nx_displacement : 0), comm_dims(topo)[i]) :
149+
0;
132150
}
133151

134152
return comm_rank_from_coords(topo, coords);
@@ -390,6 +408,12 @@ namespace quda
390408
return comm_dims(topo)[dim];
391409
}
392410

411+
bool comm_dim_cstar(int dim)
412+
{
413+
Topology *topo = comm_default_topology();
414+
return (topo->cstar >= 2 && dim == 1) || (topo->cstar >= 3 && dim == 2);
415+
}
416+
393417
int comm_coord(int dim)
394418
{
395419
Topology *topo = comm_default_topology();

include/dirac_quda.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,15 @@ namespace quda {
11331133
virtual QudaDiracType getDiracType() const override { return QUDA_MOBIUS_DOMAIN_WALLPC_EOFA_DIRAC; }
11341134
};
11351135

1136+
/**
1137+
* @brief Applies gamma matrices to spinor fields
1138+
*
1139+
* @param[out] out Output field
1140+
* @param[in] in Input field
1141+
* @param[in] dir Direction index of gamma matrix
1142+
*/
1143+
void ApplyGamma(cvector_ref<ColorSpinorField> &out, cvector_ref<const ColorSpinorField> &in, QudaGammaDirection_s dir);
1144+
11361145
void gamma5(cvector_ref<ColorSpinorField> &out, cvector_ref<const ColorSpinorField> &in);
11371146

11381147
/**

include/eigensolve_quda.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,11 @@ namespace quda
255255

256256
/**
257257
@brief Computes Left/Right SVD from pre computed Right/Left
258-
@param[in] evecs Computed eigenvectors of NormOp
259-
@param[in] evals Computed eigenvalues of NormOp
258+
@param[in,out] evecs Computed eigenvectors of NormOp
259+
@param[in,out] evals Computed eigenvalues of NormOp
260+
@param[in] dagger Whether NormOp was MdagM (false) or MMdag (true)
260261
*/
261-
void computeSVD(std::vector<ColorSpinorField> &evecs, std::vector<Complex> &evals);
262+
void computeSVD(std::vector<ColorSpinorField> &evecs, std::vector<Complex> &evals, bool dagger = false);
262263

263264
/**
264265
@brief Compute eigenvalues and their residiua

0 commit comments

Comments
 (0)