HILA
Loading...
Searching...
No Matches
suN_gauge_gf_measure_hb_and_or_eff.cpp
1#include "hila.h"
2#include "gauge/staples.h"
9
10#ifndef NCOLOR
11#define NCOLOR 3
12#endif
13
14#ifndef BCOPEN
15#define BCOPEN -1
16#endif
17
18#if BCOPEN==-1
19#include "gauge/polyakov.h"
21#endif
22
23using ftype = double;
25
26// define a struct to hold the input parameters: this
27// makes it simpler to pass the values around
28struct parameters {
29 ftype beta; // inverse gauge coupling
30 int n_traj; // number of trajectories to generate
31 int n_therm; // number of thermalization trajectories (counts only accepted traj.)
32 int n_update; // number of heat-bath sweeps per "trajectory"
33 int n_overrelax; // number of overrelaxation sweeps between heat-batch sweeps
34 int gflow_freq; // number of trajectories between gflow measurements
35 ftype gflow_max_l; // flow scale at which gradient flow stops
36 ftype gflow_l_step; // flow scale interval between flow measurements
37 ftype gflow_a_accu; // desired absolute accuracy of gradient flow integration steps
38 ftype gflow_r_accu; // desired relative accuracy of gradient flow integration steps
39 int n_save; // number of trajectories between config. check point
40 std::string config_file;
41 ftype time_offset;
42};
43
44double acc[2]{0};
45double att[2]{0};
46
47
48///////////////////////////////////////////////////////////////////////////////////
49// heat-bath functions
50
51/**
52 * @brief Wrapper function to updated GaugeField per direction
53 * @details Computes first staplesum, then uses computed result to evolve GaugeField either with
54 * over relaxation or heat bath
55 *
56 * @tparam group
57 * @param U GaugeField to evolve
58 * @param p parameter struct
59 * @param par Parity
60 * @param d Direction to evolve
61 * @param relax If true evolves GaugeField with over relaxation if false then with heat bath
62 * @param plaqw plaquette weights
63 */
64template <typename group>
65double update_parity_dir(GaugeField<group> &U, const parameters &p, Parity par, Direction d,
66 bool relax, const plaqw_t<ftype> &plaqw) {
67
68 static hila::timer hb_timer("Heatbath");
69 static hila::timer or_timer("Overrelax");
70 static hila::timer staples_timer("Staplesum");
71
72 double accr = 0.0;
73
74 Field<group> staples;
75
76 staples_timer.start();
77
78 staplesum(U, staples, d, plaqw, par);
79
80 staples_timer.stop();
81
82 Reduction<double> acc = 0;
83 acc.allreduce(false).delayed(true);
84 Reduction<double> att = 0;
85 att.allreduce(false).delayed(true);
86
87 if (relax) {
88
89 or_timer.start();
90
91 onsites(par) {
92 if(plaqw[d][d][X] != 0) {
93#ifdef SUN_OVERRELAX_dFJ
94 acc += suN_overrelax_dFJ(U[d][X], staples[X], p.beta);
95 att += 1.0;
96#else
97 //suN_overrelax(U[d][X], staples[X]);
98 acc += suN_overrelax(U[d][X], staples[X], p.beta);
99 att += 1.0;
100 // U[d][X] = suN_max_staple_sum_rot(staples[X]);
101#endif
102 }
103 }
104 or_timer.stop();
105
106 } else {
107
108 hb_timer.start();
109 onsites(par) {
110 if (plaqw[d][d][X] != 0) {
111 acc += suN_heatbath(U[d][X], staples[X], p.beta);
112 att += 1.0;
113 }
114 }
115 hb_timer.stop();
116
117 }
118 accr = att.value();
119 if (accr > 0) {
120 accr = acc.value() / accr;
121 }
122
123 return accr;
124}
125
126/**
127 * @brief Wrapper update function
128 * @details Gauge Field update sweep with randomly chosen parities and directions
129 *
130 * @tparam group
131 * @param U GaugeField to update
132 * @param p Parameter struct
133 * @param plaqw plaquette weights
134 */
135template <typename group>
136void update(GaugeField<group> &U, const parameters &p, const plaqw_t<ftype> &plaqw) {
137 for (int i = 0; i < 2 * NDIM; ++i) {
138 int tdp = hila::broadcast((int)(hila::random() * 2 * NDIM));
139 int tdir = tdp / 2;
140 int tpar = 1 + (tdp % 2);
141 bool relax = hila::broadcast((int)(hila::random() * (1 + p.n_overrelax)) != 0);
142 // hila::out0 << " " << Parity(tpar) << " -- " << Direction(tdir);
143 acc[relax]+=update_parity_dir(U, p, Parity(tpar), Direction(tdir), relax, plaqw);
144 att[relax] += 1.0;
145 }
146 // hila::out0 << "\n";
147}
148
149/**
150 * @brief Evolve gauge field
151 * @details Evolution happens by means of heat bath and overrelaxation. For each heatbath update
152 * (p.n_update) we do on average also p.n_overrelax overrelaxation updates.
153 *
154 * @tparam group
155 * @param U
156 * @param p
157 */
158template <typename group>
159void do_trajectory(GaugeField<group> &U, const plaqw_t<ftype> &plaqw, const parameters &p) {
160 for (int n = 0; n < p.n_update; n++) {
161 for (int i = 0; i <= p.n_overrelax; i++) {
162 update(U, p, plaqw);
163 //hila::out0 << relax << "\n";
164 }
165 }
167}
168
169// heat-bath functions
170///////////////////////////////////////////////////////////////////////////////////
171// measurement functions
172
173template <typename group>
174std::vector<double> measure_s_wplaq_ps(const GaugeField<group> &U, Direction obd,
175 const plaqw_t<ftype> &plaqw) {
176 // measure the total Wilson plaquette action for the gauge field U
177 int obdlsize = lattice.size(obd);
178 ReductionVector<double> plaql(obdlsize);
179 plaql = 0.0;
180 plaql.allreduce(false).delayed(true);
181 double normf = 2.0 / (NDIM * (NDIM - 1) * lattice.volume() / obdlsize);
182
183 foralldir(dir1) foralldir(dir2) if (dir1 < dir2) {
184 U[dir2].start_gather(dir1, ALL);
185 U[dir1].start_gather(dir2, ALL);
186 onsites(ALL) {
187 double tplq = (1.0 - real(trace(U[dir1][X] * U[dir2][X + dir1] *
188 (U[dir2][X] * U[dir1][X + dir2]).dagger())) /
189 group::size()) *
190 plaqw[dir1][dir2][X] * normf;
191 int obdind = X.coordinate(obd);
192 if (dir1 != obd && dir2 != obd) {
193 plaql[obdind] += tplq;
194 } else {
195 if (obdind > 0 && obdind < obdlsize - 1) {
196 if (obdind == 1) {
197 plaql[obdind] += tplq;
198 plaql[obdind + 1] += 0.5 * tplq;
199 } else if (obdind == obdlsize - 2) {
200 plaql[obdind] += 0.5 * tplq;
201 plaql[obdind + 1] += tplq;
202 } else {
203 plaql[obdind] += 0.5 * tplq;
204 plaql[obdind + 1] += 0.5 * tplq;
205 }
206 }
207 }
208 }
209 }
210 plaql.reduce();
211 return plaql.vector();
212}
213
214/**
215 * @brief Measure Polyakov lines to direction dir
216 * @details Naive implementation, includes extra communication
217 * @tparam T GaugeField Group
218 * @param U GaugeField to measure
219 * @param dir Direction
220 * @return Complex<double>
221 */
222template <typename T>
223std::vector<Complex<double>> measure_polyakov_ps(const GaugeField<T> &U, Direction obd,
224 Direction dir = Direction(NDIM - 1)) {
225
226 Field<T> polyakov = U[dir];
227
228 // mult links so that polyakov[X.dir == 0] contains the polyakov loop
229 for (int plane = lattice.size(dir) - 2; plane >= 0; plane--) {
230
231 // safe_access(polyakov) pragma allows the expression below, otherwise
232 // hilapp would reject it because X and X+dir can refer to the same
233 // site on different "iterations" of the loop. However, here this
234 // is restricted on single dir-plane so it works but we must tell it to hilapp.
235
236#pragma hila safe_access(polyakov)
237 onsites(ALL) {
238 if (X.coordinate(dir) == plane) {
239 polyakov[X] = U[dir][X] * polyakov[X + dir];
240 }
241 }
242 }
243
244 ReductionVector<Complex<double>> ploopl(lattice.size(obd));
245 ploopl = 0.0;
246 ploopl.allreduce(false).delayed(true);
247
248 int obdlsize = lattice.size(obd);
249 double normf = 1.0 / (lattice.volume() / (lattice.size(dir) * obdlsize));
250
251 onsites(ALL) if (X.coordinate(dir) == 0) {
252 ploopl[X.coordinate(obd)] += trace(polyakov[X]) * normf;
253 }
254 ploopl.reduce();
255
256 return ploopl.vector();
257}
258
259template <typename group>
260void measure_stuff(const GaugeField<group> &U, const plaqw_t<ftype> &plaqw) {
261 // perform measurements on current gauge and momentum pair (U, E) and
262 // print results in formatted form to standard output
263 static bool first = true;
264#if BCOPEN >= 0 && BCOPEN < NDIM
265 if (first) {
266 // print legend for measurement output
267 hila::out0 << "LMPLAQPS: plaq[1] plaq[2] plaq[3] plaq[4] ...\n";
268 hila::out0 << "LMPOLPS: P[1].re P[1].im P[2].re P[2].im ...\n";
269 first = false;
270 }
271 Direction obd = Direction(BCOPEN);
272 auto plaql = measure_s_wplaq_ps(U, obd, plaqw);
273 auto polyl = measure_polyakov_ps(U, obd, e_t);
274 hila::out0 << "MPLAQPS";
275 for (int i = 1; i < lattice.size(obd); ++i) {
276 hila::out0 << string_format(" % 0.6e", plaql[i]);
277 }
278 hila::out0 << '\n';
279 hila::out0 << "MPOLPS ";
280 for (int i = 1; i < lattice.size(obd); ++i) {
281 hila::out0 << string_format(" % 0.6e % 0.6e", polyl[i].real(), polyl[i].imag());
282 }
283 hila::out0 << '\n';
284#else
285 if (first) {
286 // print legend for measurement output
287 hila::out0 << "LMEAS: plaq P.real P.imag\n";
288 first = false;
289 }
290 auto plaq = measure_s_wplaq(U) / (lattice.volume() * NDIM * (NDIM - 1) / 2);
291 auto poly = measure_polyakov(U, e_t);
292 hila::out0 << string_format("MEAS % 0.6e % 0.6e % 0.6e", plaq, poly.real(), poly.imag())
293 << '\n';
294
295 hila::out0 << string_format("MEASEFF HB: % 0.6e , OR: % 0.6e ", acc[0] / att[0],
296 acc[1] / att[1])
297 << '\n';
298 acc[0] = 0;
299 att[0] = 0;
300 acc[1] = 0;
301 att[1] = 0;
302#endif
303}
304
305// end measurement functions
306///////////////////////////////////////////////////////////////////////////////////
307// load/save config functions
308
309template <typename group>
310void checkpoint(const GaugeField<group> &U, int trajectory, const parameters &p) {
311 double t = hila::gettime();
312 // name of config with extra suffix
313 std::string config_file =
314 p.config_file + "_" + std::to_string(abs((trajectory + 1) / p.n_save) % 2);
315 // save config
316 U.config_write(config_file);
317 // write run_status file
318 if (hila::myrank() == 0) {
319 std::ofstream outf;
320 outf.open("run_status", std::ios::out | std::ios::trunc);
321 outf << "trajectory " << trajectory + 1 << '\n';
322 outf << "seed " << static_cast<uint64_t>(hila::random() * (1UL << 61)) << '\n';
323 outf << "time " << hila::gettime() << '\n';
324 // write config name to status file:
325 outf << "config name " << config_file << '\n';
326 outf.close();
327 }
328 std::stringstream msg;
329 msg << "Checkpointing, time " << hila::gettime() - t;
330 hila::timestamp(msg.str().c_str());
331}
332
333template <typename group>
334bool restore_checkpoint(GaugeField<group> &U, int &trajectory, parameters &p) {
335 uint64_t seed;
336 bool ok = true;
337 p.time_offset = 0;
338 hila::input status;
339 if (status.open("run_status", false, false)) {
340 hila::out0 << "RESTORING FROM CHECKPOINT:\n";
341 trajectory = status.get("trajectory");
342 seed = status.get("seed");
343 p.time_offset = status.get("time");
344 // get config name with suffix from status file:
345 std::string config_file = status.get("config name");
346 status.close();
347 hila::seed_random(seed);
348 U.config_read(config_file);
349 ok = true;
350 } else {
351 std::ifstream in;
352 in.open(p.config_file, std::ios::in | std::ios::binary);
353 if (in.is_open()) {
354 in.close();
355 hila::out0 << "READING initial config\n";
356 U.config_read(p.config_file);
357 ok = true;
358 } else {
359 ok = false;
360 }
361 }
362 return ok;
363}
364
365// end load/save config functions
366///////////////////////////////////////////////////////////////////////////////////
367
368
369int main(int argc, char **argv) {
370
371 // hila::initialize should be called as early as possible
372 hila::initialize(argc, argv);
373
374 // hila provides an input class hila::input, which is
375 // a convenient way to read in parameters from input files.
376 // parameters are presented as key - value pairs, as an example
377 // " lattice size 64, 64, 64, 64"
378 // is read below.
379 //
380 // Values are broadcast to all MPI nodes.
381 //
382 // .get() -method can read many different input types,
383 // see file "input.h" for documentation
384
385 hila::out0 << "SU(" << mygroup::size() << ") heat-bath with overrelaxation\n";
386
387 hila::out0 << "Using floating point epsilon: " << fp<ftype>::epsilon << "\n";
388
389 parameters p;
390
391 hila::input par("parameters");
392
393 CoordinateVector lsize;
394 // reads NDIM numbers
395 lsize = par.get("lattice size");
396 // inverse gauge coupling
397 p.beta = par.get("beta");
398 // number of trajectories
399 p.n_traj = par.get("number of trajectories");
400 // number of heat-bath (HB) sweeps per trajectory
401 p.n_update = par.get("updates in trajectory");
402 // number of overrelaxation sweeps petween HB sweeps
403 p.n_overrelax = par.get("overrelax steps");
404 // number of thermalization trajectories
405 p.n_therm = par.get("thermalization trajs");
406 // wilson flow frequency (number of traj. between w. flow measurement)
407 p.gflow_freq = par.get("gflow freq");
408 // wilson flow max. flow-distance
409 p.gflow_max_l = par.get("gflow max lambda");
410 // wilson flow flow-distance step size
411 p.gflow_l_step = par.get("gflow lambda step");
412 // wilson flow absolute accuracy (per integration step)
413 p.gflow_a_accu = par.get("gflow abs. accuracy");
414 // wilson flow relative accuracy (per integration step)
415 p.gflow_r_accu = par.get("gflow rel. accuracy");
416 // random seed = 0 -> get seed from time
417 long seed = par.get("random seed");
418 // save config and checkpoint
419 p.n_save = par.get("trajs/saved");
420 // measure surface properties and print "profile"
421 p.config_file = par.get("config name");
422
423 par.close(); // file is closed also when par goes out of scope
424
425 // set up the lattice
426 lattice.setup(lsize);
427
428 // We need random number here
429 hila::seed_random(seed);
430
431 // Alloc gauge field and momenta (E)
434
435 plaqw_t<ftype> plaqw;
436 foralldir(d1) {
437 foralldir(d2) {
438 onsites(ALL) {
439 plaqw[d1][d2][X] = 1.0;
440 }
441 }
442 }
443
444#if BCOPEN>=0 && BCOPEN<NDIM
445 Direction obd = Direction(BCOPEN);
446 hila::out0 << "Using open boundary conditions in " << obd << "-direction\n";
447 foralldir(d1) {
448 foralldir(d2) {
449 onsites(ALL) {
450 if (X.coordinate(obd) == 0) {
451 plaqw[d1][d2][X] = 0;
452 }
453 if (X.coordinate(obd) == 1) {
454 if (d1 != obd && d2 != obd) {
455 plaqw[d1][d2][X] = 0.5;
456 }
457 }
458 if (X.coordinate(obd) == lattice.size(obd) - 1) {
459 if (d1 != obd && d2 != obd) {
460 plaqw[d1][d2][X] = 0.5;
461 } else {
462 plaqw[d1][d2][X] = 0;
463 }
464 }
465 }
466 }
467 }
468#endif //END BCOPEN
469
470 // use negative trajectory for thermal
471 int start_traj = -p.n_therm;
472
473 if (!restore_checkpoint(U, start_traj, p)) {
474 U = 1;
475 }
476
477
478 hila::timer update_timer("Updates");
479 hila::timer measure_timer("Measurements");
480 hila::timer gf_timer("Gradient Flow");
481
482 ftype t_step0 = 0;
483 for (int trajectory = start_traj; trajectory < p.n_traj; ++trajectory) {
484
485 ftype ttime = hila::gettime();
486
487 update_timer.start();
488
489 do_trajectory(U, plaqw, p);
490
491 // put sync here in order to get approx gpu timing
492 hila::synchronize_threads();
493 update_timer.stop();
494
495 measure_timer.start();
496
497 hila::out0 << "Measure_start " << trajectory << '\n';
498
499 measure_stuff(U, plaqw);
500
501 hila::out0 << "Measure_end " << trajectory << '\n';
502
503 measure_timer.stop();
504
505 if (trajectory >= 0) {
506
507 if (p.gflow_freq > 0 && trajectory % p.gflow_freq == 0) {
508
509
510 int gtrajectory = trajectory / p.gflow_freq;
511 if (p.gflow_l_step > 0) {
512
513 gf_timer.start();
514
515 int nflow_steps = (int)(p.gflow_max_l / p.gflow_l_step);
516 ftype gftime = hila::gettime();
517 hila::out0 << "Gflow_start " << gtrajectory << '\n';
518
520
521 ftype t_step = t_step0;
522 measure_gradient_flow_stuff(V, (ftype)0.0, t_step);
523 t_step = do_gradient_flow_adapt(V, (ftype)0.0, p.gflow_l_step, p.gflow_a_accu,
524 p.gflow_r_accu, t_step);
525 measure_gradient_flow_stuff(V, p.gflow_l_step, t_step);
526 t_step0 = t_step;
527
528 for (int i = 1; i < nflow_steps; ++i) {
529
530 t_step =
531 do_gradient_flow_adapt(V, i * p.gflow_l_step, (i + 1) * p.gflow_l_step,
532 p.gflow_a_accu, p.gflow_r_accu, t_step);
533
534 measure_gradient_flow_stuff(V, (i + 1) * p.gflow_l_step, t_step);
535 }
536
537 hila::out0 << "Gflow_end " << gtrajectory << " time " << std::setprecision(3)
538 << hila::gettime() - gftime << '\n';
539
540 gf_timer.stop();
541 }
542 }
543 }
544
545 if (p.n_save > 0 && (trajectory + 1) % p.n_save == 0) {
546 checkpoint(U, trajectory, p);
547 }
548 }
549
551}
Array< n, m, hila::arithmetic_type< T > > imag(const Array< n, m, T > &arg)
Return imaginary part of Array.
Definition array.h:703
Array< n, m, hila::arithmetic_type< T > > real(const Array< n, m, T > &arg)
Return real part of Array.
Definition array.h:689
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
Definition field.h:62
Gauge field class.
Definition gaugefield.h:23
void reunitarize_gauge()
Reunitarize Gauge Field consisting of matrices.
Definition gaugefield.h:95
void config_write(const std::string &filename) const
config_write writes the gauge field to file, with additional "verifying" header
Definition gaugefield.h:162
void setup(const CoordinateVector &siz)
lattice.setup(CoordinateVector size) - set up the base lattice. Called at the beginning of the progra...
Definition lattice.h:447
int size(Direction d) const
lattice.size() -> CoordinateVector or lattice.size(d) -> int returns the dimensions of the lattice,...
Definition lattice.h:433
int64_t volume() const
lattice.volume() returns lattice volume Can be used inside onsites()-loops
Definition lattice.h:424
static constexpr int size()
Returns size of Vector or square Matrix.
Definition matrix.h:248
Special reduction class: enables delayed and non-blocking reductions, which are not possible with the...
Definition reduction.h:14
Class for SU(N) matrix.
Definition sun_matrix.h:110
hila::input - Class for parsing runtime parameter files.
Definition input.h:53
void close()
Closes input parameter file.
Definition input.cpp:94
returntype get(const std::string &key)
Get next value in stack of read in input string from parameters file.
Definition input.h:273
bool open(const std::string &fname, bool use_cmdline=true, bool exit_on_error=true)
Open file that parameters are read from.
Definition input.cpp:27
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Definition cmplx.h:1302
T abs(const Complex< T > &a)
Return absolute value of Complex number.
Definition cmplx.h:1266
Parity
Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site (x,...
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:80
Direction
Enumerator for direction that assigns integer to direction to be interpreted as unit vector.
Definition coordinates.h:34
constexpr Parity ALL
bit pattern: 011
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:121
int myrank()
rank of this node
Definition com_mpi.cpp:237
std::ostream out0
This writes output only from main process (node 0)
void initialize(int argc, char **argv)
Initial setup routines.
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...
Definition random.cpp:86
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
Definition com_mpi.h:170
double gettime()
Definition timing.cpp:167
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...
Complex< double > measure_polyakov(const GaugeField< T > &U, Direction dir=Direction(NDIM - 1))
Measure Polyakov lines to direction dir.
Definition polyakov.h:17
void update(GaugeField< group > &U, const parameters &p, bool relax)
Wrapper update function.
Definition suN_gauge.cpp:73
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.
void measure_stuff(const GaugeField< group > &U, const parameters &p)
Measures Polyakov lines and Wilson action.
Definition suN_gauge.cpp:41
double suN_heatbath(SU< N, T > &U, const SU< N, T > &staple, double beta)
heatbath
int suN_overrelax(SU< N, T > &U, const SU< N, T > &staple, Btype beta)
overrelaxation using matrix obtained from max_staple_sum_rot() routine