HILA
Loading...
Searching...
No Matches
gradient_flow.h
Go to the documentation of this file.
1/** @file gradient_flow.h */
2
3#ifndef GRADIENT_FLOW_H_
4#define GRADIENT_FLOW_H_
5
6#include "hila.h"
10#include "gauge/clover_action.h"
12
13#ifdef GFLOWACTION
14#define GFLOWS GFLOWACTION
15#else
16#define GFLOWS 3
17#endif
18
19#if GFLOWS == 1
21#elif GFLOWS > 1
22#if GFLOWS < 5
24#else
26#endif
27#endif
28
29#include "tools/string_format.h"
30
31
32template <typename group, typename atype = hila::arithmetic_type<group>>
33void get_gf_force(const GaugeField<group> &U, VectorField<Algebra<group>> &E) {
34 // wrapper for force computation routine to be used for gradient flow
35
36 atype eps = 1.0; // in principle need factor 2.0 here to switch from unoriented to oriented
37 // plaquettes (factor is usually absorbed in \beta, but gradient flow force
38 // is computed from action term with \beta-factor stripped off)
39 // however; it seems that in practice factor 1.0 is used.
40 // note: when switching to factor 2.0, remember to change also the stability
41 // limit in the do_gradient_flow_adapt() below
42
43#if GFLOWS == 1 // Bulk-Prevention (BP)
44 get_force_bp(U, E, eps);
45#elif GFLOWS == 2 // Luscher-Weisz (LW)
46 atype c12 = -1.0 / 12.0; // rectangle weight
47 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
48 get_force_impr(U, E, eps * c11, eps * c12);
49#elif GFLOWS == 3 // IWASAKI
50 atype c12 = -0.331; // rectangle weight
51 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
52 get_force_impr(U, E, eps * c11, eps * c12);
53#elif GFLOWS == 4 // DBW2
54 atype c12 = -1.4088; // rectangle weight
55 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
56 get_force_impr(U, E, eps * c11, eps * c12);
57#elif GFLOWS == 5 // LOG-PLAQUETTE
58 get_force_log_plaq(U, E, eps);
59#else // WILSON
60 get_force_wplaq(U, E, eps);
61#endif
62
63 // 2/9*BP+7/9*Wilson
64 // get_force_bp(U,E,eps*2.0/9.0);
65 // get_force_wplaq_add(U,E,eps*7.0/9.0);
66};
67
68template <typename group, typename atype = hila::arithmetic_type<group>>
69atype measure_gf_s(const GaugeField<group> &U) {
70 // wrapper for gauge action computation routine
71 // (for gauge action that is used to evolve the flow)
72#if GFLOWS == 1 // BP
73 atype res = measure_s_bp(U);
74#elif GFLOWS == 2 // LW
75 atype c12 = -1.0 / 12.0; // rectangle weight
76 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
77 atype res = measure_s_impr(U, c11, c12);
78#elif GFLOWS == 3 // IWASAKI
79 atype c12 = -0.331; // rectangle weight
80 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
81 atype res = measure_s_impr(U, c11, c12);
82#elif GFLOWS == 4 // DBW2
83 atype c12 = -1.4088; // rectangle weight
84 atype c11 = 1.0 - 8.0 * c12; // plaquette weight
85 atype res = measure_s_impr(U, c11, c12);
86#elif GFLOWS == 5 // LOG-PLAQUETTE
87 atype res = measure_s_log_plaq(U);
88#else // WILSON
89 atype res = measure_s_wplaq(U);
90#endif
91
92 // 2/9*BP+7/9*Wilson
93 // atype res=measure_s_bp(U,E,eps*2.0/9.0)+measure_s_wplaq(U,E,eps*7.0/9.0);
94
95 return res;
96}
97
98template <typename group, typename atype = hila::arithmetic_type<group>>
99atype measure_dE_wplaq_dt(const GaugeField<group> &U) {
100 Reduction<double> de = 0;
101 de.allreduce(false).delayed(true);
103 get_gf_force(U, K);
104 get_force_wplaq(U, Kc, -2.0);
105 foralldir(d) {
106 onsites(ALL) {
107 de += Kc[d][X].dot(K[d][X]);
108 }
109 }
110 return (atype)de.value();
111}
112
113template <typename group, typename atype = hila::arithmetic_type<group>>
114atype measure_dE_clov_dt(const GaugeField<group> &U) {
115 Reduction<double> de = 0;
116 de.allreduce(false).delayed(true);
118 get_gf_force(U, K);
119 get_force_clover(U, Kc, -2.0);
120 foralldir(d) {
121 onsites(ALL) {
122 de += Kc[d][X].dot(K[d][X]);
123 }
124 }
125 return (atype)de.value();
126}
127
128template <typename group, typename atype = hila::arithmetic_type<group>>
129atype measure_dE_log_dt(const GaugeField<group> &U) {
130 Reduction<double> de = 0;
131 de.allreduce(false).delayed(true);
133 get_gf_force(U, K);
134 get_force_log(U, Kc, -2.0);
135 foralldir(d) {
136 onsites(ALL) {
137 de += Kc[d][X].dot(K[d][X]);
138 }
139 }
140 return (atype)de.value();
141}
142
143template <typename group, typename atype = hila::arithmetic_type<group>>
144void measure_gradient_flow_stuff(const GaugeField<group> &V, atype flow_l, atype t_step) {
145 // perform measurements on flowed gauge configuration V at flow scale flow_l
146 // [t_step is the flow time integration step size used in last gradient flow step]
147 // and print results in formatted form to standard output
148 static bool first = true;
149 if (first) {
150 // print info about used flow action
151#if GFLOWS == 1 // BP
152 hila::out0 << "GFINFO using bulk-prevention action\n";
153#elif GFLOWS == 2 // LW
154 hila::out0 << "GFINFO using Luscher-Weisz action\n";
155#elif GFLOWS == 3 // IWASAKI
156 hila::out0 << "GFINFO using Iwasaki action\n";
157#elif GFLOWS == 4 // DBW2
158 hila::out0 << "GFINFO using DBW2 action\n";
159#elif GFLOWS == 5 // LOG-PLAQUETTE
160 hila::out0 << "GFINFO using log-plaquette action\n";
161#else // WILSON
162 hila::out0 << "GFINFO using Wilson's plaquette action\n";
163#endif
164 // print legend for flow measurement output
165 hila::out0 << "LGFLMEAS l(ambda) S-flow S-plaq E_plaq dE_plaq/dl "
166 " E_clv dE_clv/dl Qtopo_clv E_log dE_log/dl "
167 "Qtopo_log [t_step_size] [max_S-plaq]\n";
168 first = false;
169 }
170 atype slocal = measure_gf_s(V) /
171 (lattice.volume() * NDIM * (NDIM - 1) / 2); // average action per plaquette
172
173 atype max_plaq = 0;
174 atype plaq = measure_s_wplaq(V, max_plaq) /
175 (lattice.volume() * NDIM * (NDIM - 1) / 2); // average wilson plaquette action
176 atype eplaq = plaq * NDIM * (NDIM - 1) *
177 group::size(); // naive energy density (based on wilson plaquette action)
178
179 // average energy density and toplogical charge from
180 // clover definition of field strength tensor :
181 atype qtopocl, ecl;
182 measure_topo_charge_and_energy_clover(V, qtopocl, ecl);
183 ecl /= lattice.volume();
184
185 // average energy density and toplogical charge from
186 // symmetric log definition of field strength tensor :
187 atype qtopolog, elog;
188 measure_topo_charge_and_energy_log(V, qtopolog, elog);
189 elog /= lattice.volume();
190
191 // derivative of plaquette energy density w.r.t. to flow time :
192 atype deplaqdt = measure_dE_wplaq_dt(V) / lattice.volume();
193
194 // derivative of clover energy density w.r.t. to flow time :
195 atype declovdt = measure_dE_clov_dt(V) / lattice.volume();
196
197 // derivative of log energy density w.r.t. to flow time :
198 atype delogdt = measure_dE_log_dt(V) / lattice.volume();
199
200 // print formatted results to standard output :
201 hila::out0 << string_format("GFLMEAS % 9.3f % 0.6e % 0.6e % 0.6e % 0.6e % 0.6e % 0.6e % 0.6e "
202 "% 0.6e % 0.6e % 0.6e [%0.3e] [%0.3e]",
203 flow_l, slocal, plaq, eplaq, 0.25 * flow_l * deplaqdt, ecl,
204 0.25 * flow_l * declovdt, qtopocl, elog, 0.25 * flow_l * delogdt,
205 qtopolog, t_step, max_plaq)
206 << '\n';
207}
208
209template <typename group, typename atype = hila::arithmetic_type<group>>
210atype do_gradient_flow_adapt(GaugeField<group> &V, atype l_start, atype l_end, atype atol = 1.0e-6,
211 atype rtol = 1.0e-4, atype tstep = 0.0) {
212 // wilson flow integration from flow scale l_start to l_end using 3rd order
213 // 3-step Runge-Kutta (RK3) from arXiv:1006.4518 (cf. appendix C of
214 // arXiv:2101.05320 for derivation of this Runge-Kutta method)
215 // and embedded RK2 for adaptive step size
216
217 atype esp = 3.0; // expected single step error scaling power: err ~ step^(esp)
218 // - for RK3 with embedded RK2: esp \approx 3.0
219 atype iesp = 1.0 / esp; // inverse single step error scaling power
220
221 atype stepmf = 1.0;
222 atype maxstepmf = 10.0; // max. growth factor of adaptive step size
223 atype minstepmf = 0.1; // min. growth factor of adaptive step size
224
225 // translate flow scale interval [l_start,l_end] to corresponding
226 // flow time interval [t,tmax] :
227 atype t = l_start * l_start / 8.0;
228 atype tmax = l_end * l_end / 8.0;
229
230 atype ubstep = (tmax - t) / 2.0; // max. allowed time step
231
232 atype tatol = atol * sqrt(2.0);
233
234 // hila::out0<<"t: "<<t<<" , tmax: "<<tmax<<" , step: "<<tstep<<" , minmaxreldiff:
235 // "<<minmaxreldiff<<"\n";
236
237 // temporary variables :
238 VectorField<Algebra<group>> k1, k2, tk;
239 GaugeField<group> V2, V0;
240 Field<atype> reldiff;
241
242 // RK3 coefficients from arXiv:1006.4518 :
243 // correspond to standard RK3 with Butcher-tableau
244 // (cf. arXiv:2101.05320, Appendix C)
245 // 0 | 0 0 0
246 // # | 1/4 0 0
247 // # | -2/9 8/9 0
248 // -------------------------
249 // | 1/4 0 3/4
250 //
251 atype a11 = 0.25;
252 atype a21 = -17.0 / 36.0, a22 = 8.0 / 9.0;
253 atype a33 = 0.75;
254
255 // RK2 coefficients :
256 // cf. Alg. 6 and Eqn. (13)-(14) in arXiv:2101.05320 to see
257 // how these are obtained from standard RK2 with Butcher-tableau
258 // 0 | 0 0
259 // # | 1/4 0
260 // -----------------
261 // | -1 2
262 //
263 atype b21 = -1.25, b22 = 2.0;
264
265 atype step = min(tstep, ubstep); // initial step size
266
267 if (t == 0 || step == 0) {
268 // when using a gauge action for gradient flow that is different from
269 // the one used to sample the gauge cofingurations, the initial force
270 // can be huge. Therefore, if no t_step is provided as input, the inital
271 // value for step is here adjustet so that
272 // step * <largest local force> = maxstk
273 atype maxstk = 1.0e-1;
274
275 // get max. local gauge force:
276 get_gf_force(V, tk);
277 atype maxtk = 0.0;
278 foralldir(d) {
279 onsites(ALL) {
280 reldiff[X] = (tk[d][X].squarenorm());
281 }
282 atype tmaxtk = reldiff.max();
283 if(tmaxtk>maxtk) {
284 maxtk = tmaxtk;
285 }
286 }
287 maxtk = sqrt(0.5 * maxtk);
288
289 if (step == 0) {
290 if (maxtk > maxstk) {
291 step = min(maxstk / maxtk,
292 ubstep); // adjust initial step size based on max. force magnitude
293 hila::out0 << "GFINFO using max. gauge force (max_X |F(X)|=" << maxtk
294 << ") to set initial flow time step size: " << step << "\n";
295 } else {
296 step = min((atype)1.0, ubstep);
297 }
298 } else if (step * maxtk > maxstk) {
299 step = min(maxstk / maxtk,
300 ubstep); // adjust initial step size based on max. force magnitude
301 hila::out0 << "GFINFO using max. gauge force (max_X |F(X)|=" << maxtk
302 << ") to set initial flow time step size: " << step << "\n";
303 }
304 }
305
306
307 V0 = V;
308 bool stop = false;
309 while (t < tmax && !stop) {
310 tstep = step;
311 if (t + step >= tmax) {
312 step = tmax - t;
313 stop = true;
314 }
315
316 get_gf_force(V, k1);
317 foralldir(d) onsites(ALL) {
318 // first steps of RK3 and RK2 are the same :
319 V[d][X] = chexp(k1[d][X] * (step * a11)) * V[d][X];
320 }
321
322 get_gf_force(V, k2);
323 foralldir(d) onsites(ALL) {
324 // second step of RK2 :
325 // (tk[d][X] will be used for rel. error computation)
326 tk[d][X] = k2[d][X];
327 tk[d][X] *= (step * b22);
328 tk[d][X] += k1[d][X] * (step * b21);
329 V2[d][X] = chexp(tk[d][X]) * V[d][X];
330
331 // second step of RK3 :
332 k2[d][X] *= (step * a22);
333 k2[d][X] += k1[d][X] * (step * a21);
334 V[d][X] = chexp(k2[d][X]) * V[d][X];
335 }
336
337 get_gf_force(V, k1);
338 foralldir(d) onsites(ALL) {
339 // third step of RK3 :
340 k1[d][X] *= (step * a33);
341 k1[d][X] -= k2[d][X];
342 V[d][X] = chexp(k1[d][X]) * V[d][X];
343 }
344
345 // determine maximum difference between RK3 and RK2,
346 // relative to desired accuracy :
347 atype relerr = 0.0;
348 foralldir(d) {
349 onsites(ALL) {
350 reldiff[X] = (V2[d][X] * V[d][X].dagger()).project_to_algebra().norm() /
351 (tatol + rtol * tk[d][X].norm() / step);
352 // note: we divide tk.norm() by step to have consistent leading stepsize dependency
353 // no mather whether relative or absolute error tollerance dominates
354 }
355 atype trelerr = reldiff.max();
356 if (trelerr > relerr) {
357 relerr = trelerr;
358 }
359 }
360
361 if (relerr < 1.0) {
362 // proceed to next iteration
363 t += step;
365 V0 = V;
366 } else {
367 // repeat current iteration if single step error was too large
368 V = V0;
369 stop = false;
370 }
371
372 // determine step size to achieve desired accuracy goal :
373 stepmf = pow(relerr, -iesp);
374 if (stepmf <= minstepmf) {
375 stepmf = minstepmf;
376 } else if (stepmf >= maxstepmf) {
377 stepmf = maxstepmf;
378 }
379
380 // adjust step size :
381 step = min((atype)0.9 * stepmf * step, ubstep);
382 }
383
384 return tstep;
385}
386
387#endif
Array< n, m, T > sqrt(Array< n, m, T > a)
Square root.
Definition array.h:1039
Array< n, m, T > pow(Array< n, m, T > a, int b)
Power.
Definition array.h:1204
Definition su2.h:7
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
Definition field.h:61
T max(Parity par=ALL) const
Find maximum value from Field.
Definition reduction.h:424
double norm()
Norm.
Definition field.h:1101
Gauge field class.
Definition gaugefield.h:22
void reunitarize_gauge()
Reunitarize Gauge Field consisting of matrices.
Definition gaugefield.h:94
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
Reduction & delayed(bool b=true)
deferred(bool) turns deferred on or off. By default turns on.
Definition reduction.h:148
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
constexpr Parity ALL
bit pattern: 011
int chexp(const Matrix_t< n, m, T, MT > &mat, Matrix_t< n, m, T, MT > &omat, Mt(&pl)[n])
Calculate exp of a square matrix.
Definition matrix.h:2933
std::ostream out0
This writes output only from main process (node 0)