ATLAS Offline Software
Loading...
Searching...
No Matches
RNtupleFieldHelpers.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Local include(s):
7
8// EDM include(s):
17
18// ROOT include(s):
19#include <TClass.h>
20#include <TVirtualCollectionProxy.h>
21#include <ROOT/RNTupleModel.hxx>
22
23// System include(s):
24#include <iostream>
25#include <regex>
26#include <algorithm>
27
28namespace {
29 // Mirroring TempInterface from TreeBranchHelpers.cxx
30 class TempInterface : public SG::AuxVectorData {
31 public:
32 TempInterface( size_t size, SG::auxid_t auxid, void* ptr ) : m_size(size) {
33 setCache( auxid, ptr );
34 }
35 using AuxVectorData::setStore;
36 virtual size_t size_v() const { return m_size; }
37 virtual size_t capacity_v() const { return m_size; }
38 private:
39 size_t m_size;
40 };
41
42 // Helper to abstract .data() access, as std::vector<bool> does not support it
43 template<typename T>
44 void* getVectorData( std::vector<T>& v ) {
45 return v.data();
46 }
47
48 // Specialization for vector<bool>
49 void* getVectorData( std::vector<bool>& ) {
50 return nullptr;
51 }
52
53 // Helper to generate RNTuple fields based on type_info
54 template <typename TYPE>
55 std::shared_ptr<void> makeScalarField(ROOT::RNTupleModel& model,
56 const std::string& fieldName,
57 void*& rawPtr) {
58 auto ptr = model.MakeField<TYPE>(fieldName);
59 rawPtr = ptr.get();
60 return ptr;
61 }
62
63 template <typename TYPE>
64 std::shared_ptr<void> makeVecField(ROOT::RNTupleModel& model,
65 const std::string& fieldName,
66 void*& rawPtr,
68 auto ptr = model.MakeField<std::vector<TYPE>>(fieldName);
69 rawPtr = ptr.get();
70 ops.resize = [ptr](size_t n){ ptr->resize(n); };
71 ops.getData = [ptr]() -> void* { return getVectorData(*ptr); };
72 return ptr;
73 }
74
75 std::shared_ptr<void> makeField( ROOT::RNTupleModel& model,
76 const std::string& fieldName,
77 const std::type_info& type_info,
78 void*& rawPtr,
80 MsgStream& msg ) {
81
82 using namespace ROOT;
83
84 // Scalar types
85 if ( type_info == typeid(float) ) return makeScalarField<float>(model, fieldName, rawPtr);
86 if ( type_info == typeid(double) ) return makeScalarField<double>(model, fieldName, rawPtr);
87 if ( type_info == typeid(int) ) return makeScalarField<int>(model, fieldName, rawPtr);
88 if ( type_info == typeid(unsigned int) ) return makeScalarField<unsigned int>(model, fieldName, rawPtr);
89 if ( type_info == typeid(short) ) return makeScalarField<short>(model, fieldName, rawPtr);
90 if ( type_info == typeid(unsigned short) ) return makeScalarField<unsigned short>(model, fieldName, rawPtr);
91 if ( type_info == typeid(long) ) return makeScalarField<long>(model, fieldName, rawPtr);
92 if ( type_info == typeid(unsigned long) ) return makeScalarField<unsigned long>(model, fieldName, rawPtr);
93 if ( type_info == typeid(long long) ) return makeScalarField<long long>(model, fieldName, rawPtr);
94 if ( type_info == typeid(unsigned long long) ) return makeScalarField<unsigned long long>(model, fieldName, rawPtr);
95 if ( type_info == typeid(char) ) return makeScalarField<char>(model, fieldName, rawPtr);
96 if ( type_info == typeid(unsigned char) ) return makeScalarField<unsigned char>(model, fieldName, rawPtr);
97 if ( type_info == typeid(bool) ) return makeScalarField<bool>(model, fieldName, rawPtr);
98
99 // Vector types
100 if ( type_info == typeid(std::vector<float>) ) return makeVecField<float>(model, fieldName, rawPtr, ops);
101 if ( type_info == typeid(std::vector<double>) ) return makeVecField<double>(model, fieldName, rawPtr, ops);
102 if ( type_info == typeid(std::vector<int>) ) return makeVecField<int>(model, fieldName, rawPtr, ops);
103 if ( type_info == typeid(std::vector<unsigned int>) ) return makeVecField<unsigned int>(model, fieldName, rawPtr, ops);
104 if ( type_info == typeid(std::vector<short>) ) return makeVecField<short>(model, fieldName, rawPtr, ops);
105 if ( type_info == typeid(std::vector<unsigned short>) ) return makeVecField<unsigned short>(model, fieldName, rawPtr, ops);
106 if ( type_info == typeid(std::vector<long>) ) return makeVecField<long>(model, fieldName, rawPtr, ops);
107 if ( type_info == typeid(std::vector<unsigned long>) ) return makeVecField<unsigned long>(model, fieldName, rawPtr, ops);
108 if ( type_info == typeid(std::vector<long long>) ) return makeVecField<long long>(model, fieldName, rawPtr, ops);
109 if ( type_info == typeid(std::vector<unsigned long long>) ) return makeVecField<unsigned long long>(model, fieldName, rawPtr, ops);
110 if ( type_info == typeid(std::vector<char>) ) return makeVecField<char>(model, fieldName, rawPtr, ops);
111 if ( type_info == typeid(std::vector<unsigned char>) ) return makeVecField<unsigned char>(model, fieldName, rawPtr, ops);
112 if ( type_info == typeid(std::vector<bool>) ) return makeVecField<bool>(model, fieldName, rawPtr, ops);
113 if ( type_info == typeid(std::vector<std::string>) ) return makeVecField<std::string>(model, fieldName, rawPtr, ops);
114
115 if ( type_info == typeid(std::string) ) {
116 auto ptr = model.MakeField<std::string>(fieldName);
117 rawPtr = ptr.get();
118 return ptr;
119 }
120
121 msg << MSG::ERROR << "Unsupported type for RNTuple field \"" << fieldName << "\"" << endmsg;
122 return nullptr;
123 }
124
125 bool auxItemExists( const std::string& key ) {
127 return reg.findAuxID( key ) != SG::null_auxid;
128 }
129
130#ifdef XAOD_STANDALONE
131
132 const SG::AuxVectorBase* getVector( const std::string& key,
133 asg::SgEvent& evtStore,
134 bool allowMissing,
135 const TClass*& cl,
136 MsgStream& msg ) {
137 if( allowMissing &&
138 ( ! evtStore.contains< const SG::AuxVectorBase >( key ) ) ) {
139 return nullptr;
140 }
141 const SG::AuxVectorBase* c = nullptr;
142 if( ! evtStore.retrieve( c, key ).isSuccess() ) {
143 msg << MSG::ERROR << "Couldn't retrieve container with key \"" << key
144 << "\"" << endmsg;
145 return nullptr;
146 }
147 const xAOD::THolder* holder = evtStore.tds()->holder( key );
148 if( holder != nullptr ) {
149 const std::type_info* ti = holder->getTypeInfo();
150 cl = TClass::GetClass( *ti );
151 } else {
152 cl = TClass::GetClass( typeid( *c ) );
153 }
154 if( ( allowMissing == false ) && ( cl == nullptr ) ) {
155 msg << MSG::ERROR
156 << "Couldn't find TClass dictionary for container \"" << key
157 << "\"" << endmsg;
158 return nullptr;
159 }
160 return c;
161 }
162
163 const SG::AuxElement* getElement( const std::string& key,
164 asg::SgEvent& evtStore,
165 bool allowMissing,
166 MsgStream& msg ) {
167 if( allowMissing &&
168 ( ! evtStore.contains< const SG::AuxElement >( key ) ) ) {
169 return nullptr;
170 }
171 const SG::AuxElement* e = nullptr;
172 if( ! evtStore.retrieve( e, key ).isSuccess() ) {
173 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
174 << "\"" << endmsg;
175 return nullptr;
176 }
177 return e;
178 }
179
180#else
181
182 class ProxyWithName {
183 public:
184 typedef const SG::DataProxy* argument_type;
185 ProxyWithName( const std::string& name ) : m_name( name ) {}
186 bool operator()( argument_type proxy ) const {
187 return ( proxy->name() == m_name );
188 }
189 private:
190 std::string m_name;
191 };
192
193 const SG::AuxVectorBase* getVector ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
194 IProxyDict& evtStore,
195 bool allowMissing,
196 const TClass*& cl,
197 MsgStream& msg ) {
198
199 auto proxies = evtStore.proxies();
200 proxies.erase( std::remove_if( proxies.begin(), proxies.end(),
201 std::not_fn( ProxyWithName( key ) ) ),
202 proxies.end() );
203 for( const SG::DataProxy* proxy : proxies ) {
204 SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy );
205 DataBucketBase* bucket =
206 dynamic_cast< DataBucketBase* >( proxy_nc->accessData() );
207 if( ! bucket ) {
208 msg << MSG::ERROR
209 << "Couldn't access data object as a data bucket?!?" << endmsg;
210 return nullptr;
211 }
212 cl = TClass::GetClass( bucket->tinfo() );
213 if( ! cl ) {
214 if( msg.level() <= MSG::VERBOSE ) {
215 msg << MSG::VERBOSE << "No dictionary found for: "
216 << bucket->tinfo().name() << endmsg;
217 }
218 continue;
219 }
220 if( ! cl->InheritsFrom( "SG::AuxVectorBase" ) ) {
221 if( msg.level() <= MSG::VERBOSE ) {
222 msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName()
223 << "\" does not inherit from SG::AuxVectorBase" << endmsg;
224 }
225 continue;
226 }
228 reinterpret_cast< const SG::AuxVectorBase* >( bucket->object() );
229 return result;
230 }
231
232 if( ! allowMissing ) {
233 msg << MSG::ERROR << "Couldn't retrieve object \"" << key
234 << "\" as SG::AuxVectorBase" << endmsg;
235 }
236 return nullptr;
237 }
238
239 const SG::AuxElement* getElement ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
240 StoreGateSvc& evtStore,
241 bool allowMissing,
242 MsgStream& msg ) {
243
244 const SG::AuxElement* e = nullptr;
245 if( !evtStore.retrieve( e, key ).isSuccess() ) {
246 if(!allowMissing) {
247 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
248 << "\"" << endmsg;
249 }
250 return nullptr;
251 }
252 return e;
253
254 }
255#endif // XAOD_STANDALONE
256
257}
258
259namespace CP {
260 namespace RNtupleFieldHelpers {
261 // ======================================================================
262 // ElementFieldProcessor
263 // ======================================================================
264
265 StatusCode ElementFieldProcessor::setup( ROOT::RNTupleModel& model,
266 const BranchConfig& branchConfig,
267 OutputBranchData& outputData,
268 MsgStream& msg ) {
269 m_fieldName = outputData.branchName;
270 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
271
272 if( branchConfig.auxFactory && branchConfig.auxType ) {
273 m_factory = branchConfig.auxFactory;
274 const std::type_info* type_info = branchConfig.auxType;
275
276 FieldOps dummyOps;
277 m_field = makeField( model, m_fieldName, *type_info, m_dataPtr, dummyOps, msg );
278 } else {
279 msg << MSG::ERROR << "BranchConfig not properly configured for " << outputData.auxName << endmsg;
280 return StatusCode::FAILURE;
281 }
282
283 return m_field ? StatusCode::SUCCESS : StatusCode::FAILURE;
284 }
285
286 StatusCode ElementFieldProcessor::setup( TTree& /*tree*/,
287 const BranchConfig& /*branchConfig*/,
288 OutputBranchData& /*outputData*/,
289 MsgStream& msg ) {
290 msg << MSG::ERROR << "setup(TTree, ...) called, but only setup(ROOT::RNTupleModel, ...) should be implemented for this processor" << endmsg;
291 return StatusCode::FAILURE;
292 }
293
294 StatusCode ElementFieldProcessor::process( const SG::AuxElement& element, MsgStream& /*msg*/ ) {
295 // Use High-Level copy via TempInterface
296 // copy( auxid, dst_container, dst_index, src_container, src_index, n )
297 TempInterface dstiface( 1, m_acc->auxid(), m_dataPtr );
298 m_factory->copy( m_acc->auxid(), dstiface, 0, *element.container(), element.index(), 1 );
299 return StatusCode::SUCCESS;
300 }
301
302
303 // ======================================================================
304 // ContainerFieldProcessor
305 // ======================================================================
306
307 StatusCode ContainerFieldProcessor::setup( ROOT::RNTupleModel& model,
308 const BranchConfig& branchConfig,
309 OutputBranchData& outputData,
310 MsgStream& msg ) {
311 m_fieldName = outputData.branchName;
312 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
313
314 if( branchConfig.auxFactory && branchConfig.auxVecType ) {
315 m_factory = branchConfig.auxFactory;
316 const std::type_info* type_info = branchConfig.auxVecType;
317
318 m_field = makeField( model, m_fieldName, *type_info, m_dataPtr, m_ops, msg );
319 } else {
320 msg << MSG::ERROR << "BranchConfig not properly configured for " << outputData.auxName << endmsg;
321 return StatusCode::FAILURE;
322 }
323
324 if( !m_field ) return StatusCode::FAILURE;
325
326 if( !m_ops.resize || !m_ops.getData ) {
327 msg << MSG::ERROR << "Container field " << m_fieldName << " must be a vector type" << endmsg;
328 return StatusCode::FAILURE;
329 }
330 return StatusCode::SUCCESS;
331 }
332
333 StatusCode ContainerFieldProcessor::setup( TTree& /*tree*/,
334 const BranchConfig& /*branchConfig*/,
335 OutputBranchData& /*outputData*/,
336 MsgStream& msg ) {
337 msg << MSG::ERROR << "setup(TTree, ...) called, but only setup(ROOT::RNTupleModel, ...) should be implemented for this processor" << endmsg;
338 return StatusCode::FAILURE;
339 }
340
341 StatusCode ContainerFieldProcessor::resize( size_t size, MsgStream& /*msg*/ ) {
342 if( m_ops.resize ) {
343 m_ops.resize( size );
344 return StatusCode::SUCCESS;
345 }
346 return StatusCode::FAILURE;
347 }
348
349 StatusCode ContainerFieldProcessor::process( const SG::AuxElement& element, size_t index, MsgStream& msg ) {
350 void* rawDataPtr = getData();
351 if( !rawDataPtr && index > 0 ) return StatusCode::FAILURE;
352
353 try {
354 TempInterface dstiface( index + 1, m_acc->auxid(), rawDataPtr );
355 m_factory->copy( m_acc->auxid(), dstiface, index, *element.container(), element.index(), 1 );
356 } catch( ... ) {
357 msg << MSG::ERROR << "Failed to copy data for " << m_fieldName << endmsg;
358 return StatusCode::FAILURE;
359 }
360 return StatusCode::SUCCESS;
361 }
362
363
364 // ======================================================================
365 // ElementProcessor
366 // ======================================================================
367
368 ElementProcessor::ElementProcessor(const std::string& sgName)
369 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ElementProcessor/" + sgName ), m_sgName(sgName) {}
370
372 static const bool ALLOW_MISSING = false;
373 const SG::AuxElement* el = getElement( m_sgName,
374 evtStore,
375 ALLOW_MISSING, msg() );
376 if( ! el ) {
377 ATH_MSG_ERROR( "Failed to retrieve object \"" << m_sgName << "\"" );
378 return StatusCode::FAILURE;
379 }
380
381 for( auto& p : m_fields ) {
382 ATH_CHECK( p->process( *el, msg() ) );
383 }
384 return StatusCode::SUCCESS;
385 }
386
387 StatusCode ElementProcessor::addBranch( ROOT::RNTupleModel& model,
388 const BranchConfig& branchConfig,
389 OutputBranchData& outputData ) {
390 if( !auxItemExists(outputData.auxName) ) {
391 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
392 return StatusCode::FAILURE;
393 }
394 m_fields.emplace_back( std::make_unique<ElementFieldProcessor>() );
395 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
396 return StatusCode::SUCCESS;
397 }
398
399 StatusCode ElementProcessor::addBranch( TTree& /*tree*/,
400 const BranchConfig& /*branchConfig*/,
401 OutputBranchData& /*outputData*/ ) {
402 ATH_MSG_ERROR("ElementProcessor::addBranch for TTree should not be called");
403 return StatusCode::FAILURE;
404 }
405
406 // ======================================================================
407 // ContainerProcessor
408 // ======================================================================
409
410 ContainerProcessor::ContainerProcessor(const std::string& sgName)
411 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ContainerProcessor/" + sgName ), m_sgName(sgName) {}
412
413 StatusCode ContainerProcessor::addBranch( ROOT::RNTupleModel& model,
414 const BranchConfig& branchConfig,
415 OutputBranchData& outputData ) {
416 if( !auxItemExists(outputData.auxName) ) {
417 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
418 return StatusCode::FAILURE;
419 }
420 m_fields.emplace_back( std::make_unique<ContainerFieldProcessor>() );
421 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
422 return StatusCode::SUCCESS;
423 }
424
425 StatusCode ContainerProcessor::addBranch( TTree& /*tree*/,
426 const BranchConfig& /*branchConfig*/,
427 OutputBranchData& /*outputData*/ ) {
428 ATH_MSG_ERROR("ContainerProcessor::addBranch for TTree should not be called");
429 return StatusCode::FAILURE;
430 }
431
433 // Retrieve the container:
434 static const bool ALLOW_MISSING = false;
435 const TClass* cl = nullptr;
436 const SG::AuxVectorBase* vec = getVector( m_sgName,
437 evtStore,
438 ALLOW_MISSING, cl, msg() );
439
440 if( ! vec ) {
441 ATH_MSG_ERROR( "Failed to retrieve container \""
442 << m_sgName << "\"" );
443 return StatusCode::FAILURE;
444 }
445 const SG::AuxVectorBase& container = *vec;
446 if( ! m_collProxy ) {
447
448 // Get the collection proxy from the dictionary.
449 m_collProxy = cl->GetCollectionProxy();
450 if( ! m_collProxy ) {
451 ATH_MSG_ERROR( "No collection proxy provided by type: "
452 << cl->GetName() );
453 return StatusCode::FAILURE;
454 }
455
456 // Get the offset that one needs to use to get from the element
457 // pointers to SG::AuxElement pointers.
458 static const TClass* const auxElementClass =
459 TClass::GetClass( typeid( SG::AuxElement ) );
461 m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass );
462 if( m_auxElementOffset < 0 ) {
463 ATH_MSG_ERROR( "Vector element type \""
464 << m_collProxy->GetValueClass()->GetName()
465 << "\" doesn't seem to inherit from \""
466 << auxElementClass->GetName() << "\"" );
467 return StatusCode::FAILURE;
468 }
469 }
470
471 void* cPtr =
472 const_cast< void* >( static_cast< const void* >( &container ) );
473 TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr );
474 const UInt_t cSize = m_collProxy->Size();
475
476 for( auto& p : m_fields ) {
477 ATH_CHECK( p->resize( cSize, msg() ) );
478 }
479
480 for (UInt_t i = 0; i < cSize; ++i) {
481 char* elPtr = static_cast< char* >( m_collProxy->At( i ) );
482 if( ! elPtr ) {
483 ATH_MSG_ERROR( "Failed to get element " << i << " from container" );
484 return StatusCode::FAILURE;
485 }
486 const SG::AuxElement* element =
487 reinterpret_cast< const SG::AuxElement* >( elPtr +
489
490 for ( auto& p : m_fields ) {
491 ATH_CHECK( p->process( *element, i, msg() ) );
492 }
493 }
494 return StatusCode::SUCCESS;
495 }
496 // ======================================================================
497 // ElementProcessorMET
498 // ======================================================================
499 ElementProcessorMet::ElementProcessorMet(const std::string& sgName, const std::string& termName)
500 : ElementProcessor(sgName),
501 m_termName(termName) {
502 }
503
505
506 const xAOD::MissingETContainer* met = nullptr;
507 ANA_CHECK(evtStore.retrieve(met, m_sgName));
508 const SG::AuxElement& element = *(*met)[m_termName];
509 // Process all fields.
510 for (auto& p : m_fields) {
511 ATH_CHECK(p->process(element, msg()));
512 }
513
514 return StatusCode::SUCCESS;
515 }
516
517 // ======================================================================
518 // ProcessorList
519 // ======================================================================
520 StatusCode ProcessorList::setupTree( const std::vector<std::string>& branches,
521 std::unordered_set<std::string> nonContainers,
522 ISystematicsSvc& sysSvc,
523 ROOT::RNTupleModel& model ) {
524 m_nonContainers = std::move(nonContainers);
525
526 std::vector<BranchConfig> branchConfigs;
527 branchConfigs.reserve( branches.size() );
528 for ( const std::string& branchDecl : branches ) {
529 branchConfigs.emplace_back();
530 ATH_CHECK( branchConfigs.back().parse( branchDecl, msg() ) );
531 if (!branchConfigs.back().basketSize.has_value())
532 branchConfigs.back().basketSize = defaultBasketSize;
533 }
534
535 // This will loop over all branches, collect the name of any
536 // aux-store decorations that have no type and report them at the
537 // end. This allows to get the full list of missing decorations in
538 // a single run, as opposed to having to re-run the job once per
539 // missing decoration.
540 std::set<std::string> decosWithoutType;
541 for (auto& branchConfig : branchConfigs) {
542 ATH_CHECK ( branchConfig.configureTypes (decosWithoutType, msg()) );
543 }
544 if (!decosWithoutType.empty()) {
545 msg() << MSG::ERROR << "The following decorations have no type information:";
546 for (const auto& deco : decosWithoutType) {
547 msg() << " " << deco;
548 }
549 msg() << endmsg;
550 return StatusCode::FAILURE;
551 }
552
553
554 for (auto& branchConfig : branchConfigs) {
555 ATH_CHECK ( branchConfig.configureSystematics (sysSvc, msg()) );
556 }
557
558 auto sysVector = sysSvc.makeSystematicsVector();
559 // Ensure that the nominal systematic is first
560 if (!sysVector.at(0).empty()) {
561 ATH_MSG_ERROR ("The first systematic in the list is not nominal!");
562 return StatusCode::FAILURE;
563 }
564
565 // The branches we intend to write out
566 std::vector<OutputBranchData> outputBranches;
567
568 // All the branches that will be created
569 std::unordered_set<std::string> allBranches;
570
571 // Iterate over the branch specifications.
572 for( const auto& branchConfig : branchConfigs ) {
573
574 // All the branches that will be created for this rule
575 std::unordered_set<std::string> branchesForRule;
576
577 // Consider all systematics but skip the nominal one
578 for( const auto& sys : sysVector ) {
579
580 if (branchConfig.nominalOnly && !sys.empty()) continue;
581 OutputBranchData outputData;
582 outputData.branchConfig = &branchConfig;
583 outputData.sysIndex = &sys - &sysVector.front();
584 ATH_CHECK( outputData.configureNames (branchConfig, sys, sysSvc, msg()) );
585
586 // Skip branches that have already been created for other
587 // systematics for this rule. That's mostly nominal, but for
588 // systematics correlation studies it can also do other things.
589 if (branchesForRule.contains(outputData.branchName))
590 {
591 ANA_MSG_VERBOSE ("Branch \"" << outputData.branchName << "\" for rule \"" << branchConfig.branchDecl << "\" and systematic \"" << sys.name() << "\" already exists, skipping." );
592 continue;
593 }
594 branchesForRule.insert(outputData.branchName);
595
596 // If this branch already exists from another rule, report
597 // it as an error.
598 if (allBranches.contains(outputData.branchName))
599 {
600 ANA_MSG_ERROR ("Branch \"" << outputData.branchName << "\" would be created twice!" );
601 return StatusCode::FAILURE;
602 }
603 allBranches.insert(outputData.branchName);
604 outputBranches.push_back(std::move(outputData));
605 }
606 }
607
608 // Group all branches by systematic index to ensure that when
609 // reading a single systematic the branches are contiguous on
610 // disk.
611 std::stable_sort (outputBranches.begin(), outputBranches.end(),
612 [](const OutputBranchData& a, const OutputBranchData& b) {
613 return a.sysIndex < b.sysIndex; });
614
615 for (auto &outputData : outputBranches)
616 ATH_CHECK( setupBranch( *outputData.branchConfig, outputData, model ) );
617
618 // Return gracefully.
619 return StatusCode::SUCCESS;
620 }
621
622 StatusCode ProcessorList::setupBranch( const BranchConfig& branchConfig,
623 OutputBranchData& outputData,
624 ROOT::RNTupleModel& model ) {
625
626 ATH_CHECK( getObjectProcessor( branchConfig, outputData.sgName ).addBranch( model, branchConfig, outputData ) );
627 ATH_MSG_DEBUG( "Writing RNTuple field \"" << outputData.branchName
628 << "\" from container/variable \"" << outputData.sgName
629 << "." << outputData.auxName << "\"" );
630
631 return StatusCode::SUCCESS;
632 }
633
634 StatusCode ProcessorList::process( StoreType& evtStore ) {
635 for( auto& [name, processor] : m_processors ) {
636 ATH_CHECK( processor->retrieveProcess( evtStore ) );
637 }
638 return StatusCode::SUCCESS;
639 }
640
641 TreeBranchHelpers::IObjectProcessor& ProcessorList::getObjectProcessor( const BranchConfig& branchConfig, const std::string& sgName ) {
642 std::string processorName = sgName;
643 if (!branchConfig.metTermName.empty()) {
644 processorName += ":metTerm=" + branchConfig.metTermName;
645 }
646
647 if (auto iter = m_processors.find(processorName); iter != m_processors.end()) {
648 return *iter->second;
649 }
650 if (!branchConfig.metTermName.empty())
651 return *m_processors.emplace (processorName, std::make_unique<ElementProcessorMet>(sgName, branchConfig.metTermName)).first->second;
652
653
654 if (m_nonContainers.contains(sgName)) {
655 return *(m_processors.emplace(processorName, std::make_unique<ElementProcessor>(sgName)).first->second);
656 }
657 return *(m_processors.emplace(processorName, std::make_unique<ContainerProcessor>(sgName)).first->second);
658 }
659
660} // namespace RNtupleFieldHelpers
661} // namespace CP
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
Base class for elements of a container that can have aux data.
Handle mappings between names and auxid_t.
Manage index tracking and synchronization of auxiliary data.
std::vector< size_t > vec
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_MSG_VERBOSE(xmsg)
Macro printing verbose messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
Interface for factory objects that create vectors.
static Double_t a
static HEPVis_BooleanProcessor processor
void operator()(T1)
size_t size() const
Number of registered mappings.
#define TYPE(CODE, TYP, IOTYP)
#define ATLAS_NOT_CONST_THREAD_SAFE
the interface for the central systematics service
virtual std::vector< CP::SystematicSet > makeSystematicsVector() const =0
get the list of systematics
std::unique_ptr< SG::TypelessConstAccessor > m_acc
StatusCode process(const SG::AuxElement &element, size_t index, MsgStream &msg)
virtual StatusCode setup(ROOT::RNTupleModel &model, const BranchConfig &branchConfig, OutputBranchData &outputData, MsgStream &msg) override
StatusCode resize(size_t size, MsgStream &msg)
virtual StatusCode addBranch(ROOT::RNTupleModel &model, const BranchConfig &branchConfig, OutputBranchData &outputData) override
std::vector< std::unique_ptr< ContainerFieldProcessor > > m_fields
virtual StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
std::unique_ptr< SG::TypelessConstAccessor > m_acc
StatusCode process(const SG::AuxElement &element, MsgStream &msg)
virtual StatusCode setup(ROOT::RNTupleModel &model, const BranchConfig &branchConfig, OutputBranchData &outputData, MsgStream &msg) override
const SG::IAuxTypeVectorFactory * m_factory
ElementProcessorMet(const std::string &sgName, const std::string &termName)
virtual StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
virtual StatusCode retrieveProcess(StoreType &evtStore) override
retrieve and process the object
std::vector< std::unique_ptr< ElementFieldProcessor > > m_fields
virtual StatusCode addBranch(ROOT::RNTupleModel &model, const BranchConfig &branchConfig, OutputBranchData &outputData) override
StatusCode process(StoreType &evtStore)
StatusCode setupTree(const std::vector< std::string > &branches, std::unordered_set< std::string > nonContainers, ISystematicsSvc &sysSvc, ROOT::RNTupleModel &model)
std::unordered_set< std::string > m_nonContainers
std::unordered_map< std::string, std::unique_ptr< TreeBranchHelpers::IObjectProcessor > > m_processors
TreeBranchHelpers::IObjectProcessor & getObjectProcessor(const BranchConfig &branchConfig, const std::string &sgName)
StatusCode setupBranch(const BranchConfig &branchConfig, OutputBranchData &outputData, ROOT::RNTupleModel &model)
the interface class for classes reading an object from the event store and processing it
virtual StatusCode addBranch(TTree &, const BranchConfig &, OutputBranchData &)=0
Add one branch to the output tree.
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
virtual void * object()=0
virtual const std::type_info & tinfo() const =0
Return the type_info for the stored object.
virtual std::vector< const SG::DataProxy * > proxies() const =0
Return the list of all current proxies in store.
Handle mappings between names and auxid_t.
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Manage index tracking and synchronization of auxiliary data.
Manage lookup of vectors of auxiliary data.
DataObject * accessData()
Access DataObject on-demand using conversion service.
Helper class to provide const generic access to aux data.
The Athena Transient Store API.
StatusCode retrieve(const T *&ptr) const
Retrieve the default object into a const T*.
MsgStream & msg() const
The standard message stream.
MsgStream & msg() const
The standard message stream.
AsgMessaging(const std::string &name)
Constructor with a name.
Wrapper for Event to make it look like StoreGate.
Definition SgEvent.h:44
bool contains(const std::string &name) const
Check if an object is available for constant access.
xAOD::TStore * tds() const
Return the underlying transient data store.
Definition SgEvent.cxx:33
T * retrieve(const std::string &name) const
Function retrieving a constant or non-constant object.
This class takes care of holding EDM objects in memory.
Definition THolder.h:35
const std::type_info * getTypeInfo() const
Definition THolder.cxx:412
const THolder * holder(const std::string &key) const
return holder for key
Definition TStore.cxx:50
TreeBranchHelpers::OutputBranchData OutputBranchData
TreeBranchHelpers::BranchConfig BranchConfig
Select isolated Photons, Electrons and Muons.
const SG::AuxVectorData * getVectorData(const T &cont)
Selection rules: declare transient members.
Definition DataVector.h:581
static const auxid_t null_auxid
To signal no aux data item.
Definition AuxTypes.h:30
AuxElement(SG::AuxVectorData *container, size_t index)
Base class for elements of a container that can have aux data.
virtual const IAuxTypeVector * getVector(SG::auxid_t auxid) const override
Return vector interface for one aux data item.
size_t auxid_t
Identifier for a particular aux data item.
Definition AuxTypes.h:27
void * ptr(T *p)
Definition SGImplSvc.cxx:74
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition index.py:1
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
std::function< void(size_t)> resize
const SG::IAuxTypeVectorFactory * auxFactory
pointer to the aux vector factory
const std::type_info * auxVecType
the vector type of the decoration we read
const std::type_info * auxType
the type of the decoration we read
std::string metTermName
MET ONLY: the name of the MET term to write out.
const BranchConfig * branchConfig
the BranchConfig we are based on
std::size_t sysIndex
the index in the systematics list
StatusCode configureNames(const BranchConfig &branchConfig, const CP::SystematicSet &sys, ISystematicsSvc &sysSvc, MsgStream &msg)
configure names for systematics
std::string auxName
the name of the decoration in the aux-store
std::string sgName
the SG name of the object to read from
std::string branchName
the name of the output branch
MsgStream & msg
Definition testRead.cxx:32