HILA
Loading...
Searching...
No Matches
stout_smear.h
1#ifndef STOUT_SMEAR_H_
2#define STOUT_SMEAR_H_
3
4#include "hila.h"
5
7
8/////////////////////////////////////////////////////////////////////////////
9/// Do stout smearing for the gauge fields
10/// U' = exp( -coeff * Proj_to_Alg(U * Staples) ) * U
11
12/**
13 * @brief Compute sum of staples around all links
14 * @details Compute staple sums around all positively oriented (i.e. corresponding
15 * plaquette sums are obtained by multiplying the staple sums by the corresponding
16 * positively oriented link variables)
17 * @tparam T Matrix element type
18 * @param U input gauge field of type T
19 * @param staples output vector/gauge field of type T
20 * @return void
21 */
22template <typename T>
23void staplesums(const GaugeField<T> &U, out_only GaugeField<T> &staples) {
24 Field<T> tF1, lw1;
25 foralldir(d1) {
26 foralldir(d2) if (d2 != d1) {
27 U[d2].start_gather(d1, ALL);
28 }
29 onsites(ALL) staples[d1][X] = 0;
30 }
31
32 foralldir(d1) foralldir(d2) if (d2 != d1) {
33 onsites(ALL) {
34 // tF1[X] = (U[d1][X] * U[d2][X + d1]).dagger();
35 mult_aa(U[d1][X], U[d2][X + d1], tF1[X]);
36 // lw1[X] = tF1[X] * U[d2][X];
37 mult(tF1[X], U[d2][X], lw1[X]);
38 }
39
40 lw1.start_gather(-d2, ALL);
41
42 onsites(ALL) {
43 // staple[d2][X] += U[d1][X + d2] * tF1[X];
44 mult_add(U[d1][X + d2], tF1[X], staples[d2][X]);
45 }
46 onsites(ALL) {
47 staples[d1][X] += lw1[X - d2];
48 }
49 }
50}
51
52template <typename T, typename atype = hila::arithmetic_type<T>>
53void stout_smear1(const GaugeField<T> &U, out_only GaugeField<T> &stout, atype coeff) {
54 staplesums(U, stout);
55 foralldir(d) {
56 onsites(ALL) {
57 stout[d][X] =
58 chexp((U[d][X] * stout[d][X]).project_to_algebra_scaled(-coeff).expand()) * U[d][X];
59 }
60 }
61}
62
63template <typename T, typename atype = hila::arithmetic_type<T>>
64void stout_smear1(const GaugeField<T> &U, out_only GaugeField<T> &stout,
65 out_only VectorField<T> &stap, atype coeff) {
66 staplesums(U, stap);
67 foralldir(d) {
68 onsites(ALL) {
69 stout[d][X] = chexp((U[d][X] * stap[d][X]).project_to_algebra_scaled(-coeff).expand()) * U[d][X];
70 }
71 }
72}
73
74/**
75 * @brief performs iter stout smearing steps with smearing coefficient coeff on the gauge field U
76 * and stores the resulting gague field in stout
77 * @tparam T Matrix element type
78 * @tparam atype arithmetic_type of T
79 * @param U input gauge field of type T
80 * @param stout Matrix of type T, containing resulting smeared gauge field
81 * @param coeff atype number specifying the smearing coefficient
82 * @param iter int number specifying the number of stout smearing steps to perform
83 * @return void
84 */
85template <typename T, typename atype = hila::arithmetic_type<T>>
86void stout_smear(const GaugeField<T> &U, GaugeField<T> &stout, atype coeff, int iter) {
87 GaugeField<T> tmp;
88 if(iter % 2 == 0) {
89 stout = U;
90 for (int i = 0; i < iter / 2; ++i) {
91 stout_smear1(stout, tmp, coeff);
92 stout_smear1(tmp, stout, coeff);
93 }
94 } else {
95 tmp = U;
96 for (int i = 0; i < iter / 2; ++i) {
97 stout_smear1(tmp, stout, coeff);
98 stout_smear1(stout, tmp, coeff);
99 }
100 stout_smear1(tmp, stout, coeff);
101 }
102}
103
104/**
105 * @brief Compute staples and staple sums around all links
106 * @details Compute staples and their sums around all positively oriented (i.e.
107 * corresponding plaquettes are obtained by multiplying the staple matrices by
108 * their corresponding positively oriented missing link variables)
109
110 * @tparam T Matrix element type
111 * @tparam nstap number of staples around each link
112 * @param U input gauge field of type T
113 * @param S array of nstap vector/gauge fields of type T
114 * @param Ssum vector/gauge field of type T, containing the staple sums
115 * @return void
116 */
117template <typename T, const int nstap = 2 * (NDIM - 1)>
118void get_stout_staples(const GaugeField<T> &U, VectorField<T>(out_only &S)[nstap],
119 out_only VectorField<T> &Ssum) {
120 Field<T> tF1, lw1;
121 foralldir(d1) {
122 foralldir(d2) if (d2 != d1) {
123 U[d2].start_gather(d1, ALL);
124 }
125 }
126 int l, rl, k, rk;
127 l = 0;
128 foralldir(d1) {
129 k = 0;
130 foralldir(d2) if (d2 != d1) {
131 onsites(ALL) {
132 // tF1[X] = (U[d1][X] * U[d2][X + d1]).dagger();
133 mult_aa(U[d1][X], U[d2][X + d1], tF1[X]);
134 // lw1[X] = tF1[X] * U[d2][X];
135 mult(tF1[X], U[d2][X], lw1[X]);
136 }
137
138 lw1.start_gather(-d2, ALL);
139 if(d1<d2) {
140 rl = l;
141 } else {
142 rl = l - 1;
143 }
144 onsites(ALL) {
145 // S[rl][d2][X] = U[d1][X + d2] * tF1[X];
146 mult(U[d1][X + d2], tF1[X], S[rl][d2][X]);
147 }
148 rk = nstap - 1 - k;
149 onsites(ALL) {
150 S[rk][d1][X] = lw1[X - d2];
151 }
152 ++k;
153 }
154 ++l;
155 }
156 foralldir(d1) {
157 onsites(ALL) Ssum[d1][X] = S[0][d1][X];
158 for (k = 1; k < nstap; ++k) {
159 onsites(ALL) Ssum[d1][X] += S[k][d1][X];
160 }
161 }
162}
163
164template <typename T, typename atype = hila::arithmetic_type<T>>
165void stout_smear(const GaugeField<T> &U, out_only std::vector<GaugeField<T>> &stoutlist,
166 out_only std::vector<VectorField<T>> &staplist, atype coeff) {
167 // performs as many stout smearing steps on the gauge field U as necessary to fill stoutlist
168 // storing the gague field obtained after the i-th smearing step in stoutlist[i]
169 stoutlist[0] = U; // original field
170 for (int i = 1; i < stoutlist.size(); ++i) {
171 stout_smear1(stoutlist[i - 1], stoutlist[i], staplist[i - 1], coeff);
172 }
173}
174
175template <typename T, typename atype = hila::arithmetic_type<T>>
176void stout_smear_force(const std::vector<GaugeField<T>> &stoutlist,
177 const std::vector<VectorField<T>> &staplist,
178 const VectorField<Algebra<T>> &K, out_only VectorField<Algebra<T>> &KS,
179 atype coeff) {
180 // uses the list stoutlist[] of smeared gauge fields to compute the pullback of the
181 // algebra-valued force field K under the smearing and returns the force acting on the unsmeared
182 // link variables as algebra-valued field KS
183 // Note: our definition of the force field is different from the one used in [arXiv:hep-lat/0311018v1],
184 // in order to match the force field representation used by our HMC implementation.
186 Field<T> K21, K22, K23, K24;
187
188 foralldir(d1) onsites(ALL) KS[d1][X] = K[d1][X];
189
190 for (int i = stoutlist.size() - 2; i >= 0; --i) {
191 const GaugeField<T> &U0 = stoutlist[i + 1];
192 const GaugeField<T> &U = stoutlist[i];
193 const VectorField<T> &staps = staplist[i];
194
195 foralldir(d1) {
196 //get_stout_staples(U, d1, stapl, staps);
197 onsites(ALL) {
198 // compute stout smearing operator and its derivatives:
199
200 // temp. variables:
201 T mtexp;
202 T mdtexp;
203 // turn staple sum into plaquette sum by multiplying with link variable:
204 //T tplaqs = U[d1][X] * staps[X];
205 T tplaqs = U[d1][X] * staps[d1][X];
206 // the following function computes first for X = -coeff * tplaqs the smearing
207 // operator Q = exp(X) and its derivatives dQ/dX[][], and uses these to
208 // compute the two matrices:
209 // mtexp = Q.dagger() * KS[d1][X].expand() * Q
210 // and
211 // mdtexp[i][j] = trace(Q.dagger() * KS[d1][X].expand() * dQ/dX[j][i]) :
212 mult_chexp(tplaqs.project_to_algebra_scaled(-coeff).expand(), KS[d1][X].expand(),
213 mtexp, mdtexp);
214
215 // set K1[d1][X] to be the equivalent of the \Lambda matrix from eq.(73) in
216 // [arXiv:hep-lat/0311018v1]:
217 K1[d1][X] = mdtexp.project_to_algebra_scaled(coeff).expand();
218
219 // equivalent of first line and first term on second line of eq.(75) in
220 // [arXiv:hep-lat/0311018v1]:
221 KS[d1][X] = (mtexp - tplaqs * K1[d1][X]).project_to_algebra();
222
223 // multiply K1[d1] by U[d1]:
224 K1[d1][X] *= U[d1][X];
225 }
226 }
227
228 // equivalent of remaining terms of eq.(75) in [arXiv:hep-lat/0311018v1]:
229 foralldir(d1) foralldir(d2) if (d1 != d2) {
230 onsites(ALL) {
231 T U2, U4, tM1;
232
233 U2 = U[d2][X + d1];
234 U4 = U[d2][X].dagger();
235
236 tM1 = U2 * U[d1][X + d2].dagger();
237 K21[X] = U4 * K1[d1][X] * tM1;
238 tM1 *= U4;
239 K22[X] = tM1 * K1[d1][X];
240 K24[X] = K1[d1][X] * tM1;
241
242 tM1 = U2 * K1[d1][X + d2].dagger() * U4;
243 K23[X] = U[d1][X] * tM1;
244 K22[X] += tM1 * U[d1][X];
245
246 K24[X] += K23[X];
247 }
248
249 onsites(ALL) {
250 KS[d2][X] -= (K22[X - d1] - K24[X]).project_to_algebra();
251 KS[d1][X] -= (K23[X] - K21[X - d2]).project_to_algebra();
252 }
253 }
254 }
255}
256
257template <typename T, typename atype = hila::arithmetic_type<T>>
258void stout_smear1k(const GaugeField<T> &U, out_only GaugeField<T> &stout,
259 out_only VectorField<T> &stap, out_only VectorField<T> &stoutk, atype coeff) {
260 staplesums(U, stap);
261 foralldir(d) {
262 onsites(ALL) {
263 stout[d][X] = chexpk((U[d][X] * stap[d][X]).project_to_algebra_scaled(-coeff).expand(),
264 stoutk[d][X]) * U[d][X];
265 }
266 }
267}
268
269template <typename T, typename atype = hila::arithmetic_type<T>>
270void stout_smeark(const GaugeField<T> &U, out_only std::vector<GaugeField<T>> &stoutlist,
271 out_only std::vector<VectorField<T>> &staplist,
272 out_only std::vector<VectorField<T>> &stoutklist, atype coeff) {
273 // performs nst stout smearing steps on the gauge field U and stores the gague field obtained
274 // after the i-th smearing step in stoutlist[i]
275 stoutlist[0] = U; // original field
276 for (int i = 1; i < stoutlist.size(); ++i) {
277 stout_smear1k(stoutlist[i - 1], stoutlist[i], staplist[i - 1], stoutklist[i - 1], coeff);
278 }
279}
280
281template <typename T, typename atype = hila::arithmetic_type<T>>
282void stout_smeark_force(
283 const std::vector<GaugeField<T>> &stoutlist, const std::vector<VectorField<T>> &staplist,
284 const std::vector<GaugeField<T>> &stoutklist, const VectorField<Algebra<T>> &K,
285 out_only VectorField<Algebra<T>> &KS, atype coeff) {
286 // uses the list stoutlist[] of smeared gauge fields to compute the pullback of the
287 // algebra-valued force field K under the smearing and returns the force acting on the unsmeared
288 // link variables as algebra-valued field KS
289 // Note: our definition of the force field is different from the one used in
290 // [arXiv:hep-lat/0311018v1], in order to match the force field representation used by our HMC
291 // implementation.
293 Field<T> K21, K22, K23, K24;
294
295 foralldir(d1) onsites(ALL) KS[d1][X] = K[d1][X];
296
297 for (int i = stoutlist.size() - 2; i >= 0; --i) {
298 const GaugeField<T> &U0 = stoutlist[i + 1];
299 const GaugeField<T> &U = stoutlist[i];
300 const GaugeField<T> &dUK = stoutklist[i];
301 const VectorField<T> &staps = staplist[i];
302
303 foralldir(d1) {
304 // get_stout_staples(U, d1, stapl, staps);
305 onsites(ALL) {
306 // compute stout smearing operator and its derivatives:
307
308 // temp. variables:
309 T mtexp;
310 T mdtexp;
311 // turn staple sum into plaquette sum by multiplying with link variable:
312 // T tplaqs = U[d1][X] * staps[X];
313 T tplaqs = U[d1][X] * staps[d1][X];
314 // the following function computes first for X = -coeff * tplaqs the smearing
315 // operator Q = exp(X) and its derivatives dQ/dX[][], and uses these to
316 // compute the two matrices:
317 // mtexp = Q.dagger() * KS[d1][X].expand() * Q
318 // and
319 // mdtexp[i][j] = trace(Q.dagger() * KS[d1][X].expand() * dQ/dX[j][i]) :
320 mult_chexpk_fast(tplaqs.project_to_algebra_scaled(-coeff).expand(),
321 U0[d1][X] * U[d1][X].dagger(), dUK[d1][X], KS[d1][X].expand(),
322 mtexp, mdtexp);
323
324 // set K1[d1][X] to be the equivalent of the \Lambda matrix from eq.(73) in
325 // [arXiv:hep-lat/0311018v1]:
326 K1[d1][X] = mdtexp.project_to_algebra_scaled(coeff).expand();
327
328 // equivalent of first line and first term on second line of eq.(75) in
329 // [arXiv:hep-lat/0311018v1]:
330 KS[d1][X] = (mtexp - tplaqs * K1[d1][X]).project_to_algebra();
331
332 // multiply K1[d1] by U[d1]:
333 K1[d1][X] *= U[d1][X];
334 }
335 }
336
337 // equivalent of remaining terms of eq.(75) in [arXiv:hep-lat/0311018v1]:
338 foralldir(d1) foralldir(d2) if (d1 != d2) {
339 onsites(ALL) {
340 /*
341 T U2, U4, U2U3, U2U3U4, U2L2U4;
342
343 U2 = U[d2][X + d1];
344 U4 = U[d2][X].dagger();
345
346 U2U3 = U2 * U[d1][X + d2].dagger();
347 U2U3U4 = U2U3 * U4;
348 U2L2U4 = U2 * K1[d1][X + d2].dagger() * U4;
349
350 K21[X] = U4 * K1[d1][X] * U2U3;
351 K23[X] = U[d1][X] * U2L2U4;
352
353 K22[X] = U2L2U4 * U[d1][X] + U2U3U4 * K1[d1][X];
354 K24[X] = K23[X] + K1[d1][X] * U2U3U4;
355 */
356 T U2, U4, tM1;
357
358 U2 = U[d2][X + d1];
359 U4 = U[d2][X].dagger();
360
361 tM1 = U2 * U[d1][X + d2].dagger();
362 K21[X] = U4 * K1[d1][X] * tM1;
363 tM1 *= U4;
364 K22[X] = tM1 * K1[d1][X];
365 K24[X] = K1[d1][X] * tM1;
366
367 tM1 = U2 * K1[d1][X + d2].dagger() * U4;
368 K23[X] = U[d1][X] * tM1;
369 K22[X] += tM1 * U[d1][X];
370
371 K24[X] += K23[X];
372 }
373
374 onsites(ALL) {
375 KS[d2][X] -= (K22[X - d1] - K24[X]).project_to_algebra();
376 KS[d1][X] -= (K23[X] - K21[X - d2]).project_to_algebra();
377 }
378 }
379 }
380}
381
382
383template <typename T, int N = T::rows(), int NSTP = 2 * (NDIM - 1),
384 typename atype = hila::arithmetic_type<T>>
385void stout_smeark_force_b(const std::vector<GaugeField<T>> &stoutlist,
386 const std::vector<GaugeField<T>> &stoutklist,
387 const VectorField<Algebra<T>> &K, out_only VectorField<Algebra<T>> &KS,
388 atype coeff) {
389 // uses the list stoutlist[] of smeared gauge fields to compute the pullback of the
390 // algebra-valued force field K under the smearing and returns the force acting on the unsmeared
391 // link variables as algebra-valued field KS
392 // Note: our definition of the force field is different from the one used in
393 // [arXiv:hep-lat/0311018v1], in order to match the force field representation used by our HMC
394 // implementation.
395 VectorField<T> stapl[NSTP];
396 // Field<T> staps;
397 VectorField<T> staps;
399
400 foralldir(d1) onsites(ALL) KS[d1][X] = K[d1][X];
401
402 for (int i = stoutlist.size() - 2; i >= 0; --i) {
403 const GaugeField<T> &U0 = stoutlist[i + 1];
404 const GaugeField<T> &U = stoutlist[i];
405 const GaugeField<T> &dUK = stoutklist[i];
406
407 get_stout_staples(U, stapl, staps);
408 foralldir(d1) {
409 // get_stout_staples(U, d1, stapl, staps);
410 onsites(ALL) {
411 // compute stout smearing operator and its derivatives:
412
413 // temp. variables:
414 T mtexp;
415 T mdtexp;
416 // turn staple sum into plaquette sum by multiplying with link variable:
417 // T tplaqs = U[d1][X] * staps[X];
418 T tplaqs = U[d1][X] * staps[d1][X];
419 // the following function computes first for X = -coeff * tplaqs the smearing
420 // operator Q = exp(X) and its derivatives dQ/dX[][], and uses these to
421 // compute the two matrices:
422 // mtexp = Q.dagger() * KS[d1][X].expand() * Q
423 // and
424 // mdtexp[i][j] = trace(Q.dagger() * KS[d1][X].expand() * dQ/dX[j][i]) :
425 mult_chexpk_fast(tplaqs.project_to_algebra_scaled(-coeff).expand(),
426 U0[d1][X] * U[d1][X].dagger(), dUK[d1][X], KS[d1][X].expand(),
427 mtexp, mdtexp);
428
429 // set K1[d1][X] to be the equivalent of the \Lambda matrix from eq.(73) in
430 // [arXiv:hep-lat/0311018v1]:
431 K1[d1][X] = mdtexp.project_to_algebra_scaled(coeff).expand();
432
433 // equivalent of first line and first term on second line of eq.(75) in
434 // [arXiv:hep-lat/0311018v1]:
435 KS[d1][X] = (mtexp - tplaqs * K1[d1][X]).project_to_algebra();
436
437 // multiply K1[d1] by U[d1]:
438 K1[d1][X] *= U[d1][X];
439 // (the latter is done so that the parallel transport of
440 // U[d1][X] * stapl[][d1][X] * K1[d1][X] in negative d1-direction, required
441 // in the next section, can be computed simply as stapl[][d1][X-d1] * K1[d1][X-d1]
442 }
443
444 // multiply all the stapl[][d1] by K1[d1] and start sending the resulting matrices
445 // to the neighboring sites in negative d1-direction:
446 // (this is done in the same order in which they will be used below)
447 int istp = 0;
448 int istn;
449 foralldir(d2) if (d2 != d1) {
450 onsites(ALL) stapl[istp][d1][X] *= K1[d1][X];
451 stapl[istp][d1].start_gather(-d1, ALL);
452 istn = NSTP - 1 - istp;
453 onsites(ALL) stapl[istn][d1][X] *= K1[d1][X];
454 stapl[istn][d1].start_gather(-d1, ALL);
455 ++istp;
456 }
457 }
458
459 foralldir(d1) {
460 // compute the equivalent of the terms in the curly bracket of eq.(75) in
461 // [arXiv:hep-lat/0311018v1]:
462 int istp = 0;
463 int istn;
464 foralldir(d2) if (d2 != d1) {
465 // term from d1-d2-plaquette for positive d2-direction:
466 onsites(ALL) {
467 // staps[X] = stapl[istp][d1][X - d1];
468 staps[d1][X] = stapl[istp][d1][X - d1];
469 }
470 // define for each modified stout staple matrix the correspondin path of gauge
471 // links:
472 std::vector<Direction> pathp = {d2, -d1, -d2};
473 // get_wloop_force_from_wl_add(U, pathp, staps, 1.0, KS);
474 get_wloop_force_from_wl_add(U, pathp, staps[d1], 1.0, KS);
475
476 // term from d1-d2-plaquette for negative d2-direction:
477 istn = NSTP - 1 - istp;
478 onsites(ALL) {
479 // staps[X] = stapl[istn][d1][X - d1];
480 staps[d1][X] = stapl[istn][d1][X - d1];
481 }
482 // define for each modified stout staple matrix the correspondin path of gauge
483 // links:
484 std::vector<Direction> pathn = {-d2, -d1, d2};
485 // get_wloop_force_from_wl_add(U, pathn, staps, 1.0, KS);
486 get_wloop_force_from_wl_add(U, pathn, staps[d1], 1.0, KS);
487 ++istp;
488 }
489 }
490 }
491}
492
493#endif
Definition su2.h:7
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
dir_mask_t start_gather(Direction d, Parity p=ALL) const
Definition field_comm.h:262
Gauge field class.
Definition gaugefield.h:22
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
constexpr Parity ALL
bit pattern: 011
void mult_chexp(const Matrix_t< n, m, T, MT > &mat, const Matrix_t< n, m, T, MT > &mmat, Matrix_t< n, m, T, MT > &omat, Matrix_t< n, m, T, MT > &domat)
Calculate exp(mat).dagger()*mmat*exp(mat) and trace(exp(mat).dagger*mmat*dexp(mat))
Definition matrix.h:3275
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
void mult_add(const Mt1 &a, const Mt2 &b, Mt3 &res)
compute product of two matrices and add result to existing matrix
Definition matrix.h:2437
void mult_chexpk_fast(const Matrix_t< n, m, T, MT > &mat, const Matrix_t< n, m, T, MT > &texp, const Matrix_t< n, m, T, MT > &kmats, const Matrix_t< n, m, T, MT > &mmat, Matrix_t< n, m, T, MT > &omat, Matrix_t< n, m, T, MT > &domat)
Calculate exp(mat).dagger()*mmat*exp(mat) and trace(exp(mat).dagger*mmat*dexp(mat)) from output of ch...
Definition matrix.h:3604
void chexpk(const Matrix_t< n, m, T, MT > &mat, Matrix_t< n, m, T, MT > &omat, Matrix_t< n, m, T, MT > &kmats)
Calculate exp(mat) and the decomposition k_{i,j} of dexp in terms bilinears of powers of mat.
Definition matrix.h:3453
void mult_aa(const Mt1 &a, const Mt2 &b, Mt3 &res)
compute hermitian conjugate of product of two matrices and write result to existing matrix
Definition matrix.h:2356
void mult(const Mt1 &a, const Mt2 &b, Mt3 &res)
compute product of two matrices and write result to existing matrix
Definition matrix.h:2327