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