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