3#include "gauge/stout_smear.h"
13enum class poly_limit { OFF, RANGE, PARABOLIC };
26 std::string config_file;
28 poly_limit polyakov_pot;
29 double poly_min, poly_max, poly_m2;
30 std::vector<int> n_smear;
32 std::vector<int> z_smear;
52 U[d2].start_gather(d1,
ALL);
53 U[d1].start_gather(d2, par);
57 onsites(opp_parity(par)) {
59 if (2 * X.z() < lattice.size(e_z))
64 lower[X] = m * U[d2][X].dagger() * U[d1][X] * U[d2][X + d1];
71 if (2 * X.z() < lattice.size(e_z))
76 staples[X] += m * U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger() + lower[X - d2];
101 onsites(opp_parity(par)) {
102 if (X.t() == lattice.size(e_t) - 1 || X.t() == 0) {
103 lower[X] = U[d2][X].dagger() * U[d1][X] * U[d2][X + d1];
112 upper[X] = U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger();
116 onsites(par)
if (X.t() == 0) {
117 staples[X] += upper[X + e_t] + lower[X - e_t];
124 staples[X] += U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger() + lower[X - d2];
132template <
typename group>
133double measure_plaq_db(
const GaugeField<group> &U,
bool oddT =
false,
double db = 0.0) {
140 if (!oddT || X.t() != 0) {
141 plaq += 1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
148 if (!oddT || X.t() != 0) {
150 if (2 * X.z() < lattice.size(e_z))
156 c * (1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
184 for (
int plane = lattice.size(e_t) - 2; plane >= 0; plane--) {
191#pragma hila safe_access(polyakov)
193 if (X.coordinate(e_t) == plane) {
194 polyakov[X] = Ut[X] * polyakov[X + e_t];
199 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
200 pl[X] =
real(trace(polyakov[X]));
206void smear_polyakov_field(
Field<float> &pl,
int nsmear,
float smear_coeff) {
211 for (
int i = 0; i < nsmear; i++) {
212 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
213 pl2[X] = pl[X] + smear_coeff * (pl[X + e_x] + pl[X - e_x] + pl[X + e_y] +
214 pl[X - e_y] + pl[X + e_z] + pl[X - e_z]);
217 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
218 pl[X] = pl2[X] / (1 + 6 * smear_coeff);
226std::vector<float> measure_polyakov_profile(
Field<float> &pl, std::vector<float> &pro1) {
230 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
232 if (X.x() == 0 && X.y() == 0)
242template <
typename group>
249 p[X.z()] += 1.0 -
real(trace(U[dir1][X] * U[dir2][X + dir1] *
256 for (
int z = 0; z < lattice.size(e_z); z++) {
258 << p[z] / (NDIM * (NDIM - 1) / 2 * lattice.volume() / lattice.size(e_z)) <<
'\n';
265template <
typename group>
268 static bool first =
true;
272 if (p.polyakov_pot == poly_limit::PARABOLIC)
279 double pnorm = lattice.volume() * NDIM * (NDIM - 1) / 2;
281 pnorm *= ((double)lattice.size(e_t) - 1) / lattice.size(e_t);
285 auto plaq = measure_plaq_db(U, p.odd_T_extent) / pnorm;
287 hila::out0 <<
"MEAS " << std::setprecision(14);
290 if (p.polyakov_pot == poly_limit::PARABOLIC) {
291 hila::out0 << -polyakov_potential(p, poly.real()) <<
' ';
299void spectraldensity_surface(std::vector<float> &surf, std::vector<double> &npow,
300 std::vector<int> &hits) {
303 static bool first =
true;
305 static fftw_plan fftwplan;
307 int area = lattice.size(e_x) * lattice.size(e_y);
316 fftwplan = fftw_plan_dft_2d(lattice.size(e_y), lattice.size(e_x), (fftw_complex *)buf,
317 (fftw_complex *)buf, FFTW_FORWARD, FFTW_ESTIMATE);
320 for (
int i = 0; i < area; i++) {
324 fftw_execute(fftwplan);
326 int pow_size = npow.size();
328 for (
int i = 0; i < area; i++) {
329 int x = i % lattice.size(e_x);
330 int y = i / lattice.size(e_x);
331 x = (x <= lattice.size(e_x) / 2) ? x : (lattice.size(e_x) - x);
332 y = (y <= lattice.size(e_y) / 2) ? y : (lattice.size(e_y) - y);
334 int k = x * x + y * y;
336 npow[k] += buf[i].
squarenorm() / (area * area);
346 return (z + lattice.size(e_z)) % lattice.size(e_z);
351template <
typename group>
352void measure_polyakov_surface(
GaugeField<group> &U,
const parameters &p,
int traj) {
363 for (
int s = 0; s < 20; s++) {
365 U[e_t][
ALL] = (U[e_t][X] + 0.5 * staples[X]) / (1 + 6 * 0.5);
368 measure_polyakov_field(U[e_t], pl);
374 measure_polyakov_field(U[e_t], pl);
379 std::vector<float> profile, prof1;
382 for (
int sl = 0; sl < p.n_smear.size(); sl++) {
384 int smear = p.n_smear.at(sl);
385 smear_polyakov_field(pl, smear - prev_smear, p.smear_coeff);
389 if (p.z_smear.at(sl) > 0) {
391 for (
int j = 0; j < p.z_smear.at(sl); j++) {
392 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
393 pl2[X] = plz[X] + p.smear_coeff * (plz[X + e_z] + plz[X - e_z]);
395 onsites(
ALL)
if (X.coordinate(e_t) == 0) {
396 plz[X] = pl2[X] / (1 + 2 * p.smear_coeff);
401 profile = measure_polyakov_profile(plz, prof1);
403 double m = 1.0 / (lattice.size(e_x) * lattice.size(e_y));
404 for (
int i = 0; i < profile.size(); i++) {
406 hila::out0 <<
"PRO" << sl <<
' ' << i <<
' ' << profile[i] <<
' ' << prof1[i] <<
'\n';
409 float min = 1e8, max = 0;
411 for (
int i = 0; i < profile.size(); i++) {
412 if (min > profile[i]) {
416 if (max < profile[i]) {
423 float surface_level = max * 0.5;
424 int area = lattice.size(e_x) * lattice.size(e_y);
426 hila::out0 <<
"Surface_level" << sl <<
' ' << surface_level <<
'\n';
428 int startloc, startloc2;
430 startloc = (maxloc + minloc) / 2;
432 startloc = ((maxloc + minloc + lattice.size(e_z)) / 2) % lattice.size(e_z);
435 startloc2 =
z_ind(startloc + lattice.size(e_z) / 2);
437 std::vector<float> surf1, surf2;
445 std::vector<float> poly;
446 std::vector<float> line(lattice.size(e_z));
451 for (
int y = 0; y < lattice.size(e_y); y++) {
456 for (
int x = 0; x < lattice.size(e_x); x++) {
460 for (
int z = 0; z < lattice.size(e_z); z++) {
461 line[z] = poly[x + lattice.size(e_x) * (z)];
468 while (line[
z_ind(z)] > surface_level && startloc - z < lattice.size(e_z) * 0.4)
471 while (line[
z_ind(z + 1)] <= surface_level &&
472 z - startloc < lattice.size(e_z) * 0.4)
478 surf1[x + y * lattice.size(e_x)] =
480 (surface_level - line[
z_ind(z)]) / (line[
z_ind(z + 1)] - line[
z_ind(z)]);
482 if (p.n_surface > 0 && (traj + 1) % p.n_surface == 0) {
483 hila::out0 <<
"SURF" << sl <<
' ' << x <<
' ' << y <<
' '
484 << surf1[x + y * lattice.size(e_x)] <<
'\n';
491 while (line[
z_ind(z)] <= surface_level &&
492 startloc2 - z < lattice.size(e_z) * 0.4)
495 while (line[
z_ind(z + 1)] > surface_level &&
496 z - startloc2 < lattice.size(e_z) * 0.4)
501 surf2[x + y * lattice.size(e_x)] =
503 (surface_level - line[
z_ind(z)]) / (line[
z_ind(z + 1)] - line[
z_ind(z)]);
509 constexpr int pow_size = 200;
510 std::vector<double> npow(pow_size);
511 std::vector<int> hits(pow_size);
513 spectraldensity_surface(surf1, npow, hits);
514 spectraldensity_surface(surf2, npow, hits);
516 for (
int i = 0; i < pow_size; i++) {
518 hila::out0 <<
"POW" << sl <<
' ' << i <<
' ' << npow[i] / hits[i] <<
' '
528template <
typename group>
540template <
typename group>
541inline void suN_update(group &U,
const group &staples,
const double beta,
const bool relax) {
545#ifdef SUN_OVERRELAX_dFJ
546 suN_overrelax_dFJ(U, staples, beta);
559template <
typename group>
569 staples_timer.start();
572 staplesum_db(U, staples, d, par, p.deltab);
576 staples_timer.stop();
584 if (!p.odd_T_extent) {
587 onsites(par) suN_update(U[d][X], staples[X], p.beta, relax);
594 if (X.t() != 0 && (d == e_t || X.t() != 1)) {
595 suN_update(U[d][X], staples[X], p.beta, relax);
603 staplesum_T_slice(U, staples, par, d);
605 onsites(par)
if (X.t() == 0) {
606 suN_update(U[d][X], staples[X], p.beta, relax);
610#pragma hila safe_access(U[d])
611 onsites(opp_parity(par))
if (X.t() == 1) {
612 U[d][X] = U[d][X - e_t];
615 onsites(
ALL)
if (X.t() == 0) {
629template <
typename group>
632 for (
int n = 0; n < p.n_update; n++) {
633 for (
int i = 0; i < p.n_overrelax; i++) {
643double polyakov_potential(
const parameters &p,
const double poly) {
645 return p.poly_m2 * (
sqr(poly - p.poly_min));
651bool accept_polyakov(
const parameters &p,
const double p_old,
const double p_new) {
653 if (p.polyakov_pot == poly_limit::PARABOLIC) {
654 double dpot = polyakov_potential(p, p_new) - polyakov_potential(p, p_old);
660 if (p_new >= p.poly_min && p_new <= p.poly_max)
662 if (p_new > p.poly_max && p_new < p_old)
664 if (p_new < p.poly_min && p_new > p_old)
672template <
typename group>
673double update_once_with_range(
GaugeField<group> &U,
const parameters &p,
double &poly,
bool relax) {
694 bool acc_update = accept_polyakov(p, poly, p_now);
700 U[e_t][par] = Ut_old[X];
708template <
typename group>
709double trajectory_with_range(
GaugeField<group> &U,
const parameters &p,
double &poly) {
716 for (
int n = 0; n < p.n_update; n++) {
717 for (
int i = 0; i < p.n_overrelax; i++) {
720 acc_or += update_once_with_range(U, p, p_now,
true);
725 acc_hb += update_once_with_range(U, p, p_now,
false);
729 return (acc_or + acc_hb) / (p.n_update * (p.n_overrelax + 1));
735int main(
int argc,
char **argv) {
758 lsize = par.get(
"lattice size");
760 p.beta = par.get(
"beta");
763 p.deltab = par.get(
"delta beta fraction");
765 p.n_overrelax = par.get(
"overrelax steps");
766 p.n_update = par.get(
"updates in trajectory");
767 p.n_trajectories = par.get(
"trajectories");
768 p.n_thermal = par.get(
"thermalization");
771 uint64_t seed = par.get(
"random seed");
773 p.n_save = par.get(
"traj/saved");
775 p.config_file = par.get(
"config name");
778 int p_item = par.get_item(
"polyakov potential", {
"off",
"min",
"range"});
780 p.polyakov_pot = poly_limit::OFF;
781 }
else if (p_item == 1) {
782 p.polyakov_pot = poly_limit::PARABOLIC;
783 p.poly_min = par.get();
784 p.poly_m2 = par.get(
"mass2");
786 p.polyakov_pot = poly_limit::RANGE;
793 if (par.get_item(
"updates/profile meas", {
"off",
"%i"}) == 1) {
794 p.n_profile = par.get();
800 p.n_smear = par.get(
"smearing steps");
801 p.smear_coeff = par.get(
"smear coefficient");
802 p.z_smear = par.get(
"z smearing steps");
803 p.n_surface = par.get(
"traj/surface");
804 p.n_dump_polyakov = par.get(
"traj/polyakov dump");
806 if (p.n_smear.size() != p.z_smear.size()) {
807 hila::out0 <<
"Error in input file: number of values in 'smearing steps' != 'z "
813 p.n_dump_polyakov = 0;
818 if (lsize[e_t] % 2) {
819 hila::out0 <<
"USING FAKE ODD - N_t LATTICE, logical " << lsize[e_t] <<
" physical "
820 << ++lsize[e_t] <<
'\n';
821 p.odd_T_extent =
true;
823 p.odd_T_extent =
false;
828 lattice.
setup(lsize);
836 int start_traj = -p.n_thermal;
841 restore_checkpoint(U, p.config_file, p.n_trajectories, start_traj);
849 for (
int trajectory = start_traj; trajectory < p.n_trajectories; trajectory++) {
853 update_timer.start();
856 if (p.polyakov_pot != poly_limit::OFF) {
857 acc += trajectory_with_range(U, p, p_now);
863 hila::synchronize_threads();
867 if (trajectory >= 0) {
868 measure_timer.start();
870 hila::out0 <<
"Measure_start " << trajectory <<
'\n';
874 if (p.n_profile && (trajectory + 1) % p.n_profile == 0) {
875 measure_polyakov_surface(U, p, trajectory);
876 measure_plaq_profile(U);
879 if (p.n_dump_polyakov && (trajectory + 1) % p.n_dump_polyakov == 0) {
883 poly.open(
"polyakov", std::ios::out | std::ios::app);
885 measure_polyakov_field(U[e_t], pl);
886 pl.write_slice(poly, {-1, -1, -1, 0});
889 if (p.polyakov_pot != poly_limit::OFF) {
893 hila::out0 <<
"Measure_end " << trajectory << std::endl;
895 measure_timer.stop();
898 if (p.n_save > 0 && (trajectory + 1) % p.n_save == 0) {
899 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