HILA
Loading...
Searching...
No Matches
hila_healthcheck.cpp
Go to the documentation of this file.
1/**
2 * @file hila_healthcheck.cpp
3 * @author Kari Rummukainen
4 * @brief HILA healthcheck application.
5 * @details Performs a comprehensive health check on HILA libraries.
6 */
7#include "hila.h"
8
9#include "clusters.h"
10
11// unistd.h needed for isatty()
12#include <unistd.h>
13
14
15// report the result of the test -- TODO: nicer formatting?
16bool report_pass(std::string message, double eps, double limit) {
17
18 static int is_terminal = -1;
19 static std::string ok_string, fail_string;
20
21 if (is_terminal < 0) {
22 is_terminal = isatty(fileno(stdout));
23
24 if (is_terminal) {
25 ok_string = "\x1B[32m --- \033[0m ";
26 fail_string = "\x1B[31m *** \033[0m ";
27 } else {
28 ok_string = " --- ";
29 fail_string = " *** ";
30 }
31 }
32
33 if (abs(eps) < limit) {
34 hila::out0 << ok_string << message << " passed" << std::endl;
35 return true;
36 } else {
37 hila::out0 << fail_string << message << " FAILED: eps " << eps << " limit " << limit
38 << std::endl;
39 return false;
40 }
41}
42
43/**
44 * @brief Test various functions on fields.
45 * @details Test functions exp (on both real and complex field) and sin.
46 *
47 */
49
50 Field<double> df = 0;
51 report_pass("Field functions: real exp", exp(df).sum() - lattice.volume(), 1e-8);
52
54 report_pass("Field functions: complex exp", abs(exp(cf).sum() - lattice.volume()), 1e-8);
55
56 df[ALL] = sin(X.x() * 2 * M_PI / lattice.size(e_x));
57 report_pass("Field functions: sin", df.sum(), 1e-8);
58}
59
60
61/////////////////////////////////////////////////////////////////////////////////////
62
63/**
64 * @brief Test reduction operations on fields
65 * @details Test normal reduction `+=` and ReductionVector on fields with different types such as
66 * real, complex, matrix and SU matrix.
67 *
68 */
70
71
72 // test reductions
73
74 {
76 f[ALL] = expi(2 * M_PI * X.coordinate(e_x) / lattice.size(e_x));
77
78 Complex<double> sum = 0;
79 onsites(ALL) sum += f[X];
80
81 sum /= lattice.volume();
82 report_pass("Complex reduction value " + hila::prettyprint(sum), abs(sum), 1e-4);
83
84 ReductionVector<Complex<double>> rv(lattice.size(e_x));
85
86 onsites(ALL) {
87 rv[X.coordinate(e_x)] += f[X];
88 }
89
90 sum = 0;
91 for (int i = 0; i < lattice.size(e_x); i++) {
92 sum += expi(2 * M_PI * i / lattice.size(e_x)) -
93 rv[i] / (lattice.volume() / lattice.size(e_x));
94 }
95 report_pass("Complex ReductionVector, sum " + hila::prettyprint(sum), abs(sum), 1e-4);
96
97 // do a combined reduction too
98 sum = 0;
99 rv = 0;
100 onsites(ALL) {
101 rv[X.x()] += f[X];
102 rv[0] += 1;
103 rv[1] += -0.01;
104
105 sum += f[X];
106 }
107
108 sum /= lattice.volume();
109 Complex<double> sum2 = 0;
110 rv[0] -= lattice.volume();
111 rv[1] += 0.01 * lattice.volume();
112
113 for (int i = 0; i < lattice.size(e_x); i++) {
114 sum2 += expi(2 * M_PI * i / lattice.size(e_x)) -
115 rv[i] / (lattice.volume() / lattice.size(e_x));
116 }
117 report_pass("Combined reductions, sum " + hila::prettyprint(sum) + ", sum2 " +
118 hila::prettyprint(sum2),
119 abs(sum) + abs(sum2), 1e-4);
120 }
121
122 {
123 // reductionvector with long
125 lf[ALL] = X.x();
126
127 ReductionVector<int64_t> rv(lattice.size(e_x));
128
129 onsites(ALL) {
130 rv[X.x()] += lf[X];
131 }
132
133 long s = 0;
134 for (int x = 0; x < rv.size(); x++) {
135 s += abs(rv[x] - x * (lattice.volume() / lattice.size(e_x)));
136 }
137
138 report_pass("ReductionVector<int64_t>, sum " + hila::prettyprint(s), s, 1e-15);
139
140 int64_t psum = 0;
141 onsites(ALL) {
142 if (X.parity() == EVEN)
143 psum += 1;
144 }
145 // If volume is odd there is 1 extra even site
146 psum -= lattice.volume() / 2 + lattice.volume() % 2;
147
148 report_pass("Reduction with parity", psum, 1e-15);
149 }
150
151 {
152 // reductionvector with long
154 lf[ALL] = X.x();
155
156 ReductionVector<int64_t> rv(lattice.size(e_x));
157
158 onsites(ALL) {
159 rv[X.x()] += lf[X];
160 }
161
162 long s = 0;
163 for (int x = 0; x < rv.size(); x++) {
164 s += abs(rv[x] - x * (lattice.volume() / lattice.size(e_x)));
165 }
166
167 report_pass("ReductionVector<int64_t>, sum " + hila::prettyprint(s), s, 1e-15);
168 }
169
170
171 {
172
173 constexpr int N = 5;
174
176 mf = 1;
177 // onsites(ALL) mf[X] = (mf[X] + mf[X])*0.5;
178
179 ReductionVector<SU<N, double>> rmf(lattice.size(e_x));
180
181 onsites(ALL) {
182 rmf[X.x()] += mf[X];
183 }
184
185
186 double diff = 0;
187 for (int i = 0; i < lattice.size(e_x); i++) {
188 diff += (rmf[i] - lattice.size(e_y) * lattice.size(e_z)).squarenorm();
189 }
190
191
192 report_pass("SU(" + std::to_string(N) + ") ReductionVector", diff, 1e-8);
193 }
194}
195
196
197/**
198 * @brief Test site access
199 * @details Test simple site access by writing and reading to random field site index c.
200 *
201 */
203
205 Complex<double> sum;
206
208 for (int i = 0; i < 3; i++) {
209 foralldir(d) c[d] = hila::random() * lattice.size(d);
210 hila::broadcast(c); // need to broadcast!
211
212 f[c] = 4; // write to location c
213 sum = f[c]; // read back - does mpi comm
214 report_pass("Setting and reading a value at " + hila::prettyprint(c.transpose()),
215 abs(sum - 4), 1e-10);
216 }
217}
218
219
220/**
221 * @brief Test min and max operations on fields
222 * @details Test min and max operations on fields with different parities.
223 *
224 */
226
227 CoordinateVector c, loc;
229
230 for (Parity par : {ALL, EVEN, ODD}) {
231
232 n[par] = hila::random();
233 do {
234 foralldir(d) c[d] = hila::random() * lattice.size(d);
235 } while (!(par == ALL || c.parity() == par));
237 n[c] = 2;
238
239 if (par != ALL)
240 n[opp_parity(par)] = 3;
241
242 auto v = n.max(par, loc);
243 report_pass("Maxloc parity " + hila::prettyprint(par) + " is " +
244 hila::prettyprint(loc.transpose()),
245 (c - loc).norm(), 1e-8);
246 report_pass("Max parity " + hila::prettyprint(par) + " value " + hila::prettyprint(v),
247 v - 2, 1e-9);
248
249 do {
250 foralldir(d) c[d] = hila::random() * lattice.size(d);
251 } while (!(par == ALL || c.parity() == par));
253 n[c] = -1;
254
255 if (par != ALL)
256 n[opp_parity(par)] = -3;
257
258 v = n.min(par, loc);
259 report_pass("Minloc parity " + hila::prettyprint(par) + " is " +
260 hila::prettyprint(loc.transpose()),
261 (c - loc).norm(), 1e-8);
262 report_pass("Min parity " + hila::prettyprint(par) + " value " + hila::prettyprint(v),
263 v + 1, 1e-9);
264 }
265}
266
267/**
268 * @brief Test Gaussian random field generation
269 * @details Generate a Gaussian random field and check its average and width^2.
270 *
271 */
273
274 constexpr int n_loops = 100;
275
277
278 double fsum = 0, fsqr = 0;
279 for (int i = 0; i < n_loops; i++) {
280 f.gaussian_random();
281 double s = 0, s2 = 0;
282 onsites(ALL) {
283 s += f[X];
284 s2 += sqr(f[X]);
285 }
286 fsum += s / lattice.volume();
287 fsqr += s2 / lattice.volume();
288 }
289
290 fsum /= n_loops;
291 fsqr /= n_loops;
292
293 report_pass("Gaussian random average (6 sigma limit) " + hila::prettyprint(fsum), abs(fsum),
294 6 / sqrt(((double)n_loops) * lattice.volume()));
295
296 report_pass("Gaussian random width^2 " + hila::prettyprint(fsqr), fsqr - 1,
297 6 / sqrt(((double)n_loops) * lattice.volume()));
298}
299
300
301/**
302 * @brief Test setting elements and selecting them
303 * @details Set elements in a field at random coordinates and then select them using SiteSelect
304 * and SiteValueSelect.
305 */
307
310
311 std::vector<CoordinateVector> cvec;
312 std::vector<Complex<double>> vals;
313
314
315 if (hila::myrank() == 0) {
316 int k = 1;
317 for (int i = 0; i <= 50; i++) {
318 foralldir(d) c[d] = hila::random() * lattice.size(d);
319 bool found = false;
320
321 // don't overwrite previous loc
322 for (auto &r : cvec)
323 if (r == c)
324 found = true;
325 if (!found) {
326 cvec.push_back(c);
327 vals.push_back(Complex<double>(k, k));
328 k++;
329 }
330 }
331 }
332
333 hila::broadcast(vals);
334 hila::broadcast(cvec);
335
336 f.set_elements(vals, cvec);
337
338 vals = f.get_elements(cvec, true);
339
340 Complex<double> sum = 0;
341 for (int i = 0; i < vals.size(); i++) {
342 sum += vals[i] - Complex<double>(i + 1, i + 1);
343 }
344
345 report_pass("Field set_elements and get_elements with " + hila::prettyprint(vals.size()) +
346 " coordinates",
347 abs(sum), 1e-8);
348
349 // use the same vector for siteselect
350
351 SiteSelect s;
352 SiteValueSelect<Complex<double>> sv;
353
354 onsites(ALL) {
355 if (squarenorm(f[X]) >= 1) {
356 s.select(X);
357 sv.select(X, f[X]);
358 }
359 }
360
361 report_pass("SiteSelect size " + hila::prettyprint(s.size()), s.size() - cvec.size(), 1e-3);
362 report_pass("SiteValueSelect size " + hila::prettyprint(sv.size()), sv.size() - cvec.size(),
363 1e-3);
364
365 int ok = 1;
366
367 for (auto &c : cvec) {
368 bool found = false;
369 for (int i = 0; !found && i < s.size(); i++) {
370 if (s.coordinates(i) == c)
371 found = true;
372 }
373 if (!found)
374 ok = 0;
375 }
376
377 report_pass("SiteSelect content", 1 - ok, 1e-6);
378
379 ok = 1;
380 for (int k = 0; k < cvec.size(); k++) {
381
382 bool found = false;
383 for (int i = 0; !found && i < sv.size(); i++) {
384 if (sv.coordinates(i) == cvec[k] && sv.value(i) == vals[k])
385 found = true;
386 }
387 if (!found)
388 ok = 0;
389 }
390
391 report_pass("SiteValueSelect content", 1 - ok, 1e-6);
392
393
394 onsites(ALL) {}
395}
396
397
398/**
399 * @brief Test subvolume operations
400 *
401 */
403
404 bool ok = true;
405 for (int i = 0; i < 20; i++) {
407 foralldir(d) c[d] = hila::random() * lattice.size(d);
408 auto si = SiteIndex(c);
409 if (si.coordinates() != c)
410 ok = false;
411 }
412
413
414 report_pass("SiteIndex", ok == false, 1e-2);
415
416
418 f[ALL] = SiteIndex(X.coordinates());
419
421 c.fill(-1);
422 size_t vol = lattice.volume();
423 foralldir(d) if (d < NDIM - 1) {
424 c[d] = hila::random() * lattice.size(d);
426
427 auto slice = f.get_slice(c);
428
429 vol /= lattice.size(d);
430 if (hila::myrank() == 0) {
431
432 report_pass(hila::prettyprint(NDIM - (int)d - 1) + "-dimensional slice size " +
433 hila::prettyprint(vol),
434 slice.size() - vol, 1e-3);
435
436
437 bool pass = true;
438
439 CoordinateVector mycoord = 0;
440 foralldir(d2) {
441 if (c[d2] >= 0)
442 mycoord[d2] = c[d2];
443 }
444 foralldir(d2) {
445 if (c[d2] < 0) {
446 mycoord[d2] = -1;
447 break;
448 }
449 }
450
451 for (auto s : slice) {
452
453 // get the coordinate which should be here
454 bool add = true;
455 foralldir(d2) {
456 if (add && c[d2] < 0) {
457 mycoord[d2]++;
458 if (mycoord[d2] < lattice.size(d2)) {
459 add = false;
460 } else {
461 mycoord[d2] = 0;
462 }
463 }
464 }
465
466 if (pass && mycoord != s.coordinates()) {
467 hila::out0 << "Slice coord error, should be "
468 << hila::prettyprint(mycoord.transpose()) << " is "
469 << hila::prettyprint(s.coordinates().transpose()) << " slice is "
470 << hila::prettyprint(c.transpose()) << '\n';
471 pass = false;
472 break;
473 }
474 }
475
476 report_pass("slice content", pass == false, 1e-2);
477 }
478 }
479}
480
481/**
482 * @brief Test FFT
483 * @details Test forward and inverse FFT on fields.
484 *
485 */
486void test_fft() {
487
488
489 using T = Complex<double>;
490
491 Field<T> f, p, p2;
492
493 // Start with unit field
494 f = 1;
495
496 // After one FFT the field is 0 except at coord 0
497 p2 = 0;
498
499 p2[{0, 0, 0}] = lattice.volume();
500
501 FFT_field(f, p);
502
503 double eps = squarenorm_relative(p, p2);
504
505 report_pass("FFT constant field", eps, 1e-13 * sqrt(lattice.volume()));
506
507 //-----------------------------------------------------------------
508 // After two applications the field should be back to a constant * volume
509
510 FFT_field(p, f, fft_direction::back);
511
512 double sum = 0;
513 double tnorm = 0;
514 onsites(ALL) {
515 sum += (f[X] - lattice.volume()).squarenorm();
516 tnorm += f[X].squarenorm();
517 }
518
519 eps = fabs(sum / tnorm);
520
521 report_pass("FFT inverse transform", eps, 1e-10);
522
523 //-----------------------------------------------------------------
524 for (int iter = 0; iter < 5; iter++) {
527 foralldir(d) {
528 kx[d] = hila::broadcast(hila::random()) * lattice.size(d);
529 }
530
531 kv = kx.convert_to_k();
532
533
534 onsites(ALL) {
535 double d = kv.dot(X.coordinates());
536 f[X] = expi(d);
537 }
538
539 FFT_field(f, p);
540
541 p2 = 0;
542 p2[kx] = lattice.volume();
543
544 eps = squarenorm_relative(p, p2);
545
546 report_pass("FFT of wave vector " + hila::prettyprint(kx.transpose()), eps,
547 1e-13 * sqrt(lattice.volume()));
548 }
549
550 //-----------------------------------------------------------------
551
552 {
554 onsites(ALL) r[X] = hila::gaussrand();
555
556 f = r.FFT_real_to_complex();
557 p = f.FFT(fft_direction::back) / lattice.volume();
558 eps = squarenorm_relative(r, p);
559
560 report_pass("FFT real to complex", eps, 1e-13 * sqrt(lattice.volume()));
561
562 bool odd = false;
563 foralldir(d) odd = odd || (lattice.size(d) % 2 > 0);
564 if (!odd) {
565 auto r2 = f.FFT_complex_to_real(fft_direction::back) / lattice.volume();
566 eps = squarenorm_relative(r, r2);
567
568 report_pass("FFT complex to real", eps, 1e-13 * sqrt(lattice.volume()));
569 } else {
570 hila::out0 << " ... Skipping FFT complex to real because lattice size is odd\n";
571 }
572 }
573
574 //-----------------------------------------------------------------
575 // Check fft norm
576
577
578 onsites(ALL) {
579 p[X] = hila::random() * exp(-X.coordinates().convert_to_k().squarenorm());
580 }
581 f = p.FFT(fft_direction::back) / sqrt(lattice.volume());
582
583 double nf = f.squarenorm();
584 double np = p.squarenorm();
585 report_pass("Norm of field = " + hila::prettyprint(nf) + " and FFT = " + hila::prettyprint(np),
586 (nf - np) / nf, 1e-10);
587
589 b.k_max(M_PI * sqrt(3.0));
590
591 auto bf = b.bin_k_field(p.conj() * p);
592
593 double s = 0;
594 for (auto b : bf) {
595 s += abs(b);
596 }
598
599 report_pass("Norm of binned FFT = " + hila::prettyprint(s), (s - np) / np, 1e-10);
600}
601
602/**
603 * @brief Test spectral density
604 * @details Test spectral density extraction from field.
605 *
606 */
608
609
610 // test spectral density for single waves
611
613
615 b.k_max(M_PI * sqrt(3.0));
616
617 // test std binning first
618
619 for (int iter = 0; iter < 3; iter++) {
622 foralldir(d) {
623 kx[d] = hila::broadcast(hila::random()) * lattice.size(d);
624 }
625 kv = kx.convert_to_k();
626 auto absk = kv.norm();
627
628 // test first std. binning (normally )
629 f = 0;
630 f[kx] = 1;
631
632 auto fb = b.bin_k_field(f);
633
634 double sum = 0;
635 for (int i = 0; i < b.bins(); i++) {
636 if (b.bin_min(i) <= absk && b.bin_max(i) > absk) {
637 // should be one hit here
638 sum += squarenorm(fb[i] - 1);
639 } else {
640 sum += squarenorm(fb[i]);
641 }
642 }
643
644 report_pass("Binning test at vector " + hila::prettyprint(kx.transpose()), sum, 1e-10);
645
646 // then test the spectral density extraction
647 // set single wave
648 onsites(ALL) {
649 double d = kv.dot(X.coordinates());
650 f[X] = expi(d);
651 }
652
653 auto fsd = b.spectraldensity(f);
654
655 sum = 0;
656 for (int i = 0; i < b.bins(); i++) {
657 if (b.bin_min(i) <= absk && b.bin_max(i) > absk) {
658 // should be one hit here
659 sum += fabs(fsd[i] / pow(lattice.volume(), 2) - 1);
660 } else {
661 sum += fabs(fsd[i]);
662 }
663 }
664
665 report_pass("Spectral density test with above vector ", sum, 1e-10);
666 }
667}
668
669//--------------------------------------------------------------------------------
670
671void test_field_slices() {
672
674 onsites(ALL) {
675 s[X] = SiteIndex(X.coordinates());
676 }
677}
678
679
680/**
681 * @brief Test matrix operations
682 * @details Test matrix multiplication and addition, as well as operations with imaginary operator.
683 *
684 */
686
688
689 onsites(ALL) mf[X].fill(1 + I);
690
692 cm.asArray() = 4;
693 double sum = 0;
694 onsites(ALL) {
695 sum += (mf[X] * mf[X].dagger() - cm).squarenorm();
696 }
697
698 report_pass("matrix multiply and addition", sum, 1e-8);
699
700 auto dm = cm * I - 2 * I;
701 dm.asArray() *= I;
702 dm = ((dm - 2).asArray() + 4).asMatrix();
703 report_pass("Array and imaginary unit operations", dm.squarenorm(), 1e-8);
704}
705
706
707/**
708 * @brief Test matrix decomposition
709 * @details Test matrix decompositions such as eigen decomposition and singular value decomposition
710 * (SVD).
711 */
713
714 using myMatrix = SquareMatrix<4, Complex<double>>;
715
717 Field<double> delta;
718
719 M.gaussian_random(2.0);
720
721 // eigenvalue test - show that M = U D U^*, where D is diagonal eigenvalue matrix and U
722 // matrix of eigenvectors
723
724 onsites(ALL) {
725 auto H = M[X] * M[X].dagger(); // make hermitean
726
727 auto r = H.eigen_hermitean();
728 delta[X] = (H - r.eigenvectors * r.eigenvalues * r.eigenvectors.dagger()).norm();
729 }
730
731 auto max_delta = delta.max();
732
733 report_pass("Eigenvalue analysis with " + hila::prettyprint(myMatrix::rows()) + "x" +
734 hila::prettyprint(myMatrix::columns()) + " Hermitean matrix",
735 max_delta, 1e-10);
736
737 // Singular value test - non-pivoted
738
739 onsites(ALL) {
740 auto r = M[X].svd();
741 delta[X] = (M[X] - r.U * r.singularvalues * r.V.dagger()).norm();
742 }
743
744 max_delta = delta.max();
745
746 report_pass("SVD with " + hila::prettyprint(myMatrix::rows()) + "x" +
747 hila::prettyprint(myMatrix::columns()) + " Complex matrix",
748 max_delta, 1e-10);
749
750 // pivoted singular values
751
752 M.gaussian_random();
753
754 onsites(ALL) {
755 auto r = M[X].svd_pivot(hila::sort::ascending);
756 delta[X] = (M[X] - r.U * r.singularvalues * r.V.dagger()).norm();
757 }
758
759 max_delta = delta.max();
760
761 report_pass("Fully pivoted SVD with " + hila::prettyprint(myMatrix::rows()) + "x" +
762 hila::prettyprint(myMatrix::columns()) + " Complex matrix",
763 max_delta, 1e-10);
764}
765
766/**
767 * @brief Test extended type
768 * @details Test extended type for sums that exibit loss in accuracy with double.
769 *
770 */
772
773 // ExtendedPrecision type test with T = double
775
776 ExtendedPrecision e = 2.4;
777 e = 5 * e - e - e - 3 * e;
778 report_pass("ExtendedPrecision basic arithmetics: " + hila::prettyprint(e), fabs(e.to_double()),
779 1e-20);
780
781 e = 1;
782 e += 1e-25;
783 bool ok = (e > 1) && (e == e);
784
785 report_pass("ExtendedPrecision comparison ops", ok ? 0 : 1, 1e-20);
786
787 for (double mag = 1e8; mag <= 1e+32; mag *= 1e8) {
788
789 size_t nsqr = 0, nmag = 0, n1 = 0;
790
791 onsites(ALL) {
792 if (X.x() % 2 == 0) {
793 if (X.y() % 2 == 0) {
794 g[X] = sqr(mag);
795 nsqr += 1;
796 } else {
797 g[X] = mag;
798 nmag += 1;
799 }
800 } else {
801 g[X] = 1;
802 n1 += 1;
803 }
804 }
805 ExtendedPrecision ev = 0;
806 double s = 0;
807 onsites(ALL) {
808 ev += g[X];
809 s += g[X];
810 }
811
812 double result = n1 + nmag * mag + nsqr * sqr(mag);
813
814 // ev -= lattice.volume() / 2;
815 // ev -= mag * (lattice.volume() / 4);
816 // ev -= sqr(mag) * (lattice.volume() / 4);
817
818 // above multiplication loses precision! Subtracting
819 // here step-by-step
820
821 ExtendedPrecision res = 0, r;
822 r = sqr(mag);
823 r *= nsqr;
824 res = r;
825
826 r = mag;
827 r *= nmag;
828 res += r;
829
830 r = 1;
831 r *= n1;
832 res += r;
833
834 ev -= res;
835 s -= res.to_double();
836
837
838 // for (int i = 0; i < n1; i++) {
839 // ev -= 1;
840 // s -= 1;
841 // }
842
843
844 // for (int i = 0; i < lattice.volume() / 4; i++) {
845 // ev -= mag;
846 // ev -= sqr(mag);
847 // s -= mag;
848 // s -= sqr(mag);
849 // }
850
851 // s -= sqr(mag) * lattice.volume() / 4;
852 // s -= mag * lattice.volume() / 4;
853 // s -= lattice.volume() / 2;
854
855 // hila::out0 << "RES " << ev.value << " + " << ev.compensation << " + " <<
856 // ev.compensation2
857 // << '\n';
858
859
860 std::stringstream ssres;
861 ssres << "Extended reduction residual w. delta " << mag << " : " << ev.to_double() / result
862 << " (double " << s / result << ")";
863
864 report_pass(ssres.str(), ev.to_double() / result, 1e-20);
865 }
866}
867
868
869//--------------------------------------------------------------------------------
870
871void test_clusters() {
872
873 Field<int> m;
874
875 m = hila::clusters::background;
876
877 onsites(ALL) {
878 auto c = X.coordinates();
879 if (c[e_x] == 0 && c[e_y] == 0)
880 m[X] = 1;
881 else if (c[e_x] == 2 && c[e_z] == 2)
882 m[X] = 2;
883 else if (c[e_x] == 4 && c[e_y] < 3 && c[e_z] > 1 && c[e_z] <= 4)
884 m[X] = 3;
885 }
886
887 hila::clusters cl(m);
888
889 report_pass("Cluster test: number of clusters ", cl.number() - 3, 1e-10);
890 if (cl.number() == 3) {
891 double sumsize =
892 fabs(cl.size(0) - (lattice.volume() / (lattice.size(e_x) * lattice.size(e_y)))) +
893 fabs(cl.size(1) - (lattice.volume() / (lattice.size(e_x) * lattice.size(e_z)))) +
894 fabs(cl.size(2) - 1 * 3 * 3);
895 report_pass("Cluster test: cluster sizes ", sumsize, 1e-10);
896
897 double types = abs(cl.type(0) - 1) + abs(cl.type(1) - 2) + abs(cl.type(2) - 3);
898 report_pass("Cluster test: cluster types ", types, 1e-10);
899
900#if NDIM == 3
901 double area = abs(cl.area(0) - 4 * lattice.size(e_z)) +
902 abs(cl.area(1) - 4 * lattice.size(e_y)) +
903 abs(cl.area(2) - 2 * (1 * 3 + 1 * 3 + 3 * 3));
904
905 report_pass("Cluster test: cluster area ", area, 1e-10);
906
907#endif
908 }
909}
910
911void test_blocking() {
912
913 CoordinateVector blocking;
914 blocking.fill(2);
915 if (lattice.can_block(blocking)) {
916
917 Field<CoordinateVector> cvf, cvfb;
918 cvf[ALL] = X.coordinates();
919
920 hila::print_dashed_line();
921 lattice.block(blocking);
922 hila::out0 << "Testing blocked lattice of size " << lattice.size() << '\n';
923
924 cvfb.block_from(cvf);
925 double sum = 0;
926 onsites(ALL) {
927 sum += (cvfb[X] - 2*X.coordinates()).squarenorm();
928 cvfb[X] *= -1;
929 }
930
931 report_pass("Field blocking test",sum,1e-5);
932
935
936 lattice.unblock();
937 cvfb.unblock_to(cvf);
938
939 hila::print_dashed_line();
940 hila::out0 << "Return lattice to size " << lattice.size() << '\n';
941
942
943 sum = 0;
944 onsites(ALL) {
945 if (X.coordinates().is_divisible({2,2,2})) {
946 sum += (X.coordinates() + cvf[X]).squarenorm();
947 }
948 }
949
950 report_pass("Field unblocking test",sum,1e-5);
951
954 }
955}
956
957
958//////////////////////////////////////////////////////////////////////////////////////////
959
960int main(int argc, char **argv) {
961
962 hila::initialize(argc, argv);
963
964 hila::input par("parameters");
965
966 CoordinateVector lsize = par.get("lattice size"); // reads NDIM numbers
967 long seed = par.get("random seed");
968
969 par.close();
970
971 // setting up the lattice is convenient to do after reading
972 // the parameters
973 lattice.setup(lsize);
974
975 // We need random number here
976 hila::seed_random(seed);
977
978
979 ///////////////////////////////////////////////////////////////
980 // start tests
981
985 test_minmax();
986 test_random();
990 test_fft();
994 test_clusters();
995 test_blocking();
996
998}
hila::arithmetic_type< T > squarenorm(const Array< n, m, T > &rhs)
Return square norm of Array.
Definition array.h:1019
Complex definition.
Definition cmplx.h:58
Vector< 4, double > convert_to_k() const
Convert momentum space CoordinateVector to wave number k, where -pi/2 < k_i <= pi_2 Utility function ...
Definition fft.h:36
The field class implements the standard methods for accessing Fields. Hilapp replaces the parity acce...
Definition field.h:62
Field< A > dagger() const
Returns dagger or Hermitian conjugate of Field depending on how it is defined for Field type T.
Definition field.h:1188
T max(Parity par=ALL) const
Find maximum value from Field.
Definition reduction.h:413
Field< Complex< hila::arithmetic_type< T > > > FFT_real_to_complex(fft_direction fdir=fft_direction::forward) const
Definition fft.h:474
Field< T > conj() const
Returns field with all elements conjugated depending how conjugate is defined for type.
Definition field.h:1175
double squarenorm() const
Squarenorm.
Definition field.h:1148
std::vector< T > get_elements(const std::vector< CoordinateVector > &coord_list, bool broadcast=false) const
Get a list of elements and store them into a vector.
Definition field_comm.h:658
T min(Parity par=ALL) const
Find minimum value from Field.
Definition reduction.h:393
T sum(Parity par=Parity::all, bool allreduce=true) const
Sum reduction of Field.
Definition reduction.h:287
std::vector< T > get_slice(const CoordinateVector &c, bool broadcast=false) const
Get a slice (subvolume)
Definition field_comm.h:696
void unblock_to(Field< T > &target) const
Copy content to the argument Field on blocked (sparse) sites. a.unblock_to(b) is the inverse of a....
Definition field_comm.h:971
void setup(const CoordinateVector &siz)
lattice.setup(CoordinateVector size) - set up the base lattice. Called at the beginning of the progra...
Definition lattice.h:447
Lattice unblock()
Unblock lattice, returning to parent. Current lattice must be a blocked lattice.
Definition lattice.h:589
int size(Direction d) const
lattice.size() -> CoordinateVector or lattice.size(d) -> int returns the dimensions of the lattice,...
Definition lattice.h:433
bool can_block(const CoordinateVector &factor) const
Test if lattice can be blocked by factor given in argument.
Definition lattice.h:531
int64_t volume() const
lattice.volume() returns lattice volume Can be used inside onsites()-loops
Definition lattice.h:424
hila::arithmetic_type< T > norm() const
Calculate vector norm - sqrt of squarenorm.
Definition matrix.h:1225
const auto & fill(const S rhs)
Matrix fill.
Definition matrix.h:1022
Rtype transpose() const
Transpose of matrix.
Definition matrix.h:1039
R dot(const Matrix< p, q, S > &rhs) const
Dot product.
Definition matrix.h:1314
const Array< n, m, T > & asArray() const
Cast Matrix to Array.
Definition matrix.h:476
Matrix class which defines matrix operations.
Definition matrix.h:1742
size_t size() const
methods from std::vector:
Running index for locating sites on the lattice.
Definition site_index.h:17
hila::input - Class for parsing runtime parameter files.
Definition input.h:53
std::vector< double > spectraldensity(const Field< T > &f)
k_binning & k_max(double km)
Max value of k.
double bin_min(int i)
std::vector< T > bin_k_field(const Field< T > &f)
Generic k-space field binner routine - returns field element type vector.
k_binning & bins(int n)
Set number of bins in histogram.
provides cluster finding tools
constexpr Imaginary_t< double > I(1.0)
Imaginary unit I - global variable.
T abs(const Complex< T > &a)
Return absolute value of Complex number.
Definition cmplx.h:1266
Parity
Parity enum with values EVEN, ODD, ALL; refers to parity of the site. Parity of site (x,...
constexpr Parity EVEN
bit pattern: 001
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:80
constexpr Parity ODD
bit pattern: 010
constexpr Parity ALL
bit pattern: 011
constexpr T sqr(const T &arg)
Define convenience function sqr(), returning square of argument.
Definition defs.h:163
void FFT_field(const Field< T > &input, Field< T > &result, const CoordinateVector &directions, fft_direction fftdir=fft_direction::forward)
Definition fft.h:381
void test_spectraldensity()
Test spectral density.
void test_minmax()
Test min and max operations on fields.
void test_fft()
Test FFT.
void test_matrix_algebra()
Test matrix decomposition.
void test_set_elements_and_select()
Test setting elements and selecting them.
void test_reductions()
Test reduction operations on fields.
void test_matrix_operations()
Test matrix operations.
void test_subvolumes()
Test subvolume operations.
void test_random()
Test Gaussian random field generation.
void test_site_access()
Test site access.
void test_extended()
Test extended type.
void test_functions()
Test various functions on fields.
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:121
int myrank()
rank of this node
Definition com_mpi.cpp:237
double gaussrand()
Gaussian random generation routine.
Definition random.cpp:240
std::ostream out0
This writes output only from main process (node 0)
void initialize(int argc, char **argv)
Initial setup routines.
void seed_random(uint64_t seed, bool device_rng=true)
Seed random generators with 64-bit unsigned value. On MPI shuffles the seed so that different MPI ran...
Definition random.cpp:86
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
Definition com_mpi.h:170
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...