]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - HLT/MUON/OfflineInterface/AliHLTMUONRootifierComponent.cxx
Adding AliHLTMUONTrack object to store ROOTified internal dHLT track data in new...
[u/mrichter/AliRoot.git] / HLT / MUON / OfflineInterface / AliHLTMUONRootifierComponent.cxx
index e121a041095b3011f11c155473679c6b84ad1e57..6f0e9165815f9e755e988308bfc602a11359ae13 100644 (file)
@@ -1,5 +1,5 @@
 /**************************************************************************
- * This file is property of and copyright by the ALICE HLT Project        * 
+ * This file is property of and copyright by the ALICE HLT Project        *
  * All rights reserved.                                                   *
  *                                                                        *
  * Primary Authors:                                                       *
  * without fee, provided that the above copyright notice appears in all   *
  * copies and that both the copyright notice and this permission notice   *
  * appear in the supporting documentation. The authors make no claims     *
- * about the suitability of this software for any purpose. It is          * 
+ * about the suitability of this software for any purpose. It is          *
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
 
-/* $Id$ */
+// $Id$
 
 ///
 /// @file   AliHLTMUONRootifierComponent.cxx
 /// @date   29 Sep 2007
 /// @brief  Implementation of the AliHLTMUONRootifierComponent component.
 ///
+/// Implements a component to convert dHLT raw data into TObjects.
 
 #include "AliHLTMUONRootifierComponent.h"
 #include "AliHLTMUONEvent.h"
 #include "AliHLTMUONConstants.h"
 #include "AliHLTMUONUtils.h"
-#include "AliHLTMUONDataBlockReader.h"
 #include "AliHLTMUONRecHit.h"
 #include "AliHLTMUONTriggerRecord.h"
 #include "AliHLTMUONMansoTrack.h"
+#include "AliHLTMUONTrack.h"
 #include "AliHLTMUONDecision.h"
+#include "AliMUONTriggerDDLDecoderEventHandler.h"
 #include "TClonesArray.h"
 #include <cassert>
+#include <map>
 
 ClassImp(AliHLTMUONRootifierComponent);
 
 
 AliHLTMUONRootifierComponent::AliHLTMUONRootifierComponent() :
-       AliHLTProcessor(),
+       AliHLTMUONProcessor(),
        fWarnForUnexpecedBlock(false)
 {
        ///
@@ -56,6 +59,23 @@ AliHLTMUONRootifierComponent::~AliHLTMUONRootifierComponent()
 }
 
 
