]>
Commit | Line | Data |
---|---|---|
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 | :fReady(kFALSE), | |
62 | fNinputs(0), | |
63 | fNoutputs(0), | |
64 | fOutputReady(NULL), | |
65 | fPublishedData(NULL), | |
66 | fInputs(NULL), | |
67 | fOutputs(NULL) | |
68 | { | |
69 | // Default constructor. | |
70 | } | |
71 | ||
72 | //______________________________________________________________________________ | |
73 | AliAnalysisTask::AliAnalysisTask(const char *name, const char *title) | |
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) | |
82 | { | |
83 | // Constructor. | |
84 | fInputs = new TObjArray(2); | |
85 | fOutputs = new TObjArray(2); | |
86 | } | |
87 | ||
88 | //______________________________________________________________________________ | |
89 | AliAnalysisTask::AliAnalysisTask(const AliAnalysisTask &task) | |
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) | |
98 | { | |
99 | // Copy ctor. | |
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 | |
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 | } | |
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; | |
237 | fInputs->AddAtAndExpand(input, islot); | |
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 | } | |
255 | fOutputs->AddAtAndExpand(output, islot); | |
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 | } |