Files
aare/src/Interpolator.cpp

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