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