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