ATLAS Offline Software
TBranchAuxDynReader.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
10 #include "RootUtils/Type.h"
11 
12 #include "TBranchAuxDynReader.h"
13 #include "TBranchAuxDynStore.h"
15 
16 #include "TTree.h"
17 #include "TBranch.h"
18 #include "TClass.h"
19 #include "TClassTable.h"
20 #include "TClassEdit.h"
21 #include "TVirtualCollectionProxy.h"
22 #include "TROOT.h"
23 #include "TDictAttributeMap.h"
24 
25 using std::string;
26 
27 namespace {
28 
29 const std::type_info* dataTypeToTypeInfo (EDataType type, std::string& typeName)
30 {
31  RootUtils::Type typ (type);
32  typeName = typ.getTypeName();
33  return typ.getTypeInfo();
34 }
35 
36 
52 const std::type_info*
53 getAuxElementType( TClass *expectedClass, EDataType expectedType, bool standalone,
54  std::string& elementTypeName, std::string& storageTypeName)
55 {
56  if (standalone) {
57  if(expectedClass) {
58  elementTypeName = expectedClass->GetName();
59  storageTypeName = elementTypeName;
60  return expectedClass->GetTypeInfo();
61  }
62  const std::type_info* ret = dataTypeToTypeInfo(expectedType, elementTypeName);
63  storageTypeName = elementTypeName;
64  return ret;
65  }
66 
67  // Not standalone; branch should be a vector.
68  if (!expectedClass) return 0;
69 
70  storageTypeName = expectedClass->GetName();
71  if (strncmp (expectedClass->GetName(), "vector<", 7) == 0) {
72  TVirtualCollectionProxy* prox = expectedClass->GetCollectionProxy();
73  if (!prox) return 0;
74  if (prox->GetValueClass()) {
75  elementTypeName = prox->GetValueClass()->GetName();
76  return prox->GetValueClass()->GetTypeInfo();
77  }
78  return dataTypeToTypeInfo (prox->GetType(), elementTypeName);
79  }
80  else if (strncmp (expectedClass->GetName(), "SG::PackedContainer<", 20) == 0){
81  elementTypeName.clear();
82  {
83  // Protect against data race inside TClassEdit.
84  // https://github.com/root-project/root/issues/10353
85  // Should be fixed in root 6.26.02.
86  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
87  TClassEdit::TSplitType split (expectedClass->GetName());
88  if (split.fElements.size() > 1) {
89  elementTypeName = split.fElements[1];
90  }
91  }
92  if (!elementTypeName.empty()) {
93  RootUtils::Type typ (elementTypeName);
94  return typ.getTypeInfo();
95  }
96  }
97  return 0;
98 }
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 } // anonymous namespace
123 
124 
126 {
127  if( needsSE ) {
128  if( (edtyp == kULong_t or edtyp == kULong64_t or edtyp == kLong_t or edtyp == kLong64_t) and
129  (SE_edt == kULong_t or SE_edt == kULong64_t or SE_edt == kLong_t or SE_edt == kLong64_t) and
130  sizeof(Long_t) == sizeof(Long64_t) ) {
131  // There is no need to attempt ROOT schema evolution between these types (and it will not work anyhow)
132  needsSE = false;
133  }
134  }
135  if( needsSE ) {
136  // reading through the TTree - allows for schema evolution
137  int rc = branch->GetTree()->SetBranchAddress( branch->GetName(), data, SE_tclass, SE_edt, true);
138  if( rc < 0 ) {
139  std::ostringstream msg;
140  msg << "SetBranchAddress() failed for " << branch->GetName() << " error=" << rc;
141  throw msg.str();
142  }
143  } else {
144  branch->SetAddress(data);
145  }
146 }
147 
148 
149 // ----------------- TBranchAuxDynReader ---------------------------------------
150 
151 // Fix Reader for a specific tree and branch base name.
152 // Find all dynamic attribute branches that share the base name
153 TBranchAuxDynReader::TBranchAuxDynReader(TTree *tree, TBranch *base_branch)
154  : m_baseBranchName( base_branch->GetName() ),
155  m_key( RootAuxDynIO::getKeyFromBranch(base_branch) ),
156  m_tree( tree )
157 {
158  // The Branch here is the object (AuxContainer) branch, not the attribute branch
159  TClass *tc = nullptr, *storeTC = nullptr;
160  EDataType type;
161  base_branch->GetExpectedType(tc, type); //MN: Errors would be coaught in isAuxDynBranch() earlier
162  if( tc ) storeTC = tc->GetBaseClass("SG::IAuxStoreHolder");
163  if( storeTC ) m_storeHolderOffset = tc->GetBaseClassOffset( storeTC );
164  if( m_storeHolderOffset < 0 ) {
165  const std::string name = (tc? tc->GetName() : m_baseBranchName);
166  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "TBranchAuxDynReader");
167  msg << "IAuxStoreHolder interface not found in " << name << " - will not read dynamic attributes";
168  }
169 
171  string branch_prefix = RootAuxDynIO::auxBranchName("", m_baseBranchName);
172  TObjArray *all_branches = m_tree->GetListOfBranches();
173  for( int i=0; i<all_branches->GetEntriesFast(); i++ ) {
174  const char *bname = (*all_branches)[i]->GetName();
175  if( strncmp(bname, branch_prefix.c_str(), branch_prefix.size()) == 0 ) {
176  const string attr_inFile = bname+branch_prefix.size();
177  const string attr = r.inputRename (m_key, attr_inFile);
178  m_branchMap[attr] = (TBranch*)(*all_branches)[i];
179  }
180  }
181 }
182 
183 
185  const std::string& attr,
186  TBranch* branch)
187 {
188  TClass* expectedClass = 0;
189  EDataType expectedType = kOther_t;
190  if( branch->GetExpectedType(expectedClass, expectedType) != 0) {
191  // raise hell
192  }
193 
194  SG::auxid_t linked_auxid = SG::null_auxid;
195  if (expectedClass) {
196  std::string className = expectedClass->GetName();
198  std::string linkedAttr = SG::AuxTypeRegistry::linkedName (attr);
199  auto it = m_branchMap.find (linkedAttr);
200  if (it != m_branchMap.end()) {
201  linked_auxid = initBranch (standalone, linkedAttr, it->second);
202  }
203  if (linked_auxid == SG::null_auxid) {
204  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "TBranchAuxDynReader::initBranch");
205  msg << "Could not find linked variable for " << branch->GetName()
206  << " type: " << expectedClass->GetName();
207  }
208  }
209  }
210 
211  SG::auxid_t auxid = getAuxIdForAttribute(attr, expectedClass, expectedType, standalone,
212  linked_auxid);
213 
214  // add AuxID to the list
215  // May still be null if we don't have a dictionary for the branch.
216  if (auxid != SG::null_auxid) {
217  m_auxids.insert(auxid);
218  } else {
219  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "TBranchAuxDynReader::initBranch");
220  msg << "Could not find auxid for " << branch->GetName()
221  << " type: " << expectedClass->GetName();
222 
223  }
224  return auxid;
225 }
226 
227 // Has to be a separate method because 'standalone' status is not know at construction time
228 // Prepare all branch infos for dynamic attributes (auxids and types)
229 void TBranchAuxDynReader::init(bool standalone)
230 {
231  if( m_initialized ) return;
232 
233  for( const auto& attr2branch: m_branchMap ) {
234  initBranch (standalone, attr2branch.first, attr2branch.second);
235  }
236  m_initialized = true;
237 }
238 
239 // Called by the AuxStore when it is reading new attribute data from the file
240 // All information is cached in a BranchInfo object for better performance
243 {
244  BranchInfo& brInfo = m_branchInfos[auxid];
245  if( brInfo.status == BranchInfo::NotInitialized )
246  {
248  brInfo.auxid = auxid;
249  brInfo.attribName = r.getName(auxid);
250  // Don't match this attribute if it's been renamed.
251  // For example, suppose we've renamed attribute `foo' to `foo_old',
252  // and someone then comes and asks for `foo'.
253  // `foo' will not be found in the m_branchMap test below
254  // (`foo_old' will be in this map). However, in the following
255  // else clause, we'll recreate the branch name from `foo'.
256  // This branch exists (renaming is only in the transient store),
257  // so if we didn't have the condition here, then we'd then
258  // make a `foo' attribute from that branch.
259  if (r.inputRename (m_key, brInfo.attribName) != brInfo.attribName) {
260  brInfo.status = BranchInfo::NotFound;
261  return brInfo;
262  }
263 
264  auto it = m_branchMap.find (brInfo.attribName);
265  if (it != m_branchMap.end()) {
266  brInfo.branch = it->second;
267  }
268  else {
269  const string aux_branch_name = RootAuxDynIO::auxBranchName(brInfo.attribName, m_baseBranchName);
270  brInfo.branch = m_tree->GetBranch( aux_branch_name.c_str() );
271  }
272 
273  // mark initialized here so it remembers this branch was not found
274  if( !brInfo.branch ) {
275  brInfo.status = BranchInfo::NotFound;
276  return brInfo;
277  }
278  if( brInfo.branch->GetExpectedType( brInfo.tclass, brInfo.edtyp) ) {
279  brInfo.status = BranchInfo::TypeError;
280  throw string("Error getting branch type for ") + brInfo.branch->GetName();
281  }
282 
283  if( !store.standalone() )
284  if( brInfo.tclass && strncmp( brInfo.tclass->GetName(), "SG::PackedContainer<", 20) == 0)
285  brInfo.isPackedContainer = true;
286 
287  string elem_tname, branch_tname;
288  // AuxElement TypeID
289  const std::type_info* ti = getAuxElementType( brInfo.tclass, brInfo.edtyp, store.standalone(),
290  elem_tname, branch_tname );
291  const std::type_info* reg_ti = r.getType(auxid);
292  // I/O / Storage TypeID
293  const std::type_info *io_tinf = store.getIOType(auxid);
294  const std::type_info *tcls_tinf = brInfo.tclass ? brInfo.tclass->GetTypeInfo() : ti;
295 
296  if (not io_tinf){
297  brInfo.status = BranchInfo::TypeError;
298  throw string("Error getting IO type for AUX branch ") + brInfo.branch->GetName();
299  }
300  // if there is a TClass compare the whole storage types (usually vectors), because the Element type
301  // returned by CollProxy loses the pointer component and element type comparison for vector<T*> fails
302  brInfo.needsSE = brInfo.tclass ?
303  io_tinf != tcls_tinf && (!tcls_tinf || strcmp(io_tinf->name(), tcls_tinf->name()) != 0)
304  : ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0;
305  if( brInfo.needsSE ) {
306  // type in registry is different than type in the file.
307  // will need to use ROOT auto schema evolution
308  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "TBranchAuxDynReader");
309  msg << "attribute '" << brInfo.attribName << "' (id=" << auxid
310  << " typename=" << SG::normalizedTypeinfoName(*reg_ti)
311  << ") has different type than the branch: " << branch_tname;
312  msg << " Marking for schema evolution.";
313 
314  brInfo.SE_tclass = TClass::GetClass(*io_tinf);
315  brInfo.SE_edt = kOther_t;
316  if( !brInfo.SE_tclass ) {
317  brInfo.SE_edt = TDataType::GetType(*io_tinf);
318  if( brInfo.SE_edt <=0 ) {
319  brInfo.status = BranchInfo::TypeError;
320  throw string("Error getting ROOT type for AUX branch ") + brInfo.branch->GetName()
321  + " typeinfo=" + io_tinf->name();
322  }
323  }
324  }
326  }
327  return brInfo;
328 }
329 
330 
331 void TBranchAuxDynReader::addReaderToObject(void* object, size_t ttree_row, std::recursive_mutex* iomtx)
332 {
333  if( m_storeHolderOffset >= 0 ) {
334  auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset);
335  bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore };
336  if( !m_initialized )
337  init(standalone);
338  store_holder->setStore( new TBranchAuxDynStore(*this, ttree_row, standalone, iomtx) );
339  }
340 }
TBranchAuxDynReader::initBranch
SG::auxid_t initBranch(bool standalone, const std::string &attr, TBranch *branch)
Definition: TBranchAuxDynReader.cxx:184
beamspotman.r
def r
Definition: beamspotman.py:676
store
StoreGateSvc * store
Definition: fbtTestBasics.cxx:69
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
SG::IAuxStoreHolder::getStoreType
virtual AuxStoreType getStoreType() const =0
Return the type of the store object.
TBranchAuxDynReader::m_branchInfos
std::map< SG::auxid_t, BranchInfo > m_branchInfos
Definition: TBranchAuxDynReader.h:79
TBranchAuxDynReader::BranchInfo
Definition: TBranchAuxDynReader.h:24
SG::AuxTypeRegistry::instance
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Definition: AuxTypeRegistry.cxx:49
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
tree
TChain * tree
Definition: tile_monitor.h:30
TBranchAuxDynReader::init
void init(bool standalone)
Definition: TBranchAuxDynReader.cxx:229
exceptions.h
Exceptions that can be thrown from AthContainers.
skel.it
it
Definition: skel.GENtoEVGEN.py:423
TBranchAuxDynReader::BranchInfo::status
enum Status status
Definition: TBranchAuxDynReader.h:37
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:979
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:46
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:989
TBranchAuxDynReader::m_storeHolderOffset
int m_storeHolderOffset
Definition: TBranchAuxDynReader.h:71
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:67
TBranchAuxDynReader::BranchInfo::TypeError
@ TypeError
Definition: TBranchAuxDynReader.h:25
SG::AuxTypeRegistry
Handle mappings between names and auxid_t.
Definition: AuxTypeRegistry.h:62
JetTagCalibConfig.className
string className
Definition: JetTagCalibConfig.py:31
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:92
CxxUtils::ConcurrentBitset::insert
ConcurrentBitset & insert(bit_t bit, bit_t new_nbits=0)
Set a bit to 1.
TBranchAuxDynReader::TBranchAuxDynReader
TBranchAuxDynReader(TTree *tree, TBranch *base_branch)
Definition: TBranchAuxDynReader.cxx:153
ret
T ret(T t)
Definition: rootspy.cxx:260
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.
Definition: RootAuxDynIO.cxx:40
error.h
Helper for emitting error messages.
TBranchAuxDynReader::m_branchMap
std::map< std::string, TBranch * > m_branchMap
Definition: TBranchAuxDynReader.h:77
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:331
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:195
TBranchAuxDynReader::m_initialized
bool m_initialized
Definition: TBranchAuxDynReader.h:72
TBranchAuxDynReader::BranchInfo::setAddress
void setAddress(void *data)
Definition: TBranchAuxDynReader.cxx:125
TBranchAuxDynReader::getBranchInfo
BranchInfo & getBranchInfo(const SG::auxid_t &auxid, const SG::AuxStoreInternal &store)
Definition: TBranchAuxDynReader.cxx:242
RootAuxDynIO
Specialization of RootAuxDynStore for reading Aux Dynamic attributes from RNTuple.
Definition: RNTupleContainer.h:25
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
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
AuxTypeRegistry.h
Handle mappings between names and auxid_t.
TBranchAuxDynReader::m_key
std::string m_key
Definition: TBranchAuxDynReader.h:73
RootUtils::Type
Wrapper for ROOT types.
Definition: Type.h:40
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
TBranchAuxDynStore.h
TBranchAuxDynStore
Definition: TBranchAuxDynStore.h:21
TBranchAuxDynReader::m_tree
TTree * m_tree
Definition: TBranchAuxDynReader.h:75
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
TBranchAuxDynReader::m_auxids
SG::auxid_set_t m_auxids
Definition: TBranchAuxDynReader.h:65
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Trk::split
@ split
Definition: LayerMaterialProperties.h:38