spin_sim/statistics/
results.rs1use super::equilibration::EquilCheckpoint;
2use super::overlap::OverlapStats;
3
4pub struct ClusterSnapshot {
5 pub sweep_id: usize,
6 pub mode_idx: usize,
7 pub cluster_ids: Vec<Vec<u32>>,
8 pub blue_ids: Option<Vec<Vec<u32>>>,
9 pub spins: Vec<[Vec<i8>; 2]>,
10 pub system_ids: Vec<[usize; 2]>,
11}
12
13pub struct ClusterStats {
14 pub fk_csd: Vec<Vec<u64>>,
16 pub overlap_csd: Vec<Vec<Vec<u64>>>,
18 pub top_cluster_sizes: Vec<Vec<[f64; 4]>>,
20}
21
22pub struct Diagnostics {
23 pub mags2_tau: Vec<f64>,
26 pub overlap2_tau: Vec<f64>,
29 pub equil_checkpoints: Vec<EquilCheckpoint>,
32}
33
34pub struct SweepResult {
39 pub mags: Vec<f64>,
41 pub mags2: Vec<f64>,
43 pub mags4: Vec<f64>,
45 pub energies: Vec<f64>,
47 pub energies2: Vec<f64>,
49 pub overlap_stats: OverlapStats,
50 pub cluster_stats: ClusterStats,
51 pub diagnostics: Diagnostics,
52 pub cluster_snapshots: Vec<ClusterSnapshot>,
53}
54
55impl SweepResult {
56 pub fn aggregate(results: &[Self]) -> Self {
58 let n = results.len() as f64;
59 let n_temps = results[0].mags.len();
60 let n_fk_csd = results[0].cluster_stats.fk_csd.len();
61
62 let fk_len = results[0]
63 .cluster_stats
64 .fk_csd
65 .first()
66 .map_or(0, |v| v.len());
67
68 let n_modes = results[0].cluster_stats.overlap_csd.len();
69 let ov_inner_len = results[0]
70 .cluster_stats
71 .overlap_csd
72 .first()
73 .and_then(|v| v.first())
74 .map_or(0, |v| v.len());
75 let ov_inner_temps = results[0]
76 .cluster_stats
77 .overlap_csd
78 .first()
79 .map_or(0, |v| v.len());
80
81 let n_top_modes = results[0].cluster_stats.top_cluster_sizes.len();
82 let n_top_temps = results[0]
83 .cluster_stats
84 .top_cluster_sizes
85 .first()
86 .map_or(0, |v| v.len());
87
88 let m2_tau_len = results[0].diagnostics.mags2_tau.len();
89 let q2_tau_len = results[0].diagnostics.overlap2_tau.len();
90 let n_ckpts = results[0].diagnostics.equil_checkpoints.len();
91
92 let overlap_stats =
93 OverlapStats::aggregate(&results.iter().map(|r| &r.overlap_stats).collect::<Vec<_>>());
94
95 let mut agg = SweepResult {
96 mags: vec![0.0; n_temps],
97 mags2: vec![0.0; n_temps],
98 mags4: vec![0.0; n_temps],
99 energies: vec![0.0; n_temps],
100 energies2: vec![0.0; n_temps],
101 overlap_stats,
102 cluster_stats: ClusterStats {
103 fk_csd: (0..n_fk_csd).map(|_| vec![0u64; fk_len]).collect(),
104 overlap_csd: (0..n_modes)
105 .map(|_| {
106 (0..ov_inner_temps)
107 .map(|_| vec![0u64; ov_inner_len])
108 .collect()
109 })
110 .collect(),
111 top_cluster_sizes: (0..n_top_modes)
112 .map(|_| vec![[0.0; 4]; n_top_temps])
113 .collect(),
114 },
115 diagnostics: Diagnostics {
116 mags2_tau: vec![0.0; m2_tau_len],
117 overlap2_tau: vec![0.0; q2_tau_len],
118 equil_checkpoints: (0..n_ckpts)
119 .map(|i| EquilCheckpoint {
120 sweep: results[0].diagnostics.equil_checkpoints[i].sweep,
121 energy_avg: vec![0.0; n_temps],
122 link_overlap_avg: vec![0.0; n_temps],
123 })
124 .collect(),
125 },
126 cluster_snapshots: Vec::new(),
127 };
128
129 for r in results {
130 for (a, &v) in agg.mags.iter_mut().zip(r.mags.iter()) {
131 *a += v;
132 }
133 for (a, &v) in agg.mags2.iter_mut().zip(r.mags2.iter()) {
134 *a += v;
135 }
136 for (a, &v) in agg.mags4.iter_mut().zip(r.mags4.iter()) {
137 *a += v;
138 }
139 for (a, &v) in agg.energies.iter_mut().zip(r.energies.iter()) {
140 *a += v;
141 }
142 for (a, &v) in agg.energies2.iter_mut().zip(r.energies2.iter()) {
143 *a += v;
144 }
145 for (a, s) in agg
146 .cluster_stats
147 .fk_csd
148 .iter_mut()
149 .zip(r.cluster_stats.fk_csd.iter())
150 {
151 for (ah, &sh) in a.iter_mut().zip(s.iter()) {
152 *ah += sh;
153 }
154 }
155 for (am, sm) in agg
156 .cluster_stats
157 .overlap_csd
158 .iter_mut()
159 .zip(r.cluster_stats.overlap_csd.iter())
160 {
161 for (a, s) in am.iter_mut().zip(sm.iter()) {
162 for (ah, &sh) in a.iter_mut().zip(s.iter()) {
163 *ah += sh;
164 }
165 }
166 }
167 for (am, sm) in agg
168 .cluster_stats
169 .top_cluster_sizes
170 .iter_mut()
171 .zip(r.cluster_stats.top_cluster_sizes.iter())
172 {
173 for (a, &s) in am.iter_mut().zip(sm.iter()) {
174 for k in 0..4 {
175 a[k] += s[k];
176 }
177 }
178 }
179 for (a, &v) in agg
180 .diagnostics
181 .mags2_tau
182 .iter_mut()
183 .zip(r.diagnostics.mags2_tau.iter())
184 {
185 *a += v;
186 }
187 for (a, &v) in agg
188 .diagnostics
189 .overlap2_tau
190 .iter_mut()
191 .zip(r.diagnostics.overlap2_tau.iter())
192 {
193 *a += v;
194 }
195 for (ac, rc) in agg
196 .diagnostics
197 .equil_checkpoints
198 .iter_mut()
199 .zip(r.diagnostics.equil_checkpoints.iter())
200 {
201 for (a, &v) in ac.energy_avg.iter_mut().zip(rc.energy_avg.iter()) {
202 *a += v;
203 }
204 for (a, &v) in ac
205 .link_overlap_avg
206 .iter_mut()
207 .zip(rc.link_overlap_avg.iter())
208 {
209 *a += v;
210 }
211 }
212 }
213
214 for v in agg
215 .mags
216 .iter_mut()
217 .chain(agg.mags2.iter_mut())
218 .chain(agg.mags4.iter_mut())
219 .chain(agg.energies.iter_mut())
220 .chain(agg.energies2.iter_mut())
221 {
222 *v /= n;
223 }
224
225 for mode_tops in agg.cluster_stats.top_cluster_sizes.iter_mut() {
226 for arr in mode_tops.iter_mut() {
227 for v in arr.iter_mut() {
228 *v /= n;
229 }
230 }
231 }
232
233 for v in agg.diagnostics.mags2_tau.iter_mut() {
234 *v /= n;
235 }
236 for v in agg.diagnostics.overlap2_tau.iter_mut() {
237 *v /= n;
238 }
239 for ckpt in agg.diagnostics.equil_checkpoints.iter_mut() {
240 for v in ckpt.energy_avg.iter_mut() {
241 *v /= n;
242 }
243 for v in ckpt.link_overlap_avg.iter_mut() {
244 *v /= n;
245 }
246 }
247
248 agg
249 }
250}