From 313445a937e0edd8be4da125431e23c596551e53 Mon Sep 17 00:00:00 2001 From: Florine de Geus Date: Fri, 11 Oct 2024 09:27:03 +0200 Subject: [PATCH] [ntuple] Add a common `RNTupleOpenSpec` The specification structs `RNTupleReader::ROpenSpec` and `RNTupleSourceSpec` (used by `RNTupleProcessor`) are virtually identical, so it makes no sense to keep both around. --- tree/ntuple/v7/inc/ROOT/RNTupleProcessor.hxx | 29 +++++++------------- tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx | 12 +------- tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx | 10 +++++++ tree/ntuple/v7/src/RNTupleProcessor.cxx | 11 ++++---- tree/ntuple/v7/src/RNTupleReader.cxx | 2 +- tree/ntuple/v7/test/ntuple_friends.cxx | 6 ++-- tree/ntuple/v7/test/ntuple_multi_column.cxx | 2 +- tree/ntuple/v7/test/ntuple_processor.cxx | 22 +++++++-------- tree/ntuple/v7/test/ntuple_show.cxx | 2 +- tree/ntuple/v7/test/ntuple_test.hxx | 2 +- tutorials/v7/ntuple/ntpl006_friends.C | 5 ++-- tutorials/v7/ntuple/ntpl012_processor.C | 13 +++++---- 12 files changed, 52 insertions(+), 64 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleProcessor.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleProcessor.hxx index e6437484b6740..11cab440d1d35 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleProcessor.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleProcessor.hxx @@ -32,15 +32,6 @@ namespace ROOT { namespace Experimental { -/// Helper type representing the name and storage location of an RNTuple. -struct RNTupleSourceSpec { - std::string fName; - std::string fLocation; - - RNTupleSourceSpec() = default; - RNTupleSourceSpec(std::string_view n, std::string_view s) : fName(n), fLocation(s) {} -}; - // clang-format off /** \class ROOT::Experimental::RNTupleProcessor @@ -52,9 +43,9 @@ Example usage (see ntpl012_processor.C for a full example): ~~~{.cpp} #include using ROOT::Experimental::RNTupleProcessor; -using ROOT::Experimental::RNTupleSourceSpec; +using ROOT::Experimental::RNTupleOpenSpec; -std::vector ntuples = {{"ntuple1", "ntuple1.root"}, {"ntuple2", "ntuple2.root"}}; +std::vector ntuples = {{"ntuple1", "ntuple1.root"}, {"ntuple2", "ntuple2.root"}}; auto processor = RNTupleProcessor::CreateChain(ntuples); for (const auto &entry : processor) { @@ -62,7 +53,7 @@ for (const auto &entry : processor) { } ~~~ -An RNTupleProcessor is created by providing one or more RNTupleSourceSpecs, each of which contains the name and storage +An RNTupleProcessor is created by providing one or more RNTupleOpenSpecs, each of which contains the name and storage location of a single RNTuple. The RNTuples are processed in the order in which they were provided. The RNTupleProcessor constructor also (optionally) accepts an RNTupleModel, which determines which fields should be @@ -108,7 +99,7 @@ protected: void SetConcreteField() { fConcreteField = fProtoField->Clone(fProtoField->GetFieldName()); } }; - std::vector fNTuples; + std::vector fNTuples; std::unique_ptr fEntry; std::unique_ptr fPageSource; std::vector fFieldContexts; @@ -120,13 +111,13 @@ protected: ///////////////////////////////////////////////////////////////////////////// /// \brief Connect an RNTuple for processing. /// - /// \param[in] ntuple The RNTupleSourceSpec describing the RNTuple to connect. + /// \param[in] ntuple The RNTupleOpenSpec describing the RNTuple to connect. /// /// \return The number of entries in the newly-connected RNTuple. /// /// Creates and attaches new page source for the specified RNTuple, and connects the fields that are known by /// the processor to it. - virtual NTupleSize_t ConnectNTuple(const RNTupleSourceSpec &ntuple) = 0; + virtual NTupleSize_t ConnectNTuple(const RNTupleOpenSpec &ntuple) = 0; ///////////////////////////////////////////////////////////////////////////// /// \brief Creates and connects concrete fields to the current page source, based on the proto-fields. @@ -142,7 +133,7 @@ protected: /// is connected or the iterator has reached the end. virtual NTupleSize_t Advance() = 0; - RNTupleProcessor(const std::vector &ntuples) + RNTupleProcessor(const std::vector &ntuples) : fNTuples(ntuples), fNEntriesProcessed(0), fCurrentNTupleNumber(0), fLocalEntryNumber(0) { } @@ -243,7 +234,7 @@ public: /// /// \return A pointer to the newly created RNTupleProcessor. static std::unique_ptr - CreateChain(const std::vector &ntuples, std::unique_ptr model = nullptr); + CreateChain(const std::vector &ntuples, std::unique_ptr model = nullptr); }; // clang-format off @@ -257,7 +248,7 @@ class RNTupleChainProcessor : public RNTupleProcessor { friend class RNTupleProcessor; private: - NTupleSize_t ConnectNTuple(const RNTupleSourceSpec &ntuple) final; + NTupleSize_t ConnectNTuple(const RNTupleOpenSpec &ntuple) final; void ConnectFields() final; NTupleSize_t Advance() final; @@ -270,7 +261,7 @@ private: /// specified, it is created from the descriptor of the first RNTuple specified in `ntuples`. /// /// RNTuples are processed in the order in which they are specified. - RNTupleChainProcessor(const std::vector &ntuples, std::unique_ptr model = nullptr); + RNTupleChainProcessor(const std::vector &ntuples, std::unique_ptr model = nullptr); }; } // namespace Experimental diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx index d3e04e821dfd4..10117801eaf63 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleReader.hxx @@ -135,16 +135,6 @@ public: bool operator!=(const iterator &rh) const { return fIndex != rh.fIndex; } }; - /// Used to specify the underlying RNTuples in OpenFriends() - struct ROpenSpec { - std::string fNTupleName; - std::string fStorage; - RNTupleReadOptions fOptions; - - ROpenSpec() = default; - ROpenSpec(std::string_view n, std::string_view s) : fNTupleName(n), fStorage(s) {} - }; - /// Open an RNTuple for reading. /// /// Throws an RException if there is no RNTuple with the given name. @@ -173,7 +163,7 @@ public: /// have an identical number of entries. Fields in the combined RNTuple are named with the ntuple name /// as a prefix, e.g. myNTuple1.px and myNTuple2.pt (see tutorial ntpl006_friends) static std::unique_ptr - OpenFriends(std::span ntuples, const RNTupleReadOptions &options = RNTupleReadOptions()); + OpenFriends(std::span ntuples, const RNTupleReadOptions &options = RNTupleReadOptions()); std::unique_ptr Clone() { auto options = RNTupleReadOptions{}; diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx index b3f68f1cbb84d..812021930396c 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx @@ -22,6 +22,7 @@ #include #include +#include namespace ROOT { namespace Experimental { @@ -228,6 +229,15 @@ struct RNTupleLocator { } }; +/// Used to specify the underlying RNTuples in RNTupleProcessor and RNTupleReader::OpenFriends() +struct RNTupleOpenSpec { + std::string fNTupleName; + std::string fStorage; + RNTupleReadOptions fOptions; + + RNTupleOpenSpec(std::string_view n, std::string_view s) : fNTupleName(n), fStorage(s) {} +}; + namespace Internal { template auto MakeAliasedSharedPtr(T *rawPtr) diff --git a/tree/ntuple/v7/src/RNTupleProcessor.cxx b/tree/ntuple/v7/src/RNTupleProcessor.cxx index 760aa93b81a3a..928efebe2231a 100644 --- a/tree/ntuple/v7/src/RNTupleProcessor.cxx +++ b/tree/ntuple/v7/src/RNTupleProcessor.cxx @@ -18,7 +18,7 @@ #include std::unique_ptr -ROOT::Experimental::RNTupleProcessor::CreateChain(const std::vector &ntuples, +ROOT::Experimental::RNTupleProcessor::CreateChain(const std::vector &ntuples, std::unique_ptr model) { return std::unique_ptr(new RNTupleChainProcessor(ntuples, std::move(model))); @@ -26,14 +26,14 @@ ROOT::Experimental::RNTupleProcessor::CreateChain(const std::vector &ntuples, +ROOT::Experimental::RNTupleChainProcessor::RNTupleChainProcessor(const std::vector &ntuples, std::unique_ptr model) : RNTupleProcessor(ntuples) { if (fNTuples.empty()) throw RException(R__FAIL("at least one RNTuple must be provided")); - fPageSource = Internal::RPageSource::Create(fNTuples[0].fName, fNTuples[0].fLocation); + fPageSource = Internal::RPageSource::Create(fNTuples[0].fNTupleName, fNTuples[0].fStorage); fPageSource->Attach(); if (fPageSource->GetNEntries() == 0) { @@ -64,13 +64,12 @@ ROOT::Experimental::RNTupleChainProcessor::RNTupleChainProcessor(const std::vect ConnectFields(); } -ROOT::Experimental::NTupleSize_t -ROOT::Experimental::RNTupleChainProcessor::ConnectNTuple(const RNTupleSourceSpec &ntuple) +ROOT::Experimental::NTupleSize_t ROOT::Experimental::RNTupleChainProcessor::ConnectNTuple(const RNTupleOpenSpec &ntuple) { for (auto &fieldContext : fFieldContexts) { fieldContext.ResetConcreteField(); } - fPageSource = Internal::RPageSource::Create(ntuple.fName, ntuple.fLocation); + fPageSource = Internal::RPageSource::Create(ntuple.fNTupleName, ntuple.fStorage); fPageSource->Attach(); ConnectFields(); return fPageSource->GetNEntries(); diff --git a/tree/ntuple/v7/src/RNTupleReader.cxx b/tree/ntuple/v7/src/RNTupleReader.cxx index 126d1c373a7b7..1dbcc8899a251 100644 --- a/tree/ntuple/v7/src/RNTupleReader.cxx +++ b/tree/ntuple/v7/src/RNTupleReader.cxx @@ -113,7 +113,7 @@ ROOT::Experimental::RNTupleReader::Open(std::unique_ptr model, con } std::unique_ptr -ROOT::Experimental::RNTupleReader::OpenFriends(std::span ntuples, const RNTupleReadOptions &options) +ROOT::Experimental::RNTupleReader::OpenFriends(std::span ntuples, const RNTupleReadOptions &options) { std::vector> sources; sources.reserve(ntuples.size()); diff --git a/tree/ntuple/v7/test/ntuple_friends.cxx b/tree/ntuple/v7/test/ntuple_friends.cxx index fc1454a47a73e..ef475791ab7ff 100644 --- a/tree/ntuple/v7/test/ntuple_friends.cxx +++ b/tree/ntuple/v7/test/ntuple_friends.cxx @@ -23,7 +23,7 @@ TEST(RPageStorageFriends, Null) TEST(RPageStorageFriends, Empty) { - std::span ntuples; + std::span ntuples; auto reader = RNTupleReader::OpenFriends(ntuples); EXPECT_EQ(0u, reader->GetNEntries()); EXPECT_EQ(0u, reader->GetModel().GetFieldZero().GetOnDiskId()); @@ -68,9 +68,7 @@ TEST(RPageStorageFriends, Basic) ntuple->Fill(); } - std::vector friends{ - {"ntpl1", fileGuard1.GetPath()}, - {"ntpl2", fileGuard2.GetPath()} }; + std::vector friends{{"ntpl1", fileGuard1.GetPath()}, {"ntpl2", fileGuard2.GetPath()}}; auto ntuple = RNTupleReader::OpenFriends(friends); EXPECT_EQ(3u, ntuple->GetNEntries()); diff --git a/tree/ntuple/v7/test/ntuple_multi_column.cxx b/tree/ntuple/v7/test/ntuple_multi_column.cxx index fd18e4ca0586b..ec44bdb9bb39c 100644 --- a/tree/ntuple/v7/test/ntuple_multi_column.cxx +++ b/tree/ntuple/v7/test/ntuple_multi_column.cxx @@ -417,7 +417,7 @@ TEST(RNTuple, MultiColumnRepresentationFriends) writer->Fill(); } - std::vector friends{{"ntpl1", fileGuard1.GetPath()}, {"ntpl2", fileGuard2.GetPath()}}; + std::vector friends{{"ntpl1", fileGuard1.GetPath()}, {"ntpl2", fileGuard2.GetPath()}}; auto reader = RNTupleReader::OpenFriends(friends); EXPECT_EQ(2u, reader->GetNEntries()); auto viewPt = reader->GetView("ntpl1.pt"); diff --git a/tree/ntuple/v7/test/ntuple_processor.cxx b/tree/ntuple/v7/test/ntuple_processor.cxx index 073e08560a037..15646db70aec8 100644 --- a/tree/ntuple/v7/test/ntuple_processor.cxx +++ b/tree/ntuple/v7/test/ntuple_processor.cxx @@ -16,7 +16,7 @@ TEST(RNTupleProcessor, Basic) } } - std::vector ntuples; + std::vector ntuples; try { auto proc = RNTupleProcessor::CreateChain(ntuples); FAIL() << "creating a processor without at least one RNTuple should throw"; @@ -57,7 +57,7 @@ TEST(RNTupleProcessor, WithModel) auto model = RNTupleModel::Create(); auto fldY = model->MakeField("y"); - std::vector ntuples = {{"ntuple", fileGuard.GetPath()}}; + std::vector ntuples = {{"ntuple", fileGuard.GetPath()}}; auto proc = RNTupleProcessor::CreateChain(ntuples, std::move(model)); for (const auto &entry : *proc) { @@ -89,7 +89,7 @@ TEST(RNTupleProcessor, WithBareModel) auto model = RNTupleModel::CreateBare(); model->MakeField("y"); - std::vector ntuples = {{"ntuple", fileGuard.GetPath()}}; + std::vector ntuples = {{"ntuple", fileGuard.GetPath()}}; auto proc = RNTupleProcessor::CreateChain(ntuples, std::move(model)); for (const auto &entry : *proc) { @@ -132,7 +132,7 @@ TEST(RNTupleProcessor, SimpleChain) } } - std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, {"ntuple", fileGuard2.GetPath()}}; + std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, {"ntuple", fileGuard2.GetPath()}}; std::uint64_t nEntries = 0; auto proc = RNTupleProcessor::CreateChain(ntuples); @@ -184,7 +184,7 @@ TEST(RNTupleProcessor, SimpleChainWithModel) auto model = RNTupleModel::Create(); auto fldX = model->MakeField("x"); - std::vector ntuples = { + std::vector ntuples = { {"ntuple", fileGuard1.GetPath()}, {"ntuple", fileGuard2.GetPath()}, {"ntuple", fileGuard3.GetPath()}}; auto proc = RNTupleProcessor::CreateChain(ntuples, std::move(model)); @@ -246,11 +246,11 @@ TEST(RNTupleProcessor, EmptyNTuples) auto ntuple = RNTupleWriter::Recreate(std::move(model), "ntuple", fileGuard5.GetPath()); } - std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, - {"ntuple", fileGuard2.GetPath()}, - {"ntuple", fileGuard3.GetPath()}, - {"ntuple", fileGuard4.GetPath()}, - {"ntuple", fileGuard5.GetPath()}}; + std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, + {"ntuple", fileGuard2.GetPath()}, + {"ntuple", fileGuard3.GetPath()}, + {"ntuple", fileGuard4.GetPath()}, + {"ntuple", fileGuard5.GetPath()}}; std::uint64_t nEntries = 0; @@ -294,7 +294,7 @@ TEST(RNTupleProcessor, ChainUnalignedModels) ntuple->Fill(); } - std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, {"ntuple", fileGuard2.GetPath()}}; + std::vector ntuples = {{"ntuple", fileGuard1.GetPath()}, {"ntuple", fileGuard2.GetPath()}}; auto proc = RNTupleProcessor::CreateChain(ntuples); auto entry = proc->begin(); diff --git a/tree/ntuple/v7/test/ntuple_show.cxx b/tree/ntuple/v7/test/ntuple_show.cxx index 648ca23ac4efb..edea1fa4ce7ab 100644 --- a/tree/ntuple/v7/test/ntuple_show.cxx +++ b/tree/ntuple/v7/test/ntuple_show.cxx @@ -639,7 +639,7 @@ TEST(RNTupleShow, Friends) writer->Fill(); } - std::vector friends = {{"ntpl1", fileGuard1.GetPath()}, {"ntpl2", fileGuard2.GetPath()}}; + std::vector friends = {{"ntpl1", fileGuard1.GetPath()}, {"ntpl2", fileGuard2.GetPath()}}; auto ntuple = RNTupleReader::OpenFriends(friends); std::ostringstream os; ntuple->Show(0, os); diff --git a/tree/ntuple/v7/test/ntuple_test.hxx b/tree/ntuple/v7/test/ntuple_test.hxx index 82fe7574c40ab..0e8161bd04f15 100644 --- a/tree/ntuple/v7/test/ntuple_test.hxx +++ b/tree/ntuple/v7/test/ntuple_test.hxx @@ -99,11 +99,11 @@ using RNTupleMerger = ROOT::Experimental::Internal::RNTupleMerger; using RNTupleMergeOptions = ROOT::Experimental::Internal::RNTupleMergeOptions; using ENTupleMergingMode = ROOT::Experimental::Internal::ENTupleMergingMode; using RNTupleModel = ROOT::Experimental::RNTupleModel; +using RNTupleOpenSpec = ROOT::Experimental::RNTupleOpenSpec; using RNTuplePlainCounter = ROOT::Experimental::Detail::RNTuplePlainCounter; using RNTuplePlainTimer = ROOT::Experimental::Detail::RNTuplePlainTimer; using RNTupleProcessor = ROOT::Experimental::RNTupleProcessor; using RNTupleSerializer = ROOT::Experimental::Internal::RNTupleSerializer; -using RNTupleSourceSpec = ROOT::Experimental::RNTupleSourceSpec; using RPage = ROOT::Experimental::Internal::RPage; using RPageAllocatorHeap = ROOT::Experimental::Internal::RPageAllocatorHeap; using RPagePool = ROOT::Experimental::Internal::RPagePool; diff --git a/tutorials/v7/ntuple/ntpl006_friends.C b/tutorials/v7/ntuple/ntpl006_friends.C index 9148a2ad73b7f..d47167352a7e7 100644 --- a/tutorials/v7/ntuple/ntpl006_friends.C +++ b/tutorials/v7/ntuple/ntpl006_friends.C @@ -28,6 +28,7 @@ constexpr char const* kNTupleMainFileName = "ntpl006_data.root"; constexpr char const* kNTupleFriendFileName = "ntpl006_reco.root"; using RNTupleModel = ROOT::Experimental::RNTupleModel; +using RNTupleOpenSpec = ROOT::Experimental::RNTupleOpenSpec; using RNTupleReader = ROOT::Experimental::RNTupleReader; using RNTupleWriter = ROOT::Experimental::RNTupleWriter; @@ -69,9 +70,7 @@ void ntpl006_friends() { Generate(); - std::vector friends{ - {"data", kNTupleMainFileName}, - {"reco", kNTupleFriendFileName} }; + std::vector friends{{"data", kNTupleMainFileName}, {"reco", kNTupleFriendFileName}}; auto ntuple = RNTupleReader::OpenFriends(friends); auto c = new TCanvas("c", "", 200, 10, 700, 500); diff --git a/tutorials/v7/ntuple/ntpl012_processor.C b/tutorials/v7/ntuple/ntpl012_processor.C index b6787688db458..39817fc3bd5be 100644 --- a/tutorials/v7/ntuple/ntpl012_processor.C +++ b/tutorials/v7/ntuple/ntpl012_processor.C @@ -23,8 +23,8 @@ // Import classes from the `Experimental` namespace for the time being. using ROOT::Experimental::RNTupleModel; +using ROOT::Experimental::RNTupleOpenSpec; using ROOT::Experimental::RNTupleProcessor; -using ROOT::Experimental::RNTupleSourceSpec; using ROOT::Experimental::RNTupleWriter; // Number of events to generate for each ntuple. @@ -61,7 +61,7 @@ void Write(std::string_view ntupleName, std::string_view ntupleFileName) } } -void Read(const std::vector &ntuples) +void Read(const std::vector &ntuples) { auto c = new TCanvas("c", "RNTupleProcessor Example", 200, 10, 700, 500); TH1F hPx("h", "This is the px distribution", 100, -4, 4); @@ -80,7 +80,7 @@ void Read(const std::vector &ntuples) // The RNTupleProcessor provides some additional bookkeeping information. The local entry number is reset each // a new ntuple in the chain is opened for processing. if (processor->GetLocalEntryNumber() == 0) { - std::cout << "Processing " << ntuples.at(processor->GetCurrentNTupleNumber()).fName << " (" + std::cout << "Processing " << ntuples.at(processor->GetCurrentNTupleNumber()).fNTupleName << " (" << processor->GetNEntriesProcessed() << " total entries processed so far)" << std::endl; } @@ -96,12 +96,13 @@ void Read(const std::vector &ntuples) void ntpl012_processor() { - // The ntuples to generate (for the purpose of this tutorial) and subsequently process. - std::vector ntuples = { + // The ntuples to generate and subsequently process. The model of the first ntuple will be used to construct the + // entry used by the processor. + std::vector ntuples = { {"ntuple1", "ntuple1.root"}, {"ntuple2", "ntuple2.root"}, {"ntuple3", "ntuple3.root"}}; for (const auto &ntuple : ntuples) { - Write(ntuple.fName, ntuple.fLocation); + Write(ntuple.fNTupleName, ntuple.fStorage); } Read(ntuples);