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 #if ROOT_VERSION_CODE < ROOT_VERSION( 6, 35, 0 )
27 namespace ROOT {
28  using ROOT::Experimental::RNTupleDescriptor;
29  using ROOT::Experimental::RFieldDescriptor;
30  using ROOT::Experimental::DescriptorId_t;
31  using ROOT::Experimental::kInvalidDescriptorId;
32 }
33 #endif
34 
35 namespace {
36 
50 const std::type_info*
51 getAuxElementType( bool standalone, std::string& elementTypeName, const std::string& storageTypeName)
52 {
53  if (standalone) {
54  elementTypeName = storageTypeName;
55  // Need to stay with 'long long' for [mc]eventNumber as defined in the EventInfo class
56  if( elementTypeName == "std::uint64_t") return &typeid(unsigned long long);
57  return RootUtils::Type(storageTypeName).getTypeInfo();
58  }
59 
60  // Not standalone - type should be a vector.
61  if( storageTypeName.rfind("vector<", 0) == 0
62  || storageTypeName.rfind("std::vector<", 0) == 0 ) {
63  const TClass *tclass = RootUtils::Type(storageTypeName).getClass();
64  if( !tclass ) return nullptr;
65  TVirtualCollectionProxy* proxy = tclass->GetCollectionProxy();
66  if( !proxy ) return nullptr;
67  if( proxy->GetValueClass() ) {
68  elementTypeName = proxy->GetValueClass()->GetName();
69  return proxy->GetValueClass()->GetTypeInfo();
70  }
71  RootUtils::Type elemtype( proxy->GetType() );
72  elementTypeName = elemtype.getTypeName();
73  return elemtype.getTypeInfo();
74  }
75  else
76  if( storageTypeName.rfind("SG::PackedContainer<", 0) == 0) {
77  elementTypeName.clear();
78  {
79  // Protect against data race inside TClassEdit.
80  // https://github.com/root-project/root/issues/10353
81  // Should be fixed in root 6.26.02.
82  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
83  TClassEdit::TSplitType split( storageTypeName.c_str() );
84  if( split.fElements.size() > 1 ) {
85  elementTypeName = split.fElements[1];
86  }
87  }
88  if( !elementTypeName.empty() ) {
89  return RootUtils::Type(elementTypeName).getTypeInfo();
90  }
91  }
92  return 0;
93 }
94 
95 
97 getAuxIdForAttribute(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 
106 getLinkedAuxId (const SG::AuxTypeRegistry& r,
107  const ROOT::RNTupleDescriptor& desc,
108  const std::string& field_prefix,
109  const std::string& attr_name,
110  const std::string& attr_type,
111  bool standalone)
112 {
113  SG::auxid_t linked_auxid = SG::null_auxid;
114  if (SG::AuxTypeRegistry::classNameHasLink (attr_type)) {
115  std::string linked_attr = SG::AuxTypeRegistry::linkedName (attr_name);
116  ROOT::DescriptorId_t did = desc.FindFieldId (field_prefix + linked_attr);
117  if (did != ROOT::kInvalidDescriptorId) {
118  const ROOT::RFieldDescriptor& linked_f = desc.GetFieldDescriptor (did);
119  linked_auxid = getAuxIdForAttribute (r, desc, field_prefix,
120  linked_attr, linked_f.GetTypeName(), standalone);
121  }
122  if (linked_auxid == SG::null_auxid) {
123  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader.cxx:getLinkedAuxId");
124  msg << "Could not find linked variable for " << attr_name
125  << " type: " << attr_type;
126  }
127  }
128  return linked_auxid;
129 }
130 
131 
133 getAuxIdForAttribute(const SG::AuxTypeRegistry& r,
134  const ROOT::RNTupleDescriptor& desc,
135  const std::string& field_prefix,
136  const std::string& attr_name,
137  const std::string& attr_type,
138  bool standalone)
139 {
140  SG::auxid_t auxid = r.findAuxID(attr_name);
141  if(auxid != SG::null_auxid)
142  return auxid;
143 
144  string element_type;
145  const std::type_info* ti = getAuxElementType(standalone, element_type, attr_type);
146  if( !ti )
147  return auxid;
148 
149  SG::auxid_t linked_auxid = getLinkedAuxId (r, desc, field_prefix, attr_name, attr_type, standalone);
150 
151  return SG::getDynamicAuxID (*ti, attr_name, element_type, attr_type, standalone, linked_auxid);
152 }
153 
154 } // anonymous namespace
155 
156 
157 namespace RootAuxDynIO
158 {
159  // New RNTupleReader for dynamic attributes of an AuxContainer-type object
160  // stored in the Field 'field_name'
161  RNTupleAuxDynReader::RNTupleAuxDynReader(const std::string& field_name,
162  const std::string& field_type,
163  ROOT::RNTupleReader* reader)
164  : AthMessaging( std::string("RNTupleAuxDynReader[")+field_name+"]" ),
165  m_storeFieldName( field_name ),
166  m_ntupleReader( reader )
167  {
168  const std::string field_prefix = field_type + "_";
169  if( m_storeFieldName.rfind( field_type, 0 ) != std::string::npos ) {
170  m_key = m_storeFieldName.substr( field_type.size()+1 );
171  }
172  else if( m_storeFieldName.ends_with( "Aux:" ) ) {
173  m_key = m_storeFieldName.substr( 0, m_storeFieldName.size() - 4 );
174  }
175  ATH_MSG_VERBOSE("field name=" << m_storeFieldName << " field_prefix=" << field_prefix << " key=" << m_key);
176  TClass *tc = TClass::GetClass( field_type.c_str() );
177  if( tc ) {
178  TClass *storeTC = tc->GetBaseClass("SG::IAuxStoreHolder");
179  if( storeTC ) {
180  m_storeHolderOffset = tc->GetBaseClassOffset( storeTC );
181  } else {
182  throw std::runtime_error(string("Class ") + tc->GetName() +" does not implement SG::IAuxStoreHolder");
183  }
184  } else {
185  throw std::runtime_error(string("Class ") + field_type +" could not be found");
186  }
187  }
188 
189 
190 // Has to be a separate method because 'standalone' status is not know at construction time
191 // Prepare all Field infos for dynamic attributes (auxids and types)
193  {
194  if( m_initialized ) return;
195 
197  const string field_prefix = RootAuxDynIO::auxFieldName("", m_storeFieldName);
198  const auto& desc = m_ntupleReader->GetDescriptor();
199  for( const auto &f : desc.GetTopLevelFields() ) {
200  const string field_name = f.GetFieldName();
201  if( field_name.starts_with(field_prefix) ) {
202  const string attr_infile = field_name.substr(field_prefix.size());
203  const string attr_name = reg.inputRename(m_key, attr_infile);
204  const string field_type = f.GetTypeName();
205 
206  SG::auxid_t auxid = getAuxIdForAttribute(reg, desc, field_prefix,
207  attr_name, field_type, standalone);
208  // add AuxID to the list
209  // May still be null if we don't have a dictionary for this field
210  if( auxid != SG::null_auxid ) {
211  addAuxID(auxid);
212  m_fieldInfos[auxid].fieldName = field_name;
213 #if ROOT_VERSION_CODE < ROOT_VERSION( 6, 35, 0 )
214  m_fieldInfos[auxid].view = m_ntupleReader->GetView<void>(field_name, nullptr);
215 #else
216  // Can't use type_info because of default template argument in DataVectors ATEAM-1087
217  const std::string& tiname = (standalone and !reg.isLinked(auxid))? reg.getTypeName(auxid) : reg.getVecTypeName(auxid);
218  m_fieldInfos[auxid].view = m_ntupleReader->GetView(field_name, nullptr, tiname);
219 #endif
220  } else {
221  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader::init");
222  msg << "Could not find auxid for " << attr_infile << " type: " << field_type
223  << " standalone=" << standalone;
224  }
225  }
226  }
227  m_initialized = true;
228  }
229 
230 // Called by the AuxStore when it is reading new attribute data from the file
231 // All information is cached in a FieldInfo object for better performance
234  {
235  FieldInfo& fieldInfo = m_fieldInfos[auxid];
236  if( fieldInfo.status == FieldInfo::NotInitialized )
237  {
239  fieldInfo.auxid = auxid;
240  fieldInfo.attribName = reg.getName(auxid);
241  // Don't match this attribute if it's been renamed.
242  // For example, suppose we've renamed attribute `foo' to `foo_old',
243  // and someone then comes and asks for `foo'.
244  // `foo' will not be found in the m_fieldMap test below
245  // (`foo_old' will be in this map). However, in the following
246  // else clause, we'll recreate the field name from `foo'.
247  // This field exists (renaming is only in the transient store),
248  // so if we didn't have the condition here, then we'd then
249  // make a `foo' attribute from that field.
250  if( reg.inputRename(m_key, fieldInfo.attribName) != fieldInfo.attribName ) {
251  fieldInfo.status = FieldInfo::NotFound;
252  return fieldInfo;
253  }
254 
255  if( fieldInfo.fieldName.empty() ) {
256  // mark initialized here so it remembers this field was not found
257  fieldInfo.status = FieldInfo::NotFound;
258  return fieldInfo;
259  }
260 
261  if( !store.standalone() and fieldInfo.fieldName.rfind("SG::PackedContainer<", 0) == 0 )
262  fieldInfo.isPackedContainer = true;
263 
264  /*
265  string elem_tname, branch_tname;
266  const type_info* ti = getAuxElementType( fieldInfo.tclass, typ, store.standalone(),
267  elem_tname, branch_tname );
268  const type_info* reg_ti = reg.getType(auxid);
269  if( ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0 )
270  {
271  // type in registry is different than type in the file.
272  // will need to use ROOT auto schema evolution
273  fieldInfo.needsSE = true;
274  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "RNTupleAuxDynReader");
275  msg << "attribute " << fieldInfo.attribName << " (id=" << auxid <<
276  " typename=" << SG::AuxTypeRegistry::instance().getType(auxid)->name()
277  << ") has different type than the branch " << branch_tname;
278 
279  const std::type_info *tinf = store.getIOType(auxid);
280  fieldInfo.SE_tclass = TClass::GetClass(*tinf);
281  fieldInfo.SE_edt = kOther_t;
282  if( !fieldInfo.SE_tclass ) {
283  fieldInfo.SE_edt = TDataType::GetType(*tinf);
284  if( fieldInfo.SE_edt <=0 ) {
285  fieldInfo.status = FieldInfo::TypeError;
286  throw string("Error getting ROOT type for AUX branch ") + fieldInfo.branch->GetName()
287  + " typeinfo=" + tinf->name();
288  }
289  }
290  }
291  */
292  fieldInfo.status = FieldInfo::Initialized;
293  }
294  return fieldInfo;
295  }
296 
297 
298  void RNTupleAuxDynReader::addReaderToObject(void* object, size_t row, std::recursive_mutex* iomtx)
299  {
300  auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset);
301  bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore };
302  if( !m_initialized )
303  init(standalone);
304  store_holder->setStore( new RNTupleAuxDynStore(*this, row, standalone, iomtx) );
305  }
306 
307 }// namespace
SGTest::store
TestStore store
Definition: TestStore.cxx:23
beamspotman.r
def r
Definition: beamspotman.py:674
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:639
RootAuxDynIO::RNTupleAuxDynReader::m_storeHolderOffset
int m_storeHolderOffset
Definition: RNTupleAuxDynReader.h:71
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo
Definition: RNTupleAuxDynReader.h:35
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::Initialized
@ Initialized
Definition: RNTupleAuxDynReader.h:36
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:161
SG::AuxTypeRegistry::getName
std::string getName(SG::auxid_t auxid) const
Return the name of an aux data item.
Definition: AuxTypeRegistry.cxx:881
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:951
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:1273
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:1302
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
RootAuxDynIO::RNTupleAuxDynReader::m_key
std::string m_key
Definition: RNTupleAuxDynReader.h:73
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:1312
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:298
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::NotFound
@ NotFound
Definition: RNTupleAuxDynReader.h:36
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:46
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:923
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::fieldName
std::string fieldName
Definition: RNTupleAuxDynReader.h:47
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::auxid
SG::auxid_t auxid
Definition: RNTupleAuxDynReader.h:45
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:43
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:233
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:192
RootAuxDynIO::RNTupleAuxDynReader::m_initialized
bool m_initialized
Definition: RNTupleAuxDynReader.h:72
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:41
RootAuxDynIO::RNTupleAuxDynReader::m_fieldInfos
std::map< SG::auxid_t, FieldInfo > m_fieldInfos
Definition: RNTupleAuxDynReader.h:76
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:79
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:36
RootAuxDynReader::addAuxID
bool addAuxID(const SG::auxid_t &id)
Definition: RootAuxDynReader.h:60
RootAuxDynIO::RNTupleAuxDynReader::m_storeFieldName
std::string m_storeFieldName
Definition: RNTupleAuxDynReader.h:69
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
ROOT
Selection rules: declare transient members.
Definition: DataVector.h:580
Trk::split
@ split
Definition: LayerMaterialProperties.h:38