ATLAS Offline Software
Loading...
Searching...
No Matches
Control/xAODRootAccess/Root/TEvent.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3// Local include(s).
5
6#include "IOUtils.h"
7
8// System include(s):
9#include <cassert>
10#include <cstring>
11#include <iomanip>
12#include <sstream>
13
14// ROOT include(s):
15#include <TBranch.h>
16#include <TChain.h>
17#include <TChainElement.h>
18#include <TError.h>
19#include <TFile.h>
20#include <TFriendElement.h>
21#include <TKey.h>
22#include <TMethodCall.h>
23#include <TSystem.h>
24#include <TTree.h>
25
26// Gaudi/Athena include(s):
33#ifndef XAOD_STANDALONE
35#include "SGTools/DataProxy.h"
36#endif // not XAOD_STANDALONE
37#include "CxxUtils/ClassName.h"
39
40// Interface include(s):
42
43// xAOD include(s):
48
49// Local include(s):
67
68namespace xAOD {
69
71static const ::Int_t CACHE_SIZE = -1;
72
73TEvent::TEvent(EAuxMode mode) : Event("xAOD::TEvent"), m_auxMode(mode) {}
74
75TEvent::TEvent(::TFile* file, EAuxMode mode) : TEvent(mode) {
76
77 // Let the initialisation function deal with setting up the object.
78 readFrom(file).ignore();
79}
81TEvent::TEvent(::TTree* tree, EAuxMode mode) : TEvent(mode) {
83 // Let the initialisation function deal with setting up the object.
84 readFrom(tree).ignore();
85}
86
88
89 // Check that the user didn't forget to call finishWritingTo().
90 if (m_outTree) {
92 "Did not call finishWritingTo() before destroying the TEvent object!");
93 }
94
95 // Clear the input and output objects before the input/output files would be
96 // closed. Otherwise we can be left with "TTree related" objects pointing
97 // nowhere.
98 m_inputObjects.clear();
99 m_outputObjects.clear();
100}
101
105
106void TEvent::setOtherMetaDataTreeNamePattern(const std::string &pattern) {
107 // Only change if pattern provided is not empty
108 if (pattern.size()) {
109 // User provided a regular expression for other MetaData trees
110 m_otherMetaDataTreeNamePattern = std::regex(pattern);
111 }
112}
113
115StatusCode TEvent::readFrom(TFile& inFile) {
116 ATH_CHECK(readFrom(&inFile));
117 return StatusCode::SUCCESS;
118}
119
120
130StatusCode TEvent::readFrom(::TFile* file, bool useTreeCache,
131 std::string_view treeName) {
132
133 // If no file was specified, return gracefully.
134 if (file == nullptr) {
135 ATH_MSG_DEBUG("No input file specified for readFrom(...)");
136 return StatusCode::SUCCESS;
137 }
138
139 // Clear the cached input objects.
140 m_inputObjects.clear();
141 m_inputMissingObjects.clear();
142 m_inputMetaObjects.clear();
143 {
145 lock.upgrade();
146 m_branches.clear();
147 }
148
149 // Reset the internal flags.
150 m_inTreeMissing = kFALSE;
151 m_entry = -1;
152
153 // Make sure we return to the current directory:
155
156 // Set up the file access tracer.
158
159 // Look for the metadata tree:
161 if (m_inMetaTree == nullptr) {
162 ATH_MSG_ERROR("Couldn't find metadata tree on input. Object is unusable!");
163 return StatusCode::FAILURE;
164 }
165
166 // Set metadata entry to be read
167 // NB: no reading is done calling LoadTree
168 if (m_inMetaTree->LoadTree(0) < 0) {
169 ATH_MSG_ERROR("Failed to load entry 0 for metadata tree");
170 return StatusCode::FAILURE;
171 }
172
173 // A sanity check.
174 if (m_inMetaTree->GetEntries() != 1) {
175 ATH_MSG_WARNING("Was expecting a metadata tree with size 1, instead of "
176 << m_inMetaTree->GetEntries() << ".");
177 ATH_MSG_WARNING("The input file was most probably produced by hadd...");
178 }
179
180 // Make sure that the xAOD::EventFormat dictonary is loaded.
181 // This may not be the case if streamer information reading is turned
182 // off.
183 static const std::string eventFormatTypeName =
185 ::TClass* cl = ::TClass::GetClass(eventFormatTypeName.c_str());
186 if (cl == nullptr) {
187 ATH_MSG_WARNING("Couldn't load the xAOD::EventFormat dictionary");
188 }
189
190 // Helper lambda for collecting the event format metadata from an RNTuple
191 // with a given name.
192 auto readEventFormatMetadata =
193 [&](std::string_view thisTreeName) -> StatusCode {
194 // Look for the metadata tree:
195 TTree* metaTree = file->Get<TTree>(thisTreeName.data());
196 if (metaTree == nullptr) {
197 ATH_MSG_ERROR("Couldn't find metadata tree \"" << thisTreeName
198 << "\"on input.");
199 return StatusCode::FAILURE;
200 }
201 // Set metadata entry to be read.
202 if (metaTree->LoadTree(0) < 0) {
203 ATH_MSG_ERROR("Failed to load entry 0 for metadata tree \""
204 << thisTreeName << "\"");
205 return StatusCode::FAILURE;
206 }
207
208 // Check if the EventFormat branch is available:
209 const std::string eventFormatBranchName =
211 if (!metaTree->GetBranch(eventFormatBranchName.c_str())) {
212 // This can happen when the file was produced by an Athena job that
213 // didn't have any input events itself. This means that the file
214 // doesn't actually have any useful metadata.
215 ATH_MSG_INFO("Input file provides no event or metadata");
216 return StatusCode::RECOVERABLE;
217 }
218
219 // Read in the event format object:
220 EventFormat* format = 0;
221 ::TBranch* br = 0;
222 const Int_t status =
223 metaTree->SetBranchAddress(eventFormatBranchName.c_str(), &format, &br);
224 if (status < 0) {
225 ATH_MSG_ERROR("Failed to connect to xAOD::EventFormat object");
226 return StatusCode::FAILURE;
227 }
228
229 // Merge the object into our private member.
230 br->GetEntry(0);
231 for (const auto &[key, element] : *format) {
232 m_inputEventFormat.add(element);
233 }
234
235 // This is a strange place. The object has to be deleted, as it is the
236 // responsibility of the user code to do so. But if I also explicitly
237 // tell the branch to forget about the address of the pointer, then
238 // all hell breaks loose...
239 delete format;
240
241 // Return gracefully.
242 return StatusCode::SUCCESS;
243 };
244
245 // Read in the metadata from the "main" metadata ntuple.
247 const StatusCode sc = readEventFormatMetadata(METADATA_OBJECT_NAME);
248 if (sc.isRecoverable()) {
249 m_inTree = nullptr;
250 m_inTreeMissing = true;
251 return StatusCode::SUCCESS;
252 }
253 ATH_CHECK(sc);
254
255 // List all the other Metadata trees in the input file
256 // Having several metatrees can happen for augmented files for instance
257 // as one metadata tree per stream is produced
258 std::set<std::string> lOtherMetaTreeNames = {};
259 TList* lKeys = file->GetListOfKeys();
260
261 if (lKeys) {
262 for (int iKey = 0; iKey < lKeys->GetEntries(); iKey++) {
263 // iterate over keys and add
264 std::string keyName = lKeys->At(iKey)->GetName();
265 // Make sure the key corresponds to a metadata tree but
266 // do not add the current metadata tree in the list of other trees
267 // and do not add the metadata tree handlers to the list
268 if ((keyName != METADATA_OBJECT_NAME) &&
269 std::regex_match(keyName, m_otherMetaDataTreeNamePattern)) {
270 // Make sure key corresponds to a tree
271 const char* className = ((::TKey* )lKeys->At(iKey))->GetClassName();
272 static constexpr Bool_t LOAD = kFALSE;
273 static constexpr Bool_t SILENT = kTRUE;
274 ::TClass* cl = ::TClass::GetClass(className, LOAD, SILENT);
275 if ((cl != nullptr) && cl->InheritsFrom(::TTree::Class())) {
276 // key is corresponding to a metadata tree
277 lOtherMetaTreeNames.insert(std::move(keyName));
278 }
279 }
280 }
281 }
282
283 // Loop over the other metadata trees found (if any).
284 for (const std::string &metaTreeName : lOtherMetaTreeNames) {
285 ATH_CHECK(readEventFormatMetadata(metaTreeName));
286 }
287
288 // Look for the event tree in the input file.
289 m_inTree = file->Get<TTree>(treeName.data());
290 if (m_inTree == nullptr) {
291 // This is no longer an error condition. As it can happen for DxAODs
292 // that don't have any events in them. But they still have metadata
293 // that needs to be collected.
294 m_inTreeMissing = kTRUE;
295 }
296
297 // Turn on the cache if requested.
298 if (m_inTree && useTreeCache && (!m_inTree->GetCacheSize())) {
299 m_inTree->SetCacheSize(CACHE_SIZE);
300 m_inTree->SetCacheLearnEntries(10);
301 }
302
303 // Init the statistics collection.
305 // Update the event counter in the statistics object.
307 if (m_inTree) {
308 stats.setNEvents(stats.nEvents() + m_inTree->GetEntries());
309 }
310
311 // Notify the listeners that a new file was opened.
312 const TIncident beginIncident(IncidentType::BeginInputFile);
313 for (TVirtualIncidentListener* listener : m_listeners) {
314 listener->handle(beginIncident);
315 }
316 // For now implement a very simple scheme in which we claim already
317 // at the start that the entire file was processed. Since we have no way
318 // of ensuring that the user indeed does this. And we can't delay calling
319 // this function, as the user may likely close his/her output file before
320 // closing the last opened input file.
321 const TIncident endIncident(IncidentType::EndInputFile);
322 for (TVirtualIncidentListener* listener : m_listeners) {
323 listener->handle(endIncident);
324 }
325
326 // The initialisation was successful.
327 return StatusCode::SUCCESS;
328}
329
338StatusCode TEvent::readFrom(::TTree* tree, bool useTreeCache) {
339
340 // Remember the info:
341 m_inTree = nullptr;
342 m_inTreeMissing = false;
343 m_inChain = dynamic_cast<TChain* >(tree);
344 m_inMetaTree = nullptr;
345
346 if (m_inChain) {
347
348 // Set up the caching on the chain level. The individual trees of the
349 // input files will get a cache set up automatically after this.
350 if (useTreeCache && (!m_inChain->GetCacheSize())) {
351 m_inChain->SetCacheSize(CACHE_SIZE);
352 m_inChain->SetCacheLearnEntries(10);
353 }
354
355 // Explicitly open the first file of the chain. To correctly auto-load
356 // the dictionaries necessary. This doesn't happen automatically with
357 // some ROOT versions...
358 const TObjArray* files = m_inChain->GetListOfFiles();
359 if (!files) {
360 ATH_MSG_ERROR("Couldn't get the list of files from the input TChain");
361 return StatusCode::FAILURE;
362 }
363 if (!files->GetEntries()) {
364 ATH_MSG_ERROR("No files are present in the received TChain");
365 return StatusCode::FAILURE;
366 }
367 const ::TChainElement* chEl =
368 dynamic_cast<const ::TChainElement* >(files->At(0));
369 if (!chEl) {
370 ATH_MSG_ERROR("Couldn't cast object to TChainElement");
371 return StatusCode::FAILURE;
372 }
373 {
374 std::unique_ptr<TFile> dummyFile{TFile::Open(chEl->GetTitle())};
375 if (!dummyFile) {
376 ATH_MSG_ERROR("Couldn't open file " << chEl->GetTitle());
377 return StatusCode::FAILURE;
378 }
379 }
380
381 // Set up a tracker for the chain.
382 if (!m_inChainTracker) {
383 m_inChainTracker = std::make_unique<TChainStateTracker>();
384 }
385 m_inChainTracker->reset();
386 tree->SetNotify(m_inChainTracker.get());
387
388 // Stop at this point. The first file will be opened when the user
389 // asks for the first event. Otherwise we open the first file of the
390 // chain multiple times.
391 m_inTreeNumber = -1;
392 return StatusCode::SUCCESS;
393
394 } else {
395
396 // If it's a simple TTree, then let's fully initialise the object
397 // using its file:
398 m_inTreeNumber = -1;
399 if (m_inChainTracker) {
400 m_inChainTracker.reset();
401 }
402 ::TFile* file = tree->GetCurrentFile();
403 return readFrom(file, useTreeCache, tree->GetName());
404 }
405}
406
407
414StatusCode TEvent::writeTo(TFile& file) {
415
416 // Forward call
418
419 // Return gracefully:
420 return StatusCode::SUCCESS;
421}
422
431StatusCode TEvent::writeTo(::TFile* file, int autoFlush,
432 std::string_view treeName) {
433
434 // Just a simple security check.
435 if (!file) {
436 ATH_MSG_ERROR("Null pointer received!");
437 return StatusCode::FAILURE;
438 }
439
440 // Check that the object is in the "right state":
441 if (m_outTree) {
442 ATH_MSG_ERROR("Object already writing to a file. Close that file first!");
443 return StatusCode::FAILURE;
444 }
445
446 // Make sure we return to the current directory:
448
449 // Create the output TTree:
450 file->cd();
451 m_outTree = std::make_unique<TTree>(treeName.data(), "xAOD event tree");
452 m_outTree->SetDirectory(file);
453 m_outTree->SetAutoSave(1000000);
454 m_outTree->SetAutoFlush(autoFlush);
455
456 // Access the EventFormat object associated with this file:
459
460 // Return gracefully:
461 return StatusCode::SUCCESS;
462}
463
470StatusCode TEvent::finishWritingTo(TFile& file) {
471 return finishWritingTo(&file);
472}
473
480StatusCode TEvent::finishWritingTo(::TFile* file) {
481
482 // A small sanity check:
483 if (!m_outTree) {
484 ATH_MSG_ERROR("The object doesn't seem to be connected to an output file!");
485 return StatusCode::FAILURE;
486 }
487
488 // Make sure we return to the current directory:
490
491 // Notify the listeners that they should write out their metadata, if they
492 // have any.
494 for (auto &listener : m_listeners) {
495 listener->handle(incident);
496 }
497
498 // Write out the event tree, and delete it:
499 m_outTree->AutoSave("FlushBaskets");
500 m_outTree->SetDirectory(0);
501 m_outTree.reset();
502
503 // Now go to the output file:
504 file->cd();
505
506 // Check if there's already a metadata tree in the output:
507 if (file->Get(METADATA_OBJECT_NAME)) {
508 // Let's assume that the metadata is complete in the file already.
509 return StatusCode::SUCCESS;
510 }
511
512 // Create the metadata tree.
513 auto metatree =
514 std::make_unique<TTree>(METADATA_OBJECT_NAME, "xAOD metadata tree");
515 metatree->SetAutoSave(10000);
516 metatree->SetAutoFlush(-30000000);
517 metatree->SetDirectory(file);
518
519 // Create the xAOD::EventFormat branch in it.
520 try {
521 metatree->Branch(
522 "EventFormat",
525 } catch (const CxxUtils::ClassName::ExcBadClassName &e) {
526 ::Error("xAOD::TEvent::finishWritingTo",
527 XAOD_MESSAGE("Class name parsing fails for %s ! "), e.what());
528 return StatusCode::FAILURE;
529 }
530
531 // Create a copy of the m_outputMetaObjects variable. This is necessary
532 // because the putAux(...) function will modify this variable while we
533 // loop over it.
534 std::vector<std::pair<std::string, TObjectManager* >> outputMetaObjects;
535 outputMetaObjects.reserve(m_outputMetaObjects.size());
536 for (const auto &[key, mgr] : m_outputMetaObjects) {
537 TObjectManager* objMgr = dynamic_cast<TObjectManager* >(mgr.get());
538 if (objMgr == nullptr) {
539 ATH_MSG_FATAL("Internal logic error detected");
540 return StatusCode::FAILURE;
541 }
542 outputMetaObjects.emplace_back(key, objMgr);
543 }
544
545 // Now loop over all the metadata objects that need to be put into the
546 // output file:
547 for (auto &[key, mgr] : outputMetaObjects) {
548
549 // Select a split level depending on whether this is an interface or an
550 // auxiliary object:
551 const ::Int_t splitLevel = (key.ends_with("Aux.") ? 1 : 0);
552 // Create the new branch:
553 *(mgr->branchPtr()) =
554 metatree->Branch(key.c_str(), mgr->holder()->getClass()->GetName(),
555 mgr->holder()->getPtr(), 32000, splitLevel);
556 if (!mgr->branch()) {
557 ATH_MSG_ERROR("Failed to create metadata branch \""
558 << mgr->holder()->getClass()->GetName() << "/" << key
559 << "\"");
560 return StatusCode::FAILURE;
561 }
562 // Set up the saving of all the dynamic auxiliary properties
563 // of the object if it has any:
564 static constexpr bool METADATA = true;
565 ATH_CHECK(putAux(*metatree, *mgr, METADATA));
566 }
567
568 // Write the metadata objects:
569 if (metatree->Fill() <= 0) {
570 ATH_MSG_ERROR("Failed to write event format metadata into the output");
571 metatree->SetDirectory(nullptr);
572 return StatusCode::FAILURE;
573 }
574
575 // Now clean up:
576 metatree->Write();
577 metatree->SetDirectory(nullptr);
578 m_outputEventFormat = nullptr;
579 m_outputObjects.clear();
580 m_outputMetaObjects.clear();
581
582 // Return gracefully:
583 return StatusCode::SUCCESS;
584}
585
595SG::IAuxStore* TEvent::recordAux(const std::string &key,
597
598 // A sanity check:
599 if (!m_outTree) {
600 ATH_MSG_ERROR("No output tree given to the object");
601 return nullptr;
602 }
603
604 // Check for an object with this name in the output list:
605 Object_t::iterator itr = m_outputObjects.find(key);
606 if (itr == m_outputObjects.end()) {
607 // Create one if if it doesn't exist yet...
608 // Translate the store type:
610 switch (type) {
613 break;
616 break;
617 default:
618 ATH_MSG_ERROR("Unknown store type (" << type << ") requested");
619 return nullptr;
620 }
621 // Create and record the object:
622 static constexpr bool TOP_STORE = true;
623 if (record(std::make_unique<TAuxStore>(key, TOP_STORE, mode), key)
624 .isFailure()) {
625 ATH_MSG_ERROR("Couldn't connect TAuxStore object to the output");
626 return nullptr;
627 }
628 // Update the iterator:
629 itr = m_outputObjects.find(key);
630 }
631
632 // A security check:
633 if (itr == m_outputObjects.end()) {
634 ATH_MSG_ERROR("Internal logic error detected");
635 return nullptr;
636 }
637
638 // Check that it is of the right type:
639 TAuxManager* mgr = dynamic_cast<TAuxManager* >(itr->second.get());
640 if (!mgr) {
641 ATH_MSG_ERROR("Internal logic error detected");
642 return nullptr;
643 }
644
645 // Extract the pointer out of it:
646 TAuxStore* store = mgr->getStore();
647
648 // Give it to the user:
649 return store;
650}
651
654::Long64_t TEvent::getEntries() const {
655
656 if (m_inChain) {
657 return m_inChain->GetEntries();
658 } else if (m_inTree) {
659 return m_inTree->GetEntries();
660 } else if (m_inTreeMissing) {
661 // The input file is empty:
662 return 0;
663 } else {
664 ATH_MSG_ERROR("Function called on an uninitialised object");
665 return 0;
666 }
667}
668
683::Int_t TEvent::getEntry(::Long64_t entry, ::Int_t getall) {
684
685 // A little sanity check:
686 if ((!m_inTree) && (!m_inChain)) {
687 ATH_MSG_ERROR("Function called on an uninitialised object");
688 return -1;
689 }
690
691 // If we have a chain as input:
692 if (m_inChain) {
693 // Make sure that the correct tree is loaded:
694 const ::Long64_t fileEntry = m_inChain->LoadTree(entry);
695 if (fileEntry < 0) {
696 ATH_MSG_ERROR("Failure in loading entry " << entry
697 << " from the input chain");
698 return -1;
699 }
700 // Check if a new file was loaded:
701 if ((m_inTreeNumber != m_inChain->GetTreeNumber()) ||
702 m_inChainTracker->internalStateChanged()) {
703 // Reset the tracker:
704 m_inChainTracker->reset();
705 // Connect to this new file:
706 m_inTreeNumber = m_inChain->GetTreeNumber();
707 ::TFile* file = m_inChain->GetFile();
708 // The useTreeCache parameter is set to false, since the cache
709 // is anyway set up through the TChain. It shouldn't be modified
710 // on the file level.
711 static constexpr bool USE_TREE_CACHE = false;
712 if (readFrom(file, USE_TREE_CACHE, m_inChain->GetName()).isFailure()) {
713 ATH_MSG_ERROR("Couldn't connect to input file #"
714 << m_inTreeNumber << " of the input chain");
715 return -1;
716 }
717 }
718 // Restore the previously received entry number.
719 m_entry = fileEntry;
720 }
721 // If we have a regular file/tree as input:
722 else {
723 m_entry = entry;
724 }
725
726 // In order to make the reading of branches+tree cache work
727 // NB: TTree::LoadTree() only set the entry that should be read for each
728 // branch but no reading of the branch content is performed when calling that
729 // function. The entry set that can be retrieved with
730 // branch->GetTree()->GetReadEntry()
731 // For friend trees, if an index was built, then the entry which is set for
732 // the related branches is found by the LoadTree function by matching the the
733 // major and minor values of the main tree and friend tree
734 if (m_inTree && m_inTree->LoadTree(m_entry) < 0) {
735 ATH_MSG_ERROR("Failure in loading entry " << m_entry
736 << " from the input file");
737 return -1;
738 }
739
740 // Stats counter needs to know it's the next event:
742
743 // The final number of bytes read.
744 ::Int_t result = 0;
745
746 // Check if objects need to be read in.
747 if (getall) {
748 if (m_auxMode == kAthenaAccess) {
749 // In kAthenaAccess mode we need to use getInputObject(...) to load
750 // all the input objects correctly.
751 for (auto &[key, mgr] : m_inputObjects) {
752 static const std::string dynStorePostfix = "Aux.Dynamic";
753 if (key.ends_with(dynStorePostfix)) {
754 // Ignore the dynamic store objects. They get loaded through
755 // their parents.
756 } else {
757 // Load the objects and their auxiliary stores through the
758 // getInputObject(...) function, which takes care of correctly
759 // setting them up. The type is irrelevant here. We don't
760 // really care about the exact type of the objects.
761 static constexpr bool SILENT = true;
762 static constexpr bool METADATA = false;
763 getInputObject(key, typeid(int), SILENT, METADATA);
764 }
765 }
766 } else {
767 // In a "reasonable" access mode, we do something very simple:
768 for (auto &[key, mgr] : m_inputObjects) {
769 result += mgr->getEntry(getall);
770 }
771 }
772 }
773
774 // Notify the listeners that a new event was loaded:
775 const TIncident incident(IncidentType::BeginEvent);
776 for (auto &listener : m_listeners) {
777 listener->handle(incident);
778 }
779
780 // Return the number of bytes read:
781 return result;
782}
783
793::Long64_t TEvent::getFiles() const {
794
795 if (m_inChain) {
796 return m_inChain->GetListOfFiles()->GetEntries();
797 } else if (m_inTree || m_inTreeMissing) {
798 return 1;
799 } else {
800 return 0;
801 }
802}
803
813::Int_t TEvent::getFile(::Long64_t file, ::Int_t getall) {
814
815 // Check if the file number is valid:
816 if ((file < 0) || (file >= getFiles())) {
817 ATH_MSG_ERROR("Function called with invalid file number (" << file << ")");
818 return -1;
819 }
820
821 // If we are not reading a TChain, return at this point. As the one and
822 // only file is open already...
823 if (!m_inChain) {
824 return 0;
825 }
826
827 // Trigger the "scanning" of the input files, so the TChain would know
828 // how many entries are in the various files.
829 getEntries();
830
831 // Calculate which entry/event we need to load:
832 ::Long64_t entry = 0;
833 for (::Long64_t i = 0; i < file; ++i) {
834 entry += m_inChain->GetTreeOffset()[i];
835 }
836
837 // Load this entry using the regular event opening function:
838 return getEntry(entry, getall);
839}
840
847::Int_t TEvent::fill() {
848
849 // A little sanity check:
850 if (!m_outTree) {
851 ATH_MSG_ERROR("Object not connected to an output file!");
852 return 0;
853 }
854
855 // Make sure that all objects have been read in. The 99 as the value
856 // has a special meaning for TAuxStore. With this value it doesn't
857 // delete its transient (decoration) variables. Otherwise it does.
858 // (As it's supposed to, when moving to a new event.)
859 Int_t readBytes = 0;
860 if (m_inChain != nullptr) {
861 readBytes = getEntry(m_inChain->GetReadEntry(), 99);
862 } else if (m_inTree != nullptr) {
863 readBytes = getEntry(m_entry, 99);
864 }
865 if (readBytes < 0) {
866 ATH_MSG_ERROR("getEntry failed!");
867 return readBytes;
868 }
869
870 // Prepare the objects for writing. Note that we need to iterate over a
871 // copy of the m_outputObjects container. Since the putAux(...) function
872 // called inside the loop may itself add elements to the m_outputObject
873 // container.
874 std::string unsetObjects;
875 std::vector<std::pair<std::string, TVirtualManager* >> outputObjectsCopy;
876 outputObjectsCopy.reserve(m_outputObjects.size());
877 for (const auto &[key, mgr] : m_outputObjects) {
878 outputObjectsCopy.emplace_back(key, mgr.get());
879 }
880 for (auto &[key, mgr] : outputObjectsCopy) {
881 // Check that a new object was provided in the event:
882 if (!mgr->create()) {
883 // We are now going to fail. But let's collect the names of
884 // all the unset objects:
885 if (unsetObjects.size()) {
886 unsetObjects += ", ";
887 }
888 unsetObjects.append("\"" + key + "\"");
889 continue;
890 }
891 // Make sure that any dynamic auxiliary variables that
892 // were added to the object after it was put into the event,
893 // get added to the output:
894 static constexpr bool METADATA = false;
895 if (putAux(*m_outTree, *mgr, METADATA).isFailure()) {
896 ATH_MSG_ERROR("Failed to put dynamic auxiliary variables "
897 "in the output for object \""
898 << key << "\"");
899 return 0;
900 }
901 }
902
903 // Check if there were any unset objects:
904 if (unsetObjects.size()) {
905 ATH_MSG_ERROR("The following objects were not set in the current event: "
906 << unsetObjects);
907 return 0;
908 }
909
910 // Write the entry, and check the return value:
911 const ::Int_t ret = m_outTree->Fill();
912 if (ret <= 0) {
913 ATH_MSG_ERROR("Output tree filling failed with return value: " << ret);
914 }
915
916 // Reset the object managers.
917 for (auto &[key, mgr] : m_outputObjects) {
918 mgr->reset();
919 }
920
921 // Return the value:
922 return ret;
923}
924
925bool TEvent::hasInput() const {
926
927 return ((m_inTree != nullptr) || (m_inChain != nullptr));
928}
929
930bool TEvent::hasOutput() const { return (m_outTree.get() != nullptr); }
931
932StatusCode TEvent::getNames(const std::string &targetClassName,
933 std::vector<std::string> &vkeys,
934 bool metadata) const {
935 // The results go in here
936 std::set<std::string> keys;
937
938 // Get list of branches from
939 // the input metadata tree or input tree
940 std::vector<TObjArray* > fullListOfBranches = {};
941 if (metadata) {
942 if (m_inMetaTree) {
943 // No friend tree expected for metadata tree
944 // Only add the list of branches of the metadata tree
945 ATH_MSG_DEBUG("Scanning for input metadata objects");
946 fullListOfBranches.push_back(m_inMetaTree->GetListOfBranches());
947 }
948 } else {
949 if (m_inTree) {
950 ATH_MSG_DEBUG("Scanning for input data objects");
951 // Add the list of branches of the main tree
952 fullListOfBranches.push_back(m_inTree->GetListOfBranches());
953 // If the input tree has friend trees
954 // add as well the list of friend tree branches
955 if (m_inTree->GetListOfFriends()) {
956 // Get the list of friends
957 TList* fList = m_inTree->GetListOfFriends();
958 // Loop over friend elements
959 for (TObject* feObj : *fList) {
960 if (feObj) {
961 // Get corresponding friend tree
962 auto* pElement = dynamic_cast<TFriendElement* >(feObj);
963 if (pElement == nullptr) {
964 continue;
965 }
966 TTree* friendTree = pElement->GetTree();
967 // Add list of branches of the friend tree
968 fullListOfBranches.push_back(friendTree->GetListOfBranches());
969 }
970 }
971 }
972 }
973 }
974
975 // Loop over all list of branches (if any)
976 for (const TObjArray* in : fullListOfBranches) {
977 // Loop over all branches inside the current list of branches
978 for (const TObject* obj : *in) {
979
980 if (obj == nullptr) {
981 continue;
982 }
983 const TBranch* element = dynamic_cast<const TBranch* >(obj);
984 if (!element) {
985 ATH_MSG_ERROR("Failure inspecting input data objects");
986 return StatusCode::FAILURE;
987 }
988 const std::string objClassName = element->GetClassName();
989 std::string key = obj->GetName();
990 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
991 << "\"");
992 if (objClassName == targetClassName) {
993 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
994 << "\"");
995 keys.insert(std::move(key));
996 }
997 }
998 }
999
1000 const Object_t &inAux = (metadata ? m_inputMetaObjects : m_inputObjects);
1001
1002 ATH_MSG_DEBUG("Scanning input objects for \"" << targetClassName << "\"");
1003 for (const auto &[key, vmgr] : inAux) {
1004 // All (metadata) objects should be held by TObjectManager objects.
1005 const TObjectManager* mgr =
1006 dynamic_cast<const TObjectManager* >(vmgr.get());
1007 if (mgr == nullptr) {
1008 continue;
1009 }
1010 const std::string &objClassName = mgr->holder()->getClass()->GetName();
1011 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
1012 << "\"");
1013 if (objClassName == targetClassName) {
1014 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
1015 << "\"");
1016 keys.insert(key);
1017 }
1018 }
1019
1020 // Check for output objects.
1021 if ((metadata == false) && m_outTree) {
1022 const TObjArray* out = m_outTree->GetListOfBranches();
1023 ATH_MSG_DEBUG("Scanning for output data objects");
1024
1025 for (const TObject* obj : *out) {
1026 if (obj == nullptr) {
1027 continue;
1028 }
1029 const TBranch* element = dynamic_cast<const TBranch* >(obj);
1030 if (element == nullptr) {
1031 ATH_MSG_ERROR("Failure inspecting output objects");
1032 return StatusCode::FAILURE;
1033 }
1034 const std::string objClassName = element->GetClassName();
1035 std::string key = obj->GetName();
1036 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
1037 << "\"");
1038 if (objClassName == targetClassName) {
1039 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
1040 << "\"");
1041 keys.insert(std::move(key));
1042 }
1043 }
1044 }
1045
1046 const Object_t &outAux = (metadata ? m_outputMetaObjects : m_outputObjects);
1047
1048 // Search though the in-memory output objects.
1049 ATH_MSG_DEBUG("Scanning output objects for \"" << targetClassName << "\"");
1050 for (const auto &[key, vmgr] : outAux) {
1051 // All (metadata) objects should be held by TObjectManager objects.
1052 TObjectManager* mgr = dynamic_cast<TObjectManager* >(vmgr.get());
1053 if (mgr == nullptr) {
1054 continue;
1055 }
1056 const std::string &objClassName = mgr->holder()->getClass()->GetName();
1057 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
1058 << "\"");
1059 if (objClassName == targetClassName) {
1060 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
1061 << "\"");
1062 keys.insert(key);
1063 }
1064 }
1065
1066 vkeys.insert(vkeys.end(), keys.begin(), keys.end());
1067
1068 // Return gracefully.
1069 return StatusCode::SUCCESS;
1070}
1071
1089StatusCode TEvent::connectObject(const std::string &key, bool silent) {
1090
1091 // A little sanity check:
1092 if (hasInput() == false) {
1093 ATH_MSG_ERROR("Function called on un-initialised object");
1094 return StatusCode::FAILURE;
1095 }
1096
1097 // Increment the access counter on this container:
1099
1100 // Check if the branch is already connected:
1101 if (m_inputObjects.contains(key)) {
1102 return StatusCode::SUCCESS;
1103 }
1104 // Check if it was already found to be missing.
1105 if (m_inputMissingObjects.contains(key)) {
1106 if (silent == false) {
1107 ATH_MSG_WARNING("Branch \"" << key << "\" not available on input");
1108 }
1109 return StatusCode::RECOVERABLE;
1110 }
1111
1112 // Check if we have metadata about this branch:
1113 const xAOD::EventFormatElement* ef = nullptr;
1114 if (m_inputEventFormat.exists(key) == false) {
1115 if (silent == false) {
1116 ATH_MSG_WARNING("No metadata available for branch: " << key);
1117 }
1118 } else {
1119 ef = m_inputEventFormat.get(key);
1120 }
1121
1122 // Check if the branch exists in our input tree:
1123 ::TBranch* br = m_inTree->GetBranch(key.c_str());
1124 if (br == nullptr) {
1125 if (!silent) {
1126 ATH_MSG_WARNING("Branch \"" << key << "\" not available on input");
1127 }
1128 m_inputMissingObjects.insert(key);
1129 return StatusCode::RECOVERABLE;
1130 }
1131
1132 // Make sure that it's not in "MakeClass mode":
1133 br->SetMakeClass(0);
1134
1135 // Decide about the type that we need to use for the reading of this
1136 // branch:
1137 std::string className = br->GetClassName();
1138 if (className == "") {
1139 if (ef) {
1140 // This is a fairly weird situation, but let's fall back to taking
1141 // the class name from the metadata object in this case.
1142 className = ef->className();
1143 } else {
1145 "Couldn't find an appropriate type with a dictionary for branch \""
1146 << key << "\"");
1147 return StatusCode::FAILURE;
1148 }
1149 }
1150 ::TClass* realClass = ::TClass::GetClass(className.c_str());
1151 if (((!realClass) || (!realClass->IsLoaded())) && ef) {
1152 // We may need to do an actual schema evolution here, in which
1153 // case let's fall back on the class name coming from the metadata
1154 // object.
1155 className = ef->className();
1156 realClass = ::TClass::GetClass(className.c_str());
1157 }
1158 if ((!realClass) || (!realClass->IsLoaded())) {
1159 // Now we're in trouble...
1161 "Couldn't find an appropriate type with a dictionary for branch \""
1162 << key << "\"");
1163 return StatusCode::FAILURE;
1164 }
1165
1166 // Make sure that the current object is the "active event":
1167 setActive();
1168
1169 // The data type is always "other" for us:
1170 static const ::EDataType dataType = kOther_t;
1171
1172 // Check if the output already has this object. If it does, let's
1173 // assume that we have been copying the object to the output. Which
1174 // means that we need to resume filling the same memory address that
1175 // the output holder points to.
1176 void* ptr = nullptr;
1177 Object_t::const_iterator out_itr = m_outputObjects.find(key);
1178 if (out_itr != m_outputObjects.end()) {
1179 // It needs to be an object manager...
1180 TObjectManager* mgr = dynamic_cast<TObjectManager* >(out_itr->second.get());
1181 if (mgr == nullptr) {
1182 ATH_MSG_ERROR("Couldn't access output manager for: " << key);
1183 return StatusCode::FAILURE;
1184 }
1185 // Get the pointer out of it:
1186 ptr = mgr->holder()->get();
1187 }
1188
1189 // If there is no output object, then let's create one ourselves.
1190 // This is the only way in which we can have the memory management of
1191 // THolder do the right thing with this object.
1192 if (ptr == nullptr) {
1193 ptr = realClass->New();
1194 }
1195
1196 // Create the new manager object that will hold this EDM object:
1197 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1198 auto mgr = std::make_unique<TObjectManager>(
1199 nullptr, std::make_unique<THolder>(ptr, realClass), renewOnRead);
1200
1201 // One final check. If it's not an auxiliary store, then it must have
1202 // a split level of 0. Otherwise read rules may not work on it. Causing
1203 // *very* serious silent corruption in the data read, if we don't use
1204 // the "Athena read mode".
1205 if ((m_auxMode != kAthenaAccess) && (br->GetSplitLevel() != 0) &&
1206 (Details::isAuxStore(*(mgr->holder()->getClass())) == false)) {
1207 ATH_MSG_ERROR("Split level for branch \""
1208 << key << "\" is " << br->GetSplitLevel()
1209 << ". This can only be read in kAthenaAccess mode.");
1210 // Clean up:
1211 *(mgr->holder()->getPtr()) = nullptr;
1212 m_inputObjects.erase(key);
1213 return StatusCode::FAILURE;
1214 }
1215
1216 // Now try to connect to the branch:
1217 const ::Int_t status =
1218 m_inTree->SetBranchAddress(key.c_str(), mgr->holder()->getPtr(),
1219 mgr->branchPtr(), realClass, dataType, kTRUE);
1220 if (status < 0) {
1221 ATH_MSG_ERROR("Couldn't connect variable of type \""
1222 << className << "\" to input branch \"" << key
1223 << "\". Return code: " << status);
1224 // Clean up:
1225 *(mgr->holder()->getPtr()) = 0;
1226 m_inputObjects.erase(key);
1227 return StatusCode::FAILURE;
1228 }
1229
1230 // At this point we have successfully connected the branch.
1231 TObjectManager* mgrPtr = mgr.get();
1232 m_inputObjects[key] = std::move(mgr);
1233
1234 // If it's an auxiliary store object, set it up correctly:
1235 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
1237 }
1238
1239 // If there may be an auxiliary object connected to this one,
1240 // connect that as well:
1241 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
1243 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
1244 }
1245
1246 // Return gracefully.
1247 return StatusCode::SUCCESS;
1248}
1249
1258StatusCode TEvent::connectMetaObject(const std::string &key, bool silent) {
1259
1260 // A little sanity check:
1261 if (!m_inMetaTree) {
1262 ATH_MSG_ERROR("Function called on un-initialised object");
1263 return StatusCode::FAILURE;
1264 }
1265
1266 // Check if the branch is already connected:
1267 if (m_inputMetaObjects.contains(key)) {
1268 return StatusCode::SUCCESS;
1269 }
1270
1271 // Check if the branch exists in our metadata tree:
1272 ::TBranch* br = m_inMetaTree->GetBranch(key.c_str());
1273 if (br == nullptr) {
1274 if (silent == false) {
1275 ATH_MSG_WARNING("Metadata branch \"" << key
1276 << "\" not available on input");
1277 }
1278 return StatusCode::RECOVERABLE;
1279 }
1280
1281 // Check that we have an entry in the branch:
1282 if (br->GetEntries() == 0) {
1283 if (silent == false) {
1284 ATH_MSG_WARNING("Metadata branch \"" << key
1285 << "\" doesn't hold any data");
1286 }
1287 return StatusCode::RECOVERABLE;
1288 }
1289
1290 // Make sure that it's not in "MakeClass mode":
1291 br->SetMakeClass(0);
1292
1293 // Extract the type of the branch:
1294 ::TClass* cl = 0;
1295 ::EDataType dt = kOther_t;
1296 if (br->GetExpectedType(cl, dt) || (!cl)) {
1297 ATH_MSG_ERROR("Couldn't get the type for metadata branch \"" << key
1298 << "\"");
1299 return StatusCode::FAILURE;
1300 }
1301
1302 // Create the object, and all of the managers around it:
1303 void* ptr = cl->New();
1304 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1305 auto mgr = std::make_unique<TObjectManager>(
1306 nullptr, std::make_unique<THolder>(ptr, cl), renewOnRead);
1307
1308 // Now try to connect to the branch:
1309 const ::Int_t status = m_inMetaTree->SetBranchAddress(
1310 key.c_str(), mgr->holder()->getPtr(), mgr->branchPtr(), cl, dt, kTRUE);
1311 if (status < 0) {
1312 ATH_MSG_ERROR("Couldn't connect variable of type \""
1313 << cl->GetName() << "\" to input branch \"" << key
1314 << "\". Return code: " << status);
1315 // Clean up:
1316 *(mgr->holder()->getPtr()) = 0;
1317 m_inputMetaObjects.erase(key);
1318 return StatusCode::FAILURE;
1319 }
1320
1321 // Store the manager.
1322 TObjectManager *mgrPtr = mgr.get();
1323 m_inputMetaObjects[key] = std::move(mgr);
1324
1325 // Read in the object:
1326 if (mgrPtr->getEntry() < 0) {
1327 ATH_MSG_ERROR("Couldn't read in metadata object with key \"" << key
1328 << "\"");
1329 return StatusCode::FAILURE;
1330 }
1331
1332 // If it's an auxiliary store object, set it up correctly:
1333 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
1335 }
1336
1337 // If there may be an auxiliary object connected to this one,
1338 // connect that as well.
1339 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
1341 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
1342 static constexpr bool METADATA = true;
1343 ATH_CHECK(setAuxStore(key, *mgrPtr, METADATA));
1344 }
1345
1346 // We succeeded:
1347 return StatusCode::SUCCESS;
1348}
1349
1359StatusCode TEvent::connectAux(const std::string &prefix, bool standalone) {
1360
1361 // A simple test...
1362 if (hasInput() == false) {
1363 ATH_MSG_ERROR("No input tree is available");
1364 return StatusCode::FAILURE;
1365 }
1366
1367 // Check if we know anything about this auxiliary object:
1368 if ((!m_inTree->GetBranch(prefix.c_str())) &&
1370 // If not, then let's just return right away. Not having
1371 // an auxiliary object with this name is not an error per se.
1372 return StatusCode::SUCCESS;
1373 }
1374
1375 // Check if the branch is already connected.
1376 if (m_inputObjects.contains(prefix)) {
1377 return StatusCode::SUCCESS;
1378 }
1379
1380 // Do different things based on the "auxiliary mode" we are in.
1381 if ((m_auxMode == kClassAccess) || (m_auxMode == kAthenaAccess)) {
1382
1383 // In "class" and "athena" access modes just connect the concrete auxiliary
1384 // object to the input.
1385 static constexpr bool SILENT = false;
1386 ATH_CHECK(connectObject(prefix, SILENT));
1387
1388 // Return gracefully.
1389 return StatusCode::SUCCESS;
1390
1391 } else if (m_auxMode == kBranchAccess) {
1392
1393 // In "branch access mode" let's create a TAuxStore object, and let
1394 // that take care of the auxiliary store access.
1395 static constexpr bool TOP_STORE = true;
1396 auto store = std::make_unique<TAuxStore>(
1397 prefix, TOP_STORE,
1400
1401 // Connect it to the input tree.
1402 ATH_CHECK(store->readFrom(*m_inTree));
1403
1404 // We're using this object to read from the input, it needs to be
1405 // locked:
1406 store->lock();
1407
1408 // Finally, set up an appropriate manager for it.
1409 static constexpr bool IS_OWNER = true;
1410 m_inputObjects[prefix] =
1411 std::make_unique<TAuxManager>(store.release(), IS_OWNER);
1412
1413 // Return gracefully:
1414 return StatusCode::SUCCESS;
1415 }
1416
1417 // There was some problem:
1418 ATH_MSG_ERROR("Unknown auxiliary access mode set (" << m_auxMode << ")");
1419 return StatusCode::FAILURE;
1420}
1421
1431StatusCode TEvent::connectMetaAux(const std::string &prefix, bool standalone) {
1432
1433 // Check if the branch is already connected:
1434 if (m_inputMetaObjects.contains(prefix)) {
1435 return StatusCode::SUCCESS;
1436 }
1437
1438 // A sanity check:
1439 if (!m_inMetaTree) {
1440 ATH_MSG_FATAL("Internal logic error detected");
1441 return StatusCode::FAILURE;
1442 }
1443
1444 // Do different things based on the "auxiliary mode" we are in:
1446
1447 // In "class" and "athena" access modes just connect the concrete auxiliary
1448 // object to the input.
1449 static constexpr bool SILENT = false;
1450 ATH_CHECK(connectMetaObject(prefix, SILENT));
1451
1452 // Return gracefully:
1453 return StatusCode::SUCCESS;
1454
1455 } else if (m_auxMode == kBranchAccess) {
1456
1457 // In "branch access mode" let's create a TAuxStore object, and let
1458 // that take care of the auxiliary store access.
1459 static constexpr bool TOP_STORE = true;
1460 auto store = std::make_unique<TAuxStore>(
1461 prefix, TOP_STORE,
1464
1465 // Connect it to the input tree.
1466 ATH_CHECK(store->readFrom(*m_inMetaTree));
1467
1468 // We're using this object to read from the input, it needs to be
1469 // locked:
1470 store->lock();
1471
1472 // Finally, set up an appropriate manager for it.
1473 static constexpr bool IS_OWNER = true;
1474 m_inputMetaObjects[prefix] =
1475 std::make_unique<TAuxManager>(store.release(), IS_OWNER);
1476
1477 // Return gracefully.
1478 return StatusCode::SUCCESS;
1479 }
1480
1481 // There was some problem:
1482 ATH_MSG_ERROR("Unknown auxiliary access mode set (" << m_auxMode << ")");
1483 return StatusCode::FAILURE;
1484}
1485
1495StatusCode TEvent::setAuxStore(const std::string &key,
1496 Details::IObjectManager &mgr, bool metadata) {
1497
1498 // Pre-compute some values.
1499 const bool isAuxStore = Details::isAuxStore(*(mgr.holder()->getClass()));
1500
1501 // Check if we need to do anything.
1502 if ((Details::hasAuxStore(*(mgr.holder()->getClass())) == false) &&
1503 (isAuxStore == false)) {
1504 return StatusCode::SUCCESS;
1505 }
1506
1507 // Select which object container to use:
1508 Object_t &objects = (metadata ? m_inputMetaObjects : m_inputObjects);
1509
1510 // Look up the auxiliary object's manager:
1511 TVirtualManager* auxMgr = nullptr;
1512 std::string auxKey;
1513 if (isAuxStore) {
1514 auxMgr = &mgr;
1515 auxKey = key;
1516 } else {
1517 auto itr = objects.find(key + "Aux.");
1518 if (itr == objects.end()) {
1519 // Apparently there's no auxiliary object for this DV, so let's
1520 // give up:
1521 return StatusCode::SUCCESS;
1522 }
1523 auxMgr = itr->second.get();
1524 auxKey = key + "Aux.";
1525 }
1526
1527 if (metadata == false) {
1528 // Make sure the auxiliary object is up to date:
1529 const ::Int_t readBytes = auxMgr->getEntry();
1530 if (readBytes < 0) {
1532 "Couldn't load current entry for auxiliary object with key \""
1533 << auxKey << "\"");
1534 return StatusCode::FAILURE;
1535 }
1536
1537 // Check if there is a separate auxiliary object for the dynamic
1538 // variables:
1539 const std::string dynAuxKey = auxKey + "Dynamic";
1540 auto dynAuxMgr = objects.find(dynAuxKey);
1541
1542 if ((dynAuxMgr != objects.end()) &&
1543 (readBytes || (m_auxMode == kAthenaAccess) || (auxMgr == &mgr))) {
1544 // Do different things based on the access mode:
1545 if (m_auxMode != kAthenaAccess) {
1546 // In "normal" access modes just tell the dynamic store object
1547 // to switch to a new event.
1548 dynAuxMgr->second->getEntry();
1549 } else {
1550 // In "Athena mode" this object has already been deleted when
1551 // the main auxiliary store object was switched to the new
1552 // event. So let's re-create it:
1553 xAOD::TObjectManager &auxMgrRef =
1554 dynamic_cast<xAOD::TObjectManager &>(*auxMgr);
1555 ATH_CHECK(
1556 setUpDynamicStore(auxMgrRef, (metadata ? m_inMetaTree : m_inTree)));
1557 // Now tell the newly created dynamic store object which event
1558 // it should be looking at:
1559 auto dynAuxMgr = objects.find(dynAuxKey);
1560 if (dynAuxMgr == objects.end()) {
1561 ATH_MSG_ERROR("Internal logic error detected");
1562 return StatusCode::FAILURE;
1563 }
1564 dynAuxMgr->second->getEntry();
1565 }
1566 }
1567 }
1568
1569 // Stop here if we've set up an auxiliary store.
1570 if (isAuxStore) {
1571 return StatusCode::SUCCESS;
1572 }
1573
1574 // Access the auxiliary base class of the object/vector:
1576 SG::AuxElement* aux = 0;
1577 switch (mgr.holder()->typeKind()) {
1578 case THolder::DATAVECTOR: {
1579 void* vvec = mgr.holder()->getAs(typeid(SG::AuxVectorBase));
1580 vec = reinterpret_cast<SG::AuxVectorBase*>(vvec);
1581 } break;
1582 case THolder::AUXELEMENT: {
1583 void* vaux = mgr.holder()->getAs(typeid(SG::AuxElement));
1584 aux = reinterpret_cast<SG::AuxElement*>(vaux);
1585 } break;
1586 default:
1587 break;
1588 }
1589
1590 // Check whether index tracking is enabled for the type. If not, then
1591 // we need to fix it...
1592 if (vec && (!vec->trackIndices())) {
1593 Details::forceTrackIndices(*vec);
1594 }
1595
1596 // Check if we were successful:
1597 if ((!vec) && (!aux)) {
1598 ATH_MSG_FATAL("Couldn't access class \""
1599 << mgr.holder()->getClass()->GetName()
1600 << "\" as SG::AuxVectorBase or SG::AuxElement");
1601 return StatusCode::FAILURE;
1602 }
1603
1604 // Get the auxiliary store object:
1605 const SG::IConstAuxStore* store = 0;
1606 if (m_auxMode == kBranchAccess) {
1607 // Get the concrete auxiliary manager:
1608 TAuxManager* amgr = dynamic_cast<TAuxManager* >(auxMgr);
1609 if (!amgr) {
1610 ATH_MSG_FATAL("Auxiliary manager for \""
1611 << auxKey << "\" is not of the right type");
1612 return StatusCode::FAILURE;
1613 }
1614 store = amgr->getConstStore();
1615 // If the store still doesn't know its type, help it now:
1616 if (amgr->getStore()->structMode() ==
1618 const TAuxStore::EStructMode mode =
1621 amgr->getStore()->setStructMode(mode);
1622 }
1623 } else if (m_auxMode == kClassAccess || m_auxMode == kAthenaAccess) {
1624 // Get the concrete auxiliary manager:
1625 TObjectManager* omgr = dynamic_cast<TObjectManager* >(auxMgr);
1626 if (!omgr) {
1627 ATH_MSG_FATAL("Auxiliary manager for \""
1628 << auxKey << "\" is not of the right type");
1629 return StatusCode::FAILURE;
1630 }
1631 void* p = omgr->holder()->getAs(typeid(SG::IConstAuxStore));
1632 store = reinterpret_cast<const SG::IConstAuxStore* >(p);
1633 }
1634 if (!store) {
1635 ATH_MSG_FATAL("Logic error detected in the code");
1636 return StatusCode::FAILURE;
1637 }
1638
1639 // Connect the two:
1640 if (vec) {
1641 vec->setStore(store);
1642 } else if (aux) {
1643 aux->setStore(store);
1644 } else {
1645 ATH_MSG_FATAL("Logic error detected in the code");
1646 return StatusCode::FAILURE;
1647 }
1648
1649 // We succeeded:
1650 return StatusCode::SUCCESS;
1651}
1652
1668StatusCode TEvent::record(void* obj, const std::string &typeName,
1669 const std::string &key, bool overwrite, bool metadata,
1670 bool isOwner) {
1671
1672 // Check if we have an output tree when writing an event:
1673 if (!m_outTree && !metadata) {
1675 "No output tree defined. Did you forget to call writeTo(...)?");
1676 return StatusCode::FAILURE;
1677 }
1678 assert(m_outputEventFormat != 0);
1679
1680 // If this is metadata, just take ownership of it. The object will only
1681 // be recorded into the output file when calling finishWritingTo(...).
1682 if (metadata) {
1683 // Check whether we already have such an object:
1684 if ((!overwrite) &&
1685 (m_outputMetaObjects.find(key) != m_outputMetaObjects.end())) {
1686 ATH_MSG_ERROR("Meta-object \"" << typeName << "\"/\"" << key
1687 << "\" already recorded");
1688 return StatusCode::FAILURE;
1689 }
1690 // Check if we have a dictionary for this object:
1691 TClass* cl = TClass::GetClass(typeName.c_str());
1692 if (!cl) {
1693 ATH_MSG_ERROR("Didn't find dictionary for type: " << typeName);
1694 return StatusCode::FAILURE;
1695 }
1696 // Let's create a holder for the object:
1697 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1698 m_outputMetaObjects[key] = std::make_unique<TObjectManager>(
1699 nullptr, std::make_unique<THolder>(obj, cl, isOwner), renewOnRead);
1700 // We're done. The rest will be done later on.
1701 return StatusCode::SUCCESS;
1702 }
1703
1704 // Check if we accessed this object on the input. If yes, then this
1705 // key may not be used for recording.
1706 if ((!overwrite) && (m_inputObjects.find(key) != m_inputObjects.end())) {
1707 ATH_MSG_ERROR("Object \"" << typeName << "\"/\"" << key
1708 << "\" already accessed from the input, can't be "
1709 "overwritten in memory");
1710 return StatusCode::FAILURE;
1711 }
1712
1713 // Choose a split level.
1714 const Int_t splitLevel = (key.ends_with("Aux.") ? 1 : 0);
1715
1716 // Check if we need to add it to the event record:
1717 Object_t::iterator vitr = m_outputObjects.find(key);
1718 if (vitr == m_outputObjects.end()) {
1719
1720 // Check if we have a dictionary for this object:
1721 TClass* cl = TClass::GetClass(typeName.c_str());
1722 if (cl == nullptr) {
1723 ATH_MSG_ERROR("Didn't find dictionary for type: " << typeName);
1724 return StatusCode::FAILURE;
1725 }
1726
1727 // Check if this is a new object "type" or not.
1728 if (!m_outputEventFormat->exists(key)) {
1730 EventFormatElement(key, cl->GetName(), "", getHash(key)));
1731 }
1732
1733 // Let's create a holder for the object.
1734 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1735 auto mgr = std::make_unique<TObjectManager>(
1736 nullptr, std::make_unique<THolder>(obj, cl, isOwner), renewOnRead);
1737 TObjectManager* mgrPtr = mgr.get();
1738 m_outputObjects[key] = std::move(mgr);
1739
1740 // ... and let's add it to the output TTree.
1741 static constexpr Int_t basketSize = 32000;
1742 *(mgrPtr->branchPtr()) =
1743 m_outTree->Branch(key.c_str(), cl->GetName(),
1744 mgrPtr->holder()->getPtr(), basketSize, splitLevel);
1745 if (!mgrPtr->branch()) {
1746 ATH_MSG_ERROR("Failed to create branch \"" << key << "\" out of type \""
1747 << cl->GetName() << "\"");
1748 // Clean up:
1749 mgrPtr->holder()->setOwner(kFALSE);
1750 return StatusCode::FAILURE;
1751 }
1752
1753 // Set up the saving of all the dynamic auxiliary properties
1754 // of the object if it has any:
1755 static constexpr bool METADATA = false;
1756 ATH_CHECK(putAux(*m_outTree, *mgrPtr, METADATA));
1757
1758 // Return at this point, as we don't want to run the rest of
1759 // the function's code:
1760 return StatusCode::SUCCESS;
1761 }
1762
1763 // Access the object manager:
1764 TObjectManager* omgr = dynamic_cast<TObjectManager* >(vitr->second.get());
1765 if (!omgr) {
1766 ATH_MSG_ERROR("Manager object of the wrong type encountered");
1767 return StatusCode::FAILURE;
1768 }
1769
1770 // Check that the type of the object matches that of the previous
1771 // object:
1772 if (typeName != omgr->holder()->getClass()->GetName()) {
1773 // This may still be, when the ROOT dictionary name differs from the
1774 // "simple type name" known to C++. So let's get the ROOT name of the
1775 // new type:
1776 TClass* cl = TClass::GetClass(typeName.c_str());
1777 if ((!cl) ||
1778 ::strcmp(cl->GetName(), omgr->holder()->getClass()->GetName())) {
1779 ATH_MSG_ERROR("For output key \""
1780 << key << "\" the previous type was \""
1781 << omgr->holder()->getClass()->GetName()
1782 << "\", but the newly requested type is \"" << typeName
1783 << "\"");
1784 return StatusCode::FAILURE;
1785 }
1786 }
1787
1788 // Replace the managed object.
1789 omgr->setObject(obj);
1790
1791 // Replace the auxiliary objects.
1792 static constexpr bool METADATA = false;
1793 ATH_CHECK(putAux(*m_outTree, *omgr, METADATA));
1794
1795 // Return gracefully.
1796 return StatusCode::SUCCESS;
1797}
1798
1799StatusCode TEvent::recordAux(TVirtualManager &mgr, const std::string &key,
1800 bool metadata) {
1801
1802 // Check if the auxiliary store is a generic object.
1803 Details::IObjectManager* iomgr = dynamic_cast<Details::IObjectManager*>(&mgr);
1804 if (iomgr != nullptr) {
1805 // Record the auxiliary object using the main record function.
1806 static const bool OVERWRITE = true;
1807 static const bool IS_OWNER = true;
1808 ATH_CHECK(record(iomgr->object(), iomgr->holder()->getClass()->GetName(),
1809 key, OVERWRITE, metadata, IS_OWNER));
1810 return StatusCode::SUCCESS;
1811 }
1812
1813 // Check if it's a TAuxStore object.
1814 TAuxManager* auxmgr = dynamic_cast<TAuxManager* >(&mgr);
1815 if (auxmgr != nullptr) {
1816 // This type has to be an event object.
1817 if (metadata) {
1819 "TAuxStore auxiliary objects can only be recorded for event data");
1820 return StatusCode::FAILURE;
1821 }
1822 // Record the auxiliary object with the dedicated record function.
1823 ATH_CHECK(recordAux(auxmgr->getStore(), key));
1824 return StatusCode::SUCCESS;
1825 }
1826
1827 // Apparently we didn't recorgnize the auxiliary store type.
1828 ATH_MSG_ERROR("Unknown auxiliary store manager type encountered");
1829 return StatusCode::FAILURE;
1830}
1831
1838StatusCode TEvent::initStats() {
1839
1840 // If we're dealing with an empty input file, stop here:
1841 if (m_inTreeMissing) {
1842 return StatusCode::SUCCESS;
1843 }
1844
1845 // A little sanity check:
1846 if (!m_inTree) {
1847 ATH_MSG_ERROR("Function called on an uninitialised object");
1848 return StatusCode::FAILURE;
1849 }
1850
1851 // Reset the number of input branches information:
1853
1854 // Loop over the EventFormat information
1857 for (; itr != end; ++itr) {
1858
1859 // Get the name of the branch in question:
1860 const std::string &branchName = itr->second.branchName();
1861
1862 // If it's an auxiliary container, scan it using TAuxStore:
1863 if (branchName.find("Aux.") != std::string::npos) {
1864
1865 // But first decide whether it describes a container, or just
1866 // a single object. Since the file may have been written in
1867 // kBranchAccess mode, it's not necessarily a good idea to check
1868 // the type of the auxiliary class. So let's check the interface
1869 // class instead.
1870 //
1871 // Get the name of the interface object/container:
1872 const std::string intName = branchName.substr(0, branchName.size() - 4);
1873 if (!m_inputEventFormat.exists(intName)) {
1874 // When this happens, it may still be that both the interface and
1875 // the auxiliary container is missing from the file. As we didn't
1876 // check yet whether the auxiliary container is in place or not.
1877 // So, before printing a warning, let's check for this.
1878 // Unfortunately the check is pretty expensive, but this should
1879 // not be performance critical code after all...
1880 ::Bool_t auxFound = kFALSE;
1881 const std::string dynName = Utils::dynBranchPrefix(branchName);
1882
1883 std::vector<TObjArray* > fullListOfBranches = {};
1884 // Add the list of branches of the main tree
1885 fullListOfBranches.push_back(m_inTree->GetListOfBranches());
1886 // If input tree has friend trees
1887 // add as well the list of friend tree branches
1888 if (m_inTree->GetListOfFriends()) {
1889 // Get the list of friends
1890 TList* fList = m_inTree->GetListOfFriends();
1891 // Loop over friend elements
1892 for (TObject* feObj : *fList) {
1893 if (feObj) {
1894 // Get corresponding friend tree
1895 auto* pElement = dynamic_cast<TFriendElement* >(feObj);
1896 if (not pElement)
1897 continue;
1898 TTree* friendTree = pElement->GetTree();
1899 // Add list of branches of the friend tree
1900 fullListOfBranches.push_back(friendTree->GetListOfBranches());
1901 }
1902 }
1903 }
1904
1905 for (TObjArray* branches : fullListOfBranches) {
1906 for (Int_t i = 0; i < branches->GetEntriesFast(); ++i) {
1907 if (!branches->At(i))
1908 continue;
1909
1910 const TString name(branches->At(i)->GetName());
1911 if (name.BeginsWith(branchName) || name.BeginsWith(dynName)) {
1912 auxFound = kTRUE;
1913 break;
1914 }
1915 }
1916 }
1917 if (auxFound) {
1918 ATH_MSG_WARNING("Couldn't find interface object/container \""
1919 << intName << "\" belonging to branch \""
1920 << branchName << "\"");
1921 }
1922 continue;
1923 }
1924
1925 // Get the type of the interface:
1926 const EventFormatElement* el = m_inputEventFormat.get(intName);
1927 ::TClass* cl = ::TClass::GetClass(el->className().c_str());
1928 if ((!cl) || (!cl->IsLoaded())) {
1929 ATH_MSG_WARNING("Couldn't find dictionary for type \""
1930 << el->className() << "\"");
1931 continue;
1932 }
1933
1934 // Get the dictionary for the DataVector base class:
1935 static const std::type_info &baseTi = typeid(SG::AuxVectorBase);
1936 static const std::string baseName = SG::normalizedTypeinfoName(baseTi);
1937 static ::TClass* const baseCl = ::TClass::GetClass(baseName.c_str());
1938 if (!baseCl) {
1939 ATH_MSG_ERROR("Couldn't get dictionary for type \"" << baseName
1940 << "\"");
1941 return StatusCode::FAILURE;
1942 }
1943
1944 // The type of the auxiliary store is finally deduced from the
1945 // inheritance of the interface container.
1946 const TAuxStore::EStructMode mode =
1947 (cl->InheritsFrom(baseCl) ? TAuxStore::EStructMode::kContainerStore
1949
1950 // Scan the branches using a temporary TAuxStore instance:
1951 static constexpr bool TOP_STORE = true;
1952 TAuxStore temp(branchName, TOP_STORE, mode);
1953 static constexpr bool PRINT_WARNINGS = false;
1954 ATH_CHECK(temp.readFrom(*m_inTree, PRINT_WARNINGS));
1955
1956 // Conveninence variable:
1957 ReadStats &stats = IOStats::instance().stats();
1958
1959 // Teach the cache about all the branches:
1960 for (SG::auxid_t id : temp.getAuxIDs()) {
1961 stats.branch(branchName, id);
1962 }
1963
1964 // Increment the number of known branches:
1965 stats.setBranchNum(stats.branchNum() + temp.getAuxIDs().size());
1966 }
1967 // If it's an interface container:
1968 else {
1969 // Try to access the branch:
1970 const ::TBranch* container = m_inTree->GetBranch(branchName.c_str());
1971 // If it exists, let's remember it:
1972 if (container) {
1973 IOStats::instance().stats().container(branchName);
1974 }
1975 }
1976 }
1977
1978 // Return gracefully:
1979 return StatusCode::SUCCESS;
1980}
1981
1994StatusCode TEvent::record(std::unique_ptr<TAuxStore> store,
1995 const std::string &key) {
1996
1997 // Check if we have an output tree:
1998 if (!m_outTree) {
2000 "No output tree defined. Did you forget to call writeTo(...)?");
2001 return StatusCode::FAILURE;
2002 }
2003
2004 // Check if we have a filtering rule for this key:
2005 const std::set<std::string>* filter = 0;
2006 auto filter_itr = m_auxItemList.find(key);
2007 if (filter_itr != m_auxItemList.end()) {
2008 filter = &(filter_itr->second);
2009 }
2010
2011 // Check if we need to add it to the event record:
2012 Object_t::iterator vitr = m_outputObjects.find(key);
2013 if (vitr == m_outputObjects.end()) {
2014
2015 // Configure the object for variable filtering:
2016 if (filter) {
2017 store->selectAux(*filter);
2018 }
2019 // Tell the object where to write its contents:
2020 ATH_CHECK(store->writeTo(*m_outTree));
2021 // Record it to the output list:
2022 static constexpr bool OWNS_STORE = true;
2023 m_outputObjects[key] =
2024 std::make_unique<TAuxManager>(store.release(), OWNS_STORE);
2025
2026 // We're done:
2027 return StatusCode::SUCCESS;
2028 }
2029
2030 // Check if the output has the right store:
2031 if (vitr->second->object() == store.get()) {
2032 // We're done already:
2033 return StatusCode::SUCCESS;
2034 }
2035
2036 // If not, update the output manager. This can happen when we copy
2037 // objects from the input to the output files, and we process
2038 // multiple input files.
2039
2040 // Check if the output manager is of the right type:
2041 TAuxManager* mgr = dynamic_cast<TAuxManager* >(vitr->second.get());
2042 if (mgr == nullptr) {
2043 ATH_MSG_ERROR("Output object with key \""
2044 << key << "\" already exists, and is not of type TAuxStore");
2045 return StatusCode::FAILURE;
2046 }
2047
2048 // Configure the object for variable filtering:
2049 if (filter) {
2050 store->selectAux(*filter);
2051 }
2052
2053 // Connect the auxiliary store to the output tree:
2054 ATH_CHECK(store->writeTo(*m_outTree));
2055
2056 // Update the manager:
2057 mgr->setObject(store.release());
2058
2059 // Return gracefully:
2060 return StatusCode::SUCCESS;
2061}
2062
2072
2073 // Check if we can call setName(...) on the object:
2074 ::TMethodCall setNameCall;
2075 // Don't use this code in Athena access mode. And just accept that access
2076 // monitoring is disabled in this case...
2077 if (m_auxMode != kAthenaAccess) {
2078 setNameCall.InitWithPrototype(mgr.holder()->getClass(), "setName",
2079 "const char*");
2080 if (setNameCall.IsValid()) {
2081 // Yes, there is such a function. Let's call it with the branch
2082 // name:
2083 const ::TString params =
2084 ::TString::Format("\"%s\"", mgr.branch()->GetName());
2085 const char* charParams = params.Data();
2086 setNameCall.Execute(mgr.holder()->get(), charParams);
2087 } else {
2088 // This is weird. What sort of auxiliary container is this? :-/
2089 ATH_MSG_WARNING("Couldn't find setName(...) function for container \""
2090 << mgr.branch()->GetName() << "\" (type: "
2091 << mgr.holder()->getClass()->GetName() << ")");
2092 }
2093 }
2094
2095 // Check if we can switch out the internal store of this object:
2096 static const TClass* const holderClass =
2097 TClass::GetClass(typeid(SG::IAuxStoreHolder));
2098 if (!mgr.holder()->getClass()->InheritsFrom(holderClass)) {
2099 // Nope... So let's just end the journey here.
2100 return StatusCode::SUCCESS;
2101 }
2102
2103 // Try to get the object as an IAuxStoreHolder:
2104 SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder* >(
2105 mgr.holder()->getAs(typeid(SG::IAuxStoreHolder)));
2106 if (!storeHolder) {
2107 ATH_MSG_FATAL("There's a logic error in the code");
2108 return StatusCode::FAILURE;
2109 }
2110
2111 // Create a TAuxStore instance that will read the dynamic variables
2112 // of this container. Notice that the TAuxManager doesn't own the
2113 // TAuxStore object. It will be owned by the SG::IAuxStoreHolder
2114 // object.
2115 static constexpr bool TOP_STORE = false;
2116 auto store = std::make_unique<TAuxStore>(
2117 mgr.branch()->GetName(), TOP_STORE,
2121 // This object is used to read data from the input, it needs to be
2122 // locked:
2123 store->lock();
2124
2125 // Set it up to read from the input RNTuple.
2126 ATH_CHECK(store->readFrom(*tree));
2127
2128 // Set it up to read from the input TTree.
2129 ATH_CHECK(store->readFrom(*tree));
2130 // Tell the auxiliary store which entry to use. This is essential for
2131 // metadata objects, and non-important for event data objects, which will
2132 // get a possibly different entry loaded in setAuxStore(...).
2133 store->getEntry(0);
2134
2135 // Set up a manager for it.
2136 static constexpr bool SHARED_OWNER = false;
2137 m_inputObjects[std::string(mgr.branch()->GetName()) + "Dynamic"] =
2138 std::make_unique<TAuxManager>(store.get(), SHARED_OWNER);
2139
2140 // Give this object to the store holder:
2141 storeHolder->setStore(store.release());
2142
2143 // Return gracefully:
2144 return StatusCode::SUCCESS;
2145}
2146
2157StatusCode TEvent::putAux(::TTree &outTree, TVirtualManager &vmgr,
2158 bool metadata) {
2159
2160 // A little sanity check:
2161 assert(m_outputEventFormat != 0);
2162
2163 // Do the conversion:
2164 TObjectManager* mgr = dynamic_cast<TObjectManager* >(&vmgr);
2165 if (!mgr) {
2166 // It's not an error any more when we don't get a TObjectManager.
2167 return StatusCode::SUCCESS;
2168 }
2169
2170 // Check if we need to do anything here:
2171 if (!mgr->holder()->getClass()->InheritsFrom("SG::IAuxStoreIO")) {
2172 return StatusCode::SUCCESS;
2173 }
2174
2175 // Get a pointer to the auxiliary store I/O interface:
2176 SG::IAuxStoreIO* aux = reinterpret_cast<SG::IAuxStoreIO* >(
2177 mgr->holder()->getAs(typeid(SG::IAuxStoreIO)));
2178 if (!aux) {
2179 ATH_MSG_FATAL("There is a logic error in the code!");
2180 return StatusCode::FAILURE;
2181 }
2182
2183 // Check if we have rules defined for which auxiliary properties
2184 // to write out:
2186 if (!metadata) {
2187 auto item_itr = m_auxItemList.find(mgr->branch()->GetName());
2188 if (item_itr != m_auxItemList.end()) {
2189 sel.selectAux(item_itr->second);
2190 }
2191 }
2192
2193 // Get the dynamic auxiliary variables held by this object, which
2194 // were selected to be written:
2195 const SG::auxid_set_t auxids =
2196 sel.getSelectedAuxIDs(aux->getSelectedAuxIDs());
2197
2198 // If there are no dynamic auxiliary variables in the object, return
2199 // right away:
2200 if (auxids.empty()) {
2201 return StatusCode::SUCCESS;
2202 }
2203
2204 // Decide what should be the prefix of all the dynamic branches:
2205 const std::string dynNamePrefix =
2206 Utils::dynBranchPrefix(mgr->branch()->GetName());
2207
2208 // Select which container to add the variables to:
2209 Object_t &objects = (metadata ? m_outputMetaObjects : m_outputObjects);
2210
2211 // This iteration will determine the ordering of branches within
2212 // the tree, so sort auxids by name.
2214 typedef std::pair<std::string, SG::auxid_t> AuxVarSort_t;
2215 std::vector<AuxVarSort_t> varsort;
2216 varsort.reserve(auxids.size());
2217 for (SG::auxid_t id : auxids) {
2218 varsort.emplace_back(r.getName(id), id);
2219 }
2220 std::sort(varsort.begin(), varsort.end());
2221
2222 // Extract all the dynamic variables from the object:
2223 for (const auto &p : varsort) {
2224
2225 // The auxiliary ID:
2226 const SG::auxid_t id = p.second;
2227
2228 // Construct a name for the branch that we will write:
2229 const std::string brName = dynNamePrefix + p.first;
2230
2231 // Try to find the branch:
2232 Object_t::iterator bmgr = objects.find(brName);
2233
2234 // Check if we already know about this variable:
2235 if (bmgr == objects.end()) {
2236
2237 // Construct the full type name of the variable:
2238 const std::type_info* brType = aux->getIOType(id);
2239 if (!brType) {
2240 ATH_MSG_ERROR("No I/O type found for variable " << brName);
2241 return StatusCode::FAILURE;
2242 }
2243 const std::string brTypeName = Utils::getTypeName(*brType);
2244 std::string brProperTypeName = "<unknown>";
2245
2246 // The branch that will hopefully be created:
2247 ::TBranch* br = 0;
2248
2249 // Check if it's a primitive type or not:
2250 if (strlen(brType->name()) == 1) {
2251
2252 // Making the "proper" type name is simple in this case:
2253 brProperTypeName = brTypeName;
2254
2255 // Get the character describing this type for ROOT:
2256 const char rootType = Utils::rootType(brType->name()[0]);
2257 if (rootType == '\0') {
2258 ATH_MSG_ERROR("Type not known for variable \""
2259 << brName << "\" of type \"" << brTypeName << "\"");
2260 return StatusCode::FAILURE;
2261 }
2262
2263 // Create the full description of the variable for ROOT:
2264 std::ostringstream leaflist;
2265 leaflist << brName << "/" << rootType;
2266
2267 // Let's create a holder for this property:
2268 static constexpr bool IS_OWNER = false;
2269 auto auxmgr = std::make_unique<TPrimitiveAuxBranchManager>(
2270 id, nullptr, new THolder(aux->getIOData(id), nullptr, IS_OWNER));
2271
2272 // ... and let's add it to the output TTree:
2273 static constexpr Int_t BASKET_SIZE = 32000;
2274 *(auxmgr->branchPtr()) =
2275 outTree.Branch(brName.c_str(), auxmgr->holder()->get(),
2276 leaflist.str().c_str(), BASKET_SIZE);
2277 if (!auxmgr->branch()) {
2278 ATH_MSG_ERROR("Failed to create branch \""
2279 << brName << "\" out of type \"" << brProperTypeName
2280 << "\"");
2281 // Clean up:
2282 *(auxmgr->holder()->getPtr()) = 0;
2283 return StatusCode::FAILURE;
2284 }
2285 br = auxmgr->branch();
2286
2287 // Store it in the output list.
2288 objects[brName] = std::move(auxmgr);
2289
2290 } else {
2291
2292 // Check if we have a dictionary for this type:
2293 static constexpr Bool_t LOAD_IF_NOT_FOUND = kTRUE;
2294 static constexpr Bool_t SILENT = kTRUE;
2295 TClass* cl = TClass::GetClass(*brType, LOAD_IF_NOT_FOUND, SILENT);
2296 if (cl == nullptr) {
2297 // The dictionary needs to be loaded now. This could be an
2298 // issue. But let's hope for the best...
2299 cl = TClass::GetClass(brTypeName.c_str());
2300 // If still not found...
2301 if (cl == nullptr) {
2302 ATH_MSG_ERROR("Dictionary not available for variable \""
2303 << brName << "\" of type \"" << brTypeName << "\"");
2304 return StatusCode::FAILURE;
2305 }
2306 }
2307
2308 // The proper type name comes from the dictionary in this case:
2309 brProperTypeName = cl->GetName();
2310
2311 // Let's create a holder for this property:
2312 static constexpr bool IS_OWNER = false;
2313 auto auxmgr = std::make_unique<TAuxBranchManager>(
2314 id, nullptr, new THolder(aux->getIOData(id), cl, IS_OWNER));
2315
2316 // ... and let's add it to the output TTree.
2317 static constexpr Int_t BASKET_SIZE = 32000;
2318 static constexpr Int_t SPLIT_LEVEL = 0;
2319 *(auxmgr->branchPtr()) = outTree.Branch(brName.c_str(), cl->GetName(),
2320 auxmgr->holder()->getPtr(),
2321 BASKET_SIZE, SPLIT_LEVEL);
2322 if (!auxmgr->branch()) {
2323 ATH_MSG_ERROR("Failed to create branch \""
2324 << brName << "\" out of type \"" << brProperTypeName
2325 << "\"");
2326 // Clean up:
2327 *(auxmgr->holder()->getPtr()) = 0;
2328 return StatusCode::FAILURE;
2329 }
2330 br = auxmgr->branch();
2331
2332 // Store it in the output list.
2333 objects[brName] = std::move(auxmgr);
2334 }
2335
2336 // If this is not the first event, fill up the already filled
2337 // events with (empty) content:
2338 if (outTree.GetEntries()) {
2339 void* ptr = br->GetAddress();
2340 br->SetAddress(0);
2341 for (::Long64_t i = 0; i < outTree.GetEntries(); ++i) {
2342 br->Fill();
2343 }
2344 br->SetAddress(ptr);
2345 }
2346
2347 // If all went fine, let's add this branch to the event format
2348 // metadata:
2349 if (!m_outputEventFormat->exists(brName)) {
2350 m_outputEventFormat->add(EventFormatElement(brName, brProperTypeName,
2351 mgr->branch()->GetName(),
2352 getHash(brName)));
2353 }
2354
2355 // We don't need to do the rest:
2356 continue;
2357 }
2358
2359 // Access the object manager:
2360 bmgr = objects.find(brName);
2361 if (bmgr == objects.end()) {
2362 ATH_MSG_FATAL("There is an internal logic error in the code...");
2363 return StatusCode::FAILURE;
2364 }
2365
2366 // Replace the managed object:
2367 void* nc_data ATLAS_THREAD_SAFE = // we hold non-const pointers but check
2368 // on retrieve
2369 const_cast<void* >(static_cast<const void* >(aux->getIOData(id)));
2370 bmgr->second->setObject(nc_data);
2371 }
2372
2373 // Return gracefully:
2374 return StatusCode::SUCCESS;
2375}
2376
2377StatusCode TEvent::recordAux(TAuxStore* store, const std::string &key) {
2378
2379 // Check if we have an output tree:
2380 if (hasOutput() == false) {
2381 ATH_MSG_ERROR("No output tree set up.");
2382 return StatusCode::FAILURE;
2383 }
2384
2385 // Check if we have a filtering rule for this key:
2386 const std::set<std::string>* filter = 0;
2387 auto filter_itr = m_auxItemList.find(key);
2388 if (filter_itr != m_auxItemList.end()) {
2389 filter = &(filter_itr->second);
2390 }
2391
2392 // Check if we need to add it to the event record:
2393 Object_t::iterator vitr = m_outputObjects.find(key);
2394 if (vitr == m_outputObjects.end()) {
2395
2396 // Configure the object for variable filtering:
2397 if (filter) {
2398 store->selectAux(*filter);
2399 }
2400 // Tell the object where to write its contents:
2401 ATH_CHECK(store->writeTo(*m_outTree));
2402 // Record it to the output list.
2403 static constexpr bool OWNS_STORE = false;
2404 m_outputObjects[key] = std::make_unique<TAuxManager>(store, OWNS_STORE);
2405
2406 // We're done:
2407 return StatusCode::SUCCESS;
2408 }
2409
2410 // Check if the output has the right store:
2411 if (vitr->second->object() == store) {
2412 // We're done already:
2413 return StatusCode::SUCCESS;
2414 }
2415
2416 // If not, update the output manager. This can happen when we copy
2417 // objects from the input to the output files, and we process
2418 // multiple input files.
2419
2420 // Check if the output manager is of the right type:
2421 TAuxManager* mgr = dynamic_cast<TAuxManager* >(vitr->second.get());
2422 if (mgr == nullptr) {
2423 ATH_MSG_ERROR("Output object with key \""
2424 << key << "\" already exists, and is not of type TAuxStore");
2425 return StatusCode::FAILURE;
2426 }
2427
2428 // Configure the object for variable filtering:
2429 if (filter) {
2430 store->selectAux(*filter);
2431 }
2432
2433 // Connect the auxiliary store to the output tree:
2434 ATH_CHECK(store->writeTo(*m_outTree));
2435
2436 // Update the manager:
2437 mgr->setObject(store);
2438
2439 // Return gracefully:
2440 return StatusCode::SUCCESS;
2441}
2442
2443} // namespace xAOD
#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.
Handle mappings between names and auxid_t.
Manage index tracking and synchronization of auxiliary data.
std::vector< size_t > vec
#define XAOD_MESSAGE(MESSAGE)
Simple macro for printing error/verbose messages.
Recursively separate out template arguments in a C++ class name.
Interface providing I/O for a generic auxiliary store.
static Double_t sc
Hold a pointer to the current event store.
void upgrade()
Convert the lock from upgrade to exclusive.
Exception to signal a malformed class name.
bit_t size() const
Count the number of 1 bits in the set.
bool empty() const
Return true if there are no 1 bits in the set.
Base class for elements of a container that can have aux data.
Definition AuxElement.h:484
void setStore(const SG::IConstAuxStore *store)
Set the store associated with this object.
Handle mappings between names and auxid_t.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Manage index tracking and synchronization of auxiliary data.
Interface for objects taking part in direct ROOT I/O.
AuxStoreType
Type of the auxiliary store.
@ 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 providing I/O for a generic auxiliary store.
Definition IAuxStoreIO.h:44
virtual SG::auxid_set_t getSelectedAuxIDs() const
Get a list of dynamic variables that need to be written out.
Definition IAuxStoreIO.h:86
virtual const std::type_info * getIOType(SG::auxid_t auxid) const =0
Return the type of the data to be stored for one aux data item.
virtual const void * getIOData(SG::auxid_t auxid) const =0
Return a pointer to the data to be stored for one aux data item.
Interface for non-const operations on an auxiliary store.
Definition IAuxStore.h:48
Interface for const operations on an auxiliary store.
A set of aux data identifiers.
Definition AuxTypes.h:47
Class helping in dealing with dynamic branch selection.
Manager for EDM objects created by ROOT.
const THolder * holder() const
Accessor to the Holder object.
Class describing one branch of the ROOT file.
KeyedData_t::const_iterator const_iterator
Iterator for looping over the elements of the object.
EventFormat m_inputEventFormat
Format of the current input file.
Definition Event.h:350
const std::string & name() const override
Get the name of the instance.
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:340
const void * getInputObject(SG::sgkey_t key, const std::type_info &ti, bool silent) override
Function for retrieving an input object in a non-template way.
upgrade_mutex_t m_branchesMutex
Mutex for multithread synchronization.
Definition Event.h:383
AthContainers_detail::upgrading_lock< upgrade_mutex_t > upgrading_lock_t
Lock type for multithread synchronization.
Definition Event.h:380
Object_t m_inputObjects
Collection of all the managed input objects.
Definition Event.h:337
static const char *const METADATA_OBJECT_NAME
Name of the metadata tree or RNTuple.
Definition Event.h:78
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:333
StatusCode keys(std::vector< std::string > &vkeys, bool metadata) const
Provide a list of all data object keys associated with a specific type.
void setActive() const
Set this event object as the currently active one.
Definition EventCore.cxx:54
SG::sgkey_t getHash(const std::string &key) const override
Function returning the hash describing an object name.
Object_t m_inputMetaObjects
Collection of all the managed input meta-objects.
Definition Event.h:345
std::unordered_map< std::string, std::set< std::string > > m_auxItemList
Rules for selecting which auxiliary branches to write.
Definition Event.h:355
EventFormat * m_outputEventFormat
Format of the current output file.
Definition Event.h:352
Object_t m_outputObjects
Collection of all the managed output object.
Definition Event.h:342
SG::SGKeyMap< BranchInfo > m_branches ATLAS_THREAD_SAFE
Map from hashed sgkey to BranchInfo.
Definition Event.h:387
std::vector< TVirtualIncidentListener * > m_listeners
Listeners who should be notified when certain incidents happen.
Definition Event.h:358
Object_t m_outputMetaObjects
Collection of all the managed output meta-objects.
Definition Event.h:347
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
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.
Manager for TAuxStore objects.
Definition TAuxManager.h:33
TAuxStore * getStore()
Get a type-specific pointer to the managed object.
const SG::IConstAuxStore * getConstStore() const
Get a convenience pointer to the managed object.
"ROOT @c TTree implementation" of IAuxStore
Definition TAuxStore.h:30
Helper class for making sure the current directory is preserved.
static const TEventFormatRegistry & instance()
Access the only instance of the object in memory.
EventFormat & getEventFormat(const TFile *file) const
Access the managed EventFormat object.
@ kAthenaAccess
Access containers/objects like Athena does.
@ kClassAccess
Access auxiliary data using the aux containers.
@ kBranchAccess
Access auxiliary data branch-by-branch.
::TTree * m_inMetaTree
Pointer to the metadata tree in the input file.
StatusCode connectObject(const std::string &key, bool silent) override
Function setting up access to a particular object.
StatusCode connectMetaAux(const std::string &prefix, bool standalone) override
Function setting up access to a set of auxiliary branches for a metadata object.
StatusCode connectAux(const std::string &prefix, bool standalone) override
Function setting up access to a set of auxiliary branches.
bool hasOutput() const override
Check if an output file is connected to the object.
std::unique_ptr< TChainStateTracker > m_inChainTracker
Optional object for tracking the state changes of an input TChain.
::Int_t getEntry(::Long64_t entry, ::Int_t getall=0) override
Function loading a given entry of the input TTree.
StatusCode setAuxStore(const std::string &key, Details::IObjectManager &mgr, bool metadata) override
Function connecting a DV object to its auxiliary store.
EAuxMode auxMode() const
Get what auxiliary access mode the object was constructed with.
bool hasInput() const override
Check if an input file is connected to the object.
StatusCode initStats()
Function to initialise the statistics for all Tree content.
::Long64_t m_entry
The entry to look at from the input tree.
::Long64_t getFiles() const
Get how many files are available on the currently defined input.
void setOtherMetaDataTreeNamePattern(const std::string &pattern)
Change the pattern used for collecting information from other MetaData trees NB: Additional MetaData ...
StatusCode finishWritingTo(TFile &file) override
Finish writing to an output file.
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.
StatusCode setUpDynamicStore(TObjectManager &mgr, ::TTree *tree)
Function adding dynamic variable reading capabilities to an auxiliary store object.
::TChain * m_inChain
The (optional) chain provided as input.
StatusCode putAux(::TTree &outTree, TVirtualManager &mgr, bool metadata)
Function saving the dynamically created auxiliary properties.
EAuxMode m_auxMode
The auxiliary access mode.
::Int_t fill() override
Function filling one event into the output tree.
StatusCode readFrom(::TFile &inFile) override
Set up the reading of an input file from TFile This method implements the interface from Event.
TEvent(EAuxMode mode=kClassAccess)
Default constructor.
SG::IAuxStore * recordAux(const std::string &key, SG::IAuxStoreHolder::AuxStoreType type=SG::IAuxStoreHolder::AST_ContainerStore)
Add an auxiliary store object to the output.
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.
std::unique_ptr<::TTree > m_outTree
The tree that we are writing to.
bool m_inTreeMissing
Internal status flag showing that an input file is open, but it doesn't contain an event tree.
::Int_t m_inTreeNumber
The number of the currently open tree in the input chain.
::Int_t getFile(::Long64_t file, ::Int_t getall=0)
Load the first event for a given file from the input TChain.
StatusCode writeTo(TFile &file) override
Connect the object to an output file.
::TTree * m_inTree
The main tree that we are reading from.
StatusCode connectMetaObject(const std::string &key, bool silent) override
Function setting up access to a particular metadata object.
::Long64_t getEntries() const override
Get how many entries are available from the current input file(s)
void add(std::string_view fileName)
Add information about a new file that got accessed.
static TFileAccessTracer & instance()
Access the singleton instance of this class.
This class takes care of holding EDM objects in memory.
Definition THolder.h:35
void setOwner(::Bool_t state=kTRUE)
Set whether the holder should own its object.
Definition THolder.cxx:258
void ** getPtr()
Return a typeless pointer to the held object's pointer.
Definition THolder.cxx:226
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
Manager for EDM objects created by ROOT.
::TBranch ** branchPtr()
Pointer to the branch's pointer.
virtual void setObject(void *obj) override
Function replacing the object being handled.
virtual::Int_t getEntry(::Int_t getall=0) override
Function for updating the object in memory if needed.
::TBranch * branch()
Accessor to the branch.
Class providing an interface for classes listening to xAOD incidents.
Interface class for the "manager classes".
virtual const void * object() const =0
Function getting a const pointer to the object being handled.
virtual::Int_t getEntry(::Int_t getall=0)=0
Function for updating the object in memory if needed.
void setStructMode(EStructMode mode)
Set the structure mode of the object to a new value.
EStructMode
"Structural" modes of the object
@ kUndefinedStore
The structure mode is not defined.
@ kObjectStore
The object describes a single object.
@ kContainerStore
The object describes an entire container.
EStructMode structMode() const
Get what structure mode the object was constructed with.
int r
Definition globals.cxx:22
std::vector< std::string > files
file names and file pointers
Definition hcg.cxx:50
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
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
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 ::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 MetaDataStop
The metadata for the output file should be written out.
Definition TIncident.h:31
static const ::Int_t BeginInputFile
A new input file was just opened.
Definition TIncident.h:27
std::string dynBranchPrefix(const std::string &key)
This function is used to figure out what to name dynamic auxiliary branches coming from a container c...
char rootType(char typeidType)
This function is used internally in the code when creating primitive dynamic auxiliary branches.
std::string getFirstBranchMatch(TTree *tree, const std::string &pre)
This function is used to search for a branch in a TTree that contains a given substring.
std::string getTypeName(const std::type_info &ti)
This function is necessary in order to create type names that ROOT can understand.
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
EventFormat_v1 EventFormat
Definition of the current event format version.
Definition EventFormat.h:16
static const ::Int_t CACHE_SIZE
Size of a possible TTreeCache.
Helper to disable undefined behavior sanitizer for a function.
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
TChain * tree
TFile * file