Skip to content

Commit 77f0ca8

Browse files
committed
[ntuple] add streaming vector tutorial
1 parent 52d111e commit 77f0ca8

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/// \file
2+
/// \ingroup tutorial_ntuple
3+
///
4+
/// Example of a streaming vector: a special purpose container that reads large vectors piece-wise.
5+
///
6+
/// \macro_code
7+
///
8+
/// \date November 2024
9+
/// \author Peter van Gemmeren, the ROOT Team
10+
11+
// NOTE: The RNTuple classes are experimental at this point.
12+
// Functionality and interface are still subject to changes.
13+
14+
#include <ROOT/RNTupleModel.hxx>
15+
#include <ROOT/RNTupleReader.hxx>
16+
#include <ROOT/RNTupleUtil.hxx>
17+
#include <ROOT/RNTupleView.hxx>
18+
#include <ROOT/RNTupleWriter.hxx>
19+
20+
#include <TRandom3.h>
21+
22+
#include <cstdint>
23+
#include <iostream>
24+
25+
#include <vector>
26+
27+
using namespace ROOT::Experimental;
28+
29+
constexpr char const* kFileName = "ntpl015_streaming_vector.root";
30+
constexpr char const* kNTupleName = "ntpl";
31+
constexpr char const* kFieldName = "LargeVector";
32+
constexpr unsigned int kNEvents = 10;
33+
constexpr unsigned int kVectorSize = 1'000'000;
34+
35+
void CreateRNTuple() {
36+
std::unique_ptr<RNTupleModel> model = RNTupleModel::Create();
37+
auto ptrLargeVector = model->MakeField<std::vector<std::uint32_t>>(kFieldName);
38+
auto writer = RNTupleWriter::Recreate(std::move(model), kNTupleName, kFileName);
39+
40+
auto prng = std::make_unique<TRandom3>();
41+
prng->SetSeed();
42+
43+
for (NTupleSize_t i = 0; i < kNEvents; i++) {
44+
ptrLargeVector->clear();
45+
for (std::size_t j = 0; j < kVectorSize; j++)
46+
ptrLargeVector->emplace_back(prng->Integer(-1));
47+
writer->Fill();
48+
}
49+
std::cout << "RNTuple written" << std::endl;
50+
}
51+
52+
/*
53+
* ==================================================================================================
54+
*/
55+
56+
void ReadRNTupleSimple()
57+
{
58+
auto reader = RNTupleReader::Open(kNTupleName, kFileName);
59+
60+
const auto nEntries = reader->GetNEntries();
61+
std::cout << "Simple reading, found " << nEntries << " entries" << std::endl;
62+
63+
auto ptrLargeVector = reader->GetModel().GetDefaultEntry().GetPtr<std::vector<std::uint32_t>>(kFieldName);
64+
for (NTupleSize_t i = 0; i < nEntries; i++) {
65+
reader->LoadEntry(i);
66+
67+
const auto vectorSize = ptrLargeVector->size();
68+
uint64_t sum = 0;
69+
for (auto val : *ptrLargeVector)
70+
sum += val;
71+
72+
std::cout << "Size and sum of vector: " << vectorSize << " " << sum << std::endl;
73+
}
74+
std::cout << "RNTuple simple read" << std::endl;
75+
}
76+
77+
/*
78+
* ==================================================================================================
79+
*/
80+
81+
template <class T>
82+
class RStreamingVector {
83+
RNTupleCollectionView fVectorView;
84+
RNTupleView<T> fItemView;
85+
std::unique_ptr<RNTupleClusterRange> fRange;
86+
NTupleSize_t fEntry{0};
87+
NTupleSize_t fSize{0};
88+
89+
public:
90+
class iterator {
91+
RNTupleClusterRange::RIterator fIndex;
92+
RNTupleView<T> &fView;
93+
94+
public:
95+
iterator(RNTupleClusterRange::RIterator index, RNTupleView<T> &view) : fIndex(index), fView(view) {}
96+
~iterator() = default;
97+
98+
iterator operator++(int) /* postfix */ { auto r = *this; ++(*this); return r; }
99+
iterator& operator++() /* prefix */ { ++fIndex; return *this; }
100+
const T& operator* () { return fView.operator()(*fIndex); }
101+
const T* operator->() { return &fView.operator()(*fIndex); }
102+
bool operator==(const iterator& rh) const { return fIndex == rh.fIndex; }
103+
bool operator!=(const iterator& rh) const { return fIndex != rh.fIndex; }
104+
};
105+
106+
RStreamingVector(RNTupleReader &reader, const std::string &fieldName)
107+
: fVectorView(reader.GetCollectionView(fieldName)), fItemView(fVectorView.GetView<T>("_0")) {}
108+
~RStreamingVector() = default;
109+
110+
NTupleSize_t size() const { return fSize; }
111+
112+
iterator begin() { return iterator(fRange->begin(), fItemView); }
113+
iterator end() { return iterator(fRange->end(), fItemView); }
114+
115+
void LoadEntry(NTupleSize_t entry) {
116+
fEntry = entry;
117+
fRange = std::make_unique<RNTupleClusterRange>(fVectorView.GetCollectionRange(fEntry));
118+
fSize = fVectorView.operator()(fEntry);
119+
}
120+
};
121+
122+
void ReadRNTupleStreamingVector()
123+
{
124+
auto reader = RNTupleReader::Open(kNTupleName, kFileName);
125+
126+
const auto nEntries = reader->GetNEntries();
127+
std::cout << "Streamed reading, found " << nEntries << " entries" << std::endl;
128+
129+
RStreamingVector<std::uint32_t> streamingVector(*reader, kFieldName);
130+
for (NTupleSize_t i = 0; i < nEntries; i++) {
131+
streamingVector.LoadEntry(i);
132+
133+
const auto vectorSize = streamingVector.size();
134+
uint64_t sum = 0;
135+
for (auto val : streamingVector)
136+
sum += val;
137+
138+
std::cout << "Size and sum of vector: " << vectorSize << " " << sum << std::endl;
139+
}
140+
std::cout << "RNTuple streaming read" << std::endl;
141+
}
142+
143+
void ntpl015_streaming_vector()
144+
{
145+
CreateRNTuple();
146+
ReadRNTupleSimple();
147+
ReadRNTupleStreamingVector();
148+
}

0 commit comments

Comments
 (0)