Skip to content

Commit ad552e4

Browse files
committed
[df] First integration of RHist filling
As the classes are experimental, using the method will print a warning to inform the user.
1 parent f4a7d74 commit ad552e4

File tree

8 files changed

+344
-0
lines changed

8 files changed

+344
-0
lines changed

tree/dataframe/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ if (imt)
2626
list(APPEND RDATAFRAME_EXTRA_DEPS Imt)
2727
endif(imt)
2828

29+
if (root7)
30+
list(APPEND RDATAFRAME_EXTRA_DEPS ROOTHist)
31+
endif()
32+
2933
set (EXTRA_DICT_OPTS)
3034
if (runtime_cxxmodules AND WIN32)
3135
set (EXTRA_DICT_OPTS NO_CXXMODULE)

tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
#include "ROOT/RDF/RActionImpl.hxx"
3333
#include "ROOT/RDF/RMergeableValue.hxx"
3434

35+
#include "RConfigure.h" // for R__HAS_ROOT7
36+
#ifdef R__HAS_ROOT7
37+
#include <ROOT/RHist.hxx>
38+
#include <ROOT/RHistConcurrentFiller.hxx>
39+
#endif
40+
3541
#include <algorithm>
3642
#include <array>
3743
#include <limits>
@@ -469,6 +475,52 @@ public:
469475
}
470476
};
471477

478+
#ifdef R__HAS_ROOT7
479+
template <typename BinContentType>
480+
class R__CLING_PTRCHECK(off) RHistFillHelper : public ROOT::Detail::RDF::RActionImpl<RHistFillHelper<BinContentType>> {
481+
public:
482+
using Result_t = ROOT::Experimental::RHist<BinContentType>;
483+
484+
private:
485+
std::unique_ptr<ROOT::Experimental::RHistConcurrentFiller<BinContentType>> fFiller;
486+
std::vector<std::shared_ptr<ROOT::Experimental::RHistFillContext<BinContentType>>> fContexts;
487+
488+
public:
489+
RHistFillHelper(std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> h, unsigned int nSlots)
490+
: fFiller(new ROOT::Experimental::RHistConcurrentFiller<BinContentType>(h)), fContexts(nSlots)
491+
{
492+
for (unsigned int i = 0; i < nSlots; i++) {
493+
fContexts[i] = fFiller->CreateFillContext();
494+
}
495+
}
496+
RHistFillHelper(const RHistFillHelper &) = delete;
497+
RHistFillHelper(RHistFillHelper &&) = default;
498+
RHistFillHelper &operator=(const RHistFillHelper &) = delete;
499+
RHistFillHelper &operator=(RHistFillHelper &&) = default;
500+
~RHistFillHelper() = default;
501+
502+
std::shared_ptr<Result_t> GetResultPtr() const { return fFiller.GetHist(); }
503+
504+
void Initialize() {}
505+
void InitTask(TTreeReader *, unsigned int) {}
506+
507+
template <typename... ColumnTypes>
508+
void Exec(unsigned int slot, const ColumnTypes &...columnValues)
509+
{
510+
fContexts[slot]->Fill(columnValues...);
511+
}
512+
513+
void Finalize()
514+
{
515+
for (auto &&context : fContexts) {
516+
context->Flush();
517+
}
518+
}
519+
520+
std::string GetActionName() { return "Hist"; }
521+
};
522+
#endif
523+
472524
class R__CLING_PTRCHECK(off) FillTGraphHelper : public ROOT::Detail::RDF::RActionImpl<FillTGraphHelper> {
473525
public:
474526
using Result_t = ::TGraph;

tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <string_view>
2929
#include <ROOT/RDF/RVariation.hxx>
3030
#include <ROOT/TypeTraits.hxx>
31+
#include <RConfigure.h> // for R__HAS_ROOT7
3132
#include <TError.h> // gErrorIgnoreLevel
3233
#include <TH1.h>
3334
#include <TROOT.h> // IsImplicitMTEnabled
@@ -90,6 +91,7 @@ struct Histo2D{};
9091
struct Histo3D{};
9192
struct HistoND{};
9293
struct HistoNSparseD{};
94+
struct Hist{};
9395
struct Graph{};
9496
struct GraphAsymmErrors{};
9597
struct Profile1D{};
@@ -171,6 +173,20 @@ BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h,
171173
}
172174
}
173175

176+
#ifdef R__HAS_ROOT7
177+
// Action for RHist using RHistConcurrentFiller
178+
template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
179+
std::unique_ptr<RActionBase>
180+
BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
181+
const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
182+
const RColumnRegister &colRegister)
183+
{
184+
using Helper_t = RHistFillHelper<BinContentType>;
185+
using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
186+
return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
187+
}
188+
#endif
189+
174190
template <typename... ColTypes, typename PrevNodeType>
175191
std::unique_ptr<RActionBase>
176192
BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,

tree/dataframe/inc/ROOT/RDF/RInterface.hxx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
#include "TProfile2D.h"
4646
#include "TStatistic.h"
4747

48+
#include "RConfigure.h" // for R__HAS_ROOT7
49+
#ifdef R__HAS_ROOT7
50+
#include <ROOT/RHist.hxx>
51+
#endif
52+
4853
#include <algorithm>
4954
#include <cstddef>
5055
#include <initializer_list>
@@ -2357,6 +2362,66 @@ public:
23572362
columnList, h, h, fProxiedPtr, columnList.size());
23582363
}
23592364

