d3967ab0e2ba8a122cd8a0ba6e534132b8e0b7a6
[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 <TMethodCall.h>
35 #include <TChain.h>
36 #include <TSystem.h>
37 #include <TROOT.h>
38 #include <TCanvas.h>
39 #include <TStopwatch.h>
40
41 #include "AliAnalysisSelector.h"
42 #include "AliAnalysisGrid.h"
43 #include "AliAnalysisTask.h"
44 #include "AliAnalysisDataContainer.h"
45 #include "AliAnalysisDataSlot.h"
46 #include "AliVEventHandler.h"
47 #include "AliVEventPool.h"
48 #include "AliSysInfo.h"
49 #include "AliAnalysisManager.h"
50
51 ClassImp(AliAnalysisManager)
52
53 AliAnalysisManager *AliAnalysisManager::fgAnalysisManager = NULL;
54 TString AliAnalysisManager::fgCommonFileName = "";
55
56 //______________________________________________________________________________
57 AliAnalysisManager::AliAnalysisManager(const char *name, const char *title)
58                    :TNamed(name,title),
59                     fTree(NULL),
60                     fInputEventHandler(NULL),
61                     fOutputEventHandler(NULL),
62                     fMCtruthEventHandler(NULL),
63                     fEventPool(NULL),
64                     fCurrentEntry(-1),
65                     fNSysInfo(0),
66                     fMode(kLocalAnalysis),
67                     fInitOK(kFALSE),
68                     fDebug(0),
69                     fSpecialOutputLocation(""), 
70                     fTasks(NULL),
71                     fTopTasks(NULL),
72                     fZombies(NULL),
73                     fContainers(NULL),
74                     fInputs(NULL),
75                     fOutputs(NULL),
76                     fCommonInput(NULL),
77                     fCommonOutput(NULL),
78                     fSelector(NULL),
79                     fGridHandler(NULL),
80                     fExtraFiles("")
81 {
82 // Default constructor.
83    fgAnalysisManager = this;
84    fgCommonFileName  = "AnalysisResults.root";
85    fTasks      = new TObjArray();
86    fTopTasks   = new TObjArray();
87    fZombies    = new TObjArray();
88    fContainers = new TObjArray();
89    fInputs     = new TObjArray();
90    fOutputs    = new TObjArray();
91    SetEventLoop(kTRUE);
92    TObject::SetObjectStat(kFALSE);
93 }
94
95 //______________________________________________________________________________
96 AliAnalysisManager::AliAnalysisManager(const AliAnalysisManager& other)
97                    :TNamed(other),
98                     fTree(NULL),
99                     fInputEventHandler(NULL),
100                     fOutputEventHandler(NULL),
101                     fMCtruthEventHandler(NULL),
102                     fEventPool(NULL),
103                     fCurrentEntry(-1),
104                     fNSysInfo(0),
105                     fMode(other.fMode),
106                     fInitOK(other.fInitOK),
107                     fDebug(other.fDebug),
108                     fSpecialOutputLocation(""), 
109                     fTasks(NULL),
110                     fTopTasks(NULL),
111                     fZombies(NULL),
112                     fContainers(NULL),
113                     fInputs(NULL),
114                     fOutputs(NULL),
115                     fCommonInput(NULL),
116                     fCommonOutput(NULL),
117                     fSelector(NULL),
118                     fGridHandler(NULL),
119                     fExtraFiles()
120 {
121 // Copy constructor.
122    fTasks      = new TObjArray(*other.fTasks);
123    fTopTasks   = new TObjArray(*other.fTopTasks);
124    fZombies    = new TObjArray(*other.fZombies);
125    fContainers = new TObjArray(*other.fContainers);
126    fInputs     = new TObjArray(*other.fInputs);
127    fOutputs    = new TObjArray(*other.fOutputs);
128    fgCommonFileName  = "AnalysisResults.root";
129    fgAnalysisManager = this;
130    TObject::SetObjectStat(kFALSE);
131 }
132    
133 //______________________________________________________________________________
134 AliAnalysisManager& AliAnalysisManager::operator=(const AliAnalysisManager& other)
135 {
136 // Assignment
137    if (&other != this) {
138       TNamed::operator=(other);
139       fInputEventHandler   = other.fInputEventHandler;
140       fOutputEventHandler  = other.fOutputEventHandler;
141       fMCtruthEventHandler = other.fMCtruthEventHandler;
142       fEventPool           = other.fEventPool;
143       fTree       = NULL;
144       fCurrentEntry = -1;
145       fNSysInfo   = other.fNSysInfo;
146       fMode       = other.fMode;
147       fInitOK     = other.fInitOK;
148       fDebug      = other.fDebug;
149       fTasks      = new TObjArray(*other.fTasks);
150       fTopTasks   = new TObjArray(*other.fTopTasks);
151       fZombies    = new TObjArray(*other.fZombies);
152       fContainers = new TObjArray(*other.fContainers);
153       fInputs     = new TObjArray(*other.fInputs);
154       fOutputs    = new TObjArray(*other.fOutputs);
155       fCommonInput = NULL;
156       fCommonOutput = NULL;
157       fSelector   = NULL;
158       fGridHandler = NULL;
159       fExtraFiles = other.fExtraFiles;
160       fgCommonFileName = "AnalysisResults.root";
161       fgAnalysisManager = this;
162    }
163    return *this;
164 }
165
166 //______________________________________________________________________________
167 AliAnalysisManager::~AliAnalysisManager()
168 {
169 // Destructor.
170    if (fTasks) {fTasks->Delete(); delete fTasks;}
171    if (fTopTasks) delete fTopTasks;
172    if (fZombies) delete fZombies;
173    if (fContainers) {fContainers->Delete(); delete fContainers;}
174    if (fInputs) delete fInputs;
175    if (fOutputs) delete fOutputs;
176    if (fGridHandler) delete fGridHandler;
177    if (fgAnalysisManager==this) fgAnalysisManager = NULL;
178    TObject::SetObjectStat(kTRUE);
179 }
180
181 //______________________________________________________________________________
182 Int_t AliAnalysisManager::GetEntry(Long64_t entry, Int_t getall)
183 {
184 // Read one entry of the tree or a whole branch.
185    if (fDebug > 0) printf("== AliAnalysisManager::GetEntry(%lld)\n", entry);
186    fCurrentEntry = entry;
187    return fTree ? fTree->GetTree()->GetEntry(entry, getall) : 0;
188 }
189    
190 //______________________________________________________________________________
191 Bool_t AliAnalysisManager::Init(TTree *tree)
192 {
193   // The Init() function is called when the selector needs to initialize
194   // a new tree or chain. Typically here the branch addresses of the tree
195   // will be set. It is normaly not necessary to make changes to the
196   // generated code, but the routine can be extended by the user if needed.
197   // Init() will be called many times when running with PROOF.
198    Bool_t init = kFALSE;
199    if (!tree) return kFALSE; // Should not happen - protected in selector caller
200    if (fDebug > 0) {
201       printf("->AliAnalysisManager::Init(%s)\n", tree->GetName());
202    }
203    // Call InitTree of EventHandler
204    if (fOutputEventHandler) {
205       if (fMode == kProofAnalysis) {
206          init = fOutputEventHandler->Init(0x0, "proof");
207       } else {
208          init = fOutputEventHandler->Init(0x0, "local");
209       }
210       if (!init) {
211          Error("Init", "Output event handler failed to initialize");
212          return kFALSE;
213       }         
214    }
215    
216    if (fInputEventHandler) {
217       if (fMode == kProofAnalysis) {
218          init = fInputEventHandler->Init(tree, "proof");
219       } else {
220          init = fInputEventHandler->Init(tree, "local");
221       }
222       if (!init) {
223          Error("Init", "Input event handler failed to initialize tree"); 
224          return kFALSE;
225       }         
226    } else {
227       // If no input event handler we need to get the tree once
228       // for the chain
229       if(!tree->GetTree()) {
230          Long64_t readEntry = tree->LoadTree(0);
231          if (readEntry == -2) {
232             Error("Init", "Input tree has no entry. Aborting");
233             return kFALSE;
234          }
235       }   
236    }
237
238    if (fMCtruthEventHandler) {
239       if (fMode == kProofAnalysis) {
240          init = fMCtruthEventHandler->Init(0x0, "proof");
241       } else {
242          init = fMCtruthEventHandler->Init(0x0, "local");
243       }
244       if (!init) {
245          Error("Init", "MC event handler failed to initialize"); 
246          return kFALSE;
247       }         
248    }
249
250    if (!fInitOK) InitAnalysis();
251    if (!fInitOK) return kFALSE;
252    fTree = tree;
253    AliAnalysisDataContainer *top = fCommonInput;
254    if (!top) top = (AliAnalysisDataContainer*)fInputs->At(0);
255    if (!top) {
256       Error("Init","No top input container !");
257       return kFALSE;
258    }
259    top->SetData(tree);
260    if (fDebug > 0) {
261       printf("<-AliAnalysisManager::Init(%s)\n", tree->GetName());
262    }
263    return kTRUE;
264 }
265
266 //______________________________________________________________________________
267 void AliAnalysisManager::SlaveBegin(TTree *tree)
268 {
269   // The SlaveBegin() function is called after the Begin() function.
270   // When running with PROOF SlaveBegin() is called on each slave server.
271   // The tree argument is deprecated (on PROOF 0 is passed).
272    if (fDebug > 0) printf("->AliAnalysisManager::SlaveBegin()\n");
273    static Bool_t isCalled = kFALSE;
274    Bool_t init = kFALSE;
275    Bool_t initOK = kTRUE;
276    TString msg;
277    TDirectory *curdir = gDirectory;
278    // Call SlaveBegin only once in case of mixing
279    if (isCalled && fMode==kMixingAnalysis) return;
280    // Call Init of EventHandler
281    if (fOutputEventHandler) {
282       if (fMode == kProofAnalysis) {
283          // Merging AOD's in PROOF via TProofOutputFile
284          if (fDebug > 1) printf("   Initializing AOD output file %s...\n", fOutputEventHandler->GetOutputFileName());
285          init = fOutputEventHandler->Init("proof");
286          if (!init) msg = "Failed to initialize output handler on worker";
287       } else {
288          init = fOutputEventHandler->Init("local");
289          if (!init) msg = "Failed to initialize output handler";
290       }
291       initOK &= init;
292       if (!fSelector) Error("SlaveBegin", "Selector not set");
293       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
294    }
295
296    if (fInputEventHandler) {
297       fInputEventHandler->SetInputTree(tree);
298       if (fMode == kProofAnalysis) {
299          init = fInputEventHandler->Init("proof");
300          if (!init) msg = "Failed to initialize input handler on worker";
301       } else {
302          init = fInputEventHandler->Init("local");
303          if (!init) msg = "Failed to initialize input handler";
304       }
305       initOK &= init;
306       if (!fSelector) Error("SlaveBegin", "Selector not set");      
307       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
308    }
309
310    if (fMCtruthEventHandler) {
311       if (fMode == kProofAnalysis) {
312          init = fMCtruthEventHandler->Init("proof");
313          if (!init) msg = "Failed to initialize MC handler on worker";
314       } else {
315          init = fMCtruthEventHandler->Init("local");
316          if (!init) msg = "Failed to initialize MC handler";
317       }
318       initOK &= init;
319       if (!fSelector) Error("SlaveBegin", "Selector not set");      
320       else if (!init) {fSelector->Abort(msg); fSelector->SetStatus(-1);}
321    }
322    if (curdir) curdir->cd();
323    isCalled = kTRUE;
324    if (!initOK) return;   
325    TIter next(fTasks);
326    AliAnalysisTask *task;
327    // Call CreateOutputObjects for all tasks
328    while ((task=(AliAnalysisTask*)next())) {
329       curdir = gDirectory;
330       task->CreateOutputObjects();
331       if (curdir) curdir->cd();
332    }
333    if (fDebug > 0) printf("<-AliAnalysisManager::SlaveBegin()\n");
334 }
335
336 //______________________________________________________________________________
337 Bool_t AliAnalysisManager::Notify()
338 {
339    // The Notify() function is called when a new file is opened. This
340    // can be either for a new TTree in a TChain or when when a new TTree
341    // is started when using PROOF. It is normaly not necessary to make changes
342    // to the generated code, but the routine can be extended by the
343    // user if needed. The return value is currently not used.
344    if (!fTree) return kFALSE;
345
346    TFile *curfile = fTree->GetCurrentFile();
347    if (!curfile) {
348       Error("Notify","No current file");
349       return kFALSE;
350    }   
351    
352    if (fDebug > 0) printf("->AliAnalysisManager::Notify() file: %s\n", curfile->GetName());
353    TIter next(fTasks);
354    AliAnalysisTask *task;
355    // Call Notify for all tasks
356    while ((task=(AliAnalysisTask*)next())) 
357       task->Notify();
358         
359    // Call Notify of the event handlers
360    if (fInputEventHandler) {
361        fInputEventHandler->Notify(curfile->GetName());
362    }
363
364    if (fOutputEventHandler) {
365        fOutputEventHandler->Notify(curfile->GetName());
366    }
367
368    if (fMCtruthEventHandler) {
369        fMCtruthEventHandler->Notify(curfile->GetName());
370    }
371    if (fDebug > 0) printf("<-AliAnalysisManager::Notify()\n");
372    return kTRUE;
373 }    
374
375 //______________________________________________________________________________
376 Bool_t AliAnalysisManager::Process(Long64_t entry)
377 {
378   // The Process() function is called for each entry in the tree (or possibly
379   // keyed object in the case of PROOF) to be processed. The entry argument
380   // specifies which entry in the currently loaded tree is to be processed.
381   // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()
382   // to read either all or the required parts of the data. When processing
383   // keyed objects with PROOF, the object is already loaded and is available
384   // via the fObject pointer.
385   //
386   // This function should contain the "body" of the analysis. It can contain
387   // simple or elaborate selection criteria, run algorithms on the data
388   // of the event and typically fill histograms.
389
390   // WARNING when a selector is used with a TChain, you must use
391   //  the pointer to the current TTree to call GetEntry(entry).
392   //  The entry is always the local entry number in the current tree.
393   //  Assuming that fChain is the pointer to the TChain being processed,
394   //  use fChain->GetTree()->GetEntry(entry).
395    if (fDebug > 0) printf("->AliAnalysisManager::Process(%lld)\n", entry);
396
397    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
398    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
399    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
400    
401    GetEntry(entry);
402    ExecAnalysis();
403    if (fDebug > 0) printf("<-AliAnalysisManager::Process()\n");
404    return kTRUE;
405 }
406
407 //______________________________________________________________________________
408 void AliAnalysisManager::PackOutput(TList *target)
409 {
410   // Pack all output data containers in the output list. Called at SlaveTerminate
411   // stage in PROOF case for each slave.
412    if (fDebug > 0) printf("->AliAnalysisManager::PackOutput()\n");
413    if (!target) {
414       Error("PackOutput", "No target. Aborting.");
415       return;
416    }
417    if (fInputEventHandler)   fInputEventHandler  ->Terminate();
418    if (fOutputEventHandler)  fOutputEventHandler ->Terminate();
419    if (fMCtruthEventHandler) fMCtruthEventHandler->Terminate();
420
421    // Call FinishTaskOutput() for each event loop task (not called for 
422    // post-event loop tasks - use Terminate() fo those)
423    TIter nexttask(fTasks);
424    AliAnalysisTask *task;
425    while ((task=(AliAnalysisTask*)nexttask())) {
426       if (!task->IsPostEventLoop()) {
427          if (fDebug > 0) printf("->FinishTaskOutput: task %s\n", task->GetName());
428          task->FinishTaskOutput();
429          if (fDebug > 0) printf("<-FinishTaskOutput: task %s\n", task->GetName());
430       }
431    }      
432    
433    if (fMode == kProofAnalysis) {
434       TIter next(fOutputs);
435       AliAnalysisDataContainer *output;
436       Bool_t isManagedByHandler = kFALSE;
437       while ((output=(AliAnalysisDataContainer*)next())) {
438          // Do not consider outputs of post event loop tasks
439          isManagedByHandler = kFALSE;
440          if (output->GetProducer()->IsPostEventLoop()) continue;
441          const char *filename = output->GetFileName();
442          if (!(strcmp(filename, "default")) && fOutputEventHandler) {
443             isManagedByHandler = kTRUE;
444             printf("#### Handler output. Extra: %s\n", fExtraFiles.Data());
445             filename = fOutputEventHandler->GetOutputFileName();
446          }
447          // Check if data was posted to this container. If not, issue an error.
448          if (!output->GetData() && !isManagedByHandler) {
449             Error("PackOutput", "No data for output container %s. Forgot to PostData ?", output->GetName());
450             continue;
451          }   
452          if (!output->IsSpecialOutput()) {
453             // Normal outputs
454             if (strlen(filename) && !isManagedByHandler) {
455                // Backup current folder
456                TDirectory *opwd = gDirectory;
457                // File resident outputs. 
458                // Check first if the file exists.
459                TString open_option = "RECREATE";
460                if (!gSystem->AccessPathName(output->GetFileName())) open_option = "UPDATE";
461                TFile *file = AliAnalysisManager::OpenFile(output, open_option, kTRUE);
462                // Clear file list to release object ownership to user.
463                file->Clear();
464                // Save data to file, then close.
465                if (output->GetData()->InheritsFrom(TCollection::Class())) {
466                   // If data is a collection, we set the name of the collection 
467                   // as the one of the container and we save as a single key.
468                   TCollection *coll = (TCollection*)output->GetData();
469                   coll->SetName(output->GetName());
470                   coll->Write(output->GetName(), TObject::kSingleKey);
471                } else {
472                   if (output->GetData()->InheritsFrom(TTree::Class())) {
473                      TTree *tree = (TTree*)output->GetData();
474                      // tree->SetDirectory(file);
475                      tree->AutoSave();
476                   } else {
477                      output->GetData()->Write();
478                   }   
479                }      
480                if (fDebug > 1) printf("PackOutput %s: memory merge, file resident output\n", output->GetName());
481                if (fDebug > 2) {
482                   printf("   file %s listing content:\n", filename);
483                   file->ls();
484                }   
485                file->Close();
486                output->SetFile(NULL);
487                // Restore current directory
488                if (opwd) opwd->cd();
489             } else {
490                // Memory-resident outputs   
491                if (fDebug > 1) printf("PackOutput %s: memory merge memory resident output\n", filename);
492             }   
493             AliAnalysisDataWrapper *wrap = 0;
494             if (isManagedByHandler) {
495                wrap = new AliAnalysisDataWrapper(fOutputEventHandler->GetTree());
496                wrap->SetName(output->GetName());
497             }   
498             else                    wrap =output->ExportData();
499             // Output wrappers must NOT delete data after merging - the user owns them
500             wrap->SetDeleteData(kFALSE);
501             target->Add(wrap);
502          } else {
503          // Special outputs. The file must be opened and connected to the container.
504             TDirectory *opwd = gDirectory;
505             TFile *file = output->GetFile();
506             if (!file) {
507                AliAnalysisTask *producer = output->GetProducer();
508                Fatal("PackOutput", 
509                      "File %s for special container %s was NOT opened in %s::CreateOutputObjects !!!",
510                      output->GetFileName(), output->GetName(), producer->ClassName());
511                continue;
512             }   
513             TString outFilename = file->GetName();
514             if (fDebug > 1) printf("PackOutput %s: special output\n", output->GetName());
515             if (isManagedByHandler) {
516                // Terminate IO for files managed by the output handler
517                // file->Write() moved to AOD handler (A.G. 11.01.10)
518 //               if (file) file->Write();
519                if (file && fDebug > 2) {
520                   printf("   handled file %s listing content:\n", file->GetName());
521                   file->ls();
522                }   
523                fOutputEventHandler->TerminateIO();
524             } else {               
525                file->cd();
526                // Release object ownership to users after writing data to file
527                if (output->GetData()->InheritsFrom(TCollection::Class())) {
528                   // If data is a collection, we set the name of the collection 
529                   // as the one of the container and we save as a single key.
530                   TCollection *coll = (TCollection*)output->GetData();
531                   coll->SetName(output->GetName());
532                   coll->Write(output->GetName(), TObject::kSingleKey);
533                } else {
534                   if (output->GetData()->InheritsFrom(TTree::Class())) {
535                      TTree *tree = (TTree*)output->GetData();
536                      tree->SetDirectory(file);
537                      tree->AutoSave();
538                   } else {
539                      output->GetData()->Write();
540                   }   
541                }      
542                file->Clear();
543                if (fDebug > 2) {
544                   printf("   file %s listing content:\n", output->GetFileName());
545                   file->ls();
546                }
547                file->Close();
548                output->SetFile(NULL);
549             }
550             // Restore current directory
551             if (opwd) opwd->cd();
552             // Check if a special output location was provided or the output files have to be merged
553             if (strlen(fSpecialOutputLocation.Data())) {
554                TString remote = fSpecialOutputLocation;
555                remote += "/";
556                Int_t gid = gROOT->ProcessLine("gProofServ->GetGroupId();");
557                if (remote.BeginsWith("alien://")) {
558                   gROOT->ProcessLine("TGrid::Connect(\"alien://pcapiserv01.cern.ch:10000\", gProofServ->GetUser());");
559                   remote += outFilename;
560                   remote.ReplaceAll(".root", Form("_%d.root", gid));
561                } else {   
562                   remote += Form("%s_%d_", gSystem->HostName(), gid);
563                   remote += outFilename;
564                }   
565                if (fDebug > 1) 
566                   Info("PackOutput", "Output file for container %s to be copied \n   at: %s. No merging.",
567                        output->GetName(), remote.Data());
568                TFile::Cp ( outFilename.Data(), remote.Data() );
569                // Copy extra outputs
570                if (fExtraFiles.Length() && isManagedByHandler) {
571                   TObjArray *arr = fExtraFiles.Tokenize(" ");
572                   TObjString *os;
573                   TIter nextfilename(arr);
574                   while ((os=(TObjString*)nextfilename())) {
575                      outFilename = os->GetString();
576                      remote = fSpecialOutputLocation;
577                      remote += "/";
578                      if (remote.BeginsWith("alien://")) {
579                         remote += outFilename;
580                         remote.ReplaceAll(".root", Form("_%d.root", gid));
581                      } else {   
582                         remote += Form("%s_%d_", gSystem->HostName(), gid);
583                         remote += outFilename;
584                      }   
585                      if (fDebug > 1) 
586                         Info("PackOutput", "Extra AOD file %s to be copied \n   at: %s. No merging.",
587                              outFilename.Data(), remote.Data());
588                      TFile::Cp ( outFilename.Data(), remote.Data() );
589                   }   
590                   delete arr;
591                }   
592             } else {
593             // No special location specified-> use TProofOutputFile as merging utility
594             // The file at this output slot must be opened in CreateOutputObjects
595                if (fDebug > 1) printf("   File for container %s to be merged via file merger...\n", output->GetName());
596             }
597          }      
598       }
599    } 
600    if (fDebug > 0) printf("<-AliAnalysisManager::PackOutput: output list contains %d containers\n", target->GetSize());
601 }
602
603 //______________________________________________________________________________
604 void AliAnalysisManager::ImportWrappers(TList *source)
605 {
606 // Import data in output containers from wrappers coming in source.
607    if (fDebug > 0) printf("->AliAnalysisManager::ImportWrappers()\n");
608    TIter next(fOutputs);
609    AliAnalysisDataContainer *cont;
610    AliAnalysisDataWrapper   *wrap;
611    Int_t icont = 0;
612    Bool_t inGrid = (fMode == kGridAnalysis)?kTRUE:kFALSE;
613    TDirectory *cdir = gDirectory;
614    while ((cont=(AliAnalysisDataContainer*)next())) {
615       wrap = 0;
616       if (cont->GetProducer()->IsPostEventLoop() && !inGrid) continue;
617       if (cont->IsRegisterDataset()) continue;
618       const char *filename = cont->GetFileName();
619       Bool_t isManagedByHandler = kFALSE;
620       if (!(strcmp(filename, "default")) && fOutputEventHandler) {
621          isManagedByHandler = kTRUE;
622          filename = fOutputEventHandler->GetOutputFileName();
623       }
624       if (cont->IsSpecialOutput() || inGrid) {
625          if (strlen(fSpecialOutputLocation.Data())) continue;
626          // Copy merged file from PROOF scratch space. 
627          // In case of grid the files are already in the current directory.
628          if (!inGrid) {
629             if (isManagedByHandler && fExtraFiles.Length()) {
630                // Copy extra registered dAOD files.
631                TObjArray *arr = fExtraFiles.Tokenize(" ");
632                TObjString *os;
633                TIter nextfilename(arr);
634                while ((os=(TObjString*)nextfilename())) GetFileFromWrapper(os->GetString(), source);
635                delete arr;
636             }
637             if (!GetFileFromWrapper(filename, source)) continue;
638          }   
639          // Normally we should connect data from the copied file to the
640          // corresponding output container, but it is not obvious how to do this
641          // automatically if several objects in file...
642          TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
643          if (!f) f = TFile::Open(filename, "READ");
644          if (!f) {
645             Error("ImportWrappers", "Cannot open file %s in read-only mode", filename);
646             continue;
647          }   
648          TObject *obj = 0;
649          // Cd to the directory pointed by the container
650          TString folder = cont->GetFolderName();
651          if (!folder.IsNull()) f->cd(folder);
652          // Try to fetch first an object having the container name.
653          obj = gDirectory->Get(cont->GetName());
654          if (!obj) {
655             Warning("ImportWrappers", "Could not import object for container %s in file %s:%s.\n Object will not be available in Terminate()", 
656                     cont->GetName(), filename, cont->GetFolderName());
657             continue;
658          }  
659          wrap = new AliAnalysisDataWrapper(obj);
660          wrap->SetDeleteData(kFALSE);
661       }   
662       if (!wrap) wrap = (AliAnalysisDataWrapper*)source->FindObject(cont->GetName());
663       if (!wrap) {
664          Error("ImportWrappers","Container %s not found in analysis output !", cont->GetName());
665          continue;
666       }
667       icont++;
668       if (fDebug > 1) {
669          printf("   Importing data for container %s\n", cont->GetName());
670          if (strlen(filename)) printf("    -> file %s\n", filename);
671          else printf("\n");
672       }   
673       cont->ImportData(wrap);
674    }
675    if (cdir) cdir->cd();
676    if (fDebug > 0) printf("<-AliAnalysisManager::ImportWrappers(): %d containers imported\n", icont);
677 }
678
679 //______________________________________________________________________________
680 void AliAnalysisManager::UnpackOutput(TList *source)
681 {
682   // Called by AliAnalysisSelector::Terminate only on the client.
683    if (fDebug > 0) printf("->AliAnalysisManager::UnpackOutput()\n");
684    if (!source) {
685       Error("UnpackOutput", "No target. Aborting.");
686       return;
687    }
688    if (fDebug > 1) printf("   Source list contains %d containers\n", source->GetSize());
689
690    if (fMode == kProofAnalysis) ImportWrappers(source);
691
692    TIter next(fOutputs);
693    AliAnalysisDataContainer *output;
694    while ((output=(AliAnalysisDataContainer*)next())) {
695       if (!output->GetData()) continue;
696       // Check if there are client tasks that run post event loop
697       if (output->HasConsumers()) {
698          // Disable event loop semaphore
699          output->SetPostEventLoop(kTRUE);
700          TObjArray *list = output->GetConsumers();
701          Int_t ncons = list->GetEntriesFast();
702          for (Int_t i=0; i<ncons; i++) {
703             AliAnalysisTask *task = (AliAnalysisTask*)list->At(i);
704             task->CheckNotify(kTRUE);
705             // If task is active, execute it
706             if (task->IsPostEventLoop() && task->IsActive()) {
707                if (fDebug > 0) printf("== Executing post event loop task %s\n", task->GetName());
708                task->ExecuteTask();
709             }   
710          }
711       }   
712    }
713    if (fDebug > 0) printf("<-AliAnalysisManager::UnpackOutput()\n");
714 }
715
716 //______________________________________________________________________________
717 void AliAnalysisManager::Terminate()
718 {
719   // The Terminate() function is the last function to be called during
720   // a query. It always runs on the client, it can be used to present
721   // the results graphically.
722    if (fDebug > 0) printf("->AliAnalysisManager::Terminate()\n");
723    AliAnalysisTask *task;
724    AliAnalysisDataContainer *output;
725    TIter next(fTasks);
726    TStopwatch timer;
727    // Call Terminate() for tasks
728    while (!IsSkipTerminate() && (task=(AliAnalysisTask*)next())) {
729       // Save all the canvases produced by the Terminate
730       TString pictname = Form("%s_%s", task->GetName(), task->ClassName());
731       task->Terminate();
732       if (TObject::TestBit(kSaveCanvases)) {
733          if (!gROOT->IsBatch()) {
734             Warning("Terminate", "Waiting 5 sec for %s::Terminate() to finish drawing", task->ClassName());
735             timer.Start();
736             while (timer.CpuTime()<5) {
737                timer.Continue();
738                gSystem->ProcessEvents();
739             }
740          }
741          Int_t iend = gROOT->GetListOfCanvases()->GetEntries();
742          if (iend==0) continue;
743          TCanvas *canvas;
744          for (Int_t ipict=0; ipict<iend; ipict++) {
745             canvas = (TCanvas*)gROOT->GetListOfCanvases()->At(ipict);
746             if (!canvas) continue;         
747             canvas->SaveAs(Form("%s_%02d.gif", pictname.Data(),ipict));
748          } 
749          gROOT->GetListOfCanvases()->Delete(); 
750       }
751    }   
752    //
753    if (fInputEventHandler)   fInputEventHandler  ->TerminateIO();
754    if (fOutputEventHandler)  fOutputEventHandler ->TerminateIO();
755    if (fMCtruthEventHandler) fMCtruthEventHandler->TerminateIO();
756    TIter next1(fOutputs);
757    TString handlerFile = "";
758    if (fOutputEventHandler) {
759       handlerFile = fOutputEventHandler->GetOutputFileName();
760    }
761    while ((output=(AliAnalysisDataContainer*)next1())) {
762       // Special outputs or grid files have the files already closed and written.
763       if (fMode == kGridAnalysis) continue;
764       if (fMode == kProofAnalysis) {
765         if (output->IsSpecialOutput() || output->IsRegisterDataset()) continue;
766       }  
767       const char *filename = output->GetFileName();
768       TString open_option = "RECREATE";
769       if (!(strcmp(filename, "default"))) continue;
770       if (!strlen(filename)) continue;
771       if (!output->GetData()) continue;
772       TDirectory *opwd = gDirectory;
773       TFile *file = output->GetFile();
774       if (!file) file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
775       if (!file) {
776               printf("Terminate : handlerFile = %s, filename = %s\n",handlerFile.Data(),filename);
777               //if (handlerFile == filename && !gSystem->AccessPathName(filename)) open_option = "UPDATE";
778          if (!gSystem->AccessPathName(filename)) open_option = "UPDATE";
779          file = new TFile(filename, open_option);
780       }
781       if (file->IsZombie()) {
782          Error("Terminate", "Cannot open output file %s", filename);
783          continue;
784       }   
785       output->SetFile(file);
786       file->cd();
787       // Check for a folder request
788       TString dir = output->GetFolderName();
789       if (!dir.IsNull()) {
790          if (!file->GetDirectory(dir)) file->mkdir(dir);
791          file->cd(dir);
792       }  
793       if (fDebug > 1) printf("   writing output data %s to file %s:%s\n", output->GetData()->GetName(), file->GetName(), output->GetFolderName());
794       if (output->GetData()->InheritsFrom(TCollection::Class())) {
795       // If data is a collection, we set the name of the collection 
796       // as the one of the container and we save as a single key.
797          TCollection *coll = (TCollection*)output->GetData();
798          coll->SetName(output->GetName());
799          coll->Write(output->GetName(), TObject::kSingleKey);
800       } else {
801          if (output->GetData()->InheritsFrom(TTree::Class())) {
802             TTree *tree = (TTree*)output->GetData();
803             tree->SetDirectory(file);
804             tree->AutoSave();
805          } else {
806             output->GetData()->Write();
807          }   
808       }      
809       if (opwd) opwd->cd();
810    }   
811    next1.Reset();
812    while ((output=(AliAnalysisDataContainer*)next1())) {
813       // Close all files at output
814       TDirectory *opwd = gDirectory;
815       if (output->GetFile()) {
816          output->GetFile()->Close();
817          output->SetFile(NULL);
818          // Copy merged outputs in alien if requested
819          if (fSpecialOutputLocation.Length() && 
820              fSpecialOutputLocation.BeginsWith("alien://")) {
821             Info("Terminate", "Copy file %s to %s", output->GetFile()->GetName(),fSpecialOutputLocation.Data()); 
822             TFile::Cp(output->GetFile()->GetName(), 
823                       Form("%s/%s", fSpecialOutputLocation.Data(), output->GetFile()->GetName()));
824          }             
825       }   
826       if (opwd) opwd->cd();
827    }   
828
829    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
830    if (getsysInfo) {
831       TDirectory *cdir = gDirectory;
832       TFile f("syswatch.root", "RECREATE");
833       if (!f.IsZombie()) {
834          TTree *tree = AliSysInfo::MakeTree("syswatch.log");
835          tree->SetMarkerStyle(kCircle);
836          tree->SetMarkerColor(kBlue);
837          tree->SetMarkerSize(0.5);
838          if (!gROOT->IsBatch()) {
839             tree->SetAlias("event", "id0");
840             tree->SetAlias("memUSED", "mi.fMemUsed");
841             new TCanvas("SysInfo","SysInfo",10,10,800,600);
842             tree->Draw("memUSED:event","","", 1234567890, 0);
843          }   
844          tree->Write();
845          f.Close();
846          delete tree;
847       }
848       if (cdir) cdir->cd();
849    }
850    // Validate the output files
851    if (ValidateOutputFiles()) {
852       ofstream out;
853       out.open("outputs_valid", ios::out);
854       out.close();
855    }      
856    if (fDebug > 0) printf("<-AliAnalysisManager::Terminate()\n");
857 }
858
859 //______________________________________________________________________________
860 void AliAnalysisManager::AddTask(AliAnalysisTask *task)
861 {
862 // Adds a user task to the global list of tasks.
863    if (fTasks->FindObject(task)) {
864       Warning("AddTask", "Task %s: the same object already added to the analysis manager. Not adding.", task->GetName());
865       return;
866    }   
867    task->SetActive(kFALSE);
868    fTasks->Add(task);
869 }  
870
871 //______________________________________________________________________________
872 AliAnalysisTask *AliAnalysisManager::GetTask(const char *name) const
873 {
874 // Retreive task by name.
875    if (!fTasks) return NULL;
876    return (AliAnalysisTask*)fTasks->FindObject(name);
877 }
878
879 //______________________________________________________________________________
880 AliAnalysisDataContainer *AliAnalysisManager::CreateContainer(const char *name, 
881                                 TClass *datatype, EAliAnalysisContType type, const char *filename)
882 {
883 // Create a data container of a certain type. Types can be:
884 //   kExchangeContainer  = 0, used to exchange data between tasks
885 //   kInputContainer   = 1, used to store input data
886 //   kOutputContainer  = 2, used for writing result to a file
887 // filename: composed by file#folder (e.g. results.root#INCLUSIVE) - will write
888 // the output object to a folder inside the output file
889    if (fContainers->FindObject(name)) {
890       Error("CreateContainer","A container named %s already defined !",name);
891       return NULL;
892    }   
893    AliAnalysisDataContainer *cont = new AliAnalysisDataContainer(name, datatype);
894    fContainers->Add(cont);
895    switch (type) {
896       case kInputContainer:
897          fInputs->Add(cont);
898          break;
899       case kOutputContainer:
900          fOutputs->Add(cont);
901          if (filename && strlen(filename)) {
902             cont->SetFileName(filename);
903             cont->SetDataOwned(kFALSE);  // data owned by the file
904          }   
905          break;
906       case kExchangeContainer:
907          break;   
908    }
909    return cont;
910 }
911          
912 //______________________________________________________________________________
913 Bool_t AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
914                                         AliAnalysisDataContainer *cont)
915 {
916 // Connect input of an existing task to a data container.
917    if (!task) {
918       Error("ConnectInput", "Task pointer is NULL");
919       return kFALSE;
920    }   
921    if (!fTasks->FindObject(task)) {
922       AddTask(task);
923       Info("ConnectInput", "Task %s was not registered. Now owned by analysis manager", task->GetName());
924    } 
925    Bool_t connected = task->ConnectInput(islot, cont);
926    return connected;
927 }   
928
929 //______________________________________________________________________________
930 Bool_t AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
931                                         AliAnalysisDataContainer *cont)
932 {
933 // Connect output of an existing task to a data container.
934    if (!task) {
935       Error("ConnectOutput", "Task pointer is NULL");
936       return kFALSE;
937    }   
938    if (!fTasks->FindObject(task)) {
939       AddTask(task);
940       Warning("ConnectOutput", "Task %s not registered. Now owned by analysis manager", task->GetName());
941    } 
942    Bool_t connected = task->ConnectOutput(islot, cont);
943    return connected;
944 }   
945                                
946 //______________________________________________________________________________
947 void AliAnalysisManager::CleanContainers()
948 {
949 // Clean data from all containers that have already finished all client tasks.
950    TIter next(fContainers);
951    AliAnalysisDataContainer *cont;
952    while ((cont=(AliAnalysisDataContainer *)next())) {
953       if (cont->IsOwnedData() && 
954           cont->IsDataReady() && 
955           cont->ClientsExecuted()) cont->DeleteData();
956    }
957 }
958
959 //______________________________________________________________________________
960 Bool_t AliAnalysisManager::InitAnalysis()
961 {
962 // Initialization of analysis chain of tasks. Should be called after all tasks
963 // and data containers are properly connected
964    // Reset flag and remove valid_outputs file if exists
965    fInitOK = kFALSE;
966    if (!gSystem->AccessPathName("outputs_valid"))
967       gSystem->Unlink("outputs_valid");
968    // Check for top tasks (depending only on input data containers)
969    if (!fTasks->First()) {
970       Error("InitAnalysis", "Analysis has no tasks !");
971       return kFALSE;
972    }   
973    TIter next(fTasks);
974    AliAnalysisTask *task;
975    AliAnalysisDataContainer *cont;
976    Int_t ntop = 0;
977    Int_t nzombies = 0;
978    Bool_t iszombie = kFALSE;
979    Bool_t istop = kTRUE;
980    Int_t i;
981    while ((task=(AliAnalysisTask*)next())) {
982       istop = kTRUE;
983       iszombie = kFALSE;
984       Int_t ninputs = task->GetNinputs();
985       for (i=0; i<ninputs; i++) {
986          cont = task->GetInputSlot(i)->GetContainer();
987          if (!cont) {
988             if (!iszombie) {
989                task->SetZombie();
990                fZombies->Add(task);
991                nzombies++;
992                iszombie = kTRUE;
993             }   
994             Error("InitAnalysis", "Input slot %d of task %s has no container connected ! Declared zombie...", 
995                   i, task->GetName()); 
996          }
997          if (iszombie) continue;
998          // Check if cont is an input container
999          if (istop && !fInputs->FindObject(cont)) istop=kFALSE;
1000          // Connect to parent task
1001       }
1002       if (istop) {
1003          ntop++;
1004          fTopTasks->Add(task);
1005       }
1006    }
1007    if (!ntop) {
1008       Error("InitAnalysis", "No top task defined. At least one task should be connected only to input containers");
1009       return kFALSE;
1010    }                        
1011    // Check now if there are orphan tasks
1012    for (i=0; i<ntop; i++) {
1013       task = (AliAnalysisTask*)fTopTasks->At(i);
1014       task->SetUsed();
1015    }
1016    Int_t norphans = 0;
1017    next.Reset();
1018    while ((task=(AliAnalysisTask*)next())) {
1019       if (!task->IsUsed()) {
1020          norphans++;
1021          Warning("InitAnalysis", "Task %s is orphan", task->GetName());
1022       }   
1023    }          
1024    // Check the task hierarchy (no parent task should depend on data provided
1025    // by a daughter task)
1026    for (i=0; i<ntop; i++) {
1027       task = (AliAnalysisTask*)fTopTasks->At(i);
1028       if (task->CheckCircularDeps()) {
1029          Error("InitAnalysis", "Found illegal circular dependencies between following tasks:");
1030          PrintStatus("dep");
1031          return kFALSE;
1032       }   
1033    }
1034    // Check that all containers feeding post-event loop tasks are in the outputs list
1035    TIter nextcont(fContainers); // loop over all containers
1036    while ((cont=(AliAnalysisDataContainer*)nextcont())) {
1037       if (!cont->IsPostEventLoop() && !fOutputs->FindObject(cont)) {
1038          if (cont->HasConsumers()) {
1039          // Check if one of the consumers is post event loop
1040             TIter nextconsumer(cont->GetConsumers());
1041             while ((task=(AliAnalysisTask*)nextconsumer())) {
1042                if (task->IsPostEventLoop()) {
1043                   fOutputs->Add(cont);
1044                   break;
1045                }
1046             }
1047          }
1048       }
1049    }   
1050    // Check if all special output containers have a file name provided
1051    TIter nextout(fOutputs);
1052    while ((cont=(AliAnalysisDataContainer*)nextout())) {
1053       if (cont->IsSpecialOutput() && !strlen(cont->GetFileName())) {
1054          Error("InitAnalysis", "Wrong container %s : a file name MUST be provided for special outputs", cont->GetName());
1055          return kFALSE;
1056       }
1057    }      
1058    fInitOK = kTRUE;
1059    return kTRUE;
1060 }   
1061
1062 //______________________________________________________________________________
1063 void AliAnalysisManager::PrintStatus(Option_t *option) const
1064 {
1065 // Print task hierarchy.
1066    if (!fInitOK) {
1067       Info("PrintStatus", "Analysis manager %s not initialized : call InitAnalysis() first", GetName());
1068       return;
1069    }   
1070    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1071    if (getsysInfo)
1072       Info("PrintStatus", "System information will be collected each %lld events", fNSysInfo);
1073    TIter next(fTopTasks);
1074    AliAnalysisTask *task;
1075    while ((task=(AliAnalysisTask*)next()))
1076       task->PrintTask(option);
1077 }
1078
1079 //______________________________________________________________________________
1080 void AliAnalysisManager::ResetAnalysis()
1081 {
1082 // Reset all execution flags and clean containers.
1083    CleanContainers();
1084 }
1085
1086 //______________________________________________________________________________
1087 void AliAnalysisManager::StartAnalysis(const char *type, TTree *tree, Long64_t nentries, Long64_t firstentry)
1088 {
1089 // Start analysis for this manager. Analysis task can be: LOCAL, PROOF, GRID or
1090 // MIX. Process nentries starting from firstentry
1091    if (!fInitOK) {
1092       Error("StartAnalysis","Analysis manager was not initialized !");
1093       return;
1094    }
1095    if (fDebug > 0) printf("StartAnalysis %s\n",GetName());
1096    TString anaType = type;
1097    anaType.ToLower();
1098    fMode = kLocalAnalysis;
1099    Bool_t runlocalinit = kTRUE;
1100    if (anaType.Contains("file")) {
1101       runlocalinit = kFALSE;
1102    }   
1103    if (anaType.Contains("proof"))     fMode = kProofAnalysis;
1104    else if (anaType.Contains("grid")) fMode = kGridAnalysis;
1105    else if (anaType.Contains("mix"))  fMode = kMixingAnalysis;
1106
1107    if (fMode == kGridAnalysis) {
1108       if (!fGridHandler) {
1109          Error("StartAnalysis", "Cannot start grid analysis without a grid handler.");
1110          Info("===", "Add an AliAnalysisAlien object as plugin for this manager and configure it.");
1111          return;
1112       }
1113       // Write analysis manager in the analysis file
1114       cout << "===== RUNNING GRID ANALYSIS: " << GetName() << endl;
1115       // run local task configuration
1116       TIter nextTask(fTasks);
1117       AliAnalysisTask *task;
1118       while ((task=(AliAnalysisTask*)nextTask())) {
1119          task->LocalInit();
1120       }
1121       if (!fGridHandler->StartAnalysis(nentries, firstentry)) {
1122          Info("StartAnalysis", "Grid analysis was stopped and cannot be terminated");
1123          return;
1124       }   
1125
1126       // Terminate grid analysis
1127       if (fSelector && fSelector->GetStatus() == -1) return;
1128       if (fGridHandler->GetRunMode() == AliAnalysisGrid::kOffline) return;
1129       cout << "===== MERGING OUTPUTS REGISTERED BY YOUR ANALYSIS JOB: " << GetName() << endl;
1130       if (!fGridHandler->MergeOutputs()) {
1131          // Return if outputs could not be merged or if it alien handler
1132          // was configured for offline mode or local testing.
1133          return;
1134       }
1135       ImportWrappers(NULL);
1136       Terminate();
1137       return;
1138    }
1139    char line[256];
1140    SetEventLoop(kFALSE);
1141    // Enable event loop mode if a tree was provided
1142    if (tree || fMode==kMixingAnalysis) SetEventLoop(kTRUE);
1143
1144    TChain *chain = 0;
1145    TString ttype = "TTree";
1146    if (tree && tree->IsA() == TChain::Class()) {
1147       chain = (TChain*)tree;
1148       if (!chain || !chain->GetListOfFiles()->First()) {
1149          Error("StartAnalysis", "Cannot process null or empty chain...");
1150          return;
1151       }   
1152       ttype = "TChain";
1153    }   
1154
1155    // Initialize locally all tasks (happens for all modes)
1156    TIter next(fTasks);
1157    AliAnalysisTask *task;
1158    if (runlocalinit) {
1159       while ((task=(AliAnalysisTask*)next())) {
1160          task->LocalInit();
1161       }
1162    }   
1163    
1164    switch (fMode) {
1165       case kLocalAnalysis:
1166          if (!tree) {
1167             TIter nextT(fTasks);
1168             // Call CreateOutputObjects for all tasks
1169             while ((task=(AliAnalysisTask*)nextT())) {
1170                TDirectory *curdir = gDirectory;
1171                task->CreateOutputObjects();
1172                if (curdir) curdir->cd();
1173             }   
1174             if (IsExternalLoop()) {
1175                Info("StartAnalysis", "Initialization done. Event loop is controlled externally.\
1176                      \nSetData for top container, call ExecAnalysis in a loop and then Terminate manually");
1177                return;
1178             }         
1179             ExecAnalysis();
1180             Terminate();
1181             return;
1182          } 
1183          // Run tree-based analysis via AliAnalysisSelector  
1184          cout << "===== RUNNING LOCAL ANALYSIS " << GetName() << " ON TREE " << tree->GetName() << endl;
1185          fSelector = new AliAnalysisSelector(this);
1186          tree->Process(fSelector, "", nentries, firstentry);
1187          break;
1188       case kProofAnalysis:
1189          if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1190             Error("StartAnalysis", "No PROOF!!! Aborting.");
1191             return;
1192          }   
1193          sprintf(line, "gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1194          gROOT->ProcessLine(line);
1195          if (chain) {
1196             chain->SetProof();
1197             cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON CHAIN " << chain->GetName() << endl;
1198             chain->Process("AliAnalysisSelector", "", nentries, firstentry);
1199          } else {
1200             Error("StartAnalysis", "No chain!!! Aborting.");
1201             return;
1202          }      
1203          break;
1204       case kGridAnalysis:
1205          Warning("StartAnalysis", "GRID analysis mode not implemented. Running local.");
1206          break;
1207       case kMixingAnalysis:   
1208          // Run event mixing analysis
1209          if (!fEventPool) {
1210             Error("StartAnalysis", "Cannot run event mixing without event pool");
1211             return;
1212          }
1213          cout << "===== RUNNING EVENT MIXING ANALYSIS " << GetName() << endl;
1214          fSelector = new AliAnalysisSelector(this);
1215          while ((chain=fEventPool->GetNextChain())) {
1216             next.Reset();
1217             // Call NotifyBinChange for all tasks
1218             while ((task=(AliAnalysisTask*)next()))
1219                if (!task->IsPostEventLoop()) task->NotifyBinChange();
1220             chain->Process(fSelector);
1221          }
1222          PackOutput(fSelector->GetOutputList());
1223          Terminate();
1224    }   
1225 }   
1226
1227 //______________________________________________________________________________
1228 void AliAnalysisManager::StartAnalysis(const char *type, const char *dataset, Long64_t nentries, Long64_t firstentry)
1229 {
1230 // Start analysis for this manager on a given dataset. Analysis task can be: 
1231 // LOCAL, PROOF or GRID. Process nentries starting from firstentry.
1232    if (!fInitOK) {
1233       Error("StartAnalysis","Analysis manager was not initialized !");
1234       return;
1235    }
1236    if (fDebug > 0) printf("StartAnalysis %s\n",GetName());
1237    TString anaType = type;
1238    anaType.ToLower();
1239    if (!anaType.Contains("proof")) {
1240       Error("StartAnalysis", "Cannot process datasets in %s mode. Try PROOF.", type);
1241       return;
1242    }   
1243    fMode = kProofAnalysis;
1244    char line[256];
1245    SetEventLoop(kTRUE);
1246    // Set the dataset flag
1247    TObject::SetBit(kUseDataSet);
1248    fTree = 0;
1249
1250    // Initialize locally all tasks
1251    TIter next(fTasks);
1252    AliAnalysisTask *task;
1253    while ((task=(AliAnalysisTask*)next())) {
1254       task->LocalInit();
1255    }
1256    
1257    if (!gROOT->GetListOfProofs() || !gROOT->GetListOfProofs()->GetEntries()) {
1258       Error("StartAnalysis", "No PROOF!!! Aborting.");
1259       return;
1260    }   
1261    sprintf(line, "gProof->AddInput((TObject*)0x%lx);", (ULong_t)this);
1262    gROOT->ProcessLine(line);
1263    sprintf(line, "gProof->GetDataSet(\"%s\");", dataset);
1264    if (!gROOT->ProcessLine(line)) {
1265       Error("StartAnalysis", "Dataset %s not found", dataset);
1266       return;
1267    }   
1268    sprintf(line, "gProof->Process(\"%s\", \"AliAnalysisSelector\", \"\", %lld, %lld);",
1269            dataset, nentries, firstentry);
1270    cout << "===== RUNNING PROOF ANALYSIS " << GetName() << " ON DATASET " << dataset << endl;
1271    gROOT->ProcessLine(line);
1272 }   
1273
1274 //______________________________________________________________________________
1275 TFile *AliAnalysisManager::OpenFile(AliAnalysisDataContainer *cont, const char *option, Bool_t ignoreProof)
1276 {
1277 // Opens according the option the file specified by cont->GetFileName() and changes
1278 // current directory to cont->GetFolderName(). If the file was already opened, it
1279 // checks if the option UPDATE was preserved. File open via TProofOutputFile can
1280 // be optionally ignored.
1281   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1282   TString filename = cont->GetFileName();
1283   TFile *f = NULL;
1284   if (filename.IsNull()) {
1285     ::Error("AliAnalysisManager::OpenFile", "No file name specified for container %s", cont->GetName());
1286     return NULL;
1287   }
1288   if (mgr->GetAnalysisType()==AliAnalysisManager::kProofAnalysis && cont->IsSpecialOutput()
1289       && !ignoreProof)
1290     f = mgr->OpenProofFile(cont,option);
1291   else {
1292     // Check first if the file is already opened
1293     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1294     if (f) {
1295       // Check if option "UPDATE" was preserved 
1296       TString opt(option);
1297       opt.ToUpper();
1298       if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1299         ::Info("AliAnalysisManager::OpenFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1300     } else {
1301       f = TFile::Open(filename, option);
1302     }    
1303   }   
1304   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1305     cont->SetFile(f);
1306     // Cd to file
1307     f->cd();
1308     // Check for a folder request
1309     TString dir = cont->GetFolderName(); 
1310     if (!dir.IsNull()) {
1311       if (!f->GetDirectory(dir)) f->mkdir(dir);
1312       f->cd(dir);
1313     }
1314     return f;
1315   }
1316   ::Fatal("AliAnalysisManager::OpenFile", "File %s could not be opened", filename.Data());
1317   cont->SetFile(NULL);
1318   return NULL;
1319 }    
1320  
1321 //______________________________________________________________________________
1322 TFile *AliAnalysisManager::OpenProofFile(AliAnalysisDataContainer *cont, const char *option)
1323 {
1324 // Opens a special output file used in PROOF.
1325   TString line;
1326   TString filename = cont->GetFileName();
1327   if (cont == fCommonOutput) {
1328      if (fOutputEventHandler) filename = fOutputEventHandler->GetOutputFileName();
1329      else Fatal("OpenProofFile","No output container. Aborting.");
1330   }   
1331   TFile *f = NULL;
1332   if (fMode!=kProofAnalysis || !fSelector) {
1333     Fatal("OpenProofFile","Cannot open PROOF file %s: no PROOF or selector",filename.Data());
1334     return NULL;
1335   } 
1336   if (fSpecialOutputLocation.Length()) {
1337     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1338     if (f) {
1339       // Check if option "UPDATE" was preserved 
1340       TString opt(option);
1341       opt.ToUpper();
1342       if ((opt=="UPDATE") && (opt!=f->GetOption()))
1343         ::Info("OpenProofFile", "File %s already opened in %s mode!", cont->GetFileName(), f->GetOption());
1344     } else {
1345       f = new TFile(filename, option);
1346     }
1347     if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1348       cont->SetFile(f);
1349       // Cd to file
1350       f->cd();
1351       // Check for a folder request
1352       TString dir = cont->GetFolderName(); 
1353       if (dir.Length()) {
1354         if (!f->GetDirectory(dir)) f->mkdir(dir);
1355         f->cd(dir);
1356       }      
1357       return f;
1358     }
1359     Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1360     cont->SetFile(NULL);
1361     return NULL;       
1362   }
1363   // Check if there is already a proof output file in the output list
1364   TObject *pof = fSelector->GetOutputList()->FindObject(filename);
1365   if (pof) {
1366     // Get the actual file
1367     line = Form("((TProofOutputFile*)0x%lx)->GetFileName();", (ULong_t)pof);
1368     filename = (const char*)gROOT->ProcessLine(line);
1369     if (fDebug>1) {
1370       printf("File: %s already booked via TProofOutputFile\n", filename.Data());
1371     }  
1372     f = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1373     if (!f) Fatal("OpenProofFile", "Proof output file found but no file opened for %s", filename.Data());
1374     // Check if option "UPDATE" was preserved 
1375     TString opt(option);
1376     opt.ToUpper();
1377     if ((opt=="UPDATE") && (opt!=f->GetOption())) 
1378       Fatal("OpenProofFile", "File %s already opened, but not in UPDATE mode!", cont->GetFileName());
1379   } else {
1380     if (cont->IsRegisterDataset()) {
1381       TString dset_name = filename;
1382       dset_name.ReplaceAll(".root", cont->GetTitle());
1383       dset_name.ReplaceAll(":","_");
1384       if (fDebug>1) printf("Booking dataset: %s\n", dset_name.Data());
1385       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\", \"DROV\", \"%s\");", filename.Data(), dset_name.Data());
1386     } else {
1387       if (fDebug>1) printf("Booking TProofOutputFile: %s to be merged\n", filename.Data());
1388       line = Form("TProofOutputFile *pf = new TProofOutputFile(\"%s\");", filename.Data());
1389     }
1390     if (fDebug > 1) printf("=== %s\n", line.Data());
1391     gROOT->ProcessLine(line);
1392     line = Form("pf->OpenFile(\"%s\");", option);
1393     gROOT->ProcessLine(line);
1394     f = gFile;
1395     if (fDebug > 1) {
1396       gROOT->ProcessLine("pf->Print()");
1397       printf(" == proof file name: %s", f->GetName());
1398     }   
1399     // Add to proof output list
1400     line = Form("((TList*)0x%lx)->Add(pf);",(ULong_t)fSelector->GetOutputList());
1401     if (fDebug > 1) printf("=== %s\n", line.Data());
1402     gROOT->ProcessLine(line);
1403   }
1404   if (f && !f->IsZombie() && !f->TestBit(TFile::kRecovered)) {
1405     cont->SetFile(f);
1406     // Cd to file
1407     f->cd();
1408     // Check for a folder request
1409     TString dir = cont->GetFolderName(); 
1410     if (!dir.IsNull()) {
1411       if (!f->GetDirectory(dir)) f->mkdir(dir);
1412       f->cd(dir);
1413     }
1414     return f;
1415   }
1416   Fatal("OpenProofFile", "File %s could not be opened", cont->GetFileName());
1417   cont->SetFile(NULL);  
1418   return NULL;
1419 }   
1420
1421 //______________________________________________________________________________
1422 void AliAnalysisManager::ExecAnalysis(Option_t *option)
1423 {
1424 // Execute analysis.
1425    static Long64_t ncalls = 0;
1426    Bool_t getsysInfo = ((fNSysInfo>0) && (fMode==kLocalAnalysis))?kTRUE:kFALSE;
1427    if (getsysInfo && ncalls==0) AliSysInfo::AddStamp("Start", (Int_t)ncalls);
1428    ncalls++;
1429    if (!fInitOK) {
1430      Error("ExecAnalysis", "Analysis manager was not initialized !");
1431       return;
1432    }   
1433    AliAnalysisTask *task;
1434    // Check if the top tree is active.
1435    if (fTree) {
1436       TIter next(fTasks);
1437    // De-activate all tasks
1438       while ((task=(AliAnalysisTask*)next())) task->SetActive(kFALSE);
1439       AliAnalysisDataContainer *cont = fCommonInput;
1440       if (!cont) cont = (AliAnalysisDataContainer*)fInputs->At(0);
1441       if (!cont) {
1442               Error("ExecAnalysis","Cannot execute analysis in TSelector mode without at least one top container");
1443          return;
1444       }   
1445       cont->SetData(fTree); // This will notify all consumers
1446       Long64_t entry = fTree->GetTree()->GetReadEntry();
1447       
1448 //
1449 //    Call BeginEvent() for optional input/output and MC services 
1450       if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(entry);
1451       if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(entry);
1452       if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(entry);
1453 //
1454 //    Execute the tasks
1455 //      TIter next1(cont->GetConsumers());
1456       TIter next1(fTopTasks);
1457       while ((task=(AliAnalysisTask*)next1())) {
1458          if (fDebug >1) {
1459             cout << "    Executing task " << task->GetName() << endl;
1460          }   
1461          
1462          task->ExecuteTask(option);
1463       }
1464 //
1465 //    Call FinishEvent() for optional output and MC services 
1466       if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
1467       if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
1468       if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
1469       // Gather system information if requested
1470       if (getsysInfo && ((ncalls%fNSysInfo)==0)) 
1471          AliSysInfo::AddStamp(Form("Event#%lld",ncalls),(Int_t)ncalls);
1472       return;
1473    }   
1474    // The event loop is not controlled by TSelector   
1475 //
1476 //  Call BeginEvent() for optional input/output and MC services 
1477    if (fInputEventHandler)   fInputEventHandler  ->BeginEvent(-1);
1478    if (fOutputEventHandler)  fOutputEventHandler ->BeginEvent(-1);
1479    if (fMCtruthEventHandler) fMCtruthEventHandler->BeginEvent(-1);
1480    TIter next2(fTopTasks);
1481    while ((task=(AliAnalysisTask*)next2())) {
1482       task->SetActive(kTRUE);
1483       if (fDebug > 1) {
1484          cout << "    Executing task " << task->GetName() << endl;
1485       }   
1486       task->ExecuteTask(option);
1487    }   
1488 //
1489 // Call FinishEvent() for optional output and MC services 
1490    if (fInputEventHandler)   fInputEventHandler  ->FinishEvent();
1491    if (fOutputEventHandler)  fOutputEventHandler ->FinishEvent();
1492    if (fMCtruthEventHandler) fMCtruthEventHandler->FinishEvent();
1493 }
1494
1495 //______________________________________________________________________________
1496 void AliAnalysisManager::FinishAnalysis()
1497 {
1498 // Finish analysis.
1499 }
1500
1501 //______________________________________________________________________________
1502 void AliAnalysisManager::SetInputEventHandler(AliVEventHandler*  handler)
1503 {
1504 // Set the input event handler and create a container for it.
1505    fInputEventHandler   = handler;
1506    fCommonInput = CreateContainer("cAUTO_INPUT", TChain::Class(), AliAnalysisManager::kInputContainer);
1507    Warning("SetInputEventHandler", " An automatic input container for the input chain was created.\nPlease use: mgr->GetCommonInputContainer() to access it.");
1508 }
1509
1510 //______________________________________________________________________________
1511 void AliAnalysisManager::SetOutputEventHandler(AliVEventHandler*  handler)
1512 {
1513 // Set the input event handler and create a container for it.
1514    fOutputEventHandler   = handler;
1515    fCommonOutput = CreateContainer("cAUTO_OUTPUT", TTree::Class(), AliAnalysisManager::kOutputContainer, "default");
1516    fCommonOutput->SetSpecialOutput();
1517    Warning("SetOutputEventHandler", " An automatic output container for the output tree was created.\nPlease use: mgr->GetCommonOutputContainer() to access it.");
1518 }
1519
1520 //______________________________________________________________________________
1521 void AliAnalysisManager::RegisterExtraFile(const char *fname)
1522 {
1523 // This method is used externally to register output files which are not
1524 // connected to any output container, so that the manager can properly register,
1525 // retrieve or merge them when running in distributed mode. The file names are
1526 // separated by blancs. The method has to be called in MyAnalysisTask::LocalInit().
1527    if (fExtraFiles.Length()) fExtraFiles += " ";
1528    fExtraFiles += fname;
1529 }
1530
1531 //______________________________________________________________________________
1532 Bool_t AliAnalysisManager::GetFileFromWrapper(const char *filename, TList *source)
1533 {
1534 // Copy a file from the location specified ina the wrapper with the same name from the source list.
1535    char full_path[512];
1536    char ch_url[512];
1537    TObject *pof =  source->FindObject(filename);
1538    if (!pof || !pof->InheritsFrom("TProofOutputFile")) {
1539       Error("GetFileFromWrapper", "TProofOutputFile object not found in output list for file %s", filename);
1540       return kFALSE;
1541    }
1542    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", ((TProofOutputFile*)0x%lx)->GetOutputFileName();)", full_path, pof));
1543    gROOT->ProcessLine(Form("sprintf((char*)0x%lx, \"%%s\", gProof->GetUrl();)", ch_url));
1544    TString clientUrl(ch_url);
1545    TString full_path_str(full_path);
1546    if (clientUrl.Contains("localhost")){
1547       TObjArray* array = full_path_str.Tokenize ( "//" );
1548       TObjString *strobj = ( TObjString *)array->At(1);
1549       TObjArray* arrayPort = strobj->GetString().Tokenize ( ":" );
1550       TObjString *strobjPort = ( TObjString *) arrayPort->At(1);
1551       full_path_str.ReplaceAll(strobj->GetString().Data(),"localhost:PORT");
1552       full_path_str.ReplaceAll(":PORT",Form(":%s",strobjPort->GetString().Data()));
1553       if (fDebug > 1) Info("GetFileFromWrapper","Using tunnel from %s to %s",full_path_str.Data(),filename);
1554       delete arrayPort;
1555       delete array;
1556    }
1557    if (fDebug > 1) 
1558       Info("GetFileFromWrapper","Copying file %s from PROOF scratch space", full_path_str.Data());
1559    Bool_t gotit = TFile::Cp(full_path_str.Data(), filename); 
1560    if (!gotit)
1561       Error("GetFileFromWrapper", "Could not get file %s from proof scratch space", filename);
1562    return gotit;
1563 }
1564
1565 //______________________________________________________________________________
1566 void AliAnalysisManager::GetAnalysisTypeString(TString &type) const
1567 {
1568 // Fill analysis type in the provided string.
1569    switch (fMode) {
1570       case kLocalAnalysis:
1571          type = "local";
1572          return;
1573       case kProofAnalysis:
1574          type = "proof";
1575          return;
1576       case kGridAnalysis:
1577          type = "grid";
1578          return;
1579       case kMixingAnalysis:
1580          type = "mix";
1581    }
1582 }
1583
1584 //______________________________________________________________________________
1585 Bool_t AliAnalysisManager::ValidateOutputFiles() const
1586 {
1587 // Validate all output files.
1588    TIter next(fOutputs);
1589    AliAnalysisDataContainer *output;
1590    TDirectory *cdir = gDirectory;
1591    TString openedFiles;
1592    while ((output=(AliAnalysisDataContainer*)next())) {
1593       if (output->IsRegisterDataset()) continue;
1594       TString filename = output->GetFileName();
1595       if (filename == "default") {
1596          if (!fOutputEventHandler) continue;
1597          filename = fOutputEventHandler->GetOutputFileName();
1598          // Main AOD may not be there
1599          if (gSystem->AccessPathName(filename)) continue;
1600       }
1601       // Check if the file is closed
1602       if (openedFiles.Contains(filename)) continue;;
1603       TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
1604       if (file) {
1605          Warning("ValidateOutputs", "File %s was not closed. Closing.", filename.Data());
1606          file->Close();
1607       }
1608       file = TFile::Open(filename);
1609       if (!file || file->IsZombie() || file->TestBit(TFile::kRecovered)) {
1610          Error("ValidateOutputs", "Output file <%s> was not created or invalid", filename.Data());
1611          cdir->cd();
1612          return kFALSE;
1613       }
1614       file->Close();
1615       openedFiles += filename;
1616       openedFiles += " ";
1617    }
1618    cdir->cd();
1619    return kTRUE;
1620 }   
1621
1622 //______________________________________________________________________________
1623 void AliAnalysisManager::ProgressBar(const char *opname, Long64_t current, Long64_t size, TStopwatch *watch, Bool_t last, Bool_t refresh)
1624 {
1625 // Implements a nice text mode progress bar.
1626    static Long64_t icount = 0;
1627    static TString oname;
1628    static TString nname;
1629    static Long64_t ocurrent = 0;
1630    static Long64_t osize = 0;
1631    static Int_t oseconds = 0;
1632    static TStopwatch *owatch = 0;
1633    static Bool_t oneoftwo = kFALSE;
1634    static Int_t nrefresh = 0;
1635    static Int_t nchecks = 0;
1636    const char symbol[4] = {'=','\\','|','/'}; 
1637    char progress[11] = "          ";
1638    Int_t ichar = icount%4;
1639    
1640    if (!refresh) {
1641       nrefresh = 0;
1642       if (!size) return;
1643       owatch = watch;
1644       oname = opname;
1645       ocurrent = TMath::Abs(current);
1646       osize = TMath::Abs(size);
1647       if (ocurrent > osize) ocurrent=osize;
1648    } else {
1649       nrefresh++;
1650       if (!osize) return;
1651    }     
1652    icount++;
1653    Double_t time = 0.;
1654    Int_t hours = 0;
1655    Int_t minutes = 0;
1656    Int_t seconds = 0;
1657    if (owatch && !last) {
1658       owatch->Stop();
1659       time = owatch->RealTime();
1660       hours = (Int_t)(time/3600.);
1661       time -= 3600*hours;
1662       minutes = (Int_t)(time/60.);
1663       time -= 60*minutes;
1664       seconds = (Int_t)time;
1665       if (refresh)  {
1666          if (oseconds==seconds) {
1667             owatch->Continue();
1668             return;
1669          }
1670          oneoftwo = !oneoftwo;   
1671       }
1672       oseconds = seconds;   
1673    }
1674    if (refresh && oneoftwo) {
1675       nname = oname;
1676       if (nchecks <= 0) nchecks = nrefresh+1;
1677       Int_t pctdone = (Int_t)(100.*nrefresh/nchecks);
1678       oname = Form("     == %d%% ==", pctdone);
1679    }         
1680    Double_t percent = 100.0*ocurrent/osize;
1681    Int_t nchar = Int_t(percent/10);
1682    if (nchar>10) nchar=10;
1683    Int_t i;
1684    for (i=0; i<nchar; i++)  progress[i] = '=';
1685    progress[nchar] = symbol[ichar];
1686    for (i=nchar+1; i<10; i++) progress[i] = ' ';
1687    progress[10] = '\0';
1688    oname += "                    ";
1689    oname.Remove(20);
1690    if(size<10000) fprintf(stderr, "%s [%10s] %4lld ", oname.Data(), progress, ocurrent);
1691    else if(size<100000) fprintf(stderr, "%s [%10s] %5lld ",oname.Data(), progress, ocurrent);
1692    else fprintf(stderr, "%s [%10s] %7lld ",oname.Data(), progress, ocurrent);
1693    if (time>0.) fprintf(stderr, "[%6.2f %%]   TIME %.2d:%.2d:%.2d             \r", percent, hours, minutes, seconds);
1694    else fprintf(stderr, "[%6.2f %%]\r", percent);
1695    if (refresh && oneoftwo) oname = nname;
1696    if (owatch) owatch->Continue();
1697    if (last) {
1698       icount = 0;
1699       owatch = 0;
1700       ocurrent = 0;
1701       osize = 0;
1702       oseconds = 0;
1703       oneoftwo = kFALSE;
1704       nrefresh = 0;
1705       fprintf(stderr, "\n");
1706    }   
1707 }