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