]>
Commit | Line | Data |
---|---|---|
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() | |
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 | //______________________________________________________________________________ | |
73 | AliAnalysisTask::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 | //______________________________________________________________________________ | |
87 | AliAnalysisTask::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 | //______________________________________________________________________________ | |
107 | AliAnalysisTask::~AliAnalysisTask() | |
108 | { | |
109 | // Dtor. | |
110 | if (fInputs) {fInputs->Delete(); delete fInputs;} | |
111 | if (fOutputs) {fOutputs->Delete(); delete fOutputs;} | |
112 | } | |
113 | ||
114 | //______________________________________________________________________________ | |
115 | AliAnalysisTask& 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 | //______________________________________________________________________________ | |
138 | Bool_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 | //______________________________________________________________________________ | |
166 | void 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 | //______________________________________________________________________________ | |
181 | Bool_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 | //______________________________________________________________________________ | |
204 | Bool_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 | //______________________________________________________________________________ | |
227 | void 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 | //______________________________________________________________________________ | |
236 | void 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 | //______________________________________________________________________________ | |
254 | TClass *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 | //______________________________________________________________________________ | |
266 | TClass *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 | //______________________________________________________________________________ | |
278 | TObject *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 | //______________________________________________________________________________ | |
291 | Bool_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 | //______________________________________________________________________________ | |
317 | void 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 | //______________________________________________________________________________ | |
331 | Bool_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 | //______________________________________________________________________________ | |
349 | void 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 | //______________________________________________________________________________ | |
382 | void 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 | } |