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 size_t size_v() const override { return m_size; }
37 size_t capacity_v() const override { 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 = std::make_unique<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 = std::make_unique<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 if( *type_info == typeid(std::vector<bool>) ) {
318 // std::vector<bool> provides no contiguous storage to copy into
319 msg << MSG::ERROR << "std::vector<bool> is not supported for container field " << m_fieldName << endmsg;
320 return StatusCode::FAILURE;
321 }
322
323 m_field = makeField( model, m_fieldName, *type_info, m_dataPtr, m_ops, msg );
324 } else {
325 msg << MSG::ERROR << "BranchConfig not properly configured for " << outputData.auxName << endmsg;
326 return StatusCode::FAILURE;
327 }
328
329 if( !m_field ) return StatusCode::FAILURE;
330
331 if( !m_ops.resize || !m_ops.getData ) {
332 msg << MSG::ERROR << "Container field " << m_fieldName << " must be a vector type" << endmsg;
333 return StatusCode::FAILURE;
334 }
335 return StatusCode::SUCCESS;
336 }
337
338 StatusCode ContainerFieldProcessor::setup( TTree& /*tree*/,
339 const BranchConfig& /*branchConfig*/,
340 OutputBranchData& /*outputData*/,
341 MsgStream& msg ) {
342 msg << MSG::ERROR << "setup(TTree, ...) called, but only setup(ROOT::RNTupleModel, ...) should be implemented for this processor" << endmsg;
343 return StatusCode::FAILURE;
344 }
345
346 StatusCode ContainerFieldProcessor::resize( size_t size, MsgStream& /*msg*/ ) {
347 if( m_ops.resize ) {
348 m_ops.resize( size );
349 return StatusCode::SUCCESS;
350 }
351 return StatusCode::FAILURE;
352 }
353
354 StatusCode ContainerFieldProcessor::process( const SG::AuxElement& element, size_t index, MsgStream& msg ) {
355 void* rawDataPtr = getData();
356 if( !rawDataPtr ) {
357 msg << MSG::ERROR << "No data available for " << m_fieldName << endmsg;
358 return StatusCode::FAILURE;
359 }
360
361 try {
362 TempInterface dstiface( index + 1, m_acc->auxid(), rawDataPtr );
363 m_factory->copy( m_acc->auxid(), dstiface, index, *element.container(), element.index(), 1 );
364 } catch( ... ) {
365 msg << MSG::ERROR << "Failed to copy data for " << m_fieldName << endmsg;
366 return StatusCode::FAILURE;
367 }
368 return StatusCode::SUCCESS;
369 }
370
371
372 // ======================================================================
373 // ElementProcessor
374 // ======================================================================
375
376 ElementProcessor::ElementProcessor(const std::string& sgName)
377 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ElementProcessor/" + sgName ), m_sgName(sgName) {}
378
380 static const bool ALLOW_MISSING = false;
381 const SG::AuxElement* el = getElement( m_sgName,
382 evtStore,
383 ALLOW_MISSING, msg() );
384 if( ! el ) {
385 ATH_MSG_ERROR( "Failed to retrieve object \"" << m_sgName << "\"" );
386 return StatusCode::FAILURE;
387 }
388
389 for( auto& p : m_fields ) {
390 ATH_CHECK( p->process( *el, msg() ) );
391 }
392 return StatusCode::SUCCESS;
393 }
394
395 StatusCode ElementProcessor::addBranch( ROOT::RNTupleModel& model,
396 const BranchConfig& branchConfig,
397 OutputBranchData& outputData ) {
398 if( !auxItemExists(outputData.auxName) ) {
399 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
400 return StatusCode::FAILURE;
401 }
402 m_fields.emplace_back( std::make_unique<ElementFieldProcessor>() );
403 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
404 return StatusCode::SUCCESS;
405 }
406
407 StatusCode ElementProcessor::addBranch( TTree& /*tree*/,
408 const BranchConfig& /*branchConfig*/,
409 OutputBranchData& /*outputData*/ ) {
410 ATH_MSG_ERROR("ElementProcessor::addBranch for TTree should not be called");
411 return StatusCode::FAILURE;
412 }
413
414 // ======================================================================
415 // ContainerProcessor
416 // ======================================================================
417
418 ContainerProcessor::ContainerProcessor(const std::string& sgName)
419 : asg::AsgMessaging( "CP::RNtupleFieldHelpers::ContainerProcessor/" + sgName ), m_sgName(sgName) {}
420
421 StatusCode ContainerProcessor::addBranch( ROOT::RNTupleModel& model,
422 const BranchConfig& branchConfig,
423 OutputBranchData& outputData ) {
424 if( !auxItemExists(outputData.auxName) ) {
425 ATH_MSG_ERROR("Aux item " << outputData.auxName << " missing");
426 return StatusCode::FAILURE;
427 }
428 m_fields.emplace_back( std::make_unique<ContainerFieldProcessor>() );
429 ATH_CHECK( m_fields.back()->setup( model, branchConfig, outputData, msg() ) );
430 return StatusCode::SUCCESS;
431 }
432
433 StatusCode ContainerProcessor::addBranch( TTree& /*tree*/,
434 const BranchConfig& /*branchConfig*/,
435 OutputBranchData& /*outputData*/ ) {
436 ATH_MSG_ERROR("ContainerProcessor::addBranch for TTree should not be called");
437 return StatusCode::FAILURE;
438 }
439
441 // Retrieve the container:
442 static const bool ALLOW_MISSING = false;
443 const TClass* cl = nullptr;
444 const SG::AuxVectorBase* vec = getVector( m_sgName,
445 evtStore,
446 ALLOW_MISSING, cl, msg() );
447
448 if( ! vec ) {
449 ATH_MSG_ERROR( "Failed to retrieve container \""
450 << m_sgName << "\"" );
451 return StatusCode::FAILURE;
452 }
453 const SG::AuxVectorBase& container = *vec;
454 if( ! m_collProxy ) {
455
456 // Get the collection proxy from the dictionary.
457 m_collProxy = cl->GetCollectionProxy();
458 if( ! m_collProxy ) {
459 ATH_MSG_ERROR( "No collection proxy provided by type: "
460 << cl->GetName() );
461 return StatusCode::FAILURE;
462 }
463
464 // Get the offset that one needs to use to get from the element
465 // pointers to SG::AuxElement pointers.
466 static const TClass* const auxElementClass =
467 TClass::GetClass( typeid( SG::AuxElement ) );
469 m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass );
470 if( m_auxElementOffset < 0 ) {
471 ATH_MSG_ERROR( "Vector element type \""
472 << m_collProxy->GetValueClass()->GetName()
473 << "\" doesn't seem to inherit from \""
474 << auxElementClass->GetName() << "\"" );
475 return StatusCode::FAILURE;
476 }
477 }
478
479 void* cPtr =
480 const_cast< void* >( static_cast< const void* >( &container ) );
481 TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr );
482 const UInt_t cSize = m_collProxy->Size();
483
484 for( auto& p : m_fields ) {
485 ATH_CHECK( p->resize( cSize, msg() ) );
486 }
487
488 for (UInt_t i = 0; i < cSize; ++i) {
489 char* elPtr = static_cast< char* >( m_collProxy->At( i ) );
490 if( ! elPtr ) {
491 ATH_MSG_ERROR( "Failed to get element " << i << " from container" );
492 return StatusCode::FAILURE;
493 }
494 const SG::AuxElement* element =
495 reinterpret_cast< const SG::AuxElement* >( elPtr +
497
498 for ( auto& p : m_fields ) {
499 ATH_CHECK( p->process( *element, i, msg() ) );
500 }
501 }
502 return StatusCode::SUCCESS;
503 }
504 // ======================================================================
505 // ElementProcessorMET
506 // ======================================================================
507 ElementProcessorMet::ElementProcessorMet(const std::string& sgName, const std::string& termName)
508 : ElementProcessor(sgName),
509 m_termName(termName) {
510 }
511
513
514 const xAOD::MissingETContainer* met = nullptr;
515 ANA_CHECK(evtStore.retrieve(met, m_sgName));
516 const xAOD::MissingET *term = (*met)[m_termName];
517 if( term == nullptr ) {
518 ANA_MSG_ERROR( "MET term " << m_termName << " not found in container " << m_sgName);
519 return StatusCode::FAILURE;
520 }
521 const SG::AuxElement& element = *term;
522 // Process all fields.
523 for (auto& p : m_fields) {
524 ATH_CHECK(p->process(element, msg()));
525 }
526
527 return StatusCode::SUCCESS;
528 }
529
530 // ======================================================================
531 // ProcessorList
532 // ======================================================================
533 StatusCode ProcessorList::setupTree( const std::vector<std::string>& branches,
534 std::unordered_set<std::string> nonContainers,
535 ISystematicsSvc& sysSvc,
536 ROOT::RNTupleModel& model ) {
537 m_nonContainers = std::move(nonContainers);
538
539 std::vector<BranchConfig> branchConfigs;
540 branchConfigs.reserve( branches.size() );
541 for ( const std::string& branchDecl : branches ) {
542 branchConfigs.emplace_back();
543 ATH_CHECK( branchConfigs.back().parse( branchDecl, msg() ) );
544 }
545
546 // This will loop over all branches, collect the name of any
547 // aux-store decorations that have no type and report them at the
548 // end. This allows to get the full list of missing decorations in
549 // a single run, as opposed to having to re-run the job once per
550 // missing decoration.
551 std::set<std::string> decosWithoutType;
552 for (auto& branchConfig : branchConfigs) {
553 ATH_CHECK ( branchConfig.configureTypes (decosWithoutType, msg()) );
554 }
555 if (!decosWithoutType.empty()) {
556 msg() << MSG::ERROR << "The following decorations have no type information:";
557 for (const auto& deco : decosWithoutType) {
558 msg() << " " << deco;
559 }
560 msg() << endmsg;
561 return StatusCode::FAILURE;
562 }
563
564
565 for (auto& branchConfig : branchConfigs) {
566 ATH_CHECK ( branchConfig.configureSystematics (sysSvc, msg()) );
567 }
568
569 auto sysVector = sysSvc.makeSystematicsVector();
570 // Ensure that the nominal systematic is first
571 if (!sysVector.at(0).empty()) {
572 ATH_MSG_ERROR ("The first systematic in the list is not nominal!");
573 return StatusCode::FAILURE;
574 }
575
576 // The branches we intend to write out
577 std::vector<OutputBranchData> outputBranches;
578
579 // All the branches that will be created
580 std::unordered_set<std::string> allBranches;
581
582 // Iterate over the branch specifications.
583 for( const auto& branchConfig : branchConfigs ) {
584
585 // All the branches that will be created for this rule
586 std::unordered_set<std::string> branchesForRule;
587
588 // Consider all systematics but skip the nominal one
589 for( const auto& sys : sysVector ) {
590
591 if (branchConfig.nominalOnly && !sys.empty()) continue;
592 OutputBranchData outputData;
593 outputData.branchConfig = &branchConfig;
594 outputData.sysIndex = &sys - &sysVector.front();
595 ATH_CHECK( outputData.configureNames (branchConfig, sys, sysSvc, msg()) );
596
597 // Skip branches that have already been created for other
598 // systematics for this rule. That's mostly nominal, but for
599 // systematics correlation studies it can also do other things.
600 if (branchesForRule.contains(outputData.branchName))
601 {
602 ANA_MSG_VERBOSE ("Branch \"" << outputData.branchName << "\" for rule \"" << branchConfig.branchDecl << "\" and systematic \"" << sys.name() << "\" already exists, skipping." );
603 continue;
604 }
605 branchesForRule.insert(outputData.branchName);
606
607 // If this branch already exists from another rule, report
608 // it as an error.
609 if (allBranches.contains(outputData.branchName))
610 {
611 ANA_MSG_ERROR ("Branch \"" << outputData.branchName << "\" would be created twice!" );
612 return StatusCode::FAILURE;
613 }
614 allBranches.insert(outputData.branchName);
615 outputBranches.push_back(std::move(outputData));
616 }
617 }
618
619 // Group all branches by systematic index to ensure that when
620 // reading a single systematic the branches are contiguous on
621 // disk.
622 std::stable_sort (outputBranches.begin(), outputBranches.end(),
623 [](const OutputBranchData& a, const OutputBranchData& b) {
624 return a.sysIndex < b.sysIndex; });
625
626 for (auto &outputData : outputBranches)
627 ATH_CHECK( setupBranch( *outputData.branchConfig, outputData, model ) );
628
629 // Return gracefully.
630 return StatusCode::SUCCESS;
631 }
632
633 StatusCode ProcessorList::setupBranch( const BranchConfig& branchConfig,
634 OutputBranchData& outputData,
635 ROOT::RNTupleModel& model ) {
636
637 ATH_CHECK( getObjectProcessor( branchConfig, outputData.sgName ).addBranch( model, branchConfig, outputData ) );
638 ATH_MSG_DEBUG( "Writing RNTuple field \"" << outputData.branchName
639 << "\" from container/variable \"" << outputData.sgName
640 << "." << outputData.auxName << "\"" );
641
642 return StatusCode::SUCCESS;
643 }
644
645 StatusCode ProcessorList::process( StoreType& evtStore ) {
646 for( auto& [name, processor] : m_processors ) {
647 ATH_CHECK( processor->retrieveProcess( evtStore ) );
648 }
649 return StatusCode::SUCCESS;
650 }
651
652 TreeBranchHelpers::IObjectProcessor& ProcessorList::getObjectProcessor( const BranchConfig& branchConfig, const std::string& sgName ) {
653 std::string processorName = sgName;
654 if (!branchConfig.metTermName.empty()) {
655 processorName += ":metTerm=" + branchConfig.metTermName;
656 }
657
658 if (auto iter = m_processors.find(processorName); iter != m_processors.end()) {
659 return *iter->second;
660 }
661 if (!branchConfig.metTermName.empty())
662 return *m_processors.emplace (processorName, std::make_unique<ElementProcessorMet>(sgName, branchConfig.metTermName)).first->second;
663
664
665 if (m_nonContainers.contains(sgName)) {
666 return *(m_processors.emplace(processorName, std::make_unique<ElementProcessor>(sgName)).first->second);
667 }
668 return *(m_processors.emplace(processorName, std::make_unique<ContainerProcessor>(sgName)).first->second);
669 }
670
671} // namespace RNtupleFieldHelpers
672} // namespace CP
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(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.
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:583
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:76
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.
MissingET_v1 MissingET
Version control by type defintion.
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