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 | |
57 | ClassImp(AliAnalysisTask) |
58 | |
59 | //______________________________________________________________________________ |
60 | AliAnalysisTask::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 | //______________________________________________________________________________ |
73 | AliAnalysisTask::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 | //______________________________________________________________________________ |
89 | AliAnalysisTask::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 | //______________________________________________________________________________ |
113 | AliAnalysisTask::~AliAnalysisTask() |
114 | { |
115 | // Dtor. |
116 | if (fInputs) {fInputs->Delete(); delete fInputs;} |
117 | if (fOutputs) {fOutputs->Delete(); delete fOutputs;} |
118 | } |
119 | |
120 | //______________________________________________________________________________ |
121 | AliAnalysisTask& 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 | //______________________________________________________________________________ |
143 | Bool_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 | //______________________________________________________________________________ |
171 | void 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 | //______________________________________________________________________________ |
186 | Bool_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 | //______________________________________________________________________________ |
209 | Bool_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 | //______________________________________________________________________________ |
232 | void 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 | //______________________________________________________________________________ |
241 | void 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 | //______________________________________________________________________________ |
259 | TClass *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 | //______________________________________________________________________________ |
271 | TClass *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 | //______________________________________________________________________________ |
283 | TObject *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 | //______________________________________________________________________________ |
296 | Bool_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 | //______________________________________________________________________________ |
322 | void 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 | //______________________________________________________________________________ |
336 | Bool_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 | //______________________________________________________________________________ |
354 | void 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 | //______________________________________________________________________________ |
387 | void 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 | } |