ATLAS Offline Software
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).
23 #include "xAODCore/AuxInfoBase.h"
24 #include "xAODCore/tools/IOStats.h"
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 
40 namespace {
41 
51 std::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 
67 namespace xAOD::Experimental {
68 
69 // Initialise some static data.
70 static const char* const EVENT_NTUPLE_NAME = "EventData";
71 static const char* const METADATA_NTUPLE_NAME = "MetaData";
72 
73 REvent::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 
91 
92  // Clear the cached input objects.
93  m_inputObjects.clear();
94  m_inputMissingObjects.clear();
95  m_inputMetaObjects.clear();
96  {
98  lock.upgrade();
99  m_branches.clear();
100  }
101  m_eventReader.reset();
102 
103  // Reset the internal flags.
104  m_entry = -1;
105  m_inputNTupleIsMissing = false;
106 
107  // Clear out the current object.
108  m_inputEventFormat = {};
109 
110  // Set up a reader for the metadata ntuple.
111  m_metaReader = ROOT::RNTupleReader::Open(METADATA_NTUPLE_NAME, fileName);
112  if (!m_metaReader) {
113  ATH_MSG_ERROR("Couldn't find \"" << METADATA_NTUPLE_NAME
114  << "\" tree in input file: " << fileName);
115  return StatusCode::FAILURE;
116  }
117  ATH_MSG_DEBUG("Created RNTupleReader for \"" << METADATA_NTUPLE_NAME
118  << "\" in file: " << fileName);
119 
120  // Make sure that the xAOD::EventFormat dictonary is loaded.
121  // This may not be the case if streamer information reading is turned
122  // off.
123  static const std::string eventFormatTypeName =
125  if (::TClass::GetClass(eventFormatTypeName.c_str()) == nullptr) {
126  ATH_MSG_WARNING("Couldn't load the EventFormat dictionary");
127  }
128  ATH_MSG_VERBOSE("Loaded the xAOD::EventFormat dictionary");
129 
130  // Helper lambda for collecting the event format metadata from an RNTuple
131  // with a given name.
132  auto readEventFormatMetadata = [&](std::string_view tupleName) -> StatusCode {
133  // Set up a reader. This may technically be the same as m_metaReader, but
134  // it's easier to write the code this way.
135  auto metaReader = ROOT::RNTupleReader::Open(tupleName, fileName);
136  if (!metaReader) {
137  ATH_MSG_ERROR("Couldn't find \""
138  << tupleName << "\" ntuple in input file: " << fileName);
139  return StatusCode::FAILURE;
140  }
141  ATH_MSG_VERBOSE("Created temporary RNTupleReader for \""
142  << tupleName << "\" in file: " << fileName);
143 
144  // Try to read in the event format metadata.
145  const std::string eventFormatFieldName =
146  getFirstFieldMatch(*m_metaReader, "EventFormat");
147  try {
148  // Add its elements to m_inputEventFormat.
149  auto ef = m_metaReader->GetView<xAOD::EventFormat>(eventFormatFieldName);
150  for (const auto& [key, element] : ef(0u)) {
151  m_inputEventFormat.add(element);
152  }
153  } catch (const ROOT::RException&) {
154  ATH_MSG_WARNING("Input file provides no event or metadata");
155  return StatusCode::RECOVERABLE;
156  }
157  ATH_MSG_VERBOSE("Merged event format metadata from \"" << tupleName
158  << "\" ntuple");
159 
160  // Return gracefully.
161  return StatusCode::SUCCESS;
162  };
163 
164  // Read in the metadata from the "main" metadata ntuple.
165  const StatusCode sc = readEventFormatMetadata(METADATA_NTUPLE_NAME);
166  if (sc.isRecoverable()) {
167  m_inputNTupleIsMissing = true;
168  return StatusCode::SUCCESS;
169  }
170  ATH_CHECK(sc);
171 
172  // List all the other Metadata RNTuples in the input file.
173  // Having several metadata tuples can happen for augmented files
174  // as one metadata tree per stream is produced.
175  std::set<std::string> lOtherMetaTupleNames;
176  {
177  std::unique_ptr<TFile> inFile(TFile::Open(fileName.data(), "READ"));
178  TList* lKeys = inFile->GetListOfKeys();
179  if (lKeys == nullptr) {
180  ATH_MSG_ERROR("Could not get list of keys for input file: " << fileName);
181  return StatusCode::FAILURE;
182  }
183  for (const TObject* obj : *lKeys) {
184  const std::string keyName = obj->GetName();
185  // Make sure the key corresponds to a metadata ntuple but
186  // do not add the current metadata tree in the list of other trees
187  // and do not add the metadata tree handlers to the list
188  if ((keyName != METADATA_NTUPLE_NAME) &&
189  (keyName.find("MetaData") != std::string::npos) &&
190  (keyName.find("MetaDataHdr") == std::string::npos)) {
191  // Make sure key corresponds to an RNTuple
192  const TKey* key = dynamic_cast<const TKey*>(obj);
193  if (key == nullptr) {
194  ATH_MSG_ERROR("Object describing \"" << keyName << "\" in file \""
195  << fileName
196  << "\" is not a TKey?");
197  return StatusCode::FAILURE;
198  }
199  const char* className = key->GetClassName();
200  static constexpr bool LOAD = kFALSE;
201  static constexpr bool SILENT = kTRUE;
202  ::TClass* cl = ::TClass::GetClass(className, LOAD, SILENT);
203  if ((cl != nullptr) && cl->InheritsFrom(ROOT::RNTuple::Class())) {
204  lOtherMetaTupleNames.insert(keyName);
205  }
206  }
207  }
208  }
209 
210  // Read in the metadata from any additonal NTuples found (if any).
211  for (const std::string& tupleName : lOtherMetaTupleNames) {
212  ATH_CHECK(readEventFormatMetadata(tupleName));
213  }
214 
215  // Set up the main ntuple reader.
216  m_eventReader = ROOT::RNTupleReader::Open(EVENT_NTUPLE_NAME, fileName);
217  if (!m_eventReader) {
218  ATH_MSG_ERROR("Couldn't access RNTuple \"" << EVENT_NTUPLE_NAME
219  << "\" in file: " << fileName);
220  return StatusCode::FAILURE;
221  }
222  ATH_MSG_DEBUG("Created RNTupleReader for \"" << EVENT_NTUPLE_NAME
223  << "\" in file: " << fileName);
224 
225  // Init the statistics collection.
226  ATH_CHECK(initStats());
227  // Update the event counter in the statistics object:
229  stats.setNEvents(stats.nEvents() + m_eventReader->GetNEntries());
230 
231  // Notify the listeners that a new file was opened:
232  const TIncident beginIncident(IncidentType::BeginInputFile);
233  for (TVirtualIncidentListener* listener : m_listeners) {
234  listener->handle(beginIncident);
235  }
236  // For now implement a very simple scheme in which we claim already
237  // at the start that the entire file was processed. Since we have no way
238  // of ensuring that the user indeed does this. And we can't delay calling
239  // this function, as the user may likely close his/her output file before
240  // closing the last opened input file.
241  const TIncident endIncident(IncidentType::EndInputFile);
242  for (TVirtualIncidentListener* listener : m_listeners) {
243  listener->handle(endIncident);
244  }
245 
246  // The initialisation was successful:
247  return StatusCode::SUCCESS;
248 }
249 
252 ::Long64_t REvent::getEntries() const {
253 
254  if (m_eventReader) {
255  return m_eventReader->GetNEntries();
256  } else if (m_inputNTupleIsMissing) {
257  return 0u;
258  } else {
259  ATH_MSG_ERROR("Function called on an uninitialised object");
260  return 0u;
261  }
262 }
263 
278 ::Int_t REvent::getEntry(::Long64_t entry, ::Int_t getall) {
279 
280  // A little sanity check:
281  if (!m_eventReader) {
282  ATH_MSG_ERROR("Function called on an uninitialised object");
283  return -1;
284  }
285 
286  // Check if anything needs to be done.
287  if (entry == m_entry) {
288  ATH_MSG_DEBUG("Entry " << entry << " is already the active one");
289  return 0;
290  }
291 
292  // Set entry value
293  m_entry = entry;
294 
295  // Stats counter needs to know it's the next event.
297 
298  // Loop over all input object managers, and force them to load their
299  // content. But only if getall was used.
300  ::Int_t result = 0;
301  if (getall) {
302  for (auto& [key, inObj] : m_inputObjects) {
303  result += inObj->getEntry(getall);
304  }
305  }
306 
307  // Notify the listeners that a new event was loaded.
308  const TIncident incident(IncidentType::BeginEvent);
309  for (TVirtualIncidentListener* listener : m_listeners) {
310  listener->handle(incident);
311  }
312 
313  // Return the number of bytes read.
314  return result;
315 }
316 
317 bool REvent::hasInput() const {
318 
320 }
321 
322 bool REvent::hasOutput() const {
323 
324  return false;
325 }
326 
327 StatusCode REvent::getNames(const std::string& /*targetClassName*/,
328  std::vector<std::string>& /*vkeys*/,
329  bool /*metadata*/) const {
330 
331  ATH_MSG_ERROR("xAOD::REvent::getNames not yet implemented");
332  return StatusCode::FAILURE;
333 }
334 
352 StatusCode REvent::connectObject(const std::string& key, ::Bool_t silent) {
353 
354  // A little sanity check.
355  if (!m_eventReader) {
356  ATH_MSG_ERROR("Function called on un-initialised object");
357  return StatusCode::FAILURE;
358  }
359 
360  // Increment the access counter on this container.
362 
363  // Check if the branch is already connected.
364  if (m_inputObjects.contains(key)) {
365  return StatusCode::SUCCESS;
366  }
367  // Check if it was already found to be missing.
368  if (m_inputMissingObjects.contains(key)) {
369  if (!silent) {
370  ATH_MSG_WARNING("Field \"" << key << "\" not available on input");
371  }
372  return StatusCode::RECOVERABLE;
373  }
374 
375  // Tell the user what's happening.
376  ATH_MSG_DEBUG("Connecting to branch \"" << key << "\"");
377 
378  // Check if we have metadata about this branch.
379  const xAOD::EventFormatElement* ef = nullptr;
380 
381  // RNTuples store fields with an "Aux:" postfix instead of "Aux.".
382  std::string key_to_read = key;
383  if (key.ends_with("Aux.")) {
384  key_to_read.replace(key_to_read.size() - 1, 1, ":");
385  }
386 
387  if (m_inputEventFormat.exists(key) == false) {
388  if (!silent) {
389  ATH_MSG_WARNING("No metadata available for object: " << key);
390  }
391  } else {
393  }
394 
395  // Check if the field exists in our input RNTuple.
396  if (m_eventReader->GetDescriptor().FindFieldId(key_to_read.c_str()) ==
397  ROOT::kInvalidDescriptorId) {
398  // Field doesn't exist
399  if (!silent) {
400  ATH_MSG_WARNING("Field \"" << key_to_read << "\" not available on input");
401  }
402  m_inputMissingObjects.insert(key);
403  return StatusCode::RECOVERABLE;
404  }
405 
406  // RDS: may need some logic here to get type from inputEventFormat rather than
407  // the view
408  // to read in with automatic schema evolution
409 
410  // Get class name from the field
411  ROOT::RNTupleView<void> view =
412  m_eventReader->GetView<void>(key_to_read.c_str(), nullptr);
413  std::string className = view.GetField().GetTypeName();
414  if (className == "") {
415  if (ef) {
416  // This is a fairly weird situation, but let's fall back to taking
417  // the class name from the metadata object in this case.
418  className = ef->className();
419  } else {
421  "Couldn't find an appropriate type with a dictionary for field \""
422  << key_to_read << "\"");
423  return StatusCode::FAILURE;
424  }
425  }
426  ::TClass* realClass = ::TClass::GetClass(className.c_str());
427  if (((!realClass) || (!realClass->IsLoaded())) && ef) {
428  // We may need to do an actual schema evolution here, in which
429  // case let's fall back on the class name coming from the metadata
430  // object.
431  className = ef->className();
432  realClass = ::TClass::GetClass(className.c_str());
433  }
434  if ((!realClass) || (!realClass->IsLoaded())) {
435  // Now we're in trouble...
437  "Couldn't find an appropriate type with a dictionary for field \""
438  << key_to_read << "\"");
439  return StatusCode::FAILURE;
440  }
441 
442  // Make sure that the current object is the "active event":
443  setActive();
444 
445  // Check if the output already has this object. If it does, let's
446  // assume that we have been copying the object to the output. Which
447  // means that we need to resume filling the same memory address that
448  // the output holder points to.
449  void* ptr = nullptr;
450 
451  // Handle the case where an output object with this key already exists.
452 
453  // If there is no output object, then let's create one ourselves.
454  // This is the only way in which we can have the memory management of
455  // THolder do the right thing with this object.
456  if (ptr == nullptr) {
457  ptr = realClass->New();
458  }
459 
460  // Create the new manager object that will hold this EDM object.
461  auto mgr = std::make_unique<RObjectManager>(
462  m_eventReader->GetView(key_to_read, ptr, className), m_entry,
463  std::make_unique<THolder>(ptr, realClass));
464  RObjectManager* mgrPtr = mgr.get();
465  m_inputObjects[key] = std::move(mgr);
466 
467  // If it's an auxiliary store object, set it up correctly.
468  if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
470  }
471 
472  // If it (probably) has an associated auxiliary store, set it up as well.
473  if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
475  key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
476  }
477 
478  // Return gracefully.
479  return StatusCode::SUCCESS;
480 }
481 
490 StatusCode REvent::connectMetaObject(const std::string& key, bool silent) {
491 
492  // A little sanity check.
493  if (!m_metaReader) {
494  ATH_MSG_ERROR("Function called on un-initialised object");
495  return StatusCode::FAILURE;
496  }
497 
498  // Check if the branch is already connected.
499  if (m_inputMetaObjects.contains(key)) {
500  return StatusCode::SUCCESS;
501  }
502 
503  // RNTuples store fields with an "Aux:" postfix instead of "Aux.".
504  std::string key_to_read = key;
505  if (key.ends_with("Aux.")) {
506  key_to_read.replace(key_to_read.size() - 1, 1, ":");
507  }
508 
509  // Check if the field exists in our input RNTuple.
510  if (m_metaReader->GetDescriptor().FindFieldId(key_to_read.c_str()) ==
511  ROOT::kInvalidDescriptorId) {
512  // Field doesn't exist
513  if (!silent) {
514  ATH_MSG_WARNING("Field \"" << key_to_read << "\" not available on input");
515  }
516  return StatusCode::RECOVERABLE;
517  }
518 
519  // RDS: may need some logic here to get type from inputEventFormat rather than
520  // the view
521  // to read in with automatic schema evolution
522 
523  // Get class name from the field
524  ROOT::RNTupleView<void> view =
525  m_metaReader->GetView<void>(key_to_read.c_str(), nullptr);
526  std::string className = view.GetField().GetTypeName();
527  if (className == "") {
529  "Couldn't find an appropriate type with a dictionary for field \""
530  << key_to_read << "\"");
531  return StatusCode::FAILURE;
532  }
533  ::TClass* realClass = ::TClass::GetClass(className.c_str());
534  if ((!realClass) || (!realClass->IsLoaded())) {
535  // Now we're in trouble...
537  "Couldn't find an appropriate type with a dictionary for field \""
538  << key_to_read << "\"");
539  return StatusCode::FAILURE;
540  }
541 
542  // Create the object and the manager(s) around it.
543  void* ptr = realClass->New();
544  static const ::Long64_t FIRST_ENTRY = 0;
545  auto mgr = std::make_unique<RObjectManager>(
546  m_metaReader->GetView(key_to_read, ptr, className), FIRST_ENTRY,
547  std::make_unique<THolder>(ptr, realClass));
548  RObjectManager* mgrPtr = mgr.get();
549  m_inputMetaObjects[key] = std::move(mgr);
550 
551  // If it's an auxiliary store object, set it up correctly.
552  if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
554  }
555 
556  // If it (probably) has an associated auxiliary store, set it up as well.
557  if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
559  key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
560  }
561 
562  // Return gracefully.
563  return StatusCode::SUCCESS;
564 }
565 
576 StatusCode REvent::connectAux(const std::string& prefix, ::Bool_t standalone) {
577 
578  // A little sanity check.
579  if (!m_eventReader) {
580  ATH_MSG_ERROR("Function called on un-initialised object");
581  return StatusCode::FAILURE;
582  }
583 
584  // Check if the field is already connected.
585  if (m_inputObjects.contains(prefix)) {
586  return StatusCode::SUCCESS;
587  }
588 
589  // Connect to the field as we would for any other.
590  static constexpr bool SILENT = false;
591  ATH_CHECK(connectObject(prefix, SILENT));
592 
593  // Access the object's manager.
594  Object_t::const_iterator mgr_itr = m_inputObjects.find(prefix);
595  if (mgr_itr == m_inputObjects.end()) {
596  ATH_MSG_FATAL("There's a logic error in the code");
597  return StatusCode::FAILURE;
598  }
599  const Details::IObjectManager* omgr =
600  dynamic_cast<const RObjectManager*>(mgr_itr->second.get());
601  if (omgr == nullptr) {
602  ATH_MSG_FATAL("There's a logic error in the code");
603  return StatusCode::FAILURE;
604  }
605 
606  // Check if we can switch out the internal store of this object.
607  static const TClass* const holderClass =
608  TClass::GetClass(typeid(SG::IAuxStoreHolder));
609  if (omgr->holder()->getClass()->InheritsFrom(holderClass) == false) {
610  // Nope... So let's just end the journey here.
611  return StatusCode::SUCCESS;
612  }
613 
614  // Try to get the object as an IAuxStoreHolder.
615  SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
616  omgr->holder()->getAs(typeid(SG::IAuxStoreHolder)));
617  if (!storeHolder) {
618  ATH_MSG_FATAL("There's a logic error in the code");
619  return StatusCode::FAILURE;
620  }
621 
622  // A sanity check to see whether the store's type is in sync with the
623  // object's type that it will be connected to:
624  if ((standalone &&
625  (storeHolder->getStoreType() != SG::IAuxStoreHolder::AST_ObjectStore)) ||
626  ((!standalone) && (storeHolder->getStoreType() !=
628  ATH_MSG_ERROR("Requested store types inconsistent for: " << prefix);
629  ATH_MSG_ERROR("standalone = "
630  << standalone << ", getStoreType() = "
631  << static_cast<int>(storeHolder->getStoreType()));
632  return StatusCode::FAILURE;
633  }
634 
635  // Return gracefully.
636  return StatusCode::SUCCESS;
637 }
638 
649  ::Bool_t standalone) {
650 
651  // A little sanity check.
652  if (!m_metaReader) {
653  ATH_MSG_ERROR("Function called on un-initialised object");
654  return StatusCode::FAILURE;
655  }
656 
657  // Check if the field is already connected.
658  if (m_inputMetaObjects.contains(prefix)) {
659  return StatusCode::SUCCESS;
660  }
661 
662  // Connect to the field as we would for any other.
663  static constexpr bool SILENT = false;
665 
666  // Access the object's manager.
667  Object_t::const_iterator mgr_itr = m_inputMetaObjects.find(prefix);
668  if (mgr_itr == m_inputMetaObjects.end()) {
669  ATH_MSG_FATAL("There's a logic error in the code");
670  return StatusCode::FAILURE;
671  }
672  const Details::IObjectManager* omgr =
673  dynamic_cast<const RObjectManager*>(mgr_itr->second.get());
674  if (omgr == nullptr) {
675  ATH_MSG_FATAL("There's a logic error in the code");
676  return StatusCode::FAILURE;
677  }
678 
679  // Check if we can switch out the internal store of this object.
680  static const TClass* const holderClass =
681  TClass::GetClass(typeid(SG::IAuxStoreHolder));
682  if (omgr->holder()->getClass()->InheritsFrom(holderClass) == false) {
683  // Nope... So let's just end the journey here.
684  return StatusCode::SUCCESS;
685  }
686 
687  // Try to get the object as an IAuxStoreHolder.
688  SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
689  omgr->holder()->getAs(typeid(SG::IAuxStoreHolder)));
690  if (!storeHolder) {
691  ATH_MSG_FATAL("There's a logic error in the code");
692  return StatusCode::FAILURE;
693  }
694 
695  // A sanity check to see whether the store's type is in sync with the
696  // object's type that it will be connected to:
697  if ((standalone &&
698  (storeHolder->getStoreType() != SG::IAuxStoreHolder::AST_ObjectStore)) ||
699  ((!standalone) && (storeHolder->getStoreType() !=
701  ATH_MSG_ERROR("Requested store types inconsistent for: " << prefix);
702  ATH_MSG_ERROR("standalone = "
703  << standalone << ", getStoreType() = "
704  << static_cast<int>(storeHolder->getStoreType()));
705  return StatusCode::FAILURE;
706  }
707 
708  // Return gracefully.
709  return StatusCode::SUCCESS;
710 }
711 
723 StatusCode REvent::setAuxStore(const std::string& key,
725 
726  // Check if we need to do anything:
727  if ((Details::hasAuxStore(*(mgr.holder()->getClass())) == false) &&
728  (Details::isAuxStore(*(mgr.holder()->getClass())) == false)) {
729  return StatusCode::SUCCESS;
730  }
731 
732  // Select which object container to use:
734 
735  // Look up the auxiliary object's manager:
736  TVirtualManager* auxMgr = nullptr;
737  std::string auxKey;
738  if (Details::isAuxStore(*(mgr.holder()->getClass()))) {
739  auxMgr = &mgr;
740  auxKey = key;
741  } else {
742  auto itr = objects.find(key + "Aux.");
743  if (itr == objects.end()) {
744  // Apparently there's no auxiliary object for this DV, so let's
745  // give up.
746  return StatusCode::SUCCESS;
747  }
748  auxMgr = itr->second.get();
749  auxKey = key + "Aux:";
750  }
751 
752  if (!metadata) {
753  // Make sure the auxiliary object is up to date.
754  ::Int_t readBytes = auxMgr->getEntry();
755 
756  // Check if there is a separate auxiliary object for the dynamic
757  // variables, which would need to be updated.
758  const std::string dynAuxKey = auxKey + "Dynamic";
759  auto dynAuxMgr = objects.find(dynAuxKey);
760  if ((dynAuxMgr != objects.end()) && (readBytes || (auxMgr == &mgr))) {
761 
762  // Tell the dynamic store object to switch to a new entry.
763  dynAuxMgr->second->getEntry();
764  }
765  }
766 
767  // Stop here if we've set up an auxiliary store.
768  if (auxMgr == &mgr) {
769  return StatusCode::SUCCESS;
770  }
771 
772  // Access the auxiliary base class of the object/vector:
773  SG::AuxVectorBase* vec = 0;
774  SG::AuxElement* aux = 0;
775  switch (mgr.holder()->typeKind()) {
776  case THolder::DATAVECTOR: {
777  void* vvec = mgr.holder()->getAs(typeid(SG::AuxVectorBase));
778  vec = reinterpret_cast<SG::AuxVectorBase*>(vvec);
779  } break;
780  case THolder::AUXELEMENT: {
781  void* vaux = mgr.holder()->getAs(typeid(SG::AuxElement));
782  aux = reinterpret_cast<SG::AuxElement*>(vaux);
783  } break;
784  default:
785  break;
786  }
787 
788  // Check whether index tracking is enabled for the type. If not, then
789  // we need to fix it...
790  if (vec && (!vec->trackIndices())) {
791  Details::forceTrackIndices(*vec);
792  }
793 
794  // Check if we were successful:
795  if ((!vec) && (!aux)) {
796  ATH_MSG_FATAL("Couldn't access class \""
797  << mgr.holder()->getClass()->GetName()
798  << "\" as SG::AuxVectorBase or SG::AuxElement");
799  return StatusCode::FAILURE;
800  }
801 
802  // Get the concrete auxiliary manager:
803  RObjectManager* omgr = dynamic_cast<RObjectManager*>(auxMgr);
804  if (!omgr) {
805  ATH_MSG_FATAL("Auxiliary manager for \"" << auxKey
806  << "\" is not of the right type");
807  return StatusCode::FAILURE;
808  }
809  void* p = omgr->holder()->getAs(typeid(SG::IConstAuxStore));
810  const SG::IConstAuxStore* store =
811  reinterpret_cast<const SG::IConstAuxStore*>(p);
812  if (store == nullptr) {
813  ATH_MSG_FATAL("There's a logic error in the code");
814  return StatusCode::FAILURE;
815  }
816 
817  // Connect the two:
818  if (vec) {
819  vec->setStore(store);
820  } else if (aux) {
821  aux->setStore(store);
822  } else {
823  ATH_MSG_FATAL("There's a logic error in the code");
824  return StatusCode::FAILURE;
825  }
826 
827  // We succeeded:
828  return StatusCode::SUCCESS;
829 }
830 
831 StatusCode REvent::record(void*, const std::string&, const std::string&, bool,
832  bool, bool) {
833 
834  ATH_MSG_ERROR("xAOD::REvent::record not yet implemented");
835  return StatusCode::FAILURE;
836 }
837 
838 StatusCode REvent::recordAux(TVirtualManager&, const std::string&, bool) {
839 
840  ATH_MSG_ERROR("xAOD::REvent::recordAux not yet implemented");
841  return StatusCode::FAILURE;
842 }
843 
851 
852  // A little sanity check.
853  if (!m_eventReader) {
854  ATH_MSG_ERROR("Function called on an uninitialised object");
855  return StatusCode::FAILURE;
856  }
857 
858  // Reset the number of input branches information.
860 
861  // Loop over the EventFormat information.
862  for (const auto& [key, format] : m_inputEventFormat) {
863 
864  ATH_MSG_DEBUG("Investigating object \"" << key << "\" of class \""
865  << format.className() << "\"");
866 
867  // If it's an auxiliary container, scan it using RAuxStore.
868  if (key.ends_with("Aux.")) {
869 
870  // But first decide whether it describes a container, or just
871  // a single object. For that, first get the class that it was
872  // written with.
873  TClass* cl = TClass::GetClass(format.className().c_str());
874  if ((cl == nullptr) || (cl->IsLoaded() == false)) {
876  "Couldn't find the dictionary for type: " << format.className());
877  continue;
878  }
879 
880  // And then check if it inherits from xAOD::AuxContainerBase or from
881  // xAOD::AuxInfoBase.
882  static TClass* const auxContCl = TClass::GetClass(
884  static TClass* const auxInfoCl = TClass::GetClass(
886  if ((auxContCl == nullptr) || (auxInfoCl == nullptr)) {
888  "Couldn't get dictionary for xAOD::AuxContainerBase or "
889  "xAOD::AuxInfoBase");
890  return StatusCode::FAILURE;
891  }
892  const bool isContainer = cl->InheritsFrom(auxContCl);
893  const bool isInfo = cl->InheritsFrom(auxInfoCl);
894  if ((isContainer == false) && (isInfo == false)) {
895  ATH_MSG_WARNING("Auxiliary store \""
896  << key
897  << "\" is of an unknown type: " << format.className());
898  continue;
899  }
900  ATH_MSG_VERBOSE("isContainer = " << isContainer
901  << ", isInfo = " << isInfo);
902 
903  // Scan the branches using a temporary RAuxStore instance.
904  const std::string fieldName = key.substr(0, key.size() - 1) + ":";
908  static constexpr bool TOP_STORE = true;
909  RAuxStore temp(fieldName, TOP_STORE, mode);
911 
912  // Add all the auxids to the statistics object:
914  for (SG::auxid_t id : temp.getAuxIDs()) {
915  stats.branch(fieldName, id);
916  }
917 
918  // Increment the number of known branches.
919  stats.setBranchNum(stats.branchNum() + temp.getAuxIDs().size());
920  }
921  // If it's an interface container.
922  else {
923  // Check if it's part of the input ntuple.
924  if (m_eventReader->GetDescriptor().FindFieldId(key) !=
925  ROOT::kInvalidDescriptorId) {
927  }
928  }
929  }
930 
931  // Return gracefully:
932  return StatusCode::SUCCESS;
933 }
934 
944  ROOT::RNTupleReader& reader) {
945 
946  // The name of the field that the object is connected to.
947  const std::string fieldName = mgr.field().GetField().GetFieldName();
948 
949  // Check if we can call setName(...) on the object.
950  ::TMethodCall setNameCall;
951  setNameCall.InitWithPrototype(mgr.holder()->getClass(), "setName",
952  "const char*");
953  if (setNameCall.IsValid()) {
954  // Yes, there is such a function. Let's call it with the field
955  // name.
956  const ::TString params = ::TString::Format("\"%s\"", fieldName.c_str());
957  const char* charParams = params.Data();
958  setNameCall.Execute(mgr.holder()->get(), charParams);
959  } else {
960  // This is weird. What sort of auxiliary container is this? :-/
961  ATH_MSG_WARNING("Couldn't find setName(...) function for container \""
962  << fieldName << "\" (type: "
963  << mgr.holder()->getClass()->GetName() << ")");
964  }
965 
966  // Check if we can switch out the internal store of this object:
967  static const TClass* const holderClass =
968  TClass::GetClass(typeid(SG::IAuxStoreHolder));
969  if (!mgr.holder()->getClass()->InheritsFrom(holderClass)) {
970  // Nope... So let's just end the journey here.
971  return StatusCode::SUCCESS;
972  }
973 
974  // Try to get the object as an IAuxStoreHolder:
975  SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder*>(
976  mgr.holder()->getAs(typeid(SG::IAuxStoreHolder)));
977  if (!storeHolder) {
978  ATH_MSG_FATAL("There's a logic error in the code");
979  return StatusCode::FAILURE;
980  }
981 
982  // Create an RAuxStore instance that will read the dynamic variables
983  // of this container. Notice that the RAuxManager doesn't own the
984  // RAuxStore object. It will be owned by the SG::IAuxStoreHolder
985  // object.
986  static constexpr bool TOP_STORE = false;
987  auto store = std::make_unique<RAuxStore>(
988  fieldName, TOP_STORE,
992  // This object is used to read data from the input, it needs to be
993  // locked:
994  store->lock();
995 
996  // Set it up to read from the input RNTuple.
997  ATH_CHECK(store->readFrom(reader));
998  // Tell the auxiliary store which entry to use. This is essential for
999  // metadata objects, and non-important for event data objects, which will
1000  // get a possibly different entry loaded in setAuxStore(...).
1001  ATH_CHECK(store->getEntry(0));
1002 
1003  // Set up a manager for it.
1004  static constexpr bool SHARED_OWNER = false;
1005  m_inputObjects[fieldName + "Dynamic"] =
1006  std::make_unique<RAuxManager>(store.get(), m_entry, SHARED_OWNER);
1007 
1008  // Give this object to the store holder.
1009  storeHolder->setStore(store.release());
1010 
1011  // Return gracefully:
1012  return StatusCode::SUCCESS;
1013 }
1014 
1015 } // namespace xAOD::Experimental
xAOD::AuxInfoBase
Common base class for auxiliary info objects.
Definition: AuxInfoBase.h:45
mergePhysValFiles.pattern
pattern
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:25
SGTest::store
TestStore store
Definition: TestStore.cxx:23
xAOD::EventFormat_v1::get
const EventFormatElement * get(const std::string &key, bool quiet=false) const
Get the description of a given branch.
Definition: EventFormat_v1.cxx:91
xAOD::THolder::AUXELEMENT
@ AUXELEMENT
A type inheriting from SG::AuxElement.
Definition: THolder.h:106
xAOD::Experimental::REvent::connectObject
StatusCode connectObject(const std::string &key, bool silent) override
Function setting up access to a particular object.
Definition: REvent.cxx:352
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
xAOD::Experimental::REvent::setAuxStore
StatusCode setAuxStore(const std::string &key, Details::IObjectManager &mgr, bool metadata) override
Function connecting a DV object to its auxiliary store.
Definition: REvent.cxx:723
IAuxStoreHolder.h
get_generator_info.result
result
Definition: get_generator_info.py:21
SG::IAuxStoreHolder::getStoreType
virtual AuxStoreType getStoreType() const =0
Return the type of the store object.
LArConditions2Ntuple.objects
objects
Definition: LArConditions2Ntuple.py:64
vtune_athena.format
format
Definition: vtune_athena.py:14
xAOD::Experimental::REvent::connectMetaAux
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:648
xAOD::IOStats::stats
ReadStats & stats()
Access the object belonging to the current thread.
Definition: IOStats.cxx:17
L1CaloPhase1Monitoring.standalone
standalone
Definition: L1CaloPhase1Monitoring.py:139
RAuxManager.h
xAOD::details::AuxStoreBase::getAuxIDs
virtual const SG::auxid_set_t & getAuxIDs() const override
Get the types(names) of variables handled by this container.
Definition: AuxStoreBase.cxx:106
xAOD::Experimental::REvent::connectMetaObject
StatusCode connectMetaObject(const std::string &key, bool silent) override
Function setting up access to a particular metadata object.
Definition: REvent.cxx:490
xAOD::Experimental::REvent::getEntries
::Long64_t getEntries() const
Get how many entries are available from the current input file(s)
Definition: REvent.cxx:252
xAOD::Event::m_inputObjects
Object_t m_inputObjects
Collection of all the managed input objects.
Definition: Event.h:308
xAOD::Experimental::RObjectManager
Manager for EDM objects created by ROOT.
Definition: RObjectManager.h:30
SG::normalizedTypeinfoName
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...
Definition: normalizedTypeinfoName.cxx:120
RAuxStore.h
xAOD::Event::m_inputEventFormat
EventFormat m_inputEventFormat
Format of the current input file.
Definition: Event.h:321
SG::AuxElement
Base class for elements of a container that can have aux data.
Definition: AuxElement.h:483
xAOD::THolder::DATAVECTOR
@ DATAVECTOR
A DataVector container.
Definition: THolder.h:105
xAOD::THolder::getAs
virtual void * getAs(const std::type_info &tid, ::Bool_t silent=kFALSE) const
Return the object as a specific pointer.
Definition: THolder.cxx:370
AuxInfoBase.h
makeTOC.inFile
string inFile
Definition: makeTOC.py:5
StateLessPT_NewConfig.Format
Format
Definition: StateLessPT_NewConfig.py:149
xAOD::Details::IObjectManager::holder
const THolder * holder() const
Accessor to the Holder object.
Definition: IObjectManager.cxx:43
xAOD::Event::setActive
void setActive() const
Set this event object as the currently active one.
Definition: EventCore.cxx:54
xAOD::TVirtualManager::getEntry
virtual ::Int_t getEntry(::Int_t getall=0)=0
Function for updating the object in memory if needed.
xAOD::details::AuxStoreBase::EStructMode
EStructMode
"Structural" modes of the object
Definition: AuxStoreBase.h:30
AuxContainerBase.h
xAOD::Experimental
Definition: REvent.cxx:67
xAOD::AuxContainerBase
Common base class for the auxiliary containers.
Definition: AuxContainerBase.h:55
xAOD::RAuxStore
"ROOT @c RNTuple implementation" of IAuxStore
Definition: RAuxStore.h:38
xAOD::Experimental::REvent::hasOutput
bool hasOutput() const override
Check if an output file is connected to the object.
Definition: REvent.cxx:322
xAOD::ReadStats::container
BranchStats * container(const std::string &name)
Access the description of a container. Creating it if necessary.
xAOD::TVirtualIncidentListener
Class providing an interface for classes listening to xAOD incidents.
Definition: TVirtualIncidentListener.h:25
xAOD::EventFormatElement
Class describing one branch of the ROOT file.
Definition: EventFormatElement.h:35
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:9
python.RatesEmulationExample.lock
lock
Definition: RatesEmulationExample.py:148
ReadOfcFromCool.field
field
Definition: ReadOfcFromCool.py:48
Utils.h
xAOD::Experimental::REvent::m_inputNTupleIsMissing
bool m_inputNTupleIsMissing
Whether the input has an event RNTuple or not.
Definition: REvent.h:104
xAOD::TVirtualManager
Interface class for the "manager classes".
Definition: TVirtualManager.h:24
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::Experimental::REvent::getEntry
::Int_t getEntry(::Long64_t entry, ::Int_t getall=0)
Function loading a given entry of the input TTree.
Definition: REvent.cxx:278
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
IOStats.h
TVirtualIncidentListener.h
xAOD::Experimental::REvent::connectAux
StatusCode connectAux(const std::string &prefix, bool standalone) override
Function setting up access to a set of auxiliary branches.
Definition: REvent.cxx:576
xAOD::Experimental::REvent::recordAux
StatusCode recordAux(TVirtualManager &mgr, const std::string &key, bool metadata) override
Record an auxiliary store into a connected output file.
Definition: REvent.cxx:838
trigbs_dumpHLTContentInBS.stats
stats
Definition: trigbs_dumpHLTContentInBS.py:91
xAOD::details::AuxStoreBase::EStructMode::kObjectStore
@ kObjectStore
The object describes a single object.
xAOD::Event::m_listeners
std::vector< TVirtualIncidentListener * > m_listeners
Listeners who should be notified when certain incidents happen.
Definition: Event.h:329
AuxVectorBase.h
Manage index tracking and synchronization of auxiliary data.
xAOD::details::AuxStoreBase::EStructMode::kContainerStore
@ kContainerStore
The object describes an entire container.
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
SG::AuxVectorBase
Manage index tracking and synchronization of auxiliary data.
Definition: AuxVectorBase.h:98
xAOD::Event::Object_t
std::unordered_map< std::string, std::unique_ptr< TVirtualManager > > Object_t
Definition of the internal data structure type.
Definition: Event.h:305
xAOD::Event::m_inputMetaObjects
Object_t m_inputMetaObjects
Collection of all the managed input meta-objects.
Definition: Event.h:316
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
xAOD::Experimental::REvent::readFrom
StatusCode readFrom(std::string_view fileName)
Set up the reading of an input file.
Definition: REvent.cxx:90
xAOD::ReadStats::nextEvent
void nextEvent()
Function incrementing the processed event counter.
xAOD::THolder::getClass
const ::TClass * getClass() const
Definition: THolder.cxx:401
PrepareReferenceFile.regex
regex
Definition: PrepareReferenceFile.py:43
python.checkMetadata.metadata
metadata
Definition: checkMetadata.py:175
BchCleanup.mgr
mgr
Definition: BchCleanup.py:294
REvent.h
SG::auxid_t
size_t auxid_t
Identifier for a particular aux data item.
Definition: AuxTypes.h:27
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
CxxUtils::ConcurrentBitset::size
bit_t size() const
Count the number of 1 bits in the set.
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ReadStats.h
xAOD::Utils::getTypeName
std::string getTypeName(const std::type_info &ti)
This function is necessary in order to create type names that ROOT can understand.
Definition: Control/xAODRootAccess/Root/Utils.cxx:354
SG::AuxElement::setStore
void setStore(const SG::IConstAuxStore *store)
Set the store associated with this object.
Definition: AuxElement.cxx:241
xAOD::Experimental::REvent::REvent
REvent()
Default constructor.
Definition: REvent.cxx:73
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::TIncident
Class describing a certain "incident" that is communicated to user code.
Definition: TIncident.h:58
taskman.fieldName
fieldName
Definition: taskman.py:489
xAOD::Event::m_branchesMutex
upgrade_mutex_t m_branchesMutex
Mutex for multithread synchronization.
Definition: Event.h:354
checkCorrelInHIST.prefix
dictionary prefix
Definition: checkCorrelInHIST.py:391
xAOD::Details::isStandalone
bool isStandalone(const TClass &cl)
Helper function deciding if a given type "is a standalone object".
Definition: IOUtils.cxx:65
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
Preparation.mode
mode
Definition: Preparation.py:107
xAOD::ReadStats::setBranchNum
void setBranchNum(::Int_t num)
Set the total number of branches on the input.
xAOD::Experimental::REvent::setUpDynamicStore
StatusCode setUpDynamicStore(RObjectManager &mgr, ROOT::RNTupleReader &ntupleReader)
event uses RNTupleReader:
Definition: REvent.cxx:943
plotmaker.keyName
keyName
Definition: plotmaker.py:145
xAOD::IOStats::instance
static IOStats & instance()
Singleton object accessor.
Definition: IOStats.cxx:11
xAOD::Experimental::REvent::hasInput
bool hasInput() const override
Check if an input file is connected to the object.
Definition: REvent.cxx:317
normalizedTypeinfoName.h
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
xAOD::Experimental::REvent::~REvent
virtual ~REvent()
Destructor.
Definition: REvent.cxx:75
SG::IAuxStoreHolder::setStore
virtual void setStore(IAuxStore *store)=0
Give an auxiliary store object to the holder object.
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
xAOD::Event::m_inputMissingObjects
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
xAOD::RAuxStore::readFrom
StatusCode readFrom(ROOT::RNTupleReader &reader)
Connect the object to an input RNTuple.
Definition: RAuxStore.cxx:615
xAOD::Event::m_outputObjects
Object_t m_outputObjects
Collection of all the managed output object.
Definition: Event.h:313
xAOD::EventFormat_v1
Event format metadata for xAOD files.
Definition: EventFormat_v1.h:38
IOUtils.h
xAOD::ReadStats::readContainer
void readContainer(const std::string &name)
Function incrementing the read counter on a specific container.
xAOD::Experimental::REvent::m_entry
::Long64_t m_entry
The entry to look at from the input tree.
Definition: REvent.h:109
xAOD::Experimental::REvent::record
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:831
python.trfDecorators.silent
def silent(func)
Redirect stdout/err to /dev/null Useful wrapper to get rid of ROOT verbosity...
Definition: trfDecorators.py:24
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
THolder.h
xAOD::Experimental::REvent::m_metaReader
std::unique_ptr< ROOT::RNTupleReader > m_metaReader
The metadata reader.
Definition: REvent.h:106
AthContainers_detail::upgrading_lock
Lock object for taking out upgradable locks.
Definition: threading.h:177
xAOD::Details::hasAuxStore
bool hasAuxStore(const TClass &cl)
Helper function deciding if a given type "has an auxiliary store".
Definition: IOUtils.cxx:40
xAOD::Experimental::REvent::initStats
StatusCode initStats()
Function to initialise the statistics for all Tree content.
Definition: REvent.cxx:850
jobOptions.fileName
fileName
Definition: jobOptions.SuperChic_ALP2.py:39
PowhegControl_ttFCNC_NLO.params
params
Definition: PowhegControl_ttFCNC_NLO.py:226
collisions.reader
reader
read the goodrunslist xml file(s)
Definition: collisions.py:22
xAOD::EventFormat_v1::add
void add(const EventFormatElement &element, bool updatePersistent=true)
Add the description of a new branch.
Definition: EventFormat_v1.cxx:43
xAOD::Details::IObjectManager
Manager for EDM objects created by ROOT.
Definition: IObjectManager.h:20
xAOD::ReadStats
Class describing the access statistics of a collection of branches.
Definition: ReadStats.h:123
xAOD::Event
Base class for the event (xAOD::TEvent and xAOD::REvent) classes.
Definition: Event.h:59
SG::IConstAuxStore
Interface for const operations on an auxiliary store.
Definition: IConstAuxStore.h:64
python.PyAthena.obj
obj
Definition: PyAthena.py:132
SG::IAuxStoreHolder::AST_ObjectStore
@ AST_ObjectStore
The store describes a single object.
Definition: IAuxStoreHolder.h:67
SG::IAuxStoreHolder
Interface for objects taking part in direct ROOT I/O.
Definition: IAuxStoreHolder.h:36
xAOD::Experimental::REvent::m_eventReader
std::unique_ptr< ROOT::RNTupleReader > m_eventReader
The main event data reader.
Definition: REvent.h:102
TIncident.h
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:25
LArL1Calo_ComputeHVCorr.className
className
Definition: LArL1Calo_ComputeHVCorr.py:135
xAOD::Experimental::REvent::getNames
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:327
TActiveStore.h
LheEventFiller_Common.ef
ef
Definition: SFGen_i/share/common/LheEventFiller_Common.py:7
TStore.h
xAOD::EventFormat_v1::exists
bool exists(const std::string &key) const
Check if a description exists about a given branch.
Definition: EventFormat_v1.cxx:65
AuxElement.h
Base class for elements of a container that can have aux data.
RObjectManager.h
SG::IAuxStoreHolder::AST_ContainerStore
@ AST_ContainerStore
The store describes a container.
Definition: IAuxStoreHolder.h:68
drawFromPickle.view
view
Definition: drawFromPickle.py:294
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
xAOD::Details::isAuxStore
bool isAuxStore(const TClass &cl)
Helper function deciding if a given type "is an auxiliary store".
Definition: IOUtils.cxx:53