Possibility to create an independent par file containing the new analysis framework...
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisTask.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// AliAnalysysTask - Class representing a basic analysis task. Any
21// user-defined task should derive from it and implement the Exec() virtual
22// method.
23//==============================================================================
24//
25// A specific user analysis task have to derive from this class. The list of
26// specific input and output slots have to be defined in the derived class ctor:
27//
28// UserTask::UserTask(name, title)
29// {
30// DefineInput(0, TTree::Class());
31// DefineInput(1, TH1::Class());
32// ...
33// DefineOutput(0, TTree::Class());
34// DefineOutput(1, MyObject::Class());
35// ...
36// }
37//
38// An existing data contaner (AliAnalysisDataContainer) can be connected to the
39// input/output slots of an analysis task. Containers should not be defined and
40// connected by the derived analysis task, but from the level of AliAnalysisManager:
41//
42// AliAnalysisManager::ConnectInput(AliAnalysisTask *task, Int_t islot,
43// AliAnalysisDataContainer *cont)
44// AliAnalysisManager::ConnectOutput(AliAnalysisTask *task, Int_t islot,
45// AliAnalysisDataContainer *cont)
46// To connect a slot to a data container, the data types declared by both must
47// match.
327eaf46 48//
49// The method Init will be called once per session at the moment when the data is
50// available at all input slots.
51// The method Init() has to be overloaded by the derived class in order to:
52// 1. Define objects that should be created only once per session (e.g. output
53// histograms)
54// 2. Set the branch address or connect to a branch address in case the input
55// slots are connected to trees.
56//
57// Example:
58// MyAnalysisTask::Init(Option_t *)
59// {
60// if (!fHist1) fHist1 = new TH1F("h1", ....);
61// if (!fHist2) fHist2 = new TH1F("h2", ....);
62// fESD = GetBranchAddress(islot=0, "ESD");
63// if (!fESD) SetBranchAddress(islot=0, "ESD", &fESD);
64// }
65//
66// The method Terminate() will be called by the framework once at the end of
67// data processing. Overload this if needed.
68//
d3106602 69//==============================================================================
70
11026a80 71#include "Riostream.h"
72
d3106602 73#include "TClass.h"
74
11026a80 75//#include "AliLog.h"
d3106602 76#include "AliAnalysisTask.h"
77#include "AliAnalysisDataSlot.h"
78#include "AliAnalysisDataContainer.h"
79
80ClassImp(AliAnalysisTask)
81
82//______________________________________________________________________________
83AliAnalysisTask::AliAnalysisTask()
37a26056 84 :fReady(kFALSE),
327eaf46 85 fInitialized(kFALSE),
37a26056 86 fNinputs(0),
87 fNoutputs(0),
88 fOutputReady(NULL),
89 fPublishedData(NULL),
90 fInputs(NULL),
91 fOutputs(NULL)
d3106602 92{
93// Default constructor.
d3106602 94}
95
96//______________________________________________________________________________
97AliAnalysisTask::AliAnalysisTask(const char *name, const char *title)
37a26056 98 :TTask(name,title),
99 fReady(kFALSE),
327eaf46 100 fInitialized(kFALSE),
37a26056 101 fNinputs(0),
102 fNoutputs(0),
103 fOutputReady(NULL),
104 fPublishedData(NULL),
105 fInputs(NULL),
106 fOutputs(NULL)
d3106602 107{
37a26056 108// Constructor.
d3106602 109 fInputs = new TObjArray(2);
110 fOutputs = new TObjArray(2);
111}
112
113//______________________________________________________________________________
114AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task)
37a26056 115 :TTask(task),
116 fReady(task.fReady),
327eaf46 117 fInitialized(task.fInitialized),
37a26056 118 fNinputs(task.fNinputs),
119 fNoutputs(task.fNoutputs),
120 fOutputReady(NULL),
121 fPublishedData(NULL),
122 fInputs(NULL),
123 fOutputs(NULL)
d3106602 124{
125// Copy ctor.
d3106602 126 fInputs = new TObjArray((fNinputs)?fNinputs:2);
127 fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
128 fPublishedData = 0;
129 Int_t i;
130 for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
131 fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
132 for (i=0; i<fNoutputs; i++) {
133 fOutputReady[i] = IsOutputReady(i);
134 fOutputs->AddAt(task.GetOutputSlot(i),i);
135 }
136}
137
138//______________________________________________________________________________
139AliAnalysisTask::~AliAnalysisTask()
140{
141// Dtor.
142 if (fInputs) {fInputs->Delete(); delete fInputs;}
143 if (fOutputs) {fOutputs->Delete(); delete fOutputs;}
144}
145
146//______________________________________________________________________________
147AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task)
148{
149// Assignment
37a26056 150 if (&task == this) return *this;
151 TTask::operator=(task);
152 fReady = task.IsReady();
327eaf46 153 fInitialized = task.IsInitialized();
37a26056 154 fNinputs = task.GetNinputs();
155 fNoutputs = task.GetNoutputs();
156 fInputs = new TObjArray((fNinputs)?fNinputs:2);
157 fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
158 fPublishedData = 0;
159 Int_t i;
160 for (i=0; i<fNinputs; i++) fInputs->AddAt(new AliAnalysisDataSlot(*task.GetInputSlot(i)),i);
161 fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
162 for (i=0; i<fNoutputs; i++) {
163 fOutputReady[i] = IsOutputReady(i);
164 fOutputs->AddAt(new AliAnalysisDataSlot(*task.GetOutputSlot(i)),i);
165 }
d3106602 166 return *this;
167}
168
169//______________________________________________________________________________
170Bool_t AliAnalysisTask::AreSlotsConnected()
171{
172// Check if all input/output slots are connected. If this is the case fReady=true
173 fReady = kFALSE;
174 if (!fNinputs || !fNoutputs) return kFALSE;
175 Int_t i;
176 AliAnalysisDataSlot *slot;
177 for (i=0; i<fNinputs; i++) {
178 slot = (AliAnalysisDataSlot*)fInputs->At(i);
179 if (!slot) {
11026a80 180 cout<<"Input slot "<<i<<" of task "<<GetName()<<" not defined !"<<endl;
181 //AliError(Form("Input slot %i of task %s not defined !",i,GetName()));
d3106602 182 return kFALSE;
183 }
184 if (!slot->IsConnected()) return kFALSE;
185 }
186 for (i=0; i<fNoutputs; i++) {
187 slot = (AliAnalysisDataSlot*)fOutputs->At(i);
188 if (!slot) {
11026a80 189 cout<<"Output slot "<<i<<" of task "<<GetName()<<" not defined !"<<endl;
190 //AliError(Form("Output slot %i of task %s not defined !",i,GetName()));
d3106602 191 return kFALSE;
192 }
193 if (!slot->IsConnected()) return kFALSE;
194 }
195 fReady = kTRUE;
196 return kTRUE;
197}
198
199//______________________________________________________________________________
327eaf46 200void AliAnalysisTask::CheckNotify(Bool_t init)
d3106602 201{
202// Check if data is available from all inputs. Change the status of the task
203// accordingly. This method is called automatically for all tasks connected
204// to a container where the data was published.
327eaf46 205 if (init) fInitialized = kFALSE;
d3106602 206 for (Int_t islot=0; islot<fNinputs; islot++) {
207 if (!GetInputData(islot)) {
208 SetActive(kFALSE);
209 return;
210 }
211 }
212 SetActive(kTRUE);
327eaf46 213 if (fInitialized) return;
214 TDirectory *cursav = gDirectory;
215 Init();
216 if (cursav) cursav->cd();
217 fInitialized = kTRUE;
d3106602 218}
219
220//______________________________________________________________________________
221Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont)
222{
223// Connect an input slot to a data container.
224 AliAnalysisDataSlot *input = GetInputSlot(islot);
225 if (!input) {
11026a80 226 cout<<"Input slot "<<islot<<" not defined for analysis task "<<GetName()<<endl;
227 //AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
d3106602 228 return kFALSE;
229 }
230 // Check type matching
231 if (!input->GetType()->InheritsFrom(cont->GetType())) {
11026a80 232 cout<<"Data type "<<input->GetType()->GetName()<<" for input "<<islot<<" of task "<<GetName()<<" not matching container "<<cont->GetName()<<" of type "<<cont->GetType()->GetName()<<endl;
233 //AliError(Form("Data type %s for input %i of task %s not matching container %s of type %s",input->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
d3106602 234 return kFALSE;
235 }
236 // Connect the slot to the container as input
237 if (!input->ConnectContainer(cont)) return kFALSE;
238 // Add this to the list of container consumers
239 cont->AddConsumer(this, islot);
240 AreSlotsConnected();
241 return kTRUE;
242}
243
244//______________________________________________________________________________
245Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont)
246{
247// Connect an output slot to a data container.
248 AliAnalysisDataSlot *output = GetOutputSlot(islot);
249 if (!output) {
11026a80 250 cout<<"Output slot "<<islot<<" not defined for analysis task "<<GetName()<<endl;
251 //AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
d3106602 252 return kFALSE;
253 }
254 // Check type matching
255 if (!output->GetType()->InheritsFrom(cont->GetType())) {
11026a80 256 cout<<"Data type "<<output->GetType()->GetName()<<" for output "<<islot<<" of task "<<GetName()<<" not matching container "<<cont->GetName()<<" of type "<<cont->GetType()->GetName()<<endl;
257 //AliError(Form("Data type %s for output %i of task %s not matching container %s of type %s",output->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
d3106602 258 return kFALSE;
259 }
260 // Connect the slot to the container as output
261 if (!output->ConnectContainer(cont)) return kFALSE;
262 // Declare this as the data producer
263 cont->SetProducer(this, islot);
264 AreSlotsConnected();
265 return kTRUE;
266}
267
268//______________________________________________________________________________
269void AliAnalysisTask::DefineInput(Int_t islot, TClass *type)
270{
271// Define an input slot and its type.
272 AliAnalysisDataSlot *input = new AliAnalysisDataSlot(type, this);
273 if (fNinputs<islot+1) fNinputs = islot+1;
6ae18197 274 fInputs->AddAtAndExpand(input, islot);
d3106602 275}
276
277//______________________________________________________________________________
278void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type)
279{
280// Define an output slot and its type.
281 if (islot<0) {
11026a80 282 cout<<"Cannot define negative output slot number for task "<<GetName()<<endl;
283 //AliError(Form("Cannot define negative output slot number for task %s", GetName()));
d3106602 284 return;
285 }
286 AliAnalysisDataSlot *output = new AliAnalysisDataSlot(type, this);
287 if (fNoutputs<islot+1) {
288 fNoutputs = islot+1;
289 if (fOutputReady) delete [] fOutputReady;
290 fOutputReady = new Bool_t[fNoutputs];
291 memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
292 }
6ae18197 293 fOutputs->AddAtAndExpand(output, islot);
d3106602 294}
295
296//______________________________________________________________________________
297TClass *AliAnalysisTask::GetInputType(Int_t islot) const
298{
299// Retreive type of a given input slot.
300 AliAnalysisDataSlot *input = GetInputSlot(islot);
301 if (!input) {
11026a80 302 cout<<"Input slot "<<islot<<" not defined for analysis task "<<GetName()<<endl;
303 //AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
d3106602 304 return NULL;
305 }
306 return (input->GetType());
307}
308
309//______________________________________________________________________________
310TClass *AliAnalysisTask::GetOutputType(Int_t islot) const
311{
312// Retreive type of a given output slot.
313 AliAnalysisDataSlot *output = GetOutputSlot(islot);
314 if (!output) {
11026a80 315 cout<<"Output slot "<<islot<<" not defined for analysis task "<<GetName()<<endl;
316 //AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
d3106602 317 return NULL;
318 }
319 return (output->GetType());
320}
321
322//______________________________________________________________________________
323TObject *AliAnalysisTask::GetInputData(Int_t islot) const
324{
325// Retreive input data for a slot if ready. Normally called by Exec() and
326// the object has to be statically cast to the appropriate type.
327 AliAnalysisDataSlot *input = GetInputSlot(islot);
328 if (!input) {
11026a80 329 cout<<"Input slot "<<islot<<" not defined for analysis task "<<GetName()<<endl;
330 //AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
d3106602 331 return NULL;
332 }
333 return (input->GetData());
334}
335
327eaf46 336//______________________________________________________________________________
337char *AliAnalysisTask::GetBranchAddress(Int_t islot, const char *branch) const
338{
339// Check if a branch with a given name from the specified input is connected
340// to some address. Call this in Init() before trying to call SetBranchAddress()
341// since the adress may be set by other task.
342 return (char *)GetInputSlot(islot)->GetBranchAddress(branch);
343}
344
345//______________________________________________________________________________
346Bool_t AliAnalysisTask::SetBranchAddress(Int_t islot, const char *branch, void *address) const
347{
348// Connect an object address to a branch of the specified input.
349 return GetInputSlot(islot)->SetBranchAddress(branch, address);
350}
351
352//______________________________________________________________________________
353void AliAnalysisTask::Init(Option_t *)
354{
355// Branch address initialization.
356}
357
358//______________________________________________________________________________
359void AliAnalysisTask::Terminate(Option_t *)
360{
361// Method called by the framework at the end of data processing.
362}
363
364//______________________________________________________________________________
365void AliAnalysisTask::OpenFile(Int_t iout, const char *name, Option_t *option) const
366{
367// Set data at output iout to be written in the specified file.
368 GetOutputSlot(iout)->GetContainer()->OpenFile(name, option);
369}
370
d3106602 371//______________________________________________________________________________
372Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option)
373{
374// Post output data for a given ouput slot in the corresponding data container.
375// Published data becomes owned by the data container.
376// If option is specified, the container connected to the output slot must have
377// an associated file name defined. The option represents the method to open the file.
378 fPublishedData = 0;
379 AliAnalysisDataSlot *output = GetOutputSlot(iout);
380 if (!output) {
11026a80 381 cout<<"Output slot "<<iout<<" not defined for analysis task "<<GetName()<<endl;
382 //AliError(Form("Output slot %i not defined for analysis task %s", iout, GetName()));
d3106602 383 return kFALSE;
384 }
385 if (!output->IsConnected()) {
11026a80 386 cout<<"Output slot "<<iout<<" of analysis task "<<GetName()<<" not connected to any data container"<<endl;
387 //AliError(Form("Output slot %i of analysis task %s not connected to any data container", iout, GetName()));
d3106602 388 return kFALSE;
389 }
390 if (!fOutputReady) {
391 fOutputReady = new Bool_t[fNoutputs];
392 memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
393 }
394 fOutputReady[iout] = kTRUE;
395 fPublishedData = data;
396 return (output->GetContainer()->SetData(data, option));
397}
398
399//______________________________________________________________________________
400void AliAnalysisTask::SetUsed(Bool_t flag)
401{
402// Set 'used' flag recursively to task and all daughter tasks.
403 if (TestBit(kTaskUsed)==flag) return;
404 TObject::SetBit(kTaskUsed,flag);
405 Int_t nd = fTasks->GetSize();
406 AliAnalysisTask *task;
407 for (Int_t i=0; i<nd; i++) {
408 task = (AliAnalysisTask*)fTasks->At(i);
409 task->SetUsed(flag);
410 }
411}
412
413//______________________________________________________________________________
414Bool_t AliAnalysisTask::CheckCircularDeps()
415{
416// Check for illegal circular dependencies, e.g. a daughter task should not have
417// a hierarchical parent as subtask.
418 if (IsChecked()) return kTRUE;
419 SetChecked();
420 TList *tasks = GetListOfTasks();
421 Int_t ntasks = tasks->GetSize();
422 AliAnalysisTask *task;
423 for (Int_t i=0; i<ntasks; i++) {
424 task = (AliAnalysisTask*)tasks->At(i);
425 if (task->CheckCircularDeps()) return kTRUE;
426 }
427 SetChecked(kFALSE);
428 return kFALSE;
429}
430
431//______________________________________________________________________________
432void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const
433{
434// Print task info.
435 AliAnalysisTask *thistask = (AliAnalysisTask*)this;
436 TString opt(option);
437 opt.ToLower();
438 Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
439 TString ind;
440 Int_t islot;
441 AliAnalysisDataContainer *cont;
442 for (Int_t i=0; i<indent; i++) ind += " ";
443 if (!dep || (dep && IsChecked())) {
444 printf("%s\n", Form("%stask: %s ACTIVE=%i", ind.Data(), GetName(),IsActive()));
445 if (dep) thistask->SetChecked(kFALSE);
446 else {
447 for (islot=0; islot<fNinputs; islot++) {
448 printf("%s", Form("%s INPUT #%i: %s <- ",ind.Data(),islot, GetInputType(islot)->GetName()));
449 cont = GetInputSlot(islot)->GetContainer();
450 if (cont) printf(" [%s]\n", cont->GetName());
451 else printf(" [NO CONTAINER]\n");
452 }
453 for (islot=0; islot<fNoutputs; islot++) {
454 printf("%s", Form("%s OUTPUT #%i: %s -> ",ind.Data(),islot, GetOutputType(islot)->GetName()));
455 cont = GetOutputSlot(islot)->GetContainer();
456 if (cont) printf(" [%s]\n", cont->GetName());
457 else printf(" [NO CONTAINER]\n");
458 }
459 }
460 }
461 PrintContainers(option, indent+3);
462}
463
464//______________________________________________________________________________
465void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const
466{
467// Print containers info.
468 AliAnalysisDataContainer *cont;
469 TString ind;
470 for (Int_t i=0; i<indent; i++) ind += " ";
471 Int_t islot;
472 for (islot=0; islot<fNoutputs; islot++) {
473 cont = GetOutputSlot(islot)->GetContainer();
474 cont->PrintContainer(option, indent);
475 }
476}