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