ROOT logo
// Macro mergeOutput.C is used to merge output files "AnalysisResults.root" locally. 
// (To merge output files "AnalysisResults.root" on Grid use macro mergeOutputOnGrid.C.)
// Its usage relies on the following directory structure and naming conventions:
//  1.) In directory <dir> there are subdirectories <subdir1>, <subdir2>, ...;   
//  2.) In subdirectory <subdir*> there is a file named "AnalysisResults.root";
//  3.) Copy macro mergeOutput.C in directory <dir> and launch it. It will automatically 
//      access from each subdirectory a file "AnalysisResults.root" and by making use of 
//      TFileMerger utility it will produce a merged file "mergedAnalysisResults.root" 
//      and save it in directory <dir>;
//  4.) IMPORTANT: Macro mergeOutput.C must be used in a combination with macro redoFinish.C
//      in order to get the analysis done on merged, large statistics sample. In particular,
//      after you got the file "mergedAnalysisResults.root", copy macro redoFinish.C in 
//      directory <dir> and launch it. This macro will access "mergedAnalysisResults.root"
//      and produce the output file "AnalysisResults.root" in directory <dir>. This file will 
//      hold the final results for merged, large statistics sample. 
//  5.) REMARK 1: To see plots for some of results use macro compareFlowResults.C. This macro
//      accesses file "AnalysisResults.root" and produces couple of predefined example plots.        
//  6.) REMARK 2: To use this macro for merging of other root files (having other name than
//      the default "AnalysisResults.root") modify the declaration of TString outputFileName.

// Name of the output files to be merged (sitting in <subdir1>, <subdir2>, ...):
TString outputFileName = "AnalysisResults.root";
// Name of the merged, large statistics file (to be saved in <dir>):
TString mergedFileName = "mergedAnalysisResults.root";
// Optionally set maximum number of files to be merged:
Int_t maxNoOfFiles = -1; // -1 = ignore
// For a large number of output files merging is done in cycles and this is the cycle period: 
const Int_t cycle = 50;

enum libModes {mLocal,mLocalSource};

