Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
RNTupleProcessor.cxx
Go to the documentation of this file.
1/// \file RNTupleProcessor.cxx
2/// \ingroup NTuple ROOT7
3/// \author Florine de Geus <florine.de.geus@cern.ch>
4/// \date 2024-03-26
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
17
18#include <ROOT/RFieldBase.hxx>
19#include <ROOT/RNTuple.hxx>
21
22#include <TDirectory.h>
23
24std::unique_ptr<ROOT::Experimental::Internal::RPageSource> ROOT::Experimental::RNTupleOpenSpec::CreatePageSource() const
25{
26 if (const std::string *storagePath = std::get_if<std::string>(&fStorage))
28
29 auto dir = std::get<TDirectory *>(fStorage);
30 auto ntuple = std::unique_ptr<ROOT::RNTuple>(dir->Get<ROOT::RNTuple>(fNTupleName.c_str()));
32}
33
34std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
35ROOT::Experimental::RNTupleProcessor::Create(RNTupleOpenSpec ntuple, std::unique_ptr<ROOT::RNTupleModel> model)
36{
37 auto processorName = ntuple.fNTupleName;
38 return Create(std::move(ntuple), processorName, std::move(model));
39}
40
41std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
43 std::unique_ptr<ROOT::RNTupleModel> model)
44{
45 return std::unique_ptr<RNTupleSingleProcessor>(
46 new RNTupleSingleProcessor(std::move(ntuple), processorName, std::move(model)));
47}
48
49std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
51 std::unique_ptr<ROOT::RNTupleModel> model)
52{
53 if (ntuples.empty())
54 throw RException(R__FAIL("at least one RNTuple must be provided"));
55
56 auto processorName = ntuples[0].fNTupleName;
57 return CreateChain(std::move(ntuples), processorName, std::move(model));
58}
59
60std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
61ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<RNTupleOpenSpec> ntuples, std::string_view processorName,
62 std::unique_ptr<ROOT::RNTupleModel> model)
63{
64 if (ntuples.empty())
65 throw RException(R__FAIL("at least one RNTuple must be provided"));
66
67 std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors;
68 innerProcessors.reserve(ntuples.size());
69
70 // If no model is provided, infer it from the first ntuple.
71 if (!model) {
72 auto firstPageSource = ntuples[0].CreatePageSource();
73 firstPageSource->Attach();
74 model = firstPageSource->GetSharedDescriptorGuard()->CreateModel();
75 }
76
77 for (auto &ntuple : ntuples) {
78 innerProcessors.emplace_back(Create(std::move(ntuple), model->Clone()));
79 }
80
81 return CreateChain(std::move(innerProcessors), processorName, std::move(model));
82}
83
84std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
85ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
86 std::unique_ptr<ROOT::RNTupleModel> model)
87{
88 if (innerProcessors.empty())
89 throw RException(R__FAIL("at least one inner processor must be provided"));
90
91 auto processorName = innerProcessors[0]->GetProcessorName();
92 return CreateChain(std::move(innerProcessors), processorName, std::move(model));
93}
94
95std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
96ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
97 std::string_view processorName,
98 std::unique_ptr<ROOT::RNTupleModel> model)
99{
100 if (innerProcessors.empty())
101 throw RException(R__FAIL("at least one inner processor must be provided"));
102
103 // If no model is provided, infer it from the first inner processor.
104 if (!model) {
105 model = innerProcessors[0]->GetModel().Clone();
106 }
107
108 return std::unique_ptr<RNTupleChainProcessor>(
109 new RNTupleChainProcessor(std::move(innerProcessors), processorName, std::move(model)));
110}
111
112std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
114 const std::vector<RNTupleOpenSpec> &auxNTuples,
115 const std::vector<std::string> &joinFields,
116 std::unique_ptr<ROOT::RNTupleModel> primaryModel,
117 std::vector<std::unique_ptr<ROOT::RNTupleModel>> auxModels)
118{
119 return CreateJoin(primaryNTuple, auxNTuples, joinFields, primaryNTuple.fNTupleName, std::move(primaryModel),
120 std::move(auxModels));
121}
122
123std::unique_ptr<ROOT::Experimental::RNTupleProcessor> ROOT::Experimental::RNTupleProcessor::CreateJoin(
124 const RNTupleOpenSpec &primaryNTuple, const std::vector<RNTupleOpenSpec> &auxNTuples,
125 const std::vector<std::string> &joinFields, std::string_view processorName,
126 std::unique_ptr<ROOT::RNTupleModel> primaryModel, std::vector<std::unique_ptr<ROOT::RNTupleModel>> auxModels)
127{
128 if (!auxModels.empty() && auxModels.size() != auxNTuples.size())
129 throw RException(R__FAIL("number of auxiliary models and auxiliary RNTuples does not match"));
130
131 if (joinFields.size() > 4) {
132 throw RException(R__FAIL("a maximum of four join fields is allowed"));
133 }
134
135 if (std::set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
136 throw RException(R__FAIL("join fields must be unique"));
137 }
138
139 // Ensure that all ntuples are uniquely named to prevent name clashes.
140 // TODO(fdegeus) allow for the provision of aliases for ntuples with the same name, removing the constraint of
141 // uniquely-named ntuples.
142 std::unordered_set<std::string> uniqueNTupleNames{primaryNTuple.fNTupleName};
143 for (const auto &ntuple : auxNTuples) {
144 auto res = uniqueNTupleNames.emplace(ntuple.fNTupleName);
145 if (!res.second) {
146 throw ROOT::RException(R__FAIL("joining RNTuples with the same name is not allowed"));
147 }
148 }
149
150 std::unique_ptr<RNTupleJoinProcessor> processor = std::unique_ptr<RNTupleJoinProcessor>(new RNTupleJoinProcessor(
152
153 processor->SetJoinFieldTokens(joinFields);
154 processor->ConnectFields();
155
156 return processor;
157}
158
161{
162 pageSource.Attach();
163 auto desc = pageSource.GetSharedDescriptorGuard();
164
165 const auto fieldId = desc->FindFieldId(fieldContext.GetProtoField().GetFieldName());
167 throw RException(
168 R__FAIL("field \"" + fieldContext.GetProtoField().GetFieldName() + "\" not found in current RNTuple"));
169 }
170
171 fieldContext.SetConcreteField();
172 fieldContext.fConcreteField->SetOnDiskId(fieldId);
174
175 auto valuePtr = entry.GetPtr<void>(fieldContext.fToken);
176 auto value = fieldContext.fConcreteField->BindValue(valuePtr);
177 entry.UpdateValue(fieldContext.fToken, value);
178}
179
180//------------------------------------------------------------------------------
181
183 std::string_view processorName,
184 std::unique_ptr<ROOT::RNTupleModel> model)
185 : RNTupleProcessor(processorName, std::move(model)), fNTupleSpec(std::move(ntuple))
186{
187 if (!fModel) {
189 fPageSource->Attach();
190 fModel = fPageSource->GetSharedDescriptorGuard()->CreateModel();
191 }
192
193 fModel->Freeze();
194 fEntry = fModel->CreateEntry();
195
196 for (const auto &value : *fEntry) {
197 auto &field = value.GetField();
198 auto token = fEntry->GetToken(field.GetFieldName());
199
200 // If the model has a default entry, use the value pointers from the entry in the entry managed by the
201 // processor. This way, the pointers returned by RNTupleModel::MakeField can be used in the processor loop
202 // to access the corresponding field values.
203 if (!fModel->IsBare()) {
204 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(token);
205 fEntry->BindValue(token, valuePtr);
206 }
207
208 auto fieldContext = RFieldContext(field.Clone(field.GetFieldName()), token);
209 fFieldContexts.try_emplace(field.GetFieldName(), std::move(fieldContext));
210 }
211}
212
214{
215 Connect();
216
217 if (entryNumber >= fNEntries)
218 return kInvalidNTupleIndex;
219
220 fEntry->Read(entryNumber);
221
222 fNEntriesProcessed++;
223 fCurrentEntryNumber = entryNumber;
224 return entryNumber;
225}
226
228{
229 for (const auto &value : *fEntry) {
230 auto &field = value.GetField();
231 auto valuePtr = entry.GetPtr<void>(field.GetQualifiedFieldName());
232
233 fEntry->BindValue(field.GetQualifiedFieldName(), valuePtr);
234 }
235}
236
238{
239 // The processor has already been connected.
240 if (fNEntries != kInvalidNTupleIndex)
241 return;
242
243 if (!fPageSource)
244 fPageSource = fNTupleSpec.CreatePageSource();
245 fPageSource->Attach();
246 fNEntries = fPageSource->GetNEntries();
247
248 for (auto &[_, fieldContext] : fFieldContexts) {
249 ConnectField(fieldContext, *fPageSource, *fEntry);
250 }
251}
252
253//------------------------------------------------------------------------------
254
256 std::vector<std::unique_ptr<RNTupleProcessor>> processors, std::string_view processorName,
257 std::unique_ptr<ROOT::RNTupleModel> model)
258 : RNTupleProcessor(processorName, std::move(model)), fInnerProcessors(std::move(processors))
259{
261
262 fModel->Freeze();
263 fEntry = fModel->CreateEntry();
264
265 for (const auto &value : *fEntry) {
266 auto &field = value.GetField();
267 auto token = fEntry->GetToken(field.GetQualifiedFieldName());
268
269 // If the model has a default entry, use the value pointers from the entry in the entry managed by the
270 // processor. This way, the pointers returned by RNTupleModel::MakeField can be used in the processor loop
271 // to access the corresponding field values.
272 if (!fModel->IsBare()) {
273 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(token);
274 fEntry->BindValue(token, valuePtr);
275 }
276 }
277
278 for (auto &innerProc : fInnerProcessors) {
279 innerProc->SetEntryPointers(*fEntry);
280 }
281}
282
284{
285 if (fNEntries == kInvalidNTupleIndex) {
286 fNEntries = 0;
287
288 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
289 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
290 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
291 }
292
293 fNEntries += fInnerNEntries[i];
294 }
295 }
296
297 return fNEntries;
298}
299
301{
302 for (const auto &value : *fEntry) {
303 auto &field = value.GetField();
304 auto valuePtr = entry.GetPtr<void>(field.GetQualifiedFieldName());
305
306 fEntry->BindValue(field.GetQualifiedFieldName(), valuePtr);
307 }
308
309 for (auto &innerProc : fInnerProcessors) {
310 innerProc->SetEntryPointers(*fEntry);
311 }
312}
313
315{
317 size_t currProcessor = 0;
318
319 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
320 // of entries in this processor and try with the next processor until we find the correct local entry number.
321 while (fInnerProcessors[currProcessor]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
322 if (fInnerNEntries[currProcessor] == kInvalidNTupleIndex) {
323 fInnerNEntries[currProcessor] = fInnerProcessors[currProcessor]->GetNEntries();
324 }
325
326 localEntryNumber -= fInnerNEntries[currProcessor];
327
328 // The provided global entry number is larger than the number of available entries.
329 if (++currProcessor >= fInnerProcessors.size())
330 return kInvalidNTupleIndex;
331 }
332
333 if (currProcessor != fCurrentProcessorNumber)
334 fCurrentProcessorNumber = currProcessor;
335
336 fNEntriesProcessed++;
337 fCurrentEntryNumber = entryNumber;
338 return entryNumber;
339}
340
341//------------------------------------------------------------------------------
342
344 const RNTupleOpenSpec &mainNTuple, const std::vector<RNTupleOpenSpec> &auxNTuples,
345 const std::vector<std::string> &joinFields, std::string_view processorName,
346 std::unique_ptr<ROOT::RNTupleModel> primaryModel, std::vector<std::unique_ptr<ROOT::RNTupleModel>> auxModels)
348{
349 fNTuples.emplace_back(mainNTuple);
350 fNTuples.insert(fNTuples.end(), auxNTuples.begin(), auxNTuples.end());
351
352 fPageSource = mainNTuple.CreatePageSource();
353 fPageSource->Attach();
354
355 if (fPageSource->GetNEntries() == 0) {
356 throw RException(R__FAIL("provided RNTuple is empty"));
357 }
358
359 fNEntries = fPageSource->GetNEntries();
360
361 for (const auto &auxNTuple : auxNTuples) {
362 fAuxiliaryPageSources.emplace_back(auxNTuple.CreatePageSource());
363 if (!joinFields.empty())
365 }
366
367 if (!primaryModel)
368 primaryModel = fPageSource->GetSharedDescriptorGuard()->CreateModel();
369 if (auxModels.empty()) {
370 auxModels.resize(fAuxiliaryPageSources.size());
371 }
372 for (unsigned i = 0; i < fAuxiliaryPageSources.size(); ++i) {
373 if (!auxModels[i]) {
374 fAuxiliaryPageSources[i]->Attach();
375 auxModels[i] = fAuxiliaryPageSources[i]->GetSharedDescriptorGuard()->CreateModel();
376 }
377 }
378
379 SetModel(std::move(primaryModel), std::move(auxModels));
380
381 fModel->Freeze();
382 fEntry = fModel->CreateEntry();
383
384 for (const auto &value : *fEntry) {
385 auto &field = value.GetField();
386 const auto &fieldName = field.GetQualifiedFieldName();
387
388 // If the model provided by the user has a default entry, use the value pointers from the default entry of the
389 // model that was passed to this constructor. This way, the pointers returned by RNTupleModel::MakeField can be
390 // used in the processor loop to access the corresponding field values.
391 if (!fModel->IsBare()) {
392 auto valuePtr = fModel->GetDefaultEntry().GetPtr<void>(fieldName);
393 fEntry->BindValue(fieldName, valuePtr);
394 }
395
396 auto auxNTupleName = std::find_if(auxNTuples.cbegin(), auxNTuples.cend(), [&fieldName](const RNTupleOpenSpec &n) {
397 return fieldName.substr(0, n.fNTupleName.size()) == n.fNTupleName;
398 });
399
400 // If the current field name does not begin with the name of one of the auxiliary ntuples, we are dealing with a
401 // field from the primary ntuple, so it can be added as a field context. Otherwise, if it does begin with the
402 // name, but is not equal to just the name (e.g. it is a subfield of `auxNTupleName`, which means it is a proper
403 // field in the corresponding auxiliary ntuple) we also need to add it as a field context. If it is exactly equal
404 // to an auxiliary ntuple name, it is the untyped record field containing the auxiliary fields itself. This one we
405 // don't want to add as a field context, because there is nothing to read from.
406 // TODO(fdegeus) handle the case where a primary field has the name of an auxiliary ntuple.
407 if (auxNTupleName == auxNTuples.end()) {
408 fFieldContexts.try_emplace(fieldName, field.Clone(field.GetFieldName()), fEntry->GetToken(fieldName));
409 } else if (fieldName != auxNTupleName->fNTupleName) {
410 // Add 1 because we also have to take into account the primary ntuple.
411 auto ntupleIdx = std::distance(auxNTuples.begin(), auxNTupleName) + 1;
412 fFieldContexts.try_emplace(fieldName, field.Clone(field.GetFieldName()), fEntry->GetToken(fieldName),
413 ntupleIdx);
414 }
415 }
416}
417
419 std::vector<std::unique_ptr<ROOT::RNTupleModel>> auxModels)
420{
421 fModel = std::move(primaryModel);
422 fModel->Unfreeze();
423
424 // Create an anonymous record field for each auxiliary ntuple, containing their top-level fields. These original
425 // top-level fields are registered as subfields in the join model, such that they can be accessed as
426 // `auxNTupleName.fieldName`.
427 for (unsigned i = 0; i < auxModels.size(); ++i) {
428 std::vector<std::unique_ptr<ROOT::RFieldBase>> auxFields;
429 auxFields.reserve(auxModels[i]->GetFieldNames().size());
430
431 for (const auto &fieldName : auxModels[i]->GetFieldNames()) {
432 auxFields.emplace_back(auxModels[i]->GetConstField(fieldName).Clone(fieldName));
433 }
434
435 auto auxParentField = std::make_unique<ROOT::RRecordField>(fNTuples[i + 1].fNTupleName, std::move(auxFields));
436 const auto &subFields = auxParentField->GetConstSubfields();
437 fModel->AddField(std::move(auxParentField));
438
439 for (const auto &field : subFields) {
440 fModel->RegisterSubfield(field->GetQualifiedFieldName());
441 }
442
443 // If the model has a default entry, adopt its value pointers. This way, the pointers returned by
444 // RNTupleModel::MakeField can be used in the processor loop to access the corresponding field values.
445 if (!auxModels[i]->IsBare()) {
446 const auto &auxDefaultEntry = auxModels[i]->GetDefaultEntry();
447 auto &joinDefaultEntry = fModel->GetDefaultEntry();
448 for (const auto &fieldName : auxModels[i]->GetFieldNames()) {
449 auto valuePtr = auxDefaultEntry.GetPtr<void>(fieldName);
450 joinDefaultEntry.BindValue(fNTuples[i + 1].fNTupleName + "." + fieldName, valuePtr);
451 }
452 }
453 }
454
455 fModel->Freeze();
456}
457
459{
460 for (auto &[_, fieldContext] : fFieldContexts) {
462 fieldContext.IsAuxiliary() ? *fAuxiliaryPageSources.at(fieldContext.fNTupleIdx - 1) : *fPageSource;
463 ConnectField(fieldContext, pageSource, *fEntry);
464 }
465}
466
468{
469 for (const auto &[_, fieldContext] : fFieldContexts) {
470 auto fieldName = fieldContext.GetProtoField().GetQualifiedFieldName();
471 if (fieldContext.IsAuxiliary()) {
472 fieldName = fNTuples[fieldContext.fNTupleIdx].fNTupleName + "." + fieldName;
473 }
474 auto valuePtr = entry.GetPtr<void>(fieldName);
475 fEntry->BindValue(fieldName, valuePtr);
476 }
477}
478
480{
481 if (entryNumber >= fPageSource->GetNEntries())
483
484 // Read the values of the primary ntuple. If no join table is used (i.e., the join is aligned), also read the values
485 // of auxiliary ntuples.
486 for (const auto &[_, fieldContext] : fFieldContexts) {
487 if (!fieldContext.IsAuxiliary() || !HasJoinTable()) {
488 auto &value = fEntry->GetValue(fieldContext.fToken);
489 value.Read(entryNumber);
490 }
491 }
492
493 fCurrentEntryNumber = entryNumber;
494 fNEntriesProcessed++;
495
496 // If no join table is used (i.e., the join is aligned), there's nothing left to do.
497 if (!HasJoinTable())
498 return entryNumber;
499
500 // First build the join tables if this hasn't been done yet.
501 if (!fJoinTablesAreBuilt) {
502 for (unsigned i = 0; i < fJoinTables.size(); ++i) {
503 fJoinTables[i]->Add(*fAuxiliaryPageSources[i]);
504 }
505
506 fJoinTablesAreBuilt = true;
507 }
508
509 // Collect the values of the join fields for this entry.
510 std::vector<void *> valPtrs;
511 valPtrs.reserve(fJoinFieldTokens.size());
512 for (const auto &token : fJoinFieldTokens) {
513 auto ptr = fEntry->GetPtr<void>(token);
514 valPtrs.push_back(ptr.get());
515 }
516
517 // Find the entry index corresponding to the join field values for each auxiliary ntuple.
518 std::vector<ROOT::NTupleSize_t> auxEntryIdxs;
519 auxEntryIdxs.reserve(fJoinTables.size());
520 for (const auto &joinTable : fJoinTables) {
521 auto entryIdxs = joinTable->GetEntryIndexes(valPtrs);
522
523 if (entryIdxs.empty())
525 else
526 auxEntryIdxs.push_back(entryIdxs[0]);
527 }
528
529 // For each auxiliary field, load its value according to the entry number we just found of the ntuple it belongs to.
530 for (const auto &[_, fieldContext] : fFieldContexts) {
531 if (!fieldContext.IsAuxiliary())
532 continue;
533
534 auto &value = fEntry->GetValue(fieldContext.fToken);
535 if (auxEntryIdxs[fieldContext.fNTupleIdx - 1] == ROOT::kInvalidNTupleIndex) {
536 // No matching entry exists, so we reset the field's value to a default value.
537 // TODO(fdegeus): further consolidate how non-existing join matches should be handled. N.B.: in case
538 // ConstructValue is not used anymore in the future, remove friend in ROOT::RFieldBase.
539 fieldContext.fProtoField->ConstructValue(value.GetPtr<void>().get());
540 } else {
541 value.Read(auxEntryIdxs[fieldContext.fNTupleIdx - 1]);
542 }
543 }
544
545 return entryNumber;
546}
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:299
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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 value
#define _(A, B)
Definition cfortran.h:108
static std::unique_ptr< RNTupleJoinTable > Create(const std::vector< std::string > &joinFieldNames)
Create an RNTupleJoinTable from an existing RNTuple.
static std::unique_ptr< RPageSourceFile > CreateFromAnchor(const RNTuple &anchor, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Used from the RNTuple class to build a datasource if the anchor is already available.
Abstract interface to read data from an ntuple.
static std::unique_ptr< RPageSource > Create(std::string_view ntupleName, std::string_view location, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Guess the concrete derived page source from the file name (location)
Processor specialization for vertically combined (chained) RNTupleProcessors.
void SetEntryPointers(const ROOT::REntry &) final
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
std::vector< ROOT::NTupleSize_t > fInnerNEntries
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
std::vector< std::unique_ptr< RNTupleProcessor > > fInnerProcessors
Processor specialization for horizontally combined (joined) RNTuples.
void SetEntryPointers(const ROOT::REntry &) final
std::vector< std::unique_ptr< Internal::RPageSource > > fAuxiliaryPageSources
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided entry number of the primary RNTuple.
void SetModel(std::unique_ptr< ROOT::RNTupleModel > primaryModel, std::vector< std::unique_ptr< ROOT::RNTupleModel > > auxModels)
Set fModel by combining the primary and auxiliary models.
void ConnectFields()
Connect all fields, once the primary and all auxiliary RNTuples have been added.
std::vector< std::unique_ptr< Internal::RNTupleJoinTable > > fJoinTables
Specification of the name and location of an RNTuple, used for creating a new RNTupleProcessor.
std::variant< std::string, TDirectory * > fStorage
std::unique_ptr< Internal::RPageSource > CreatePageSource() const
Manager for a field as part of the RNTupleProcessor.
Interface for iterating over entries of RNTuples and vertically concatenated RNTuples (chains).
std::unique_ptr< ROOT::REntry > fEntry
std::unique_ptr< ROOT::RNTupleModel > fModel
static std::unique_ptr< RNTupleProcessor > Create(RNTupleOpenSpec ntuple, std::unique_ptr< ROOT::RNTupleModel > model=nullptr)
Create an RNTupleProcessor for a single RNTuple.
ROOT::NTupleSize_t fNEntries
Total number of entries.
static std::unique_ptr< RNTupleProcessor > CreateJoin(const RNTupleOpenSpec &primaryNTuple, const std::vector< RNTupleOpenSpec > &auxNTuples, const std::vector< std::string > &joinFields, std::unique_ptr< ROOT::RNTupleModel > primaryModel=nullptr, std::vector< std::unique_ptr< ROOT::RNTupleModel > > auxModels={})
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
std::unordered_map< std::string, RFieldContext > fFieldContexts
Maps the (qualified) field name to its corresponding field context.
void ConnectField(RFieldContext &fieldContext, Internal::RPageSource &pageSource, ROOT::REntry &entry)
Create and connect a concrete field to the current page source, based on its proto field.
std::unique_ptr< Internal::RPageSource > fPageSource
static std::unique_ptr< RNTupleProcessor > CreateChain(std::vector< RNTupleOpenSpec > ntuples, std::unique_ptr< ROOT::RNTupleModel > model=nullptr)
Create an RNTupleProcessor for a chain (i.e., a vertical combination) of RNTuples.
std::vector< RNTupleOpenSpec > fNTuples
Processor specialization for processing a single RNTuple.
void SetEntryPointers(const ROOT::REntry &entry) final
void Connect()
Connect the page source of the underlying RNTuple.
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition REntry.hxx:56
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:69
const_iterator begin() const
const_iterator end() const
const Int_t n
Definition legend1.C:16
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Experimental::Internal::RPageSource &)
constexpr NTupleSize_t kInvalidNTupleIndex
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId