HILA
Loading...
Searching...
No Matches
suN_gauge_surface_oddT.cpp
1#include "hila.h"
2#include "gauge/polyakov.h"
3#include "gauge/stout_smear.h"
4#include "gauge/staples.h"
7#include "checkpoint.h"
8
9#include <fftw3.h>
10
12
13enum class poly_limit { OFF, RANGE, PARABOLIC };
14
15// define a struct to hold the input parameters: this
16// makes it simpler to pass the values around
17struct parameters {
18 double beta;
19 double deltab;
20 int n_overrelax;
21 int n_update;
22 int n_trajectories;
23 int n_thermal;
24 int n_save;
25 int n_profile;
26 std::string config_file;
27 double time_offset;
28 poly_limit polyakov_pot;
29 double poly_min, poly_max, poly_m2;
30 std::vector<int> n_smear;
31 double smear_coeff;
32 std::vector<int> z_smear;
33 int n_surface;
34 int n_dump_polyakov;
35 bool odd_T_extent; // NEW
36};
37
38
39template <typename T>
40void staplesum_db(const GaugeField<T> &U, Field<T> &staples, Direction d1, Parity par,
41 double deltab) {
42
43 Field<T> lower;
44
45 // zero staples just in case
46 staples[par] = 0;
47
48 foralldir(d2) if (d2 != d1) {
49
50 // anticipate that these are needed
51 // not really necessary, but may be faster
52 U[d2].start_gather(d1, ALL);
53 U[d1].start_gather(d2, par);
54
55 // calculate first lower 'U' of the staple sum
56 // do it on opp parity
57 onsites(opp_parity(par)) {
58 double m;
59 if (2 * X.z() < lattice.size(e_z))
60 m = 1.0 - deltab;
61 else
62 m = 1.0 + deltab;
63
64 lower[X] = m * U[d2][X].dagger() * U[d1][X] * U[d2][X + d1];
65 }
66
67 // calculate then the upper 'n', and add the lower
68 // lower could also be added on a separate loop
69 onsites(par) {
70 double m;
71 if (2 * X.z() < lattice.size(e_z))
72 m = 1.0 - deltab;
73 else
74 m = 1.0 + deltab;
75
76 staples[X] += m * U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger() + lower[X - d2];
77 }
78 }
79}
80
81// special staplesum routine which moves upper d,t -staple from t=1 to t=0
82// calculates the staplesums only for t==0 timeslice!
83
84template <typename T>
85void staplesum_T_slice(const GaugeField<T> &U, Field<T> &staples, Parity par, Direction d1) {
86
87 Field<T> lower, upper;
88
89 // zero staples just in case
90 staples[par] = 0;
91
92 foralldir(d2) if (d2 != d1) {
93
94 // // anticipate that these are needed
95 // // not really necessary, but may be faster
96 // U[d2].start_gather(d1, ALL);
97 // U[d1].start_gather(d2, ALL);
98
99 // calculate first lower 'U' of the staple sum
100 // do it on opp parity, on last timeslice and slice 0
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];
104 }
105 }
106
107 // calculate then the upper 'n', and add the lower
108 // lower could also be added on a separate loop
109 if (d2 == e_t) {
110 onsites(ALL) {
111 if (X.t() == 1) {
112 upper[X] = U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger();
113 }
114 }
115 // shift upper from t==1 plane
116 onsites(par) if (X.t() == 0) {
117 staples[X] += upper[X + e_t] + lower[X - e_t];
118 }
119
120 } else {
121 // now d2 != e_t (also d1)
122 onsites(par) {
123 if (X.t() == 0) {
124 staples[X] += U[d2][X] * U[d1][X + d2] * U[d2][X + d1].dagger() + lower[X - d2];
125 }
126 }
127 }
128 }
129}
130
131
132template <typename group>
133double measure_plaq_db(const GaugeField<group> &U, bool oddT = false, double db = 0.0) {
135 plaq.allreduce(false);
136
137 foralldir(dir1) foralldir(dir2) if (dir1 < dir2) {
138 if (db == 0.0) {
139 onsites(ALL) {
140 if (!oddT || X.t() != 0) {
141 plaq += 1.0 - real(trace(U[dir1][X] * U[dir2][X + dir1] *
142 U[dir1][X + dir2].dagger() * U[dir2][X].dagger())) /
143 group::size();
144 }
145 }
146 } else {
147 onsites(ALL) {
148 if (!oddT || X.t() != 0) {
149 double c;
150 if (2 * X.z() < lattice.size(e_z))
151 c = 1 - db;
152 else
153 c = 1 + db;
154
155 plaq +=
156 c * (1.0 - real(trace(U[dir1][X] * U[dir2][X + dir1] *
157 U[dir1][X + dir2].dagger() * U[dir2][X].dagger())) /
158 group::size());
159 }
160 }
161 }
162 }
163 return plaq.value();
164}
165
166// template <typename group>
167// double measure_action(const GaugeField<group> &U, const VectorField<Algebra<group>> &E,
168// const parameters &p) {
169
170// auto plaq = measure_plaq_bp(U, p.deltab);
171
172// return p.beta * plaq;
173// }
174
175/////////////////////////////////////////////////////////////////////////////
176/// Measure polyakov "field"
177///
178
179template <typename T>
180void measure_polyakov_field(const Field<T> &Ut, Field<float> &pl) {
181 Field<T> polyakov = Ut;
182
183 // mult links so that polyakov[X.dir == 0] contains the polyakov loop
184 for (int plane = lattice.size(e_t) - 2; plane >= 0; plane--) {
185
186 // safe_access(polyakov) pragma allows the expression below, otherwise
187 // hilapp would reject it because X and X+dir can refer to the same
188 // site on different "iterations" of the loop. However, here this
189 // is restricted on single dir-plane so it works but we must tell it to hilapp.
190
191#pragma hila safe_access(polyakov)
192 onsites(ALL) {
193 if (X.coordinate(e_t) == plane) {
194 polyakov[X] = Ut[X] * polyakov[X + e_t];
195 }
196 }
197 }
198
199 onsites(ALL) if (X.coordinate(e_t) == 0) {
200 pl[X] = real(trace(polyakov[X]));
201 }
202}
203
204////////////////////////////////////////////////////////////////////
205
206void smear_polyakov_field(Field<float> &pl, int nsmear, float smear_coeff) {
207
208 if (nsmear > 0) {
209 Field<float> pl2 = 0;
210
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]);
215 }
216
217 onsites(ALL) if (X.coordinate(e_t) == 0) {
218 pl[X] = pl2[X] / (1 + 6 * smear_coeff);
219 }
220 }
221 }
222}
223
224/////////////////////////////////////////////////////////////////////////////
225
226std::vector<float> measure_polyakov_profile(Field<float> &pl, std::vector<float> &pro1) {
227 ReductionVector<float> p(lattice.size(e_z)), p1(lattice.size(e_z));
228 p.allreduce(false);
229 p1.allreduce(false);
230 onsites(ALL) if (X.coordinate(e_t) == 0) {
231 p[X.z()] += pl[X];
232 if (X.x() == 0 && X.y() == 0)
233 p1[X.z()] += pl[X];
234 }
235 pro1 = p1.vector();
236 return p.vector();
237}
238
239
240///////////////////////////////////////////////////////////////////////////////////
241
242template <typename group>
243void measure_plaq_profile(GaugeField<group> &U) {
244 ReductionVector<float> p(lattice.size(e_z));
245 p.allreduce(false);
246 p.delayed(true);
247 foralldir(dir1) foralldir(dir2) if (dir2 > dir1) {
248 onsites(ALL) {
249 p[X.z()] += 1.0 - real(trace(U[dir1][X] * U[dir2][X + dir1] *
250 U[dir1][X + dir2].dagger() * U[dir2][X].dagger())) /
251 group::size();
252 }
253 }
254 p.reduce();
255
256 for (int z = 0; z < lattice.size(e_z); z++) {
257 hila::out0 << "PPLAQ " << z << ' '
258 << p[z] / (NDIM * (NDIM - 1) / 2 * lattice.volume() / lattice.size(e_z)) << '\n';
259 }
260}
261
262
263///////////////////////////////////////////////////////////////////////////////////
264
265template <typename group>
266void measure_stuff(const GaugeField<group> &U, const parameters &p) {
267
268 static bool first = true;
269
270 if (first) {
271 hila::out0 << "Legend:";
272 if (p.polyakov_pot == poly_limit::PARABOLIC)
273 hila::out0 << " -V(polyakov)";
274 hila::out0 << " plaq P.real P.imag\n";
275
276 first = false;
277 }
278
279 double pnorm = lattice.volume() * NDIM * (NDIM - 1) / 2;
280 if (p.odd_T_extent)
281 pnorm *= ((double)lattice.size(e_t) - 1) / lattice.size(e_t);
282
283 auto poly = measure_polyakov(U);
284
285 auto plaq = measure_plaq_db(U, p.odd_T_extent) / pnorm;
286
287 hila::out0 << "MEAS " << std::setprecision(14);
288
289 // write the -(polyakov potential) first, this is used as a weight factor in aa
290 if (p.polyakov_pot == poly_limit::PARABOLIC) {
291 hila::out0 << -polyakov_potential(p, poly.real()) << ' ';
292 }
293
294 hila::out0 << plaq << ' ' << poly << '\n';
295}
296
297///////////////////////////////////////////////////////////////////////////////////
298
299void spectraldensity_surface(std::vector<float> &surf, std::vector<double> &npow,
300 std::vector<int> &hits) {
301
302 // do fft for the surface
303 static bool first = true;
304 static Complex<double> *buf;
305 static fftw_plan fftwplan;
306
307 int area = lattice.size(e_x) * lattice.size(e_y);
308
309 if (first) {
310 first = false;
311
312 buf = (Complex<double> *)fftw_malloc(sizeof(Complex<double>) * area);
313
314 // note: we had x as the "fast" dimension, but fftw wants the 2nd dim to be
315 // the "fast" one. thus, first y, then x.
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);
318 }
319
320 for (int i = 0; i < area; i++) {
321 buf[i] = surf[i];
322 }
323
324 fftw_execute(fftwplan);
325
326 int pow_size = npow.size();
327
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);
333
334 int k = x * x + y * y;
335 if (k < pow_size) {
336 npow[k] += buf[i].squarenorm() / (area * area);
337 hits[k]++;
338 }
339 }
340}
341
342///////////////////////////////////////////////////////////////////////////////////
343// helper function to get valid z-coordinate index
344
345int z_ind(int z) {
346 return (z + lattice.size(e_z)) % lattice.size(e_z);
347}
348
349///////////////////////////////////////////////////////////////////////////////////
350
351template <typename group>
352void measure_polyakov_surface(GaugeField<group> &U, const parameters &p, int traj) {
353
354 Field<float> pl;
355
356
357 if (0) {
358 // this section does local sums of poly lines
359 Field<group> staples, Ut;
360
361 Ut = U[e_t];
362
363 for (int s = 0; s < 20; s++) {
364 staplesum(U, staples, e_t);
365 U[e_t][ALL] = (U[e_t][X] + 0.5 * staples[X]) / (1 + 6 * 0.5);
366 }
367
368 measure_polyakov_field(U[e_t], pl);
369
370 U[e_t] = Ut;
371
372 } else {
373 // here standard non-link integrated field
374 measure_polyakov_field(U[e_t], pl);
375 }
376
377 hila::out0 << std::setprecision(8);
378
379 std::vector<float> profile, prof1;
380
381 int prev_smear = 0;
382 for (int sl = 0; sl < p.n_smear.size(); sl++) {
383
384 int smear = p.n_smear.at(sl);
385 smear_polyakov_field(pl, smear - prev_smear, p.smear_coeff);
386 prev_smear = smear;
387
388 Field<float> plz = pl;
389 if (p.z_smear.at(sl) > 0) {
390 Field<float> pl2;
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]);
394 }
395 onsites(ALL) if (X.coordinate(e_t) == 0) {
396 plz[X] = pl2[X] / (1 + 2 * p.smear_coeff);
397 }
398 }
399 }
400
401 profile = measure_polyakov_profile(plz, prof1);
402
403 double m = 1.0 / (lattice.size(e_x) * lattice.size(e_y));
404 for (int i = 0; i < profile.size(); i++) {
405 profile[i] *= m;
406 hila::out0 << "PRO" << sl << ' ' << i << ' ' << profile[i] << ' ' << prof1[i] << '\n';
407 }
408
409 float min = 1e8, max = 0;
410 int minloc, maxloc;
411 for (int i = 0; i < profile.size(); i++) {
412 if (min > profile[i]) {
413 min = profile[i];
414 minloc = i;
415 }
416 if (max < profile[i]) {
417 max = profile[i];
418 maxloc = i;
419 }
420 }
421
422 // find the surface between minloc and maxloc
423 float surface_level = max * 0.5; // assume min is really 0
424 int area = lattice.size(e_x) * lattice.size(e_y);
425
426 hila::out0 << "Surface_level" << sl << ' ' << surface_level << '\n';
427
428 int startloc, startloc2;
429 if (maxloc > minloc)
430 startloc = (maxloc + minloc) / 2;
431 else
432 startloc = ((maxloc + minloc + lattice.size(e_z)) / 2) % lattice.size(e_z);
433
434 // starting positio for the other surface
435 startloc2 = z_ind(startloc + lattice.size(e_z) / 2);
436
437 std::vector<float> surf1, surf2;
438 if (hila::myrank() == 0) {
439 surf1.resize(area);
440 surf2.resize(area);
441 }
442
443 hila::out0 << std::setprecision(8);
444
445 std::vector<float> poly;
446 std::vector<float> line(lattice.size(e_z));
447
448 // get full xyz-volume t=0 slice to main node
449 // poly = plz.get_slice({-1, -1, -1, 0});
450
451 for (int y = 0; y < lattice.size(e_y); y++) {
452 // get now full xz-plane polyakov line to main node
453 // reduces MPI calls compared with doing line-by-line
454 poly = plz.get_slice({-1, y, -1, 0});
455 if (hila::myrank() == 0) {
456 for (int x = 0; x < lattice.size(e_x); x++) {
457 // line = plz.get_slice({x, y, -1, 0});
458
459 // copy ploop data to line - x runs fastest
460 for (int z = 0; z < lattice.size(e_z); z++) {
461 line[z] = poly[x + lattice.size(e_x) * (z)];
462 }
463
464 // if (hila::myrank() == 0) {
465 // start search of the surface from the center between min and max
466 int z = startloc;
467
468 while (line[z_ind(z)] > surface_level && startloc - z < lattice.size(e_z) * 0.4)
469 z--;
470
471 while (line[z_ind(z + 1)] <= surface_level &&
472 z - startloc < lattice.size(e_z) * 0.4)
473 z++;
474
475
476 // do linear interpolation
477 // surf[x + y * lattice.size(e_x)] = z;
478 surf1[x + y * lattice.size(e_x)] =
479 z +
480 (surface_level - line[z_ind(z)]) / (line[z_ind(z + 1)] - line[z_ind(z)]);
481
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';
485 }
486
487 // and locate the other surface - start from Lz/2 offset
488
489 z = startloc2;
490
491 while (line[z_ind(z)] <= surface_level &&
492 startloc2 - z < lattice.size(e_z) * 0.4)
493 z--;
494
495 while (line[z_ind(z + 1)] > surface_level &&
496 z - startloc2 < lattice.size(e_z) * 0.4)
497 z++;
498
499 // do linear interpolation
500 // surf[x + y * lattice.size(e_x)] = z;
501 surf2[x + y * lattice.size(e_x)] =
502 z +
503 (surface_level - line[z_ind(z)]) / (line[z_ind(z + 1)] - line[z_ind(z)]);
504 }
505 }
506 }
507
508 if (hila::myrank() == 0) {
509 constexpr int pow_size = 200;
510 std::vector<double> npow(pow_size);
511 std::vector<int> hits(pow_size);
512
513 spectraldensity_surface(surf1, npow, hits);
514 spectraldensity_surface(surf2, npow, hits);
515
516 for (int i = 0; i < pow_size; i++) {
517 if (hits[i] > 0)
518 hila::out0 << "POW" << sl << ' ' << i << ' ' << npow[i] / hits[i] << ' '
519 << hits[i] << '\n';
520 }
521 }
522 }
523}
524
525
526////////////////////////////////////////////////////////////////
527
528template <typename group>
529void update(GaugeField<group> &U, const parameters &p, bool relax) {
530
531 for (const auto &dp : hila::shuffle_directions_and_parities()) {
532
533 update_parity_dir(U, p, dp.parity, dp.direction, relax);
534 }
535}
536
537
538// enclose generic update to this function
539
540template <typename group>
541inline void suN_update(group &U, const group &staples, const double beta, const bool relax) {
542
543 if (relax) {
544
545#ifdef SUN_OVERRELAX_dFJ
546 suN_overrelax_dFJ(U, staples, beta);
547#else
548 suN_overrelax(U, staples);
549#endif
550
551 } else {
552
553 suN_heatbath(U, staples, beta);
554 }
555}
556
557////////////////////////////////////////////////////////////////
558
559template <typename group>
560void update_parity_dir(GaugeField<group> &U, const parameters &p, Parity par, Direction d,
561 bool relax) {
562
563 static hila::timer hb_timer("Heatbath");
564 static hila::timer or_timer("Overrelax");
565 static hila::timer staples_timer("Staplesum");
566
567 Field<group> staples;
568
569 staples_timer.start();
570
571 if (p.deltab != 0)
572 staplesum_db(U, staples, d, par, p.deltab);
573 else
574 staplesum(U, staples, d, par);
575
576 staples_timer.stop();
577
578 if (relax)
579 or_timer.start();
580 else
581 hb_timer.start();
582
583
584 if (!p.odd_T_extent) {
585 // standard update
586
587 onsites(par) suN_update(U[d][X], staples[X], p.beta, relax);
588
589 } else {
590 // now this branch goes to fake T extension
591 // first other besides t=0 or 1 slices, more or less std update
592
593 onsites(par) {
594 if (X.t() != 0 && (d == e_t || X.t() != 1)) {
595 suN_update(U[d][X], staples[X], p.beta, relax);
596 }
597 }
598
599 // then t=0,1 slices if d!=e_t
600 if (d != e_t) {
601 // need to get staples again - shifted suitably!
602 // staples only for t==0 slice
603 staplesum_T_slice(U, staples, par, d);
604
605 onsites(par) if (X.t() == 0) {
606 suN_update(U[d][X], staples[X], p.beta, relax);
607 }
608
609 // Copy now U from t=0 to t=1
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];
613 }
614 // set the t-links to unity, should be that in any case?
615 onsites(ALL) if (X.t() == 0) {
616 U[e_t][X] = 1;
617 }
618 }
619 }
620
621 if (relax)
622 or_timer.stop();
623 else
624 hb_timer.stop();
625}
626
627////////////////////////////////////////////////////////////////
628
629template <typename group>
630void do_trajectory(GaugeField<group> &U, const parameters &p) {
631
632 for (int n = 0; n < p.n_update; n++) {
633 for (int i = 0; i < p.n_overrelax; i++) {
634 update(U, p, true);
635 }
636 update(U, p, false);
637 }
639}
640
641////////////////////////////////////////////////////////////////
642
643double polyakov_potential(const parameters &p, const double poly) {
644
645 return p.poly_m2 * (sqr(poly - p.poly_min));
646}
647
648
649////////////////////////////////////////////////////////////////
650
651bool accept_polyakov(const parameters &p, const double p_old, const double p_new) {
652
653 if (p.polyakov_pot == poly_limit::PARABOLIC) {
654 double dpot = polyakov_potential(p, p_new) - polyakov_potential(p, p_old);
655
656 bool accept = hila::broadcast(hila::random() < exp(-dpot));
657
658 return accept;
659 } else {
660 if (p_new >= p.poly_min && p_new <= p.poly_max)
661 return true;
662 if (p_new > p.poly_max && p_new < p_old)
663 return true;
664 if (p_new < p.poly_min && p_new > p_old)
665 return true;
666 return false;
667 }
668}
669
670////////////////////////////////////////////////////////////////
671
672template <typename group>
673double update_once_with_range(GaugeField<group> &U, const parameters &p, double &poly, bool relax) {
674
675 Field<group> Ut_old;
676
677 Ut_old = U[e_t];
678
679 // spatial links always updated, t-links are conditional
680 // acc/rej separately for parities
681
682 foralldir(d) if (d < e_t) {
683 for (Parity par : {EVEN, ODD})
684 update_parity_dir(U, p, par, d, relax);
685 }
686
687 // t-links
688 double acc = 0;
689 for (Parity par : {EVEN, ODD}) {
690 update_parity_dir(U, p, par, e_t, relax);
691
692 double p_now = measure_polyakov(U).real();
693
694 bool acc_update = accept_polyakov(p, poly, p_now);
695
696 if (acc_update) {
697 poly = p_now;
698 acc += 0.5;
699 } else {
700 U[e_t][par] = Ut_old[X]; // restore rejected
701 }
702 }
703 return acc;
704}
705
706////////////////////////////////////////////////////////////////
707
708template <typename group>
709double trajectory_with_range(GaugeField<group> &U, const parameters &p, double &poly) {
710
711 double acc_or = 0;
712 double acc_hb = 0;
713
714 double p_now = measure_polyakov(U).real();
715
716 for (int n = 0; n < p.n_update; n++) {
717 for (int i = 0; i < p.n_overrelax; i++) {
718
719 // OR updates
720 acc_or += update_once_with_range(U, p, p_now, true);
721 }
722
723 // and then HBs
724
725 acc_hb += update_once_with_range(U, p, p_now, false);
726
728 }
729 return (acc_or + acc_hb) / (p.n_update * (p.n_overrelax + 1));
730}
731
732/////////////////////////////////////////////////////////////////
733
734
735int main(int argc, char **argv) {
736
737 // hila::initialize should be called as early as possible
738 hila::initialize(argc, argv);
739
740 // hila provides an input class hila::input, which is
741 // a convenient way to read in parameters from input files.
742 // parameters are presented as key - value pairs, as an example
743 // " lattice size 64, 64, 64, 64"
744 // is read below.
745 //
746 // Values are broadcast to all MPI nodes.
747 //
748 // .get() -method can read many different input types,
749 // see file "input.h" for documentation
750
751 parameters p;
752
753 hila::out0 << "SU(" << mygroup::size() << ") heat bath + overrelax update\n";
754
755 hila::input par("parameters");
756
757 CoordinateVector lsize;
758 lsize = par.get("lattice size"); // reads NDIM numbers
759
760 p.beta = par.get("beta");
761 // deltab sets system to different beta on different sides, by beta*(1 +- deltab)
762 // use for initial config generation only
763 p.deltab = par.get("delta beta fraction");
764 // trajectory length in steps
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");
769
770 // random seed = 0 -> get seed from time
771 uint64_t seed = par.get("random seed");
772 // save config and checkpoint
773 p.n_save = par.get("traj/saved");
774 // measure surface properties and print "profile"
775 p.config_file = par.get("config name");
776
777 // if polyakov range is off, do nothing with
778 int p_item = par.get_item("polyakov potential", {"off", "min", "range"});
779 if (p_item == 0) {
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");
785 } else {
786 p.polyakov_pot = poly_limit::RANGE;
788 r = par.get();
789 p.poly_min = r[0];
790 p.poly_max = r[1];
791 }
792
793 if (par.get_item("updates/profile meas", {"off", "%i"}) == 1) {
794 p.n_profile = par.get();
795 } else {
796 p.n_profile = 0;
797 }
798
799 if (p.n_profile) {
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");
805
806 if (p.n_smear.size() != p.z_smear.size()) {
807 hila::out0 << "Error in input file: number of values in 'smearing steps' != 'z "
808 "smearing steps'\n";
810 }
811
812 } else {
813 p.n_dump_polyakov = 0;
814 }
815
816 par.close(); // file is closed also when par goes out of scope
817
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;
822 } else {
823 p.odd_T_extent = false;
824 }
825
826 // setting up the lattice is convenient to do after reading
827 // the parameter
828 lattice.setup(lsize);
829
830 // Alloc gauge field
832
833 U = 1;
834
835 // use negative trajectory for thermal
836 int start_traj = -p.n_thermal;
837
838 hila::timer update_timer("Updates");
839 hila::timer measure_timer("Measurements");
840
841 restore_checkpoint(U, p.config_file, p.n_trajectories, start_traj);
842
843 // We need random number here
844 if (!hila::is_rng_seeded())
845 hila::seed_random(seed);
846
847 double p_now = measure_polyakov(U).real();
848
849 for (int trajectory = start_traj; trajectory < p.n_trajectories; trajectory++) {
850
851 double ttime = hila::gettime();
852
853 update_timer.start();
854
855 double acc = 0;
856 if (p.polyakov_pot != poly_limit::OFF) {
857 acc += trajectory_with_range(U, p, p_now);
858 } else {
859 do_trajectory(U, p);
860 }
861
862 // put sync here in order to get approx gpu timing
863 hila::synchronize_threads();
864 update_timer.stop();
865
866 // trajectory is negative during thermalization
867 if (trajectory >= 0) {
868 measure_timer.start();
869
870 hila::out0 << "Measure_start " << trajectory << '\n';
871
872 measure_stuff(U, p);
873
874 if (p.n_profile && (trajectory + 1) % p.n_profile == 0) {
875 measure_polyakov_surface(U, p, trajectory);
876 measure_plaq_profile(U);
877 }
878
879 if (p.n_dump_polyakov && (trajectory + 1) % p.n_dump_polyakov == 0) {
880 Field<float> pl;
881 std::ofstream poly;
882 if (hila::myrank() == 0) {
883 poly.open("polyakov", std::ios::out | std::ios::app);
884 }
885 measure_polyakov_field(U[e_t], pl);
886 pl.write_slice(poly, {-1, -1, -1, 0});
887 }
888
889 if (p.polyakov_pot != poly_limit::OFF) {
890 hila::out0 << "ACCP " << acc << '\n';
891 }
892
893 hila::out0 << "Measure_end " << trajectory << std::endl;
894
895 measure_timer.stop();
896 }
897
898 if (p.n_save > 0 && (trajectory + 1) % p.n_save == 0) {
899 checkpoint(U, p.config_file, p.n_trajectories, trajectory);
900 }
901 }
902
904}
Array< n, m, T > exp(Array< n, m, T > a)
Exponential.
Definition array.h:1059
Array< n, m, hila::arithmetic_type< T > > real(const Array< n, m, T > &arg)
Return real part of Array.
Definition array.h:688
Complex definition.
Definition cmplx.h:56
T squarenorm() const
Compute square norm of Complex number.
Definition cmplx.h:248
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
Definition field.h:61
std::vector< T > get_slice(const CoordinateVector &c, bool broadcast=false) const
and get a slice (subvolume)
Definition field_comm.h:703
Gauge field class.
Definition gaugefield.h:22
void reunitarize_gauge()
Reunitarize Gauge Field consisting of matrices.
Definition gaugefield.h:94
static constexpr int size()
Returns size of Vector or square Matrix.
Definition matrix.h:248
Matrix class which defines matrix operations.
Definition matrix.h:1620
Special reduction class: enables delayed and non-blocking reductions, which are not possible with the...
Definition reduction.h:14
const T value()
Return value of the reduction variable. Wait for the comms if needed.
Definition reduction.h:157
Reduction & allreduce(bool b=true)
allreduce(bool) turns allreduce on or off. By default on.
Definition reduction.h:130
Class for SU(N) matrix.
Definition sun_matrix.h:110
hila::input - Class for parsing runtime parameter files.
Definition input.h:52
void setup(const CoordinateVector &siz)
General lattice setup.
Definition lattice.cpp:33
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Definition cmplx.h:1223
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)
Definition coordinates.h:78
constexpr Parity ODD
bit pattern: 010
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
constexpr T sqr(const T &arg)
Define convenience function sqr(), returning square of argument.
Definition defs.h:154
Implement hila::swap for gauge fields.
Definition array.h:981
auto shuffle_directions_and_parities()
Definition shuffle.h:49
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:121
int myrank()
rank of this node
Definition com_mpi.cpp:234
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...
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:152
double gettime()
Definition timing.cpp:163
bool is_rng_seeded()
Check if RNG is seeded already.
Definition random.cpp:243
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.
Definition polyakov.h:17
void staplesum(const GaugeField< T > &U, Field< T > &staples, Direction d1, Parity par=ALL)
Sum the staples of link matrices to direction dir.
Definition staples.h:28
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.
int z_ind(int z)
Helper function to get valid z-coordinate index.
Definition suN_gauge.cpp:29
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
void suN_overrelax(SU< N, T > &U, const SU< N, T > &staple)
Overrelaxation using SU(2) subgroups