ATLAS Offline Software
Loading...
Searching...
No Matches
TAuxStore.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 "isRegisteredType.h"
7#include "lookupVectorType.h"
12
13// Athena include(s).
23
24// ROOT include(s).
25#include <TBranch.h>
26#include <TBranchElement.h>
27#include <TClass.h>
28#include <TError.h>
29#include <TROOT.h>
30#include <TStreamerElement.h>
31#include <TStreamerInfo.h>
32#include <TString.h>
33#include <TTree.h>
34#include <TVirtualCollectionProxy.h>
35
36// System include(s):
37#include <cassert>
38#include <format>
39#include <sstream>
40#include <stdexcept>
41
42namespace {
43
45bool isPrimitiveBranch(TBranch& br) {
46
47 // The variables needed for the check:
48 ::TClass* cl = nullptr;
49 ::EDataType dType = kOther_t;
50
51 // Get the variable type from the branch:
52 if (br.GetExpectedType(cl, dType)) {
53 ::Error("::isPrimitiveBranch",
54 XAOD_MESSAGE("Couldn't determine the type of branch "
55 "\"%s\""),
56 br.GetName());
57 return false;
58 }
59
60 // The check is made using the data type variable:
61 return ((dType != kOther_t) && (dType != kNoType_t) && (dType != kVoid_t));
62}
63
81bool isContainerBranch(TBranch& br, SG::auxid_t auxid) {
82
83 // For unknown types it doesn't matter if the branch describes a
84 // container or a single element.
86 return true;
87 }
88
89 // The variables needed for the check:
90 ::TClass* cl = nullptr;
91 ::EDataType dType = kOther_t;
92
93 // Get the variable type from the branch:
94 if (br.GetExpectedType(cl, dType)) {
95 ::Error("::isContainerBranch",
96 XAOD_MESSAGE("Couldn't determine the type of branch \"%s\""),
97 br.GetName());
98 return false;
99 }
100
101 // If there is no class associated with the branch then it should be
102 // a branch describing a standalone object. (As it should be a
103 // "primitive" branch in this case.)
104 if (!cl) {
105 return false;
106 }
107
108 // If there is a class, ask for the type_info of its type:
109 const std::type_info* root_ti = cl->GetTypeInfo();
110 if (!root_ti) {
111 // This may be an emulated class. One known case is when the type name
112 // is saved as "basic_string<char>" rather than "string" by Athena I/O.
113 // (It's not fully understood why this happens for dynamic branches...)
114 // So, let's see if we can get a functional TClass by massaging the
115 // type name a bit.
116 ::TString typeName(cl->GetName());
117 typeName.ReplaceAll("basic_string<char>", "string");
118 ::TClass* newCl = ::TClass::GetClass(typeName);
119 if (newCl) {
120 root_ti = newCl->GetTypeInfo();
121 }
122 }
123 if (!root_ti) {
124 ::Error("::isContainerBranch",
125 XAOD_MESSAGE("Couldn't get an std::type_info object out of "
126 "branch \"%s\" of type \"%s\""),
127 br.GetName(), cl->GetName());
128 return false;
129 }
130
131 // Ask for the auxiliary type infos:
132 const std::type_info* aux_obj_ti =
134 if (!aux_obj_ti) {
135 ::Error("::isContainerBranch",
136 XAOD_MESSAGE("Couldn't get std::type_info object for "
137 "auxiliary id: %i"),
138 static_cast<int>(auxid));
139 return false;
140 }
141 const std::type_info* aux_vec_ti =
143 if (!aux_vec_ti) {
144 ::Error("::isContainerBranch",
145 XAOD_MESSAGE("Couldn't get std::type_info object for "
146 "auxiliary id: %i"),
147 static_cast<int>(auxid));
148 return false;
149 }
150
151 // Check which one the ROOT type info agrees with:
152 if (*root_ti == *aux_obj_ti) {
153 // This branch describes a single object:
154 return false;
155 } else if (*root_ti == *aux_vec_ti) {
156 // This branch describes a container of objects:
157 return true;
158 }
159
160 // For enum and vector<enum> types (PFO...) the type given by
161 // the aux type registry is vector<int>. We have to take it into account
162 // here...
163 if (cl->GetCollectionProxy() && (*aux_vec_ti == typeid(std::vector<int>))) {
164 return true;
165 }
166
167 TClass* cl2 = xAOD::details::lookupVectorType(*cl);
168 if (cl2) {
169 if (*cl2->GetTypeInfo() == *aux_vec_ti) {
170 return true;
171 }
172 }
173
174 // If we got this far, the branch may have undergone schema evolution. If
175 // it's one that ROOT can deal with itself, then we should still be able
176 // to read the branch with this code.
177 //
178 // Note that even after looking at the ROOT source code, I'm still not
179 // 100% sure whether we would need to delete the objects returned by
180 // TClass::GetConversionStreamerInfo(...) in this code. :-( But based on
181 // general experience with the ROOT code, I'm going to say no...
182 TClass* aux_vec_cl =
183 TClass::GetClass(xAOD::Utils::getTypeName(*aux_vec_ti).c_str());
184 if (aux_vec_cl &&
185 aux_vec_cl->GetConversionStreamerInfo(cl, cl->GetClassVersion())) {
186 return true;
187 }
188 TClass* aux_obj_cl =
189 TClass::GetClass(xAOD::Utils::getTypeName(*aux_obj_ti).c_str());
190 if (aux_obj_cl &&
191 aux_obj_cl->GetConversionStreamerInfo(cl, cl->GetClassVersion())) {
192 return false;
193 }
194
195 // If neither, then something went wrong...
196 ::Error("::isContainerBranch",
197 XAOD_MESSAGE("Couldn't determine if branch describes a single "
198 "object or a container"));
199 ::Error("::isContainerBranch", XAOD_MESSAGE("ROOT type : %s"),
200 xAOD::Utils::getTypeName(*root_ti).c_str());
201 ::Error(":isContainerBranch", XAOD_MESSAGE("Object type: %s"),
202 xAOD::Utils::getTypeName(*aux_obj_ti).c_str());
203 ::Error("::isContainerBranch", XAOD_MESSAGE("Vector type: %s"),
204 xAOD::Utils::getTypeName(*aux_vec_ti).c_str());
205 return false;
206}
207
213class TBranchHandle {
214
215 public:
217 TBranchHandle(bool staticBranch, bool primitiveBranch,
218 const std::type_info* ti, void* obj, SG::auxid_t auxid,
219 std::string_view prefix)
220 : m_branch(0),
221 m_entry(0),
222 m_object(obj),
223 m_static(staticBranch),
224 m_primitive(primitiveBranch),
225 m_typeInfo(ti),
226 m_needsRead(true),
227 m_auxid(auxid),
228 m_prefix(prefix) {}
229
237 ::Int_t getEntry() {
238
239 // A little sanity check:
240 if (!m_branch) {
241 // This is no longer an error. We can have such objects for
242 // decorations, which don't exist on the input.
243 return 0;
244 }
245
246 // Update the I/O monitoring:
247 xAOD::IOStats::instance().stats().readBranch(std::string{m_prefix},
248 m_auxid);
249
250 // Make sure that the branch is associated to a tree
251 // as the entry to be read is retrieved from the tree
252 if (!m_branch->GetTree()) {
253 Error(
254 "xAOD::TAuxStore::TBranchHandle::getEntry",
255 XAOD_MESSAGE("Branch=%s is not associated to any tree while reading "
256 "of branches within this class relies on that"),
257 m_branch->GetName());
258 return -1;
259 }
260
261 // Get the entry that should be read
262 // The entry to be read is set with TTree::LoadTree()
263 // NB: for a branch from a friend tree and if the friend tree has an index
264 // built, then the entry to read is found when calling the TTree::LoadTree()
265 // function that matches the major and minor values between the main tree
266 // and the friend tree
267 ::Long64_t entry = m_branch->GetTree()->GetReadEntry();
268
269 if (entry < 0) {
270 // Raise error as it implies
271 // either that the TTree::LoadTree() function has not been called
272 // or
273 // the entry requested to be read by the user
274 // is not corresponding to any entry for the friend tree
275 Error("xAOD::TAuxStore::TBranchHandle::getEntry",
277 "Entry to read is not set for branch=%s from tree=%s. "
278 "It is either because TTree::LoadTree(entry) was not called "
279 "beforehand in the TEvent class OR "
280 "the entry requested to be read for the main tree is not "
281 "corresponding to an event for the friend tree"),
282 m_branch->GetName(), m_branch->GetTree()->GetName());
283 return -1;
284 }
285
286 // Check if anything needs to be done:
287 if ((entry == m_entry) && (!m_needsRead)) {
288 return 0;
289 }
290
291 // Switch the branch in the right mode:
292 if (!m_primitive) {
293 if ((m_branch->GetMakeClass() != m_static) &&
294 (!m_branch->SetMakeClass(m_static))) {
295 ::Error("xAOD::TAuxStore::TBranchHandle::getEntry",
296 XAOD_MESSAGE("Failed to call SetMakeClass(%i) on "
297 "branch \"%s\""),
298 static_cast<int>(m_static), m_branch->GetName());
299 return -1;
300 }
301 }
302
303 // Load the entry.
304 const ::Int_t nbytes = m_branch->GetEntry(entry);
305
306 // If the load was successful, remember that we loaded this entry.
307 if (nbytes >= 0) {
308 m_entry = entry;
309 // The reading will now be done:
310 m_needsRead = false;
311 }
312
313 // Return the number of bytes read.
314 return nbytes;
315 }
316
325 ::TBranch** branchPtr() { return &m_branch; }
326
335 void* objectPtr() { return m_object; }
336
354 void* inputObjectPtr() {
355 // Return the correct pointer:
356 if (m_static || m_primitive) {
357 return m_object;
358 } else {
359 return &m_object;
360 }
361 }
373 void* outputObjectPtr() {
374 // Return the correct pointer:
375 if (m_primitive) {
376 return m_object;
377 } else {
378 return &m_object;
379 }
380 }
382 const std::type_info* typeInfo() const { return m_typeInfo; }
396 void reset() { m_needsRead = true; }
397
399 SG::auxid_t auxid() const { return m_auxid; }
400
401
402 private:
404 ::TBranch* m_branch;
406 ::Long64_t m_entry;
408 void* m_object;
410 bool m_static;
412 bool m_primitive;
414 const std::type_info* m_typeInfo;
416 bool m_needsRead;
418 SG::auxid_t m_auxid;
420 std::string_view m_prefix;
421
422}; // class TBranchHandle
423
424} // namespace
425
426namespace xAOD {
427
429
447 StatusCode scanInputTree() {
448
449 // Check if an input tree is even available:
450 if (!m_inTree) {
451 // It's not an error if it isn't.
452 return StatusCode::SUCCESS;
453 }
454
455 // Check if the input was already scanned:
456 if (m_inputScanned) {
457 return StatusCode::SUCCESS;
458 }
459
460 // Get a list of all branches in the tree:
461 TObjArray* branches = m_inTree->GetListOfBranches();
462
463 // Check each of them:
464 for (Int_t i = 0; i < branches->GetEntriesFast(); ++i) {
465
466 // The name of this top-level branch:
467 const TString brName = branches->At(i)->GetName();
468
469 // Access the branch pointer:
470 TBranch* br = dynamic_cast<TBranch*>(branches->At(i));
471 if (!br) {
472 ::Fatal("xAOD::TAuxStore::impl::scanInputTree",
473 XAOD_MESSAGE("Logic error detected"));
474 }
475
476 // For top-level stores let's scan the static branches as well:
477 if (m_data.m_topStore && (brName == m_data.m_prefix)) {
478
479 // Make sure the object has been instantiated so that aux data
480 // registrations will have been done.
481 br->SetAddress(0);
482
483 // Get a list of its sub-branches:
484 TObjArray* sbranches = br->GetListOfBranches();
485
486 // ...and then loop over them:
487 for (Int_t j = 0; j < sbranches->GetEntriesFast(); ++j) {
488
489 // The name of the sub-branch:
490 const TString brName = sbranches->At(j)->GetName();
491
492 // Try to make a variable name out of the branch name:
493 const TString auxName =
494 brName(brName.Index(".") + 1, brName.Length());
495
496 // Skip this entry if it refers to a base class:
497 if (auxName.BeginsWith("xAOD::") || auxName.BeginsWith("SG::") ||
498 (auxName == "ILockable")) {
499 continue;
500 }
501
502 // The sub-branch:
503 ::TBranch* sbr = dynamic_cast< ::TBranch*>(sbranches->At(j));
504 if (!sbr) {
505 ::Fatal("xAOD::TAuxStore::impl::scanInputTree",
506 XAOD_MESSAGE("Logic error detected"));
507 }
508
509 // Leave the rest up to the function that is shared with the
510 // dynamic branches:
511 //cppcheck-suppress nullPointerRedundantCheck
512 RETURN_CHECK("xAOD::TAuxStore::impl::scanInputTree",setupAuxBranch(*sbr, auxName, true));
513 }
514
515 // Don't check the rest of the loop's body:
516 continue;
517 }
518
519 // Check if it has the right prefix to be a dynamic variable:
520 if (!brName.BeginsWith(m_data.m_dynPrefix.data())) {
521 continue;
522 }
523 // It's possible to create dynamic variables with an empty name
524 // as well. Which is a bug. Such variables are just ignored
525 // for now.
526 if (brName == m_data.m_dynPrefix) {
527 ::Warning("xAOD::TAuxStore::impl::scanInputTree",
528 "Dynamic branch with empty name found on container: %s",
529 m_data.m_prefix.data());
530 continue;
531 }
532
533 // The auxiliary property name:
534 const TString auxName = brName(brName.Index(".") + 1, brName.Length());
535
536 // Leave the rest up to the function that is shared with the
537 // dynamic branches:
538 RETURN_CHECK("xAOD::TAuxStore::impl::scanInputTree",
539 setupAuxBranch(*br, auxName, false));
540 }
541
542 // Okay, the input was successfully scanned:
543 m_inputScanned = true;
544
545 // Return gracefully:
546 return StatusCode::SUCCESS;
547 }
548
550 const std::type_info* auxBranchType(
551 ::TBranch& br, std::string_view auxName, bool staticBranch,
552 std::string* expectedClassName = nullptr) {
553
554 // Get the branch's type:
555 ::TClass* expectedClass = nullptr;
556 ::EDataType expectedType = kOther_t;
557 if (br.GetExpectedType(expectedClass, expectedType) &&
558 ((!staticBranch) || (!auxName.starts_with("m_")))) {
559 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
560 "Couldn't get the type of branch \"%s\"", br.GetName());
561 }
562
563 // Check for schema evolution:
564 // If a branch has automatic schema evolution from one class to another,
565 // then what we get from GetExpectedType will be the on-disk class.
566 // What we have in memory is given by GetCurrentClass.
567 if (expectedClass) {
568 if (TBranchElement* bre = dynamic_cast<TBranchElement*>(&br)) {
569 TClass* newClass = bre->GetCurrentClass();
570 if (newClass && newClass != expectedClass) {
571 expectedClass = newClass;
572 }
573 }
574 if (expectedClassName) {
575 *expectedClassName = expectedClass->GetName();
576 }
577 }
578
579 // If this is a primitive variable, and we're still not sure whether this
580 // is a store for an object or a container, the answer is given...
581 if ((!expectedClass) &&
582 (m_data.m_structMode == EStructMode::kUndefinedStore)) {
583 m_data.m_structMode = EStructMode::kObjectStore;
584 }
585
586 // Get the type_info of the branch.
587 const std::type_info* ti = nullptr;
588 if (m_data.m_structMode == EStructMode::kObjectStore) {
589 if (expectedClass) {
590 ti = expectedClass->GetTypeInfo();
591 } else {
592 ti = &(Utils::getTypeInfo(expectedType));
593 }
594 } else {
595 if (!expectedClass) {
596 if ((!staticBranch) || (!auxName.starts_with("m_"))) {
597 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
598 "Couldn't get the type of branch \"%s\"", br.GetName());
599 }
600 } else {
601 ::TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy();
602
603 if (!prox) {
604 TClass* cl2 = details::lookupVectorType(*expectedClass);
605 if (cl2) {
606 prox = cl2->GetCollectionProxy();
607 }
608 }
609
610 if (!prox) {
611 if ((!staticBranch) || (!auxName.starts_with("m_"))) {
612 ::Warning("xAOD::TAuxStore::impl::auxBranchType",
613 "Couldn't get the type of branch \"%s\"", br.GetName());
614 }
615 } else {
616 if (prox->GetValueClass()) {
617 ti = prox->GetValueClass()->GetTypeInfo();
618 } else {
619 ti = &(Utils::getTypeInfo(prox->GetType()));
620 }
621 }
622 }
623 }
624
625 return ti;
626 }
627
646 StatusCode setupAuxBranch(::TBranch& br, std::string_view auxName,
647 bool staticBranch) {
648
649 // Get the (on disk) type of the branch.
650 std::string expectedClassName;
651 const std::type_info* ti =
652 auxBranchType(br, auxName, staticBranch, &expectedClassName);
653 if (ti == nullptr) {
654 // If we didn't find a type_info for the branch, give up now...
655 return StatusCode::SUCCESS;
656 }
657
658 // Get the registry:
660
661 // Check if the registry already knows this variable name. If yes, let's
662 // use the type known by the registry. To be able to deal with simple
663 // schema evolution in dynamic branches.
664 if (const SG::auxid_t regAuxid = registry.findAuxID(std::string{auxName});
665 regAuxid != SG::null_auxid) {
666 m_data.m_auxIDs.insert(regAuxid);
667 return StatusCode::SUCCESS;
668 }
669
670 SG::AuxVarFlags flags = SG::AuxVarFlags::SkipNameCheck;
671 SG::auxid_t linked_auxid = SG::null_auxid;
672
673 if (SG::AuxTypeRegistry::isLinkedName(std::string{auxName})) {
674 flags |= SG::AuxVarFlags::Linked;
675 } else if (SG::AuxTypeRegistry::classNameHasLink(expectedClassName)) {
676 std::string linkedAttr =
677 SG::AuxTypeRegistry::linkedName(std::string{auxName});
678 std::string linkedBranch = SG::AuxTypeRegistry::linkedName(br.GetName());
679 ::TBranch* lbr = m_inTree->GetBranch(linkedBranch.c_str());
680 const std::type_info* lti = nullptr;
681 if (lbr) {
682 lti = auxBranchType(*lbr, linkedAttr, staticBranch);
683 }
684 if (lti) {
685 linked_auxid = registry.getAuxID(
686 *lti, linkedAttr, "",
687 SG::AuxVarFlags::SkipNameCheck | SG::AuxVarFlags::Linked);
688 }
689 if (linked_auxid == SG::null_auxid) {
690 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
691 "Could not find linked variable for %s type %s", auxName.data(),
692 expectedClassName.c_str());
693 }
694 }
695
696 // Check for an auxiliary ID for this branch:
697 SG::auxid_t auxid =
698 registry.getAuxID(*ti, std::string{auxName}, "", flags, linked_auxid);
699
700 // First try to find a compiled factory for the vector type:
701 if (auxid == SG::null_auxid) {
702
703 // Construct the name of the factory's class:
704 // But be careful --- if we don't exactly match the name
705 // in TClassTable, then we may trigger autoparsing. Besides the
706 // resource usage that implies, that can lead to crashes in dbg
707 // builds due to cling bugs.
708 std::string tn = Utils::getTypeName(*ti);
709 if (tn.starts_with("std::vector<")) {
710 tn.erase(0, 5);
711 }
712 std::string fac_class_name =
713 "SG::AuxTypeVectorFactory<" + tn + ",allocator<" + tn;
714 if (fac_class_name[fac_class_name.size() - 1] == '>') {
715 fac_class_name += ' ';
716 }
717 fac_class_name += "> >";
718
719 // Look for the dictionary of this type:
720 ::TClass* fac_class = TClass::GetClass(fac_class_name.c_str());
721 if (fac_class && fac_class->IsLoaded()) {
722 ::TClass* base_class = ::TClass::GetClass("SG::IAuxTypeVectorFactory");
723 if (base_class && base_class->IsLoaded()) {
724 const Int_t offs = fac_class->GetBaseClassOffset(base_class);
725 if (offs >= 0) {
726 void* fac_vp = fac_class->New();
727 if (fac_vp) {
728 unsigned long tmp =
729 reinterpret_cast<unsigned long>(fac_vp) + offs;
731 reinterpret_cast<SG::IAuxTypeVectorFactory*>(tmp);
732 registry.addFactory(
733 *ti, *fac->tiAlloc(),
734 std::unique_ptr<SG::IAuxTypeVectorFactory>(fac));
735 auxid = registry.getAuxID(*ti, std::string{auxName}, "", flags,
736 linked_auxid);
737 }
738 }
739 }
740 }
741 }
742
743 // If that didn't succeed, let's assign a generic factory to this type:
744 if (auxid == SG::null_auxid && linked_auxid == SG::null_auxid) {
745
746 // Construct the name of the vector type:
747 std::string vec_class_name = "std::vector<" + Utils::getTypeName(*ti);
748 if (vec_class_name[vec_class_name.size() - 1] == '>') {
749 vec_class_name += ' ';
750 }
751 vec_class_name += '>';
752
753 // Get the dictionary for the type:
754 ::TClass* vec_class = ::TClass::GetClass(vec_class_name.c_str());
755 if (vec_class && vec_class->IsLoaded()) {
756 auto fac = std::make_unique<TAuxVectorFactory>(vec_class);
757 if (fac->tiAlloc()) {
758 const std::type_info* tiAlloc = fac->tiAlloc();
759 registry.addFactory(*ti, *tiAlloc, std::move(fac));
760 } else {
761 std::string tiAllocName = fac->tiAllocName();
762 registry.addFactory(*ti, tiAllocName, std::move(fac));
763 }
764 auxid = registry.getAuxID(*ti, std::string{auxName}, "",
765 SG::AuxVarFlags::SkipNameCheck);
766 } else {
767 ::Warning("xAOD::TAuxStore::impl::setupAuxBranch",
768 "Couldn't find dictionary for type: %s",
769 vec_class_name.c_str());
770 }
771 }
772
773 // Check if we succeeded:
774 if (auxid == SG::null_auxid) {
775 if (linked_auxid != SG::null_auxid) {
776 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
777 XAOD_MESSAGE("Dynamic ROOT vector factory not implemented for "
778 "linked types; branch "
779 "\"%s\""),
780 br.GetName());
781 } else {
782 ::Error("xAOD::TAuxStore::impl::setupAuxBranch",
783 XAOD_MESSAGE("Couldn't assign auxiliary ID to branch "
784 "\"%s\""),
785 br.GetName());
786 }
787 return StatusCode::FAILURE;
788 }
789
790 // Remember the auxiliary ID:
791 m_data.m_auxIDs.insert(auxid);
792 return StatusCode::SUCCESS;
793 }
794
795 impl(const EventContext& ctx, Members& data, int basketSize, int splitLevel)
797 {}
798
800 const EventContext& m_ctx;
801
803 // cppcheck-suppress uninitMemberVarNoCtor
805
807 int m_basketSize = 2048;
810
812 ::TTree* m_inTree = nullptr;
814 ::TTree* m_outTree = nullptr;
815
817 bool m_inputScanned = false;
818
820 std::vector<std::unique_ptr<TBranchHandle> > m_branches;
822 std::vector<bool> m_branchesWritten;
825 std::vector<bool> m_missingBranches;
826
829};
830
831TAuxStore::TAuxStore(const EventContext& ctx,
832 std::string_view prefix, bool topStore, EStructMode mode,
833 int basketSize, int splitLevel)
834 : details::AuxStoreBase(topStore, mode),
835 m_impl{std::make_unique<impl>(ctx, m_data, basketSize, splitLevel)} {
836
838}
839
840TAuxStore::~TAuxStore() = default;
841
842void TAuxStore::setPrefix(std::string_view prefix) {
843
844 m_data.m_prefix = prefix;
845 m_data.m_dynPrefix = Utils::dynBranchPrefix(m_data.m_prefix);
846 reset();
847}
848
850
851 assert(m_impl);
852 return m_impl->m_basketSize;
853}
854
856
857 assert(m_impl);
858 m_impl->m_basketSize = value;
859}
860
862
863 assert(m_impl);
864 return m_impl->m_splitLevel;
865}
866
868
869 assert(m_impl);
870 m_impl->m_splitLevel = value;
871}
872
878StatusCode TAuxStore::readFrom(::TTree& tree, bool printWarnings) {
879
880 assert(m_impl);
881
882 // Make sure that everything will be re-read after this:
883 reset();
884
885 // We will need to check again which branches are available:
886 m_impl->m_missingBranches.clear();
887
888 // Remember the tree:
889 m_impl->m_inTree = &tree;
890
891 // Catalogue all the branches:
892 RETURN_CHECK("xAOD::TAuxStore::readFrom", m_impl->scanInputTree());
893
894 // Check if we'll be likely to be able to read the "static"
895 // variables:
896 assert(m_impl->m_inTree != nullptr);
897 TBranch* br = m_impl->m_inTree->GetBranch(m_data.m_prefix.data());
898 if (br == nullptr) {
899 // We might not even have static branches, so this is not an error
900 // by itself...
901 return StatusCode::SUCCESS;
902 }
903 // In order to read complex objects, like smart pointers from an
904 // auxiliary container variable-by-variable, the split level of the
905 // branch must be exactly 1.
906 if ((br->GetSplitLevel() != 1) && m_data.m_topStore && printWarnings) {
907 ::Warning("xAOD::TAuxStore::readFrom",
908 "Static branch (%s) with split level %i discovered",
909 m_data.m_prefix.data(), br->GetSplitLevel());
910 ::Warning("xAOD::TAuxStore::readFrom",
911 "The reading of complex variables from it may/will fail!");
912 }
913
914 // Return gracefully.
915 return StatusCode::SUCCESS;
916}
917
923StatusCode TAuxStore::writeTo(::TTree& tree) {
924
925 assert(m_impl);
926
927 // Look for any auxiliary branches that have not been connected to yet:
928 RETURN_CHECK("xAOD::TAuxStore::writeTo", m_impl->scanInputTree());
929
930 // Store the TTree pointer:
931 m_impl->m_outTree = &tree;
932
933 // Create all the variables that we already know about. Notice that the
934 // code makes a copy of the auxid set on purpose. Because the underlying
935 // AuxSelection object gets modified while doing the for loop.
936 const SG::auxid_set_t selAuxIDs = getSelectedAuxIDs();
937 for (SG::auxid_t id : selAuxIDs) {
938 RETURN_CHECK("xAOD::TAuxStore::writeTo", setupOutputData(id));
939 }
940
941 // Return gracefully.
942 return StatusCode::SUCCESS;
943}
944
945int TAuxStore::getEntry(int getall) {
946
947 assert(m_impl);
948
949 // Guard against multi-threaded execution:
950 guard_t guard(m_impl->m_mutex);
951
952 // Reset the transient store. TEvent::fill() calls this function with
953 // getall==99. When that is happening, we need to keep the transient
954 // store still around. Since the user may want to interact with the
955 // object after it was written out. (And since TEvent::fill() asks for
956 // the transient decorations after calling getEntry(...).)
957 if (m_data.m_transientStore && (getall != 99)) {
958 // Remove the transient auxiliary IDs from the internal list:
959 m_data.m_auxIDs -= m_data.m_transientStore->getAuxIDs();
960 m_data.m_decorIDs -= m_data.m_transientStore->getDecorIDs();
961 // Delete the object:
962 m_data.m_transientStore.reset();
963 }
964
965 // Now remove the IDs of the decorations that are getting persistified:
966 if (getall != 99) {
967 for (SG::auxid_t auxid = 0; auxid < m_data.m_isDecoration.size(); ++auxid) {
968 if (!m_data.m_isDecoration[auxid]) {
969 continue;
970 }
971 m_data.m_auxIDs.erase(auxid);
972 m_data.m_decorIDs.erase(auxid);
973 }
974 }
975
976 // If we don't need everything loaded, return now:
977 if (!getall) {
978 return 0;
979 }
980
981 // Get all the variables at once:
982 int bytesRead = 0;
983 for (auto& branchHandle : m_impl->m_branches) {
984 if (branchHandle) {
985 bytesRead += branchHandle->getEntry();
986#ifndef XAOD_STANDALONE
987 m_data.m_vecs[branchHandle->auxid()]->toTransient( m_impl->m_ctx );
988#endif
989 }
990 }
991 return bytesRead;
992}
993
995
996 assert(m_impl);
997
998 for (auto& branchHandle : m_impl->m_branches) {
999 if (branchHandle) {
1000 branchHandle->reset();
1001 }
1002 }
1003 m_impl->m_inputScanned = false;
1004}
1005
1007
1008 assert(m_impl);
1009 return ((m_impl->m_branches.size() > auxid) && m_impl->m_branches[auxid]);
1010}
1011
1013
1014 assert(m_impl);
1015 assert(m_impl->m_branches.size() > auxid);
1016 assert(m_impl->m_branches[auxid]);
1017 const ::Int_t readBytes = m_impl->m_branches[auxid]->getEntry();
1018 if (readBytes < 0) {
1019 ::Error("xAOD::TAuxStore::getEntryFor",
1020 XAOD_MESSAGE("Couldn't read in variable %s"),
1021 SG::AuxTypeRegistry::instance().getName(auxid).c_str());
1022 return StatusCode::FAILURE;
1023 }
1024#ifndef XAOD_STANDALONE
1025 m_data.m_vecs[auxid]->toTransient( m_impl->m_ctx );
1026#endif
1027 return StatusCode::SUCCESS;
1028}
1029
1031
1032 assert(m_impl);
1033 return (m_impl->m_outTree != nullptr);
1034}
1035
1047
1048 assert(m_impl);
1049
1050 // Return right away if we already know that the branch is missing.
1051 if ((auxid < m_impl->m_missingBranches.size()) &&
1052 m_impl->m_missingBranches[auxid]) {
1053 return StatusCode::RECOVERABLE;
1054 }
1055
1056 // Make sure the internal storage is large enough:
1057 if (m_data.m_vecs.size() <= auxid) {
1058 m_data.m_vecs.resize(auxid + 1);
1059 }
1060 if (m_impl->m_branches.size() <= auxid) {
1061 m_impl->m_branches.resize(auxid + 1);
1062 }
1063
1064 // Check if we need to do anything:
1065 if (m_data.m_vecs[auxid] && m_impl->m_branches[auxid]) {
1066 return StatusCode::SUCCESS;
1067 }
1068
1069 // A little sanity check.
1070 if (m_impl->m_inTree == nullptr) {
1071 ::Error("xAOD::TAuxStore::setupInputData",
1072 XAOD_MESSAGE("No input TTree set up!"));
1073 return StatusCode::FAILURE;
1074 }
1075
1076 // Another sanity check.
1077 if (m_data.m_vecs[auxid] || m_impl->m_branches[auxid]) {
1078 ::Error("xAOD::TAuxStore::setupInputData",
1079 XAOD_MESSAGE("Internal logic error!"));
1080 return StatusCode::FAILURE;
1081 }
1082
1083 // Convenience access to the registry.
1085
1086 // Get the property name:
1087 const TString statBrName =
1088 std::format("{}{}", m_data.m_prefix, r.getName(auxid));
1089 const TString dynBrName =
1090 std::format("{}{}", m_data.m_dynPrefix, r.getName(auxid));
1091
1092 // Check if the branch exists:
1093 Bool_t staticBranch = true;
1094 TString brName = statBrName;
1095
1096 TBranch* br = m_impl->m_inTree->GetBranch(statBrName);
1097 if (!br) {
1098 br = m_impl->m_inTree->GetBranch(dynBrName);
1099 if (!br) {
1100 // Since TTree::GetBranch / TTObjArray::FindObject is expensive,
1101 // remember that we didn't find this branch in this file.
1102 if (m_impl->m_missingBranches.size() <= auxid) {
1103 m_impl->m_missingBranches.resize(auxid + 1);
1104 }
1105 m_impl->m_missingBranches[auxid] = true;
1106 // The branch doesn't exist, but this is not an error per se.
1107 // The user may just be calling isAvailable(...) on the variable.
1108 return StatusCode::RECOVERABLE;
1109 }
1110 // We have a dynamic branch:
1111 staticBranch = false;
1112 brName = dynBrName;
1113 }
1114
1115 // Check if it's a "primitive branch":
1116 const Bool_t primitiveBranch = isPrimitiveBranch(*br);
1117 // Check if it's a "container branch":
1118 const Bool_t containerBranch =
1119 (primitiveBranch ? false : isContainerBranch(*br, auxid));
1120
1121 // Set the structure mode if it has not been defined externally:
1122 if (m_data.m_structMode == EStructMode::kUndefinedStore) {
1123 m_data.m_structMode = (containerBranch ? EStructMode::kContainerStore
1125 }
1126
1127 // Check that the branch type makes sense:
1128 if ((containerBranch &&
1129 (m_data.m_structMode != EStructMode::kContainerStore) &&
1130 !r.isLinked(auxid)) ||
1131 ((!containerBranch) &&
1132 (m_data.m_structMode != EStructMode::kObjectStore))) {
1133 ::Error("xAOD::TAuxStore::setupInputData",
1134 XAOD_MESSAGE("Branch type and requested structure mode "
1135 "differ for branch: %s"),
1136 brName.Data());
1137 return StatusCode::FAILURE;
1138 }
1139
1140 // Check what variable it is:
1141 ::TClass* clDummy = 0;
1142 ::EDataType dType = kOther_t;
1143 if (br->GetExpectedType(clDummy, dType)) {
1144 ::Error("xAOD::TAuxStore::setupInputData",
1145 XAOD_MESSAGE("Couldn't determine the type of branch \"%s\""),
1146 brName.Data());
1147 return StatusCode::FAILURE;
1148 }
1149
1150 // Get the property type:
1151 const std::type_info* brType = 0;
1152 if (details::isRegisteredType(auxid)) {
1153 // Get the type from the auxiliary type registry:
1154 brType = (containerBranch ? r.getVecType(auxid) : r.getType(auxid));
1155 } else {
1156 // Get the type from the input branch itself:
1157 brType = (clDummy ? clDummy->GetTypeInfo() : &(Utils::getTypeInfo(dType)));
1158 }
1159 if (!brType) {
1160 ::Error("xAOD::TAuxStore::setupInputData",
1161 XAOD_MESSAGE("Can't read/copy variable %s (%s)"), brName.Data(),
1162 clDummy->GetName());
1163 return StatusCode::RECOVERABLE;
1164 }
1165 const TString brTypeName = Utils::getTypeName(*brType).c_str();
1166
1167 // Check if we have the needed dictionary for an object branch:
1168 ::TClass* brClass = 0;
1169 if (!primitiveBranch) {
1170 // Get the property's class:
1171 brClass = ::TClass::GetClass(*brType, true, true);
1172 if (!brClass) {
1173 brClass = ::TClass::GetClass(brTypeName);
1174 }
1175 if (!brClass) {
1176 ::Error("xAOD::TAuxStore::setupInputData",
1177 XAOD_MESSAGE("No dictionary available for class \"%s\""),
1178 brTypeName.Data());
1179 return StatusCode::FAILURE;
1180 }
1181 }
1182
1183 // Create the smart object holding this vector:
1184 if (details::isRegisteredType(auxid)) {
1185 m_data.m_vecs[auxid] = r.makeVector(auxid, (size_t)0, (size_t)0);
1186 if (!containerBranch) {
1187 m_data.m_vecs[auxid]->resize(1);
1188 }
1189 if (clDummy &&
1190 strncmp(clDummy->GetName(), "SG::PackedContainer<", 20) == 0) {
1191 std::unique_ptr<SG::IAuxTypeVector> packed =
1192 m_data.m_vecs[auxid]->toPacked();
1193 std::swap(m_data.m_vecs[auxid], packed);
1194 }
1195 } else {
1196 ::Error("xAOD::TAuxStore::setupInputData",
1197 XAOD_MESSAGE("Couldn't create in-memory vector for "
1198 "variable %s (%i)"),
1199 brName.Data(), static_cast<int>(auxid));
1200 return StatusCode::FAILURE;
1201 }
1202
1203 // Create a new branch handle:
1204 const std::type_info* objType = brType;
1205 if (containerBranch) {
1206 objType = m_data.m_vecs[auxid]->objType();
1207 if (!objType)
1208 objType = r.getType(auxid);
1209 }
1210 m_impl->m_branches[auxid] = std::make_unique<TBranchHandle>(
1211 staticBranch, primitiveBranch, objType,
1212 (containerBranch ? m_data.m_vecs[auxid]->toVector()
1213 : m_data.m_vecs[auxid]->toPtr()),
1214 auxid, m_data.m_prefix);
1215
1216 // Set the tree/branch in the "right mode":
1217 if (staticBranch) {
1218 br->SetMakeClass();
1219 }
1220
1221 // Connect to the branch:
1222 ::Int_t status = 0;
1223 if (clDummy && ::TString(clDummy->GetName()).Contains("basic_string<char>")) {
1224 // This is pretty much just a hack. As it happens, Athena I/O can
1225 // create dynamic branches that consider themselves to be of type
1226 // "vector<basic_string<char> >" and similar. (Instead of the
1227 // canonical "vector<string>" name.) When we encounter such a branch,
1228 // we just connect to it without performing any compatibility checks.
1229 // Since we don't need to apply any read rules in this case anyway.
1230 status = m_impl->m_inTree->SetBranchAddress(
1231 brName, m_impl->m_branches[auxid]->inputObjectPtr(),
1232 m_impl->m_branches[auxid]->branchPtr());
1233 } else {
1234 status = m_impl->m_inTree->SetBranchAddress(
1235 brName, m_impl->m_branches[auxid]->inputObjectPtr(),
1236 m_impl->m_branches[auxid]->branchPtr(), brClass, dType,
1237 ((!staticBranch) && (!primitiveBranch)));
1238 }
1239 if (status < 0) {
1240 ::Error("xAOD::TAuxStore::setupInputData",
1241 XAOD_MESSAGE("Coulnd't connect to branch \"%s\""), brName.Data());
1242 ::Error("xAOD::TAuxStore::setupInputData", XAOD_MESSAGE("Return code: %i"),
1243 status);
1244 m_data.m_vecs[auxid].reset();
1245 m_impl->m_branches[auxid].reset();
1246 return StatusCode::FAILURE;
1247 }
1248
1249 // Get the current entry:
1250 m_impl->m_branches[auxid]->getEntry();
1251#ifndef XAOD_STANDALONE
1252 m_data.m_vecs[auxid]->toTransient( m_impl->m_ctx );
1253#endif
1254
1255 // Remember which variable got created:
1256 m_data.m_auxIDs.insert(auxid);
1257
1258 // Check if we just replaced a generic object:
1259 if (details::isRegisteredType(auxid)) {
1260 // The name of the variable we just created:
1261 const std::string auxname = r.getName(auxid);
1262 // Check if there's another variable with this name already:
1263 for (SG::auxid_t i = 0; i < m_data.m_vecs.size(); ++i) {
1264 // Check if we have this aux ID:
1265 if (!m_data.m_vecs[i]) {
1266 continue;
1267 }
1268 // Ingore the object that we *just* created:
1269 if (i == auxid) {
1270 continue;
1271 }
1272 // The name of the variable:
1273 const std::string testname = r.getName(i);
1274 // Check if it has the same name:
1275 if (testname != auxname) {
1276 continue;
1277 }
1278 // Check that the other one is a non-registered type:
1280 ::Error("xAOD::TAuxStore::setupInputData",
1281 XAOD_MESSAGE("Internal logic error!"));
1282 continue;
1283 }
1284 // Okay, we do need to remove this object:
1285 m_data.m_vecs[i].reset();
1286 m_impl->m_branches[i].reset();
1287 m_data.m_auxIDs.erase(i);
1288 }
1289 }
1290
1291 SG::auxid_t linked_auxid = r.linkedVariable(auxid);
1292 if (linked_auxid != SG::null_auxid) {
1293 return setupInputData(linked_auxid);
1294 }
1295
1296 // Return gracefully.
1297 return StatusCode::SUCCESS;
1298}
1299
1310
1311 assert(m_impl);
1312
1313 // Check whether we need to do anything:
1314 if (!m_impl->m_outTree) {
1315 return StatusCode::SUCCESS;
1316 }
1317
1318 // Check if the variable needs to be written out:
1319 if (!isAuxIDSelected(auxid)) {
1320 return StatusCode::SUCCESS;
1321 }
1322
1323 // Make sure that containers are large enough:
1324 if (m_data.m_vecs.size() <= auxid) {
1325 m_data.m_vecs.resize(auxid + 1);
1326 }
1327 if (m_impl->m_branches.size() <= auxid) {
1328 m_impl->m_branches.resize(auxid + 1);
1329 }
1330 if (m_impl->m_branchesWritten.size() <= auxid) {
1331 m_impl->m_branchesWritten.resize(auxid + 1);
1332 }
1333
1334 // Check if this auxiliary variable is already in the output:
1335 if (m_impl->m_branchesWritten[auxid]) {
1336 return StatusCode::SUCCESS;
1337 }
1338
1339 // The registry:
1341
1342 // Check if the variable was put into the transient store as a
1343 // decoration, and now needs to be put into the output file:
1344 if ((!m_data.m_vecs[auxid]) && m_data.m_transientStore &&
1345 (m_data.m_transientStore->getAuxIDs().test(auxid))) {
1346
1347 // Get the variable from the transient store:
1348 const void* pptr = m_data.m_transientStore->getData(auxid);
1349 if (!pptr) {
1350 ::Fatal("xAOD::TAuxStore::setupOutputData",
1351 XAOD_MESSAGE("Internal logic error detected"));
1352 return StatusCode::FAILURE;
1353 }
1354
1355 // Create the new object:
1356 m_data.m_vecs[auxid] = reg.makeVector(auxid, m_data.m_size, m_data.m_size);
1357 void* ptr = m_data.m_vecs[auxid]->toPtr();
1358 if (!ptr) {
1359 ::Error("xAOD::TAuxStore::setupOutputData",
1360 XAOD_MESSAGE("Couldn't create decoration in memory "
1361 "for writing"));
1362 return StatusCode::FAILURE;
1363 }
1364
1365 // Get the type of this variable:
1366 const std::type_info* type = reg.getType(auxid);
1367 if (!type) {
1368 ::Error("xAOD::TAuxStore::setupOutputData",
1369 XAOD_MESSAGE("Couldn't get the type of transient "
1370 "variable %i"),
1371 static_cast<int>(auxid));
1372 return StatusCode::FAILURE;
1373 }
1374 // Now get the factory for this variable:
1375 const SG::IAuxTypeVectorFactory* factory = reg.getFactory(auxid);
1376 if (!factory) {
1377 ::Error("xAOD::TAuxStore::setupOutputData",
1378 XAOD_MESSAGE("No factory found for transient variable "
1379 "%i"),
1380 static_cast<int>(auxid));
1381 return StatusCode::FAILURE;
1382 }
1383
1384 // Mark it as a decoration already, otherwise the copy may fail.
1385 if (m_data.m_isDecoration.size() <= auxid) {
1386 m_data.m_isDecoration.resize(auxid + 1);
1387 }
1388 m_data.m_isDecoration[auxid] = true;
1389
1390 // Finally, do the copy:
1391 factory->copy(auxid, SG::AuxVectorInterface(*this), 0,
1392 SG::AuxVectorInterface(*m_data.m_transientStore), 0,
1393 m_data.m_size);
1394 }
1395
1396 // Check if we know about this variable to be on the input,
1397 // but haven't connected to it yet:
1398 if ((m_data.m_auxIDs.test(auxid)) && (!m_data.m_vecs[auxid]) &&
1399 (!m_impl->m_branches[auxid])) {
1400 RETURN_CHECK("xAOD::TAuxStore::setupOutputData", setupInputData(auxid));
1401 }
1402
1403 // Check that we know the store's type:
1404 if ((m_data.m_structMode != EStructMode::kContainerStore) &&
1405 (m_data.m_structMode != EStructMode::kObjectStore)) {
1406 ::Error("xAOD::TAuxStore::setupOutputData",
1407 XAOD_MESSAGE("Structure mode unknown for variable %s"),
1408 SG::AuxTypeRegistry::instance().getName(auxid).c_str());
1409 return StatusCode::FAILURE;
1410 }
1411
1412 // Check if the variable exists already in memory:
1413 if (!m_data.m_vecs[auxid]) {
1414 m_data.m_vecs[auxid] =
1415 SG::AuxTypeRegistry::instance().makeVector(auxid, (size_t)0, (size_t)0);
1416 if (m_data.m_structMode == EStructMode::kObjectStore) {
1417 m_data.m_vecs[auxid]->resize(1);
1418 }
1419 }
1420
1421 // Check if the branch handle exists already:
1422 if (!m_impl->m_branches[auxid]) {
1423 // Get the property type:
1424 const std::type_info* brType =
1425 (m_data.m_structMode == EStructMode::kContainerStore
1428 // Create the handle object:
1429 bool primitiveBranch = (strlen(brType->name()) == 1);
1430 m_impl->m_branches[auxid] = std::make_unique<TBranchHandle>(
1431 false, (strlen(brType->name()) == 1),
1432 (primitiveBranch ? brType : m_data.m_vecs[auxid]->objType()),
1433 (m_data.m_structMode == EStructMode::kObjectStore
1434 ? m_data.m_vecs[auxid]->toPtr()
1435 : m_data.m_vecs[auxid]->toVector()),
1436 auxid, m_data.m_prefix);
1437 }
1438
1439 // Construct a name for the branch:
1440 const TString brName =
1441 std::format("{}{}", m_data.m_dynPrefix,
1442 SG::AuxTypeRegistry::instance().getName(auxid));
1443
1444 // If the output branch exists already, assume that it was us making
1445 // it:
1446 ::TBranch* br = m_impl->m_outTree->GetBranch(brName);
1447 if (br) {
1448 // Apparently a branch that was already set up for copying as a basic
1449 // variable, now got accessed explicitly. So let's update the output
1450 // branch to point to this new location now.
1451 br->SetAddress(m_impl->m_branches[auxid]->outputObjectPtr());
1452 // Update the cache. Notice that the "write status" of the typeless
1453 // auxiliary ID is not turned off. But it shouldn't matter, as the
1454 // variable will not be accessed in a typeless way anymore.
1455 m_impl->m_branchesWritten[auxid] = true;
1456 // Return gracefully:
1457 return StatusCode::SUCCESS;
1458 }
1459
1460 // Check that we know the type of the branch:
1461 const std::type_info* brType = m_impl->m_branches[auxid]->typeInfo();
1462 if (!brType) {
1463 ::Error("xAOD::TAuxStore::setupOutputData",
1464 XAOD_MESSAGE("There's an internal logic error in the "
1465 "code"));
1466 return StatusCode::FAILURE;
1467 }
1468 const std::string brTypeName = Utils::getTypeName(*brType);
1469
1470 // Decide if this is a primitive branch:
1471 const Bool_t primitiveBranch = (strlen(brType->name()) == 1);
1472
1473 // Let's create the branch now:
1474 if (primitiveBranch) {
1475
1476 // Get the "ROOT type" belonging to this primitive:
1477 const char rootType = Utils::rootType(brType->name()[0]);
1478 if (rootType == '\0') {
1479 ::Error("xAOD::TAuxStore::setupOutputData",
1480 XAOD_MESSAGE("Type not known for variable \"%s\" "
1481 "of type \"%s\""),
1482 brName.Data(), brTypeName.c_str());
1483 return StatusCode::FAILURE;
1484 }
1485
1486 // Construct the type description:
1487 std::ostringstream typeDesc;
1488 typeDesc << brName << "/" << rootType;
1489
1490 // Create the branch:
1491 br = m_impl->m_outTree->Branch(
1492 brName, m_impl->m_branches[auxid]->outputObjectPtr(),
1493 typeDesc.str().c_str(), m_impl->m_basketSize);
1494
1495 } else {
1496
1497 // Access the dictionary for the type:
1498 TClass* cl = TClass::GetClass(*brType);
1499 if (!cl) {
1500 cl = TClass::GetClass(brTypeName.c_str());
1501 }
1502 if (!cl) {
1503 ::Error("xAOD::TAuxStore::setupOutputData",
1504 XAOD_MESSAGE("Couldn't find dictionary for type: %s"),
1505 brTypeName.c_str());
1506 return StatusCode::FAILURE;
1507 }
1508 if (!cl->GetStreamerInfo()) {
1509 ::Error("xAOD::TAuxStore::setupOutputData",
1510 XAOD_MESSAGE("No streamer info available for type %s"),
1511 cl->GetName());
1512 return StatusCode::FAILURE;
1513 }
1514
1515 // Create the branch:
1516 br = m_impl->m_outTree->Branch(brName, cl->GetName(),
1517 m_impl->m_branches[auxid]->outputObjectPtr(),
1518 m_impl->m_basketSize, m_impl->m_splitLevel);
1519 }
1520
1521 // Check if we succeeded:
1522 if (!br) {
1523 ::Error("xAOD::TAuxStore::setupOutputData",
1524 XAOD_MESSAGE("Failed creating branch \"%s\" of type "
1525 "\"%s\""),
1526 brName.Data(), brTypeName.c_str());
1527 return StatusCode::FAILURE;
1528 }
1529
1530 // If this is not the first event, fill up the branch with dummy
1531 // info:
1532 for (Long64_t i = 0; i < m_impl->m_outTree->GetEntries(); ++i) {
1533 br->Fill();
1534 }
1535
1536 // Update the cache:
1537 m_impl->m_branchesWritten[auxid] = true;
1538
1539 // Also, remember that we now handle this variable:
1540 m_data.m_auxIDs.insert(auxid);
1541
1542 // We were successful:
1543 return StatusCode::SUCCESS;
1544}
1545
1546const void* TAuxStore::getInputObject(SG::auxid_t auxid) const {
1547
1548 assert(m_impl);
1549 assert(m_impl->m_branches.size() > auxid);
1550 assert(m_impl->m_branches[auxid]);
1551 return m_impl->m_branches[auxid]->objectPtr();
1552}
1553
1554const std::type_info* TAuxStore::getInputType(SG::auxid_t auxid) const {
1555
1556 assert(m_impl);
1557 assert(m_impl->m_branches.size() > auxid);
1558 assert(m_impl->m_branches[auxid]);
1559 return m_impl->m_branches[auxid]->typeInfo();
1560}
1561
1562} // namespace xAOD
An auxiliary data store that holds data internally.
Handle mappings between names and auxid_t.
Make an AuxVectorData object from either a raw vector or an aux store.
Exceptions that can be thrown from AthContainers.
#define XAOD_MESSAGE(MESSAGE)
Simple macro for printing error/verbose messages.
#define RETURN_CHECK(CONTEXT, EXP)
Helper macro for checking return codes in a compact form in the code.
Definition ReturnCheck.h:26
Helper for getting a const version of a pointer.
Define macros for attributes used to control the static checker.
Handle mappings between names and auxid_t.
const std::type_info * getType(SG::auxid_t auxid) const
Return the type of an aux data item.
SG::auxid_t getAuxID(const std::string &name, const std::string &clsname="", const Flags flags=Flags::None, const SG::auxid_t linkedVariable=SG::null_auxid)
Look up a name -> auxid_t mapping.
SG::auxid_t findAuxID(const std::string &name, const std::string &clsname="") const
Look up a name -> auxid_t mapping.
static bool isLinkedName(const std::string &name)
Test if a variable name corresponds to a linked variable.
static std::string linkedName(const std::string &name)
Given a variable name, return the name of the corresponding linked variable.
const std::type_info * getVecType(SG::auxid_t auxid) const
Return the type of the STL vector used to hold an aux data item.
static bool classNameHasLink(const std::string &className)
Test to see if a class name corresponds to a class with a linked variable.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
const IAuxTypeVectorFactory * addFactory(const std::type_info &ti, const std::type_info &ti_alloc, std::unique_ptr< const IAuxTypeVectorFactory > factory)
Add a new type -> factory mapping.
std::unique_ptr< IAuxTypeVector > makeVector(SG::auxid_t auxid, size_t size, size_t capacity) const
Construct a new vector to hold an aux item.
Make an AuxVectorData object from either a raw array or an aux store.
Interface for factory objects that create vectors.
virtual const std::type_info * tiAlloc() const =0
Return the type_info of the vector allocator.
virtual void copy(SG::auxid_t auxid, AuxVectorData &dst, size_t dst_index, const AuxVectorData &src, size_t src_index, size_t n) const =0
Copy elements between vectors.
A set of aux data identifiers.
Definition AuxTypes.h:47
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
void readBranch(const std::string &prefix, SG::auxid_t auxid)
Function incrementing the read counter on a specific branch.
int getEntry(int getall=0)
Read the values from the TTree entry that was loaded with TTree::LoadTree().
virtual ~TAuxStore()
Destructor.
virtual const std::type_info * getInputType(SG::auxid_t auxid) const override
Get the type of an input object, for getIOType().
virtual void reset() override
Tell the object that all branches will need to be re-read.
virtual bool hasEntryFor(SG::auxid_t auxid) const override
Check if a given variable is available from the input.
virtual bool hasOutput() const override
Check if an output is being written by the object.
void setSplitLevel(int value)
Set the split level of the output branches.
TAuxStore(const EventContext &ctx, std::string_view prefix="", bool topStore=true, EStructMode mode=EStructMode::kUndefinedStore, int basketSize=2048, int splitLevel=0)
Constructor.
virtual StatusCode setupInputData(SG::auxid_t auxid) override
Connect a variable to the input.
StatusCode readFrom(::TTree &tree, bool printWarnings=true)
Connect the object to an input TTree.
int splitLevel() const
Get the split level of the output branches.
virtual StatusCode setupOutputData(SG::auxid_t auxid) override
Connect a variable to the output.
virtual void setPrefix(std::string_view prefix) override
Set the object name prefix.
StatusCode writeTo(::TTree &tree)
Connect the object to an output TTree.
virtual StatusCode getEntryFor(SG::auxid_t auxid) override
Load a single variable from the input.
std::unique_ptr< impl > m_impl
Pointer to the internal object.
Definition TAuxStore.h:93
void setBasketSize(int value)
Set the size of the baskets created for the output branches.
int basketSize() const
Get the size of the baskets created for the output branches.
virtual const void * getInputObject(SG::auxid_t auxid) const override
Get a pointer to an input object, as it is in memory, for getIOData().
const std::string & prefix() const
Get the currently configured object name prefix.
bool isAuxIDSelected(SG::auxid_t auxid) const
Check if an auxiliary variable is selected for ouput writing.
virtual SG::auxid_set_t getSelectedAuxIDs() const override
Get the IDs of the selected aux variables.
AthContainers_detail::mutex mutex_t
Mutex type for multithread synchronization.
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.
AuxStoreBase(bool topStore=true, EStructMode mode=EStructMode::kUndefinedStore)
Constructor.
Members m_data
Member variables of the base class.
AthContainers_detail::lock_guard< mutex_t > guard_t
Guard type for multithreaded synchronisation.
int r
Definition globals.cxx:22
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition Error.h:16
AuxVarFlags
Additional flags to qualify an auxiliary variable.
Definition AuxTypes.h:58
static const auxid_t null_auxid
To signal no aux data item.
Definition AuxTypes.h:30
SG::auxid_t auxid() const
Return the aux id for this variable.
virtual void reset() override
Free all allocated elements.
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
STL namespace.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
const std::type_info & getTypeInfo(EDataType type)
This function is used when reading a primitive branch from an input file without the user explicitly ...
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 getTypeName(const std::type_info &ti)
This function is necessary in order to create type names that ROOT can understand.
TClass * lookupVectorType(TClass &cl)
Internal function used by xAOD::TAuxStore and xAOD::RAuxStore.
bool isRegisteredType(SG::auxid_t auxid)
Check if the auxiliary variable has a registered type.
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
int m_basketSize
The basket size for the output branches.
Members & m_data
Variables coming from AuxStoreBase.
StatusCode setupAuxBranch(::TBranch &br, std::string_view auxName, bool staticBranch)
Register one input branch as an available auxiliary variable.
std::vector< bool > m_branchesWritten
"Write status" of the different variables
std::vector< bool > m_missingBranches
Mark branches we've found to be missing.
StatusCode scanInputTree()
Scan the input TTree for auxiliary branches.
::TTree * m_inTree
The TTree being read from.
impl(const EventContext &ctx, Members &data, int basketSize, int splitLevel)
std::vector< std::unique_ptr< TBranchHandle > > m_branches
Branches reading the various auxiliary variables.
mutex_t m_mutex
Mutex object used for multithreaded synchronisation.
const std::type_info * auxBranchType(::TBranch &br, std::string_view auxName, bool staticBranch, std::string *expectedClassName=nullptr)
Find the type_info to use as the aux type for a given branch.
bool m_inputScanned
"Scan status" of the input TTree
::TTree * m_outTree
The TTree being written to.
int m_splitLevel
The split level for the output branches.
const EventContext & m_ctx
The context for this event.
Struct collecting all member variables of this base class.
TChain * tree