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