HILA
Loading...
Searching...
No Matches
spectraldensity.h
1#ifndef SPECTRALDENSITY_H
2#define SPECTRALDENSITY_H
3
4#include "hila.h"
5
6
7extern hila::timer binning_timer;
8
9/// sd_k_bin_parameters holds the parameters to define binning.
10
12 double max; // min and max of k (default: 0 and pi)
13 double power; // binned function k^p, default p=1 : note, min and max are "powered"
14 // too
15 double binwidth;
16 int bins; // how many bins in output (default=max of lattice.size(d)/2)
17
18 int exact; // do this many low k-value "bins" exactly NOT IMPLEMENTED YET
19 bool bins_set; // bool to keep track if number of bins have been set
20};
21
22
23/// get bin
24/// TODO: this should be insider k_binning class but hilapp is not yet able to handle
25/// it!
26
27inline int sd_get_k_bin(const CoordinateVector &cv, const sd_k_bin_parameters &p) {
28
29 double kr = convert_to_k(cv).norm();
30
31 kr = kr / p.max;
32 int b = pow(kr, p.power) * p.bins;
33 return b;
34}
35
36
37namespace hila {
38
39/// class hila::k_binning is used to bin "k-space" fields (typically fourier transformed
40/// from real space). Vector k is normalized so that -pi < k_i <= pi, i.e.
41// k_i = 2*pi*x_i/L_i, where L_i = lattice.size(i) and x_i is the L_i/2 modded
42/// coordinate.
43/// Bin is determined by formula
44/// b = (int) ( (k/k_max)^p * n_bins ), where p is the power in binning - usually 1
45///
46/// hila::k_binning kb;
47/// kb.bins(80).k_max(M_PI);
48/// auto sd = kb.spectraldensity(f); // get the spectral density of field f
49///
50/// methods: (use as kb.xxx)
51/// hila::k_binning & bins(int n) set number of bins (k_max const.)
52/// int bins() get number of bins
53/// hila::k_binning & k_max(double m) set max value of k in binning
54/// if bins have been modified it is kept constant, otherwise
55/// number of bins is changed so that binwidth is const.
56/// double k_max() get max value of k
57/// hila::k_binning & power(double p) set the "power" in binning
58/// double power() get power
59/// hila::k_binning & binwidth(double w) set binwidth (k_max const, so bins changes)
60/// double binwidth() get binwidth
61///
62/// std::vector<T> bin_k_field(const Field<T> &f) bin the k-space field f
63/// std::vector<double> bin_k_field_squarenorm(const Field<T & f)
64/// bin the square norm of k-space field f
65/// std::vector<double> spectraldensity(const Field<T> &f)
66/// FFT real-space field f and bin the result in squarenorm
67///
68/// double k(int b) return the average k within bin b
69/// long count(int b) return the number of points within bin b
70/// double bin_min(int b) return the minimum k of bin b
71/// double bin_max(int b) maximum k in bin b
72class k_binning {
73 private:
75 std::vector<double> k_avg;
76 std::vector<size_t> bin_count;
77
78 public:
79 k_binning() {
80 par.max = M_PI;
81 par.power = 1;
82 par.exact = 0;
83 par.bins = 1;
84 par.bins_set = false;
85 foralldir(d) {
86 if (lattice.size(d) > 2 * par.bins)
87 par.bins = lattice.size(d) / 2;
88 }
89 par.binwidth = par.max / par.bins;
90 }
91
92 k_binning(int b) {
93 par.max = M_PI;
94 par.power = 1;
95 par.exact = 0;
96 par.bins = b;
97 par.bins_set = true;
98 par.binwidth = par.max / par.bins;
99 }
100
101 /// Set number of bins in histogram
102 k_binning &bins(int n) {
103 assert(n > 0);
104 par.bins = n;
105 par.bins_set = true;
106 par.binwidth = par.max / par.bins;
107 return *this;
108 }
109
110 int bins(void) {
111 return par.bins;
112 }
113
114 /// Max value of k
115 k_binning &k_max(double km) {
116 assert(km > 0);
117 par.max = km;
118 if (!par.bins_set) {
119 par.bins = ceil(par.max / par.binwidth);
120 par.max = par.binwidth * par.bins;
121 }
122 return *this;
123 }
124
125 double k_max(void) {
126 return par.max;
127 }
128
129 k_binning &binwidth(double w) {
130 assert(w > 0);
131 par.binwidth = w;
132 par.bins = ceil(par.max / w);
133 par.max = par.binwidth * par.bins;
134 par.bins_set = false;
135 return *this;
136 }
137
138 double binwidth() {
139 return par.binwidth;
140 }
141
142 /// Bin quantity k^p
143 k_binning &power(double p) {
144 assert(p > 0);
145 par.power = p;
146 return *this;
147 }
148
149 double power() {
150 return par.power;
151 }
152
153 /// Bin exactly this many bins
155 assert(e >= 0);
156 par.exact = e;
157 return *this;
158 }
159
160 int exact_bins() {
161 return par.exact;
162 }
163
164 /// Generic k-space field binner routine - returns field element type vector
165
166 template <typename T>
167 std::vector<T> bin_k_field(const Field<T> &f) {
168
169 binning_timer.start();
170
171 if (k_avg.size() != par.bins)
173
174 ReductionVector<T> s(par.bins);
175 s.allreduce(false);
176 s = 0;
177
178 onsites(ALL) {
179
180 int b = sd_get_k_bin(X.coordinates(), par);
181 if (b >= 0 && b < par.bins) {
182 s[b] += f[X];
183 }
184 }
185
186 binning_timer.stop();
187
188 return s.vector();
189 }
190
191 /// sum up the square norm of all elements
192
193 template <typename T>
194 std::vector<double> bin_k_field_squarenorm(const Field<T> &f) {
195
196 using float_t = hila::arithmetic_type<T>;
197 constexpr int n_float = sizeof(T) / sizeof(float_t);
198
199 binning_timer.start();
200
201 if (k_avg.size() != par.bins)
203
204 ReductionVector<double> s(par.bins);
205 s.allreduce(false);
206 s = 0;
207
208 onsites(ALL) {
209
210 int b = sd_get_k_bin(X.coordinates(), par);
211 if (b >= 0 && b < par.bins) {
212 double ps = 0;
213 for (int i = 0; i < n_float; i++) {
214 auto a = hila::get_number_in_var(f[X], i);
215 ps += a * a;
216 }
217 s[b] += ps;
218 }
219 }
220
221 binning_timer.stop();
222
223 return s.vector();
224 }
225
226
227 //////////////////////////////////////////////////////////////////////////////////
228 /// Spectral density
229 /// This version takes in complex field
230
231 template <typename T, std::enable_if_t<hila::contains_complex<T>::value, int> = 0>
232 std::vector<double> spectraldensity(const Field<T> &f) {
233
234 Field<T> ftrans;
235 FFT_field(f, ftrans);
236
237 return bin_k_field_squarenorm(ftrans);
238 }
239
240 //////////////////////////////////////////////////////////////////////////////////
241 /// interface for real fields - an extra copy which could be avoided
242 template <typename T, std::enable_if_t<!hila::contains_complex<T>::value, int> = 0>
243 std::vector<double> spectraldensity(const Field<T> &f) {
244
245 using cmplx_t = Complex<hila::arithmetic_type<T>>;
246
247 if constexpr (sizeof(T) % sizeof(Complex<hila::arithmetic_type<T>>) == 0) {
248 // real field, size is even -- cast the field to pseudo-complex
249 // This works because layouts are compatible in all archs - if this changes
250 // then need copy
251 constexpr int nc = sizeof(T) / sizeof(cmplx_t);
252
253 return spectraldensity(*reinterpret_cast<const Field<Vector<nc, cmplx_t>> *>(&f));
254 } else {
255 // now the size of input is not evenly divisible by sizeof complex.
256 // new complex field
257 constexpr int nc = sizeof(T) / sizeof(cmplx_t) + 1;
258
260
261 onsites(ALL) {
262
263 cfield[X] = 0;
264 for (int i = 0; i < sizeof(T) / sizeof(hila::arithmetic_type<T>); i++) {
265 auto a = hila::get_number_in_var(f[X], i);
266 hila::set_number_in_var(cfield[X], i, a);
267 }
268 }
269
270 return spectraldensity(cfield);
271 }
272 }
273
274
275 /// Data structure to hold the binning info - two vectors,
276 /// holding average k value in a bin and count of lattice points
277
279
280 k_avg.resize(par.bins);
281 bin_count.resize(par.bins);
282
283 ReductionVector<double> s(par.bins);
285 s = 0;
286 count = 0;
287
288 onsites(ALL) {
289
290 double kr = convert_to_k(X.coordinates()).norm();
291 int b = sd_get_k_bin(X.coordinates(), par);
292
293 if (b >= 0 && b < par.bins) {
294 s[b] += kr;
295 count[b] += 1;
296 }
297 }
298
299 for (int i = 0; i < par.bins; i++) {
300 bin_count[i] = count[i];
301 k_avg[i] = s[i] / count[i];
302 }
303 }
304
305 /// Get the average k-value of bin i
306
307 double k(int i) {
308
309 if (k_avg.size() == 0) {
311 }
312
313 if (i >= 0 && i < par.bins)
314 return k_avg[i];
315 else
316 return 0.0;
317 }
318
319 /// get the count of points within bin i
320
321 long count(int i) {
322
323 if (bin_count.size() == 0) {
325 }
326
327 if (i >= 0 && i < par.bins)
328 return bin_count[i];
329 else
330 return 0;
331 }
332
333 /// Bin limits
334 /// bin is b = floor((k / k_max)^p * n_bins)
335 /// thus, k_min(b) = (b/n_bins)^(1/p) * k_max
336
337 double bin_min(int i) {
338 return pow(((double)i) / par.bins, 1.0 / par.power) * par.max;
339 }
340
341 double bin_max(int i) {
342 return bin_min(i + 1);
343 }
344};
345
346} // namespace hila
347
348#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
ReductionVector & allreduce(bool b=true)
allreduce(bool) turns allreduce on or off. By default on.
std::vector< double > spectraldensity(const Field< T > &f)
k_binning & k_max(double km)
Max value of k.
k_binning & exact_bins(int e)
Bin exactly this many bins.
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.
double k(int i)
Get the average k-value of bin i.
k_binning & power(double p)
Bin quantity k^p.
k_binning & bins(int n)
Set number of bins in histogram.
long count(int i)
get the count of points within bin i
std::vector< double > bin_k_field_squarenorm(const Field< T > &f)
sum up the square norm of all elements
#define foralldir(d)
Macro to loop over (all) Direction(s)
Definition coordinates.h:78
constexpr Parity ALL
bit pattern: 011
Vector< 4, double > convert_to_k(const CoordinateVector &cv)
Convert momentum space CoordinateVector to wave number k, where -pi/2 < k_i <= pi/2.
Definition fft.h:32
void FFT_field(const Field< T > &input, Field< T > &result, const CoordinateVector &directions, fft_direction fftdir=fft_direction::forward)
Definition fft.h:376
Invert diagonal + const. matrix using Sherman-Morrison formula.
Definition array.h:920
hila::arithmetic_type< T > get_number_in_var(const T &var, int i)
Definition type_tools.h:118
sd_k_bin_parameters holds the parameters to define binning.