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