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 free(staples);
131 free(smeared_fields);
132 }
133
134 // Represent the fields
135 void refresh() {
136 Field<sun> *previous;
137 previous = &base_field.gauge[0];
138
139 for (int step = 0; step < smear_steps; step++) {
140 foralldir(dir) { previous[dir].check_alloc(); }
141 foralldir(dir) {
142 staples[step][dir] = calc_staples(previous, dir);
143 onsites(ALL) {
144 element<sun> Q;
145 Q = -c * previous[dir][X] * staples[step][dir][X];
146 project_antihermitean(Q);
147 Q = Q.exp(exp_steps);
148 smeared_fields[step][dir][X] = previous[dir][X] * Q;
149 }
150 }
151 previous = smeared_fields[step];
152 }
153 }
154
155 void set_unity() {
156 base_field.set_unity();
157 refresh();
158 }
159
160 void random() {
161 base_field.random();
162 refresh();
163 }
164
166 // Two storage fields for the current and previous levels of the force
169 foralldir(dir) { storage1[dir] = force[dir]; }
170 Field<SquareMatrix<N, Complex<basetype>>> *previous = &storage1[0];
171 Field<SquareMatrix<N, Complex<basetype>>> *result = &storage2[0];
172
173 // Another storage Field, for the derivative of the exponential
174 Field<sun> Lambda[NDIM];
175
176 for (int step = smear_steps - 1; step >= 0; step--) {
177 // Find the gauge field the current level is calculated from
178 Field<sun> *basegauge;
179 if (step == 0) {
180 basegauge = &base_field.gauge[0];
181 } else {
182 basegauge = smeared_fields[step - 1];
183 }
184
185 // Take the derivative of the exponential
186 foralldir(dir) {
187 result[dir][ALL] = 0;
188 onsites(ALL) {
189 element<sun> m0, m1, qn, eQ, Q;
190 Q = -c * basegauge[dir][X] * staples[step][dir][X];
191 project_antihermitean(Q);
192
193 m0 = previous[dir][X] * basegauge[dir][X];
194 exp_and_derivative(Q, m0, Lambda[dir][X], eQ, exp_steps);
195
196 project_antihermitean(Lambda[dir][X]);
197
198 // First derivative term, R in R*exp(Q)*L
199 result[dir][X] = eQ * previous[dir][X];
200
201 // second derivative term, the first link in the plaquette
202 result[dir][X] -= c * staples[step][dir][X] * Lambda[dir][X];
203
204 // Now update Lambda to the derivative of the staple
205 Lambda[dir][X] = -c * Lambda[dir][X] * basegauge[dir][X];
206 }
207 }
208
209 // Take the derivetive with respect to the links in the staples
210 foralldir(dir1) foralldir(dir2) if (dir1 != dir2) {
211 staple_dir_derivative(basegauge[dir1], basegauge[dir2], Lambda[dir1],
212 result[dir1], result[dir2], dir1, dir2);
213 }
214
215 // Swap previous and result for the next iteration
217 previous = result;
218 result = tmp;
219 basegauge = &smeared_fields[step][0];
220 }
221
222 // Since we swap at the end, the force is now in "previous"
223 base_field.add_momentum(previous);
224 }
225
226 void draw_momentum() { base_field.draw_momentum(); }
227 void zero_momentum() { base_field.zero_momentum(); }
228
229 void backup() { base_field.backup(); }
230
231 // Restore the previous backup
232 void restore_backup() { base_field.restore_backup(); }
233
234 Field<sun> &get_momentum(int dir) { return base_field.get_momentum(dir); }
235 Field<sun> &get_gauge(int dir) { return base_field.get_gauge(dir); }
236};
237
238#if NDIM == 4
239
240template <typename sun> struct HEX_smeared_field : public gauge_field_base<sun> {
241 using gauge_type = sun;
242 using fund_type = sun;
243 using basetype = hila::arithmetic_type<sun>;
244 static constexpr int Nf = sun::size;
245 static constexpr int N = sun::size;
246
247 // SU2 default parameters
248 double c1 = 0.13;
249 double c2 = 0.1525;
250 double c3 = 0.175;
251 int exp_steps = 10;
252
253 gauge_field<sun> &base_field;
254 Field<sun> staples3[NDIM][NDIM];
255 Field<sun> level3[NDIM][NDIM];
256 Field<sun> staples2[NDIM][NDIM];
257 Field<sun> level2[NDIM][NDIM];
258 Field<sun> staples1[NDIM];
259
260 HEX_smeared_field(gauge_field<fund_type> &f) : base_field(f) {
262 }
263 HEX_smeared_field(gauge_field<fund_type> &f, int nsteps)
264 : base_field(f), exp_steps(nsteps) {
266 }
267 HEX_smeared_field(gauge_field<fund_type> &f, double _c1, double _c2, double _c3)
268 : base_field(f), c1(_c1), c2(_c2), c3(_c3) {
270 }
271 HEX_smeared_field(gauge_field<fund_type> &f, double _c1, double _c2, double _c3,
272 int nsteps)
273 : base_field(f), c1(_c1), c2(_c2), c3(_c3), exp_steps(nsteps) {
275 }
276
277 // Represent the fields
278 void refresh() {
279 Field<sun> *previous;
280 previous = &base_field.gauge[0];
281
282 foralldir(mu) { base_field.gauge[mu].check_alloc(); }
283
284 // Level 3, link to Direction mu, staples only summed to
285 // to Direction nu
286 foralldir(mu) foralldir(nu) if (mu != nu) {
287 staples3[nu][mu] = calc_staples(base_field.gauge, base_field.gauge, mu, nu);
288 onsites(ALL) {
289 element<sun> Q;
290 Q = -c3 * base_field.gauge[mu][X] * staples3[nu][mu][X];
291 project_antihermitean(Q);
292 Q = Q.exp(exp_steps);
293 level3[nu][mu][X] = base_field.gauge[mu][X] * Q;
294 }
295 }
296
297 // Level 2, link to Direction mu, staples summed to Direction
298 // rho != mu, nu. label directions nu and rho by eta != mu, nu, rho
299 foralldir(mu) foralldir(nu) if (mu != nu) {
300 staples2[nu][mu][ALL] = 0;
301 foralldir(rho) if (rho != mu) if (rho != nu) {
302 Direction eta;
303 foralldir(e) if (e != mu && e != nu && e != rho) eta = e;
304 Field<sun> stp = calc_staples(level3[eta], level3[eta], mu, rho);
305 staples2[nu][mu][ALL] = staples2[nu][mu][X] + stp[X];
306 }
307 onsites(ALL) {
308 element<sun> Q;
309 Q = -c2 * base_field.gauge[mu][X] * staples2[nu][mu][X];
310 project_antihermitean(Q);
311 Q = Q.exp(exp_steps);
312 level2[nu][mu][X] = base_field.gauge[mu][X] * Q;
313 }
314 }
315
316 // Level 1, link to Direction mu, staples summed to directions nu
317 // with Direction nu excluded from lower levels
318 foralldir(mu) {
319 staples1[mu][ALL] = 0;
320 foralldir(nu) if (mu != nu) {
321 Field<sun> stp = calc_staples(level2[nu], level2[mu], mu, nu);
322 staples1[mu][ALL] = staples1[mu][X] + stp[X];
323 }
324 onsites(ALL) {
325 element<sun> Q;
326 Q = -c1 * base_field.gauge[mu][X] * staples1[mu][X];
327 project_antihermitean(Q);
328 Q = Q.exp(exp_steps);
329 this->gauge[mu][X] = base_field.gauge[mu][X] * Q;
330 }
331 }
332 }
333
334 void set_unity() {
335 base_field.set_unity();
336 refresh();
337 }
338
339 void random() {
340 base_field.random();
341 refresh();
342 }
343
345 Field<sun> lambda1[NDIM];
346 Field<SquareMatrix<N, Complex<basetype>>> result1[NDIM][NDIM];
347 Field<sun> lambda2[NDIM][NDIM];
348 Field<SquareMatrix<N, Complex<basetype>>> result2[NDIM][NDIM];
349 Field<sun> lambda3[NDIM][NDIM];
351
352 foralldir(mu) {
353 result[mu] = 0;
354 foralldir(nu) {
355 result1[mu][nu] = 0;
356 result2[mu][nu] = 0;
357 }
358 }
359
360 // Level1 exponential
361 foralldir(mu) {
362 onsites(ALL) {
363 element<sun> m0, m1, qn, eQ, Q;
364 Q = -c1 * base_field.gauge[mu][X] * staples1[mu][X];
365 project_antihermitean(Q);
366
367 m0 = force[mu][X] * base_field.gauge[mu][X];
368 exp_and_derivative(Q, m0, lambda1[mu][X], eQ, exp_steps);
369 project_antihermitean(lambda1[mu][X]);
370
371 // First derivative term, R in R*exp(Q)*L
372 result[mu][X] = eQ * force[mu][X];
373
374 // second derivative term, the first link in the plaquette
375 result[mu][X] -= c1 * staples1[mu][X] * lambda1[mu][X];
376
377 // Now update Lambda to the derivative with respect to the staple
378 lambda1[mu][X] = -c1 * lambda1[mu][X] * base_field.gauge[mu][X];
379 }
380 }
381
382 // level1 staple
383 foralldir(mu) foralldir(nu) if (mu != nu) {
384 staple_dir_derivative(level2[nu][mu], level2[mu][nu], lambda1[mu],
385 result1[nu][mu], result1[mu][nu], mu, nu);
386 }
387
388 // level2 exponential
389 foralldir(mu) foralldir(nu) if (mu != nu) {
390 onsites(ALL) {
391 element<sun> m0, m1, qn, eQ, Q;
392 Q = -c2 * base_field.gauge[mu][X] * staples2[nu][mu][X];
393 project_antihermitean(Q);
394
395 m0 = result1[nu][mu][X] * base_field.gauge[mu][X];
396 exp_and_derivative(Q, m0, lambda2[nu][mu][X], eQ, exp_steps);
397 project_antihermitean(lambda2[nu][mu][X]);
398
399 // First derivative term, R in R*exp(Q)*L
400 result[mu][X] += eQ * result1[nu][mu][X];
401
402 // second derivative term, the first link in the plaquette
403 result[mu][X] -= c2 * staples2[nu][mu][X] * lambda2[nu][mu][X];
404
405 // Now update Lambda to the derivative with respect to the staple
406 lambda2[nu][mu][X] = -c2 * lambda2[nu][mu][X] * base_field.gauge[mu][X];
407 }
408 }
409
410 // level2 staple
411 foralldir(mu) foralldir(nu) if (mu != nu) {
412 foralldir(rho) if (rho != mu) if (rho != nu) {
413 Direction eta;
414 foralldir(e) if (e != mu && e != nu && e != rho) eta = e;
415 staple_dir_derivative(level3[eta][mu], level3[eta][rho], lambda2[nu][mu],
416 result2[eta][mu], result2[eta][rho], mu, rho);
417 }
418 }
419
420 // level3 exponential
421 foralldir(mu) foralldir(nu) if (mu != nu) {
422 onsites(ALL) {
423 element<sun> m0, m1, qn, eQ, Q;
424 Q = -c3 * base_field.gauge[mu][X] * staples3[nu][mu][X];
425 project_antihermitean(Q);
426
427 m0 = result2[nu][mu][X] * base_field.gauge[mu][X];
428 exp_and_derivative(Q, m0, lambda3[nu][mu][X], eQ, exp_steps);
429 project_antihermitean(lambda3[nu][mu][X]);
430
431 // First derivative term, R in R*exp(Q)*L
432 result[mu][X] += eQ * result2[nu][mu][X];
433
434 // second derivative term, the first link in the plaquette
435 result[mu][X] -= c3 * staples3[nu][mu][X] * lambda3[nu][mu][X];
436
437 // Now update Lambda to the derivative with respect to the staple
438 lambda3[nu][mu][X] = -c3 * lambda3[nu][mu][X] * base_field.gauge[mu][X];
439 }
440 }
441
442 // level3 staple
443 foralldir(mu) foralldir(nu) if (mu != nu) {
444 staple_dir_derivative(base_field.gauge[mu], base_field.gauge[nu],
445 lambda3[nu][mu], result[mu], result[nu], mu, nu);
446 }
447
448 // Add to the base gauge momentum
449 base_field.add_momentum(result);
450 }
451
452 void draw_momentum() { base_field.draw_momentum(); }
453 void zero_momentum() { base_field.zero_momentum(); }
454
455 void backup() { base_field.backup(); }
456
457 // Restore the previous backup
458 void restore_backup() { base_field.restore_backup(); }
459
460 Field<sun> &get_momentum(int dir) { return base_field.get_momentum(dir); }
461 Field<sun> &get_gauge(int dir) { return base_field.get_gauge(dir); }
462};
463
464#endif
465
466#endif
Complex definition.
Definition cmplx.h:50
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:1160
void check_alloc()
Allocate Field if it is not already allocated.
Definition field.h:459
Matrix class which defines matrix operations.
Definition matrix.h:1679
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:160
void draw_momentum()
Draw gaussian random momentum.
Definition smearing.h:226
void set_unity()
Set the field to unity.
Definition smearing.h:155
void zero_momentum()
Set the momentum to zero.
Definition smearing.h:227
void add_momentum(Field< SquareMatrix< N, Complex< basetype > > > *force)
Update the momentum by given force.
Definition smearing.h:165
void backup()
Make a copy of the gauge field for HMC.
Definition smearing.h:229
void refresh()
Recalculate represented or smeared field.
Definition smearing.h:135
Complex< T > dagger(const Complex< T > &val)
Return dagger of Complex number.
Definition cmplx.h:1358
#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