Made changes to the trigger reconstructor component algorithm to interpret raw DDL...
[u/mrichter/AliRoot.git] / HLT / MUON / OnlineAnalysis / AliHLTMUONTriggerReconstructorComponent.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        *
3  * All rights reserved.                                                   *
4  *                                                                        *
5  * Primary Authors:                                                       *
6  *   Indranil Das <indra.das@saha.ac.in>                                  *
7  *   Artur Szostak <artursz@iafrica.com>                                  *
8  *                                                                        *
9  * Permission to use, copy, modify and distribute this software and its   *
10  * documentation strictly for non-commercial purposes is hereby granted   *
11  * without fee, provided that the above copyright notice appears in all   *
12  * copies and that both the copyright notice and this permission notice   *
13  * appear in the supporting documentation. The authors make no claims     *
14  * about the suitability of this software for any purpose. It is          *
15  * provided "as is" without express or implied warranty.                  *
16  **************************************************************************/
17
18 /* $Id$ */
19
20 ///
21 /// @file   AliHLTMUONTriggerReconstructorComponent.cxx
22 /// @author Indranil Das <indra.das@saha.ac.in>, Artur Szostak <artursz@iafrica.com>
23 /// @date   18 Sep 2007
24 /// @brief  Implementation of the trigger DDL reconstructor component.
25 ///
26
27 #include "AliHLTMUONTriggerReconstructorComponent.h"
28 #include "AliHLTMUONTriggerReconstructor.h"
29 #include "AliHLTMUONHitReconstructor.h"
30 #include "AliHLTMUONConstants.h"
31 #include "AliHLTMUONUtils.h"
32 #include "AliHLTMUONDataBlockWriter.h"
33 #include "AliRawDataHeader.h"
34 #include "AliCDBManager.h"
35 #include "AliCDBStorage.h"
36 #include "AliGeomManager.h"
37 #include "AliMUONGeometryTransformer.h"
38 #include "AliMUONGeometryDetElement.h"
39 #include "AliMpCDB.h"
40 #include "AliMpDDLStore.h"
41 #include "AliMpPad.h"
42 #include "AliMpSegmentation.h"
43 #include "AliMpDEIterator.h"
44 #include "AliMpVSegmentation.h"
45 #include "AliMpDEManager.h"
46 #include "AliMpLocalBoard.h"
47 #include "AliMpTriggerCrate.h"
48 #include <cstdlib>
49 #include <cerrno>
50 #include <cassert>
51 #include <fstream>
52
53
54 ClassImp(AliHLTMUONTriggerReconstructorComponent)
55
56
57 AliHLTMUONTriggerReconstructorComponent::AliHLTMUONTriggerReconstructorComponent() :
58         AliHLTMUONProcessor(),
59         fTrigRec(NULL),
60         fDDL(-1),
61         fWarnForUnexpecedBlock(false),
62         fStopOnOverflow(false),
63         fUseCrateId(true)
64 {
65         ///
66         /// Default constructor.
67         ///
68 }
69
70
71 AliHLTMUONTriggerReconstructorComponent::~AliHLTMUONTriggerReconstructorComponent()
72 {
73         ///
74         /// Default destructor.
75         ///
76         
77         if (fTrigRec != NULL) delete fTrigRec;
78 }
79
80
81 const char* AliHLTMUONTriggerReconstructorComponent::GetComponentID()
82 {
83         ///
84         /// Inherited from AliHLTComponent. Returns the component ID.
85         ///
86         
87         return AliHLTMUONConstants::TriggerReconstructorId();
88 }
89
90
91 void AliHLTMUONTriggerReconstructorComponent::GetInputDataTypes( std::vector<AliHLTComponentDataType>& list)
92 {
93         ///
94         /// Inherited from AliHLTProcessor. Returns the list of expected input data types.
95         ///
96         
97         list.clear();
98         list.push_back( AliHLTMUONConstants::DDLRawDataType() );
99 }
100
101
102 AliHLTComponentDataType AliHLTMUONTriggerReconstructorComponent::GetOutputDataType()
103 {
104         ///
105         /// Inherited from AliHLTComponent. Returns the output data type.
106         ///
107         
108         return AliHLTMUONConstants::TriggerRecordsBlockDataType();
109 }
110
111
112 void AliHLTMUONTriggerReconstructorComponent::GetOutputDataSize(
113                 unsigned long& constBase, double& inputMultiplier
114         )
115 {
116         ///
117         /// Inherited from AliHLTComponent. Returns an estimate of the expected output data size.
118         ///
119         
120         constBase = sizeof(AliHLTMUONTriggerRecordsBlockWriter::HeaderType);
121         inputMultiplier = 4;
122 }
123
124
125 AliHLTComponent* AliHLTMUONTriggerReconstructorComponent::Spawn()
126 {
127         ///
128         /// Inherited from AliHLTComponent. Creates a new object instance.
129         ///
130         
131         return new AliHLTMUONTriggerReconstructorComponent;
132 }
133
134
135 int AliHLTMUONTriggerReconstructorComponent::DoInit(int argc, const char** argv)
136 {
137         ///
138         /// Inherited from AliHLTComponent.
139         /// Parses the command line parameters and initialises the component.
140         ///
141         
142         // perform initialization.
143         
144         HLTInfo("Initialising dHLT trigger reconstructor component.");
145         
146         // Make sure to cleanup fTrigRec if it is still there for some reason.
147         if (fTrigRec != NULL)
148         {
149                 delete fTrigRec;
150                 fTrigRec = NULL;
151         }
152         
153         try
154         {
155                 fTrigRec = new AliHLTMUONTriggerReconstructor();
156         }
157         catch (const std::bad_alloc&)
158         {
159                 HLTError("Could not allocate more memory for the trigger reconstructor component.");
160                 return -ENOMEM;
161         }
162         
163         fDDL = -1;
164         fWarnForUnexpecedBlock = false;
165         fStopOnOverflow = false;
166         fUseCrateId = true;
167         
168         const char* lutFileName = NULL;
169         const char* cdbPath = NULL;
170         Int_t run = -1;
171         bool useCDB = false;
172         bool suppressPartialTrigs = true;
173         bool tryRecover = false;
174         
175         for (int i = 0; i < argc; i++)
176         {
177                 if (strcmp( argv[i], "-lut" ) == 0)
178                 {
179                         if ( argc <= i+1 )
180                         {
181                                 HLTError("LookupTable filename not specified." );
182                                 // Make sure to delete fTrigRec to avoid partial initialisation.
183                                 delete fTrigRec;
184                                 fTrigRec = NULL;
185                                 return -EINVAL;
186                         }
187                         
188                         lutFileName = argv[i+1];
189                         
190                         i++;
191                         continue;
192                 }
193                 
194                 if (strcmp( argv[i], "-ddl" ) == 0)
195                 {
196                         if ( argc <= i+1 )
197                         {
198                                 HLTError("DDL number not specified. It must be in the range [21..22]" );
199                                 // Make sure to delete fTrigRec to avoid partial initialisation.
200                                 delete fTrigRec;
201                                 fTrigRec = NULL;
202                                 return -EINVAL;
203                         }
204                 
205                         char* cpErr = NULL;
206                         unsigned long num = strtoul(argv[i+1], &cpErr, 0);
207                         if (cpErr == NULL or *cpErr != '\0')
208                         {
209                                 HLTError("Cannot convert '%s' to a DDL Number.", argv[i+1]);
210                                 // Make sure to delete fTrigRec to avoid partial initialisation.
211                                 delete fTrigRec;
212                                 fTrigRec = NULL;
213                                 return -EINVAL;
214                         }
215                         if (num < 21 or 22 < num)
216                         {
217                                 HLTError("The DDL number must be in the range [21..22].");
218                                 // Make sure to delete fTrigRec to avoid partial initialisation.
219                                 delete fTrigRec;
220                                 fTrigRec = NULL;
221                                 return -EINVAL;
222                         }
223                         fDDL = num - 1; // Convert to DDL number in the range 0..21
224                         
225                         i++;
226                         continue;
227                 }
228                 
229                 if (strcmp( argv[i], "-ddlid" ) == 0)
230                 {
231                         if ( argc <= i+1 )
232                         {
233                                 HLTError("DDL equipment ID number not specified. It must be in the range [2816..2817]" );
234                                 // Make sure to delete fTrigRec to avoid partial initialisation.
235                                 delete fTrigRec;
236                                 fTrigRec = NULL;
237                                 return -EINVAL;
238                         }
239                 
240                         char* cpErr = NULL;
241                         unsigned long num = strtoul(argv[i+1], &cpErr, 0);
242                         if (cpErr == NULL or *cpErr != '\0')
243                         {
244                                 HLTError("Cannot convert '%s' to a DDL equipment ID Number.", argv[i+1]);
245                                 // Make sure to delete fTrigRec to avoid partial initialisation.
246                                 delete fTrigRec;
247                                 fTrigRec = NULL;
248                                 return -EINVAL;
249                         }
250                         fDDL = AliHLTMUONUtils::EquipIdToDDLNumber(num); // Convert to DDL number in the range 0..21
251                         if (fDDL < 20 or 21 < fDDL)
252                         {
253                                 HLTError("The DDL equipment ID number must be in the range [2816..2817].");
254                                 // Make sure to delete fTrigRec to avoid partial initialisation.
255                                 delete fTrigRec;
256                                 fTrigRec = NULL;
257                                 return -EINVAL;
258                         }
259                         
260                         i++;
261                         continue;
262                 }
263                 
264                 if (strcmp( argv[i], "-cdb" ) == 0)
265                 {
266                         useCDB = true;
267                         continue;
268                 }
269                 
270                 if (strcmp( argv[i], "-cdbpath" ) == 0)
271                 {
272                         if ( argc <= i+1 )
273                         {
274                                 HLTError("The CDB path was not specified." );
275                                 // Make sure to delete fTrigRec to avoid partial initialisation.
276                                 delete fTrigRec;
277                                 fTrigRec = NULL;
278                                 return -EINVAL;
279                         }
280                         cdbPath = argv[i+1];
281                         useCDB = true;
282                         i++;
283                         continue;
284                 }
285         
286                 if (strcmp( argv[i], "-run" ) == 0)
287                 {
288                         if ( argc <= i+1 )
289                         {
290                                 HLTError("The RUN number was not specified." );
291                                 // Make sure to delete fTrigRec to avoid partial initialisation.
292                                 delete fTrigRec;
293                                 fTrigRec = NULL;
294                                 return -EINVAL;
295                         }
296                         
297                         char* cpErr = NULL;
298                         run = Int_t( strtoul(argv[i+1], &cpErr, 0) );
299                         if (cpErr == NULL or *cpErr != '\0')
300                         {
301                                 HLTError("Cannot convert '%s' to a valid run number."
302                                         " Expected an integer value.", argv[i+1]
303                                 );
304                                 // Make sure to delete fTrigRec to avoid partial initialisation.
305                                 delete fTrigRec;
306                                 fTrigRec = NULL;
307                                 return -EINVAL;
308                         }
309                         
310                         i++;
311                         continue;
312                 }
313                 
314                 if (strcmp( argv[i], "-warn_on_unexpected_block" ) == 0)
315                 {
316                         fWarnForUnexpecedBlock = true;
317                         continue;
318                 }
319                 
320                 if (strcmp( argv[i], "-suppress_partial_triggers" ) == 0)
321                 {
322                         suppressPartialTrigs = true;
323                         continue;
324                 }
325                 
326                 if (strcmp( argv[i], "-generate_partial_triggers" ) == 0)
327                 {
328                         suppressPartialTrigs = false;
329                         continue;
330                 }
331                 
332                 if (strcmp( argv[i], "-stop_on_buffer_overflow" ) == 0)
333                 {
334                         fStopOnOverflow = true;
335                         continue;
336                 }
337                 
338                 if (strcmp( argv[i], "-tryrecover" ) == 0)
339                 {
340                         tryRecover = true;
341                         continue;
342                 }
343                 
344                 if (strcmp( argv[i], "-dont_use_crateid" ) == 0)
345                 {
346                         fUseCrateId = false;
347                         continue;
348                 }
349                 
350                 HLTError("Unknown option '%s'.", argv[i] );
351                 // Make sure to delete fTrigRec to avoid partial initialisation.
352                 delete fTrigRec;
353                 fTrigRec = NULL;
354                 return -EINVAL;
355                 
356         } // for loop
357         
358         if (lutFileName == NULL) useCDB = true;
359         
360         if (fDDL == -1)
361         {
362                 HLTWarning("DDL number not specified. Cannot check if incomming data is valid.");
363         }
364         
365         int result = 0;
366         if (useCDB)
367         {
368                 HLTInfo("Loading lookup table information from CDB for DDL %d (ID = %d).",
369                         fDDL+1, AliHLTMUONUtils::DDLNumberToEquipId(fDDL)
370                 );
371                 if (fDDL == -1)
372                         HLTWarning("DDL number not specified. The lookup table loaded from CDB will be empty!");
373                 result = ReadCDB(cdbPath, run);
374         }
375         else
376         {
377                 HLTInfo("Loading lookup table information from file %s.", lutFileName);
378                 result = ReadLookUpTable(lutFileName);
379         }
380         if (result != 0)
381         {
382                 // Error messages already generated in ReadCDB or ReadLookUpTable.
383                 
384                 // Make sure to delete fTrigRec to avoid partial initialisation.
385                 delete fTrigRec;
386                 fTrigRec = NULL;
387                 return result;
388         }
389         
390         fTrigRec->SuppressPartialTriggers(suppressPartialTrigs);
391         fTrigRec->TryRecover(tryRecover);
392         fTrigRec->UseCrateId(fUseCrateId);
393         
394         return 0;
395 }
396
397
398 int AliHLTMUONTriggerReconstructorComponent::DoDeinit()
399 {
400         ///
401         /// Inherited from AliHLTComponent. Performs a cleanup of the component.
402         ///
403         
404         HLTInfo("Deinitialising dHLT trigger reconstructor component.");
405
406         if (fTrigRec != NULL)
407         {
408                 delete fTrigRec;
409                 fTrigRec = NULL;
410         }
411         return 0;
412 }
413
414
415 int AliHLTMUONTriggerReconstructorComponent::DoEvent(
416                 const AliHLTComponentEventData& evtData,
417                 const AliHLTComponentBlockData* blocks,
418                 AliHLTComponentTriggerData& /*trigData*/,
419                 AliHLTUInt8_t* outputPtr,
420                 AliHLTUInt32_t& size,
421                 std::vector<AliHLTComponentBlockData>& outputBlocks
422         )
423 {
424         ///
425         /// Inherited from AliHLTProcessor. Processes the new event data.
426         ///
427         
428         // Process an event
429         unsigned long totalSize = 0; // Amount of memory currently consumed in bytes.
430
431         HLTDebug("Processing event %llu with %u input data blocks.",
432                 evtData.fEventID, evtData.fBlockCnt
433         );
434         
435         // Loop over all input blocks in the event and run the trigger DDL
436         // reconstruction algorithm on the raw data.
437         for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; n++)
438         {
439                 HLTDebug("Handling block: %u, with fDataType = '%s', fPtr = %p and fSize = %u bytes.",
440                         n, DataType2Text(blocks[n].fDataType).c_str(), blocks[n].fPtr, blocks[n].fSize
441                 );
442
443                 if (blocks[n].fDataType != AliHLTMUONConstants::DDLRawDataType()
444                     or not AliHLTMUONUtils::IsTriggerDDL(blocks[n].fSpecification)
445                    )
446                 {
447                         // Log a message indicating that we got a data block that we
448                         // do not know how to handle.
449                         if (fWarnForUnexpecedBlock)
450                                 HLTWarning("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
451                                         DataType2Text(blocks[n].fDataType).c_str(), blocks[n].fSpecification
452                                 );
453                         else
454                                 HLTDebug("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
455                                         DataType2Text(blocks[n].fDataType).c_str(), blocks[n].fSpecification
456                                 );
457                         
458                         continue;
459                 }
460                 
461                 AliHLTInt32_t receivedDDL = AliHLTMUONUtils::SpecToDDLNumber(blocks[n].fSpecification);
462                 if (fDDL != -1)
463                 {
464                         if (receivedDDL != fDDL)
465                         {
466                                 HLTWarning("Received raw data from DDL %d (ID = %d),"
467                                         " but expect data only from DDL %d (ID = %d).",
468                                         receivedDDL+1, AliHLTMUONUtils::DDLNumberToEquipId(receivedDDL),
469                                         fDDL+1, AliHLTMUONUtils::DDLNumberToEquipId(fDDL)
470                                 );
471                         }
472                 }
473                 
474                 // Create a new output data block and initialise the header.
475                 AliHLTMUONTriggerRecordsBlockWriter block(outputPtr+totalSize, size-totalSize);
476                 if (not block.InitCommonHeader())
477                 {
478                         HLTError("There is not enough space in the output buffer for the new data block."
479                                  " We require at least %ufTrigRec->GetkDDLHeaderSize() bytes, but have %u bytes left.",
480                                 sizeof(AliHLTMUONTriggerRecordsBlockWriter::HeaderType),
481                                 block.BufferSize()
482                         );
483                         break;
484                 }
485
486                 AliHLTUInt32_t totalDDLSize = blocks[n].fSize;
487                 if (totalDDLSize < sizeof(AliRawDataHeader))
488                 {
489                         HLTError("Raw data block %d is %d bytes in size and is too short to"
490                                  " possibly contain valid DDL raw data. We expect it to have"
491                                  " at least %d bytes for the commond data header.",
492                                 n, totalDDLSize, sizeof(AliRawDataHeader)
493                         );
494                         continue;
495                 }
496                 AliRawDataHeader* header = reinterpret_cast<AliRawDataHeader*>(blocks[n].fPtr);
497                 AliHLTUInt32_t payloadSize = totalDDLSize - sizeof(AliRawDataHeader);
498                 AliHLTUInt8_t* buffer = reinterpret_cast<AliHLTUInt8_t*>(header + 1);
499                 AliHLTUInt32_t nofTrigRec = block.MaxNumberOfEntries();
500                 
501                 // Decode if this is a scalar event or not.
502                 bool scalarEvent = ((header->GetL1TriggerMessage() & 0x1) == 0x1);
503                 
504                 // Remember: the following does NOT change the mapping!
505                 // It is just to generate unique trigger record IDs.
506                 fTrigRec->SetDDL(receivedDDL);
507                 
508                 bool runOk = fTrigRec->Run(
509                                 buffer, payloadSize, scalarEvent,
510                                 block.GetArray(), nofTrigRec
511                         );
512                 if (not runOk)
513                 {
514                         HLTError("Error while processing the trigger DDL reconstruction algorithm.");
515                         if (not fTrigRec->OverflowedOutputBuffer()
516                             or (fTrigRec->OverflowedOutputBuffer() and fStopOnOverflow)
517                            )
518                         {
519                                 size = totalSize; // Must tell the framework how much buffer space was used.
520                                 return -EIO;
521                         }
522                 }
523                 
524                 // nofTrigRec should now contain the number of triggers actually found
525                 // and filled into the output data block, so we can set this number.
526                 assert( nofTrigRec <= block.MaxNumberOfEntries() );
527                 block.SetNumberOfEntries(nofTrigRec);
528                 
529                 HLTDebug("Number of trigger records found is %d", nofTrigRec);
530                 
531                 // Fill a block data structure for our output block.
532                 AliHLTComponentBlockData bd;
533                 FillBlockData(bd);
534                 bd.fPtr = outputPtr;
535                 // This block's start (offset) is after all other blocks written so far.
536                 bd.fOffset = totalSize;
537                 bd.fSize = block.BytesUsed();
538                 bd.fDataType = AliHLTMUONConstants::TriggerRecordsBlockDataType();
539                 bd.fSpecification = blocks[n].fSpecification;
540                 outputBlocks.push_back(bd);
541                 
542                 HLTDebug("Created a new output data block at fPtr = %p,"
543                           " with fOffset = %u (0x%.X) and fSize = %u bytes.", 
544                         bd.fPtr, bd.fOffset, bd.fOffset, bd.fSize
545                 );
546                 
547                 // Increase the total amount of data written so far to our output memory.
548                 totalSize += block.BytesUsed();
549         }
550         
551         // Finally we set the total size of output memory we consumed.
552         size = totalSize;
553         return 0;
554 }
555
556
557 int AliHLTMUONTriggerReconstructorComponent::ReadLookUpTable(const char* lutpath)
558 {
559         ///
560         /// Read in the lookup table from file.
561         ///
562         
563         assert(fTrigRec != NULL);
564
565         fstream file;
566         file.open(lutpath, fstream::binary | fstream::in);
567         if (not file)
568         {
569                 HLTError("Could not open file: %s", lutpath);
570                 return -ENOENT;
571         }
572         
573         file.read(reinterpret_cast<char*>(fTrigRec->LookupTableBuffer()), fTrigRec->LookupTableSize());
574         if (file.eof())
575         {
576                 HLTError("The file %s was too short to contain a valid lookup table for this component.", lutpath);
577                 file.close();
578                 return -EIO;
579         }
580         if (file.fail())
581         {
582                 HLTError("Could not read from file: %s", lutpath);
583                 file.close();
584                 return -EIO;
585         }
586         
587         file.close();
588         return 0;
589 }
590
591
592 int AliHLTMUONTriggerReconstructorComponent::ReadCDB(const char* cdbPath, Int_t run)
593 {
594         /// Loads the lookup table containing channel and geometrical position
595         /// information about trigger strips from CDB.
596         /// \param cdbPath  This specifies the CDB path to use to load from.
597         ///                 Can be set to NULL meaning the default storage is used.
598         /// \param run  Specifies the run number to use. If set to -1 then the
599         ///             default / current run number set for the CDB is used.
600         /// \return 0 on success and non zero codes for errors.
601
602         if (fDDL == -1)
603         {
604                 HLTError("No DDL number specified for which to load LUT data from CDB.");
605                 return -EINVAL;
606         }
607
608         int result = FetchMappingStores(cdbPath, run);
609         // Error message already generated in FetchMappingStores.
610         if (result != 0) return result;
611         AliMpDDLStore* ddlStore = AliMpDDLStore::Instance();
612         
613         AliMpSegmentation* segmentation = AliMpSegmentation::Instance();
614         if (segmentation == NULL)
615         {
616                 HLTError("Could not find segmentation mapping (AliMpSegmentation) instance.");
617                 return -EIO;
618         }
619         
620         // Only load geometry if not already loaded.
621         if (AliGeomManager::GetGeometry() == NULL)
622         {
623                 AliGeomManager::LoadGeometry();
624         }
625         AliMUONGeometryTransformer transformer;
626         if (not transformer.LoadGeometryData())
627         {
628                 HLTError("Could not load geometry into transformer.");
629                 return -ENOENT;
630         }
631         
632         AliHLTMUONTriggerRecoLookupTable* lookupTable = fTrigRec->LookupTableBuffer();
633         
634         for (Int_t i = 0; i < 16; i++)
635         for (Int_t j = 0; j < 16; j++)
636         for (Int_t k = 0; k < 4; k++)
637         for (Int_t n = 0; n < 2; n++)
638         for (Int_t m = 0; m < 16; m++)
639         {
640                 lookupTable->fRow[i][j][k][n][m].fIdFlags = 0x0;
641                 lookupTable->fRow[i][j][k][n][m].fX = 0;
642                 lookupTable->fRow[i][j][k][n][m].fY = 0;
643                 lookupTable->fRow[i][j][k][n][m].fZ = 0;
644         }
645         
646         AliMpDEIterator detElemIter;
647         for (Int_t iReg = 0; iReg < 8; iReg++)
648         {
649                 AliMpTriggerCrate* crate = ddlStore->GetTriggerCrate(fDDL, iReg);
650                 if (crate == NULL)
651                 {
652                         HLTError("Could not get crate mapping for regional header = %d"
653                                 " and DDL %d (ID = %d).",
654                                 iReg, fDDL+1, AliHLTMUONUtils::DDLNumberToEquipId(fDDL)
655                         );
656                         continue;
657                 }
658                 // Depending on the value of fUseCrateId, use either the crate ID as would
659                 // be found in the regional header structures or the sequencial index number
660                 // of the structure.
661                 UInt_t crateId = (fUseCrateId ? crate->GetId() : iReg);
662                 if (crateId >= 16)
663                 {
664                         HLTError("The crate ID number (%d) for regional header = %d and"
665                                 " DDL %d (ID = %d) is too big. It should be in the range [0..15]",
666                                 crateId, iReg, fDDL+1, AliHLTMUONUtils::DDLNumberToEquipId(fDDL)
667                         );
668                         continue;
669                 }
670                 
671                 for (Int_t iLocBoard = 0; iLocBoard < 16; iLocBoard++)
672                 {
673                         Int_t boardId = crate->GetLocalBoardId(iLocBoard);
674                         if (boardId == 0) continue;
675                         
676                         AliMpLocalBoard* localBoard = ddlStore->GetLocalBoard(boardId);
677                         if (localBoard == NULL)
678                         {
679                                 HLTError("Could not get local board: %d.", boardId);
680                                 continue;
681                         }
682
683                         // skip copy cards
684                         if (! localBoard->IsNotified()) continue;
685                 
686                         for (Int_t iChamber = 0; iChamber < 4; iChamber++)
687                         {
688                                 Int_t detElemId = ddlStore->GetDEfromLocalBoard(boardId, iChamber);
689                                 
690                                 AliHLTUInt32_t idflags = AliHLTMUONUtils::PackRecHitFlags(iChamber+10, detElemId);
691                                 
692                                 const AliMUONGeometryDetElement* detElemTransform = transformer.GetDetElement(detElemId);
693                                 if (detElemTransform == NULL)
694                                 {
695                                         HLTError("Got NULL pointer for geometry transformer"
696                                                 " for detection element ID = %d.",
697                                                 detElemId
698                                         );
699                                         continue;
700                                 }
701                                 
702                                 for (Int_t iCathode = 0; iCathode <= 1; iCathode++)
703                                 {
704                                         const AliMpVSegmentation* seg = segmentation->GetMpSegmentation(
705                                                         detElemId, AliMp::GetCathodType(iCathode)
706                                                 );
707                                         
708                                         for (Int_t bitxy = 0; bitxy < 16; bitxy++)
709                                         {
710                                                 Int_t offset = 0;
711                                                 if (iCathode && localBoard->GetSwitch(6)) offset = -8;
712                                                 
713                                                 AliMpPad pad = seg->PadByLocation(AliMpIntPair(boardId, bitxy+offset), kFALSE);
714                                         
715                                                 if (! pad.IsValid())
716                                                 {
717                                                         // There is no pad associated with the given local board and bit pattern.
718                                                         continue;
719                                                 }
720                                                 
721                                                 // Get the global coodinates of the pad.
722                                                 Float_t lx = pad.Position().X();
723                                                 Float_t ly = pad.Position().Y();
724                                                 Float_t gx, gy, gz;
725                                                 detElemTransform->Local2Global(lx, ly, 0, gx, gy, gz);
726                                                 
727                                                 // Fill the LUT
728                                                 lookupTable->fRow[crateId][iLocBoard][iChamber][iCathode][bitxy].fIdFlags = idflags;
729                                                 lookupTable->fRow[crateId][iLocBoard][iChamber][iCathode][bitxy].fX = gx;
730                                                 lookupTable->fRow[crateId][iLocBoard][iChamber][iCathode][bitxy].fY = gy;
731                                                 lookupTable->fRow[crateId][iLocBoard][iChamber][iCathode][bitxy].fZ = gz;
732                                         }
733                                 }
734                         }
735                 }
736         }
737         
738         return 0;
739 }
740
741
742 bool AliHLTMUONTriggerReconstructorComponent::GenerateLookupTable(
743                 AliHLTInt32_t ddl, const char* filename,
744                 const char* cdbPath, Int_t run
745                 //TODO add option fCrateId
746         )
747 {
748         /// Generates a binary file containing the lookup table (LUT) from the
749         /// CDB, which can be used for the trigger reconstructor component later.
750         /// @param ddl  Must be the DDL for which to generate the DDL,
751         ///             in the range [20..21].
752         /// @param filename  The name of the LUT file to generate.
753         /// @param cdbPath  The CDB path to use.
754         /// @param run  The run number to use for the CDB.
755         /// @return  True if the generation of the LUT file succeeded.
756         
757         AliHLTMUONTriggerReconstructorComponent comp;
758         
759         if (ddl < 20 or 21 < ddl)
760         {
761                 std::cerr << "ERROR: the DDL number must be in the range [20..21]." << std::endl;
762                 return false;
763         }
764         
765         char ddlNum[32];
766         char runNum[32];
767         sprintf(ddlNum, "%d", ddl+1);
768         sprintf(runNum, "%d", run);
769         const char* argv[7] = {"-ddl", ddlNum, "-cdbpath", cdbPath, "-run", runNum, NULL};
770         int result = comp.DoInit(6, argv);
771         if (result != 0)
772         {
773                 // Error message already generated in DoInit.
774                 return false;
775         }
776         
777         std::fstream file(filename, std::ios::out);
778         if (not file)
779         {
780                 std::cerr << "ERROR: could not open file: " << filename << std::endl;
781                 return false;
782         }
783         
784         file.write(
785                         reinterpret_cast<char*>(comp.fTrigRec->LookupTableBuffer()),
786                         comp.fTrigRec->LookupTableSize()
787                 );
788         if (not file)
789         {
790                 std::cerr << "ERROR: There was a problem writing to the file: " << filename << std::endl;
791                 return false;
792         }
793         file.close();
794         
795         comp.DoDeinit();
796         
797         return true;
798 }