ATLAS Offline Software
RNTupleAuxDynReader.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 "RNTupleAuxDynReader.h"
14 #include "RNTupleAuxDynStore.h"
15 
16 #include "TClass.h"
17 #include "TClassEdit.h"
18 #include "TVirtualCollectionProxy.h"
19 
20 #include "ROOT/RNTuple.hxx"
21 #include "ROOT/RNTupleReader.hxx"
22 #include "ROOT/RField.hxx"
23 
24 using std::string;
25 
26 namespace {
27 
41 const std::type_info*
42 getAuxElementType( bool standalone, std::string& elementTypeName, const std::string& storageTypeName)
43 {
44  if (standalone) {
45  elementTypeName = storageTypeName;
46  // Need to stay with 'long long' for [mc]eventNumber as defined in the EventInfo class
47  if( elementTypeName == "std::uint64_t") return &typeid(unsigned long long);
48  return RootUtils::Type(storageTypeName).getTypeInfo();
49  }
50 
51  // Not standalone - type should be a vector.
52  if( storageTypeName.rfind("vector<", 0) == 0
53  || storageTypeName.rfind("std::vector<", 0) == 0 ) {
54  const TClass *tclass = RootUtils::Type(storageTypeName).getClass();
55  if( !tclass ) return nullptr;
56  TVirtualCollectionProxy* proxy = tclass->GetCollectionProxy();
57  if( !proxy ) return nullptr;
58  if( proxy->GetValueClass() ) {
59  elementTypeName = proxy->GetValueClass()->GetName();
60  return proxy->GetValueClass()->GetTypeInfo();
61  }
62  RootUtils::Type elemtype( proxy->GetType() );
63  elementTypeName = elemtype.getTypeName();
64  return elemtype.getTypeInfo();
65  }
66  else
67  if( storageTypeName.rfind("SG::PackedContainer<", 0) == 0) {
68  elementTypeName.clear();
69  {
70  // Protect against data race inside TClassEdit.
71  // https://github.com/root-project/root/issues/10353
72  // Should be fixed in root 6.26.02.
73  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
74  TClassEdit::TSplitType split( storageTypeName.c_str() );
75  if( split.fElements.size() > 1 ) {
76  elementTypeName = split.fElements[1];
77  }
78  }
79  if( !elementTypeName.empty() ) {
80  return RootUtils::Type(elementTypeName).getTypeInfo();
81  }
82  }
83  return 0;
84 }
85 
86 
88 getAuxIdForAttribute(const SG::AuxTypeRegistry& r,
89  const ROOT::RNTupleDescriptor& desc,
90  const std::string& field_prefix,
91  const std::string& attr_name,
92  const std::string& attr_type,
93  bool standalone);
94 
95 
97 getLinkedAuxId (const SG::AuxTypeRegistry& r,
98  const ROOT::RNTupleDescriptor& desc,
99  const std::string& field_prefix,
100  const std::string& attr_name,
101  const std::string& attr_type,
102  bool standalone)
103 {
104  SG::auxid_t linked_auxid = SG::null_auxid;
105  if (SG::AuxTypeRegistry::classNameHasLink (attr_type)) {
106  std::string linked_attr = SG::AuxTypeRegistry::linkedName (attr_name);
107  ROOT::DescriptorId_t did = desc.FindFieldId (field_prefix + linked_attr);
108  if (did != ROOT::kInvalidDescriptorId) {
109  const ROOT::RFieldDescriptor& linked_f = desc.GetFieldDescriptor (did);
110  linked_auxid = getAuxIdForAttribute (r, desc, field_prefix,
111  linked_attr, linked_f.GetTypeName(), standalone);
112  }
113  if (linked_auxid == SG::null_auxid) {
114  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader.cxx:getLinkedAuxId");
115  msg << "Could not find linked variable for " << attr_name
116  << " type: " << attr_type;
117  }
118  }
119  return linked_auxid;
120 }
121 
122 
124 getAuxIdForAttribute(const SG::AuxTypeRegistry& r,
125  const ROOT::RNTupleDescriptor& desc,
126  const std::string& field_prefix,
127  const std::string& attr_name,
128  const std::string& attr_type,
129  bool standalone)
130 {
131  SG::auxid_t auxid = r.findAuxID(attr_name);
132  if(auxid != SG::null_auxid)
133  return auxid;
134 
135  string element_type;
136  const std::type_info* ti = getAuxElementType(standalone, element_type, attr_type);
137  if( !ti )
138  return auxid;
139 
140  SG::auxid_t linked_auxid = getLinkedAuxId (r, desc, field_prefix, attr_name, attr_type, standalone);
141 
142  return SG::getDynamicAuxID (*ti, attr_name, element_type, attr_type, standalone, linked_auxid);
143 }
144 
145 } // anonymous namespace
146 
147 
148 namespace RootAuxDynIO
149 {
150  // New RNTupleReader for dynamic attributes of an AuxContainer-type object
151  // stored in the Field 'field_name'
152  RNTupleAuxDynReader::RNTupleAuxDynReader(const std::string& field_name,
153  const std::string& field_type,
154  ROOT::RNTupleReader* reader)
155  : AthMessaging( std::string("RNTupleAuxDynReader[")+field_name+"]" ),
156  m_storeFieldName( field_name ),
157  m_ntupleReader( reader )
158  {
159  const std::string field_prefix = field_type + "_";
160  if( m_storeFieldName.rfind( field_type, 0 ) != std::string::npos ) {
161  m_key = m_storeFieldName.substr( field_type.size()+1 );
162  }
163  else if( m_storeFieldName.ends_with( "Aux:" ) ) {
164  m_key = m_storeFieldName.substr( 0, m_storeFieldName.size() - 4 );
165  }
166  ATH_MSG_VERBOSE("field name=" << m_storeFieldName << " field_prefix=" << field_prefix << " key=" << m_key);
167  TClass *tc = TClass::GetClass( field_type.c_str() );
168  if( tc ) {
169  TClass *storeTC = tc->GetBaseClass("SG::IAuxStoreHolder");
170  if( storeTC ) {
171  m_storeHolderOffset = tc->GetBaseClassOffset( storeTC );
172  } else {
173  throw std::runtime_error(string("Class ") + tc->GetName() +" does not implement SG::IAuxStoreHolder");
174  }
175  } else {
176  throw std::runtime_error(string("Class ") + field_type +" could not be found");
177  }
178  }
179 
180 
181 // Has to be a separate method because 'standalone' status is not know at construction time
182 // Prepare all Field infos for dynamic attributes (auxids and types)
184  {
185  if( m_initialized ) return;
186 
188  const string field_prefix = RootAuxDynIO::auxFieldName("", m_storeFieldName);
189  const auto& desc = m_ntupleReader->GetDescriptor();
190  for( const auto &f : desc.GetTopLevelFields() ) {
191  const string field_name = f.GetFieldName();
192  if( field_name.starts_with(field_prefix) ) {
193  const string attr_infile = field_name.substr(field_prefix.size());
194  const string attr_name = reg.inputRename(m_key, attr_infile);
195  const string field_type = f.GetTypeName();
196 
197  SG::auxid_t auxid = getAuxIdForAttribute(reg, desc, field_prefix,
198  attr_name, field_type, standalone);
199  // add AuxID to the list
200  // May still be null if we don't have a dictionary for this field
201  if( auxid != SG::null_auxid ) {
202  addAuxID(auxid);
203  m_fieldInfos[auxid].fieldName = field_name;
204  // Can't use type_info because of default template argument in DataVectors ATEAM-1087
205  const std::string& tiname = (standalone and !reg.isLinked(auxid))? reg.getTypeName(auxid) : reg.getVecTypeName(auxid);
206  m_fieldInfos[auxid].view = m_ntupleReader->GetView(field_name, nullptr, tiname);
207  } else {
208  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader::init");
209  msg << "Could not find auxid for " << attr_infile << " type: " << field_type
210  << " standalone=" << standalone;
211  }
212  }
213  }
214  m_initialized = true;
215  }
216 
217 // Called by the AuxStore when it is reading new attribute data from the file
218 // All information is cached in a FieldInfo object for better performance
221  {
222  FieldInfo& fieldInfo = m_fieldInfos[auxid];
223  if( fieldInfo.status == FieldInfo::NotInitialized )
224  {
226  fieldInfo.auxid = auxid;
227  fieldInfo.attribName = reg.getName(auxid);
228  // Don't match this attribute if it's been renamed.
229  // For example, suppose we've renamed attribute `foo' to `foo_old',
230  // and someone then comes and asks for `foo'.
231  // `foo' will not be found in the m_fieldMap test below
232  // (`foo_old' will be in this map). However, in the following
233  // else clause, we'll recreate the field name from `foo'.
234  // This field exists (renaming is only in the transient store),
235  // so if we didn't have the condition here, then we'd then
236  // make a `foo' attribute from that field.
237  if( reg.inputRename(m_key, fieldInfo.attribName) != fieldInfo.attribName ) {
238  fieldInfo.status = FieldInfo::NotFound;
239  return fieldInfo;
240  }
241 
242  if( fieldInfo.fieldName.empty() ) {
243  // mark initialized here so it remembers this field was not found
244  fieldInfo.status = FieldInfo::NotFound;
245  return fieldInfo;
246  }
247 
248  if( !store.standalone() and fieldInfo.fieldName.rfind("SG::PackedContainer<", 0) == 0 )
249  fieldInfo.isPackedContainer = true;
250 
251  /*
252  string elem_tname, branch_tname;
253  const type_info* ti = getAuxElementType( fieldInfo.tclass, typ, store.standalone(),
254  elem_tname, branch_tname );
255  const type_info* reg_ti = reg.getType(auxid);
256  if( ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0 )
257  {
258  // type in registry is different than type in the file.
259  // will need to use ROOT auto schema evolution
260  fieldInfo.needsSE = true;
261  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "RNTupleAuxDynReader");
262  msg << "attribute " << fieldInfo.attribName << " (id=" << auxid <<
263  " typename=" << SG::AuxTypeRegistry::instance().getType(auxid)->name()
264  << ") has different type than the branch " << branch_tname;
265 
266  const std::type_info *tinf = store.getIOType(auxid);
267  fieldInfo.SE_tclass = TClass::GetClass(*tinf);
268  fieldInfo.SE_edt = kOther_t;
269  if( !fieldInfo.SE_tclass ) {
270  fieldInfo.SE_edt = TDataType::GetType(*tinf);
271  if( fieldInfo.SE_edt <=0 ) {
272  fieldInfo.status = FieldInfo::TypeError;
273  throw string("Error getting ROOT type for AUX branch ") + fieldInfo.branch->GetName()
274  + " typeinfo=" + tinf->name();
275  }
276  }
277  }
278  */
279  fieldInfo.status = FieldInfo::Initialized;
280  }
281  return fieldInfo;
282  }
283 
284 
285  void RNTupleAuxDynReader::addReaderToObject(void* object, size_t row, std::recursive_mutex* iomtx)
286  {
287  auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset);
288  bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore };
289  if( !m_initialized )
290  init(standalone);
291  store_holder->setStore( new RNTupleAuxDynStore(*this, row, standalone, iomtx) );
292  }
293 
294 }// namespace
SGTest::store
TestStore store
Definition: TestStore.cxx:23
beamspotman.r
def r
Definition: beamspotman.py:672
IAuxStoreHolder.h
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:407
RNTupleAuxDynStore
Definition: RNTupleAuxDynStore.h:19
L1CaloPhase1Monitoring.standalone
standalone
Definition: L1CaloPhase1Monitoring.py:139
SG::AuxTypeRegistry::instance
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Definition: AuxTypeRegistry.cxx:640
RootAuxDynIO::RNTupleAuxDynReader::m_storeHolderOffset
int m_storeHolderOffset
Definition: RNTupleAuxDynReader.h:63
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo
Definition: RNTupleAuxDynReader.h:27
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::Initialized
@ Initialized
Definition: RNTupleAuxDynReader.h:28
RootAuxDynIO::RNTupleAuxDynReader::RNTupleAuxDynReader
RNTupleAuxDynReader(const std::string &field_name, const std::string &field_type, ROOT::RNTupleReader *reader)
create Reader for Aux attributes of an AuxContainer object stored in a given field
Definition: RNTupleAuxDynReader.cxx:152
SG::AuxTypeRegistry::getName
std::string getName(SG::auxid_t auxid) const
Return the name of an aux data item.
Definition: AuxTypeRegistry.cxx:882
SG::AuxTypeRegistry::getVecTypeName
std::string getVecTypeName(SG::auxid_t auxid) const
Return the type of the STL vector used to hold an aux data item.
Definition: AuxTypeRegistry.cxx:952
exceptions.h
Exceptions that can be thrown from AthContainers.
SG::AuxTypeRegistry::inputRename
const std::string & inputRename(const std::string &key, const std::string &name) const
Check for an input renaming of an auxiliary variable.
Definition: AuxTypeRegistry.cxx:1274
keylayer_zslicemap.row
row
Definition: keylayer_zslicemap.py:155
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:1303
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
RootAuxDynIO::RNTupleAuxDynReader::m_key
std::string m_key
Definition: RNTupleAuxDynReader.h:65
errorcheck::ReportMessage
Helper class to use to report a message.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:173
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:1313
RootAuxDynIO::RNTupleAuxDynReader::addReaderToObject
virtual void addReaderToObject(void *object, size_t row, std::recursive_mutex *iomtx=nullptr) override final
attach RNTupleAuxStore to the current Aux container @object
Definition: RNTupleAuxDynReader.cxx:285
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::NotFound
@ NotFound
Definition: RNTupleAuxDynReader.h:28
AuxDataOption.h
Hold information about an option setting request.
SG::AuxTypeRegistry
Handle mappings between names and auxid_t.
Definition: AuxTypeRegistry.h:61
Type
RootType Type
Definition: TrigTSerializer.h:30
SG::auxid_t
size_t auxid_t
Identifier for a particular aux data item.
Definition: AuxTypes.h:27
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::attribName
std::string attribName
Definition: RNTupleAuxDynReader.h:38
CaloCondBlobAlgs_fillNoiseFromASCII.desc
desc
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:53
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
SG::AuxTypeRegistry::getTypeName
std::string getTypeName(SG::auxid_t auxid) const
Return the type name of an aux data item.
Definition: AuxTypeRegistry.cxx:924
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::fieldName
std::string fieldName
Definition: RNTupleAuxDynReader.h:39
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::auxid
SG::auxid_t auxid
Definition: RNTupleAuxDynReader.h:37
getDynamicAuxID.h
Find the auxid for a dynamic branch.
RootAuxDynIO::auxFieldName
std::string auxFieldName(const std::string &attr_name, const std::string &baseName)
Construct field name for a given dynamic attribute.
Definition: RootAuxDynDefs.h:69
error.h
Helper for emitting error messages.
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::status
enum Status status
Definition: RNTupleAuxDynReader.h:35
hist_file_dump.f
f
Definition: hist_file_dump.py:140
RootAuxDynIO::RNTupleAuxDynReader::getFieldInfo
FieldInfo & getFieldInfo(const SG::auxid_t &auxid, const SG::AuxStoreInternal &store)
get field informatino for auxid
Definition: RNTupleAuxDynReader.cxx:220
AthMessaging::msg
MsgStream & msg() const
The standard message stream.
Definition: AthMessaging.h:164
RootAuxDynIO::RNTupleAuxDynReader::init
void init(bool standalone)
initialize once the mode of the Aux store is known
Definition: RNTupleAuxDynReader.cxx:183
RootAuxDynIO::RNTupleAuxDynReader::m_initialized
bool m_initialized
Definition: RNTupleAuxDynReader.h:64
RNTupleAuxDynReader.h
SG::AuxTypeRegistry::isLinked
bool isLinked(SG::auxid_t auxid) const
Test whether this is a linked variable.
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::isPackedContainer
bool isPackedContainer
Definition: RNTupleAuxDynReader.h:33
RootAuxDynIO::RNTupleAuxDynReader::m_fieldInfos
std::map< SG::auxid_t, FieldInfo > m_fieldInfos
Definition: RNTupleAuxDynReader.h:68
RNTupleAuxDynStore.h
RootAuxDynIO
Specialization of RootAuxDynStore for reading Aux Dynamic attributes from RNTuple.
Definition: RNTupleContainer.h:28
SG::AuxStoreInternal
An auxiliary data store that holds data internally.
Definition: AuxStoreInternal.h:43
RootAuxDynIO::RNTupleAuxDynReader::m_ntupleReader
ROOT::RNTupleReader * m_ntupleReader
Definition: RNTupleAuxDynReader.h:71
AuxTypeRegistry.h
Handle mappings between names and auxid_t.
RootUtils::Type
Wrapper for ROOT types.
Definition: Type.h:40
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::NotInitialized
@ NotInitialized
Definition: RNTupleAuxDynReader.h:28
RootAuxDynReader::addAuxID
bool addAuxID(const SG::auxid_t &id)
Definition: RootAuxDynReader.h:60
RootAuxDynIO::RNTupleAuxDynReader::m_storeFieldName
std::string m_storeFieldName
Definition: RNTupleAuxDynReader.h:61
collisions.reader
reader
read the goodrunslist xml file(s)
Definition: collisions.py:22
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
Trk::split
@ split
Definition: LayerMaterialProperties.h:38