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