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