diff --git a/Framework/Utilities/SaveBoostHistogram.hpp b/Framework/Utilities/SaveBoostHistogram.hpp index ea02dcaba8ef02530554de90c041b6898da98479..8418457f0ab8c9fe86412a77352cca278e919f35 100644 --- a/Framework/Utilities/SaveBoostHistogram.hpp +++ b/Framework/Utilities/SaveBoostHistogram.hpp @@ -23,30 +23,34 @@ namespace corsika { void save_hist(boost::histogram::histogram<Axes, Storage> const& h, std::string const& filename) { int const rank = h.rank(); - int const size = h.size(); - using value_type = typename boost::histogram::histogram<Axes, Storage>::value_type; std::vector<size_t> axes_dims; axes_dims.reserve(rank); + auto overflow = std::make_unique<bool[]>(rank); + auto underflow = std::make_unique<bool[]>(rank); + std::vector<char> axis_types; axis_types.reserve(rank); for (int i = 0; i < rank; ++i) { auto const& ax = h.axis(i); - int const has_underflow = (ax.options() & 0x01) ? 1 : 0; - int const has_overflow = (ax.options() & 0x02) ? 1 : 0; + unsigned const has_underflow = (ax.options() & 0x01) ? 1 : 0; + unsigned const has_overflow = (ax.options() & 0x02) ? 1 : 0; + + underflow[i] = has_underflow; + overflow[i] = has_overflow; axes_dims.emplace_back(ax.size() + has_underflow + has_overflow); if (ax.continuous()) { axis_types.push_back('c'); std::vector<double> ax_edges; - ax_edges.reserve(ax.size()); + ax_edges.reserve(ax.size() + 1); + + for (int j = 0; j < ax.size(); ++j) { ax_edges.push_back(ax.bin(j).lower()); } - for (int j = 0; j < ax.size() + has_overflow; ++j) { - ax_edges.push_back(ax.bin(j).lower()); - } + ax_edges.push_back(ax.bin(ax.size() - 1).upper()); cnpy::npz_save(filename, std::string{"binedges_"} + std::to_string(i), ax_edges.data(), {ax_edges.size()}, "a"); @@ -63,29 +67,30 @@ namespace corsika { cnpy::npz_save(filename, std::string{"axistypes"}, axis_types.data(), {axis_types.size()}, "a"); + + cnpy::npz_save(filename, std::string{"overflow"}, overflow.get(), + {axis_types.size()}, "a"); + cnpy::npz_save(filename, std::string{"underflow"}, underflow.get(), + {axis_types.size()}, "a"); } - auto const prod_axis_size = - std::accumulate(axes_dims.cbegin(), axes_dims.cend(), 1, std::multiplies<>()); - auto temp = std::make_unique<value_type[]>(prod_axis_size); + auto const prod_axis_size = std::accumulate(axes_dims.cbegin(), axes_dims.cend(), + unsigned{1}, std::multiplies<>()); + auto temp = std::make_unique<float[]>(prod_axis_size); - std::cout << "rank = " << rank << std::endl; - std::cout << "size = " << size << std::endl; - std::cout << "prod_axis_size = " << prod_axis_size << std::endl; + assert(prod_axis_size == h.size()); // reduce multi-dim. to 1-dim, row-major (i.e., last axis index is contiguous in - // memory) take special care of underflow bins, which have -1 as index and thus need + // memory) take special care of underflow bins which have -1 as index and thus need // to be shifted by +1 for (auto&& x : indexed(h, boost::histogram::coverage::all)) { - int const offset_underflow = (h.axis(0).options() & 0x01) ? 1 : 0; - auto p = x.index(0) + offset_underflow; // 1-d-index + int p = 0; - for (int axis_index = 1; axis_index < rank; ++axis_index) { + for (int axis_index = 0; axis_index < rank; ++axis_index) { int const offset_underflow = (h.axis(axis_index).options() & 0x01) ? 1 : 0; auto k = x.index(axis_index) + offset_underflow; p = k + p * axes_dims.at(axis_index); - std::cout << " " << x.index(axis_index); } temp[p] = *x; diff --git a/Framework/Utilities/testSaveBoostHistogram.cc b/Framework/Utilities/testSaveBoostHistogram.cc index b00777480d769ec330e6cc528ae7fe211ff17d68..aa05a1947a9c989724dee5244f41859fa634f59f 100644 --- a/Framework/Utilities/testSaveBoostHistogram.cc +++ b/Framework/Utilities/testSaveBoostHistogram.cc @@ -11,23 +11,28 @@ #include <random> +namespace bh = boost::histogram; + TEST_CASE("SaveHistogram") { std::mt19937 rng; std::normal_distribution n1{2., 6.}; std::exponential_distribution e{1.}; std::uniform_int_distribution u{1, 10}; + std::uniform_real_distribution<double> r{-3, 3}; - auto h = - boost::histogram::make_histogram(boost::histogram::axis::regular{5, 0, 10, "x"}, - boost::histogram::axis::regular{3, 0, 4, "y"}, - boost::histogram::axis::category{1, 4, 8}); + auto h = bh::make_histogram( + bh::axis::regular{5, 0, 10, "normal"}, bh::axis::regular{3, 0, 4, "exponential"}, + bh::axis::category<int>{{2, 3, 5, 7}, "integer category"}, + bh::axis::regular<double, bh::use_default, bh::use_default, + bh::axis::option::growth_t>{10, -1, 1, "integer category"}); for (int i{0}; i < 100'000; ++i) { auto const a = n1(rng); auto const b = e(rng); auto const c = u(rng); + auto const d = r(rng); - h(a, b, c); + h(a, b, c, d); } corsika::utl::save_hist(h, "hist.npz"); diff --git a/Tools/read_hist.py b/Tools/read_hist.py index 1d3a69490ba6ccea7dde99fc5d3075a35582ed60..4348e118bdcb4fe4bc3e11fcd50b626425238788 100755 --- a/Tools/read_hist.py +++ b/Tools/read_hist.py @@ -11,14 +11,16 @@ def read_hist(filename): """ d = np.load(filename) - axistypes = d['axistypes'].view('c') + axistypes = d['axistypes'].view('c') + overflow = d['overflow'] + underflow = d['underflow'] axes = [] - for i, at in enumerate(axistypes): + for i, (at, has_overflow, has_underflow) in enumerate(zip(axistypes, overflow, underflow)): if at == b'c': - axes.append(bh.axis.Variable(d[f'binedges_{i}'], overflow=True, underflow=True)) + axes.append(bh.axis.Variable(d[f'binedges_{i}'], overflow=has_overflow, underflow=has_underflow)) elif at == b'd': - axes.append(bh.axis.IntCategory(d[f'binedges_{i}'])) + axes.append(bh.axis.IntCategory(d[f'bins_{i}'], growth=(not has_overflow))) h = bh.Histogram(*axes) h.view(flow=True)[:] = d['data']