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