ROOT logo
// Macro mergeOutputOnGrid.C is used to merge output files "AnalysisResults.root" 
// from the AliEn file catalog. Remarks:
//  1.) It uses your local AliRoot version - try to have locally the same AliRoot
//      version as the one you have specified for the analysis on Grid, otherwise
//      strange things might happen ....  
//  2.) It produces the merged, large statistics file "mergedAnalysisResults.root" 
//      in the directory <dir> from which the macro was launched. Results stored 
//      in merged file are WRONG because after merging the results from small 
//      statistics files are trivially summed up in all histograms. To get the 
//      final correct flow estimates for the large statistics file copy in <dir> 
//      and execute macro redoFinish.C (see comments in redoFinish.C). 

// Name of the output files to be merged:
TString outputFileName = "AnalysisResults.root";
// Name of the merged, large statistics file:
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 = 25;

void mergeOutputOnGrid(const char* gridPath = "/alice/cern.ch/user/a/abilandz/sim/LHC10e16/default/output/*") 
{
 // Cross-check user settings before starting:
 CrossCheckUserSettings(); 
 // Time: 
 TStopwatch timer;
 timer.Start();
 // Load needed flow libraries:
 gSystem->AddIncludePath("-I$ROOTSYS/include");
 gSystem->AddIncludePath("-I$ALICE_ROOT/include");
 gSystem->Load("libPWGflowBase");
 //cerr<<"Library \"libPWGflowBase\" loaded ...."<<endl;
 // Connect to the GRID:
 TGrid::Connect("alien://");  
 // Query the file catalog and get a TGridResult:
 TString queryPattern = outputFileName;
 TGridResult *result = gGrid->Query(gridPath,queryPattern.Data());
 Int_t nEntries = result->GetEntries();
 Printf("\n Found %d files \"%s\" in subdirectories of directory \n %s \n Let the merging begins! \n",nEntries,outputFileName.Data(),gridPath);   
 gSystem->Sleep(4400); // in ms
 // Create a TFileMerger:
 TFileMerger *fileMerger = new TFileMerger(); 
 Int_t fileCounter = 0;
 TString *baseDirPath = new TString(gSystem->pwd());
 // Loop over the TGridResult's entries and add the files to the TFileMerger:
 TString alienUrl;
 for(Int_t i=0;i<nEntries;i++) 
 {
  alienUrl = result->GetKey(i,"turl");
  //Printf("%s",alienUrl.Data());  
  if(gROOT->GetVersionDate()>=20100404) // to be improved - removed eventually (this is temporary protection)
  { 
   Bool_t success = fileMerger->AddFile(alienUrl.Data(),kFALSE); // kFALSE switches off cp printout (not supported in older Root)
   if(success){fileCounter++;}
  } else 
    {
     Bool_t success = fileMerger->AddFile(alienUrl.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 current cycle:
   TString *mergedFileForCurrentCycle = new TString("mergedCycle"); 
   (*mergedFileForCurrentCycle)+=(fileCounter/cycle);
   (*mergedFileForCurrentCycle)+=".root";    
   fileMerger->OutputFile(mergedFileForCurrentCycle->Data());
   fileMerger->Merge();
   Int_t percentage = 0;
   if(maxNoOfFiles > 0)
   {
    percentage = (Int_t)100.*fileCounter/maxNoOfFiles;
   } else
     {
      percentage = (Int_t)100.*fileCounter/nEntries;   
     }   
   Int_t max = 0;
   if(maxNoOfFiles > 0)
   {
    max = maxNoOfFiles;
   } else
     {
      max = nEntries;
     }     
   if(max-fileCounter > 0)
   {  
    cout<<endl;
    cout<<" .... merged "<<percentage<<"% requested files so far, marching on ....                       "<<endl;   
    cout<<endl;
   }  
   fileMerger->Reset();    
   delete mergedFileForPreviousCycle;
   delete mergedFileForCurrentCycle;
  } // end of if(fileCounter % cycle == 0) 
  if(fileCounter==maxNoOfFiles){break;}
 } // end of for(Int_t i=0;i<nEntries;i++) 

 //================================================================================================= 
 
 // 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;
 
 if(!(gSystem->AccessPathName(mergedFileName.Data(),kFileExists)) && fileCounter > 0)
 {
  cout<<endl;
  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 mergeOutputOnGrid(const char* gridPath = "...")

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

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() 
 mergeOutputOnGrid.C:1
 mergeOutputOnGrid.C:2
 mergeOutputOnGrid.C:3
 mergeOutputOnGrid.C:4
 mergeOutputOnGrid.C:5
 mergeOutputOnGrid.C:6
 mergeOutputOnGrid.C:7
 mergeOutputOnGrid.C:8
 mergeOutputOnGrid.C:9
 mergeOutputOnGrid.C:10
 mergeOutputOnGrid.C:11
 mergeOutputOnGrid.C:12
 mergeOutputOnGrid.C:13
 mergeOutputOnGrid.C:14
 mergeOutputOnGrid.C:15
 mergeOutputOnGrid.C:16
 mergeOutputOnGrid.C:17
 mergeOutputOnGrid.C:18
 mergeOutputOnGrid.C:19
 mergeOutputOnGrid.C:20
 mergeOutputOnGrid.C:21
 mergeOutputOnGrid.C:22
 mergeOutputOnGrid.C:23
 mergeOutputOnGrid.C:24
 mergeOutputOnGrid.C:25
 mergeOutputOnGrid.C:26
 mergeOutputOnGrid.C:27
 mergeOutputOnGrid.C:28
 mergeOutputOnGrid.C:29
 mergeOutputOnGrid.C:30
 mergeOutputOnGrid.C:31
 mergeOutputOnGrid.C:32
 mergeOutputOnGrid.C:33
 mergeOutputOnGrid.C:34
 mergeOutputOnGrid.C:35
 mergeOutputOnGrid.C:36
 mergeOutputOnGrid.C:37
 mergeOutputOnGrid.C:38
 mergeOutputOnGrid.C:39
 mergeOutputOnGrid.C:40
 mergeOutputOnGrid.C:41
 mergeOutputOnGrid.C:42
 mergeOutputOnGrid.C:43
 mergeOutputOnGrid.C:44
 mergeOutputOnGrid.C:45
 mergeOutputOnGrid.C:46
 mergeOutputOnGrid.C:47
 mergeOutputOnGrid.C:48
 mergeOutputOnGrid.C:49
 mergeOutputOnGrid.C:50
 mergeOutputOnGrid.C:51
 mergeOutputOnGrid.C:52
 mergeOutputOnGrid.C:53
 mergeOutputOnGrid.C:54
 mergeOutputOnGrid.C:55
 mergeOutputOnGrid.C:56
 mergeOutputOnGrid.C:57
 mergeOutputOnGrid.C:58
 mergeOutputOnGrid.C:59
 mergeOutputOnGrid.C:60
 mergeOutputOnGrid.C:61
 mergeOutputOnGrid.C:62
 mergeOutputOnGrid.C:63
 mergeOutputOnGrid.C:64
 mergeOutputOnGrid.C:65
 mergeOutputOnGrid.C:66
 mergeOutputOnGrid.C:67
 mergeOutputOnGrid.C:68
 mergeOutputOnGrid.C:69
 mergeOutputOnGrid.C:70
 mergeOutputOnGrid.C:71
 mergeOutputOnGrid.C:72
 mergeOutputOnGrid.C:73
 mergeOutputOnGrid.C:74
 mergeOutputOnGrid.C:75
 mergeOutputOnGrid.C:76
 mergeOutputOnGrid.C:77
 mergeOutputOnGrid.C:78
 mergeOutputOnGrid.C:79
 mergeOutputOnGrid.C:80
 mergeOutputOnGrid.C:81
 mergeOutputOnGrid.C:82
 mergeOutputOnGrid.C:83
 mergeOutputOnGrid.C:84
 mergeOutputOnGrid.C:85
 mergeOutputOnGrid.C:86
 mergeOutputOnGrid.C:87
 mergeOutputOnGrid.C:88
 mergeOutputOnGrid.C:89
 mergeOutputOnGrid.C:90
 mergeOutputOnGrid.C:91
 mergeOutputOnGrid.C:92
 mergeOutputOnGrid.C:93
 mergeOutputOnGrid.C:94
 mergeOutputOnGrid.C:95
 mergeOutputOnGrid.C:96
 mergeOutputOnGrid.C:97
 mergeOutputOnGrid.C:98
 mergeOutputOnGrid.C:99
 mergeOutputOnGrid.C:100
 mergeOutputOnGrid.C:101
 mergeOutputOnGrid.C:102
 mergeOutputOnGrid.C:103
 mergeOutputOnGrid.C:104
 mergeOutputOnGrid.C:105
 mergeOutputOnGrid.C:106
 mergeOutputOnGrid.C:107
 mergeOutputOnGrid.C:108
 mergeOutputOnGrid.C:109
 mergeOutputOnGrid.C:110
 mergeOutputOnGrid.C:111
 mergeOutputOnGrid.C:112
 mergeOutputOnGrid.C:113
 mergeOutputOnGrid.C:114
 mergeOutputOnGrid.C:115
 mergeOutputOnGrid.C:116
 mergeOutputOnGrid.C:117
 mergeOutputOnGrid.C:118
 mergeOutputOnGrid.C:119
 mergeOutputOnGrid.C:120
 mergeOutputOnGrid.C:121
 mergeOutputOnGrid.C:122
 mergeOutputOnGrid.C:123
 mergeOutputOnGrid.C:124
 mergeOutputOnGrid.C:125
 mergeOutputOnGrid.C:126
 mergeOutputOnGrid.C:127
 mergeOutputOnGrid.C:128
 mergeOutputOnGrid.C:129
 mergeOutputOnGrid.C:130
 mergeOutputOnGrid.C:131
 mergeOutputOnGrid.C:132
 mergeOutputOnGrid.C:133
 mergeOutputOnGrid.C:134
 mergeOutputOnGrid.C:135
 mergeOutputOnGrid.C:136
 mergeOutputOnGrid.C:137
 mergeOutputOnGrid.C:138
 mergeOutputOnGrid.C:139
 mergeOutputOnGrid.C:140
 mergeOutputOnGrid.C:141
 mergeOutputOnGrid.C:142
 mergeOutputOnGrid.C:143
 mergeOutputOnGrid.C:144
 mergeOutputOnGrid.C:145
 mergeOutputOnGrid.C:146
 mergeOutputOnGrid.C:147
 mergeOutputOnGrid.C:148
 mergeOutputOnGrid.C:149
 mergeOutputOnGrid.C:150
 mergeOutputOnGrid.C:151
 mergeOutputOnGrid.C:152
 mergeOutputOnGrid.C:153
 mergeOutputOnGrid.C:154
 mergeOutputOnGrid.C:155
 mergeOutputOnGrid.C:156
 mergeOutputOnGrid.C:157
 mergeOutputOnGrid.C:158
 mergeOutputOnGrid.C:159
 mergeOutputOnGrid.C:160
 mergeOutputOnGrid.C:161
 mergeOutputOnGrid.C:162
 mergeOutputOnGrid.C:163
 mergeOutputOnGrid.C:164
 mergeOutputOnGrid.C:165
 mergeOutputOnGrid.C:166
 mergeOutputOnGrid.C:167
 mergeOutputOnGrid.C:168
 mergeOutputOnGrid.C:169
 mergeOutputOnGrid.C:170
 mergeOutputOnGrid.C:171
 mergeOutputOnGrid.C:172
 mergeOutputOnGrid.C:173
 mergeOutputOnGrid.C:174
 mergeOutputOnGrid.C:175
 mergeOutputOnGrid.C:176
 mergeOutputOnGrid.C:177
 mergeOutputOnGrid.C:178
 mergeOutputOnGrid.C:179
 mergeOutputOnGrid.C:180
 mergeOutputOnGrid.C:181
 mergeOutputOnGrid.C:182
 mergeOutputOnGrid.C:183
 mergeOutputOnGrid.C:184
 mergeOutputOnGrid.C:185
 mergeOutputOnGrid.C:186
 mergeOutputOnGrid.C:187
 mergeOutputOnGrid.C:188
 mergeOutputOnGrid.C:189
 mergeOutputOnGrid.C:190
 mergeOutputOnGrid.C:191
 mergeOutputOnGrid.C:192