diff --git a/projections/README.md b/projections/README.md index 172f4af..761ff92 100644 --- a/projections/README.md +++ b/projections/README.md @@ -1,4 +1,6 @@ # Projections * [`cardinality`](cardinality): `ROOT::RNTupleCardinality` + * [`collection`](collection): of collection fields * [`leaf`](leaf): of leaf fields + * [`nested`](nested): projection of nested fields diff --git a/projections/collection/README.md b/projections/collection/README.md new file mode 100644 index 0000000..c68948e --- /dev/null +++ b/projections/collection/README.md @@ -0,0 +1,11 @@ +# Projections of Collection Fields + +## Fields + + * `Vector` of type `std::vector` + * A projected field `Projected` of types `ROOT::RVec` + +## Entries + +1. Ascending values +2. Empty collection diff --git a/projections/collection/read.C b/projections/collection/read.C new file mode 100644 index 0000000..25ebea5 --- /dev/null +++ b/projections/collection/read.C @@ -0,0 +1,67 @@ +#include +#include +#include + +using ROOT::Experimental::REntry; +using ROOT::Experimental::RNTupleReader; + +#include +#include +#include +#include +#include +#include + +template +static void PrintCollectionValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + C &value = *entry.GetPtr(name); + os << " \"" << name << "\": ["; + bool first = true; + for (auto element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n " << element; + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; + if (!last) { + os << ","; + } + os << "\n"; +} + +void read(std::string_view input = "projections.collection.root", + std::string_view output = "projections.collection.json") { + std::ofstream os(std::string{output}); + os << "[\n"; + + auto reader = RNTupleReader::Open("ntpl", input); + auto &entry = reader->GetModel().GetDefaultEntry(); + bool first = true; + for (auto index : *reader) { + reader->LoadEntry(index); + + if (first) { + first = false; + } else { + os << ",\n"; + } + os << " {\n"; + + PrintCollectionValue>(entry, "Vector", os); + PrintCollectionValue>(entry, "Projected", os, + /*last=*/true); + + os << " }"; + // Newline is intentionally missing, may need to print a comma before the + // next entry. + } + os << "\n"; + os << "]\n"; +} diff --git a/projections/collection/write.C b/projections/collection/write.C new file mode 100644 index 0000000..e7a96b8 --- /dev/null +++ b/projections/collection/write.C @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +using ROOT::Experimental::RField; +using ROOT::Experimental::RNTupleModel; +using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::Experimental::RNTupleWriter; + +#include +#include +#include +#include +#include + +void write(std::string_view filename = "projections.collection.root") { + auto model = RNTupleModel::Create(); + + auto Vector = model->MakeField>("Vector"); + auto Projected = + std::make_unique>>("Projected"); + model->AddProjectedField(std::move(Projected), + [](const std::string &fieldName) { + if (fieldName == "Projected") { + return "Vector"; + } else { + return "Vector._0"; + } + }); + + RNTupleWriteOptions options; + options.SetCompression(0); + auto writer = + RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options); + + // First entry: ascending values + *Vector = {1, 2}; + writer->Fill(); + + // Second entry: empty collection + Vector->clear(); + writer->Fill(); +} diff --git a/projections/nested/README.md b/projections/nested/README.md new file mode 100644 index 0000000..1b87330 --- /dev/null +++ b/projections/nested/README.md @@ -0,0 +1,11 @@ +# Projections of Nested Fields + +## Fields + + * `VectorPair` of type `std::vector>` + * `VectorInt` and `VectorFloat` projected fields of types `std::vector` and `std::vector` + +## Entries + +1. Ascending values +2. Empty collection diff --git a/projections/nested/read.C b/projections/nested/read.C new file mode 100644 index 0000000..2395788 --- /dev/null +++ b/projections/nested/read.C @@ -0,0 +1,93 @@ +#include +#include +#include + +using ROOT::Experimental::REntry; +using ROOT::Experimental::RNTupleReader; + +#include +#include +#include +#include +#include +#include +#include + +template static void PrintValue(const T &value, std::ostream &os); + +template <> void PrintValue(const std::int32_t &value, std::ostream &os) { + os << value; +} + +template <> void PrintValue(const float &value, std::ostream &os) { + os << "\"" << value << "\""; +} + +template <> +void PrintValue(const std::pair &value, std::ostream &os) { + os << "[\n"; + os << " "; + PrintValue(value.first, os); + os << ",\n"; + os << " "; + PrintValue(value.second, os); + os << "\n"; + os << " ]"; +} + +template +static void PrintVectorValue(const REntry &entry, std::string_view name, + std::ostream &os, bool last = false) { + auto &value = *entry.GetPtr>(name); + os << " \"" << name << "\": ["; + bool first = true; + for (auto element : value) { + if (first) { + first = false; + } else { + os << ","; + } + os << "\n "; + PrintValue(element, os); + } + if (!value.empty()) { + os << "\n "; + } + os << "]"; + if (!last) { + os << ","; + } + os << "\n"; +} + +void read(std::string_view input = "projections.nested.root", + std::string_view output = "projections.nested.json") { + std::ofstream os(std::string{output}); + // Print floating-point numbers as hexadecimal literals. + os << std::hexfloat; + os << "[\n"; + + auto reader = RNTupleReader::Open("ntpl", input); + auto &entry = reader->GetModel().GetDefaultEntry(); + bool first = true; + for (auto index : *reader) { + reader->LoadEntry(index); + + if (first) { + first = false; + } else { + os << ",\n"; + } + os << " {\n"; + + PrintVectorValue>(entry, "VectorPair", os); + PrintVectorValue(entry, "VectorInt", os); + PrintVectorValue(entry, "VectorFloat", os, /*last=*/true); + + os << " }"; + // Newline is intentionally missing, may need to print a comma before the + // next entry. + } + os << "\n"; + os << "]\n"; +} diff --git a/projections/nested/write.C b/projections/nested/write.C new file mode 100644 index 0000000..39ae6e5 --- /dev/null +++ b/projections/nested/write.C @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +using ROOT::Experimental::RField; +using ROOT::Experimental::RNTupleModel; +using ROOT::Experimental::RNTupleWriteOptions; +using ROOT::Experimental::RNTupleWriter; + +#include +#include +#include +#include +#include +#include + +template +static void AddProjectedField(RNTupleModel &model, std::string_view name, + std::string_view source) { + auto field = std::make_unique>>(name); + model.AddProjectedField(std::move(field), + [&name, &source](const std::string &fieldName) { + if (fieldName == name) { + return std::string("VectorPair"); + } else { + return "VectorPair._0." + std::string(source); + } + }); +} + +void write(std::string_view filename = "projections.nested.root") { + auto model = RNTupleModel::Create(); + + auto VectorPair = + model->MakeField>>( + "VectorPair"); + AddProjectedField(*model, "VectorInt", "_0"); + AddProjectedField(*model, "VectorFloat", "_1"); + + RNTupleWriteOptions options; + options.SetCompression(0); + auto writer = + RNTupleWriter::Recreate(std::move(model), "ntpl", filename, options); + + // First entry: ascending values + VectorPair->emplace_back(1, 2.0); + VectorPair->emplace_back(3, 4.0); + writer->Fill(); + + // Second entry: empty collection + VectorPair->clear(); + writer->Fill(); +}