Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #include <H5Cpp.h> | ||
4 | #include <iostream> | ||
5 | #include <stdexcept> | ||
6 | #include <string> | ||
7 | #include <unordered_map> | ||
8 | #include <vector> | ||
9 | #include <yaml-cpp/yaml.h> | ||
10 | |||
11 | #include "multiindex.hpp" | ||
12 | #include "particle.hpp" | ||
13 | #include "analyzers.hpp" | ||
14 | #include "rng.hpp" | ||
15 | #include "system.hpp" | ||
16 | #include "types.hpp" | ||
17 | |||
18 | template <int d> class Histogram; | ||
19 | |||
20 | class Observables { | ||
21 | protected: | ||
22 | virtual void doSample(double weight) = 0; | ||
23 | |||
24 | public: | ||
25 | System *system; | ||
26 | int numSpeciesIndices; | ||
27 | int numSpecies; | ||
28 | std::vector<std::string> keys; | ||
29 | double totalWeight; | ||
30 | double tLast; | ||
31 | double every; | ||
32 | |||
33 | Observables(System *system, int numSpeciesIndices, const YAML::Node &config); | ||
34 | ✗ | virtual ~Observables() = default; | |
35 | |||
36 | virtual std::string type() = 0; | ||
37 | virtual std::vector<std::string> axisLabels() = 0; | ||
38 | virtual std::vector<int> shape() = 0; | ||
39 | virtual std::vector<double> coordinates(int axis) = 0; | ||
40 | virtual std::vector<double> &data(const std::string &key, | ||
41 | Eigen::Array<int, Eigen::Dynamic, 1> species) = 0; | ||
42 | |||
43 | ✗ | virtual std::vector<std::string> analyzers() { return {}; }; | |
44 | void sample(double weight); | ||
45 | }; | ||
46 | |||
47 | template <int d, int speciesIndices> class Fields : public Observables { | ||
48 | protected: | ||
49 | 6 | void customExtent(const YAML::Node &config, const std::string &key, int axis) { | |
50 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
6 | if (config[key]) { |
51 | ✗ | double eNew = YAML::parse<double>(config, key); | |
52 | ✗ | if (eNew < extent[axis]) { | |
53 | ✗ | extent[axis] = eNew; | |
54 | ✗ | dr = extent / bins.template cast<double>(); | |
55 | } else { | ||
56 | std::clog | ||
57 | << "WARNING: You have set the custom extent " << key << " to " << std::to_string(eNew) | ||
58 | ✗ | << " in Observable " << this->type() | |
59 | ✗ | << ", which is above the maximum allowed value. This custom setting will be ignored"; | |
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | virtual double dV(const Eigen::Array<int, d, 1> &index) = 0; | ||
65 | |||
66 | public: | ||
67 | Eigen::Array<int, d, 1> bins; | ||
68 | Eigen::Array<double, d, 1> extent; | ||
69 | Eigen::Array<double, d, 1> dr; | ||
70 | Multiindex<speciesIndices> speciesMultiindex; | ||
71 | std::unordered_map<std::string, std::vector<Histogram<d>>> histograms; | ||
72 | |||
73 | 18 | Fields(System *system, const Eigen::Array<int, d, 1> &bins, | |
74 | const Eigen::Array<double, d, 1> &extent, const YAML::Node &config) | ||
75 | 18 | : Observables(system, speciesIndices, config), bins(bins), extent(extent), | |
76 | 18 | dr(extent / bins.template cast<double>()), | |
77 |
2/3✓ Branch 5 taken 3 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
18 | speciesMultiindex(Eigen::Array<int, speciesIndices, 1>::Constant(numSpecies)) { |
78 |
7/12✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 18 times.
✓ Branch 15 taken 9 times.
✓ Branch 16 taken 9 times.
✗ Branch 17 not taken.
|
126 | for (auto &k : config["keys"]) { |
79 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | std::string key = k.as<std::string>(); |
80 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | this->keys.push_back(key); |
81 |
3/6✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
|
72 | this->histograms[key] = std::vector<Histogram<d>>(speciesMultiindex.linsize, Histogram<d>(bins)); |
82 | } | ||
83 | } | ||
84 | |||
85 | 18 | virtual ~Fields() = default; | |
86 | |||
87 | 24 | std::vector<int> shape() { | |
88 | 24 | std::vector<int> shape; | |
89 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 11 times.
|
78 | for (int axis = 0; axis < d; axis++) { |
90 |
1/2✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
|
54 | shape.push_back(bins[axis]); |
91 | } | ||
92 | 24 | return shape; | |
93 | } | ||
94 | |||
95 | 8 | std::vector<double> coordinates(int axis) { | |
96 | 8 | std::vector<double> coords; | |
97 | 8 | Eigen::Array<int, d, 1> index = Eigen::Array<int, d, 1>::Zero(); | |
98 | 8 | Eigen::Array<double, d, 1> real; | |
99 |
2/2✓ Branch 3 taken 52 times.
✓ Branch 4 taken 4 times.
|
112 | for (; index[axis] < bins[axis]; ++index[axis]) { |
100 | 104 | real = index2real(index); | |
101 |
1/2✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
|
104 | coords.push_back(real[axis]); |
102 | } | ||
103 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
8 | coords.push_back(extent[axis]); |
104 | 8 | return coords; | |
105 | } | ||
106 | |||
107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | std::vector<double> &data( |
108 | const std::string &key, | ||
109 | Eigen::Array<int, Eigen::Dynamic, 1> species = Eigen::Array<int, speciesIndices, 1>::Zero()) { | ||
110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | if (species.size() != speciesIndices) { |
111 | ✗ | throw std::invalid_argument("Wrong number of species given in data()"); | |
112 | } | ||
113 | 6 | Histogram<d> &histogram = histograms.at(key).at(speciesMultiindex.multi2lin(species)); | |
114 |
2/2✓ Branch 0 taken 746 times.
✓ Branch 1 taken 3 times.
|
1498 | for (int i = 0; i < histogram.multiindex.linsize; ++i) { |
115 | 1494 | double normFactor = dV(histogram.multiindex.lin2multi(i)) * totalWeight; | |
116 | 1492 | histogram.valuesNormed[i] = histogram.values[i] / normFactor; | |
117 | } | ||
118 | 6 | return histogram.valuesNormed; | |
119 | } | ||
120 | |||
121 | 11 | Eigen::Array<int, d, 1> real2index(const Eigen::Array<double, d, 1> &real) { | |
122 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
11 | return (real / dr).template cast<int>(); |
123 | } | ||
124 | |||
125 | 78 | Eigen::Array<double, d, 1> index2real(const Eigen::Array<int, d, 1> &index) { | |
126 | 78 | return index.template cast<double>() * dr; | |
127 | } | ||
128 | }; | ||
129 | |||
130 | class Scalar : public Fields<0, 0> { | ||
131 | public: | ||
132 | inline static std::unordered_map<std::string, double (*)(System *s)> functions = { | ||
133 | {"N", [](System *s) -> double { return s->particles.size(); }}, | ||
134 | {"E", [](System *s) -> double { return s->E; }}, | ||
135 | {"clusterSizeMax", | ||
136 | ✗ | [](System *s) -> double { | |
137 | ✗ | PercolationAnalyzer *percolation = | |
138 | ✗ | static_cast<PercolationAnalyzer *>(s->analyzers["percolation"]); | |
139 | ✗ | return percolation->clusterSizeMax; | |
140 | }}, | ||
141 | }; | ||
142 | |||
143 | double dV(const Eigen::Array<int, 0, 1> &index); | ||
144 | void doSample(double weight); | ||
145 | |||
146 | Scalar(System *system, const YAML::Node &config); | ||
147 | |||
148 | ✗ | std::string type() { return "scalar"; } | |
149 | ✗ | std::vector<std::string> axisLabels() { return {}; } | |
150 | std::vector<std::string> analyzers(); | ||
151 | }; | ||
152 | |||
153 | class Onebody : public Fields<DIM, 1> { | ||
154 | double dV_; | ||
155 | double dV(const Eigen::Array<int, DIM, 1> &index); | ||
156 | void doSample(double weight); | ||
157 | |||
158 | public: | ||
159 | inline static std::unordered_map<std::string, double (*)(System *s, const Particle &p)> | ||
160 | functions = { | ||
161 | {"1", [](System *s, const Particle &p) -> double { return 1.; }}, | ||
162 | {"Eext", [](System *s, const Particle &p) -> double { return p.Eext; }}, | ||
163 | {"Fextx", [](System *s, const Particle &p) -> double { return p.Fext[0]; }}, | ||
164 | {"Fexty", [](System *s, const Particle &p) -> double { return p.Fext[1]; }}, | ||
165 | {"Fextz", [](System *s, const Particle &p) -> double { return p.Fext[2]; }}, | ||
166 | {"Fintx", [](System *s, const Particle &p) -> double { return p.Fint[0]; }}, | ||
167 | {"Finty", [](System *s, const Particle &p) -> double { return p.Fint[1]; }}, | ||
168 | {"Fintz", [](System *s, const Particle &p) -> double { return p.Fint[2]; }}, | ||
169 | {"rRandx", [](System *s, const Particle &p) -> double { return p.rRand[0]; }}, | ||
170 | {"rRandy", [](System *s, const Particle &p) -> double { return p.rRand[1]; }}, | ||
171 | {"rRandz", [](System *s, const Particle &p) -> double { return p.rRand[2]; }}, | ||
172 | {"N", [](System *s, const Particle &p) -> double { return s->particles.size(); }}, | ||
173 | {"H", [](System *s, const Particle &p) -> double { return s->E; }}, | ||
174 | {"clusterSizeMax", | ||
175 | ✗ | [](System *s, const Particle &p) -> double { | |
176 | ✗ | PercolationAnalyzer *percolation = static_cast<PercolationAnalyzer *>(s->analyzers["percolation"]); | |
177 | ✗ | return percolation->clusterSizeMax; | |
178 | } | ||
179 | }, | ||
180 | }; | ||
181 | |||
182 | Onebody(System *system, const YAML::Node &config); | ||
183 | |||
184 | ✗ | std::string type() { return "onebody"; } | |
185 | ✗ | std::vector<std::string> axisLabels() { return {"x", "y", "z"}; } | |
186 | std::vector<std::string> analyzers(); | ||
187 | }; | ||
188 | |||
189 | ✗ | static Vec deltaF_deltar(System *s, Particle &p, const Vec &e_r, const double deltar = 1e-5) { | |
190 | // Save current state | ||
191 | ✗ | Vec r_before = p.r; | |
192 | ✗ | Vec F_before = p.Fint; | |
193 | // Shift particle for finite difference | ||
194 | ✗ | p.r += deltar * e_r; | |
195 | ✗ | s->applyPeriodic(p); | |
196 | ✗ | s->updateParticleState(p); | |
197 | ✗ | Vec F_after = p.Fint; | |
198 | // Restore initial state | ||
199 | ✗ | p.r = r_before; | |
200 | ✗ | s->updateParticleMeta(p); | |
201 | ✗ | p.Fint = F_before; | |
202 | ✗ | return (F_after - F_before) / deltar; | |
203 | } | ||
204 | |||
205 | ✗ | static Vec deltaF1_deltar0(System *s, Particle &p0, Particle &p1, const Vec &e_r0, | |
206 | double deltar0 = 1e-5) { | ||
207 | // Save current state | ||
208 | ✗ | Vec r0_before = p0.r; | |
209 | ✗ | Vec F1_before = p1.Fint; | |
210 | // Shift particle 0 for finite difference | ||
211 | ✗ | deltar0 *= rand() % 2 ? 1 : -1; | |
212 | ✗ | p0.r += deltar0 * e_r0; | |
213 | ✗ | s->applyPeriodic(p0); | |
214 | ✗ | s->updateParticleMeta(p0); | |
215 | ✗ | s->updateParticleState(p1); | |
216 | ✗ | Vec F1_after = p1.Fint; | |
217 | // Restore initial state | ||
218 | ✗ | p0.r = r0_before; | |
219 | ✗ | s->updateParticleMeta(p0); | |
220 | ✗ | p1.Fint = F1_before; | |
221 | ✗ | return (F1_after - F1_before) / deltar0; | |
222 | } | ||
223 | |||
224 | ✗ | static Vec deltaF1_deltar0_fullUpdate(System *s, Particle &p0, Particle &p1, const Vec &e_r0, | |
225 | const double deltar0 = 1e-5) { | ||
226 | // Save current state | ||
227 | ✗ | static std::vector<Particle> particlesBefore = s->particles; | |
228 | ✗ | Vec F1_before = p1.Fint; | |
229 | // Shift particle 0 for finite difference | ||
230 | ✗ | p0.r += deltar0 * e_r0; | |
231 | ✗ | s->applyPeriodic(p0); | |
232 | ✗ | s->updateState(); | |
233 | ✗ | Vec F1_after = p1.Fint; | |
234 | // Restore initial state | ||
235 | ✗ | s->particles = particlesBefore; | |
236 | ✗ | s->updateParticleMeta(p0); | |
237 | ✗ | return (F1_after - F1_before) / deltar0; | |
238 | } | ||
239 | |||
240 | ✗ | inline static Vec e_tan_safe(const Vec &e_r, const Vec &F1, const Vec &F2 = Vec::Zero(), | |
241 | const double tol = 1e-4) { | ||
242 | ✗ | Vec e_tan = (F1 - F1.dot(e_r) * e_r).normalized(); | |
243 | ✗ | if (std::abs(e_tan.norm() - 1.) > tol || std::abs(e_tan.dot(e_r)) > tol) { | |
244 | ✗ | e_tan = (F2 - F2.dot(e_r) * e_r).normalized(); | |
245 | ✗ | if (std::abs(e_tan.norm() - 1.) > tol || std::abs(e_tan.dot(e_r)) > tol) { | |
246 | ✗ | if constexpr (DIM == 3) { | |
247 | ✗ | e_tan = e_r.cross(Vec{1, 0, 0}).normalized(); | |
248 | } | ||
249 | } | ||
250 | } | ||
251 | ✗ | return e_tan; | |
252 | } | ||
253 | |||
254 | ✗ | inline static Vec e_tan_random(const Vec &e_r, const double tol = 1e-4) { | |
255 | ✗ | static RNG rng{}; | |
256 | Vec e_tan; | ||
257 | ✗ | do { | |
258 | ✗ | Vec randVec = rng.vecNormal().normalized(); | |
259 | ✗ | e_tan = (randVec - randVec.dot(e_r) * e_r).normalized(); | |
260 | ✗ | } while (std::abs(e_tan.norm() - 1.) > tol || std::abs(e_tan.dot(e_r)) > tol); | |
261 | ✗ | return e_tan; | |
262 | } | ||
263 | |||
264 | class Radial : public Fields<1, 2> { | ||
265 | double dV(const Eigen::Array<int, 1, 1> &index); | ||
266 | void doSample(double weight); | ||
267 | |||
268 | public: | ||
269 | inline static std::unordered_map<std::string, double (*)(System *s, Particle &p0, Particle &p1, | ||
270 | const Vec &e_r)> | ||
271 | functions = { | ||
272 | {"1", [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { return 1.; }}, | ||
273 | {"F0_rad", | ||
274 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
275 | ✗ | return p0.F().dot(e_r); | |
276 | }}, | ||
277 | {"F1_rad", | ||
278 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
279 | ✗ | return p1.F().dot(e_r); | |
280 | }}, | ||
281 | {"F0_rad_F1_rad", | ||
282 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
283 | ✗ | return p0.F().dot(e_r) * p1.F().dot(e_r); | |
284 | }}, | ||
285 | {"F0_tan_dot_F1_tan", | ||
286 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
287 | ✗ | Vec F0 = p0.F(); | |
288 | ✗ | Vec F1 = p1.F(); | |
289 | ✗ | Vec F0tan = F0 - F0.dot(e_r) * e_r; | |
290 | ✗ | Vec F1tan = F1 - F1.dot(e_r) * e_r; | |
291 | ✗ | return F0tan.dot(F1tan); | |
292 | }}, | ||
293 | {"(F0_tan_cross_F1_tan)_rad", | ||
294 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
295 | ✗ | if constexpr (DIM == 3) { | |
296 | ✗ | Vec F0 = p0.F(); | |
297 | ✗ | Vec F1 = p1.F(); | |
298 | ✗ | Vec F0tan = F0 - F0.dot(e_r) * e_r; | |
299 | ✗ | Vec F1tan = F1 - F1.dot(e_r) * e_r; | |
300 | ✗ | return F0tan.cross(F1tan).dot(e_r); | |
301 | } else { | ||
302 | return 0.; | ||
303 | } | ||
304 | }}, | ||
305 | {"F0_dot_F1", | ||
306 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
307 | ✗ | return p0.F().dot(p1.F()); | |
308 | }}, | ||
309 | {"grad0(F0)_rad", | ||
310 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
311 | ✗ | return deltaF_deltar(s, p0, e_r).dot(e_r); | |
312 | }}, | ||
313 | {"grad0(F0)_tan", | ||
314 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
315 | ✗ | Vec e_tan = e_tan_safe(e_r, p0.F()); | |
316 | ✗ | return deltaF_deltar(s, p0, e_tan).dot(e_tan); | |
317 | }}, | ||
318 | {"grad0(F1)_rad", | ||
319 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
320 | ✗ | return deltaF1_deltar0(s, p0, p1, e_r).dot(e_r); | |
321 | }}, | ||
322 | {"grad0(F1)_tan", | ||
323 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
324 | ✗ | Vec e_tan = e_tan_safe(e_r, p0.F(), p1.F()); | |
325 | ✗ | return deltaF1_deltar0(s, p0, p1, e_tan).dot(e_tan); | |
326 | }}, | ||
327 | {"grad0(F1)_tan_u", | ||
328 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
329 | ✗ | Vec e_tan = e_tan_safe(e_r, p0.u, p1.u); | |
330 | ✗ | return deltaF1_deltar0(s, p0, p1, e_tan).dot(e_tan); | |
331 | }}, | ||
332 | {"grad0(F1)_tan_random", | ||
333 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
334 | ✗ | Vec e_tan = e_tan_random(e_r); | |
335 | ✗ | return deltaF1_deltar0(s, p0, p1, e_tan).dot(e_tan); | |
336 | }}, | ||
337 | {"grad0(F1)_rad_fullUpdate", | ||
338 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
339 | ✗ | return deltaF1_deltar0_fullUpdate(s, p0, p1, e_r).dot(e_r); | |
340 | }}, | ||
341 | {"grad0(F1)_tan_fullUpdate", | ||
342 | ✗ | [](System *s, Particle &p0, Particle &p1, const Vec &e_r) -> double { | |
343 | ✗ | Vec e_tan = e_tan_safe(e_r, p0.F(), p1.F()); | |
344 | ✗ | return deltaF1_deltar0_fullUpdate(s, p0, p1, e_tan).dot(e_tan); | |
345 | }}, | ||
346 | }; | ||
347 | |||
348 | Radial(System *system, const YAML::Node &config); | ||
349 | |||
350 | ✗ | std::string type() { return "radial"; } | |
351 | ✗ | std::vector<std::string> axisLabels() { return {"r"}; } | |
352 | }; | ||
353 | |||
354 | class TwobodyPlanar : public Fields<3, 2> { | ||
355 | double dV(const Eigen::Array<int, 3, 1> &index); | ||
356 | void doSample(double weight); | ||
357 | |||
358 | public: | ||
359 | inline static std::unordered_map<std::string, | ||
360 | double (*)(System *s, const Particle &p0, const Particle &p1)> | ||
361 | functions = { | ||
362 | {"1", [](System *s, const Particle &p0, const Particle &p1) -> double { return 1.; }}, | ||
363 | }; | ||
364 | |||
365 | TwobodyPlanar(System *system, const YAML::Node &config); | ||
366 | |||
367 | ✗ | std::string type() { return "twobodyplanar"; } | |
368 | ✗ | std::vector<std::string> axisLabels() { return {"z_1", "z_2", "r^*"}; } | |
369 | }; | ||
370 | |||
371 | class Clusters : public Observables { | ||
372 | void doSample(double weight); | ||
373 | |||
374 | public: | ||
375 | inline static std::unordered_map<std::string, | ||
376 | double (*)(PercolationAnalyzer *percolation, int i, int n)> | ||
377 | functions = { | ||
378 | {"clusters", | ||
379 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
380 | return (double)percolation->clusterSizeCount[i] / n; | ||
381 | }}, | ||
382 | {"coordinations", | ||
383 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
384 | return (double)percolation->coordinationCount[i] / n; | ||
385 | }}, | ||
386 | {"P0", | ||
387 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
388 | return percolation->coordinationCount[0] == i ? 1. : 0.; | ||
389 | }}, | ||
390 | {"P1", | ||
391 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
392 | return percolation->coordinationCount[1] == i ? 1. : 0.; | ||
393 | }}, | ||
394 | {"P2", | ||
395 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
396 | return percolation->coordinationCount[2] == i ? 1. : 0.; | ||
397 | }}, | ||
398 | {"P3", | ||
399 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
400 | return percolation->coordinationCount[3] == i ? 1. : 0.; | ||
401 | }}, | ||
402 | {"P4", | ||
403 | [](PercolationAnalyzer *percolation, int i, int n) -> double { | ||
404 | return percolation->coordinationCount[4] == i ? 1. : 0.; | ||
405 | }}, | ||
406 | }; | ||
407 | |||
408 | int nMax; | ||
409 | std::unordered_map<std::string, std::vector<double>> distributions; | ||
410 | std::unordered_map<std::string, std::vector<double>> distributionsNormed; | ||
411 | |||
412 | Clusters(System *system, const YAML::Node &config); | ||
413 | |||
414 | ✗ | std::string type() { return "clusters"; } | |
415 | ✗ | std::vector<std::string> axisLabels() { return {"n"}; } | |
416 | ✗ | std::vector<std::string> analyzers() { return {"percolation"}; }; | |
417 | std::vector<int> shape(); | ||
418 | std::vector<double> coordinates(int axis); | ||
419 | std::vector<double> &data(const std::string &key = "clusters", | ||
420 | Eigen::Array<int, Eigen::Dynamic, 1> species = {}); | ||
421 | }; | ||
422 | |||
423 | class ObservablesFactory { | ||
424 | public: | ||
425 | static Observables *create(System *system, const std::string &category, const YAML::Node &config); | ||
426 | }; | ||
427 |