void mergeOutput(Int_t mode=mLocal)
{
 // Mode: if mode = mLocal: analyze data on your computer using aliroot
 //       if mode = mLocalSource: analyze data on your computer using root + source files 
 
 // Cross-check user settings before starting:
 CrossCheckUserSettings(); 
 
 // Load needed flow libraries:
 LoadLibrariesMO(mode);  
 
 // Standard magic:
 TString *baseDirPath = new TString(gSystem->pwd());
 TSystemDirectory *baseDir = new TSystemDirectory(".",baseDirPath->Data());          
 TList *listOfFilesInBaseDir = baseDir->GetListOfFiles();
 TStopwatch timer;
 timer.Start();
 //listOfFilesInBaseDir->Print();
 
 // Count number of files to be merged:
 CountNumberOfFilesToBeMerged(baseDirPath,listOfFilesInBaseDir);
 
 // Loop over all files and from each subdirectory add file <outputFileName> to TFileMerger:
 Int_t nFiles = listOfFilesInBaseDir->GetEntries();
 Int_t fileCounter = 0;
 TFileMerger *fileMerger = new TFileMerger(); 
 cout<<" .... merging in progress, silence please ...."<<"\r"<<flush;
 for(Int_t iFile=0;iFile<nFiles;iFile++)
 {
  TSystemFile *currentFile = (TSystemFile*)listOfFilesInBaseDir->At(iFile);
  // Consider only subdirectories: 
  if(!currentFile || 
     !currentFile->IsDirectory() || 
     strcmp(currentFile->GetName(), ".") == 0 || 
     strcmp(currentFile->GetName(), "..") == 0){continue;} 
  // Accessing the output file <outputFileName> in current subdirectory: 
  TString currentSubDirName = baseDirPath->Data();
  (currentSubDirName+="/")+=currentFile->GetName();
  currentSubDirName+="/";
  TString fileName = currentSubDirName; 
  fileName+=outputFileName.Data();
  if(!(gSystem->AccessPathName(fileName.Data(),kFileExists)))
  {
   if(gROOT->GetVersionDate()>=20100404) // to be improved - removed eventually (this is temporary protection)
   { 
    Bool_t success = fileMerger->AddFile(fileName.Data(),kFALSE); // kFALSE switches off cp printout (not supported in older Root)
    if(success){fileCounter++;}
   } else 
     {
      Bool_t success = fileMerger->AddFile(fileName.Data());
      if(success){fileCounter++;}
     }    
   // Merging in cycles:
   if(fileCounter % cycle == 0)
   {
    // If the merged output from previous cycle exists add it to TFileMerger:
    TString *mergedFileForPreviousCycle = new TString("mergedCycle"); 
    (*mergedFileForPreviousCycle)+=(fileCounter/cycle - 1);
    (*mergedFileForPreviousCycle)+=".root";
    if(!(gSystem->AccessPathName(mergedFileForPreviousCycle->Data(),kFileExists)))
    {
     if(gROOT->GetVersionDate()>=20100404) // to be improved - removed eventually (this is temporary protection)
     {  
      fileMerger->AddFile(mergedFileForPreviousCycle->Data(),kFALSE); // kFALSE switches off cp printout (not supported in older Root)
     } else
       {
        fileMerger->AddFile(mergedFileForPreviousCycle->Data());
       }
     // Delete merged output from previous cycle:
     TSystemFile *file = new TSystemFile(mergedFileForPreviousCycle->Data(),baseDirPath->Data());
     file->Delete();
     delete file;
    }    
    // Create merged output for the current cycle:
    TString *mergedFileForCurrentCycle = new TString("mergedCycle"); 
    (*mergedFileForCurrentCycle)+=(fileCounter/cycle);
    (*mergedFileForCurrentCycle)+=".root";    
    fileMerger->OutputFile(mergedFileForCurrentCycle->Data());
    fileMerger->Merge();
    cout<<" .... merged "<<fileCounter<<" files so far, marching on ....                       "<<"\r"<<flush;
    fileMerger->Reset();    
    delete mergedFileForPreviousCycle;
    delete mergedFileForCurrentCycle;
   } // end of if(fileCounter % cycle == 0) 
  } // end of if(!(gSystem->AccessPathName(fileName.Data(),kFileExists))) 
  if(fileCounter==maxNoOfFiles){break;}
 } // end of for(Int_t iFile=0;iFile<nFiles;iFile++)
 
 //=================================================================================================
 
 // Final merging at the end of the day (3 distinct cases):
 gSystem->cd(baseDirPath->Data());
 if(fileCounter < cycle)
 {
  fileMerger->OutputFile(mergedFileName.Data());
  fileMerger->Merge();
 } else if(fileCounter % cycle == 0)
   {
    TString *mergedFileForPreviousCycle = new TString("mergedCycle"); 
    (*mergedFileForPreviousCycle)+=(fileCounter/cycle);
    (*mergedFileForPreviousCycle)+=".root";    
    if(!(gSystem->AccessPathName(mergedFileForPreviousCycle->Data(),kFileExists)))
    {
     gSystem->Rename(mergedFileForPreviousCycle->Data(),mergedFileName.Data());
    }     
   } else
     {
      TString *mergedFileForPreviousCycle = new TString("mergedCycle"); 
      (*mergedFileForPreviousCycle)+=((Int_t)fileCounter/cycle);
      (*mergedFileForPreviousCycle)+=".root";      
      if(gROOT->GetVersionDate()>=20100404) // to be improved - removed eventually (this is temporary protection)
      {  
       fileMerger->AddFile(mergedFileForPreviousCycle->Data(),kFALSE);
      } else
        {
         fileMerger->AddFile(mergedFileForPreviousCycle->Data());      
        }
      // Delete merged output from previous cycle:
      TSystemFile *file = new TSystemFile(mergedFileForPreviousCycle->Data(),baseDirPath->Data());
      file->Delete();
      delete file;
      fileMerger->OutputFile(mergedFileName.Data());
      fileMerger->Merge();
      delete mergedFileForPreviousCycle;
     }
 delete fileMerger;
 delete baseDirPath;
 delete baseDir;

 if(!(gSystem->AccessPathName(mergedFileName.Data(),kFileExists)) && fileCounter > 0)
 {
  cout<<" Merging went successfully: "<<fileCounter<<" files \""<<outputFileName.Data()<<"\" were"<<endl;
  cout<<" merged into the newly created file \""<<mergedFileName.Data()<<"\"."<<endl;
  cout<<endl;
  cout<<" Launch now macro redoFinish.C to get the correct final results."<<endl;
 } else
   {
    cout<<" WARNING: Merging failed miserably !!!!"<<endl;
   }   
 cout<<endl;
 timer.Stop();
 timer.Print(); 
 cout<<endl;

} // End of void mergeOutput(Int_t mode=mLocal)

