mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2025-12-29 00:11:25 +01:00
147 lines
5.7 KiB
C++
147 lines
5.7 KiB
C++
// SPDX-License-Identifier: MPL-2.0
|
|
#include "aare/Interpolator.hpp"
|
|
|
|
namespace aare {
|
|
|
|
Interpolator::Interpolator(NDView<double, 1> xbins, NDView<double, 1> ybins,
|
|
NDView<double, 1> ebins)
|
|
: m_etabinsx(xbins), m_etabinsy(ybins), m_energy_bins(ebins){};
|
|
|
|
Interpolator::Interpolator(NDView<double, 3> etacube, NDView<double, 1> xbins,
|
|
NDView<double, 1> ybins, NDView<double, 1> ebins)
|
|
: m_etabinsx(xbins), m_etabinsy(ybins), m_energy_bins(ebins) {
|
|
if (etacube.shape(0) + 1 != xbins.size() ||
|
|
etacube.shape(1) + 1 != ybins.size() ||
|
|
etacube.shape(2) + 1 != ebins.size()) {
|
|
throw std::invalid_argument(
|
|
"The shape of the etacube does not match the shape of the bins");
|
|
}
|
|
|
|
m_ietax = NDArray<double, 3>(etacube);
|
|
|
|
m_ietay = NDArray<double, 3>(etacube);
|
|
|
|
// prefix sum - conditional CDF
|
|
for (ssize_t i = 0; i < m_ietax.shape(0); i++) {
|
|
for (ssize_t j = 0; j < m_ietax.shape(1); j++) {
|
|
for (ssize_t k = 0; k < m_ietax.shape(2); k++) {
|
|
m_ietax(i, j, k) += (i == 0) ? 0 : m_ietax(i - 1, j, k);
|
|
|
|
m_ietay(i, j, k) += (j == 0) ? 0 : m_ietay(i, j - 1, k);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Standardize, if norm less than 1 don't do anything
|
|
for (ssize_t i = 0; i < m_ietax.shape(0); i++) {
|
|
for (ssize_t j = 0; j < m_ietax.shape(1); j++) {
|
|
for (ssize_t k = 0; k < m_ietax.shape(2); k++) {
|
|
auto shift_x = etacube(0, j, k);
|
|
auto val_etax = m_ietax(m_ietax.shape(0) - 1, j, k) - shift_x;
|
|
double norm_etax = val_etax == 0 ? 1 : val_etax;
|
|
m_ietax(i, j, k) -= shift_x;
|
|
m_ietax(i, j, k) /= norm_etax;
|
|
auto shift_y = etacube(i, 0, k);
|
|
auto val_etay = m_ietay(i, m_ietay.shape(1) - 1, k) - shift_y;
|
|
double norm_etay = val_etay == 0 ? 1 : val_etay;
|
|
m_ietay(i, j, k) -= shift_y;
|
|
|
|
m_ietay(i, j, k) /= norm_etay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Interpolator::rosenblatttransform(NDView<double, 3> etacube) {
|
|
|
|
if (etacube.shape(0) + 1 != m_etabinsx.size() ||
|
|
etacube.shape(1) + 1 != m_etabinsy.size() ||
|
|
etacube.shape(2) + 1 != m_energy_bins.size()) {
|
|
throw std::invalid_argument(
|
|
"The shape of the etacube does not match the shape of the bins");
|
|
}
|
|
|
|
// TODO: less loops and better performance if ebins is first dimension
|
|
// (violates backwardscompatibility ieta_x and ieta_y public getters,
|
|
// previously generated etacubes)
|
|
// TODO: maybe more loops is better then storing total_sum_y and
|
|
// total_sum_x
|
|
|
|
// marginal CDF for eta_x
|
|
NDArray<double, 2> marg_CDF_EtaX(
|
|
std::array<ssize_t, 2>{m_etabinsx.size() - 1, m_energy_bins.size() - 1},
|
|
0.0); // simulate proper probability distribution with zero at start
|
|
|
|
// conditional CDF for eta_y
|
|
NDArray<double, 3> cond_CDF_EtaY(etacube);
|
|
|
|
for (ssize_t i = 0; i < cond_CDF_EtaY.shape(0); ++i) {
|
|
for (ssize_t j = 0; j < cond_CDF_EtaY.shape(1); ++j) {
|
|
for (ssize_t k = 0; k < cond_CDF_EtaY.shape(2); ++k) {
|
|
// cumsum along y-axis
|
|
marg_CDF_EtaX(i, k) +=
|
|
etacube(i, j,
|
|
k); // marginal probability for etaX
|
|
|
|
// cumsum along y-axis
|
|
cond_CDF_EtaY(i, j, k) +=
|
|
(j == 0) ? 0 : cond_CDF_EtaY(i, j - 1, k);
|
|
}
|
|
}
|
|
}
|
|
|
|
// cumsum along x-axis
|
|
for (ssize_t i = 1; i < marg_CDF_EtaX.shape(0); ++i) {
|
|
for (ssize_t k = 0; k < marg_CDF_EtaX.shape(1); ++k) {
|
|
marg_CDF_EtaX(0, k) =
|
|
0.0; // shift by first value to ensure values between 0 and 1
|
|
|
|
marg_CDF_EtaX(i, k) += marg_CDF_EtaX(i - 1, k);
|
|
}
|
|
}
|
|
|
|
// normalize marg_CDF_EtaX
|
|
for (ssize_t i = 1; i < marg_CDF_EtaX.shape(0); ++i) {
|
|
for (ssize_t k = 0; k < marg_CDF_EtaX.shape(1); ++k) {
|
|
double norm = marg_CDF_EtaX(marg_CDF_EtaX.shape(0) - 1, k) == 0
|
|
? 1
|
|
: marg_CDF_EtaX(marg_CDF_EtaX.shape(0) - 1, k);
|
|
marg_CDF_EtaX(i, k) /= norm;
|
|
}
|
|
}
|
|
|
|
// standardize, normalize conditional CDF for etaY
|
|
// Note P(EtaY|EtaX) = P(EtaY,EtaX)/P(EtaX) we dont divide by P(EtaX) as it
|
|
// cancels out during normalization
|
|
for (ssize_t i = 0; i < cond_CDF_EtaY.shape(0); ++i) {
|
|
for (ssize_t j = 0; j < cond_CDF_EtaY.shape(1); ++j) {
|
|
for (ssize_t k = 0; k < cond_CDF_EtaY.shape(2); ++k) {
|
|
double shift = etacube(i, 0, k);
|
|
double norm =
|
|
(cond_CDF_EtaY(i, cond_CDF_EtaY.shape(1) - 1, k) - shift) ==
|
|
0
|
|
? 1
|
|
: cond_CDF_EtaY(i, cond_CDF_EtaY.shape(1) - 1, k) -
|
|
shift;
|
|
cond_CDF_EtaY(i, j, k) -= shift;
|
|
cond_CDF_EtaY(i, j, k) /= norm;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_ietay = std::move(
|
|
cond_CDF_EtaY); // TODO maybe rename m_ietay to lookup or CDF_EtaY_cond
|
|
|
|
// TODO: should actually be only 2dimensional keep three dimension due to
|
|
// consistency with Annas code change though
|
|
m_ietax = NDArray<double, 3>(
|
|
std::array<ssize_t, 3>{m_etabinsx.size() - 1, m_etabinsy.size() - 1,
|
|
m_energy_bins.size() - 1});
|
|
|
|
for (ssize_t i = 0; i < m_etabinsx.size() - 1; ++i)
|
|
for (ssize_t j = 0; j < m_etabinsy.size() - 1; ++j)
|
|
for (ssize_t k = 0; k < m_energy_bins.size() - 1; ++k)
|
|
m_ietax(i, j, k) = marg_CDF_EtaX(i, k);
|
|
}
|
|
|
|
} // namespace aare
|