]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG/muondep/AccEffTemplates/AODtrainsim.C
7bb84bb0a9e80d2639ab37af40ea3987024252be
[u/mrichter/AliRoot.git] / PWG / muondep / AccEffTemplates / AODtrainsim.C
1 // ### Settings that make sense when using the Alien plugin
2 //==============================================================================
3 Int_t       runOnData          = 0;       // Set to 1 if processing real data
4 Int_t       iCollision         = 0;       // 0=pp, 1=Pb-Pb
5 //==============================================================================
6 Bool_t      usePhysicsSelection = kFALSE; // use physics selection
7 Bool_t      useTender           = kFALSE; // use tender wagon
8 Bool_t      useCentrality       = kFALSE; // centrality
9 Bool_t      useV0tender         = kFALSE;  // use V0 correction in tender
10 Bool_t      useDBG              = kFALSE;  // activate debugging
11 Bool_t      useMC               = kTRUE;  // use MC info
12 Bool_t      useKFILTER          = kTRUE;  // use Kinematics filter
13 Bool_t      useTR               = kTRUE;  // use track references
14 Bool_t      useCORRFW           = kFALSE; // do not change
15 Bool_t      useAODTAGS          = kFALSE; // use AOD tags
16 Bool_t      useSysInfo          = kFALSE; // use sys info
17
18 // ### Analysis modules to be included. Some may not be yet fully implemented.
19 //==============================================================================
20 Int_t       iAODhandler        = 1;      // Analysis produces an AOD or dAOD's
21 Int_t       iESDMCLabelAddition= 1;
22 Int_t       iESDfilter         = 1;      // ESD to AOD filter (barrel + muon tracks)
23 Int_t       iMUONcopyAOD       = 1;      // Task that copies only muon events in a separate AOD (PWG3)
24 Int_t       iMUONRefit         = 0;      // Refit ESD muon tracks before producing AODs
25 Int_t       iMUONPerformance   = 0;      // Task to study the muon performances in MC simulation
26 Int_t       iMUONEfficiency    = 0;      // Task to measure the muon efficiency
27 Int_t       iJETAN             = 0;      // Jet analysis (PWG4)
28 Int_t       iJETANdelta        = 0;      // Jet delta AODs
29 Int_t       iPWG3vertexing     = 0;      // Vertexing HF task (PWG3)
30 Int_t       iPWG3JPSIfilter    = 0;      // JPSI filtering (PWG3)
31 Int_t       iPWG3d2h           = 0;      // D0->2 hadrons (PWG3)
32
33 // ### Configuration macros used for each module
34 //==============================================================================
35 TString configPWG3d2h = (iCollision==0)?"$ALICE_ROOT/PWG3/vertexingHF/ConfigVertexingHF.C"
36 :"$ALICE_ROOT/PWG3/vertexingHF/ConfigVertexingHF_highmult.C";
37
38 // Temporaries.
39 class AliOADBPhysicsSelection;
40 AliOADBPhysicsSelection *CreateOADBphysicsSelection();
41 void AODmerge();
42 void AddAnalysisTasks(Int_t);
43 Bool_t LoadCommonLibraries();
44 Bool_t LoadAnalysisLibraries();
45 Bool_t LoadLibrary(const char *);
46 TChain *CreateChain();
47
48 //______________________________________________________________________________
49 void AODtrainsim(Int_t merge=0)
50 {
51   // Main analysis train macro.
52   // merge = 0: production
53   // merge = 1: intermediate merging
54   // merge = 2: final merging + terminate
55
56   if (merge) {
57     TGrid::Connect("alien://");
58     if (!gGrid || !gGrid->IsConnected()) {
59       ::Error("QAtrain", "No grid connection");
60       return;
61     }
62   }
63   // Set temporary merging directory to current one
64   gSystem->Setenv("TMPDIR", gSystem->pwd());
65   // Set temporary compilation directory to current one
66   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);
67   printf("==================================================================\n");
68   printf("===========    RUNNING FILTERING TRAIN   ==========\n");
69   printf("==================================================================\n");
70   printf("=  Configuring analysis train for:                               =\n");
71   if (usePhysicsSelection)   printf("=  Physics selection                                                =\n");
72   if (useTender)    printf("=  TENDER                                                        =\n");
73   if (iESDfilter)   printf("=  ESD filter                                                    =\n");
74   if (iMUONcopyAOD) printf("=  MUON copy AOD                                                 =\n");
75   if (iJETAN)       printf("=  Jet analysis                                                  =\n");
76   if (iJETANdelta)  printf("=     Jet delta AODs                                             =\n");
77   if (iPWG3vertexing) printf("=  PWG3 vertexing                                                =\n");
78   if (iPWG3JPSIfilter) printf("=  PWG3 j/psi filter                                             =\n");
79   if (iPWG3d2h) printf("=  PWG3 D0->2 hadrons QA                                     =\n");
80
81   // Load common libraries and set include path
82   if (!LoadCommonLibraries()) {
83     ::Error("AnalysisTrain", "Could not load common libraries");
84     return;
85   }
86
87   // Make the analysis manager and connect event handlers
88   AliAnalysisManager *mgr  = new AliAnalysisManager("Analysis Train", "Production train");
89   if (useSysInfo) mgr->SetNSysInfo(100);
90   // Load analysis specific libraries
91   if (!LoadAnalysisLibraries()) {
92     ::Error("AnalysisTrain", "Could not load analysis libraries");
93     return;
94   }
95
96   // Create input handler (input container created automatically)
97   // ESD input handler
98   AliESDInputHandler *esdHandler = new AliESDInputHandler();
99   mgr->SetInputEventHandler(esdHandler);
100   // Monte Carlo handler
101   if (useMC) {
102     AliMCEventHandler* mcHandler = new AliMCEventHandler();
103     mgr->SetMCtruthEventHandler(mcHandler);
104     mcHandler->SetReadTR(useTR);
105   }
106   // AOD output container, created automatically when setting an AOD handler
107   if (iAODhandler) {
108     // AOD output handler
109     AliAODHandler* aodHandler   = new AliAODHandler();
110     aodHandler->SetOutputFileName("AliAOD.root");
111     mgr->SetOutputEventHandler(aodHandler);
112   }
113   // Debugging if needed
114   if (useDBG) mgr->SetDebugLevel(3);
115
116   AddAnalysisTasks(merge);
117   if (merge) {
118     AODmerge();
119     if (merge > 1) {
120       mgr->InitAnalysis();
121       mgr->SetGridHandler(new AliAnalysisAlien());
122       mgr->StartAnalysis("grid terminate",0);
123     }
124     return;
125   }
126   // Run the analysis
127   //
128   TChain *chain = CreateChain();
129   if (!chain) return;
130
131   TStopwatch timer;
132   timer.Start();
133   mgr->SetSkipTerminate(kTRUE);
134   if (mgr->InitAnalysis()) {
135     mgr->PrintStatus();
136     mgr->StartAnalysis("local", chain);
137   }
138   timer.Print();
139 }
140
141 //______________________________________________________________________________
142 void AddAnalysisTasks(Int_t merge){
143   // Add all analysis task wagons to the train
144   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
145
146   //
147   // Tender and supplies. Needs to be called for every event.
148   //
149   //AliAnalysisManager::SetCommonFileName("AODQA.root");
150   if (useTender) {
151     gROOT->LoadMacro("$ALICE_ROOT/TENDER/TenderSupplies/AddTaskTender.C");
152     // IF V0 tender needed, put kTRUE below
153     AliAnalysisTaskSE *tender = AddTaskTender(useV0tender);
154     //      tender->SetDebugLevel(2);
155   }
156
157   if (usePhysicsSelection) {
158     // Physics selection task
159     gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
160     mgr->RegisterExtraFile("event_stat.root");
161     AliPhysicsSelectionTask *physSelTask = AddTaskPhysicsSelection(kFALSE);
162     //      AliOADBPhysicsSelection * oadbDefaultPbPb = CreateOADBphysicsSelection();
163     //      physSelTask->GetPhysicsSelection()->SetCustomOADBObjects(oadbDefaultPbPb,0,0);
164     //      if (!merge) mgr->AddStatisticsTask(AliVEvent::kAny);
165   }
166   // Centrality (only Pb-Pb)
167   if (iCollision && useCentrality) {
168     gROOT->LoadMacro("$ALICE_ROOT/OADB/macros/AddTaskCentrality.C");
169     AliCentralitySelectionTask *taskCentrality = AddTaskCentrality();
170     taskCentrality->SelectCollisionCandidates(AliVEvent::kAny);
171   }
172
173   if (iMUONRefit) {
174     gROOT->LoadMacro("$ALICE_ROOT/PWG/muondep/AddTaskMuonRefit.C");
175     AliAnalysisTaskMuonRefit* refit = AddTaskMuonRefit(-1., -1., kTRUE, -1., -1.);
176     refit->RemoveMonoCathodClusters(kTRUE, kFALSE);
177   }
178
179   if(iESDMCLabelAddition) {
180     gROOT->LoadMacro("$ALICE_ROOT/PWG/muondep/AddTaskESDMCLabelAddition.C");
181     AliAnalysisTaskESDMCLabelAddition *esdmclabel = AddTaskESDMCLabelAddition();
182   }
183
184   if (useMC && useTR && iMUONPerformance) {
185     gROOT->LoadMacro("$ALICE_ROOT/PWGPP/MUON/dep/AddTaskMuonPerformance.C");
186     AliAnalysisTaskMuonPerformance* muonPerformance = AddTaskMuonPerformance();
187     if (usePhysicsSelection) muonPerformance->SelectCollisionCandidates(AliVEvent::kAny);
188     muonPerformance->UseMCKinematics(kTRUE);
189     muonPerformance->SetMCTrigLevelFromMatchTrk(kTRUE);
190   }
191
192   if (iMUONEfficiency) {
193     gROOT->LoadMacro("$ALICE_ROOT/PWGPP/MUON/dep/AddTaskMUONTrackingEfficiency.C");
194     AliAnalysisTaskMuonTrackingEff* muonEfficiency = AddTaskMUONTrackingEfficiency(kTRUE, kTRUE);
195     if (usePhysicsSelection) muonEfficiency->SelectCollisionCandidates(AliVEvent::kAny);
196     muonEfficiency->UseMCLabel(kTRUE);
197   }
198
199   if (iESDfilter) {
200     //  ESD filter task configuration.
201     gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/ESDfilter/macros/AddTaskESDFilter.C");
202     if (iMUONcopyAOD) {
203       printf("Registering delta AOD file\n");
204       mgr->RegisterExtraFile("AliAOD.Muons.root");
205       mgr->RegisterExtraFile("AliAOD.Dimuons.root");
206       int muonMCMode=VAR_MUONMCMODE; // 1 to keep all ancestors, whether or not we get something in the muon arm
207       AliAnalysisTaskESDfilter *taskesdfilter = AddTaskESDFilter(useKFILTER, kTRUE, kFALSE, kFALSE /*usePhysicsSelection*/,kFALSE,kTRUE,kTRUE,kTRUE,1100,muonMCMode); // others
208     } else {
209       AliAnalysisTaskESDfilter *taskesdfilter = AddTaskESDFilter(useKFILTER, kFALSE, kFALSE, kFALSE /*usePhysicsSelection*/,kFALSE,kTRUE,kTRUE,kTRUE,1100,muonMCMode); // others
210     }
211
212     if ( 0 && VAR_USE_ITS_RECO ) /* 0 for the moment to get this macro running also with AliRoot <= .... */
213     {
214       AliAnalysisTaskESDMuonFilter* muFilter = mgr->GetTask("ESD Muon Filter");
215       if ( !muFilter )
216       {
217         std::cout << "ERROR : got a NULL muFilter ! so I cannot ask to keep SPD tracklets !" << std::endl;
218       }
219       else
220       {
221         muFilter->SetWithSPDtracklets(kTRUE);
222       }
223     }
224   }
225
226   // ********** PWG3 wagons ******************************************************
227   // PWG3 vertexing
228   if (iPWG3vertexing) {
229     gROOT->LoadMacro("$ALICE_ROOT/PWG3/vertexingHF/macros/AddTaskVertexingHF.C");
230     if (!iPWG3d2h) TFile::Cp(gSystem->ExpandPathName(configPWG3d2h.Data()), "file:ConfigVertexingHF.C");
231     AliAnalysisTaskSEVertexingHF *taskvertexingHF = AddTaskVertexingHF();
232     if (!taskvertexingHF) ::Warning("AnalysisTrainNew", "AliAnalysisTaskSEVertexingHF cannot run for this train conditions - EXCLUDED");
233     else mgr->RegisterExtraFile("AliAOD.VertexingHF.root");
234     taskvertexingHF->SelectCollisionCandidates(0);
235   }
236
237   // PWG3 JPSI filtering (only pp)
238   if (iPWG3JPSIfilter && (iCollision==0)) {
239     gROOT->LoadMacro("$ALICE_ROOT/PWG3/dielectron/macros/AddTaskJPSIFilter.C");
240     AliAnalysisTaskSE *taskJPSIfilter = AddTaskJPSIFilter();
241     if (!taskJPSIfilter) ::Warning("AnalysisTrainNew", "AliAnalysisTaskDielectronFilter cannot run for this train conditions - EXCLUDED");
242     else mgr->RegisterExtraFile("AliAOD.Dielectron.root");
243     taskJPSIfilter->SelectCollisionCandidates(0);
244   }
245
246   // PWG3 D2h
247   if (iPWG3d2h) {
248     gROOT->LoadMacro("$ALICE_ROOT/PWG3/vertexingHF/AddD2HTrain.C");
249     TFile::Cp(gSystem->ExpandPathName(configPWG3d2h.Data()), "file:ConfigVertexingHF.C");
250     AddD2HTrain(kFALSE, 1,0,0,0,0,0,0,0,0,0,0);
251   }
252
253   // ********** PWG4 wagons ******************************************************
254   // Jet analysis
255
256   // Configurations flags, move up?
257   TString kDeltaAODJetName = "AliAOD.Jets.root"; //
258   Bool_t  kIsPbPb = (iCollision==0)?false:true; // can be more intlligent checking the name of the data set
259   TString kDefaultJetBackgroundBranch = "";
260   TString kJetSubtractBranches = "";
261   UInt_t kHighPtFilterMask = 128;// from esd filter
262   UInt_t iPhysicsSelectionFlag = AliVEvent::kMB;
263   if (iJETAN) {
264     gROOT->LoadMacro("$ALICE_ROOT/PWG4/macros/AddTaskJets.C");
265     // Default jet reconstructor running on ESD's
266     AliAnalysisTaskJets *taskjets = AddTaskJets("AOD","UA1",0.4,kHighPtFilterMask,1.,0); // no background subtraction
267     if (!taskjets) ::Fatal("AnalysisTrainNew", "AliAnalysisTaskJets cannot run for this train conditions - EXCLUDED");
268     if(kDeltaAODJetName.Length()>0) taskjets->SetNonStdOutputFile(kDeltaAODJetName.Data());
269     if (iJETANdelta) {
270       //            AddTaskJetsDelta("AliAOD.Jets.root"); // need to modify this accordingly in the add task jets
271       mgr->RegisterExtraFile(kDeltaAODJetName.Data());
272       TString cTmp("");
273       if(kIsPbPb){
274         // UA1 intrinsic background subtraction
275         taskjets = AddTaskJets("AOD","UA1",0.4,kHighPtFilterMask,1.,2); // background subtraction
276         if(kDeltaAODJetName.Length()>0)taskjets->SetNonStdOutputFile(kDeltaAODJetName.Data());
277       }
278       // SICONE
279       taskjets = AddTaskJets("AOD","SISCONE",0.4,kHighPtFilterMask,0.15,0); //no background subtration to be done later....
280       if(kDeltaAODJetName.Length()>0)taskjets->SetNonStdOutputFile(kDeltaAODJetName.Data());
281       cTmp = taskjets->GetNonStdBranch();
282       if(cTmp.Length()>0)kJetSubtractBranches += Form("%s ",cTmp.Data());
283
284       // Add the clusters..
285       gROOT->LoadMacro("$ALICE_ROOT/PWG4/macros/AddTaskJetCluster.C");
286       AliAnalysisTaskJetCluster *taskCl = 0;
287       Float_t fCenUp = 0;
288       Float_t fCenLo = 0;
289       Float_t fTrackEtaWindow = 0.9;
290       taskCl = AddTaskJetCluster("AOD","",kHighPtFilterMask,iPhysicsSelectionFlag,"KT",0.4,0,1, kDeltaAODJetName.Data(),0.15,fTrackEtaWindow,0); // this one is for the background and random jets, random cones with no skip
291       taskCl->SetBackgroundCalc(kTRUE);
292       taskCl->SetNRandomCones(10);
293       taskCl->SetCentralityCut(fCenLo,fCenUp);
294       taskCl->SetGhostEtamax(fTrackEtaWindow);
295       kDefaultJetBackgroundBranch = Form("%s_%s",AliAODJetEventBackground::StdBranchName(),taskCl->GetJetOutputBranch());
296
297       taskCl = AddTaskJetCluster("AOD","",kHighPtFilterMask,iPhysicsSelectionFlag,"ANTIKT",0.4,2,1,kDeltaAODJetName.Data(),0.15);
298       taskCl->SetCentralityCut(fCenLo,fCenUp);
299       if(kIsPbPb)taskCl->SetBackgroundBranch(kDefaultJetBackgroundBranch.Data());
300       taskCl->SetNRandomCones(10);
301       kJetSubtractBranches += Form("%s ",taskCl->GetJetOutputBranch());
302
303       taskCl = AddTaskJetCluster("AOD","",kHighPtFilterMask,iPhysicsSelectionFlag,"ANTIKT",0.2,0,1,kDeltaAODJetName.Data(),0.15);
304       taskCl->SetCentralityCut(fCenLo,fCenUp);
305       if(kIsPbPb)taskCl->SetBackgroundBranch(kDefaultJetBackgroundBranch.Data());
306       kJetSubtractBranches += Form("%s ",taskCl->GetJetOutputBranch());
307
308       // DO THE BACKGROUND SUBTRACTION
309       if(kIsPbPb&&kJetSubtractBranches.Length()){
310         gROOT->LoadMacro("$ALICE_ROOT/PWG4/macros/AddTaskJetBackgroundSubtract.C");
311         AliAnalysisTaskJetBackgroundSubtract *taskSubtract = 0;
312         taskSubtract = AddTaskJetBackgroundSubtract(kJetSubtractBranches,1,"B0","B%d");
313         taskSubtract->SetBackgroundBranch(kDefaultJetBackgroundBranch.Data());
314         if(kDeltaAODJetName.Length()>0)taskSubtract->SetNonStdOutputFile(kDeltaAODJetName.Data());
315       }
316     }
317   }
318 }
319
320 //______________________________________________________________________________
321 Bool_t LoadCommonLibraries()
322 {
323   // Load common analysis libraries.
324   if (!gSystem->Getenv("ALICE_ROOT")) {
325     ::Error("AnalysisTrainNew.C::LoadCommonLibraries", "Analysis train requires that analysis libraries are compiled with a local AliRoot");
326     return kFALSE;
327   }
328   Bool_t success = kTRUE;
329   // Load framework classes. Par option ignored here.
330   success &= LoadLibrary("libSTEERBase.so");
331   success &= LoadLibrary("libESD.so");
332   success &= LoadLibrary("libAOD.so");
333   success &= LoadLibrary("libANALYSIS.so");
334   success &= LoadLibrary("libOADB.so");
335   success &= LoadLibrary("libANALYSISalice.so");
336   success &= LoadLibrary("libCORRFW.so");
337   success &= LoadLibrary("libESDfilter.so");
338   gROOT->ProcessLine(".include $ALICE_ROOT/include");
339   if (success) {
340     ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Load common libraries:    SUCCESS");
341     ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Include path for Aclic compilation:\n%s",
342            gSystem->GetIncludePath());
343   } else {
344     ::Info("AnalysisTrainNew.C::LoadCommodLibraries", "Load common libraries:    FAILED");
345   }
346   return success;
347 }
348
349 //______________________________________________________________________________
350 Bool_t LoadAnalysisLibraries()
351 {
352   // Load common analysis libraries.
353   if (useTender) {
354     if (!LoadLibrary("TENDER") ||
355         !LoadLibrary("TENDERSupplies")) return kFALSE;
356   }
357   if (iESDfilter || iPWG3MuonTrain) {
358     if (!LoadLibrary("PWGmuon")) return kFALSE;
359     //      if (!LoadLibrary("PWG3base")) return kFALSE;
360     //      if (!LoadLibrary("PWG3muon")) return kFALSE;
361   }
362   if (iMUONRefit || iESDMCLabelAddition) {
363     if (!LoadLibrary("PWGmuondep")) return kFALSE;
364   }
365   if ((useMC && useTR && iMUONPerformance) || iMUONEfficiency) {
366     if (!LoadLibrary("PWGPPMUONdep")) return kFALSE;
367   }
368   // JETAN
369   if (iJETAN) {
370     if (!LoadLibrary("JETAN")) return kFALSE;
371   }
372   if (iJETANdelta) {
373     if (!LoadLibrary("JETAN") ||
374         !LoadLibrary("CGAL") ||
375         !LoadLibrary("fastjet") ||
376         !LoadLibrary("siscone") ||
377         !LoadLibrary("SISConePlugin") ||
378         !LoadLibrary("FASTJETAN")) return kFALSE;
379   }
380   // PWG3 Vertexing HF
381   if (iPWG3vertexing || iPWG3d2h) {
382     if (!LoadLibrary("PWG3base") ||
383         !LoadLibrary("PWG3vertexingHF")) return kFALSE;
384   }
385   // PWG3 dielectron
386   if (iPWG3JPSIfilter) {
387     if (!LoadLibrary("PWG3dielectron")) return kFALSE;
388   }
389
390   ::Info("AnalysisTrainNew.C::LoadAnalysisLibraries", "Load other libraries:   SUCCESS");
391   return kTRUE;
392 }
393
394 //______________________________________________________________________________
395 Bool_t LoadLibrary(const char *module)
396 {
397   // Load a module library in a given mode. Reports success.
398   Int_t result;
399   TString mod(module);
400   if (!mod.Length()) {
401     ::Error("AnalysisTrainNew.C::LoadLibrary", "Empty module name");
402     return kFALSE;
403   }
404   // If a library is specified, just load it
405   if (mod.EndsWith(".so")) {
406     mod.Remove(mod.Index(".so"));
407     result = gSystem->Load(mod);
408     if (result < 0) {
409       ::Error("AnalysisTrainNew.C::LoadLibrary", "Could not load library %s", module);
410       return kFALSE;
411     }
412     return kTRUE;
413   }
414   // Check if the library is already loaded
415   if (strlen(gSystem->GetLibraries(module, "", kFALSE)) > 0) return kTRUE;
416   result = gSystem->Load(Form("lib%s", module));
417   if (result < 0) {
418     ::Error("AnalysisTrainNew.C::LoadLibrary", "Could not load module %s", module);
419     return kFALSE;
420   }
421   return kTRUE;
422 }
423
424
425 //______________________________________________________________________________
426 TChain *CreateChain()
427 {
428   // Create the input chain
429   chain = new TChain("esdTree");
430   if (gSystem->AccessPathName("AliESDs.root"))
431     ::Error("AnalysisTrainNew.C::CreateChain", "File: AliESDs.root not in ./data dir");
432   else
433     chain->Add("AliESDs.root");
434   if (chain->GetNtrees()) return chain;
435   return NULL;
436 }
437
438 //______________________________________________________________________________
439 void AODmerge()
440 {
441   // Merging method. No staging and no terminate phase.
442   TStopwatch timer;
443   timer.Start();
444   TString outputDir = "wn.xml";
445   TString outputFiles = VAR_AOD_MERGE_FILES;
446   TString mergeExcludes = "";
447   TObjArray *list = outputFiles.Tokenize(",");
448   TIter *iter = new TIter(list);
449   TObjString *str;
450   TString outputFile;
451   Bool_t merged = kTRUE;
452   while((str=(TObjString*)iter->Next())) {
453     outputFile = str->GetString();
454     // Skip already merged outputs
455     if (!gSystem->AccessPathName(outputFile)) {
456       printf("Output file <%s> found. Not merging again.",outputFile.Data());
457       continue;
458     }
459     if (mergeExcludes.Contains(outputFile.Data())) continue;
460     merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, 10, 0);
461     if (!merged) {
462       printf("ERROR: Cannot merge %s\n", outputFile.Data());
463       return;
464     }
465   }
466   // all outputs merged, validate
467   ofstream out;
468   out.open("outputs_valid_merge", ios::out);
469   out.close();
470   timer.Print();
471 }