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