Implemented a new version of cluster (with its store and iterator):
[u/mrichter/AliRoot.git] / HLT / MUON / OfflineInterface / AliHLTMUONRecHitsSource.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        * 
3  * All rights reserved.                                                   *
4  *                                                                        *
5  * Primary Authors:                                                       *
6  *   Artur Szostak <artursz@iafrica.com>                                  *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          * 
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /* $Id$ */
18
19 /**
20  * @file   AliHLTMUONRecHitsSource.cxx
21  * @author Artur Szostak <artursz@iafrica.com>
22  * @date   
23  * @brief  Implementation of the AliHLTMUONRecHitsSource component.
24  */
25
26 #include "AliHLTMUONRecHitsSource.h"
27 #include "AliHLTMUONConstants.h"
28 #include "AliHLTMUONUtils.h"
29 #include "AliHLTMUONDataBlockWriter.h"
30 #include "AliMUONMCDataInterface.h"
31 #include "AliMUONDataInterface.h"
32 #include "AliMUONHit.h"
33 #include "AliMUONVCluster.h"
34 #include "AliMUONConstants.h"
35 #include "AliMUONVClusterStore.h"
36 #include "AliMUONVHitStore.h"
37 #include "mapping/AliMpCDB.h"
38 #include "mapping/AliMpDEManager.h"
39 #include "mapping/AliMpDetElement.h"
40 #include "TClonesArray.h"
41 #include <cstdlib>
42 #include <cstdio>
43 #include <cerrno>
44 #include <cassert>
45 #include <new>
46
47 namespace
48 {
49         // The global object used for automatic component registration.
50         // Note DO NOT use this component for calculation!
51         AliHLTMUONRecHitsSource gAliHLTMUONRecHitsSource;
52 }
53
54
55 ClassImp(AliHLTMUONRecHitsSource);
56
57
58 AliHLTMUONRecHitsSource::AliHLTMUONRecHitsSource() :
59         AliHLTOfflineDataSource(),
60         fMCDataInterface(NULL),
61         fDataInterface(NULL),
62         fSelection(kWholePlane),
63         fCurrentEvent(0)
64 {
65         for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++)
66                 fServeChamber[i] = false;
67 }
68
69
70 AliHLTMUONRecHitsSource::~AliHLTMUONRecHitsSource()
71 {
72         assert( fMCDataInterface == NULL );
73         assert( fDataInterface == NULL );
74 }
75
76
77 int AliHLTMUONRecHitsSource::DoInit(int argc, const char** argv)
78 {
79         assert( fMCDataInterface == NULL );
80         assert( fDataInterface == NULL );
81         
82         // Parse the command line arguments:
83         bool simdata = false;
84         bool recdata = false;
85         bool chamberWasSet = false;
86         fCurrentEvent = 0;
87         bool firstEventSet = false;
88         bool eventNumLitSet = false;
89         
90         for (int i = 0; i < argc; i++)
91         {
92                 if (strcmp(argv[i], "-simdata") == 0)
93                 {
94                         simdata = true;
95                 }
96                 else if (strcmp(argv[i], "-recdata") == 0)
97                 {
98                         recdata = true;
99                 }
100                 else if (strcmp(argv[i], "-plane") == 0)
101                 {
102                         i++;
103                         if (i >= argc)
104                         {
105                                 Logging(kHLTLogError,
106                                         "AliHLTMUONRecHitsSource::DoInit",
107                                         "Missing parameter",
108                                         "Expected one of 'left', 'right' or 'all' after '-plane'."
109                                 );
110                                 return EINVAL;
111                         }
112                         if (strcmp(argv[i], "left") == 0)
113                                 fSelection = kLeftPlane;
114                         else if (strcmp(argv[i], "right") == 0)
115                                 fSelection = kRightPlane;
116                         else if (strcmp(argv[i], "all") == 0)
117                                 fSelection = kWholePlane;
118                         else
119                         {
120                                 Logging(kHLTLogError,
121                                         "AliHLTMUONRecHitsSource::DoInit",
122                                         "Invalid parameter",
123                                         "The parameter '%s' is invalid and must be one of 'left',"
124                                           " 'right' or 'all'.",
125                                         argv[i]
126                                 );
127                                 return EINVAL;
128                         }
129                 }
130                 else if (strcmp(argv[i], "-chamber") == 0)
131                 {
132                         i++;
133                         if (i >= argc)
134                         {
135                                 Logging(kHLTLogError,
136                                         "AliHLTMUONRecHitsSource::DoInit",
137                                         "Missing parameter",
138                                         "Expected a chamber number, range eg. '1-10' or list eg."
139                                           " '1,2,3' after '-chamber'."
140                                 );
141                                 return EINVAL;
142                         }
143                         int result = ParseChamberString(argv[i]);
144                         if (result != 0) return result;
145                         chamberWasSet = true;
146                 }
147                 else if (strcmp(argv[i], "-firstevent") == 0)
148                 {
149                         if (eventNumLitSet)
150                         {
151                                 HLTWarning("The -firstevent flag is overridden by a"
152                                         " previous use of -event_number_literal."
153                                 );
154                         }
155                         i++;
156                         if (i >= argc)
157                         {
158                                 HLTError("Expected a positive number after -firstevent.");
159                                 return EINVAL;
160                         }
161                         char* end = "";
162                         long num = strtol(argv[i], &end, 0);
163                         if (*end != '\0' or num < 0) // Check if the conversion is OK.
164                         {
165                                 HLTError(Form(
166                                         "Expected a positive number after -firstevent"
167                                         " but got: %s", argv[i]
168                                 ));
169                                 return EINVAL;
170                         }
171                         fCurrentEvent = Int_t(num);
172                         firstEventSet = true;
173                 }
174                 else if (strcmp(argv[i], "-event_number_literal") == 0)
175                 {
176                         if (firstEventSet)
177                         {
178                                 HLTWarning("The -event_number_literal option will"
179                                         " override -firstevent."
180                                 );
181                         }
182                         fCurrentEvent = -1;
183                         eventNumLitSet = true;
184                 }
185                 else
186                 {
187                         Logging(kHLTLogError,
188                                 "AliHLTMUONRecHitsSource::DoInit",
189                                 "Unknown argument",
190                                 "The argument '%s' is invalid.",
191                                 argv[i]
192                         );
193                         return EINVAL;
194                 }
195         }
196
197         // Check the parameters we have parsed.
198         if (simdata and recdata)
199         {
200                 Logging(kHLTLogError,
201                         "AliHLTMUONRecHitsSource::DoInit",
202                         "Invalid arguments",
203                         "Cannot have both -simdata and -recdata set."
204                 );
205                 return EINVAL;
206         }
207         
208         if (not simdata and not recdata)
209         {
210                 Logging(kHLTLogError,
211                         "AliHLTMUONRecHitsSource::DoInit",
212                         "Missing arguments",
213                         "Must have either -simdata or -recdata specified."
214                 );
215                 return EINVAL;
216         }
217         
218         if (not chamberWasSet)
219         {
220                 Logging(kHLTLogInfo,
221                         "AliHLTMUONRecHitsSource::DoInit",
222                         "Setting Parameters",
223                         "No chambers were selected so we will publish for all chambers."
224                 );
225                 for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++)
226                         fServeChamber[i] = true;
227         }
228         
229         // Must load the mapping data for AliMpDetElement::GetDdlId()
230         // to return useful information later on.
231         AliMpCDB::LoadDDLStore();
232                 
233         // Now we can initialise the data interface objects and loaders.
234         if (simdata)
235         {
236                 Logging(kHLTLogDebug,
237                         "AliHLTMUONRecHitsSource::DoInit",
238                         "Data interface",
239                         "Loading simulated GEANT hits with AliMUONMCDataInterface."
240                 );
241
242                 try
243                 {
244                         fMCDataInterface = new AliMUONMCDataInterface("galice.root");
245                 }
246                 catch (const std::bad_alloc&)
247                 {
248                         Logging(kHLTLogError,
249                                 "AliHLTMUONRecHitsSource::DoInit",
250                                 "Out of memory",
251                                 "Not enough memory to allocate AliMUONMCDataInterface."
252                         );
253                         return ENOMEM;
254                 }
255         }
256         else if (recdata)
257         {
258                 Logging(kHLTLogDebug,
259                         "AliHLTMUONRecHitsSource::DoInit",
260                         "Data interface",
261                         "Loading reconstructed clusters with AliMUONDataInterface."
262                 );
263                 
264                 try
265                 {
266                         fDataInterface = new AliMUONDataInterface("galice.root");
267                 }
268                 catch (const std::bad_alloc&)
269                 {
270                         Logging(kHLTLogError,
271                                 "AliHLTMUONRecHitsSource::DoInit",
272                                 "Out of memory",
273                                 "Not enough memory to allocate AliMUONDataInterface."
274                         );
275                         return ENOMEM;
276                 }
277         }
278         
279         // Check that the fCurrentEvent number falls within the correct range.
280         UInt_t maxevent = 0;
281         if (fMCDataInterface != NULL)
282                 maxevent = UInt_t(fMCDataInterface->NumberOfEvents());
283         else if (fDataInterface != NULL)
284                 maxevent = UInt_t(fDataInterface->NumberOfEvents());
285         if (fCurrentEvent != -1 and UInt_t(fCurrentEvent) >= maxevent and maxevent != 0)
286         {
287                 fCurrentEvent = 0;
288                 HLTWarning(Form("The selected first event number (%d) was larger than"
289                         " the available number of events (%d). Resetting the event"
290                         " counter to zero.", fCurrentEvent, maxevent
291                 ));
292         }
293         
294         return 0;
295 }
296
297
298 int AliHLTMUONRecHitsSource::DoDeinit()
299 {
300         if (fMCDataInterface != NULL)
301         {
302                 delete fMCDataInterface;
303                 fMCDataInterface = NULL;
304         }
305         if (fDataInterface != NULL)
306         {
307                 delete fDataInterface;
308                 fDataInterface = NULL;
309         }
310         return 0;
311 }
312
313
314 const char* AliHLTMUONRecHitsSource::GetComponentID()
315 {
316         return AliHLTMUONConstants::RecHitsSourceId();
317 }
318
319
320 AliHLTComponentDataType AliHLTMUONRecHitsSource::GetOutputDataType()
321 {
322         return AliHLTMUONConstants::RecHitsBlockDataType();
323 }
324
325
326 void AliHLTMUONRecHitsSource::GetOutputDataSize(
327                 unsigned long& constBase, double& inputMultiplier
328         )
329 {
330         constBase = sizeof(AliHLTMUONRecHitsBlockStruct)
331                 + 256*16*sizeof(AliHLTMUONRecHitStruct);
332         inputMultiplier = 0;
333 }
334
335
336 AliHLTComponent* AliHLTMUONRecHitsSource::Spawn()
337 {
338         return new AliHLTMUONRecHitsSource();
339 }
340
341
342 int AliHLTMUONRecHitsSource::GetEvent(
343                 const AliHLTComponentEventData& evtData,
344                 AliHLTComponentTriggerData& /*trigData*/,
345                 AliHLTUInt8_t* outputPtr, 
346                 AliHLTUInt32_t& size,
347                 vector<AliHLTComponentBlockData>& outputBlocks
348         )
349 {
350         assert( fMCDataInterface != NULL or fDataInterface != NULL );
351
352         // Check the size of the event descriptor structure.
353         if (evtData.fStructSize < sizeof(AliHLTComponentEventData))
354         {
355                 Logging(kHLTLogError,
356                         "AliHLTMUONRecHitsSource::GetEvent",
357                         "Invalid event descriptor",
358                         "The event descriptor (AliHLTComponentEventData) size is"
359                           " smaller than expected. It claims to be %d bytes, but"
360                           " we expect it to be %d bytes.",
361                         evtData.fStructSize,
362                         sizeof(AliHLTComponentEventData)
363                 );
364                 size = 0; // Important to tell framework that nothing was generated.
365                 return EINVAL;
366         }
367         
368         // Use the fEventID as the event number to load if fCurrentEvent == -1,
369         // check it and load that event with the runloader.
370         // If fCurrentEvent is a positive number then us it instead and
371         // increment it.
372         UInt_t eventnumber = UInt_t(evtData.fEventID);
373         UInt_t maxevent = fMCDataInterface != NULL ?
374                 UInt_t(fMCDataInterface->NumberOfEvents())
375                 : UInt_t(fDataInterface->NumberOfEvents());
376         if (fCurrentEvent != -1)
377         {
378                 eventnumber = UInt_t(fCurrentEvent);
379                 fCurrentEvent++;
380                 if (UInt_t(fCurrentEvent) >= maxevent)
381                         fCurrentEvent = 0;
382         }
383         if ( eventnumber >= maxevent )
384         {
385                 Logging(kHLTLogError,
386                         "AliHLTMUONRecHitsSource::GetEvent",
387                         "Bad event ID",
388                         "The event number (%d) is larger than the available number"
389                           " of events on file (%d).",
390                         eventnumber,
391                         maxevent
392                 );
393                 size = 0; // Important to tell framework that nothing was generated.
394                 return EINVAL;
395         }
396         
397         // Create and initialise a new data block.
398         AliHLTMUONRecHitsBlockWriter block(outputPtr, size);
399         if (not block.InitCommonHeader())
400         {
401                 Logging(kHLTLogError,
402                         "AliHLTMUONRecHitsSource::GetEvent",
403                         "Buffer too small",
404                         "There is not enough buffer space to create a new data block."
405                           " We require at least %d bytes but the buffer is only %d bytes.",
406                         sizeof(AliHLTMUONRecHitsBlockWriter::HeaderType),
407                         block.BufferSize()
408                 );
409                 size = 0; // Important to tell framework that nothing was generated.
410                 return ENOBUFS;
411         }
412         
413         // Initialise the DDL list containing the DDLs which contributed to the
414         // data block. These are required to create the specification word later.
415         bool ddlList[22];
416         for (Int_t i = 0; i < 22; i++)
417                 ddlList[i] = false;
418         
419         if (fMCDataInterface != NULL)
420         {
421                 Logging(kHLTLogDebug,
422                         "AliHLTMUONRecHitsSource::GetEvent",
423                         "Filling hits",
424                         "Filling data block with GEANT hits for event %d.",
425                         eventnumber
426                 );
427                 
428                 // Loop over all tracks, extract the hits and write them to the
429                 // data block.
430                 Int_t ntracks = fMCDataInterface->NumberOfTracks(eventnumber);
431                 for (Int_t i = 0; i < ntracks; ++i)
432                 {
433                         AliMUONVHitStore* hitStore = fMCDataInterface->HitStore(eventnumber,i);
434                         AliMUONHit* hit;
435                         TIter next(hitStore->CreateIterator());
436                         while ( ( hit = static_cast<AliMUONHit*>(next()) ) )
437                         {
438                                 // Select only hits on selected chambers.
439                                 Int_t chamber = hit->Chamber() - 1;
440                                 if (chamber > AliMUONConstants::NTrackingCh()) continue;
441                                 if (not fServeChamber[chamber]) continue;
442                                 
443                                 // Only select hits from the given part of the plane
444                                 if (fSelection == kLeftPlane and not (hit->Xref() < 0)) continue;
445                                 if (fSelection == kRightPlane and not (hit->Xref() >= 0)) continue;
446                                 
447                                 AliHLTMUONRecHitStruct* rechit = block.AddEntry();
448                                 if (rechit == NULL)
449                                 {
450                                         Logging(kHLTLogError,
451                                                 "AliHLTMUONRecHitsSource::GetEvent",
452                                                 "Buffer overflow",
453                                                 "There is not enough buffer space to add more hits."
454                                                   " We overflowed the buffer which is only %d bytes.",
455                                                 block.BufferSize()
456                                         );
457                                         size = 0; // Important to tell framework that nothing was generated.
458                                         return ENOBUFS;
459                                 }
460                                 
461                                 rechit->fX = hit->Xref();
462                                 rechit->fY = hit->Yref();
463                                 rechit->fZ = hit->Zref();
464                                 
465                                 // Workout which DDL this hit will be readout of.
466                                 AliMpDetElement* de = AliMpDEManager::GetDetElement(hit->DetElemId());
467                                 if (de != NULL and (0 <= de->GetDdlId() and de->GetDdlId() < 22))
468                                         ddlList[de->GetDdlId()] = true;
469                                 else
470                                         Logging(kHLTLogError,
471                                                 "AliHLTMUONRecHitsSource::GetEvent",
472                                                 "No DDL ID",
473                                                 "Could not find the DDL ID from which readout would take place."
474                                         );
475                         }
476                 }
477         }
478         else if (fDataInterface != NULL)
479         {
480                 Logging(kHLTLogDebug,
481                         "AliHLTMUONRecHitsSource::GetEvent",
482                         "Filling hits",
483                         "Filling data block with reconstructed raw clusters for event %d.",
484                         eventnumber
485                 );
486                 
487                 AliMUONVClusterStore* clusterStore = fDataInterface->ClusterStore(eventnumber);
488     
489                 // Loop over selected chambers and extract the raw clusters.
490                 for (Int_t chamber = 0; chamber < AliMUONConstants::NTrackingCh(); chamber++)
491                 {
492                         // Select only hits on selected chambers.
493                         if (not fServeChamber[chamber]) continue;
494                         
495                         TIter next(clusterStore->CreateChamberIterator(chamber,chamber));
496                         AliMUONVCluster* cluster;
497                         while ( ( cluster = static_cast<AliMUONVCluster*>(next()) ) )
498                         {
499                                 // Only select hits from the given part of the plane
500                                 if (fSelection == kLeftPlane and not (cluster->GetX() < 0)) continue;
501                                 if (fSelection == kRightPlane and not (cluster->GetX() >= 0)) continue;
502                         
503                                 AliHLTMUONRecHitStruct* rechit = block.AddEntry();
504                                 if (rechit == NULL)
505                                 {
506                                         Logging(kHLTLogError,
507                                                 "AliHLTMUONRecHitsSource::GetEvent",
508                                                 "Buffer overflow",
509                                                 "There is not enough buffer space to add more hits."
510                                                   " We overflowed the buffer which is only %d bytes.",
511                                                 block.BufferSize()
512                                         );
513                                         size = 0; // Important to tell framework that nothing was generated.
514                                         return ENOBUFS;
515                                 }
516                                 
517                                 rechit->fX = cluster->GetX();
518                                 rechit->fY = cluster->GetY();
519                                 rechit->fZ = cluster->GetZ();
520                                 
521                                 // Workout which DDL this hit will be readout of.
522                                 AliMpDetElement* de = AliMpDEManager::GetDetElement(cluster->GetDetElemId());
523                                 if (de != NULL and (0 <= de->GetDdlId() and de->GetDdlId() < 22))
524                                         ddlList[de->GetDdlId()] = true;
525                                 else
526                                         Logging(kHLTLogError,
527                                                 "AliHLTMUONRecHitsSource::GetEvent",
528                                                 "No DDL ID",
529                                                 "Could not find the DDL ID from which readout would take place."
530                                         );
531                         }
532                 }
533         }
534         else
535         {
536                 Logging(kHLTLogError,
537                         "AliHLTMUONRecHitsSource::GetEvent",
538                         "Missing data interface",
539                         "Neither AliMUONDataInterface nor AliMUONMCDataInterface were created."
540                 );
541                 size = 0; // Important to tell framework that nothing was generated.
542                 return EFAULT;
543         }
544         
545         AliHLTComponentBlockData bd;
546         FillBlockData(bd);
547         bd.fPtr = outputPtr;
548         bd.fOffset = 0;
549         bd.fSize = block.BytesUsed();
550         bd.fDataType = AliHLTMUONConstants::RecHitsBlockDataType();
551         bd.fSpecification = AliHLTMUONUtils::PackSpecBits(ddlList);
552         outputBlocks.push_back(bd);
553         size = block.BytesUsed();
554
555         return 0;
556 }
557
558
559 int AliHLTMUONRecHitsSource::ParseChamberString(const char* str)
560 {
561         char* end = const_cast<char*>(str);
562         long lastChamber = -1;
563         do
564         {
565                 // Parse the next number.
566                 char* current = end;
567                 long chamber = strtol(current, &end, 0);
568                 
569                 // Check for parse errors of the number.
570                 if (current == end)
571                 {
572                         Logging(kHLTLogError,
573                                 "AliHLTMUONRecHitsSource::GetEvent",
574                                 "Parse error",
575                                 "Expected a number in the range [1..%d] but got '%s'.",
576                                 AliMUONConstants::NTrackingCh(), current
577                         );
578                         return EINVAL;
579                 }
580                 if (chamber < 1 or AliMUONConstants::NTrackingCh() < chamber)
581                 {
582                         Logging(kHLTLogError,
583                                 "AliHLTMUONRecHitsSource::GetEvent",
584                                 "Parse error",
585                                 "Got the chamber number %d which is outside the valid range of [1..%d].",
586                                 chamber, AliMUONConstants::NTrackingCh()
587                         );
588                         return EINVAL;
589                 }
590                 
591                 // Skip any whitespace after the number
592                 while (*end != '\0' and (*end == ' ' or *end == '\t' or *end == '\r' or *end == '\n')) end++;
593                 
594                 // Check if we are dealing with a list or range, or if we are at
595                 // the end of the string.
596                 if (*end == '-')
597                 {
598                         lastChamber = chamber;
599                         end++;
600                         continue;
601                 }
602                 else if (*end == ',')
603                 {
604                         assert( 1 <= chamber and chamber <= 10 );
605                         fServeChamber[chamber-1] = true;
606                         end++;
607                 }
608                 else if (*end == '\0')
609                 {
610                         assert( 1 <= chamber and chamber <= 10 );
611                         fServeChamber[chamber-1] = true;
612                 }
613                 else
614                 {
615                         Logging(kHLTLogError,
616                                 "AliHLTMUONRecHitsSource::GetEvent",
617                                 "Parse error",
618                                 "Could not understand parameter list '%s'. Expected '-', ','"
619                                   " or end of line but got '%c' at character %d.",
620                                 str, *end, (int)(end - str) +1
621                         );
622                         return EINVAL;
623                 }
624                 
625                 // Set the range of chambers to publish for.
626                 if (lastChamber > 0)
627                 {
628                         Int_t min, max;
629                         if (lastChamber < chamber)
630                         {
631                                 min = lastChamber;
632                                 max = chamber;
633                         }
634                         else
635                         {
636                                 min = chamber;
637                                 max = lastChamber;
638                         }
639                         assert( min >= 1 );
640                         assert( max <= 10 );
641                         for (Int_t i = min; i <= max; i++)
642                                 fServeChamber[i-1] = true;
643                 }
644                 lastChamber = -1;
645         }
646         while (*end != '\0');
647         return 0;
648 }