Please note that this tutorial has very simplified versions of classes that could be found in a framework, such as DataProduct, FileService, ParallelOutputter, and SerializingOutputter. They try to mimick the usage in a framework (for example, Outputters are agnostic of the data written, which is encapsulated in std::vector<DataProduct>), but are not meant for production usage!
Also note that this tutorial uses std::thread and std::mutex directly instead of a task scheduling library such as Threading Building Blocks (TBB). For that reason, turning on ROOT's implicit multithreading (IMT) would not be very efficient with the simplified code in this tutorial because a thread blocking to acquire a std::mutex cannot "help" the other thread that is currently in the critical section by executing its tasks. If that is wanted, the framework should use synchronization methods provided by TBB directly (which goes beyond the scope of this tutorial).
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <random>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>
using ModelTokensPair = std::pair<std::unique_ptr<RNTupleModel>, std::vector<REntry::RFieldToken>>;
void *address;
};
std::unique_ptr<TFile> fFile;
std::mutex fMutex;
public:
{
fFile.reset(
TFile::Open(std::string(
url).c_str(), std::string(options).c_str()));
}
TFile &GetFile() {
return *fFile; }
std::mutex &GetMutex() { return fMutex; }
};
public:
virtual void InitSlot(
unsigned slot) = 0;
virtual void Fill(
unsigned slot,
const std::vector<DataProduct> &
products) = 0;
};
std::vector<REntry::RFieldToken>
fTokens;
std::unique_ptr<REntry>
entry;
};
public:
const RNTupleWriteOptions &options)
{
}
void InitSlot(
unsigned slot)
final
{
}
}
void Fill(
unsigned slot,
const std::vector<DataProduct> &
products)
final
{
}
RNTupleFillStatus status;
if (status.ShouldFlushCluster()) {
{
}
}
}
};
std::unique_ptr<RNTupleWriter> fWriter;
std::vector<REntry::RFieldToken>
fTokens;
std::unique_ptr<REntry>
entry;
};
public:
const RNTupleWriteOptions &options)
{
}
void InitSlot(
unsigned slot)
final
{
}
fSlots[
slot].entry = fWriter->GetModel().CreateBareEntry();
}
void Fill(
unsigned slot,
const std::vector<DataProduct> &
products)
final
{
}
{
RNTupleFillStatus status;
fWriter->FillNoFlush(
entry, status);
if (status.ShouldFlushCluster()) {
fWriter->FlushColumns();
{
fWriter->FlushCluster();
}
}
}
}
};
float eta;
float mass;
float phi;
};
};
std::vector<ChargedTrack>
muons;
};
{
auto model = RNTupleModel::CreateBare();
std::vector<REntry::RFieldToken>
tokens;
tokens.push_back(model->GetToken(
"eventId"));
model->MakeField<decltype(Event::runId)>("runId");
tokens.push_back(model->GetToken(
"runId"));
model->MakeField<decltype(Event::electrons)>("electrons");
tokens.push_back(model->GetToken(
"electrons"));
model->MakeField<decltype(Event::photons)>("photons");
tokens.push_back(model->GetToken(
"photons"));
model->MakeField<decltype(Event::muons)>("muons");
tokens.push_back(model->GetToken(
"muons"));
return {std::move(model), std::move(
tokens)};
}
{
products.emplace_back(2, &event.electrons);
products.emplace_back(3, &event.photons);
}
struct Run {
std::uint32_t nEvents;
};
{
auto model = RNTupleModel::CreateBare();
std::vector<REntry::RFieldToken>
tokens;
model->MakeField<decltype(Run::runId)>("runId");
tokens.push_back(model->GetToken(
"runId"));
model->MakeField<decltype(Run::nEvents)>("nEvents");
tokens.push_back(model->GetToken(
"nEvents"));
return {std::move(model), std::move(
tokens)};
}
{
}
{
std::uniform_real_distribution<float>
floatDist;
std::uint32_t nEvents = 0;
nEvents =
static_cast<std::uint32_t
>(
nEventsD);
}
for (std::uint32_t eventId = 0; eventId < nEvents; eventId++) {
event.eventId = eventId;
}
}
muon.charge = (gen() % 2 ? 1 : -1);
}
}
Run run;
run.nEvents = nEvents;
}
}
{
RNTupleWriteOptions options;
options.SetUseBufferedWrite(true);
options.SetApproxZippedClusterSize(2 * 1024 * 1024);
options.SetUseBufferedWrite(true);
options.SetApproxZippedClusterSize(1024);
}
}
}
}
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
A context for filling entries (data) into clusters of an RNTuple.
A status object after filling an entry.
The RNTupleModel encapulates the schema of an ntuple.
A writer to fill an RNTuple from multiple contexts.
Common user-tunable settings for storing ntuples.
An RNTuple that gets filled with entries (data) and writes them to storage.
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
double product(double const *factors, std::size_t nFactors)