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