OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
SpectrumTestSupport.h
Go to the documentation of this file.
1
6#ifndef OPALX_UNIT_TESTS_PHYSICS_SPECTRUM_TEST_SUPPORT_H
7#define OPALX_UNIT_TESTS_PHYSICS_SPECTRUM_TEST_SUPPORT_H
8
9#include <cmath>
10#include <cstddef>
11#include <fstream>
12#include <stdexcept>
13#include <string>
14#include <vector>
15
16namespace opalx::test {
17
18 struct Histogram1D {
19 double low = 0.0;
20 double high = 0.0;
21 std::size_t nBins = 0;
22 std::vector<double> counts;
23 std::vector<double> density;
24
25 double binWidth() const { return (high - low) / static_cast<double>(nBins); }
26
27 double center(std::size_t i) const {
28 return low + (static_cast<double>(i) + 0.5) * binWidth();
29 }
30
31 double edgeLow(std::size_t i) const { return low + static_cast<double>(i) * binWidth(); }
32
33 double edgeHigh(std::size_t i) const {
34 return low + static_cast<double>(i + 1) * binWidth();
35 }
36 };
37
39 const std::vector<double>& samples, double low, double high, std::size_t nBins) {
40 if (nBins == 0 || !(high > low)) {
41 throw std::invalid_argument("makeHistogram: invalid range or nBins");
42 }
44 h.low = low;
45 h.high = high;
46 h.nBins = nBins;
47 h.counts.assign(nBins, 0.0);
48 h.density.assign(nBins, 0.0);
49
50 const double width = h.binWidth();
51 double totalIn = 0.0;
52 for (double s : samples) {
53 if (s < low || s >= high) {
54 continue;
55 }
56 const std::size_t idx = static_cast<std::size_t>((s - low) / width);
57 if (idx < nBins) {
58 h.counts[idx] += 1.0;
59 totalIn += 1.0;
60 }
61 }
62 if (totalIn > 0.0) {
63 for (std::size_t i = 0; i < nBins; ++i) {
64 h.density[i] = h.counts[i] / (totalIn * width);
65 }
66 }
67 return h;
68 }
69
72 inline double l1Distance(const Histogram1D& sampled, const std::vector<double>& analyticPdf) {
73 if (sampled.density.size() != analyticPdf.size()) {
74 throw std::invalid_argument("l1Distance: size mismatch");
75 }
76 const double width = sampled.binWidth();
77 double sum = 0.0;
78 for (std::size_t i = 0; i < sampled.density.size(); ++i) {
79 sum += std::abs(sampled.density[i] - analyticPdf[i]) * width;
80 }
81 return sum;
82 }
83
85 inline double histogramArea(const Histogram1D& h) {
86 const double width = h.binWidth();
87 double sum = 0.0;
88 for (double d : h.density) {
89 sum += d * width;
90 }
91 return sum;
92 }
93
94 inline double sampleMean(const std::vector<double>& samples) {
95 if (samples.empty()) {
96 return 0.0;
97 }
98 double s = 0.0;
99 for (double x : samples) {
100 s += x;
101 }
102 return s / static_cast<double>(samples.size());
103 }
104
108 inline void writeSpectrumCsv(
109 const std::string& path, const Histogram1D& h, const std::vector<double>& analyticPdf,
110 const std::string& xLabel) {
111 if (analyticPdf.size() != h.nBins) {
112 throw std::invalid_argument("writeSpectrumCsv: analyticPdf size mismatch");
113 }
114 std::ofstream out(path);
115 if (!out) {
116 throw std::runtime_error("writeSpectrumCsv: cannot open " + path);
117 }
118 out.precision(17);
119 out << "# x_label: " << xLabel << "\n";
120 out << "# columns: bin_low,bin_high,bin_center,density,count,analytic_pdf\n";
121 for (std::size_t i = 0; i < h.nBins; ++i) {
122 out << h.edgeLow(i) << ',' << h.edgeHigh(i) << ',' << h.center(i) << ',' << h.density[i]
123 << ',' << h.counts[i] << ',' << analyticPdf[i] << '\n';
124 }
125 }
126
127} // namespace opalx::test
128
129#endif // OPALX_UNIT_TESTS_PHYSICS_SPECTRUM_TEST_SUPPORT_H
void writeSpectrumCsv(const std::string &path, const Histogram1D &h, const std::vector< double > &analyticPdf, const std::string &xLabel)
Histogram1D makeHistogram(const std::vector< double > &samples, double low, double high, std::size_t nBins)
double histogramArea(const Histogram1D &h)
Riemann sum of the histogram density (should be ~1 if all samples were in range).
double l1Distance(const Histogram1D &sampled, const std::vector< double > &analyticPdf)
double sampleMean(const std::vector< double > &samples)
double center(std::size_t i) const
double edgeHigh(std::size_t i) const
std::vector< double > counts
raw sample counts per bin (out-of-range excluded)
std::vector< double > density
counts / total / binWidth (PDF estimate)
double edgeLow(std::size_t i) const