40 : TObject(), m_input(), m_copiedInput(), m_output( 0 ),
41 m_treesToSkip( {
"##Shapes",
"##Links",
"##Params",
43 "CollectionTreeInDet::Track_tlp2",
44 "POOLContainerForm",
"POOLContainer",
45 "POOLCollectionTree",
"MetaData",
46 "MetaDataHdrForm",
"MetaDataHdr" } ),
47 m_events(), m_helperFiles(),
48 m_metaDataToolNames(), m_metaDataTools(),
62 const std::string& mode ) {
67 Error(
"setOutputFileName",
68 XAOD_MESSAGE(
"Couldn't open output file \"%s\" in mode "
70 name.c_str(), mode.c_str() );
71 return StatusCode::FAILURE;
75 Info(
"setOutputFileName",
"Opened \"%s\" for writing",
82 return StatusCode::SUCCESS;
90 std::string localName =
name;
96 TString::Format(
"%s/XAODMERGE-%s.root",
97 gSystem->TempDirectory(), uuid.AsString() ).Data();
99 if( ! TFile::Cp(
name.c_str(), localName.c_str(), kTRUE ) ) {
101 XAOD_MESSAGE(
"Couldn't create local copy of \"%s\" under "
103 name.c_str(), localName.c_str() );
104 return StatusCode::FAILURE;
107 Info(
"addFile",
"Made a local copy of: %s",
name.c_str() );
111 ::TFile* ifile = ::TFile::Open( localName.c_str(),
"READ" );
113 Error(
"addFile",
XAOD_MESSAGE(
"Couldn't open file \"%s\"" ),
115 return StatusCode::FAILURE;
121 Info(
"addFile",
"Opened \"%s\" for reading", localName.c_str() );
127 return StatusCode::SUCCESS;
146 Warning(
"addMetaDataTool",
147 "Tool of type \"%s\" is already specified",
149 return StatusCode::RECOVERABLE;
153 ::TClass* cl = ::TClass::GetClass( typeName.c_str() );
155 Error(
"addMetaDataTool",
158 return StatusCode::FAILURE;
166 Info(
"addMetaDataTool",
"Added tool of type \"%s\"",
171 return StatusCode::SUCCESS;
187 Error(
"merge",
XAOD_MESSAGE(
"No output file specified" ) );
188 return StatusCode::FAILURE;
193 Warning(
"merge",
"No input files were specified" );
194 return StatusCode::RECOVERABLE;
199 Warning(
"merge",
"Number of entries can't be specified in fast "
220 return StatusCode::SUCCESS;
259 Info(
"closeFiles",
"Closing all open files" );
271 for( ; ev_itr != ev_end; ++ev_itr ) {
272 if( ev_itr->second->m_outTree &&
m_output ) {
274 ev_itr->second->finishWritingTo(
m_output ) );
279 for(
size_t i = 0; i <
m_input.size(); ++i ) {
282 Info(
"closeFiles",
"Closed: %s",
m_input[ i ]->GetName() );
285 TString p(
m_input[ i ]->GetPath() );
286 p = p( 0, p.Index(
':', 0 ) );
287 if( gSystem->Unlink( p ) ) {
291 return StatusCode::FAILURE;
294 Info(
"closeFiles",
"Deleted: %s",
m_input[ i ]->GetName() );
306 Info(
"closeFiles",
"Closed: %s",
m_output->GetName() );
322 return StatusCode::SUCCESS;
337 ::TDirectory& output,
342 Info(
"mergeDirectory",
"Merging directories:" );
343 Info(
"mergeDirectory",
" input : %s", input.GetName() );
344 Info(
"mergeDirectory",
" output: %s", output.GetName() );
348 TList* keyList = input.GetListOfKeys();
350 Error(
"mergeDirectory",
351 XAOD_MESSAGE(
"Couldn't get list of keys from input directory "
352 "\"%s\"" ), input.GetName() );
353 return StatusCode::FAILURE;
362 std::set< std::string > processedTrees;
363 for( Int_t i = 0; i < keyList->GetSize(); ++i ) {
366 TKey* key =
dynamic_cast< TKey*
>( keyList->At( i ) );
368 Error(
"mergeDirectory",
371 return StatusCode::FAILURE;
374 Info(
"mergeDirectory",
"Evaluating key \"%s;%hi\" with type "
376 key->GetName(), key->GetCycle(), key->GetClassName() );
380 TObject* obj = input.Get( TString::Format(
"%s;%hi", key->GetName(),
383 Error(
"mergeDirectory",
386 key->GetName(), key->GetCycle() );
387 return StatusCode::FAILURE;
393 if( obj->IsA()->InheritsFrom(
"TDirectory" ) ) {
396 Info(
"mergeDirectory",
"Appears to be a TDirectory" );
400 TDirectory* indir =
dynamic_cast< TDirectory*
>( obj );
402 Error(
"mergeDirectory",
403 XAOD_MESSAGE(
"Couldn't cast to object to TDirectory" ) );
404 return StatusCode::FAILURE;
409 dynamic_cast< TDirectory*
>( output.Get( key->GetName() ) );
412 if( ! ( outdir = output.mkdir( key->GetName(),
413 "dummy title" ) ) ) {
414 Error(
"mergeDirectory",
418 return StatusCode::FAILURE;
429 }
else if( obj->IsA()->InheritsFrom(
"TTree" ) ) {
432 Info(
"mergeDirectory",
"Appears to be a TTree" );
441 Info(
"mergeDirectory",
442 "Skipping it because of m_treesToSkip" );
448 if( processedTrees.find( key->GetName() ) !=
449 processedTrees.end() ) {
451 Info(
"mergeDirectory",
452 "Skipping it, because it was processed already" );
458 Info(
"mergeDirectory",
459 "Tree not processed yet. Doing so now." );
463 ::TObject* treeObj = input.Get( key->GetName() );
465 Fatal(
"mergeDirectory",
467 return StatusCode::FAILURE;
469 ::TTree* itree =
dynamic_cast< TTree*
>( treeObj );
471 Error(
"mergeDirectory",
474 treeObj->GetName() );
475 return StatusCode::FAILURE;
480 if( itree->GetListOfFriends() &&
481 itree->GetListOfFriends()->GetSize() ) {
483 Info(
"mergeDirectory",
"TTree \"%s\" has friends; "
484 "skipping from merge", itree->GetName() );
495 std::unique_ptr< TEvent >&
event =
m_events[ key->GetName() ];
496 if( ( ! event.get() ) || ( event->auxMode() !=
m_mode ) ) {
497 event.reset(
new TEvent(
m_mode ) );
505 event->readFrom( itree ) );
507 Info(
"mergeDirectory",
"Copying xAOD tree \"%s\"",
511 Info(
"mergeDirectory",
"Copying non-xAOD tree \"%s\"",
521 std::unique_ptr< TEvent >&
event =
m_events[ key->GetName() ];
522 if( ! event.get() ) {
523 event.reset(
new TEvent() );
525 if( ! event->m_outTree ) {
531 new ::TMemFile( TString::Format(
"%sHelper.root",
536 event->writeTo( ofile, 200,
541 const EventFormat* ief =
event->inputEventFormat();
543 if( ( ! ief ) || ( ! oef ) ) {
544 Error(
"mergeDirectory",
546 Error(
"mergeDirectory",
548 static_cast< const void*
>( ief ),
549 static_cast< void*
>( oef ) );
550 return StatusCode::FAILURE;
552 auto itr = ief->
begin();
553 auto end = ief->end();
554 for( ; itr != end; ++itr ) {
555 if( ! oef->exists( itr->first ) ) {
556 oef->add( itr->second );
565 dynamic_cast< ::TTree*
>( output.Get( key->GetName() ) );
569 Info(
"mergeDirectory",
570 "Merging the tree into an existing one" );
575 const std::vector< ::TBranch* > missingMerged =
577 const std::vector< ::TBranch* > missingIncoming =
580 Info(
"mergeDirectory",
"missingMerged.size() = %i",
581 static_cast< int >( missingMerged.size() ) );
582 Info(
"mergeDirectory",
"missingIncoming.size() = %i",
583 static_cast< int >( missingIncoming.size() ) );
589 for( ::TBranch* br : missingIncoming ) {
591 Info(
"mergeDirectory",
"Adding auxiliary branch: %s",
600 const std::vector< ::TBranch* > skippedBranches =
602 for( ::TBranch* br : skippedBranches ) {
603 itree->SetBranchStatus( br->GetName(), 0 );
605 Info(
"mergeDirectory",
606 "Deactivated branch \"%s\" from merging",
613 TObjArray* obranches = otree->GetListOfBranches();
614 std::map< ::Int_t, ::TBranch* > auxIndices;
615 for( ::TBranch* br : missingMerged ) {
616 const Int_t
index = obranches->IndexOf( br );
618 Error(
"mergeDirectory",
621 return StatusCode::FAILURE;
623 auxIndices[
index ] = br;
624 obranches->RemoveAt(
index );
626 Info(
"mergeDirectory",
"Removed branch \"%s\" from "
627 "fast merge list", br->GetName() );
630 if( auxIndices.size() ) {
631 obranches->Compress();
637 cloner( itree, otree,
"fast SortBasketsByBranch",
638 ( ::TTreeCloner::kNoWarnings |
639 ::TTreeCloner::kIgnoreMissingTopLevel ) );
641 if( ! cloner.IsValid()) {
643 static const char*
const okerror =
"One of the export branch";
644 if( ::strncmp( cloner.GetWarning(), okerror,
645 ::strlen( okerror ) ) == 0 ) {
648 Error(
"mergeDirectory",
650 cloner.GetWarning() );
651 return StatusCode::FAILURE;
656 otree->SetEntries( otree->GetEntries() +
657 itree->GetEntries() );
658 if( ! cloner.Exec() ) {
659 Error(
"mergeDirectory",
661 return StatusCode::FAILURE;
666 for(
auto it : auxIndices ) {
667 const Int_t last = obranches->GetLast();
669 obranches->AddAtAndExpand( obranches->At( last ),
671 for( Int_t ind = last - 1; ind >= it.first; --ind ) {
672 obranches->AddAt( obranches->At( ind ), ind + 1 );
674 obranches->AddAt( it.second, it.first );
676 obranches->Add( it.second );
680 const ::Long64_t ientries = itree->GetEntries();
681 for( ::TBranch* br : missingMerged ) {
683 for( ::Long64_t i = 0; i < ientries; ++i ) {
684 if( br->Fill() < 0 ) {
685 Error(
"mergeDirectory",
687 "with default content" ),
689 return StatusCode::FAILURE;
695 otree->AutoSave(
"FlushBaskets" );
700 Info(
"mergeDirectory",
"Cloning the tree as is" );
712 const std::vector< ::TBranch* > skippedBranches =
714 for( ::TBranch* br : skippedBranches ) {
715 itree->SetBranchStatus( br->GetName(), 0 );
717 Info(
"mergeDirectory",
718 "Deactivated branch \"%s\" from cloning",
726 itree->CloneTree( -1,
727 "fast SortBasketsByBranch" ) ) ) {
728 Error(
"mergeDirectory",
732 return StatusCode::FAILURE;
734 otree->SetDirectory( &output );
745 std::unique_ptr< TEvent >&
event =
m_events[ key->GetName() ];
746 if( ! event.get() ) {
747 event.reset(
new TEvent() );
751 if( ! event->m_outTree ) {
753 ::TFile* ofile =
dynamic_cast< ::TFile*
>( &output );
755 Error(
"mergeDirectory",
757 return StatusCode::FAILURE;
760 event->writeTo( ofile, 200, key->GetName() ) );
765 Info(
"mergeDirectory",
"Slow copying xAOD tree \"%s\"",
770 const ::Long64_t
entries =
event->getEntries();
771 for( ::Long64_t entry = 0; entry <
entries; ++entry ) {
779 if( event->getEntry( entry ) < 0 ) {
780 Error(
"mergeDirectory",
783 static_cast< int >( entry ), key->GetName() );
784 return StatusCode::FAILURE;
788 if( ! ( entry % 500 ) ) {
789 Info(
"mergeDirectory",
"Copied %i / %i entries",
790 static_cast< int >( entry ),
792 static_cast< int >(
entries ) :
801 const ::Int_t bytes =
event->fill();
803 Error(
"mergeDirectory",
806 static_cast< int >( entry ), key->GetName() );
807 return StatusCode::FAILURE;
808 }
else if( bytes == 0 ) {
809 Warning(
"mergeDirectory",
810 "No payload was written for entry %i",
811 static_cast< int >( entry ) );
816 Fatal(
"mergeDirectory",
818 static_cast< int >( mode ) );
822 processedTrees.insert( key->GetName() );
824 }
else if( obj->IsA()->InheritsFrom(
"TObject" ) ) {
827 Info(
"mergeDirectory",
"Appears to be a TObject of type %s",
828 obj->IsA()->GetName() );
832 ::TClass* cl = ::TClass::GetClass( key->GetClassName() );
833 if( ( ! cl ) || ( ! cl->IsLoaded() ) ) {
838 Info(
"mergeDirectory",
"We seem to have a dictionary for it" );
842 TObject* oobj = output.Get( key->GetName() );
848 if( ret.isSuccess() ) {
851 oobj->Write( 0, TObject::kOverwrite );
853 }
else if( ret.isFailure() ) {
855 Error(
"mergeDirectory",
857 "\"%s\"" ), obj->GetName() );
858 return StatusCode::FAILURE;
863 Info(
"mergeDirectory",
"Simply writing it to the output" );
874 return StatusCode::SUCCESS;
896 Info(
"mergeObject",
"Called mergeObject( %s, %s )",
897 input.GetName(), output.GetName() );
901 if( strcmp( input.IsA()->GetName(), output.IsA()->GetName() ) ) {
902 Error(
"mergeObject",
903 XAOD_MESSAGE(
"Received objects of different types" ) );
904 Error(
"mergeObject",
906 Error(
"mergeObject",
907 XAOD_MESSAGE(
"output = %s" ), output.IsA()->GetName() );
908 return StatusCode::FAILURE;
912 ::TMethodCall mergeMethod;
913 mergeMethod.InitWithPrototype( output.IsA(),
"Merge",
"TCollection*" );
914 if( ! mergeMethod.IsValid() ) {
917 Info(
"mergeObject",
"Type doesn't have a Merge function" );
919 return StatusCode::RECOVERABLE;
928 mergeMethod.SetParam( ( Long_t ) &list );
929 mergeMethod.Execute( &output );
932 Info(
"mergeObject",
"Merging executed successfully" );
936 return StatusCode::SUCCESS;
950 ::TClass* cl = ::TClass::GetClass( typeName.c_str() );
952 Error(
"createMetaDataTools",
955 return StatusCode::FAILURE;
957 void* ptr = cl->New();
959 Error(
"createMetaDataTools",
961 "\"%s\"" ), typeName.c_str() );
962 return StatusCode::FAILURE;
966 ::TMethodCall initMethod;
967 initMethod.InitWithPrototype( cl,
"initialize",
"" );
968 if( initMethod.IsValid() ) {
971 const std::string returnTypeName =
972 initMethod.GetMethod()->GetReturnTypeNormalizedName();
973 ::TClass* returnCl = ::TClass::GetClass( returnTypeName.c_str(),
976 returnCl->GetListOfMethods()->FindObject(
"ignore" ) ) {
977 char* statusCode = 0;
978 initMethod.Execute( ptr,
"", &statusCode );
980 Warning(
"createMetaDataTools",
"No StatusCode was returned" );
982 ::TMethodCall ignoreMethod;
983 ignoreMethod.InitWithPrototype( returnCl,
"ignore",
"" );
984 if( ignoreMethod.IsValid() && statusCode ) {
985 ignoreMethod.Execute(
static_cast< void*
>( statusCode ) );
987 Error(
"createMetaDataTools",
989 "of the initialize() function's return "
996 initMethod.Execute( ptr );
999 Warning(
"createMetaDataTools",
1000 "No initialize() function found for tool \"%s\"",
1007 Info(
"createMetaDataTools",
"Created tool of type \"%s\"",
1013 return StatusCode::SUCCESS;
1024 std::vector< ::TBranch* >
1026 ::TTree* second )
const {
1029 std::vector< ::TBranch* >
result;
1032 ::TObjArray* brFirst = first->GetListOfBranches();
1033 ::TObjArray* brSecond = second->GetListOfBranches();
1036 for( ::Int_t i = 0; i < brFirst->GetEntries(); ++i ) {
1038 if( brSecond->FindObject( brFirst->At( i )->GetName() ) ) {
1042 ::TBranch* br =
dynamic_cast< ::TBranch*
>( brFirst->At( i ) );
1044 Fatal(
"getMissingBranches",
1045 XAOD_MESSAGE(
"Couldn't cast branch to TBranch?!?" ) );
1050 ::EDataType dt = kOther_t;
1051 if( br->GetExpectedType( cl, dt ) ) {
1052 Error(
"getMissingBranches",
1053 XAOD_MESSAGE(
"Type could not be extracted for branch "
1054 "\"%s\"" ), br->GetName() );
1057 if( cl && ( ! cl->IsLoaded() ) ) {
1069 std::vector< ::TBranch* >
1073 std::vector< ::TBranch* >
result;
1076 ::TObjArray* branches =
tree->GetListOfBranches();
1080 for( ::Int_t i = 0; i < branches->GetEntries(); ++i ) {
1082 ::TBranch* br =
dynamic_cast< ::TBranch*
>( branches->At( i ) );
1084 Fatal(
"getSkippedBranches",
1085 XAOD_MESSAGE(
"Couldn't cast branch to TBranch?!?" ) );
1090 ::EDataType dt = kOther_t;
1091 if( br->GetExpectedType( cl, dt ) ) {
1092 Error(
"getSkippedBranches",
1093 XAOD_MESSAGE(
"Type could not be extracted for branch "
1094 "\"%s\"" ), br->GetName() );
1099 if( cl && ( ! cl->IsLoaded() ) ) {
1115 ::TBranch* ibranch )
const {
1119 ::EDataType dt = kOther_t;
1120 if( ibranch->GetExpectedType( cl, dt ) ) {
1121 Error(
"addAuxBranch",
1122 XAOD_MESSAGE(
"Type could not be extracted for branch \"%s\"" ),
1123 ibranch->GetName() );
1124 return StatusCode::FAILURE;
1128 ::TBranch* obranch = 0;
1134 obranch = otree->Branch( ibranch->GetName(), cl->GetName(),
1135 &ptr, ibranch->GetBasketSize(),
1136 ibranch->GetSplitLevel() );
1138 Error(
"addAuxBranch",
1139 XAOD_MESSAGE(
"Couldn't create auxiliary branch \"%s\" with "
1141 ibranch->GetName(), cl->GetName() );
1142 return StatusCode::FAILURE;
1144 }
else if( dt != kOther_t ) {
1146 const char rootType =
1148 if( rootType ==
'\0' ) {
1149 Error(
"addAuxBranch",
1150 XAOD_MESSAGE(
"Type can't be extracted for EDataType = %i"),
1151 static_cast< int >( dt ) );
1152 return StatusCode::FAILURE;
1154 std::ostringstream leaflist;
1155 leaflist << ibranch->GetName() <<
"/" << rootType;
1157 obranch = otree->Branch( ibranch->GetName(), ptr,
1158 leaflist.str().c_str(),
1159 ibranch->GetBasketSize() );
1161 Error(
"addAuxBranch",
1162 XAOD_MESSAGE(
"Couldn't create auxiliary branch \"%s\" with "
1164 ibranch->GetName(),
static_cast< int >( dt ) );
1165 return StatusCode::FAILURE;
1168 Error(
"addAuxBranch",
1169 XAOD_MESSAGE(
"Couldn't figure out the type of branch \"%s\"" ),
1170 ibranch->GetName() );
1171 return StatusCode::FAILURE;
1175 obranch->SetAddress( 0 );
1176 for( ::Long64_t i = 0; i < otree->GetEntries(); ++i ) {
1177 if( obranch->Fill() < 0 ) {
1178 Error(
"addAuxBranch",
1179 XAOD_MESSAGE(
"Failed to fill branch \"%s\" with dummy "
1180 "data" ), obranch->GetName() );
1181 return StatusCode::FAILURE;
1186 return StatusCode::SUCCESS;