Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
10 #include "RootUtils/Type.h"
11 
12 #include "RNTupleAuxDynReader.h"
13 #include "RNTupleAuxDynStore.h"
15 
16 #include "TClass.h"
17 #include "TClassEdit.h"
18 #include "TVirtualCollectionProxy.h"
19 #include "TROOT.h"
20 
21 #include "ROOT/RNTuple.hxx"
22 #include "ROOT/RNTupleReader.hxx"
23 #include "ROOT/RField.hxx"
24 
25 using std::string;
26 
27 #if ROOT_VERSION_CODE >= ROOT_VERSION( 6, 35, 0 )
28  using ROOT::RNTupleDescriptor;
29  using ROOT::RFieldDescriptor;
30  using ROOT::DescriptorId_t;
31  using ROOT::kInvalidDescriptorId;
32 #else
33  using ROOT::Experimental::RNTupleDescriptor;
34  using ROOT::Experimental::RFieldDescriptor;
35  using ROOT::Experimental::DescriptorId_t;
36  using ROOT::Experimental::kInvalidDescriptorId;
37 #endif
38 
39 namespace {
40 
54 const std::type_info*
55 getAuxElementType( bool standalone, std::string& elementTypeName, const std::string& storageTypeName)
56 {
57  if (standalone) {
58  elementTypeName = storageTypeName;
59  // Need to stay with 'long long' for [mc]eventNumber as defined in the EventInfo class
60  if( elementTypeName == "std::uint64_t") return &typeid(unsigned long long);
61  return RootUtils::Type(storageTypeName).getTypeInfo();
62  }
63 
64  // Not standalone - type should be a vector.
65  if( storageTypeName.rfind("vector<", 0) == 0
66  || storageTypeName.rfind("std::vector<", 0) == 0 ) {
67  const TClass *tclass = RootUtils::Type(storageTypeName).getClass();
68  if( !tclass ) return nullptr;
69  TVirtualCollectionProxy* proxy = tclass->GetCollectionProxy();
70  if( !proxy ) return nullptr;
71  if( proxy->GetValueClass() ) {
72  elementTypeName = proxy->GetValueClass()->GetName();
73  return proxy->GetValueClass()->GetTypeInfo();
74  }
75  RootUtils::Type elemtype( proxy->GetType() );
76  elementTypeName = elemtype.getTypeName();
77  return elemtype.getTypeInfo();
78  }
79  else
80  if( storageTypeName.rfind("SG::PackedContainer<", 0) == 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( storageTypeName.c_str() );
88  if( split.fElements.size() > 1 ) {
89  elementTypeName = split.fElements[1];
90  }
91  }
92  if( !elementTypeName.empty() ) {
93  return RootUtils::Type(elementTypeName).getTypeInfo();
94  }
95  }
96  return 0;
97 }
98 
99 
101 getAuxIdForAttribute(const SG::AuxTypeRegistry& r,
102  const RNTupleDescriptor& desc,
103  const std::string& field_prefix,
104  const std::string& attr_name,
105  const std::string& attr_type,
106  bool standalone);
107 
108 
110 getLinkedAuxId (const SG::AuxTypeRegistry& r,
111  const RNTupleDescriptor& desc,
112  const std::string& field_prefix,
113  const std::string& attr_name,
114  const std::string& attr_type,
115  bool standalone)
116 {
117  SG::auxid_t linked_auxid = SG::null_auxid;
118  if (SG::AuxTypeRegistry::classNameHasLink (attr_type)) {
119  std::string linked_attr = SG::AuxTypeRegistry::linkedName (attr_name);
120  DescriptorId_t did = desc.FindFieldId (field_prefix + linked_attr);
121  if (did != kInvalidDescriptorId) {
122  const RFieldDescriptor& linked_f = desc.GetFieldDescriptor (did);
123  linked_auxid = getAuxIdForAttribute (r, desc, field_prefix,
124  linked_attr, linked_f.GetTypeName(), standalone);
125  }
126  if (linked_auxid == SG::null_auxid) {
127  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader.cxx:getLinkedAuxId");
128  msg << "Could not find linked variable for " << attr_name
129  << " type: " << attr_type;
130  }
131  }
132  return linked_auxid;
133 }
134 
135 
137 getAuxIdForAttribute(const SG::AuxTypeRegistry& r,
138  const RNTupleDescriptor& desc,
139  const std::string& field_prefix,
140  const std::string& attr_name,
141  const std::string& attr_type,
142  bool standalone)
143 {
144  SG::auxid_t auxid = r.findAuxID(attr_name);
145  if(auxid != SG::null_auxid)
146  return auxid;
147 
148  string element_type;
149  const std::type_info* ti = getAuxElementType(standalone, element_type, attr_type);
150  if( !ti )
151  return auxid;
152 
153  SG::auxid_t linked_auxid = getLinkedAuxId (r, desc, field_prefix, attr_name, attr_type, standalone);
154 
155  return SG::getDynamicAuxID (*ti, attr_name, element_type, attr_type, standalone, linked_auxid);
156 }
157 
158 } // anonymous namespace
159 
160 
161 namespace RootAuxDynIO
162 {
163  // New RNTupleReader for dynamic attributes of an AuxContainer-type object
164  // stored in the Field 'field_name'
165  RNTupleAuxDynReader::RNTupleAuxDynReader(const std::string& field_name,
166  const std::string& field_type,
168  : AthMessaging( std::string("RNTupleAuxDynReader[")+field_name+"]" ),
169  m_storeFieldName( field_name ),
170  m_ntupleReader( reader )
171  {
172  const std::string field_prefix = field_type + "_";
173  if( m_storeFieldName.rfind( field_type, 0 ) != std::string::npos ) {
174  m_key = m_storeFieldName.substr( field_type.size()+1 );
175  }
176  else if( m_storeFieldName.ends_with( "Aux:" ) ) {
177  m_key = m_storeFieldName.substr( 0, m_storeFieldName.size() - 4 );
178  }
179  ATH_MSG_VERBOSE("field name=" << m_storeFieldName << " field_prefix=" << field_prefix << " key=" << m_key);
180  TClass *tc = TClass::GetClass( field_type.c_str() );
181  if( tc ) {
182  TClass *storeTC = tc->GetBaseClass("SG::IAuxStoreHolder");
183  if( storeTC ) {
184  m_storeHolderOffset = tc->GetBaseClassOffset( storeTC );
185  } else {
186  throw std::runtime_error(string("Class ") + tc->GetName() +" does not implement SG::IAuxStoreHolder");
187  }
188  } else {
189  throw std::runtime_error(string("Class ") + field_type +" could not be found");
190  }
191  }
192 
193 
194 // Has to be a separate method because 'standalone' status is not know at construction time
195 // Prepare all Field infos for dynamic attributes (auxids and types)
197  {
198  if( m_initialized ) return;
199 
201  const string field_prefix = RootAuxDynIO::auxFieldName("", m_storeFieldName);
202  const auto& desc = m_ntupleReader->GetDescriptor();
203  for( const auto &f : desc.GetTopLevelFields() ) {
204  const string field_name = f.GetFieldName();
205  if( field_name.rfind(field_prefix,0) == 0 ) {
206  const string attr_infile = field_name.substr(field_prefix.size());
207  const string attr_name = reg.inputRename(m_key, attr_infile);
208  const string field_type = f.GetTypeName();
209 
210  SG::auxid_t auxid = getAuxIdForAttribute(reg, desc, field_prefix,
211  attr_name, field_type, standalone);
212  // add AuxID to the list
213  // May still be null if we don't have a dictionary for this field
214  if( auxid != SG::null_auxid ) {
215  m_auxids.insert(auxid);
216  m_fieldInfos[auxid].fieldName = field_name;
217  m_fieldInfos[auxid].view = m_ntupleReader->GetView<void>(field_name, nullptr);
218  } else {
219  errorcheck::ReportMessage msg (MSG::WARNING, ERRORCHECK_ARGS, "RNTupleAuxDynReader::init");
220  msg << "Could not find auxid for " << attr_infile << " type: " << field_type
221  << " standalone=" << standalone;
222  }
223  }
224  }
225  m_initialized = true;
226  }
227 
228 // Called by the AuxStore when it is reading new attribute data from the file
229 // All information is cached in a FieldInfo object for better performance
232  {
233  FieldInfo& fieldInfo = m_fieldInfos[auxid];
234  if( fieldInfo.status == FieldInfo::NotInitialized )
235  {
237  fieldInfo.auxid = auxid;
238  fieldInfo.attribName = reg.getName(auxid);
239  // Don't match this attribute if it's been renamed.
240  // For example, suppose we've renamed attribute `foo' to `foo_old',
241  // and someone then comes and asks for `foo'.
242  // `foo' will not be found in the m_fieldMap test below
243  // (`foo_old' will be in this map). However, in the following
244  // else clause, we'll recreate the field name from `foo'.
245  // This field exists (renaming is only in the transient store),
246  // so if we didn't have the condition here, then we'd then
247  // make a `foo' attribute from that field.
248  if( reg.inputRename(m_key, fieldInfo.attribName) != fieldInfo.attribName ) {
249  fieldInfo.status = FieldInfo::NotFound;
250  return fieldInfo;
251  }
252 
253  if( fieldInfo.fieldName.empty() ) {
254  // mark initialized here so it remembers this field was not found
255  fieldInfo.status = FieldInfo::NotFound;
256  return fieldInfo;
257  }
258 
259  if( !store.standalone() and fieldInfo.fieldName.rfind("SG::PackedContainer<", 0) == 0 )
260  fieldInfo.isPackedContainer = true;
261 
262  /*
263  string elem_tname, branch_tname;
264  const type_info* ti = getAuxElementType( fieldInfo.tclass, typ, store.standalone(),
265  elem_tname, branch_tname );
266  const type_info* reg_ti = reg.getType(auxid);
267  if( ti && ti != reg_ti && strcmp(ti->name(), reg_ti->name()) != 0 )
268  {
269  // type in registry is different than type in the file.
270  // will need to use ROOT auto schema evolution
271  fieldInfo.needsSE = true;
272  errorcheck::ReportMessage msg (MSG::INFO, ERRORCHECK_ARGS, "RNTupleAuxDynReader");
273  msg << "attribute " << fieldInfo.attribName << " (id=" << auxid <<
274  " typename=" << SG::AuxTypeRegistry::instance().getType(auxid)->name()
275  << ") has different type than the branch " << branch_tname;
276 
277  const std::type_info *tinf = store.getIOType(auxid);
278  fieldInfo.SE_tclass = TClass::GetClass(*tinf);
279  fieldInfo.SE_edt = kOther_t;
280  if( !fieldInfo.SE_tclass ) {
281  fieldInfo.SE_edt = TDataType::GetType(*tinf);
282  if( fieldInfo.SE_edt <=0 ) {
283  fieldInfo.status = FieldInfo::TypeError;
284  throw string("Error getting ROOT type for AUX branch ") + fieldInfo.branch->GetName()
285  + " typeinfo=" + tinf->name();
286  }
287  }
288  }
289  */
290  fieldInfo.status = FieldInfo::Initialized;
291  }
292  return fieldInfo;
293  }
294 
295 
296  void RNTupleAuxDynReader::addReaderToObject(void* object, size_t row, std::recursive_mutex* iomtx)
297  {
298  auto store_holder = reinterpret_cast<SG::IAuxStoreHolder*>((char*)object + m_storeHolderOffset);
299  bool standalone { store_holder->getStoreType()==SG::IAuxStoreHolder::AST_ObjectStore };
300  if( !m_initialized )
301  init(standalone);
302  store_holder->setStore( new RNTupleAuxDynStore(*this, row, standalone, iomtx) );
303  }
304 
305 }// namespace
query_example.row
row
Definition: query_example.py:24
SGTest::store
TestStore store
Definition: TestStore.cxx:23
beamspotman.r
def r
Definition: beamspotman.py:676
IAuxStoreHolder.h
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:392
RNTupleAuxDynStore
Definition: RNTupleAuxDynStore.h:23
L1CaloPhase1Monitoring.standalone
standalone
Definition: L1CaloPhase1Monitoring.py:120
SG::AuxTypeRegistry::instance
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Definition: AuxTypeRegistry.cxx:639
RootAuxDynIO::RNTupleAuxDynReader::RNTupleAuxDynReader
RNTupleAuxDynReader(const std::string &field_name, const std::string &field_type, RNTupleReader *reader)
create Reader for Aux attributes of an AuxContainer object stored in a given field
Definition: RNTupleAuxDynReader.cxx:165
RootAuxDynIO::RNTupleAuxDynReader::m_ntupleReader
RNTupleReader * m_ntupleReader
Definition: RNTupleAuxDynReader.h:91
RootAuxDynIO::RNTupleAuxDynReader::m_storeHolderOffset
int m_storeHolderOffset
Definition: RNTupleAuxDynReader.h:83
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo
Definition: RNTupleAuxDynReader.h:33
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::Initialized
@ Initialized
Definition: RNTupleAuxDynReader.h:34
SG::AuxTypeRegistry::getName
std::string getName(SG::auxid_t auxid) const
Return the name of an aux data item.
Definition: AuxTypeRegistry.cxx:881
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
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:85
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::m_auxids
SG::auxid_set_t m_auxids
Definition: RNTupleAuxDynReader.h:77
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:296
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::NotFound
@ NotFound
Definition: RNTupleAuxDynReader.h:34
AuxDataOption.h
Hold information about an option setting request.
SG::AuxTypeRegistry
Handle mappings between names and auxid_t.
Definition: AuxTypeRegistry.h:61
collListGuids.attr_name
attr_name
Definition: collListGuids.py:72
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:44
CaloCondBlobAlgs_fillNoiseFromASCII.desc
desc
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:54
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
CxxUtils::ConcurrentBitset::insert
ConcurrentBitset & insert(bit_t bit, bit_t new_nbits=0)
Set a bit to 1.
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::fieldName
std::string fieldName
Definition: RNTupleAuxDynReader.h:45
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::auxid
SG::auxid_t auxid
Definition: RNTupleAuxDynReader.h:43
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:41
hist_file_dump.f
f
Definition: hist_file_dump.py:141
RootAuxDynIO::RNTupleAuxDynReader::getFieldInfo
FieldInfo & getFieldInfo(const SG::auxid_t &auxid, const SG::AuxStoreInternal &store)
get field informatino for auxid
Definition: RNTupleAuxDynReader.cxx:231
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:196
RootAuxDynIO::RNTupleAuxDynReader::m_initialized
bool m_initialized
Definition: RNTupleAuxDynReader.h:84
RNTupleAuxDynReader.h
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::isPackedContainer
bool isPackedContainer
Definition: RNTupleAuxDynReader.h:39
RootAuxDynIO::RNTupleAuxDynReader::m_fieldInfos
std::map< SG::auxid_t, FieldInfo > m_fieldInfos
Definition: RNTupleAuxDynReader.h:88
RNTupleAuxDynStore.h
RootAuxDynIO
Specialization of RootAuxDynStore for reading Aux Dynamic attributes from RNTuple.
Definition: RNTupleContainer.h:26
SG::AuxStoreInternal
An auxiliary data store that holds data internally.
Definition: AuxStoreInternal.h:43
AuxTypeRegistry.h
Handle mappings between names and auxid_t.
RNTupleReader
ROOT::Experimental::RNTupleReader RNTupleReader
Definition: RNTupleAuxDynStore.h:19
RootUtils::Type
Wrapper for ROOT types.
Definition: Type.h:40
RootAuxDynIO::RNTupleAuxDynReader::FieldInfo::NotInitialized
@ NotInitialized
Definition: RNTupleAuxDynReader.h:34
RootAuxDynIO::RNTupleAuxDynReader::m_storeFieldName
std::string m_storeFieldName
Definition: RNTupleAuxDynReader.h:79
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