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