+bool AliHLTMUONRootifierComponent::IgnoreArgument(const char* arg) const
+{
+       /// Return true if the argument is one of -cdbpath -run or -delaysetup
+       /// to prevent the parent class from parsing these arguments in DoInit.
+       
+       if (strcmp(arg, "-cdbpath") == 0 or strcmp(arg, "-run") == 0 or
+           strcmp(arg, "-delaysetup") == 0)
+       {
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+
 int AliHLTMUONRootifierComponent::DoInit(int argc, const char** argv)
 {
        ///
@@ -64,11 +84,17 @@ int AliHLTMUONRootifierComponent::DoInit(int argc, const char** argv)
        ///
        
        HLTInfo("Initialising dHLT rootifier component.");
+
+       // Inherit the parents functionality.
+       int result = AliHLTMUONProcessor::DoInit(argc, argv);
+       if (result != 0) return result;
        
        fWarnForUnexpecedBlock = false;
        
        for (int i = 0; i < argc; i++)
        {
+               if (ArgumentAlreadyHandled(i, argv[i])) continue;
+
                if (strcmp(argv[i], "-warn_on_unexpected_block") == 0)
                {
                        fWarnForUnexpecedBlock = true;
@@ -117,14 +143,12 @@ int AliHLTMUONRootifierComponent::GetOutputDataTypes(AliHLTComponentDataTypeList
 {
        /// Inherited from AliHLTComponent. Returns the output data types.
        
-       tgtList.push_back(kAliHLTAnyDataType);
-       return 1;
+       tgtList.push_back(AliHLTMUONConstants::RootifiedEventDataType());
+       return tgtList.size();
 }
 
 
-void AliHLTMUONRootifierComponent::GetInputDataTypes(
-               vector<AliHLTComponentDataType>& list
-       )
+void AliHLTMUONRootifierComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
 {
        ///
        /// Inherited from AliHLTProcessor. Returns the list of expected input data types.
@@ -159,15 +183,19 @@ AliHLTComponent* AliHLTMUONRootifierComponent::Spawn()
 
 int AliHLTMUONRootifierComponent::DoEvent(
                const AliHLTComponentEventData& evtData,
-               AliHLTComponentTriggerData& /*trigData*/
+               AliHLTComponentTriggerData& trigData
        )
 {
        ///
        /// Inherited from AliHLTProcessor. Processes the new event data.
        ///
        
+       if (not IsDataEvent()) return 0;
+       
        AliHLTMUONEvent event(evtData.fEventID);
        const AliHLTComponentBlockData* block = NULL;
+       AliHLTUInt32_t specification = 0;  // Contains the output data block spec bits.
+       std::map<AliHLTInt32_t, AliHLTMUONTriggerRecord*> triggerMap;
 
        // First process the blocks of reconstructed hits and trigger records.
        for (int i = 0; i < GetNumberOfInputBlocks(); i++)
@@ -181,38 +209,11 @@ int AliHLTMUONRootifierComponent::DoEvent(
                
                if (block->fDataType == AliHLTMUONConstants::RecHitsBlockDataType())
                {
-                       AliHLTUInt8_t* ptr = reinterpret_cast<AliHLTUInt8_t*>(block->fPtr);
-                       ptr += block->fOffset;
-                       AliHLTMUONRecHitsBlockReader inblock(ptr, block->fSize);
-                       if (not inblock.BufferSizeOk())
+                       specification |= block->fSpecification;
+                       AliHLTMUONRecHitsBlockReader inblock(block->fPtr, block->fSize);
+                       if (not BlockStructureOk(inblock))
                        {
-                               size_t headerSize = sizeof(AliHLTMUONRecHitsBlockReader::HeaderType);
-                               if (block->fSize < headerSize)
-                               {
-                                       HLTError("Received a reconstructed hits data block with a size of %d bytes,"
-                                               " which is smaller than the minimum valid header size of %d bytes."
-                                               " The block must be corrupt.",
-                                               block->fSize, headerSize
-                                       );
-                                       continue;
-                               }
-                               
-                               size_t expectedWidth = sizeof(AliHLTMUONRecHitsBlockReader::ElementType);
-                               if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
-                               {
-                                       HLTError("Received a reconstructed hits data block with a record"
-                                               " width of %d bytes, but the expected value is %d bytes."
-                                               " The block might be corrupt.",
-                                               block->fSize, headerSize
-                                       );
-                                       continue;
-                               }
-                               
-                               HLTError("Received a reconstructed hits data block with a size of %d bytes,"
-                                       " but the block header claims the block should be %d bytes."
-                                       " The block might be corrupt.",
-                                       block->fSize, inblock.BytesUsed()
-                               );
+                               if (DumpDataOnError()) DumpEvent(evtData, trigData);
                                continue;
                        }
                        
@@ -247,43 +248,19 @@ int AliHLTMUONRootifierComponent::DoEvent(
                        for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
                        {
                                const AliHLTMUONRecHitStruct& h = inblock[n];
-                               event.Add(new AliHLTMUONRecHit(h.fX, h.fY, h.fZ, sourceDDL));
+                               AliHLTUInt8_t chamber;
+                               AliHLTUInt16_t detElemId;
+                               AliHLTMUONUtils::UnpackRecHitFlags(h.fFlags, chamber, detElemId);
+                               event.Add(new AliHLTMUONRecHit(h.fX, h.fY, h.fZ, sourceDDL, detElemId));
                        }
                }
                else if (block->fDataType == AliHLTMUONConstants::TriggerRecordsBlockDataType())
                {
-                       AliHLTUInt8_t* ptr = reinterpret_cast<AliHLTUInt8_t*>(block->fPtr);
-                       ptr += block->fOffset;
-                       AliHLTMUONTriggerRecordsBlockReader inblock(ptr, block->fSize);
-                       if (not inblock.BufferSizeOk())
+                       specification |= block->fSpecification;
+                       AliHLTMUONTriggerRecordsBlockReader inblock(block->fPtr, block->fSize);
+                       if (not BlockStructureOk(inblock))
                        {
-                               size_t headerSize = sizeof(AliHLTMUONTriggerRecordsBlockReader::HeaderType);
-                               if (block->fSize < headerSize)
-                               {
-                                       HLTError("Received a trigger records data block with a size of %d bytes,"
-                                               " which is smaller than the minimum valid header size of %d bytes."
-                                               " The block must be corrupt.",
-                                               block->fSize, headerSize
-                                       );
-                                       continue;
-                               }
-                               
-                               size_t expectedWidth = sizeof(AliHLTMUONTriggerRecordsBlockReader::ElementType);
-                               if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
-                               {
-                                       HLTError("Received a trigger records data block with a record"
-                                               " width of %d bytes, but the expected value is %d bytes."
-                                               " The block might be corrupt.",
-                                               block->fSize, headerSize
-                                       );
-                                       continue;
-                               }
-                               
-                               HLTError("Received a trigger records data block with a size of %d bytes,"
-                                       " but the block header claims the block should be %d bytes."
-                                       " The block might be corrupt.",
-                                       block->fSize, inblock.BytesUsed()
-                               );
+                               if (DumpDataOnError()) DumpEvent(evtData, trigData);
                                continue;
                        }
                        
@@ -329,13 +306,22 @@ int AliHLTMUONRootifierComponent::DoEvent(
                                                t.fId, sign, t.fPx, t.fPy, t.fPz, sourceDDL
                                        );
                                for (int k = 0; k < 4; k++)
-                                       tr->SetHit(k+11, t.fHit[k].fX, t.fHit[k].fY, t.fHit[k].fZ);
+                               {
+                                       if (not hitset[k]) continue;
+                                       Int_t detElemId = AliHLTMUONUtils::GetDetElemIdFromFlags(t.fHit[k].fFlags);
+                                       tr->SetHit(k+11, t.fHit[k].fX, t.fHit[k].fY, t.fHit[k].fZ, detElemId);
+                               }
                                event.Add(tr);
+                               triggerMap[t.fId] = tr;
                        }
                }
                else
                {
-                       if (block->fDataType != AliHLTMUONConstants::MansoTracksBlockDataType() and
+                       if (block->fDataType != AliHLTMUONConstants::TrigRecsDebugBlockDataType() and
+                           block->fDataType != AliHLTMUONConstants::ClusterBlockDataType() and
+                           block->fDataType != AliHLTMUONConstants::ChannelBlockDataType() and
+                           block->fDataType != AliHLTMUONConstants::MansoTracksBlockDataType() and
+                           block->fDataType != AliHLTMUONConstants::MansoCandidatesBlockDataType() and
                            block->fDataType != AliHLTMUONConstants::SinglesDecisionBlockDataType() and
                            block->fDataType != AliHLTMUONConstants::PairsDecisionBlockDataType()
                           )
@@ -346,149 +332,376 @@ int AliHLTMUONRootifierComponent::DoEvent(
                                        HLTWarning("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
                                                DataType2Text(block->fDataType).c_str(), block->fSpecification
                                        );
+#ifdef __DEBUG
                                else
                                        HLTDebug("Received a data block of a type we cannot handle: '%s', spec: 0x%X",
                                                DataType2Text(block->fDataType).c_str(), block->fSpecification
                                        );
+#endif
                        }
                }
        }
        
-       // Now we can look for tracks to add. We needed the ROOT trigger records
-       // and reco hits created before we can create track objects.
-       for (block = GetFirstInputBlock(AliHLTMUONConstants::MansoTracksBlockDataType());
+       // We need to check if there are any trigger record debug data blocks
+       // and add their information to the AliHLTMUONTriggerRecord objects.
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::TrigRecsDebugBlockDataType());
             block != NULL;
             block = GetNextInputBlock()
            )
        {
-               AliHLTUInt8_t* ptr = reinterpret_cast<AliHLTUInt8_t*>(block->fPtr);
-               ptr += block->fOffset;
-               AliHLTMUONMansoTracksBlockReader inblock(ptr, block->fSize);
-               if (not inblock.BufferSizeOk())
+               specification |= block->fSpecification;
+               AliHLTMUONTrigRecsDebugBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
                {
-                       size_t headerSize = sizeof(AliHLTMUONMansoTracksBlockReader::HeaderType);
-                       if (block->fSize < headerSize)
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
+                       continue;
+               }
+               
+               for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
+               {
+                       const AliHLTMUONTrigRecInfoStruct& triginfo = inblock[n];
+                       
+                       AliHLTMUONTriggerRecord* trigrec = triggerMap[triginfo.fTrigRecId];
+                       if (trigrec == NULL)
                        {
-                               HLTError("Received a Manso tracks data block with a size of %d bytes,"
-                                       " which is smaller than the minimum valid header size of %d bytes."
-                                       " The block must be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
+                               // Decode the source DDL from the specification bits.
+                               Int_t sourceDDL = -1;
+                               bool ddl[22];
+                               AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
+                               for (int k = 0; k < 22; k++)
+                               {
+                                       if (ddl[k])
+                                       {
+                                               if (sourceDDL == -1)
+                                               {
+                                                       sourceDDL = k+1;
+                                               }
+                                               else
+                                               {
+                                                       HLTWarning("An trigger debug information data block"
+                                                               " contains data from multiple DDL sources."
+                                                       );
+                                               }
+                                       }
+                               }
+                               if (sourceDDL != -1 and (sourceDDL < 21 or sourceDDL > 22))
+                               {
+                                       HLTWarning("The source DDL for a trigger debug information data"
+                                               " block is %d. The expected range for the DDL is [21..22].",
+                                               sourceDDL
+                                       );
+                               }
+                               
+                               trigrec = new AliHLTMUONTriggerRecord(
+                                               0, 0, 0, 0, 0, sourceDDL
+                                       );
                        }
-                       
-                       size_t expectedWidth = sizeof(AliHLTMUONMansoTracksBlockReader::ElementType);
-                       if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
+                       else
                        {
-                               HLTError("Received a Manso tracks data block with a record"
-                                       " width of %d bytes, but the expected value is %d bytes."
-                                       " The block might be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
+                               for (Int_t j = 0; j < 4; ++j)
+                               {
+                                       if (trigrec->DetElemId(j+11) != -1 and triginfo.fDetElemId[j] != trigrec->DetElemId(j+11))
+                                       {
+                                               HLTWarning("Found a trigger record with a hit on chamber %d with a different"
+                                                       " detector element ID %d than the debug information %d.",
+                                                       j, trigrec->DetElemId(j+11), triginfo.fDetElemId[j]
+                                               );
+                                       }
+                               }
                        }
                        
-                       HLTError("Received a Manso tracks data block with a size of %d bytes,"
-                               " but the block header claims the block should be %d bytes."
-                               " The block might be corrupt.",
-                               block->fSize, inblock.BytesUsed()
-                       );
+                       typedef AliMUONTriggerDDLDecoderEventHandler Handler;
+                       
+                       trigrec->SetDebugInfo(triginfo.fZmiddle, triginfo.fBl);
+                       
+                       UShort_t patternX[4][3] = {
+                               {
+                                       Handler::GetLocalX1(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalX1(&triginfo.fL0Struct),
+                                       Handler::GetLocalX1(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalX2(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalX2(&triginfo.fL0Struct),
+                                       Handler::GetLocalX2(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalX3(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalX3(&triginfo.fL0Struct),
+                                       Handler::GetLocalX3(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalX4(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalX4(&triginfo.fL0Struct),
+                                       Handler::GetLocalX4(&triginfo.fL0StructNext)
+                               }
+                       };
+                       UShort_t patternY[4][3] = {
+                               {
+                                       Handler::GetLocalY1(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalY1(&triginfo.fL0Struct),
+                                       Handler::GetLocalY1(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalY2(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalY2(&triginfo.fL0Struct),
+                                       Handler::GetLocalY2(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalY3(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalY3(&triginfo.fL0Struct),
+                                       Handler::GetLocalY3(&triginfo.fL0StructNext)
+                               },{
+                                       Handler::GetLocalY4(&triginfo.fL0StructPrev),
+                                       Handler::GetLocalY4(&triginfo.fL0Struct),
+                                       Handler::GetLocalY4(&triginfo.fL0StructNext)
+                               }
+                       };
+                       
+                       for (Int_t j = 0; j < 4; ++j)
+                       {
+                               trigrec->SetHitDebugInfo(j+11, patternX[j], patternY[j]);
+                       }
+               }
+       }
+       
+       std::map<AliHLTInt32_t, AliHLTMUONRecHit*> clusterMap;
+       
+       // We need to check if there are any cluster data blocks and add their
+       // information to the AliHLTMUONRecHit objects.
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::ClusterBlockDataType());
+            block != NULL;
+            block = GetNextInputBlock()
+           )
+       {
+               specification |= block->fSpecification;
+               AliHLTMUONClustersBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
+               {
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
                        continue;
                }
                
                for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
                {
-                       const AliHLTMUONMansoTrackStruct& t = inblock[n];
+                       const AliHLTMUONClusterStruct& clust = inblock[n];
                        
-                       AliHLTMUONParticleSign sign;
-                       bool hitset[4];
-                       AliHLTMUONUtils::UnpackMansoTrackFlags(
-                                       t.fFlags, sign, hitset
+                       AliHLTUInt8_t chamber;
+                       AliHLTUInt16_t detElemId;
+                       AliHLTMUONUtils::UnpackRecHitFlags(clust.fHit.fFlags, chamber, detElemId);
+                       if (clust.fDetElemId != detElemId)
+                       {
+                               HLTWarning("Found a cluster with a different detector element ID (%d)"
+                                       " from its corresponding hit (x,y,z = %f,%f,%f and detElemId = %d).",
+                                       clust.fDetElemId,
+                                       clust.fHit.fX, clust.fHit.fY, clust.fHit.fZ,
+                                       detElemId
                                );
+                       }
                        
-                       // Try find the trigger record in 'event'.
-                       const AliHLTMUONTriggerRecord* trigrec = NULL;
+                       // Try find the corresponding reconstructed hit in 'event'.
+                       AliHLTMUONRecHit* hit = NULL;
                        for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
                        {
-                               if (event.Array()[k]->IsA() != AliHLTMUONTriggerRecord::Class())
+                               if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
                                        continue;
-                               const AliHLTMUONTriggerRecord* tk =
-                                       static_cast<const AliHLTMUONTriggerRecord*>(event.Array()[k]);
-                               if (tk->Id() == t.fTrigRec)
+                               AliHLTMUONRecHit* h = static_cast<AliHLTMUONRecHit*>(event.Array()[k]);
+                               if (h->DetElemId() == detElemId and h->X() == clust.fHit.fX
+                                   and h->Y() == clust.fHit.fY and h->Z() == clust.fHit.fZ)
                                {
-                                       trigrec = tk;
+                                       hit = h;
                                        break;
                                }
                        }
                        
-                       // Now try find the hits in 'event'.
-                       // If they cannot be found then create new ones.
-                       const AliHLTMUONRecHit* hit7 = NULL;
-                       const AliHLTMUONRecHit* hit8 = NULL;
-                       const AliHLTMUONRecHit* hit9 = NULL;
-                       const AliHLTMUONRecHit* hit10 = NULL;
-                       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
+                       // If we could not find the corresponding hit then we need to create
+                       // a new hit object, otherwise we can just append the information.
+                       if (hit == NULL)
                        {
-                               if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
-                                       continue;
-                               const AliHLTMUONRecHit* h =
-                                       static_cast<const AliHLTMUONRecHit*>(event.Array()[k]);
-                               
-                               if (hitset[0] and h->X() == t.fHit[0].fX and h->Y() == t.fHit[0].fY
-                                       and h->Z() == t.fHit[0].fZ)
-                               {
-                                       hit7 = h;
-                               }
-                               if (hitset[1] and h->X() == t.fHit[1].fX and h->Y() == t.fHit[1].fY
-                                       and h->Z() == t.fHit[1].fZ)
-                               {
-                                       hit8 = h;
-                               }
-                               if (hitset[2] and h->X() == t.fHit[2].fX and h->Y() == t.fHit[2].fY
-                                       and h->Z() == t.fHit[2].fZ)
+                               // Decode the source DDL from the specification bits.
+                               Int_t sourceDDL = -1;
+                               bool ddl[22];
+                               AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
+                               for (int k = 0; k < 22; k++)
                                {
-                                       hit9 = h;
+                                       if (ddl[k])
+                                       {
+                                               if (sourceDDL == -1)
+                                               {
+                                                       sourceDDL = k+1;
+                                               }
+                                               else
+                                               {
+                                                       HLTWarning("An input block of cluster data contains"
+                                                               " data from multiple DDL sources."
+                                                       );
+                                               }
+                                       }
                                }
-                               if (hitset[3] and h->X() == t.fHit[3].fX and h->Y() == t.fHit[3].fY
-                                       and h->Z() == t.fHit[3].fZ)
+                               if (sourceDDL > 20)
                                {
-                                       hit10 = h;
+                                       HLTWarning("The source DDL of a cluster data input block is %d."
+                                               " The expected range for the DDL is [1..20].",
+                                               sourceDDL
+                                       );
                                }
+                               hit = new AliHLTMUONRecHit(
+                                               clust.fHit.fX, clust.fHit.fY, clust.fHit.fZ,
+                                               sourceDDL, detElemId
+                                       );
+                               event.Add(hit);
                        }
-                       AliHLTMUONRecHit* newhit;
-                       if (hitset[0] and hit7 == NULL)
+                       else
                        {
-                               newhit = new AliHLTMUONRecHit(t.fHit[0].fX, t.fHit[0].fY, t.fHit[0].fZ);
-                               event.Add(newhit);
-                               hit7 = newhit;
+                               hit->SetDebugInfo(
+                                                 detElemId, clust.fId,
+                                                 clust.fNchannelsB, clust.fNchannelsNB,
+                                                 clust.fChargeB, clust.fChargeNB,
+                                                 hit->SourceDDL()
+                               );
                        }
-                       if (hitset[1] and hit8 == NULL)
+                       
+                       clusterMap[clust.fId] = hit;
+               }
+       }
+       
+       // We need to check if there are any channel data blocks and add their
+       // information to the AliHLTMUONRecHit objects.
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::ChannelBlockDataType());
+            block != NULL;
+            block = GetNextInputBlock()
+           )
+       {
+               specification |= block->fSpecification;
+               AliHLTMUONChannelsBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
+               {
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
+                       continue;
+               }
+               
+               for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
+               {
+                       const AliHLTMUONChannelStruct& channel = inblock[n];
+                       
+                       AliHLTMUONRecHit* hit = clusterMap[channel.fClusterId];
+                       if (hit == NULL)
                        {
-                               newhit = new AliHLTMUONRecHit(t.fHit[1].fX, t.fHit[1].fY, t.fHit[1].fZ);
-                               event.Add(newhit);
-                               hit8 = newhit;
+                               // Decode the source DDL from the specification bits.
+                               Int_t sourceDDL = -1;
+                               bool ddl[22];
+                               AliHLTMUONUtils::UnpackSpecBits(block->fSpecification, ddl);
+                               for (int k = 0; k < 22; k++)
+                               {
+                                       if (ddl[k])
+                                       {
+                                               if (sourceDDL == -1)
+                                               {
+                                                       sourceDDL = k+1;
+                                               }
+                                               else
+                                               {
+                                                       HLTWarning("An input block of cluster data contains"
+                                                               " data from multiple DDL sources."
+                                                       );
+                                               }
+                                       }
+                               }
+                               if (sourceDDL > 20)
+                               {
+                                       HLTWarning("The source DDL of a cluster data input block is %d."
+                                               " The expected range for the DDL is [1..20].",
+                                               sourceDDL
+                                       );
+                               }
+                               hit = new AliHLTMUONRecHit(0, 0, 0, sourceDDL, -1);
+                               event.Add(hit);
                        }
-                       if (hitset[2] and hit9 == NULL)
+                       
+                       hit->AddChannel(
+                                       channel.fBusPatch, channel.fManu,
+                                       channel.fChannelAddress, channel.fSignal,
+                                       channel.fRawDataWord
+                               );
+               }
+       }
+       
+       // Now we can look for tracks to add. We needed the ROOT trigger records
+       // and reco hits created before we can create track objects.
+       
+       std::map<AliHLTInt32_t, AliHLTMUONTrack*> trackMap;
+       
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::TracksBlockDataType());
+            block != NULL;
+            block = GetNextInputBlock()
+           )
+       {
+               specification |= block->fSpecification;
+               AliHLTMUONTracksBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
+               {
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
+                       continue;
+               }
+               
+               for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
+               {
+                       const AliHLTMUONTrackStruct& t = inblock[n];
+                       trackMap[t.fId] = AddTrack(event, t);
+               }
+       }
+
+       std::map<AliHLTInt32_t, AliHLTMUONMansoTrack*> mansoTrackMap;
+       
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::MansoTracksBlockDataType());
+            block != NULL;
+            block = GetNextInputBlock()
+           )
+       {
+               specification |= block->fSpecification;
+               AliHLTMUONMansoTracksBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
+               {
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
+                       continue;
+               }
+               
+               for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
+               {
+                       const AliHLTMUONMansoTrackStruct& t = inblock[n];
+                       mansoTrackMap[t.fId] = AddTrack(event, t);
+               }
+       }
+       
+       // Look for Manso track candidates to add the debug info to the tracks.
+       for (block = GetFirstInputBlock(AliHLTMUONConstants::MansoCandidatesBlockDataType());
+            block != NULL;
+            block = GetNextInputBlock()
+           )
+       {
+               specification |= block->fSpecification;
+               AliHLTMUONMansoCandidatesBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
+               {
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
+                       continue;
+               }
+               
+               for (AliHLTUInt32_t n = 0; n < inblock.Nentries(); n++)
+               {
+                       const AliHLTMUONMansoCandidateStruct& tc = inblock[n];
+                       AliHLTMUONMansoTrack* mtrack = mansoTrackMap[tc.fTrack.fId];
+                       if (mtrack == NULL)
                        {
-                               newhit = new AliHLTMUONRecHit(t.fHit[2].fX, t.fHit[2].fY, t.fHit[2].fZ);
-                               event.Add(newhit);
-                               hit9 = newhit;
+                               // If we got here then we could not find the corresponding Manso
+                               // track. So we need to create and add a new track object.
+                               mtrack = AddTrack(event, tc.fTrack);
                        }
-                       if (hitset[3] and hit10 == NULL)
+                       mtrack->SetDebugData(tc.fZmiddle, tc.fBl);
+                       for (AliHLTUInt32_t i = 0; i < 4; ++i)
                        {
-                               newhit = new AliHLTMUONRecHit(t.fHit[3].fX, t.fHit[3].fY, t.fHit[3].fZ);
-                               event.Add(newhit);
-                               hit10 = newhit;
+                               if (tc.fRoI[i] == AliHLTMUONConstants::NilMansoRoIStruct()) continue;
+                               mtrack->SetRoI(i+7, tc.fRoI[i].fX, tc.fRoI[i].fY, tc.fRoI[i].fZ, tc.fRoI[i].fRadius);
                        }
-               
-                       AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(
-                                       t.fId, sign, t.fPx, t.fPy, t.fPz, t.fChi2,
-                                       trigrec, hit7, hit8, hit9, hit10
-                               );
-                       event.Add(tr);
                }
        }
        
+       bool decisionBlockFound = false;
        UInt_t numLowPt = 0;
        UInt_t numHighPt = 0;
        TClonesArray singlesDecisions("AliHLTMUONDecision::AliTrackDecision");
@@ -500,38 +713,12 @@ int AliHLTMUONRootifierComponent::DoEvent(
             block = GetNextInputBlock()
            )
        {
-               AliHLTUInt8_t* ptr = reinterpret_cast<AliHLTUInt8_t*>(block->fPtr);
-               ptr += block->fOffset;
-               AliHLTMUONSinglesDecisionBlockReader inblock(ptr, block->fSize);
-               if (not inblock.BufferSizeOk())
+               decisionBlockFound = true;
+               specification |= block->fSpecification;
+               AliHLTMUONSinglesDecisionBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
                {
-                       size_t headerSize = sizeof(AliHLTMUONSinglesDecisionBlockReader::HeaderType);
-                       if (block->fSize < headerSize)
-                       {
-                               HLTError("Received a single tracks trigger decision data block with a size of %d bytes,"
-                                       " which is smaller than the minimum valid header size of %d bytes."
-                                       " The block must be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
-                       }
-                       
-                       size_t expectedWidth = sizeof(AliHLTMUONSinglesDecisionBlockReader::ElementType);
-                       if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
-                       {
-                               HLTError("Received a single tracks trigger decision data block with a record"
-                                       " width of %d bytes, but the expected value is %d bytes."
-                                       " The block might be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
-                       }
-                       
-                       HLTError("Received a single tracks trigger decision data block with a size of %d bytes,"
-                               " but the block header claims the block should be %d bytes."
-                               " The block might be corrupt.",
-                               block->fSize, inblock.BytesUsed()
-                       );
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
                        continue;
                }
                
@@ -545,20 +732,9 @@ int AliHLTMUONRootifierComponent::DoEvent(
                        bool highPt, lowPt;
                        AliHLTMUONUtils::UnpackTrackDecisionBits(t.fTriggerBits, highPt, lowPt);
                        
-                       // Try find the corresponding track in the 'event'.
-                       const AliHLTMUONMansoTrack* track = NULL;
-                       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
-                       {
-                               if (event.Array()[k]->IsA() != AliHLTMUONMansoTrack::Class())
-                                       continue;
-                               const AliHLTMUONMansoTrack* tk =
-                                       static_cast<const AliHLTMUONMansoTrack*>(event.Array()[k]);
-                               if (tk->Id() == t.fTrackId)
-                               {
-                                       track = tk;
-                                       break;
-                               }
-                       }
+                       // Try find the corresponding track.
+                       const TObject* track = trackMap[t.fTrackId];
+                       if (track == NULL) track = mansoTrackMap[t.fTrackId];
                        
                        // If the track was not found then create a dummy one.
                        if (track == NULL)
@@ -591,38 +767,12 @@ int AliHLTMUONRootifierComponent::DoEvent(
             block = GetNextInputBlock()
            )
        {
-               AliHLTUInt8_t* ptr = reinterpret_cast<AliHLTUInt8_t*>(block->fPtr);
-               ptr += block->fOffset;
-               AliHLTMUONPairsDecisionBlockReader inblock(ptr, block->fSize);
-               if (not inblock.BufferSizeOk())
+               decisionBlockFound = true;
+               specification |= block->fSpecification;
+               AliHLTMUONPairsDecisionBlockReader inblock(block->fPtr, block->fSize);
+               if (not BlockStructureOk(inblock))
                {
-                       size_t headerSize = sizeof(AliHLTMUONPairsDecisionBlockReader::HeaderType);
-                       if (block->fSize < headerSize)
-                       {
-                               HLTError("Received a track pairs trigger decision data block with a size of %d bytes,"
-                                       " which is smaller than the minimum valid header size of %d bytes."
-                                       " The block must be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
-                       }
-                       
-                       size_t expectedWidth = sizeof(AliHLTMUONPairsDecisionBlockReader::ElementType);
-                       if (inblock.CommonBlockHeader().fRecordWidth != expectedWidth)
-                       {
-                               HLTError("Received a track pairs trigger decision data block with a record"
-                                       " width of %d bytes, but the expected value is %d bytes."
-                                       " The block might be corrupt.",
-                                       block->fSize, headerSize
-                               );
-                               continue;
-                       }
-                       
-                       HLTError("Received a track pairs trigger decision data block with a size of %d bytes,"
-                               " but the block header claims the block should be %d bytes."
-                               " The block might be corrupt.",
-                               block->fSize, inblock.BytesUsed()
-                       );
+                       if (DumpDataOnError()) DumpEvent(evtData, trigData);
                        continue;
                }
                
@@ -647,19 +797,11 @@ int AliHLTMUONRootifierComponent::DoEvent(
                                        highPtCount, lowPtCount
                                );
                        
-                       // Try find the corresponding tracks in the 'event'.
-                       const AliHLTMUONMansoTrack* trackA = NULL;
-                       const AliHLTMUONMansoTrack* trackB = NULL;
-                       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
-                       {
-                               if (event.Array()[k]->IsA() != AliHLTMUONMansoTrack::Class())
-                                       continue;
-                               const AliHLTMUONMansoTrack* tk =
-                                       static_cast<const AliHLTMUONMansoTrack*>(event.Array()[k]);
-                               if (tk->Id() == t.fTrackAId) trackA = tk;
-                               if (tk->Id() == t.fTrackBId) trackB = tk;
-                               if (trackA != NULL and trackB != NULL) break;
-                       }
+                       // Try find the corresponding tracks.
+                       const TObject* trackA = trackMap[t.fTrackAId];
+                       if (trackA == NULL) trackA = mansoTrackMap[t.fTrackAId];
+                       const TObject* trackB = trackMap[t.fTrackBId];
+                       if (trackB == NULL) trackB = mansoTrackMap[t.fTrackBId];
                        
                        // If either of the tracks was not found then create a dummy one.
                        if (trackA == NULL)
@@ -683,27 +825,195 @@ int AliHLTMUONRootifierComponent::DoEvent(
                }
        }
        
-       AliHLTMUONDecision* triggerDecision = new AliHLTMUONDecision(
-                       numLowPt, numHighPt, numUnlikeAnyPt, numUnlikeLowPt,
-                       numUnlikeHighPt, numLikeAnyPt, numLikeLowPt,
-                       numLikeHighPt, numAnyMass, numLowMass, numHighMass
+       // Do not add the decision if no decision blocks were found.
+       if (decisionBlockFound)
+       {
+               AliHLTMUONDecision* triggerDecision = new AliHLTMUONDecision(
+                               numLowPt, numHighPt, numUnlikeAnyPt, numUnlikeLowPt,
+                               numUnlikeHighPt, numLikeAnyPt, numLikeLowPt,
+                               numLikeHighPt, numAnyMass, numLowMass, numHighMass
+                       );
+               for (Int_t i = 0; i < singlesDecisions.GetEntriesFast(); i++)
+               {
+                       AliHLTMUONDecision::AliTrackDecision* decision =
+                               static_cast<AliHLTMUONDecision::AliTrackDecision*>( singlesDecisions[i] );
+                       triggerDecision->AddDecision(decision);
+               }
+               for (Int_t j = 0; j < pairsDecisions.GetEntriesFast(); j++)
+               {
+                       AliHLTMUONDecision::AliPairDecision* decision =
+                               static_cast<AliHLTMUONDecision::AliPairDecision*>( pairsDecisions[j] );
+                       triggerDecision->AddDecision(decision);
+               }
+               
+               event.Add(triggerDecision);
+       }
+       
+       PushBack(&event, AliHLTMUONConstants::RootifiedEventDataType(), specification);
+       
+       return 0;
+}
+
+
+AliHLTMUONMansoTrack* AliHLTMUONRootifierComponent::AddTrack(
+               AliHLTMUONEvent& event, const AliHLTMUONMansoTrackStruct& track
+       )
+{
+       // Converts the track structure and adds it to the event object.
+       
+       AliHLTMUONParticleSign sign;
+       bool hitset[4];
+       AliHLTMUONUtils::UnpackMansoTrackFlags(
+                       track.fFlags, sign, hitset
                );
-       for (Int_t i = 0; i < singlesDecisions.GetEntriesFast(); i++)
+       
+       // Try find the trigger record in 'event'.
+       const AliHLTMUONTriggerRecord* trigrec = NULL;
+       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
+       {
+               if (event.Array()[k]->IsA() != AliHLTMUONTriggerRecord::Class())
+                       continue;
+               const AliHLTMUONTriggerRecord* tk =
+                       static_cast<const AliHLTMUONTriggerRecord*>(event.Array()[k]);
+               if (tk->Id() == track.fTrigRec)
+               {
+                       trigrec = tk;
+                       break;
+               }
+       }
+       
+       // Now try find the hits in 'event'.
+       // If they cannot be found then create new ones.
+       const AliHLTMUONRecHit* hit7 = NULL;
+       const AliHLTMUONRecHit* hit8 = NULL;
+       const AliHLTMUONRecHit* hit9 = NULL;
+       const AliHLTMUONRecHit* hit10 = NULL;
+       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
+       {
+               if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
+                       continue;
+               const AliHLTMUONRecHit* h =
+                       static_cast<const AliHLTMUONRecHit*>(event.Array()[k]);
+               
+               if (hitset[0] and h->X() == track.fHit[0].fX and h->Y() == track.fHit[0].fY
+                       and h->Z() == track.fHit[0].fZ)
+               {
+                       hit7 = h;
+               }
+               if (hitset[1] and h->X() == track.fHit[1].fX and h->Y() == track.fHit[1].fY
+                       and h->Z() == track.fHit[1].fZ)
+               {
+                       hit8 = h;
+               }
+               if (hitset[2] and h->X() == track.fHit[2].fX and h->Y() == track.fHit[2].fY
+                       and h->Z() == track.fHit[2].fZ)
+               {
+                       hit9 = h;
+               }
+               if (hitset[3] and h->X() == track.fHit[3].fX and h->Y() == track.fHit[3].fY
+                       and h->Z() == track.fHit[3].fZ)
+               {
+                       hit10 = h;
+               }
+       }
+       AliHLTMUONRecHit* newhit;
+       if (hitset[0] and hit7 == NULL)
+       {
+               newhit = new AliHLTMUONRecHit(track.fHit[0].fX, track.fHit[0].fY, track.fHit[0].fZ);
+               event.Add(newhit);
+               hit7 = newhit;
+       }
+       if (hitset[1] and hit8 == NULL)
+       {
+               newhit = new AliHLTMUONRecHit(track.fHit[1].fX, track.fHit[1].fY, track.fHit[1].fZ);
+               event.Add(newhit);
+               hit8 = newhit;
+       }
+       if (hitset[2] and hit9 == NULL)
        {
-               AliHLTMUONDecision::AliTrackDecision* decision =
-                       static_cast<AliHLTMUONDecision::AliTrackDecision*>( singlesDecisions[i] );
-               triggerDecision->AddDecision(decision);
+               newhit = new AliHLTMUONRecHit(track.fHit[2].fX, track.fHit[2].fY, track.fHit[2].fZ);
+               event.Add(newhit);
+               hit9 = newhit;
        }
-       for (Int_t j = 0; j < pairsDecisions.GetEntriesFast(); j++)
+       if (hitset[3] and hit10 == NULL)
        {
-               AliHLTMUONDecision::AliPairDecision* decision =
-                       static_cast<AliHLTMUONDecision::AliPairDecision*>( pairsDecisions[j] );
-               triggerDecision->AddDecision(decision);
+               newhit = new AliHLTMUONRecHit(track.fHit[3].fX, track.fHit[3].fY, track.fHit[3].fZ);
+               event.Add(newhit);
+               hit10 = newhit;
        }
-       event.Add(triggerDecision);
+
+       AliHLTMUONMansoTrack* tr = new AliHLTMUONMansoTrack(
+                       track.fId, sign, track.fPx, track.fPy, track.fPz, track.fChi2,
+                       trigrec, hit7, hit8, hit9, hit10
+               );
+       event.Add(tr);
+       return tr;
+}
+
+
+AliHLTMUONTrack* AliHLTMUONRootifierComponent::AddTrack(
+               AliHLTMUONEvent& event, const AliHLTMUONTrackStruct& track
+       )
+{
+       // Converts the track structure and adds it to the event object.
        
-       PushBack(&event, "ROOTEVNT", "MUON");
+       AliHLTMUONParticleSign sign;
+       bool hitset[16];
+       AliHLTMUONUtils::UnpackTrackFlags(
+                       track.fFlags, sign, hitset
+               );
        
-       return 0;
-}
+       // Try find the trigger record in 'event'.
+       const AliHLTMUONTriggerRecord* trigrec = NULL;
+       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
+       {
+               if (event.Array()[k]->IsA() != AliHLTMUONTriggerRecord::Class())
+                       continue;
+               const AliHLTMUONTriggerRecord* tk =
+                       static_cast<const AliHLTMUONTriggerRecord*>(event.Array()[k]);
+               if (tk->Id() == track.fTrigRec)
+               {
+                       trigrec = tk;
+                       break;
+               }
+       }
+       
+       // Now try find the hits in 'event'.
+       // If they cannot be found then create new ones.
+       const AliHLTMUONRecHit* hits[16];
+       for (int i = 0; i < 16; ++i) hits[i] = NULL;
+       for (Int_t k = 0; k < event.Array().GetEntriesFast(); k++)
+       {
+               if (event.Array()[k]->IsA() != AliHLTMUONRecHit::Class())
+                       continue;
+               const AliHLTMUONRecHit* h =
+                       static_cast<const AliHLTMUONRecHit*>(event.Array()[k]);
+               for (int i = 0; i < 16; ++i)
+               {
+                       if (hitset[i] and h->X() == track.fHit[i].fX and h->Y() == track.fHit[i].fY
+                           and h->Z() == track.fHit[i].fZ)
+                       {
+                               hits[i] = h;
+                       }
+               }
+       }
+       AliHLTMUONRecHit* newhit;
+       for (int i = 0; i < 16; ++i)
+       {
+               if (hitset[i] and hits[i] == NULL)
+               {
+                       newhit = new AliHLTMUONRecHit(track.fHit[i].fX, track.fHit[i].fY, track.fHit[i].fZ);
+                       event.Add(newhit);
+                       hits[i] = newhit;
+               }
+       }
 
+       AliHLTMUONTrack* tr = new AliHLTMUONTrack(
+                       track.fId, sign, track.fPx, track.fPy, track.fPz,
+                       track.fInverseBendingMomentum, track.fThetaX, track.fThetaY,
+                       track.fX, track.fY, track.fZ, track.fChi2,
+                       trigrec, hits
+               );
+       event.Add(tr);
+       return tr;
+}