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