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
114 if ( type_info == typeid(std::string) ) {
115 auto ptr = model.MakeField<std::string>(fieldName);
116 rawPtr = ptr.get();
117 return ptr;
118 }
119
120 msg << MSG::ERROR << "Unsupported type for RNTuple field \"" << fieldName << "\"" << endmsg;
121 return nullptr;
122 }
123
124 bool auxItemExists( const std::string& key ) {
126 return reg.findAuxID( key ) != SG::null_auxid;
127 }
128
129#ifdef XAOD_STANDALONE
130
131 const SG::AuxVectorBase* getVector( const std::string& key,
132 asg::SgTEvent& evtStore,
133 bool allowMissing,
134 const TClass*& cl,
135 MsgStream& msg ) {
136 if( allowMissing &&
137 ( ! evtStore.contains< const SG::AuxVectorBase >( key ) ) ) {
138 return nullptr;
139 }
140 const SG::AuxVectorBase* c = nullptr;
141 if( ! evtStore.retrieve( c, key ).isSuccess() ) {
142 msg << MSG::ERROR << "Couldn't retrieve container with key \"" << key
143 << "\"" << endmsg;
144 return nullptr;
145 }
146 const xAOD::THolder* holder = evtStore.tds()->holder( key );
147 if( holder != nullptr ) {
148 const std::type_info* ti = holder->getTypeInfo();
149 cl = TClass::GetClass( *ti );
150 } else {
151 cl = TClass::GetClass( typeid( *c ) );
152 }
153 if( ( allowMissing == false ) && ( cl == nullptr ) ) {
154 msg << MSG::ERROR
155 << "Couldn't find TClass dictionary for container \"" << key
156 << "\"" << endmsg;
157 return nullptr;
158 }
159 return c;
160 }
161
162 const SG::AuxElement* getElement( const std::string& key,
163 asg::SgTEvent& evtStore,
164 bool allowMissing,
165 MsgStream& msg ) {
166 if( allowMissing &&
167 ( ! evtStore.contains< const SG::AuxElement >( key ) ) ) {
168 return nullptr;
169 }
170 const SG::AuxElement* e = nullptr;
171 if( ! evtStore.retrieve( e, key ).isSuccess() ) {
172 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
173 << "\"" << endmsg;
174 return nullptr;
175 }
176 return e;
177 }
178
179#else
180
181 class ProxyWithName {
182 public:
183 typedef const SG::DataProxy* argument_type;
184 ProxyWithName( const std::string& name ) : m_name( name ) {}
185 bool operator()( argument_type proxy ) const {
186 return ( proxy->name() == m_name );
187 }
188 private:
189 std::string m_name;
190 };
191
192 const SG::AuxVectorBase* getVector ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
193 IProxyDict& evtStore,
194 bool allowMissing,
195 const TClass*& cl,
196 MsgStream& msg ) {
197
198 auto proxies = evtStore.proxies();
199 proxies.erase( std::remove_if( proxies.begin(), proxies.end(),
200 std::not_fn( ProxyWithName( key ) ) ),
201 proxies.end() );
202 for( const SG::DataProxy* proxy : proxies ) {
203 SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy );
204 DataBucketBase* bucket =
205 dynamic_cast< DataBucketBase* >( proxy_nc->accessData() );
206 if( ! bucket ) {
207 msg << MSG::ERROR
208 << "Couldn't access data object as a data bucket?!?" << endmsg;
209 return nullptr;
210 }
211 cl = TClass::GetClass( bucket->tinfo() );
212 if( ! cl ) {
213 if( msg.level() <= MSG::VERBOSE ) {
214 msg << MSG::VERBOSE << "No dictionary found for: "
215 << bucket->tinfo().name() << endmsg;
216 }
217 continue;
218 }
219 if( ! cl->InheritsFrom( "SG::AuxVectorBase" ) ) {
220 if( msg.level() <= MSG::VERBOSE ) {
221 msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName()
222 << "\" does not inherit from SG::AuxVectorBase" << endmsg;
223 }
224 continue;
225 }
227 reinterpret_cast< const SG::AuxVectorBase* >( bucket->object() );
228 return result;
229 }
230
231 if( ! allowMissing ) {
232 msg << MSG::ERROR << "Couldn't retrieve object \"" << key
233 << "\" as SG::AuxVectorBase" << endmsg;
234 }
235 return nullptr;
236 }
237
238 const SG::AuxElement* getElement ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
239 StoreGateSvc& evtStore,
240 bool allowMissing,
241 MsgStream& msg ) {
242
243 const SG::AuxElement* e = nullptr;
244 if( !evtStore.retrieve( e, key ).isSuccess() ) {
245 if(!allowMissing) {
246 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
247 << "\"" << endmsg;
248 }
249 return nullptr;
250 }
251 return e;
252
253 }
254#endif // XAOD_STANDALONE
255
256}
257
258namespace CP {
259 namespace RNtupleFieldHelpers {
260 // ======================================================================
261 // ElementFieldProcessor
262 // ======================================================================
263
264 StatusCode ElementFieldProcessor::setup( ROOT::RNTupleModel& model,
265 const BranchConfig& branchConfig,
266 OutputBranchData& outputData,
267 MsgStream& msg ) {
268 m_fieldName = outputData.branchName;
269 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
270
271 if( branchConfig.auxFactory && branchConfig.auxType ) {
272 m_factory = branchConfig.auxFactory;
273 const std::type_info* type_info = branchConfig.auxType;
274
275 FieldOps dummyOps;
276 m_field = makeField( model, m_fieldName, *type_info, m_dataPtr, dummyOps, msg );
277 } else {
278 msg << MSG::ERROR << "BranchConfig not properly configured for " << outputData.auxName << endmsg;
279 return StatusCode::FAILURE;
280 }
281
282 return m_field ? StatusCode::SUCCESS : StatusCode::FAILURE;
283 }
284
285 StatusCode ElementFieldProcessor::setup( TTree& /*tree*/,
286 const BranchConfig& /*branchConfig*/,
287 OutputBranchData& /*outputData*/,
288 MsgStream& msg ) {
289 msg << MSG::ERROR << "setup(TTree, ...) called, but only setup(ROOT::RNTupleModel, ...) should be implemented for this processor" << endmsg;
290 return StatusCode::FAILURE;
291 }
292
293 StatusCode ElementFieldProcessor::process( const SG::AuxElement& element, MsgStream& /*msg*/ ) {
294 // Use High-Level copy via TempInterface
295 // copy( auxid, dst_container, dst_index, src_container, src_index, n )
296 TempInterface dstiface( 1, m_acc->auxid(), m_dataPtr );
297 m_factory->copy( m_acc->auxid(), dstiface, 0, *element.container(), element.index(), 1 );
298 return StatusCode::SUCCESS;
299 }
300
301
302 // ======================================================================
303 // ContainerFieldProcessor
304 // ======================================================================
305
306 StatusCode ContainerFieldProcessor::setup( ROOT::RNTupleModel& model,
307 const BranchConfig& branchConfig,
308 OutputBranchData& outputData,
309 MsgStream& msg ) {
310 m_fieldName = outputData.branchName;
311 m_acc.reset( new SG::TypelessConstAccessor( *branchConfig.auxType, outputData.auxName ) );
312
313 if( branchConfig.auxFactory && branchConfig.auxVecType ) {
314 m_factory = branchConfig.auxFactory;
315 const std::type_info* type_info = branchConfig.auxVecType;
316
317 m_field = makeField( model, m_fieldName, *type_info, m_dataPtr, m_ops, msg );
318 } else {
319 msg << MSG::ERROR << "BranchConfig not properly configured for " << outputData.auxName << endmsg;
320 return StatusCode::FAILURE;
321 }
322
323 if( !m_field ) return StatusCode::FAILURE;
324
325 if( !m_ops.resize || !m_ops.getData ) {
326 msg << MSG::ERROR << "Container field " << m_fieldName << " must be a vector type" << endmsg;
327 return StatusCode::FAILURE;
328 }
329 return StatusCode::SUCCESS;
330 }
331
332 StatusCode ContainerFieldProcessor::setup( TTree& /*tree*/,
333 const BranchConfig& /*branchConfig*/,
334 OutputBranchData& /*outputData*/,
335 MsgStream& msg ) {
336 msg << MSG::ERROR << "setup(TTree, ...) called, but only setup(ROOT::RNTupleModel, ...) should be implemented for this processor" << endmsg;
337 return StatusCode::FAILURE;
338 }
339
340 StatusCode ContainerFieldProcessor::resize( size_t size, MsgStream& /*msg*/ ) {
341 if( m_ops.resize ) {
342 m_ops.resize( size );
343 return StatusCode::SUCCESS;
344 }
345 return StatusCode::FAILURE;
346 }
347
348 StatusCode ContainerFieldProcessor::process( const SG::AuxElement& element, size_t index, MsgStream& msg ) {
349 void* rawDataPtr = getData();
350 if( !rawDataPtr && index > 0 ) return StatusCode::FAILURE;
351
352 try {
353 TempInterface dstiface( index + 1, m_acc->auxid(), rawDataPtr );
354 m_factory->copy( m_acc->auxid(), dstiface, index, *element.container(), element.index(), 1 );
355 } catch( ... ) {
356 msg << MSG::ERROR << "Failed to copy data for " << m_fieldName << endmsg;
357 return StatusCode::FAILURE;
358 }
359 return StatusCode::SUCCESS;
360 }
361
362
363 // ======================================================================
364 // ElementProcessor
365 // ======================================================================
366
367 ElementProcessor::ElementProcessor(const std::string& sgName)
368 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ElementProcessor/" + sgName ), m_sgName(sgName) {}
369
371 static const bool ALLOW_MISSING = false;
372 const SG::AuxElement* el = getElement( m_sgName,
373 evtStore,
374 ALLOW_MISSING, msg() );
375 if( ! el ) {
376 ATH_MSG_ERROR( "Failed to retrieve object \"" << m_sgName << "\"" );
377 return StatusCode::FAILURE;
378 }
379
380 for( auto& p : m_fields ) {
381 ATH_CHECK( p->process( *el, msg() ) );
382 }
383 return StatusCode::SUCCESS;
384 }
385
386 StatusCode ElementProcessor::addBranch( ROOT::RNTupleModel& model,
387 const BranchConfig& branchConfig,
388 OutputBranchData& outputData ) {
389 if( !auxItemExists(outputData.auxName) ) {
390 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
391 return StatusCode::FAILURE;
392 }
393 m_fields.emplace_back( std::make_unique<ElementFieldProcessor>() );
394 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
395 return StatusCode::SUCCESS;
396 }
397
398 StatusCode ElementProcessor::addBranch( TTree& /*tree*/,
399 const BranchConfig& /*branchConfig*/,
400 OutputBranchData& /*outputData*/ ) {
401 ATH_MSG_ERROR("ElementProcessor::addBranch for TTree should not be called");
402 return StatusCode::FAILURE;
403 }
404
405 // ======================================================================
406 // ContainerProcessor
407 // ======================================================================
408
409 ContainerProcessor::ContainerProcessor(const std::string& sgName)
410 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ContainerProcessor/" + sgName ), m_sgName(sgName) {}
411
412 StatusCode ContainerProcessor::addBranch( ROOT::RNTupleModel& model,
413 const BranchConfig& branchConfig,
414 OutputBranchData& outputData ) {
415 if( !auxItemExists(outputData.auxName) ) {
416 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
417 return StatusCode::FAILURE;
418 }
419 m_fields.emplace_back( std::make_unique<ContainerFieldProcessor>() );
420 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
421 return StatusCode::SUCCESS;
422 }
423
424 StatusCode ContainerProcessor::addBranch( TTree& /*tree*/,
425 const BranchConfig& /*branchConfig*/,
426 OutputBranchData& /*outputData*/ ) {
427 ATH_MSG_ERROR("ContainerProcessor::addBranch for TTree should not be called");
428 return StatusCode::FAILURE;
429 }
430
432 // Retrieve the container:
433 static const bool ALLOW_MISSING = false;
434 const TClass* cl = nullptr;
435 const SG::AuxVectorBase* vec = getVector( m_sgName,
436 evtStore,
437 ALLOW_MISSING, cl, msg() );
438
439 if( ! vec ) {
440 ATH_MSG_ERROR( "Failed to retrieve container \""
441 << m_sgName << "\"" );
442 return StatusCode::FAILURE;
443 }
444 const SG::AuxVectorBase& container = *vec;
445 if( ! m_collProxy ) {
446
447 // Get the collection proxy from the dictionary.
448 m_collProxy = cl->GetCollectionProxy();
449 if( ! m_collProxy ) {
450 ATH_MSG_ERROR( "No collection proxy provided by type: "
451 << cl->GetName() );
452 return StatusCode::FAILURE;
453 }
454
455 // Get the offset that one needs to use to get from the element
456 // pointers to SG::AuxElement pointers.
457 static const TClass* const auxElementClass =
458 TClass::GetClass( typeid( SG::AuxElement ) );
460 m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass );
461 if( m_auxElementOffset < 0 ) {
462 ATH_MSG_ERROR( "Vector element type \""
463 << m_collProxy->GetValueClass()->GetName()
464 << "\" doesn't seem to inherit from \""
465 << auxElementClass->GetName() << "\"" );
466 return StatusCode::FAILURE;
467 }
468 }
469
470 void* cPtr =
471 const_cast< void* >( static_cast< const void* >( &container ) );
472 TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr );
473 const UInt_t cSize = m_collProxy->Size();
474
475 for( auto& p : m_fields ) {
476 ATH_CHECK( p->resize( cSize, msg() ) );
477 }
478
479 for (UInt_t i = 0; i < cSize; ++i) {
480 char* elPtr = static_cast< char* >( m_collProxy->At( i ) );
481 if( ! elPtr ) {
482 ATH_MSG_ERROR( "Failed to get element " << i << " from container" );
483 return StatusCode::FAILURE;
484 }
485 const SG::AuxElement* element =
486 reinterpret_cast< const SG::AuxElement* >( elPtr +
488
489 for ( auto& p : m_fields ) {
490 ATH_CHECK( p->process( *element, i, msg() ) );
491 }
492 }
493 return StatusCode::SUCCESS;
494 }
495 // ======================================================================
496 // ElementProcessorMET
497 // ======================================================================
498 ElementProcessorMet::ElementProcessorMet(const std::string& sgName, const std::string& termName)
499 : ElementProcessor(sgName),
500 m_termName(termName) {
501 }
502
504
505 const xAOD::MissingETContainer* met = nullptr;
506 ANA_CHECK(evtStore.retrieve(met, m_sgName));
507 const SG::AuxElement& element = *(*met)[m_termName];
508 // Process all fields.
509 for (auto& p : m_fields) {
510 ATH_CHECK(p->process(element, msg()));
511 }
512
513 return StatusCode::SUCCESS;
514 }
515
516 // ======================================================================
517 // ProcessorList
518 // ======================================================================
519 StatusCode ProcessorList::setupTree( const std::vector<std::string>& branches,
520 std::unordered_set<std::string> nonContainers,
521 ISystematicsSvc& sysSvc,
522 ROOT::RNTupleModel& model ) {
523 m_nonContainers = std::move(nonContainers);
524
525 std::vector<BranchConfig> branchConfigs;
526 branchConfigs.reserve( branches.size() );
527 for ( const std::string& branchDecl : branches ) {
528 branchConfigs.emplace_back();
529 ATH_CHECK( branchConfigs.back().parse( branchDecl, msg() ) );
530 if (!branchConfigs.back().basketSize.has_value())
531 branchConfigs.back().basketSize = defaultBasketSize;
532 }
533
534 // This will loop over all branches, collect the name of any
535 // aux-store decorations that have no type and report them at the
536 // end. This allows to get the full list of missing decorations in
537 // a single run, as opposed to having to re-run the job once per
538 // missing decoration.
539 std::set<std::string> decosWithoutType;
540 for (auto& branchConfig : branchConfigs) {
541 ATH_CHECK ( branchConfig.configureTypes (decosWithoutType, msg()) );
542 }
543 if (!decosWithoutType.empty()) {
544 msg() << MSG::ERROR << "The following decorations have no type information:";
545 for (const auto& deco : decosWithoutType) {
546 msg() << " " << deco;
547 }
548 msg() << endmsg;
549 return StatusCode::FAILURE;
550 }
551
552
553 for (auto& branchConfig : branchConfigs) {
554 ATH_CHECK ( branchConfig.configureSystematics (sysSvc, msg()) );
555 }
556
557 auto sysVector = sysSvc.makeSystematicsVector();
558 // Ensure that the nominal systematic is first
559 if (!sysVector.at(0).empty()) {
560 ATH_MSG_ERROR ("The first systematic in the list is not nominal!");
561 return StatusCode::FAILURE;
562 }
563
564 // The branches we intend to write out
565 std::vector<OutputBranchData> outputBranches;
566
567 // All the branches that will be created
568 std::unordered_set<std::string> allBranches;
569
570 // Iterate over the branch specifications.
571 for( const auto& branchConfig : branchConfigs ) {
572
573 // All the branches that will be created for this rule
574 std::unordered_set<std::string> branchesForRule;
575
576 // Consider all systematics but skip the nominal one
577 for( const auto& sys : sysVector ) {
578
579 if (branchConfig.nominalOnly && !sys.empty()) continue;
580 OutputBranchData outputData;
581 outputData.branchConfig = &branchConfig;
582 outputData.sysIndex = &sys - &sysVector.front();
583 ATH_CHECK( outputData.configureNames (branchConfig, sys, sysSvc, msg()) );
584
585 // Skip branches that have already been created for other
586 // systematics for this rule. That's mostly nominal, but for
587 // systematics correlation studies it can also do other things.
588 if (branchesForRule.contains(outputData.branchName))
589 {
590 ANA_MSG_VERBOSE ("Branch \"" << outputData.branchName << "\" for rule \"" << branchConfig.branchDecl << "\" and systematic \"" << sys.name() << "\" already exists, skipping." );
591 continue;
592 }
593 branchesForRule.insert(outputData.branchName);
594
595 // If this branch already exists from another rule, report
596 // it as an error.
597 if (allBranches.contains(outputData.branchName))
598 {
599 ANA_MSG_ERROR ("Branch \"" << outputData.branchName << "\" would be created twice!" );
600 return StatusCode::FAILURE;
601 }
602 allBranches.insert(outputData.branchName);
603 outputBranches.push_back(std::move(outputData));
604 }
605 }
606
607 // Group all branches by systematic index to ensure that when
608 // reading a single systematic the branches are contiguous on
609 // disk.
610 std::stable_sort (outputBranches.begin(), outputBranches.end(),
611 [](const OutputBranchData& a, const OutputBranchData& b) {
612 return a.sysIndex < b.sysIndex; });
613
614 for (auto &outputData : outputBranches)
615 ATH_CHECK( setupBranch( *outputData.branchConfig, outputData, model ) );
616
617 // Return gracefully.
618 return StatusCode::SUCCESS;
619 }
620
621 StatusCode ProcessorList::setupBranch( const BranchConfig& branchConfig,
622 OutputBranchData& outputData,
623 ROOT::RNTupleModel& model ) {
624
625 ATH_CHECK( getObjectProcessor( branchConfig, outputData.sgName ).addBranch( model, branchConfig, outputData ) );
626 ATH_MSG_DEBUG( "Writing RNTuple field \"" << outputData.branchName
627 << "\" from container/variable \"" << outputData.sgName
628 << "." << outputData.auxName << "\"" );
629
630 return StatusCode::SUCCESS;
631 }
632
633 StatusCode ProcessorList::process( StoreType& evtStore ) {
634 for( auto& [name, processor] : m_processors ) {
635 ATH_CHECK( processor->retrieveProcess( evtStore ) );
636 }
637 return StatusCode::SUCCESS;
638 }
639
640 TreeBranchHelpers::IObjectProcessor& ProcessorList::getObjectProcessor( const BranchConfig& branchConfig, const std::string& sgName ) {
641 std::string processorName = sgName;
642 if (!branchConfig.metTermName.empty()) {
643 processorName += ":metTerm=" + branchConfig.metTermName;
644 }
645
646 if (auto iter = m_processors.find(processorName); iter != m_processors.end()) {
647 return *iter->second;
648 }
649 if (!branchConfig.metTermName.empty())
650 return *m_processors.emplace (processorName, std::make_unique<ElementProcessorMet>(sgName, branchConfig.metTermName)).first->second;
651
652
653 if (m_nonContainers.contains(sgName)) {
654 return *(m_processors.emplace(processorName, std::make_unique<ElementProcessor>(sgName)).first->second);
655 }
656 return *(m_processors.emplace(processorName, std::make_unique<ContainerProcessor>(sgName)).first->second);
657 }
658
659} // namespace RNtupleFieldHelpers
660} // 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
#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.
Base class for elements of a container that can have aux data.
Definition AuxElement.h:484
const SG::AuxVectorData * container() const
Return the container holding this element.
size_t index() const
Return the index of this element within its container.
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 TEvent to make it look like StoreGate.
Definition SgTEvent.h:44
bool contains(const std::string &name) const
Check if an object is available for constant access.
T * retrieve(const std::string &name) const
Function retrieving a constant or non-constant object.
xAOD::TStore * tds() const
Return the underlying transient data store.
Definition SgTEvent.cxx:33
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
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