Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ntpl020_soa.C File Reference

Detailed Description

View in nbviewer Open in SWAN
Example of RNTuple I/O on collections with a SoA memory layout

RNTuple on-disk collections can be used in struct-of-arrays (SoA) memory layout. An RNTuple SoA class consists of persistent members of type RVec corresponding to and underlying record type, as shown in this tutorial.

NOTE: The RNTuple SoA I/O is still experimental at this point. Functionality and interface are subject to changes.

#include <ROOT/REntry.hxx>
#include <ROOT/RVec.hxx>
#include <TCanvas.h>
#include <TClass.h>
#include <TEllipse.h>
#include <TGraph.h>
#include <TRandom.h>
#include <iostream>
#include <memory>
constexpr const char *kFileName = "ntpl020_soa.root";
constexpr const char *kNTupleName = "ntpl";
// The SoA class for this tutorial. Contains a number of 2D points. All vectors have to have the same length.
// Note that RVecs can adopt memory.
struct PointSoA {
};
// The underlying record type for the SoA class. Members between the SoA class and the underlying record type
// are matched by name. Every member of type `T` in the underlying record type has to be of type `ROOT::RVec<T>` in
// the SoA class.
struct PointRecord {
float fX;
float fY;
};
void Write()
{
// Create a model with a SoA field
model->AddField(ROOT::RFieldBase::Create("points", "PointSoA").Unwrap());
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), kNTupleName, kFileName);
auto entry = writer->GetModel().CreateBareEntry();
for (auto nPoints : {100, 500, 1000, 10000}) {
// We will use our own memory are to store the points
auto memory = std::make_unique<float[]>(nPoints * 2);
// Create random points in the unit square
// Adopt the memory by a PointSoA object. First all x values, then all y values.
entry->BindRawPtr("points", &points);
writer->Fill(*entry);
}
}
void Read()
{
// Show on-disk layout: collection of underlying record type (AoS)
reader->PrintInfo();
// Used to draw the points
auto canvas = new TCanvas("c", "", 1200, 1200);
canvas->Divide(2, 2);
// Read back the points in two steps: first get the size and then read into adopted RVecs.
auto viewSize = reader->GetCollectionView("points");
auto viewSoA = reader->GetView("points", &points, "PointSoA");
for (auto i : reader->GetEntryRange()) {
const auto N = viewSize(i); // size of this entry's SoA collection
auto memory = std::make_unique<float[]>(N * 2);
viewSoA(i);
// Use the raw memory area to draw the points
canvas->cd(i + 1);
auto *graph = new TGraph(N, &memory[0], &memory[N]);
graph->SetTitle((std::to_string(N) + " Points").c_str());
graph->SetMarkerStyle(29);
graph->SetMarkerSize(1);
graph->SetMarkerColor(kRed);
graph->Draw("AP");
auto *circle = new TEllipse(0.5, 0.5, 0.5, 0.5);
circle->SetFillStyle(0);
circle->SetLineColor(kBlue);
circle->SetLineWidth(4);
circle->Draw();
// Use adopted RVec's to approximate PI
points.fX -= 0.5;
points.fY -= 0.5;
auto isInCircle = points.fX * points.fX + points.fY * points.fY < 0.25;
float approxPI = 4.0 * static_cast<float>(hits) / static_cast<float>(N);
std::cout << "Approximated PI with " << N << " points to " << approxPI << std::endl;
}
canvas->Update();
}
{
// Usually, the SoA class dictionary definition would mark it as a SoA class of the corresponding
// underlying record type like this
// #pragma link C++ options=rntupleSoARecord(PointRecord) class PointSoA+;
// For the interpreted classes in this tutorial, we mark the SoA class at runtime:
auto cl = TClass::GetClass("PointSoA");
cl->CreateAttributeMap();
cl->GetAttributeMap()->AddProperty("rntuple.SoARecord", "PointRecord");
Write();
Read();
}
@ kRed
Definition Rtypes.h:67
@ kBlue
Definition Rtypes.h:67
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t points
R__EXTERN TRandom * gRandom
Definition TRandom.h:73
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
static std::unique_ptr< RNTupleModel > CreateBare()
Creates a "bare model", i.e. an RNTupleModel with no default entry.
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.
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1530
The Canvas class.
Definition TCanvas.h:23
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
Draw Ellipses.
Definition TEllipse.h:24
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
SCoord_t fY
Definition TPoint.h:36
SCoord_t fX
Definition TPoint.h:35
virtual void RndmArray(Int_t n, Float_t *array)
Return an array of n random numbers uniformly distributed in ]0,1[.
Definition TRandom.cxx:594
T Sum(const RVec< T > &v, const T zero=T(0))
Sum elements of an RVec.
Definition RVec.hxx:1955
Date
April 2026
Author
The ROOT Team

Definition in file ntpl020_soa.C.