adding cleanup of HLT memory pages
[u/mrichter/AliRoot.git] / HLT / rec / AliHLTReconstructor.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   AliHLTReconstructor.cxx
20     @author Matthias Richter
21     @date   
22     @brief  Binding class for HLT reconstruction in AliRoot. */
23
24 #include <TSystem.h>
25 #include <TObjString.h>
26 #include "TFile.h"
27 #include "TTree.h"
28 #include "TObject.h"
29 #include "TObjArray.h"
30 #include "TClass.h"
31 #include "TStreamerInfo.h"
32 #include "AliHLTReconstructor.h"
33 #include "AliLog.h"
34 #include "AliRawReader.h"
35 #include "AliESDEvent.h"
36 #include "AliHLTSystem.h"
37 #include "AliHLTOUTRawReader.h"
38 #include "AliHLTOUTDigitReader.h"
39 #include "AliHLTEsdManager.h"
40 #include "AliHLTPluginBase.h"
41 #include "AliHLTMisc.h"
42 #include "AliCDBManager.h"
43 #include "AliCDBEntry.h"
44 #include "AliHLTMessage.h"
45 #include "AliCentralTrigger.h"
46 #include "AliTriggerConfiguration.h"
47 #include "AliTriggerClass.h"
48 #include "AliTriggerCluster.h"
49 #include "AliDAQ.h"
50
51 class AliCDBEntry;
52
53 ClassImp(AliHLTReconstructor)
54
55 AliHLTReconstructor::AliHLTReconstructor()
56   : 
57   AliReconstructor(),
58   fFctProcessHLTOUT(NULL),
59   fpEsdManager(NULL),
60   fpPluginBase(new AliHLTPluginBase)
61   , fFlags(0)
62
63   //constructor
64 }
65
66 AliHLTReconstructor::AliHLTReconstructor(const char* options)
67   : 
68   AliReconstructor(),
69   fFctProcessHLTOUT(NULL),
70   fpEsdManager(NULL),
71   fpPluginBase(new AliHLTPluginBase)
72   , fFlags(0)
73
74   //constructor
75   if (options) Init(options);
76 }
77
78 AliHLTReconstructor::~AliHLTReconstructor()
79
80   //destructor
81
82   if (fpPluginBase) {
83   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
84   if (pSystem) {
85     AliDebug(0, Form("terminate HLT system: status %#x", pSystem->GetStatusFlags()));
86     if (pSystem->CheckStatus(AliHLTSystem::kStarted)) {
87       // send specific 'event' to execute the stop sequence
88       pSystem->Reconstruct(0, NULL, NULL);
89     }
90   }
91   delete fpPluginBase;
92   }
93   fpPluginBase=NULL;
94
95   if (fpEsdManager) AliHLTEsdManager::Delete(fpEsdManager);
96   fpEsdManager=NULL;
97 }
98
99 void AliHLTReconstructor::Init(const char* options)
100 {
101   // init the reconstructor
102   SetOption(options);
103   Init();
104 }
105
106 void AliHLTReconstructor::Init()
107 {
108   // init the reconstructor
109   if (!fpPluginBase) {
110     AliError("internal memory error: can not get AliHLTSystem instance from plugin");
111     return;
112   }
113
114   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
115   if (!pSystem) {
116     AliError("can not create AliHLTSystem object");
117     return;
118   }
119   if (pSystem->CheckStatus(AliHLTSystem::kError)) {
120     AliError("HLT system in error state");
121     return;
122   }
123
124   TString esdManagerOptions;
125
126   // the options scan has been moved to AliHLTSystem, the old code
127   // here is kept to be able to run an older version of the HLT code
128   // with newer AliRoot versions.
129   TString libs("");
130   TString option = GetOption();
131   TObjArray* pTokens=option.Tokenize(" ");
132   option="";
133   if (pTokens) {
134     int iEntries=pTokens->GetEntries();
135     for (int i=0; i<iEntries; i++) {
136       TString token=(((TObjString*)pTokens->At(i))->GetString());
137       if (token.Contains("loglevel=")) {
138         TString param=token.ReplaceAll("loglevel=", "");
139         if (param.IsDigit()) {
140           pSystem->SetGlobalLoggingLevel((AliHLTComponentLogSeverity)param.Atoi());
141         } else if (param.BeginsWith("0x") &&
142                    param.Replace(0,2,"",0).IsHex()) {
143           int severity=0;
144           sscanf(param.Data(),"%x", &severity);
145           pSystem->SetGlobalLoggingLevel((AliHLTComponentLogSeverity)severity);
146         } else {
147           AliWarning("wrong parameter for option \'loglevel=\', (hex) number expected");
148         }
149       } else if (token.Contains("alilog=off")) {
150         pSystem->SwitchAliLog(0);
151       } else if (token.CompareTo("ignore-hltout")==0) {
152         fFlags|=kAliHLTReconstructorIgnoreHLTOUT;
153       } else if (token.CompareTo("ignore-ctp")==0) {
154         fFlags|=kAliHLTReconstructorIgnoreCTP;
155       } else if (token.Contains("esdmanager=")) {
156         token.ReplaceAll("esdmanager=", "");
157         token.ReplaceAll(","," ");
158         token.ReplaceAll("'","");
159         esdManagerOptions=token;
160       } else if (token.BeginsWith("lib") && token.EndsWith(".so")) {
161         libs+=token;
162         libs+=" ";
163       } else {
164         if (option.Length()>0) option+=" ";
165         option+=token;
166       }
167     }
168     delete pTokens;
169   }
170
171   TString ecsParam;
172   TString ctpParam;
173   if ((fFlags&kAliHLTReconstructorIgnoreCTP)==0 &&
174       BuildCTPTriggerClassString(ctpParam)>=0) {
175     if (!ecsParam.IsNull()) ecsParam+=";";
176     ecsParam+="CTP_TRIGGER_CLASS=";
177     ecsParam+=ctpParam;
178   }
179
180   if (!ecsParam.IsNull()) {
181     option+=" ECS=";
182     option+=ecsParam;
183   }
184
185   if (!libs.IsNull() &&
186       (!pSystem->CheckStatus(AliHLTSystem::kLibrariesLoaded)) &&
187       (pSystem->LoadComponentLibraries(libs.Data())<0)) {
188     AliError("error while loading HLT libraries");
189     return;
190   }
191
192   if (!pSystem->CheckStatus(AliHLTSystem::kReady)) {
193     typedef int (*AliHLTSystemSetOptions)(AliHLTSystem* pInstance, const char* options);
194     gSystem->Load("libHLTinterface.so");
195     AliHLTSystemSetOptions pFunc=(AliHLTSystemSetOptions)(gSystem->DynFindSymbol("libHLTinterface.so", "AliHLTSystemSetOptions"));
196     if (pFunc) {
197       if ((pFunc)(pSystem, option.Data())<0) {
198       AliError("error setting options for HLT system");
199       return;   
200       }
201     } else if (option.Length()>0) {
202       AliError(Form("version of HLT system does not support the options \'%s\'", option.Data()));
203       return;
204     }
205     if ((pSystem->Configure())<0) {
206       AliError("error during HLT system configuration");
207       return;
208     }
209   }
210
211   gSystem->Load("libHLTinterface.so");
212   fFctProcessHLTOUT=(void (*)())gSystem->DynFindSymbol("libHLTinterface.so", "AliHLTSystemProcessHLTOUT");
213
214   fpEsdManager=AliHLTEsdManager::New();
215   fpEsdManager->SetOption(esdManagerOptions.Data());
216
217   InitStreamerInfos();
218 }
219
220 const char* AliHLTReconstructor::fgkCalibStreamerInfoEntry="HLT/Calib/StreamerInfo";
221
222 int AliHLTReconstructor::InitStreamerInfos()
223 {
224   // init streamer infos for HLT reconstruction
225   // Root schema evolution is not enabled for AliHLTMessage and all streamed objects.
226   // Objects in the raw data payload rely on the availability of the correct stream info.
227   // The relevant streamer info for a specific run is stored in the OCDB.
228   // The method evaluates the following entries:
229   // - HLT/Calib/StreamerInfo
230   int iResult=0;
231
232   // to be activated later, this is supposed to go as patch into the v4-17-Release branch
233   // which doe snot have the AliHLTMisc implementation
234   //AliCDBEntry* pEntry=AliHLTMisc::Instance().LoadOCDBEntry(fgkCalibStreamerInfoEntry);
235   AliCDBEntry* pEntry=AliCDBManager::Instance()->Get(fgkCalibStreamerInfoEntry);
236   TObject* pObject=NULL;
237   //if (pEntry && (pObject=AliHLTMisc::Instance().ExtractObject(pEntry))!=NULL)
238   if (pEntry && (pObject=pEntry->GetObject())!=NULL)
239     {
240     TObjArray* pSchemas=dynamic_cast<TObjArray*>(pObject);
241     if (pSchemas) {
242       iResult=InitStreamerInfos(pSchemas);
243     } else {
244       AliError(Form("internal mismatch in OCDB entry %s: wrong class type", fgkCalibStreamerInfoEntry));
245     }
246   } else {
247     AliWarning(Form("missing HLT reco data (%s), skipping initialization of streamer info for TObjects in HLT raw data payload", fgkCalibStreamerInfoEntry));
248   }
249   return iResult;
250 }
251
252 int AliHLTReconstructor::InitStreamerInfos(TObjArray* pSchemas) const
253 {
254   // init streamer infos for HLT reconstruction from an array of TStreamerInfo objects
255
256   for (int i=0; i<pSchemas->GetEntriesFast(); i++) {
257     if (pSchemas->At(i)) {
258       TStreamerInfo* pSchema=dynamic_cast<TStreamerInfo*>(pSchemas->At(i));
259       if (pSchema) {
260         int version=pSchema->GetClassVersion();
261         TClass* pClass=TClass::GetClass(pSchema->GetName());
262         if (pClass) {
263           if (pClass->GetClassVersion()==version) {
264             AliDebug(0,Form("skipping schema definition %d version %d to class %s as this is the native version", i, version, pSchema->GetName()));
265             continue;
266           }
267           TObjArray* pInfos=pClass->GetStreamerInfos();
268           if (pInfos /*&& version<pInfos->GetEntriesFast()*/) {
269             if (pInfos->At(version)==NULL) {
270               TStreamerInfo* pClone=(TStreamerInfo*)pSchema->Clone();
271               if (pClone) {
272                 pClone->SetClass(pClass);
273                 pClone->BuildOld();
274                 pInfos->AddAtAndExpand(pClone, version);
275                 AliDebug(0,Form("adding schema definition %d version %d to class %s", i, version, pSchema->GetName()));
276               } else {
277                 AliError(Form("skipping schema definition %d (%s), unable to create clone object", i, pSchema->GetName()));
278               }
279             } else {
280               TStreamerInfo* pInfo=dynamic_cast<TStreamerInfo*>(pInfos->At(version));
281               if (pInfo && pInfo->GetClassVersion()==version) {
282                 AliDebug(0,Form("schema definition %d version %d already available in class %s, skipping ...", i, version, pSchema->GetName()));
283               } else {
284                 AliError(Form("can not verify version for already existing schema definition %d (%s) version %d: version of existing definition is %d", i, pSchema->GetName(), version, pInfo?pInfo->GetClassVersion():-1));
285               }
286             }
287           } else {
288             AliError(Form("skipping schema definition %d (%s), unable to set version %d in info array of size %d", i, pSchema->GetName(), version, pInfos?pInfos->GetEntriesFast():-1));
289           }
290         } else {
291           AliError(Form("skipping schema definition %d (%s), unable to find class", i, pSchema->GetName()));
292         }
293       } else {
294         AliError(Form("skipping schema definition %d, not of TStreamerInfo", i));
295       }
296     }
297   }
298
299   return 0;
300 }
301
302 void AliHLTReconstructor::Reconstruct(AliRawReader* rawReader, TTree* /*clustersTree*/) const 
303 {
304   // reconstruction of real data without writing of ESD
305   // For each event, HLT reconstruction chains can be executed and
306   // added to the existing HLTOUT data
307   // The HLTOUT data is finally processed in FillESD
308   if (!fpPluginBase) {
309     AliError("internal memory error: can not get AliHLTSystem instance from plugin");
310     return;
311   }
312
313   int iResult=0;
314   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
315
316   if (pSystem) {
317     if (pSystem->CheckStatus(AliHLTSystem::kError)) {
318       AliError("HLT system in error state");
319       return;
320     }
321     if (!pSystem->CheckStatus(AliHLTSystem::kReady)) {
322       AliError("HLT system in wrong state");
323       return;
324     }
325     if ((iResult=pSystem->Reconstruct(1, NULL, rawReader))>=0) {
326     }
327   }
328 }
329
330 void AliHLTReconstructor::FillESD(AliRawReader* rawReader, TTree* /*clustersTree*/, 
331                                   AliESDEvent* esd) const
332 {
333   // reconstruct real data and fill ESD
334   if (!rawReader || !esd) {
335     AliError("missing raw reader or esd object");
336     return;
337   }
338
339   if (!fpPluginBase) {
340     AliError("internal memory error: can not get AliHLTSystem instance from plugin");
341     return;
342   }
343
344   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
345
346   if (pSystem) {
347     if (pSystem->CheckStatus(AliHLTSystem::kError)) {
348       AliError("HLT system in error state");
349       return;
350     }
351     if (!pSystem->CheckStatus(AliHLTSystem::kReady)) {
352       AliError("HLT system in wrong state");
353       return;
354     }
355     pSystem->FillESD(-1, NULL, esd);
356
357     AliRawReader* input=NULL;
358     if ((fFlags&kAliHLTReconstructorIgnoreHLTOUT) == 0 ) {
359       input=rawReader;
360     }
361     AliHLTOUTRawReader* pHLTOUT=new AliHLTOUTRawReader(input, esd->GetEventNumberInFile(), fpEsdManager);
362     if (pHLTOUT) {
363       ProcessHLTOUT(pHLTOUT, esd, (pSystem->GetGlobalLoggingLevel()&kHLTLogDebug)!=0);
364       delete pHLTOUT;
365     } else {
366       AliError("error creating HLTOUT handler");
367     }
368   }
369 }
370
371 void AliHLTReconstructor::Reconstruct(TTree* /*digitsTree*/, TTree* /*clustersTree*/) const
372 {
373   // reconstruct simulated data
374
375   // all reconstruction has been moved to FillESD
376   //AliReconstructor::Reconstruct(digitsTree,clustersTree);
377   AliInfo("running digit data reconstruction");
378 }
379
380 void AliHLTReconstructor::FillESD(TTree* /*digitsTree*/, TTree* /*clustersTree*/, AliESDEvent* esd) const
381 {
382   // reconstruct simulated data and fill ESD
383
384   // later this is the place to extract the simulated HLT data
385   // for now it's only an user failure condition as he tries to run HLT reconstruction
386   // on simulated data 
387   TString option = GetOption();
388   if (!option.IsNull() && 
389       (option.Contains("config=") || option.Contains("chains="))) {
390     AliWarning(Form("HLT reconstruction can be run embedded into Alireconstruction from\n"
391                     "raw data (real or simulated)). Reconstruction of of digit data takes\n"
392                     "place in AliSimulation, appropriate input conversion is needed.\n"
393                     "Consider running embedded into AliSimulation."
394                     "        /***  run macro *****************************************/\n"
395                     "        AliSimulation sim;\n"
396                     "        sim.SetRunHLT(\"%s\");\n"
397                     "        sim.SetRunGeneration(kFALSE);\n"
398                     "        sim.SetMakeDigits(\"\");\n"
399                     "        sim.SetMakeSDigits(\"\");\n"
400                     "        sim.SetMakeDigitsFromHits(\"\");\n"
401                     "        sim.Run();\n"
402                     "        /*********************************************************/", option.Data()));
403   }
404   if (!fpPluginBase) {
405     AliError("internal memory error: can not get AliHLTSystem instance from plugin");
406     return;
407   }
408
409   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
410   if (pSystem) {
411     if (pSystem->CheckStatus(AliHLTSystem::kError)) {
412       AliError("HLT system in error state");
413       return;
414     }
415     if (!pSystem->CheckStatus(AliHLTSystem::kReady)) {
416       AliError("HLT system in wrong state");
417       return;
418     }
419
420     AliHLTOUTDigitReader* pHLTOUT=new AliHLTOUTDigitReader(esd->GetEventNumberInFile(), fpEsdManager);
421     if (pHLTOUT) {
422       ProcessHLTOUT(pHLTOUT, esd, (pSystem->GetGlobalLoggingLevel()&kHLTLogDebug)!=0);
423       delete pHLTOUT;
424     } else {
425       AliError("error creating HLTOUT handler");
426     }
427   }
428 }
429
430 void AliHLTReconstructor::ProcessHLTOUT(AliHLTOUT* pHLTOUT, AliESDEvent* esd, bool bVerbose) const
431 {
432   // treatment of simulated or real HLTOUT data
433   if (!pHLTOUT) return;
434   if (!fpPluginBase) {
435     AliError("internal memory error: can not get AliHLTSystem instance from plugin");
436     return;
437   }
438
439   AliHLTSystem* pSystem=fpPluginBase->GetInstance();
440   if (!pSystem) {
441     AliError("error getting HLT system instance");
442     return;
443   }
444
445   if (pHLTOUT->Init()<0) {
446     AliError("error : initialization of HLTOUT handler failed");
447     return;
448   }
449
450   if (bVerbose)
451     PrintHLTOUTContent(pHLTOUT);
452
453   int blockindex=pHLTOUT->SelectFirstDataBlock(kAliHLTDataTypeStreamerInfo);
454   if (blockindex>=0) {
455     const AliHLTUInt8_t* pBuffer=NULL;
456     AliHLTUInt32_t size=0;
457     if (pHLTOUT->GetDataBuffer(pBuffer, size)>=0) {
458       TObject* pObject=AliHLTMessage::Extract(pBuffer, size);
459       if (pObject) {
460         TObjArray* pArray=dynamic_cast<TObjArray*>(pObject);
461         if (pArray) {
462           InitStreamerInfos(pArray);
463         } else {
464           AliError(Form("wrong class type of streamer info list: expected TObjArray, but object is of type %s", pObject->Class()->GetName()));
465         }
466       } else {
467         AliError(Form("failed to extract object from data block of type %s", AliHLTComponent::DataType2Text(kAliHLTDataTypeStreamerInfo).c_str()));
468       }
469     } else {
470       AliError(Form("failed to get data buffer for block of type %s", AliHLTComponent::DataType2Text(kAliHLTDataTypeStreamerInfo).c_str()));
471     }
472   }
473
474   if (fFctProcessHLTOUT) {
475     typedef int (*AliHLTSystemProcessHLTOUT)(AliHLTSystem* pInstance, AliHLTOUT* pHLTOUT, AliESDEvent* esd);
476     AliHLTSystemProcessHLTOUT pFunc=(AliHLTSystemProcessHLTOUT)fFctProcessHLTOUT;
477     if ((pFunc)(pSystem, pHLTOUT, esd)<0) {
478       AliError("error processing HLTOUT");
479     }
480   }
481   if (bVerbose) {
482     AliInfo("HLT ESD content:");
483     esd->Print();
484   }
485   pHLTOUT->Reset();
486 }
487
488 void AliHLTReconstructor::ProcessHLTOUT(const char* digitFile, AliESDEvent* pEsd) const
489 {
490   // debugging/helper function to examine simulated data
491   if (!digitFile) return;
492
493   // read the number of events
494   TFile f(digitFile);
495   if (f.IsZombie()) return;
496   TTree* pTree=NULL;
497   f.GetObject("rawhltout", pTree);
498   if (!pTree) {
499     AliWarning(Form("can not find tree rawhltout in file %s", digitFile));
500     return ;
501   }
502   int nofEvents=pTree->GetEntries();
503   f.Close();
504   //delete pTree; OF COURSE NOT! its an object in the file
505   pTree=NULL;
506
507   for (int event=0; event<nofEvents; event++) {
508     AliHLTOUTDigitReader* pHLTOUT=new AliHLTOUTDigitReader(event, fpEsdManager, digitFile);
509     if (pHLTOUT) {
510       AliInfo(Form("event %d", event));
511       ProcessHLTOUT(pHLTOUT, pEsd, true);
512       delete pHLTOUT;
513     } else {
514       AliError("error creating HLTOUT handler");
515     }
516   }
517 }
518
519 void AliHLTReconstructor::ProcessHLTOUT(AliRawReader* pRawReader, AliESDEvent* pEsd) const
520 {
521   // debugging/helper function to examine simulated or real HLTOUT data
522   if (!pRawReader) return;
523
524   pRawReader->RewindEvents();
525   for (int event=0; pRawReader->NextEvent(); event++) {
526     AliHLTOUTRawReader* pHLTOUT=new AliHLTOUTRawReader(pRawReader, event, fpEsdManager);
527     if (pHLTOUT) {
528       AliInfo(Form("event %d", event));
529       // the two event fields contain: period - orbit - bunch crossing counter
530       //        id[0]               id[1]
531       // |32                0|32                0|
532       //
533       // |      28 bit    |       24 bit     | 12|
534       //        period          orbit         bcc
535       AliHLTUInt64_t eventId=0;
536       const UInt_t* rawreaderEventId=pRawReader->GetEventId();
537       if (rawreaderEventId) {
538         eventId=rawreaderEventId[0];
539         eventId=eventId<<32;
540         eventId|=rawreaderEventId[1];
541       }
542       AliInfo(Form("Event Id from rawreader:\t 0x%016llx", eventId));
543       ProcessHLTOUT(pHLTOUT, pEsd, true);
544       delete pHLTOUT;
545     } else {
546       AliError("error creating HLTOUT handler");
547     }
548   }
549 }
550
551 void AliHLTReconstructor::PrintHLTOUTContent(AliHLTOUT* pHLTOUT) const
552 {
553   // print the block specifications of the HLTOUT data blocks
554   if (!pHLTOUT) return;
555   int iResult=0;
556
557   AliInfo(Form("Event Id from hltout:\t 0x%016llx", pHLTOUT->EventId()));
558   for (iResult=pHLTOUT->SelectFirstDataBlock();
559        iResult>=0;
560        iResult=pHLTOUT->SelectNextDataBlock()) {
561     AliHLTComponentDataType dt=kAliHLTVoidDataType;
562     AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
563     pHLTOUT->GetDataBlockDescription(dt, spec);
564     const AliHLTUInt8_t* pBuffer=NULL;
565     AliHLTUInt32_t size=0;
566     if (pHLTOUT->GetDataBuffer(pBuffer, size)>=0) {
567       pHLTOUT->ReleaseDataBuffer(pBuffer);
568       pBuffer=NULL; // just a dummy
569     }
570     AliInfo(Form("   %s  0x%x: size %d", AliHLTComponent::DataType2Text(dt).c_str(), spec, size));
571   }
572 }
573
574 int AliHLTReconstructor::BuildCTPTriggerClassString(TString& triggerclasses) const
575 {
576   // build the CTP trigger class string from the OCDB entry of the CTP trigger
577   int iResult=0;
578   
579   triggerclasses.Clear();
580   AliCentralTrigger* pCTP = new AliCentralTrigger();
581   AliTriggerConfiguration *config=NULL;
582   TString configstr("");
583   if (pCTP->LoadConfiguration(configstr) && 
584       (config = pCTP->GetConfiguration())!=NULL) {
585     const TObjArray& classesArray = config->GetClasses();
586     int nclasses = classesArray.GetEntriesFast();
587     for( int iclass=0; iclass < nclasses; iclass++ ) {
588       AliTriggerClass* trclass = NULL;
589       if (classesArray.At(iclass) && (trclass=dynamic_cast<AliTriggerClass*>(classesArray.At(iclass)))!=NULL) {
590         TString entry;
591         int trindex = TMath::Nint(TMath::Log2(trclass->GetMask()));
592         entry.Form("%02d:%s:", trindex, trclass->GetName());
593         AliTriggerCluster* cluster=NULL;
594         TObject* clusterobj=config->GetClusters().FindObject(trclass->GetCluster());
595         if (clusterobj && (cluster=dynamic_cast<AliTriggerCluster*>(clusterobj))!=NULL) {
596           TString detectors=cluster->GetDetectorsInCluster();
597           TObjArray* pTokens=detectors.Tokenize(" ");
598           if (pTokens) {
599             for (int dix=0; dix<pTokens->GetEntriesFast(); dix++) {
600               int id=AliDAQ::DetectorID(((TObjString*)pTokens->At(dix))->GetString());
601               if (id>=0) {
602                 TString detstr; detstr.Form("%s%02d", dix>0?"-":"", id);
603                 entry+=detstr;
604               } else {
605                 AliError(Form("invalid detector name extracted from trigger cluster: %s (%s)", ((TObjString*)pTokens->At(dix))->GetString().Data(), detectors.Data()));
606                 iResult=-EPROTO;
607                 break;
608               }
609             }
610             delete pTokens;
611           }
612         } else {
613           AliError(Form("can not find trigger cluster %s in config", trclass->GetCluster()));
614           iResult=-EPROTO;
615           break;
616         }
617         if (!triggerclasses.IsNull()) triggerclasses+=",";
618         triggerclasses+=entry;
619       }
620     }
621   }
622
623   return iResult;
624 }