Skip to content

Commit 997c849

Browse files
committed
Add test for ROOT::RNTupleCardinality projection
Closes #25
1 parent 3c426b3 commit 997c849

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

projections/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Projections
2+
3+
* [`cardinality`](cardinality): `ROOT::RNTupleCardinality`

projections/cardinality/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# `ROOT::RNTupleCardinality`
2+
3+
## Fields
4+
5+
* `[Split]Index{32,64}` of type `std::vector<std::int32_t>` with the corresponding column type for the offset column of the collection parent field
6+
* `[Split]Index{32,64}Cardinality` projected field of type `ROOT::RNTupleCardinality<std::uint{32,64}_t`
7+
8+
## Entries
9+
10+
1. Single-element vectors, with ascending values
11+
2. Empty vectors
12+
3. Increasing number of elements in the vector:
13+
one element in the first field, two elements in the second field, etc.

projections/cardinality/read.C

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include <ROOT/REntry.hxx>
2+
#include <ROOT/RNTupleReader.hxx>
3+
#include <ROOT/RNTupleUtil.hxx>
4+
5+
using ROOT::Experimental::REntry;
6+
using ROOT::Experimental::RNTupleReader;
7+
8+
#include <cstdint>
9+
#include <fstream>
10+
#include <ostream>
11+
#include <string>
12+
#include <string_view>
13+
#include <vector>
14+
15+
using Vector = std::vector<std::int32_t>;
16+
17+
static void PrintVectorValue(const REntry &entry, std::string_view name,
18+
std::ostream &os, bool last = false) {
19+
Vector &value = *entry.GetPtr<Vector>(name);
20+
os << " \"" << name << "\": [";
21+
bool first = true;
22+
for (auto element : value) {
23+
if (first) {
24+
first = false;
25+
} else {
26+
os << ",";
27+
}
28+
os << "\n " << element;
29+
}
30+
if (!value.empty()) {
31+
os << "\n ";
32+
}
33+
os << "]";
34+
if (!last) {
35+
os << ",";
36+
}
37+
os << "\n";
38+
}
39+
40+
template <typename T>
41+
static void PrintCardinality(const REntry &entry, std::string_view name,
42+
std::ostream &os, bool last = false) {
43+
T value = *entry.GetPtr<ROOT::RNTupleCardinality<T>>(name);
44+
os << " \"" << name << "\": " << value;
45+
if (!last) {
46+
os << ",";
47+
}
48+
os << "\n";
49+
}
50+
51+
void read(std::string_view input = "projections.cardinality.root",
52+
std::string_view output = "projections.cardinality.json") {
53+
std::ofstream os(std::string{output});
54+
os << "[\n";
55+
56+
auto reader = RNTupleReader::Open("ntpl", input);
57+
auto &entry = reader->GetModel().GetDefaultEntry();
58+
bool first = true;
59+
for (auto index : *reader) {
60+
reader->LoadEntry(index);
61+
62+
if (first) {
63+
first = false;
64+
} else {
65+
os << ",\n";
66+
}
67+
os << " {\n";
68+
69+
PrintVectorValue(entry, "Index32", os);
70+
PrintCardinality<std::uint32_t>(entry, "Index32Cardinality", os);
71+
PrintVectorValue(entry, "Index64", os);
72+
PrintCardinality<std::uint64_t>(entry, "Index64Cardinality", os);
73+
PrintVectorValue(entry, "SplitIndex32", os);
74+
PrintCardinality<std::uint32_t>(entry, "SplitIndex32Cardinality", os);
75+
PrintVectorValue(entry, "SplitIndex64", os);
76+
PrintCardinality<std::uint64_t>(entry, "SplitIndex64Cardinality", os,
77+
/*last=*/true);
78+
79+
os << " }";
80+
// Newline is intentionally missing, may need to print a comma before the
81+
// next entry.
82+
}
83+
os << "\n";
84+
os << "]\n";
85+
}

projections/cardinality/write.C

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <ROOT/RField.hxx>
2+
#include <ROOT/RNTupleModel.hxx>
3+
#include <ROOT/RNTupleUtil.hxx>
4+
#include <ROOT/RNTupleWriteOptions.hxx>
5+
#include <ROOT/RNTupleWriter.hxx>
6+
7+
using ROOT::Experimental::EColumnType;
8+
using ROOT::Experimental::RField;
9+
using ROOT::Experimental::RNTupleModel;
10+
using ROOT::Experimental::RNTupleWriteOptions;
11+
using ROOT::Experimental::RNTupleWriter;
12+
13+
#include <cstdint>
14+
#include <memory>
15+
#include <string>
16+
#include <string_view>
17+
#include <vector>
18+
19+
using Vector = std::vector<std::int32_t>;
20+
21+
static std::shared_ptr<Vector> MakeVectorField(RNTupleModel &model,
22+
std::string_view name,
23+
EColumnType indexType) {
24+
auto field = std::make_unique<RField<Vector>>(name);
25+
field->SetColumnRepresentatives({{indexType}});
26+
model.AddField(std::move(field));
27+
return model.GetDefaultEntry().GetPtr<Vector>(name);
28+
}
29+
30+
template <typename T>
31+
static void AddProjectedCardinalityField(RNTupleModel &model,
32+
std::string_view name,
33+
std::string_view source) {
34+
auto field = std::make_unique<RField<ROOT::RNTupleCardinality<T>>>(name);
35+
model.AddProjectedField(std::move(field), [&source](const std::string &) {
36+
return std::string{source};
37+
});
38+
}
39+
40+
void write(std::string_view filename = "projections.cardinality.root") {
41+
auto model = RNTupleModel::Create();
42+
43+
// Non-split index encoding
44+
auto Index32 = MakeVectorField(*model, "Index32", EColumnType::kIndex32);
45+
auto Index64 = MakeVectorField(*model, "Index64", EColumnType::kIndex64);
46+
47+
// Split index encoding
48+
auto SplitIndex32 =
49+
MakeVectorField(*model, "SplitIndex32", EColumnType::kSplitIndex32);
50+
auto SplitIndex64 =
51+
MakeVectorField(*model, "SplitIndex64", EColumnType::kSplitIndex64);
52+
53+
// Create RNTupleCardinality projections
54+
AddProjectedCardinalityField<std::uint32_t>(*model, "Index32Cardinality",
55+
"Index32");
56+
AddProjectedCardinalityField<std::uint64_t>(*model, "Index64Cardinality",
57+
"Index64");
58+
AddProjectedCardinalityField<std::uint32_t>(*model, "SplitIndex32Cardinality",
59+
"SplitIndex32");
60+
AddProjectedCardinalityField<std::uint64_t>(*model, "SplitIndex64Cardinality",
61+
"SplitIndex64");
62+
63+
RNTupleWriteOptions options;
64+
options.SetCompression(0);
65+
auto writer =
66+
RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options);
67+
68+
// First entry: single-element vectors, with ascending values
69+
*Index32 = {1};
70+
*Index64 = {2};
71+
*SplitIndex32 = {3};
72+
*SplitIndex64 = {4};
73+
writer->Fill();
74+
75+
// Second entry: empty vectors
76+
*Index32 = {};
77+
*Index64 = {};
78+
*SplitIndex32 = {};
79+
*SplitIndex64 = {};
80+
writer->Fill();
81+
82+
// Third entry: increasing number of elements in the vector
83+
*Index32 = {1};
84+
*Index64 = {2, 3};
85+
*SplitIndex32 = {4, 5, 6};
86+
*SplitIndex64 = {7, 8, 9, 10};
87+
writer->Fill();
88+
}

0 commit comments

Comments
 (0)