6#ifndef OPALX_UNIT_TESTS_PHYSICS_SPECTRUM_TEST_SUPPORT_H
7#define OPALX_UNIT_TESTS_PHYSICS_SPECTRUM_TEST_SUPPORT_H
28 return low + (
static_cast<double>(i) + 0.5) *
binWidth();
34 return low +
static_cast<double>(i + 1) *
binWidth();
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");
47 h.
counts.assign(nBins, 0.0);
52 for (
double s : samples) {
53 if (s < low || s >= high) {
56 const std::size_t idx =
static_cast<std::size_t
>((s - low) / width);
63 for (std::size_t i = 0; i < nBins; ++i) {
73 if (sampled.
density.size() != analyticPdf.size()) {
74 throw std::invalid_argument(
"l1Distance: size mismatch");
76 const double width = sampled.
binWidth();
78 for (std::size_t i = 0; i < sampled.
density.size(); ++i) {
79 sum += std::abs(sampled.
density[i] - analyticPdf[i]) * width;
94 inline double sampleMean(
const std::vector<double>& samples) {
95 if (samples.empty()) {
99 for (
double x : samples) {
102 return s /
static_cast<double>(samples.size());
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");
114 std::ofstream out(path);
116 throw std::runtime_error(
"writeSpectrumCsv: cannot open " + path);
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) {
123 <<
',' << h.
counts[i] <<
',' << analyticPdf[i] <<
'\n';
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