Using AddAndAxpand instead of AddAt (Andrei)
[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.
48//==============================================================================
49
50#include "TClass.h"
51
52#include "AliLog.h"
53#include "AliAnalysisTask.h"
54#include "AliAnalysisDataSlot.h"
55#include "AliAnalysisDataContainer.h"
56
57ClassImp(AliAnalysisTask)
58
59//______________________________________________________________________________
60AliAnalysisTask::AliAnalysisTask()
37a26056 61 :fReady(kFALSE),
62 fNinputs(0),
63 fNoutputs(0),
64 fOutputReady(NULL),
65 fPublishedData(NULL),
66 fInputs(NULL),
67 fOutputs(NULL)
d3106602 68{
69// Default constructor.
d3106602 70}
71
72//______________________________________________________________________________
73AliAnalysisTask::AliAnalysisTask(const char *name, const char *title)
37a26056 74 :TTask(name,title),
75 fReady(kFALSE),
76 fNinputs(0),
77 fNoutputs(0),
78 fOutputReady(NULL),
79 fPublishedData(NULL),
80 fInputs(NULL),
81 fOutputs(NULL)
d3106602 82{
37a26056 83// Constructor.
d3106602 84 fInputs = new TObjArray(2);
85 fOutputs = new TObjArray(2);
86}
87
88//______________________________________________________________________________
89AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task)
37a26056 90 :TTask(task),
91 fReady(task.fReady),
92 fNinputs(task.fNinputs),
93 fNoutputs(task.fNoutputs),
94 fOutputReady(NULL),
95 fPublishedData(NULL),
96 fInputs(NULL),
97 fOutputs(NULL)
d3106602 98{
99// Copy ctor.
d3106602 100 fInputs = new TObjArray((fNinputs)?fNinputs:2);
101 fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
102 fPublishedData = 0;
103 Int_t i;
104 for (i=0; i<fNinputs; i++) fInputs->AddAt(task.GetInputSlot(i),i);
105 fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
106 for (i=0; i<fNoutputs; i++) {
107 fOutputReady[i] = IsOutputReady(i);
108 fOutputs->AddAt(task.GetOutputSlot(i),i);
109 }
110}
111
112//______________________________________________________________________________
113AliAnalysisTask::~AliAnalysisTask()
114{
115// Dtor.
116 if (fInputs) {fInputs->Delete(); delete fInputs;}
117 if (fOutputs) {fOutputs->Delete(); delete fOutputs;}
118}
119
120//______________________________________________________________________________
121AliAnalysisTask& AliAnalysisTask::operator=(const AliAnalysisTask& task)
122{
123// Assignment
37a26056 124 if (&task == this) return *this;
125 TTask::operator=(task);
126 fReady = task.IsReady();
127 fNinputs = task.GetNinputs();
128 fNoutputs = task.GetNoutputs();
129 fInputs = new TObjArray((fNinputs)?fNinputs:2);
130 fOutputs = new TObjArray((fNoutputs)?fNoutputs:2);
131 fPublishedData = 0;
132 Int_t i;
133 for (i=0; i<fNinputs; i++) fInputs->AddAt(new AliAnalysisDataSlot(*task.GetInputSlot(i)),i);
134 fOutputReady = new Bool_t[(fNoutputs)?fNoutputs:2];
135 for (i=0; i<fNoutputs; i++) {
136 fOutputReady[i] = IsOutputReady(i);
137 fOutputs->AddAt(new AliAnalysisDataSlot(*task.GetOutputSlot(i)),i);
138 }
d3106602 139 return *this;
140}
141
142//______________________________________________________________________________
143Bool_t AliAnalysisTask::AreSlotsConnected()
144{
145// Check if all input/output slots are connected. If this is the case fReady=true
146 fReady = kFALSE;
147 if (!fNinputs || !fNoutputs) return kFALSE;
148 Int_t i;
149 AliAnalysisDataSlot *slot;
150 for (i=0; i<fNinputs; i++) {
151 slot = (AliAnalysisDataSlot*)fInputs->At(i);
152 if (!slot) {
153 AliError(Form("Input slot %i of task %s not defined !",i,GetName()));
154 return kFALSE;
155 }
156 if (!slot->IsConnected()) return kFALSE;
157 }
158 for (i=0; i<fNoutputs; i++) {
159 slot = (AliAnalysisDataSlot*)fOutputs->At(i);
160 if (!slot) {
161 AliError(Form("Output slot %i of task %s not defined !",i,GetName()));
162 return kFALSE;
163 }
164 if (!slot->IsConnected()) return kFALSE;
165 }
166 fReady = kTRUE;
167 return kTRUE;
168}
169
170//______________________________________________________________________________
171void AliAnalysisTask::CheckNotify()
172{
173// Check if data is available from all inputs. Change the status of the task
174// accordingly. This method is called automatically for all tasks connected
175// to a container where the data was published.
176 for (Int_t islot=0; islot<fNinputs; islot++) {
177 if (!GetInputData(islot)) {
178 SetActive(kFALSE);
179 return;
180 }
181 }
182 SetActive(kTRUE);
183}
184
185//______________________________________________________________________________
186Bool_t AliAnalysisTask::ConnectInput(Int_t islot, AliAnalysisDataContainer *cont)
187{
188// Connect an input slot to a data container.
189 AliAnalysisDataSlot *input = GetInputSlot(islot);
190 if (!input) {
191 AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
192 return kFALSE;
193 }
194 // Check type matching
195 if (!input->GetType()->InheritsFrom(cont->GetType())) {
196 AliError(Form("Data type %s for input %i of task %s not matching container %s of type %s",
197 input->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
198 return kFALSE;
199 }
200 // Connect the slot to the container as input
201 if (!input->ConnectContainer(cont)) return kFALSE;
202 // Add this to the list of container consumers
203 cont->AddConsumer(this, islot);
204 AreSlotsConnected();
205 return kTRUE;
206}
207
208//______________________________________________________________________________
209Bool_t AliAnalysisTask::ConnectOutput(Int_t islot, AliAnalysisDataContainer *cont)
210{
211// Connect an output slot to a data container.
212 AliAnalysisDataSlot *output = GetOutputSlot(islot);
213 if (!output) {
214 AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
215 return kFALSE;
216 }
217 // Check type matching
218 if (!output->GetType()->InheritsFrom(cont->GetType())) {
219 AliError(Form("Data type %s for output %i of task %s not matching container %s of type %s",
220 output->GetType()->GetName(), islot, GetName(), cont->GetName(), cont->GetType()->GetName()));
221 return kFALSE;
222 }
223 // Connect the slot to the container as output
224 if (!output->ConnectContainer(cont)) return kFALSE;
225 // Declare this as the data producer
226 cont->SetProducer(this, islot);
227 AreSlotsConnected();
228 return kTRUE;
229}
230
231//______________________________________________________________________________
232void AliAnalysisTask::DefineInput(Int_t islot, TClass *type)
233{
234// Define an input slot and its type.
235 AliAnalysisDataSlot *input = new AliAnalysisDataSlot(type, this);
236 if (fNinputs<islot+1) fNinputs = islot+1;
6ae18197 237 fInputs->AddAtAndExpand(input, islot);
d3106602 238}
239
240//______________________________________________________________________________
241void AliAnalysisTask::DefineOutput(Int_t islot, TClass *type)
242{
243// Define an output slot and its type.
244 if (islot<0) {
245 AliError(Form("Cannot define negative output slot number for task %s", GetName()));
246 return;
247 }
248 AliAnalysisDataSlot *output = new AliAnalysisDataSlot(type, this);
249 if (fNoutputs<islot+1) {
250 fNoutputs = islot+1;
251 if (fOutputReady) delete [] fOutputReady;
252 fOutputReady = new Bool_t[fNoutputs];
253 memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
254 }
6ae18197 255 fOutputs->AddAtAndExpand(output, islot);
d3106602 256}
257
258//______________________________________________________________________________
259TClass *AliAnalysisTask::GetInputType(Int_t islot) const
260{
261// Retreive type of a given input slot.
262 AliAnalysisDataSlot *input = GetInputSlot(islot);
263 if (!input) {
264 AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
265 return NULL;
266 }
267 return (input->GetType());
268}
269
270//______________________________________________________________________________
271TClass *AliAnalysisTask::GetOutputType(Int_t islot) const
272{
273// Retreive type of a given output slot.
274 AliAnalysisDataSlot *output = GetOutputSlot(islot);
275 if (!output) {
276 AliError(Form("Output slot %i not defined for analysis task %s", islot, GetName()));
277 return NULL;
278 }
279 return (output->GetType());
280}
281
282//______________________________________________________________________________
283TObject *AliAnalysisTask::GetInputData(Int_t islot) const
284{
285// Retreive input data for a slot if ready. Normally called by Exec() and
286// the object has to be statically cast to the appropriate type.
287 AliAnalysisDataSlot *input = GetInputSlot(islot);
288 if (!input) {
289 AliError(Form("Input slot %i not defined for analysis task %s", islot, GetName()));
290 return NULL;
291 }
292 return (input->GetData());
293}
294
295//______________________________________________________________________________
296Bool_t AliAnalysisTask::PostData(Int_t iout, TObject *data, Option_t *option)
297{
298// Post output data for a given ouput slot in the corresponding data container.
299// Published data becomes owned by the data container.
300// If option is specified, the container connected to the output slot must have
301// an associated file name defined. The option represents the method to open the file.
302 fPublishedData = 0;
303 AliAnalysisDataSlot *output = GetOutputSlot(iout);
304 if (!output) {
305 AliError(Form("Output slot %i not defined for analysis task %s", iout, GetName()));
306 return kFALSE;
307 }
308 if (!output->IsConnected()) {
309 AliError(Form("Output slot %i of analysis task %s not connected to any data container", iout, GetName()));
310 return kFALSE;
311 }
312 if (!fOutputReady) {
313 fOutputReady = new Bool_t[fNoutputs];
314 memset(fOutputReady, 0, fNoutputs*sizeof(Bool_t));
315 }
316 fOutputReady[iout] = kTRUE;
317 fPublishedData = data;
318 return (output->GetContainer()->SetData(data, option));
319}
320
321//______________________________________________________________________________
322void AliAnalysisTask::SetUsed(Bool_t flag)
323{
324// Set 'used' flag recursively to task and all daughter tasks.
325 if (TestBit(kTaskUsed)==flag) return;
326 TObject::SetBit(kTaskUsed,flag);
327 Int_t nd = fTasks->GetSize();
328 AliAnalysisTask *task;
329 for (Int_t i=0; i<nd; i++) {
330 task = (AliAnalysisTask*)fTasks->At(i);
331 task->SetUsed(flag);
332 }
333}
334
335//______________________________________________________________________________
336Bool_t AliAnalysisTask::CheckCircularDeps()
337{
338// Check for illegal circular dependencies, e.g. a daughter task should not have
339// a hierarchical parent as subtask.
340 if (IsChecked()) return kTRUE;
341 SetChecked();
342 TList *tasks = GetListOfTasks();
343 Int_t ntasks = tasks->GetSize();
344 AliAnalysisTask *task;
345 for (Int_t i=0; i<ntasks; i++) {
346 task = (AliAnalysisTask*)tasks->At(i);
347 if (task->CheckCircularDeps()) return kTRUE;
348 }
349 SetChecked(kFALSE);
350 return kFALSE;
351}
352
353//______________________________________________________________________________
354void AliAnalysisTask::PrintTask(Option_t *option, Int_t indent) const
355{
356// Print task info.
357 AliAnalysisTask *thistask = (AliAnalysisTask*)this;
358 TString opt(option);
359 opt.ToLower();
360 Bool_t dep = (opt.Contains("dep"))?kTRUE:kFALSE;
361 TString ind;
362 Int_t islot;
363 AliAnalysisDataContainer *cont;
364 for (Int_t i=0; i<indent; i++) ind += " ";
365 if (!dep || (dep && IsChecked())) {
366 printf("%s\n", Form("%stask: %s ACTIVE=%i", ind.Data(), GetName(),IsActive()));
367 if (dep) thistask->SetChecked(kFALSE);
368 else {
369 for (islot=0; islot<fNinputs; islot++) {
370 printf("%s", Form("%s INPUT #%i: %s <- ",ind.Data(),islot, GetInputType(islot)->GetName()));
371 cont = GetInputSlot(islot)->GetContainer();
372 if (cont) printf(" [%s]\n", cont->GetName());
373 else printf(" [NO CONTAINER]\n");
374 }
375 for (islot=0; islot<fNoutputs; islot++) {
376 printf("%s", Form("%s OUTPUT #%i: %s -> ",ind.Data(),islot, GetOutputType(islot)->GetName()));
377 cont = GetOutputSlot(islot)->GetContainer();
378 if (cont) printf(" [%s]\n", cont->GetName());
379 else printf(" [NO CONTAINER]\n");
380 }
381 }
382 }
383 PrintContainers(option, indent+3);
384}
385
386//______________________________________________________________________________
387void AliAnalysisTask::PrintContainers(Option_t *option, Int_t indent) const
388{
389// Print containers info.
390 AliAnalysisDataContainer *cont;
391 TString ind;
392 for (Int_t i=0; i<indent; i++) ind += " ";
393 Int_t islot;
394 for (islot=0; islot<fNoutputs; islot++) {
395 cont = GetOutputSlot(islot)->GetContainer();
396 cont->PrintContainer(option, indent);
397 }
398}