19#include <boost/algorithm/string/case_conv.hpp>
23#include <TDirectory.h>
59 template <
typename InputIterator,
typename OutputIterator,
typename UnaryOperation,
typename UnaryPredicate>
60 OutputIterator transform_if( InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op,
61 UnaryPredicate pred ) {
62 while ( first != last ) {
63 if ( pred( *first ) ) *result++ = op( *first );
69 constexpr struct select1st_t {
70 template <
typename T,
typename S>
71 const T& operator()(
const std::pair<T, S>& p )
const {
110 static TROOT root(
"root",
"ROOT I/O" );
116 if (
p_incSvc.retrieve().isFailure() ) {
117 error() <<
"unable to get the IncidentSvc" <<
endmsg;
120 p_incSvc->addListener(
this,
"EndEvent", 100,
true );
123 if (
p_fileMgr.retrieve().isFailure() ) {
131 using namespace std::placeholders;
134 error() <<
"unable to register ROOT file open action with FileMgr" <<
endmsg;
136 auto bea = [
this](
const Io::FileAttr* fa,
const std::string& caller ) {
140 error() <<
"unable to register ROOT file open Error action with FileMgr" <<
endmsg;
154 error() <<
"unable to get the IoComponentMgr" <<
endmsg;
157 if ( !iomgr->io_register(
this ).isSuccess() ) {
158 error() <<
"could not register with the I/O component manager !" <<
endmsg;
161 bool all_good =
true;
163 for (
const auto& reg :
m_files ) {
164 const std::string& fname = reg.second.first->GetName();
167 if ( !iomgr->io_register(
this, iomode, fname ).isSuccess() ) {
168 warning() <<
"could not register file [" << fname <<
"] with the I/O component manager..." <<
endmsg;
171 info() <<
"registered file [" << fname <<
"]... [ok]" <<
endmsg;
175 error() <<
"problem while registering input/output files with "
176 <<
"the I/O component manager !" <<
endmsg;
203 const std::map<uidMap_t::key_type, uidMap_t::mapped_type> sorted_uids{ begin(
m_uids ), end(
m_uids ) };
204 for (
const auto& itr : sorted_uids ) {
205 THistID& thid = itr.second->at( 0 );
206 TObject* tobj = thid.
obj;
208 std::string dirname(
"none" );
210 TTree* tree =
dynamic_cast<TTree*
>( tobj );
211 if ( tree->GetDirectory() != 0 ) { dirname = tree->GetDirectory()->GetPath(); }
214 dirname = thid.
file->GetPath();
215 std::string id2( thid.
id );
216 id2.erase( 0, id2.find(
"/", 1 ) );
217 id2.erase( id2.rfind(
"/" ), id2.length() );
218 if ( id2.starts_with(
"/" ) ) { id2.erase( 0, 1 ); }
224 TH1* th =
dynamic_cast<TH1*
>( tobj );
225 if ( th ==
nullptr ) {
226 error() <<
"Couldn't dcast: " << itr.first <<
endmsg;
228 if ( th->GetDirectory() != 0 ) { dirname = th->GetDirectory()->GetPath(); }
230 }
else if ( !tobj ) {
241 std::vector<TFile*> deleted_files;
243 if ( std::find( deleted_files.begin(), deleted_files.end(), itr.second.first ) == deleted_files.end() ) {
244 deleted_files.push_back( itr.second.first );
248 debug() <<
"finalizing stream/file " << itr.first <<
":" << itr.second.first->GetName() <<
endmsg;
259 info() <<
"==> File: " << itr.second.first->GetName() <<
" stream: " << itr.first <<
endmsg;
261 itr.second.first->Print(
"base" );
264 std::string tmpfn = itr.second.first->GetName();
268 if ( itr.second.second ==
SHARE ) {
270 void* vfile =
nullptr;
279 TFile* outputfile = (TFile*)vfile;
288 error() <<
"unable to open temporary file: \"" << tmpfn <<
endmsg;
292 TFile* inputfile = (TFile*)vfile;
294 outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() );
304 std::remove( tmpfn.c_str() );
306 delete itr.second.first;
319 if ( obj.second.second == 0 ) {
320 delete obj.second.first;
331 std::unique_ptr<TH1> hist =
nullptr;
332 return regHist_i( std::move( hist ),
id,
false );
336 return regHist_i( std::move( hist ),
id,
false );
340 std::unique_ptr<TH1> hist( hist_ptr );
341 return regHist_i( std::move( hist ),
id,
false );
346 if ( hist !=
nullptr ) {
355 if ( hist !=
nullptr ) {
364 if ( hist !=
nullptr ) {
372 std::unique_ptr<TTree> tree =
nullptr;
373 return regHist_i( std::move( tree ),
id,
false );
387 std::unique_ptr<TTree> tree( tree_ptr );
399 if ( tree !=
nullptr ) {
407 std::unique_ptr<TGraph> graph = std::make_unique<TGraph>();
408 return regHist_i( std::move( graph ),
id,
false );
412 if ( strcmp( graph->GetName(),
"Graph" ) == 0 ) {
413 std::string id2(
id );
414 std::string::size_type i = id2.rfind(
"/" );
415 if ( i != std::string::npos ) { id2.erase( 0, i + 1 ); }
417 info() <<
"setting name of TGraph id: \"" <<
id <<
"\" to \"" << id2 <<
"\" since it is unset" <<
endmsg;
418 graph->SetName( id2.c_str() );
421 return regHist_i( std::move( graph ),
id,
false );
425 std::unique_ptr<TGraph> graph( graph_ptr );
426 if ( strcmp( graph->GetName(),
"Graph" ) == 0 ) {
427 std::string id2(
id );
428 std::string::size_type i = id2.rfind(
"/" );
429 if ( i != std::string::npos ) { id2.erase( 0, i + 1 ); }
431 info() <<
"setting name of TGraph id: \"" <<
id <<
"\" to \"" << id2 <<
"\" since it is unset" <<
endmsg;
432 graph->SetName( id2.c_str() );
435 return regHist_i( std::move( graph ),
id,
false );
440 if ( graph !=
nullptr ) {
448 std::unique_ptr<TEfficiency> eff =
nullptr;
449 return regHist_i( std::move( eff ),
id,
false );
453 return regHist_i( std::move( eff ),
id,
false );
457 std::unique_ptr<TEfficiency> eff( eff_ptr );
458 return regHist_i( std::move( eff ),
id,
false );
463 if ( eff !=
nullptr ) {
562 auto itr =
m_uids.find(
id );
563 if ( itr ==
m_uids.end() ) {
564 error() <<
"Problem deregistering id \"" <<
id <<
"\": not found in registry" <<
endmsg;
571 debug() <<
"will deregister " << vh->size() <<
" elements of id \"" <<
id <<
"\"" <<
endmsg;
575 size_t vh_size = vh->size();
576 while ( vh_size-- ) {
579 error() <<
"Problems deRegistering " << vh->size() <<
" element of id \"" <<
id <<
"\"" <<
endmsg;
588 objMap_t::iterator obj_itr =
m_tobjs.find( obj );
589 if ( obj_itr !=
m_tobjs.end() ) {
590 vhid_t* vhid = obj_itr->second.first;
591 THistID hid = obj_itr->second.first->at( obj_itr->second.second );
593 auto uid_itr =
m_uids.find( hid.
id );
594 if ( uid_itr ==
m_uids.end() ) {
595 error() <<
"Problems deregistering TObject \"" << obj->GetName() <<
"\" with id \"" << hid.
id
596 <<
"\": not in uidMap" <<
endmsg;
600 if ( vhid->size() == 1 ) {
604 std::string root, rem;
607 auto mitr =
m_ids.equal_range( rem );
608 auto id_itr = std::find_if( mitr.first, mitr.second,
609 [&]( idMap_t::const_reference i ) { return i.second->at( 0 ).obj == obj; } );
610 if ( id_itr == mitr.second ) {
611 error() <<
"Problems deregistering TObject \"" << obj->GetName() <<
"\" with id \"" << hid.
id
612 <<
"\": not in idMap" <<
endmsg;
616 auto hlist_itr = std::find(
m_hlist.begin(),
m_hlist.end(), vhid );
617 if ( hlist_itr ==
m_hlist.end() ) {
618 error() <<
"Problems deregistering TObject \"" << obj->GetName() <<
"\" with id \"" << hid.
id
619 <<
"\": not in hlist" <<
endmsg;
623 vhid->erase( vhid->begin() + obj_itr->second.second );
627 m_ids.erase( id_itr );
632 }
else if ( vhid->size() > 1 ) {
633 vhid->erase( vhid->begin() + obj_itr->second.second );
638 error() <<
"Deregistration failed unexpectedly. (bug in THistSvc?)" <<
endmsg;
642 error() <<
"Cannot unregister TObject \"" << obj->GetName() <<
"\": not known to THistSvc" <<
endmsg;
649 if ( itr ==
m_uids.end() ) {
654 return merge( itr->second );
658 objMap_t::iterator itr =
m_tobjs.find( obj );
660 return merge( itr->second.first );
662 error() <<
"merge: unknown object " << obj <<
endmsg;
682 std::vector<std::string> names;
683 names.reserve(
m_uids.size() );
684 transform_if( std::begin(
m_uids ), std::end(
m_uids ), std::back_inserter( names ), select1st,
685 []( uidMap_t::const_reference i ) {
return i.second->at( 0 ).type ==
ObjectType::TH1; } );
690 std::vector<std::string> names;
691 names.reserve(
m_uids.size() );
692 transform_if( std::begin(
m_uids ), std::end(
m_uids ), std::back_inserter( names ), select1st,
693 []( uidMap_t::const_reference i ) {
return i.second->at( 0 ).type ==
ObjectType::TTREE; } );
698 std::vector<std::string> names;
699 names.reserve(
m_uids.size() );
700 transform_if( std::begin(
m_uids ), std::end(
m_uids ), std::back_inserter( names ), select1st,
701 []( uidMap_t::const_reference i ) {
return i.second->at( 0 ).type ==
ObjectType::TGRAPH; } );
706 std::vector<std::string> names;
707 names.reserve(
m_uids.size() );
708 transform_if( std::begin(
m_uids ), std::end(
m_uids ), std::back_inserter( names ), select1st,
716 gErrorIgnoreLevel = kBreak;
719 error() <<
"getTHists: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
724 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
727 TIter nextkey( td->GetListOfKeys() );
728 while ( TKey* key = (TKey*)nextkey() ) {
731 TObject* obj = key->ReadObj();
732 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
734 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TH1" ) ) {
737 }
else if ( obj != 0 ) {
745 nextkey = td->GetListOfKeys();
746 while ( TKey* key = (TKey*)nextkey() ) {
747 TObject* obj = key->ReadObj();
748 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
749 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
762 gErrorIgnoreLevel = kBreak;
766 std::string stream, rem, r2;
769 auto itr =
m_files.find( stream );
771 r2 = itr->second.first->GetName();
776 debug() <<
"getTHists: \"" << dir <<
"\" looks like a stream name."
777 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
780 if ( gDirectory->cd( r2.c_str() ) ) {
793 if ( !gDirectory->cd( dir.c_str() ) ) {
794 error() <<
"getTHists: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
806 gErrorIgnoreLevel = kBreak;
809 error() <<
"getTHists: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
814 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
817 TIter nextkey( td->GetListOfKeys() );
818 while ( TKey* key = (TKey*)nextkey() ) {
821 TObject* obj = key->ReadObj();
822 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
824 }
else if ( obj && obj->IsA()->InheritsFrom(
"TH1" ) ) {
828 std::string dir = td->GetPath();
829 std::string fil = td->GetFile()->GetName();
830 dir.erase( 0, fil.length() + 1 );
833 id =
id +
"/" + key->GetName();
835 id =
id + dir +
"/" + key->GetName();
852 nextkey = td->GetListOfKeys();
853 while ( TKey* key = (TKey*)nextkey() ) {
854 TObject* obj = key->ReadObj();
855 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
856 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
868 gErrorIgnoreLevel = kBreak;
872 std::string stream, rem, r2;
875 auto itr =
m_files.find( stream );
877 r2 = itr->second.first->GetName();
882 debug() <<
"getTHists: \"" << dir <<
"\" looks like a stream name."
883 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
886 if ( gDirectory->cd( r2.c_str() ) ) {
888 sc =
getTHists( gDirectory, tl, rcs, reg );
897 if ( !gDirectory->cd( dir.c_str() ) ) {
898 error() <<
"getTHists: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
902 warning() <<
"Unable to register histograms automatically "
903 <<
"without a valid stream name" <<
endmsg;
906 sc =
getTHists( gDirectory, tl, rcs, reg );
915 gErrorIgnoreLevel = kBreak;
918 error() <<
"getTTrees: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
923 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
926 TIter nextkey( td->GetListOfKeys() );
927 while ( TKey* key = (TKey*)nextkey() ) {
930 TObject* obj = key->ReadObj();
931 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
933 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TTree" ) ) {
936 }
else if ( obj != 0 ) {
944 nextkey = td->GetListOfKeys();
945 while ( TKey* key = (TKey*)nextkey() ) {
946 TObject* obj = key->ReadObj();
947 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
948 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
960 gErrorIgnoreLevel = kBreak;
964 std::string stream, rem, r2;
967 auto itr =
m_files.find( stream );
969 r2 = itr->second.first->GetName();
974 debug() <<
"getTTrees: \"" << dir <<
"\" looks like a stream name."
975 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
978 if ( gDirectory->cd( r2.c_str() ) ) {
return getTTrees( gDirectory, tl, rcs ); }
984 if ( !gDirectory->cd( dir.c_str() ) ) {
985 error() <<
"getTTrees: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
996 gErrorIgnoreLevel = kBreak;
999 error() <<
"getTTrees: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
1004 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
1007 TIter nextkey( td->GetListOfKeys() );
1008 while ( TKey* key = (TKey*)nextkey() ) {
1009 auto& log =
debug();
1011 TObject* obj = key->ReadObj();
1012 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1014 }
else if ( obj && obj->IsA()->InheritsFrom(
"TTree" ) ) {
1018 std::string dir = td->GetPath();
1019 std::string fil = td->GetFile()->GetName();
1020 dir.erase( 0, fil.length() + 1 );
1023 id =
id +
"/" + key->GetName();
1025 id =
id + dir +
"/" + key->GetName();
1034 }
else if ( obj != 0 ) {
1042 nextkey = td->GetListOfKeys();
1043 while ( TKey* key = (TKey*)nextkey() ) {
1044 TObject* obj = key->ReadObj();
1045 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1046 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
1058 gErrorIgnoreLevel = kBreak;
1062 std::string stream, rem, r2;
1065 auto itr =
m_files.find( stream );
1067 r2 = itr->second.first->GetName();
1072 debug() <<
"getTTrees: \"" << dir <<
"\" looks like a stream name."
1073 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1076 if ( gDirectory->cd( r2.c_str() ) ) {
1077 return getTTrees( gDirectory, tl, rcs, reg );
1085 if ( !gDirectory->cd( dir.c_str() ) ) {
1086 error() <<
"getTTrees: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1090 return getTTrees( gDirectory, tl, rcs, reg );
1096 gErrorIgnoreLevel = kBreak;
1099 error() <<
"getTEfficiencies: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
1104 debug() <<
"getTEfficiencies: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys"
1108 TIter nextkey( td->GetListOfKeys() );
1109 while ( TKey* key = (TKey*)nextkey() ) {
1110 auto& log =
debug();
1112 TObject* obj = key->ReadObj();
1113 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1115 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TEfficiency" ) ) {
1118 }
else if ( obj != 0 ) {
1126 nextkey = td->GetListOfKeys();
1127 while ( TKey* key = (TKey*)nextkey() ) {
1128 TObject* obj = key->ReadObj();
1129 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1130 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
1143 gErrorIgnoreLevel = kBreak;
1147 std::string stream, rem, r2;
1150 auto itr =
m_files.find( stream );
1152 r2 = itr->second.first->GetName();
1157 debug() <<
"getTEfficiencies: \"" << dir <<
"\" looks like a stream name."
1158 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1161 if ( gDirectory->cd( r2.c_str() ) ) {
1174 if ( !gDirectory->cd( dir.c_str() ) ) {
1175 error() <<
"getTEfficiencies: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1187 gErrorIgnoreLevel = kBreak;
1190 error() <<
"getTEfficiencies: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
1195 debug() <<
"getTEfficiencies: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys"
1199 TIter nextkey( td->GetListOfKeys() );
1200 while ( TKey* key = (TKey*)nextkey() ) {
1201 auto& log =
debug();
1203 TObject* obj = key->ReadObj();
1204 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1206 }
else if ( obj && obj->IsA()->InheritsFrom(
"TEfficiency" ) ) {
1210 std::string dir = td->GetPath();
1211 std::string fil = td->GetFile()->GetName();
1212 dir.erase( 0, fil.length() + 1 );
1215 id =
id +
"/" + key->GetName();
1217 id =
id + dir +
"/" + key->GetName();
1234 nextkey = td->GetListOfKeys();
1235 while ( TKey* key = (TKey*)nextkey() ) {
1236 TObject* obj = key->ReadObj();
1237 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1238 TDirectory* tt =
dynamic_cast<TDirectory*
>( obj );
1250 gErrorIgnoreLevel = kBreak;
1254 std::string stream, rem, r2;
1257 auto itr =
m_files.find( stream );
1259 r2 = itr->second.first->GetName();
1264 debug() <<
"getTEfficiencies: \"" << dir <<
"\" looks like a stream name."
1265 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1268 if ( gDirectory->cd( r2.c_str() ) ) {
1279 if ( !gDirectory->cd( dir.c_str() ) ) {
1280 error() <<
"getTEfficiencies: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1284 warning() <<
"Unable to register histograms automatically "
1285 <<
"without a valid stream name" <<
endmsg;
1301 Long64_t mfs = (Long64_t)
m_maxFileSize.value() * (Long64_t)1048576;
1302 Long64_t mfs_warn = mfs * 95 / 100;
1306 for (
const auto& f :
m_files ) {
1307 TFile* tf = f.second.first;
1311 debug() <<
"stream: " << f.first <<
" name: " << tf->GetName() <<
" size: " << tf->GetSize() <<
endmsg;
1316 if ( tf->GetSize() > mfs ) {
1319 throw GaudiException( std::format(
"file \"{}\" associated with stream \"{}\" has exceeded the max "
1320 "file size of {} MB. Terminating Job.",
1324 }
else if ( tf->GetSize() > mfs_warn ) {
1325 warning() <<
"file \"" << tf->GetName() <<
"\" associated with stream \"" << f.first
1326 <<
"\" is at 95% of its maximum allowable file size of " <<
m_maxFileSize.value() <<
"MB" <<
endmsg;
1335 bool all_good =
true;
1342 error() <<
"could not retrieve I/O component manager !" <<
endmsg;
1349 gErrorIgnoreLevel = kFatal;
1351 for (
auto& ifile :
m_files ) {
1352 TFile* f = ifile.second.first;
1353 std::string fname = f->GetName();
1355 debug() <<
"file [" << fname <<
"] mode: [" << f->GetOption() <<
"] r:" << f->GetFileBytesRead()
1356 <<
" w:" << f->GetFileBytesWritten() <<
" cnt:" << f->GetFileCounter() <<
endmsg;
1359 if ( ifile.second.second ==
READ ) {
1364 if ( !iomgr->io_retrieve(
this, fname ).isSuccess() ) {
1365 error() <<
"could not retrieve new name for [" << fname <<
"] !!" <<
endmsg;
1368 }
else if ( fname.empty() ) {
1376 Option_t* opts = f->GetOption();
1379 error() <<
"unable to open file \"" << fname <<
"\" for writing" <<
endmsg;
1382 TFile* newfile = (TFile*)vf;
1383 newfile->SetOption( opts );
1387 ifile.second.first = newfile;
1391 for (
auto& uid :
m_uids ) {
1392 for (
auto& hid : *uid.second ) {
1393 if ( hid.file != f )
continue;
1394 TDirectory* olddir = this->
changeDir( hid );
1397 TDirectory* newdir = this->
changeDir( hid );
1398 TClass* cl = hid.obj->IsA();
1403 TTree& tree =
dynamic_cast<TTree&
>( *hid.obj );
1404 tree.SetDirectory( newdir );
1407 TH1& hist =
dynamic_cast<TH1&
>( *hid.obj );
1408 hist.SetDirectory( newdir );
1411 dynamic_cast<TEfficiency&
>( *hid.obj ).SetDirectory( newdir );
1413 olddir->Remove( hid.obj );
1414 newdir->Append( hid.obj );
1416 error() <<
"id: \"" << hid.id <<
"\" is not a inheriting from a class "
1417 <<
"we know how to handle (received [" << cl->GetName() <<
"], "
1418 <<
"expected [TTree, TH1, TGraph or TEfficiency]) !" <<
endmsg <<
"attaching to current dir ["
1419 << newdir->GetPath() <<
"] "
1420 <<
"nonetheless..." <<
endmsg;
1421 olddir->Remove( hid.obj );
1422 newdir->Append( hid.obj );
1426 f->ReOpen(
"READ" );
1450template <
typename T>
1466 for (
auto uitr =
m_uids.begin(); uitr !=
m_uids.end(); ++uitr ) {
1467 for (
auto& hid : *( uitr->second ) ) {
1470 if ( hid.type !=
ObjectType::TTREE || hid.temp || hid.mode ==
READ || hid.obj ==
nullptr )
continue;
1473 verbose() <<
" update: " << uitr->first <<
" " << hid.id <<
" " << hid.mode <<
endmsg;
1475 TTree* tr =
dynamic_cast<TTree*
>( hid.obj );
1476 TFile* oldFile = hid.file;
1477 TFile* newFile = tr->GetCurrentFile();
1479 if ( oldFile != newFile ) {
1480 std::string newFileName = newFile->GetName();
1481 std::string oldFileName, streamName, rem;
1482 TFile* dummy =
nullptr;
1483 findStream( hid.id, streamName, rem, dummy );
1486 if ( itr.second.first == oldFile ) { itr.second.first = newFile; }
1489 for (
auto uitr2 = uitr; uitr2 !=
m_uids.end(); ++uitr2 ) {
1490 for (
auto& hid2 : *( uitr2->second ) ) {
1491 if ( hid2.file == oldFile ) { hid2.file = newFile; }
1496 [&]( streamMap::const_reference s ) {
return s.second == streamName; } );
1497 if ( sitr != std::end(
m_fileStreams ) ) oldFileName = sitr->first;
1501 debug() <<
"migrating uid: " << hid.id <<
" stream: " << streamName <<
" oldFile: " << oldFileName
1502 <<
" newFile: " << newFileName <<
endmsg;
1506 if ( !oldFileName.empty() ) {
1508 while ( i != std::end(
m_fileStreams ) && i->first == oldFileName ) {
1511 debug() <<
"changing filename \"" << i->first <<
"\" to \"" << newFileName <<
"\" for stream \""
1512 << i->second <<
"\"" <<
endmsg;
1515 std::string nm = std::move( i->second );
1520 error() <<
"Problems updating fileStreams with new file name" <<
endmsg;
1530 std::for_each(
m_files.begin(),
m_files.end(), []( std::pair<
const std::string, std::pair<TFile*, Mode>>& i ) {
1531 auto mode = i.second.second;
1532 auto file = i.second.first;
1533 if ( mode == WRITE || mode == UPDATE || mode == SHARE ) {
1534 file->Write(
"", TObject::kOverwrite );
1535 }
else if ( mode ==
APPEND ) {
1541 debug() <<
"THistSvc::writeObjectsToFile()::List of Files connected in ROOT " <<
endmsg;
1542 TSeqCollection* filelist = gROOT->GetListOfFiles();
1543 for (
int ii = 0; ii < filelist->GetEntries(); ii++ ) {
1544 debug() <<
"THistSvc::writeObjectsToFile()::List of Files connected in ROOT: \"" << filelist->At( ii )->GetName()
1553 auto loc = ident.find(
" " );
1554 std::string stream = ident.substr( 0, loc );
1556 typedef std::pair<std::string, std::string> Prop;
1557 std::vector<Prop> props;
1558 std::string filename, db_typ(
"ROOT" );
1561 if ( loc != std::string::npos ) {
1563 for (
auto attrib : Parser( ident.substr( loc + 1 ) ) ) {
1567 auto TAG = attrib.tag;
1568 auto VAL = attrib.value;
1569 boost::algorithm::to_upper( TAG );
1570 boost::algorithm::to_upper( VAL );
1572 if ( TAG ==
"FILE" || TAG ==
"DATAFILE" ) {
1573 filename = attrib.value;
1575 }
else if ( TAG ==
"OPT" ) {
1576 if ( VAL ==
"APPEND" || VAL ==
"UPDATE" ) {
1578 }
else if ( VAL ==
"CREATE" || VAL ==
"NEW" || VAL ==
"WRITE" ) {
1580 }
else if ( VAL ==
"RECREATE" ) {
1582 }
else if ( VAL ==
"SHARE" ) {
1584 }
else if ( VAL ==
"OLD" || VAL ==
"READ" ) {
1587 error() <<
"Unknown OPT: \"" << attrib.value <<
"\"" <<
endmsg;
1590 }
else if ( TAG ==
"TYP" ) {
1591 db_typ = std::move( attrib.value );
1592 }
else if ( TAG ==
"CL" ) {
1593 cl = std::stoi( attrib.value );
1595 props.emplace_back( attrib.tag, attrib.value );
1600 if ( stream ==
"temp" ) {
1601 error() <<
"in JobOption \"" << ident <<
"\": stream name \"temp\" reserved." <<
endmsg;
1605 if ( db_typ !=
"ROOT" ) {
1606 error() <<
"in JobOption \"" << ident <<
"\": technology type \"" << db_typ <<
"\" not supported." <<
endmsg;
1611 error() <<
"in JobOption \"" << ident <<
"\":\n stream \"" << stream <<
"\" already connected to file: \""
1618 error() <<
"No OPT= specified or unknown access mode in: " << ident <<
endmsg;
1626 const std::string& oldstream = fitr.first->second;
1628 const auto& f_info =
m_files[oldstream];
1630 if ( newMode != f_info.second ) {
1631 error() <<
"in JobOption \"" << ident <<
"\":\n file \"" << filename <<
"\" already opened by stream: \""
1632 << oldstream <<
"\" with different access mode." <<
endmsg;
1635 TFile* f2 = f_info.first;
1636 m_files[stream] = std::make_pair( f2, newMode );
1638 debug() <<
"Connecting stream: \"" << stream <<
"\" to previously opened TFile: \"" << filename <<
"\""
1652 error() <<
"Unable to open ROOT file " << filename <<
" for reading" <<
endmsg;
1666 error() <<
"Unable to open ROOT file " << filename <<
" for writing" <<
endmsg;
1676 error() <<
"unable to open file \"" << filename <<
"\" for appending" <<
endmsg;
1687 static int ishared = 0;
1688 std::string realfilename = filename;
1689 filename =
"tmp_THistSvc_" + std::to_string( ishared++ ) +
".root";
1692 debug() <<
"Creating temp file \"" << filename <<
"\" and realfilename=" << realfilename <<
endmsg;
1699 error() <<
"Unable to open ROOT file " << filename <<
" for writing" <<
endmsg;
1710 error() <<
"Unable to open ROOT file " << filename <<
" for appending" <<
endmsg;
1717 m_files[stream] = std::make_pair( f, newMode );
1721 debug() <<
"Opening TFile \"" << filename <<
"\" stream: \"" << stream <<
"\" mode: \"" << typ <<
"\""
1722 <<
" comp level: " << cl <<
endmsg;
1729 std::string uid = hid.
id;
1730 TFile* file = hid.
file;
1731 std::string stream, fdir, bdir, dir, id;
1743 if ( !gDirectory->GetKey( dir.c_str() ) ) { gDirectory->mkdir( dir.c_str() ); }
1744 gDirectory->cd( dir.c_str() );
1751 std::string::size_type i = dir.find(
"/" );
1753 if ( i == std::string::npos )
return {};
1760 std::string root = dir.substr( 0, i );
1767 while (
id.find(
"//" ) != std::string::npos ) {
id.replace(
id.find(
"//" ), 2,
"/" ); }
1772 TString path( (
char*)strstr( target->GetPath(),
":" ) );
1773 path.Remove( 0, 2 );
1776 TDirectory* current_sourcedir = gDirectory;
1779 TList* lkeys = current_sourcedir->GetListOfKeys();
1780 int nkeys = lkeys->GetEntries();
1781 TKey* key =
nullptr;
1782 for (
int jj = 0; jj < nkeys; jj++ ) {
1783 key = (TKey*)lkeys->At( jj );
1784 std::string pathnameinsource = current_sourcedir->GetPath() + std::string(
"/" ) + key->GetName();
1786 TObject* obj = source->Get( pathnameinsource.c_str() );
1789 if ( obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1795 TDirectory* newtargetdir = target->mkdir( obj->GetName(), obj->GetTitle() );
1799 }
else if ( obj->IsA()->InheritsFrom(
"TTree" ) ) {
1801 TTree* mytree =
dynamic_cast<TTree*
>( obj );
1802 int nentries = (int)mytree->GetEntries();
1803 mytree->SetBranchStatus(
"*", 1 );
1807 mytree->CloneTree();
1811 obj->Write( key->GetName() );
1818 auto pos =
id.find(
"/" );
1820 if ( pos == std::string::npos ) {
1824 }
else if ( pos != 0 ) {
1831 auto pos2 =
id.find(
"/", pos + 1 );
1833 if ( pos2 == std::string::npos ) {
1835 error() <<
"badly formed Hist/Tree id: \"" <<
id <<
"\"" <<
endmsg;
1841 if ( stream ==
"temp" ) {
1846 auto itr =
m_files.find( stream );
1847 file = ( itr !=
m_files.end() ? itr->second.first :
nullptr );
1848 if ( !file ) {
warning() <<
"no stream \"" << stream <<
"\" associated with id: \"" <<
id <<
"\"" <<
endmsg; }
1854 auto pos =
id.find(
"/" );
1856 if ( pos == std::string::npos ) {
1859 }
else if ( pos == 0 ) {
1862 root =
id.substr( 0, pos );
1863 rem =
id.substr( pos + 1 );
1869 debug() <<
"Delaying connection of Input Files until Initialize"
1874 debug() <<
"Now connecting of Input Files" <<
endmsg;
1880 if (
connect( itr ).isFailure() ) {
1893 debug() <<
"Delaying connection of Output Files until Initialize"
1900 if (
connect( itr ).isFailure() ) {
1913 debug() <<
"copyFileLayout() to destination path: " << destination->GetPath() <<
endmsg;
1917 TString path( (
char*)strstr( destination->GetPath(),
":" ) );
1918 path.Remove( 0, 2 );
1921 TDirectory* current_source_dir = gDirectory;
1924 TList* key_list = current_source_dir->GetListOfKeys();
1925 int n = key_list->GetEntries();
1926 for (
int j = 0; j < n; ++j ) {
1927 TKey* k = (TKey*)key_list->At( j );
1928 const std::string source_pathname = current_source_dir->GetPath() + std::string(
"/" ) + k->GetName();
1929 TObject* o = source->Get( source_pathname.c_str() );
1931 if ( o && o->IsA()->InheritsFrom(
"TDirectory" ) ) {
1935 TDirectory* destination_dir = destination->mkdir( o->GetName(), o->GetTitle() );
1936 if ( destination_dir ==
nullptr ) destination_dir = destination->GetDirectory( o->GetName() );
1946 std::string idr(
id );
1951 if ( idr.starts_with(
"/" ) ) {
1953 auto itr =
m_uids.find( idr );
1954 if ( itr ==
m_uids.end() ) {
1959 if ( index >= itr->second->size() ) {
1960 error() <<
"no index " << index <<
" found for Hist " << idr <<
endmsg;
1963 hid = &( itr->second->at( index ) );
1968 auto mitr =
m_ids.equal_range( idr );
1969 if ( mitr.first == mitr.second ) {
1972 }
else if ( distance( mitr.first, mitr.second ) == 1 ) {
1974 if ( index >= mitr.first->second->size() ) {
1975 error() <<
"no index " << index <<
" found for Hist " << idr <<
endmsg;
1978 hid = &( mitr.first->second->at( 0 ) );
1982 hid = &( mitr.first->second->at( 0 ) );
1983 return distance( mitr.first, mitr.second );
1989 std::ostringstream ost;
1992 ost <<
"m_hlist: size: " <<
m_hlist.size() <<
"\n";
1994 ost <<
" - " << vh->at( 0 ) <<
" :: [" << vh <<
"] " << vh->size() <<
" {";
1995 for (
auto& e : *vh ) {
1997 ost <<
"[" << o <<
"]";
2004 <<
"m_uids: " <<
m_uids.size() <<
"\n";
2005 for (
auto& e :
m_uids ) { ost <<
" - " << e.first <<
" [" << e.second <<
"]" << std::endl; }
2009 <<
"m_ids: " <<
m_ids.size() <<
"\n";
2010 for (
auto& e :
m_ids ) { ost <<
" - " << e.first <<
" [" << e.second <<
"]" << std::endl; }
2014 <<
"m_tobjs: " <<
m_tobjs.size() <<
"\n";
2016 TObject* o = e.first;
2017 THistID& i = e.second.first->at( e.second.second );
2018 ost <<
" - " << o <<
" -> " << i << std::endl;
2021 debug() <<
"dumping THistSvc contents\n" << ost.str() <<
endmsg;
2027 const std::string&
name = vh->at( 0 ).id;
2028 if ( vh->size() == 1 ) {
2029 debug() <<
"merge: id: \"" <<
name <<
"\" is size 1. nothing to do" <<
endmsg;
2034 error() <<
"merge: id \"" <<
name <<
"\" is not a THn. Cannot merge" <<
endmsg;
2038 TList* l =
new TList();
2039 for (
size_t i = 1; i < vh->size(); ++i ) {
2040 debug() <<
"merge: id: \"" <<
name <<
"\" (" << vh->at( i ).obj <<
") adding index " << i <<
endmsg;
2041 l->Add( vh->at( i ).obj );
2044 TH1* t0 =
dynamic_cast<TH1*
>( vh->at( 0 ).obj );
2046 error() <<
"merge: could not dcast " <<
name <<
"(" << t0 <<
") index " << 0 <<
" to TH1" <<
endmsg;
2050 Long64_t n = t0->Merge( l );
2052 debug() <<
"merge: id: \"" <<
name <<
"\" merged " << n <<
" entries" <<
endmsg;
2054 for (
size_t i = 1; i < vh->size(); ++i ) {
2055 TH1* th =
dynamic_cast<TH1*
>( vh->at( i ).obj );
2057 debug() <<
"clearing index " << i <<
"(" << th <<
")" <<
endmsg;
2058 th->SetDirectory(
nullptr );
2061 error() <<
"merge: could not dcast " <<
name <<
" index " << i <<
" to TH1" <<
endmsg;
This file contains the class definition for the FileIncident class.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
#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
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...
Base class for all Incidents (computing events).
const std::string & desc() const
const std::string & name() const
Provides automatic lock/unlock access to a class upon deref of ptr.
Gaudi::StateMachine::State FSMState() const override
StatusCode finalize() override
const std::string & name() const override
Retrieve name of the service.
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
StatusCode initialize() override
This class is used for returning status codes from appropriate routines.
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
constexpr static const auto SUCCESS
constexpr static const auto FAILURE
Helper class that manages ROOts global directory and file.
TDirectory * m_gDirectory
~GlobalDirectoryRestore()
GlobalDirectoryRestore(THistSvcMutex_t &mut)
std::lock_guard< THistSvcMutex_t > m_lock
StatusCode finalize() override
std::recursive_mutex THistSvcMutex_t
LockedHandle< T > regShared_i(const std::string &id, std::unique_ptr< T > hist)
StatusCode io_reinit() override
callback method to reinitialize the internal state of the component for I/O purposes (e....
StatusCode initialize() override
bool existsHist(const std::string &name) const override
Check if histogram with given name is managed by THistSvcMT.
T * getHist_i(const std::string &name, const size_t &ind=0, bool quiet=false) const
T * readHist_i(const std::string &name) const
Gaudi::Property< int > m_maxFileSize
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.
ServiceHandle< IIncidentSvc > p_incSvc
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.
T * readHist(const std::string &name) const
StatusCode getTTrees(TDirectory *td, TList &, bool recurse=false) const override
void setupOutputFile()
call-back method to handle output stream property
std::map< std::string, std::pair< TFile *, Mode > > m_files
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...
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)
Gaudi::Property< std::vector< std::string > > m_inputfile
std::vector< THistID > vhid_t
std::vector< std::string > getEfficiencies() const override
std::vector< std::string > getHists() const override
StatusCode regTree(const std::string &name) override
Register a new TTree with a given name.
ServiceHandle< IFileMgr > p_fileMgr
bool existsEfficiency(const std::string &name) const override
Check if TEfficiency with given name is managed by THistSvcMT.
TDirectory * changeDir(const THistSvc::THistID &hid) const
void MergeRootFile(TDirectory *, TDirectory *)
Gaudi::Property< std::vector< std::string > > m_outputfile
std::string stripDirectoryName(std::string &dir) const
static Mode charToMode(const char typ)
Convert a char to a Mode enum.
TTree * readTree(const std::string &name) const
StatusCode merge(const std::string &id) override
Merge all clones for object with a given id.
Gaudi::Property< int > m_autoSave
StatusCode deReg(const std::string &name) override
Deregister object with given name and give up ownership (without deletion!)
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.
std::map< std::string, std::string > m_sharedFiles
void parseString(const std::string &id, std::string &root, std::string &rem) const
StatusCode writeObjectsToFile()
Gaudi::Property< int > m_autoFlush
void removeDoubleSlash(std::string &) const
StatusCode rootOpenAction(FILEMGR_CALLBACK_ARGS)
Gaudi::Property< bool > m_print
void updateFiles()
Handle case where TTree grows beyond TTree::fgMaxTreeSize.
LockedHandle< T > getShared_i(const std::string &name) const
std::vector< std::string > getTrees() const override
std::set< std::string > m_alreadyConnectedOutFiles
list of already connected files.
StatusCode regEfficiency(const std::string &name) override
Register a new TEfficiency with a given name.
StatusCode reinitialize() override
std::vector< std::string > getGraphs() const override
bool findStream(const std::string &name, std::string &root, std::string &rem, TFile *&file) const
StatusCode getEfficiency(const std::string &name, TEfficiency *&) const override
Return TEfficiency with given name.
bool existsGraph(const std::string &name) const override
Check if graph with given name is managed by THistSvcMT.
bool existsTree(const std::string &name) const override
Check if tree with given name is managed by THistSvcMT.
std::set< std::string > m_alreadyConnectedInFiles
list of already connected files.
StatusCode rootOpenErrAction(FILEMGR_CALLBACK_ARGS)
StatusCode getTree(const std::string &name, TTree *&) const override
Return TTree with given name.
StatusCode regGraph(const std::string &name) override
Register a new TGraph with a given name.
StatusCode getTHists(TDirectory *td, TList &, bool recurse=false) const override
StatusCode regHist(const std::string &name) override
Register a new ROOT histogram TH*X with a name.
StatusCode getTEfficiencies(TDirectory *td, TList &, bool recurse=false) const override
StatusCode getGraph(const std::string &name, TGraph *&) const override
Return TGraph with given name.
THistSvc(const std::string &name, ISvcLocator *svcloc)
Helper struct that bundles the histogram ID with a mutex, TFile and TObject*.