1use crate::geometry::Lattice;
2
3use super::Statistics;
4
5pub struct OverlapStats {
9 pub overlap: Vec<f64>,
11 pub overlap2: Vec<f64>,
13 pub overlap4: Vec<f64>,
15 pub link_overlap: Vec<f64>,
17 pub link_overlap2: Vec<f64>,
19 pub link_overlap4: Vec<f64>,
21 pub histogram: Vec<Vec<u64>>,
24 pub ql_at_q_sum: Vec<Vec<f64>>,
27 pub ql2_at_q_sum: Vec<Vec<f64>>,
30 pub per_sample_histogram: Vec<Vec<Vec<u64>>>,
33 pub per_sample_ql_at_q_sum: Vec<Vec<Vec<f64>>>,
36 pub per_sample_ql2_at_q_sum: Vec<Vec<Vec<f64>>>,
39}
40
41impl OverlapStats {
42 pub fn empty() -> Self {
43 Self {
44 overlap: vec![],
45 overlap2: vec![],
46 overlap4: vec![],
47 link_overlap: vec![],
48 link_overlap2: vec![],
49 link_overlap4: vec![],
50 histogram: vec![],
51 ql_at_q_sum: vec![],
52 ql2_at_q_sum: vec![],
53 per_sample_histogram: vec![],
54 per_sample_ql_at_q_sum: vec![],
55 per_sample_ql2_at_q_sum: vec![],
56 }
57 }
58
59 pub fn aggregate(results: &[&Self]) -> Self {
60 if results[0].overlap.is_empty() {
61 return Self::empty();
62 }
63
64 let n = results.len() as f64;
65 let n_temps = results[0].overlap.len();
66 let n_hist = results[0].histogram.len();
67 let hist_bins = results[0].histogram[0].len();
68 let n_ql = results[0].ql_at_q_sum.len();
69 let ql_bins = results[0].ql_at_q_sum.first().map_or(0, |v| v.len());
70
71 let mut agg = Self {
72 overlap: vec![0.0; n_temps],
73 overlap2: vec![0.0; n_temps],
74 overlap4: vec![0.0; n_temps],
75 link_overlap: vec![0.0; n_temps],
76 link_overlap2: vec![0.0; n_temps],
77 link_overlap4: vec![0.0; n_temps],
78 histogram: (0..n_hist).map(|_| vec![0u64; hist_bins]).collect(),
79 ql_at_q_sum: (0..n_ql).map(|_| vec![0.0; ql_bins]).collect(),
80 ql2_at_q_sum: (0..n_ql).map(|_| vec![0.0; ql_bins]).collect(),
81 per_sample_histogram: results.iter().map(|r| r.histogram.clone()).collect(),
82 per_sample_ql_at_q_sum: results.iter().map(|r| r.ql_at_q_sum.clone()).collect(),
83 per_sample_ql2_at_q_sum: results.iter().map(|r| r.ql2_at_q_sum.clone()).collect(),
84 };
85
86 for r in results {
87 for (a, &v) in agg.overlap.iter_mut().zip(r.overlap.iter()) {
88 *a += v;
89 }
90 for (a, &v) in agg.overlap2.iter_mut().zip(r.overlap2.iter()) {
91 *a += v;
92 }
93 for (a, &v) in agg.overlap4.iter_mut().zip(r.overlap4.iter()) {
94 *a += v;
95 }
96 for (a, &v) in agg.link_overlap.iter_mut().zip(r.link_overlap.iter()) {
97 *a += v;
98 }
99 for (a, &v) in agg.link_overlap2.iter_mut().zip(r.link_overlap2.iter()) {
100 *a += v;
101 }
102 for (a, &v) in agg.link_overlap4.iter_mut().zip(r.link_overlap4.iter()) {
103 *a += v;
104 }
105 for (a, s) in agg.histogram.iter_mut().zip(r.histogram.iter()) {
106 for (ah, &sh) in a.iter_mut().zip(s.iter()) {
107 *ah += sh;
108 }
109 }
110 for (a, s) in agg.ql_at_q_sum.iter_mut().zip(r.ql_at_q_sum.iter()) {
111 for (ah, &sh) in a.iter_mut().zip(s.iter()) {
112 *ah += sh;
113 }
114 }
115 for (a, s) in agg.ql2_at_q_sum.iter_mut().zip(r.ql2_at_q_sum.iter()) {
116 for (ah, &sh) in a.iter_mut().zip(s.iter()) {
117 *ah += sh;
118 }
119 }
120 }
121
122 for v in agg
123 .overlap
124 .iter_mut()
125 .chain(agg.overlap2.iter_mut())
126 .chain(agg.overlap4.iter_mut())
127 .chain(agg.link_overlap.iter_mut())
128 .chain(agg.link_overlap2.iter_mut())
129 .chain(agg.link_overlap4.iter_mut())
130 {
131 *v /= n;
132 }
133
134 agg
135 }
136}
137
138pub struct OverlapAccum {
140 n_pairs: usize,
141 n_temps: usize,
142 n_spins: usize,
143 n_bonds: usize,
144 equil_diag: bool,
145 collect_q2_ac: bool,
146
147 overlap_stat: Statistics,
148 overlap2_stat: Statistics,
149 overlap4_stat: Statistics,
150 link_overlap_stat: Statistics,
151 link_overlap2_stat: Statistics,
152 link_overlap4_stat: Statistics,
153
154 histogram: Vec<Vec<u64>>,
155 ql_at_q_sum: Vec<Vec<f64>>,
156 ql2_at_q_sum: Vec<Vec<f64>>,
157
158 overlaps_buf: Vec<f32>,
159 overlaps2_buf: Vec<f32>,
160 overlaps4_buf: Vec<f32>,
161 link_overlaps_buf: Vec<f32>,
162 link_overlaps2_buf: Vec<f32>,
163 link_overlaps4_buf: Vec<f32>,
164
165 pub diag_ql_buf: Vec<f32>,
166 pub q2_ac_buf: Vec<f64>,
167}
168
169impl OverlapAccum {
170 pub fn new(
171 n_temps: usize,
172 n_spins: usize,
173 n_pairs: usize,
174 n_neighbors: usize,
175 equil_diag: bool,
176 collect_q2_ac: bool,
177 ) -> Self {
178 let has_pairs = n_pairs > 0;
179 Self {
180 n_pairs,
181 n_temps,
182 n_spins,
183 n_bonds: n_spins * n_neighbors,
184 equil_diag,
185 collect_q2_ac,
186
187 overlap_stat: Statistics::new(n_temps, 1),
188 overlap2_stat: Statistics::new(n_temps, 1),
189 overlap4_stat: Statistics::new(n_temps, 1),
190 link_overlap_stat: Statistics::new(n_temps, 1),
191 link_overlap2_stat: Statistics::new(n_temps, 1),
192 link_overlap4_stat: Statistics::new(n_temps, 1),
193
194 histogram: if has_pairs {
195 (0..n_temps).map(|_| vec![0u64; n_spins + 1]).collect()
196 } else {
197 vec![]
198 },
199 ql_at_q_sum: if has_pairs {
200 (0..n_temps).map(|_| vec![0.0f64; n_spins + 1]).collect()
201 } else {
202 vec![]
203 },
204 ql2_at_q_sum: if has_pairs {
205 (0..n_temps).map(|_| vec![0.0f64; n_spins + 1]).collect()
206 } else {
207 vec![]
208 },
209
210 overlaps_buf: vec![0.0f32; n_temps],
211 overlaps2_buf: vec![0.0f32; n_temps],
212 overlaps4_buf: vec![0.0f32; n_temps],
213 link_overlaps_buf: vec![0.0f32; n_temps],
214 link_overlaps2_buf: vec![0.0f32; n_temps],
215 link_overlaps4_buf: vec![0.0f32; n_temps],
216
217 diag_ql_buf: if equil_diag {
218 vec![0.0f32; n_temps]
219 } else {
220 vec![]
221 },
222 q2_ac_buf: if collect_q2_ac {
223 vec![0.0f64; n_temps]
224 } else {
225 vec![]
226 },
227 }
228 }
229
230 #[inline]
231 pub fn collect(&mut self, lattice: &Lattice, spins: &[i8], system_ids: &[usize], record: bool) {
232 if self.equil_diag {
233 self.diag_ql_buf.fill(0.0);
234 }
235 if self.collect_q2_ac && record {
236 self.q2_ac_buf.fill(0.0);
237 }
238
239 for pair_idx in 0..self.n_pairs {
240 let r_a = 2 * pair_idx;
241 let r_b = 2 * pair_idx + 1;
242
243 for t in 0..self.n_temps {
244 let sys_a = system_ids[r_a * self.n_temps + t];
245 let sys_b = system_ids[r_b * self.n_temps + t];
246 let base_a = sys_a * self.n_spins;
247 let base_b = sys_b * self.n_spins;
248
249 let mut dot_spin = 0i64;
250 let mut dot_link = 0i64;
251 for j in 0..self.n_spins {
252 let sa = spins[base_a + j] as i64;
253 let sb = spins[base_b + j] as i64;
254 dot_spin += sa * sb;
255 for d in 0..lattice.n_neighbors {
256 let k = lattice.neighbor_fwd(j, d);
257 dot_link +=
258 (sa * spins[base_a + k] as i64) * (sb * spins[base_b + k] as i64);
259 }
260 }
261
262 let ql = dot_link as f32 / self.n_bonds as f32;
263
264 if self.equil_diag {
265 self.diag_ql_buf[t] += ql;
266 }
267 if !record {
268 continue;
269 }
270
271 let q = dot_spin as f32 / self.n_spins as f32;
272 let q2 = q * q;
273 self.overlaps_buf[t] = q;
274 self.overlaps2_buf[t] = q2;
275 self.overlaps4_buf[t] = q2 * q2;
276
277 let ql2 = ql * ql;
278 self.link_overlaps_buf[t] = ql;
279 self.link_overlaps2_buf[t] = ql2;
280 self.link_overlaps4_buf[t] = ql2 * ql2;
281
282 let idx = ((dot_spin + self.n_spins as i64) / 2) as usize;
283 self.histogram[t][idx] += 1;
284 self.ql_at_q_sum[t][idx] += ql as f64;
285 self.ql2_at_q_sum[t][idx] += (ql * ql) as f64;
286 }
287
288 if !record {
289 continue;
290 }
291
292 if self.collect_q2_ac {
293 for t in 0..self.n_temps {
294 self.q2_ac_buf[t] += self.overlaps2_buf[t] as f64;
295 }
296 }
297
298 self.overlap_stat.update(&self.overlaps_buf);
299 self.overlap2_stat.update(&self.overlaps2_buf);
300 self.overlap4_stat.update(&self.overlaps4_buf);
301 self.link_overlap_stat.update(&self.link_overlaps_buf);
302 self.link_overlap2_stat.update(&self.link_overlaps2_buf);
303 self.link_overlap4_stat.update(&self.link_overlaps4_buf);
304 }
305
306 if self.equil_diag {
307 let inv = 1.0 / self.n_pairs as f32;
308 for v in self.diag_ql_buf.iter_mut() {
309 *v *= inv;
310 }
311 }
312 }
313
314 pub fn finish(self) -> OverlapStats {
315 if self.n_pairs == 0 {
316 return OverlapStats::empty();
317 }
318 OverlapStats {
319 overlap: self.overlap_stat.average(),
320 overlap2: self.overlap2_stat.average(),
321 overlap4: self.overlap4_stat.average(),
322 link_overlap: self.link_overlap_stat.average(),
323 link_overlap2: self.link_overlap2_stat.average(),
324 link_overlap4: self.link_overlap4_stat.average(),
325 histogram: self.histogram,
326 ql_at_q_sum: self.ql_at_q_sum,
327 ql2_at_q_sum: self.ql2_at_q_sum,
328 per_sample_histogram: vec![],
329 per_sample_ql_at_q_sum: vec![],
330 per_sample_ql2_at_q_sum: vec![],
331 }
332 }
333}