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