19#include <boost/algorithm/string/case_conv.hpp>
23#include <TDirectory.h>
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 );
56 constexpr struct select1st_t {
57 template <
typename T,
typename S>
58 const T& operator()(
const std::pair<T, S>& p )
const {
97 static TROOT root(
"root",
"ROOT I/O" );
103 if (
p_incSvc.retrieve().isFailure() ) {
104 error() <<
"unable to get the IncidentSvc" <<
endmsg;
107 p_incSvc->addListener(
this,
"EndEvent", 100,
true );
110 if (
p_fileMgr.retrieve().isFailure() ) {
118 using namespace std::placeholders;
121 error() <<
"unable to register ROOT file open action with FileMgr" <<
endmsg;
123 auto bea = [
this](
const Io::FileAttr* fa,
const std::string& caller ) {
127 error() <<
"unable to register ROOT file open Error action with FileMgr" <<
endmsg;
141 error() <<
"unable to get the IoComponentMgr" <<
endmsg;
144 if ( !iomgr->io_register(
this ).isSuccess() ) {
145 error() <<
"could not register with the I/O component manager !" <<
endmsg;
148 bool all_good =
true;
150 for (
const auto& reg :
m_files ) {
151 const std::string& fname = reg.second.first->GetName();
154 if ( !iomgr->io_register(
this, iomode, fname ).isSuccess() ) {
155 warning() <<
"could not register file [" << fname <<
"] with the I/O component manager..." <<
endmsg;
158 info() <<
"registered file [" << fname <<
"]... [ok]" <<
endmsg;
162 error() <<
"problem while registering input/output files with "
163 <<
"the I/O component manager !" <<
endmsg;
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;
195 std::string dirname(
"none" );
197 TTree* tree =
dynamic_cast<TTree*
>( tobj );
198 if ( tree->GetDirectory() != 0 ) { dirname = tree->GetDirectory()->GetPath(); }
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 ); }
211 TH1* th =
dynamic_cast<TH1*
>( tobj );
212 if ( th ==
nullptr ) {
213 error() <<
"Couldn't dcast: " << itr.first <<
endmsg;
215 if ( th->GetDirectory() != 0 ) { dirname = th->GetDirectory()->GetPath(); }
217 }
else if ( !tobj ) {
228 std::vector<TFile*> deleted_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 );
235 debug() <<
"finalizing stream/file " << itr.first <<
":" << itr.second.first->GetName() <<
endmsg;
246 info() <<
"==> File: " << itr.second.first->GetName() <<
" stream: " << itr.first <<
endmsg;
248 itr.second.first->Print(
"base" );
251 std::string tmpfn = itr.second.first->GetName();
255 if ( itr.second.second ==
SHARE ) {
257 void* vfile =
nullptr;
266 TFile* outputfile = (TFile*)vfile;
275 error() <<
"unable to open temporary file: \"" << tmpfn <<
endmsg;
279 TFile* inputfile = (TFile*)vfile;
281 outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() );
291 std::remove( tmpfn.c_str() );
293 delete itr.second.first;
307 THistID& hid = obj.second.first->at( obj.second.second );
308 if ( hid.
temp ) {
delete obj.first; }
310 if ( obj.second.second == 0 ) {
311 delete obj.second.first;
322 std::unique_ptr<TH1> hist =
nullptr;
323 return regHist_i( std::move( hist ),
id,
false );
327 return regHist_i( std::move( hist ),
id,
false );
331 std::unique_ptr<TH1> hist( hist_ptr );
332 return regHist_i( std::move( hist ),
id,
false );
337 if ( hist !=
nullptr ) {
346 if ( hist !=
nullptr ) {
355 if ( hist !=
nullptr ) {
363 std::unique_ptr<TTree> tree =
nullptr;
364 return regHist_i( std::move( tree ),
id,
false );
378 std::unique_ptr<TTree> tree( tree_ptr );
390 if ( tree !=
nullptr ) {
398 std::unique_ptr<TGraph> graph = std::make_unique<TGraph>();
399 return regHist_i( std::move( graph ),
id,
false );
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 ); }
408 info() <<
"setting name of TGraph id: \"" <<
id <<
"\" to \"" << id2 <<
"\" since it is unset" <<
endmsg;
409 graph->SetName( id2.c_str() );
412 return regHist_i( std::move( graph ),
id,
false );
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 ); }
422 info() <<
"setting name of TGraph id: \"" <<
id <<
"\" to \"" << id2 <<
"\" since it is unset" <<
endmsg;
423 graph->SetName( id2.c_str() );
426 return regHist_i( std::move( graph ),
id,
false );
431 if ( graph !=
nullptr ) {
439 std::unique_ptr<TEfficiency> eff =
nullptr;
440 return regHist_i( std::move( eff ),
id,
false );
444 return regHist_i( std::move( eff ),
id,
false );
448 std::unique_ptr<TEfficiency> eff( eff_ptr );
449 return regHist_i( std::move( eff ),
id,
false );
454 if ( eff !=
nullptr ) {
553 auto itr =
m_uids.find(
id );
554 if ( itr ==
m_uids.end() ) {
555 error() <<
"Problem deregistering id \"" <<
id <<
"\": not found in registry" <<
endmsg;
562 debug() <<
"will deregister " << vh->size() <<
" elements of id \"" <<
id <<
"\"" <<
endmsg;
566 size_t vh_size = vh->size();
567 while ( vh_size-- ) {
570 error() <<
"Problems deRegistering " << vh->size() <<
" element of id \"" <<
id <<
"\"" <<
endmsg;
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 );
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;
591 if ( vhid->size() == 1 ) {
595 std::string root, rem;
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;
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;
614 vhid->erase( vhid->begin() + obj_itr->second.second );
618 m_ids.erase( id_itr );
623 }
else if ( vhid->size() > 1 ) {
624 vhid->erase( vhid->begin() + obj_itr->second.second );
629 error() <<
"Deregistration failed unexpectedly. (bug in THistSvc?)" <<
endmsg;
633 error() <<
"Cannot unregister TObject \"" << obj->GetName() <<
"\": not known to THistSvc" <<
endmsg;
640 if ( itr ==
m_uids.end() ) {
645 return merge( itr->second );
649 objMap_t::iterator itr =
m_tobjs.find( obj );
651 return merge( itr->second.first );
653 error() <<
"merge: unknown object " << obj <<
endmsg;
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; } );
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; } );
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; } );
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,
707 gErrorIgnoreLevel = kBreak;
710 error() <<
"getTHists: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
715 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
718 TIter nextkey( td->GetListOfKeys() );
719 while ( TKey* key = (TKey*)nextkey() ) {
722 TObject* obj = key->ReadObj();
723 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
725 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TH1" ) ) {
728 }
else if ( obj != 0 ) {
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 );
753 gErrorIgnoreLevel = kBreak;
757 std::string stream, rem, r2;
760 auto itr =
m_files.find( stream );
762 r2 = itr->second.first->GetName();
767 debug() <<
"getTHists: \"" << dir <<
"\" looks like a stream name."
768 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
771 if ( gDirectory->cd( r2.c_str() ) ) {
784 if ( !gDirectory->cd( dir.c_str() ) ) {
785 error() <<
"getTHists: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
797 gErrorIgnoreLevel = kBreak;
800 error() <<
"getTHists: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
805 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
808 TIter nextkey( td->GetListOfKeys() );
809 while ( TKey* key = (TKey*)nextkey() ) {
812 TObject* obj = key->ReadObj();
813 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
815 }
else if ( obj && obj->IsA()->InheritsFrom(
"TH1" ) ) {
819 std::string dir = td->GetPath();
820 std::string fil = td->GetFile()->GetName();
821 dir.erase( 0, fil.length() + 1 );
824 id =
id +
"/" + key->GetName();
826 id =
id + dir +
"/" + key->GetName();
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 );
859 gErrorIgnoreLevel = kBreak;
863 std::string stream, rem, r2;
866 auto itr =
m_files.find( stream );
868 r2 = itr->second.first->GetName();
873 debug() <<
"getTHists: \"" << dir <<
"\" looks like a stream name."
874 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
877 if ( gDirectory->cd( r2.c_str() ) ) {
879 sc =
getTHists( gDirectory, tl, rcs, reg );
888 if ( !gDirectory->cd( dir.c_str() ) ) {
889 error() <<
"getTHists: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
893 warning() <<
"Unable to register histograms automatically "
894 <<
"without a valid stream name" <<
endmsg;
897 sc =
getTHists( gDirectory, tl, rcs, reg );
906 gErrorIgnoreLevel = kBreak;
909 error() <<
"getTTrees: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
914 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
917 TIter nextkey( td->GetListOfKeys() );
918 while ( TKey* key = (TKey*)nextkey() ) {
921 TObject* obj = key->ReadObj();
922 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
924 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TTree" ) ) {
927 }
else if ( obj != 0 ) {
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 );
951 gErrorIgnoreLevel = kBreak;
955 std::string stream, rem, r2;
958 auto itr =
m_files.find( stream );
960 r2 = itr->second.first->GetName();
965 debug() <<
"getTTrees: \"" << dir <<
"\" looks like a stream name."
966 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
969 if ( gDirectory->cd( r2.c_str() ) ) {
return getTTrees( gDirectory, tl, rcs ); }
975 if ( !gDirectory->cd( dir.c_str() ) ) {
976 error() <<
"getTTrees: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
987 gErrorIgnoreLevel = kBreak;
990 error() <<
"getTTrees: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
995 debug() <<
"getTHists: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys" <<
endmsg;
998 TIter nextkey( td->GetListOfKeys() );
999 while ( TKey* key = (TKey*)nextkey() ) {
1000 auto& log =
debug();
1002 TObject* obj = key->ReadObj();
1003 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1005 }
else if ( obj && obj->IsA()->InheritsFrom(
"TTree" ) ) {
1009 std::string dir = td->GetPath();
1010 std::string fil = td->GetFile()->GetName();
1011 dir.erase( 0, fil.length() + 1 );
1014 id =
id +
"/" + key->GetName();
1016 id =
id + dir +
"/" + key->GetName();
1025 }
else if ( obj != 0 ) {
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 );
1049 gErrorIgnoreLevel = kBreak;
1053 std::string stream, rem, r2;
1056 auto itr =
m_files.find( stream );
1058 r2 = itr->second.first->GetName();
1063 debug() <<
"getTTrees: \"" << dir <<
"\" looks like a stream name."
1064 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1067 if ( gDirectory->cd( r2.c_str() ) ) {
1068 return getTTrees( gDirectory, tl, rcs, reg );
1076 if ( !gDirectory->cd( dir.c_str() ) ) {
1077 error() <<
"getTTrees: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1081 return getTTrees( gDirectory, tl, rcs, reg );
1087 gErrorIgnoreLevel = kBreak;
1090 error() <<
"getTEfficiencies: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
1095 debug() <<
"getTEfficiencies: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys"
1099 TIter nextkey( td->GetListOfKeys() );
1100 while ( TKey* key = (TKey*)nextkey() ) {
1101 auto& log =
debug();
1103 TObject* obj = key->ReadObj();
1104 if ( obj != 0 && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1106 }
else if ( obj != 0 && obj->IsA()->InheritsFrom(
"TEfficiency" ) ) {
1109 }
else if ( obj != 0 ) {
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 );
1134 gErrorIgnoreLevel = kBreak;
1138 std::string stream, rem, r2;
1141 auto itr =
m_files.find( stream );
1143 r2 = itr->second.first->GetName();
1148 debug() <<
"getTEfficiencies: \"" << dir <<
"\" looks like a stream name."
1149 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1152 if ( gDirectory->cd( r2.c_str() ) ) {
1165 if ( !gDirectory->cd( dir.c_str() ) ) {
1166 error() <<
"getTEfficiencies: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1178 gErrorIgnoreLevel = kBreak;
1181 error() <<
"getTEfficiencies: No such TDirectory \"" << td->GetPath() <<
"\"" <<
endmsg;
1186 debug() <<
"getTEfficiencies: \"" << td->GetPath() <<
"\": found " << td->GetListOfKeys()->GetSize() <<
" keys"
1190 TIter nextkey( td->GetListOfKeys() );
1191 while ( TKey* key = (TKey*)nextkey() ) {
1192 auto& log =
debug();
1194 TObject* obj = key->ReadObj();
1195 if ( obj && obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1197 }
else if ( obj && obj->IsA()->InheritsFrom(
"TEfficiency" ) ) {
1201 std::string dir = td->GetPath();
1202 std::string fil = td->GetFile()->GetName();
1203 dir.erase( 0, fil.length() + 1 );
1206 id =
id +
"/" + key->GetName();
1208 id =
id + dir +
"/" + key->GetName();
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 );
1241 gErrorIgnoreLevel = kBreak;
1245 std::string stream, rem, r2;
1248 auto itr =
m_files.find( stream );
1250 r2 = itr->second.first->GetName();
1255 debug() <<
"getTEfficiencies: \"" << dir <<
"\" looks like a stream name."
1256 <<
" associated TFile: \"" << itr->second.first->GetName() <<
"\"" <<
endmsg;
1259 if ( gDirectory->cd( r2.c_str() ) ) {
1270 if ( !gDirectory->cd( dir.c_str() ) ) {
1271 error() <<
"getTEfficiencies: No such TDirectory/stream \"" << dir <<
"\"" <<
endmsg;
1275 warning() <<
"Unable to register histograms automatically "
1276 <<
"without a valid stream name" <<
endmsg;
1292 Long64_t mfs = (Long64_t)
m_maxFileSize.value() * (Long64_t)1048576;
1293 Long64_t mfs_warn = mfs * 95 / 100;
1297 for (
const auto& f :
m_files ) {
1298 TFile* tf = f.second.first;
1302 debug() <<
"stream: " << f.first <<
" name: " << tf->GetName() <<
" size: " << tf->GetSize() <<
endmsg;
1307 if ( tf->GetSize() > mfs ) {
1310 throw GaudiException( std::format(
"file \"{}\" associated with stream \"{}\" has exceeded the max "
1311 "file size of {} MB. Terminating Job.",
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;
1326 bool all_good =
true;
1333 error() <<
"could not retrieve I/O component manager !" <<
endmsg;
1340 gErrorIgnoreLevel = kFatal;
1342 for (
auto& ifile :
m_files ) {
1343 TFile* f = ifile.second.first;
1344 std::string fname = f->GetName();
1346 debug() <<
"file [" << fname <<
"] mode: [" << f->GetOption() <<
"] r:" << f->GetFileBytesRead()
1347 <<
" w:" << f->GetFileBytesWritten() <<
" cnt:" << f->GetFileCounter() <<
endmsg;
1350 if ( ifile.second.second ==
READ ) {
1355 if ( !iomgr->io_retrieve(
this, fname ).isSuccess() ) {
1356 error() <<
"could not retrieve new name for [" << fname <<
"] !!" <<
endmsg;
1359 }
else if ( fname.empty() ) {
1367 Option_t* opts = f->GetOption();
1370 error() <<
"unable to open file \"" << fname <<
"\" for writing" <<
endmsg;
1373 TFile* newfile = (TFile*)vf;
1374 newfile->SetOption( opts );
1378 ifile.second.first = newfile;
1382 for (
auto& uid :
m_uids ) {
1383 for (
auto& hid : *uid.second ) {
1384 if ( hid.file != f )
continue;
1385 TDirectory* olddir = this->
changeDir( hid );
1388 TDirectory* newdir = this->
changeDir( hid );
1389 TClass* cl = hid.obj->IsA();
1394 TTree& tree =
dynamic_cast<TTree&
>( *hid.obj );
1395 tree.SetDirectory( newdir );
1398 TH1& hist =
dynamic_cast<TH1&
>( *hid.obj );
1399 hist.SetDirectory( newdir );
1402 dynamic_cast<TEfficiency&
>( *hid.obj ).SetDirectory( newdir );
1404 olddir->Remove( hid.obj );
1405 newdir->Append( hid.obj );
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 );
1417 f->ReOpen(
"READ" );
1441template <
typename T>
1457 for (
auto uitr =
m_uids.begin(); uitr !=
m_uids.end(); ++uitr ) {
1458 for (
auto& hid : *( uitr->second ) ) {
1461 if ( hid.type !=
ObjectType::TTREE || hid.temp || hid.mode ==
READ || hid.obj ==
nullptr )
continue;
1464 verbose() <<
" update: " << uitr->first <<
" " << hid.id <<
" " << hid.mode <<
endmsg;
1466 TTree* tr =
dynamic_cast<TTree*
>( hid.obj );
1467 TFile* oldFile = hid.file;
1468 TFile* newFile = tr->GetCurrentFile();
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 );
1477 if ( itr.second.first == oldFile ) { itr.second.first = newFile; }
1480 for (
auto uitr2 = uitr; uitr2 !=
m_uids.end(); ++uitr2 ) {
1481 for (
auto& hid2 : *( uitr2->second ) ) {
1482 if ( hid2.file == oldFile ) { hid2.file = newFile; }
1487 [&]( streamMap::const_reference s ) {
return s.second == streamName; } );
1488 if ( sitr != std::end(
m_fileStreams ) ) oldFileName = sitr->first;
1492 debug() <<
"migrating uid: " << hid.id <<
" stream: " << streamName <<
" oldFile: " << oldFileName
1493 <<
" newFile: " << newFileName <<
endmsg;
1497 if ( !oldFileName.empty() ) {
1499 while ( i != std::end(
m_fileStreams ) && i->first == oldFileName ) {
1502 debug() <<
"changing filename \"" << i->first <<
"\" to \"" << newFileName <<
"\" for stream \""
1503 << i->second <<
"\"" <<
endmsg;
1506 std::string nm = std::move( i->second );
1511 error() <<
"Problems updating fileStreams with new file name" <<
endmsg;
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 ) {
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()
1544 auto loc = ident.find(
" " );
1545 std::string stream = ident.substr( 0, loc );
1547 typedef std::pair<std::string, std::string> Prop;
1548 std::vector<Prop> props;
1549 std::string filename, db_typ(
"ROOT" );
1552 if ( loc != std::string::npos ) {
1554 for (
auto attrib : Parser( ident.substr( loc + 1 ) ) ) {
1558 auto TAG = attrib.tag;
1559 auto VAL = attrib.value;
1560 boost::algorithm::to_upper( TAG );
1561 boost::algorithm::to_upper( VAL );
1563 if ( TAG ==
"FILE" || TAG ==
"DATAFILE" ) {
1564 filename = attrib.value;
1566 }
else if ( TAG ==
"OPT" ) {
1567 if ( VAL ==
"APPEND" || VAL ==
"UPDATE" ) {
1569 }
else if ( VAL ==
"CREATE" || VAL ==
"NEW" || VAL ==
"WRITE" ) {
1571 }
else if ( VAL ==
"RECREATE" ) {
1573 }
else if ( VAL ==
"SHARE" ) {
1575 }
else if ( VAL ==
"OLD" || VAL ==
"READ" ) {
1578 error() <<
"Unknown OPT: \"" << attrib.value <<
"\"" <<
endmsg;
1581 }
else if ( TAG ==
"TYP" ) {
1582 db_typ = std::move( attrib.value );
1583 }
else if ( TAG ==
"CL" ) {
1584 cl = std::stoi( attrib.value );
1586 props.emplace_back( attrib.tag, attrib.value );
1591 if ( stream ==
"temp" ) {
1592 error() <<
"in JobOption \"" << ident <<
"\": stream name \"temp\" reserved." <<
endmsg;
1596 if ( db_typ !=
"ROOT" ) {
1597 error() <<
"in JobOption \"" << ident <<
"\": technology type \"" << db_typ <<
"\" not supported." <<
endmsg;
1602 error() <<
"in JobOption \"" << ident <<
"\":\n stream \"" << stream <<
"\" already connected to file: \""
1609 error() <<
"No OPT= specified or unknown access mode in: " << ident <<
endmsg;
1617 const std::string& oldstream = fitr.first->second;
1619 const auto& f_info =
m_files[oldstream];
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;
1626 TFile* f2 = f_info.first;
1627 m_files[stream] = std::make_pair( f2, newMode );
1629 debug() <<
"Connecting stream: \"" << stream <<
"\" to previously opened TFile: \"" << filename <<
"\""
1643 error() <<
"Unable to open ROOT file " << filename <<
" for reading" <<
endmsg;
1657 error() <<
"Unable to open ROOT file " << filename <<
" for writing" <<
endmsg;
1667 error() <<
"unable to open file \"" << filename <<
"\" for appending" <<
endmsg;
1678 static int ishared = 0;
1679 std::string realfilename = filename;
1680 filename =
"tmp_THistSvc_" + std::to_string( ishared++ ) +
".root";
1683 debug() <<
"Creating temp file \"" << filename <<
"\" and realfilename=" << realfilename <<
endmsg;
1690 error() <<
"Unable to open ROOT file " << filename <<
" for writing" <<
endmsg;
1701 error() <<
"Unable to open ROOT file " << filename <<
" for appending" <<
endmsg;
1708 m_files[stream] = std::make_pair( f, newMode );
1712 debug() <<
"Opening TFile \"" << filename <<
"\" stream: \"" << stream <<
"\" mode: \"" << typ <<
"\""
1713 <<
" comp level: " << cl <<
endmsg;
1720 std::string uid = hid.
id;
1721 TFile* file = hid.
file;
1722 std::string stream, fdir, bdir, dir, id;
1734 if ( !gDirectory->GetKey( dir.c_str() ) ) { gDirectory->mkdir( dir.c_str() ); }
1735 gDirectory->cd( dir.c_str() );
1742 std::string::size_type i = dir.find(
"/" );
1744 if ( i == std::string::npos )
return {};
1751 std::string root = dir.substr( 0, i );
1758 while (
id.find(
"//" ) != std::string::npos ) {
id.replace(
id.find(
"//" ), 2,
"/" ); }
1763 TString path( (
char*)strstr( target->GetPath(),
":" ) );
1764 path.Remove( 0, 2 );
1767 TDirectory* current_sourcedir = gDirectory;
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();
1777 TObject* obj = source->Get( pathnameinsource.c_str() );
1780 if ( obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
1786 TDirectory* newtargetdir = target->mkdir( obj->GetName(), obj->GetTitle() );
1790 }
else if ( obj->IsA()->InheritsFrom(
"TTree" ) ) {
1792 TTree* mytree =
dynamic_cast<TTree*
>( obj );
1793 int nentries = (int)mytree->GetEntries();
1794 mytree->SetBranchStatus(
"*", 1 );
1798 mytree->CloneTree();
1802 obj->Write( key->GetName() );
1809 auto pos =
id.find(
"/" );
1811 if ( pos == std::string::npos ) {
1815 }
else if ( pos != 0 ) {
1822 auto pos2 =
id.find(
"/", pos + 1 );
1824 if ( pos2 == std::string::npos ) {
1826 error() <<
"badly formed Hist/Tree id: \"" <<
id <<
"\"" <<
endmsg;
1832 if ( stream ==
"temp" ) {
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; }
1845 auto pos =
id.find(
"/" );
1847 if ( pos == std::string::npos ) {
1850 }
else if ( pos == 0 ) {
1853 root =
id.substr( 0, pos );
1854 rem =
id.substr( pos + 1 );
1860 debug() <<
"Delaying connection of Input Files until Initialize"
1865 debug() <<
"Now connecting of Input Files" <<
endmsg;
1871 if (
connect( itr ).isFailure() ) {
1884 debug() <<
"Delaying connection of Output Files until Initialize"
1891 if (
connect( itr ).isFailure() ) {
1904 debug() <<
"copyFileLayout() to destination path: " << destination->GetPath() <<
endmsg;
1908 TString path( (
char*)strstr( destination->GetPath(),
":" ) );
1909 path.Remove( 0, 2 );
1912 TDirectory* current_source_dir = gDirectory;
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() );
1922 if ( o && o->IsA()->InheritsFrom(
"TDirectory" ) ) {
1926 TDirectory* destination_dir = destination->mkdir( o->GetName(), o->GetTitle() );
1927 if ( destination_dir ==
nullptr ) destination_dir = destination->GetDirectory( o->GetName() );
1937 std::string idr(
id );
1942 if ( idr.starts_with(
"/" ) ) {
1944 auto itr =
m_uids.find( idr );
1945 if ( itr ==
m_uids.end() ) {
1950 if ( index >= itr->second->size() ) {
1951 error() <<
"no index " << index <<
" found for Hist " << idr <<
endmsg;
1954 hid = &( itr->second->at( index ) );
1959 auto mitr =
m_ids.equal_range( idr );
1960 if ( mitr.first == mitr.second ) {
1963 }
else if ( distance( mitr.first, mitr.second ) == 1 ) {
1965 if ( index >= mitr.first->second->size() ) {
1966 error() <<
"no index " << index <<
" found for Hist " << idr <<
endmsg;
1969 hid = &( mitr.first->second->at( 0 ) );
1973 hid = &( mitr.first->second->at( 0 ) );
1974 return distance( mitr.first, mitr.second );
1980 std::ostringstream ost;
1983 ost <<
"m_hlist: size: " <<
m_hlist.size() <<
"\n";
1985 ost <<
" - " << vh->at( 0 ) <<
" :: [" << vh <<
"] " << vh->size() <<
" {";
1986 for (
auto& e : *vh ) {
1988 ost <<
"[" << o <<
"]";
1995 <<
"m_uids: " <<
m_uids.size() <<
"\n";
1996 for (
auto& e :
m_uids ) { ost <<
" - " << e.first <<
" [" << e.second <<
"]" << std::endl; }
2000 <<
"m_ids: " <<
m_ids.size() <<
"\n";
2001 for (
auto& e :
m_ids ) { ost <<
" - " << e.first <<
" [" << e.second <<
"]" << std::endl; }
2005 <<
"m_tobjs: " <<
m_tobjs.size() <<
"\n";
2007 TObject* o = e.first;
2008 THistID& i = e.second.first->at( e.second.second );
2009 ost <<
" - " << o <<
" -> " << i << std::endl;
2012 debug() <<
"dumping THistSvc contents\n" << ost.str() <<
endmsg;
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;
2025 error() <<
"merge: id \"" <<
name <<
"\" is not a THn. Cannot merge" <<
endmsg;
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 );
2035 TH1* t0 =
dynamic_cast<TH1*
>( vh->at( 0 ).obj );
2037 error() <<
"merge: could not dcast " <<
name <<
"(" << t0 <<
") index " << 0 <<
" to TH1" <<
endmsg;
2041 Long64_t n = t0->Merge( l );
2043 debug() <<
"merge: id: \"" <<
name <<
"\" merged " << n <<
" entries" <<
endmsg;
2045 for (
size_t i = 1; i < vh->size(); ++i ) {
2046 TH1* th =
dynamic_cast<TH1*
>( vh->at( i ).obj );
2048 debug() <<
"clearing index " << i <<
"(" << th <<
")" <<
endmsg;
2049 th->SetDirectory(
nullptr );
2052 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
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...
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*.