ATLAS Offline Software
Loading...
Searching...
No Matches
REvent.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3// Local include(s).
5
6#include "IOUtils.h"
16
17// Framework include(s).
26
27// ROOT include(s).
28#include <TFile.h>
29#include <TKey.h>
30#include <TMethodCall.h>
31
32#include <ROOT/RNTuple.hxx>
33
34// System include(s).
35#include <regex>
36#include <stdexcept>
37#include <typeinfo>
38#include <utility>
39
40namespace {
41
51std::string getFirstFieldMatch(ROOT::RNTupleReader& reader,
52 const std::string& pre) {
53
54 const std::regex pattern(".*" + pre + ".*");
55 for (const auto& field : reader.GetDescriptor().GetTopLevelFields()) {
56
57 if (std::regex_match(field.GetFieldName(), pattern)) {
58 return field.GetFieldName();
59 }
60 }
61
62 return pre;
63}
64
65} // namespace
66
68
69// Initialise some static data.
70static const char* const EVENT_NTUPLE_NAME = "EventData";
71static const char* const METADATA_NTUPLE_NAME = "MetaData";
72
73REvent::REvent() : Event("xAOD::Experimental::REvent") {}
74
76
77 // Clear the input and output objects before the input/output files would be
78 // closed. Otherwise we can be left with RNTuple view objects pointing
79 // nowhere.
80 m_inputObjects.clear();
81 m_outputObjects.clear();
82}
83
90StatusCode REvent::readFrom(std::string_view fileName) {
91
92 ATH_MSG_INFO("REvent::readFrom: fileName " << fileName);
93
94
95 // Clear the cached input objects.
96 m_inputObjects.clear();
98 m_inputMetaObjects.clear();
99 {
101 lock.upgrade();
102 m_branches.clear();
103 }
104 m_eventReader.reset();
105
106 // Reset the internal flags.
107 m_entry = -1;
109
110 // Clear out the current object.
112
113
114 ATH_MSG_DEBUG("Create RNTupleReader for \"" << METADATA_NTUPLE_NAME
115 << "\" in file: " << fileName);
116
117
118 // Set up a reader for the metadata ntuple.
119 // Since some types are non-xAOD types and so not 'visible' when running in AnalysisBase
120 // we need to protect for unknown types with SetEmulateUnknownTypes(true)
121 ROOT::RNTupleDescriptor::RCreateModelOptions opts;
122 opts.SetEmulateUnknownTypes(true);
123 m_metaReader = ROOT::RNTupleReader::Open(opts, METADATA_NTUPLE_NAME, fileName);
124 if (!m_metaReader) {
125 ATH_MSG_ERROR("Couldn't find \"" << METADATA_NTUPLE_NAME
126 << "\" tree in input file: " << fileName);
127 return StatusCode::FAILURE;
128 }
129 ATH_MSG_DEBUG("Created RNTupleReader for \"" << METADATA_NTUPLE_NAME
130 << "\" in file: " << fileName);
131
132 // Make sure that the xAOD::EventFormat dictonary is loaded.
133 // This may not be the case if streamer information reading is turned
134 // off.
135 static const std::string eventFormatTypeName =
137 if (::TClass::GetClass(eventFormatTypeName.c_str()) == nullptr) {
138 ATH_MSG_WARNING("Couldn't load the EventFormat dictionary");
139 }
140 ATH_MSG_VERBOSE("Loaded the xAOD::EventFormat dictionary");
141
142 // Helper lambda for collecting the event format metadata from an RNTuple
143 // with a given name.
144 auto readEventFormatMetadata = [&](std::string_view tupleName) -> StatusCode {
145 // Set up a reader. This may technically be the same as m_metaReader, but
146 // it's easier to write the code this way.
147 auto metaReader = ROOT::RNTupleReader::Open(tupleName, fileName);
148 if (!metaReader) {
149 ATH_MSG_ERROR("Couldn't find \""
150 << tupleName << "\" ntuple in input file: " << fileName);
151 return StatusCode::FAILURE;
152 }
153 ATH_MSG_VERBOSE("Created temporary RNTupleReader for \""
154 << tupleName << "\" in file: " << fileName);
155
156 // Try to read in the event format metadata.
157 const std::string eventFormatFieldName =
158 getFirstFieldMatch(*m_metaReader, "EventFormat");
159 try {
160 // Add its elements to m_inputEventFormat.
161 auto ef = m_metaReader->GetView<xAOD::EventFormat>(eventFormatFieldName);
162 for (const auto& [key, element] : ef(0u)) {
163 m_inputEventFormat.add(element);
164 }
165 } catch (const ROOT::RException&) {
166 ATH_MSG_WARNING("Input file provides no event or metadata");
167 return StatusCode::RECOVERABLE;
168 }
169 ATH_MSG_VERBOSE("Merged event format metadata from \"" << tupleName
170 << "\" ntuple");
171
172 // Return gracefully.
173 return StatusCode::SUCCESS;
174 };
175
176 // Read in the metadata from the "main" metadata ntuple.
177 const StatusCode sc = readEventFormatMetadata(METADATA_NTUPLE_NAME);
178 if (sc.isRecoverable()) {
180 return StatusCode::SUCCESS;
181 }
182 ATH_CHECK(sc);
183
184 // List all the other Metadata RNTuples in the input file.
185 // Having several metadata tuples can happen for augmented files
186 // as one metadata tree per stream is produced.
187 std::set<std::string> lOtherMetaTupleNames;
188 {
189 std::unique_ptr<TFile> inFile(TFile::Open(fileName.data(), "READ"));
190 TList* lKeys = inFile->GetListOfKeys();
191 if (lKeys == nullptr) {
192 ATH_MSG_ERROR("Could not get list of keys for input file: " << fileName);
193 return StatusCode::FAILURE;
194 }
195 for (const TObject* obj : *lKeys) {
196 const std::string keyName = obj->GetName();
197 // Make sure the key corresponds to a metadata ntuple but
198 // do not add the current metadata tree in the list of other trees
199 // and do not add the metadata tree handlers to the list
200 if ((keyName != METADATA_NTUPLE_NAME) &&
201 (keyName.find("MetaData") != std::string::npos) &&
202 (keyName.find("MetaDataHdr") == std::string::npos)) {
203 // Make sure key corresponds to an RNTuple
204 const TKey* key = dynamic_cast<const TKey*>(obj);
205 if (key == nullptr) {
206 ATH_MSG_ERROR("Object describing \"" << keyName << "\" in file \""
207 << fileName
208 << "\" is not a TKey?");
209 return StatusCode::FAILURE;
210 }
211 const char* className = key->GetClassName();
212 static constexpr bool LOAD = kFALSE;
213 static constexpr bool SILENT = kTRUE;
214 ::TClass* cl = ::TClass::GetClass(className, LOAD, SILENT);
215 if ((cl != nullptr) && cl->InheritsFrom(ROOT::RNTuple::Class())) {
216 lOtherMetaTupleNames.insert(std::move(keyName));
217 }
218 }
219 }
220 }
221
222 // Read in the metadata from any additonal NTuples found (if any).
223 for (const std::string& tupleName : lOtherMetaTupleNames) {
224 ATH_CHECK(readEventFormatMetadata(tupleName));
225 }
226
227 // Set up the main ntuple reader.
228 m_eventReader = ROOT::RNTupleReader::Open(EVENT_NTUPLE_NAME, fileName);
229 if (!m_eventReader) {
230 ATH_MSG_ERROR("Couldn't access RNTuple \"" << EVENT_NTUPLE_NAME
231 << "\" in file: " << fileName);
232 return StatusCode::FAILURE;
233 }
234 ATH_MSG_DEBUG("Created RNTupleReader for \"" << EVENT_NTUPLE_NAME
235 << "\" in file: " << fileName);
236
237 // Init the statistics collection.
239 // Update the event counter in the statistics object:
241 stats.setNEvents(stats.nEvents() + m_eventReader->GetNEntries());
242
243 // Notify the listeners that a new file was opened:
244 const TIncident beginIncident(IncidentType::BeginInputFile);
245 for (TVirtualIncidentListener* listener : m_listeners) {
246 listener->handle(beginIncident);
247 }
248 // For now implement a very simple scheme in which we claim already
249 // at the start that the entire file was processed. Since we have no way
250 // of ensuring that the user indeed does this. And we can't delay calling
251 // this function, as the user may likely close his/her output file before
252 // closing the last opened input file.
253 const TIncident endIncident(IncidentType::EndInputFile);
254 for (TVirtualIncidentListener* listener : m_listeners) {
255 listener->handle(endIncident);
256 }
257
258 // The initialisation was successful:
259 return StatusCode::SUCCESS;
260}
261
264::Long64_t REvent::getEntries() const {
265
266 if (m_eventReader) {
267 return m_eventReader->GetNEntries();
268 } else if (m_inputNTupleIsMissing) {
269 return 0u;
270 } else {
271 ATH_MSG_ERROR("Function called on an uninitialised object");
272 return 0u;
273 }
274}
275
290::Int_t REvent::getEntry(::Long64_t entry, ::Int_t getall) {
291
292 // A little sanity check:
293 if (!m_eventReader) {
294 ATH_MSG_ERROR("Function called on an uninitialised object");
295 return -1;
296 }
297
298 // Check if anything needs to be done.
299 if (entry == m_entry) {
300 ATH_MSG_DEBUG("Entry " << entry << " is already the active one");
301 return 0;
302 }
303
304 // Set entry value
305 m_entry = entry;
306
307 // Stats counter needs to know it's the next event.
309
310 // Loop over all input object managers, and force them to load their
311 // content. But only if getall was used.
312 ::Int_t result = 0;
313 if (getall) {
314 for (auto& [key, inObj] : m_inputObjects) {
315 result += inObj->getEntry(getall);
316 }
317 }
318
319 // Notify the listeners that a new event was loaded.
320 const TIncident incident(IncidentType::BeginEvent);
321 for (TVirtualIncidentListener* listener : m_listeners) {
322 listener->handle(incident);
323 }
324
325 // Return the number of bytes read.
326 return result;
327}
328
329bool REvent::hasInput() const {
330
332}
333
334bool REvent::hasOutput() const {
335
336 return false;
337}
338
339StatusCode REvent::getNames(const std::string& /*targetClassName*/,
340 std::vector<std::string>& /*vkeys*/,
341 bool /*metadata*/) const {
342
343 ATH_MSG_ERROR("xAOD::REvent::getNames not yet implemented");
344 return StatusCode::FAILURE;
345}
346
364StatusCode REvent::connectObject(const std::string& key, ::Bool_t silent) {
365
366 // A little sanity check.
367 if (!m_eventReader) {
368 ATH_MSG_ERROR("Function called on un-initialised object");
369 return StatusCode::FAILURE;
370 }
371
372 // Increment the access counter on this container.
374
375 // Check if the branch is already connected.
376 if (m_inputObjects.contains(key)) {
377 return StatusCode::SUCCESS;
378 }
379 // Check if it was already found to be missing.
380 if (m_inputMissingObjects.contains(key)) {
381 if (!silent) {
382 ATH_MSG_WARNING("Field \"" << key << "\" not available on input");
383 }
384 return StatusCode::RECOVERABLE;
385 }
386
387 // Tell the user what's happening.
388 ATH_MSG_DEBUG("Connecting to branch \"" << key << "\"");
389
390 // Check if we have metadata about this branch.
391 const xAOD::EventFormatElement* ef = nullptr;
392
393 // RNTuples store fields with an "Aux:" postfix instead of "Aux.".
394 std::string key_to_read = key;
395 if (key.ends_with("Aux.")) {
396 key_to_read.replace(key_to_read.size() - 1, 1, ":");
397 }
398
399 if (m_inputEventFormat.exists(key) == false) {
400 if (!silent) {
401 ATH_MSG_WARNING("No metadata available for object: " << key);
402 }
403 } else {
404 ef = m_inputEventFormat.get(key);
405 }
406
407 // Check if the field exists in our input RNTuple.
408 if (m_eventReader->GetDescriptor().FindFieldId(key_to_read.c_str()) ==
409 ROOT::kInvalidDescriptorId) {
410 // Field doesn't exist
411 if (!silent) {
412 ATH_MSG_WARNING("Field \"" << key_to_read << "\" not available on input");
413 }
414 m_inputMissingObjects.insert(key);
415 return StatusCode::RECOVERABLE;
416 }
417
418 // RDS: may need some logic here to get type from inputEventFormat rather than
419 // the view
420 // to read in with automatic schema evolution
421
422 // Get class name from the field
423 ROOT::RNTupleView<void> view =
424 m_eventReader->GetView<void>(key_to_read.c_str(), nullptr);
425 std::string className = view.GetField().GetTypeName();
426 if (className == "") {
427 if (ef) {
428 // This is a fairly weird situation, but let's fall back to taking
429 // the class name from the metadata object in this case.
430 className = ef->className();
431 } else {
433 "Couldn't find an appropriate type with a dictionary for field \""
434 << key_to_read << "\"");
435 return StatusCode::FAILURE;
436 }
437 }
438 ::TClass* realClass = ::TClass::GetClass(className.c_str());
439 if (((!realClass) || (!realClass->IsLoaded())) && ef) {
440 // We may need to do an actual schema evolution here, in which
441 // case let's fall back on the class name coming from the metadata
442 // object.
443 className = ef->className();
444 realClass = ::TClass::GetClass(className.c_str());
445 }
446 if ((!realClass) || (!realClass->IsLoaded())) {
447 // Now we're in trouble...
449 "Couldn't find an appropriate type with a dictionary for field \""
450 << key_to_read << "\"");
451 return StatusCode::FAILURE;
452 }
453
454 // Make sure that the current object is the "active event":
455 setActive();
456
457 // Check if the output already has this object. If it does, let's
458 // assume that we have been copying the object to the output. Which
459 // means that we need to resume filling the same memory address that
460 // the output holder points to.
461 void* ptr = nullptr;
462
463 // Handle the case where an output object with this key already exists.
464
465 // If there is no output object, then let's create one ourselves.
466 // This is the only way in which we can have the memory management of
467 // THolder do the right thing with this object.
468 if (ptr == nullptr) {
469 ptr = realClass->New();
470 }
471
472 // Create the new manager object that will hold this EDM object.
473 auto mgr = std::make_unique<RObjectManager>(
474 m_eventReader->GetView(key_to_read, ptr, className), m_entry,
475 std::make_unique<THolder>(ptr, realClass));
476 RObjectManager* mgrPtr = mgr.get();
477 m_inputObjects[key] = std::move(mgr);
478
479 // If it's an auxiliary store object, set it up correctly.
480 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
482 }
483
484 // If it (probably) has an associated auxiliary store, set it up as well.
485 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
487 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
488 }
489
490 // Return gracefully.
491 return StatusCode::SUCCESS;
492}
493
502StatusCode REvent::connectMetaObject(const std::string& key, bool silent) {
503
504 // A little sanity check.
505 if (!m_metaReader) {
506 ATH_MSG_ERROR("Function called on un-initialised object");
507 return StatusCode::FAILURE;
508 }
509
510 // Check if the branch is already connected.
511 if (m_inputMetaObjects.contains(key)) {
512 return StatusCode::SUCCESS;
513 }
514
515 // RNTuples store fields with an "Aux:" postfix instead of "Aux.".
516 std::string key_to_read = key;
517 if (key.ends_with("Aux.")) {
518 key_to_read.replace(key_to_read.size() - 1, 1, ":");
519 }
520
521 // Check if the field exists in our input RNTuple.
522 if (m_metaReader->GetDescriptor().FindFieldId(key_to_read.c_str()) ==
523 ROOT::kInvalidDescriptorId) {
524 // Field doesn't exist
525 if (!silent) {
526 ATH_MSG_WARNING("Field \"" << key_to_read << "\" not available on input");
527 }
528 return StatusCode::RECOVERABLE;
529 }
530
531 // RDS: may need some logic here to get type from inputEventFormat rather than
532 // the view
533 // to read in with automatic schema evolution
534
535 // Get class name from the field
536 ROOT::RNTupleView<void> view =
537 m_metaReader->GetView<void>(key_to_read.c_str(), nullptr);
538 std::string className = view.GetField().GetTypeName();
539 if (className == "") {
541 "Couldn't find an appropriate type with a dictionary for field \""
542 << key_to_read << "\"");
543 return StatusCode::FAILURE;
544 }
545 ::TClass* realClass = ::TClass::GetClass(className.c_str());
546 if ((!realClass) || (!realClass->IsLoaded())) {
547 // Now we're in trouble...
549 "Couldn't find an appropriate type with a dictionary for field \""
550 << key_to_read << "\"");
551 return StatusCode::FAILURE;
552 }
553
554 // Create the object and the manager(s) around it.
555 void* ptr = realClass->New();
556 static const ::Long64_t FIRST_ENTRY = 0;
557 auto mgr = std::make_unique<RObjectManager>(
558 m_metaReader->GetView(key_to_read, ptr, className), FIRST_ENTRY,
559 std::make_unique<THolder>(ptr, realClass));
560 // For metadata, we must read in the first entry - entry number already set by FIRST_ENTRY in constructor
561 mgr->getEntry();
562 RObjectManager* mgrPtr = mgr.get();
563 m_inputMetaObjects[key] = std::move(mgr);
564
565 // If it's an auxiliary store object, set it up correctly.
566 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
567 // For reading in of the dynamic variables for metadata
569 }
570
571 // If it (probably) has an associated auxiliary store, set it up as well.
572 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
574 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
575 static constexpr bool METADATA = true;
576 ATH_CHECK(setAuxStore(key, *mgrPtr, METADATA));
577 }
578
579 // Return gracefully.
580 return StatusCode::SUCCESS;
581} // connectMetaObject
582
593StatusCode REvent::connectAux(const std::string& prefix, ::Bool_t standalone) {
594
595 // A little sanity check.
596 if (!m_eventReader) {
597 ATH_MSG_ERROR("Function called on un-initialised object");
598 return StatusCode::FAILURE;
599 }
600
601 // Check if the field is already connected.
602 if (m_inputObjects.contains(prefix)) {
603 return StatusCode::SUCCESS;
604 }
605
606 // Connect to the field as we would for any other.
607 static constexpr bool SILENT = false;
608 ATH_CHECK(connectObject(prefix, SILENT));
609
610 // Access the object's manager.
611 Object_t::const_iterator mgr_itr = m_inputObjects.find(prefix);
612 if (mgr_itr == m_inputObjects.end()) {
613 ATH_MSG_FATAL("There's a logic error in the code");
614 return StatusCode::FAILURE;
615 }
616 const Details::IObjectManager* omgr =
617 dynamic_cast<const RObjectManager*>(mgr_itr->second.get());
618 if (omgr == nullptr) {
619 ATH_MSG_FATAL("There's a logic error in the code");
620 return StatusCode::FAILURE;
621 }
622
623 // Check if we can switch out the internal store of this object.
624 static const TClass* const holderClass =
625 TClass::GetClass(typeid(SG::IAuxStoreHolder));
626 if (omgr->holder()->getClass()->InheritsFrom(holderClass) == false) {
627 // Nope... So let's just end the journey here.
628 return StatusCode::SUCCESS;
629 }
630
631 // Try to get the object as an IAuxStoreHolder.
632 SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
633 omgr->holder()->getAs(typeid(SG::IAuxStoreHolder)));
634 if (!storeHolder) {
635 ATH_MSG_FATAL("There's a logic error in the code");
636 return StatusCode::FAILURE;
637 }
638
639 // A sanity check to see whether the store's type is in sync with the
640 // object's type that it will be connected to:
641 if ((standalone &&
643 ((!standalone) && (storeHolder->getStoreType() !=
645 ATH_MSG_ERROR("Requested store types inconsistent for: " << prefix);
646 ATH_MSG_ERROR("standalone = "
647 << standalone << ", getStoreType() = "
648 << static_cast<int>(storeHolder->getStoreType()));
649 return StatusCode::FAILURE;
650 }
651
652 // Return gracefully.
653 return StatusCode::SUCCESS;
654}
655
665StatusCode REvent::connectMetaAux(const std::string& prefix,
666 ::Bool_t standalone) {
667
668 // A little sanity check.
669 if (!m_metaReader) {
670 ATH_MSG_ERROR("Function called on un-initialised object");
671 return StatusCode::FAILURE;
672 }
673
674 // Check if the field is already connected.
675 if (m_inputMetaObjects.contains(prefix)) {
676 return StatusCode::SUCCESS;
677 }
678
679 // Connect to the field as we would for any other.
680 static constexpr bool SILENT = false;
681 ATH_CHECK(connectMetaObject(prefix, SILENT));
682
683 // Access the object's manager.
684 Object_t::const_iterator mgr_itr = m_inputMetaObjects.find(prefix);
685 if (mgr_itr == m_inputMetaObjects.end()) {
686 ATH_MSG_FATAL("There's a logic error in the code");
687 return StatusCode::FAILURE;
688 }
689 const Details::IObjectManager* omgr =
690 dynamic_cast<const RObjectManager*>(mgr_itr->second.get());
691 if (omgr == nullptr) {
692 ATH_MSG_FATAL("There's a logic error in the code");
693 return StatusCode::FAILURE;
694 }
695
696 // Check if we can switch out the internal store of this object.
697 static const TClass* const holderClass =
698 TClass::GetClass(typeid(SG::IAuxStoreHolder));
699 if (omgr->holder()->getClass()->InheritsFrom(holderClass) == false) {
700 // Nope... So let's just end the journey here.
701 return StatusCode::SUCCESS;
702 }
703
704 // Try to get the object as an IAuxStoreHolder.
705 SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
706 omgr->holder()->getAs(typeid(SG::IAuxStoreHolder)));
707 if (!storeHolder) {
708 ATH_MSG_FATAL("There's a logic error in the code");
709 return StatusCode::FAILURE;
710 }
711
712 // A sanity check to see whether the store's type is in sync with the
713 // object's type that it will be connected to:
714 if ((standalone &&
716 ((!standalone) && (storeHolder->getStoreType() !=
718 ATH_MSG_ERROR("Requested store types inconsistent for: " << prefix);
719 ATH_MSG_ERROR("standalone = "
720 << standalone << ", getStoreType() = "
721 << static_cast<int>(storeHolder->getStoreType()));
722 return StatusCode::FAILURE;
723 }
724
725 // Return gracefully.
726 return StatusCode::SUCCESS;
727}
728
740StatusCode REvent::setAuxStore(const std::string& key,
741 Details::IObjectManager& mgr, bool metadata) {
742
743 // Check if we need to do anything:
744 if ((Details::hasAuxStore(*(mgr.holder()->getClass())) == false) &&
745 (Details::isAuxStore(*(mgr.holder()->getClass())) == false)) {
746 return StatusCode::SUCCESS;
747 }
748
749 // Select which object container to use:
750 Object_t& objects = (metadata ? m_inputMetaObjects : m_inputObjects);
751
752 // Look up the auxiliary object's manager:
753 TVirtualManager* auxMgr = nullptr;
754 std::string auxKey;
755 if (Details::isAuxStore(*(mgr.holder()->getClass()))) {
756 auxMgr = &mgr;
757 auxKey = key;
758 } else {
759 auto itr = objects.find(key + "Aux.");
760 if (itr == objects.end()) {
761 // Apparently there's no auxiliary object for this DV, so let's
762 // give up.
763 return StatusCode::SUCCESS;
764 }
765 auxMgr = itr->second.get();
766 auxKey = key + "Aux:";
767 }
768
769 if (!metadata) {
770 // Make sure the auxiliary object is up to date.
771 ::Int_t readBytes = auxMgr->getEntry();
772
773 // Check if there is a separate auxiliary object for the dynamic
774 // variables, which would need to be updated.
775 const std::string dynAuxKey = auxKey + "Dynamic";
776 auto dynAuxMgr = objects.find(dynAuxKey);
777 if ((dynAuxMgr != objects.end()) && (readBytes || (auxMgr == &mgr))) {
778
779 // Tell the dynamic store object to switch to a new entry.
780 dynAuxMgr->second->getEntry();
781 }
782 }
783
784 // Stop here if we've set up an auxiliary store.
785 if (auxMgr == &mgr) {
786 return StatusCode::SUCCESS;
787 }
788
789 // Access the auxiliary base class of the object/vector:
791 SG::AuxElement* aux = 0;
792 switch (mgr.holder()->typeKind()) {
793 case THolder::DATAVECTOR: {
794 void* vvec = mgr.holder()->getAs(typeid(SG::AuxVectorBase));
795 vec = reinterpret_cast<SG::AuxVectorBase*>(vvec);
796 } break;
797 case THolder::AUXELEMENT: {
798 void* vaux = mgr.holder()->getAs(typeid(SG::AuxElement));
799 aux = reinterpret_cast<SG::AuxElement*>(vaux);
800 } break;
801 default:
802 break;
803 }
804
805 // Check whether index tracking is enabled for the type. If not, then
806 // we need to fix it...
807 if (vec && (!vec->trackIndices())) {
808 Details::forceTrackIndices(*vec);
809 }
810
811 // Check if we were successful:
812 if ((!vec) && (!aux)) {
813 ATH_MSG_FATAL("Couldn't access class \""
814 << mgr.holder()->getClass()->GetName()
815 << "\" as SG::AuxVectorBase or SG::AuxElement");
816 return StatusCode::FAILURE;
817 }
818
819 // Get the concrete auxiliary manager:
820 RObjectManager* omgr = dynamic_cast<RObjectManager*>(auxMgr);
821 if (!omgr) {
822 ATH_MSG_FATAL("Auxiliary manager for \"" << auxKey
823 << "\" is not of the right type");
824 return StatusCode::FAILURE;
825 }
826 void* p = omgr->holder()->getAs(typeid(SG::IConstAuxStore));
827 const SG::IConstAuxStore* store =
828 reinterpret_cast<const SG::IConstAuxStore*>(p);
829 if (store == nullptr) {
830 ATH_MSG_FATAL("There's a logic error in the code");
831 return StatusCode::FAILURE;
832 }
833
834 // Connect the two:
835 if (vec) {
836 vec->setStore(store);
837 } else if (aux) {
838 aux->setStore(store);
839 } else {
840 ATH_MSG_FATAL("There's a logic error in the code");
841 return StatusCode::FAILURE;
842 }
843
844 // We succeeded:
845 return StatusCode::SUCCESS;
846}
847
848StatusCode REvent::record(void*, const std::string&, const std::string&, bool,
849 bool, bool) {
850
851 ATH_MSG_ERROR("xAOD::REvent::record not yet implemented");
852 return StatusCode::FAILURE;
853}
854
855StatusCode REvent::recordAux(TVirtualManager&, const std::string&, bool) {
856
857 ATH_MSG_ERROR("xAOD::REvent::recordAux not yet implemented");
858 return StatusCode::FAILURE;
859}
860
867StatusCode REvent::initStats() {
868
869 // A little sanity check.
870 if (!m_eventReader) {
871 ATH_MSG_ERROR("Function called on an uninitialised object");
872 return StatusCode::FAILURE;
873 }
874
875 // Reset the number of input branches information.
877
878 // Loop over the EventFormat information.
879 for (const auto& [key, format] : m_inputEventFormat) {
880
881 ATH_MSG_DEBUG("Investigating object \"" << key << "\" of class \""
882 << format.className() << "\"");
883
884 // If it's an auxiliary container, scan it using RAuxStore.
885 if (key.ends_with("Aux.")) {
886
887 // But first decide whether it describes a container, or just
888 // a single object. For that, first get the class that it was
889 // written with.
890 TClass* cl = TClass::GetClass(format.className().c_str());
891 if ((cl == nullptr) || (cl->IsLoaded() == false)) {
893 "Couldn't find the dictionary for type: " << format.className());
894 continue;
895 }
896
897 // And then check if it inherits from xAOD::AuxContainerBase or from
898 // xAOD::AuxInfoBase.
899 static TClass* const auxContCl = TClass::GetClass(
901 static TClass* const auxInfoCl = TClass::GetClass(
903 if ((auxContCl == nullptr) || (auxInfoCl == nullptr)) {
905 "Couldn't get dictionary for xAOD::AuxContainerBase or "
906 "xAOD::AuxInfoBase");
907 return StatusCode::FAILURE;
908 }
909 const bool isContainer = cl->InheritsFrom(auxContCl);
910 const bool isInfo = cl->InheritsFrom(auxInfoCl);
911 if ((isContainer == false) && (isInfo == false)) {
912 ATH_MSG_WARNING("Auxiliary store \""
913 << key
914 << "\" is of an unknown type: " << format.className());
915 continue;
916 }
917 ATH_MSG_VERBOSE("isContainer = " << isContainer
918 << ", isInfo = " << isInfo);
919
920 // Scan the branches using a temporary RAuxStore instance.
921 const std::string fieldName = key.substr(0, key.size() - 1) + ":";
922 const RAuxStore::EStructMode mode =
925 static constexpr bool TOP_STORE = true;
926 RAuxStore temp(fieldName, TOP_STORE, mode);
927 ATH_CHECK(temp.readFrom(*m_eventReader));
928
929 // Add all the auxids to the statistics object:
930 ReadStats& stats = IOStats::instance().stats();
931 for (SG::auxid_t id : temp.getAuxIDs()) {
932 stats.branch(fieldName, id);
933 }
934
935 // Increment the number of known branches.
936 stats.setBranchNum(stats.branchNum() + temp.getAuxIDs().size());
937 }
938 // If it's an interface container.
939 else {
940 // Check if it's part of the input ntuple.
941 if (m_eventReader->GetDescriptor().FindFieldId(key) !=
942 ROOT::kInvalidDescriptorId) {
944 }
945 }
946 }
947
948 // Return gracefully:
949 return StatusCode::SUCCESS;
950}
951
961 ROOT::RNTupleReader& reader) {
962
963 // The name of the field that the object is connected to.
964 const std::string fieldName = mgr.field().GetField().GetFieldName();
965
966 // Check if we can call setName(...) on the object.
967 ::TMethodCall setNameCall;
968 setNameCall.InitWithPrototype(mgr.holder()->getClass(), "setName",
969 "const char*");
970 if (setNameCall.IsValid()) {
971 // Yes, there is such a function. Let's call it with the field
972 // name.
973 const ::TString params = ::TString::Format("\"%s\"", fieldName.c_str());
974 const char* charParams = params.Data();
975 setNameCall.Execute(mgr.holder()->get(), charParams);
976 } else {
977 // This is weird. What sort of auxiliary container is this? :-/
978 ATH_MSG_WARNING("Couldn't find setName(...) function for container \""
979 << fieldName << "\" (type: "
980 << mgr.holder()->getClass()->GetName() << ")");
981 }
982
983 // Check if we can switch out the internal store of this object:
984 static const TClass* const holderClass =
985 TClass::GetClass(typeid(SG::IAuxStoreHolder));
986 if (!mgr.holder()->getClass()->InheritsFrom(holderClass)) {
987 // Nope... So let's just end the journey here.
988 return StatusCode::SUCCESS;
989 }
990
991 // Try to get the object as an IAuxStoreHolder:
992 SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
993 mgr.holder()->getAs(typeid(SG::IAuxStoreHolder)));
994 if (!storeHolder) {
995 ATH_MSG_FATAL("There's a logic error in the code");
996 return StatusCode::FAILURE;
997 }
998
999 // Create an RAuxStore instance that will read the dynamic variables
1000 // of this container. Notice that the RAuxManager doesn't own the
1001 // RAuxStore object. It will be owned by the SG::IAuxStoreHolder
1002 // object.
1003 static constexpr bool TOP_STORE = false;
1004 auto store = std::make_unique<RAuxStore>(
1005 fieldName, TOP_STORE,
1009 // This object is used to read data from the input, it needs to be
1010 // locked:
1011 store->lock();
1012
1013 // Set it up to read from the input RNTuple.
1014 ATH_CHECK(store->readFrom(reader));
1015 // Tell the auxiliary store which entry to use. This is essential for
1016 // metadata objects, and non-important for event data objects, which will
1017 // get a possibly different entry loaded in setAuxStore(...).
1018 ATH_CHECK(store->getEntry(0));
1019
1020 // Set up a manager for it.
1021 static constexpr bool SHARED_OWNER = false;
1022 m_inputObjects[fieldName + "Dynamic"] =
1023 std::make_unique<RAuxManager>(store.get(), m_entry, SHARED_OWNER);
1024
1025 // Give this object to the store holder.
1026 storeHolder->setStore(store.release());
1027
1028 // Return gracefully:
1029 return StatusCode::SUCCESS;
1030}
1031
1032} // namespace xAOD::Experimental
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Base class for elements of a container that can have aux data.
Manage index tracking and synchronization of auxiliary data.
std::vector< size_t > vec
static Double_t sc
void upgrade()
Convert the lock from upgrade to exclusive.
Base class for elements of a container that can have aux data.
Definition AuxElement.h:483
Manage index tracking and synchronization of auxiliary data.
Interface for objects taking part in direct ROOT I/O.
@ AST_ContainerStore
The store describes a container.
@ AST_ObjectStore
The store describes a single object.
virtual AuxStoreType getStoreType() const =0
Return the type of the store object.
virtual void setStore(IAuxStore *store)=0
Give an auxiliary store object to the holder object.
Interface for const operations on an auxiliary store.
Common base class for the auxiliary containers.
Common base class for auxiliary info objects.
Definition AuxInfoBase.h:45
Manager for EDM objects created by ROOT.
const THolder * holder() const
Accessor to the Holder object.
Class describing one branch of the ROOT file.
EventFormat m_inputEventFormat
Format of the current input file.
Definition Event.h:321
std::set< std::string > m_inputMissingObjects
Objects that have been asked for, but were found to be missing in the current input.
Definition Event.h:311
upgrade_mutex_t m_branchesMutex
Mutex for multithread synchronization.
Definition Event.h:354
AthContainers_detail::upgrading_lock< upgrade_mutex_t > upgrading_lock_t
Lock type for multithread synchronization.
Definition Event.h:351
Object_t m_inputObjects
Collection of all the managed input objects.
Definition Event.h:308
Event(std::string_view name)
Constructor with a name.
Definition EventCore.cxx:27
std::unordered_map< std::string, std::unique_ptr< TVirtualManager > > Object_t
Definition of the internal data structure type.
Definition Event.h:304
void setActive() const
Set this event object as the currently active one.
Definition EventCore.cxx:54
Object_t m_inputMetaObjects
Collection of all the managed input meta-objects.
Definition Event.h:316
Object_t m_outputObjects
Collection of all the managed output object.
Definition Event.h:313
std::vector< TVirtualIncidentListener * > m_listeners
Listeners who should be notified when certain incidents happen.
Definition Event.h:329
bool m_inputNTupleIsMissing
Whether the input has an event RNTuple or not.
Definition REvent.h:104
StatusCode setUpDynamicStore(RObjectManager &mgr, ROOT::RNTupleReader &ntupleReader)
event uses RNTupleReader:
Definition REvent.cxx:960
StatusCode record(void *obj, const std::string &typeName, const std::string &key, bool overwrite, bool metadata, bool isOwner) override
Record an object into a connected output file.
Definition REvent.cxx:848
std::unique_ptr< ROOT::RNTupleReader > m_eventReader
The main event data reader.
Definition REvent.h:102
StatusCode connectMetaAux(const std::string &prefix, bool standalone) override
Function setting up access to a set of auxiliary branches for a metadata object.
Definition REvent.cxx:665
StatusCode readFrom(std::string_view fileName)
Set up the reading of an input file.
Definition REvent.cxx:90
std::unique_ptr< ROOT::RNTupleReader > m_metaReader
The metadata reader.
Definition REvent.h:106
StatusCode recordAux(TVirtualManager &mgr, const std::string &key, bool metadata) override
Record an auxiliary store into a connected output file.
Definition REvent.cxx:855
::Long64_t getEntries() const
Get how many entries are available from the current input file(s)
Definition REvent.cxx:264
StatusCode setAuxStore(const std::string &key, Details::IObjectManager &mgr, bool metadata) override
Function connecting a DV object to its auxiliary store.
Definition REvent.cxx:740
bool hasOutput() const override
Check if an output file is connected to the object.
Definition REvent.cxx:334
::Int_t getEntry(::Long64_t entry, ::Int_t getall=0)
Function loading a given entry of the input TTree.
Definition REvent.cxx:290
StatusCode getNames(const std::string &targetClassName, std::vector< std::string > &vkeys, bool metadata) const override
Function determining the list keys associated with a type name.
Definition REvent.cxx:339
StatusCode connectObject(const std::string &key, bool silent) override
Function setting up access to a particular object.
Definition REvent.cxx:364
::Long64_t m_entry
The entry to look at from the input tree.
Definition REvent.h:109
REvent()
Default constructor.
Definition REvent.cxx:73
virtual ~REvent()
Destructor.
Definition REvent.cxx:75
StatusCode connectAux(const std::string &prefix, bool standalone) override
Function setting up access to a set of auxiliary branches.
Definition REvent.cxx:593
StatusCode initStats()
Function to initialise the statistics for all Tree content.
Definition REvent.cxx:867
StatusCode connectMetaObject(const std::string &key, bool silent) override
Function setting up access to a particular metadata object.
Definition REvent.cxx:502
bool hasInput() const override
Check if an input file is connected to the object.
Definition REvent.cxx:329
Manager for EDM objects created by ROOT.
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
"ROOT @c RNTuple implementation" of IAuxStore
Definition RAuxStore.h:38
Class describing the access statistics of a collection of branches.
Definition ReadStats.h:123
void nextEvent()
Function incrementing the processed event counter.
BranchStats * container(const std::string &name)
Access the description of a container. Creating it if necessary.
void setBranchNum(::Int_t num)
Set the total number of branches on the input.
void readContainer(const std::string &name)
Function incrementing the read counter on a specific container.
const ::TClass * getClass() const
Definition THolder.cxx:402
virtual void * getAs(const std::type_info &tid, ::Bool_t silent=kFALSE) const
Return the object as a specific pointer.
Definition THolder.cxx:371
@ DATAVECTOR
A DataVector container.
Definition THolder.h:105
@ AUXELEMENT
A type inheriting from SG::AuxElement.
Definition THolder.h:106
Class describing a certain "incident" that is communicated to user code.
Definition TIncident.h:58
Class providing an interface for classes listening to xAOD incidents.
Interface class for the "manager classes".
virtual::Int_t getEntry(::Int_t getall=0)=0
Function for updating the object in memory if needed.
EStructMode
"Structural" modes of the object
@ kObjectStore
The object describes a single object.
@ kContainerStore
The object describes an entire container.
std::string normalizedTypeinfoName(const std::type_info &info)
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
bool hasAuxStore(const TClass &cl)
Helper function deciding if a given type "has an auxiliary store".
Definition IOUtils.cxx:40
bool isAuxStore(const TClass &cl)
Helper function deciding if a given type "is an auxiliary store".
Definition IOUtils.cxx:53
bool isStandalone(const TClass &cl)
Helper function deciding if a given type "is a standalone object".
Definition IOUtils.cxx:65
static const char *const METADATA_NTUPLE_NAME
Definition REvent.cxx:71
static const char *const EVENT_NTUPLE_NAME
Definition REvent.cxx:70
static const ::Int_t BeginEvent
A new event was just loaded.
Definition TIncident.h:29
static const ::Int_t EndInputFile
The processing of an input file has finished.
Definition TIncident.h:40
static const ::Int_t BeginInputFile
A new input file was just opened.
Definition TIncident.h:27
std::string getTypeName(const std::type_info &ti)
This function is necessary in order to create type names that ROOT can understand.
EventFormat_v1 EventFormat
Definition of the current event format version.
Definition EventFormat.h:16
Convert a type_info to a normalized string representation (matching the names used in the root dictio...