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