// ===================================================================================

void CrossCheckUserSettings()
{
 // Cross-check user settings before starting:
 
 if(cycle>100)
 {
  cout<<endl;
  cout<<" WARNING: Cycle is too big !!!!"<<endl; 
  cout<<"          Set \"const Int_t cycle\" to smaller value in the macro."<<endl;
  cout<<endl;
  exit(0);
 }

} // void CrossCheckUserSettings() 
 
// ===================================================================================

void CountNumberOfFilesToBeMerged(TString *baseDirPath,TList *listOfFilesInBaseDir)
{
 // Count number of files to be merged and print info on the screen.
 
 if(!(baseDirPath && listOfFilesInBaseDir))
 {
  cout<<endl;
  cout<<" WARNING: baseDirPath||listOfFilesInBaseDir is NULL in CountNumberOfFilesToBeMerged(...) !!!!"<<endl;
  cout<<endl;
  exit(0);
 }
 
 Int_t nFiles = listOfFilesInBaseDir->GetEntries();
 Int_t fileCounter = 0;
 for(Int_t iFile=0;iFile<nFiles;iFile++)
 {
  TSystemFile *currentFile = (TSystemFile*)listOfFilesInBaseDir->At(iFile);
  // Consider only subdirectories: 
  if(!currentFile || 
     !currentFile->IsDirectory() || 
     strcmp(currentFile->GetName(), ".") == 0 || 
     strcmp(currentFile->GetName(), "..") == 0) continue; 
  // Accessing the output file <outputFileName> in current subdirectory: 
  TString currentSubDirName = baseDirPath->Data();
  (currentSubDirName+="/")+=currentFile->GetName();
  currentSubDirName+="/";
  TString fileName = currentSubDirName; 
  fileName+=outputFileName.Data();
  if(!(gSystem->AccessPathName(fileName.Data(),kFileExists)))
  {
   fileCounter++;
  }
 } // end of for(Int_t iFile=0;iFile<nFiles;iFile++)

 // Print info on the screen:
 if(fileCounter>0)
 { 
  cout<<endl;
  cout<<" In subdirectores of directory "<<baseDirPath->Data()<<endl;
  cout<<" there are "<<fileCounter<<" files \""<<outputFileName.Data()<<"\" to be merged."<<endl;
  cout<<" Let the merging begins!"<<endl;
  cout<<endl;
 }
 else if(fileCounter==0)
 {
  cout<<endl;
  cout<<" TFileMerger wasn't lucky :'( "<<endl;
  cout<<" Couldn't find a single file \""<<outputFileName.Data()<<"\" to merge"<<endl;
  cout<<" in subdirectories of directory "<<baseDirPath->Data()<<" !!!!"<<endl;
  cout<<endl;
  exit(0);
 }
 
 return;
 
} // void CountNumberOfFilesToBeMerged(TString *dirName,TList *listOfAllFiles)

