]>
Commit | Line | Data |
---|---|---|
94ef1a28 | 1 | /************************************************************************** |
2 | * Copyright(c) 1998-2007, 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 | ||
27de2dfb | 16 | /* $Id$ */ |
17 | ||
94ef1a28 | 18 | //----------------------------------------------------------------------------- |
19 | /// \class AliCounterCollection | |
20 | /// | |
21 | /// generic class to handle a collection of counters | |
22 | /// | |
23 | /// \author Philippe Pillot | |
24 | //----------------------------------------------------------------------------- | |
25 | ||
26 | #include "AliCounterCollection.h" | |
27 | ||
5d8c0c8a | 28 | #include <limits.h> |
29 | ||
94ef1a28 | 30 | #include <AliLog.h> |
31 | ||
32 | #include <TString.h> | |
33 | #include <TObjString.h> | |
34 | #include <TObjArray.h> | |
35 | #include <THnSparse.h> | |
36 | #include <THashList.h> | |
37 | #include <TArrayI.h> | |
38 | #include <TH1D.h> | |
39 | #include <TH2D.h> | |
40 | #include <TCollection.h> | |
41 | ||
42 | ClassImp(AliCounterCollection) | |
43 | ||
44 | //----------------------------------------------------------------------- | |
45 | AliCounterCollection::AliCounterCollection(const char* name) : | |
46 | TNamed(name,name), | |
47 | fRubrics(new THashList(10)), | |
48 | fRubricsSize(new TArrayI(10)), | |
d810835e | 49 | fCounters(0x0), |
5d8c0c8a | 50 | fWeightedCounters(kFALSE), |
51 | fLongCounters(kFALSE) | |
94ef1a28 | 52 | { |
53 | /// Constructor | |
54 | fRubrics->SetOwner(); | |
55 | } | |
56 | ||
57 | //----------------------------------------------------------------------- | |
58 | AliCounterCollection::~AliCounterCollection() | |
59 | { | |
60 | /// Destructor | |
61 | delete fRubrics; | |
62 | delete fRubricsSize; | |
63 | delete fCounters; | |
64 | } | |
65 | ||
66 | //----------------------------------------------------------------------- | |
67 | void AliCounterCollection::Clear(Option_t*) | |
68 | { | |
69 | /// Clear counters | |
70 | fRubrics->Clear(); | |
71 | fRubricsSize->Reset(); | |
72 | delete fCounters; fCounters = 0x0; | |
d810835e | 73 | fWeightedCounters = kFALSE; |
5d8c0c8a | 74 | fLongCounters = kFALSE; |
94ef1a28 | 75 | } |
76 | ||
77 | //----------------------------------------------------------------------- | |
78 | void AliCounterCollection::AddRubric(TString name, TString listOfKeyWords) | |
79 | { | |
80 | /// Add a new rubric with the complete list of related key words separated by "/". | |
81 | /// If the key word "any" is not defined, the overall statistics is | |
82 | /// assumed to be the sum of the statistics under each key word. | |
83 | ||
84 | name.ToUpper(); | |
85 | listOfKeyWords.ToUpper(); | |
86 | ||
87 | if (fRubrics->Contains(name.Data())) { | |
88 | AliError(Form("rubric named %s already exist",name.Data())); | |
89 | return; | |
90 | } | |
91 | ||
92 | // add the list of autorized key words | |
93 | TObjArray* rubric = listOfKeyWords.Tokenize("/"); | |
94 | CleanListOfStrings(rubric); | |
95 | rubric->SetName(name.Data()); | |
96 | Int_t nRubrics = fRubrics->GetSize(); | |
97 | rubric->SetUniqueID(nRubrics); | |
98 | fRubrics->AddLast(rubric); | |
99 | ||
100 | // save the number of autorized key words (expand the array if needed) | |
101 | if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize()); | |
102 | (*fRubricsSize)[nRubrics] = rubric->GetEntriesFast(); | |
103 | } | |
104 | ||
105 | //----------------------------------------------------------------------- | |
106 | void AliCounterCollection::AddRubric(TString name, Int_t maxNKeyWords) | |
107 | { | |
108 | /// Add a new rubric containing at maximum maxNKeyWords key words. | |
109 | /// Key words will be added as the counters get filled until the maximum is reached. | |
110 | /// If the key word "any" is never defined, the overall statistics is | |
111 | /// assumed to be the sum of the statistics under each key word. | |
112 | ||
113 | name.ToUpper(); | |
114 | ||
115 | if (fRubrics->Contains(name.Data())) { | |
116 | AliError(Form("rubric named %s already exist",name.Data())); | |
117 | return; | |
118 | } | |
119 | ||
120 | // create the empty rubric | |
121 | TObjString* rubric = new TObjString(name.Data()); | |
122 | Int_t nRubrics = fRubrics->GetSize(); | |
123 | rubric->SetUniqueID(nRubrics); | |
124 | fRubrics->AddLast(rubric); | |
125 | ||
126 | // save the maximum number of autorized key words | |
127 | if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize()); | |
128 | (*fRubricsSize)[nRubrics] = maxNKeyWords; | |
129 | } | |
130 | ||
131 | //----------------------------------------------------------------------- | |
d810835e | 132 | void AliCounterCollection::Init(Bool_t weightedCounters) |
94ef1a28 | 133 | { |
134 | /// Initialize the internal counters from the added rubrics. | |
135 | ||
136 | // create the counters | |
137 | delete fCounters; | |
d810835e | 138 | fWeightedCounters = weightedCounters; |
139 | if (fWeightedCounters) | |
140 | fCounters = new THnSparseT<TArrayF>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0); | |
141 | else | |
142 | fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0); | |
94ef1a28 | 143 | |
144 | // loop over axis | |
145 | TObject* rubric = 0x0; | |
146 | TIter nextRubric(fRubrics); | |
147 | while ((rubric = nextRubric())) { | |
148 | TAxis* axis = fCounters->GetAxis((Int_t)rubric->GetUniqueID()); | |
149 | ||
150 | // set axis name | |
151 | axis->SetName(rubric->GetName()); | |
152 | ||
153 | // set labels if already known | |
154 | TObjArray* keyWords = dynamic_cast<TObjArray*>(rubric); | |
155 | if (keyWords) { | |
156 | TObjString* label = 0x0; | |
157 | Int_t bin = 1; | |
158 | TIter nextLabel(keyWords); | |
159 | while ((label = static_cast<TObjString*>(nextLabel()))) axis->SetBinLabel(bin++, label->String().Data()); | |
160 | } | |
161 | ||
162 | } | |
163 | ||
164 | } | |
165 | ||
6f5626c7 | 166 | //----------------------------------------------------------------------- |
167 | Int_t AliCounterCollection::GetNActiveBins(Int_t dim) | |
168 | { | |
169 | /// return the number of labels in that rubric. | |
170 | THashList* labels = fCounters->GetAxis(dim)->GetLabels(); | |
171 | return (labels) ? labels->GetSize() : 0; | |
172 | } | |
173 | ||
174 | //----------------------------------------------------------------------- | |
175 | Bool_t AliCounterCollection::ContainsAny(Int_t dim) | |
176 | { | |
177 | /// return kTRUE if that rubric contains the keyWord "ANY". | |
178 | THashList* labels = fCounters->GetAxis(dim)->GetLabels(); | |
179 | return (labels && labels->Contains("ANY")); | |
180 | } | |
181 | ||
94ef1a28 | 182 | //----------------------------------------------------------------------- |
183 | const Int_t* AliCounterCollection::FindBins(const TString& externalKey, Bool_t allocate, Int_t& nEmptySlots) | |
184 | { | |
185 | /// Return the corresponding bins ordered by rubric or 0x0 if externalKey is not valid. | |
186 | /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/... | |
187 | /// If allocate = kTRUE, new key words are added to the corresponding rubric if possible. | |
188 | /// If a rubric is not filled in, the coresponding slot contain -1 in the array. | |
189 | /// It is the responsability of the user to delete the returned array. | |
190 | ||
191 | // produce an empty array of keys | |
192 | Int_t nRubrics = fRubrics->GetSize(); | |
193 | Int_t* bins = new Int_t[nRubrics]; | |
6f5626c7 | 194 | for (Int_t i=0; i<nRubrics; i++) bins[i] = -1; |
94ef1a28 | 195 | nEmptySlots = nRubrics; |
196 | Bool_t isValid = kTRUE; | |
197 | ||
198 | // get the list of rubric:keyWord pairs | |
199 | TObjArray* rubricKeyPairs = externalKey.Tokenize("/"); | |
200 | ||
201 | // loop over each rubric:keyWord pair | |
202 | TObjString* pair = 0x0; | |
203 | TIter next(rubricKeyPairs); | |
204 | while ((pair = static_cast<TObjString*>(next()))) { | |
205 | ||
206 | // get both rubric and associated key word | |
207 | TObjArray* rubricKeyPair = pair->String().Tokenize(":"); | |
208 | ||
209 | // check the format of the pair | |
210 | if (rubricKeyPair->GetEntriesFast() != 2) { | |
211 | AliError("invalid key format"); | |
212 | isValid = kFALSE; | |
213 | delete rubricKeyPair; | |
214 | break; | |
215 | } | |
216 | ||
217 | // get the axis corresponding to that rubric | |
218 | Int_t dim = FindDim(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String()); | |
219 | if (dim < 0) { | |
220 | isValid = kFALSE; | |
221 | delete rubricKeyPair; | |
222 | break; | |
223 | } | |
224 | ||
225 | // find the bin corresponding to that key word | |
226 | Int_t bin = FindBin(dim, static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String(), allocate); | |
227 | if (bin < 0) { | |
228 | isValid = kFALSE; | |
229 | delete rubricKeyPair; | |
230 | break; | |
231 | } | |
232 | ||
233 | // check if the array of keys already contains something for that rubric | |
234 | if (bins[dim] >= 0) { | |
235 | AliWarning("key already given for that rubric --> ignored"); | |
236 | delete rubricKeyPair; | |
237 | continue; | |
238 | } | |
239 | ||
240 | // store the corresponding bin for that slot | |
241 | bins[dim] = bin; | |
242 | nEmptySlots--; | |
243 | ||
244 | // clean memory | |
245 | delete rubricKeyPair; | |
246 | } | |
247 | ||
248 | // delete the array in case of problem | |
249 | if (!isValid) { | |
250 | delete[] bins; | |
251 | bins = 0x0; | |
252 | nEmptySlots = nRubrics; | |
253 | } | |
254 | ||
255 | // clean memory | |
256 | delete rubricKeyPairs; | |
257 | ||
258 | return bins; | |
259 | } | |
260 | ||
261 | //----------------------------------------------------------------------- | |
262 | Int_t AliCounterCollection::FindDim(const TString& rubricName) const | |
263 | { | |
264 | /// Return the dimension corresponding to that rubric (or -1 in case of failure). | |
265 | TObject* rubric = fRubrics->FindObject(rubricName.Data()); | |
266 | if (!rubric) { | |
267 | AliError(Form("invalid rubric: %s",rubricName.Data())); | |
268 | return -1; | |
269 | } | |
270 | return (Int_t) rubric->GetUniqueID(); | |
271 | } | |
272 | ||
273 | //----------------------------------------------------------------------- | |
274 | Int_t AliCounterCollection::FindBin(Int_t dim, const TString& keyWord, Bool_t allocate) | |
275 | { | |
276 | /// Return the bin number corresponding to that key word (or -1 in case of failure). | |
277 | /// If allocate = kTRUE, try to add the key word if possible. | |
278 | ||
279 | TAxis* axis = fCounters->GetAxis(dim); | |
280 | ||
281 | // look for the bin corresponding to keyWord | |
282 | THashList* labels = axis->GetLabels(); | |
283 | TObjString* label = (labels) ? static_cast<TObjString*>(labels->FindObject(keyWord.Data())) : 0x0; | |
284 | Int_t bin = (label) ? (Int_t)label->GetUniqueID() : -1; | |
285 | ||
286 | // in case the keyWord does not exist, try to add it if required | |
287 | if (bin<0 && allocate) { | |
288 | Int_t nLabels = (labels) ? labels->GetSize() : 0; | |
289 | if (nLabels < axis->GetNbins()) { | |
290 | bin = nLabels+1; | |
291 | axis->SetBinLabel(bin, keyWord.Data()); | |
292 | } | |
293 | } | |
294 | ||
295 | if (bin<0) AliError(Form("invalid key word: %s:%s",axis->GetName(),keyWord.Data())); | |
296 | ||
297 | return bin; | |
298 | } | |
299 | ||
6f5626c7 | 300 | //----------------------------------------------------------------------- |
301 | Short_t** AliCounterCollection::DecodeSelection(const TString& selections, const TObjArray& displayedRubrics) | |
302 | { | |
303 | /// Tag the selected keywords in each rubric (-1=subtract; 0=discard; 1=add). Format: | |
304 | /// "rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.." (order does not matter). | |
305 | /// It is the responsability of the user to delete the returned array. | |
306 | ||
307 | // produce an empty array of selected keys | |
308 | Int_t nRubrics = fCounters->GetNdimensions(); | |
309 | Short_t** selects = new Short_t*[nRubrics]; | |
310 | for (Int_t i=0; i<nRubrics; i++) selects[i] = 0x0; | |
311 | ||
312 | // get the list of rubric:LisOfKeyWord pairs | |
313 | TObjArray* rubricKeyPairs = selections.Tokenize("/"); | |
314 | ||
315 | // loop over each rubric:keyWord pair | |
316 | TObjString* pair = 0x0; | |
317 | TIter next(rubricKeyPairs); | |
318 | while ((pair = static_cast<TObjString*>(next()))) { | |
319 | ||
320 | // get both rubric and associated list of key words | |
321 | TObjArray* rubricKeyPair = pair->String().Tokenize(":"); | |
322 | ||
323 | // check the format of the pair | |
324 | if (rubricKeyPair->GetEntriesFast() != 2) { | |
325 | AliError("invalid key format"); | |
326 | delete rubricKeyPair; | |
327 | delete rubricKeyPairs; | |
328 | for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i]; | |
329 | delete[] selects; | |
330 | return 0x0; | |
331 | } | |
332 | ||
333 | // check wether to select or to discard the keyWords | |
334 | Int_t include = kTRUE; | |
335 | TString ListOfKeyWords(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String()); | |
336 | if (ListOfKeyWords.BeginsWith("ANY-")) { | |
337 | ListOfKeyWords.Remove(0,4); | |
338 | include = kFALSE; | |
339 | } | |
340 | ||
341 | // select the key words | |
342 | const TString& rubric = static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String(); | |
343 | if (!Select(include, rubric, ListOfKeyWords, displayedRubrics.Contains(rubric.Data()), selects)) { | |
344 | delete rubricKeyPair; | |
345 | delete rubricKeyPairs; | |
346 | for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i]; | |
347 | delete[] selects; | |
348 | return 0x0; | |
349 | } | |
350 | ||
351 | // clean memory | |
352 | delete rubricKeyPair; | |
353 | } | |
354 | ||
355 | // clean memory | |
356 | delete rubricKeyPairs; | |
357 | ||
358 | // complete the selection of other rubrics | |
359 | for (Int_t i=0; i<nRubrics; i++) { | |
360 | ||
361 | // skip already processed rubrics | |
362 | if (selects[i]) continue; | |
363 | ||
364 | // create the list of bins | |
365 | Int_t nBins = GetNActiveBins(i) + 1; | |
366 | selects[i] = new Short_t[nBins]; | |
367 | ||
368 | // select all key words or only the key work "ANY" | |
369 | if (ContainsAny(i) && !displayedRubrics.Contains(fCounters->GetAxis(i)->GetName())) { | |
370 | memset(selects[i], 0, sizeof(Short_t) * nBins); | |
371 | selects[i][FindBin(i, "ANY", kFALSE)] = 1; | |
372 | } else for (Int_t j=0; j<nBins; j++) selects[i][j] = 1; | |
373 | ||
374 | } | |
375 | ||
376 | return selects; | |
377 | } | |
378 | ||
379 | //----------------------------------------------------------------------- | |
380 | Bool_t AliCounterCollection::Select(Bool_t include, const TString& rubric, const TString& keywords, | |
381 | Bool_t displayed, Short_t* selectBins[]) | |
382 | { | |
383 | /// Tag the selected keywords (separated by ',') in that rubric (-1=subtract; 0=discard; 1=add). | |
384 | ||
385 | Int_t dim = FindDim(rubric); | |
386 | if (dim < 0) return kFALSE; | |
387 | ||
388 | if (selectBins[dim]) { | |
389 | AliWarning(Form("selection already made for rubric %s --> ignored",rubric.Data())); | |
390 | return kTRUE; | |
391 | } | |
392 | ||
393 | // get list of key words to select | |
394 | TObjArray* keys = keywords.Tokenize(","); | |
395 | if (keys->GetEntriesFast() == 0) { | |
396 | AliError(Form("no key word specified for rubric %s",rubric.Data())); | |
397 | delete keys; | |
398 | return kFALSE; | |
399 | } | |
400 | ||
401 | // create the list of bins | |
402 | Int_t nBins = GetNActiveBins(dim) + 1; | |
403 | selectBins[dim] = new Short_t[nBins]; | |
404 | ||
405 | // select/unselect all bins | |
406 | Bool_t containsAny = ContainsAny(dim); | |
407 | if (include || (containsAny && !displayed)) { | |
408 | memset(selectBins[dim], 0, sizeof(Short_t) * nBins); | |
409 | if (!include) selectBins[dim][FindBin(dim, "ANY", kFALSE)] = 1; | |
410 | } else for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1; | |
411 | ||
412 | // select/unselect specific key words | |
413 | TObjString* key = 0x0; | |
414 | TIter nextKey(keys); | |
415 | while ((key = static_cast<TObjString*>(nextKey()))) { | |
416 | ||
417 | // special case of key word "ANY" | |
418 | if (key->String() == "ANY") { | |
419 | ||
420 | if (containsAny) { | |
421 | ||
422 | Int_t binAny = FindBin(dim, "ANY", kFALSE); | |
423 | if (include) selectBins[dim][binAny] = 1; | |
424 | else selectBins[dim][binAny] = 0; | |
425 | ||
426 | } else { | |
427 | ||
428 | if (include) for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1; | |
429 | else memset(selectBins[dim], 0, sizeof(Short_t) * nBins); | |
430 | ||
431 | } | |
432 | ||
433 | } else { // other cases | |
434 | ||
435 | // find the corresponding bin | |
436 | Int_t bin = FindBin(dim, key->String().Data(), kFALSE); | |
437 | if (bin < 0) { | |
438 | delete keys; | |
439 | return kFALSE; | |
440 | } | |
441 | ||
442 | // select/unselect it | |
443 | if (include) selectBins[dim][bin] = 1; | |
444 | else if (containsAny && !displayed) selectBins[dim][bin] = -1; | |
445 | else selectBins[dim][bin] = 0; | |
446 | ||
447 | } | |
448 | ||
449 | } | |
450 | ||
451 | // clean memory | |
452 | delete keys; | |
453 | ||
454 | return kTRUE; | |
455 | } | |
456 | ||
94ef1a28 | 457 | //----------------------------------------------------------------------- |
458 | void AliCounterCollection::CleanListOfStrings(TObjArray* list) | |
459 | { | |
460 | /// Make sure all strings appear only once in this list | |
461 | ||
462 | // remove multiple-occurrence | |
463 | Int_t nEntries = list->GetEntriesFast(); | |
464 | for (Int_t i = 0; i < nEntries; i++) { | |
465 | TObjString* entry1 = static_cast<TObjString*>(list->UncheckedAt(i)); | |
466 | if (!entry1) continue; | |
467 | for (Int_t j = i+1; j < nEntries; j++) { | |
468 | TObjString* entry2 = static_cast<TObjString*>(list->UncheckedAt(j)); | |
469 | if (entry2 && entry2->IsEqual(entry1)) { | |
470 | AliWarning(Form("multiple-occurence of string \"%s\" --> removed",entry2->String().Data())); | |
471 | list->RemoveAt(j); | |
472 | } | |
473 | } | |
474 | } | |
475 | ||
476 | // remove empty slots | |
477 | list->Compress(); | |
478 | } | |
479 | ||
480 | //----------------------------------------------------------------------- | |
481 | void AliCounterCollection::Count(TString externalKey, Int_t value) | |
d810835e | 482 | { |
483 | /// Add "value" to the counter referenced by "externalKey". | |
484 | /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/... | |
485 | if (value > 0) CountAsDouble(externalKey, (Double_t)value); | |
486 | else if (value < 0) AliError("cannot count negative values"); | |
487 | } | |
488 | ||
489 | //----------------------------------------------------------------------- | |
490 | void AliCounterCollection::Count(TString externalKey, Double_t value) | |
491 | { | |
492 | /// Add "value" to the counter referenced by "externalKey". | |
493 | /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/... | |
494 | if (fWeightedCounters) CountAsDouble(externalKey, value); | |
495 | else AliError("non-weighted counters can only be filled with intergers"); | |
496 | } | |
497 | ||
498 | //----------------------------------------------------------------------- | |
499 | void AliCounterCollection::CountAsDouble(TString externalKey, Double_t value) | |
94ef1a28 | 500 | { |
501 | /// Add "value" to the counter referenced by "externalKey". | |
502 | /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/... | |
503 | ||
94ef1a28 | 504 | if (!fCounters) { |
505 | AliError("counters are not initialized"); | |
506 | return; | |
507 | } | |
508 | ||
509 | externalKey.ToUpper(); | |
510 | ||
511 | // convert external to internal key | |
512 | Int_t nEmptySlots = 0; | |
513 | const Int_t* bins = FindBins(externalKey, kTRUE, nEmptySlots); | |
514 | if (!bins) return; | |
515 | ||
516 | // check for empty slots | |
517 | if (nEmptySlots > 0) { | |
518 | AliError("incomplete key"); | |
519 | delete[] bins; | |
520 | return; | |
521 | } | |
522 | ||
5d8c0c8a | 523 | if (fWeightedCounters || fLongCounters) { |
524 | ||
525 | // increment the corresponding counter | |
526 | fCounters->AddBinContent(bins, value); | |
527 | ||
528 | } else { | |
529 | ||
530 | // switch to long counters if needed before incrementing | |
531 | Long64_t linBin = fCounters->GetBin(bins, kTRUE); | |
532 | Double_t currentValue = fCounters->GetBinContent(linBin); | |
533 | if (currentValue+value > INT_MAX) { | |
534 | ConvertToTHnSparseL(fCounters); | |
535 | fLongCounters = kTRUE; | |
536 | fCounters->AddBinContent(bins, value); | |
537 | } else fCounters->AddBinContent(linBin, value); | |
538 | ||
539 | } | |
94ef1a28 | 540 | |
541 | // clean memory | |
542 | delete[] bins; | |
543 | } | |
544 | ||
545 | //----------------------------------------------------------------------- | |
546 | void AliCounterCollection::Print(const Option_t* opt) const | |
547 | { | |
7471ae1a | 548 | /// Print every individual counters if opt=="" or call "Print(opt, "")". |
94ef1a28 | 549 | |
550 | if (strcmp(opt,"")) { | |
551 | const_cast<AliCounterCollection*>(this)->Print(opt, ""); | |
552 | return; | |
553 | } | |
554 | ||
555 | if (!fCounters) { | |
556 | AliError("counters are not initialized"); | |
557 | return; | |
558 | } | |
559 | ||
560 | if (fCounters->GetNbins() == 0) { | |
561 | printf("\nall counters are empty\n\n"); | |
562 | return; | |
563 | } | |
564 | ||
565 | Int_t nRubrics = fCounters->GetNdimensions(); | |
566 | Int_t* bins = new Int_t[nRubrics]; | |
567 | ||
568 | // loop over every filled counters | |
569 | for (Long64_t i=0; i<fCounters->GetNbins(); ++i) { | |
570 | ||
571 | // get the content of the bin | |
d810835e | 572 | Double_t value = fCounters->GetBinContent(i, bins); |
94ef1a28 | 573 | |
574 | // build the corresponding counter name | |
575 | TString counter; | |
576 | for (Int_t j=0; j<nRubrics; j++) counter += Form("/%s",fCounters->GetAxis(j)->GetBinLabel(bins[j])); | |
577 | counter += "/"; | |
578 | ||
579 | // print value | |
d810835e | 580 | if (fWeightedCounters) printf("\n%s %g", counter.Data(), value); |
5d8c0c8a | 581 | else if (fLongCounters) printf("\n%s %ld", counter.Data(), (Long_t)value); |
d810835e | 582 | else printf("\n%s %d", counter.Data(), (Int_t)value); |
94ef1a28 | 583 | } |
584 | printf("\n\n"); | |
585 | ||
586 | // clean memory | |
587 | delete[] bins; | |
588 | } | |
589 | ||
590 | //----------------------------------------------------------------------- | |
d649ab79 | 591 | TString AliCounterCollection::GetKeyWords(TString rubric) const |
592 | { | |
593 | /// return the list of key words for the given rubric. | |
594 | ||
595 | TString keyWords = ""; | |
596 | ||
597 | if (!fCounters) { | |
598 | AliError("counters are not initialized"); | |
599 | return keyWords; | |
600 | } | |
601 | ||
602 | rubric.ToUpper(); | |
603 | ||
604 | // get the dimension corresponding to that rubric | |
605 | Int_t dim = FindDim(rubric); | |
606 | if (dim < 0) return keyWords; | |
607 | ||
608 | // build list of key words | |
609 | TObjString* label = 0x0; | |
610 | TIter nextLabel(fCounters->GetAxis(dim)->GetLabels()); | |
611 | while ((label = static_cast<TObjString*>(nextLabel()))) keyWords += Form("%s,",label->String().Data()); | |
612 | keyWords.Remove(TString::kTrailing, ','); | |
613 | ||
614 | return keyWords; | |
615 | } | |
616 | ||
d810835e | 617 | //----------------------------------------------------------------------- |
5d8c0c8a | 618 | Double_t AliCounterCollection::GetSum(TString selections, Bool_t* longCounters) |
d810835e | 619 | { |
620 | /// Get the overall statistics for the given selection (result is integrated over not specified rubrics): | |
621 | /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). | |
5d8c0c8a | 622 | /// - The flag "longCounters" tells whether the histogram contains value(s) larger than INT_MAX. |
623 | ||
624 | // set the flag "longCounters" according to the content of current counters | |
625 | if (longCounters) *longCounters = fLongCounters; | |
d810835e | 626 | |
627 | if (!fCounters) { | |
628 | AliError("counters are not initialized"); | |
629 | return 0.; | |
630 | } | |
631 | ||
632 | selections.ToUpper(); | |
633 | ||
634 | // decode the selections | |
635 | Short_t** select = DecodeSelection(selections, TObjArray()); | |
636 | if (!select) return 0.; | |
637 | ||
638 | // loop over every filled counters and compute integral | |
639 | Double_t sum = 0.; | |
640 | Int_t nDims = fCounters->GetNdimensions(); | |
641 | Int_t* coord = new Int_t[nDims]; | |
642 | for (Long64_t i=0; i<fCounters->GetNbins(); ++i) { | |
643 | ||
644 | // get the content of the counter | |
645 | Double_t value = fCounters->GetBinContent(i, coord); | |
646 | ||
647 | // discard not selected counters and compute the selection factor | |
648 | Int_t selectionFactor = 1; | |
649 | for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]]; | |
650 | if (selectionFactor == 0) continue; | |
651 | ||
652 | // compute integral | |
653 | sum += selectionFactor * value; | |
654 | } | |
655 | ||
5d8c0c8a | 656 | // check if the sum exceed INT_MAX (only in case of integer counters) |
657 | if (longCounters && !fWeightedCounters && sum > INT_MAX) *longCounters = kTRUE; | |
658 | ||
d810835e | 659 | // clean memory |
660 | for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim]; | |
661 | delete[] select; | |
662 | delete[] coord; | |
663 | ||
664 | return sum; | |
665 | } | |
666 | ||
d649ab79 | 667 | //----------------------------------------------------------------------- |
94ef1a28 | 668 | void AliCounterCollection::PrintKeyWords() const |
669 | { | |
670 | /// Print the full list of key words. | |
671 | ||
672 | if (!fCounters) { | |
673 | AliError("counters are not initialized"); | |
674 | return; | |
675 | } | |
676 | ||
677 | // loop over rubrics | |
678 | Int_t nRubrics = fCounters->GetNdimensions(); | |
679 | for (Int_t iDim=0; iDim<nRubrics; iDim++) { | |
680 | TAxis* axis = fCounters->GetAxis(iDim); | |
681 | ||
682 | // print rubric's name | |
683 | printf("\n%s:", axis->GetName()); | |
684 | ||
685 | // loop over key words | |
686 | Bool_t first = kTRUE; | |
687 | TObjString* label = 0x0; | |
688 | TIter nextLabel(axis->GetLabels()); | |
689 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
690 | ||
691 | //print key word's name | |
692 | if (first) { | |
693 | printf("%s", label->String().Data()); | |
694 | first = kFALSE; | |
695 | } else printf(",%s", label->String().Data()); | |
696 | ||
697 | } | |
698 | } | |
699 | printf("\n\n"); | |
700 | } | |
701 | ||
702 | //----------------------------------------------------------------------- | |
703 | void AliCounterCollection::PrintValue(TString selections) | |
704 | { | |
705 | /// Print value of selected counter. | |
6f5626c7 | 706 | /// format of "selections" is rubric:keyWord/rubric:keyWord/rubric:keyWord/... |
94ef1a28 | 707 | |
708 | if (!fCounters) { | |
709 | AliError("counters are not initialized"); | |
710 | return; | |
711 | } | |
712 | ||
713 | selections.ToUpper(); | |
714 | ||
715 | // convert external to internal key | |
716 | Int_t nEmptySlots = 0; | |
717 | const Int_t* selectedBins = FindBins(selections, kFALSE, nEmptySlots); | |
718 | if (!selectedBins) return; | |
719 | ||
720 | // check for empty slots | |
721 | if (nEmptySlots > 0) { | |
722 | AliError("incomplete key"); | |
723 | delete[] selectedBins; | |
724 | return; | |
725 | } | |
726 | ||
727 | // print value | |
d810835e | 728 | if (fWeightedCounters) printf("\n%g\n\n", fCounters->GetBinContent(selectedBins)); |
5d8c0c8a | 729 | else if (fLongCounters) printf("\n%ld\n\n", (Long_t) fCounters->GetBinContent(selectedBins)); |
d810835e | 730 | else printf("\n%d\n\n", (Int_t) fCounters->GetBinContent(selectedBins)); |
94ef1a28 | 731 | |
732 | // clean memory | |
733 | delete[] selectedBins; | |
734 | } | |
735 | ||
736 | //----------------------------------------------------------------------- | |
7471ae1a | 737 | void AliCounterCollection::Print(TString rubrics, TString selections, Bool_t removeEmpty) |
94ef1a28 | 738 | { |
739 | /// Print desired rubrics for the given selection: | |
740 | /// - format of "rubrics" is rubric1/rubric2/.. (order matters only for output). | |
6f5626c7 | 741 | /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). |
94ef1a28 | 742 | /// If "data" contains 1 rubric, the output will be one counter for each element of that rubric. |
743 | /// If "data" contains 2 rubrics, the output will be an array of counters, rubric1 vs rubric2. | |
744 | /// If "data" contains 3 rubrics, the output will be an array rubric1 vs rubric2 for each element in rubric3. | |
745 | /// ... | |
746 | /// Results are integrated over rubrics not specified neither in "rubrics" nor in "selections". | |
747 | ||
748 | if (!fCounters) { | |
749 | AliError("counters are not initialized"); | |
750 | return; | |
751 | } | |
752 | ||
753 | rubrics.ToUpper(); | |
754 | selections.ToUpper(); | |
755 | ||
756 | // get the rubrics to print | |
757 | TObjArray* rubricsToPrint = rubrics.Tokenize("/"); | |
758 | if (rubricsToPrint->GetEntriesFast() == 0) { | |
759 | delete rubricsToPrint; | |
760 | return; | |
761 | } | |
762 | ||
763 | // remove rubrics called twice | |
764 | CleanListOfStrings(rubricsToPrint); | |
765 | ||
766 | // project counters in the rubrics to print according to the selections | |
5d8c0c8a | 767 | Bool_t longCounters = kFALSE; |
768 | TObject* hist = Projection(*rubricsToPrint, selections, longCounters); | |
94ef1a28 | 769 | if (!hist) { |
770 | delete rubricsToPrint; | |
771 | return; | |
772 | } | |
773 | ||
774 | // print counters | |
775 | Int_t nRubricsToPrint = rubricsToPrint->GetEntriesFast(); | |
6f5626c7 | 776 | if (nRubricsToPrint == 1 && (static_cast<TH1D*>(hist))->GetEntries() > 0) |
5d8c0c8a | 777 | PrintList(static_cast<TH1D*>(hist), removeEmpty, longCounters); |
6f5626c7 | 778 | else if (nRubricsToPrint == 2 && (static_cast<TH2D*>(hist))->GetEntries() > 0) |
5d8c0c8a | 779 | PrintArray(static_cast<TH2D*>(hist), removeEmpty, longCounters); |
6f5626c7 | 780 | else if (nRubricsToPrint > 2 && (static_cast<THnSparse*>(hist))->GetEntries() > 0) |
5d8c0c8a | 781 | PrintListOfArrays(static_cast<THnSparse*>(hist), removeEmpty, longCounters); |
94ef1a28 | 782 | else |
783 | printf("\nselected counters are empty\n\n"); | |
784 | ||
785 | // clean memory | |
786 | delete rubricsToPrint; | |
787 | delete hist; | |
788 | } | |
789 | ||
790 | //----------------------------------------------------------------------- | |
6f5626c7 | 791 | void AliCounterCollection::PrintSum(TString selections) |
94ef1a28 | 792 | { |
6f5626c7 | 793 | /// Print the overall statistics for the given selection (result is integrated over not specified rubrics): |
794 | /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). | |
5d8c0c8a | 795 | Bool_t longCounters = kFALSE; |
796 | Double_t sum = GetSum(selections, &longCounters); | |
d810835e | 797 | if (fWeightedCounters) printf("\n%g\n\n", sum); |
5d8c0c8a | 798 | else if (longCounters) printf("\n%ld\n\n", (Long_t)sum); |
d810835e | 799 | else printf("\n%d\n\n", (Int_t)sum); |
94ef1a28 | 800 | } |
801 | ||
802 | //----------------------------------------------------------------------- | |
5d8c0c8a | 803 | void AliCounterCollection::PrintList(const TH1D* hist, Bool_t removeEmpty, Bool_t longCounters) const |
94ef1a28 | 804 | { |
805 | /// Print the content of 1D histogram as a list. | |
806 | ||
807 | // set the format to print labels | |
808 | THashList* labels = hist->GetXaxis()->GetLabels(); | |
d810835e | 809 | TString format = ""; |
5d8c0c8a | 810 | if (fWeightedCounters) format = Form("\n%%%ds %%10g",GetMaxLabelSize(labels)); |
811 | else if (longCounters) format = Form("\n%%%ds %%16ld",GetMaxLabelSize(labels)); | |
812 | else format = Form("\n%%%ds %%10d",GetMaxLabelSize(labels)); | |
94ef1a28 | 813 | |
814 | // print value for each label | |
815 | TObjString* label = 0x0; | |
816 | TIter nextLabel(labels); | |
817 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
818 | Int_t bin = (Int_t) label->GetUniqueID(); | |
7471ae1a | 819 | Double_t value = hist->GetBinContent(bin); |
820 | if (removeEmpty && value == 0.) continue; | |
821 | if (fWeightedCounters) printf(format.Data(), label->String().Data(), value); | |
5d8c0c8a | 822 | else if (longCounters) printf(format.Data(), label->String().Data(), (Long_t) value); |
7471ae1a | 823 | else printf(format.Data(), label->String().Data(), (Int_t) value); |
94ef1a28 | 824 | } |
825 | printf("\n\n"); | |
826 | } | |
827 | ||
828 | //----------------------------------------------------------------------- | |
5d8c0c8a | 829 | void AliCounterCollection::PrintArray(const TH2D* hist, Bool_t removeEmpty, Bool_t longCounters) const |
94ef1a28 | 830 | { |
831 | /// Print the content of 2D histogram as an array. | |
832 | ||
833 | // set the format to print labels in X direction | |
834 | THashList* labelsX = hist->GetXaxis()->GetLabels(); | |
835 | TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX))); | |
836 | ||
5d8c0c8a | 837 | // set the format to print labels in Y direction |
94ef1a28 | 838 | THashList* labelsY = hist->GetYaxis()->GetLabels(); |
5d8c0c8a | 839 | Int_t maxLabelSizeY = GetMaxLabelSize(labelsY); |
840 | TString formatYv = ""; | |
841 | if (fWeightedCounters) { | |
842 | maxLabelSizeY = TMath::Max(10, maxLabelSizeY); | |
843 | formatYv = Form("%%%dg ",maxLabelSizeY); | |
844 | } else if (longCounters) { | |
845 | maxLabelSizeY = TMath::Max(16, maxLabelSizeY); | |
846 | formatYv = Form("%%%dld ",maxLabelSizeY); | |
847 | } else { | |
848 | maxLabelSizeY = TMath::Max(10, maxLabelSizeY); | |
849 | formatYv = Form("%%%dd ",maxLabelSizeY); | |
850 | } | |
851 | TString formatYs = Form("%%%ds ",maxLabelSizeY); | |
94ef1a28 | 852 | |
7471ae1a | 853 | // if required, set the list of labels for which all counters are not empty |
854 | Bool_t *useLabelX = 0x0, *useLabelY = 0x0; | |
855 | TObjString *labelX = 0x0, *labelY = 0x0; | |
856 | TIter nextLabelX(labelsX); | |
857 | TIter nextLabelY(labelsY); | |
858 | if (removeEmpty) { | |
859 | ||
860 | // create label flags and set them as unused | |
861 | useLabelX = new Bool_t[labelsX->GetSize()+1]; | |
862 | memset(useLabelX, kFALSE, sizeof(Bool_t) * (labelsX->GetSize()+1)); | |
863 | useLabelY = new Bool_t[labelsY->GetSize()+1]; | |
864 | memset(useLabelY, kFALSE, sizeof(Bool_t) * (labelsY->GetSize()+1)); | |
865 | ||
866 | // loop over labels in X direction | |
867 | while ((labelX = static_cast<TObjString*>(nextLabelX()))) { | |
868 | Int_t binX = (Int_t) labelX->GetUniqueID(); | |
869 | ||
870 | // loop over labels in Y direction | |
871 | nextLabelY.Reset(); | |
872 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { | |
873 | Int_t binY = (Int_t) labelY->GetUniqueID(); | |
874 | ||
875 | // both labels already set as used | |
876 | if (useLabelX[binX] && useLabelY[binY]) continue; | |
877 | ||
878 | // skip empty bins | |
879 | if (hist->GetBinContent(binX, binY) == 0.) continue; | |
880 | ||
881 | // set label as used | |
882 | useLabelX[binX] = kTRUE; | |
883 | useLabelY[binY] = kTRUE; | |
884 | ||
885 | } | |
886 | ||
887 | } | |
888 | ||
889 | } | |
890 | ||
94ef1a28 | 891 | // print labels in Y axis |
892 | printf(formatX.Data()," "); | |
7471ae1a | 893 | nextLabelY.Reset(); |
894 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { | |
895 | if (removeEmpty && !useLabelY[labelY->GetUniqueID()]) continue; | |
94ef1a28 | 896 | printf(formatYs.Data(), labelY->String().Data()); |
7471ae1a | 897 | } |
94ef1a28 | 898 | |
899 | // fill array for each label in X axis | |
7471ae1a | 900 | nextLabelX.Reset(); |
94ef1a28 | 901 | while ((labelX = static_cast<TObjString*>(nextLabelX()))) { |
902 | Int_t binX = (Int_t) labelX->GetUniqueID(); | |
903 | ||
7471ae1a | 904 | if (removeEmpty && !useLabelX[binX]) continue; |
905 | ||
94ef1a28 | 906 | // print label X |
907 | printf(formatX.Data(), labelX->String().Data()); | |
908 | ||
909 | // print value for each label in Y axis | |
910 | nextLabelY.Reset(); | |
911 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { | |
912 | Int_t binY = (Int_t) labelY->GetUniqueID(); | |
7471ae1a | 913 | if (removeEmpty && !useLabelY[binY]) continue; |
5d8c0c8a | 914 | if (fWeightedCounters) printf(formatYv.Data(), hist->GetBinContent(binX, binY)); |
915 | else if (longCounters) printf(formatYv.Data(), (Long_t) hist->GetBinContent(binX, binY)); | |
916 | else printf(formatYv.Data(), (Int_t) hist->GetBinContent(binX, binY)); | |
94ef1a28 | 917 | } |
918 | } | |
919 | printf("\n\n"); | |
7471ae1a | 920 | |
921 | // clean memory | |
922 | if (removeEmpty) { | |
923 | delete[] useLabelX; | |
924 | delete[] useLabelY; | |
925 | } | |
94ef1a28 | 926 | } |
927 | ||
928 | //----------------------------------------------------------------------- | |
5d8c0c8a | 929 | void AliCounterCollection::PrintListOfArrays(const THnSparse* hist, Bool_t removeEmpty, Bool_t longCounters) const |
94ef1a28 | 930 | { |
931 | /// Print the content of nD histogram as a list of arrays. | |
932 | ||
933 | // set the format to print labels in X direction | |
934 | THashList* labelsX = hist->GetAxis(0)->GetLabels(); | |
935 | TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX))); | |
936 | ||
5d8c0c8a | 937 | // set the format to print labels in Y direction |
94ef1a28 | 938 | THashList* labelsY = hist->GetAxis(1)->GetLabels(); |
5d8c0c8a | 939 | Int_t maxLabelSizeY = GetMaxLabelSize(labelsY); |
940 | TString formatYv = ""; | |
941 | if (fWeightedCounters) { | |
942 | maxLabelSizeY = TMath::Max(10, maxLabelSizeY); | |
943 | formatYv = Form("%%%dg ",maxLabelSizeY); | |
944 | } else if (longCounters) { | |
945 | maxLabelSizeY = TMath::Max(16, maxLabelSizeY); | |
946 | formatYv = Form("%%%dld ",maxLabelSizeY); | |
947 | } else { | |
948 | maxLabelSizeY = TMath::Max(10, maxLabelSizeY); | |
949 | formatYv = Form("%%%dd ",maxLabelSizeY); | |
950 | } | |
94ef1a28 | 951 | TString formatYs(Form("%%%ds ",maxLabelSizeY)); |
94ef1a28 | 952 | |
953 | // create a list containing each combination of labels refering the arrays to be printout | |
954 | TList listOfCombis; | |
955 | listOfCombis.SetOwner(); | |
956 | ||
957 | // add a first empty combination | |
958 | Int_t nDim = hist->GetNdimensions(); | |
959 | listOfCombis.AddLast(new TObjArray(nDim-2)); | |
960 | ||
961 | // loop over the nDim-2 other rubrics | |
962 | for (Int_t i=2; i<nDim; i++) { | |
963 | ||
964 | // save the last label of that rubic | |
965 | THashList* labels = hist->GetAxis(i)->GetLabels(); | |
966 | TObjString* lastLabel = (labels) ? static_cast<TObjString*>(labels->Last()) : 0x0; | |
967 | if (!lastLabel) return; | |
968 | ||
969 | // prepare iteration over the list of labels | |
970 | TIter nextLabel(labels); | |
971 | ||
972 | // loop over existing combinations | |
973 | TObjLink* lnk = listOfCombis.FirstLink(); | |
974 | while (lnk) { | |
975 | ||
976 | // get the current combination | |
977 | TObjArray* currentCombi = static_cast<TObjArray*>(lnk->GetObject()); | |
978 | ||
979 | // loop over labels in the current rubric | |
980 | nextLabel.Reset(); | |
981 | TObjString* label = 0x0; | |
982 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
983 | ||
984 | // stop at the last one | |
985 | if (label == lastLabel) break; | |
986 | ||
987 | // copy the current combination, add the current label to it and add it to the list of combinations | |
988 | TObjArray* combi = new TObjArray(*currentCombi); | |
989 | combi->AddLast(label); | |
990 | listOfCombis.AddBefore(lnk, combi); | |
991 | } | |
992 | ||
993 | // add the last label to the current combination | |
994 | currentCombi->AddLast(lastLabel); | |
995 | ||
996 | lnk = lnk->Next(); | |
997 | } | |
998 | ||
999 | } | |
1000 | ||
1001 | // create bin coordinates to access individual counters | |
1002 | Int_t* bins = new Int_t[nDim]; | |
1003 | ||
7471ae1a | 1004 | // create label flags |
1005 | Bool_t *useLabelX = 0x0, *useLabelY = 0x0; | |
1006 | if (removeEmpty) { | |
1007 | useLabelX = new Bool_t[labelsX->GetSize()+1]; | |
1008 | useLabelY = new Bool_t[labelsY->GetSize()+1]; | |
1009 | } | |
1010 | ||
94ef1a28 | 1011 | // loop over each combination of labels |
1012 | TObjArray* combi = 0x0; | |
1013 | TIter nextCombi(&listOfCombis); | |
1014 | while ((combi = static_cast<TObjArray*>(nextCombi()))) { | |
1015 | ||
1016 | // make the name of the combination and fill the corresponding bin coordinates | |
1017 | TString combiName = "/"; | |
1018 | for (Int_t i=2; i<nDim; i++) { | |
1019 | TObjString* label = static_cast<TObjString*>(combi->UncheckedAt(i-2)); | |
1020 | combiName += Form("%s/",label->String().Data()); | |
1021 | bins[i] = (Int_t)label->GetUniqueID(); | |
1022 | } | |
1023 | ||
7471ae1a | 1024 | // reset the list of labels for which all counters are not empty |
1025 | if (removeEmpty) { | |
1026 | memset(useLabelX, kFALSE, sizeof(Bool_t) * (labelsX->GetSize()+1)); | |
1027 | memset(useLabelY, kFALSE, sizeof(Bool_t) * (labelsY->GetSize()+1)); | |
1028 | } | |
1029 | ||
94ef1a28 | 1030 | Bool_t empty = kTRUE; |
1031 | TObjString* labelX = 0x0; | |
1032 | TObjString* labelY = 0x0; | |
1033 | TIter nextLabelX(labelsX); | |
1034 | TIter nextLabelY(labelsY); | |
7471ae1a | 1035 | // loop over labels in X direction |
94ef1a28 | 1036 | while ((labelX = static_cast<TObjString*>(nextLabelX()))) { |
1037 | bins[0] = (Int_t) labelX->GetUniqueID(); | |
7471ae1a | 1038 | |
1039 | // loop over labels in Y direction | |
94ef1a28 | 1040 | nextLabelY.Reset(); |
1041 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { | |
1042 | bins[1] = (Int_t) labelY->GetUniqueID(); | |
7471ae1a | 1043 | |
1044 | // both labels already set as used | |
1045 | if (removeEmpty && useLabelX[bins[0]] && useLabelY[bins[1]]) continue; | |
1046 | ||
1047 | // skip empty bins | |
1048 | if (hist->GetBinContent(bins) == 0.) continue; | |
1049 | ||
1050 | // set label as used and array as not empty | |
1051 | empty = kFALSE; | |
1052 | if (removeEmpty) { | |
1053 | useLabelX[bins[0]] = kTRUE; | |
1054 | useLabelY[bins[1]] = kTRUE; | |
1055 | } else break; | |
1056 | ||
94ef1a28 | 1057 | } |
7471ae1a | 1058 | |
1059 | if (!removeEmpty && !empty) break; | |
1060 | ||
94ef1a28 | 1061 | } |
7471ae1a | 1062 | |
1063 | // skip empty arrays | |
94ef1a28 | 1064 | if (empty) continue; |
1065 | ||
1066 | // print the name of the combination of labels refering the incoming array | |
1067 | printf("\n%s:\n",combiName.Data()); | |
1068 | ||
1069 | // print labels in Y axis | |
1070 | printf(formatX.Data()," "); | |
1071 | nextLabelY.Reset(); | |
7471ae1a | 1072 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { |
1073 | if (removeEmpty && !useLabelY[labelY->GetUniqueID()]) continue; | |
94ef1a28 | 1074 | printf(formatYs.Data(), labelY->String().Data()); |
7471ae1a | 1075 | } |
94ef1a28 | 1076 | |
1077 | // fill array for each label in X axis | |
1078 | nextLabelX.Reset(); | |
1079 | while ((labelX = static_cast<TObjString*>(nextLabelX()))) { | |
1080 | bins[0] = (Int_t) labelX->GetUniqueID(); | |
1081 | ||
7471ae1a | 1082 | if (removeEmpty && !useLabelX[bins[0]]) continue; |
1083 | ||
94ef1a28 | 1084 | // print label X |
1085 | printf(formatX.Data(), labelX->String().Data()); | |
1086 | ||
1087 | // print value for each label in Y axis | |
1088 | nextLabelY.Reset(); | |
1089 | while ((labelY = static_cast<TObjString*>(nextLabelY()))) { | |
1090 | bins[1] = (Int_t) labelY->GetUniqueID(); | |
7471ae1a | 1091 | if (removeEmpty && !useLabelY[bins[1]]) continue; |
5d8c0c8a | 1092 | if (fWeightedCounters) printf(formatYv.Data(), hist->GetBinContent(bins)); |
1093 | else if (longCounters) printf(formatYv.Data(), (Long_t) hist->GetBinContent(bins)); | |
1094 | else printf(formatYv.Data(), (Int_t) hist->GetBinContent(bins)); | |
94ef1a28 | 1095 | } |
1096 | } | |
1097 | printf("\n\n"); | |
1098 | } | |
1099 | ||
1100 | // clean memory | |
1101 | delete[] bins; | |
7471ae1a | 1102 | if (removeEmpty) { |
1103 | delete[] useLabelX; | |
1104 | delete[] useLabelY; | |
1105 | } | |
94ef1a28 | 1106 | } |
1107 | ||
1108 | //----------------------------------------------------------------------- | |
1109 | Int_t AliCounterCollection::GetMaxLabelSize(THashList* labels) const | |
1110 | { | |
1111 | /// Return the number of characters of the longest label. | |
1112 | Int_t maxLabelSize = 0; | |
1113 | TObjString* label = 0x0; | |
1114 | TIter nextLabel(labels); | |
1115 | while ((label = static_cast<TObjString*>(nextLabel()))) | |
1116 | maxLabelSize = TMath::Max(maxLabelSize, label->String().Length()); | |
1117 | return maxLabelSize; | |
1118 | } | |
1119 | ||
1120 | //----------------------------------------------------------------------- | |
0dc8b856 | 1121 | TH1D* AliCounterCollection::Get(TString rubric, TString selections) |
94ef1a28 | 1122 | { |
0dc8b856 | 1123 | /// Get counters of the rubric "rubric" for the given "selection". |
6f5626c7 | 1124 | /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). |
94ef1a28 | 1125 | /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections". |
1126 | /// It is the responsability of the user to delete the returned histogram. | |
1127 | ||
1128 | if (!fCounters) { | |
1129 | AliError("counters are not initialized"); | |
1130 | return 0x0; | |
1131 | } | |
1132 | ||
1133 | rubric.ToUpper(); | |
1134 | selections.ToUpper(); | |
1135 | ||
1136 | // fill the rubrics to print | |
1137 | TObjArray rubricsToPrint(1); | |
1138 | rubricsToPrint.SetOwner(); | |
1139 | rubricsToPrint.AddLast(new TObjString(rubric.Data())); | |
1140 | ||
1141 | // project counters in the rubrics to print according to the selections | |
5d8c0c8a | 1142 | Bool_t longCounters = kFALSE; |
1143 | TH1D* hist = static_cast<TH1D*>(Projection(rubricsToPrint, selections, longCounters)); | |
94ef1a28 | 1144 | |
0dc8b856 | 1145 | // make it ready to display |
94ef1a28 | 1146 | if (hist) { |
1147 | ||
0dc8b856 | 1148 | // remove statistic box |
94ef1a28 | 1149 | hist->SetStats(kFALSE); |
1150 | ||
0dc8b856 | 1151 | // prepare X axis |
94ef1a28 | 1152 | TAxis* axis = hist->GetXaxis(); |
1153 | THashList* labels = axis->GetLabels(); | |
1154 | Int_t nLabels = (labels) ? labels->GetSize() : 1; | |
1155 | axis->SetRange(1,nLabels); | |
1156 | axis->SetNdivisions(1,kFALSE); | |
1157 | axis->SetTitle(rubric.Data()); | |
1158 | ||
0dc8b856 | 1159 | // prepare Y axis |
94ef1a28 | 1160 | hist->GetYaxis()->SetTitle("Counts"); |
1161 | } | |
1162 | ||
1163 | return hist; | |
1164 | } | |
1165 | ||
1166 | //----------------------------------------------------------------------- | |
0dc8b856 | 1167 | TH2D* AliCounterCollection::Get(TString rubric1, TString rubric2, TString selections) |
94ef1a28 | 1168 | { |
0dc8b856 | 1169 | /// Get counters of the "rubric1" vs "rubric2" for the given "selection". |
6f5626c7 | 1170 | /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). |
94ef1a28 | 1171 | /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections". |
1172 | /// It is the responsability of the user to delete the returned histogram. | |
1173 | ||
1174 | if (!fCounters) { | |
1175 | AliError("counters are not initialized"); | |
1176 | return 0x0; | |
1177 | } | |
1178 | ||
1179 | rubric1.ToUpper(); | |
1180 | rubric2.ToUpper(); | |
1181 | selections.ToUpper(); | |
1182 | ||
1183 | // fill the rubrics to print | |
1184 | TObjArray rubricsToPrint(2); | |
1185 | rubricsToPrint.SetOwner(); | |
1186 | rubricsToPrint.AddLast(new TObjString(rubric2.Data())); | |
1187 | rubricsToPrint.AddLast(new TObjString(rubric1.Data())); | |
1188 | ||
1189 | // project counters in the rubrics to print according to the selections | |
5d8c0c8a | 1190 | Bool_t longCounters = kFALSE; |
1191 | TH2D* hist = static_cast<TH2D*>(Projection(rubricsToPrint, selections, longCounters)); | |
94ef1a28 | 1192 | |
1193 | // draw counters | |
1194 | if (hist) { | |
1195 | ||
0dc8b856 | 1196 | // remove statistic box |
94ef1a28 | 1197 | hist->SetStats(kFALSE); |
1198 | ||
0dc8b856 | 1199 | // prepare X axis |
94ef1a28 | 1200 | TAxis* axisX = hist->GetXaxis(); |
1201 | THashList* labelsX = axisX->GetLabels(); | |
1202 | Int_t nLabelsX = (labelsX) ? labelsX->GetSize() : 1; | |
1203 | axisX->SetRange(1,nLabelsX); | |
1204 | axisX->SetNdivisions(1,kFALSE); | |
1205 | axisX->SetTitle(rubric2.Data()); | |
1206 | ||
0dc8b856 | 1207 | // prepare Y axis |
94ef1a28 | 1208 | TAxis* axisY = hist->GetYaxis(); |
1209 | THashList* labelsY = axisY->GetLabels(); | |
1210 | Int_t nLabelsY = (labelsY) ? labelsY->GetSize() : 1; | |
1211 | axisY->SetRange(1,nLabelsY); | |
1212 | axisY->SetNdivisions(1,kFALSE); | |
1213 | axisY->SetTitle(rubric1.Data()); | |
1214 | } | |
1215 | ||
1216 | return hist; | |
1217 | } | |
1218 | ||
0dc8b856 | 1219 | //----------------------------------------------------------------------- |
1220 | TH1D* AliCounterCollection::Draw(TString rubric, TString selections) | |
1221 | { | |
1222 | /// Draw counters of the rubric "rubric" for the given "selection". | |
1223 | /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). | |
1224 | /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections". | |
1225 | /// It is the responsability of the user to delete the returned histogram. | |
1226 | TH1D* hist = Get(rubric, selections); | |
1227 | if (hist) hist->Draw("htext"); | |
1228 | return hist; | |
1229 | } | |
1230 | ||
1231 | //----------------------------------------------------------------------- | |
1232 | TH2D* AliCounterCollection::Draw(TString rubric1, TString rubric2, TString selections) | |
1233 | { | |
1234 | /// Draw counters of the "rubric1" vs "rubric2" for the given "selection". | |
1235 | /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter). | |
1236 | /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections". | |
1237 | /// It is the responsability of the user to delete the returned histogram. | |
1238 | TH2D* hist = Get(rubric1, rubric2, selections); | |
1239 | if (hist) hist->Draw("text"); | |
1240 | return hist; | |
1241 | } | |
1242 | ||
94ef1a28 | 1243 | //----------------------------------------------------------------------- |
5d8c0c8a | 1244 | TObject* AliCounterCollection::Projection(const TObjArray& data, const TString& selections, Bool_t& longCounters) |
94ef1a28 | 1245 | { |
1246 | /// Return desired "data" for the given "selection" stored in a new histogram or 0x0 in case of failure. | |
1247 | /// The type of the histogram (TH1D, TH2D or THnSparse) depend on the number of data. | |
5d8c0c8a | 1248 | /// The flag "longCounters" tells whether the histogram contains value(s) larger than INT_MAX. |
94ef1a28 | 1249 | /// It is the responsability of the user to delete the returned histogram. |
1250 | ||
5d8c0c8a | 1251 | // set the flag "longCounters" according to the content of current counters |
1252 | longCounters = fLongCounters; | |
1253 | ||
6f5626c7 | 1254 | // decode the selections |
1255 | Short_t** select = DecodeSelection(selections, data); | |
1256 | if (!select) return 0x0; | |
1257 | ||
1258 | // define name and dimensions of projection histo | |
1259 | TString name(fCounters->GetName()); | |
1260 | Int_t nDims = fCounters->GetNdimensions(); | |
1261 | Int_t nTargetDims = data.GetEntriesFast(); | |
1262 | TArrayI targetDims(nTargetDims); | |
1263 | TArrayI nNewBins(nTargetDims); | |
1264 | TArrayI* OldToNewCoord = new TArrayI[nTargetDims]; | |
1265 | for (Int_t i=0; i<nTargetDims; i++) { | |
1266 | ||
1267 | // histo name | |
1268 | name += Form("_%s",static_cast<TObjString*>(data.UncheckedAt(i))->String().Data()); | |
1269 | ||
1270 | // find target dims | |
94ef1a28 | 1271 | targetDims[i] = FindDim(static_cast<TObjString*>(data.UncheckedAt(i))->String()); |
6f5626c7 | 1272 | |
1273 | // set number of selected bins in the target dims and make the correspondence between old and new coordinates | |
1274 | nNewBins[i] = 0; | |
1275 | if (targetDims[i] > -1) { | |
1276 | Int_t nBins = GetNActiveBins(targetDims[i]) + 1; | |
1277 | OldToNewCoord[i].Set(nBins); | |
1278 | for (Int_t j=1; j<nBins; j++) if (select[targetDims[i]][j] > 0) OldToNewCoord[i][j] = ++nNewBins[i]; | |
1279 | } | |
1280 | ||
1281 | // clean memory and return 0x0 in case of problem | |
1282 | if (nNewBins[i] == 0) { | |
1283 | for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim]; | |
1284 | delete[] select; | |
1285 | delete[] OldToNewCoord; | |
94ef1a28 | 1286 | return 0x0; |
1287 | } | |
6f5626c7 | 1288 | |
94ef1a28 | 1289 | } |
1290 | ||
6f5626c7 | 1291 | // define title of projection histo |
1292 | TString title = "Selections: "; | |
1293 | TString selectionString(selections); | |
1294 | selectionString.Remove(TString::kBoth, '/'); | |
1295 | if (selectionString.Length() > 0) title += Form("%s/", selectionString.Data()); | |
1296 | TObject* rub = 0x0; | |
1297 | TIter nextRubric(fRubrics); | |
1298 | while ((rub = nextRubric())) { | |
1299 | if (selectionString.Contains(Form("%s:",rub->GetName()))) continue; | |
1300 | if (data.Contains(rub->GetName())) continue; | |
1301 | title += Form("%s:ANY/", rub->GetName()); | |
94ef1a28 | 1302 | } |
6f5626c7 | 1303 | title.ReplaceAll("/", " "); |
94ef1a28 | 1304 | |
6f5626c7 | 1305 | // Create new histograms |
1306 | TObject* hist; | |
1307 | if (nTargetDims == 1) hist = new TH1D(name.Data(), title.Data(), nNewBins[0], 0., 1.); | |
1308 | else if (nTargetDims == 2) hist = new TH2D(name.Data(), title.Data(), nNewBins[0], 0., 1., nNewBins[1], 0., 1.); | |
d810835e | 1309 | else if (fWeightedCounters) hist = new THnSparseT<TArrayF>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0); |
5d8c0c8a | 1310 | else if (fLongCounters) hist = new THnSparseT<TArrayL>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0); |
6f5626c7 | 1311 | else hist = new THnSparseT<TArrayI>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0); |
94ef1a28 | 1312 | |
6f5626c7 | 1313 | // Set new axis labels |
1314 | TObjString* label; | |
1315 | if (nTargetDims < 3) { | |
94ef1a28 | 1316 | |
6f5626c7 | 1317 | // X axis |
1318 | TIter nextLabelX(fCounters->GetAxis(targetDims[0])->GetLabels()); | |
1319 | while ((label = static_cast<TObjString*>(nextLabelX()))) { | |
1320 | if (select[targetDims[0]][label->GetUniqueID()] > 0) { | |
1321 | static_cast<TH1*>(hist)->GetXaxis()->SetBinLabel(OldToNewCoord[0][label->GetUniqueID()], label->String().Data()); | |
1322 | } | |
94ef1a28 | 1323 | } |
1324 | ||
6f5626c7 | 1325 | // Y axis if any |
1326 | if (nTargetDims == 2) { | |
1327 | TIter nextLabelY(fCounters->GetAxis(targetDims[1])->GetLabels()); | |
1328 | while ((label = static_cast<TObjString*>(nextLabelY()))) { | |
1329 | if (select[targetDims[1]][label->GetUniqueID()] > 0) { | |
1330 | static_cast<TH1*>(hist)->GetYaxis()->SetBinLabel(OldToNewCoord[1][label->GetUniqueID()], label->String().Data()); | |
1331 | } | |
1332 | } | |
1333 | } | |
94ef1a28 | 1334 | |
6f5626c7 | 1335 | } else { |
94ef1a28 | 1336 | |
6f5626c7 | 1337 | // all axes |
1338 | for (Int_t i=0; i<nTargetDims; i++) { | |
1339 | TIter nextLabel(fCounters->GetAxis(targetDims[i])->GetLabels()); | |
1340 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
1341 | if (select[targetDims[i]][label->GetUniqueID()] > 0) { | |
1342 | static_cast<THnSparse*>(hist)->GetAxis(i)->SetBinLabel(OldToNewCoord[i][label->GetUniqueID()], label->String().Data()); | |
1343 | } | |
1344 | } | |
94ef1a28 | 1345 | } |
1346 | ||
6f5626c7 | 1347 | } |
1348 | ||
1349 | // loop over every filled counters | |
1350 | Int_t* coord = new Int_t[nDims]; | |
1351 | Int_t* newCoord = new Int_t[nTargetDims]; | |
1352 | Int_t nEntries = 0; | |
1353 | for (Long64_t i=0; i<fCounters->GetNbins(); ++i) { | |
94ef1a28 | 1354 | |
6f5626c7 | 1355 | // get the content of the counter |
1356 | Double_t value = fCounters->GetBinContent(i, coord); | |
94ef1a28 | 1357 | |
6f5626c7 | 1358 | // discard not selected counters and compute the selection factor |
1359 | Int_t selectionFactor = 1; | |
1360 | for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]]; | |
1361 | if (selectionFactor == 0) continue; | |
94ef1a28 | 1362 | |
6f5626c7 | 1363 | // find new coordinates in the projection histo |
1364 | for (Int_t d = 0; d < nTargetDims; ++d) newCoord[d] = OldToNewCoord[d][coord[targetDims[d]]]; | |
1365 | ||
1366 | // fill projection histo | |
1367 | if (nTargetDims < 3) { | |
5d8c0c8a | 1368 | |
6f5626c7 | 1369 | Int_t linBin = (nTargetDims == 1) ? newCoord[0] : static_cast<TH1*>(hist)->GetBin(newCoord[0], newCoord[1]); |
1370 | static_cast<TH1*>(hist)->AddBinContent(linBin, selectionFactor*value); | |
5d8c0c8a | 1371 | |
1372 | // check if the new value exceed INT_MAX (only in case of integer counters) | |
1373 | if (!fWeightedCounters && !longCounters && static_cast<TH1*>(hist)->GetBinContent(linBin) > INT_MAX) | |
1374 | longCounters = kTRUE; | |
1375 | ||
1376 | } else if (fWeightedCounters || longCounters) { | |
1377 | ||
1378 | static_cast<THnSparse*>(hist)->AddBinContent(newCoord, selectionFactor*value); | |
1379 | ||
1380 | } else { | |
1381 | ||
1382 | // switch to long counters if needed before filling | |
1383 | Long64_t linBin = static_cast<THnSparse*>(hist)->GetBin(newCoord, kTRUE); | |
1384 | Double_t currentValue = static_cast<THnSparse*>(hist)->GetBinContent(linBin); | |
1385 | if (currentValue+selectionFactor*value > INT_MAX) { | |
1386 | THnSparse* h = static_cast<THnSparse*>(hist); | |
1387 | ConvertToTHnSparseL(h); | |
1388 | hist = h; | |
1389 | longCounters = kTRUE; | |
1390 | static_cast<THnSparse*>(hist)->AddBinContent(newCoord, selectionFactor*value); | |
1391 | } else static_cast<THnSparse*>(hist)->AddBinContent(linBin, selectionFactor*value); | |
1392 | ||
1393 | } | |
94ef1a28 | 1394 | |
6f5626c7 | 1395 | nEntries++; |
94ef1a28 | 1396 | } |
1397 | ||
6f5626c7 | 1398 | // update the number of entries |
1399 | if (nTargetDims < 3) static_cast<TH1*>(hist)->SetEntries(nEntries); | |
1400 | else static_cast<THnSparse*>(hist)->SetEntries(nEntries); | |
1401 | ||
94ef1a28 | 1402 | // clean memory |
6f5626c7 | 1403 | for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim]; |
1404 | delete[] select; | |
1405 | delete[] coord; | |
1406 | delete[] newCoord; | |
1407 | delete[] OldToNewCoord; | |
94ef1a28 | 1408 | |
1409 | return hist; | |
1410 | } | |
1411 | ||
1412 | //----------------------------------------------------------------------- | |
1413 | Int_t* AliCounterCollection::CheckConsistency(const AliCounterCollection* c) | |
1414 | { | |
1415 | /// Consistency check of the two counter collections. To be consistent, both counters | |
1416 | /// must have the same rubrics with the same list of authorized key words if any. | |
1417 | /// Return the correspondence between the local rubric ordering and the one of the other counter, | |
1418 | /// or 0x0 in case of problem. It is the responsability of the user to delete the returned array. | |
1419 | ||
1420 | if (!fCounters || !c->fCounters) { | |
1421 | AliError("counters are not initialized"); | |
1422 | return 0x0; | |
1423 | } | |
1424 | ||
d810835e | 1425 | // check if both counters are weighted or not |
1426 | if (c->fWeightedCounters != fWeightedCounters) AliWarning("merging non-weighted with weigthed counters"); | |
1427 | ||
94ef1a28 | 1428 | // check if the number of rubrics is the same |
1429 | Int_t nRubrics = fRubrics->GetSize(); | |
1430 | if (c->fRubrics->GetSize() != nRubrics) { | |
1431 | AliError("both counters do not contain the same number of rubrics"); | |
1432 | return 0x0; | |
1433 | } | |
1434 | ||
1435 | Int_t* otherDims = new Int_t[nRubrics]; | |
1436 | ||
1437 | // loop over local rubrics | |
1438 | TObject* rubric1 = 0x0; | |
1439 | TIter nextRubric(fRubrics); | |
1440 | while ((rubric1 = nextRubric())) { | |
1441 | ||
1442 | // find that rubric in the other counter | |
1443 | TObject* rubric2 = c->fRubrics->FindObject(rubric1->GetName()); | |
1444 | if (!rubric2) { | |
1445 | AliError(Form("the other counter does not contain the rubric %s", rubric1->GetName())); | |
1446 | delete[] otherDims; | |
1447 | return 0x0; | |
1448 | } | |
1449 | ||
1450 | // check the list of authorized key words if any | |
1451 | TObjArray* keyWords1 = dynamic_cast<TObjArray*>(rubric1); | |
1452 | TObjArray* keyWords2 = dynamic_cast<TObjArray*>(rubric2); | |
1453 | if (keyWords1 && keyWords2) { | |
1454 | ||
1455 | // check if the number of key words is the same | |
1456 | if (keyWords1->GetEntriesFast() != keyWords2->GetEntriesFast()) { | |
1457 | AliError("that rubric does not contain the same number of authorized key words in both counters"); | |
1458 | delete[] otherDims; | |
1459 | return 0x0; | |
1460 | } | |
1461 | ||
1462 | // loop over local key words | |
1463 | TObjString* keyWord = 0x0; | |
1464 | TIter nextKeyWord(keyWords1); | |
1465 | while ((keyWord = static_cast<TObjString*>(nextKeyWord()))) { | |
1466 | ||
1467 | // find that key word in the corresponding rubric of the other counter | |
1468 | if (!keyWords2->FindObject(keyWord->String().Data())) { | |
1469 | AliError(Form("rubric %s does not contain the key word %s in the other counter", rubric1->GetName(), keyWord->String().Data())); | |
1470 | delete[] otherDims; | |
1471 | return 0x0; | |
1472 | } | |
1473 | ||
1474 | } | |
1475 | ||
1476 | } else if (keyWords1 || keyWords2) { | |
1477 | ||
1478 | // that rubric has not been initialized the same way in both counter | |
1479 | if (keyWords1) { | |
1480 | AliError(Form("rubric %s of the other counter does not contain a list of authorized key words while this does", rubric1->GetName())); | |
1481 | } else { | |
1482 | AliError(Form("rubric %s of this counter does not contain a list of authorized key words while the other does", rubric1->GetName())); | |
1483 | } | |
1484 | delete[] otherDims; | |
1485 | return 0x0; | |
1486 | ||
1487 | } | |
1488 | ||
1489 | // save the correspondence of rubric IDs in both counters | |
1490 | otherDims[rubric1->GetUniqueID()] = rubric2->GetUniqueID(); | |
1491 | ||
1492 | } | |
1493 | ||
1494 | return otherDims; | |
1495 | } | |
1496 | ||
1497 | //----------------------------------------------------------------------- | |
1498 | void AliCounterCollection::Add(const AliCounterCollection* counter) | |
1499 | { | |
1500 | /// Add the given AliCounterCollections to this. They must have the | |
1501 | /// same rubrics with the same list of authorized key words if any. | |
1502 | ||
1503 | // check the consistency between the other counter and this and get the correspondences between rubric IDs. | |
1504 | Int_t* otherDims = CheckConsistency(counter); | |
1505 | if (!otherDims) return; | |
1506 | ||
5d8c0c8a | 1507 | // switch to long counters if the given counter collection is of that type |
1508 | if (counter->fLongCounters && !fLongCounters) { | |
1509 | ConvertToTHnSparseL(fCounters); | |
1510 | fLongCounters = kTRUE; | |
1511 | } | |
1512 | ||
94ef1a28 | 1513 | Int_t nRubrics = fCounters->GetNdimensions(); |
1514 | Int_t* thisBins = new Int_t[nRubrics]; | |
1515 | Int_t* otherBins = new Int_t[nRubrics]; | |
1516 | ||
1517 | // loop over every filled bins inside the other counter | |
1518 | for (Long64_t i = 0; i < counter->fCounters->GetNbins(); i++) { | |
1519 | ||
1520 | // get the content of the bin | |
1521 | Double_t value = counter->fCounters->GetBinContent(i, otherBins); | |
1522 | ||
1523 | // convert "other" bin coordinates to "this" bin coordinates | |
1524 | Bool_t ok = kTRUE; | |
1525 | for (Int_t dim = 0; dim < nRubrics; dim++) { | |
1526 | TString label = counter->fCounters->GetAxis(otherDims[dim])->GetBinLabel(otherBins[otherDims[dim]]); | |
1527 | thisBins[dim] = FindBin(dim, label, kTRUE); | |
1528 | if (thisBins[dim] < 0) { | |
1529 | AliError("this counter is full, unable to add that key word"); | |
1530 | ok = kFALSE; | |
1531 | break; | |
1532 | } | |
1533 | } | |
1534 | if (!ok) continue; | |
1535 | ||
5d8c0c8a | 1536 | if (fWeightedCounters || fLongCounters) { |
1537 | ||
1538 | // increment the corresponding local counter | |
1539 | fCounters->AddBinContent(thisBins, value); | |
1540 | ||
1541 | } else { | |
1542 | ||
1543 | // switch to long counters if needed before incrementing | |
1544 | Long64_t linBin = fCounters->GetBin(thisBins, kTRUE); | |
1545 | Double_t currentValue = fCounters->GetBinContent(linBin); | |
1546 | if (currentValue+value > INT_MAX) { | |
1547 | ConvertToTHnSparseL(fCounters); | |
1548 | fLongCounters = kTRUE; | |
1549 | fCounters->AddBinContent(thisBins, value); | |
1550 | } else fCounters->AddBinContent(linBin, value); | |
1551 | ||
1552 | } | |
1553 | ||
94ef1a28 | 1554 | } |
1555 | ||
1556 | // clean memory | |
1557 | delete[] otherDims; | |
1558 | delete[] thisBins; | |
1559 | delete[] otherBins; | |
1560 | } | |
1561 | ||
1562 | //----------------------------------------------------------------------- | |
1563 | Long64_t AliCounterCollection::Merge(TCollection* list) | |
1564 | { | |
1565 | /// Merge this with a list of AliCounterCollections. All AliCounterCollections provided | |
1566 | /// must have the same rubrics with the same list of authorized key words if any. | |
1567 | ||
1568 | if (!list || !fCounters) return 0; | |
1569 | if (list->IsEmpty()) return (Long64_t)fCounters->GetEntries(); | |
1570 | ||
1571 | TIter next(list); | |
1572 | const TObject* obj = 0x0; | |
1573 | while ((obj = next())) { | |
1574 | ||
1575 | // check that "obj" is an object of the class AliCounterCollection | |
1576 | const AliCounterCollection* counter = dynamic_cast<const AliCounterCollection*>(obj); | |
1577 | if (!counter) { | |
ca23a51f | 1578 | AliFatal(Form("object named \"%s\" is a %s instead of an AliCounterCollection!", obj->GetName(), obj->ClassName())); |
94ef1a28 | 1579 | continue; |
1580 | } | |
1581 | ||
1582 | // merge counter to this one | |
1583 | Add(counter); | |
1584 | ||
1585 | } | |
1586 | ||
1587 | return (Long64_t)fCounters->GetEntries(); | |
1588 | } | |
1589 | ||
1590 | //----------------------------------------------------------------------- | |
1591 | void AliCounterCollection::Sort(Option_t* opt, Bool_t asInt) | |
1592 | { | |
1593 | /// Sort rubrics defined without a list of authorized key words or all rubrics if opt=="all". | |
1594 | /// If asInt=kTRUE, key words are ordered as interger instead of alphabetically. | |
1595 | ||
1596 | if (!fCounters) { | |
1597 | AliError("counters are not initialized"); | |
1598 | return; | |
1599 | } | |
1600 | ||
1601 | Bool_t all = (!strcasecmp(opt, "all")); | |
1602 | ||
1603 | Bool_t somethingToSort = kFALSE; | |
1604 | Int_t nRubrics = fRubrics->GetSize(); | |
1605 | Bool_t* rubricsToSort = new Bool_t[nRubrics]; | |
1606 | memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics); | |
1607 | ||
1608 | // choose rubrics to sort | |
1609 | TObject* rubric = 0x0; | |
1610 | TIter nextRubric(fRubrics); | |
1611 | while ((rubric = nextRubric())) { | |
1612 | ||
1613 | if (all || dynamic_cast<TObjString*>(rubric)) { | |
1614 | ||
1615 | // check if something to sort | |
1616 | THashList* labels = fCounters->GetAxis((Int_t)rubric->GetUniqueID())->GetLabels(); | |
1617 | if (!labels || labels->GetSize() < 2) continue; | |
1618 | ||
1619 | // select that rubric | |
1620 | rubricsToSort[(Int_t)rubric->GetUniqueID()] = kTRUE; | |
1621 | somethingToSort = kTRUE; | |
1622 | ||
1623 | } | |
1624 | ||
1625 | } | |
1626 | ||
1627 | // sort selected rubrics if any | |
1628 | if (somethingToSort) Sort(rubricsToSort, asInt); | |
1629 | ||
1630 | // clean memory | |
1631 | delete[] rubricsToSort; | |
1632 | } | |
1633 | ||
1634 | //----------------------------------------------------------------------- | |
1635 | void AliCounterCollection::SortRubric(TString rubric, Bool_t asInt) | |
1636 | { | |
1637 | /// Sort only that rubric. If asInt=kTRUE, key words are ordered as interger instead of alphabetically. | |
1638 | ||
1639 | if (!fCounters) { | |
1640 | AliError("counters are not initialized"); | |
1641 | return; | |
1642 | } | |
1643 | ||
1644 | rubric.ToUpper(); | |
1645 | ||
1646 | // find the rubric to sort | |
1647 | Int_t dim = FindDim(rubric); | |
1648 | if (dim < 0) return; | |
1649 | ||
1650 | // check if something to sort | |
1651 | THashList* labels = fCounters->GetAxis(dim)->GetLabels(); | |
1652 | if (!labels || labels->GetSize() < 2) return; | |
1653 | ||
1654 | // select that rubric | |
1655 | Int_t nRubrics = fRubrics->GetSize(); | |
1656 | Bool_t* rubricsToSort = new Bool_t[nRubrics]; | |
1657 | memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics); | |
1658 | rubricsToSort[dim] = kTRUE; | |
1659 | ||
1660 | // sort it | |
1661 | Sort(rubricsToSort, asInt); | |
1662 | ||
1663 | // clean memory | |
1664 | delete[] rubricsToSort; | |
1665 | } | |
1666 | ||
1667 | //----------------------------------------------------------------------- | |
1668 | void AliCounterCollection::Sort(const Bool_t* rubricsToSort, Bool_t asInt) | |
1669 | { | |
1670 | /// Sort labels (alphabetically or as integer) in each rubric flagged in "rubricsToSort". | |
1671 | ||
1672 | // create a new counter | |
1673 | THnSparse* oldCounters = fCounters; | |
1674 | Int_t nRubrics = fRubrics->GetSize(); | |
d810835e | 1675 | if (fWeightedCounters) |
1676 | fCounters = new THnSparseT<TArrayF>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0); | |
5d8c0c8a | 1677 | else if (fLongCounters) |
1678 | fCounters = new THnSparseT<TArrayL>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0); | |
d810835e | 1679 | else |
1680 | fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0); | |
94ef1a28 | 1681 | Int_t** newBins = new Int_t*[nRubrics]; |
ca23a51f | 1682 | Bool_t newBinsFilled = kTRUE; |
94ef1a28 | 1683 | |
1684 | // define the new axes | |
1685 | for (Int_t i=0; i<nRubrics; i++) { | |
1686 | TAxis* oldAxis = oldCounters->GetAxis(i); | |
1687 | TAxis* newAxis = fCounters->GetAxis(i); | |
1688 | ||
1689 | // set the name of the new axis | |
1690 | newAxis->SetName(oldAxis->GetName()); | |
1691 | ||
1692 | // get old labels | |
1693 | THashList* oldLabels = oldAxis->GetLabels(); | |
ca23a51f | 1694 | if (!oldLabels) { |
1695 | newBins[i] = 0x0; | |
1696 | newBinsFilled = kFALSE; | |
1697 | continue; | |
1698 | } | |
94ef1a28 | 1699 | |
1700 | // sort them if required | |
1701 | if (rubricsToSort[i]) { | |
1702 | if (asInt) { oldLabels = SortAsInt(oldLabels); } | |
1703 | else { oldLabels->Sort(); } | |
1704 | } | |
1705 | ||
1706 | // set labels in the new axis and save the correspondence between new and old bins | |
1707 | newBins[i] = new Int_t[oldLabels->GetSize()+1]; | |
1708 | TObjString* label = 0x0; | |
1709 | Int_t bin = 1; | |
1710 | TIter nextLabel(oldLabels); | |
1711 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
1712 | newAxis->SetBinLabel(bin, label->String().Data()); | |
1713 | newBins[i][(Int_t)label->GetUniqueID()] = bin; | |
1714 | bin++; | |
1715 | } | |
1716 | ||
1717 | // clean memory | |
1718 | if (rubricsToSort[i] && asInt) delete oldLabels; | |
1719 | } | |
1720 | ||
ca23a51f | 1721 | // fill the new fCounters only if all axes have label(s) defined (otherwise it is empty) |
1722 | if (newBinsFilled) { | |
1723 | ||
1724 | // fill the new counters | |
1725 | Int_t* oldCoor = new Int_t[nRubrics]; | |
1726 | Int_t* newCoor = new Int_t[nRubrics]; | |
1727 | for (Long64_t i = 0; i < oldCounters->GetNbins(); i++) { | |
1728 | Double_t value = oldCounters->GetBinContent(i, oldCoor); | |
1729 | for (Int_t dim = 0; dim < nRubrics; dim++) newCoor[dim] = newBins[dim][oldCoor[dim]]; | |
1730 | fCounters->AddBinContent(newCoor, value); | |
1731 | } | |
1732 | ||
1733 | // clean memory | |
1734 | delete[] oldCoor; | |
1735 | delete[] newCoor; | |
94ef1a28 | 1736 | } |
1737 | ||
1738 | // clean memory | |
1739 | for (Int_t i=0; i<nRubrics; i++) delete[] newBins[i]; | |
1740 | delete[] newBins; | |
94ef1a28 | 1741 | delete oldCounters; |
1742 | } | |
1743 | ||
1744 | //----------------------------------------------------------------------- | |
1745 | THashList* AliCounterCollection::SortAsInt(const THashList* labels) | |
1746 | { | |
1747 | /// Return a list (not owner) of labels sorted assuming they are integers. | |
1748 | /// It is the responsability of user to delete the returned list. | |
1749 | ||
1750 | THashList* sortedLabels = new THashList(labels->GetSize()); | |
1751 | TIter nextSortedLabel(sortedLabels); | |
1752 | ||
1753 | // loop over labels | |
1754 | TObjString* label = 0x0; | |
1755 | TIter nextLabel(labels); | |
1756 | while ((label = static_cast<TObjString*>(nextLabel()))) { | |
1757 | ||
1758 | // find where to add it | |
1759 | TObjString* sortedLabel = 0x0; | |
1760 | nextSortedLabel.Reset(); | |
1761 | while ((sortedLabel = static_cast<TObjString*>(nextSortedLabel())) && | |
1762 | (sortedLabel->String().Atoi() <= label->String().Atoi())) {} | |
1763 | ||
1764 | // add it | |
1765 | if (sortedLabel) sortedLabels->AddBefore(sortedLabel, label); | |
1766 | else sortedLabels->AddLast(label); | |
1767 | } | |
1768 | ||
1769 | return sortedLabels; | |
1770 | } | |
1771 | ||
5d8c0c8a | 1772 | //----------------------------------------------------------------------- |
1773 | void AliCounterCollection::ConvertToTHnSparseL(THnSparse* &h) | |
1774 | { | |
1775 | /// Convert the given THnSparse to a THnSparseL (able to handle numbers >= 2^31) | |
1776 | ||
1777 | // create the new THnSparse | |
1778 | Int_t nDims = h->GetNdimensions(); | |
1779 | Int_t* nBins = new Int_t[nDims]; | |
1780 | for (Int_t i=0; i<nDims; i++) nBins[i] = h->GetAxis(i)->GetNbins(); | |
1781 | THnSparse* hNew = new THnSparseT<TArrayL>("new", "new", nDims, nBins, 0x0, 0x0); | |
1782 | delete[] nBins; | |
1783 | ||
1784 | // transfer the axes | |
1785 | for (Int_t i=0; i<nDims; i++) { | |
1786 | TAxis* oldAxis = h->GetAxis(i); | |
1787 | TAxis* newAxis = hNew->GetAxis(i); | |
1788 | ||
1789 | // transfer the name | |
1790 | newAxis->SetName(oldAxis->GetName()); | |
1791 | ||
1792 | // transfer labels | |
1793 | TObjString* label = 0x0; | |
1794 | TIter nextLabel(oldAxis->GetLabels()); | |
1795 | while ((label = static_cast<TObjString*>(nextLabel()))) | |
1796 | newAxis->SetBinLabel(label->GetUniqueID(), label->String().Data()); | |
1797 | } | |
1798 | ||
1799 | // fill the new THnSparse | |
1800 | Int_t* coor = new Int_t[nDims]; | |
1801 | for (Long64_t i = 0; i < h->GetNbins(); i++) { | |
1802 | Double_t value = h->GetBinContent(i, coor); | |
1803 | hNew->AddBinContent(coor, value); | |
1804 | } | |
1805 | delete[] coor; | |
1806 | ||
1807 | // transfer the number of entries | |
1808 | hNew->SetEntries(h->GetEntries()); | |
1809 | ||
1810 | // remove old THnSparse and transfer its name and title to the new one | |
1811 | TString name(h->GetName()); | |
1812 | TString title(h->GetTitle()); | |
1813 | delete h; | |
1814 | h = hNew; | |
1815 | h->SetNameTitle(name.Data(), title.Data()); | |
1816 | } | |
1817 |