]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisManager.cxx
A task can now declare the list of input branches that are requested during analysis.
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisManager.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17 // Author: Andrei Gheata, 31/05/2006
18
19 //==============================================================================
20 //   AliAnalysisManager - Manager analysis class. Allows creation of several
21 // analysis tasks and data containers storing their input/output. Allows
22 // connecting/chaining tasks via shared data containers. Serializes the current
23 // event for all tasks depending only on initial input data.
24 //==============================================================================
25 //
26 //==============================================================================
27
28 #include <Riostream.h>
29
30 #include <TError.h>
31 #include <TClass.h>
32 #include <TFile.h>
33 //#include <TKey.h>
34 #include <TMath.h>
35 #include <TH1.h>
36 #include <TMethodCall.h>
37 #include <TChain.h>
38 #include <TSystem.h>
39 #include <TROOT.h>
40 #include <TCanvas.h>
41 #include <TStopwatch.h>
42
43 #include "AliAnalysisSelector.h"
44 #include "AliAnalysisGrid.h"
45 #include "AliAnalysisTask.h"
46 #include "AliAnalysisDataContainer.h"
47 #include "AliAnalysisDataSlot.h"
48 #include "AliVEventHandler.h"
49 #include "AliVEventPool.h"
50 #include "AliSysInfo.h"
51 #include "AliAnalysisManager.h"
52
53 ClassImp(AliAnalysisManager)
54
55 AliAnalysisManager *AliAnalysisManager::fgAnalysisManager = NULL;
56 TString AliAnalysisManager::fgCommonFileName = "";
57
58 //______________________________________________________________________________
59 AliAnalysisManager::AliAnalysisManager(const char *name, const char *title)
60                    :TNamed(name,title),
61                     fTree(NULL),
62                     fInputEventHandler(NULL),
63                     fOutputEventHandler(NULL),
64                     fMCtruthEventHandler(NULL),
65                     fEventPool(NULL),
66                     fCurrentEntry(-1),
67                     fNSysInfo(0),
68                     fMode(kLocalAnalysis),
69                     fInitOK(kFALSE),
70                     fIsRemote(kFALSE),
71                     fDebug(0),
72                     fSpecialOutputLocation(""), 
73                     fTasks(NULL),
74                     fTopTasks(NULL),
75                     fZombies(NULL),
76                     fContainers(NULL),
77                     fInputs(NULL),
78                     fOutputs(NULL),
79                     fParamCont(NULL),
80                     fCommonInput(NULL),
81                     fCommonOutput(NULL),
82                     fSelector(NULL),
83                     fGridHandler(NULL),
84                     fExtraFiles(""),
85                     fAutoBranchHandling(kTRUE), 
86                     fTable(),
87                     fRunFromPath(0),
88                     fNcalls(0),
89                     fStatisticsMsg(),
90                     fRequestedBranches()
91 {
92 // Default constructor.
93    fgAnalysisManager = this;
94    fgCommonFileName  = "AnalysisResults.root";
95    fTasks      = new TObjArray();
96    fTopTasks   = new TObjArray();
97    fZombies    = new TObjArray();
98    fContainers = new TObjArray();
99    fInputs     = new TObjArray();
100    fOutputs    = new TObjArray();
101    fParamCont  = new TObjArray();
102    SetEventLoop(kTRUE);
103    TObject::SetObjectStat(kFALSE);
104 }
105
106 //______________________________________________________________________________
107 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
108                    :TNamed(other),
109                     fTree(NULL),
110                     fInputEventHandler(NULL),
111                     fOutputEventHandler(NULL),
112                     fMCtruthEventHandler(NULL),
113                     fEventPool(NULL),
114                     fCurrentEntry(-1),
115                     fNSysInfo(0),
116                     fMode(other.fMode),
117                     fInitOK(other.fInitOK),
118                     fIsRemote(other.fIsRemote),
119                     fDebug(other.fDebug),
120                     fSpecialOutputLocation(""), 
121                     fTasks(NULL),
122                     fTopTasks(NULL),
123                     fZombies(NULL),
124                     fContainers(NULL),
125                     fInputs(NULL),
126                     fOutputs(NULL),
127                     fParamCont(NULL),
128                     fCommonInput(NULL),
129                     fCommonOutput(NULL),
130                     fSelector(NULL),
131                     fGridHandler(NULL),
132                     fExtraFiles(),
133                     fAutoBranchHandling(other.fAutoBranchHandling), 
134                     fTable(),
135                     fRunFromPath(0),
136                     fNcalls(other.fNcalls),
137                     fStatisticsMsg(other.fStatisticsMsg),
138                     fRequestedBranches(other.fRequestedBranches)
139 {
140 // Copy constructor.
141    fTasks      = new TObjArray(*other.fTasks);
142    fTopTasks   = new TObjArray(*other.fTopTasks);
143    fZombies    = new TObjArray(*other.fZombies);
144    fContainers = new TObjArray(*other.fContainers);
145    fInputs     = new TObjArray(*other.fInputs);
146    fOutputs    = new TObjArray(*other.fOutputs);
147    fParamCont  = new TObjArray(*other.fParamCont);
148    fgCommonFileName  = "AnalysisResults.root";
149    fgAnalysisManager = this;
150    TObject::SetObjectStat(kFALSE);
151 }
152    
153 //______________________________________________________________________________
154 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
155 {
156 // Assignment
157    if (&other != this) {
158       TNamed::operator=(other);
159       fInputEventHandler   = other.fInputEventHandler;
160       fOutputEventHandler  = other.fOutputEventHandler;
161       fMCtruthEventHandler = other.fMCtruthEventHandler;
162       fEventPool           = other.fEventPool;
163       fTree       = NULL;
164       fCurrentEntry = -1;
165       fNSysInfo   = other.fNSysInfo;
166       fMode       = other.fMode;
167       fInitOK     = other.fInitOK;
168       fIsRemote   = other.fIsRemote;
169       fDebug      = other.fDebug;
170       fTasks      = new TObjArray(*other.fTasks);
171       fTopTasks   = new TObjArray(*other.fTopTasks);
172       fZombies    = new TObjArray(*other.fZombies);
173       fContainers = new TObjArray(*other.fContainers);
174       fInputs     = new TObjArray(*other.fInputs);
175       fOutputs    = new TObjArray(*other.fOutputs);
176       fParamCont  = new TObjArray(*other.fParamCont);
177       fCommonInput = NULL;
178       fCommonOutput = NULL;
179       fSelector   = NULL;
180       fGridHandler = NULL;
181       fExtraFiles = other.fExtraFiles;
182       fgCommonFileName = "AnalysisResults.root";
183       fgAnalysisManager = this;
184       fAutoBranchHandling = other.fAutoBranchHandling;
185       fTable.Clear("nodelete");
186       fRunFromPath = other.fRunFromPath;
187       fNcalls     = other. fNcalls;
188       fStatisticsMsg = other.fStatisticsMsg;
189       fRequestedBranches = other.fRequestedBranches;
190    }
191    return *this;
192 }
193
194 //______________________________________________________________________________
195 AliAnalysisManager::~AliAnalysisManager()
196 {
197 // Destructor.
198    if (fTasks) {fTasks->Delete(); delete fTasks;}
199    if (fTopTasks) delete fTopTasks;
200    if (fZombies) delete fZombies;
201    if (fContainers) {fContainers->Delete(); delete fContainers;}
202    if (fInputs) delete fInputs;
203    if (fOutputs) delete fOutputs;
204    if (fParamCont) delete fParamCont;
205    if (fGridHandler) delete fGridHandler;
206    if (fInputEventHandler) delete fInputEventHandler;
207    if (fOutputEventHandler) delete fOutputEventHandler;
208    if (fMCtruthEventHandler) delete fMCtruthEventHandler;
209    if (fEventPool) delete fEventPool;
210    if (fgAnalysisManager==this) fgAnalysisManager = NULL;
211    TObject::SetObjectStat(kTRUE);
212 }
213
214 //______________________________________________________________________________
215 Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall)
216 {
217 // Read one entry of the tree or a whole branch.
218    fCurrentEntry = entry;
219    if (!fAutoBranchHandling)
220      return entry;
221    return fTree ? fTree->GetTree()->GetEntry(entry, getall) : 0;
222 }
223
224 //______________________________________________________________________________
225 Int_t AliAnalysisManager::GetRunFromAlienPath(const char *path)
226 {
227 // Attempt to extract run number from input data path. Works only for paths to
228 // alice data in alien.
229 //    sim:  /alice/sim/<production>/run_no/...
230 //    data: /alice/data/year/period/000run_no/... (ESD or AOD)
231    TString s(path);
232    TString srun;
233    Int_t run = 0;
234    Int_t index = s.Index("/alice/sim");
235    if (index >= 0) {
236       for (Int_t i=0; i<3; i++) {
237          index = s.Index("/", index+1);
238          if (index<0) return 0;
239       }
240       srun = s(index+1,6);
241       run = atoi(srun);
242    }
243    index = s.Index("/alice/data");
244    if (index >= 0) {
245       for (Int_t i=0; i<4; i++) {
246          index = s.Index("/", index+1);
247          if (index<0) return 0;
248       }
249       srun = s(index+1,9);
250       run = atoi(srun);
251    }
252    return run;
253 }   
254
255 //______________________________________________________________________________
256 Bool_t AliAnalysisManager::Init(TTree *tree)
257 {
258   // The Init() function is called when the selector needs to initialize
259   // a new tree or chain. Typically here the branch addresses of the tree
260   // will be set. It is normaly not necessary to make changes to the
261   // generated code, but the routine can be extended by the user if needed.
262   // Init() will be called many times when running with PROOF.
263    Bool_t init = kFALSE;
264    if (!tree) return kFALSE; // Should not happen - protected in selector caller
265    if (fDebug > 1) {
266       printf("->AliAnalysisManager::Init(%s)\n", tree->GetName());
267    }
268    // Call InitTree of EventHandler
269    if (fOutputEventHandler) {
270       if (fMode == kProofAnalysis) {
271          init = fOutputEventHandler->Init(0x0, "proof");
272       } else {
273          init = fOutputEventHandler->Init(0x0, "local");
274       }
275       if (!init) {
276          Error("Init", "Output event handler failed to initialize");
277          return kFALSE;
278       }         
279    }
280    
281    if (fInputEventHandler) {
282       if (fMode == kProofAnalysis) {
283          init = fInputEventHandler->Init(tree, "proof");
284       } else {
285          init = fInputEventHandler->Init(tree, "local");
286       }
287       if (!init) {
288          Error("Init", "Input event handler failed to initialize tree"); 
289          return kFALSE;
290       }         
291    } else {
292       // If no input event handler we need to get the tree once
293       // for the chain
294       if(!tree->GetTree()) {
295          Long64_t readEntry = tree->LoadTree(0);
296          if (readEntry == -2) {
297             Error("Init", "Input tree has no entry. Exiting");
298             return kFALSE;
299          }
300       }   
301    }
302
303    if (fMCtruthEventHandler) {
304       if (fMode == kProofAnalysis) {
305          init = fMCtruthEventHandler->Init(0x0, "proof");
306       } else {
307          init = fMCtruthEventHandler->Init(0x0, "local");
308       }
309       if (!init) {
310          Error("Init", "MC event handler failed to initialize"); 
311          return kFALSE;
312       }         
313    }
314
315    if (!fInitOK) InitAnalysis();
316    if (!fInitOK) return kFALSE;
317    fTree = tree;
318    fTable.Rehash(100);
319    AliAnalysisDataContainer *top = fCommonInput;
320    if (!top) top = (AliAnalysisDataContainer*)fInputs->At(0);
321    if (!top) {
322       Error("Init","No top input container !");
323       return kFALSE;
324    }
325    top->SetData(tree);
326    CheckBranches(kFALSE);
327    if (fDebug > 1) {
328       printf("<-AliAnalysisManager::Init(%s)\n", tree->GetName());
329    }
330    return kTRUE;
331 }
332
333 //______________________________________________________________________________
334 void AliAnalysisManager::SlaveBegin(TTree *tree)
335 {
336   // The SlaveBegin() function is called after the Begin() function.
337   // When running with PROOF SlaveBegin() is called on each slave server.
338   // The tree argument is deprecated (on PROOF 0 is passed).
339    if (fDebug > 1) printf("->AliAnalysisManager::SlaveBegin()\n");
340    static Bool_t isCalled = kFALSE;
341    Bool_t init = kFALSE;
342    Bool_t initOK = kTRUE;
343    TString msg;
344    TDirectory *curdir = gDirectory;
345    // Call SlaveBegin only once in case of mixing
346    if (isCalled && fMode==kMixingAnalysis) return;
347    gROOT->cd();
348    // Call Init of EventHandler
349    if (fOutputEventHandler) {
350       if (fMode == kProofAnalysis) {
351          // Merging AOD's in PROOF via TProofOutputFile
352          if (fDebug > 1) printf("   Initializing AOD output file %s...\n", fOutputEventHandler->GetOutputFileName());
353          init = fOutputEventHandler->Init("proof");
354          if (!init) msg = "Failed to initialize output handler on worker";
355       } else {
356          init = fOutputEventHandler->Init("local");
357          if (!init) msg = "Failed to initialize output handler";
358       }
359       initOK &= init;
360       if (!fSelector) Error("SlaveBegin", "Selector not set");
361       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
362    }
363    gROOT->cd();
364    if (fInputEventHandler) {
365       fInputEventHandler->SetInputTree(tree);
366       if (fMode == kProofAnalysis) {
367          init = fInputEventHandler->Init("proof");
368          if (!init) msg = "Failed to initialize input handler on worker";
369       } else {
370          init = fInputEventHandler->Init("local");
371          if (!init) msg = "Failed to initialize input handler";
372       }
373       initOK &= init;
374       if (!fSelector) Error("SlaveBegin", "Selector not set");      
375       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
376    }
377    gROOT->cd();
378    if (fMCtruthEventHandler) {
379       if (fMode == kProofAnalysis) {
380          init = fMCtruthEventHandler->Init("proof");
381          if (!init) msg = "Failed to initialize MC handler on worker";
382       } else {
383          init = fMCtruthEventHandler->Init("local");
384          if (!init) msg = "Failed to initialize MC handler";
385       }
386       initOK &= init;
387       if (!fSelector) Error("SlaveBegin", "Selector not set");      
388       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
389    }
390    if (curdir) curdir->cd();
391    isCalled = kTRUE;
392    if (!initOK) return;   
393    TIter next(fTasks);
394    AliAnalysisTask *task;
395    // Call CreateOutputObjects for all tasks
396    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
397    Bool_t dirStatus = TH1::AddDirectoryStatus();
398    Int_t itask = 0;
399    while ((task=(AliAnalysisTask*)next())) {
400       gROOT->cd();
401       // Start with memory as current dir and make sure by default histograms do not get attached to files.
402       TH1::AddDirectory(kFALSE);
403       task->CreateOutputObjects();
404       if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
405       itask++;
406    }
407    TH1::AddDirectory(dirStatus);
408    if (curdir) curdir->cd();
409    if (fDebug > 1) printf("<-AliAnalysisManager::SlaveBegin()\n");
410 }
411
412 //______________________________________________________________________________
413 Bool_t AliAnalysisManager::Notify()
414 {
415    // The Notify() function is called when a new file is opened. This
416    // can be either for a new TTree in a TChain or when when a new TTree
417    // is started when using PROOF. It is normaly not necessary to make changes
418    // to the generated code, but the routine can be extended by the
419    // user if needed. The return value is currently not used.
420    if (!fTree) return kFALSE;
421
422    fTable.Clear("nodelete"); // clearing the hash table may not be needed -> C.L.
423    if (fMode == kProofAnalysis) fIsRemote = kTRUE;
424
425    TFile *curfile = fTree->GetCurrentFile();
426    if (!curfile) {
427       Error("Notify","No current file");
428       return kFALSE;
429    }   
430    
431    if (fDebug > 1) printf("->AliAnalysisManager::Notify() file: %s\n", curfile->GetName());
432    Int_t run = AliAnalysisManager::GetRunFromAlienPath(curfile->GetName());
433    if (run) SetRunFromPath(run);
434    if (fDebug > 1) printf("   ### run found from path: %d\n", run); 
435    TIter next(fTasks);
436    AliAnalysisTask *task;
437         
438    // Call Notify of the event handlers
439    if (fInputEventHandler) {
440        fInputEventHandler->Notify(curfile->GetName());
441    }
442
443    if (fOutputEventHandler) {
444        fOutputEventHandler->Notify(curfile->GetName());
445    }
446
447    if (fMCtruthEventHandler) {
448        fMCtruthEventHandler->Notify(curfile->GetName());
449    }
450
451    // Call Notify for all tasks
452    while ((task=(AliAnalysisTask*)next())) 
453       task->Notify();
454
455    if (fDebug > 1) printf("<-AliAnalysisManager::Notify()\n");
456    return kTRUE;
457 }    
458
459 //______________________________________________________________________________
460 Bool_t AliAnalysisManager::Process(Long64_t entry)
461 {
462   // The Process() function is called for each entry in the tree (or possibly
463   // keyed object in the case of PROOF) to be processed. The entry argument
464   // specifies which entry in the currently loaded tree is to be processed.
465   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
466   // to read either all or the required parts of the data. When processing
467   // keyed objects with PROOF, the object is already loaded and is available
468   // via the fObject pointer.
469   //
470   // This function should contain the "body" of the analysis. It can contain
471   // simple or elaborate selection criteria, run algorithms on the data
472   // of the event and typically fill histograms.
473
474   // WARNING when a selector is used with a TChain, you must use
475   //  the pointer to the current TTree to call GetEntry(entry).
476   //  The entry is always the local entry number in the current tree.
477   //  Assuming that fChain is the pointer to the TChain being processed,
478   //  use fChain->GetTree()->GetEntry(entry).
479    if (fDebug > 1) printf("->AliAnalysisManager::Process(%lld)\n", entry);
480
481    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
482    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
483    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
484    
485    GetEntry(entry);
486
487    if (fInputEventHandler)   fInputEventHandler  ->GetEntry();
488
489    ExecAnalysis();
490    if (fDebug > 1) printf("<-AliAnalysisManager::Process()\n");
491    return kTRUE;
492 }
493
494 //______________________________________________________________________________
495 void AliAnalysisManager::PackOutput(TList *target)
496 {
497   // Pack all output data containers in the output list. Called at SlaveTerminate
498   // stage in PROOF case for each slave.
499    if (fDebug > 1) printf("->AliAnalysisManager::PackOutput()\n");
500    if (!target) {
501       Error("PackOutput", "No target. Exiting.");
502       return;
503    }
504    TDirectory *cdir = gDirectory;
505    gROOT->cd();
506    if (fInputEventHandler)   fInputEventHandler  ->Terminate();
507    if (fOutputEventHandler)  fOutputEventHandler ->Terminate();
508    if (fMCtruthEventHandler) fMCtruthEventHandler->Terminate();
509    gROOT->cd();
510
511    // Call FinishTaskOutput() for each event loop task (not called for 
512    // post-event loop tasks - use Terminate() fo those)
513    TIter nexttask(fTasks);
514    AliAnalysisTask *task;
515    while ((task=(AliAnalysisTask*)nexttask())) {
516       if (!task->IsPostEventLoop()) {
517          if (fDebug > 1) printf("->FinishTaskOutput: task %s\n", task->GetName());
518          task->FinishTaskOutput();
519          gROOT->cd();
520          if (fDebug > 1) printf("<-FinishTaskOutput: task %s\n", task->GetName());
521       }
522    }
523    // Write statistics message on the workers.
524    WriteStatisticsMsg(fNcalls);
525    
526    if (fMode == kProofAnalysis) {
527       TIter next(fOutputs);
528       AliAnalysisDataContainer *output;
529       Bool_t isManagedByHandler = kFALSE;
530       TList filestmp;
531       filestmp.SetOwner();
532       while ((output=(AliAnalysisDataContainer*)next())) {
533          // Do not consider outputs of post event loop tasks
534          isManagedByHandler = kFALSE;
535          if (output->GetProducer() && output->GetProducer()->IsPostEventLoop()) continue;
536          const char *filename = output->GetFileName();
537          if (!(strcmp(filename, "default")) && fOutputEventHandler) {
538             isManagedByHandler = kTRUE;
539             printf("#### Handler output. Extra: %s\n", fExtraFiles.Data());
540             filename = fOutputEventHandler->GetOutputFileName();
541          }
542          // Check if data was posted to this container. If not, issue an error.
543          if (!output->GetData() && !isManagedByHandler) {
544             Error("PackOutput", "No data for output container %s. Forgot to PostData ?", output->GetName());
545             continue;
546          }   
547          if (!output->IsSpecialOutput()) {
548             // Normal outputs
549             if (strlen(filename) && !isManagedByHandler) {
550                // Backup current folder
551                TDirectory *opwd = gDirectory;
552                // File resident outputs. 
553                // Check first if the file exists.
554                TString openoption = "RECREATE";
555                Bool_t firsttime = kTRUE;
556                if (filestmp.FindObject(output->GetFileName())) {
557                   firsttime = kFALSE;
558                } else {   
559                   filestmp.Add(new TNamed(output->GetFileName(),""));
560                }   
561                if (!gSystem->AccessPathName(output->GetFileName()) && !firsttime) openoption = "UPDATE";
562 //               TFile *file = AliAnalysisManager::OpenFile(output, openoption, kTRUE);
563                // Save data to file, then close.
564                if (output->GetData()->InheritsFrom(TCollection::Class())) {
565                   // If data is a collection, we set the name of the collection 
566                   // as the one of the container and we save as a single key.
567                   TCollection *coll = (TCollection*)output->GetData();
568                   coll->SetName(output->GetName());
569 //                  coll->Write(output->GetName(), TObject::kSingleKey);
570                } else {
571                   if (output->GetData()->InheritsFrom(TTree::Class())) {
572                      TFile *file = AliAnalysisManager::OpenFile(output, openoption, kTRUE);
573                      // Save data to file, then close.
574                      TTree *tree = (TTree*)output->GetData();
575                      // Check if tree is in memory
576                      if (tree->GetDirectory()==gROOT) tree->SetDirectory(gDirectory);
577                      tree->AutoSave();
578                      file->Close();
579                   } else {
580 //                     output->GetData()->Write();
581                   }   
582                }      
583                if (fDebug > 1) printf("PackOutput %s: memory merge, file resident output\n", output->GetName());
584 //               if (fDebug > 2) {
585 //                  printf("   file %s listing content:\n", filename);
586 //                  file->ls();
587 //               }   
588                // Clear file list to release object ownership to user.
589 //               file->Clear();
590 //               file->Close();
591                output->SetFile(NULL);
592                // Restore current directory
593                if (opwd) opwd->cd();
594             } else {
595                // Memory-resident outputs   
596                if (fDebug > 1) printf("PackOutput %s: memory merge memory resident output\n", filename);
597             }   
598             AliAnalysisDataWrapper *wrap = 0;
599             if (isManagedByHandler) {
600                wrap = new AliAnalysisDataWrapper(fOutputEventHandler->GetTree());
601                wrap->SetName(output->GetName());
602             }   
603             else                    wrap =output->ExportData();
604             // Output wrappers must NOT delete data after merging - the user owns them
605             wrap->SetDeleteData(kFALSE);
606             target->Add(wrap);
607          } else {
608          // Special outputs. The file must be opened and connected to the container.
609             TDirectory *opwd = gDirectory;
610             TFile *file = output->GetFile();
611             if (!file) {
612                AliAnalysisTask *producer = output->GetProducer();
613                Fatal("PackOutput", 
614                      "File %s for special container %s was NOT opened in %s::CreateOutputObjects !!!",
615                      output->GetFileName(), output->GetName(), producer->ClassName());
616                continue;
617             }   
618             TString outFilename = file->GetName();
619             if (fDebug > 1) printf("PackOutput %s: special output\n", output->GetName());
620             if (isManagedByHandler) {
621                // Terminate IO for files managed by the output handler
622                // file->Write() moved to AOD handler (A.G. 11.01.10)
623 //               if (file) file->Write();
624                if (file && fDebug > 2) {
625                   printf("   handled file %s listing content:\n", file->GetName());
626                   file->ls();
627                }   
628                fOutputEventHandler->TerminateIO();
629             } else {               
630                file->cd();
631                // Release object ownership to users after writing data to file
632                if (output->GetData()->InheritsFrom(TCollection::Class())) {
633                   // If data is a collection, we set the name of the collection 
634                   // as the one of the container and we save as a single key.
635                   TCollection *coll = (TCollection*)output->GetData();
636                   coll->SetName(output->GetName());
637                   coll->Write(output->GetName(), TObject::kSingleKey);
638                } else {
639                   if (output->GetData()->InheritsFrom(TTree::Class())) {
640                      TTree *tree = (TTree*)output->GetData();
641                      tree->SetDirectory(file);
642                      tree->AutoSave();
643                   } else {
644                      output->GetData()->Write();
645                   }   
646                }      
647                if (fDebug > 2) {
648                   printf("   file %s listing content:\n", output->GetFileName());
649                   file->ls();
650                }
651                // Clear file list to release object ownership to user.
652 //               file->Clear();
653                file->Close();
654                output->SetFile(NULL);
655             }
656             // Restore current directory
657             if (opwd) opwd->cd();
658             // Check if a special output location was provided or the output files have to be merged
659             if (strlen(fSpecialOutputLocation.Data())) {
660                TString remote = fSpecialOutputLocation;
661                remote += "/";
662                Int_t gid = gROOT->ProcessLine("gProofServ->GetGroupId();");
663                if (remote.BeginsWith("alien:")) {
664                   gROOT->ProcessLine("TGrid::Connect(\"alien:\", gProofServ->GetUser());");
665                   remote += outFilename;
666                   remote.ReplaceAll(".root", Form("_%d.root", gid));
667                } else {   
668                   remote += Form("%s_%d_", gSystem->HostName(), gid);
669                   remote += outFilename;
670                }   
671                if (fDebug > 1) 
672                   Info("PackOutput", "Output file for container %s to be copied \n   at: %s. No merging.",
673                        output->GetName(), remote.Data());
674                TFile::Cp ( outFilename.Data(), remote.Data() );
675                // Copy extra outputs
676                if (fExtraFiles.Length() && isManagedByHandler) {
677                   TObjArray *arr = fExtraFiles.Tokenize(" ");
678                   TObjString *os;
679                   TIter nextfilename(arr);
680                   while ((os=(TObjString*)nextfilename())) {
681                      outFilename = os->GetString();
682                      remote = fSpecialOutputLocation;
683                      remote += "/";
684                      if (remote.BeginsWith("alien://")) {
685                         remote += outFilename;
686                         remote.ReplaceAll(".root", Form("_%d.root", gid));
687                      } else {   
688                         remote += Form("%s_%d_", gSystem->HostName(), gid);
689                         remote += outFilename;
690                      }   
691                      if (fDebug > 1) 
692                         Info("PackOutput", "Extra AOD file %s to be copied \n   at: %s. No merging.",
693                              outFilename.Data(), remote.Data());
694                      TFile::Cp ( outFilename.Data(), remote.Data() );
695                   }   
696                   delete arr;
697                }   
698             } else {
699             // No special location specified-> use TProofOutputFile as merging utility
700             // The file at this output slot must be opened in CreateOutputObjects
701                if (fDebug > 1) printf("   File for container %s to be merged via file merger...\n", output->GetName());
702             }
703          }      
704       }
705    } 
706    cdir->cd();
707    if (fDebug > 1) printf("<-AliAnalysisManager::PackOutput: output list contains %d containers\n", target->GetSize());
708 }
709
710 //______________________________________________________________________________
711 void AliAnalysisManager::ImportWrappers(TList *source)
712 {
713 // Import data in output containers from wrappers coming in source.
714    if (fDebug > 1) printf("->AliAnalysisManager::ImportWrappers()\n");
715    TIter next(fOutputs);
716    AliAnalysisDataContainer *cont;
717    AliAnalysisDataWrapper   *wrap;
718    Int_t icont = 0;
719    Bool_t inGrid = (fMode == kGridAnalysis)?kTRUE:kFALSE;
720    TDirectory *cdir = gDirectory;
721    while ((cont=(AliAnalysisDataContainer*)next())) {
722       wrap = 0;
723       if (cont->GetProducer() && cont->GetProducer()->IsPostEventLoop() && !inGrid) continue;
724       if (cont->IsRegisterDataset()) continue;
725       const char *filename = cont->GetFileName();
726       Bool_t isManagedByHandler = kFALSE;
727       if (!(strcmp(filename, "default")) && fOutputEventHandler) {
728          isManagedByHandler = kTRUE;
729          filename = fOutputEventHandler->GetOutputFileName();
730       }
731       if (cont->IsSpecialOutput() || inGrid) {
732          if (strlen(fSpecialOutputLocation.Data())) continue;
733          // Copy merged file from PROOF scratch space. 
734          // In case of grid the files are already in the current directory.
735          if (!inGrid) {
736             if (isManagedByHandler && fExtraFiles.Length()) {
737                // Copy extra registered dAOD files.
738                TObjArray *arr = fExtraFiles.Tokenize(" ");
739                TObjString *os;
740                TIter nextfilename(arr);
741                while ((os=(TObjString*)nextfilename())) GetFileFromWrapper(os->GetString(), source);
742                delete arr;
743             }
744             if (!GetFileFromWrapper(filename, source)) continue;
745          }   
746          // Normally we should connect data from the copied file to the
747          // corresponding output container, but it is not obvious how to do this
748          // automatically if several objects in file...
749          TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
750          if (!f) f = TFile::Open(filename, "READ");
751          if (!f) {
752             Error("ImportWrappers", "Cannot open file %s in read-only mode", filename);
753             continue;
754          }   
755          TObject *obj = 0;
756          // Cd to the directory pointed by the container
757          TString folder = cont->GetFolderName();
758          if (!folder.IsNull()) f->cd(folder);
759          // Try to fetch first an object having the container name.
760          obj = gDirectory->Get(cont->GetName());
761          if (!obj) {
762             Warning("ImportWrappers", "Could not import object of type:%s for container %s in file %s:%s.\n Object will not be available in Terminate(). Try if possible to name the output object as the container (%s) or to embed it in a TList", 
763                     cont->GetType()->GetName(), cont->GetName(), filename, cont->GetFolderName(), cont->GetName());
764             continue;
765          }  
766          wrap = new AliAnalysisDataWrapper(obj);
767          wrap->SetDeleteData(kFALSE);
768       }   
769       if (!wrap) wrap = (AliAnalysisDataWrapper*)source->FindObject(cont->GetName());
770       if (!wrap) {
771          Error("ImportWrappers","Container %s not found in analysis output !", cont->GetName());
772          continue;
773       }
774       icont++;
775       if (fDebug > 1) {
776          printf("   Importing data for container %s\n", cont->GetName());
777          if (strlen(filename)) printf("    -> file %s\n", filename);
778          else printf("\n");
779       }   
780       cont->ImportData(wrap);
781    }
782    if (cdir) cdir->cd();
783    if (fDebug > 1) printf("<-AliAnalysisManager::ImportWrappers(): %d containers imported\n", icont);
784 }
785
786 //______________________________________________________________________________
787 void AliAnalysisManager::UnpackOutput(TList *source)
788 {
789   // Called by AliAnalysisSelector::Terminate only on the client.
790    if (fDebug > 1) printf("->AliAnalysisManager::UnpackOutput()\n");
791    if (!source) {
792       Error("UnpackOutput", "No target. Exiting.");
793       return;
794    }
795    if (fDebug > 1) printf("   Source list contains %d containers\n", source->GetSize());
796
797    if (fMode == kProofAnalysis) ImportWrappers(source);
798
799    TIter next(fOutputs);
800    AliAnalysisDataContainer *output;
801    while ((output=(AliAnalysisDataContainer*)next())) {
802       if (!output->GetData()) continue;
803       // Check if there are client tasks that run post event loop
804       if (output->HasConsumers()) {
805          // Disable event loop semaphore
806          output->SetPostEventLoop(kTRUE);
807          TObjArray *list = output->GetConsumers();
808          Int_t ncons = list->GetEntriesFast();
809          for (Int_t i=0; i<ncons; i++) {
810             AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
811             task->CheckNotify(kTRUE);
812             // If task is active, execute it
813             if (task->IsPostEventLoop() && task->IsActive()) {
814                if (fDebug > 1) printf("== Executing post event loop task %s\n", task->GetName());
815                task->ExecuteTask();
816             }   
817          }
818       }   
819    }
820    if (fDebug > 1) printf("<-AliAnalysisManager::UnpackOutput()\n");
821 }
822
823 //______________________________________________________________________________
824 void AliAnalysisManager::Terminate()
825 {
826   // The Terminate() function is the last function to be called during
827   // a query. It always runs on the client, it can be used to present
828   // the results graphically.
829    if (fDebug > 1) printf("->AliAnalysisManager::Terminate()\n");
830    TDirectory *cdir = gDirectory;
831    gROOT->cd();
832    AliAnalysisTask *task;
833    AliAnalysisDataContainer *output;
834    TIter next(fTasks);
835    TStopwatch timer;
836    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
837    // Call Terminate() for tasks
838    Int_t itask = 0;
839    while (!IsSkipTerminate() && (task=(AliAnalysisTask*)next())) {
840       // Save all the canvases produced by the Terminate
841       TString pictname = Form("%s_%s", task->GetName(), task->ClassName());
842       task->Terminate();
843       gROOT->cd();
844       if (getsysInfo) 
845          AliSysInfo::AddStamp(Form("%s_TERMINATE",task->ClassName()),0, itask, 2);
846       itask++;   
847       if (TObject::TestBit(kSaveCanvases)) {
848          if (!gROOT->IsBatch()) {
849             if (fDebug>1) printf("Waiting 5 sec for %s::Terminate() to finish drawing ...\n", task->ClassName());
850             timer.Start();
851             while (timer.CpuTime()<5) {
852                timer.Continue();
853                gSystem->ProcessEvents();
854             }
855          }
856          Int_t iend = gROOT->GetListOfCanvases()->GetEntries();
857          if (iend==0) continue;
858          TCanvas *canvas;
859          for (Int_t ipict=0; ipict<iend; ipict++) {
860             canvas = (TCanvas*)gROOT->GetListOfCanvases()->At(ipict);
861             if (!canvas) continue;         
862             canvas->SaveAs(Form("%s_%02d.gif", pictname.Data(),ipict));
863          } 
864          gROOT->GetListOfCanvases()->Delete(); 
865       }
866    }   
867    //
868    if (fInputEventHandler)   fInputEventHandler  ->TerminateIO();
869    if (fOutputEventHandler)  fOutputEventHandler ->TerminateIO();
870    if (fMCtruthEventHandler) fMCtruthEventHandler->TerminateIO();
871    gROOT->cd();
872    TObjArray *allOutputs = new TObjArray();
873    Int_t icont;
874    for (icont=0; icont<fOutputs->GetEntriesFast(); icont++) allOutputs->Add(fOutputs->At(icont));
875    if (!IsSkipTerminate())
876       for (icont=0; icont<fParamCont->GetEntriesFast(); icont++) allOutputs->Add(fParamCont->At(icont));
877    TIter next1(allOutputs);
878    TString handlerFile = "";
879    TString extraOutputs = "";
880    if (fOutputEventHandler) {
881       handlerFile = fOutputEventHandler->GetOutputFileName();
882       extraOutputs = fOutputEventHandler->GetExtraOutputs();
883    }
884    icont = 0;
885    TList filestmp;
886    while ((output=(AliAnalysisDataContainer*)next1())) {
887       // Special outputs or grid files have the files already closed and written.
888       icont++;
889       if (fMode == kGridAnalysis && icont<=fOutputs->GetEntriesFast()) continue;
890       if (fMode == kProofAnalysis) {
891         if (output->IsSpecialOutput() || output->IsRegisterDataset()) continue;
892       }  
893       const char *filename = output->GetFileName();
894       TString openoption = "RECREATE";
895       if (!(strcmp(filename, "default"))) continue;
896       if (!strlen(filename)) continue;
897       if (!output->GetData()) continue;
898       TDirectory *opwd = gDirectory;
899       TFile *file = output->GetFile();
900       if (!file) file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
901       if (!file) {
902               //if (handlerFile == filename && !gSystem->AccessPathName(filename)) openoption = "UPDATE";
903          Bool_t firsttime = kTRUE;
904          if (filestmp.FindObject(filename) || extraOutputs.Contains(filename)) {
905             firsttime = kFALSE;
906          } else {   
907             filestmp.Add(new TNamed(filename,""));
908          }   
909          if (!gSystem->AccessPathName(filename) && !firsttime) openoption = "UPDATE";
910               if (fDebug>1) printf("Opening file: %s  option=%s\n",filename, openoption.Data());
911          file = new TFile(filename, openoption);
912       } else {
913          if (fDebug>1) printf("File <%s> already opened with option: <%s> \n", filename, file->GetOption());
914          openoption = file->GetOption();
915          if (openoption == "READ") {
916             if (fDebug>1) printf("...reopening in UPDATE mode\n");
917             file->ReOpen("UPDATE");            
918          }
919       }   
920       if (file->IsZombie()) {
921          Error("Terminate", "Cannot open output file %s", filename);
922          continue;
923       }   
924       output->SetFile(file);
925       file->cd();
926       // Check for a folder request
927       TString dir = output->GetFolderName();
928       if (!dir.IsNull()) {
929          if (!file->GetDirectory(dir)) file->mkdir(dir);
930          file->cd(dir);
931       }  
932       if (fDebug > 1) printf("...writing container %s to file %s:%s\n", output->GetName(), file->GetName(), output->GetFolderName());
933       if (output->GetData()->InheritsFrom(TCollection::Class())) {
934       // If data is a collection, we set the name of the collection 
935       // as the one of the container and we save as a single key.
936          TCollection *coll = (TCollection*)output->GetData();
937          coll->SetName(output->GetName());
938          coll->Write(output->GetName(), TObject::kSingleKey);
939       } else {
940          if (output->GetData()->InheritsFrom(TTree::Class())) {
941             TTree *tree = (TTree*)output->GetData();
942             tree->SetDirectory(gDirectory);
943             tree->AutoSave();
944          } else {
945             output->GetData()->Write();
946          }   
947       }      
948       if (opwd) opwd->cd();
949    }
950    gROOT->cd();
951    next1.Reset();
952    while ((output=(AliAnalysisDataContainer*)next1())) {
953       // Close all files at output
954       TDirectory *opwd = gDirectory;
955       if (output->GetFile()) {
956          // Clear file list to release object ownership to user.
957 //         output->GetFile()->Clear();
958          output->GetFile()->Close();
959          output->SetFile(NULL);
960          // Copy merged outputs in alien if requested
961          if (fSpecialOutputLocation.Length() && 
962              fSpecialOutputLocation.BeginsWith("alien://")) {
963             Info("Terminate", "Copy file %s to %s", output->GetFile()->GetName(),fSpecialOutputLocation.Data()); 
964             TFile::Cp(output->GetFile()->GetName(), 
965                       Form("%s/%s", fSpecialOutputLocation.Data(), output->GetFile()->GetName()));
966          }             
967       }   
968       if (opwd) opwd->cd();
969    }   
970    delete allOutputs;
971    //Write statistics information on the client
972    WriteStatisticsMsg(fNcalls);
973    if (getsysInfo) {
974       TDirectory *crtdir = gDirectory;
975       TFile f("syswatch.root", "RECREATE");
976       TH1 *hist;
977       TString cut;
978       if (!f.IsZombie()) {
979          TTree *tree = AliSysInfo::MakeTree("syswatch.log");
980          tree->SetName("syswatch");
981          tree->SetMarkerStyle(kCircle);
982          tree->SetMarkerColor(kBlue);
983          tree->SetMarkerSize(0.5);
984          if (!gROOT->IsBatch()) {
985             tree->SetAlias("event", "id0");
986             tree->SetAlias("task",  "id1");
987             tree->SetAlias("stage", "id2");
988             // Already defined aliases
989             // tree->SetAlias("deltaT","stampSec-stampOldSec");
990             // tree->SetAlias("T","stampSec-first");
991             // tree->SetAlias("deltaVM","(pI.fMemVirtual-pIOld.fMemVirtual)");
992             // tree->SetAlias("VM","pI.fMemVirtual");
993             TCanvas *canvas = new TCanvas("SysInfo","SysInfo",10,10,1200,800);
994             Int_t npads = 1 /*COO plot for all tasks*/ +
995                           fTopTasks->GetEntries() /*Exec plot per task*/ +
996                           1 /*Terminate plot for all tasks*/ +
997                           1; /*vm plot*/
998                           
999             Int_t iopt = (Int_t)TMath::Sqrt((Double_t)npads);
1000             if (npads<iopt*(iopt+1))
1001                canvas->Divide(iopt, iopt+1, 0.01, 0.01);
1002             else
1003                canvas->Divide(iopt+1, iopt+1, 0.01, 0.01);
1004             Int_t ipad = 1;
1005             // draw the plot of deltaVM for Exec for each task
1006             for (itask=0; itask<fTopTasks->GetEntriesFast(); itask++) {
1007                task = (AliAnalysisTask*)fTopTasks->At(itask);
1008                canvas->cd(ipad++);
1009                cut = Form("task==%d && stage==1", itask);
1010                tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
1011                hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
1012                if (hist) {
1013                   hist->SetTitle(Form("%s: Exec dVM[kB]/event", task->GetName()));
1014                   hist->GetYaxis()->SetTitle("deltaVM [kB]");
1015                }   
1016             }
1017             // Draw the plot of deltaVM for CreateOutputObjects for all tasks
1018             canvas->cd(ipad++);
1019             tree->SetMarkerStyle(kFullTriangleUp);
1020             tree->SetMarkerColor(kRed);
1021             tree->SetMarkerSize(0.8);
1022             cut = "task>=0 && task<1000 && stage==0";
1023             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1024             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");            
1025             if (hist) {
1026                hist->SetTitle("Memory in CreateOutputObjects()");
1027                hist->GetYaxis()->SetTitle("deltaVM [kB]");
1028                hist->GetXaxis()->SetTitle("task");
1029             }   
1030             // draw the plot of deltaVM for Terminate for all tasks
1031             canvas->cd(ipad++);
1032             tree->SetMarkerStyle(kOpenSquare);
1033             tree->SetMarkerColor(kMagenta);
1034             cut = "task>=0 && task<1000 && stage==2";
1035             tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1036             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1037             if (hist) {
1038                hist->SetTitle("Memory in Terminate()");
1039                hist->GetYaxis()->SetTitle("deltaVM [kB]");
1040                hist->GetXaxis()->SetTitle("task");
1041             }   
1042             // Full VM profile
1043             canvas->cd(ipad++);
1044             tree->SetMarkerStyle(kFullCircle);
1045             tree->SetMarkerColor(kGreen);
1046             cut = Form("task==%d && stage==1",fTopTasks->GetEntriesFast()-1);            
1047             tree->Draw("VM:event",cut,"", 1234567890, 0);
1048             hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1049             if (hist) {
1050                hist->SetTitle("Virtual memory");
1051                hist->GetYaxis()->SetTitle("VM [kB]");
1052             }
1053             canvas->Modified();   
1054          }   
1055          tree->SetMarkerStyle(kCircle);
1056          tree->SetMarkerColor(kBlue);
1057          tree->SetMarkerSize(0.5);
1058          tree->Write();
1059          f.Close();
1060          delete tree;
1061       }
1062       if (crtdir) crtdir->cd();
1063    }
1064    // Validate the output files
1065    if (ValidateOutputFiles()) {
1066       ofstream out;
1067       out.open("outputs_valid", ios::out);
1068       out.close();
1069    }
1070    cdir->cd();      
1071    if (fDebug > 1) printf("<-AliAnalysisManager::Terminate()\n");
1072 }
1073 //______________________________________________________________________________
1074 void AliAnalysisManager::ProfileTask(Int_t itop, const char *option) const
1075 {
1076 // Profiles the task having the itop index in the list of top (first level) tasks.
1077    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->At(itop);
1078    if (!task) {
1079       Error("ProfileTask", "There are only %d top tasks in the manager", fTopTasks->GetEntries());
1080       return;
1081    }
1082    ProfileTask(task->GetName(), option);
1083 }      
1084
1085 //______________________________________________________________________________
1086 void AliAnalysisManager::ProfileTask(const char *name, const char */*option*/) const
1087 {
1088 // Profile a managed task after the execution of the analysis in case NSysInfo
1089 // was used.
1090    if (gSystem->AccessPathName("syswatch.root")) {
1091       Error("ProfileTask", "No file syswatch.root found in the current directory");
1092       return;
1093    }
1094    if (gROOT->IsBatch()) return;
1095    AliAnalysisTask *task = (AliAnalysisTask*)fTopTasks->FindObject(name);
1096    if (!task) {
1097       Error("ProfileTask", "No top task named %s known by the manager.", name);
1098       return;
1099    }
1100    Int_t itop = fTopTasks->IndexOf(task);
1101    Int_t itask = fTasks->IndexOf(task);
1102    // Create canvas with 2 pads: first draw COO + Terminate, second Exec
1103    TDirectory *cdir = gDirectory;
1104    TFile f("syswatch.root");
1105    TTree *tree = (TTree*)f.Get("syswatch");
1106    if (!tree) {
1107       Error("ProfileTask", "No tree named <syswatch> found in file syswatch.root");
1108       return;
1109    }   
1110    if (fDebug > 1) printf("=== Profiling task %s (class %s)\n", name, task->ClassName());
1111    TCanvas *canvas = new TCanvas(Form("profile_%d",itop),Form("Profile of task %s (class %s)",name,task->ClassName()),10,10,800,600);
1112    canvas->Divide(2, 2, 0.01, 0.01);
1113    Int_t ipad = 1;
1114    TString cut;
1115    TH1 *hist;
1116    // VM profile for COO and Terminate methods
1117    canvas->cd(ipad++);
1118    cut = Form("task==%d && (stage==0 || stage==2)",itask);
1119    tree->Draw("deltaVM:sname",cut,"", 1234567890, 0);
1120    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1121    if (hist) {
1122       hist->SetTitle("Alocated VM[kB] for COO and Terminate");
1123       hist->GetYaxis()->SetTitle("deltaVM [kB]");
1124       hist->GetXaxis()->SetTitle("method");
1125    }   
1126    // CPU profile per event
1127    canvas->cd(ipad++);
1128    cut = Form("task==%d && stage==1",itop);
1129    tree->Draw("deltaT:event",cut,"", 1234567890, 0);
1130    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1131    if (hist) {
1132       hist->SetTitle("Execution time per event");
1133       hist->GetYaxis()->SetTitle("CPU/event [s]");
1134    }   
1135    // VM profile for Exec
1136    canvas->cd(ipad++);
1137    cut = Form("task==%d && stage==1",itop);
1138    tree->Draw("deltaVM:event",cut,"", 1234567890, 0);
1139    hist = (TH1*)gPad->GetListOfPrimitives()->FindObject("htemp");
1140    if (hist) {
1141       hist->SetTitle("Alocated VM[kB] per event");
1142       hist->GetYaxis()->SetTitle("deltaVM [kB]");
1143    }   
1144    canvas->Modified();
1145    delete tree;
1146    f.Close();
1147    if (cdir) cdir->cd();
1148 }     
1149
1150 //______________________________________________________________________________
1151 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
1152 {
1153 // Adds a user task to the global list of tasks.
1154    if (fTasks->FindObject(task)) {
1155       Warning("AddTask", "Task %s: the same object already added to the analysis manager. Not adding.", task->GetName());
1156       return;
1157    }   
1158    task->SetActive(kFALSE);
1159    fTasks->Add(task);
1160 }  
1161
1162 //______________________________________________________________________________
1163 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
1164 {
1165 // Retreive task by name.
1166    if (!fTasks) return NULL;
1167    return (AliAnalysisTask*)fTasks->FindObject(name);
1168 }
1169
1170 //______________________________________________________________________________
1171 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
1172                                 TClass *datatype, EAliAnalysisContType type, const char *filename)
1173 {
1174 // Create a data container of a certain type. Types can be:
1175 //   kExchangeContainer  = 0, used to exchange data between tasks
1176 //   kInputContainer   = 1, used to store input data
1177 //   kOutputContainer  = 2, used for writing result to a file
1178 // filename: composed by file#folder (e.g. results.root#INCLUSIVE) - will write
1179 // the output object to a folder inside the output file
1180    if (fContainers->FindObject(name)) {
1181       Error("CreateContainer","A container named %s already defined !",name);
1182       return NULL;
1183    }   
1184    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
1185    fContainers->Add(cont);
1186    switch (type) {
1187       case kInputContainer:
1188          fInputs->Add(cont);
1189          break;
1190       case kOutputContainer:
1191          fOutputs->Add(cont);
1192          if (filename && strlen(filename)) {
1193             cont->SetFileName(filename);
1194             cont->SetDataOwned(kFALSE);  // data owned by the file
1195          }   
1196          break;
1197       case kParamContainer:
1198          fParamCont->Add(cont);
1199          if (filename && strlen(filename)) {
1200             cont->SetFileName(filename);
1201             cont->SetDataOwned(kFALSE);  // data owned by the file
1202          }   
1203          break;
1204       case kExchangeContainer:
1205          break;   
1206    }
1207    return cont;
1208 }
1209          
1210 //______________________________________________________________________________
1211 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
1212                                         AliAnalysisDataContainer *cont)
1213 {
1214 // Connect input of an existing task to a data container.
1215    if (!task) {
1216       Error("ConnectInput", "Task pointer is NULL");
1217       return kFALSE;
1218    }   
1219    if (!fTasks->FindObject(task)) {
1220       AddTask(task);
1221       Info("ConnectInput", "Task %s was not registered. Now owned by analysis manager", task->GetName());
1222    } 
1223    Bool_t connected = task->ConnectInput(islot, cont);
1224    return connected;
1225 }   
1226
1227 //______________________________________________________________________________
1228 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
1229                                         AliAnalysisDataContainer *cont)
1230 {
1231 // Connect output of an existing task to a data container.
1232    if (!task) {
1233       Error("ConnectOutput", "Task pointer is NULL");
1234       return kFALSE;
1235    }   
1236    if (!fTasks->FindObject(task)) {
1237       AddTask(task);
1238       Warning("ConnectOutput", "Task %s not registered. Now owned by analysis manager", task->GetName());
1239    } 
1240    Bool_t connected = task->ConnectOutput(islot, cont);
1241    return connected;
1242 }   
1243                                
1244 //______________________________________________________________________________
1245 void AliAnalysisManager::CleanContainers()
1246 {
1247 // Clean data from all containers that have already finished all client tasks.
1248    TIter next(fContainers);
1249    AliAnalysisDataContainer *cont;
1250    while ((cont=(AliAnalysisDataContainer *)next())) {
1251       if (cont->IsOwnedData() && 
1252           cont->IsDataReady() && 
1253           cont->ClientsExecuted()) cont->DeleteData();
1254    }
1255 }
1256
1257 //______________________________________________________________________________
1258 Bool_t AliAnalysisManager::InitAnalysis()
1259 {
1260 // Initialization of analysis chain of tasks. Should be called after all tasks
1261 // and data containers are properly connected
1262    // Reset flag and remove valid_outputs file if exists
1263    fInitOK = kFALSE;
1264    if (!gSystem->AccessPathName("outputs_valid"))
1265       gSystem->Unlink("outputs_valid");
1266    // Check for top tasks (depending only on input data containers)
1267    if (!fTasks->First()) {
1268       Error("InitAnalysis", "Analysis has no tasks !");
1269       return kFALSE;
1270    }   
1271    TIter next(fTasks);
1272    AliAnalysisTask *task;
1273    AliAnalysisDataContainer *cont;
1274    Int_t ntop = 0;
1275    Int_t nzombies = 0;
1276    Bool_t iszombie = kFALSE;
1277    Bool_t istop = kTRUE;
1278    Int_t i;
1279    while ((task=(AliAnalysisTask*)next())) {
1280       istop = kTRUE;
1281       iszombie = kFALSE;
1282       Int_t ninputs = task->GetNinputs();
1283       for (i=0; i<ninputs; i++) {
1284          cont = task->GetInputSlot(i)->GetContainer();
1285          if (!cont) {
1286             if (!iszombie) {
1287                task->SetZombie();
1288                fZombies->Add(task);
1289                nzombies++;
1290                iszombie = kTRUE;
1291             }   
1292             Error("InitAnalysis", "Input slot %d of task %s has no container connected ! Declared zombie...", 
1293                   i, task->GetName()); 
1294          }
1295          if (iszombie) continue;
1296          // Check if cont is an input container
1297          if (istop && !fInputs->FindObject(cont)) istop=kFALSE;
1298          // Connect to parent task
1299       }
1300       if (istop) {
1301          ntop++;
1302          fTopTasks->Add(task);
1303       }
1304    }
1305    if (!ntop) {
1306       Error("InitAnalysis", "No top task defined. At least one task should be connected only to input containers");
1307       return kFALSE;
1308    }                        
1309    // Check now if there are orphan tasks
1310    for (i=0; i<ntop; i++) {
1311       task = (AliAnalysisTask*)fTopTasks->At(i);
1312       task->SetUsed();
1313    }
1314    Int_t norphans = 0;
1315    next.Reset();
1316    while ((task=(AliAnalysisTask*)next())) {
1317       if (!task->IsUsed()) {
1318          norphans++;
1319          Warning("InitAnalysis", "Task %s is orphan", task->GetName());
1320       }   
1321    }          
1322    // Check the task hierarchy (no parent task should depend on data provided
1323    // by a daughter task)
1324    for (i=0; i<ntop; i++) {
1325       task = (AliAnalysisTask*)fTopTasks->At(i);
1326       if (task->CheckCircularDeps()) {
1327          Error("InitAnalysis", "Found illegal circular dependencies between following tasks:");
1328          PrintStatus("dep");
1329          return kFALSE;
1330       }   
1331    }
1332    // Check that all containers feeding post-event loop tasks are in the outputs list
1333    TIter nextcont(fContainers); // loop over all containers
1334    while ((cont=(AliAnalysisDataContainer*)nextcont())) {
1335       if (!cont->IsPostEventLoop() && !fOutputs->FindObject(cont)) {
1336          if (cont->HasConsumers()) {
1337          // Check if one of the consumers is post event loop
1338             TIter nextconsumer(cont->GetConsumers());
1339             while ((task=(AliAnalysisTask*)nextconsumer())) {
1340                if (task->IsPostEventLoop()) {
1341                   fOutputs->Add(cont);
1342                   break;
1343                }
1344             }
1345          }
1346       }
1347    }   
1348    // Check if all special output containers have a file name provided
1349    TIter nextout(fOutputs);
1350    while ((cont=(AliAnalysisDataContainer*)nextout())) {
1351       if (cont->IsSpecialOutput() && !strlen(cont->GetFileName())) {
1352          Error("InitAnalysis", "Wrong container %s : a file name MUST be provided for special outputs", cont->GetName());
1353          return kFALSE;
1354       }
1355    }
1356    // Initialize requested branch list if needed
1357    if (!fAutoBranchHandling) {
1358       next.Reset();
1359       while ((task=(AliAnalysisTask*)next())) {
1360          if (!task->HasBranches()) {
1361             Error("InitAnalysis", "Manual branch loading requested but task %s of type %s does not define branches.\nUse: fBranchNames = \"ESD:br1,br2,...,brN AOD:bra1,bra2,...,braM\"",
1362                   task->GetName(), task->ClassName());
1363             return kFALSE;
1364          }
1365          if (!fInputEventHandler || !strlen(fInputEventHandler->GetDataType())) {
1366             Error("InitAnalysis", "Manual branch loading requested but no input handler defined or handler does not define data type.");
1367             return kFALSE;
1368          }
1369          TString taskbranches;
1370          task->GetBranches(fInputEventHandler->GetDataType(), taskbranches);
1371          if (taskbranches.IsNull()) {
1372             Error("InitAnalysis", "Manual branch loading requested but task %s of type %s does not define branches of type %s:",
1373                   task->GetName(), task->ClassName(), fInputEventHandler->GetDataType());
1374             return kFALSE;      
1375          }
1376          AddBranches(taskbranches);
1377       }         
1378    }
1379    fInitOK = kTRUE;
1380    return kTRUE;
1381 }   
1382
1383 //______________________________________________________________________________
1384 void AliAnalysisManager::AddBranches(const char *branches)
1385 {
1386 // Add branches to the existing fRequestedBranches.
1387    TString br(branches);
1388    TObjArray *arr = br.Tokenize(",");
1389    TIter next(arr);
1390    TObject *obj;
1391    while ((obj=next())) {
1392       if (!fRequestedBranches.Contains(obj->GetName())) {
1393          if (!fRequestedBranches.IsNull()) fRequestedBranches += ",";
1394          fRequestedBranches += obj->GetName();
1395       }
1396    }
1397    if (arr) delete arr;
1398 }   
1399
1400 //______________________________________________________________________________
1401 void AliAnalysisManager::CheckBranches(Bool_t load)
1402 {
1403 // The method checks the input branches to be loaded during the analysis.
1404    if (fAutoBranchHandling || fRequestedBranches.IsNull() || !fTree) return;   
1405    TObjArray *arr = fRequestedBranches.Tokenize(",");
1406    TIter next(arr);
1407    TObject *obj;
1408    while ((obj=next())) {
1409       TBranch *br = dynamic_cast<TBranch*>(fTable.FindObject(obj->GetName()));
1410       if (!br) {
1411          br = fTree->GetBranch(obj->GetName());
1412          if (!br) {
1413             Error("CheckBranches", "Could not find branch %s",obj->GetName());
1414             continue;
1415          }
1416       }   
1417       fTable.Add(br);
1418       if (load && br->GetReadEntry()!=GetCurrentEntry()) br->GetEntry(GetCurrentEntry());
1419    }
1420 }
1421
1422 //______________________________________________________________________________
1423 void AliAnalysisManager::PrintStatus(Option_t *option) const
1424 {
1425 // Print task hierarchy.
1426    if (!fInitOK) {
1427       Info("PrintStatus", "Analysis manager %s not initialized : call InitAnalysis() first", GetName());
1428       return;
1429    }   
1430    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1431    if (getsysInfo)
1432       Info("PrintStatus", "System information will be collected each %lld events", fNSysInfo);
1433    TIter next(fTopTasks);
1434    AliAnalysisTask *task;
1435    while ((task=(AliAnalysisTask*)next()))
1436       task->PrintTask(option);
1437    if (!fAutoBranchHandling && !fRequestedBranches.IsNull()) 
1438       printf("Requested input branches:\n%s\n", fRequestedBranches.Data());
1439 }
1440
1441 //______________________________________________________________________________
1442 void AliAnalysisManager::ResetAnalysis()
1443 {
1444 // Reset all execution flags and clean containers.
1445    CleanContainers();
1446 }
1447
1448 //______________________________________________________________________________
1449 Long64_t AliAnalysisManager::StartAnalysis(const char *type, Long64_t nentries, Long64_t firstentry)
1450 {
1451 // Start analysis having a grid handler.
1452    if (!fGridHandler) {
1453       Error("StartAnalysis", "Cannot start analysis providing just the analysis type without a grid handler.");
1454       Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1455       return -1;
1456    }
1457    TTree *tree = NULL;
1458    return StartAnalysis(type, tree, nentries, firstentry);
1459 }
1460
1461 //______________________________________________________________________________
1462 Long64_t AliAnalysisManager::StartAnalysis(const char *type, TTree * const tree, Long64_t nentries, Long64_t firstentry)
1463 {
1464 // Start analysis for this manager. Analysis task can be: LOCAL, PROOF, GRID or
1465 // MIX. Process nentries starting from firstentry
1466    Long64_t retv = 0;
1467    // Backup current directory and make sure gDirectory points to gROOT
1468    TDirectory *cdir = gDirectory;
1469    gROOT->cd();
1470    if (!fInitOK) {
1471       Error("StartAnalysis","Analysis manager was not initialized !");
1472       cdir->cd();
1473       return -1;
1474    }
1475    if (fDebug > 1) printf("StartAnalysis %s\n",GetName());
1476    fIsRemote = kFALSE;
1477    TString anaType = type;
1478    anaType.ToLower();
1479    fMode = kLocalAnalysis;
1480    Bool_t runlocalinit = kTRUE;
1481    if (anaType.Contains("file")) {
1482       runlocalinit = kFALSE;
1483       fIsRemote = kTRUE;
1484    }   
1485    if (anaType.Contains("proof"))     fMode = kProofAnalysis;
1486    else if (anaType.Contains("grid")) fMode = kGridAnalysis;
1487    else if (anaType.Contains("mix"))  fMode = kMixingAnalysis;
1488
1489    if (fMode == kGridAnalysis) {
1490       fIsRemote = kTRUE;
1491       if (!anaType.Contains("terminate")) {
1492          if (!fGridHandler) {
1493             Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1494             Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1495             cdir->cd();
1496             return -1;
1497          }
1498          // Write analysis manager in the analysis file
1499          cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1500          // run local task configuration
1501          TIter nextTask(fTasks);
1502          AliAnalysisTask *task;
1503          while ((task=(AliAnalysisTask*)nextTask())) {
1504             task->LocalInit();
1505             gROOT->cd();
1506          }
1507          if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1508             Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1509             cdir->cd();
1510             return -1;
1511          }   
1512
1513          // Terminate grid analysis
1514          if (fSelector && fSelector->GetStatus() == -1) {cdir->cd(); return -1;}
1515          if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) {cdir->cd(); return 0;}
1516          cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1517          if (!fGridHandler->MergeOutputs()) {
1518             // Return if outputs could not be merged or if it alien handler
1519             // was configured for offline mode or local testing.
1520             cdir->cd();
1521             return 0;
1522          }
1523       }   
1524       cout << "===== TERMINATING GRID ANALYSIS JOB: " << GetName() << endl;
1525       ImportWrappers(NULL);
1526       Terminate();
1527       cdir->cd();
1528       return 0;
1529    }
1530    TString line;
1531    SetEventLoop(kFALSE);
1532    // Enable event loop mode if a tree was provided
1533    if (tree || fGridHandler || fMode==kMixingAnalysis) SetEventLoop(kTRUE);
1534
1535    TChain *chain = 0;
1536    TString ttype = "TTree";
1537    if (tree && tree->IsA() == TChain::Class()) {
1538       chain = (TChain*)tree;
1539       if (!chain || !chain->GetListOfFiles()->First()) {
1540          Error("StartAnalysis", "Cannot process null or empty chain...");
1541          cdir->cd();
1542          return -1;
1543       }   
1544       ttype = "TChain";
1545    }   
1546
1547    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1548    if (getsysInfo) AliSysInfo::AddStamp("Start", 0);
1549    // Initialize locally all tasks (happens for all modes)
1550    TIter next(fTasks);
1551    AliAnalysisTask *task;
1552    if (runlocalinit) {
1553       while ((task=(AliAnalysisTask*)next())) {
1554          task->LocalInit();
1555          gROOT->cd();
1556       }
1557       if (getsysInfo) AliSysInfo::AddStamp("LocalInit_all", 0);
1558    }   
1559    
1560    switch (fMode) {
1561       case kLocalAnalysis:
1562          if (!tree && !fGridHandler) {
1563             TIter nextT(fTasks);
1564             // Call CreateOutputObjects for all tasks
1565             Int_t itask = 0;
1566             Bool_t dirStatus = TH1::AddDirectoryStatus();
1567             while ((task=(AliAnalysisTask*)nextT())) {
1568                TH1::AddDirectory(kFALSE);
1569                task->CreateOutputObjects();
1570                if (getsysInfo) AliSysInfo::AddStamp(Form("%s_CREATEOUTOBJ",task->ClassName()), 0, itask, 0);
1571                gROOT->cd();
1572                itask++;
1573             }   
1574             TH1::AddDirectory(dirStatus);
1575             if (IsExternalLoop()) {
1576                Info("StartAnalysis", "Initialization done. Event loop is controlled externally.\
1577                      \nSetData for top container, call ExecAnalysis in a loop and then Terminate manually");
1578                return 0;
1579             }
1580             ExecAnalysis();
1581             Terminate();
1582             return 0;
1583          } 
1584          fSelector = new AliAnalysisSelector(this);
1585          // Check if a plugin handler is used
1586          if (fGridHandler) {
1587             // Get the chain from the plugin
1588             TString dataType = "esdTree";
1589             if (fInputEventHandler) {
1590                dataType = fInputEventHandler->GetDataType();
1591                dataType.ToLower();
1592                dataType += "Tree";
1593             }   
1594             chain = fGridHandler->GetChainForTestMode(dataType);
1595             if (!chain) {
1596                Error("StartAnalysis", "No chain for test mode. Aborting.");
1597                return -1;
1598             }
1599             cout << "===== RUNNING LOCAL ANALYSIS" << GetName() << " ON CHAIN " << chain->GetName() << endl;
1600             retv = chain->Process(fSelector, "", nentries, firstentry);
1601             break;
1602          }
1603          // Run tree-based analysis via AliAnalysisSelector  
1604          cout << "===== RUNNING LOCAL ANALYSIS " << GetName() << " ON TREE " << tree->GetName() << endl;
1605          retv = tree->Process(fSelector, "", nentries, firstentry);
1606          break;
1607       case kProofAnalysis:
1608          fIsRemote = kTRUE;
1609          // Check if the plugin is used
1610          if (fGridHandler) {
1611             return StartAnalysis(type, fGridHandler->GetProofDataSet(), nentries, firstentry);
1612          }
1613          if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1614             Error("StartAnalysis", "No PROOF!!! Exiting.");
1615             cdir->cd();
1616             return -1;
1617          }   
1618          line = Form("gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1619          gROOT->ProcessLine(line);
1620          if (chain) {
1621             chain->SetProof();
1622             cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON CHAIN " << chain->GetName() << endl;
1623             retv = chain->Process("AliAnalysisSelector", "", nentries, firstentry);
1624          } else {
1625             Error("StartAnalysis", "No chain!!! Exiting.");
1626             cdir->cd();
1627             return -1;
1628          }      
1629          break;
1630       case kGridAnalysis:
1631          fIsRemote = kTRUE;
1632          if (!anaType.Contains("terminate")) {
1633             if (!fGridHandler) {
1634                Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1635                Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1636                cdir->cd();
1637                return -1;
1638             }
1639             // Write analysis manager in the analysis file
1640             cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1641             // Start the analysis via the handler
1642             if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1643                Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1644                cdir->cd();
1645                return -1;
1646             }   
1647
1648             // Terminate grid analysis
1649             if (fSelector && fSelector->GetStatus() == -1) {cdir->cd(); return -1;}
1650             if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) {cdir->cd(); return 0;}
1651             cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1652             if (!fGridHandler->MergeOutputs()) {
1653                // Return if outputs could not be merged or if it alien handler
1654                // was configured for offline mode or local testing.
1655                cdir->cd();
1656                return 0;
1657             }
1658          }   
1659          cout << "===== TERMINATING GRID ANALYSIS JOB: " << GetName() << endl;
1660          ImportWrappers(NULL);
1661          Terminate();
1662          cdir->cd();
1663          return 0;
1664       case kMixingAnalysis:   
1665          // Run event mixing analysis
1666          if (!fEventPool) {
1667             Error("StartAnalysis", "Cannot run event mixing without event pool");
1668             cdir->cd();
1669             return -1;
1670          }
1671          cout << "===== RUNNING EVENT MIXING ANALYSIS " << GetName() << endl;
1672          fSelector = new AliAnalysisSelector(this);
1673          while ((chain=fEventPool->GetNextChain())) {
1674             next.Reset();
1675             // Call NotifyBinChange for all tasks
1676             while ((task=(AliAnalysisTask*)next()))
1677                if (!task->IsPostEventLoop()) task->NotifyBinChange();
1678             retv = chain->Process(fSelector);
1679             if (retv < 0) {
1680                Error("StartAnalysis", "Mixing analysis failed");
1681                cdir->cd();
1682                return retv;
1683             }   
1684          }
1685          PackOutput(fSelector->GetOutputList());
1686          Terminate();
1687    }
1688    cdir->cd();
1689    return retv;
1690 }   
1691
1692 //______________________________________________________________________________
1693 Long64_t AliAnalysisManager::StartAnalysis(const char *type, const char *dataset, Long64_t nentries, Long64_t firstentry)
1694 {
1695 // Start analysis for this manager on a given dataset. Analysis task can be: 
1696 // LOCAL, PROOF or GRID. Process nentries starting from firstentry.
1697    if (!fInitOK) {
1698       Error("StartAnalysis","Analysis manager was not initialized !");
1699       return -1;
1700    }
1701    fIsRemote = kTRUE;
1702    if (fDebug > 1) printf("StartAnalysis %s\n",GetName());
1703    TString anaType = type;
1704    anaType.ToLower();
1705    if (!anaType.Contains("proof")) {
1706       Error("StartAnalysis", "Cannot process datasets in %s mode. Try PROOF.", type);
1707       return -1;
1708    }   
1709    fMode = kProofAnalysis;
1710    TString line;
1711    SetEventLoop(kTRUE);
1712    // Set the dataset flag
1713    TObject::SetBit(kUseDataSet);
1714    fTree = 0;
1715    TChain *chain = 0;
1716    if (fGridHandler) {
1717       // Start proof analysis using the grid handler
1718       if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1719          Error("StartAnalysis", "The grid plugin could not start PROOF analysis");
1720          return -1;
1721       }
1722       // Check if the plugin is in test mode
1723       if (fGridHandler->GetRunMode() == AliAnalysisGrid::kTest) {
1724          dataset = "test_collection";
1725       } else {
1726          dataset = fGridHandler->GetProofDataSet();
1727       }
1728    }   
1729
1730    if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1731       Error("StartAnalysis", "No PROOF!!! Exiting.");
1732       return -1;
1733    }   
1734
1735    // Initialize locally all tasks
1736    TIter next(fTasks);
1737    AliAnalysisTask *task;
1738    while ((task=(AliAnalysisTask*)next())) {
1739       task->LocalInit();
1740    }
1741    
1742    line = Form("gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1743    gROOT->ProcessLine(line);
1744    Long_t retv;
1745    if (chain) {
1746 //      chain->SetProof();
1747       cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON TEST CHAIN " << chain->GetName() << endl;
1748       retv = chain->Process("AliAnalysisSelector", "", nentries, firstentry);
1749    } else {   
1750       line = Form("gProof->Process(\"%s\", \"AliAnalysisSelector\", \"\", %lld, %lld);",
1751                   dataset, nentries, firstentry);
1752       cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON DATASET " << dataset << endl;
1753       retv = (Long_t)gROOT->ProcessLine(line);
1754    }   
1755    return retv;
1756 }   
1757
1758 //______________________________________________________________________________
1759 TFile *AliAnalysisManager::OpenFile(AliAnalysisDataContainer *cont, const char *option, Bool_t ignoreProof)
1760 {
1761 // Opens according the option the file specified by cont->GetFileName() and changes
1762 // current directory to cont->GetFolderName(). If the file was already opened, it
1763 // checks if the option UPDATE was preserved. File open via TProofOutputFile can
1764 // be optionally ignored.
1765   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1766   TString filename = cont->GetFileName();
1767   TFile *f = NULL;
1768   if (filename.IsNull()) {
1769     ::Error("AliAnalysisManager::OpenFile", "No file name specified for container %s", cont->GetName());
1770     return NULL;
1771   }
1772   if (mgr->GetAnalysisType()==AliAnalysisManager::kProofAnalysis && cont->IsSpecialOutput()
1773       && !ignoreProof)
1774     f = mgr->OpenProofFile(cont,option);
1775   else {
1776     // Check first if the file is already opened
1777     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1778     if (f) {
1779       // Check if option "UPDATE" was preserved 
1780       TString opt(option);
1781       opt.ToUpper();
1782       if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1783         ::Info("AliAnalysisManager::OpenFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1784     } else {
1785       f = TFile::Open(filename, option);
1786     }    
1787   }   
1788   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1789     cont->SetFile(f);
1790     // Cd to file
1791     f->cd();
1792     // Check for a folder request
1793     TString dir = cont->GetFolderName(); 
1794     if (!dir.IsNull()) {
1795       if (!f->GetDirectory(dir)) f->mkdir(dir);
1796       f->cd(dir);
1797     }
1798     return f;
1799   }
1800   ::Fatal("AliAnalysisManager::OpenFile", "File %s could not be opened", filename.Data());
1801   cont->SetFile(NULL);
1802   return NULL;
1803 }    
1804  
1805 //______________________________________________________________________________
1806 TFile *AliAnalysisManager::OpenProofFile(AliAnalysisDataContainer *cont, const char *option, const char *extaod)
1807 {
1808 // Opens a special output file used in PROOF.
1809   TString line;
1810   TString filename = cont->GetFileName();
1811   if (cont == fCommonOutput) {
1812      if (fOutputEventHandler) {
1813         if (strlen(extaod)) filename = extaod;
1814         filename = fOutputEventHandler->GetOutputFileName();
1815      }   
1816      else Fatal("OpenProofFile","No output container. Exiting.");
1817   }   
1818   TFile *f = NULL;
1819   if (fMode!=kProofAnalysis || !fSelector) {
1820     Fatal("OpenProofFile","Cannot open PROOF file %s: no PROOF or selector",filename.Data());
1821     return NULL;
1822   } 
1823   if (fSpecialOutputLocation.Length()) {
1824     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1825     if (f) {
1826       // Check if option "UPDATE" was preserved 
1827       TString opt(option);
1828       opt.ToUpper();
1829       if ((opt=="UPDATE") && (opt!=f->GetOption()))
1830         ::Info("OpenProofFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1831     } else {
1832       f = new TFile(filename, option);
1833     }
1834     if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1835       cont->SetFile(f);
1836       // Cd to file
1837       f->cd();
1838       // Check for a folder request
1839       TString dir = cont->GetFolderName(); 
1840       if (dir.Length()) {
1841         if (!f->GetDirectory(dir)) f->mkdir(dir);
1842         f->cd(dir);
1843       }      
1844       return f;
1845     }
1846     Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1847     cont->SetFile(NULL);
1848     return NULL;       
1849   }
1850   // Check if there is already a proof output file in the output list
1851   TObject *pof = fSelector->GetOutputList()->FindObject(filename);
1852   if (pof) {
1853     // Get the actual file
1854     line = Form("((TProofOutputFile*)0x%lx)->GetFileName();", (ULong_t)pof);
1855     filename = (const char*)gROOT->ProcessLine(line);
1856     if (fDebug>1) {
1857       printf("File: %s already booked via TProofOutputFile\n", filename.Data());
1858     }  
1859     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1860     if (!f) {
1861        Fatal("OpenProofFile", "Proof output file found but no file opened for %s", filename.Data());
1862        return NULL;
1863     }   
1864     // Check if option "UPDATE" was preserved 
1865     TString opt(option);
1866     opt.ToUpper();
1867     if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1868       Fatal("OpenProofFile", "File %s already opened, but not in UPDATE mode!", cont->GetFileName());
1869   } else {
1870     if (cont->IsRegisterDataset()) {
1871       TString dsetName = filename;
1872       dsetName.ReplaceAll(".root", cont->GetTitle());
1873       dsetName.ReplaceAll(":","_");
1874       if (fDebug>1) printf("Booking dataset: %s\n", dsetName.Data());
1875       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\", \"DROV\", \"%s\");", filename.Data(), dsetName.Data());
1876     } else {
1877       if (fDebug>1) printf("Booking TProofOutputFile: %s to be merged\n", filename.Data());
1878       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\");", filename.Data());
1879     }
1880     if (fDebug > 1) printf("=== %s\n", line.Data());
1881     gROOT->ProcessLine(line);
1882     line = Form("pf->OpenFile(\"%s\");", option);
1883     gROOT->ProcessLine(line);
1884     f = gFile;
1885     if (fDebug > 1) {
1886       gROOT->ProcessLine("pf->Print()");
1887       printf(" == proof file name: %s", f->GetName());
1888     }   
1889     // Add to proof output list
1890     line = Form("((TList*)0x%lx)->Add(pf);",(ULong_t)fSelector->GetOutputList());
1891     if (fDebug > 1) printf("=== %s\n", line.Data());
1892     gROOT->ProcessLine(line);
1893   }
1894   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1895     cont->SetFile(f);
1896     // Cd to file
1897     f->cd();
1898     // Check for a folder request
1899     TString dir = cont->GetFolderName(); 
1900     if (!dir.IsNull()) {
1901       if (!f->GetDirectory(dir)) f->mkdir(dir);
1902       f->cd(dir);
1903     }
1904     return f;
1905   }
1906   Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1907   cont->SetFile(NULL);  
1908   return NULL;
1909 }   
1910
1911 //______________________________________________________________________________
1912 void AliAnalysisManager::ExecAnalysis(Option_t *option)
1913 {
1914 // Execute analysis.
1915    static Long64_t nentries = 0;
1916    static TTree *lastTree = 0;
1917    static TStopwatch *timer = new TStopwatch();
1918    if (fDebug > 0) printf("MGR: Processing event #%d\n", fNcalls);
1919    else {
1920       if (fTree && (fTree != lastTree)) {
1921          nentries += fTree->GetEntries();
1922          lastTree = fTree;
1923       }   
1924       if (!fNcalls) timer->Start();
1925       if (!fIsRemote && TObject::TestBit(kUseProgressBar)) ProgressBar("Processing event", fNcalls, nentries, timer, kFALSE);
1926    }
1927    gROOT->cd();
1928    TDirectory *cdir = gDirectory;
1929    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1930    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) AliSysInfo::AddStamp("Exec_start", (Int_t)fNcalls);
1931    if (!fInitOK) {
1932       Error("ExecAnalysis", "Analysis manager was not initialized !");
1933       cdir->cd();
1934       return;
1935    }
1936    fNcalls++;
1937    AliAnalysisTask *task;
1938    // Check if the top tree is active.
1939    if (fTree) {
1940       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
1941          AliSysInfo::AddStamp("Handlers_BeginEventGroup",fNcalls, 1002, 0);
1942       TIter next(fTasks);
1943    // De-activate all tasks
1944       while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE);
1945       AliAnalysisDataContainer *cont = fCommonInput;
1946       if (!cont) cont = (AliAnalysisDataContainer*)fInputs->At(0);
1947       if (!cont) {
1948               Error("ExecAnalysis","Cannot execute analysis in TSelector mode without at least one top container");
1949          cdir->cd();
1950          return;
1951       }   
1952       cont->SetData(fTree); // This will notify all consumers
1953       Long64_t entry = fTree->GetTree()->GetReadEntry();      
1954 //
1955 //    Call BeginEvent() for optional input/output and MC services 
1956       if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
1957       if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
1958       if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
1959       gROOT->cd();
1960       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
1961          AliSysInfo::AddStamp("Handlers_BeginEvent",fNcalls, 1000, 0);
1962 //
1963 //    Execute the tasks
1964 //      TIter next1(cont->GetConsumers());
1965       TIter next1(fTopTasks);
1966       Int_t itask = 0;
1967       while ((task=(AliAnalysisTask*)next1())) {
1968          if (fDebug >1) {
1969             cout << "    Executing task " << task->GetName() << endl;
1970          }       
1971          task->ExecuteTask(option);
1972          gROOT->cd();
1973          if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
1974             AliSysInfo::AddStamp(task->ClassName(), fNcalls, itask, 1);
1975          itask++;   
1976       }
1977 //
1978 //    Call FinishEvent() for optional output and MC services 
1979       if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
1980       if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
1981       if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
1982       // Gather system information if requested
1983       if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
1984          AliSysInfo::AddStamp("Handlers_FinishEvent",fNcalls, 1001, 1);
1985       cdir->cd();   
1986       return;
1987    }   
1988    // The event loop is not controlled by TSelector   
1989 //
1990 //  Call BeginEvent() for optional input/output and MC services 
1991    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(-1);
1992    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(-1);
1993    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(-1);
1994    gROOT->cd();
1995    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
1996       AliSysInfo::AddStamp("Handlers_BeginEvent",fNcalls, 1000, 0);
1997    TIter next2(fTopTasks);
1998    while ((task=(AliAnalysisTask*)next2())) {
1999       task->SetActive(kTRUE);
2000       if (fDebug > 1) {
2001          cout << "    Executing task " << task->GetName() << endl;
2002       }   
2003       task->ExecuteTask(option);
2004       gROOT->cd();
2005    }   
2006 //
2007 // Call FinishEvent() for optional output and MC services 
2008    if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
2009    if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
2010    if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
2011    if (getsysInfo && ((fNcalls%fNSysInfo)==0)) 
2012       AliSysInfo::AddStamp("Handlers_FinishEvent",fNcalls, 1000, 1);
2013    cdir->cd();   
2014 }
2015
2016 //______________________________________________________________________________
2017 void AliAnalysisManager::SetInputEventHandler(AliVEventHandler* const handler)
2018 {
2019 // Set the input event handler and create a container for it.
2020    fInputEventHandler   = handler;
2021    fCommonInput = CreateContainer("cAUTO_INPUT", TChain::Class(), AliAnalysisManager::kInputContainer);
2022 //   Warning("SetInputEventHandler", " An automatic input container for the input chain was created.\nPlease use: mgr->GetCommonInputContainer() to access it.");
2023 }
2024
2025 //______________________________________________________________________________
2026 void AliAnalysisManager::SetOutputEventHandler(AliVEventHandler* const handler)
2027 {
2028 // Set the input event handler and create a container for it.
2029    fOutputEventHandler   = handler;
2030    fCommonOutput = CreateContainer("cAUTO_OUTPUT", TTree::Class(), AliAnalysisManager::kOutputContainer, "default");
2031    fCommonOutput->SetSpecialOutput();
2032 //   Warning("SetOutputEventHandler", " An automatic output container for the output tree was created.\nPlease use: mgr->GetCommonOutputContainer() to access it.");
2033 }
2034
2035 //______________________________________________________________________________
2036 void AliAnalysisManager::RegisterExtraFile(const char *fname)
2037 {
2038 // This method is used externally to register output files which are not
2039 // connected to any output container, so that the manager can properly register,
2040 // retrieve or merge them when running in distributed mode. The file names are
2041 // separated by blancs. The method has to be called in MyAnalysisTask::LocalInit().
2042    if (fExtraFiles.Contains(fname)) return;
2043    if (fExtraFiles.Length()) fExtraFiles += " ";
2044    fExtraFiles += fname;
2045 }
2046
2047 //______________________________________________________________________________
2048 Bool_t AliAnalysisManager::GetFileFromWrapper(const char *filename, const TList *source)
2049 {
2050 // Copy a file from the location specified ina the wrapper with the same name from the source list.
2051    char fullPath[512];
2052    char chUrl[512];
2053    TObject *pof =  source->FindObject(filename);
2054    if (!pof || !pof->InheritsFrom("TProofOutputFile")) {
2055       Error("GetFileFromWrapper", "TProofOutputFile object not found in output list for file %s", filename);
2056       return kFALSE;
2057    }
2058    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", ((TProofOutputFile*)0x%lx)->GetOutputFileName();)", (ULong_t)fullPath, (ULong_t)pof));
2059    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", gProof->GetUrl();)", (ULong_t)chUrl));
2060    TString clientUrl(chUrl);
2061    TString fullPath_str(fullPath);
2062    if (clientUrl.Contains("localhost")){
2063       TObjArray* array = fullPath_str.Tokenize ( "//" );
2064       TObjString *strobj = ( TObjString *)array->At(1);
2065       TObjArray* arrayPort = strobj->GetString().Tokenize ( ":" );
2066       TObjString *strobjPort = ( TObjString *) arrayPort->At(1);
2067       fullPath_str.ReplaceAll(strobj->GetString().Data(),"localhost:PORT");
2068       fullPath_str.ReplaceAll(":PORT",Form(":%s",strobjPort->GetString().Data()));
2069       if (fDebug > 1) Info("GetFileFromWrapper","Using tunnel from %s to %s",fullPath_str.Data(),filename);
2070       delete arrayPort;
2071       delete array;
2072    }
2073    if (fDebug > 1) 
2074       Info("GetFileFromWrapper","Copying file %s from PROOF scratch space", fullPath_str.Data());
2075    Bool_t gotit = TFile::Cp(fullPath_str.Data(), filename); 
2076    if (!gotit)
2077       Error("GetFileFromWrapper", "Could not get file %s from proof scratch space", filename);
2078    return gotit;
2079 }
2080
2081 //______________________________________________________________________________
2082 void AliAnalysisManager::GetAnalysisTypeString(TString &type) const
2083 {
2084 // Fill analysis type in the provided string.
2085    switch (fMode) {
2086       case kLocalAnalysis:
2087          type = "local";
2088          return;
2089       case kProofAnalysis:
2090          type = "proof";
2091          return;
2092       case kGridAnalysis:
2093          type = "grid";
2094          return;
2095       case kMixingAnalysis:
2096          type = "mix";
2097    }
2098 }
2099
2100 //______________________________________________________________________________
2101 Bool_t AliAnalysisManager::ValidateOutputFiles() const
2102 {
2103 // Validate all output files.
2104    TIter next(fOutputs);
2105    AliAnalysisDataContainer *output;
2106    TDirectory *cdir = gDirectory;
2107    TString openedFiles;
2108    while ((output=(AliAnalysisDataContainer*)next())) {
2109       if (output->IsRegisterDataset()) continue;
2110       TString filename = output->GetFileName();
2111       if (filename == "default") {
2112          if (!fOutputEventHandler) continue;
2113          filename = fOutputEventHandler->GetOutputFileName();
2114          // Main AOD may not be there
2115          if (gSystem->AccessPathName(filename)) continue;
2116       }
2117       // Check if the file is closed
2118       if (openedFiles.Contains(filename)) continue;;
2119       TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
2120       if (file) {
2121          Warning("ValidateOutputs", "File %s was not closed. Closing.", filename.Data());
2122          // Clear file list to release object ownership to user.
2123 //         file->Clear();
2124          file->Close();
2125       }
2126       file = TFile::Open(filename);
2127       if (!file || file->IsZombie() || file->TestBit(TFile::kRecovered)) {
2128          Error("ValidateOutputs", "Output file <%s> was not created or invalid", filename.Data());
2129          cdir->cd();
2130          return kFALSE;
2131       }
2132       file->Close();
2133       openedFiles += filename;
2134       openedFiles += " ";
2135    }
2136    cdir->cd();
2137    return kTRUE;
2138 }   
2139
2140 //______________________________________________________________________________
2141 void AliAnalysisManager::ProgressBar(const char *opname, Long64_t current, Long64_t size, TStopwatch * const watch, Bool_t last, Bool_t refresh)
2142 {
2143 // Implements a nice text mode progress bar.
2144    static Long64_t icount = 0;
2145    static TString oname;
2146    static TString nname;
2147    static Long64_t ocurrent = 0;
2148    static Long64_t osize = 0;
2149    static Int_t oseconds = 0;
2150    static TStopwatch *owatch = 0;
2151    static Bool_t oneoftwo = kFALSE;
2152    static Int_t nrefresh = 0;
2153    static Int_t nchecks = 0;
2154    const char symbol[4] = {'=','\\','|','/'}; 
2155    char progress[11] = "          ";
2156    Int_t ichar = icount%4;
2157    
2158    if (!refresh) {
2159       nrefresh = 0;
2160       if (!size) return;
2161       owatch = watch;
2162       oname = opname;
2163       ocurrent = TMath::Abs(current);
2164       osize = TMath::Abs(size);
2165       if (ocurrent > osize) ocurrent=osize;
2166    } else {
2167       nrefresh++;
2168       if (!osize) return;
2169    }     
2170    icount++;
2171    Double_t time = 0.;
2172    Int_t hours = 0;
2173    Int_t minutes = 0;
2174    Int_t seconds = 0;
2175    if (owatch && !last) {
2176       owatch->Stop();
2177       time = owatch->RealTime();
2178       hours = (Int_t)(time/3600.);
2179       time -= 3600*hours;
2180       minutes = (Int_t)(time/60.);
2181       time -= 60*minutes;
2182       seconds = (Int_t)time;
2183       if (refresh)  {
2184          if (oseconds==seconds) {
2185             owatch->Continue();
2186             return;
2187          }
2188          oneoftwo = !oneoftwo;   
2189       }
2190       oseconds = seconds;   
2191    }
2192    if (refresh && oneoftwo) {
2193       nname = oname;
2194       if (nchecks <= 0) nchecks = nrefresh+1;
2195       Int_t pctdone = (Int_t)(100.*nrefresh/nchecks);
2196       oname = Form("     == %d%% ==", pctdone);
2197    }         
2198    Double_t percent = 100.0*ocurrent/osize;
2199    Int_t nchar = Int_t(percent/10);
2200    if (nchar>10) nchar=10;
2201    Int_t i;
2202    for (i=0; i<nchar; i++)  progress[i] = '=';
2203    progress[nchar] = symbol[ichar];
2204    for (i=nchar+1; i<10; i++) progress[i] = ' ';
2205    progress[10] = '\0';
2206    oname += "                    ";
2207    oname.Remove(20);
2208    if(size<10000) fprintf(stderr, "%s [%10s] %4lld ", oname.Data(), progress, ocurrent);
2209    else if(size<100000) fprintf(stderr, "%s [%10s] %5lld ",oname.Data(), progress, ocurrent);
2210    else fprintf(stderr, "%s [%10s] %7lld ",oname.Data(), progress, ocurrent);
2211    if (time>0.) fprintf(stderr, "[%6.2f %%]   TIME %.2d:%.2d:%.2d             \r", percent, hours, minutes, seconds);
2212    else fprintf(stderr, "[%6.2f %%]\r", percent);
2213    if (refresh && oneoftwo) oname = nname;
2214    if (owatch) owatch->Continue();
2215    if (last) {
2216       icount = 0;
2217       owatch = 0;
2218       ocurrent = 0;
2219       osize = 0;
2220       oseconds = 0;
2221       oneoftwo = kFALSE;
2222       nrefresh = 0;
2223       fprintf(stderr, "\n");
2224    }   
2225 }
2226
2227 //______________________________________________________________________________
2228 void AliAnalysisManager::DoLoadBranch(const char *name) 
2229 {
2230   // Get tree and load branch if needed.
2231
2232   if (fAutoBranchHandling || !fTree)
2233     return;
2234
2235   TBranch *br = dynamic_cast<TBranch*>(fTable.FindObject(name));
2236   if (!br) {
2237     br = fTree->GetBranch(name);
2238     if (!br) {
2239       Error("DoLoadBranch", "Could not find branch %s",name);
2240       return;
2241     }
2242     fTable.Add(br);
2243   }
2244   if (br->GetReadEntry()==GetCurrentEntry()) return;
2245   br->GetEntry(GetCurrentEntry());
2246 }
2247
2248 //______________________________________________________________________________
2249 void AliAnalysisManager::AddStatisticsMsg(const char *line)
2250 {
2251 // Add a line in the statistics message. If available, the statistics message is written
2252 // at the end of the SlaveTerminate phase on workers AND at the end of Terminate
2253 // on the client.
2254    if (!strlen(line)) return;
2255    if (!fStatisticsMsg.IsNull()) fStatisticsMsg += "\n";
2256    fStatisticsMsg += line;
2257 }
2258
2259 //______________________________________________________________________________
2260 void AliAnalysisManager::WriteStatisticsMsg(Int_t nevents)
2261 {
2262 // Write the statistics message in a file named <nevents.stat>
2263    if (!nevents) return;
2264    ofstream out;
2265    out.open(Form("%09d.stat", nevents), ios::out);
2266    if (!fStatisticsMsg.IsNull()) out << fStatisticsMsg << endl;
2267    out.close();
2268 }