Grid 0.7.0
WilsonFlow.h
Go to the documentation of this file.
1/*************************************************************************************
2
3Grid physics library, www.github.com/paboyle/Grid
4
5Source file: ./lib/qcd/modules/plaquette.h
6
7Copyright (C) 2017
8
9Author: Guido Cossu <guido.cossu@ed.ac.uk>
10Author: Christopher Kelly <ckelly@bnl.gov>
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation; either version 2 of the License, or
15(at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License along
23with this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
26See the full license in the file "LICENSE" in the top level distribution
27directory
28*************************************************************************************/
29 /* END LEGAL */
30
31#pragma once
32
34
35template <class Gimpl>
36class WilsonFlowBase: public Smear<Gimpl>{
37public:
38 //Store generic measurements to take during smearing process using std::function
39 typedef std::function<void(int, RealD, const typename Gimpl::GaugeField &)> FunctionType; //int: step, RealD: flow time, GaugeField : the gauge field
40
41protected:
42 std::vector< std::pair<int, FunctionType> > functions; //The int maps to the measurement frequency
43
45
46public:
48
49//Define the action used to evolve the plaquettes
50//(Lüscher: https://arxiv.org/pdf/1006.4518 eq. 1.4)
51//V'(t) = -g^2 * ( d/dVt S[Vt](g) ) * Vt
52// = -g^2 * ( d/dVt (1/g^2 * sum_p Re tr{ 1 - Vt(p) } ) ) * Vt
53// = - d/dVt ( sum_p ( Nc - Re tr Vt(p) ) * Vt
54// = - d/dVt ( Nc * sum_p ( 1 - Re tr Vt(p)/Nc ) ) * Vt
55// = - d/dVt SG[Vt](Nc) * Vt
56 explicit WilsonFlowBase(unsigned int meas_interval =1):
57 SG(WilsonGaugeAction<Gimpl>(Gimpl::num_colours)) {
58 setDefaultMeasurements(meas_interval);
59 }
60
61 void resetActions(){ functions.clear(); }
62
63 void addMeasurement(int meas_interval, FunctionType meas){ functions.push_back({meas_interval, meas}); }
64
65 //Set the class to perform the default measurements:
66 //the plaquette energy density every step
67 //the plaquette topological charge every 'topq_meas_interval' steps
68 //and output to stdout
69 void setDefaultMeasurements(int topq_meas_interval = 1);
70
71 void derivative(GaugeField&, const GaugeField&, const GaugeField&) const override{
72 assert(0);
73 // undefined for WilsonFlow
74 }
75
76 //Compute t^2 <E(t)> for time t from the plaquette
77 static RealD energyDensityPlaquette(const RealD t, const GaugeField& U);
78
79 //Compute t^2 <E(t)> for time t from the 1x1 cloverleaf form
80 //t is the Wilson flow time
81 static RealD energyDensityCloverleaf(const RealD t, const GaugeField& U);
82
83 //Evolve the gauge field by Nstep steps of epsilon and return the energy density computed every interval steps
84 //The smeared field is output as V
85 std::vector<RealD> flowMeasureEnergyDensityPlaquette(GaugeField &V, const GaugeField& U, int measure_interval = 1);
86
87 //Version that does not return the smeared field
88 std::vector<RealD> flowMeasureEnergyDensityPlaquette(const GaugeField& U, int measure_interval = 1);
89
90
91 //Evolve the gauge field by Nstep steps of epsilon and return the Cloverleaf energy density computed every interval steps
92 //The smeared field is output as V
93 std::vector<RealD> flowMeasureEnergyDensityCloverleaf(GaugeField &V, const GaugeField& U, int measure_interval = 1);
94
95 //Version that does not return the smeared field
96 std::vector<RealD> flowMeasureEnergyDensityCloverleaf(const GaugeField& U, int measure_interval = 1);
97};
98
99//Basic iterative Wilson flow
100template <class Gimpl>
101class WilsonFlow: public WilsonFlowBase<Gimpl>{
102private:
103 int Nstep; //number of steps
104 RealD epsilon; //step size
105
106 //Evolve the gauge field by 1 step of size eps and update tau
107 void evolve_step(typename Gimpl::GaugeField &U, RealD &tau) const;
108
109public:
111
112 //Integrate the Wilson flow for Nstep steps of size epsilon
113 WilsonFlow(const RealD epsilon, const int Nstep, unsigned int meas_interval = 1): WilsonFlowBase<Gimpl>(meas_interval), Nstep(Nstep), epsilon(epsilon){}
114
115 void smear(GaugeField& out, const GaugeField& in) const override;
116};
117
118//Wilson flow with adaptive step size
119template <class Gimpl>
121private:
122 RealD init_epsilon; //initial step size
123 RealD maxTau; //integrate to t=maxTau
124 RealD tolerance; //integration error tolerance
125
126 //Evolve the gauge field by 1 step and update tau and the current time step eps
127 //
128 //If the step size eps is too large that a significant integration error results,
129 //the gauge field (U) and tau will not be updated and the function will return 0; eps will be adjusted to a smaller
130 //value for the next iteration.
131 //
132 //For a successful integration step the function will return 1
133 int evolve_step_adaptive(typename Gimpl::GaugeField&U, RealD &tau, RealD &eps) const;
134
135public:
137
138 WilsonFlowAdaptive(const RealD init_epsilon, const RealD maxTau, const RealD tolerance, unsigned int meas_interval = 1):
140
141 void smear(GaugeField& out, const GaugeField& in) const override;
142};
143
145// Implementations
147
148//Compute t^2 <E(t)> for time from the plaquette form
149//(Lüscher: https://arxiv.org/pdf/1006.4518 eq. 3.1)
150//E(t) = 2 * sum_p Retr{ 1 - Vt(p) } =
151// = 2 * sum_p ( Nc - Retr Vt(p) ) =
152// = 2 * Nc * sum_p ( 1 - Retr Vt(p)/Nc )
153// = 2 * SG[Vt](Nc)
154//We divide by the volume to get an energy density per site, as is convention
155template <class Gimpl>
157 static WilsonGaugeAction<Gimpl> SG(Gimpl::num_colours);
158 return 2.0 * t * t * SG.S(U)/U.Grid()->gSites();
159}
160
161//Compute t^2 <E(t)> for time from the 1x1 cloverleaf form
162template <class Gimpl>
164 typedef typename Gimpl::GaugeLinkField GaugeMat;
165 typedef typename Gimpl::GaugeField GaugeLorentz;
166
167 assert(Nd == 4);
168 //E = 1/2 tr( F_munu F_munu )
169 //However as F_numu = -F_munu, only need to sum the trace of the squares of the following 6 field strengths:
170 //F_01 F_02 F_03 F_12 F_13 F_23
171 GaugeMat F(U.Grid());
172 LatticeComplexD R(U.Grid());
173 R = Zero();
174
175 for(int mu=0;mu<3;mu++){
176 for(int nu=mu+1;nu<4;nu++){
178 R = R + trace(F*F);
179 }
180 }
181 ComplexD out = sum(R);
182 out = t*t*out / RealD(U.Grid()->gSites());
183 return -real(out); //minus sign necessary for +ve energy
184}
185
186
187template <class Gimpl>
188std::vector<RealD> WilsonFlowBase<Gimpl>::flowMeasureEnergyDensityPlaquette(GaugeField &V, const GaugeField& U, int measure_interval){
189 std::vector<RealD> out;
190 resetActions();
191 addMeasurement(measure_interval, [&out](int step, RealD t, const typename Gimpl::GaugeField &U){
192 std::cout << GridLogMessage << "[WilsonFlow] Computing plaquette energy density for step " << step << std::endl;
193 out.push_back( energyDensityPlaquette(t,U) );
194 });
195 smear(V,U);
196 return out;
197}
198
199template <class Gimpl>
200std::vector<RealD> WilsonFlowBase<Gimpl>::flowMeasureEnergyDensityPlaquette(const GaugeField& U, int measure_interval){
201 GaugeField V(U);
202 return flowMeasureEnergyDensityPlaquette(V,U, measure_interval);
203}
204
205template <class Gimpl>
206std::vector<RealD> WilsonFlowBase<Gimpl>::flowMeasureEnergyDensityCloverleaf(GaugeField &V, const GaugeField& U, int measure_interval){
207 std::vector<RealD> out;
208 resetActions();
209 addMeasurement(measure_interval, [&out](int step, RealD t, const typename Gimpl::GaugeField &U){
210 std::cout << GridLogMessage << "[WilsonFlow] Computing Cloverleaf energy density for step " << step << std::endl;
211 out.push_back( energyDensityCloverleaf(t,U) );
212 });
213 smear(V,U);
214 return out;
215}
216
217template <class Gimpl>
218std::vector<RealD> WilsonFlowBase<Gimpl>::flowMeasureEnergyDensityCloverleaf(const GaugeField& U, int measure_interval){
219 GaugeField V(U);
220 return flowMeasureEnergyDensityCloverleaf(V,U, measure_interval);
221}
222
223template <class Gimpl>
225 addMeasurement(meas_interval, [](int step, RealD t, const typename Gimpl::GaugeField &U){
226 std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : " << step << " " << t << " " << energyDensityPlaquette(t,U) << std::endl;
227 });
228 addMeasurement(meas_interval, [](int step, RealD t, const typename Gimpl::GaugeField &U){
229 std::cout << GridLogMessage << "[WilsonFlow] Energy density (cloverleaf) : " << step << " " << t << " " << energyDensityCloverleaf(t,U) << std::endl;
230 });
231 addMeasurement(meas_interval, [](int step, RealD t, const typename Gimpl::GaugeField &U){
232 std::cout << GridLogMessage << "[WilsonFlow] Top. charge : " << step << " " << WilsonLoops<Gimpl>::TopologicalCharge(U) << std::endl;
233 });
234}
235
236
237
238template <class Gimpl>
239void WilsonFlow<Gimpl>::evolve_step(typename Gimpl::GaugeField &U, RealD &tau) const{
240 GaugeField Z(U.Grid());
241 GaugeField tmp(U.Grid());
242 this->SG.deriv(U, Z);
243 Z *= 0.25; // Z0 = 1/4 * F(U)
244 Gimpl::update_field(Z, U, -2.0*epsilon); // U = W1 = exp(ep*Z0)*W0
245
246 Z *= -17.0/8.0;
247 this->SG.deriv(U, tmp); Z += tmp; // -17/32*Z0 +Z1
248 Z *= 8.0/9.0; // Z = -17/36*Z0 +8/9*Z1
249 Gimpl::update_field(Z, U, -2.0*epsilon); // U_= W2 = exp(ep*Z)*W1
250
251 Z *= -4.0/3.0;
252 this->SG.deriv(U, tmp); Z += tmp; // 4/3*(17/36*Z0 -8/9*Z1) +Z2
253 Z *= 3.0/4.0; // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2
254 Gimpl::update_field(Z, U, -2.0*epsilon); // V(t+e) = exp(ep*Z)*W2
255 tau += epsilon;
256}
257
258template <class Gimpl>
259void WilsonFlow<Gimpl>::smear(GaugeField& out, const GaugeField& in) const{
260 std::cout << GridLogMessage
261 << "[WilsonFlow] Nstep : " << Nstep << std::endl;
262 std::cout << GridLogMessage
263 << "[WilsonFlow] epsilon : " << epsilon << std::endl;
264 std::cout << GridLogMessage
265 << "[WilsonFlow] full trajectory : " << Nstep * epsilon << std::endl;
266
267 out = in;
268 RealD taus = 0.;
269
270 // Perform initial t=0 measurements
271 for(auto const &meas : this->functions)
272 meas.second(0,taus,out);
273
274 for (unsigned int step = 1; step <= Nstep; step++) { //step indicates the number of smearing steps applied at the time of measurement
275 auto start = std::chrono::high_resolution_clock::now();
276 evolve_step(out, taus);
277 auto end = std::chrono::high_resolution_clock::now();
278 std::chrono::duration<double> diff = end - start;
279#ifdef WF_TIMING
280 std::cout << "Time to evolve " << diff.count() << " s\n";
281#endif
282 //Perform measurements
283 for(auto const &meas : this->functions)
284 if( step % meas.first == 0 ) meas.second(step,taus,out);
285 }
286}
287
288
289
290template <class Gimpl>
291int WilsonFlowAdaptive<Gimpl>::evolve_step_adaptive(typename Gimpl::GaugeField &U, RealD &tau, RealD &eps) const{
292 if (maxTau - tau < eps){
293 eps = maxTau-tau;
294 }
295 //std::cout << GridLogMessage << "Integration epsilon : " << epsilon << std::endl;
296 GaugeField Z(U.Grid());
297 GaugeField Zprime(U.Grid());
298 GaugeField tmp(U.Grid()), Uprime(U.Grid()), Usave(U.Grid());
299 Uprime = U;
300 Usave = U;
301
302 this->SG.deriv(U, Z);
303 Zprime = -Z;
304 Z *= 0.25; // Z0 = 1/4 * F(U)
305 Gimpl::update_field(Z, U, -2.0*eps); // U = W1 = exp(ep*Z0)*W0
306
307 Z *= -17.0/8.0;
308 this->SG.deriv(U, tmp); Z += tmp; // -17/32*Z0 +Z1
309 Zprime += 2.0*tmp;
310 Z *= 8.0/9.0; // Z = -17/36*Z0 +8/9*Z1
311 Gimpl::update_field(Z, U, -2.0*eps); // U_= W2 = exp(ep*Z)*W1
312
313
314 Z *= -4.0/3.0;
315 this->SG.deriv(U, tmp); Z += tmp; // 4/3*(17/36*Z0 -8/9*Z1) +Z2
316 Z *= 3.0/4.0; // Z = 17/36*Z0 -8/9*Z1 +3/4*Z2
317 Gimpl::update_field(Z, U, -2.0*eps); // V(t+e) = exp(ep*Z)*W2
318
319 // Ramos arXiv:1301.4388
320 Gimpl::update_field(Zprime, Uprime, -2.0*eps); // V'(t+e) = exp(ep*Z')*W0
321
322 // Compute distance using Ramos' definition
323 GaugeField diffU = U - Uprime;
324 RealD max_dist = 0;
325
326 for(int mu=0;mu<Nd;mu++){
327 typename Gimpl::GaugeLinkField diffU_mu = PeekIndex<LorentzIndex>(diffU, mu);
328 RealD dist_mu = sqrt( maxLocalNorm2(diffU_mu) ) /Nc/Nc; //maximize over sites
329 max_dist = std::max(max_dist, dist_mu); //maximize over mu
330 }
331
332 int ret;
333 if(max_dist < tolerance) {
334 tau += eps;
335 ret = 1;
336 } else {
337 U = Usave;
338 ret = 0;
339 }
340 eps = eps*0.95*std::pow(tolerance/max_dist,1./3.);
341 std::cout << GridLogMessage << "Adaptive smearing : Distance: "<< max_dist <<" Step successful: " << ret << " New epsilon: " << eps << std::endl;
342
343 return ret;
344}
345
346template <class Gimpl>
347void WilsonFlowAdaptive<Gimpl>::smear(GaugeField& out, const GaugeField& in) const{
348 std::cout << GridLogMessage
349 << "[WilsonFlow] initial epsilon : " << init_epsilon << std::endl;
350 std::cout << GridLogMessage
351 << "[WilsonFlow] full trajectory : " << maxTau << std::endl;
352 std::cout << GridLogMessage
353 << "[WilsonFlow] tolerance : " << tolerance << std::endl;
354 out = in;
355 RealD taus = 0.;
356 RealD eps = init_epsilon;
357 unsigned int step = 0;
358
359 // Perform initial t=0 measurements
360 for(auto const &meas : this->functions)
361 meas.second(step,taus,out);
362
363 do{
364 int step_success = evolve_step_adaptive(out, taus, eps);
365 step += step_success; //step will not be incremented if the integration step fails
366
367 //Perform measurements
368 if(step_success)
369 for(auto const &meas : this->functions)
370 if( step % meas.first == 0 ) meas.second(step,taus,out);
371 } while (taus < maxTau);
372}
373
374
375
377
#define INHERIT_GIMPL_TYPES(GImpl)
accelerator_inline Grid_simd2< S, V > trace(const Grid_simd2< S, V > &arg)
accelerator_inline Grid_simd< S, V > sqrt(const Grid_simd< S, V > &r)
auto PeekIndex(const Lattice< vobj > &lhs, int i) -> Lattice< decltype(peekIndex< Index >(vobj(), i))>
Lattice< vobj > real(const Lattice< vobj > &lhs)
RealD maxLocalNorm2(const Lattice< vobj > &arg)
vobj::scalar_object sum(const vobj *arg, Integer osites)
GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL")
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
Lattice< vTComplexD > LatticeComplexD
Definition QCD.h:361
static constexpr int Nd
Definition QCD.h:52
static constexpr int Nc
Definition QCD.h:50
std::complex< RealD > ComplexD
Definition Simd.h:79
double RealD
Definition Simd.h:61
static INTERNAL_PRECISION U
Definition Zolotarev.cc:230
static INTERNAL_PRECISION F
Definition Zolotarev.cc:230
virtual void smear(GaugeField &, const GaugeField &) const =0
int evolve_step_adaptive(typename Gimpl::GaugeField &U, RealD &tau, RealD &eps) const
Definition WilsonFlow.h:291
WilsonFlowAdaptive(const RealD init_epsilon, const RealD maxTau, const RealD tolerance, unsigned int meas_interval=1)
Definition WilsonFlow.h:138
void smear(GaugeField &out, const GaugeField &in) const override
Definition WilsonFlow.h:347
void setDefaultMeasurements(int topq_meas_interval=1)
Definition WilsonFlow.h:224
void addMeasurement(int meas_interval, FunctionType meas)
Definition WilsonFlow.h:63
void derivative(GaugeField &, const GaugeField &, const GaugeField &) const override
Definition WilsonFlow.h:71
static RealD energyDensityCloverleaf(const RealD t, const GaugeField &U)
Definition WilsonFlow.h:163
WilsonGaugeAction< Gimpl > SG
Definition WilsonFlow.h:44
std::vector< std::pair< int, FunctionType > > functions
Definition WilsonFlow.h:42
std::function< void(int, RealD, const typename Gimpl::GaugeField &)> FunctionType
Definition WilsonFlow.h:39
static RealD energyDensityPlaquette(const RealD t, const GaugeField &U)
Definition WilsonFlow.h:156
void resetActions()
Definition WilsonFlow.h:61
std::vector< RealD > flowMeasureEnergyDensityCloverleaf(GaugeField &V, const GaugeField &U, int measure_interval=1)
Definition WilsonFlow.h:206
std::vector< RealD > flowMeasureEnergyDensityPlaquette(GaugeField &V, const GaugeField &U, int measure_interval=1)
Definition WilsonFlow.h:188
WilsonFlowBase(unsigned int meas_interval=1)
Definition WilsonFlow.h:56
void smear(GaugeField &out, const GaugeField &in) const override
Definition WilsonFlow.h:259
WilsonFlow(const RealD epsilon, const int Nstep, unsigned int meas_interval=1)
Definition WilsonFlow.h:113
void evolve_step(typename Gimpl::GaugeField &U, RealD &tau) const
Definition WilsonFlow.h:239
RealD epsilon
Definition WilsonFlow.h:104
The Wilson gauge action, as introduced in Wilson, Phys. Rev. D 10, 2445. See for example Gattringer a...
static void FieldStrength(GaugeMat &FS, const GaugeLorentz &Umu, int mu, int nu)
static Real TopologicalCharge(const GaugeLorentz &U)
Definition Simd.h:194