4#include "gauge/stout_smear.h"
18enum class poly_limit { OFF, RANGE, PARABOLIC };
31 std::string config_file;
33 poly_limit polyakov_pot;
34 double poly_min, poly_max, poly_m2;
35 std::vector<int> n_smear;
37 std::vector<int> z_smear;
55 U[d2].start_gather(d1,
ALL);
56 U[d1].start_gather(d2, par);
60 onsites(opp_parity(par)) {
62 if (2 * X.z() < lattice.size(e_z))
67 lower[X] = m * U[d2][X].dagger() * U[d1][X] * U[d2][X + d1];
74 if (2 * X.z() < lattice.size(e_z))
79 staples[X] += m * U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger() + lower[X - d2];
84template <
typename group>
92 plaq += 1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
99 if (2 * X.z() < lattice.size(e_z))
104 plaq += c * (1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
113template <
typename group>
115 const parameters &p) {
117 auto plaq = measure_plaq_bp(U, p.deltab);
119 return p.beta * plaq;
131 for (
int plane = lattice.size(e_t) - 2; plane >= 0; plane--) {
138#pragma hila safe_access(polyakov)
140 if (X.coordinate(e_t) == plane) {
141 polyakov[X] = Ut[X] * polyakov[X + e_t];
146 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
147 pl[X] =
real(trace(polyakov[X]));
153void smear_polyakov_field(
Field<float> &pl,
int nsmear,
float smear_coeff) {
158 for (
int i = 0; i < nsmear; i++) {
159 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
160 pl2[X] = pl[X] + smear_coeff * (pl[X + e_x] + pl[X - e_x] + pl[X + e_y] +
161 pl[X - e_y] + pl[X + e_z] + pl[X - e_z]);
164 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
165 pl[X] = pl2[X] / (1 + 6 * smear_coeff);
173std::vector<float> measure_polyakov_profile(
Field<float> &pl, std::vector<float> &pro1) {
177 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
179 if (X.x() == 0 && X.y() == 0)
189template <
typename group>
196 p[X.z()] += 1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
203 for (
int z = 0; z < lattice.size(e_z); z++) {
205 << p[z] / (NDIM * (NDIM - 1) / 2 * lattice.volume() / lattice.size(e_z)) <<
'\n';
212template <
typename group>
215 static bool first =
true;
219 if (p.polyakov_pot == poly_limit::PARABOLIC)
228 auto plaq = measure_plaq_db(U) / (lattice.volume() * NDIM * (NDIM - 1) / 2);
230 hila::out0 <<
"MEAS " << std::setprecision(14);
233 if (p.polyakov_pot == poly_limit::PARABOLIC) {
234 hila::out0 << -polyakov_potential(p, poly.real()) <<
' ';
242void spectraldensity_surface(std::vector<float> &surf, std::vector<double> &npow,
243 std::vector<int> &hits) {
246 static bool first =
true;
248 static fftw_plan fftwplan;
250 int area = lattice.size(e_x) * lattice.size(e_y);
259 fftwplan = fftw_plan_dft_2d(lattice.size(e_y), lattice.size(e_x), (fftw_complex *)buf,
260 (fftw_complex *)buf, FFTW_FORWARD, FFTW_ESTIMATE);
263 for (
int i = 0; i < area; i++) {
267 fftw_execute(fftwplan);
269 int pow_size = npow.size();
271 for (
int i = 0; i < area; i++) {
272 int x = i % lattice.size(e_x);
273 int y = i / lattice.size(e_x);
274 x = (x <= lattice.size(e_x) / 2) ? x : (lattice.size(e_x) - x);
275 y = (y <= lattice.size(e_y) / 2) ? y : (lattice.size(e_y) - y);
277 int k = x * x + y * y;
279 npow[k] += buf[i].
squarenorm() / (area * area);
289 return (z + lattice.size(e_z)) % lattice.size(e_z);
294template <
typename group>
295void measure_polyakov_surface(
GaugeField<group> &U,
const parameters &p,
int traj) {
306 for (
int s = 0; s < 20; s++) {
308 U[e_t][
ALL] = (U[e_t][X] + 0.5 * staples[X]) / (1 + 6 * 0.5);
311 measure_polyakov_field(U[e_t], pl);
317 measure_polyakov_field(U[e_t], pl);
322 std::vector<float> profile, prof1;
325 for (
int sl = 0; sl < p.n_smear.size(); sl++) {
327 int smear = p.n_smear.at(sl);
328 smear_polyakov_field(pl, smear - prev_smear, p.smear_coeff);
332 if (p.z_smear.at(sl) > 0) {
334 for (
int j = 0; j < p.z_smear.at(sl); j++) {
335 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
336 pl2[X] = plz[X] + p.smear_coeff * (plz[X + e_z] + plz[X - e_z]);
338 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
339 plz[X] = pl2[X] / (1 + 2 * p.smear_coeff);
344 profile = measure_polyakov_profile(plz, prof1);
346 double m = 1.0 / (lattice.size(e_x) * lattice.size(e_y));
347 for (
int i = 0; i < profile.size(); i++) {
349 hila::out0 <<
"PRO" << sl <<
' ' << i <<
' ' << profile[i] <<
' ' << prof1[i] <<
'\n';
352 float min = 1e8, max = 0;
354 for (
int i = 0; i < profile.size(); i++) {
355 if (min > profile[i]) {
359 if (max < profile[i]) {
366 float surface_level = max * 0.5;
367 int area = lattice.size(e_x) * lattice.size(e_y);
369 hila::out0 <<
"Surface_level" << sl <<
' ' << surface_level <<
'\n';
371 int startloc, startloc2;
373 startloc = (maxloc + minloc) / 2;
375 startloc = ((maxloc + minloc + lattice.size(e_z)) / 2) % lattice.size(e_z);
378 startloc2 =
z_ind(startloc + lattice.size(e_z) / 2);
380 std::vector<float> surf1, surf2;
388 std::vector<float> poly;
389 std::vector<float> line(lattice.size(e_z));
394 for (
int y = 0; y < lattice.size(e_y); y++) {
399 for (
int x = 0; x < lattice.size(e_x); x++) {
403 for (
int z = 0; z < lattice.size(e_z); z++) {
404 line[z] = poly[x + lattice.size(e_x) * (z)];
411 while (line[
z_ind(z)] > surface_level && startloc - z < lattice.size(e_z) * 0.4)
414 while (line[
z_ind(z + 1)] <= surface_level &&
415 z - startloc < lattice.size(e_z) * 0.4)
421 surf1[x + y * lattice.size(e_x)] =
423 (surface_level - line[
z_ind(z)]) / (line[
z_ind(z + 1)] - line[
z_ind(z)]);
425 if (p.n_surface > 0 && (traj + 1) % p.n_surface == 0) {
426 hila::out0 <<
"SURF" << sl <<
' ' << x <<
' ' << y <<
' '
427 << surf1[x + y * lattice.size(e_x)] <<
'\n';
434 while (line[
z_ind(z)] <= surface_level &&
435 startloc2 - z < lattice.size(e_z) * 0.4)
438 while (line[
z_ind(z + 1)] > surface_level &&
439 z - startloc2 < lattice.size(e_z) * 0.4)
444 surf2[x + y * lattice.size(e_x)] =
446 (surface_level - line[
z_ind(z)]) / (line[
z_ind(z + 1)] - line[
z_ind(z)]);
452 constexpr int pow_size = 200;
453 std::vector<double> npow(pow_size);
454 std::vector<int> hits(pow_size);
456 spectraldensity_surface(surf1, npow, hits);
457 spectraldensity_surface(surf2, npow, hits);
459 for (
int i = 0; i < pow_size; i++) {
461 hila::out0 <<
"POW" << sl <<
' ' << i <<
' ' << npow[i] / hits[i] <<
' '
471template <
typename group>
482template <
typename group>
492 staples_timer.start();
494 staplesum_db(U, staples, d, par, p.deltab);
497 staples_timer.stop();
503#ifdef SUN_OVERRELAX_dFJ
504 suN_overrelax_dFJ(U[d][X], staples[X], p.beta);
524template <
typename group>
527 for (
int n = 0; n < p.n_update; n++) {
528 for (
int i = 0; i < p.n_overrelax; i++) {
538double polyakov_potential(
const parameters &p,
const double poly) {
540 return p.poly_m2 * (
sqr(poly - p.poly_min));
546bool accept_polyakov(
const parameters &p,
const double p_old,
const double p_new) {
548 if (p.polyakov_pot == poly_limit::PARABOLIC) {
549 double dpot = polyakov_potential(p, p_new) - polyakov_potential(p, p_old);
555 if (p_new >= p.poly_min && p_new <= p.poly_max)
557 if (p_new > p.poly_max && p_new < p_old)
559 if (p_new < p.poly_min && p_new > p_old)
567template <
typename group>
568double update_once_with_range(
GaugeField<group> &U,
const parameters &p,
double &poly,
bool relax) {
589 bool acc_update = accept_polyakov(p, poly, p_now);
595 U[e_t][par] = Ut_old[X];
603template <
typename group>
604double trajectory_with_range(
GaugeField<group> &U,
const parameters &p,
double &poly) {
611 for (
int n = 0; n < p.n_update; n++) {
612 for (
int i = 0; i < p.n_overrelax; i++) {
615 acc_or += update_once_with_range(U, p, p_now,
true);
620 acc_hb += update_once_with_range(U, p, p_now,
false);
624 return (acc_or + acc_hb) / (p.n_update * (p.n_overrelax + 1));
630int main(
int argc,
char **argv) {
653 lsize = par.get(
"lattice size");
655 p.beta = par.get(
"beta");
658 p.deltab = par.get(
"delta beta fraction");
660 p.n_overrelax = par.get(
"overrelax steps");
661 p.n_update = par.get(
"updates in trajectory");
662 p.n_trajectories = par.get(
"trajectories");
663 p.n_thermal = par.get(
"thermalization");
666 uint64_t seed = par.get(
"random seed");
668 p.n_save = par.get(
"traj/saved");
670 p.config_file = par.get(
"config name");
673 int p_item = par.get_item(
"polyakov potential", {
"off",
"min",
"range"});
675 p.polyakov_pot = poly_limit::OFF;
676 }
else if (p_item == 1) {
677 p.polyakov_pot = poly_limit::PARABOLIC;
678 p.poly_min = par.get();
679 p.poly_m2 = par.get(
"mass2");
681 p.polyakov_pot = poly_limit::RANGE;
688 if (par.get_item(
"updates/profile meas", {
"off",
"%i"}) == 1) {
689 p.n_profile = par.get();
695 p.n_smear = par.get(
"smearing steps");
696 p.smear_coeff = par.get(
"smear coefficient");
697 p.z_smear = par.get(
"z smearing steps");
698 p.n_surface = par.get(
"traj/surface");
699 p.n_dump_polyakov = par.get(
"traj/polyakov dump");
701 if (p.n_smear.size() != p.z_smear.size()) {
702 hila::out0 <<
"Error in input file: number of values in 'smearing steps' != 'z "
708 p.n_dump_polyakov = 0;
715 lattice.
setup(lsize);
723 int start_traj = -p.n_thermal;
728 restore_checkpoint(U, p.config_file, p.n_trajectories, start_traj);
736 for (
int trajectory = start_traj; trajectory < p.n_trajectories; trajectory++) {
740 update_timer.start();
743 if (p.polyakov_pot != poly_limit::OFF) {
744 acc += trajectory_with_range(U, p, p_now);
750 hila::synchronize_threads();
754 if (trajectory >= 0) {
755 measure_timer.start();
757 hila::out0 <<
"Measure_start " << trajectory <<
'\n';
761 if (p.n_profile && (trajectory + 1) % p.n_profile == 0) {
762 measure_polyakov_surface(U, p, trajectory);
763 measure_plaq_profile(U);
766 if (p.n_dump_polyakov && (trajectory + 1) % p.n_dump_polyakov == 0) {
770 poly.open(
"polyakov", std::ios::out | std::ios::app);
772 measure_polyakov_field(U[e_t], pl);
773 pl.write_slice(poly, {-1, -1, -1, 0});
776 if (p.polyakov_pot != poly_limit::OFF) {
780 hila::out0 <<
"Measure_end " << trajectory << std::endl;
782 measure_timer.stop();
785 if (p.n_save > 0 && (trajectory + 1) % p.n_save == 0) {
786 checkpoint(U, p.config_file, p.n_trajectories, trajectory);
Array< n, m, T > exp(Array< n, m, T > a)
Exponential.
Array< n, m, hila::arithmetic_type< T > > real(const Array< n, m, T > &arg)
Return real part of Array.
T squarenorm() const
Compute square norm of Complex number.
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
std::vector< T > get_slice(const CoordinateVector &c, bool broadcast=false) const
and get a slice (subvolume)
void reunitarize_gauge()
Reunitarize Gauge Field consisting of matrices.
static constexpr int size()
Returns size of Vector or square Matrix.
Matrix class which defines matrix operations.
Special reduction class: enables delayed and non-blocking reductions, which are not possible with the...
const T value()
Return value of the reduction variable. Wait for the comms if needed.
Reduction & allreduce(bool b=true)
allreduce(bool) turns allreduce on or off. By default on.
void setup(const CoordinateVector &siz)
General lattice setup.
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Parity
Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site (x,...
constexpr Parity EVEN
bit pattern: 001
#define foralldir(d)
Macro to loop over (all) Direction(s)
constexpr Parity ODD
bit pattern: 010
Direction
Enumerator for direction that assigns integer to direction to be interpreted as unit vector.
constexpr Parity ALL
bit pattern: 011
constexpr T sqr(const T &arg)
Define convenience function sqr(), returning square of argument.
Implement hila::swap for gauge fields.
auto shuffle_directions_and_parities()
double random()
Real valued uniform random number generator.
int myrank()
rank of this node
std::ostream out0
This writes output only from main process (node 0)
void initialize(int argc, char **argv)
Read in command line arguments. Initialise default stream and MPI communication.
void seed_random(uint64_t seed, bool device_rng=true)
Seed random generators with 64-bit unsigned value. On MPI shuffles the seed so that different MPI ran...
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
bool is_rng_seeded()
Check if RNG is seeded already.
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...
void terminate(int status)
Complex< double > measure_polyakov(const GaugeField< T > &U, Direction dir=Direction(NDIM - 1))
Measure Polyakov lines to direction dir.
void staplesum(const GaugeField< T > &U, Field< T > &staples, Direction d1, Parity par=ALL)
Sum the staples of link matrices to direction dir.
void update(GaugeField< group > &U, const parameters &p, bool relax)
Wrapper update function.
void update_parity_dir(GaugeField< group > &U, const parameters &p, Parity par, Direction d, bool relax)
Wrapper function to updated GaugeField per direction.
void do_trajectory(GaugeField< group > &U, const parameters &p)
Evolve gauge field.
int z_ind(int z)
Helper function to get valid z-coordinate index.
void measure_stuff(const GaugeField< group > &U, const parameters &p)
Measures Polyakov lines and Wilson action.
double suN_heatbath(SU< N, T > &U, const SU< N, T > &staple, double beta)
heatbath
void suN_overrelax(SU< N, T > &U, const SU< N, T > &staple)
Overrelaxation using SU(2) subgroups