Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
TBranchAuxDynReader.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
11 #include "RootUtils/Type.h"
12 
13 #include "TBranchAuxDynReader.h"
14 #include "TBranchAuxDynStore.h"
15 #include "RootAuxDynIO.h"
16 
17 #include "TTree.h"
18 #include "TBranch.h"
19 #include "TClass.h"
20 #include "TClassTable.h"
21 #include "TClassEdit.h"
22 #include "TVirtualCollectionProxy.h"
23 #include "TROOT.h"
24 #include "TDictAttributeMap.h"
25 
26 using std::string;
27 
28 namespace {
29 
30 const std::type_info* dataTypeToTypeInfo (EDataType type, std::string& typeName)
31 {
32  RootUtils::Type typ (type);
33  typeName = typ.getTypeName();
34  return typ.getTypeInfo();
35 }
36 
37 
53 const std::type_info*
54 getAuxElementType( TClass *expectedClass, EDataType expectedType, bool standalone,
55  std::string& elementTypeName, std::string& storageTypeName)
56 {
57  if (standalone) {
58  if(expectedClass) {
59  elementTypeName = expectedClass->GetName();
60  storageTypeName = elementTypeName;
61  return expectedClass->GetTypeInfo();
62  }
63  const std::type_info* ret = dataTypeToTypeInfo(expectedType, elementTypeName);
64  storageTypeName = elementTypeName;
65  return ret;
66  }
67 
68  // Not standalone; branch should be a vector.
69  if (!expectedClass) return 0;
70 
71  storageTypeName = expectedClass->GetName();
72  if (strncmp (expectedClass->GetName(), "vector<", 7) == 0) {
73  TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy();
74  if (!prox) return 0;
75  if (prox->GetValueClass()) {
76  elementTypeName = prox->GetValueClass()->GetName();
77  return prox->GetValueClass()->GetTypeInfo();
78  }
79  return dataTypeToTypeInfo (prox->GetType(), elementTypeName);
80  }
81  else if (strncmp (expectedClass->GetName(), "SG::PackedContainer<", 20) == 0){
82  elementTypeName.clear();
83  {
84  // Protect against data race inside TClassEdit.
85  // https://github.com/root-project/root/issues/10353
86  // Should be fixed in root 6.26.02.
87  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
88  TClassEdit::TSplitType split (expectedClass->GetName());
89  if (split.fElements.size() > 1) {
90  elementTypeName = split.fElements[1];
91  }
92  }
93  if (!elementTypeName.empty()) {
94  RootUtils::Type typ (elementTypeName);
95  return typ.getTypeInfo();
96  }
97  }
98  return 0;
99 }
100 
101 
103 getAuxIdForAttribute(const std::string& attr, TClass *tclass, EDataType edt, bool standalone,
104  SG::auxid_t linked_auxid)
105 {
107 
108  SG::auxid_t auxid = r.findAuxID(attr);
109  if(auxid != SG::null_auxid)
110  return auxid;
111 
112  string elemen_type_name;
113  string branch_type_name;
114  const std::type_info* ti = getAuxElementType(tclass, edt, standalone, elemen_type_name, branch_type_name);
115  if( !ti )
116  return auxid;
117 
118  return SG::getDynamicAuxID (*ti, attr, elemen_type_name, branch_type_name, standalone,
119  linked_auxid);
120 }
121 
122 
123 std::string
124 getKeyFromBranch(TBranch* branch)
125 {
126  TClass *tc = nullptr;
127  EDataType type;
128  if( branch->GetExpectedType(tc, type) == 0 && tc ) {
129  std::string key = branch->GetName();
130  const std::string clname_pfx = std::string(tc->GetName()) + '_';
131  if( key.starts_with( clname_pfx ) ) {
132  key.erase(0, clname_pfx.size());
133  }
135  return key;
136  }
137  return "";
138 }
139 
140 } // anonymous namespace
141 
142 
144 {
145  if( needsSE ) {
146  if( (edtyp == kULong_t or edtyp == kULong64_t or edtyp == kLong_t or edtyp == kLong64_t) and
147  (SE_edt == kULong_t or SE_edt == kULong64_t or SE_edt == kLong_t or SE_edt == kLong64_t) and
148  sizeof(Long_t) == sizeof(Long64_t) ) {
149  // There is no need to attempt ROOT schema evolution between these types (and it will not work anyhow)
150  needsSE = false;
151  }
152  }
153  if( needsSE ) {
154  // reading through the TTree - allows for schema evolution
155  int rc = branch->GetTree()->SetBranchAddress( branch->GetName(), data, SE_tclass, SE_edt, true);
156  if( rc < 0 ) {
157  std::ostringstream msg;
158  msg << "SetBranchAddress() failed for " << branch->GetName() << " error=" << rc;
159  throw msg.str();
160  }
161  } else {
162  branch->SetAddress(data);
163  }
164 }
165 
166 
167 // ----------------- TBranchAuxDynReader ---------------------------------------
168 
169 // Fix Reader for a specific tree and branch base name.
170 // Find all dynamic attribute branches that share the base name
171 TBranchAuxDynReader::TBranchAuxDynReader(TTree *tree, TBranch *base_branch)
172  : m_baseBranchName( base_branch->GetName() ),
173  m_key( getKeyFromBranch(base_branch) ),
174  m_tree( tree )
175 {
176  // The Branch here is the object (AuxContainer) branch, not the attribute branch
177  TClass *tc = nullptr, *storeTC = nullptr;
178  EDataType type;
179  base_branch->GetExpectedType(tc, type); //MN: Errors would be coaught in isAuxDynBranch() earlier
180  if( tc ) storeTC = tc->GetBaseClass("SG::IAuxStoreHolder");
181  if( storeTC ) m_storeHolderOffset = tc->GetBaseClassOffset( storeTC );
182  if( m_storeHolderOffset < 0 ) {
183  const std::string name = (tc? tc->GetName() : m_baseBranchName);
184  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "TBranchAuxDynReader");
185  msg << "IAuxStoreHolder interface not found in " << name << " - will not read dynamic attributes";
186  }
187 
189  string branch_prefix = RootAuxDynIO::auxBranchName("", m_baseBranchName);
190  TObjArray *all_branches = m_tree->GetListOfBranches();
191  for( int i=0; i<all_branches->GetEntriesFast(); i++ ) {
192  const char *bname = (*all_branches)[i]->GetName();
193  if( strncmp(bname, branch_prefix.c_str(), branch_prefix.size()) == 0 ) {
194  const string attr_inFile = bname+branch_prefix.size();
195  const string attr = r.inputRename (m_key, attr_inFile);
196  m_branchMap[attr] = (TBranch*)(*all_branches)[i];
197  }
198  }
199 }
200 
201 
203  const std::string& attr,
204  TBranch* branch)
205 {
206  TClass* expectedClass = 0;
207  EDataType expectedType = kOther_t;
208  if( branch->GetExpectedType(expectedClass, expectedType) != 0) {
209  // raise hell
210  }
211 
212  SG::auxid_t linked_auxid = SG::null_auxid;
213  if (expectedClass) {
214  std::string className = expectedClass->GetName();
216  std::string linkedAttr = SG::AuxTypeRegistry::linkedName (attr);
217  auto it = m_branchMap.find (linkedAttr);
218  if (it != m_branchMap.end()) {
219  linked_auxid = initBranch (standalone, linkedAttr, it->second);
220  }
221  if (linked_auxid == SG::null_auxid) {
222  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "TBranchAuxDynReader::initBranch");
223  msg << "Could not find linked variable for " << branch->GetName()
224  << " type: " << expectedClass->GetName();
225  }
226  }
227  }
228 
229  SG::auxid_t auxid = getAuxIdForAttribute(attr, expectedClass, expectedType, standalone,
230  linked_auxid);
231 
232  // add AuxID to the list
233  // May still be null if we don't have a dictionary for the branch.
234  if (auxid != SG::null_auxid) {
235  addAuxID(auxid);
236  } else {
237  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "TBranchAuxDynReader::initBranch");
238  msg << "Could not find auxid for " << branch->GetName()
239  << " type: " << expectedClass->GetName();
240 
241  }
242  return auxid;
243 }
244 
245 // Has to be a separate method because 'standalone' status is not know at construction time
246 // Prepare all branch infos for dynamic attributes (auxids and types)
248 {
249  if( m_initialized ) return;
250 
251  for( const auto& attr2branch: m_branchMap ) {
252  initBranch (standalone, attr2branch.first, attr2branch.second);
253  }
254  m_initialized = true;
255 }
256 
257 // Called by the AuxStore when it is reading new attribute data from the file
258 // All information is cached in a BranchInfo object for better performance
261 {
262  BranchInfo& brInfo = m_branchInfos[auxid];
263  if( brInfo.status == BranchInfo::NotInitialized )
264  {
266  brInfo.auxid = auxid;
267  brInfo.attribName = r.getName(auxid);
268  // Don't match this attribute if it's been renamed.
269  // For example, suppose we've renamed attribute `foo' to `foo_old',
270  // and someone then comes and asks for `foo'.
271  // `foo' will not be found in the m_branchMap test below
272  // (`foo_old' will be in this map). However, in the following
273  // else clause, we'll recreate the branch name from `foo'.
274  // This branch exists (renaming is only in the transient store),
275  // so if we didn't have the condition here, then we'd then
276  // make a `foo' attribute from that branch.
277  if (r.inputRename (m_key, brInfo.attribName) != brInfo.attribName) {
278  brInfo.status = BranchInfo::NotFound;
279  return brInfo;
280  }
281 
282  auto it = m_branchMap.find (brInfo.attribName);
283  if (it != m_branchMap.end()) {
284  brInfo.branch = it->second;
285  }
286  else {
287  const string aux_branch_name = RootAuxDynIO::auxBranchName(brInfo.attribName, m_baseBranchName);
288  brInfo.branch = m_tree->GetBranch( aux_branch_name.c_str() );
289  }
290 
291  // mark initialized here so it remembers this branch was not found
292  if( !brInfo.branch ) {
293  brInfo.status = BranchInfo::NotFound;
294  return brInfo;
295  }
296  if( brInfo.branch->GetExpectedType( brInfo.tclass, brInfo.edtyp) ) {
297  brInfo.status = BranchInfo::TypeError;
298  throw string("Error getting branch type for ") + brInfo.branch->GetName();
299  }
300 
301  if( !store.standalone() )
302  if( brInfo.tclass && strncmp( brInfo.tclass->GetName(), "SG::PackedContainer<", 20) == 0)
303  brInfo.isPackedContainer = true;
304 
305  string elem_tname, branch_tname;
306  // AuxElement TypeID
307  const std::type_info* ti = getAuxElementType( brInfo.tclass, brInfo.edtyp, store.standalone(),
308  elem_tname, branch_tname );
309  const std::type_info* reg_ti = r.getType(auxid);
310  // I/O / Storage TypeID
311  const std::type_info *io_tinf = store.getIOType(auxid);
312  const std::type_info *tcls_tinf = brInfo.tclass ? brInfo.tclass->GetTypeInfo() : ti;
313 
314  if (not io_tinf){
315  brInfo.status = BranchInfo::TypeError;
316  throw string("Error getting IO type for AUX branch ") + brInfo.branch->GetName();
317  }
318  // if there is a TClass compare the whole storage types (usually vectors), because the Element type
319  // returned by CollProxy loses the pointer component and element type comparison for vector<T*> fails
320  brInfo.needsSE = brInfo.tclass ?
321  io_tinf != tcls_tinf && (!tcls_tinf || strcmp(io_tinf->name(), tcls_tinf->name()) != 0)
322  : ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0;
323  if( brInfo.needsSE ) {
324  // type in registry is different than type in the file.
325  // will need to use ROOT auto schema evolution
326  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "TBranchAuxDynReader");
327  msg << "attribute '" << brInfo.attribName << "' (id=" << auxid
328  << " typename=" << SG::normalizedTypeinfoName(*reg_ti)
329  << ") has different type than the branch: " << branch_tname;
330  msg << " Marking for schema evolution.";
331 
332  brInfo.SE_tclass = TClass::GetClass(*io_tinf);
333  brInfo.SE_edt = kOther_t;
334  if( !brInfo.SE_tclass ) {
335  brInfo.SE_edt = TDataType::GetType(*io_tinf);
336  if( brInfo.SE_edt <=0 ) {
337  brInfo.status = BranchInfo::TypeError;
338  throw string("Error getting ROOT type for AUX branch ") + brInfo.branch->GetName()
339  + " typeinfo=" + io_tinf->name();
340  }
341  }
342  }
344  }
345  return brInfo;
346 }
347 
348 
349 void TBranchAuxDynReader::addReaderToObject(void* object, size_t ttree_row, std::recursive_mutex* iomtx)
350 {
351  if( m_storeHolderOffset >= 0 ) {
352  auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset);
353  bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore };
354  if( !m_initialized )
355  init(standalone);
356  store_holder->setStore( new TBranchAuxDynStore(*this, ttree_row, standalone, iomtx) );
357  }
358 }
SGTest::store
TestStore store
Definition: TestStore.cxx:23
TBranchAuxDynReader::initBranch
SG::auxid_t initBranch(bool standalone, const std::string &attr, TBranch *branch)
Definition: TBranchAuxDynReader.cxx:202
beamspotman.r
def r
Definition: beamspotman.py:676
TBranchAuxDynReader::BranchInfo::Initialized
@ Initialized
Definition: TBranchAuxDynReader.h:25
TBranchAuxDynReader::BranchInfo::SE_tclass
TClass * SE_tclass
Definition: TBranchAuxDynReader.h:33
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
IAuxStoreHolder.h
TBranchAuxDynReader::m_branchInfos
std::map< SG::auxid_t, BranchInfo > m_branchInfos
Definition: TBranchAuxDynReader.h:66
TBranchAuxDynReader::BranchInfo
Definition: TBranchAuxDynReader.h:24
L1CaloPhase1Monitoring.standalone
standalone
Definition: L1CaloPhase1Monitoring.py:120
SG::AuxTypeRegistry::instance
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Definition: AuxTypeRegistry.cxx:639
TBranchAuxDynReader::BranchInfo::branch
TBranch * branch
Definition: TBranchAuxDynReader.h:27
SG::normalizedTypeinfoName
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...
Definition: normalizedTypeinfoName.cxx:120
TrigInDetValidation_menu_test.tc
tc
Definition: TrigInDetValidation_menu_test.py:8
tree
TChain * tree
Definition: tile_monitor.h:30
TBranchAuxDynReader::init
void init(bool standalone)
Definition: TBranchAuxDynReader.cxx:247
exceptions.h
Exceptions that can be thrown from AthContainers.
skel.it
it
Definition: skel.GENtoEVGEN.py:407
TBranchAuxDynReader::BranchInfo::status
enum Status status
Definition: TBranchAuxDynReader.h:37
RootAuxDynIO::removeAuxPostfix
bool removeAuxPostfix(std::string &str)
if a string ends with AUX_POSTFIX then remove it
Definition: RootAuxDynDefs.h:49
TBranchAuxDynReader::BranchInfo::edtyp
EDataType edtyp
Definition: TBranchAuxDynReader.h:29
SG::AuxTypeRegistry::linkedName
static std::string linkedName(const std::string &name)
Given a variable name, return the name of the corresponding linked variable.
Definition: AuxTypeRegistry.cxx:1302
TBranchAuxDynReader::BranchInfo::auxid
SG::auxid_t auxid
Definition: TBranchAuxDynReader.h:39
TBranchAuxDynReader::BranchInfo::NotFound
@ NotFound
Definition: TBranchAuxDynReader.h:25
RootAuxDynIO::auxBranchName
std::string auxBranchName(const std::string &attr_name, const std::string &baseBranchName)
Construct branch name for a given dynamic attribute.
Definition: RootAuxDynDefs.h:60
errorcheck::ReportMessage
Helper class to use to report a message.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:173
TBranchAuxDynReader::BranchInfo::NotInitialized
@ NotInitialized
Definition: TBranchAuxDynReader.h:25
SG::AuxTypeRegistry::classNameHasLink
static bool classNameHasLink(const std::string &className)
Test to see if a class name corresponds to a class with a linked variable.
Definition: AuxTypeRegistry.cxx:1312
TBranchAuxDynReader::m_storeHolderOffset
int m_storeHolderOffset
Definition: TBranchAuxDynReader.h:58
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
TBranchAuxDynReader::BranchInfo::tclass
TClass * tclass
Definition: TBranchAuxDynReader.h:28
AuxDataOption.h
Hold information about an option setting request.
TBranchAuxDynReader::m_baseBranchName
std::string m_baseBranchName
Definition: TBranchAuxDynReader.h:56
TBranchAuxDynReader::BranchInfo::TypeError
@ TypeError
Definition: TBranchAuxDynReader.h:25
SG::AuxTypeRegistry
Handle mappings between names and auxid_t.
Definition: AuxTypeRegistry.h:61
SG::auxid_t
size_t auxid_t
Identifier for a particular aux data item.
Definition: AuxTypes.h:27
Type.h
Wrapper for ROOT types.
SG::getDynamicAuxID
SG::auxid_t getDynamicAuxID(const std::type_info &ti, const std::string &name, const std::string &elementTypeName, const std::string &branch_type_name, bool standalone, SG::auxid_t linked_auxid)
Find the auxid for a dynamic branch.
Definition: getDynamicAuxID.cxx:64
lumiFormat.i
int i
Definition: lumiFormat.py:85
TBranchAuxDynReader::TBranchAuxDynReader
TBranchAuxDynReader(TTree *tree, TBranch *base_branch)
Definition: TBranchAuxDynReader.cxx:171
TBranchAuxDynReader::BranchInfo::isPackedContainer
bool isPackedContainer
Definition: TBranchAuxDynReader.h:36
getDynamicAuxID.h
Find the auxid for a dynamic branch.
RootAuxDynIO::getKeyFromBranch
std::string getKeyFromBranch(TBranch *branch)
Exctract the Aux object SG Key from the branch name.
error.h
Helper for emitting error messages.
TBranchAuxDynReader::m_branchMap
std::map< std::string, TBranch * > m_branchMap
Definition: TBranchAuxDynReader.h:64
TBranchAuxDynReader::addReaderToObject
virtual void addReaderToObject(void *object, size_t ttree_row, std::recursive_mutex *iomtx=nullptr) override final
Attach specialized AuxStore for reading dynamic attributes.
Definition: TBranchAuxDynReader.cxx:349
TBranchAuxDynReader::BranchInfo::SE_edt
EDataType SE_edt
Definition: TBranchAuxDynReader.h:34
TBranchAuxDynReader::BranchInfo::needsSE
bool needsSE
Definition: TBranchAuxDynReader.h:32
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
TBranchAuxDynReader::m_initialized
bool m_initialized
Definition: TBranchAuxDynReader.h:59
TBranchAuxDynReader::BranchInfo::setAddress
void setAddress(void *data)
Definition: TBranchAuxDynReader.cxx:143
TBranchAuxDynReader::getBranchInfo
BranchInfo & getBranchInfo(const SG::auxid_t &auxid, const SG::AuxStoreInternal &store)
Definition: TBranchAuxDynReader.cxx:260
TBranchAuxDynReader::BranchInfo::attribName
std::string attribName
Definition: TBranchAuxDynReader.h:40
SG::AuxStoreInternal
An auxiliary data store that holds data internally.
Definition: AuxStoreInternal.h:43
TBranchAuxDynReader.h
RTTAlgmain.branch
branch
Definition: RTTAlgmain.py:61
RootAuxDynIO.h
AuxTypeRegistry.h
Handle mappings between names and auxid_t.
TBranchAuxDynReader::m_key
std::string m_key
Definition: TBranchAuxDynReader.h:60
RootUtils::Type
Wrapper for ROOT types.
Definition: Type.h:40
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
RootAuxDynReader::addAuxID
bool addAuxID(const SG::auxid_t &id)
Definition: RootAuxDynReader.h:60
TBranchAuxDynStore.h
TBranchAuxDynStore
Definition: TBranchAuxDynStore.h:21
TBranchAuxDynReader::m_tree
TTree * m_tree
Definition: TBranchAuxDynReader.h:62
SG::IAuxStoreHolder::AST_ObjectStore
@ AST_ObjectStore
The store describes a single object.
Definition: IAuxStoreHolder.h:67
SG::IAuxStoreHolder
Interface for objects taking part in direct ROOT I/O.
Definition: IAuxStoreHolder.h:36
ERRORCHECK_ARGS
#define ERRORCHECK_ARGS
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:323
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
LArL1Calo_ComputeHVCorr.className
className
Definition: LArL1Calo_ComputeHVCorr.py:135
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37