12 #include <type_traits> 16 namespace ROOT {
namespace Experimental {
19 template <
int D_,
class P_>
class... STAT>
22 template <
int D_,
class P_>
62 template <
typename Input,
typename Enable =
void>
66 static_assert(always_false<Input>,
"Unsupported histogram conversion");
69 static auto convert(
const Input& src,
const char* name);
77 template <
template <
int D_,
class P_>
class... STAT>
83 constexpr
bool stats_ok<> =
true;
87 template <
template <
int D_,
class P_>
class SINGLE_STAT>
90 constexpr
bool stats_ok<RExp::RHistStatContent> =
true;
94 template <
template <
int D_,
class P_>
class STAT_HEAD,
95 template <
int D_,
class P_>
class... STAT_TAIL>
96 constexpr
bool stats_ok<STAT_HEAD, STAT_TAIL...> =
97 stats_ok<STAT_HEAD> || stats_ok<STAT_TAIL...>;
100 template <
template <
int D_,
class P_>
class... STAT>
101 struct CheckStats :
public std::bool_constant<stats_ok<STAT...>> {
102 static_assert(stats_ok<STAT...>,
103 "Only ROOT 7 histograms that record RHistStatContent " 104 "statistics may be converted into ROOT 6 histograms");
108 template <
template <
int D_,
class P_>
class... STAT>
119 template <
int DIMENSIONS,
class PRECISION>
121 static_assert(always_false<PRECISION>,
122 "No known ROOT 6 histogram type matches the input " 123 "histogram's dimensionality and precision");
191 template <
int DIMENSIONS,
class PRECISION>
196 template <
int DIMENSIONS,
class PRECISION>
209 template <
class Output,
class Input>
239 template <
int D_,
class P_>
class... STAT>
241 std::enable_if_t<CheckRoot6Type_v<DIMS, PRECISION>
242 && CheckStats_v<STAT...>>>
250 return convert_hist<Output>(src, name);
264 template <
typename Root7Hist>
277 #include "ROOT/RAxis.hxx" 278 #include "ROOT/RHist.hxx" 279 #include "ROOT/RHistImpl.hxx" 310 template <
typename Output,
typename... BuildParams>
311 static Output make(std::tuple<BuildParams...>&& build_params) {
312 return std::make_from_tuple<Output>(std::move(build_params));
322 template <
typename Output,
typename... BuildParams>
323 static Output make(std::tuple<BuildParams...>&& th3_params) {
324 std::ostringstream s;
325 char * args_type_name;
327 args_type_name = abi::__cxa_demangle(
typeid(th3_params).name(),
331 s <<
"Unsupported TH3 axis configuration" 332 <<
" (no constructor from argument-tuple " << args_type_name
334 free(args_type_name);
335 throw std::runtime_error(s.str());
339 template <
typename Output>
341 Int_t, Double_t, Double_t,
342 Int_t, Double_t, Double_t,
343 Int_t, Double_t, Double_t>&& th3_params) {
344 return std::make_from_tuple<Output>(std::move(th3_params));
346 template <
typename Output>
348 Int_t,
const Double_t*,
349 Int_t,
const Double_t*,
350 Int_t,
const Double_t*>&& th3_params) {
351 return std::make_from_tuple<Output>(std::move(th3_params));
385 template <
class Output,
int AXIS,
int DIMS,
class... BuildParams>
387 std::tuple<BuildParams...>&& build_params) {
390 if constexpr (AXIS < DIMS) {
392 const auto axis_view = src_impl.GetAxis(AXIS);
395 const auto* eq_axis_ptr = axis_view.GetAsEquidistant();
396 if (eq_axis_ptr !=
nullptr) {
397 const auto& eq_axis = *eq_axis_ptr;
401 auto new_build_params =
403 std::move(build_params),
404 std::make_tuple((Int_t)(eq_axis.GetNBinsNoOver()),
405 (Double_t)(eq_axis.GetMinimum()),
406 (Double_t)(eq_axis.GetMaximum()))
413 std::move(new_build_params));
440 const auto* irr_axis_ptr = axis_view.GetAsIrregular();
441 if (irr_axis_ptr !=
nullptr) {
442 const auto& irr_axis = *irr_axis_ptr;
446 auto new_build_params =
448 std::move(build_params),
450 (Int_t)(irr_axis.GetNBinsNoOver()),
451 (
const Double_t*)(irr_axis.GetBinBorders().data())
459 std::move(new_build_params));
471 throw std::runtime_error(
"Unsupported histogram axis type");
472 }
else if constexpr (AXIS == DIMS) {
477 std::move(build_params)
481 static_assert(always_false<Output>,
482 "Invalid loop iteration in build_hist_loop");
490 template <
class THx,
int DIMS>
494 auto bins_similar = [](
auto src_bins,
auto dest_bins) ->
bool {
495 static constexpr
double TOLERANCE = 1e-6;
496 if (src_bins.size() != dest_bins.size())
return false;
497 for (
size_t i = 0; i < src_bins.size(); ++i) {
498 double diff = std::abs(src_bins[i] - dest_bins[i]);
499 if (diff >= TOLERANCE * std::abs(src_bins[i])) {
return false; }
505 auto print_bins = [](std::ostringstream& s,
auto local_bin_indices) {
507 for (
size_t i = 0; i < local_bin_indices.size()-1; ++i) {
508 s << local_bin_indices[i] <<
", ";
510 s << local_bin_indices[local_bin_indices.size()-1] <<
" }";
516 std::ostringstream s;
517 s <<
"Binning origin doesn't match" 518 <<
" (source histogram's first bin is at ";
519 print_bins(s, src_impl.GetBinFrom(0));
520 s <<
", target histogram's first bin is at ";
523 throw std::runtime_error(s.str());
525 if ((src_impl.GetNBins() >=2)
527 std::ostringstream s;
528 s <<
"Binning order doesn't match" 529 <<
" (source histogram's second bin is at ";
530 print_bins(s, src_impl.GetBinFrom(1));
531 s <<
", target histogram's second bin is at ";
534 throw std::runtime_error(s.str());
536 if (src_impl.GetNBins() != dest.GetNcells()) {
537 std::ostringstream s;
538 s <<
"Bin count doesn't match" 539 <<
" (source histogram has " << src_impl.GetNBins() <<
" bins" 540 <<
", target histogram has " << dest.GetNcells() <<
" bins)";
541 throw std::runtime_error(s.str());
547 template <
class Output,
class Input>
550 const auto* impl_ptr = src.GetImpl();
551 if (impl_ptr ==
nullptr) {
552 throw std::runtime_error(
"Input histogram has a null impl pointer");
554 const auto& impl = *impl_ptr;
562 auto first_build_params = std::make_tuple(name, title.c_str());
565 auto dest = convert_hist_loop<Output, 0>(impl,
566 std::move(first_build_params));
570 dest.SetStatOverflows(TH1::EStatOverflows::kConsider);
574 dest.SetBinErrorOption(TH1::EBinErrorOpt::kNormal);
577 dest.SetNormFactor(0);
589 const auto& stat = src.GetImpl()->GetStat();
590 if (stat.HasBinUncertainty()) {
592 auto& sumw2 = *dest.GetSumw2();
593 for (
size_t bin = 0; bin < stat.size(); ++bin) {
594 sumw2[bin] = stat.GetBinUncertainty(bin);
599 dest.SetEntries(stat.GetEntries());
600 for (
size_t bin = 0; bin < stat.size(); ++bin) {
601 dest.AddBinContent(bin, stat.GetBinContent(bin));
626 std::array<Double_t, TH1::kNstat> stats;
627 dest.GetStats(stats.data());
628 dest.PutStats(stats.data());
std::string convert_hist_title(const std::string &title)
constexpr bool always_false
static constexpr bool CheckStats_v
void check_binning(const THx &dest, const RHistImplBase< DIMS > &src_impl)
static Output make(std::tuple< const char *, const char *, Int_t, Double_t, Double_t, Int_t, Double_t, Double_t, Int_t, Double_t, Double_t > &&th3_params)
constexpr unsigned long long value(const Flag_t &flag)
auto into_root6_hist(const Root7Hist &src, const char *name)
static constexpr bool CheckRoot6Type_v
template TH3D convert_hist(const RExp::RHist< 3, Double_t > &, const char *)
static auto convert(const Input &src, const char *name)
typename CheckRoot6Type< DIMENSIONS, PRECISION >::type CheckRoot6Type_t
std::array< Double_t, 3 > get_bin_from_root6(const TH3 &hist, Int_t bin)
CheckRoot6Type_t< DIMS, PRECISION > Output
Output convert_hist_loop(const RHistImplBase< DIMS > &src_impl, std::tuple< BuildParams... > &&build_params)
static Output convert(const Input &src, const char *name)
void setup_axis_base(TAxis &dest, const RExp::RAxisBase &src)
static Output make(std::tuple< BuildParams... > &&th3_params)
constexpr bool stats_ok< SINGLE_STAT >
TAxis & get_root6_axis(TH3 &hist, size_t idx)
static Output make(std::tuple< const char *, const char *, Int_t, const Double_t *, Int_t, const Double_t *, Int_t, const Double_t *> &&th3_params)
static Output make(std::tuple< BuildParams... > &&build_params)
RExp::Detail::RHistImplPrecisionAgnosticBase< DIMS > RHistImplBase