The Gaudi Framework  v33r1 (b1225454)
THistSvc.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 // system headers
12 #include <cstdio>
13 #include <sstream>
14 #include <streambuf>
15 
16 // boost headers
17 #include "boost/algorithm/string/case_conv.hpp"
18 
19 // ROOT headers
20 #include "TDirectory.h"
21 #include "TError.h"
22 #include "TFile.h"
23 #include "TGraph.h"
24 #include "TKey.h"
25 #include "TROOT.h"
26 
27 // Gaudi headers
32 #include "GaudiKernel/IFileMgr.h"
37 #include "GaudiKernel/Property.h"
38 
39 // local headers
40 #include "THistSvc.h"
41 
42 // FIXME - leak sanitizers generate a number of warnings here
43 //
44 // Appears to be an issue with the mutex ownsership with LockedHandle ?
45 // clang-format off
46 // Direct leak of 40 byte(s) in 1 object(s) allocated from:
47 // #0 0x7f09944fcda8 in operator new(unsigned long) /afs/cern.ch/cms/CAF/CMSCOMM/COMM_ECAL/dkonst/GCC/build/contrib/gcc-8.2.0/src/gcc/8.2.0/libsanitizer/lsan/lsan_interceptors.cc:229
48 // #1 0x7f0987aa2e6d in StatusCode THistSvc::regHist_i<TH1>(std::unique_ptr<TH1, std::default_delete<TH1> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool, THistSvc::THistID*&) ../GaudiSvc/src/THistSvc/THistSvc.icc:139
49 // #2 0x7f0987aa3375 in LockedHandle<TH1, std::mutex> THistSvc::regShared_i<TH1>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::unique_ptr<TH1, std::default_delete<TH1> >) ../GaudiSvc/src/THistSvc/THistSvc.icc:264
50 // #3 0x7f0987a8f8ef in THistSvc::regShared(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::unique_ptr<TH1, std::default_delete<TH1> >, LockedHandle<TH1, std::mutex>&) ../GaudiSvc/src/THistSvc/THistSvc.cpp:430
51 // clang-format on
52 //
53 // These leaks are currently suppressed in Gaudi/job/Gaudi-LSan.supp - remove entry there to reactivate
54 
56 
57 namespace {
58  template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate>
59  OutputIterator transform_if( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op,
60  UnaryPredicate pred ) {
61  while ( first != last ) {
62  if ( pred( *first ) ) *result++ = op( *first );
63  ++first;
64  }
65  return result;
66  }
67 
68  constexpr struct select1st_t {
69  template <typename T, typename S>
70  const T& operator()( const std::pair<T, S>& p ) const {
71  return p.first;
72  }
73  } select1st{};
74 } // namespace
75 
76 //*************************************************************************//
77 
80 
82 
83  if ( status.isFailure() ) {
84  error() << "initializing service" << endmsg;
85  return status;
86  }
87 
89 
90  try {
92  } catch ( GaudiException& err ) {
93  error() << "Caught: " << err << endmsg;
95  }
96 
97  try {
99  } catch ( GaudiException& err ) {
100  error() << "Caught: " << err << endmsg;
101  st = StatusCode::FAILURE;
102  }
103 
104  // Protect against multiple instances of TROOT
105  if ( !gROOT ) {
106  static TROOT root( "root", "ROOT I/O" );
107  // gDebug = 99;
108  } else {
109  if ( msgLevel( MSG::VERBOSE ) ) { verbose() << "ROOT already initialized, debug = " << gDebug << endmsg; }
110  }
111 
112  if ( service( "IncidentSvc", p_incSvc, true ).isFailure() ) {
113  error() << "unable to get the IncidentSvc" << endmsg;
114  st = StatusCode::FAILURE;
115  } else {
116  p_incSvc->addListener( this, "EndEvent", 100, true );
117  }
118 
119  if ( service( "FileMgr", p_fileMgr, true ).isFailure() ) {
120  error() << "unable to get the FileMgr" << endmsg;
121  st = StatusCode::FAILURE;
122  } else {
123  debug() << "got the FileMgr" << endmsg;
124  }
125 
126  // Register open/close callback actions
127  using namespace std::placeholders;
128  auto boa = [this]( const Io::FileAttr* fa, const std::string& caller ) { return this->rootOpenAction( fa, caller ); };
129  if ( p_fileMgr->regAction( boa, Io::OPEN, Io::ROOT ).isFailure() ) {
130  error() << "unable to register ROOT file open action with FileMgr" << endmsg;
131  }
132  auto bea = [this]( const Io::FileAttr* fa, const std::string& caller ) {
133  return this->rootOpenErrAction( fa, caller );
134  };
135  if ( p_fileMgr->regAction( bea, Io::OPEN_ERR, Io::ROOT ).isFailure() ) {
136  error() << "unable to register ROOT file open Error action with FileMgr" << endmsg;
137  }
138 
139  m_okToConnect = true;
140  if ( m_delayConnect ) {
141  if ( !m_inputfile.value().empty() ) setupInputFile();
142  if ( !m_outputfile.value().empty() ) setupOutputFile();
143  m_delayConnect = false;
144  }
147 
148  IIoComponentMgr* iomgr = nullptr;
149  if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) {
150  error() << "unable to get the IoComponentMgr" << endmsg;
151  st = StatusCode::FAILURE;
152  } else {
153  if ( !iomgr->io_register( this ).isSuccess() ) {
154  error() << "could not register with the I/O component manager !" << endmsg;
155  st = StatusCode::FAILURE;
156  } else {
157  bool all_good = true;
158  // register input/output files...
159  for ( const auto& reg : m_files ) {
160  const std::string& fname = reg.second.first->GetName();
161  const IIoComponentMgr::IoMode::Type iomode =
163  if ( !iomgr->io_register( this, iomode, fname ).isSuccess() ) {
164  warning() << "could not register file [" << fname << "] with the I/O component manager..." << endmsg;
165  all_good = false;
166  } else {
167  info() << "registered file [" << fname << "]... [ok]" << endmsg;
168  }
169  }
170  if ( !all_good ) {
171  error() << "problem while registering input/output files with "
172  << "the I/O component manager !" << endmsg;
173  st = StatusCode::FAILURE;
174  }
175  }
176  }
177 
178  if ( st.isFailure() ) { fatal() << "Unable to initialize THistSvc" << endmsg; }
179 
180  return st;
181 }
182 
184  GlobalDirectoryRestore restore( m_svcMut );
185  warning() << "reinitialize not implemented" << endmsg;
186  return StatusCode::SUCCESS;
187 }
188 
190  GlobalDirectoryRestore restore( m_svcMut );
191 
192  if ( msgLevel( MSG::DEBUG ) ) {
193  dump();
194  debug() << "THistSvc::finalize" << endmsg;
195  }
196 
197 #ifndef NDEBUG
198  if ( msgLevel( MSG::DEBUG ) ) {
200  for ( const auto& itr : sorted_uids ) {
201  THistID& thid = itr.second->at( 0 );
202  TObject* tobj = thid.obj;
203 
204  std::string dirname( "none" );
205  if ( tobj && tobj->IsA()->InheritsFrom( "TTree" ) ) {
206  TTree* tree = dynamic_cast<TTree*>( tobj );
207  if ( tree->GetDirectory() != 0 ) { dirname = tree->GetDirectory()->GetPath(); }
208  } else if ( tobj && tobj->IsA()->InheritsFrom( "TGraph" ) ) {
209  if ( !thid.temp ) {
210  dirname = thid.file->GetPath();
211  std::string id2( thid.id );
212  id2.erase( 0, id2.find( "/", 1 ) );
213  id2.erase( id2.rfind( "/" ), id2.length() );
214  if ( id2.find( "/" ) == 0 ) { id2.erase( 0, 1 ); }
215  dirname += id2;
216  } else {
217  dirname = "/tmp";
218  }
219  } else if ( tobj && tobj->IsA()->InheritsFrom( "TH1" ) ) {
220  TH1* th = dynamic_cast<TH1*>( tobj );
221  if ( th == nullptr ) {
222  error() << "Couldn't dcast: " << itr.first << endmsg;
223  } else {
224  if ( th->GetDirectory() != 0 ) { dirname = th->GetDirectory()->GetPath(); }
225  }
226  } else if ( !tobj ) {
227  warning() << itr.first << " has NULL TObject ptr" << endmsg;
228  }
229  debug() << "finalize: " << thid << endmsg;
230  }
231  }
232 #endif
233 
234  if ( writeObjectsToFile().isFailure() ) { error() << "problems writing histograms" << endmsg; }
235 
236  if ( m_print ) { info() << "Listing contents of ROOT files: " << endmsg; }
237  std::vector<TFile*> deleted_files;
238  for ( auto& itr : m_files ) {
239  if ( std::find( deleted_files.begin(), deleted_files.end(), itr.second.first ) == deleted_files.end() ) {
240  deleted_files.push_back( itr.second.first );
241 
242 #ifndef NDEBUG
243  if ( msgLevel( MSG::DEBUG ) ) {
244  debug() << "finalizing stream/file " << itr.first << ":" << itr.second.first->GetName() << endmsg;
245  }
246 #endif
247  } else {
248 #ifndef NDEBUG
249  if ( msgLevel( MSG::DEBUG ) ) { debug() << "already finalized stream " << itr.first << endmsg; }
250 #endif
251  continue;
252  }
253 
254  if ( m_print && msgLevel( MSG::INFO ) ) {
255  info() << "==> File: " << itr.second.first->GetName() << " stream: " << itr.first << endmsg;
256 
257  itr.second.first->Print( "base" );
258  }
259 
260  std::string tmpfn = itr.second.first->GetName();
261 
262  p_fileMgr->close( itr.second.first, name() );
263 
264  IIncidentSvc* pIncidentSvc = nullptr;
265  if ( service( "IncidentSvc", pIncidentSvc ).isFailure() ) {
266  error() << "Unable to get the IncidentSvc" << endmsg;
267  return StatusCode::FAILURE;
268  }
269 
270  if ( itr.second.second == SHARE ) {
271  // Merge File
272  void* vfile = nullptr;
273  int returncode =
274  p_fileMgr->open( Io::ROOT, name(), m_sharedFiles[itr.first], Io::WRITE | Io::APPEND, vfile, "HIST" );
275 
276  if ( returncode ) {
277  error() << "unable to open Final Output File: \"" << m_sharedFiles[itr.first] << "\" for merging" << endmsg;
278  return StatusCode::FAILURE;
279  }
280 
281  TFile* outputfile = (TFile*)vfile;
282  pIncidentSvc->fireIncident( FileIncident( name(), IncidentType::WroteToOutputFile, m_sharedFiles[itr.first] ) );
283 
284  if ( msgLevel( MSG::DEBUG ) ) { debug() << "THistSvc::writeObjectsToFile()::Merging Rootfile " << endmsg; }
285 
286  vfile = nullptr;
287  returncode = p_fileMgr->open( Io::ROOT, name(), tmpfn, Io::READ, vfile, "HIST" );
288 
289  if ( returncode ) {
290  error() << "unable to open temporary file: \"" << tmpfn << endmsg;
291  return StatusCode::FAILURE;
292  }
293 
294  TFile* inputfile = (TFile*)vfile;
295 
296  outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() );
297 
298  MergeRootFile( outputfile, inputfile );
299 
300  outputfile->Write();
301  p_fileMgr->close( outputfile, name() );
302  p_fileMgr->close( inputfile, name() );
303 
304  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Trying to remove temporary file \"" << tmpfn << "\"" << endmsg; }
305 
306  std::remove( tmpfn.c_str() );
307  }
308  delete itr.second.first;
309  }
310 
311  m_files.clear();
314  m_hlist.clear(); // vhid* is deleted in m_tobjs
315  m_uids.clear(); // vhid* is deleted in m_tobjs
316  m_ids.clear(); // vhid* is deleted in m_tobjs
317 
318  for ( auto& obj : m_tobjs ) {
319  // TObject*'s are already dealt with through root file i/o
320  delete obj.second.first; // delete vhid*
321  }
322  m_tobjs.clear();
323 
324  return Service::finalize();
325 }
326 
327 //*************************************************************************//
328 
330  std::unique_ptr<TH1> hist = nullptr;
331  return regHist_i( std::move( hist ), id, false );
332 }
333 
335  return regHist_i( std::move( hist ), id, false );
336 }
337 
339  // This is only to support a common use case where the histogram is used after its registration
340  if ( hist_ptr != nullptr ) { hist_ptr = hist.get(); }
341  return regHist_i( std::move( hist ), id, false );
342 }
343 
344 StatusCode THistSvc::regHist( const std::string& id, TH1* hist_ptr ) {
345  std::unique_ptr<TH1> hist( hist_ptr );
346  return regHist_i( std::move( hist ), id, false );
347 }
348 
349 StatusCode THistSvc::getHist( const std::string& id, TH1*& hist, size_t ind ) const {
350  hist = getHist_i<TH1>( id, ind );
351  if ( hist != nullptr ) {
352  return StatusCode::SUCCESS;
353  } else {
354  return StatusCode::FAILURE;
355  }
356 }
357 
358 StatusCode THistSvc::getHist( const std::string& id, TH2*& hist, size_t ind ) const {
359  hist = getHist_i<TH2>( id, ind );
360  if ( hist != nullptr ) {
361  return StatusCode::SUCCESS;
362  } else {
363  return StatusCode::FAILURE;
364  }
365 }
366 
367 StatusCode THistSvc::getHist( const std::string& id, TH3*& hist, size_t ind ) const {
368  hist = getHist_i<TH3>( id, ind );
369  if ( hist != nullptr ) {
370  return StatusCode::SUCCESS;
371  } else {
372  return StatusCode::FAILURE;
373  }
374 }
375 
377  std::unique_ptr<TTree> tree = nullptr;
378  return regHist_i( std::move( tree ), id, false );
379 }
380 
382  StatusCode sc = regHist_i( std::move( tree ), id, false );
383  TTree* tr = nullptr;
384  if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) {
385  if ( m_autoSave != 0 ) { tr->SetAutoSave( m_autoSave ); }
386  tr->SetAutoFlush( m_autoFlush );
387  }
388  return sc;
389 }
390 
391 StatusCode THistSvc::regTree( const std::string& id, TTree* tree_ptr ) {
392  std::unique_ptr<TTree> tree( tree_ptr );
393  StatusCode sc = regHist_i( std::move( tree ), id, false );
394  TTree* tr = nullptr;
395  if ( getTree( id, tr ).isSuccess() && sc.isSuccess() ) {
396  if ( m_autoSave != 0 ) { tr->SetAutoSave( m_autoSave ); }
397  tr->SetAutoFlush( m_autoFlush );
398  }
399  return sc;
400 }
401 
402 StatusCode THistSvc::getTree( const std::string& id, TTree*& tree ) const {
403  tree = getHist_i<TTree>( id );
404  if ( tree != nullptr ) {
405  return StatusCode::SUCCESS;
406  } else {
407  return StatusCode::FAILURE;
408  }
409 }
410 
412  std::unique_ptr<TGraph> graph = std::make_unique<TGraph>();
413  return regHist_i( std::move( graph ), id, false );
414 }
415 
417  if ( strcmp( graph->GetName(), "Graph" ) == 0 ) {
418  std::string id2( id );
419  std::string::size_type i = id2.rfind( "/" );
420  if ( i != std::string::npos ) { id2.erase( 0, i + 1 ); }
421 
422  info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg;
423  graph->SetName( id2.c_str() );
424  }
425 
426  return regHist_i( std::move( graph ), id, false );
427 }
428 
429 StatusCode THistSvc::regGraph( const std::string& id, TGraph* graph_ptr ) {
430  std::unique_ptr<TGraph> graph( graph_ptr );
431  if ( strcmp( graph->GetName(), "Graph" ) == 0 ) {
432  std::string id2( id );
433  std::string::size_type i = id2.rfind( "/" );
434  if ( i != std::string::npos ) { id2.erase( 0, i + 1 ); }
435 
436  info() << "setting name of TGraph id: \"" << id << "\" to \"" << id2 << "\" since it is unset" << endmsg;
437  graph->SetName( id2.c_str() );
438  }
439 
440  return regHist_i( std::move( graph ), id, false );
441 }
442 
443 StatusCode THistSvc::getGraph( const std::string& id, TGraph*& graph ) const {
444  graph = getHist_i<TGraph>( id );
445  if ( graph != nullptr ) {
446  return StatusCode::SUCCESS;
447  } else {
448  return StatusCode::FAILURE;
449  }
450 }
451 
453  std::unique_ptr<TEfficiency> eff = nullptr;
454  return regHist_i( std::move( eff ), id, false );
455 }
456 
458  return regHist_i( std::move( eff ), id, false );
459 }
460 
461 StatusCode THistSvc::regEfficiency( const std::string& id, TEfficiency* eff_ptr ) {
462  std::unique_ptr<TEfficiency> eff( eff_ptr );
463  return regHist_i( std::move( eff ), id, false );
464 }
465 
466 StatusCode THistSvc::getEfficiency( const std::string& id, TEfficiency*& eff ) const {
467  eff = getHist_i<TEfficiency>( id );
468  if ( eff != nullptr ) {
469  return StatusCode::SUCCESS;
470  } else {
471  return StatusCode::FAILURE;
472  }
473 }
474 
476  lh = regShared_i<TH1>( id, std::move( hist ) );
477  if ( lh ) {
478  return StatusCode::SUCCESS;
479  } else {
480  return StatusCode::FAILURE;
481  }
482 }
483 
485  lh = regShared_i<TH2>( id, std::move( hist ) );
486  if ( lh ) {
487  return StatusCode::SUCCESS;
488  } else {
489  return StatusCode::FAILURE;
490  }
491 }
492 
494  lh = regShared_i<TH3>( id, std::move( hist ) );
495  if ( lh ) {
496  return StatusCode::SUCCESS;
497  } else {
498  return StatusCode::FAILURE;
499  }
500 }
501 
503  lh = regShared_i<TGraph>( id, std::move( graph ) );
504  if ( lh ) {
505  return StatusCode::SUCCESS;
506  } else {
507  return StatusCode::FAILURE;
508  }
509 }
510 
513  lh = regShared_i<TEfficiency>( id, std::move( eff ) );
514  if ( lh ) {
515  return StatusCode::SUCCESS;
516  } else {
517  return StatusCode::FAILURE;
518  }
519 }
520 
522  lh = getShared_i<TH1>( name );
523  if ( lh ) {
524  return StatusCode::SUCCESS;
525  } else {
526  return StatusCode::FAILURE;
527  }
528 }
529 
531  lh = getShared_i<TH2>( name );
532  if ( lh ) {
533  return StatusCode::SUCCESS;
534  } else {
535  return StatusCode::FAILURE;
536  }
537 }
538 
540  lh = getShared_i<TH3>( name );
541  if ( lh ) {
542  return StatusCode::SUCCESS;
543  } else {
544  return StatusCode::FAILURE;
545  }
546 }
547 
549  lh = getShared_i<TGraph>( name );
550  if ( lh ) {
551  return StatusCode::SUCCESS;
552  } else {
553  return StatusCode::FAILURE;
554  }
555 }
556 
558  lh = getShared_i<TEfficiency>( name );
559  if ( lh ) {
560  return StatusCode::SUCCESS;
561  } else {
562  return StatusCode::FAILURE;
563  }
564 }
565 
567  auto itr = m_uids.find( id );
568  if ( itr == m_uids.end() ) {
569  error() << "Problem deregistering id \"" << id << "\": not found in registry" << endmsg;
570  return StatusCode::FAILURE;
571  }
572 
573  vhid_t* vh = itr->second;
574  debug() << "will deregister " << vh->size() << " elements of id \"" << id << "\"" << endmsg;
576  // vh will get deleted in deReg once empty, so we cannot query the list size in the loop
577  size_t vh_size = vh->size();
578  while ( vh_size-- ) {
579  if ( deReg( vh->back().obj ).isFailure() ) {
580  sc = StatusCode::FAILURE;
581  error() << "Problems deRegistering " << vh->size() << " element of id \"" << id << "\"" << endmsg;
582  break;
583  }
584  }
585 
586  return sc;
587 }
588 
589 StatusCode THistSvc::deReg( TObject* obj ) {
590  objMap_t::iterator obj_itr = m_tobjs.find( obj );
591  if ( obj_itr != m_tobjs.end() ) {
592  vhid_t* vhid = obj_itr->second.first;
593  THistID hid = obj_itr->second.first->at( obj_itr->second.second );
594 
595  auto uid_itr = m_uids.find( hid.id );
596  if ( uid_itr == m_uids.end() ) {
597  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
598  << "\": not in uidMap" << endmsg;
599  return StatusCode::FAILURE;
600  }
601 
602  if ( vhid->size() == 1 ) {
603  // We are the last object, so we have to delete vhid properly
604  debug() << "vhid for " << hid.id << " is empty. deleting" << endmsg;
605 
606  std::string root, rem;
607  parseString( hid.id, root, rem );
608 
609  auto mitr = m_ids.equal_range( rem );
610  auto id_itr = std::find_if( mitr.first, mitr.second,
611  [&]( idMap_t::const_reference i ) { return i.second->at( 0 ).obj == obj; } );
612  if ( id_itr == mitr.second ) {
613  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
614  << "\": not in idMap" << endmsg;
615  return StatusCode::FAILURE;
616  }
617 
618  auto hlist_itr = std::find( m_hlist.begin(), m_hlist.end(), vhid );
619  if ( hlist_itr == m_hlist.end() ) {
620  error() << "Problems deregistering TObject \"" << obj->GetName() << "\" with id \"" << hid.id
621  << "\": not in hlist" << endmsg;
622  return StatusCode::FAILURE;
623  }
624 
625  vhid->erase( vhid->begin() + obj_itr->second.second );
626  m_tobjs.erase( obj_itr );
627 
628  m_uids.erase( uid_itr );
629  m_ids.erase( id_itr );
630  m_hlist.erase( hlist_itr );
631 
632  delete vhid;
633 
634  } else if ( vhid->size() > 1 ) {
635  m_tobjs.erase( obj_itr );
636  vhid->erase( vhid->begin() + obj_itr->second.second );
637 
638  // vector of THistID is still not empty (i.e. other instances with same name registered)
639  } else {
640  error() << "Deregistration failed unexpectedly. (bug in THistSvc?)" << endmsg;
641  }
642  return StatusCode::SUCCESS;
643  } else {
644  error() << "Cannot unregister TObject \"" << obj->GetName() << "\": not known to THistSvc" << endmsg;
645  return StatusCode::FAILURE;
646  }
647 }
648 
650  uidMap_t::iterator itr = m_uids.find( name );
651  if ( itr == m_uids.end() ) {
652  error() << "merge: id \"" << name << "\" not found" << endmsg;
653  return StatusCode::FAILURE;
654  }
655 
656  return merge( itr->second );
657 }
658 
659 StatusCode THistSvc::merge( TObject* obj ) {
660  objMap_t::iterator itr = m_tobjs.find( obj );
661  if ( itr != m_tobjs.end() ) {
662  return merge( itr->second.first );
663  } else {
664  error() << "merge: unknown object " << obj << endmsg;
665  return StatusCode::FAILURE;
666  }
667 }
668 
669 bool THistSvc::exists( const std::string& name ) const { return existsHist( name ); }
670 
671 bool THistSvc::existsHist( const std::string& name ) const { return ( getHist_i<TH1>( name, 0, true ) != nullptr ); }
672 
674  return ( getHist_i<TEfficiency>( name, 0, true ) != nullptr );
675 }
676 
677 bool THistSvc::existsGraph( const std::string& name ) const {
678  return ( getHist_i<TGraph>( name, 0, true ) != nullptr );
679 }
680 
681 bool THistSvc::existsTree( const std::string& name ) const { return ( getHist_i<TTree>( name, 0, true ) != nullptr ); }
682 
685  names.reserve( m_uids.size() );
686  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
687  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ); } );
688  return names;
689 }
690 
693  names.reserve( m_uids.size() );
694  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
695  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TTree" ); } );
696  return names;
697 }
698 
701  names.reserve( m_uids.size() );
702  transform_if( std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
703  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TGraph" ); } );
704  return names;
705 }
706 
709  names.reserve( m_uids.size() );
710  transform_if(
711  std::begin( m_uids ), std::end( m_uids ), std::back_inserter( names ), select1st,
712  []( uidMap_t::const_reference i ) { return i.second->at( 0 ).obj->IsA()->InheritsFrom( "TEfficiency" ); } );
713  return names;
714 }
715 
716 StatusCode THistSvc::getTHists( TDirectory* td, TList& tl, bool rcs ) const {
717  GlobalDirectoryRestore restore( m_svcMut );
718 
719  gErrorIgnoreLevel = kBreak;
720 
721  if ( !td->cd() ) {
722  error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
723  return StatusCode::FAILURE;
724  }
725 
726  if ( msgLevel( MSG::DEBUG ) ) {
727  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
728  }
729 
730  TIter nextkey( td->GetListOfKeys() );
731  while ( TKey* key = (TKey*)nextkey() ) {
732  auto& log = debug();
733  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
734  TObject* obj = key->ReadObj();
735  if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
736  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
737  } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TH1" ) ) {
738  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
739  tl.Add( obj );
740  } else if ( obj != 0 ) {
741  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
742  }
743  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
744  }
745 
746  // operate recursively
747  if ( rcs ) {
748  nextkey = td->GetListOfKeys();
749  while ( TKey* key = (TKey*)nextkey() ) {
750  TObject* obj = key->ReadObj();
751  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
752  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
753  getTHists( tt, tl, rcs ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
754  }
755  }
756  }
757 
758  return StatusCode::SUCCESS;
759 }
760 
761 StatusCode THistSvc::getTHists( const std::string& dir, TList& tl, bool rcs ) const {
762 
763  GlobalDirectoryRestore restore( m_svcMut );
764 
765  gErrorIgnoreLevel = kBreak;
766 
767  StatusCode sc;
768 
769  std::string stream, rem, r2;
770  parseString( dir, stream, rem );
771 
772  auto itr = m_files.find( stream );
773  if ( itr != m_files.end() ) {
774  r2 = itr->second.first->GetName();
775  r2 += ":/";
776  r2 += rem;
777 
778  if ( msgLevel( MSG::DEBUG ) ) {
779  debug() << "getTHists: \"" << dir << "\" looks like a stream name."
780  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
781  }
782 
783  if ( gDirectory->cd( r2.c_str() ) ) {
784  m_curstream = stream;
785  sc = getTHists( gDirectory, tl, rcs );
786  m_curstream = "";
787  return sc;
788  } else {
789  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg; }
790  }
791 
792  } else {
793  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg; }
794  }
795 
796  if ( !gDirectory->cd( dir.c_str() ) ) {
797  error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg;
798  sc = StatusCode::FAILURE;
799  } else {
800  sc = getTHists( gDirectory, tl, rcs );
801  }
802 
803  return sc;
804 }
805 
806 StatusCode THistSvc::getTHists( TDirectory* td, TList& tl, bool rcs, bool reg ) {
807  GlobalDirectoryRestore restore( m_svcMut );
808 
809  gErrorIgnoreLevel = kBreak;
810 
811  if ( !td->cd() ) {
812  error() << "getTHists: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
813  return StatusCode::FAILURE;
814  }
815 
816  if ( msgLevel( MSG::DEBUG ) ) {
817  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
818  }
819 
820  TIter nextkey( td->GetListOfKeys() );
821  while ( TKey* key = (TKey*)nextkey() ) {
822  auto& log = debug();
823  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
824  TObject* obj = key->ReadObj();
825  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
826  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
827  } else if ( obj && obj->IsA()->InheritsFrom( "TH1" ) ) {
828  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
829  tl.Add( obj );
830  if ( reg && m_curstream != "" ) {
831  std::string dir = td->GetPath();
832  std::string fil = td->GetFile()->GetName();
833  dir.erase( 0, fil.length() + 1 );
834  std::string id = "/" + m_curstream;
835  if ( dir == "/" ) {
836  id = id + "/" + key->GetName();
837  } else {
838  id = id + dir + "/" + key->GetName();
839  }
840  if ( !exists( id ) ) {
841  if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\"";
842  regHist( id ).ignore();
843  } else {
844  if ( msgLevel( MSG::DEBUG ) ) log << " already registered";
845  }
846  }
847  } else if ( obj ) {
848  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
849  }
850  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
851  }
852 
853  // operate recursively
854  if ( rcs ) {
855  nextkey = td->GetListOfKeys();
856  while ( TKey* key = (TKey*)nextkey() ) {
857  TObject* obj = key->ReadObj();
858  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
859  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
860  getTHists( tt, tl, rcs, reg ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
861  }
862  }
863  }
864 
865  return StatusCode::SUCCESS;
866 }
867 
868 StatusCode THistSvc::getTHists( const std::string& dir, TList& tl, bool rcs, bool reg ) {
869  GlobalDirectoryRestore restore( m_svcMut );
870 
871  gErrorIgnoreLevel = kBreak;
872 
873  StatusCode sc;
874 
875  std::string stream, rem, r2;
876  parseString( dir, stream, rem );
877 
878  auto itr = m_files.find( stream );
879  if ( itr != m_files.end() ) {
880  r2 = itr->second.first->GetName();
881  r2 += ":/";
882  r2 += rem;
883 
884  if ( msgLevel( MSG::DEBUG ) ) {
885  debug() << "getTHists: \"" << dir << "\" looks like a stream name."
886  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
887  }
888 
889  if ( gDirectory->cd( r2.c_str() ) ) {
890  m_curstream = stream;
891  sc = getTHists( gDirectory, tl, rcs, reg );
892  m_curstream.clear();
893  return sc;
894  }
895  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTHists: no such TDirectory \"" << r2 << "\"" << endmsg; }
896  } else {
897  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTHists: stream \"" << stream << "\" not found" << endmsg; }
898  }
899 
900  if ( !gDirectory->cd( dir.c_str() ) ) {
901  error() << "getTHists: No such TDirectory/stream \"" << dir << "\"" << endmsg;
902  sc = StatusCode::FAILURE;
903  } else {
904  if ( reg ) {
905  warning() << "Unable to register histograms automatically "
906  << "without a valid stream name" << endmsg;
907  reg = false;
908  }
909  sc = getTHists( gDirectory, tl, rcs, reg );
910  }
911 
912  return sc;
913 }
914 
915 StatusCode THistSvc::getTTrees( TDirectory* td, TList& tl, bool rcs ) const {
916  GlobalDirectoryRestore restore( m_svcMut );
917 
918  gErrorIgnoreLevel = kBreak;
919 
920  if ( !td->cd() ) {
921  error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
922  return StatusCode::FAILURE;
923  }
924 
925  if ( msgLevel( MSG::DEBUG ) ) {
926  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
927  }
928 
929  TIter nextkey( td->GetListOfKeys() );
930  while ( TKey* key = (TKey*)nextkey() ) {
931  auto& log = debug();
932  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
933  TObject* obj = key->ReadObj();
934  if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
935  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
936  } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TTree" ) ) {
937  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
938  tl.Add( obj );
939  } else if ( obj != 0 ) {
940  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
941  }
942  log << endmsg;
943  }
944 
945  // operate recursively
946  if ( rcs ) {
947  nextkey = td->GetListOfKeys();
948  while ( TKey* key = (TKey*)nextkey() ) {
949  TObject* obj = key->ReadObj();
950  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
951  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
952  getTTrees( tt, tl, rcs ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
953  }
954  }
955  }
956 
957  return StatusCode::SUCCESS;
958 }
959 
960 StatusCode THistSvc::getTTrees( const std::string& dir, TList& tl, bool rcs ) const {
961  GlobalDirectoryRestore restore( m_svcMut );
962 
963  gErrorIgnoreLevel = kBreak;
964 
965  StatusCode sc;
966 
967  std::string stream, rem, r2;
968  parseString( dir, stream, rem );
969 
970  auto itr = m_files.find( stream );
971  if ( itr != m_files.end() ) {
972  r2 = itr->second.first->GetName();
973  r2 += ":/";
974  r2 += rem;
975 
976  if ( msgLevel( MSG::DEBUG ) ) {
977  debug() << "getTTrees: \"" << dir << "\" looks like a stream name."
978  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
979  }
980 
981  if ( gDirectory->cd( r2.c_str() ) ) { return getTTrees( gDirectory, tl, rcs ); }
982  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg; }
983  } else {
984  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg; }
985  }
986 
987  if ( !gDirectory->cd( dir.c_str() ) ) {
988  error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg;
989  sc = StatusCode::FAILURE;
990  } else {
991  sc = getTTrees( gDirectory, tl, rcs );
992  }
993  return sc;
994 }
995 
996 StatusCode THistSvc::getTTrees( TDirectory* td, TList& tl, bool rcs, bool reg ) {
997  GlobalDirectoryRestore restore( m_svcMut );
998 
999  gErrorIgnoreLevel = kBreak;
1000 
1001  if ( !td->cd() ) {
1002  error() << "getTTrees: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
1003  return StatusCode::FAILURE;
1004  }
1005 
1006  if ( msgLevel( MSG::DEBUG ) ) {
1007  debug() << "getTHists: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
1008  }
1009 
1010  TIter nextkey( td->GetListOfKeys() );
1011  while ( TKey* key = (TKey*)nextkey() ) {
1012  auto& log = debug();
1013  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
1014  TObject* obj = key->ReadObj();
1015  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1016  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1017  } else if ( obj && obj->IsA()->InheritsFrom( "TTree" ) ) {
1018  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1019  tl.Add( obj );
1020  if ( reg && m_curstream != "" ) {
1021  std::string dir = td->GetPath();
1022  std::string fil = td->GetFile()->GetName();
1023  dir.erase( 0, fil.length() + 1 );
1024  std::string id = "/" + m_curstream;
1025  if ( dir == "/" ) {
1026  id = id + "/" + key->GetName();
1027  } else {
1028  id = id + dir + "/" + key->GetName();
1029  }
1030  if ( !exists( id ) ) {
1031  if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\"";
1032  regHist( id ).ignore();
1033  } else {
1034  if ( msgLevel( MSG::DEBUG ) ) log << " already registered";
1035  }
1036  }
1037  } else if ( obj != 0 ) {
1038  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
1039  }
1040  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
1041  }
1042 
1043  // operate recursively
1044  if ( rcs ) {
1045  nextkey = td->GetListOfKeys();
1046  while ( TKey* key = (TKey*)nextkey() ) {
1047  TObject* obj = key->ReadObj();
1048  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1049  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
1050  getTTrees( tt, tl, rcs, reg ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
1051  }
1052  }
1053  }
1054 
1055  return StatusCode::SUCCESS;
1056 }
1057 
1058 StatusCode THistSvc::getTTrees( const std::string& dir, TList& tl, bool rcs, bool reg ) {
1059  GlobalDirectoryRestore restore( m_svcMut );
1060 
1061  gErrorIgnoreLevel = kBreak;
1062 
1063  StatusCode sc;
1064 
1065  std::string stream, rem, r2;
1066  parseString( dir, stream, rem );
1067 
1068  auto itr = m_files.find( stream );
1069  if ( itr != m_files.end() ) {
1070  r2 = itr->second.first->GetName();
1071  r2 += ":/";
1072  r2 += rem;
1073 
1074  if ( msgLevel( MSG::DEBUG ) ) {
1075  debug() << "getTTrees: \"" << dir << "\" looks like a stream name."
1076  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
1077  }
1078 
1079  if ( gDirectory->cd( r2.c_str() ) ) {
1080  return getTTrees( gDirectory, tl, rcs, reg );
1081  } else {
1082  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTTrees: no such TDirectory \"" << r2 << "\"" << endmsg; }
1083  }
1084  } else {
1085  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTTrees: stream \"" << stream << "\" not found" << endmsg; }
1086  }
1087 
1088  if ( !gDirectory->cd( dir.c_str() ) ) {
1089  error() << "getTTrees: No such TDirectory/stream \"" << dir << "\"" << endmsg;
1090  return StatusCode::FAILURE;
1091  }
1092 
1093  return getTTrees( gDirectory, tl, rcs, reg );
1094 }
1095 
1096 StatusCode THistSvc::getTEfficiencies( TDirectory* td, TList& tl, bool rcs ) const {
1097  GlobalDirectoryRestore restore( m_svcMut );
1098 
1099  gErrorIgnoreLevel = kBreak;
1100 
1101  if ( !td->cd() ) {
1102  error() << "getTEfficiencies: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
1103  return StatusCode::FAILURE;
1104  }
1105 
1106  if ( msgLevel( MSG::DEBUG ) ) {
1107  debug() << "getTEfficiencies: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys"
1108  << endmsg;
1109  }
1110 
1111  TIter nextkey( td->GetListOfKeys() );
1112  while ( TKey* key = (TKey*)nextkey() ) {
1113  auto& log = debug();
1114  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
1115  TObject* obj = key->ReadObj();
1116  if ( obj != 0 && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1117  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1118  } else if ( obj != 0 && obj->IsA()->InheritsFrom( "TEfficiency" ) ) {
1119  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1120  tl.Add( obj );
1121  } else if ( obj != 0 ) {
1122  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
1123  }
1124  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
1125  }
1126 
1127  // operate recursively
1128  if ( rcs ) {
1129  nextkey = td->GetListOfKeys();
1130  while ( TKey* key = (TKey*)nextkey() ) {
1131  TObject* obj = key->ReadObj();
1132  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1133  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
1134  getTHists( tt, tl, rcs ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
1135  }
1136  }
1137  }
1138 
1139  return StatusCode::SUCCESS;
1140 }
1141 
1142 StatusCode THistSvc::getTEfficiencies( const std::string& dir, TList& tl, bool rcs ) const {
1143 
1144  GlobalDirectoryRestore restore( m_svcMut );
1145 
1146  gErrorIgnoreLevel = kBreak;
1147 
1148  StatusCode sc;
1149 
1150  std::string stream, rem, r2;
1151  parseString( dir, stream, rem );
1152 
1153  auto itr = m_files.find( stream );
1154  if ( itr != m_files.end() ) {
1155  r2 = itr->second.first->GetName();
1156  r2 += ":/";
1157  r2 += rem;
1158 
1159  if ( msgLevel( MSG::DEBUG ) ) {
1160  debug() << "getTEfficiencies: \"" << dir << "\" looks like a stream name."
1161  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
1162  }
1163 
1164  if ( gDirectory->cd( r2.c_str() ) ) {
1165  m_curstream = stream;
1166  sc = getTEfficiencies( gDirectory, tl, rcs );
1167  m_curstream = "";
1168  return sc;
1169  } else {
1170  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTEfficiencies: no such TDirectory \"" << r2 << "\"" << endmsg; }
1171  }
1172 
1173  } else {
1174  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTEfficiencies: stream \"" << stream << "\" not found" << endmsg; }
1175  }
1176 
1177  if ( !gDirectory->cd( dir.c_str() ) ) {
1178  error() << "getTEfficiencies: No such TDirectory/stream \"" << dir << "\"" << endmsg;
1179  sc = StatusCode::FAILURE;
1180  } else {
1181  sc = getTHists( gDirectory, tl, rcs );
1182  }
1183 
1184  return sc;
1185 }
1186 
1187 StatusCode THistSvc::getTEfficiencies( TDirectory* td, TList& tl, bool rcs, bool reg ) {
1188  GlobalDirectoryRestore restore( m_svcMut );
1189 
1190  gErrorIgnoreLevel = kBreak;
1191 
1192  if ( !td->cd() ) {
1193  error() << "getTEfficiencies: No such TDirectory \"" << td->GetPath() << "\"" << endmsg;
1194  return StatusCode::FAILURE;
1195  }
1196 
1197  if ( msgLevel( MSG::DEBUG ) ) {
1198  debug() << "getTEfficiencies: \"" << td->GetPath() << "\": found " << td->GetListOfKeys()->GetSize() << " keys"
1199  << endmsg;
1200  }
1201 
1202  TIter nextkey( td->GetListOfKeys() );
1203  while ( TKey* key = (TKey*)nextkey() ) {
1204  auto& log = debug();
1205  if ( msgLevel( MSG::DEBUG ) ) log << " key: " << key->GetName();
1206  TObject* obj = key->ReadObj();
1207  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1208  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1209  } else if ( obj && obj->IsA()->InheritsFrom( "TEfficiency" ) ) {
1210  if ( msgLevel( MSG::DEBUG ) ) log << " (" << obj->IsA()->GetName() << ")";
1211  tl.Add( obj );
1212  if ( reg && m_curstream != "" ) {
1213  std::string dir = td->GetPath();
1214  std::string fil = td->GetFile()->GetName();
1215  dir.erase( 0, fil.length() + 1 );
1216  std::string id = "/" + m_curstream;
1217  if ( dir == "/" ) {
1218  id = id + "/" + key->GetName();
1219  } else {
1220  id = id + dir + "/" + key->GetName();
1221  }
1222  if ( !exists( id ) ) {
1223  if ( msgLevel( MSG::DEBUG ) ) log << " reg as \"" << id << "\"";
1224  regHist( id ).ignore();
1225  } else {
1226  if ( msgLevel( MSG::DEBUG ) ) log << " already registered";
1227  }
1228  }
1229  } else if ( obj ) {
1230  if ( msgLevel( MSG::DEBUG ) ) log << " [" << obj->IsA()->GetName() << "]";
1231  }
1232  if ( msgLevel( MSG::DEBUG ) ) log << endmsg;
1233  }
1234 
1235  // operate recursively
1236  if ( rcs ) {
1237  nextkey = td->GetListOfKeys();
1238  while ( TKey* key = (TKey*)nextkey() ) {
1239  TObject* obj = key->ReadObj();
1240  if ( obj && obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1241  TDirectory* tt = dynamic_cast<TDirectory*>( obj );
1242  getTEfficiencies( tt, tl, rcs, reg ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
1243  }
1244  }
1245  }
1246 
1247  return StatusCode::SUCCESS;
1248 }
1249 
1250 StatusCode THistSvc::getTEfficiencies( const std::string& dir, TList& tl, bool rcs, bool reg ) {
1251  GlobalDirectoryRestore restore( m_svcMut );
1252 
1253  gErrorIgnoreLevel = kBreak;
1254 
1255  StatusCode sc;
1256 
1257  std::string stream, rem, r2;
1258  parseString( dir, stream, rem );
1259 
1260  auto itr = m_files.find( stream );
1261  if ( itr != m_files.end() ) {
1262  r2 = itr->second.first->GetName();
1263  r2 += ":/";
1264  r2 += rem;
1265 
1266  if ( msgLevel( MSG::DEBUG ) ) {
1267  debug() << "getTEfficiencies: \"" << dir << "\" looks like a stream name."
1268  << " associated TFile: \"" << itr->second.first->GetName() << "\"" << endmsg;
1269  }
1270 
1271  if ( gDirectory->cd( r2.c_str() ) ) {
1272  m_curstream = stream;
1273  sc = getTEfficiencies( gDirectory, tl, rcs, reg );
1274  m_curstream.clear();
1275  return sc;
1276  }
1277  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTEfficiencies: no such TDirectory \"" << r2 << "\"" << endmsg; }
1278  } else {
1279  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getTEfficiencies: stream \"" << stream << "\" not found" << endmsg; }
1280  }
1281 
1282  if ( !gDirectory->cd( dir.c_str() ) ) {
1283  error() << "getTEfficiencies: No such TDirectory/stream \"" << dir << "\"" << endmsg;
1284  sc = StatusCode::FAILURE;
1285  } else {
1286  if ( reg ) {
1287  warning() << "Unable to register histograms automatically "
1288  << "without a valid stream name" << endmsg;
1289  reg = false;
1290  }
1291  sc = getTEfficiencies( gDirectory, tl, rcs, reg );
1292  }
1293 
1294  return sc;
1295 }
1296 
1297 //*************************************************************************//
1298 
1299 void THistSvc::handle( const Incident& /* inc */ ) {
1300  if ( m_signaledStop ) return;
1301 
1302  if ( m_maxFileSize.value() == -1 ) return;
1303 
1304  // convert to bytes.
1305  Long64_t mfs = (Long64_t)m_maxFileSize.value() * (Long64_t)1048576;
1306  Long64_t mfs_warn = mfs * 95 / 100;
1307 
1308  updateFiles();
1309 
1310  for ( const auto& f : m_files ) {
1311  TFile* tf = f.second.first;
1312 
1313 #ifndef NDEBUG
1314  if ( msgLevel( MSG::DEBUG ) ) {
1315  debug() << "stream: " << f.first << " name: " << tf->GetName() << " size: " << tf->GetSize() << endmsg;
1316  }
1317 #endif
1318 
1319  // Signal job to terminate if output file is too large
1320  if ( tf->GetSize() > mfs ) {
1321 
1322  m_signaledStop = true;
1323 
1324  fatal() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first
1325  << "\" has exceeded the max file size of " << m_maxFileSize.value() << "MB. Terminating Job." << endmsg;
1326 
1327  IEventProcessor* evt = nullptr;
1328  if ( service( "ApplicationMgr", evt, true ).isSuccess() ) {
1329  evt->stopRun().ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ );
1330  evt->release();
1331  } else {
1332  abort();
1333  }
1334  } else if ( tf->GetSize() > mfs_warn ) {
1335  warning() << "file \"" << tf->GetName() << "\" associated with stream \"" << f.first
1336  << "\" is at 95% of its maximum allowable file size of " << m_maxFileSize.value() << "MB" << endmsg;
1337  }
1338  }
1339 }
1340 
1345  bool all_good = true;
1346  if ( msgLevel( MSG::DEBUG ) ) { debug() << "reinitializing I/O..." << endmsg; }
1347 
1348  // retrieve the I/O component manager...
1349 
1350  IIoComponentMgr* iomgr = nullptr;
1351 
1352  if ( service( "IoComponentMgr", iomgr, true ).isFailure() ) {
1353  error() << "could not retrieve I/O component manager !" << endmsg;
1354  return StatusCode::FAILURE;
1355  }
1356 
1357  GlobalDirectoryRestore restore( m_svcMut );
1358  // to hide the expected errors upon closing the files whose
1359  // file descriptors have been swept under the rug...
1360  gErrorIgnoreLevel = kFatal;
1361 
1362  for ( auto& ifile : m_files ) {
1363  TFile* f = ifile.second.first;
1364  std::string fname = f->GetName();
1365  if ( msgLevel( MSG::DEBUG ) ) {
1366  debug() << "file [" << fname << "] mode: [" << f->GetOption() << "] r:" << f->GetFileBytesRead()
1367  << " w:" << f->GetFileBytesWritten() << " cnt:" << f->GetFileCounter() << endmsg;
1368  }
1369 
1370  if ( ifile.second.second == READ ) {
1371  if ( msgLevel( MSG::DEBUG ) ) { debug() << " TFile opened in READ mode: not reassigning names" << endmsg; }
1372  continue;
1373  }
1374 
1375  if ( !iomgr->io_retrieve( this, fname ).isSuccess() ) {
1376  error() << "could not retrieve new name for [" << fname << "] !!" << endmsg;
1377  all_good = false;
1378  continue;
1379  } else if ( fname.empty() ) {
1380  if ( msgLevel( MSG::DEBUG ) ) { debug() << "empty new name for [" << fname << "], skipping..." << endmsg; }
1381  continue;
1382  } else {
1383  if ( msgLevel( MSG::DEBUG ) ) { debug() << "got a new name [" << fname << "]..." << endmsg; }
1384  }
1385 
1386  void* vf = nullptr;
1387  Option_t* opts = f->GetOption();
1388  int r = p_fileMgr->open( Io::ROOT, name(), fname, Io::WRITE, vf, "HIST" );
1389  if ( r != 0 ) {
1390  error() << "unable to open file \"" << fname << "\" for writing" << endmsg;
1391  return StatusCode::FAILURE;
1392  }
1393  TFile* newfile = (TFile*)vf;
1394  newfile->SetOption( opts );
1395 
1396  if ( ifile.second.second != THistSvc::READ ) {
1397  copyFileLayout( newfile, f );
1398  ifile.second.first = newfile;
1399  }
1400 
1401  // loop over all uids and migrate them to the new file
1402  for ( auto& uid : m_uids ) {
1403  for ( auto& hid : *uid.second ) {
1404  if ( hid.file != f ) continue;
1405  TDirectory* olddir = this->changeDir( hid );
1406  hid.file = newfile;
1407  // side-effect: create needed directories...
1408  TDirectory* newdir = this->changeDir( hid );
1409  TClass* cl = hid.obj->IsA();
1410 
1411  // migrate the objects to the new file.
1412  // thanks to the object model of ROOT, it is super easy.
1413  if ( cl->InheritsFrom( "TTree" ) ) {
1414  dynamic_cast<TTree*>( hid.obj )->SetDirectory( newdir );
1415  dynamic_cast<TTree*>( hid.obj )->Reset();
1416  } else if ( cl->InheritsFrom( "TH1" ) ) {
1417  dynamic_cast<TH1*>( hid.obj )->SetDirectory( newdir );
1418  dynamic_cast<TH1*>( hid.obj )->Reset();
1419  } else if ( cl->InheritsFrom( "TEfficiency" ) ) {
1420  dynamic_cast<TEfficiency*>( hid.obj )->SetDirectory( newdir );
1421  } else if ( cl->InheritsFrom( "TGraph" ) ) {
1422  olddir->Remove( hid.obj );
1423  newdir->Append( hid.obj );
1424  } else {
1425  error() << "id: \"" << hid.id << "\" is not a inheriting from a class "
1426  << "we know how to handle (received [" << cl->GetName() << "], "
1427  << "expected [TTree, TH1, TGraph or TEfficiency]) !" << endmsg << "attaching to current dir ["
1428  << newdir->GetPath() << "] "
1429  << "nonetheless..." << endmsg;
1430  olddir->Remove( hid.obj );
1431  newdir->Append( hid.obj );
1432  }
1433  }
1434  }
1435  f->ReOpen( "READ" );
1436  p_fileMgr->close( f, name() );
1437  f = newfile;
1438  }
1439 
1440  return all_good ? StatusCode::SUCCESS : StatusCode::FAILURE;
1441 }
1442 
1443 //*************************************************************************//
1444 
1446  m_gDirectory = gDirectory;
1447  m_gFile = gFile;
1448  m_gErrorIgnoreLevel = gErrorIgnoreLevel;
1449 }
1450 
1452  gDirectory = m_gDirectory;
1453  gFile = m_gFile;
1454  gErrorIgnoreLevel = m_gErrorIgnoreLevel;
1455 }
1456 
1457 //*************************************************************************//
1458 
1459 template <typename T>
1460 T* THistSvc::readHist( const std::string& id ) const {
1461  return dynamic_cast<T*>( readHist_i<T>( id ) );
1462 }
1463 
1464 TTree* THistSvc::readTree( const std::string& id ) const { return dynamic_cast<TTree*>( readHist_i<TTree>( id ) ); }
1465 
1467  // If TTrees grow beyond TTree::fgMaxTreeSize, a new file is
1468  // automatically created by root, and the old one closed. We
1469  // need to migrate all the UIDs over to show the correct file
1470  // pointer. This is ugly.
1471 
1472  if ( msgLevel( MSG::DEBUG ) ) debug() << "updateFiles()" << endmsg;
1473 
1474  for ( auto uitr = m_uids.begin(); uitr != m_uids.end(); ++uitr ) {
1475  for ( auto& hid : *( uitr->second ) ) {
1476 #ifndef NDEBUG
1477  if ( msgLevel( MSG::VERBOSE ) )
1478  verbose() << " update: " << uitr->first << " " << hid.id << " " << hid.mode << endmsg;
1479 #endif
1480  TObject* to = hid.obj;
1481  TFile* oldFile = hid.file;
1482  if ( !to ) {
1483  warning() << uitr->first << ": TObject == 0" << endmsg;
1484  } else if ( hid.temp || hid.mode == READ ) {
1485 // do nothing - no need to check how big the file is since we
1486 // are just reading it.
1487 #ifndef NDEBUG
1488  if ( msgLevel( MSG::VERBOSE ) ) verbose() << " skipping" << endmsg;
1489 #endif
1490  } else if ( to->IsA()->InheritsFrom( "TTree" ) ) {
1491  TTree* tr = dynamic_cast<TTree*>( to );
1492  TFile* newFile = tr->GetCurrentFile();
1493 
1494  if ( oldFile != newFile ) {
1495  std::string newFileName = newFile->GetName();
1496  std::string oldFileName, streamName, rem;
1497  TFile* dummy = nullptr;
1498  findStream( hid.id, streamName, rem, dummy );
1499 
1500  for ( auto& itr : m_files ) {
1501  if ( itr.second.first == oldFile ) { itr.second.first = newFile; }
1502  }
1503 
1504  for ( auto uitr2 = uitr; uitr2 != m_uids.end(); ++uitr2 ) {
1505  for ( auto& hid2 : *( uitr2->second ) ) {
1506  if ( hid2.file == oldFile ) { hid2.file = newFile; }
1507  }
1508  }
1509 
1511  [&]( streamMap::const_reference s ) { return s.second == streamName; } );
1512  if ( sitr != std::end( m_fileStreams ) ) oldFileName = sitr->first;
1513 
1514 #ifndef NDEBUG
1515  if ( msgLevel( MSG::DEBUG ) ) {
1516  debug() << "migrating uid: " << hid.id << " stream: " << streamName << " oldFile: " << oldFileName
1517  << " newFile: " << newFileName << endmsg;
1518  }
1519 #endif
1520 
1521  if ( !oldFileName.empty() ) {
1522  auto i = m_fileStreams.lower_bound( oldFileName );
1523  while ( i != std::end( m_fileStreams ) && i->first == oldFileName ) {
1524 #ifndef NDEBUG
1525  if ( msgLevel( MSG::DEBUG ) ) {
1526  debug() << "changing filename \"" << i->first << "\" to \"" << newFileName << "\" for stream \""
1527  << i->second << "\"" << endmsg;
1528  }
1529 #endif
1530  std::string nm = std::move( i->second );
1531  i = m_fileStreams.erase( i );
1532  m_fileStreams.emplace( newFileName, std::move( nm ) );
1533  }
1534  } else {
1535  error() << "Problems updating fileStreams with new file name" << endmsg;
1536  }
1537  }
1538  }
1539  }
1540  }
1541 }
1542 
1544  updateFiles();
1545 
1547  auto mode = i.second.second;
1548  auto file = i.second.first;
1549  if ( mode == WRITE || mode == UPDATE || mode == SHARE ) {
1550  file->Write( "", TObject::kOverwrite );
1551  } else if ( mode == APPEND ) {
1552  file->Write( "" );
1553  }
1554  } );
1555 
1556  if ( msgLevel( MSG::DEBUG ) ) {
1557  debug() << "THistSvc::writeObjectsToFile()::List of Files connected in ROOT " << endmsg;
1558  TSeqCollection* filelist = gROOT->GetListOfFiles();
1559  for ( int ii = 0; ii < filelist->GetEntries(); ii++ ) {
1560  debug() << "THistSvc::writeObjectsToFile()::List of Files connected in ROOT: \"" << filelist->At( ii )->GetName()
1561  << "\"" << endmsg;
1562  }
1563  }
1564 
1565  return StatusCode::SUCCESS;
1566 }
1567 
1569  auto loc = ident.find( " " );
1570  std::string stream = ident.substr( 0, loc );
1571  char typ( 0 );
1573  std::vector<Prop> props;
1574  std::string filename, db_typ( "ROOT" );
1575  int cl( 1 );
1576 
1577  if ( loc != std::string::npos ) {
1578  using Parser = Gaudi::Utils::AttribStringParser;
1579  for ( auto attrib : Parser( ident.substr( loc + 1 ) ) ) {
1580  auto TAG = boost::algorithm::to_upper_copy( attrib.tag );
1581  auto VAL = boost::algorithm::to_upper_copy( attrib.value );
1582 
1583  if ( TAG == "FILE" || TAG == "DATAFILE" ) {
1584  filename = attrib.value;
1586  } else if ( TAG == "OPT" ) {
1587  if ( VAL == "APPEND" || VAL == "UPDATE" ) {
1588  typ = 'A';
1589  } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) {
1590  typ = 'N';
1591  } else if ( VAL == "RECREATE" ) {
1592  typ = 'R';
1593  } else if ( VAL == "SHARE" ) {
1594  typ = 'S';
1595  } else if ( VAL == "OLD" || VAL == "READ" ) {
1596  typ = 'O';
1597  } else {
1598  error() << "Unknown OPT: \"" << attrib.value << "\"" << endmsg;
1599  typ = 0;
1600  }
1601  } else if ( TAG == "TYP" ) {
1602  db_typ = std::move( attrib.value );
1603  } else if ( TAG == "CL" ) {
1604  cl = std::stoi( attrib.value );
1605  } else {
1606  props.emplace_back( attrib.tag, attrib.value );
1607  }
1608  }
1609  }
1610 
1611  if ( stream == "temp" ) {
1612  error() << "in JobOption \"" << ident << "\": stream name \"temp\" reserved." << endmsg;
1613  return StatusCode::FAILURE;
1614  }
1615 
1616  if ( db_typ != "ROOT" ) {
1617  error() << "in JobOption \"" << ident << "\": technology type \"" << db_typ << "\" not supported." << endmsg;
1618  return StatusCode::FAILURE;
1619  }
1620 
1621  if ( m_files.find( stream ) != m_files.end() ) {
1622  error() << "in JobOption \"" << ident << "\":\n stream \"" << stream << "\" already connected to file: \""
1623  << m_files[stream].first->GetName() << "\"" << endmsg;
1624  return StatusCode::FAILURE;
1625  }
1626 
1627  const auto newMode = charToMode( typ );
1628  if ( newMode == THistSvc::INVALID ) {
1629  error() << "No OPT= specified or unknown access mode in: " << ident << endmsg;
1630  return StatusCode::FAILURE;
1631  }
1632 
1633  // Is this file already connected to another stream?
1634  if ( m_fileStreams.find( filename ) != m_fileStreams.end() ) {
1635  auto fitr = m_fileStreams.equal_range( filename );
1636 
1637  const std::string& oldstream = fitr.first->second;
1638 
1639  const auto& f_info = m_files[oldstream];
1640 
1641  if ( newMode != f_info.second ) {
1642  error() << "in JobOption \"" << ident << "\":\n file \"" << filename << "\" already opened by stream: \""
1643  << oldstream << "\" with different access mode." << endmsg;
1644  return StatusCode::FAILURE;
1645  } else {
1646  TFile* f2 = f_info.first;
1647  m_files[stream] = std::make_pair( f2, newMode );
1648  if ( msgLevel( MSG::DEBUG ) )
1649  debug() << "Connecting stream: \"" << stream << "\" to previously opened TFile: \"" << filename << "\""
1650  << endmsg;
1651  return StatusCode::SUCCESS;
1652  }
1653  }
1654 
1655  IIncidentSvc* pi = nullptr;
1656  if ( service( "IncidentSvc", pi ).isFailure() ) {
1657  error() << "Unable to get the IncidentSvc" << endmsg;
1658  return StatusCode::FAILURE;
1659  }
1660 
1661  void* vf = nullptr;
1662  TFile* f = nullptr;
1663 
1664  if ( newMode == THistSvc::READ ) {
1665  // old file
1666  int r = p_fileMgr->open( Io::ROOT, name(), filename, Io::READ, vf, "HIST" );
1667 
1668  if ( r != 0 ) {
1669  error() << "Unable to open ROOT file " << filename << " for reading" << endmsg;
1670  return StatusCode::FAILURE;
1671  }
1672 
1673  f = (TFile*)vf;
1674 
1675  // FIX ME!
1676  pi->fireIncident( FileIncident( name(), "BeginHistFile", filename ) );
1677 
1678  } else if ( newMode == THistSvc::WRITE ) {
1679  // new file. error if file exists
1680  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" );
1681 
1682  if ( r != 0 ) {
1683  error() << "Unable to open ROOT file " << filename << " for writing" << endmsg;
1684  return StatusCode::FAILURE;
1685  }
1686 
1687  f = (TFile*)vf;
1688 
1689  } else if ( newMode == THistSvc::APPEND ) {
1690  // update file
1691  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::APPEND ), vf, "HIST" );
1692  if ( r != 0 ) {
1693  error() << "unable to open file \"" << filename << "\" for appending" << endmsg;
1694  return StatusCode::FAILURE;
1695  }
1696 
1697  f = (TFile*)vf;
1698 
1699  } else if ( newMode == THistSvc::SHARE ) {
1700  // SHARE file type
1701  // For SHARE files, all data will be stored in a temp file and will be
1702  // merged into the target file in writeObjectsToFile() when finalize(),
1703  // this help to solve some confliction. e.g. with storegate
1704  static int ishared = 0;
1705  std::string realfilename = filename;
1706  filename = "tmp_THistSvc_" + std::to_string( ishared++ ) + ".root";
1707 
1708  if ( msgLevel( MSG::DEBUG ) ) {
1709  debug() << "Creating temp file \"" << filename << "\" and realfilename=" << realfilename << endmsg;
1710  }
1711  m_sharedFiles[stream] = realfilename;
1712 
1713  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE | Io::EXCL ), vf, "HIST" );
1714 
1715  if ( r != 0 ) {
1716  error() << "Unable to open ROOT file " << filename << " for writing" << endmsg;
1717  return StatusCode::FAILURE;
1718  }
1719 
1720  f = (TFile*)vf;
1721 
1722  } else if ( newMode == THistSvc::UPDATE ) {
1723  // update file
1724  int r = p_fileMgr->open( Io::ROOT, name(), filename, ( Io::WRITE | Io::CREATE ), vf, "HIST" );
1725 
1726  if ( r != 0 ) {
1727  error() << "Unable to open ROOT file " << filename << " for appending" << endmsg;
1728  return StatusCode::FAILURE;
1729  }
1730 
1731  f = (TFile*)vf;
1732  }
1733 
1734  m_files[stream] = std::make_pair( f, newMode );
1736 
1737  if ( msgLevel( MSG::DEBUG ) ) {
1738  debug() << "Opening TFile \"" << filename << "\" stream: \"" << stream << "\" mode: \"" << typ << "\""
1739  << " comp level: " << cl << endmsg;
1740  }
1741 
1742  return StatusCode::SUCCESS;
1743 }
1744 
1745 TDirectory* THistSvc::changeDir( const THistSvc::THistID& hid ) const {
1746  std::string uid = hid.id;
1747  TFile* file = hid.file;
1748  std::string stream, fdir, bdir, dir, id;
1749 
1750  if ( file ) {
1751  file->cd( "/" );
1752  } else {
1753  gROOT->cd();
1754  }
1755 
1756  fdir = uid;
1757  bdir = stripDirectoryName( fdir );
1758 
1759  while ( ( dir = stripDirectoryName( fdir ) ) != "" ) {
1760  if ( !gDirectory->GetKey( dir.c_str() ) ) { gDirectory->mkdir( dir.c_str() ); }
1761  gDirectory->cd( dir.c_str() );
1762  }
1763 
1764  return gDirectory;
1765 }
1766 
1768  std::string::size_type i = dir.find( "/" );
1769 
1770  if ( i == std::string::npos ) return {};
1771 
1772  if ( i == 0 ) {
1773  dir.erase( 0, 1 );
1774  return stripDirectoryName( dir );
1775  }
1776 
1777  std::string root = dir.substr( 0, i );
1778  dir.erase( 0, i );
1779 
1780  return root;
1781 }
1782 
1784  while ( id.find( "//" ) != std::string::npos ) { id.replace( id.find( "//" ), 2, "/" ); }
1785 }
1786 
1787 void THistSvc::MergeRootFile( TDirectory* target, TDirectory* source ) {
1788  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Target path: " << target->GetPath() << endmsg; }
1789  TString path( (char*)strstr( target->GetPath(), ":" ) );
1790  path.Remove( 0, 2 );
1791 
1792  source->cd( path );
1793  TDirectory* current_sourcedir = gDirectory;
1794 
1795  // loop over all keys in this directory
1796  TList* lkeys = current_sourcedir->GetListOfKeys();
1797  int nkeys = lkeys->GetEntries();
1798  TKey* key = nullptr;
1799  for ( int jj = 0; jj < nkeys; jj++ ) {
1800  key = (TKey*)lkeys->At( jj );
1801  std::string pathnameinsource = current_sourcedir->GetPath() + std::string( "/" ) + key->GetName();
1802  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Reading Key:" << pathnameinsource << endmsg; }
1803  TObject* obj = source->Get( pathnameinsource.c_str() );
1804 
1805  if ( obj ) {
1806  if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
1807  // it's a subdirectory
1808  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Found subdirectory " << obj->GetName() << endmsg; }
1809 
1810  // create a new subdir of same name and title in the target file
1811  target->cd();
1812  TDirectory* newtargetdir = target->mkdir( obj->GetName(), obj->GetTitle() );
1813 
1814  MergeRootFile( newtargetdir, source );
1815 
1816  } else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
1817  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Found TTree " << obj->GetName() << endmsg; }
1818  TTree* mytree = dynamic_cast<TTree*>( obj );
1819  int nentries = (int)mytree->GetEntries();
1820  mytree->SetBranchStatus( "*", 1 );
1821 
1822  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Dumping TTree " << nentries << " entries" << endmsg; }
1823  target->cd();
1824  mytree->CloneTree();
1825 
1826  } else {
1827  target->cd();
1828  obj->Write( key->GetName() );
1829  }
1830  }
1831  }
1832 }
1833 
1834 bool THistSvc::findStream( const std::string& id, std::string& stream, std::string& rem, TFile*& file ) const {
1835  auto pos = id.find( "/" );
1836 
1837  if ( pos == std::string::npos ) {
1838  // no "/" in id
1839  stream = "temp";
1840  rem = id;
1841  } else if ( pos != 0 ) {
1842  // id does not start with "/"
1843  stream = "temp";
1844  rem = id;
1845  } else {
1846  // id starts with "/"
1847 
1848  auto pos2 = id.find( "/", pos + 1 );
1849 
1850  if ( pos2 == std::string::npos ) {
1851  // need at least 2 "/" in format "/STREAM/name" or "/STREAM/dir/name"
1852  error() << "badly formed Hist/Tree id: \"" << id << "\"" << endmsg;
1853  return false;
1854  }
1855  parseString( id, stream, rem );
1856  }
1857 
1858  if ( stream == "temp" ) {
1859  file = nullptr;
1860  return true;
1861  }
1862 
1863  auto itr = m_files.find( stream );
1864  file = ( itr != m_files.end() ? itr->second.first : nullptr );
1865  if ( !file ) { warning() << "no stream \"" << stream << "\" associated with id: \"" << id << "\"" << endmsg; }
1866 
1867  return true;
1868 }
1869 
1871  auto pos = id.find( "/" );
1872 
1873  if ( pos == std::string::npos ) {
1874  root.clear();
1875  rem = id;
1876  } else if ( pos == 0 ) {
1877  parseString( id.substr( 1 ), root, rem );
1878  } else {
1879  root = id.substr( 0, pos );
1880  rem = id.substr( pos + 1 );
1881  }
1882 }
1883 
1886  debug() << "Delaying connection of Input Files until Initialize"
1887  << ". now in " << FSMState() << endmsg;
1888 
1889  m_delayConnect = true;
1890  } else {
1891  debug() << "Now connecting of Input Files" << endmsg;
1892 
1894 
1895  for ( const auto& itr : m_inputfile.value() ) {
1896  if ( m_alreadyConnectedInFiles.end() != m_alreadyConnectedInFiles.find( itr ) ) { continue; }
1897  if ( connect( itr ).isFailure() ) {
1898  sc = StatusCode::FAILURE;
1899  } else {
1901  }
1902  }
1903 
1904  if ( !sc.isSuccess() ) { throw GaudiException( "Problem connecting inputfile !!", name(), StatusCode::FAILURE ); }
1905  }
1906 }
1907 
1910  debug() << "Delaying connection of Input Files until Initialize"
1911  << ". now in " << FSMState() << endmsg;
1912  m_delayConnect = true;
1913  } else {
1915  for ( const auto& itr : m_outputfile.value() ) {
1916  if ( m_alreadyConnectedOutFiles.end() != m_alreadyConnectedOutFiles.find( itr ) ) { continue; }
1917  if ( connect( itr ).isFailure() ) {
1918  sc = StatusCode::FAILURE;
1919  } else {
1921  }
1922  }
1923 
1924  if ( !sc.isSuccess() ) { throw GaudiException( "Problem connecting outputfile !!", name(), StatusCode::FAILURE ); }
1925  }
1926 }
1927 
1928 void THistSvc::copyFileLayout( TDirectory* destination, TDirectory* source ) {
1929  if ( msgLevel( MSG::DEBUG ) ) {
1930  debug() << "copyFileLayout() to destination path: " << destination->GetPath() << endmsg;
1931  }
1932 
1933  // strip out URLs
1934  TString path( (char*)strstr( destination->GetPath(), ":" ) );
1935  path.Remove( 0, 2 );
1936 
1937  source->cd( path );
1938  TDirectory* current_source_dir = gDirectory;
1939 
1940  // loop over all keys in this directory
1941  TList* key_list = current_source_dir->GetListOfKeys();
1942  int n = key_list->GetEntries();
1943  for ( int j = 0; j < n; ++j ) {
1944  TKey* k = (TKey*)key_list->At( j );
1945  const std::string source_pathname = current_source_dir->GetPath() + std::string( "/" ) + k->GetName();
1946  TObject* o = source->Get( source_pathname.c_str() );
1947 
1948  if ( o && o->IsA()->InheritsFrom( "TDirectory" ) ) {
1949  if ( msgLevel( MSG::VERBOSE ) ) { verbose() << " subdir [" << o->GetName() << "]..." << endmsg; }
1950  destination->cd();
1951  // Create directory if it does not exist yet
1952  TDirectory* destination_dir = destination->mkdir( o->GetName(), o->GetTitle() );
1953  if ( destination_dir == nullptr ) destination_dir = destination->GetDirectory( o->GetName() );
1954  copyFileLayout( destination_dir, source );
1955  }
1956  } // loop over keys
1957  return;
1958 }
1959 
1960 size_t THistSvc::findHistID( const std::string& id, const THistID*& hid, const size_t& index ) const {
1961  GlobalDirectoryRestore restore( m_svcMut );
1962 
1963  std::string idr( id );
1964  removeDoubleSlash( idr );
1965 
1966  hid = 0;
1967 
1968  if ( idr.find( "/" ) == 0 ) {
1969  // fully specified name, starts with "/"
1970  auto itr = m_uids.find( idr );
1971  if ( itr == m_uids.end() ) {
1972  // no matches found
1973  return 0;
1974  } else {
1975  // one or more matches found (clones).
1976  if ( index >= itr->second->size() ) {
1977  error() << "no index " << index << " found for Hist " << idr << endmsg;
1978  return 0;
1979  }
1980  hid = &( itr->second->at( index ) );
1981  return 1;
1982  }
1983  } else {
1984  // name not fully specified.
1985  auto mitr = m_ids.equal_range( idr );
1986  if ( mitr.first == mitr.second ) {
1987  // not found
1988  return 0;
1989  } else if ( distance( mitr.first, mitr.second ) == 1 ) {
1990  // one found
1991  if ( index >= mitr.first->second->size() ) {
1992  error() << "no index " << index << " found for Hist " << idr << endmsg;
1993  return 0;
1994  }
1995  hid = &( mitr.first->second->at( 0 ) );
1996  return 1;
1997  } else {
1998  // multiple matches
1999  hid = &( mitr.first->second->at( 0 ) );
2000  return distance( mitr.first, mitr.second );
2001  }
2002  }
2003 }
2004 
2005 void THistSvc::dump() const {
2006  std::ostringstream ost;
2007 
2008  // list< vector<THistID> >
2009  ost << "m_hlist: size: " << m_hlist.size() << "\n";
2010  for ( auto& vh : m_hlist ) {
2011  ost << " - " << vh->at( 0 ) << " :: [" << vh << "] " << vh->size() << " {";
2012  for ( auto& e : *vh ) {
2013  TObject* o = e.obj;
2014  ost << "[" << o << "]";
2015  }
2016  ost << "}\n";
2017  }
2018 
2019  // map uid -> vector<THistID>*
2020  ost << "\n"
2021  << "m_uids: " << m_uids.size() << "\n";
2022  for ( auto& e : m_uids ) { ost << " - " << e.first << " [" << e.second << "]" << std::endl; }
2023 
2024  // multimap id -> vector<THistID>*
2025  ost << "\n"
2026  << "m_ids: " << m_ids.size() << "\n";
2027  for ( auto& e : m_ids ) { ost << " - " << e.first << " [" << e.second << "]" << std::endl; }
2028 
2029  // map TObject* -> THistID*
2030  ost << "\n"
2031  << "m_tobjs: " << m_tobjs.size() << "\n";
2032  for ( auto& e : m_tobjs ) {
2033  TObject* o = e.first;
2034  THistID& i = e.second.first->at( e.second.second );
2035  ost << " - " << o << " -> " << i << std::endl;
2036  }
2037 
2038  debug() << "dumping THistSvc contents\n" << ost.str() << endmsg;
2039 }
2040 
2041 StatusCode THistSvc::merge( const THistID& hid ) { return merge( hid.id ); }
2042 
2044  const std::string& name = vh->at( 0 ).id;
2045  if ( vh->size() == 1 ) {
2046  debug() << "merge: id: \"" << name << "\" is size 1. nothing to do" << endmsg;
2047  return StatusCode::SUCCESS;
2048  }
2049 
2050  if ( !vh->at( 0 ).obj->IsA()->InheritsFrom( "TH1" ) ) {
2051  error() << "merge: id \"" << name << "\" is not a THn. Cannot merge" << endmsg;
2052  return StatusCode::FAILURE;
2053  }
2054 
2055  TList* l = new TList();
2056  for ( size_t i = 1; i < vh->size(); ++i ) {
2057  debug() << "merge: id: \"" << name << "\" (" << vh->at( i ).obj << ") adding index " << i << endmsg;
2058  l->Add( vh->at( i ).obj );
2059  }
2060 
2061  TH1* t0 = dynamic_cast<TH1*>( vh->at( 0 ).obj );
2062  if ( t0 == 0 ) {
2063  error() << "merge: could not dcast " << name << "(" << t0 << ") index " << 0 << " to TH1" << endmsg;
2064  return StatusCode::FAILURE;
2065  }
2066 
2067  Long64_t n = t0->Merge( l );
2068 
2069  debug() << "merge: id: \"" << name << "\" merged " << n << " entries" << endmsg;
2070 
2071  for ( size_t i = 1; i < vh->size(); ++i ) {
2072  TH1* th = dynamic_cast<TH1*>( vh->at( i ).obj );
2073  if ( th != 0 ) {
2074  debug() << "clearing index " << i << "(" << th << ")" << endmsg;
2075  th->SetDirectory( nullptr );
2076  th->Reset();
2077  } else {
2078  error() << "merge: could not dcast " << name << " index " << i << " to TH1" << endmsg;
2079  return StatusCode::FAILURE;
2080  }
2081  }
2082  return StatusCode::SUCCESS;
2083 }
2084 
2086  if ( fa->tech() != Io::ROOT ) {
2087  // This should never happen
2088  return StatusCode::SUCCESS;
2089  }
2090 
2091  if ( fa->desc() != "HIST" ) { return StatusCode::SUCCESS; }
2092 
2093  p_incSvc->fireIncident( FileIncident( caller, "OpenHistFile", fa->name() ) );
2094 
2095  if ( fa->flags().isRead() ) {
2096  p_incSvc->fireIncident( FileIncident( caller, "BeginHistFile", fa->name() ) );
2097  } else if ( fa->flags().isWrite() ) {
2098  p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) );
2099  } else {
2100  // for Io::RW
2101  p_incSvc->fireIncident( FileIncident( caller, IncidentType::BeginOutputFile, fa->name() ) );
2102  }
2103 
2104  return StatusCode::SUCCESS;
2105 }
2106 
2108  if ( fa->tech() != Io::ROOT ) {
2109  // This should never happen
2110  return StatusCode::SUCCESS;
2111  }
2112 
2113  if ( fa->desc() != "HIST" ) { return StatusCode::SUCCESS; }
2114 
2115  if ( fa->flags().isRead() ) {
2116  p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailInputFile, fa->name() ) );
2117  } else if ( fa->flags().isWrite() ) {
2118  p_incSvc->fireIncident( FileIncident( caller, IncidentType::FailOutputFile, fa->name() ) );
2119  } else {
2120  // for Io::RW
2121  p_incSvc->fireIncident( FileIncident( caller, "FailRWFile", fa->name() ) );
2122  }
2123 
2124  return StatusCode::SUCCESS;
2125 }
Parse attribute strings allowing iteration over the various attributes.
void dump() const
Definition: THistSvc.cpp:2005
bool existsEfficiency(const std::string &name) const override
Check if TEfficiency with given name is managed by THistSvcMT.
Definition: THistSvc.cpp:673
GlobalDirectoryRestore(THistSvcMutex_t &mut)
Definition: THistSvc.cpp:1445
Helper struct that bundles the histogram ID with a mutex, TFile and TObject*.
Definition: THistSvc.h:240
bool m_delayConnect
Definition: THistSvc.h:400
StatusCode initialize() override
Definition: Service.cpp:70
void MergeRootFile(TDirectory *, TDirectory *)
Definition: THistSvc.cpp:1787
std::vector< std::string > getTrees() const override
Definition: THistSvc.cpp:691
This class is the FileIncident.
Definition: FileIncident.h:27
T empty(T... args)
StatusCode initialize() override
Definition: THistSvc.cpp:78
StatusCode deReg(const std::string &name) override
Deregister object with given name and give up ownership (without deletion!)
Definition: THistSvc.cpp:566
Define general base for Gaudi exception.
virtual Io::open_t open(const Io::IoTech &, const std::string &caller, const std::string &fname, const Io::IoFlags &, Io::Fd &, void *&, const std::string &desc, const bool shared=false)=0
std::string m_curstream
Definition: THistSvc.h:403
StatusCode finalize() override
Definition: Service.cpp:174
Gaudi::StateMachine::State FSMState() const override
Definition: Service.h:62
bool m_signaledStop
Definition: THistSvc.h:399
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
StatusCode regShared(const std::string &name, std::unique_ptr< TH1 >, LockedHandle< TH1 > &) override
Register shared object of type TH1 and return LockedHandle for that object.
Definition: THistSvc.cpp:475
std::vector< std::string > getEfficiencies() const override
Definition: THistSvc.cpp:707
This file contains the class definition for the FileIncident class.
StatusCode getShared(const std::string &name, LockedHandle< TH1 > &) const override
Retrieve shared object with given name as TH1 through LockedHandle.
Definition: THistSvc.cpp:521
IIncidentSvc * p_incSvc
Definition: THistSvc.h:396
T * readHist(const std::string &name) const
Definition: THistSvc.cpp:1460
T rfind(T... args)
StatusCode getTEfficiencies(TDirectory *td, TList &, bool recurse=false) const override
Definition: THistSvc.cpp:1096
T to_string(T... args)
StatusCode getTTrees(TDirectory *td, TList &, bool recurse=false) const override
Definition: THistSvc.cpp:915
T endl(T... args)
const std::string & name() const
Definition: IFileMgr.h:186
StatusCode writeObjectsToFile()
Definition: THistSvc.cpp:1543
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
StatusCode merge(const std::string &id) override
Merge all clones for object with a given id.
Definition: THistSvc.cpp:649
StatusCode getGraph(const std::string &name, TGraph *&) const override
Return TGraph with given name.
Definition: THistSvc.cpp:443
IoTech tech() const
Definition: IFileMgr.h:188
bool existsGraph(const std::string &name) const override
Check if graph with given name is managed by THistSvcMT.
Definition: THistSvc.cpp:677
T end(T... args)
StatusCode rootOpenAction(FILEMGR_CALLBACK_ARGS)
Definition: THistSvc.cpp:2085
void copyFileLayout(TDirectory *, TDirectory *)
helper function to recursively copy the layout of a TFile into a new TFile
Definition: THistSvc.cpp:1928
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
std::string stripDirectoryName(std::string &dir) const
Definition: THistSvc.cpp:1767
T lower_bound(T... args)
T remove(T... args)
bool isWrite() const
Definition: IFileMgr.h:66
STL class.
bool findStream(const std::string &name, std::string &root, std::string &rem, TFile *&file) const
Definition: THistSvc.cpp:1834
Gaudi::Property< std::vector< std::string > > m_outputfile
Definition: THistSvc.h:391
objMap_t m_tobjs
Definition: THistSvc.h:303
StatusCode getTHists(TDirectory *td, TList &, bool recurse=false) const override
Definition: THistSvc.cpp:716
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
IoFlags flags() const
Definition: IFileMgr.h:189
STL class.
virtual StatusCode regAction(Io::bfcn_action_t, const Io::Action &, const std::string &d="")=0
#define DECLARE_COMPONENT(type)
void setupOutputFile()
call-back method to handle output stream property
Definition: THistSvc.cpp:1908
void parseString(const std::string &id, std::string &root, std::string &rem) const
Definition: THistSvc.cpp:1870
T at(T... args)
hlist_t m_hlist
Definition: THistSvc.h:298
idMap_t m_ids
Definition: THistSvc.h:300
void setupInputFile()
call-back method to handle input stream property
Definition: THistSvc.cpp:1884
const std::string & name() const override
Retrieve name of the service.
Definition: Service.cpp:284
Gaudi::Property< int > m_autoSave
Definition: THistSvc.h:379
T push_back(T... args)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
std::string id
Definition: THistSvc.h:241
virtual void fireIncident(const Incident &incident)=0
Fire an Incident.
Gaudi::Property< std::vector< std::string > > m_inputfile
Definition: THistSvc.h:392
StatusCode getTree(const std::string &name, TTree *&) const override
Return TTree with given name.
Definition: THistSvc.cpp:402
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:61
bool m_okToConnect
Definition: THistSvc.h:401
Provides automatic lock/unlock access to a class upon deref of ptr.
Definition: LockedHandle.h:38
Gaudi::Property< bool > m_print
Definition: THistSvc.h:381
void handle(const Incident &) override
Definition: THistSvc.cpp:1299
Gaudi::Property< int > m_maxFileSize
Definition: THistSvc.h:382
std::vector< std::string > getHists() const override
Definition: THistSvc.cpp:683
T erase(T... args)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
static Mode charToMode(const char typ)
Convert a char to a Mode enum.
Definition: THistSvc.h:224
T str(T... args)
T make_pair(T... args)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
TDirectory * changeDir(const THistSvc::THistID &hid) const
Definition: THistSvc.cpp:1745
StatusCode rootOpenErrAction(FILEMGR_CALLBACK_ARGS)
Definition: THistSvc.cpp:2107
def end
Definition: IOTest.py:123
T clear(T... args)
bool isSuccess() const
Definition: StatusCode.h:365
bool existsHist(const std::string &name) const override
Check if histogram with given name is managed by THistSvcMT.
Definition: THistSvc.cpp:671
StatusCode finalize() override
Definition: THistSvc.cpp:189
T move(T... args)
bool existsTree(const std::string &name) const override
Check if tree with given name is managed by THistSvcMT.
Definition: THistSvc.cpp:681
StatusCode regHist_i(std::unique_ptr< T > hist, const std::string &name, bool shared)
Definition: THistSvc.icc:27
const std::string & desc() const
Definition: IFileMgr.h:187
StatusCode regHist(const std::string &name) override
Register a new ROOT histogram TH*X with a name.
Definition: THistSvc.cpp:329
dictionary l
Definition: gaudirun.py:543
StatusCode getHist(const std::string &name, TH1 *&, size_t index=0) const override
Return histogram with given name as TH1*, THistSvcMT still owns object.
Definition: THistSvc.cpp:349
virtual std::vector< std::string > io_retrieve(IIoComponent *iocomponent)=0
: retrieve all registered filenames for a given IIoComponent
T get(T... args)
constexpr double nm
Definition: SystemOfUnits.h:91
T insert(T... args)
T find(T... args)
T length(T... args)
const StatusCode & ignore() const
Ignore/check StatusCode.
Definition: StatusCode.h:168
StatusCode regEfficiency(const std::string &name) override
Register a new TEfficiency with a given name.
Definition: THistSvc.cpp:452
TObject * obj
Definition: THistSvc.h:243
STL class.
STL class.
StatusCode reinitialize() override
Definition: THistSvc.cpp:183
T begin(T... args)
T back_inserter(T... args)
void removeDoubleSlash(std::string &) const
Definition: THistSvc.cpp:1783
bool isRead() const
Definition: IFileMgr.h:65
T c_str(T... args)
Base class for all Incidents (computing events).
Definition: Incident.h:27
virtual void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false)=0
Add listener.
uidMap_t m_uids
Definition: THistSvc.h:299
std::map< std::string, std::pair< TFile *, Mode > > m_files
Definition: THistSvc.h:305
T emplace(T... args)
T back(T... args)
string s
Definition: gaudirun.py:328
StatusCode connect(const std::string &)
Definition: THistSvc.cpp:1568
constexpr static const auto FAILURE
Definition: StatusCode.h:101
The IEventProcessor is the interface to process events.
virtual StatusCode io_register(IIoComponent *iocomponent)=0
: allow a IIoComponent to register itself with this manager so appropriate actions can be taken when ...
IFileMgr * p_fileMgr
Definition: THistSvc.h:397
std::set< std::string > m_alreadyConnectedOutFiles
list of already connected files.
Definition: THistSvc.h:285
T substr(T... args)
StatusCode regTree(const std::string &name) override
Register a new TTree with a given name.
Definition: THistSvc.cpp:376
std::map< std::string, std::string > m_sharedFiles
Definition: THistSvc.h:310
StatusCode service(const std::string &name, const T *&psvc, bool createIf=true) const
Access a service by name, creating it if it doesn't already exist.
Definition: Service.h:93
bool exists(const std::string &name) const override
Check if object with given name is managed by THistSvcMT exists calls existsHist and only works for T...
Definition: THistSvc.cpp:669
MsgStream & err() const
shortcut for the method msgStream(MSG::ERROR)
bool isFailure() const
Definition: StatusCode.h:145
AttribStringParser::Iterator begin(const AttribStringParser &parser)
std::set< std::string > m_alreadyConnectedInFiles
list of already connected files.
Definition: THistSvc.h:281
StatusCode getEfficiency(const std::string &name, TEfficiency *&) const override
Return TEfficiency with given name.
Definition: THistSvc.cpp:466
T for_each(T... args)
StatusCode regGraph(const std::string &name) override
Register a new TGraph with a given name.
Definition: THistSvc.cpp:411
Gaudi::Property< int > m_autoFlush
Definition: THistSvc.h:380
T stoi(T... args)
StatusCode io_reinit() override
callback method to reinitialize the internal state of the component for I/O purposes (e....
Definition: THistSvc.cpp:1344
THistSvcMutex_t m_svcMut
Definition: THistSvc.h:405
size_t findHistID(const std::string &id, const THistID *&hid, const size_t &index=0) const
Definition: THistSvc.cpp:1960
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
TTree * readTree(const std::string &name) const
Definition: THistSvc.cpp:1464
T equal_range(T... args)
Helper class that manages ROOts global directory and file.
Definition: THistSvc.h:208
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
constexpr double pi
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:33
streamMap m_fileStreams
Definition: THistSvc.h:307
T reserve(T... args)
void updateFiles()
Handle case where TTree grows beyond TTree::fgMaxTreeSize.
Definition: THistSvc.cpp:1466
std::vector< std::string > getGraphs() const override
Definition: THistSvc.cpp:699
T emplace_back(T... args)
virtual Io::close_t close(const Io::Fd, const std::string &caller)=0