HILA
Loading...
Searching...
No Matches
smearing.h
1#ifndef SMEARING_H
2#define SMEARING_H
3
4#include "datatypes/sun.h"
5#include "hmc/gauge_field.h"
6
7/// Calculate the exponential of Q and the matrix lambda=d/dQ (e^Q m0)
8template <typename sun>
9void exp_and_derivative(sun &Q, sun &m0, sun &lambda, sun &eQ, int exp_steps) {
10 sun m1, qn;
11 eQ = 1;
12 qn = Q;
13 double n = 1.0;
14 m1 = m0;
15 if (exp_steps == 0) {
16 lambda = 0;
17 } else {
18 lambda = m1;
19 eQ = eQ + Q;
20 }
21 // gamma matrix (morningstar paper, eq 74)
22 for (int k = 2; k <= exp_steps; k++) {
23 n = n * 1.0 / ((double)k);
24 m1 = m0 * qn + Q * m1;
25 qn = qn * Q;
26 eQ = eQ + n * qn;
27 // lambda = 1/(n+1)!*m1
28 // hila::out0 << " * " << 1.0/n << "\n";
29 lambda = lambda + m1 * n;
30 }
31}
32
33/// Calculate the derivative of with respect to the links a positive and negative staple
34/// and add to result
35template <typename matrix, typename forcetype>
36void staple_dir_derivative(Field<matrix> &basegauge1, Field<matrix> &basegauge2,
37 Field<matrix> &Lambda, Field<forcetype> &result1,
38 Field<forcetype> &result2, Direction dir1, Direction dir2) {
39 Field<matrix> stapleder2, stapleder3; // Two derivatives that need to be communicated
40
41 onsites(ALL) {
42 matrix U1, U2, U3, U4, L, L2;
43 U1 = basegauge1[X];
44 U2 = basegauge2[X + dir1];
45 U3 = basegauge1[X + dir2];
46 U4 = basegauge2[X];
47 L = Lambda[X];
48 L2 = Lambda[X + dir2];
49
50 // Up staple
51 result2[X] += (L * U2 * U3.dagger()).dagger();
52 stapleder2[X] = U3.dagger() * U4.dagger() * L;
53 stapleder3[X] = (U4.dagger() * L * U2).dagger();
54
55 // Down staple
56 stapleder2[X] = stapleder2[X] + L2.dagger() * U4.dagger() * U1;
57 result1[X] += U2 * L2.dagger() * U4.dagger();
58 result2[X] += L2 * U2.dagger() * U1.dagger();
59 }
60
61 // Move derivatives up where necessary
62 onsites(ALL) {
63 result2[X] += stapleder2[X - dir1];
64 result1[X] += stapleder3[X - dir2];
65 }
66}
67
68/// A stout smeared gauge field built of a standard gauge field.
69/// The structure is the same as for the standard and represented
70/// gauge fields.
71/// refresh(): recalculates the smeared field from the underlying
72/// gauge field.
73/// add_momentum(): transforms a derivative with respect to this
74/// field to a derivative with respect to the underlying gauge
75/// field and add to the momentum of the gauge field.
76template <typename sun> class stout_smeared_field : public gauge_field_base<sun> {
77 public:
78 using gauge_type = sun;
79 using fund_type = sun;
80 using basetype = hila::arithmetic_type<sun>;
81 static constexpr int Nf = sun::size;
82 static constexpr int N = sun::size;
83
84 double c;
85 int smear_steps = 1;
86 int exp_steps = 10;
87
88 gauge_field<sun> &base_field;
89 Field<sun> **staples;
90 Field<sun> **smeared_fields;
91
93 : base_field(f), c(coeff) {
95 allocate();
96 }
97 stout_smeared_field(gauge_field<fund_type> &f, double coeff, int nsteps)
98 : base_field(f), c(coeff), smear_steps(nsteps) {
100 allocate();
101 }
102 stout_smeared_field(gauge_field<fund_type> &f, double coeff, int nsteps, int expsteps)
103 : base_field(f), c(coeff), smear_steps(nsteps), exp_steps(expsteps) {
105 allocate();
106 }
108 : base_field(r.base_field), c(r.c), smear_steps(r.smear_steps),
109 exp_steps(r.exp_steps) {
111 allocate();
112 }
113
114 void allocate() {
115 staples = (Field<sun> **)malloc(smear_steps * sizeof(Field<sun> *));
116 smeared_fields = (Field<sun> **)malloc(smear_steps * sizeof(Field<sun> *));
117 for (int step = 0; step < smear_steps - 1; step++) {
118 staples[step] = new Field<sun>[NDIM];
119 smeared_fields[step] = new Field<sun>[NDIM];
120 }
121 staples[smear_steps - 1] = new Field<sun>[NDIM];
122 smeared_fields[smear_steps - 1] = &(this->gauge[0]);
123 }
124
126 for (int step = 0; step < smear_steps - 1; step++) {
127 delete[] staples[step];
128 delete[] smeared_fields[step];
129 }
130 delete[] staples[smear_steps - 1];
131 free(staples);
132 free(smeared_fields);
133 }
134
135 // Represent the fields
136 void refresh() {
137 Field<sun> *previous;
138 previous = &base_field.gauge[0];
139
140 for (int step = 0; step < smear_steps; step++) {
141 foralldir(dir) { previous[dir].check_alloc(); }
142 foralldir(dir) {
143 staples[step][dir] = calc_staples(previous, dir);
144 onsites(ALL) {
145 element<sun> Q;
146 Q = -c * previous[dir][X] * staples[step][dir][X];
147 project_antihermitean(Q);
148 Q = Q.exp(exp_steps);
149 smeared_fields[step][dir][X] = previous[dir][X] * Q;
150 }
151 }
152 previous = smeared_fields[step];
153 }
154 }
155
156 void set_unity() {
157 base_field.set_unity();
158 refresh();
159 }
160
161 void random() {
162 base_field.random();
163 refresh();
164 }
165
167 // Two storage fields for the current and previous levels of the force
170 foralldir(dir) { storage1[dir] = force[dir]; }
171 Field<SquareMatrix<N, Complex<basetype>>> *previous = &storage1[0];
172 Field<SquareMatrix<N, Complex<basetype>>> *result = &storage2[0];
173
174 // Another storage Field, for the derivative of the exponential
175 Field<sun> Lambda[NDIM];
176
177 for (int step = smear_steps - 1; step >= 0; step--) {
178 // Find the gauge field the current level is calculated from
179 Field<sun> *basegauge;
180 if (step == 0) {
181 basegauge = &base_field.gauge[0];
182 } else {
183 basegauge = smeared_fields[step - 1];
184 }
185
186 // Take the derivative of the exponential
187 foralldir(dir) {
188 result[dir][ALL] = 0;
189 onsites(ALL) {
190 element<sun> m0, m1, qn, eQ, Q;
191 Q = -c * basegauge[dir][X] * staples[step][dir][X];
192 project_antihermitean(Q);
193
194 m0 = previous[dir][X] * basegauge[dir][X];
195 exp_and_derivative(Q, m0, Lambda[dir][X], eQ, exp_steps);
196
197 project_antihermitean(Lambda[dir][X]);
198
199 // First derivative term, R in R*exp(Q)*L
200 result[dir][X] = eQ * previous[dir][X];
201
202 // second derivative term, the first link in the plaquette
203 result[dir][X] -= c * staples[step][dir][X] * Lambda[dir][X];
204
205 // Now update Lambda to the derivative of the staple
206 Lambda[dir][X] = -c * Lambda[dir][X] * basegauge[dir][X];
207 }
208 }
209
210 // Take the derivetive with respect to the links in the staples
211 foralldir(dir1) foralldir(dir2) if (dir1 != dir2) {
212 staple_dir_derivative(basegauge[dir1], basegauge[dir2], Lambda[dir1],
213 result[dir1], result[dir2], dir1, dir2);
214 }
215
216 // Swap previous and result for the next iteration
218 previous = result;
219 result = tmp;
220 basegauge = &smeared_fields[step][0];
221 }
222
223 // Since we swap at the end, the force is now in "previous"
224 base_field.add_momentum(previous);
225 }
226
227 void draw_momentum() { base_field.draw_momentum(); }
228 void zero_momentum() { base_field.zero_momentum(); }
229
230 void backup() { base_field.backup(); }
231
232 // Restore the previous backup
233 void restore_backup() { base_field.restore_backup(); }
234
235 Field<sun> &get_momentum(int dir) { return base_field.get_momentum(dir); }
236 Field<sun> &get_gauge(int dir) { return base_field.get_gauge(dir); }
237};
238
239#if NDIM == 4
240
241template <typename sun> struct HEX_smeared_field : public gauge_field_base<sun> {
242 using gauge_type = sun;
243 using fund_type = sun;
244 using basetype = hila::arithmetic_type<sun>;
245 static constexpr int Nf = sun::size;
246 static constexpr int N = sun::size;
247
248 // SU2 default parameters
249 double c1 = 0.13;
250 double c2 = 0.1525;
251 double c3 = 0.175;
252 int exp_steps = 10;
253
254 gauge_field<sun> &base_field;
255 Field<sun> staples3[NDIM][NDIM];
256 Field<sun> level3[NDIM][NDIM];
257 Field<sun> staples2[NDIM][NDIM];
258 Field<sun> level2[NDIM][NDIM];
259 Field<sun> staples1[NDIM];
260
261 HEX_smeared_field(gauge_field<fund_type> &f) : base_field(f) {
263 }
264 HEX_smeared_field(gauge_field<fund_type> &f, int nsteps)
265 : base_field(f), exp_steps(nsteps) {
267 }
268 HEX_smeared_field(gauge_field<fund_type> &f, double _c1, double _c2, double _c3)
269 : base_field(f), c1(_c1), c2(_c2), c3(_c3) {
271 }
272 HEX_smeared_field(gauge_field<fund_type> &f, double _c1, double _c2, double _c3,
273 int nsteps)
274 : base_field(f), c1(_c1), c2(_c2), c3(_c3), exp_steps(nsteps) {
276 }
277
278 // Represent the fields
279 void refresh() {
280 Field<sun> *previous;
281 previous = &base_field.gauge[0];
282
283 foralldir(mu) { base_field.gauge[mu].check_alloc(); }
284
285 // Level 3, link to Direction mu, staples only summed to
286 // to Direction nu
287 foralldir(mu) foralldir(nu) if (mu != nu) {
288 staples3[nu][mu] = calc_staples(base_field.gauge, base_field.gauge, mu, nu);
289 onsites(ALL) {
290 element<sun> Q;
291 Q = -c3 * base_field.gauge[mu][X] * staples3[nu][mu][X];
292 project_antihermitean(Q);
293 Q = Q.exp(exp_steps);
294 level3[nu][mu][X] = base_field.gauge[mu][X] * Q;
295 }
296 }
297
298 // Level 2, link to Direction mu, staples summed to Direction
299 // rho != mu, nu. label directions nu and rho by eta != mu, nu, rho
300 foralldir(mu) foralldir(nu) if (mu != nu) {
301 staples2[nu][mu][ALL] = 0;
302 foralldir(rho) if (rho != mu) if (rho != nu) {
303 Direction eta;
304 foralldir(e) if (e != mu && e != nu && e != rho) eta = e;
305 Field<sun> stp = calc_staples(level3[eta], level3[eta], mu, rho);
306 staples2[nu][mu][ALL] = staples2[nu][mu][X] + stp[X];
307 }
308 onsites(ALL) {
309 element<sun> Q;
310 Q = -c2 * base_field.gauge[mu][X] * staples2[nu][mu][X];
311 project_antihermitean(Q);
312 Q = Q.exp(exp_steps);
313 level2[nu][mu][X] = base_field.gauge[mu][X] * Q;
314 }
315 }
316
317 // Level 1, link to Direction mu, staples summed to directions nu
318 // with Direction nu excluded from lower levels
319 foralldir(mu) {
320 staples1[mu][ALL] = 0;
321 foralldir(nu) if (mu != nu) {
322 Field<sun> stp = calc_staples(level2[nu], level2[mu], mu, nu);
323 staples1[mu][ALL] = staples1[mu][X] + stp[X];
324 }
325 onsites(ALL) {
326 element<sun> Q;
327 Q = -c1 * base_field.gauge[mu][X] * staples1[mu][X];
328 project_antihermitean(Q);
329 Q = Q.exp(exp_steps);
330 this->gauge[mu][X] = base_field.gauge[mu][X] * Q;
331 }
332 }
333 }
334
335 void set_unity() {
336 base_field.set_unity();
337 refresh();
338 }
339
340 void random() {
341 base_field.random();
342 refresh();
343 }
344
346 Field<sun> lambda1[NDIM];
347 Field<SquareMatrix<N, Complex<basetype>>> result1[NDIM][NDIM];
348 Field<sun> lambda2[NDIM][NDIM];
349 Field<SquareMatrix<N, Complex<basetype>>> result2[NDIM][NDIM];
350 Field<sun> lambda3[NDIM][NDIM];
352
353 foralldir(mu) {
354 result[mu] = 0;
355 foralldir(nu) {
356 result1[mu][nu] = 0;
357 result2[mu][nu] = 0;
358 }
359 }
360
361 // Level1 exponential
362 foralldir(mu) {
363 onsites(ALL) {
364 element<sun> m0, m1, qn, eQ, Q;
365 Q = -c1 * base_field.gauge[mu][X] * staples1[mu][X];
366 project_antihermitean(Q);
367
368 m0 = force[mu][X] * base_field.gauge[mu][X];
369 exp_and_derivative(Q, m0, lambda1[mu][X], eQ, exp_steps);
370 project_antihermitean(lambda1[mu][X]);
371
372 // First derivative term, R in R*exp(Q)*L
373 result[mu][X] = eQ * force[mu][X];
374
375 // second derivative term, the first link in the plaquette
376 result[mu][X] -= c1 * staples1[mu][X] * lambda1[mu][X];
377
378 // Now update Lambda to the derivative with respect to the staple
379 lambda1[mu][X] = -c1 * lambda1[mu][X] * base_field.gauge[mu][X];
380 }
381 }
382
383 // level1 staple
384 foralldir(mu) foralldir(nu) if (mu != nu) {
385 staple_dir_derivative(level2[nu][mu], level2[mu][nu], lambda1[mu],
386 result1[nu][mu], result1[mu][nu], mu, nu);
387 }
388
389 // level2 exponential
390 foralldir(mu) foralldir(nu) if (mu != nu) {
391 onsites(ALL) {
392 element<sun> m0, m1, qn, eQ, Q;
393 Q = -c2 * base_field.gauge[mu][X] * staples2[nu][mu][X];
394 project_antihermitean(Q);
395
396 m0 = result1[nu][mu][X] * base_field.gauge[mu][X];
397 exp_and_derivative(Q, m0, lambda2[nu][mu][X], eQ, exp_steps);
398 project_antihermitean(lambda2[nu][mu][X]);
399
400 // First derivative term, R in R*exp(Q)*L
401 result[mu][X] += eQ * result1[nu][mu][X];
402
403 // second derivative term, the first link in the plaquette
404 result[mu][X] -= c2 * staples2[nu][mu][X] * lambda2[nu][mu][X];
405
406 // Now update Lambda to the derivative with respect to the staple
407 lambda2[nu][mu][X] = -c2 * lambda2[nu][mu][X] * base_field.gauge[mu][X];
408 }
409 }
410
411 // level2 staple
412 foralldir(mu) foralldir(nu) if (mu != nu) {
413 foralldir(rho) if (rho != mu) if (rho != nu) {
414 Direction eta;
415 foralldir(e) if (e != mu && e != nu && e != rho) eta = e;
416 staple_dir_derivative(level3[eta][mu], level3[eta][rho], lambda2[nu][mu],
417 result2[eta][mu], result2[eta][rho], mu, rho);
418 }
419 }
420
421 // level3 exponential
422 foralldir(mu) foralldir(nu) if (mu != nu) {
423 onsites(ALL) {
424 element<sun> m0, m1, qn, eQ, Q;
425 Q = -c3 * base_field.gauge[mu][X] * staples3[nu][mu][X];
426 project_antihermitean(Q);
427
428 m0 = result2[nu][mu][X] * base_field.gauge[mu][X];
429 exp_and_derivative(Q, m0, lambda3[nu][mu][X], eQ, exp_steps);
430 project_antihermitean(lambda3[nu][mu][X]);
431
432 // First derivative term, R in R*exp(Q)*L
433 result[mu][X] += eQ * result2[nu][mu][X];
434
435 // second derivative term, the first link in the plaquette
436 result[mu][X] -= c3 * staples3[nu][mu][X] * lambda3[nu][mu][X];
437
438 // Now update Lambda to the derivative with respect to the staple
439 lambda3[nu][mu][X] = -c3 * lambda3[nu][mu][X] * base_field.gauge[mu][X];
440 }
441 }
442
443 // level3 staple
444 foralldir(mu) foralldir(nu) if (mu != nu) {
445 staple_dir_derivative(base_field.gauge[mu], base_field.gauge[nu],
446 lambda3[nu][mu], result[mu], result[nu], mu, nu);
447 }
448
449 // Add to the base gauge momentum
450 base_field.add_momentum(result);
451 }
452
453 void draw_momentum() { base_field.draw_momentum(); }
454 void zero_momentum() { base_field.zero_momentum(); }
455
456 void backup() { base_field.backup(); }
457
458 // Restore the previous backup
459 void restore_backup() { base_field.restore_backup(); }
460
461 Field<sun> &get_momentum(int dir) { return base_field.get_momentum(dir); }
462 Field<sun> &get_gauge(int dir) { return base_field.get_gauge(dir); }
463};
464
465#endif
466
467#endif
Complex definition.
Definition cmplx.h:56
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
Definition field.h:61
Field< A > dagger() const
Returns dagger or Hermitian conjugate of Field depending on how it is defined for Field type T.
Definition field.h:1123
void check_alloc()
Allocate Field if it is not already allocated.
Definition field.h:459
Matrix class which defines matrix operations.
Definition matrix.h:1620
Definition u1.h:14
virtual void restore_backup()
Definition gauge_field.h:43
virtual void refresh()
Recalculate represented or smeared field.
Definition gauge_field.h:27
virtual void draw_momentum()
Draw gaussian random momentum.
Definition gauge_field.h:36
virtual void random()
Draw a random gauge field.
Definition gauge_field.h:31
Field< sun > gauge[4]
A matrix field for each Direction.
Definition gauge_field.h:21
virtual void set_unity()
Set the field to unity.
Definition gauge_field.h:29
virtual void backup()
Make a copy of the gauge field for HMC.
Definition gauge_field.h:40
virtual void add_momentum(Field< SquareMatrix< N, Complex< basetype > > > *force)
Update the momentum by given force.
Definition gauge_field.h:34
virtual void zero_momentum()
Set the momentum to zero.
Definition gauge_field.h:38
void restore_backup()
Restore the previous backup.
void zero_momentum()
Set the momentum to zero.
void set_unity()
Set the gauge field to unity.
void random()
Draw a random gauge field.
void backup()
Make a copy of fields updated in a trajectory.
Field< gauge_type > & get_gauge(int dir)
Return a reference to the gauge field.
void draw_momentum()
Gaussian random momentum for each element.
void add_momentum(Field< SquareMatrix< N, Complex< basetype > > > *force)
Field< gauge_type > & get_momentum(int dir)
Return a reference to the momentum field.
void random()
Draw a random gauge field.
Definition smearing.h:161
void draw_momentum()
Draw gaussian random momentum.
Definition smearing.h:227
void set_unity()
Set the field to unity.
Definition smearing.h:156
void zero_momentum()
Set the momentum to zero.
Definition smearing.h:228
void add_momentum(Field< SquareMatrix< N, Complex< basetype > > > *force)
Update the momentum by given force.
Definition smearing.h:166
void backup()
Make a copy of the gauge field for HMC.
Definition smearing.h:230
void refresh()
Recalculate represented or smeared field.
Definition smearing.h:136
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Definition cmplx.h:1223
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
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