ATLAS Offline Software
Loading...
Searching...
No Matches
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
24using std::string;
25
26namespace {
27
41const std::type_info*
42getAuxElementType( 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
88getAuxIdForAttribute(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
97getLinkedAuxId (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;
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
124getAuxIdForAttribute(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
148namespace 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)
183 void RNTupleAuxDynReader::init( bool standalone )
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
#define ATH_MSG_VERBOSE(x)
Hold information about an option setting request.
Handle mappings between names and auxid_t.
Exceptions that can be thrown from AthContainers.
static Double_t tc
Wrapper for ROOT types.
MsgStream & msg() const
The standard message stream.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
void init(bool standalone)
initialize once the mode of the Aux store is known
FieldInfo & getFieldInfo(const SG::auxid_t &auxid, const SG::AuxStoreInternal &store)
get field informatino for auxid
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
virtual void addReaderToObject(void *object, size_t row, std::recursive_mutex *iomtx=nullptr) override final
attach RNTupleAuxStore to the current Aux container @object
std::map< SG::auxid_t, FieldInfo > m_fieldInfos
bool addAuxID(const SG::auxid_t &id)
Wrapper for ROOT types.
Definition Type.h:40
const std::type_info * getTypeInfo() const
Return the type_info for the described type.
Definition Type.cxx:366
const TClass * getClass() const
Return the ROOT class for the described type.
Definition Type.cxx:346
An auxiliary data store that holds data internally.
Handle mappings between names and auxid_t.
static std::string linkedName(const std::string &name)
Given a variable name, return the name of the corresponding linked variable.
static bool classNameHasLink(const std::string &className)
Test to see if a class name corresponds to a class with a linked variable.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Interface for objects taking part in direct ROOT I/O.
@ AST_ObjectStore
The store describes a single object.
Helper class to use to report a message.
Helper for emitting error messages.
Find the auxid for a dynamic branch.
int r
Definition globals.cxx:22
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
Specialization of RootAuxDynStore for reading Aux Dynamic attributes from RNTuple.
std::string auxFieldName(const std::string &attr_name, const std::string &baseName)
Construct field name for a given dynamic attribute.
static const auxid_t null_auxid
To signal no aux data item.
Definition AuxTypes.h:30
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.
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
STL namespace.
MsgStream & msg
Definition testRead.cxx:32