ATLAS Offline Software
Loading...
Searching...
No Matches
AsgxAODNTupleMakerAlg.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3// Local include(s):
5
6// EDM include(s):
13
14// ROOT include(s):
15#include <TClass.h>
16#include <TTree.h>
17#include <TBranch.h>
18#include <TVirtualCollectionProxy.h>
19
20// System include(s):
21#include <regex>
22#include <algorithm>
23#include <functional>
24#include <sstream>
25
26
27namespace {
28
29
30class TempInterface
31 : public SG::AuxVectorData
32{
33public:
34 TempInterface (size_t size) : m_size (size) {}
35 TempInterface (size_t size, SG::auxid_t auxid, void* ptr) :
36 m_size (size)
37 {
38 setCache (auxid, ptr);
39 }
40
41 using AuxVectorData::setStore;
42
43 virtual size_t size_v() const { return m_size; }
44 virtual size_t capacity_v() const { return m_size; }
45
46private:
47 size_t m_size;
48};
49
50
51} // anonymous namespace
52
53
54namespace {
55
56#ifdef XAOD_STANDALONE
57
70 const SG::AuxVectorBase* getVector( const std::string& key,
71 asg::SgTEvent& evtStore,
72 bool allowMissing,
73 const TClass*& cl,
74 MsgStream& msg ) {
75 if( allowMissing &&
76 ( ! evtStore.contains< const SG::AuxVectorBase >( key ) ) ) {
77 return nullptr;
78 }
79 const SG::AuxVectorBase* c = nullptr;
80 if( ! evtStore.retrieve( c, key ).isSuccess() ) {
81 msg << MSG::ERROR << "Couldn't retrieve container with key \"" << key
82 << "\"" << endmsg;
83 return nullptr;
84 }
85 const xAOD::THolder* holder = evtStore.tds()->holder( key );
86 if( holder != nullptr ) {
87 // If the object is in the transient store, get the type of it from
88 // the transient store itself. So that ConstDataVector types would be
89 // handled correctly.
90 const std::type_info* ti = holder->getTypeInfo();
91 cl = TClass::GetClass( *ti );
92 } else {
93 // If the object is not in the transient store, let's just use its
94 // "actual type".
95 cl = TClass::GetClass( typeid( *c ) );
96 }
97 if( ( allowMissing == false ) && ( cl == nullptr ) ) {
98 msg << MSG::ERROR
99 << "Couldn't find TClass dictionary for container \"" << key
100 << "\"" << endmsg;
101 return nullptr;
102 }
103
104 // Return the vector object.
105 return c;
106 }
107
119 const SG::AuxElement* getElement( const std::string& key,
120 asg::SgTEvent& evtStore,
121 bool allowMissing,
122 MsgStream& msg ) {
123 if( allowMissing &&
124 ( ! evtStore.contains< const SG::AuxElement >( key ) ) ) {
125 return nullptr;
126 }
127 const SG::AuxElement* e = nullptr;
128 if( ! evtStore.retrieve( e, key ).isSuccess() ) {
129 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
130 << "\"" << endmsg;
131 return nullptr;
132 }
133 return e;
134 }
135
136#else
137
139 class ProxyWithName {
140 public:
142 typedef const SG::DataProxy* argument_type;
144 ProxyWithName( const std::string& name ) : m_name( name ) {}
146 bool operator()( argument_type proxy ) const {
147 return ( proxy->name() == m_name );
148 }
149 private:
150 std::string m_name;
151 }; // class ProxyWithName
152
165 const SG::AuxVectorBase* getVector ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
166 IProxyDict& evtStore,
167 bool allowMissing,
168 const TClass*& cl,
169 MsgStream& msg ) {
170
171 // Find all proxies with this key:
172 auto proxies = evtStore.proxies();
173 proxies.erase( std::remove_if( proxies.begin(), proxies.end(),
174 std::not_fn( ProxyWithName( key ) ) ),
175 proxies.end() );
176 // Now iterate over them:
177 for( const SG::DataProxy* proxy : proxies ) {
178 // We need a non-const version of it... :-(
179 SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy );
180 // Try to get the right object out of it.
181 DataBucketBase* bucket =
182 dynamic_cast< DataBucketBase* >( proxy_nc->accessData() );
183 if( ! bucket ) {
184 // This is a big problem in the job. Return right away.
185 msg << MSG::ERROR
186 << "Couldn't access data object as a data bucket?!?" << endmsg;
187 return nullptr;
188 }
189 // Get the dictionary for the type:
190 cl = TClass::GetClass( bucket->tinfo() );
191 if( ! cl ) {
192 if( msg.level() <= MSG::VERBOSE ) {
193 msg << MSG::VERBOSE << "No dictionary found for: "
194 << bucket->tinfo().name() << endmsg;
195 }
196 continue;
197 }
198 // Check whether the object inherits from AuxVectorBase:
199 if( ! cl->InheritsFrom( "SG::AuxVectorBase" ) ) {
200 if( msg.level() <= MSG::VERBOSE ) {
201 msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName()
202 << "\" does not inherit from SG::AuxVectorBase" << endmsg;
203 }
204 continue;
205 }
206 // If all is well, just assume that the inheritance is direct/simple:
208 reinterpret_cast< const SG::AuxVectorBase* >( bucket->object() );
209 return result;
210 }
211
212 // Apparently we failed...
213 if( ! allowMissing ) {
214 msg << MSG::ERROR << "Couldn't retrieve object \"" << key
215 << "\" as SG::AuxVectorBase" << endmsg;
216 }
217 return nullptr;
218 }
219
231 const SG::AuxElement* getElement ATLAS_NOT_CONST_THREAD_SAFE ( const std::string& key,
232 StoreGateSvc& evtStore,
233 bool allowMissing,
234 MsgStream& msg ) {
235
236
237 const SG::AuxElement* e = nullptr;
238 if( !evtStore.retrieve( e, key ).isSuccess() ) {
239 if(!allowMissing) {
240 msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key
241 << "\"" << endmsg;
242 }
243 return nullptr;
244 }
245 return e;
246
247 }
248#endif // XAOD_STANDALONE
249
258 char rootType( char typeidType, MsgStream& msg ) {
259
260 // Do the hard-coded translation:
261 switch( typeidType ) {
262
263 case 'c':
264 return 'B';
265 break;
266 case 'h':
267 return 'b';
268 break;
269 case 's':
270 return 'S';
271 break;
272 case 't':
273 return 's';
274 break;
275 case 'i':
276 return 'I';
277 break;
278 case 'j':
279 return 'i';
280 break;
281 case 'f':
282 return 'F';
283 break;
284 case 'd':
285 return 'D';
286 break;
287 case 'x':
288 return 'L';
289 break;
290 case 'y':
291 case 'm': // Not sure how platform-independent this one is...
292 return 'l';
293 break;
294 case 'b':
295 return 'O';
296 break;
297 default:
298 // If we didn't find this type:
299 msg << MSG::ERROR << "Received an unknown type: " << typeidType
300 << endmsg;
301 return '\0';
302 break;
303 }
304 }
305
311 bool auxItemExists( const std::string& key ) {
312 // Get a pointer to the vector factory.
314
315 // Try to find the aux item
316 return reg.findAuxID( key ) != SG::null_auxid;
317 }
318} // private namespace
319
320namespace CP {
321
323
324 // Check that at least one branch is configured.
325 if( m_branches.empty() ) {
326 ATH_MSG_ERROR( "No branches set up for writing" );
327 return StatusCode::FAILURE;
328 }
329
330 // Set up the systematics list.
331 ATH_CHECK( m_systematicsService.retrieve() );
332
333 // Reset the initialisation flag:
334 m_isInitialized = false;
335
336 // Return gracefully.
337 return StatusCode::SUCCESS;
338 }
339
341
342 // Initialise the processor objects on the first event.
343 if( ! m_isInitialized ) {
344 // Initialise the output tree.
346 if( ! m_tree ) {
347 ATH_MSG_ERROR( "Could not find output tree \"" << m_treeName
348 << "\"" );
349 return StatusCode::FAILURE;
350 }
351 // Call the setup function.
352 ATH_CHECK( setupTree() );
353 // The processor objects are now set up.
354 m_isInitialized = true;
355 }
356
357 // Process the standalone objects:
358 for( auto& element_itr : m_elements ) {
359 // Retrieve the object:
360 static const bool ALLOW_MISSING = false;
361 const SG::AuxElement* el = getElement( element_itr.first,
362 *( evtStore() ),
363 ALLOW_MISSING, msg() );
364 if( ! el ) {
365 ATH_MSG_ERROR( "Failed to retrieve object \"" << element_itr.first
366 << "\"" );
367 return StatusCode::FAILURE;
368 }
369 // Process it:
370 ATH_CHECK( element_itr.second.process( *el ) );
371 }
372
373 // Process the container objects:
374 for( auto& container_itr : m_containers ) {
375 // Retrieve the container:
376 static const bool ALLOW_MISSING = false;
377 const TClass* cl = nullptr;
378 const SG::AuxVectorBase* vec = getVector( container_itr.first,
379 *( evtStore() ),
380 ALLOW_MISSING, cl, msg() );
381 if( ! vec ) {
382 ATH_MSG_ERROR( "Failed to retrieve container \""
383 << container_itr.first << "\"" );
384 return StatusCode::FAILURE;
385 }
386 // Process it.
387 ATH_CHECK( container_itr.second.process( *vec, *cl ) );
388 }
389
390 // Return gracefully.
391 return StatusCode::SUCCESS;
392 }
393
395
396 // Return gracefully.
397 return StatusCode::SUCCESS;
398 }
399
401
402 // First process nominal
403 CP::SystematicSet nominal{};
404 for( const std::string& branchDecl : m_branches ) {
405 ATH_CHECK( setupBranch( branchDecl, nominal ) );
406 }
407
408 // Consider all systematics but skip the nominal one
409 for( const auto& sys : m_systematicsService->makeSystematicsVector() ) {
410 // Nominal already processed
411 if( sys.empty() ) {
412 continue;
413 }
414
415 // Iterate over the branch specifications.
416 for( const std::string& branchDecl : m_branches ) {
417 ATH_CHECK( setupBranch( branchDecl, sys ) );
418 }
419 }
420
421 // Return gracefully.
422 return StatusCode::SUCCESS;
423 }
424
425 StatusCode AsgxAODNTupleMakerAlg::setupBranch( const std::string &branchDecl,
426 const CP::SystematicSet &sys ) {
427
428 // The regular expression used to extract the needed info. The logic
429 // is supposed to be:
430 //
431 // (match[1]).(match[2])<any whitespace>-><any whitespace>(match[3])
432 //
433 // Like:
434 // "Electrons.eta -> el_eta"
435 //
436 // , where we would pick up "Electrons", "eta" and "el_eta" as the
437 // three words using this regexp.
438 static const std::regex
439 re( "\\s*([\\w%]+)\\.([\\w%]+)\\s*->\\s*([\\w%]+)" );
440
441 // Interpret this branch declaration.
442 std::smatch match;
443 if( ! std::regex_match( branchDecl, match, re ) ) {
444 ATH_MSG_ERROR( "Expression \"" << branchDecl
445 << "\" doesn't match \"<object>.<variable> ->"
446 " <branch>\"" );
447 return StatusCode::FAILURE;
448 }
449
450 // Check if we are running nominal
451 bool nominal = sys.empty();
452 // Check if we are affected by the systematics
453 bool systematicsContainer{false};
454 bool systematicsDecoration{false};
455 bool affectedContainer{true};
456 bool affectedDecoration{true};
457
458 // Event store key for the object under consideration.
459 std::string key = match[ 1 ];
460 if( key.find( "%SYS%" ) != std::string::npos )
461 {
462 systematicsContainer = true;
463 const CP::SystematicSet affecting = m_systematicsService->getObjectSystematics( key );
464 CP::SystematicSet matching;
465 ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
466 if( !nominal && matching.empty() ) {
467 ATH_MSG_VERBOSE( "Container \"" << key << "\" is not affected by systematics \"" << sys.name() << "\"" );
468 affectedContainer = false;
469 }
470 ANA_CHECK( m_systematicsService->makeSystematicsName( key, match[ 1 ], matching ) );
471 }
472 // Auxiliary variable name for the object under consideration.
473 std::string auxName = match[ 2 ];
474 if( auxName.find( "%SYS%" ) != std::string::npos )
475 {
476 systematicsDecoration = true;
477 CP::SystematicSet affecting = m_systematicsService->getDecorSystematics( match[ 1 ], auxName );
478 if( affecting.empty() )
479 {
480 // Sometimes while object systematics were applied we are not interested in them,
481 // NOSYS will then be used on the container name.
482 // Decoration systematics however will only be aware of containers with %SYS% included.
483 // Some special handling is needed to translate from NOSYS back to %SYS%.
484 const auto nosysInKey = key.find( "NOSYS" );
485 if( nosysInKey != std::string::npos )
486 {
487 std::string sysKey = key;
488 sysKey.replace (nosysInKey, 5, "%SYS%");
489 // these will be all systematics (object+decor)
490 const CP::SystematicSet affectingDecor = m_systematicsService->getDecorSystematics( sysKey, auxName );
491 // we now need to filter-out object systematics
492 const CP::SystematicSet affectingObject = m_systematicsService->getObjectSystematics( sysKey );
493 for( const CP::SystematicVariation &variation : affectingDecor )
494 {
495 if( affectingObject.find( variation ) == affectingObject.end() )
496 {
497 affecting.insert( variation );
498 }
499 }
500 }
501 }
502 CP::SystematicSet matching;
503 ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
504 if( !nominal && matching.empty() ) {
505 ATH_MSG_VERBOSE( "Decoration \"" << auxName << "\" is not affected by systematics \"" << sys.name() << "\"" );
506 affectedDecoration = false;
507 }
508 ANA_CHECK( m_systematicsService->makeSystematicsName( auxName, match[ 2 ], matching ) );
509 }
510
511 // Ignore the branch if neither container nor decoration are affected by the systematic
512 if( !nominal
513 && ( ( systematicsContainer && systematicsDecoration && !affectedContainer && !affectedDecoration )
514 || ( !systematicsContainer && systematicsDecoration && !affectedDecoration )
515 || ( systematicsContainer && !systematicsDecoration && !affectedContainer ) ) )
516 {
517 ANA_MSG_VERBOSE( "Neither container nor decoration are affected by systematics \"" << sys.name() << "\""
518 << " for branch rule \"" << branchDecl << "\"" );
519 return StatusCode::SUCCESS;
520 }
521
522 // Branch name for the variable.
523 std::string brName = match[ 3 ];
524 if( brName.find( "%SYS%" ) != std::string::npos )
525 ANA_CHECK (m_systematicsService->makeSystematicsName( brName, match[ 3 ], sys ));
526
527 // If the %SYS% pattern was not used in this setup, then stop
528 // on non-nominal systematic.
529 if( ! nominal &&
530 ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
531 ( brName == match[ 3 ] ) ) {
532 return StatusCode::SUCCESS;
533 }
534
535 // Check that we use the %SYS% pattern reasonably in the names.
536 if( ( ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
537 ( brName != match[ 3 ] ) ) ||
538 ( ( ( key != match[ 1 ] ) || ( auxName != match[ 2 ] ) ) &&
539 ( brName == match[ 3 ] ) ) ) {
540 ATH_MSG_ERROR( "The systematic variation pattern is used "
541 "inconsistently in: \"" << branchDecl
542 << "\"" );
543 return StatusCode::FAILURE;
544 }
545
546 // Flag keeping track whether any branch was set up for this rule.
547 bool branchCreated = false;
548
549 // Decide whether the specified key belongs to a container or
550 // a standalone object.
551 static const bool ALLOW_MISSING = true;
552 const TClass* cl = nullptr;
553 if(const SG::AuxVectorData *vec = getVector( key, *( evtStore() ), ALLOW_MISSING, cl,
554 msg() ) ) {
555 // Force loading dynamic aux variables if possible
556 if (const auto *store = dynamic_cast<const SG::IAuxStoreIO *>(vec->getConstStore()))
557 store->getDynamicAuxIDs();
558 bool created = false;
559 ATH_CHECK( m_containers[ key ].addBranch( *m_tree,
560 auxName,
561 brName,
562 ALLOW_MISSING,
563 created ) );
564 if( created ) {
565 ATH_MSG_DEBUG( "Writing branch \"" << brName
566 << "\" from container/variable \"" << key
567 << "." << auxName << "\"" );
568 branchCreated = true;
569 } else {
570 ATH_MSG_DEBUG( "Skipping branch \"" << brName
571 << "\" from container/variable \"" << key
572 << "." << auxName << "\"" );
573 }
574 } else if(const SG::AuxElement *ele = getElement( key, *( evtStore() ),
575 ALLOW_MISSING, msg() ) ) {
576 // Force loading dynamic aux variables if possible
577 if (const auto *store = dynamic_cast<const SG::IAuxStoreIO *>(ele->getConstStore()))
578 store->getDynamicAuxIDs();
579 bool created = false;
580 ATH_CHECK( m_elements[ key ].addBranch( *m_tree,
581 auxName,
582 brName,
583 ALLOW_MISSING,
584 created ) );
585 if( created ) {
586 ATH_MSG_DEBUG( "Writing branch \"" << brName
587 << "\" from object/variable \"" << key
588 << "." << auxName << "\"" );
589 branchCreated = true;
590 } else {
591 ATH_MSG_DEBUG( "Skipping branch \"" << brName
592 << "\" from object/variable \"" << key
593 << "." << auxName << "\"" );
594 }
595 } else {
596 ATH_MSG_DEBUG( "Container \"" << key
597 << "\" not readable for expression: \""
598 << branchDecl << "\"" );
599 }
600
601 // Check if the rule was meaningful or not:
602 if( ! branchCreated ) {
603 ATH_MSG_ERROR( "No branch was created for rule: \""
604 << branchDecl << "\""
605 << " and systematics: \""
606 << sys.name() << "\"" );
607 return StatusCode::FAILURE;
608 }
609
610 // Return gracefully.
611 return StatusCode::SUCCESS;
612 }
613
615 : asg::AsgMessaging( "CP::AsgxAODNTupleMakerAlg::ElementProcessor" ) {
616
617 }
618
620 process( const SG::AuxElement& element ) {
621
622 // Process all branches.
623 for( BranchProcessor& p : m_branches ) {
624 ATH_CHECK( p.process( element, msg() ) );
625 }
626
627 // Return gracefully.
628 return StatusCode::SUCCESS;
629 }
630
632 addBranch( TTree& tree, const std::string& auxName,
633 const std::string& branchName,
634 bool allowMissing,
635 bool &created ) {
636
638 class BranchFinder {
639 public:
641 typedef const BranchProcessor& argument_type;
643 BranchFinder( const std::string& branchName ) : m_name( branchName ) {}
645 bool operator()( argument_type bp ) const {
646 return ( bp.m_branchName == m_name );
647 }
648 private:
649 std::string m_name;
650 }; // class BranchFinder
651
652 // Check if the corresponding aux item exists
653 bool validAuxItem = auxItemExists( auxName );
654 if( ! validAuxItem ) {
655 if( allowMissing ) {
656 // Return gracefully.
657 ATH_MSG_DEBUG( "Aux item \"" << auxName
658 << "\" not readable for branch \""
659 << branchName << "\"" );
660 return StatusCode::SUCCESS;
661 } else {
662 // Return gracefully.
663 ATH_MSG_ERROR( "Aux item \"" << auxName
664 << "\" not readable for branch \""
665 << branchName << "\"" );
666 return StatusCode::FAILURE;
667 }
668 }
669
670 // Check whether this branch is already set up:
671 auto itr = std::find_if( m_branches.begin(), m_branches.end(),
672 BranchFinder( branchName ) );
673 if( itr != m_branches.end() ) {
674 ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName );
675 return StatusCode::SUCCESS;
676 }
677
678 created = true;
679
680 // Set up the new branch.
681 m_branches.emplace_back();
682 ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) );
683
684 // Return gracefully.
685 return StatusCode::SUCCESS;
686 }
687
688 StatusCode
690 setup( TTree& tree, const std::string& auxName,
691 const std::string& branchName, MsgStream& msg ) {
692
693 // Remember the branch name.
694 m_branchName = branchName;
695
696 // Create the accessor.
697 m_acc.reset( new SG::TypelessConstAccessor( auxName ) );
698
699 // Get a pointer to the vector factory.
701 const std::type_info* ti = reg.getType( m_acc->auxid() );
702 if( ! ti ) {
703 msg << MSG::ERROR
704 << "No std::type_info available for auxiliary variable: "
705 << auxName << endmsg;
706 return StatusCode::FAILURE;
707 }
708 m_factory = reg.getFactory( m_acc->auxid() );
709 if( ! m_factory ) {
710 msg << MSG::ERROR << "No factory found for auxiliary variable: "
711 << auxName << endmsg;
712 return StatusCode::FAILURE;
713 }
714
715 // Create the data object.
716 m_data = m_factory->create( m_acc->auxid(), 1, 1, false );
717
718 // Pointer to the branch, to be created.
719 TBranch* br = nullptr;
720
721 // Decide whether we're dealing with a "primitive" or an "object" branch.
722 if( strlen( ti->name() ) == 1 ) {
723
724 // This is a "primitive" variable...
725
726 // Get the type identifier for it that ROOT will understand.
727 const char rType = rootType( ti->name()[ 0 ], msg );
728 if( rType == '\0' ) {
729 msg << MSG::ERROR << "Type not recognised for variable: "
730 << branchName << endmsg;
731 return StatusCode::FAILURE;
732 }
733
734 // Construct the type description.
735 std::ostringstream typeDesc;
736 typeDesc << branchName << "/" << rType;
737
738 // Create the primitive branch.
739 br = tree.Branch( branchName.c_str(), m_data->toPtr(),
740 typeDesc.str().c_str() );
741
742 } else {
743
744 // This is an "object" variable...
745
746 // Get a proper type name for the variable.
747 const std::string typeName = SG::normalizedTypeinfoName( *ti );
748
749 // Access the dictionary for the type.
750 TClass* cl = TClass::GetClass( *ti );
751 if( ! cl ) {
752 cl = TClass::GetClass( typeName.c_str() );
753 }
754 if( ! cl ) {
755 msg << MSG::ERROR << "Couldn't find dictionary for type: "
756 << typeName << endmsg;
757 return StatusCode::FAILURE;
758 }
759 if( ! cl->GetStreamerInfo() ) {
760 msg << MSG::ERROR << "No streamer info available for type: "
761 << cl->GetName() << endmsg;
762 return StatusCode::FAILURE;
763 }
764
765 // Create the object branch.
766 m_dataPtr = m_data->toPtr();
767 br = tree.Branch( branchName.c_str(), cl->GetName(), &m_dataPtr );
768
769 }
770
771 // Check that the branch creation succeeded.
772 if( ! br ) {
773 msg << MSG::ERROR << "Failed to create branch: " << branchName
774 << endmsg;
775 return StatusCode::FAILURE;
776 }
777
778 // Return gracefully.
779 return StatusCode::SUCCESS;
780 }
781
782 StatusCode
784 process( const SG::AuxElement& element, MsgStream& msg ) {
785
786 // A security check.
787 if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
788 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
789 return StatusCode::FAILURE;
790 }
791
792 // Get the data out of the xAOD object.
793 //const void* auxData = ( *m_acc )( element );
794
795 // Copy it into the output variable.
796 TempInterface dstiface (m_data->size(), m_acc->auxid(), m_data->toPtr());
797 m_factory->copy( m_acc->auxid(), dstiface, 0,
798 *element.container(), element.index(), 1 );
799
800 // Return gracefully.
801 return StatusCode::SUCCESS;
802 }
803
805 : asg::AsgMessaging( "CP::AsgxAODNTupleMakerAlg::ContainerProcessor" ) {
806
807 }
808
810 process( const SG::AuxVectorBase& container, const TClass& cl ) {
811
812 // Get the collection proxy for the type if it's not available yet.
813 if( ! m_collProxy ) {
814
815 // Get the collection proxy from the dictionary.
816 m_collProxy = cl.GetCollectionProxy();
817 if( ! m_collProxy ) {
818 ATH_MSG_ERROR( "No collection proxy provided by type: "
819 << cl.GetName() );
820 return StatusCode::FAILURE;
821 }
822
823 // Get the offset that one needs to use to get from the element
824 // pointers to SG::AuxElement pointers.
825 static const TClass* const auxElementClass =
826 TClass::GetClass( typeid( SG::AuxElement ) );
828 m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass );
829 if( m_auxElementOffset < 0 ) {
830 ATH_MSG_ERROR( "Vector element type \""
831 << m_collProxy->GetValueClass()->GetName()
832 << "\" doesn't seem to inherit from \""
833 << auxElementClass->GetName() << "\"" );
834 return StatusCode::FAILURE;
835 }
836 }
837
838 // Set up the iteration over the elements of the container. In a really
839 // low level / ugly way...
840 void* cPtr =
841 const_cast< void* >( static_cast< const void* >( &container ) );
842 TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr );
843 const UInt_t cSize = m_collProxy->Size();
844
845 // Tell all branch processors to resize their variables.
846 for( BranchProcessor& p : m_branches ) {
847 ATH_CHECK( p.resize( cSize, msg() ) );
848 }
849
850 // Now iterate over the container.
851 for( UInt_t i = 0; i < cSize; ++i ) {
852
853 // Get the element.
854 char* elPtr = static_cast< char* >( m_collProxy->At( i ) );
855 if( ! elPtr ) {
856 ATH_MSG_ERROR( "Failed to get element " << i << " from container" );
857 return StatusCode::FAILURE;
858 }
859 const SG::AuxElement* element =
860 reinterpret_cast< const SG::AuxElement* >( elPtr +
862
863 // Execute all branch processors on this element.
864 for( BranchProcessor& p : m_branches ) {
865 ATH_CHECK( p.process( *element, i, msg() ) );
866 }
867 }
868
869 // Return gracefully.
870 return StatusCode::SUCCESS;
871 }
872
874 addBranch( TTree& tree, const std::string& auxName,
875 const std::string& branchName,
876 bool allowMissing,
877 bool &created ) {
878
880 class BranchFinder {
881 public:
883 typedef const BranchProcessor& argument_type;
885 BranchFinder( const std::string& branchName ) : m_name( branchName ) {}
887 bool operator()( argument_type bp ) const {
888 return ( bp.m_branchName == m_name );
889 }
890 private:
891 std::string m_name;
892 }; // class BranchFinder
893
894 // Check if the corresponding aux item exists
895 bool validAuxItem = auxItemExists( auxName );
896 if( ! validAuxItem ) {
897 if( allowMissing ) {
898 // Return gracefully.
899 ATH_MSG_DEBUG( "Aux item \"" << auxName
900 << "\" not readable for branch \""
901 << branchName << "\"" );
902 return StatusCode::SUCCESS;
903 } else {
904 // Return gracefully.
905 ATH_MSG_ERROR( "Aux item \"" << auxName
906 << "\" not readable for branch \""
907 << branchName << "\"" );
908 return StatusCode::FAILURE;
909 }
910 }
911
912 // Check whether this branch is already set up:
913 auto itr = std::find_if( m_branches.begin(), m_branches.end(),
914 BranchFinder( branchName ) );
915 if( itr != m_branches.end() ) {
916 ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName );
917 return StatusCode::SUCCESS;
918 }
919
920 created = true;
921
922 // Set up the new branch.
923 m_branches.emplace_back();
924 ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) );
925
926 // Return gracefully.
927 return StatusCode::SUCCESS;
928 }
929
931 setup( TTree& tree, const std::string& auxName,
932 const std::string& branchName, MsgStream& msg ) {
933
934 // Remember the branch name.
935 m_branchName = branchName;
936
937 // Create the accessor.
938 m_acc.reset( new SG::TypelessConstAccessor( auxName ) );
939
940 // Get a pointer to the vector factory.
942 const std::type_info* ti = reg.getType( m_acc->auxid() );
943 const std::type_info* vecTi = reg.getVecType( m_acc->auxid() );
944 if( ( ! ti ) || ( ! vecTi ) ) {
945 msg << MSG::ERROR
946 << "No std::type_info available for auxiliary variable: "
947 << auxName << endmsg;
948 return StatusCode::FAILURE;
949 }
950 m_factory = reg.getFactory( m_acc->auxid() );
951 if( ! m_factory ) {
952 msg << MSG::ERROR << "No factory found for auxiliary variable: "
953 << auxName << endmsg;
954 return StatusCode::FAILURE;
955 }
956
957 // Create the data object.
958 m_data = m_factory->create( m_acc->auxid(), 0, 0, false );
959
960 // Get a proper type name for the variable.
961 const std::string typeName = SG::normalizedTypeinfoName( *vecTi );
962
963 // Access the dictionary for the type.
964 TClass* cl = TClass::GetClass( *vecTi );
965 if( ! cl ) {
966 cl = TClass::GetClass( typeName.c_str() );
967 }
968 if( ! cl ) {
969 msg << MSG::ERROR << "Couldn't find dictionary for type: "
970 << typeName << endmsg;
971 return StatusCode::FAILURE;
972 }
973 if( ! cl->GetStreamerInfo() ) {
974 msg << MSG::ERROR << "No streamer info available for type: "
975 << cl->GetName() << endmsg;
976 return StatusCode::FAILURE;
977 }
978
979 // Create the branch.
980 m_dataPtr = m_data->toVector();
981 TBranch* br = tree.Branch( branchName.c_str(), cl->GetName(),
982 &m_dataPtr );
983 if( ! br ) {
984 msg << MSG::ERROR << "Failed to create branch: " << branchName
985 << endmsg;
986 return StatusCode::FAILURE;
987 }
988
989 // Return gracefully.
990 return StatusCode::SUCCESS;
991 }
992
994 resize( size_t size, MsgStream& msg ) {
995
996 // A security check.
997 if( ! m_data ) {
998 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
999 return StatusCode::FAILURE;
1000 }
1001
1002 // Do the deed.
1003 m_data->resize( 0 );
1004 m_data->resize( size );
1005
1006 // Return gracefully.
1007 return StatusCode::SUCCESS;
1008 }
1009
1011 process( const SG::AuxElement& element, size_t index, MsgStream& msg ) {
1012
1013 // A security check.
1014 if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
1015 msg << MSG::FATAL << "Internal logic error detected" << endmsg;
1016 return StatusCode::FAILURE;
1017 }
1018
1019 // Get the data out of the xAOD object.
1020 //const void* auxData = ( *m_acc )( element );
1021
1022 // Copy it into the output variable.
1023 TempInterface dstiface (m_data->size(), m_acc->auxid(), m_data->toPtr());
1024 m_factory->copy( m_acc->auxid(), dstiface, index,
1025 *element.container(), element.index(), 1 );
1026
1027 // Return gracefully.
1028 return StatusCode::SUCCESS;
1029 }
1030
1031} // namespace CP
const boost::regex re(r_e)
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Base class for elements of a container that can have aux data.
Manage index tracking and synchronization of auxiliary data.
std::vector< size_t > vec
#define ANA_MSG_VERBOSE(xmsg)
Macro printing verbose messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
Interface providing I/O for a generic auxiliary store.
Interface for factory objects that create vectors.
#define ATLAS_NOT_CONST_THREAD_SAFE
TTree * tree(const std::string &treeName, const std::string &tDir="", const std::string &stream="")
Simplify the retrieval of registered TTrees.
std::string m_name
Instance name.
Class writing one variable from an xAOD object into a branch.
std::unique_ptr< SG::IAuxTypeVector > m_data
The object managing the memory of the written variable.
StatusCode process(const SG::AuxElement &element, size_t index, MsgStream &msg)
Function processing the object, filling the variable.
const SG::IAuxTypeVectorFactory * m_factory
Pointer to the helper object that handles this variable.
void * m_dataPtr
Helper variable, pointing at the object to be written.
StatusCode setup(TTree &tree, const std::string &auxName, const std::string &branchName, MsgStream &msg)
Function setting up the object, and the branch.
std::unique_ptr< SG::TypelessConstAccessor > m_acc
Object accessing the variable in question.
StatusCode resize(size_t size, MsgStream &msg)
Function (re)sizing the variable for a new event.
StatusCode process(const SG::AuxVectorBase &container, const TClass &cl)
Process the container.
std::list< BranchProcessor > m_branches
List of branch processors set up for this xAOD object.
StatusCode addBranch(TTree &tree, const std::string &auxName, const std::string &branchName, bool allowMissing, bool &created)
Add one branch to the output tree.
TVirtualCollectionProxy * m_collProxy
Collection proxy used for iterating over the container.
int m_auxElementOffset
Offset of the element type to SG::AuxElement.
Class writing one variable from an xAOD object into a branch.
std::unique_ptr< SG::TypelessConstAccessor > m_acc
Object accessing the variable in question.
const SG::IAuxTypeVectorFactory * m_factory
Pointer to the helper object that handles this variable.
StatusCode setup(TTree &tree, const std::string &auxName, const std::string &branchName, MsgStream &msg)
Function setting up the object, and the branch.
void * m_dataPtr
Helper variable, pointing at the object to be written.
std::string m_branchName
Name of the branch being written.
std::unique_ptr< SG::IAuxTypeVector > m_data
The object managing the memory of the written variable.
StatusCode process(const SG::AuxElement &element, MsgStream &msg)
Function processing the object, filling the variable.
StatusCode process(const SG::AuxElement &element)
Process the object.
StatusCode addBranch(TTree &tree, const std::string &auxName, const std::string &branchName, bool allowMissing, bool &created)
Add one branch to the output tree.
std::list< BranchProcessor > m_branches
List of branch processors set up for this xAOD object.
ServiceHandle< ISystematicsSvc > m_systematicsService
the handle for the systematics service
StatusCode execute() override
Function executed once per event.
StatusCode setupBranch(const std::string &branchDecl, const CP::SystematicSet &sys)
Function setting up an individual branch on the first event.
std::unordered_map< std::string, ElementProcessor > m_elements
Objects to write branches from.
StatusCode finalize() override
Function executed as part of the job finalisation.
bool m_isInitialized
Internal status flag, showing whether the algorithm is initialised.
Gaudi::Property< std::string > m_treeName
The name of the output tree to write.
StatusCode setupTree()
Function setting up the internal data structures on the first event.
TTree * m_tree
The tree being written.
Gaudi::Property< std::vector< std::string > > m_branches
The branches to write into this output tree.
std::unordered_map< std::string, ContainerProcessor > m_containers
Containers to write branches from.
StatusCode initialize() override
Function executed as part of the job initialisation.
Class to wrap a set of SystematicVariations.
bool empty() const
returns: whether the set is empty
const_iterator end() const
description: const iterator to the end of the set
void insert(const SystematicVariation &systematic)
description: insert a systematic into the set
iterator find(const SystematicVariation &sys) const
description: find an element in the set
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
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:483
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.
Interface providing I/O for a generic auxiliary store.
Definition IAuxStoreIO.h:44
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.
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
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
Select isolated Photons, Electrons and Muons.
std::string normalizedTypeinfoName(const std::type_info &info)
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
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
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition index.py:1
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.
char rootType(char typeidType)
This function is used internally in the code when creating primitive dynamic auxiliary branches.
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
MsgStream & msg
Definition testRead.cxx:32
TChain * tree