ATLAS Offline Software
Loading...
Searching...
No Matches
Control/xAODRootAccess/Root/TEvent.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"
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 tracer.add(*file);
159
160 // Look for the metadata tree:
162 if (m_inMetaTree == nullptr) {
163 ATH_MSG_ERROR("Couldn't find metadata tree on input. Object is unusable!");
164 return StatusCode::FAILURE;
165 }
166
167 // Set metadata entry to be read
168 // NB: no reading is done calling LoadTree
169 if (m_inMetaTree->LoadTree(0) < 0) {
170 ATH_MSG_ERROR("Failed to load entry 0 for metadata tree");
171 return StatusCode::FAILURE;
172 }
173
174 // A sanity check.
175 if (m_inMetaTree->GetEntries() != 1) {
176 ATH_MSG_WARNING("Was expecting a metadata tree with size 1, instead of "
177 << m_inMetaTree->GetEntries() << ".");
178 ATH_MSG_WARNING("The input file was most probably produced by hadd...");
179 }
180
181 // Make sure that the xAOD::EventFormat dictonary is loaded.
182 // This may not be the case if streamer information reading is turned
183 // off.
184 static const std::string eventFormatTypeName =
186 ::TClass* cl = ::TClass::GetClass(eventFormatTypeName.c_str());
187 if (cl == nullptr) {
188 ATH_MSG_WARNING("Couldn't load the xAOD::EventFormat dictionary");
189 }
190
191 // Helper lambda for collecting the event format metadata from an RNTuple
192 // with a given name.
193 auto readEventFormatMetadata =
194 [&](std::string_view thisTreeName) -> StatusCode {
195 // Look for the metadata tree:
196 TTree* metaTree = file->Get<TTree>(thisTreeName.data());
197 if (metaTree == nullptr) {
198 ATH_MSG_ERROR("Couldn't find metadata tree \"" << thisTreeName
199 << "\"on input.");
200 return StatusCode::FAILURE;
201 }
202 // Set metadata entry to be read.
203 if (metaTree->LoadTree(0) < 0) {
204 ATH_MSG_ERROR("Failed to load entry 0 for metadata tree \""
205 << thisTreeName << "\"");
206 return StatusCode::FAILURE;
207 }
208
209 // Check if the EventFormat branch is available:
210 const std::string eventFormatBranchName =
212 if (!metaTree->GetBranch(eventFormatBranchName.c_str())) {
213 // This can happen when the file was produced by an Athena job that
214 // didn't have any input events itself. This means that the file
215 // doesn't actually have any useful metadata.
216 ATH_MSG_INFO("Input file provides no event or metadata");
217 return StatusCode::RECOVERABLE;
218 }
219
220 // Read in the event format object:
221 EventFormat* format = 0;
222 ::TBranch* br = 0;
223 const Int_t status =
224 metaTree->SetBranchAddress(eventFormatBranchName.c_str(), &format, &br);
225 if (status < 0) {
226 ATH_MSG_ERROR("Failed to connect to xAOD::EventFormat object");
227 return StatusCode::FAILURE;
228 }
229
230 // Merge the object into our private member.
231 br->GetEntry(0);
232 for (const auto &[key, element] : *format) {
233 m_inputEventFormat.add(element);
234 }
235
236 // This is a strange place. The object has to be deleted, as it is the
237 // responsibility of the user code to do so. But if I also explicitly
238 // tell the branch to forget about the address of the pointer, then
239 // all hell breaks loose...
240 delete format;
241
242 // Return gracefully.
243 return StatusCode::SUCCESS;
244 };
245
246 // Read in the metadata from the "main" metadata ntuple.
248 const StatusCode sc = readEventFormatMetadata(METADATA_OBJECT_NAME);
249 if (sc.isRecoverable()) {
250 m_inTree = nullptr;
251 m_inTreeMissing = true;
252 return StatusCode::SUCCESS;
253 }
254 ATH_CHECK(sc);
255
256 // List all the other Metadata trees in the input file
257 // Having several metatrees can happen for augmented files for instance
258 // as one metadata tree per stream is produced
259 std::set<std::string> lOtherMetaTreeNames = {};
260 TList* lKeys = file->GetListOfKeys();
261
262 if (lKeys) {
263 for (int iKey = 0; iKey < lKeys->GetEntries(); iKey++) {
264 // iterate over keys and add
265 std::string keyName = lKeys->At(iKey)->GetName();
266 // Make sure the key corresponds to a metadata tree but
267 // do not add the current metadata tree in the list of other trees
268 // and do not add the metadata tree handlers to the list
269 if ((keyName != METADATA_OBJECT_NAME) &&
270 std::regex_match(keyName, m_otherMetaDataTreeNamePattern)) {
271 // Make sure key corresponds to a tree
272 const char* className = ((::TKey* )lKeys->At(iKey))->GetClassName();
273 static constexpr Bool_t LOAD = kFALSE;
274 static constexpr Bool_t SILENT = kTRUE;
275 ::TClass* cl = ::TClass::GetClass(className, LOAD, SILENT);
276 if ((cl != nullptr) && cl->InheritsFrom(::TTree::Class())) {
277 // key is corresponding to a metadata tree
278 lOtherMetaTreeNames.insert(std::move(keyName));
279 }
280 }
281 }
282 }
283
284 // Loop over the other metadata trees found (if any).
285 for (const std::string &metaTreeName : lOtherMetaTreeNames) {
286 ATH_CHECK(readEventFormatMetadata(metaTreeName));
287 }
288
289 // Look for the event tree in the input file.
290 m_inTree = file->Get<TTree>(treeName.data());
291 if (m_inTree == nullptr) {
292 // This is no longer an error condition. As it can happen for DxAODs
293 // that don't have any events in them. But they still have metadata
294 // that needs to be collected.
295 m_inTreeMissing = kTRUE;
296 }
297
298 // Turn on the cache if requested.
299 if (m_inTree && useTreeCache && (!m_inTree->GetCacheSize())) {
300 m_inTree->SetCacheSize(CACHE_SIZE);
301 m_inTree->SetCacheLearnEntries(10);
302 }
303
304 // Init the statistics collection.
306 // Update the event counter in the statistics object.
308 if (m_inTree) {
309 stats.setNEvents(stats.nEvents() + m_inTree->GetEntries());
310 }
311
312 // Notify the listeners that a new file was opened.
313 const TIncident beginIncident(IncidentType::BeginInputFile);
314 for (TVirtualIncidentListener* listener : m_listeners) {
315 listener->handle(beginIncident);
316 }
317 // For now implement a very simple scheme in which we claim already
318 // at the start that the entire file was processed. Since we have no way
319 // of ensuring that the user indeed does this. And we can't delay calling
320 // this function, as the user may likely close his/her output file before
321 // closing the last opened input file.
322 const TIncident endIncident(IncidentType::EndInputFile);
323 for (TVirtualIncidentListener* listener : m_listeners) {
324 listener->handle(endIncident);
325 }
326
327 // The initialisation was successful.
328 return StatusCode::SUCCESS;
329}
330
339StatusCode TEvent::readFrom(::TTree* tree, bool useTreeCache) {
340
341 // Remember the info:
342 m_inTree = nullptr;
343 m_inTreeMissing = false;
344 m_inChain = dynamic_cast<TChain* >(tree);
345 m_inMetaTree = nullptr;
346
347 if (m_inChain) {
348
349 // Set up the caching on the chain level. The individual trees of the
350 // input files will get a cache set up automatically after this.
351 if (useTreeCache && (!m_inChain->GetCacheSize())) {
352 m_inChain->SetCacheSize(CACHE_SIZE);
353 m_inChain->SetCacheLearnEntries(10);
354 }
355
356 // Explicitly open the first file of the chain. To correctly auto-load
357 // the dictionaries necessary. This doesn't happen automatically with
358 // some ROOT versions...
359 const TObjArray* files = m_inChain->GetListOfFiles();
360 if (!files) {
361 ATH_MSG_ERROR("Couldn't get the list of files from the input TChain");
362 return StatusCode::FAILURE;
363 }
364 if (!files->GetEntries()) {
365 ATH_MSG_ERROR("No files are present in the received TChain");
366 return StatusCode::FAILURE;
367 }
368 const ::TChainElement* chEl =
369 dynamic_cast<const ::TChainElement* >(files->At(0));
370 if (!chEl) {
371 ATH_MSG_ERROR("Couldn't cast object to TChainElement");
372 return StatusCode::FAILURE;
373 }
374 {
375 std::unique_ptr<TFile> dummyFile{TFile::Open(chEl->GetTitle())};
376 if (!dummyFile) {
377 ATH_MSG_ERROR("Couldn't open file " << chEl->GetTitle());
378 return StatusCode::FAILURE;
379 }
380 }
381
382 // Set up a tracker for the chain.
383 if (!m_inChainTracker) {
384 m_inChainTracker = std::make_unique<TChainStateTracker>();
385 }
386 m_inChainTracker->reset();
387 tree->SetNotify(m_inChainTracker.get());
388
389 // Stop at this point. The first file will be opened when the user
390 // asks for the first event. Otherwise we open the first file of the
391 // chain multiple times.
392 m_inTreeNumber = -1;
393 return StatusCode::SUCCESS;
394
395 } else {
396
397 // If it's a simple TTree, then let's fully initialise the object
398 // using its file:
399 m_inTreeNumber = -1;
400 if (m_inChainTracker) {
401 m_inChainTracker.reset();
402 }
403 ::TFile* file = tree->GetCurrentFile();
404 return readFrom(file, useTreeCache, tree->GetName());
405 }
406}
407
416StatusCode TEvent::writeTo(::TFile* file, int autoFlush,
417 std::string_view treeName) {
418
419 // Just a simple security check.
420 if (!file) {
421 ATH_MSG_ERROR("Null pointer received!");
422 return StatusCode::FAILURE;
423 }
424
425 // Check that the object is in the "right state":
426 if (m_outTree) {
427 ATH_MSG_ERROR("Object already writing to a file. Close that file first!");
428 return StatusCode::FAILURE;
429 }
430
431 // Make sure we return to the current directory:
433
434 // Create the output TTree:
435 file->cd();
436 m_outTree = std::make_unique<TTree>(treeName.data(), "xAOD event tree");
437 m_outTree->SetDirectory(file);
438 m_outTree->SetAutoSave(1000000);
439 m_outTree->SetAutoFlush(autoFlush);
440
441 // Access the EventFormat object associated with this file:
444
445 // Return gracefully:
446 return StatusCode::SUCCESS;
447}
448
455StatusCode TEvent::finishWritingTo(::TFile* file) {
456
457 // A small sanity check:
458 if (!m_outTree) {
459 ATH_MSG_ERROR("The object doesn't seem to be connected to an output file!");
460 return StatusCode::FAILURE;
461 }
462
463 // Make sure we return to the current directory:
465
466 // Notify the listeners that they should write out their metadata, if they
467 // have any.
469 for (auto &listener : m_listeners) {
470 listener->handle(incident);
471 }
472
473 // Write out the event tree, and delete it:
474 m_outTree->AutoSave("FlushBaskets");
475 m_outTree->SetDirectory(0);
476 m_outTree.reset();
477
478 // Now go to the output file:
479 file->cd();
480
481 // Check if there's already a metadata tree in the output:
482 if (file->Get(METADATA_OBJECT_NAME)) {
483 // Let's assume that the metadata is complete in the file already.
484 return StatusCode::SUCCESS;
485 }
486
487 // Create the metadata tree.
488 auto metatree =
489 std::make_unique<TTree>(METADATA_OBJECT_NAME, "xAOD metadata tree");
490 metatree->SetAutoSave(10000);
491 metatree->SetAutoFlush(-30000000);
492 metatree->SetDirectory(file);
493
494 // Create the xAOD::EventFormat branch in it.
495 try {
496 metatree->Branch(
497 "EventFormat",
500 } catch (const CxxUtils::ClassName::ExcBadClassName &e) {
501 ::Error("xAOD::TEvent::finishWritingTo",
502 XAOD_MESSAGE("Class name parsing fails for %s ! "), e.what());
503 return StatusCode::FAILURE;
504 }
505
506 // Create a copy of the m_outputMetaObjects variable. This is necessary
507 // because the putAux(...) function will modify this variable while we
508 // loop over it.
509 std::vector<std::pair<std::string, TObjectManager* >> outputMetaObjects;
510 outputMetaObjects.reserve(m_outputMetaObjects.size());
511 for (const auto &[key, mgr] : m_outputMetaObjects) {
512 TObjectManager* objMgr = dynamic_cast<TObjectManager* >(mgr.get());
513 if (objMgr == nullptr) {
514 ATH_MSG_FATAL("Internal logic error detected");
515 return StatusCode::FAILURE;
516 }
517 outputMetaObjects.emplace_back(key, objMgr);
518 }
519
520 // Now loop over all the metadata objects that need to be put into the
521 // output file:
522 for (auto &[key, mgr] : outputMetaObjects) {
523
524 // Select a split level depending on whether this is an interface or an
525 // auxiliary object:
526 const ::Int_t splitLevel = (key.ends_with("Aux.") ? 1 : 0);
527 // Create the new branch:
528 *(mgr->branchPtr()) =
529 metatree->Branch(key.c_str(), mgr->holder()->getClass()->GetName(),
530 mgr->holder()->getPtr(), 32000, splitLevel);
531 if (!mgr->branch()) {
532 ATH_MSG_ERROR("Failed to create metadata branch \""
533 << mgr->holder()->getClass()->GetName() << "/" << key
534 << "\"");
535 return StatusCode::FAILURE;
536 }
537 // Set up the saving of all the dynamic auxiliary properties
538 // of the object if it has any:
539 static constexpr bool METADATA = true;
540 ATH_CHECK(putAux(*metatree, *mgr, METADATA));
541 }
542
543 // Write the metadata objects:
544 if (metatree->Fill() <= 0) {
545 ATH_MSG_ERROR("Failed to write event format metadata into the output");
546 metatree->SetDirectory(nullptr);
547 return StatusCode::FAILURE;
548 }
549
550 // Now clean up:
551 metatree->Write();
552 metatree->SetDirectory(nullptr);
553 m_outputEventFormat = nullptr;
554 m_outputObjects.clear();
555 m_outputMetaObjects.clear();
556
557 // Return gracefully:
558 return StatusCode::SUCCESS;
559}
560
570SG::IAuxStore* TEvent::recordAux(const std::string &key,
572
573 // A sanity check:
574 if (!m_outTree) {
575 ATH_MSG_ERROR("No output tree given to the object");
576 return nullptr;
577 }
578
579 // Check for an object with this name in the output list:
580 Object_t::iterator itr = m_outputObjects.find(key);
581 if (itr == m_outputObjects.end()) {
582 // Create one if if it doesn't exist yet...
583 // Translate the store type:
585 switch (type) {
588 break;
591 break;
592 default:
593 ATH_MSG_ERROR("Unknown store type (" << type << ") requested");
594 return nullptr;
595 }
596 // Create and record the object:
597 static constexpr bool TOP_STORE = true;
598 if (record(std::make_unique<TAuxStore>(key, TOP_STORE, mode), key)
599 .isFailure()) {
600 ATH_MSG_ERROR("Couldn't connect TAuxStore object to the output");
601 return nullptr;
602 }
603 // Update the iterator:
604 itr = m_outputObjects.find(key);
605 }
606
607 // A security check:
608 if (itr == m_outputObjects.end()) {
609 ATH_MSG_ERROR("Internal logic error detected");
610 return nullptr;
611 }
612
613 // Check that it is of the right type:
614 TAuxManager* mgr = dynamic_cast<TAuxManager* >(itr->second.get());
615 if (!mgr) {
616 ATH_MSG_ERROR("Internal logic error detected");
617 return nullptr;
618 }
619
620 // Extract the pointer out of it:
621 TAuxStore* store = mgr->getStore();
622
623 // Give it to the user:
624 return store;
625}
626
629::Long64_t TEvent::getEntries() const {
630
631 if (m_inChain) {
632 return m_inChain->GetEntries();
633 } else if (m_inTree) {
634 return m_inTree->GetEntries();
635 } else if (m_inTreeMissing) {
636 // The input file is empty:
637 return 0;
638 } else {
639 ATH_MSG_ERROR("Function called on an uninitialised object");
640 return 0;
641 }
642}
643
658::Int_t TEvent::getEntry(::Long64_t entry, ::Int_t getall) {
659
660 // A little sanity check:
661 if ((!m_inTree) && (!m_inChain)) {
662 ATH_MSG_ERROR("Function called on an uninitialised object");
663 return -1;
664 }
665
666 // If we have a chain as input:
667 if (m_inChain) {
668 // Make sure that the correct tree is loaded:
669 const ::Long64_t fileEntry = m_inChain->LoadTree(entry);
670 if (fileEntry < 0) {
671 ATH_MSG_ERROR("Failure in loading entry " << entry
672 << " from the input chain");
673 return -1;
674 }
675 // Check if a new file was loaded:
676 if ((m_inTreeNumber != m_inChain->GetTreeNumber()) ||
677 m_inChainTracker->internalStateChanged()) {
678 // Reset the tracker:
679 m_inChainTracker->reset();
680 // Connect to this new file:
681 m_inTreeNumber = m_inChain->GetTreeNumber();
682 ::TFile* file = m_inChain->GetFile();
683 // The useTreeCache parameter is set to false, since the cache
684 // is anyway set up through the TChain. It shouldn't be modified
685 // on the file level.
686 static constexpr bool USE_TREE_CACHE = false;
687 if (readFrom(file, USE_TREE_CACHE, m_inChain->GetName()).isFailure()) {
688 ATH_MSG_ERROR("Couldn't connect to input file #"
689 << m_inTreeNumber << " of the input chain");
690 return -1;
691 }
692 }
693 // Restore the previously received entry number.
694 m_entry = fileEntry;
695 }
696 // If we have a regular file/tree as input:
697 else {
698 m_entry = entry;
699 }
700
701 // In order to make the reading of branches+tree cache work
702 // NB: TTree::LoadTree() only set the entry that should be read for each
703 // branch but no reading of the branch content is performed when calling that
704 // function. The entry set that can be retrieved with
705 // branch->GetTree()->GetReadEntry()
706 // For friend trees, if an index was built, then the entry which is set for
707 // the related branches is found by the LoadTree function by matching the the
708 // major and minor values of the main tree and friend tree
709 if (m_inTree && m_inTree->LoadTree(m_entry) < 0) {
710 ATH_MSG_ERROR("Failure in loading entry " << m_entry
711 << " from the input file");
712 return -1;
713 }
714
715 // Stats counter needs to know it's the next event:
717
718 // The final number of bytes read.
719 ::Int_t result = 0;
720
721 // Check if objects need to be read in.
722 if (getall) {
723 if (m_auxMode == kAthenaAccess) {
724 // In kAthenaAccess mode we need to use getInputObject(...) to load
725 // all the input objects correctly.
726 for (auto &[key, mgr] : m_inputObjects) {
727 static const std::string dynStorePostfix = "Aux.Dynamic";
728 if (key.ends_with(dynStorePostfix)) {
729 // Ignore the dynamic store objects. They get loaded through
730 // their parents.
731 } else {
732 // Load the objects and their auxiliary stores through the
733 // getInputObject(...) function, which takes care of correctly
734 // setting them up. The type is irrelevant here. We don't
735 // really care about the exact type of the objects.
736 static constexpr bool SILENT = true;
737 static constexpr bool METADATA = false;
738 getInputObject(key, typeid(int), SILENT, METADATA);
739 }
740 }
741 } else {
742 // In a "reasonable" access mode, we do something very simple:
743 for (auto &[key, mgr] : m_inputObjects) {
744 result += mgr->getEntry(getall);
745 }
746 }
747 }
748
749 // Notify the listeners that a new event was loaded:
750 const TIncident incident(IncidentType::BeginEvent);
751 for (auto &listener : m_listeners) {
752 listener->handle(incident);
753 }
754
755 // Return the number of bytes read:
756 return result;
757}
758
768::Long64_t TEvent::getFiles() const {
769
770 if (m_inChain) {
771 return m_inChain->GetListOfFiles()->GetEntries();
772 } else if (m_inTree || m_inTreeMissing) {
773 return 1;
774 } else {
775 return 0;
776 }
777}
778
788::Int_t TEvent::getFile(::Long64_t file, ::Int_t getall) {
789
790 // Check if the file number is valid:
791 if ((file < 0) || (file >= getFiles())) {
792 ATH_MSG_ERROR("Function called with invalid file number (" << file << ")");
793 return -1;
794 }
795
796 // If we are not reading a TChain, return at this point. As the one and
797 // only file is open already...
798 if (!m_inChain) {
799 return 0;
800 }
801
802 // Trigger the "scanning" of the input files, so the TChain would know
803 // how many entries are in the various files.
804 getEntries();
805
806 // Calculate which entry/event we need to load:
807 ::Long64_t entry = 0;
808 for (::Long64_t i = 0; i < file; ++i) {
809 entry += m_inChain->GetTreeOffset()[i];
810 }
811
812 // Load this entry using the regular event opening function:
813 return getEntry(entry, getall);
814}
815
822::Int_t TEvent::fill() {
823
824 // A little sanity check:
825 if (!m_outTree) {
826 ATH_MSG_ERROR("Object not connected to an output file!");
827 return 0;
828 }
829
830 // Make sure that all objects have been read in. The 99 as the value
831 // has a special meaning for TAuxStore. With this value it doesn't
832 // delete its transient (decoration) variables. Otherwise it does.
833 // (As it's supposed to, when moving to a new event.)
834 Int_t readBytes = 0;
835 if (m_inChain != nullptr) {
836 readBytes = getEntry(m_inChain->GetReadEntry(), 99);
837 } else if (m_inTree != nullptr) {
838 readBytes = getEntry(m_entry, 99);
839 }
840 if (readBytes < 0) {
841 ATH_MSG_ERROR("getEntry failed!");
842 return readBytes;
843 }
844
845 // Prepare the objects for writing. Note that we need to iterate over a
846 // copy of the m_outputObjects container. Since the putAux(...) function
847 // called inside the loop may itself add elements to the m_outputObject
848 // container.
849 std::string unsetObjects;
850 std::vector<std::pair<std::string, TVirtualManager* >> outputObjectsCopy;
851 outputObjectsCopy.reserve(m_outputObjects.size());
852 for (const auto &[key, mgr] : m_outputObjects) {
853 outputObjectsCopy.emplace_back(key, mgr.get());
854 }
855 for (auto &[key, mgr] : outputObjectsCopy) {
856 // Check that a new object was provided in the event:
857 if (!mgr->create()) {
858 // We are now going to fail. But let's collect the names of
859 // all the unset objects:
860 if (unsetObjects.size()) {
861 unsetObjects += ", ";
862 }
863 unsetObjects.append("\"" + key + "\"");
864 continue;
865 }
866 // Make sure that any dynamic auxiliary variables that
867 // were added to the object after it was put into the event,
868 // get added to the output:
869 static constexpr bool METADATA = false;
870 if (putAux(*m_outTree, *mgr, METADATA).isFailure()) {
871 ATH_MSG_ERROR("Failed to put dynamic auxiliary variables "
872 "in the output for object \""
873 << key << "\"");
874 return 0;
875 }
876 }
877
878 // Check if there were any unset objects:
879 if (unsetObjects.size()) {
880 ATH_MSG_ERROR("The following objects were not set in the current event: "
881 << unsetObjects);
882 return 0;
883 }
884
885 // Write the entry, and check the return value:
886 const ::Int_t ret = m_outTree->Fill();
887 if (ret <= 0) {
888 ATH_MSG_ERROR("Output tree filling failed with return value: " << ret);
889 }
890
891 // Reset the object managers.
892 for (auto &[key, mgr] : m_outputObjects) {
893 mgr->reset();
894 }
895
896 // Return the value:
897 return ret;
898}
899
900bool TEvent::hasInput() const {
901
902 return ((m_inTree != nullptr) || (m_inChain != nullptr));
903}
904
905bool TEvent::hasOutput() const { return (m_outTree.get() != nullptr); }
906
907StatusCode TEvent::getNames(const std::string &targetClassName,
908 std::vector<std::string> &vkeys,
909 bool metadata) const {
910 // The results go in here
911 std::set<std::string> keys;
912
913 // Get list of branches from
914 // the input metadata tree or input tree
915 std::vector<TObjArray* > fullListOfBranches = {};
916 if (metadata) {
917 if (m_inMetaTree) {
918 // No friend tree expected for metadata tree
919 // Only add the list of branches of the metadata tree
920 ATH_MSG_DEBUG("Scanning for input metadata objects");
921 fullListOfBranches.push_back(m_inMetaTree->GetListOfBranches());
922 }
923 } else {
924 if (m_inTree) {
925 ATH_MSG_DEBUG("Scanning for input data objects");
926 // Add the list of branches of the main tree
927 fullListOfBranches.push_back(m_inTree->GetListOfBranches());
928 // If the input tree has friend trees
929 // add as well the list of friend tree branches
930 if (m_inTree->GetListOfFriends()) {
931 // Get the list of friends
932 TList* fList = m_inTree->GetListOfFriends();
933 // Loop over friend elements
934 for (TObject* feObj : *fList) {
935 if (feObj) {
936 // Get corresponding friend tree
937 auto* pElement = dynamic_cast<TFriendElement* >(feObj);
938 if (pElement == nullptr) {
939 continue;
940 }
941 TTree* friendTree = pElement->GetTree();
942 // Add list of branches of the friend tree
943 fullListOfBranches.push_back(friendTree->GetListOfBranches());
944 }
945 }
946 }
947 }
948 }
949
950 // Loop over all list of branches (if any)
951 for (const TObjArray* in : fullListOfBranches) {
952 // Loop over all branches inside the current list of branches
953 for (const TObject* obj : *in) {
954
955 if (obj == nullptr) {
956 continue;
957 }
958 const TBranch* element = dynamic_cast<const TBranch* >(obj);
959 if (!element) {
960 ATH_MSG_ERROR("Failure inspecting input data objects");
961 return StatusCode::FAILURE;
962 }
963 const std::string objClassName = element->GetClassName();
964 std::string key = obj->GetName();
965 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
966 << "\"");
967 if (objClassName == targetClassName) {
968 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
969 << "\"");
970 keys.insert(std::move(key));
971 }
972 }
973 }
974
975 const Object_t &inAux = (metadata ? m_inputMetaObjects : m_inputObjects);
976
977 ATH_MSG_DEBUG("Scanning input objects for \"" << targetClassName << "\"");
978 for (const auto &[key, vmgr] : inAux) {
979 // All (metadata) objects should be held by TObjectManager objects.
980 const TObjectManager* mgr =
981 dynamic_cast<const TObjectManager* >(vmgr.get());
982 if (mgr == nullptr) {
983 continue;
984 }
985 const std::string &objClassName = mgr->holder()->getClass()->GetName();
986 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
987 << "\"");
988 if (objClassName == targetClassName) {
989 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
990 << "\"");
991 keys.insert(key);
992 }
993 }
994
995 // Check for output objects.
996 if ((metadata == false) && m_outTree) {
997 const TObjArray* out = m_outTree->GetListOfBranches();
998 ATH_MSG_DEBUG("Scanning for output data objects");
999
1000 for (const TObject* obj : *out) {
1001 if (obj == nullptr) {
1002 continue;
1003 }
1004 const TBranch* element = dynamic_cast<const TBranch* >(obj);
1005 if (element == nullptr) {
1006 ATH_MSG_ERROR("Failure inspecting output objects");
1007 return StatusCode::FAILURE;
1008 }
1009 const std::string objClassName = element->GetClassName();
1010 std::string key = obj->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(std::move(key));
1017 }
1018 }
1019 }
1020
1021 const Object_t &outAux = (metadata ? m_outputMetaObjects : m_outputObjects);
1022
1023 // Search though the in-memory output objects.
1024 ATH_MSG_DEBUG("Scanning output objects for \"" << targetClassName << "\"");
1025 for (const auto &[key, vmgr] : outAux) {
1026 // All (metadata) objects should be held by TObjectManager objects.
1027 TObjectManager* mgr = dynamic_cast<TObjectManager* >(vmgr.get());
1028 if (mgr == nullptr) {
1029 continue;
1030 }
1031 const std::string &objClassName = mgr->holder()->getClass()->GetName();
1032 ATH_MSG_VERBOSE("Inspecting \"" << objClassName << "\" / \"" << key
1033 << "\"");
1034 if (objClassName == targetClassName) {
1035 ATH_MSG_DEBUG("Matched \"" << targetClassName << "\" to key \"" << key
1036 << "\"");
1037 keys.insert(key);
1038 }
1039 }
1040
1041 vkeys.insert(vkeys.end(), keys.begin(), keys.end());
1042
1043 // Return gracefully.
1044 return StatusCode::SUCCESS;
1045}
1046
1064StatusCode TEvent::connectObject(const std::string &key, bool silent) {
1065
1066 // A little sanity check:
1067 if (hasInput() == false) {
1068 ATH_MSG_ERROR("Function called on un-initialised object");
1069 return StatusCode::FAILURE;
1070 }
1071
1072 // Increment the access counter on this container:
1074
1075 // Check if the branch is already connected:
1076 if (m_inputObjects.contains(key)) {
1077 return StatusCode::SUCCESS;
1078 }
1079 // Check if it was already found to be missing.
1080 if (m_inputMissingObjects.contains(key)) {
1081 if (silent == false) {
1082 ATH_MSG_WARNING("Branch \"" << key << "\" not available on input");
1083 }
1084 return StatusCode::RECOVERABLE;
1085 }
1086
1087 // Check if we have metadata about this branch:
1088 const xAOD::EventFormatElement* ef = nullptr;
1089 if (m_inputEventFormat.exists(key) == false) {
1090 if (silent == false) {
1091 ATH_MSG_WARNING("No metadata available for branch: " << key);
1092 }
1093 } else {
1094 ef = m_inputEventFormat.get(key);
1095 }
1096
1097 // Check if the branch exists in our input tree:
1098 ::TBranch* br = m_inTree->GetBranch(key.c_str());
1099 if (br == nullptr) {
1100 if (!silent) {
1101 ATH_MSG_WARNING("Branch \"" << key << "\" not available on input");
1102 }
1103 m_inputMissingObjects.insert(key);
1104 return StatusCode::RECOVERABLE;
1105 }
1106
1107 // Make sure that it's not in "MakeClass mode":
1108 br->SetMakeClass(0);
1109
1110 // Decide about the type that we need to use for the reading of this
1111 // branch:
1112 std::string className = br->GetClassName();
1113 if (className == "") {
1114 if (ef) {
1115 // This is a fairly weird situation, but let's fall back to taking
1116 // the class name from the metadata object in this case.
1117 className = ef->className();
1118 } else {
1120 "Couldn't find an appropriate type with a dictionary for branch \""
1121 << key << "\"");
1122 return StatusCode::FAILURE;
1123 }
1124 }
1125 ::TClass* realClass = ::TClass::GetClass(className.c_str());
1126 if (((!realClass) || (!realClass->IsLoaded())) && ef) {
1127 // We may need to do an actual schema evolution here, in which
1128 // case let's fall back on the class name coming from the metadata
1129 // object.
1130 className = ef->className();
1131 realClass = ::TClass::GetClass(className.c_str());
1132 }
1133 if ((!realClass) || (!realClass->IsLoaded())) {
1134 // Now we're in trouble...
1136 "Couldn't find an appropriate type with a dictionary for branch \""
1137 << key << "\"");
1138 return StatusCode::FAILURE;
1139 }
1140
1141 // Make sure that the current object is the "active event":
1142 setActive();
1143
1144 // The data type is always "other" for us:
1145 static const ::EDataType dataType = kOther_t;
1146
1147 // Check if the output already has this object. If it does, let's
1148 // assume that we have been copying the object to the output. Which
1149 // means that we need to resume filling the same memory address that
1150 // the output holder points to.
1151 void* ptr = nullptr;
1152 Object_t::const_iterator out_itr = m_outputObjects.find(key);
1153 if (out_itr != m_outputObjects.end()) {
1154 // It needs to be an object manager...
1155 TObjectManager* mgr = dynamic_cast<TObjectManager* >(out_itr->second.get());
1156 if (mgr == nullptr) {
1157 ATH_MSG_ERROR("Couldn't access output manager for: " << key);
1158 return StatusCode::FAILURE;
1159 }
1160 // Get the pointer out of it:
1161 ptr = mgr->holder()->get();
1162 }
1163
1164 // If there is no output object, then let's create one ourselves.
1165 // This is the only way in which we can have the memory management of
1166 // THolder do the right thing with this object.
1167 if (ptr == nullptr) {
1168 ptr = realClass->New();
1169 }
1170
1171 // Create the new manager object that will hold this EDM object:
1172 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1173 auto mgr = std::make_unique<TObjectManager>(
1174 nullptr, std::make_unique<THolder>(ptr, realClass), renewOnRead);
1175
1176 // One final check. If it's not an auxiliary store, then it must have
1177 // a split level of 0. Otherwise read rules may not work on it. Causing
1178 // *very* serious silent corruption in the data read, if we don't use
1179 // the "Athena read mode".
1180 if ((m_auxMode != kAthenaAccess) && (br->GetSplitLevel() != 0) &&
1181 (Details::isAuxStore(*(mgr->holder()->getClass())) == false)) {
1182 ATH_MSG_ERROR("Split level for branch \""
1183 << key << "\" is " << br->GetSplitLevel()
1184 << ". This can only be read in kAthenaAccess mode.");
1185 // Clean up:
1186 *(mgr->holder()->getPtr()) = nullptr;
1187 m_inputObjects.erase(key);
1188 return StatusCode::FAILURE;
1189 }
1190
1191 // Now try to connect to the branch:
1192 const ::Int_t status =
1193 m_inTree->SetBranchAddress(key.c_str(), mgr->holder()->getPtr(),
1194 mgr->branchPtr(), realClass, dataType, kTRUE);
1195 if (status < 0) {
1196 ATH_MSG_ERROR("Couldn't connect variable of type \""
1197 << className << "\" to input branch \"" << key
1198 << "\". Return code: " << status);
1199 // Clean up:
1200 *(mgr->holder()->getPtr()) = 0;
1201 m_inputObjects.erase(key);
1202 return StatusCode::FAILURE;
1203 }
1204
1205 // At this point we have successfully connected the branch.
1206 TObjectManager* mgrPtr = mgr.get();
1207 m_inputObjects[key] = std::move(mgr);
1208
1209 // If it's an auxiliary store object, set it up correctly:
1210 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
1212 }
1213
1214 // If there may be an auxiliary object connected to this one,
1215 // connect that as well:
1216 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
1218 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
1219 }
1220
1221 // Return gracefully.
1222 return StatusCode::SUCCESS;
1223}
1224
1233StatusCode TEvent::connectMetaObject(const std::string &key, bool silent) {
1234
1235 // A little sanity check:
1236 if (!m_inMetaTree) {
1237 ATH_MSG_ERROR("Function called on un-initialised object");
1238 return StatusCode::FAILURE;
1239 }
1240
1241 // Check if the branch is already connected:
1242 if (m_inputMetaObjects.contains(key)) {
1243 return StatusCode::SUCCESS;
1244 }
1245
1246 // Check if the branch exists in our metadata tree:
1247 ::TBranch* br = m_inMetaTree->GetBranch(key.c_str());
1248 if (br == nullptr) {
1249 if (silent == false) {
1250 ATH_MSG_WARNING("Metadata branch \"" << key
1251 << "\" not available on input");
1252 }
1253 return StatusCode::RECOVERABLE;
1254 }
1255
1256 // Check that we have an entry in the branch:
1257 if (br->GetEntries() == 0) {
1258 if (silent == false) {
1259 ATH_MSG_WARNING("Metadata branch \"" << key
1260 << "\" doesn't hold any data");
1261 }
1262 return StatusCode::RECOVERABLE;
1263 }
1264
1265 // Make sure that it's not in "MakeClass mode":
1266 br->SetMakeClass(0);
1267
1268 // Extract the type of the branch:
1269 ::TClass* cl = 0;
1270 ::EDataType dt = kOther_t;
1271 if (br->GetExpectedType(cl, dt) || (!cl)) {
1272 ATH_MSG_ERROR("Couldn't get the type for metadata branch \"" << key
1273 << "\"");
1274 return StatusCode::FAILURE;
1275 }
1276
1277 // Create the object, and all of the managers around it:
1278 void* ptr = cl->New();
1279 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1280 auto mgr = std::make_unique<TObjectManager>(
1281 nullptr, std::make_unique<THolder>(ptr, cl), renewOnRead);
1282
1283 // Now try to connect to the branch:
1284 const ::Int_t status = m_inMetaTree->SetBranchAddress(
1285 key.c_str(), mgr->holder()->getPtr(), mgr->branchPtr(), cl, dt, kTRUE);
1286 if (status < 0) {
1287 ATH_MSG_ERROR("Couldn't connect variable of type \""
1288 << cl->GetName() << "\" to input branch \"" << key
1289 << "\". Return code: " << status);
1290 // Clean up:
1291 *(mgr->holder()->getPtr()) = 0;
1292 m_inputMetaObjects.erase(key);
1293 return StatusCode::FAILURE;
1294 }
1295
1296 // Store the manager.
1297 TObjectManager *mgrPtr = mgr.get();
1298 m_inputMetaObjects[key] = std::move(mgr);
1299
1300 // Read in the object:
1301 if (mgrPtr->getEntry() < 0) {
1302 ATH_MSG_ERROR("Couldn't read in metadata object with key \"" << key
1303 << "\"");
1304 return StatusCode::FAILURE;
1305 }
1306
1307 // If it's an auxiliary store object, set it up correctly:
1308 if (Details::isAuxStore(*(mgrPtr->holder()->getClass()))) {
1310 }
1311
1312 // If there may be an auxiliary object connected to this one,
1313 // connect that as well.
1314 if (Details::hasAuxStore(*(mgrPtr->holder()->getClass()))) {
1316 key + "Aux.", Details::isStandalone(*(mgrPtr->holder()->getClass()))));
1317 static constexpr bool METADATA = true;
1318 ATH_CHECK(setAuxStore(key, *mgrPtr, METADATA));
1319 }
1320
1321 // We succeeded:
1322 return StatusCode::SUCCESS;
1323}
1324
1334StatusCode TEvent::connectAux(const std::string &prefix, bool standalone) {
1335
1336 // A simple test...
1337 if (hasInput() == false) {
1338 ATH_MSG_ERROR("No input tree is available");
1339 return StatusCode::FAILURE;
1340 }
1341
1342 // Check if we know anything about this auxiliary object:
1343 if ((!m_inTree->GetBranch(prefix.c_str())) &&
1345 // If not, then let's just return right away. Not having
1346 // an auxiliary object with this name is not an error per se.
1347 return StatusCode::SUCCESS;
1348 }
1349
1350 // Check if the branch is already connected.
1351 if (m_inputObjects.contains(prefix)) {
1352 return StatusCode::SUCCESS;
1353 }
1354
1355 // Do different things based on the "auxiliary mode" we are in.
1356 if ((m_auxMode == kClassAccess) || (m_auxMode == kAthenaAccess)) {
1357
1358 // In "class" and "athena" access modes just connect the concrete auxiliary
1359 // object to the input.
1360 static constexpr bool SILENT = false;
1361 ATH_CHECK(connectObject(prefix, SILENT));
1362
1363 // Return gracefully.
1364 return StatusCode::SUCCESS;
1365
1366 } else if (m_auxMode == kBranchAccess) {
1367
1368 // In "branch access mode" let's create a TAuxStore object, and let
1369 // that take care of the auxiliary store access.
1370 static constexpr bool TOP_STORE = true;
1371 auto store = std::make_unique<TAuxStore>(
1372 prefix, TOP_STORE,
1375
1376 // Connect it to the input tree.
1377 ATH_CHECK(store->readFrom(*m_inTree));
1378
1379 // We're using this object to read from the input, it needs to be
1380 // locked:
1381 store->lock();
1382
1383 // Finally, set up an appropriate manager for it.
1384 static constexpr bool IS_OWNER = true;
1385 m_inputObjects[prefix] =
1386 std::make_unique<TAuxManager>(store.release(), IS_OWNER);
1387
1388 // Return gracefully:
1389 return StatusCode::SUCCESS;
1390 }
1391
1392 // There was some problem:
1393 ATH_MSG_ERROR("Unknown auxiliary access mode set (" << m_auxMode << ")");
1394 return StatusCode::FAILURE;
1395}
1396
1406StatusCode TEvent::connectMetaAux(const std::string &prefix, bool standalone) {
1407
1408 // Check if the branch is already connected:
1409 if (m_inputMetaObjects.contains(prefix)) {
1410 return StatusCode::SUCCESS;
1411 }
1412
1413 // A sanity check:
1414 if (!m_inMetaTree) {
1415 ATH_MSG_FATAL("Internal logic error detected");
1416 return StatusCode::FAILURE;
1417 }
1418
1419 // Do different things based on the "auxiliary mode" we are in:
1421
1422 // In "class" and "athena" access modes just connect the concrete auxiliary
1423 // object to the input.
1424 static constexpr bool SILENT = false;
1425 ATH_CHECK(connectMetaObject(prefix, SILENT));
1426
1427 // Return gracefully:
1428 return StatusCode::SUCCESS;
1429
1430 } else if (m_auxMode == kBranchAccess) {
1431
1432 // In "branch access mode" let's create a TAuxStore object, and let
1433 // that take care of the auxiliary store access.
1434 static constexpr bool TOP_STORE = true;
1435 auto store = std::make_unique<TAuxStore>(
1436 prefix, TOP_STORE,
1439
1440 // Connect it to the input tree.
1441 ATH_CHECK(store->readFrom(*m_inMetaTree));
1442
1443 // We're using this object to read from the input, it needs to be
1444 // locked:
1445 store->lock();
1446
1447 // Finally, set up an appropriate manager for it.
1448 static constexpr bool IS_OWNER = true;
1449 m_inputMetaObjects[prefix] =
1450 std::make_unique<TAuxManager>(store.release(), IS_OWNER);
1451
1452 // Return gracefully.
1453 return StatusCode::SUCCESS;
1454 }
1455
1456 // There was some problem:
1457 ATH_MSG_ERROR("Unknown auxiliary access mode set (" << m_auxMode << ")");
1458 return StatusCode::FAILURE;
1459}
1460
1470StatusCode TEvent::setAuxStore(const std::string &key,
1471 Details::IObjectManager &mgr, bool metadata) {
1472
1473 // Pre-compute some values.
1474 const bool isAuxStore = Details::isAuxStore(*(mgr.holder()->getClass()));
1475
1476 // Check if we need to do anything.
1477 if ((Details::hasAuxStore(*(mgr.holder()->getClass())) == false) &&
1478 (isAuxStore == false)) {
1479 return StatusCode::SUCCESS;
1480 }
1481
1482 // Select which object container to use:
1483 Object_t &objects = (metadata ? m_inputMetaObjects : m_inputObjects);
1484
1485 // Look up the auxiliary object's manager:
1486 TVirtualManager* auxMgr = nullptr;
1487 std::string auxKey;
1488 if (isAuxStore) {
1489 auxMgr = &mgr;
1490 auxKey = key;
1491 } else {
1492 auto itr = objects.find(key + "Aux.");
1493 if (itr == objects.end()) {
1494 // Apparently there's no auxiliary object for this DV, so let's
1495 // give up:
1496 return StatusCode::SUCCESS;
1497 }
1498 auxMgr = itr->second.get();
1499 auxKey = key + "Aux.";
1500 }
1501
1502 if (metadata == false) {
1503 // Make sure the auxiliary object is up to date:
1504 const ::Int_t readBytes = auxMgr->getEntry();
1505 if (readBytes < 0) {
1507 "Couldn't load current entry for auxiliary object with key \""
1508 << auxKey << "\"");
1509 return StatusCode::FAILURE;
1510 }
1511
1512 // Check if there is a separate auxiliary object for the dynamic
1513 // variables:
1514 const std::string dynAuxKey = auxKey + "Dynamic";
1515 auto dynAuxMgr = objects.find(dynAuxKey);
1516
1517 if ((dynAuxMgr != objects.end()) &&
1518 (readBytes || (m_auxMode == kAthenaAccess) || (auxMgr == &mgr))) {
1519 // Do different things based on the access mode:
1520 if (m_auxMode != kAthenaAccess) {
1521 // In "normal" access modes just tell the dynamic store object
1522 // to switch to a new event.
1523 dynAuxMgr->second->getEntry();
1524 } else {
1525 // In "Athena mode" this object has already been deleted when
1526 // the main auxiliary store object was switched to the new
1527 // event. So let's re-create it:
1528 xAOD::TObjectManager &auxMgrRef =
1529 dynamic_cast<xAOD::TObjectManager &>(*auxMgr);
1530 ATH_CHECK(
1531 setUpDynamicStore(auxMgrRef, (metadata ? m_inMetaTree : m_inTree)));
1532 // Now tell the newly created dynamic store object which event
1533 // it should be looking at:
1534 auto dynAuxMgr = objects.find(dynAuxKey);
1535 if (dynAuxMgr == objects.end()) {
1536 ATH_MSG_ERROR("Internal logic error detected");
1537 return StatusCode::FAILURE;
1538 }
1539 dynAuxMgr->second->getEntry();
1540 }
1541 }
1542 }
1543
1544 // Stop here if we've set up an auxiliary store.
1545 if (isAuxStore) {
1546 return StatusCode::SUCCESS;
1547 }
1548
1549 // Access the auxiliary base class of the object/vector:
1551 SG::AuxElement* aux = 0;
1552 switch (mgr.holder()->typeKind()) {
1553 case THolder::DATAVECTOR: {
1554 void* vvec = mgr.holder()->getAs(typeid(SG::AuxVectorBase));
1555 vec = reinterpret_cast<SG::AuxVectorBase*>(vvec);
1556 } break;
1557 case THolder::AUXELEMENT: {
1558 void* vaux = mgr.holder()->getAs(typeid(SG::AuxElement));
1559 aux = reinterpret_cast<SG::AuxElement*>(vaux);
1560 } break;
1561 default:
1562 break;
1563 }
1564
1565 // Check whether index tracking is enabled for the type. If not, then
1566 // we need to fix it...
1567 if (vec && (!vec->trackIndices())) {
1568 Details::forceTrackIndices(*vec);
1569 }
1570
1571 // Check if we were successful:
1572 if ((!vec) && (!aux)) {
1573 ATH_MSG_FATAL("Couldn't access class \""
1574 << mgr.holder()->getClass()->GetName()
1575 << "\" as SG::AuxVectorBase or SG::AuxElement");
1576 return StatusCode::FAILURE;
1577 }
1578
1579 // Get the auxiliary store object:
1580 const SG::IConstAuxStore* store = 0;
1581 if (m_auxMode == kBranchAccess) {
1582 // Get the concrete auxiliary manager:
1583 TAuxManager* amgr = dynamic_cast<TAuxManager* >(auxMgr);
1584 if (!amgr) {
1585 ATH_MSG_FATAL("Auxiliary manager for \""
1586 << auxKey << "\" is not of the right type");
1587 return StatusCode::FAILURE;
1588 }
1589 store = amgr->getConstStore();
1590 // If the store still doesn't know its type, help it now:
1591 if (amgr->getStore()->structMode() ==
1593 const TAuxStore::EStructMode mode =
1596 amgr->getStore()->setStructMode(mode);
1597 }
1598 } else if (m_auxMode == kClassAccess || m_auxMode == kAthenaAccess) {
1599 // Get the concrete auxiliary manager:
1600 TObjectManager* omgr = dynamic_cast<TObjectManager* >(auxMgr);
1601 if (!omgr) {
1602 ATH_MSG_FATAL("Auxiliary manager for \""
1603 << auxKey << "\" is not of the right type");
1604 return StatusCode::FAILURE;
1605 }
1606 void* p = omgr->holder()->getAs(typeid(SG::IConstAuxStore));
1607 store = reinterpret_cast<const SG::IConstAuxStore* >(p);
1608 }
1609 if (!store) {
1610 ATH_MSG_FATAL("Logic error detected in the code");
1611 return StatusCode::FAILURE;
1612 }
1613
1614 // Connect the two:
1615 if (vec) {
1616 vec->setStore(store);
1617 } else if (aux) {
1618 aux->setStore(store);
1619 } else {
1620 ATH_MSG_FATAL("Logic error detected in the code");
1621 return StatusCode::FAILURE;
1622 }
1623
1624 // We succeeded:
1625 return StatusCode::SUCCESS;
1626}
1627
1643StatusCode TEvent::record(void* obj, const std::string &typeName,
1644 const std::string &key, bool overwrite, bool metadata,
1645 bool isOwner) {
1646
1647 // Check if we have an output tree when writing an event:
1648 if (!m_outTree && !metadata) {
1650 "No output tree defined. Did you forget to call writeTo(...)?");
1651 return StatusCode::FAILURE;
1652 }
1653 assert(m_outputEventFormat != 0);
1654
1655 // If this is metadata, just take ownership of it. The object will only
1656 // be recorded into the output file when calling finishWritingTo(...).
1657 if (metadata) {
1658 // Check whether we already have such an object:
1659 if ((!overwrite) &&
1660 (m_outputMetaObjects.find(key) != m_outputMetaObjects.end())) {
1661 ATH_MSG_ERROR("Meta-object \"" << typeName << "\"/\"" << key
1662 << "\" already recorded");
1663 return StatusCode::FAILURE;
1664 }
1665 // Check if we have a dictionary for this object:
1666 TClass* cl = TClass::GetClass(typeName.c_str());
1667 if (!cl) {
1668 ATH_MSG_ERROR("Didn't find dictionary for type: " << typeName);
1669 return StatusCode::FAILURE;
1670 }
1671 // Let's create a holder for the object:
1672 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1673 m_outputMetaObjects[key] = std::make_unique<TObjectManager>(
1674 nullptr, std::make_unique<THolder>(obj, cl, isOwner), renewOnRead);
1675 // We're done. The rest will be done later on.
1676 return StatusCode::SUCCESS;
1677 }
1678
1679 // Check if we accessed this object on the input. If yes, then this
1680 // key may not be used for recording.
1681 if ((!overwrite) && (m_inputObjects.find(key) != m_inputObjects.end())) {
1682 ATH_MSG_ERROR("Object \"" << typeName << "\"/\"" << key
1683 << "\" already accessed from the input, can't be "
1684 "overwritten in memory");
1685 return StatusCode::FAILURE;
1686 }
1687
1688 // Choose a split level.
1689 const Int_t splitLevel = (key.ends_with("Aux.") ? 1 : 0);
1690
1691 // Check if we need to add it to the event record:
1692 Object_t::iterator vitr = m_outputObjects.find(key);
1693 if (vitr == m_outputObjects.end()) {
1694
1695 // Check if we have a dictionary for this object:
1696 TClass* cl = TClass::GetClass(typeName.c_str());
1697 if (cl == nullptr) {
1698 ATH_MSG_ERROR("Didn't find dictionary for type: " << typeName);
1699 return StatusCode::FAILURE;
1700 }
1701
1702 // Check if this is a new object "type" or not.
1703 if (!m_outputEventFormat->exists(key)) {
1705 EventFormatElement(key, cl->GetName(), "", getHash(key)));
1706 }
1707
1708 // Let's create a holder for the object.
1709 const bool renewOnRead = (m_auxMode == kAthenaAccess);
1710 auto mgr = std::make_unique<TObjectManager>(
1711 nullptr, std::make_unique<THolder>(obj, cl, isOwner), renewOnRead);
1712 TObjectManager* mgrPtr = mgr.get();
1713 m_outputObjects[key] = std::move(mgr);
1714
1715 // ... and let's add it to the output TTree.
1716 static constexpr Int_t basketSize = 32000;
1717 *(mgrPtr->branchPtr()) =
1718 m_outTree->Branch(key.c_str(), cl->GetName(),
1719 mgrPtr->holder()->getPtr(), basketSize, splitLevel);
1720 if (!mgrPtr->branch()) {
1721 ATH_MSG_ERROR("Failed to create branch \"" << key << "\" out of type \""
1722 << cl->GetName() << "\"");
1723 // Clean up:
1724 mgrPtr->holder()->setOwner(kFALSE);
1725 return StatusCode::FAILURE;
1726 }
1727
1728 // Set up the saving of all the dynamic auxiliary properties
1729 // of the object if it has any:
1730 static constexpr bool METADATA = false;
1731 ATH_CHECK(putAux(*m_outTree, *mgrPtr, METADATA));
1732
1733 // Return at this point, as we don't want to run the rest of
1734 // the function's code:
1735 return StatusCode::SUCCESS;
1736 }
1737
1738 // Access the object manager:
1739 TObjectManager* omgr = dynamic_cast<TObjectManager* >(vitr->second.get());
1740 if (!omgr) {
1741 ATH_MSG_ERROR("Manager object of the wrong type encountered");
1742 return StatusCode::FAILURE;
1743 }
1744
1745 // Check that the type of the object matches that of the previous
1746 // object:
1747 if (typeName != omgr->holder()->getClass()->GetName()) {
1748 // This may still be, when the ROOT dictionary name differs from the
1749 // "simple type name" known to C++. So let's get the ROOT name of the
1750 // new type:
1751 TClass* cl = TClass::GetClass(typeName.c_str());
1752 if ((!cl) ||
1753 ::strcmp(cl->GetName(), omgr->holder()->getClass()->GetName())) {
1754 ATH_MSG_ERROR("For output key \""
1755 << key << "\" the previous type was \""
1756 << omgr->holder()->getClass()->GetName()
1757 << "\", but the newly requested type is \"" << typeName
1758 << "\"");
1759 return StatusCode::FAILURE;
1760 }
1761 }
1762
1763 // Replace the managed object.
1764 omgr->setObject(obj);
1765
1766 // Replace the auxiliary objects.
1767 static constexpr bool METADATA = false;
1768 ATH_CHECK(putAux(*m_outTree, *omgr, METADATA));
1769
1770 // Return gracefully.
1771 return StatusCode::SUCCESS;
1772}
1773
1774StatusCode TEvent::recordAux(TVirtualManager &mgr, const std::string &key,
1775 bool metadata) {
1776
1777 // Check if the auxiliary store is a generic object.
1778 Details::IObjectManager* iomgr = dynamic_cast<Details::IObjectManager*>(&mgr);
1779 if (iomgr != nullptr) {
1780 // Record the auxiliary object using the main record function.
1781 static const bool OVERWRITE = true;
1782 static const bool IS_OWNER = true;
1783 ATH_CHECK(record(iomgr->object(), iomgr->holder()->getClass()->GetName(),
1784 key, OVERWRITE, metadata, IS_OWNER));
1785 return StatusCode::SUCCESS;
1786 }
1787
1788 // Check if it's a TAuxStore object.
1789 TAuxManager* auxmgr = dynamic_cast<TAuxManager* >(&mgr);
1790 if (auxmgr != nullptr) {
1791 // This type has to be an event object.
1792 if (metadata) {
1794 "TAuxStore auxiliary objects can only be recorded for event data");
1795 return StatusCode::FAILURE;
1796 }
1797 // Record the auxiliary object with the dedicated record function.
1798 ATH_CHECK(recordAux(auxmgr->getStore(), key));
1799 return StatusCode::SUCCESS;
1800 }
1801
1802 // Apparently we didn't recorgnize the auxiliary store type.
1803 ATH_MSG_ERROR("Unknown auxiliary store manager type encountered");
1804 return StatusCode::FAILURE;
1805}
1806
1813StatusCode TEvent::initStats() {
1814
1815 // If we're dealing with an empty input file, stop here:
1816 if (m_inTreeMissing) {
1817 return StatusCode::SUCCESS;
1818 }
1819
1820 // A little sanity check:
1821 if (!m_inTree) {
1822 ATH_MSG_ERROR("Function called on an uninitialised object");
1823 return StatusCode::FAILURE;
1824 }
1825
1826 // Reset the number of input branches information:
1828
1829 // Loop over the EventFormat information
1832 for (; itr != end; ++itr) {
1833
1834 // Get the name of the branch in question:
1835 const std::string &branchName = itr->second.branchName();
1836
1837 // If it's an auxiliary container, scan it using TAuxStore:
1838 if (branchName.find("Aux.") != std::string::npos) {
1839
1840 // But first decide whether it describes a container, or just
1841 // a single object. Since the file may have been written in
1842 // kBranchAccess mode, it's not necessarily a good idea to check
1843 // the type of the auxiliary class. So let's check the interface
1844 // class instead.
1845 //
1846 // Get the name of the interface object/container:
1847 const std::string intName = branchName.substr(0, branchName.size() - 4);
1848 if (!m_inputEventFormat.exists(intName)) {
1849 // When this happens, it may still be that both the interface and
1850 // the auxiliary container is missing from the file. As we didn't
1851 // check yet whether the auxiliary container is in place or not.
1852 // So, before printing a warning, let's check for this.
1853 // Unfortunately the check is pretty expensive, but this should
1854 // not be performance critical code after all...
1855 ::Bool_t auxFound = kFALSE;
1856 const std::string dynName = Utils::dynBranchPrefix(branchName);
1857
1858 std::vector<TObjArray* > fullListOfBranches = {};
1859 // Add the list of branches of the main tree
1860 fullListOfBranches.push_back(m_inTree->GetListOfBranches());
1861 // If input tree has friend trees
1862 // add as well the list of friend tree branches
1863 if (m_inTree->GetListOfFriends()) {
1864 // Get the list of friends
1865 TList* fList = m_inTree->GetListOfFriends();
1866 // Loop over friend elements
1867 for (TObject* feObj : *fList) {
1868 if (feObj) {
1869 // Get corresponding friend tree
1870 auto* pElement = dynamic_cast<TFriendElement* >(feObj);
1871 if (not pElement)
1872 continue;
1873 TTree* friendTree = pElement->GetTree();
1874 // Add list of branches of the friend tree
1875 fullListOfBranches.push_back(friendTree->GetListOfBranches());
1876 }
1877 }
1878 }
1879
1880 for (TObjArray* branches : fullListOfBranches) {
1881 for (Int_t i = 0; i < branches->GetEntriesFast(); ++i) {
1882 if (!branches->At(i))
1883 continue;
1884
1885 const TString name(branches->At(i)->GetName());
1886 if (name.BeginsWith(branchName) || name.BeginsWith(dynName)) {
1887 auxFound = kTRUE;
1888 break;
1889 }
1890 }
1891 }
1892 if (auxFound) {
1893 ATH_MSG_WARNING("Couldn't find interface object/container \""
1894 << intName << "\" belonging to branch \""
1895 << branchName << "\"");
1896 }
1897 continue;
1898 }
1899
1900 // Get the type of the interface:
1901 const EventFormatElement* el = m_inputEventFormat.get(intName);
1902 ::TClass* cl = ::TClass::GetClass(el->className().c_str());
1903 if ((!cl) || (!cl->IsLoaded())) {
1904 ATH_MSG_WARNING("Couldn't find dictionary for type \""
1905 << el->className() << "\"");
1906 continue;
1907 }
1908
1909 // Get the dictionary for the DataVector base class:
1910 static const std::type_info &baseTi = typeid(SG::AuxVectorBase);
1911 static const std::string baseName = SG::normalizedTypeinfoName(baseTi);
1912 static ::TClass* const baseCl = ::TClass::GetClass(baseName.c_str());
1913 if (!baseCl) {
1914 ATH_MSG_ERROR("Couldn't get dictionary for type \"" << baseName
1915 << "\"");
1916 return StatusCode::FAILURE;
1917 }
1918
1919 // The type of the auxiliary store is finally deduced from the
1920 // inheritance of the interface container.
1921 const TAuxStore::EStructMode mode =
1922 (cl->InheritsFrom(baseCl) ? TAuxStore::EStructMode::kContainerStore
1924
1925 // Scan the branches using a temporary TAuxStore instance:
1926 static constexpr bool TOP_STORE = true;
1927 TAuxStore temp(branchName, TOP_STORE, mode);
1928 static constexpr bool PRINT_WARNINGS = false;
1929 ATH_CHECK(temp.readFrom(*m_inTree, PRINT_WARNINGS));
1930
1931 // Conveninence variable:
1932 ReadStats &stats = IOStats::instance().stats();
1933
1934 // Teach the cache about all the branches:
1935 for (SG::auxid_t id : temp.getAuxIDs()) {
1936 stats.branch(branchName, id);
1937 }
1938
1939 // Increment the number of known branches:
1940 stats.setBranchNum(stats.branchNum() + temp.getAuxIDs().size());
1941 }
1942 // If it's an interface container:
1943 else {
1944 // Try to access the branch:
1945 const ::TBranch* container = m_inTree->GetBranch(branchName.c_str());
1946 // If it exists, let's remember it:
1947 if (container) {
1948 IOStats::instance().stats().container(branchName);
1949 }
1950 }
1951 }
1952
1953 // Return gracefully:
1954 return StatusCode::SUCCESS;
1955}
1956
1969StatusCode TEvent::record(std::unique_ptr<TAuxStore> store,
1970 const std::string &key) {
1971
1972 // Check if we have an output tree:
1973 if (!m_outTree) {
1975 "No output tree defined. Did you forget to call writeTo(...)?");
1976 return StatusCode::FAILURE;
1977 }
1978
1979 // Check if we have a filtering rule for this key:
1980 const std::set<std::string>* filter = 0;
1981 auto filter_itr = m_auxItemList.find(key);
1982 if (filter_itr != m_auxItemList.end()) {
1983 filter = &(filter_itr->second);
1984 }
1985
1986 // Check if we need to add it to the event record:
1987 Object_t::iterator vitr = m_outputObjects.find(key);
1988 if (vitr == m_outputObjects.end()) {
1989
1990 // Configure the object for variable filtering:
1991 if (filter) {
1992 store->selectAux(*filter);
1993 }
1994 // Tell the object where to write its contents:
1995 ATH_CHECK(store->writeTo(*m_outTree));
1996 // Record it to the output list:
1997 static constexpr bool OWNS_STORE = true;
1998 m_outputObjects[key] =
1999 std::make_unique<TAuxManager>(store.release(), OWNS_STORE);
2000
2001 // We're done:
2002 return StatusCode::SUCCESS;
2003 }
2004
2005 // Check if the output has the right store:
2006 if (vitr->second->object() == store.get()) {
2007 // We're done already:
2008 return StatusCode::SUCCESS;
2009 }
2010
2011 // If not, update the output manager. This can happen when we copy
2012 // objects from the input to the output files, and we process
2013 // multiple input files.
2014
2015 // Check if the output manager is of the right type:
2016 TAuxManager* mgr = dynamic_cast<TAuxManager* >(vitr->second.get());
2017 if (mgr == nullptr) {
2018 ATH_MSG_ERROR("Output object with key \""
2019 << key << "\" already exists, and is not of type TAuxStore");
2020 return StatusCode::FAILURE;
2021 }
2022
2023 // Configure the object for variable filtering:
2024 if (filter) {
2025 store->selectAux(*filter);
2026 }
2027
2028 // Connect the auxiliary store to the output tree:
2029 ATH_CHECK(store->writeTo(*m_outTree));
2030
2031 // Update the manager:
2032 mgr->setObject(store.release());
2033
2034 // Return gracefully:
2035 return StatusCode::SUCCESS;
2036}
2037
2047
2048 // Check if we can call setName(...) on the object:
2049 ::TMethodCall setNameCall;
2050 // Don't use this code in Athena access mode. And just accept that access
2051 // monitoring is disabled in this case...
2052 if (m_auxMode != kAthenaAccess) {
2053 setNameCall.InitWithPrototype(mgr.holder()->getClass(), "setName",
2054 "const char*");
2055 if (setNameCall.IsValid()) {
2056 // Yes, there is such a function. Let's call it with the branch
2057 // name:
2058 const ::TString params =
2059 ::TString::Format("\"%s\"", mgr.branch()->GetName());
2060 const char* charParams = params.Data();
2061 setNameCall.Execute(mgr.holder()->get(), charParams);
2062 } else {
2063 // This is weird. What sort of auxiliary container is this? :-/
2064 ATH_MSG_WARNING("Couldn't find setName(...) function for container \""
2065 << mgr.branch()->GetName() << "\" (type: "
2066 << mgr.holder()->getClass()->GetName() << ")");
2067 }
2068 }
2069
2070 // Check if we can switch out the internal store of this object:
2071 static const TClass* const holderClass =
2072 TClass::GetClass(typeid(SG::IAuxStoreHolder));
2073 if (!mgr.holder()->getClass()->InheritsFrom(holderClass)) {
2074 // Nope... So let's just end the journey here.
2075 return StatusCode::SUCCESS;
2076 }
2077
2078 // Try to get the object as an IAuxStoreHolder:
2079 SG::IAuxStoreHolder* storeHolder = reinterpret_cast<SG::IAuxStoreHolder* >(
2080 mgr.holder()->getAs(typeid(SG::IAuxStoreHolder)));
2081 if (!storeHolder) {
2082 ATH_MSG_FATAL("There's a logic error in the code");
2083 return StatusCode::FAILURE;
2084 }
2085
2086 // Create a TAuxStore instance that will read the dynamic variables
2087 // of this container. Notice that the TAuxManager doesn't own the
2088 // TAuxStore object. It will be owned by the SG::IAuxStoreHolder
2089 // object.
2090 static constexpr bool TOP_STORE = false;
2091 auto store = std::make_unique<TAuxStore>(
2092 mgr.branch()->GetName(), TOP_STORE,
2096 // This object is used to read data from the input, it needs to be
2097 // locked:
2098 store->lock();
2099
2100 // Set it up to read from the input RNTuple.
2101 ATH_CHECK(store->readFrom(*tree));
2102
2103 // Set it up to read from the input TTree.
2104 ATH_CHECK(store->readFrom(*tree));
2105 // Tell the auxiliary store which entry to use. This is essential for
2106 // metadata objects, and non-important for event data objects, which will
2107 // get a possibly different entry loaded in setAuxStore(...).
2108 store->getEntry(0);
2109
2110 // Set up a manager for it.
2111 static constexpr bool SHARED_OWNER = false;
2112 m_inputObjects[std::string(mgr.branch()->GetName()) + "Dynamic"] =
2113 std::make_unique<TAuxManager>(store.get(), SHARED_OWNER);
2114
2115 // Give this object to the store holder:
2116 storeHolder->setStore(store.release());
2117
2118 // Return gracefully:
2119 return StatusCode::SUCCESS;
2120}
2121
2132StatusCode TEvent::putAux(::TTree &outTree, TVirtualManager &vmgr,
2133 bool metadata) {
2134
2135 // A little sanity check:
2136 assert(m_outputEventFormat != 0);
2137
2138 // Do the conversion:
2139 TObjectManager* mgr = dynamic_cast<TObjectManager* >(&vmgr);
2140 if (!mgr) {
2141 // It's not an error any more when we don't get a TObjectManager.
2142 return StatusCode::SUCCESS;
2143 }
2144
2145 // Check if we need to do anything here:
2146 if (!mgr->holder()->getClass()->InheritsFrom("SG::IAuxStoreIO")) {
2147 return StatusCode::SUCCESS;
2148 }
2149
2150 // Get a pointer to the auxiliary store I/O interface:
2151 SG::IAuxStoreIO* aux = reinterpret_cast<SG::IAuxStoreIO* >(
2152 mgr->holder()->getAs(typeid(SG::IAuxStoreIO)));
2153 if (!aux) {
2154 ATH_MSG_FATAL("There is a logic error in the code!");
2155 return StatusCode::FAILURE;
2156 }
2157
2158 // Check if we have rules defined for which auxiliary properties
2159 // to write out:
2161 if (!metadata) {
2162 auto item_itr = m_auxItemList.find(mgr->branch()->GetName());
2163 if (item_itr != m_auxItemList.end()) {
2164 sel.selectAux(item_itr->second);
2165 }
2166 }
2167
2168 // Get the dynamic auxiliary variables held by this object, which
2169 // were selected to be written:
2170 const SG::auxid_set_t auxids =
2171 sel.getSelectedAuxIDs(aux->getSelectedAuxIDs());
2172
2173 // If there are no dynamic auxiliary variables in the object, return
2174 // right away:
2175 if (auxids.empty()) {
2176 return StatusCode::SUCCESS;
2177 }
2178
2179 // Decide what should be the prefix of all the dynamic branches:
2180 const std::string dynNamePrefix =
2181 Utils::dynBranchPrefix(mgr->branch()->GetName());
2182
2183 // Select which container to add the variables to:
2184 Object_t &objects = (metadata ? m_outputMetaObjects : m_outputObjects);
2185
2186 // This iteration will determine the ordering of branches within
2187 // the tree, so sort auxids by name.
2189 typedef std::pair<std::string, SG::auxid_t> AuxVarSort_t;
2190 std::vector<AuxVarSort_t> varsort;
2191 varsort.reserve(auxids.size());
2192 for (SG::auxid_t id : auxids) {
2193 varsort.emplace_back(r.getName(id), id);
2194 }
2195 std::sort(varsort.begin(), varsort.end());
2196
2197 // Extract all the dynamic variables from the object:
2198 for (const auto &p : varsort) {
2199
2200 // The auxiliary ID:
2201 const SG::auxid_t id = p.second;
2202
2203 // Construct a name for the branch that we will write:
2204 const std::string brName = dynNamePrefix + p.first;
2205
2206 // Try to find the branch:
2207 Object_t::iterator bmgr = objects.find(brName);
2208
2209 // Check if we already know about this variable:
2210 if (bmgr == objects.end()) {
2211
2212 // Construct the full type name of the variable:
2213 const std::type_info* brType = aux->getIOType(id);
2214 if (!brType) {
2215 ATH_MSG_ERROR("No I/O type found for variable " << brName);
2216 return StatusCode::FAILURE;
2217 }
2218 const std::string brTypeName = Utils::getTypeName(*brType);
2219 std::string brProperTypeName = "<unknown>";
2220
2221 // The branch that will hopefully be created:
2222 ::TBranch* br = 0;
2223
2224 // Check if it's a primitive type or not:
2225 if (strlen(brType->name()) == 1) {
2226
2227 // Making the "proper" type name is simple in this case:
2228 brProperTypeName = brTypeName;
2229
2230 // Get the character describing this type for ROOT:
2231 const char rootType = Utils::rootType(brType->name()[0]);
2232 if (rootType == '\0') {
2233 ATH_MSG_ERROR("Type not known for variable \""
2234 << brName << "\" of type \"" << brTypeName << "\"");
2235 return StatusCode::FAILURE;
2236 }
2237
2238 // Create the full description of the variable for ROOT:
2239 std::ostringstream leaflist;
2240 leaflist << brName << "/" << rootType;
2241
2242 // Let's create a holder for this property:
2243 static constexpr bool IS_OWNER = false;
2244 auto auxmgr = std::make_unique<TPrimitiveAuxBranchManager>(
2245 id, nullptr, new THolder(aux->getIOData(id), nullptr, IS_OWNER));
2246
2247 // ... and let's add it to the output TTree:
2248 static constexpr Int_t BASKET_SIZE = 32000;
2249 *(auxmgr->branchPtr()) =
2250 outTree.Branch(brName.c_str(), auxmgr->holder()->get(),
2251 leaflist.str().c_str(), BASKET_SIZE);
2252 if (!auxmgr->branch()) {
2253 ATH_MSG_ERROR("Failed to create branch \""
2254 << brName << "\" out of type \"" << brProperTypeName
2255 << "\"");
2256 // Clean up:
2257 *(auxmgr->holder()->getPtr()) = 0;
2258 return StatusCode::FAILURE;
2259 }
2260 br = auxmgr->branch();
2261
2262 // Store it in the output list.
2263 objects[brName] = std::move(auxmgr);
2264
2265 } else {
2266
2267 // Check if we have a dictionary for this type:
2268 static constexpr Bool_t LOAD_IF_NOT_FOUND = kTRUE;
2269 static constexpr Bool_t SILENT = kTRUE;
2270 TClass* cl = TClass::GetClass(*brType, LOAD_IF_NOT_FOUND, SILENT);
2271 if (cl == nullptr) {
2272 // The dictionary needs to be loaded now. This could be an
2273 // issue. But let's hope for the best...
2274 cl = TClass::GetClass(brTypeName.c_str());
2275 // If still not found...
2276 if (cl == nullptr) {
2277 ATH_MSG_ERROR("Dictionary not available for variable \""
2278 << brName << "\" of type \"" << brTypeName << "\"");
2279 return StatusCode::FAILURE;
2280 }
2281 }
2282
2283 // The proper type name comes from the dictionary in this case:
2284 brProperTypeName = cl->GetName();
2285
2286 // Let's create a holder for this property:
2287 static constexpr bool IS_OWNER = false;
2288 auto auxmgr = std::make_unique<TAuxBranchManager>(
2289 id, nullptr, new THolder(aux->getIOData(id), cl, IS_OWNER));
2290
2291 // ... and let's add it to the output TTree.
2292 static constexpr Int_t BASKET_SIZE = 32000;
2293 static constexpr Int_t SPLIT_LEVEL = 0;
2294 *(auxmgr->branchPtr()) = outTree.Branch(brName.c_str(), cl->GetName(),
2295 auxmgr->holder()->getPtr(),
2296 BASKET_SIZE, SPLIT_LEVEL);
2297 if (!auxmgr->branch()) {
2298 ATH_MSG_ERROR("Failed to create branch \""
2299 << brName << "\" out of type \"" << brProperTypeName
2300 << "\"");
2301 // Clean up:
2302 *(auxmgr->holder()->getPtr()) = 0;
2303 return StatusCode::FAILURE;
2304 }
2305 br = auxmgr->branch();
2306
2307 // Store it in the output list.
2308 objects[brName] = std::move(auxmgr);
2309 }
2310
2311 // If this is not the first event, fill up the already filled
2312 // events with (empty) content:
2313 if (outTree.GetEntries()) {
2314 void* ptr = br->GetAddress();
2315 br->SetAddress(0);
2316 for (::Long64_t i = 0; i < outTree.GetEntries(); ++i) {
2317 br->Fill();
2318 }
2319 br->SetAddress(ptr);
2320 }
2321
2322 // If all went fine, let's add this branch to the event format
2323 // metadata:
2324 if (!m_outputEventFormat->exists(brName)) {
2325 m_outputEventFormat->add(EventFormatElement(brName, brProperTypeName,
2326 mgr->branch()->GetName(),
2327 getHash(brName)));
2328 }
2329
2330 // We don't need to do the rest:
2331 continue;
2332 }
2333
2334 // Access the object manager:
2335 bmgr = objects.find(brName);
2336 if (bmgr == objects.end()) {
2337 ATH_MSG_FATAL("There is an internal logic error in the code...");
2338 return StatusCode::FAILURE;
2339 }
2340
2341 // Replace the managed object:
2342 void* nc_data ATLAS_THREAD_SAFE = // we hold non-const pointers but check
2343 // on retrieve
2344 const_cast<void* >(static_cast<const void* >(aux->getIOData(id)));
2345 bmgr->second->setObject(nc_data);
2346 }
2347
2348 // Return gracefully:
2349 return StatusCode::SUCCESS;
2350}
2351
2352StatusCode TEvent::recordAux(TAuxStore* store, const std::string &key) {
2353
2354 // Check if we have an output tree:
2355 if (hasOutput() == false) {
2356 ATH_MSG_ERROR("No output tree set up.");
2357 return StatusCode::FAILURE;
2358 }
2359
2360 // Check if we have a filtering rule for this key:
2361 const std::set<std::string>* filter = 0;
2362 auto filter_itr = m_auxItemList.find(key);
2363 if (filter_itr != m_auxItemList.end()) {
2364 filter = &(filter_itr->second);
2365 }
2366
2367 // Check if we need to add it to the event record:
2368 Object_t::iterator vitr = m_outputObjects.find(key);
2369 if (vitr == m_outputObjects.end()) {
2370
2371 // Configure the object for variable filtering:
2372 if (filter) {
2373 store->selectAux(*filter);
2374 }
2375 // Tell the object where to write its contents:
2376 ATH_CHECK(store->writeTo(*m_outTree));
2377 // Record it to the output list.
2378 static constexpr bool OWNS_STORE = false;
2379 m_outputObjects[key] = std::make_unique<TAuxManager>(store, OWNS_STORE);
2380
2381 // We're done:
2382 return StatusCode::SUCCESS;
2383 }
2384
2385 // Check if the output has the right store:
2386 if (vitr->second->object() == store) {
2387 // We're done already:
2388 return StatusCode::SUCCESS;
2389 }
2390
2391 // If not, update the output manager. This can happen when we copy
2392 // objects from the input to the output files, and we process
2393 // multiple input files.
2394
2395 // Check if the output manager is of the right type:
2396 TAuxManager* mgr = dynamic_cast<TAuxManager* >(vitr->second.get());
2397 if (mgr == nullptr) {
2398 ATH_MSG_ERROR("Output object with key \""
2399 << key << "\" already exists, and is not of type TAuxStore");
2400 return StatusCode::FAILURE;
2401 }
2402
2403 // Configure the object for variable filtering:
2404 if (filter) {
2405 store->selectAux(*filter);
2406 }
2407
2408 // Connect the auxiliary store to the output tree:
2409 ATH_CHECK(store->writeTo(*m_outTree));
2410
2411 // Update the manager:
2412 mgr->setObject(store);
2413
2414 // Return gracefully:
2415 return StatusCode::SUCCESS;
2416}
2417
2418} // 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
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
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:342
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:332
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:375
AthContainers_detail::upgrading_lock< upgrade_mutex_t > upgrading_lock_t
Lock type for multithread synchronization.
Definition Event.h:372
Object_t m_inputObjects
Collection of all the managed input objects.
Definition Event.h:329
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:325
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:337
std::unordered_map< std::string, std::set< std::string > > m_auxItemList
Rules for selecting which auxiliary branches to write.
Definition Event.h:347
EventFormat * m_outputEventFormat
Format of the current output file.
Definition Event.h:344
Object_t m_outputObjects
Collection of all the managed output object.
Definition Event.h:334
SG::SGKeyMap< BranchInfo > m_branches ATLAS_THREAD_SAFE
Map from hashed sgkey to BranchInfo.
Definition Event.h:379
std::vector< TVirtualIncidentListener * > m_listeners
Listeners who should be notified when certain incidents happen.
Definition Event.h:350
Object_t m_outputMetaObjects
Collection of all the managed output meta-objects.
Definition Event.h:339
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.
StatusCode writeTo(::TFile *file, int autoFlush=200, std::string_view treeName=EVENT_TREE_NAME)
Connect the object to an output file.
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.
StatusCode finishWritingTo(::TFile *file)
Finish writing to an output file.
::Int_t fill()
Function filling one event into the output tree.
::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 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.
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.
::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)
Helper class keeping track of the files that got accessed.
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