6f61f7df5b3362884102e0f55c4cca33069900db
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTCTPData.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 //  @file   AliHLTCTPData.cxx
20 //  @author Matthias Richter
21 //  @date   2009-08-20
22 //  @brief  Container for CTP trigger classes and counters
23 //  @note
24
25 #include "AliHLTCTPData.h"
26 #include "TClass.h"
27 #include "TObjString.h"
28 #include "TFormula.h"
29 #include "AliHLTComponent.h"
30 #include "AliHLTCDHWrapper.h"
31 #include <limits>
32 #include <sstream>
33 #include <RVersion.h>
34
35 /** ROOT macro for the implementation of ROOT specific class methods */
36 ClassImp(AliHLTCTPData)
37
38 AliHLTCTPData::AliHLTCTPData()
39   : TNamed("AliHLTCTPData", "HLT counters for the CTP")
40   , AliHLTLogging()
41   , fMask(0)
42   , fTriggers(0)
43   , fClassIds(AliHLTReadoutList::Class(), gkNCTPTriggerClasses)
44   , fCounters(gkNCTPTriggerClasses)
45   , fMap()
46 {
47   // constructor
48   // see header file for class documentation
49   // or
50   // refer to README to build package
51   // or
52   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
53 }
54
55 AliHLTCTPData::AliHLTCTPData(const char* parameter)
56   : TNamed("AliHLTCTPData", "HLT counters for the CTP")
57   , AliHLTLogging()
58   , fMask(0)
59   , fTriggers(0)
60   , fClassIds(AliHLTReadoutList::Class(), gkNCTPTriggerClasses)
61   , fCounters(gkNCTPTriggerClasses)
62   , fMap()
63 {
64   // constructor, init the CTP trigger classes
65   InitCTPTriggerClasses(parameter);
66 }
67
68 AliHLTCTPData::~AliHLTCTPData()
69 {
70   // destructor
71   fClassIds.Delete();
72 }
73
74 AliHLTCTPData::AliHLTCTPData(const AliHLTCTPData& src)
75   : TNamed(src.GetName(), src.GetTitle())
76   , AliHLTLogging()
77   , fMask(src.Mask())
78   , fTriggers(src.fTriggers)
79   , fClassIds(src.fClassIds)
80   , fCounters(src.Counters())
81   , fMap()
82 {
83   // copy constructor
84   ReadMap();
85 }
86
87 AliHLTCTPData& AliHLTCTPData::operator=(const AliHLTCTPData& src)
88 {
89   // assignment operator, clone content
90   if (this!=&src) {
91     SetName(src.GetName());
92     SetTitle(src.GetTitle());
93     fMask=src.Mask();
94     fClassIds.Delete();
95     fClassIds.ExpandCreate(gkNCTPTriggerClasses);
96     for (int i=0; i<gkNCTPTriggerClasses; i++) {
97       if (i>src.fClassIds.GetLast()) break;
98       ((TNamed*)fClassIds.At(i))->SetName(src.fClassIds.At(i)->GetName());
99       ((TNamed*)fClassIds.At(i))->SetTitle(src.fClassIds.At(i)->GetTitle());
100     }
101     fCounters=src.Counters();
102   }
103
104   ReadMap();
105   return *this;
106 }
107
108 int AliHLTCTPData::Add(const AliHLTCTPData& src, int factor, int &skipped)
109 {
110   // see header file for class documentation
111   
112   skipped=0;
113   for (int i=0; i<gkNCTPTriggerClasses; i++) {
114     TString c;
115     c=fClassIds.At(i)->GetName();
116     if (c.IsNull()) continue;
117     if (c.CompareTo(src.fClassIds.At(i)->GetName())==0) {
118       fCounters[i]+=factor*src.Counter(i);
119     } else {
120       skipped++;
121     }
122   }
123   return 0;
124 }
125
126 AliHLTCTPData& AliHLTCTPData::operator += (const AliHLTCTPData& src)
127 {
128   // see header file for class documentation
129   
130   int nofInconsistencies=0;
131   Add(src, 1, nofInconsistencies);
132   if (nofInconsistencies>0) {
133     HLTError("Inconsistent operants: skipping %d of %d CTP classes for operation", nofInconsistencies, gkNCTPTriggerClasses);
134   }
135   return *this;
136 }
137
138 AliHLTCTPData& AliHLTCTPData::operator -= (const AliHLTCTPData& src)
139 {
140   // see header file for class documentation
141   
142   int nofInconsistencies=0;
143   Add(src, -1, nofInconsistencies);
144   if (nofInconsistencies>0) {
145     HLTError("Inconsistent operants: skipping %d of %d CTP classes for operation", nofInconsistencies, gkNCTPTriggerClasses);
146   }
147   return *this;
148 }
149
150 AliHLTCTPData AliHLTCTPData::operator + (const AliHLTCTPData& src) const
151 {
152   // see header file for class documentation
153
154   AliHLTCTPData result(*this);
155   result+=src;
156   return result;
157 }
158
159 AliHLTCTPData AliHLTCTPData::operator - (const AliHLTCTPData& src) const
160 {
161   // see header file for class documentation
162
163   AliHLTCTPData result(*this);
164   result-=src;
165   return result;
166 }
167
168 int AliHLTCTPData::InitCTPTriggerClasses(const char* ctpString)
169 {
170   // see header file for function documentation
171   if (!ctpString) return -EINVAL;
172
173   HLTDebug("Parameter: %s", ctpString);
174
175   fMask=0;
176   fClassIds.Delete();
177   fClassIds.ExpandCreate(gkNCTPTriggerClasses);
178
179   // general format of the CTP_TRIGGER_CLASS parameter
180   // <bit position>:<Trigger class identifier string>:<detector-id-nr>-<detector-id-nr>-...,<bit position>:<Trigger class identifier string>:<detector-id-nr>-<detector-id-nr>-...,...
181   HLTDebug(": %s", ctpString);
182   TString string=ctpString;
183   if (string.BeginsWith("CTP_TRIGGER_CLASS=")) string.ReplaceAll("CTP_TRIGGER_CLASS=", "");
184   TObjArray* classEntries=string.Tokenize(",");
185   if (classEntries) {
186     enum {kBit=0, kName, kDetectors};
187     for (int i=0; i<classEntries->GetEntriesFast(); i++) {
188       TString entry=((TObjString*)classEntries->At(i))->GetString();
189       TObjArray* entryParams=entry.Tokenize(":");
190       if (entryParams) {
191         if (entryParams->GetEntriesFast()==3 &&
192             (((TObjString*)entryParams->At(kBit))->GetString()).IsDigit()) {
193           int index=(((TObjString*)entryParams->At(kBit))->GetString()).Atoi();
194           if (index<gkNCTPTriggerClasses) {
195             AliHLTReadoutList* pCTPClass=dynamic_cast<AliHLTReadoutList*>(fClassIds.At(index));
196             if (pCTPClass) {
197               fMask.set(index);
198               pCTPClass->SetTitle("CTP Class");
199               pCTPClass->SetName((((TObjString*)entryParams->At(kName))->GetString()).Data());
200               TObjArray* detectors=(((TObjString*)entryParams->At(kDetectors))->GetString()).Tokenize("-");
201               if (detectors) {
202                 for (int dix=0; dix<detectors->GetEntriesFast(); dix++) {
203                   if (!(((TObjString*)detectors->At(dix))->GetString()).IsDigit()) {
204                     HLTError("invalid detector list format: trigger class entry %s", entry.Data());
205                     break;
206                   }
207                   // see AliHLTReadoutList::EDetectorId for defines of detectors
208                   pCTPClass->Enable(0x1<<(((TObjString*)detectors->At(dix))->GetString()).Atoi());
209                 }
210                 delete detectors;
211               }
212             } else {
213             }
214           } else {
215             // the trigger bitfield is fixed to 100 bits (gkNCTPTriggerClasses)
216             HLTError("invalid trigger class entry %s, index width of trigger bitfield exceeded (%d)", entry.Data(), gkNCTPTriggerClasses);
217           }
218         } else {
219           HLTError("invalid trigger class entry %s", entry.Data());
220         }
221         delete entryParams;
222       }
223     }
224     delete classEntries;
225   }
226
227   ResetCounters();
228   ReadMap();
229
230   return 0;
231 }
232
233 AliHLTTriggerMask_t AliHLTCTPData::ActiveTriggers(const AliHLTComponentTriggerData& trigData)
234 {
235   // extract active triggers from the trigger data
236   AliHLTCDHWrapper cdh;
237   if (AliHLTComponent::ExtractTriggerData(trigData, NULL, NULL, &cdh, NULL) != 0) return 0x0;
238   if ((cdh.GetL1TriggerMessage() & 0x1) == 0x1) return 0x0;  // invalid for software triggers.
239
240   AliHLTTriggerMask_t triggerLow(cdh.GetTriggerClasses()); //low bits
241   AliHLTTriggerMask_t triggerHigh(cdh.GetTriggerClassesNext50()); // high bits
242
243   return triggerLow | (triggerHigh << 50);
244 }
245
246 bool AliHLTCTPData::EvaluateCTPTriggerClass(const char* expression, const AliHLTComponentTriggerData& trigData) const
247 {
248   // see header file for function documentation
249   
250   AliHLTCDHWrapper cdh;
251   if (AliHLTComponent::ExtractTriggerData(trigData, NULL, NULL, &cdh, NULL, true) != 0) return false;
252   if ((cdh.GetL1TriggerMessage() & 0x1) == 0x1) return false;  // invalid for software triggers.
253
254   AliHLTTriggerMask_t triggerMask(cdh.GetTriggerClasses());
255   AliHLTTriggerMask_t triggerHigh(cdh.GetTriggerClassesNext50());
256   triggerMask |= (triggerHigh << 50);
257
258   if (fMask!=0 && (triggerMask & fMask)==0) {
259     AliHLTEventTriggerData* evtData=reinterpret_cast<AliHLTEventTriggerData*>(trigData.fData);
260     HLTWarning("invalid trigger mask %s, unknown CTP trigger, initialized %s", 
261                TriggerMaskToString(triggerMask).c_str(), TriggerMaskToString(fMask).c_str() );
262     for (int i=0; i<evtData->fCommonHeaderWordCnt; i++) HLTWarning("\t CDH[%d]=0x%lx", i, evtData->fCommonHeader[i]);
263     return false;
264   }
265
266   return EvaluateCTPTriggerClass(expression, triggerMask);
267 }
268
269 bool AliHLTCTPData::EvaluateCTPTriggerClass(const char* expression, AliHLTTriggerMask_t triggerMask) const
270 {
271   // see header file for function documentation
272
273   // use a TFormula to interprete the expression
274   // all classname are replaced by '[n]' which means the n'th parameter in the formula
275   // the parameters are set to 0 or 1 depending on the bit in the trigger mask
276   const vector<unsigned> *pMap=&fMap;
277   vector<unsigned> tmp;
278   if (fMap.size()==0 && fClassIds.GetLast()>=0) {
279     // read map into temporary array and use it
280     ReadMap(tmp);
281     pMap=&tmp;
282     static bool suppressWarning=false;
283     if (!suppressWarning) HLTWarning("map not yet initialized, creating local map (slow), suppressing further warnings");
284     suppressWarning=true;
285   }
286   vector<Double_t> par;
287   TString condition=expression;
288   for (unsigned index=0; index<pMap->size(); index++) {
289     const char* className=Name((*pMap)[index]);
290     if (className && strlen(className)>0) {
291       //HLTDebug("checking trigger class %s", className.Data());
292       if (condition.Contains(className)) {
293         TString replace; replace.Form("[%d]", (int)par.size());
294         //HLTDebug("replacing %s with %s in \"%s\"", className.Data(), replace.Data(), condition.Data());
295         condition.ReplaceAll(className, replace);
296         if ( triggerMask.test((*pMap)[index]) ) par.push_back(1.0);
297         else par.push_back(0.0);
298       }
299     }
300   }
301
302   TFormula form("trigger expression", condition);
303 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,99,0)
304   if (form.IsValid()!=0) {
305 #else
306   if (form.Compile()!=0) {
307 #endif
308     HLTError("invalid expression %s", expression);
309     return false;
310   }
311   if (form.EvalPar(&par[0], &par[0])>0.5) return true;
312   return false;
313 }
314
315 void AliHLTCTPData::ResetCounters()
316 {
317   // see header file for function documentation
318   fCounters.Set(gkNCTPTriggerClasses);
319   fCounters.Reset();
320 }
321
322 int AliHLTCTPData::Index(const char* name) const
323 {
324   // see header file for function documentation
325   TObject* obj=fClassIds.FindObject(name);
326   return obj!=NULL?fClassIds.IndexOf(obj):-1;
327 }
328
329 int AliHLTCTPData::CheckTrigger(const char* name) const
330 {
331   // check status of a trigger class
332   int index=Index(name);
333   if (index<0) return index;
334   return ( fTriggers.test(index) ? 1 : 0 );
335 }
336
337 void AliHLTCTPData::Increment(const char* classIds)
338 {
339   // see header file for function documentation
340   TString string=classIds;
341   TObjArray* classEntries=string.Tokenize(",");
342   if (classEntries) {
343     for (int i=0; i<classEntries->GetEntriesFast(); i++) {
344       int index=Index(((TObjString*)classEntries->At(i))->GetString().Data());
345       if (index>=0 && index<fCounters.GetSize()) fCounters[index]++;
346     }
347     delete classEntries;
348   }
349 }
350
351 void AliHLTCTPData::Increment(AliHLTTriggerMask_t triggerPattern)
352 {
353   // see header file for function documentation
354   AliHLTTriggerMask_t pattern=triggerPattern&fMask;
355   for (int i=0; i<fCounters.GetSize(); i++) {
356     if (!pattern.test(i)) continue;
357     fCounters[i]++;    
358   }
359 }
360
361 void AliHLTCTPData::Increment(int classIdx)
362 {
363   // see header file for function documentation
364   if (classIdx<fCounters.GetSize() &&
365       fMask.test(classIdx)) {
366     fCounters[classIdx]++;    
367   }
368   
369 }
370
371 int AliHLTCTPData::Increment(AliHLTComponentTriggerData& trigData)
372 {
373   // see header file for function documentation
374   AliHLTCDHWrapper cdh;
375   int result = AliHLTComponent::ExtractTriggerData(trigData, NULL, NULL, &cdh, NULL, true);
376   if (result != 0) return result;
377   if ((cdh.GetL1TriggerMessage() & 0x1) == 0x1) return 0;  // invalid for software triggers.
378
379   AliHLTTriggerMask_t triggerMask(cdh.GetTriggerClasses());
380   AliHLTTriggerMask_t triggerHigh(cdh.GetTriggerClassesNext50());
381   triggerMask |= (triggerHigh << 50);
382
383   if (fMask.any() && (triggerMask & fMask).none()) {
384     AliHLTEventTriggerData* evtData=reinterpret_cast<AliHLTEventTriggerData*>(trigData.fData);
385     HLTWarning("invalid trigger mask %s, unknown CTP trigger, initialized %s", 
386                TriggerMaskToString(triggerMask).c_str(), TriggerMaskToString(fMask).c_str());
387     for (int i=0; i<evtData->fCommonHeaderWordCnt; i++) 
388       HLTWarning("\t CDH[%d]=0x%lx", i, evtData->fCommonHeader[i]);
389   }
390   Increment(triggerMask);
391   return 0;
392 }
393
394 AliHLTUInt64_t AliHLTCTPData::Counter(int index) const
395 {
396   // see header file for function documentation
397   if (index>=0 && index<Counters().GetSize()) return Counters()[index];
398   return 0;
399 }
400
401 AliHLTUInt64_t AliHLTCTPData::Counter(const char* classId) const
402 {
403   // see header file for function documentation
404   return Counter(Index(classId));
405 }
406
407 const char* AliHLTCTPData::Name(int index) const
408 {
409   // see header file for function documentation
410   if (index>fClassIds.GetLast()) return NULL;
411   return fClassIds.At(index)->GetName();
412 }
413
414 int AliHLTCTPData::ReadMap(vector<unsigned> &map) const
415 {
416   // read the index map for class names
417   // for nested class names (e.g. 'myclass' is contained in
418   // 'myclassA') the longer names is added first to the map.
419   for (int index=0; index<=fClassIds.GetLast(); index++) {
420     vector<unsigned>::iterator element=map.begin();
421     for (; element!=map.end(); element++) {
422       TString name=Name(index);
423       if (name.Contains(Name(*element))) {
424         // current name contains another one already in the map
425         // -> add before and go to next entry
426         element=map.insert(element, index);
427         break;
428       }
429     }
430
431     if (element==map.end()) {
432       // unique class name, append to map
433       map.push_back(index);
434     }
435   }
436   return 0;
437 }
438
439
440 AliHLTReadoutList AliHLTCTPData::ReadoutList(const AliHLTComponentTriggerData& trigData) const
441 {
442   // see header file for function documentation
443
444   AliHLTCDHWrapper cdh;
445   if (AliHLTComponent::ExtractTriggerData(trigData, NULL, NULL, &cdh, NULL, true) != 0) return AliHLTReadoutList();
446   // Check if we are dealing with a software trigger. If so then we need to return
447   // a readout list with everything set because the CTP trigger bits are invalid.
448   // Thus we assume that everything should be read out.
449   if ((cdh.GetL1TriggerMessage() & 0x1) == 0x1) return ~ AliHLTReadoutList();
450
451   AliHLTTriggerMask_t triggerMask(cdh.GetTriggerClasses());
452   AliHLTTriggerMask_t triggerHigh(cdh.GetTriggerClassesNext50());
453   triggerMask |= (triggerHigh << 50);
454
455   if (fMask.any() && (triggerMask & fMask).none()) {
456     AliHLTEventTriggerData* evtData=reinterpret_cast<AliHLTEventTriggerData*>(trigData.fData);
457     HLTWarning("invalid trigger mask %s, unknown CTP trigger, initialized %s",
458                TriggerMaskToString(triggerMask).c_str(), TriggerMaskToString(fMask).c_str());
459     for (int i=0; i<evtData->fCommonHeaderWordCnt; i++)
460       HLTWarning("\t CDH[%d]=0x%lx", i, evtData->fCommonHeader[i]);
461   }
462
463   return ReadoutList(triggerMask);
464 }
465
466 AliHLTReadoutList AliHLTCTPData::ReadoutList(AliHLTTriggerMask_t  triggerMask) const
467 {
468   // take an 'OR' of all active trigger classes 
469   AliHLTReadoutList list;
470   for (int i=0; i<gkNCTPTriggerClasses; i++) {
471     if (i>fClassIds.GetLast()) break;
472     if (! triggerMask.test(i)) continue;
473     AliHLTReadoutList* tcrl=(AliHLTReadoutList*)fClassIds.At(i);
474     list.OrEq(*tcrl);
475   }
476
477   return list;
478 }
479
480
481 void AliHLTCTPData::Print(Option_t* /*option*/) const
482 {
483   // see header file for function documentation
484   cout << GetTitle() << endl;
485   cout << "\tactive trigger mask: 0x" << hex << fTriggers << dec << endl;
486   int count=0;
487   for (int i=0; i<gkNCTPTriggerClasses; i++) {
488     if (i>=Counters().GetSize()) break;
489     if (i>fClassIds.GetLast()) break;
490     if (! fMask.test(i)) continue;
491     count++;
492     cout << "\t" << i << "\t" << Name(i) << "\t" << Counter(i) << endl;
493   }
494   if (count==0) cout << "\t(none)" << endl;
495 }
496
497
498 std::string AliHLTCTPData::TriggerMaskToString(AliHLTTriggerMask_t mask) const
499 {
500   AliHLTTriggerMask_t max(std::numeric_limits<unsigned long>::max());
501   int digits = std::numeric_limits<unsigned long>::digits;
502   int numberOfWords = (mask.size() + digits - 1)/digits;
503   std::stringstream stream;
504   stream << "0x";
505   stream << std::hex << std::right;
506   for(int i=numberOfWords-1; i>=0; --i){
507     stream.width(digits/4);
508     stream.fill('0');
509     stream << ((mask >> (digits*i)) & max).to_ulong() << " ";
510   }
511   return stream.str();
512 }
513