Improving documentation and macros.
[u/mrichter/AliRoot.git] / HLT / MUON / OfflineInterface / AliHLTMUONRootifierComponent.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   AliHLTMUONRootifierComponent.cxx
21 /// @author Artur Szostak <artursz@iafrica.com>
22 /// @date   29 Sep 2007
23 /// @brief  Implementation of the AliHLTMUONRootifierComponent component.
24 ///
25 /// Implements a component to convert dHLT raw data into TObjects.
26
27 #include "AliHLTMUONRootifierComponent.h"
28 #include "AliHLTMUONEvent.h"
29 #include "AliHLTMUONConstants.h"
30 #include "AliHLTMUONUtils.h"
31 #include "AliHLTMUONRecHit.h"
32 #include "AliHLTMUONTriggerRecord.h"
33 #include "AliHLTMUONMansoTrack.h"
34 #include "AliHLTMUONDecision.h"
35 #include "TClonesArray.h"
36 #include <cassert>
37
38 ClassImp(AliHLTMUONRootifierComponent);
39
40
41 AliHLTMUONRootifierComponent::AliHLTMUONRootifierComponent() :
42         AliHLTMUONProcessor(),
43         fWarnForUnexpecedBlock(false)
44 {
45         ///
46         /// Default constructor.
47         ///
48 }
49
50
51 AliHLTMUONRootifierComponent::~AliHLTMUONRootifierComponent()
52 {
53         ///
54         /// Default destructor.
55         ///
56 }
57
58
59 bool AliHLTMUONRootifierComponent::IgnoreArgument(const char* arg) const
60 {
61         /// Return true if the argument is one of -cdbpath -run or -delaysetup
62         /// to prevent the parent class from parsing these arguments in DoInit.
63         
64         if (strcmp(arg, "-cdbpath") == 0 or strcmp(arg, "-run") == 0 or
65             strcmp(arg, "-delaysetup") == 0)
66         {
67                 return true;
68         }
69         else
70         {
71                 return false;
72         }
73 }
74
75
76 int AliHLTMUONRootifierComponent::DoInit(int argc, const char** argv)
77 {
78         ///
79         /// Inherited from AliHLTComponent.
80         /// Parses the command line parameters and initialises the component.
81         ///
82         
83         HLTInfo("Initialising dHLT rootifier component.");
84
85         // Inherit the parents functionality.
86         int result = AliHLTMUONProcessor::DoInit(argc, argv);
87         if (result != 0) return result;
88         
89         fWarnForUnexpecedBlock = false;
90         
91         for (int i = 0; i < argc; i++)
92         {
93                 if (ArgumentAlreadyHandled(i, argv[i])) continue;
94
95                 if (strcmp(argv[i], "-warn_on_unexpected_block") == 0)
96                 {
97                         fWarnForUnexpecedBlock = true;
98                         continue;
99                 }
100
101                 HLTError("Unknown option '%s'.", argv[i]);
102                 return -EINVAL;
103         }
104         
105         return 0;
106 }
107
108
109 int AliHLTMUONRootifierComponent::DoDeinit()
110 {
111         ///
112         /// Inherited from AliHLTComponent. Performs a cleanup of the component.
113         ///
114         
115         HLTInfo("Deinitialising dHLT rootifier component.");
116         return 0;
117 }
118
119
120 const char* AliHLTMUONRootifierComponent::GetComponentID()
121 {
122         ///
123         /// Inherited from AliHLTComponent. Returns the component ID.
124         ///
125         
126         return AliHLTMUONConstants::RootifierComponentId();
127 }
128
129
130 AliHLTComponentDataType AliHLTMUONRootifierComponent::GetOutputDataType()
131 {
132         /// Inherited from AliHLTComponent. Returns kAliHLTMultipleDataType
133         /// refer to GetOutputDataTypes for all returned data types.
134         
135         return kAliHLTMultipleDataType;
136 }
137
138
139 int AliHLTMUONRootifierComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& tgtList)
140 {
141         /// Inherited from AliHLTComponent. Returns the output data types.
142         
143         tgtList.push_back(AliHLTMUONConstants::RootifiedEventDataType());
144         return tgtList.size();
145 }
146
147
148 void AliHLTMUONRootifierComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
149 {
150         ///
151         /// Inherited from AliHLTProcessor. Returns the list of expected input data types.
152         ///
153         
154         list.push_back(kAliHLTAnyDataType);
155 }
156
157
158 void AliHLTMUONRootifierComponent::GetOutputDataSize(
159                 unsigned long& constBase, double& inputMultiplier
160         )
161 {
162         ///
163         /// Inherited from AliHLTComponent. Returns an estimate of the expected output data size.
164         ///
165         
166         constBase = 1024*1024;
167         inputMultiplier = 100;
168 }
169
170
171 AliHLTComponent* AliHLTMUONRootifierComponent::Spawn()
172 {
173         ///
174         /// Inherited from AliHLTComponent. Creates a new object instance.
175         ///
176         
177         return new AliHLTMUONRootifierComponent();
178 }
179
180
181 int AliHLTMUONRootifierComponent::DoEvent(
182                 const AliHLTComponentEventData& evtData,
183                 AliHLTComponentTriggerData& trigData
184         )
185 {
186         ///
187         /// Inherited from AliHLTProcessor. Processes the new event data.
188         ///
189         
190         if (not IsDataEvent()) return 0;
191         
192         AliHLTMUONEvent event(evtData.fEventID);
193         const AliHLTComponentBlockData* block = NULL;
194         AliHLTUInt32_t specification = 0;  // Contains the output data block spec bits.
195
196         // First process the blocks of reconstructed hits and trigger records.
197         for (int i = 0; i < GetNumberOfInputBlocks(); i++)
198         {
199                 block = GetInputBlock(i);
200                 assert( block != NULL );
201                 
202                 HLTDebug("Handling block: %u, with fDataType = '%s', fPtr = %p and fSize = %u bytes.",
203                         i, DataType2Text(block->fDataType).c_str(), block->fPtr, block->fSize
204                 );
205                 
206                 if (block->fDataType == AliHLTMUONConstants::RecHitsBlockDataType())
207                 {
208                         specification |= block->fSpecification;
209                         AliHLTMUONRecHitsBlockReader inblock(block->fPtr, block->fSize);
210                         if (not BlockStructureOk(inblock))
211                         {
212                                 if (DumpDataOnError()) DumpEvent(evtData, trigData);
213                                 continue;
214                         }
215                         
216                         // Decode the source DDL from the specification bits.
217                         Int_t sourceDDL = -1;
218                         bool ddl[22];
219                         AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
220                         for (int k = 0; k < 22; k++)
221                         {
222                                 if (ddl[k])
223                                 {
224                                         if (sourceDDL == -1)
225                                         {
226                                                 sourceDDL = k+1;
227                                         }
228                                         else
229                                         {
230                                                 HLTWarning("The input data block %d contains"
231                                                         " data from multiple DDL sources.", i
232                                                 );
233                                         }
234                                 }
235                         }
236                         if (sourceDDL > 20)
237                         {
238                                 HLTWarning("The source DDL for input data block %d is %d."
239                                         " The expected range for the DDL is [1..20].",
240                                         i, sourceDDL
241                                 );
242                         }
243                         
244                         for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
245                         {
246                                 const AliHLTMUONRecHitStruct& h = inblock[n];
247                                 AliHLTUInt8_t chamber;
248                                 AliHLTUInt16_t detElemId;
249                                 AliHLTMUONUtils::UnpackRecHitFlags(h.fFlags, chamber, detElemId);
250                                 event.Add(new AliHLTMUONRecHit(h.fX, h.fY, h.fZ, sourceDDL, detElemId));
251                         }
252                 }
253                 else if (block->fDataType == AliHLTMUONConstants::TriggerRecordsBlockDataType())
254                 {
255                         specification |= block->fSpecification;
256                         AliHLTMUONTriggerRecordsBlockReader inblock(block->fPtr, block->fSize);
257                         if (not BlockStructureOk(inblock))
258                         {
259                                 if (DumpDataOnError()) DumpEvent(evtData, trigData);
260                                 continue;
261                         }
262                         
263                         // Decode the source DDL from the specification bits.
264                         Int_t sourceDDL = -1;
265                         bool ddl[22];
266                         AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
267                         for (int k = 0; k < 22; k++)
268                         {
269                                 if (ddl[k])
270                                 {
271                                         if (sourceDDL == -1)
272                                         {
273                                                 sourceDDL = k+1;
274                                         }
275                                         else
276                                         {
277                                                 HLTWarning("The input data block %d contains"
278                                                         " data from multiple DDL sources.", i
279                                                 );
280                                         }
281                                 }
282                         }
283                         if (sourceDDL != -1 and (sourceDDL < 21 or sourceDDL > 22))
284                         {
285                                 HLTWarning("The source DDL for input data block %d is %d."
286                                         " The expected range for the DDL is [21..22].",
287                                         i, sourceDDL
288                                 );
289                         }
290                         
291                         for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
292                         {
293                                 const AliHLTMUONTriggerRecordStruct& t = inblock[n];
294                                 
295                                 AliHLTMUONParticleSign sign;
296                                 bool hitset[4];
297                                 AliHLTMUONUtils::UnpackTriggerRecordFlags(
298                                                 t.fFlags, sign, hitset
299                                         );
300                         
301                                 AliHLTMUONTriggerRecord* tr = new AliHLTMUONTriggerRecord(
302                                                 t.fId, sign, t.fPx, t.fPy, t.fPz, sourceDDL
303                                         );
304                                 for (int k = 0; k < 4; k++)
305                                         tr->SetHit(k+11, t.fHit[k].fX, t.fHit[k].fY, t.fHit[k].fZ);
306                                 event.Add(tr);
307                         }
308                 }
309                 else
310                 {
311                         if (block->fDataType != AliHLTMUONConstants::MansoTracksBlockDataType() and
312                             block->fDataType != AliHLTMUONConstants::SinglesDecisionBlockDataType() and
313                             block->fDataType != AliHLTMUONConstants::PairsDecisionBlockDataType()
314                            )
315                         {
316                                 // Log a message indicating that we got a data block that we
317                                 // do not know how to handle.
318                                 if (fWarnForUnexpecedBlock)
319                                         HLTWarning("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
320                                                 DataType2Text(block->fDataType).c_str(), block->fSpecification
321                                         );
322 #ifdef __DEBUG
323                                 else
324                                         HLTDebug("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
325                                                 DataType2Text(block->fDataType).c_str(), block->fSpecification
326                                         );
327 #endif
328                         }
329                 }
330         }
331         
332         // We need to check if there are any cluster data blocks and add their
333         // information to the AliHLTMUONRecHit objects.
334         for (block = GetFirstInputBlock(AliHLTMUONConstants::ClusterBlockDataType());
335              block != NULL;
336              block = GetNextInputBlock()
337             )
338         {
339                 specification |= block->fSpecification;
340                 AliHLTMUONClustersBlockReader inblock(block->fPtr, block->fSize);
341                 if (not BlockStructureOk(inblock))
342                 {
343                         if (DumpDataOnError()) DumpEvent(evtData, trigData);
344                         continue;
345                 }
346                 
347                 for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
348                 {
349                         const AliHLTMUONClusterStruct& clust = inblock[n];
350                         
351                         AliHLTUInt8_t chamber;
352                         AliHLTUInt16_t detElemId;
353                         AliHLTMUONUtils::UnpackRecHitFlags(clust.fHit.fFlags, chamber, detElemId);
354                         if (clust.fDetElemId != detElemId)
355                         {
356                                 HLTWarning("Found a cluster with a different detector element ID (%d)"
357                                         " from its corresponding hit (x,y,z = %f,%f,%f and detElemId = %d).",
358                                         clust.fDetElemId,
359                                         clust.fHit.fX, clust.fHit.fY, clust.fHit.fZ,
360                                         detElemId
361                                 );
362                         }
363                         
364                         // Try find the corresponding reconstructed hit in 'event'.
365                         AliHLTMUONRecHit* hit = NULL;
366                         for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
367                         {
368                                 if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
369                                         continue;
370                                 AliHLTMUONRecHit* h = static_cast<AliHLTMUONRecHit*>(event.Array()[k]);
371                                 if (h->DetElemId() == detElemId and h->X() == clust.fHit.fX
372                                     and h->Y() == clust.fHit.fY and h->Z() == clust.fHit.fZ)
373                                 {
374                                         hit = h;
375                                         break;
376                                 }
377                         }
378                         
379                         // If we could not find the corresponding hit then we need to create
380                         // a new hit object, otherwise we can just append the information.
381                         if (hit == NULL)
382                         {
383                                 // Decode the source DDL from the specification bits.
384                                 Int_t sourceDDL = -1;
385                                 bool ddl[22];
386                                 AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
387                                 for (int k = 0; k < 22; k++)
388                                 {
389                                         if (ddl[k])
390                                         {
391                                                 if (sourceDDL == -1)
392                                                 {
393                                                         sourceDDL = k+1;
394                                                 }
395                                                 else
396                                                 {
397                                                         HLTWarning("An input block of cluster data contains"
398                                                                 " data from multiple DDL sources."
399                                                         );
400                                                 }
401                                         }
402                                 }
403                                 if (sourceDDL > 20)
404                                 {
405                                         HLTWarning("The source DDL of a cluster data input block is %d."
406                                                 " The expected range for the DDL is [1..20].",
407                                                 sourceDDL
408                                         );
409                                 }
410                                 event.Add(new AliHLTMUONRecHit(
411                                                 clust.fHit.fX, clust.fHit.fY, clust.fHit.fZ,
412                                                 sourceDDL, detElemId
413                                         ));
414                         }
415                         else
416                         {
417                                 hit->SetDebugInfo(
418                                                   detElemId, clust.fId,
419                                                   clust.fNchannelsB, clust.fNchannelsNB,
420                                                   clust.fChargeB, clust.fChargeNB,
421                                                   hit->SourceDDL()
422                                 );
423                         }
424                 }
425         }
426         
427         // Now we can look for tracks to add. We needed the ROOT trigger records
428         // and reco hits created before we can create track objects.
429         for (block = GetFirstInputBlock(AliHLTMUONConstants::MansoTracksBlockDataType());
430              block != NULL;
431              block = GetNextInputBlock()
432             )
433         {
434                 specification |= block->fSpecification;
435                 AliHLTMUONMansoTracksBlockReader inblock(block->fPtr, block->fSize);
436                 if (not BlockStructureOk(inblock))
437                 {
438                         if (DumpDataOnError()) DumpEvent(evtData, trigData);
439                         continue;
440                 }
441                 
442                 for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
443                 {
444                         const AliHLTMUONMansoTrackStruct& t = inblock[n];
445                         
446                         AliHLTMUONParticleSign sign;
447                         bool hitset[4];
448                         AliHLTMUONUtils::UnpackMansoTrackFlags(
449                                         t.fFlags, sign, hitset
450                                 );
451                         
452                         // Try find the trigger record in 'event'.
453                         const AliHLTMUONTriggerRecord* trigrec = NULL;
454                         for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
455                         {
456                                 if (event.Array()[k]->IsA() != AliHLTMUONTriggerRecord::Class())
457                                         continue;
458                                 const AliHLTMUONTriggerRecord* tk =
459                                         static_cast<const AliHLTMUONTriggerRecord*>(event.Array()[k]);
460                                 if (tk->Id() == t.fTrigRec)
461                                 {
462                                         trigrec = tk;
463                                         break;
464                                 }
465                         }
466                         
467                         // Now try find the hits in 'event'.
468                         // If they cannot be found then create new ones.
469                         const AliHLTMUONRecHit* hit7 = NULL;
470                         const AliHLTMUONRecHit* hit8 = NULL;
471                         const AliHLTMUONRecHit* hit9 = NULL;
472                         const AliHLTMUONRecHit* hit10 = NULL;
473                         for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
474                         {
475                                 if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
476                                         continue;
477                                 const AliHLTMUONRecHit* h =
478                                         static_cast<const AliHLTMUONRecHit*>(event.Array()[k]);
479                                 
480                                 if (hitset[0] and h->X() == t.fHit[0].fX and h->Y() == t.fHit[0].fY
481                                         and h->Z() == t.fHit[0].fZ)
482                                 {
483                                         hit7 = h;
484                                 }
485                                 if (hitset[1] and h->X() == t.fHit[1].fX and h->Y() == t.fHit[1].fY
486                                         and h->Z() == t.fHit[1].fZ)
487                                 {
488                                         hit8 = h;
489                                 }
490                                 if (hitset[2] and h->X() == t.fHit[2].fX and h->Y() == t.fHit[2].fY
491                                         and h->Z() == t.fHit[2].fZ)
492                                 {
493                                         hit9 = h;
494                                 }
495                                 if (hitset[3] and h->X() == t.fHit[3].fX and h->Y() == t.fHit[3].fY
496                                         and h->Z() == t.fHit[3].fZ)
497                                 {
498                                         hit10 = h;
499                                 }
500                         }
501                         AliHLTMUONRecHit* newhit;
502                         if (hitset[0] and hit7 == NULL)
503                         {
504                                 newhit = new AliHLTMUONRecHit(t.fHit[0].fX, t.fHit[0].fY, t.fHit[0].fZ);
505                                 event.Add(newhit);
506                                 hit7 = newhit;
507                         }
508                         if (hitset[1] and hit8 == NULL)
509                         {
510                                 newhit = new AliHLTMUONRecHit(t.fHit[1].fX, t.fHit[1].fY, t.fHit[1].fZ);
511                                 event.Add(newhit);
512                                 hit8 = newhit;
513                         }
514                         if (hitset[2] and hit9 == NULL)
515                         {
516                                 newhit = new AliHLTMUONRecHit(t.fHit[2].fX, t.fHit[2].fY, t.fHit[2].fZ);
517                                 event.Add(newhit);
518                                 hit9 = newhit;
519                         }
520                         if (hitset[3] and hit10 == NULL)
521                         {
522                                 newhit = new AliHLTMUONRecHit(t.fHit[3].fX, t.fHit[3].fY, t.fHit[3].fZ);
523                                 event.Add(newhit);
524                                 hit10 = newhit;
525                         }
526                 
527                         AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(
528                                         t.fId, sign, t.fPx, t.fPy, t.fPz, t.fChi2,
529                                         trigrec, hit7, hit8, hit9, hit10
530                                 );
531                         event.Add(tr);
532                 }
533         }
534         
535         bool decisionBlockFound = false;
536         UInt_t numLowPt = 0;
537         UInt_t numHighPt = 0;
538         TClonesArray singlesDecisions("AliHLTMUONDecision::AliTrackDecision");
539         
540         // Find the single tracks decision blocks and add their information.
541         // We just sum the trigger scalars and single decisions.
542         for (block = GetFirstInputBlock(AliHLTMUONConstants::SinglesDecisionBlockDataType());
543              block != NULL;
544              block = GetNextInputBlock()
545             )
546         {
547                 decisionBlockFound = true;
548                 specification |= block->fSpecification;
549                 AliHLTMUONSinglesDecisionBlockReader inblock(block->fPtr, block->fSize);
550                 if (not BlockStructureOk(inblock))
551                 {
552                         if (DumpDataOnError()) DumpEvent(evtData, trigData);
553                         continue;
554                 }
555                 
556                 numLowPt += inblock.BlockHeader().fNlowPt;
557                 numHighPt += inblock.BlockHeader().fNhighPt;
558                 
559                 for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
560                 {
561                         const AliHLTMUONTrackDecisionStruct& t = inblock[n];
562                         
563                         bool highPt, lowPt;
564                         AliHLTMUONUtils::UnpackTrackDecisionBits(t.fTriggerBits, highPt, lowPt);
565                         
566                         // Try find the corresponding track in the 'event'.
567                         const AliHLTMUONMansoTrack* track = NULL;
568                         for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
569                         {
570                                 if (event.Array()[k]->IsA() != AliHLTMUONMansoTrack::Class())
571                                         continue;
572                                 const AliHLTMUONMansoTrack* tk =
573                                         static_cast<const AliHLTMUONMansoTrack*>(event.Array()[k]);
574                                 if (tk->Id() == t.fTrackId)
575                                 {
576                                         track = tk;
577                                         break;
578                                 }
579                         }
580                         
581                         // If the track was not found then create a dummy one.
582                         if (track == NULL)
583                         {
584                                 AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(t.fTrackId);
585                                 event.Add(tr);
586                                 track = tr;
587                         }
588                         
589                         new (singlesDecisions[singlesDecisions.GetEntriesFast()])
590                                 AliHLTMUONDecision::AliTrackDecision(t.fPt, lowPt, highPt, track);
591                 }
592         }
593         
594         UInt_t numUnlikeAnyPt = 0;
595         UInt_t numUnlikeLowPt = 0;
596         UInt_t numUnlikeHighPt = 0;
597         UInt_t numLikeAnyPt = 0;
598         UInt_t numLikeLowPt = 0;
599         UInt_t numLikeHighPt = 0;
600         UInt_t numAnyMass = 0;
601         UInt_t numLowMass = 0;
602         UInt_t numHighMass = 0;
603         TClonesArray pairsDecisions("AliHLTMUONDecision::AliPairDecision");
604         
605         // Find the track pairs decision blocks and add their information.
606         // We just sum the trigger scalars and track pair decisions.
607         for (block = GetFirstInputBlock(AliHLTMUONConstants::PairsDecisionBlockDataType());
608              block != NULL;
609              block = GetNextInputBlock()
610             )
611         {
612                 decisionBlockFound = true;
613                 specification |= block->fSpecification;
614                 AliHLTMUONPairsDecisionBlockReader inblock(block->fPtr, block->fSize);
615                 if (not BlockStructureOk(inblock))
616                 {
617                         if (DumpDataOnError()) DumpEvent(evtData, trigData);
618                         continue;
619                 }
620                 
621                 numUnlikeAnyPt += inblock.BlockHeader().fNunlikeAnyPt;
622                 numUnlikeLowPt += inblock.BlockHeader().fNunlikeLowPt;
623                 numUnlikeHighPt += inblock.BlockHeader().fNunlikeHighPt;
624                 numLikeAnyPt += inblock.BlockHeader().fNlikeAnyPt;
625                 numLikeLowPt += inblock.BlockHeader().fNlikeLowPt;
626                 numLikeHighPt += inblock.BlockHeader().fNlikeHighPt;
627                 numAnyMass += inblock.BlockHeader().fNmassAny;
628                 numLowMass += inblock.BlockHeader().fNmassLow;
629                 numHighMass += inblock.BlockHeader().fNmassHigh;
630                 
631                 for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
632                 {
633                         const AliHLTMUONPairDecisionStruct& t = inblock[n];
634                         
635                         bool highMass, lowMass, unlike;
636                         AliHLTUInt8_t highPtCount, lowPtCount;
637                         AliHLTMUONUtils::UnpackPairDecisionBits(
638                                         t.fTriggerBits, highMass, lowMass, unlike,
639                                         highPtCount, lowPtCount
640                                 );
641                         
642                         // Try find the corresponding tracks in the 'event'.
643                         const AliHLTMUONMansoTrack* trackA = NULL;
644                         const AliHLTMUONMansoTrack* trackB = NULL;
645                         for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
646                         {
647                                 if (event.Array()[k]->IsA() != AliHLTMUONMansoTrack::Class())
648                                         continue;
649                                 const AliHLTMUONMansoTrack* tk =
650                                         static_cast<const AliHLTMUONMansoTrack*>(event.Array()[k]);
651                                 if (tk->Id() == t.fTrackAId) trackA = tk;
652                                 if (tk->Id() == t.fTrackBId) trackB = tk;
653                                 if (trackA != NULL and trackB != NULL) break;
654                         }
655                         
656                         // If either of the tracks was not found then create a dummy one.
657                         if (trackA == NULL)
658                         {
659                                 AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(t.fTrackAId);
660                                 event.Add(tr);
661                                 trackA = tr;
662                         }
663                         if (trackB == NULL)
664                         {
665                                 AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(t.fTrackBId);
666                                 event.Add(tr);
667                                 trackB = tr;
668                         }
669                         
670                         new (pairsDecisions[pairsDecisions.GetEntriesFast()])
671                                 AliHLTMUONDecision::AliPairDecision(
672                                         t.fInvMass, lowMass, highMass, unlike,
673                                         lowPtCount, highPtCount, trackA, trackB
674                                 );
675                 }
676         }
677         
678         
679         // Do not add the decision if no decision blocks were found.
680         if (decisionBlockFound)
681         {
682                 AliHLTMUONDecision* triggerDecision = new AliHLTMUONDecision(
683                                 numLowPt, numHighPt, numUnlikeAnyPt, numUnlikeLowPt,
684                                 numUnlikeHighPt, numLikeAnyPt, numLikeLowPt,
685                                 numLikeHighPt, numAnyMass, numLowMass, numHighMass
686                         );
687                 for (Int_t i = 0; i < singlesDecisions.GetEntriesFast(); i++)
688                 {
689                         AliHLTMUONDecision::AliTrackDecision* decision =
690                                 static_cast<AliHLTMUONDecision::AliTrackDecision*>( singlesDecisions[i] );
691                         triggerDecision->AddDecision(decision);
692                 }
693                 for (Int_t j = 0; j < pairsDecisions.GetEntriesFast(); j++)
694                 {
695                         AliHLTMUONDecision::AliPairDecision* decision =
696                                 static_cast<AliHLTMUONDecision::AliPairDecision*>( pairsDecisions[j] );
697                         triggerDecision->AddDecision(decision);
698                 }
699                 
700                 event.Add(triggerDecision);
701         }
702         
703         PushBack(&event, AliHLTMUONConstants::RootifiedEventDataType(), specification);
704         
705         return 0;
706 }
707