ATLAS Offline Software
AsgxAODNTupleMakerAlg.cxx
Go to the documentation of this file.
1 // Copyright (C) 2002-2024 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 
27 namespace {
28 
29 
30 class TempInterface
31  : public SG::AuxVectorData
32 {
33 public:
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 
42 
43  virtual size_t size_v() const { return m_size; }
44  virtual size_t capacity_v() const { return m_size; }
45 
46 private:
47  size_t m_size;
48 };
49 
50 
51 } // anonymous namespace
52 
53 
54 namespace {
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:
207  const SG::AuxVectorBase* result =
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 
320 namespace 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.
345  m_tree = tree( m_treeName );
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
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;
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;
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::AuxElement::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 ) );
827  m_auxElementOffset =
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 +
861  m_auxElementOffset );
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::AuxElement::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
CP::AsgxAODNTupleMakerAlg::m_tree
TTree * m_tree
The tree being written.
Definition: AsgxAODNTupleMakerAlg.h:348
store
StoreGateSvc * store
Definition: fbtTestBasics.cxx:69
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::process
StatusCode process(const SG::AuxVectorBase &container, const TClass &cl)
Process the container.
Definition: AsgxAODNTupleMakerAlg.cxx:810
CP::AsgxAODNTupleMakerAlg::setupBranch
StatusCode setupBranch(const std::string &branchDecl, const CP::SystematicSet &sys)
Function setting up an individual branch on the first event.
Definition: AsgxAODNTupleMakerAlg.cxx:425
checkxAOD.brName
brName
Definition: Tools/PyUtils/bin/checkxAOD.py:113
get_generator_info.result
result
Definition: get_generator_info.py:21
StateLessPT_NewConfig.proxy
proxy
Definition: StateLessPT_NewConfig.py:392
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
xAOD::TStore::holder
const THolder * holder(const std::string &key) const
return holder for key
Definition: TStore.cxx:50
asg::SgTEvent::contains
bool contains(const std::string &name) const
Check if an object is available for constant access.
AsgxAODNTupleMakerAlg.h
python.Constants.FATAL
int FATAL
Definition: Control/AthenaCommon/python/Constants.py:19
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor::setup
StatusCode setup(TTree &tree, const std::string &auxName, const std::string &branchName, MsgStream &msg)
Function setting up the object, and the branch.
Definition: AsgxAODNTupleMakerAlg.cxx:931
CP::AsgxAODNTupleMakerAlg::ElementProcessor::process
StatusCode process(const SG::AuxElement &element)
Process the object.
Definition: AsgxAODNTupleMakerAlg.cxx:620
CP::AsgxAODNTupleMakerAlg::m_treeName
Gaudi::Property< std::string > m_treeName
The name of the output tree to write.
Definition: AsgxAODNTupleMakerAlg.h:91
DataBucketBase
A non-templated base class for DataBucket, allows to access the transient object address as a void*.
Definition: DataBucketBase.h:24
SG::AuxTypeRegistry::instance
static AuxTypeRegistry & instance()
Return the singleton registry instance.
Definition: AuxTypeRegistry.cxx:49
CP::AsgxAODNTupleMakerAlg::ElementProcessor::BranchProcessor::setup
StatusCode setup(TTree &tree, const std::string &auxName, const std::string &branchName, MsgStream &msg)
Function setting up the object, and the branch.
Definition: AsgxAODNTupleMakerAlg.cxx:690
SG::normalizedTypeinfoName
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...
Definition: normalizedTypeinfoName.cxx:120
index
Definition: index.py:1
SG::AuxElement
Base class for elements of a container that can have aux data.
Definition: AuxElement.h:446
xAOD::THolder
This class takes care of holding EDM objects in memory.
Definition: THolder.h:35
m_data
std::vector< T > m_data
Definition: TrackTruthMatchingBaseAlg.cxx:660
DataBucketBase::object
virtual void * object()=0
ATLAS_NOT_CONST_THREAD_SAFE
#define ATLAS_NOT_CONST_THREAD_SAFE
Definition: checker_macros.h:215
CP::SystematicSet::empty
bool empty() const
returns: whether the set is empty
Definition: SystematicSet.h:67
asg::SgTEvent::tds
xAOD::TStore * tds() const
Return the underlying transient data store.
Definition: SgTEvent.cxx:33
asg
Definition: DataHandleTestTool.h:28
CP::SystematicSet
Class to wrap a set of SystematicVariations.
Definition: SystematicSet.h:31
SG::DataProxy::accessData
DataObject * accessData()
Access DataObject on-demand using conversion service.
SG::TypelessConstAccessor
Helper class to provide const generic access to aux data.
Definition: TypelessConstAccessor.h:44
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor
Class writing one variable from an xAOD object into a branch.
Definition: AsgxAODNTupleMakerAlg.h:301
ANA_CHECK
#define ANA_CHECK(EXP)
check whether the given expression was successful
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:324
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
CP::SystematicVariation
Definition: SystematicVariation.h:47
python.DomainsRegistry.reg
reg
globals -----------------------------------------------------------------—
Definition: DomainsRegistry.py:343
CP
Select isolated Photons, Electrons and Muons.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:48
IProxyDict
A proxy dictionary.
Definition: AthenaKernel/AthenaKernel/IProxyDict.h:51
AuxVectorBase.h
Manage index tracking and synchronization of auxiliary data.
SG::AuxVectorBase
Manage index tracking and synchronization of auxiliary data.
Definition: AuxVectorBase.h:98
mapkey::sys
@ sys
Definition: TElectronEfficiencyCorrectionTool.cxx:42
CP::AsgxAODNTupleMakerAlg::ElementProcessor::BranchProcessor
Class writing one variable from an xAOD object into a branch.
Definition: AsgxAODNTupleMakerAlg.h:162
SG::IAuxStoreIO
Interface providing I/O for a generic auxiliary store.
Definition: IAuxStoreIO.h:44
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::ContainerProcessor
ContainerProcessor()
Default constructor.
Definition: AsgxAODNTupleMakerAlg.cxx:804
CP::AsgxAODNTupleMakerAlg::execute
StatusCode execute() override
Function executed once per event.
Definition: AsgxAODNTupleMakerAlg.cxx:340
StoreGateSvc::retrieve
StatusCode retrieve(const T *&ptr) const
Retrieve the default object into a const T*.
runBeamSpotCalibration.helper
helper
Definition: runBeamSpotCalibration.py:112
PrepareReferenceFile.regex
regex
Definition: PrepareReferenceFile.py:43
SG::AuxTypeRegistry
Handle mappings between names and auxid_t.
Definition: AuxTypeRegistry.h:62
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor::process
StatusCode process(const SG::AuxElement &element, size_t index, MsgStream &msg)
Function processing the object, filling the variable.
Definition: AsgxAODNTupleMakerAlg.cxx:1011
SG::AuxVectorData::setStore
void setStore(SG::IAuxStore *store)
Set the store associated with this object.
Definition: AuxVectorData.cxx:114
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
AthCommonDataStore< AthCommonMsg< Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
asg::SgTEvent::retrieve
T * retrieve(const std::string &name) const
Function retrieving a constant or non-constant object.
SG::auxid_t
size_t auxid_t
Identifier for a particular aux data item.
Definition: AuxTypes.h:27
StoreGateSvc
The Athena Transient Store API.
Definition: StoreGateSvc.h:128
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:92
SG::AuxVectorData::setCache
void setCache(SG::auxid_t auxid, void *ptr)
Explicitly set a cache pointer.
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor::resize
StatusCode resize(size_t size, MsgStream &msg)
Function (re)sizing the variable for a new event.
Definition: AsgxAODNTupleMakerAlg.cxx:994
IProxyDict::proxies
virtual std::vector< const SG::DataProxy * > proxies() const =0
Return the list of all current proxies in store.
IAuxStoreIO.h
Interface providing I/O for a generic auxiliary store.
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
top::nominal
@ nominal
Definition: ScaleFactorRetriever.h:29
CP::AsgxAODNTupleMakerAlg::m_isInitialized
bool m_isInitialized
Internal status flag, showing whether the algorithm is initialised.
Definition: AsgxAODNTupleMakerAlg.h:361
CP::AsgxAODNTupleMakerAlg::m_containers
std::unordered_map< std::string, ContainerProcessor > m_containers
Containers to write branches from.
Definition: AsgxAODNTupleMakerAlg.h:353
plotIsoValidation.el
el
Definition: plotIsoValidation.py:197
CP::SystematicSet::end
const_iterator end() const
description: const iterator to the end of the set
Definition: SystematicSet.h:59
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
CP::AsgxAODNTupleMakerAlg::m_systematicsService
ServiceHandle< ISystematicsSvc > m_systematicsService
the handle for the systematics service
Definition: AsgxAODNTupleMakerAlg.h:364
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
normalizedTypeinfoName.h
Convert a type_info to a normalized string representation (matching the names used in the root dictio...
CP::SystematicSet::insert
void insert(const SystematicVariation &systematic)
description: insert a systematic into the set
Definition: SystematicSet.cxx:88
ANA_MSG_VERBOSE
#define ANA_MSG_VERBOSE(xmsg)
Macro printing verbose messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:286
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
CP::AsgxAODNTupleMakerAlg::ElementProcessor::addBranch
StatusCode addBranch(TTree &tree, const std::string &auxName, const std::string &branchName, bool allowMissing, bool &created)
Add one branch to the output tree.
Definition: AsgxAODNTupleMakerAlg.cxx:632
CP::AsgxAODNTupleMakerAlg::ElementProcessor::BranchProcessor::process
StatusCode process(const SG::AuxElement &element, MsgStream &msg)
Function processing the object, filling the variable.
Definition: AsgxAODNTupleMakerAlg.cxx:784
asg::SgTEvent
Wrapper for TEvent to make it look like StoreGate.
Definition: SgTEvent.h:44
CP::SystematicSet::find
iterator find(const SystematicVariation &sys) const
description: find an element in the set
Definition: SystematicSet.h:63
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
CP::AsgxAODNTupleMakerAlg::finalize
StatusCode finalize() override
Function executed as part of the job finalisation.
Definition: AsgxAODNTupleMakerAlg.cxx:394
CP::AsgxAODNTupleMakerAlg::ContainerProcessor::addBranch
StatusCode addBranch(TTree &tree, const std::string &auxName, const std::string &branchName, bool allowMissing, bool &created)
Add one branch to the output tree.
Definition: AsgxAODNTupleMakerAlg.cxx:874
xAOD::THolder::getTypeInfo
const std::type_info * getTypeInfo() const
Definition: THolder.cxx:411
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
IAuxTypeVectorFactory.h
Interface for factory objects that create vectors.
re
const boost::regex re(r_e)
AthCommonMsg< Algorithm >::msg
MsgStream & msg() const
Definition: AthCommonMsg.h:24
THolder.h
CP::AsgxAODNTupleMakerAlg::initialize
StatusCode initialize() override
Function executed as part of the job initialisation.
Definition: AsgxAODNTupleMakerAlg.cxx:322
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
DataBucketBase::tinfo
virtual const std::type_info & tinfo() const =0
Return the type_info for the stored object.
CP::AsgxAODNTupleMakerAlg::setupTree
StatusCode setupTree()
Function setting up the internal data structures on the first event.
Definition: AsgxAODNTupleMakerAlg.cxx:400
SG::AuxVectorData
Manage lookup of vectors of auxiliary data.
Definition: AuxVectorData.h:167
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
SG::AuxElement::container
const SG::AuxVectorData * container() const
Return the container holding this element.
CP::AsgxAODNTupleMakerAlg::m_branches
Gaudi::Property< std::vector< std::string > > m_branches
The branches to write into this output tree.
Definition: AsgxAODNTupleMakerAlg.h:93
AthHistogramming::m_name
std::string m_name
Instance name.
Definition: AthHistogramming.h:245
SG::DataProxy
Definition: DataProxy.h:44
python.compressB64.c
def c
Definition: compressB64.py:93
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:26
CP::AsgxAODNTupleMakerAlg::m_elements
std::unordered_map< std::string, ElementProcessor > m_elements
Objects to write branches from.
Definition: AsgxAODNTupleMakerAlg.h:351
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
xAOD::Utils::rootType
char rootType(char typeidType)
This function is used internally in the code when creating primitive dynamic auxiliary branches.
Definition: Control/xAODRootAccess/Root/Utils.cxx:226
SG::AuxVectorData::capacity_v
virtual size_t capacity_v() const =0
Return the capacity of the container.
SG::AuxVectorData::size_v
virtual size_t size_v() const =0
Return the size of the container.
CP::SystematicSet::filterForAffectingSystematics
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
Definition: SystematicSet.cxx:213
match
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition: hcg.cxx:356
AuxElement.h
Base class for elements of a container that can have aux data.
AthHistogramming::tree
TTree * tree(const std::string &treeName, const std::string &tDir="", const std::string &stream="")
Simplify the retrieval of registered TTrees.
Definition: AthHistogramming.cxx:378
PlotCalibFromCool.br
br
Definition: PlotCalibFromCool.py:355
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
CP::AsgxAODNTupleMakerAlg::ElementProcessor::ElementProcessor
ElementProcessor()
Default constructor.
Definition: AsgxAODNTupleMakerAlg.cxx:614