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