RNTuple supports storing floating points on disk with less precision than their in-memory representation. Under the right circumstances, this can in save storage space while not significantly altering the results of an analysis.
Storing low-precision floats is done by setting their column representation to one of the dedicated column types:
To use these column types in RNTuple, one creates a RField<float> or RField<double> and sets its desired column representation by calling, respectively:
static constexpr char const *kNTupleName = "ntpl";
static constexpr char const *kNTupleFileName = "ntpl018_low_precision_floats.root";
static constexpr int kNEvents = 50;
std::vector<float> fPt;
std::vector<double> fE;
};
static void Write()
{
{
auto fieldReal16 = std::make_unique<ROOT::RField<float>>("myReal16");
fieldReal16->SetHalfPrecision();
model->AddField(std::move(fieldReal16));
}
{
auto fieldReal32Trunc = std::make_unique<ROOT::RField<float>>("myReal32Trunc");
fieldReal32Trunc->SetTruncated(20);
model->AddField(std::move(fieldReal32Trunc));
}
{
auto fieldReal32Quant = std::make_unique<ROOT::RField<float>>("myReal32Quant");
fieldReal32Quant->SetQuantized(24, {-1., 1.});
model->AddField(std::move(fieldReal32Quant));
}
{
auto fieldEvents = std::make_unique<ROOT::RField<Event>>("myEvents");
for (auto &field : *fieldEvents) {
std::cout << "Setting field " << field.GetQualifiedFieldName() << " to truncated.\n";
fldDouble->SetTruncated(16);
std::cout << "Setting field " << field.GetQualifiedFieldName() << " to truncated.\n";
fldFloat->SetTruncated(16);
}
}
model->AddField(std::move(fieldEvents));
}
const auto &entry = model->GetDefaultEntry();
auto myReal16 = entry.GetPtr<float>("myReal16");
auto myReal32Trunc = entry.GetPtr<float>("myReal32Trunc");
auto myReal32Quant = entry.GetPtr<float>("myReal32Quant");
auto myEvents = entry.GetPtr<
Event>(
"myEvents");
for (int i = 0; i < kNEvents; i++) {
myEvents->fPt.push_back(i);
myEvents->fE.push_back(i);
}
}
static void Read()
{
const auto &entry = reader->GetModel().GetDefaultEntry();
auto myReal16 = entry.GetPtr<float>("myReal16");
auto myReal32Trunc = entry.GetPtr<float>("myReal32Trunc");
auto myReal32Quant = entry.GetPtr<float>("myReal32Quant");
auto myEvents = entry.GetPtr<
Event>(
"myEvents");
for (auto idx : reader->GetEntryRange()) {
reader->LoadEntry(idx);
float eventsAvgPt = 0.f;
for (
float pt : myEvents->fPt)
eventsAvgPt /= myEvents->fPt.size();
double eventsAvgE = 0.f;
for (
double e : myEvents->fE)
eventsAvgE /= myEvents->fE.size();
std::cout << "[" << idx << "] Real16: " << *myReal16 << ", Real32Trunc: " << *myReal32Trunc
<< ", Real32Quant: " << *myReal32Quant << ", Events avg pt: " << eventsAvgPt << ", E: " << eventsAvgE
<< "\n";
}
}
void ntpl018_low_precision_floats()
{
Write();
Read();
}
Classes with dictionaries that can be inspected by TClass.
static std::unique_ptr< RNTupleModel > Create()
static std::unique_ptr< RNTupleReader > Open(std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Open an RNTuple for reading.
static std::unique_ptr< RNTupleWriter > Recreate(std::unique_ptr< ROOT::RNTupleModel > model, std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions())
Creates an RNTupleWriter backed by storage, overwriting it if one with the same URI exists.