ATLAS Offline Software
MakeTransientTree.cxx
Go to the documentation of this file.
1 //
2 // Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 //
4 
5 // System include(s):
6 #include <cstring>
7 #include <iostream>
8 #include <memory>
9 
10 // ROOT include(s):
11 #include <TFile.h>
12 #include <TChain.h>
13 #include <TROOT.h>
14 #include <TError.h>
15 #include <TClass.h>
16 #include <TDirectory.h>
17 
18 // Local include(s):
25 #include "xAODRootAccess/TEvent.h"
26 
27 namespace {
28 
46  class TEventNotifier : public ::TObject {
47 
48  public:
50  TEventNotifier()
51  : m_tree( 0 ), m_event( 0 ) {}
53  TEventNotifier( ::TTree* tree, xAOD::TEvent* event )
54  : m_tree( tree ), m_event( event ) {}
55 
57  void Setup( ::TTree* tree, xAOD::TEvent* event ) {
58  m_tree = tree;
59  m_event = event;
60  return;
61  }
62 
64  virtual ::Bool_t Notify() {
65  if( ( ! m_tree ) || ( ! m_event ) ) {
66  ::Error( "TEventNotifier::Notify",
67  XAOD_MESSAGE( "Function called on uninitialised "
68  "object" ) );
69  return kFALSE;
70  }
71  if( ! m_event->readFrom( m_tree ) ) {
72  ::Error( "TEventNotifier::Notify",
73  XAOD_MESSAGE( "Couldn't notify TEvent object of TTree "
74  "update" ) );
75  return kFALSE;
76  }
77  return kTRUE;
78  }
79 
80  private:
82  ::TTree* m_tree;
84  xAOD::TEvent* m_event;
85 
86  }; // TEventNotifier
87 
102  class TTransObjectHolder {
103 
104  private:
106  class TVirtualTransObject {
107  public:
109  virtual ~TVirtualTransObject() {}
110  }; // class TVirtualTransObject
111 
113  template< typename T >
114  class TTransObject : public TVirtualTransObject {
115  public:
117  TTransObject( std::unique_ptr< T >&& obj )
118  : m_obj( std::move( obj ) ) {}
120  ~TTransObject() ATLAS_NOT_THREAD_SAFE {
121  // If ROOT is already deleted, then at least some of the objects
122  // are probably also deleted by now.
123  if( ! ROOT::Internal::gROOTLocal ) {
124  (void)m_obj.release();
125  }
126  // If we're in global cleanup, then they may also have been deleted.
127  if (TTransObjectHolder::s_inCleanup)
128  (void)m_obj.release();
129  }
130  private:
131  std::unique_ptr< T > m_obj;
132  }; // struct TTransObject
133 
134  public:
136  TTransObjectHolder() : m_objects() {}
137 
139  template< typename T >
140  void add( std::unique_ptr< T >&& obj ) {
141  m_objects.push_back( std::unique_ptr< TVirtualTransObject >(
142  new TTransObject< T >( std::move( obj ) ) ) );
143  return;
144  }
145 
147  void clear() {
148  m_objects.clear();
149  return;
150  }
151 
152  // Used to flag that we're cleaning up global objects at the end
153  // of the job.
154  struct Canary
155  {
156  ~Canary() { TTransObjectHolder::s_inCleanup = true; }
157  };
158  private:
160  std::vector< std::unique_ptr< TVirtualTransObject > > m_objects;
161 
163  inline static std::atomic<bool> s_inCleanup{false};
164  }; // class TTransObjectHolder
165 
166 
167 } // private namespace
168 
169 namespace xAOD {
170 
172  static ::TTransObjectHolder s_objectHolder;
174  static ::TTransObjectHolder::Canary s_canary;
175 
176  //
177  // Forward declare the private functions:
178  //
179  ::TTree* MakeTransientTree ATLAS_NOT_THREAD_SAFE ( TEvent& event, const char* treeName );
180  ::TTree* MakeTransientMetaTree ATLAS_NOT_THREAD_SAFE ( TEvent& event, ::TTree* persMetaTree );
181 
182  TTransTrees MakeTransientTrees ATLAS_NOT_THREAD_SAFE ( ::TFile* ifile,
183  const char* treeName,
185 
186  // Create a TEvent object that will take care of retrieving objects
187  // from the persistent trees:
188  std::unique_ptr< TEvent > event( new TEvent( mode ) );
189  if( ! event->readFrom( ifile, kTRUE, treeName ) ) {
190  ::Error( "xAOD::MakeTransientTrees",
191  XAOD_MESSAGE( "Couldn't set up the reading of the input "
192  "file" ) );
193  return TTransTrees( 0, 0 );
194  }
195 
196  // Access the metadata tree of the file:
197  ::TTree* metaTree = dynamic_cast< ::TTree* >( ifile->Get( "MetaData" ) );
198  if( ! metaTree ) {
199  ::Error( "xAOD::MakeTransientTrees",
200  XAOD_MESSAGE( "Couldn't access metadata tree \"MetaData\" "
201  "in the input file" ) );
202  return TTransTrees( 0, 0 );
203  }
204 
205  // Create the transient tree using this TEvent object:
206  ::TTree* ev = MakeTransientTree( *event, treeName );
207  ::TTree* meta = MakeTransientMetaTree( *event, metaTree );
208 
209  // If no problem happened so far, let's put in the TEvent object into
210  // the object holder:
211  s_objectHolder.add( std::move( event ) );
212 
213  // Return the tree pointers:
214  return TTransTrees( ev, meta );
215  }
216 
217  void ClearTransientTrees ATLAS_NOT_THREAD_SAFE () {
218 
219  s_objectHolder.clear();
220  return;
221  }
222 
223  ::TTree* MakeTransientTree ATLAS_NOT_THREAD_SAFE ( TEvent& event, const char* treeName ) {
224 
225  // Get the input file's format:
226  const EventFormat* ef = event.inputEventFormat();
227  if( ! ef ) {
228  ::Error( "xAOD::MakeTransientTree",
229  XAOD_MESSAGE( "Couldn't get the input file's format "
230  "metadata" ) );
231  return 0;
232  }
233 
234  // Remember which directory we are in now:
235  ::TDirectory* dir = gDirectory;
236 
237  // Create the transient tree:
238  gROOT->cd();
239  auto eventTree = std::make_unique< xAODTEventTree >( event, treeName );
240 
241  // Go back to the original directory:
242  dir->cd();
243 
244  // Make sure that the first file/event is loaded at this point.
245  if( event.getEntry( 0 ) < 0 ) {
246  ::Error( "xAOD::MakeTransientTree",
247  XAOD_MESSAGE( "Couldn't load first event" ) );
248  return 0;
249  }
250 
251  // Create a branch for each xAOD interface object:
252  EventFormat::const_iterator ef_itr = ef->begin();
253  EventFormat::const_iterator ef_end = ef->end();
254  for( ; ef_itr != ef_end; ++ef_itr ) {
255 
256  // Convenience reference:
257  const xAOD::EventFormatElement& efe = ef_itr->second;
258 
259  // Just skip all branches ending in "Aux.":
260  if( efe.branchName().rfind( "Aux." ) ==
261  ( efe.branchName().size() - 4 ) ) {
262  continue;
263  }
264  // Also skip dynamic branches:
265  if( efe.parentName() != "" ) {
266  continue;
267  }
268 
269  // Don't bother if the branch is not available:
270  if( ! event.m_inTree->GetBranch( efe.branchName().c_str() ) ) {
271  continue;
272  }
273 
274  // Check if the class in question is known:
275  ::TClass* cl = ::TClass::GetClass( efe.className().c_str() );
276  if( ! cl ) continue;
277 
278  // Don't add auxiliary store objects:
279  if( cl->InheritsFrom( "SG::IConstAuxStore" ) ) {
280  continue;
281  }
282 
283  // Check if we have a type-info for this class:
284  const std::type_info* ti = cl->GetTypeInfo();
285  if( ! ti ) {
286  ::Warning( "xAOD::MakeTransientTree",
287  "Couldn't find std::type_info object for type %s "
288  "(key=%s)", cl->GetName(), efe.branchName().c_str() );
289  continue;
290  }
291 
292  // Check if the object is actually available on the input:
293  if( ! event.contains( efe.branchName(), *ti ) ) {
294  continue;
295  }
296 
297  // If everything is right, let's make the branch:
298  auto br =
299  std::make_unique< xAODTEventBranch >( *eventTree, event, *ti,
300  efe.branchName().c_str(),
301  efe.className().c_str() );
302  eventTree->AddBranch( std::move( br ) );
303 
304  }
305 
306  // Grab a simple pointer to the tree:
307  ::TTree* result = eventTree.get();
308  // Now put it into the object store:
309  s_objectHolder.add( std::move( eventTree ) );
310 
311  // Return the object that was just created:
312  ::Info( "xAOD::MakeTransientTree",
313  "Created transient tree \"%s\" in ROOT's common memory",
314  treeName );
315  return result;
316  }
317 
318  ::TTree* MakeTransientTree ATLAS_NOT_THREAD_SAFE ( ::TFile* ifile, const char* treeName,
320 
321  // Create a TEvent object that will take care of retrieving objects
322  // from the persistent tree:
323  std::unique_ptr< TEvent > event( new TEvent( mode ) );
324  if( ! event->readFrom( ifile, kTRUE, treeName ) ) {
325  ::Error( "xAOD::MakeTransientTree",
326  XAOD_MESSAGE( "Couldn't set up the reading of the input "
327  "file" ) );
328  return 0;
329  }
330 
331  // Create the transient tree using this TEvent object:
332  ::TTree* result = MakeTransientTree( *event, treeName );
333 
334  // Put the event object into the object store:
335  s_objectHolder.add( std::move( event ) );
336 
337  // Return the created tree:
338  return result;
339  }
340 
341  ::TTree* MakeTransientTree ATLAS_NOT_THREAD_SAFE ( ::TChain* itree, TEvent::EAuxMode mode ) {
342 
343  // Create the objects used by the function:
344  std::unique_ptr< TEvent > event( new TEvent( mode ) );
345  std::unique_ptr< ::TEventNotifier > notifier( new ::TEventNotifier() );
346 
347  // Set up the TEvent object that will take care of retrieving objects
348  // from the persistent tree:
349  if( ! event->readFrom( itree ) ) {
350  ::Error( "xAOD::MakeTransientTree",
351  XAOD_MESSAGE( "Couldn't set up the reading of the input "
352  "tree/chain" ) );
353  return 0;
354  }
355 
356  // Load the first event, to trigger opening the first input file:
357  if( event->getEntry( 0 ) < 0 ) {
358  ::Error( "xAOD::MakeTransientTree",
359  XAOD_MESSAGE( "Couldn't load event 0 from the chain" ) );
360  return 0;
361  }
362 
363  // Set up an object taking care of notifying the TEvent object about
364  // changes in the TChain's status:
365  notifier->Setup( itree, event.get() );
366  itree->SetNotify( notifier.get() );
367 
368  // Create the transient tree using this TEvent object:
369  ::TTree* result = MakeTransientTree( *event, itree->GetName() );
370 
371  // Put all objects into the object store:
372  s_objectHolder.add( std::move( event ) );
373  s_objectHolder.add( std::move( notifier ) );
374 
375  // Return the created tree:
376  return result;
377  }
378 
379  ::TTree* MakeTransientMetaTree ATLAS_NOT_THREAD_SAFE ( TEvent& event, ::TTree* persMetaTree ) {
380 
381  // Remember which directory we are in now:
382  ::TDirectory* dir = gDirectory;
383 
384  // Create the transient metadata tree:
385  gROOT->cd();
386  auto metaTree = std::make_unique< xAODTMetaTree >( event );
387 
388  // Go back to the original directory:
389  dir->cd();
390 
391  // Loop over the branches of the persistent metadata tree:
392  TObjArray* branches = persMetaTree->GetListOfBranches();
393  for( ::Int_t i = 0; i < branches->GetEntries(); ++i ) {
394 
395  // Access the branch object:
396  ::TBranch* br = dynamic_cast< ::TBranch* >( branches->At( i ) );
397  if( ! br ) {
398  ::Error( "xAOD::MakeTransientMetaTree",
399  XAOD_MESSAGE( "Couldn't access branch %i as a TBranch" ),
400  i );
401  continue;
402  }
403 
404  // Skip the EventFormat branch. That must not be disturbed by the
405  // generic metadata handling.
406  if( ! strcmp( br->GetName(), "EventFormat" ) ) continue;
407 
408  // Check whether we have a dictionary for this type:
409  ::TClass* cl = ::TClass::GetClass( br->GetClassName(), kTRUE, kTRUE );
410  if( ! cl ) continue;
411 
412  // Check if we have a type-info for this class:
413  const std::type_info* ti = cl->GetTypeInfo();
414  if( ! ti ) continue;
415 
416  // Don't add auxiliary store objects:
417  if( cl->InheritsFrom( "SG::IConstAuxStore" ) ) {
418  continue;
419  }
420 
421  // If everything is right, let's make the branch:
422  auto mbr = std::make_unique< xAODTMetaBranch >( *metaTree, event, *ti,
423  br->GetName(),
424  br->GetClassName() );
425  metaTree->AddBranch( std::move( mbr ) );
426  }
427 
428  // Grab a simple pointer to the tree:
429  ::TTree* result = metaTree.get();
430  // Now put it into the object store:
431  s_objectHolder.add( std::move( metaTree ) );
432 
433  // Return the object that was just created:
434  ::Info( "xAOD::MakeTransientMetaTree",
435  "Created transient metadata tree \"MetaData\" in ROOT's common "
436  "memory");
437  return result;
438  }
439 
440  ::TTree* MakeTransientMetaTree ATLAS_NOT_THREAD_SAFE ( ::TFile* ifile,
441  const char* eventTreeName,
443 
444  // Create a TEvent object that will take care of retrieving objects
445  // from the persistent tree:
446  std::unique_ptr< TEvent > event( new TEvent( mode ) );
447  if( ! event->readFrom( ifile, kTRUE, eventTreeName ) ) {
448  ::Error( "xAOD::MakeTransientMetaTree",
449  XAOD_MESSAGE( "Couldn't set up the reading of the input "
450  "file" ) );
451  return 0;
452  }
453 
454  // Access the metadata tree directly:
455  ::TTree* metaTree = dynamic_cast< ::TTree* >( ifile->Get( "MetaData" ) );
456  if( ! metaTree ) {
457  ::Error( "xAOD::MakeTransientMetaTree",
458  XAOD_MESSAGE( "Couldn't access metadata tree \"MetaData\" "
459  "in the input file" ) );
460  return 0;
461  }
462 
463  // Create the transient tree using this TEvent object:
464  ::TTree* result = MakeTransientMetaTree( *event, metaTree );
465 
466  // Put the event object into the object store:
467  s_objectHolder.add( std::move( event ) );
468 
469  // Return the created tree:
470  return result;
471  }
472 
473  ::TTree* MakeTransientMetaTree ATLAS_NOT_THREAD_SAFE ( ::TChain* ichain,
474  const char* eventTreeName,
476 
477  // Construct a helper TChain object to give to TEvent:
478  std::unique_ptr< ::TChain > helperChain( new ::TChain( eventTreeName ) );
479  ::TObjArray* files = ichain->GetListOfFiles();
480  for( ::Int_t i = 0; i < files->GetEntries(); ++i ) {
481  helperChain->Add( files->At( i )->GetTitle() );
482  }
483 
484  // Create a TEvent object that will take care of retrieving objects
485  // from the persistent tree.
486  std::unique_ptr< TEvent > event( new TEvent( mode ) );
487  if( ! event->readFrom( helperChain.get(), kTRUE ) ) {
488  ::Error( "xAOD::MakeTransientMetaTree",
489  XAOD_MESSAGE( "Couldn't set up the reading of the input "
490  "TChain" ) );
491  return 0;
492  }
493 
494  // Create the transient tree using this TEvent object:
495  ::TTree* result = MakeTransientMetaTree( *event, ichain );
496 
497  // Put the created objects into the object store:
498  s_objectHolder.add( std::move( helperChain ) );
499  s_objectHolder.add( std::move( event ) );
500 
501  // Return the created tree:
502  return result;
503  }
504 
505 } // namespace xAOD
TestSUSYToolsAlg.ifile
ifile
Definition: TestSUSYToolsAlg.py:92
get_generator_info.result
result
Definition: get_generator_info.py:21
tree
TChain * tree
Definition: tile_monitor.h:30
xAOD
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
Definition: ICaloAffectedTool.h:24
xAOD::EventFormatElement::parentName
const std::string & parentName() const
Get the name of the parent auxiliary object.
Definition: EventFormatElement.cxx:42
xAOD::EventFormatElement
Class describing one branch of the ROOT file.
Definition: EventFormatElement.h:39
xAODTEventBranch.h
XAOD_MESSAGE
#define XAOD_MESSAGE(MESSAGE)
Simple macro for printing error/verbose messages.
Definition: Control/xAODRootAccess/xAODRootAccess/tools/Message.h:19
xAOD::EventFormatElement::branchName
const std::string & branchName() const
Get the branch/key name.
Definition: EventFormatElement.cxx:30
runLayerRecalibration.branches
list branches
Definition: runLayerRecalibration.py:98
POOL::TEvent::contains
PyObject * contains(PyObject *tp, PyObject *pykey)
Definition: PhysicsAnalysis/POOLRootAccess/src/TEvent.cxx:210
xAOD::ATLAS_NOT_THREAD_SAFE
void ErrorHandler ATLAS_NOT_THREAD_SAFE(Int_t level, Bool_t abort, const char *location, const char *message)
Function filtering the warnings coming from ROOT.
Definition: Init.cxx:105
POOL::TEvent::readFrom
StatusCode readFrom(TFile *file)
Definition: PhysicsAnalysis/POOLRootAccess/src/TEvent.cxx:132
ev
int ev
Definition: globals.cxx:25
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
POOL::TEvent::getEntry
int getEntry(long entry)
Definition: PhysicsAnalysis/POOLRootAccess/src/TEvent.cxx:184
ParseInputs.gDirectory
gDirectory
Definition: Final2012/ParseInputs.py:133
lumiFormat.i
int i
Definition: lumiFormat.py:92
Message.h
generateReferenceFile.files
files
Definition: generateReferenceFile.py:12
TEvent.h
dumpFileToPlots.treeName
string treeName
Definition: dumpFileToPlots.py:20
xAOD::EventFormatElement::className
const std::string & className() const
Get the class name of this branch/key.
Definition: EventFormatElement.cxx:36
xAODTMetaBranch.h
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
Preparation.mode
mode
Definition: Preparation.py:96
python.KeyStore.clear
def clear(self)
Definition: KeyStore.py:235
beamspotman.dir
string dir
Definition: beamspotman.py:623
xAOD::EventFormat_v1
Event format metadata for xAOD files.
Definition: EventFormat_v1.h:38
xAODTEventTree.h
xAOD::TEvent::EAuxMode
EAuxMode
Auxiliary store "mode".
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:95
MakeTransientTree.h
L1Topo::Error
Error
The different types of error that can be flagged in the L1TopoRDO.
Definition: Error.h:16
xAOD::EventFormat_v1::const_iterator
KeyedData_t::const_iterator const_iterator
Iterator for looping over the elements of the object.
Definition: EventFormat_v1.h:67
xAODTMetaTree.h
python.PyAthena.obj
obj
Definition: PyAthena.py:135
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:26
LheEventFiller_Common.ef
ef
Definition: SFGen_i/share/common/LheEventFiller_Common.py:7
xAOD::TTransTrees
A simple helper class holding both event and metadata transient trees.
Definition: TTransTrees.h:29
xAOD::TEvent
Tool for accessing xAOD files outside of Athena.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:81
xAOD::ATLAS_NOT_THREAD_SAFE
::TTree *MakeTransientMetaTree ATLAS_NOT_THREAD_SAFE(::TChain *ichain, const char *eventTreeName, TEvent::EAuxMode mode)
Function creating a transient TTree object representing the input files's metadata.
Definition: MakeTransientTree.cxx:473
PlotCalibFromCool.br
br
Definition: PlotCalibFromCool.py:355