2365+
#ifdef R__HAS_ROOT7
2366+
////////////////////////////////////////////////////////////////////////////
2367+
/// \brief Fill and return an RHist (*lazy action*).
2368+
/// \tparam BinContentType The bin content type of the returned RHist.
2369+
/// \param[in] axes The returned histogram will be constructed using these axes.
2370+
/// \param[in] columnList A list containing the names of the columns that will be passed when calling `Fill`
2371+
/// \return the histogram wrapped in a RResultPtr.
2372+
///
2373+
/// This action is *lazy*: upon invocation of this method the calculation is
2374+
/// booked but not executed. Also see RResultPtr.
2375+
///
2376+
/// ### Example usage:
2377+
/// ~~~{.cpp}
2378+
/// ROOT::Experimental::RRegularAxis axis(10, {5.0, 15.0});
2379+
/// auto myHist = myDf.Hist({axis}, {"col0"});
2380+
/// ~~~
2381+
template <typename BinContentType = double, typename ColumnType = RDFDetail::RInferredType, typename... ColumnTypes>
2382+
RResultPtr<ROOT::Experimental::RHist<BinContentType>>
2383+
Hist(std::vector<ROOT::Experimental::RAxisVariant> axes, const ColumnNames_t &columnList)
2384+
{
2385+
std::shared_ptr h = std::make_shared<ROOT::Experimental::RHist<BinContentType>>(std::move(axes));
2386+
if (h->GetNDimensions() != columnList.size()) {
2387+
throw std::runtime_error("Wrong number of columns for the specified number of histogram axes.");
2388+
}
2389+
2390+
return Hist<ColumnType, ColumnTypes...>(h, columnList);
2391+
}
2392+
2393+
////////////////////////////////////////////////////////////////////////////
2394+
/// \brief Fill the provided RHist (*lazy action*).
2395+
/// \param[in] h The histogram that should be filled.
2396+
/// \param[in] columnList A list containing the names of the columns that will be passed when calling `Fill`
2397+
/// \return the histogram wrapped in a RResultPtr.
2398+
///
2399+
/// This action is *lazy*: upon invocation of this method the calculation is
2400+
/// booked but not executed. Also see RResultPtr.
2401+
///
2402+
/// During execution of the computation graph, the passed histogram must only be accessed with methods that are
2403+
/// allowed during concurrent filling.
2404+
///
2405+
/// ### Example usage:
2406+
/// ~~~{.cpp}
2407+
/// auto h = std::make_shared<ROOT::Experimental::RHist<double>>(10, {5.0, 15.0});
2408+
/// auto myHist = myDf.Hist(h, {"col0"});
2409+
/// ~~~
2410+
template <typename ColumnType = RDFDetail::RInferredType, typename... ColumnTypes, typename BinContentType>
2411+
RResultPtr<ROOT::Experimental::RHist<BinContentType>>
2412+
Hist(std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> h, const ColumnNames_t &columnList)
2413+
{
2414+
RDFInternal::WarnHist();
2415+
2416+
if (h->GetNDimensions() != columnList.size()) {
2417+
throw std::runtime_error("Wrong number of columns for the passed histogram.");
2418+
}
2419+
2420+
return CreateAction<RDFInternal::ActionTags::Hist, ColumnType, ColumnTypes...>(columnList, h, h, fProxiedPtr,
2421+
columnList.size());
2422+
}
2423+
#endif
2424+
23602425
////////////////////////////////////////////////////////////////////////////
23612426
/// \brief Fill and return a TGraph object (*lazy action*).
23622427
/// \tparam X The type of the column used to fill the x axis.

tree/dataframe/inc/ROOT/RDF/Utils.hxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct RInferredType {
6565
namespace Internal {
6666
namespace RDF {
6767

68+
/// Warn once about experimental filling of RHist.
69+
void WarnHist();
70+
6871
using namespace ROOT::TypeTraits;
6972
using namespace ROOT::Detail::RDF;
7073
using namespace ROOT::RDF;

tree/dataframe/src/RDFUtils.cxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "TTree.h"
3030

3131
#include <fstream>
32+
#include <mutex>
3233
#include <nlohmann/json.hpp> // nlohmann::json::parse
3334
#include <stdexcept>
3435
#include <string>
@@ -45,6 +46,18 @@ ROOT::RLogChannel &ROOT::Detail::RDF::RDFLogChannel()
4546
return c;
4647
}
4748

49+
// A static function, not in an anonymous namespace, because the function name is included in the user-visible message.
50+
static void WarnHist()
51+
{
52+
R__LOG_WARNING(RDFLogChannel()) << "Filling RHist is experimental and still under development.";
53+
}
54+
55+
void ROOT::Internal::RDF::WarnHist()
56+
{
57+
static std::once_flag once;
58+
std::call_once(once, ::WarnHist);
59+
}
60+
4861
namespace {
4962
using TypeInfoRef = std::reference_wrapper<const std::type_info>;
5063
struct TypeInfoRefHash {

tree/dataframe/test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ if (imt)
139139
ROOT_ADD_GTEST(dataframe_concurrency dataframe_concurrency.cxx LIBRARIES ROOTDataFrame)
140140
endif()
141141

142+
if (root7)
143+
ROOT_ADD_GTEST(dataframe_hist dataframe_hist.cxx LIBRARIES ROOTDataFrame ROOTHist)
144+
endif()
145+
142146
if(ARROW_FOUND)
143147
ROOT_ADD_GTEST(datasource_arrow datasource_arrow.cxx LIBRARIES ROOTDataFrame ${ARROW_SHARED_LIB})
144148
target_include_directories(datasource_arrow BEFORE PRIVATE ${ARROW_INCLUDE_DIR})

0 commit comments

Comments
 (0)