// ===================================================================================

void LoadLibrariesMO(const libModes mode) {
  
  //--------------------------------------
  // Load the needed libraries most of them already loaded by aliroot
  //--------------------------------------
  //gSystem->Load("libTree");
  gSystem->Load("libGeom");
  gSystem->Load("libVMC");
  gSystem->Load("libXMLIO");
  gSystem->Load("libPhysics");
  
  //----------------------------------------------------------
  // >>>>>>>>>>> Local mode <<<<<<<<<<<<<< 
  //----------------------------------------------------------
  if (mode==mLocal) {
    //--------------------------------------------------------
    // If you want to use already compiled libraries 
    // in the aliroot distribution
    //--------------------------------------------------------

  //==================================================================================  
  //load needed libraries:
  gSystem->AddIncludePath("-I$ROOTSYS/include");
  //gSystem->Load("libTree");

  // for AliRoot
  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
  gSystem->Load("libANALYSIS");
  gSystem->Load("libPWGflowBase");
  //cerr<<"libPWGflowBase loaded ..."<<endl;
  
  }
  
  else if (mode==mLocalSource) {
 
    // In root inline compile
  
    // Constants  
    gROOT->LoadMacro("BaseAliFlowCommonConstants.cxx+");
    gROOT->LoadMacro("BaseAliFlowLYZConstants.cxx+");
    
    // Flow event
    gROOT->LoadMacro("BaseAliFlowVector.cxx+"); 
    gROOT->LoadMacro("BaseAliFlowTrackSimple.cxx+");    
    gROOT->LoadMacro("BaseAliFlowTrackSimpleCuts.cxx+");    
    gROOT->LoadMacro("BaseAliFlowEventSimple.cxx+");
    
    // Output histosgrams
    gROOT->LoadMacro("BaseAliFlowCommonHist.cxx+");
    gROOT->LoadMacro("BaseAliFlowCommonHistResults.cxx+");
    gROOT->LoadMacro("BaseAliFlowLYZHist1.cxx+");
    gROOT->LoadMacro("BaseAliFlowLYZHist2.cxx+");
       
    cout << "finished loading macros!" << endl;  
    
  } // end of else if (mode==mLocalSource) 
  
} // end of void LoadLibrariesMO(const libModes mode)

 mergeOutput.C:1
 mergeOutput.C:2
 mergeOutput.C:3
 mergeOutput.C:4
 mergeOutput.C:5
 mergeOutput.C:6
 mergeOutput.C:7
 mergeOutput.C:8
 mergeOutput.C:9
 mergeOutput.C:10
 mergeOutput.C:11
 mergeOutput.C:12
 mergeOutput.C:13
 mergeOutput.C:14
 mergeOutput.C:15
 mergeOutput.C:16
 mergeOutput.C:17
 mergeOutput.C:18
 mergeOutput.C:19
 mergeOutput.C:20
 mergeOutput.C:21
 mergeOutput.C:22
 mergeOutput.C:23
 mergeOutput.C:24
 mergeOutput.C:25
 mergeOutput.C:26
 mergeOutput.C:27
 mergeOutput.C:28
 mergeOutput.C:29
 mergeOutput.C:30
 mergeOutput.C:31
 mergeOutput.C:32
 mergeOutput.C:33
 mergeOutput.C:34
 mergeOutput.C:35
 mergeOutput.C:36
 mergeOutput.C:37
 mergeOutput.C:38
 mergeOutput.C:39
 mergeOutput.C:40
 mergeOutput.C:41
 mergeOutput.C:42
 mergeOutput.C:43
 mergeOutput.C:44
 mergeOutput.C:45
 mergeOutput.C:46
 mergeOutput.C:47
 mergeOutput.C:48
 mergeOutput.C:49
 mergeOutput.C:50
 mergeOutput.C:51
 mergeOutput.C:52
 mergeOutput.C:53
 mergeOutput.C:54
 mergeOutput.C:55
 mergeOutput.C:56
 mergeOutput.C:57
 mergeOutput.C:58
 mergeOutput.C:59
 mergeOutput.C:60
 mergeOutput.C:61
 mergeOutput.C:62
 mergeOutput.C:63
 mergeOutput.C:64
 mergeOutput.C:65
 mergeOutput.C:66
 mergeOutput.C:67
 mergeOutput.C:68
 mergeOutput.C:69
 mergeOutput.C:70
 mergeOutput.C:71
 mergeOutput.C:72
 mergeOutput.C:73
 mergeOutput.C:74
 mergeOutput.C:75
 mergeOutput.C:76
 mergeOutput.C:77
 mergeOutput.C:78
 mergeOutput.C:79
 mergeOutput.C:80
 mergeOutput.C:81
 mergeOutput.C:82
 mergeOutput.C:83
 mergeOutput.C:84
 mergeOutput.C:85
 mergeOutput.C:86
 mergeOutput.C:87
 mergeOutput.C:88
 mergeOutput.C:89
 mergeOutput.C:90
 mergeOutput.C:91
 mergeOutput.C:92
 mergeOutput.C:93
 mergeOutput.C:94
 mergeOutput.C:95
 mergeOutput.C:96
 mergeOutput.C:97
 mergeOutput.C:98
 mergeOutput.C:99
 mergeOutput.C:100
 mergeOutput.C:101
 mergeOutput.C:102
 mergeOutput.C:103
 mergeOutput.C:104
 mergeOutput.C:105
 mergeOutput.C:106
 mergeOutput.C:107
 mergeOutput.C:108
 mergeOutput.C:109
 mergeOutput.C:110
 mergeOutput.C:111
 mergeOutput.C:112
 mergeOutput.C:113
 mergeOutput.C:114
 mergeOutput.C:115
 mergeOutput.C:116
 mergeOutput.C:117
 mergeOutput.C:118
 mergeOutput.C:119
 mergeOutput.C:120
 mergeOutput.C:121
 mergeOutput.C:122
 mergeOutput.C:123
 mergeOutput.C:124
 mergeOutput.C:125
 mergeOutput.C:126
 mergeOutput.C:127
 mergeOutput.C:128
 mergeOutput.C:129
 mergeOutput.C:130
 mergeOutput.C:131
 mergeOutput.C:132
 mergeOutput.C:133
 mergeOutput.C:134
 mergeOutput.C:135
 mergeOutput.C:136
 mergeOutput.C:137
 mergeOutput.C:138
 mergeOutput.C:139
 mergeOutput.C:140
 mergeOutput.C:141
 mergeOutput.C:142
 mergeOutput.C:143
 mergeOutput.C:144
 mergeOutput.C:145
 mergeOutput.C:146
 mergeOutput.C:147
 mergeOutput.C:148
 mergeOutput.C:149
 mergeOutput.C:150
 mergeOutput.C:151
 mergeOutput.C:152
 mergeOutput.C:153
 mergeOutput.C:154
 mergeOutput.C:155
 mergeOutput.C:156
 mergeOutput.C:157
 mergeOutput.C:158
 mergeOutput.C:159
 mergeOutput.C:160
 mergeOutput.C:161
 mergeOutput.C:162
 mergeOutput.C:163
 mergeOutput.C:164
 mergeOutput.C:165
 mergeOutput.C:166
 mergeOutput.C:167
 mergeOutput.C:168
 mergeOutput.C:169
 mergeOutput.C:170
 mergeOutput.C:171
 mergeOutput.C:172
 mergeOutput.C:173
 mergeOutput.C:174
 mergeOutput.C:175
 mergeOutput.C:176
 mergeOutput.C:177
 mergeOutput.C:178
 mergeOutput.C:179
 mergeOutput.C:180
 mergeOutput.C:181
 mergeOutput.C:182
 mergeOutput.C:183
 mergeOutput.C:184
 mergeOutput.C:185
 mergeOutput.C:186
 mergeOutput.C:187
 mergeOutput.C:188
 mergeOutput.C:189
 mergeOutput.C:190
 mergeOutput.C:191
 mergeOutput.C:192
 mergeOutput.C:193
 mergeOutput.C:194
 mergeOutput.C:195
 mergeOutput.C:196
 mergeOutput.C:197
 mergeOutput.C:198
 mergeOutput.C:199
 mergeOutput.C:200
 mergeOutput.C:201
 mergeOutput.C:202
 mergeOutput.C:203
 mergeOutput.C:204
 mergeOutput.C:205
 mergeOutput.C:206
 mergeOutput.C:207
 mergeOutput.C:208
 mergeOutput.C:209
 mergeOutput.C:210
 mergeOutput.C:211
 mergeOutput.C:212
 mergeOutput.C:213
 mergeOutput.C:214
 mergeOutput.C:215
 mergeOutput.C:216
 mergeOutput.C:217
 mergeOutput.C:218
 mergeOutput.C:219
 mergeOutput.C:220
 mergeOutput.C:221
 mergeOutput.C:222
 mergeOutput.C:223
 mergeOutput.C:224
 mergeOutput.C:225
 mergeOutput.C:226
 mergeOutput.C:227
 mergeOutput.C:228
 mergeOutput.C:229
 mergeOutput.C:230
 mergeOutput.C:231
 mergeOutput.C:232
 mergeOutput.C:233
 mergeOutput.C:234
 mergeOutput.C:235
 mergeOutput.C:236
 mergeOutput.C:237
 mergeOutput.C:238
 mergeOutput.C:239
 mergeOutput.C:240
 mergeOutput.C:241
 mergeOutput.C:242
 mergeOutput.C:243
 mergeOutput.C:244
 mergeOutput.C:245
 mergeOutput.C:246
 mergeOutput.C:247
 mergeOutput.C:248
 mergeOutput.C:249
 mergeOutput.C:250
 mergeOutput.C:251
 mergeOutput.C:252
 mergeOutput.C:253
 mergeOutput.C:254
 mergeOutput.C:255
 mergeOutput.C:256
 mergeOutput.C:257
 mergeOutput.C:258
 mergeOutput.C:259
 mergeOutput.C:260
 mergeOutput.C:261
 mergeOutput.C:262
 mergeOutput.C:263
 mergeOutput.C:264
 mergeOutput.C:265
 mergeOutput.C:266
 mergeOutput.C:267
 mergeOutput.C:268
 mergeOutput.C:269
 mergeOutput.C:270
 mergeOutput.C:271
 mergeOutput.C:272
 mergeOutput.C:273
 mergeOutput.C:274
 mergeOutput.C:275
 mergeOutput.C:276
 mergeOutput.C:277
 mergeOutput.C:278
 mergeOutput.C:279
 mergeOutput.C:280
 mergeOutput.C:281
 mergeOutput.C:282
 mergeOutput.C:283
 mergeOutput.C:284
 mergeOutput.C:285
 mergeOutput.C:286
 mergeOutput.C:287
 mergeOutput.C:288
 mergeOutput.C:289
 mergeOutput.C:290
 mergeOutput.C:291
 mergeOutput.C:292
 mergeOutput.C:293
 mergeOutput.C:294
 mergeOutput.C:295
 mergeOutput.C:296
 mergeOutput.C:297
 mergeOutput.C:298
 mergeOutput.C:299
 mergeOutput.C:300
 mergeOutput.C:301
 mergeOutput.C:302
 mergeOutput.C:303
 mergeOutput.C:304
 mergeOutput.C:305
 mergeOutput.C:306
 mergeOutput.C:307
 mergeOutput.C:308
 mergeOutput.C:309
 mergeOutput.C:310
 mergeOutput.C:311
 mergeOutput.C:312
 mergeOutput.C:313
 mergeOutput.C:314
 mergeOutput.C:315