]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/TPCLib/AliHLTTPCClusterAccessHLTOUT.cxx
bugfix: correct calculation of remaining payload to detect decoding errors
[u/mrichter/AliRoot.git] / HLT / TPCLib / AliHLTTPCClusterAccessHLTOUT.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /// @file   AliHLTTPCClusterAccessHLTOUT.h
20 /// @author Matthias Richter
21 /// @date   2011-06-06
22 /// @brief  Interface to HLT TPC clusters
23 ///
24
25 #include "AliHLTTPCClusterAccessHLTOUT.h"
26 #include "AliHLTTPCDataCompressionDecoder.h"
27 #include "AliHLTTPCDefinitions.h"
28 #include "AliHLTTPCClusterDataFormat.h"
29 #include "AliHLTTPCRawCluster.h"
30 #include "AliHLTTPCTransform.h"
31 #include "AliHLTOUT.h"
32 #include "AliHLTComponent.h"
33 #include "AliHLTErrorGuard.h"
34 #include "AliHLTDataInflater.h"
35 #include "AliHLTTPCDefinitions.h"
36 #include "AliLog.h"
37 #include "AliHLTSystem.h"
38 #include "AliHLTPluginBase.h"
39 #include "AliTPCclusterMI.h"
40 #include "TClonesArray.h"
41 #include <cstdlib>
42 #include <string>
43 #include <memory>
44 #include <iostream>
45 #include <iomanip>
46
47 /** ROOT macro for the implementation of ROOT specific class methods */
48 ClassImp(AliHLTTPCClusterAccessHLTOUT)
49
50 AliHLTTPCClusterAccessHLTOUT::AliHLTTPCClusterAccessHLTOUT()
51   : TObject()
52   , fVerbosity(0)
53   , fClusters(NULL)
54   , fCurrentSector(-1)
55 {
56   // see header file for class documentation
57   // or
58   // refer to README to build package
59   // or
60   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
61 }
62
63 AliHLTTPCClusterAccessHLTOUT::~AliHLTTPCClusterAccessHLTOUT()
64 {
65   // destructor
66   if (fClusters) {
67     fClusters->Clear();
68     delete fClusters;
69     fClusters=NULL;
70   }
71 }
72
73 void AliHLTTPCClusterAccessHLTOUT::Execute(const char *method,  const char *params, Int_t *error)
74 {
75   /// inherited from TObject: abstract command interface
76   if (strcmp(method, "read")==0) {
77     int iResult=ProcessClusters(params);
78     if (error) *error=iResult;
79     return;
80   }
81   if (strcmp(method, "verbosity")==0) {
82     int iResult=0;
83     if (params) {
84       char* dummy;
85       int value=strtol(params, &dummy, 0);
86       if (dummy==NULL) {
87         fVerbosity=value;
88       } else {
89         AliError("invalid argument for command 'verbosity', expecting string with number");
90       }
91     } else {
92       iResult=-EINVAL;
93     }
94     if (error) *error=iResult;
95     return;
96   }
97 }
98
99 TObject* AliHLTTPCClusterAccessHLTOUT::FindObject(const char *name) const
100 {
101   /// inherited from TObject: return the cluster array if name id "clusterarray"
102   if (strcmp(name, "clusterarray")==0) {
103     if (fCurrentSector<0) return NULL;
104     return fClusters->GetSectorArray(fCurrentSector);
105   }
106   return TObject::FindObject(name);
107 }
108
109 void AliHLTTPCClusterAccessHLTOUT::Clear(Option_t * option)
110 {
111   /// inherited from TObject: cleanup
112   if (strcmp(option, "event")==0) {
113     if (fClusters) fClusters->Clear();
114     fCurrentSector=-1;
115   }
116 }
117
118 void AliHLTTPCClusterAccessHLTOUT::Print(Option_t *option) const
119 {
120   /// inherited from TObject
121   if (fClusters) fClusters->Print(option);
122 }
123
124 int AliHLTTPCClusterAccessHLTOUT::ProcessClusters(const char* params)
125 {
126   /// process the cluster data from HLTOUT and fill array
127   /// the cluster data can be in many different formats, e.g.
128   /// raw or compressed
129   int iResult=0;
130   TString strparams(params);
131   int sector=-1;
132   std::auto_ptr<TObjArray> tokens(strparams.Tokenize(" "));
133   if (!tokens.get()) return -ENOMEM;
134   for (int i=0; i< tokens->GetEntriesFast(); i++) {
135     if (!tokens->At(i)) continue;
136     TString argument=tokens->At(i)->GetName();
137     // the offline code enumerates first the 36 inner (partitions 0+1) and then 36 outer
138     // sectors (partitions 2-5)
139     if (argument.BeginsWith("sector=")) {
140       argument.ReplaceAll("sector=", "");
141       sector=argument.Atoi();
142     }
143   }
144   if (sector<0) {
145     AliError("invalid argument, please specify \"sector=sectorno\"");
146     return -EINVAL;
147   }
148   if (sector>=76) {
149     AliError(Form("invalid sector number %d", sector));
150     return -EINVAL;
151   }
152
153   if (!fClusters) {
154     fClusters=new AliTPCclusterMIContainer;
155   }
156   if (!fClusters) return -ENOMEM;
157
158   if (fCurrentSector>=0) {
159     // cluster container already filled
160     fCurrentSector=sector;
161     TObjArray* pArray=fClusters->GetSectorArray(fCurrentSector);
162     if (!pArray) {
163       AliError(Form("can not get cluster array for sector %d", sector));
164       return -ENOBUFS;
165     }
166     if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) for sector %d", pArray->GetEntriesFast() ,sector));
167     return pArray->GetEntriesFast();
168   }
169
170   // fill the cluster container
171   AliHLTSystem* pSystem=AliHLTPluginBase::GetInstance();
172   if (!pSystem) {
173     AliError("can not access HLT system");
174     return -ENODEV;
175   }
176   AliHLTOUT* pHLTOUT=pSystem->RequestHLTOUT();
177   if (!pHLTOUT) {
178     AliError("can not access HLTOUT");
179     return -EACCES;
180   }
181
182   bool bNextBlock=false;
183   bool bHaveLabels=false;
184   bool bHaveIds=false;
185   // add cluster id and mc information data blocks
186   for (bNextBlock=(pHLTOUT->SelectFirstDataBlock()>=0);
187        bNextBlock; bNextBlock=(pHLTOUT->SelectNextDataBlock()>=0)) {
188     AliHLTComponentBlockData desc;
189     // FIXME: extend HLTOUT to get the full descriptor
190     const AliHLTUInt8_t* buffer=NULL;
191     if ((iResult=pHLTOUT->GetDataBuffer(buffer, desc.fSize))<0) {
192       continue;
193     }
194     desc.fPtr=(void*)buffer;
195     if (pHLTOUT->GetDataBlockDescription(desc.fDataType, desc.fSpecification)<0) {
196       continue;
197     }
198     if (desc.fDataType==AliHLTTPCDefinitions::AliHLTDataTypeClusterMCInfo()) {
199       // add mc information
200       if ((iResult=fClusters->AddClusterMCData(&desc))<0) {
201         return iResult;
202       }
203       bHaveLabels=true;
204     }
205     if (desc.fDataType==AliHLTTPCDefinitions::RemainingClusterIdsDataType() ||
206         desc.fDataType==AliHLTTPCDefinitions::ClusterIdTracksDataType()) {
207       // add cluster ids
208       if ((iResult=fClusters->AddClusterIds(&desc))<0) {
209         return iResult;
210       }
211       bHaveIds=true;
212     }
213   }
214
215   bool bHavePartitionRawData=false;
216   bool bHavePartitionCompressedData=false;
217   vector<bool> bHavePartitionData(216, false);
218
219   // read data
220   iResult=-ENODATA;
221   AliHLTTPCDataCompressionDecoder decoder;
222   decoder.SetVerbosity(fVerbosity);
223   int nExtractedClusters=0;
224   for (bNextBlock=(pHLTOUT->SelectFirstDataBlock()>=0);
225        bNextBlock; bNextBlock=(pHLTOUT->SelectNextDataBlock()>=0)) {
226     decoder.SetPadShift(0.0);
227     AliHLTComponentBlockData desc;
228     // FIXME: extend HLTOUT to get the full descriptor with one call
229     const AliHLTUInt8_t* buffer=NULL;
230     if ((iResult=pHLTOUT->GetDataBuffer(buffer, desc.fSize))<0) {
231       continue;
232     }
233     desc.fPtr=(void*)buffer;
234     if (pHLTOUT->GetDataBlockDescription(desc.fDataType, desc.fSpecification)<0) {
235       continue;
236     }
237     if (!TestBit(kSkipPartitionClusters) &&
238         (desc.fDataType==AliHLTTPCDefinitions::RawClustersDataType())) {
239       // This is a special handling of data blocks produced with v5-01-Release
240       // The pad shift by 0.5 was not included in the data but was applied in the
241       // unpacking in this class. Changed in r51306, the next tag containing this
242       // change in the online system is v5-01-Rev-07. There are only very few runs
243       // of Sep 2011 with recorded clusters not containing the 0.5 shift
244       // There was also a chenge in the data type of the compressed partition
245       // cluster blocks which helps to identify the blocks which need the pad shift
246       // here
247       if (desc.fSize<sizeof(AliHLTTPCRawClusterData)) continue;
248       const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(buffer);
249       if (!clusterData) continue;
250       if (clusterData->fVersion==1) {
251         // compressed clusters without the pad shift
252         // no raw clusters (version==0) have ever been recorded
253         decoder.SetPadShift(0.5);
254       }
255       AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(desc.fSpecification);
256       AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(desc.fSpecification);
257       if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(desc.fSpecification) ||
258           partition!=AliHLTTPCDefinitions::GetMaxPatchNr(desc.fSpecification)) {
259         AliFatal(Form("inconsistent cluster data: can not handle blocks containing multiple partitions, "
260                       "block specification 0x%08x", desc.fSpecification));
261       }
262       iResult=decoder.ReadClustersPartition(fClusters->BeginRemainingClusterBlock(0, desc.fSpecification),
263                                             reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
264                                             desc.fSize,
265                                             desc.fSpecification);
266       if (iResult>0) nExtractedClusters+=iResult;
267       unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
268       if (index>=bHavePartitionData.size()) bHavePartitionData.resize(index, false);
269       if (bHavePartitionData[index]) {
270         AliFatal(Form("inconsistent cluster data: multiple data blocks of identical specification indicate a failure "
271                       "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
272                       "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
273                       "block specification 0x%08x", desc.fSpecification));
274       }
275       bHavePartitionData[index]=true;
276       if (bHavePartitionCompressedData) {
277         AliFatal(Form("inconsistent cluster data: both compressed and raw cluster blocks present in HLTOUT, indicates a failure "
278                       "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
279                       "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
280                       "block specification 0x%08x", desc.fSpecification));
281       }
282       bHavePartitionRawData=true;
283       continue;
284     } else if (!TestBit(kSkipPartitionClusters) &&
285                (desc.fDataType==AliHLTTPCDefinitions::RemainingClustersCompressedDataType())) {
286       AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(desc.fSpecification);
287       AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(desc.fSpecification);
288       if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(desc.fSpecification) ||
289           partition!=AliHLTTPCDefinitions::GetMaxPatchNr(desc.fSpecification)) {
290         AliFatal(Form("inconsistent cluster data: can not handle blocks containing multiple partitions, "
291                       "block specification 0x%08x", desc.fSpecification));
292       }
293       iResult=decoder.ReadClustersPartition(fClusters->BeginRemainingClusterBlock(0, desc.fSpecification),
294                                             reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
295                                             desc.fSize,
296                                             desc.fSpecification);
297       if (iResult>0) nExtractedClusters+=iResult;
298       unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
299       if (index>=bHavePartitionData.size()) bHavePartitionData.resize(index, false);
300       if (bHavePartitionData[index]) {
301         AliFatal(Form("inconsistent cluster data: multiple data blocks of identical specification indicate a failure "
302                       "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
303                       "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
304                       "block specification 0x%08x", desc.fSpecification));
305       }
306       bHavePartitionData[index]=true;
307       bHavePartitionData[index]=true;
308       if (bHavePartitionRawData) {
309         AliFatal(Form("inconsistent cluster data: both compressed and raw cluster blocks present in HLTOUT, indicates a failure "
310                       "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
311                       "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
312                       "block specification 0x%08x", desc.fSpecification));
313       }
314       bHavePartitionCompressedData=true;
315       continue;
316     } else if (!TestBit(kSkipTrackClusters) &&
317                desc.fDataType==AliHLTTPCDefinitions::ClusterTracksCompressedDataType()) {
318       iResult=decoder.ReadTrackModelClustersCompressed(fClusters->BeginTrackModelClusterBlock(0),
319                                                         reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
320                                                         desc.fSize,
321                                                         desc.fSpecification);
322       continue;
323     }
324   }
325
326   pSystem->ReleaseHLTOUT(pHLTOUT);
327
328   if (iResult<0) return iResult;
329   if (fVerbosity>0) {
330     int nConvertedClusters=0;
331     for (int s=0; s<72; s++) {
332       TObjArray* pArray=fClusters->GetSectorArray(s);
333       if (!pArray) continue;
334       nConvertedClusters+=pArray->GetEntriesFast();
335     }
336     AliInfo(Form("extracted HLT clusters: %d, converted HLT clusters: %d", nExtractedClusters, nConvertedClusters));
337   }
338
339   fCurrentSector=sector;
340   TObjArray* pArray=fClusters->GetSectorArray(fCurrentSector);
341   if (!pArray) {
342     AliError(Form("can not get cluster array for sector %d", sector));
343     return -ENOBUFS;
344   }
345   if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) for sector %d", pArray->GetEntriesFast() ,sector));
346   return pArray->GetEntriesFast();
347 }
348
349 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCClusterMCData(AliHLTOUT* pHLTOUT, AliHLTTPCClusterMCDataList &tpcClusterLabels) const
350 {
351   // read cluster data from AliHLTTPCClusterData
352   int iResult=0;
353   if (!pHLTOUT) return -EINVAL;
354   do {
355     const AliHLTUInt8_t* pBuffer=NULL;
356     AliHLTUInt32_t size=0;
357     if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
358       continue;
359     }
360     if (pBuffer==NULL || size<4) {
361       AliError("invalid cluster mc data block");
362       continue;
363     }
364     const AliHLTTPCClusterMCData* clusterMCData = reinterpret_cast<const AliHLTTPCClusterMCData*>(pBuffer);
365     Int_t nLabels = (Int_t) clusterMCData->fCount;
366     if (nLabels*sizeof(AliHLTTPCClusterMCLabel) + sizeof(AliHLTTPCClusterMCData) != size) {
367       AliError("inconsistent cluster mc data block size, skipping block");
368       continue;
369     }
370     // id of the cluster is 
371     AliHLTComponentDataType dt=kAliHLTVoidDataType;
372     AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
373     if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
374       AliError("failed to retrieve data block description, skipping mc cluster data block ...");
375       continue;
376     }
377     AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
378     AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
379     if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(specification) ||
380         partition!=AliHLTTPCDefinitions::GetMaxPatchNr(specification)) {
381       AliError(Form("can not read cluster mc data block with data of multiple partitions, skipping block %s %08x",
382                     AliHLTComponent::DataType2Text(dt).c_str(), specification));
383       continue;
384     }
385     const AliHLTTPCClusterMCLabel *labels = clusterMCData->fLabels;
386     for (int i=0; i<nLabels; i++) {
387       AliHLTUInt32_t id=AliHLTTPCSpacePointData::GetID(slice, partition, i);
388       if (tpcClusterLabels.find(id)==tpcClusterLabels.end()) {
389         // new cluster
390         tpcClusterLabels[id]=labels[i];
391       } else {
392         AliError(Form("cluster with ID 0x%08x already existing, skipping cluster %d of data block 0x%08x",
393                       id, i, specification));
394       }
395     }
396   } while (pHLTOUT->SelectNextDataBlock()>=0);
397   return iResult;
398 }
399
400 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCClusterData(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels) const
401 {
402   // read cluster data from AliHLTTPCClusterData
403   int iResult=0;
404   if (!pHLTOUT || !pClusters) return -EINVAL;
405   do {
406     const AliHLTUInt8_t* pBuffer=NULL;
407     AliHLTUInt32_t size=0;
408     if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
409       continue;
410     }
411     if (pBuffer==NULL || size<4) {
412       AliError("invalid cluster data block");
413       continue;
414     }
415     AliHLTComponentDataType dt=kAliHLTVoidDataType;
416     AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
417     if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
418       AliError("failed to retrieve data block description, skipping mc cluster data block ...");
419       continue;
420     }
421     const AliHLTTPCClusterData* clusterData = reinterpret_cast<const AliHLTTPCClusterData*>(pBuffer);
422     Int_t nSpacepoints = (Int_t) clusterData->fSpacePointCnt;
423     if (nSpacepoints*sizeof(AliHLTTPCSpacePointData) + sizeof(AliHLTTPCClusterData) != size) {
424       AliError("inconsistent cluster data block size, skipping block");
425       continue;
426     }
427     const AliHLTTPCSpacePointData *clusters = clusterData->fSpacePoints;
428     int offset=pClusters->GetEntries();
429     pClusters->ExpandCreate(offset+nSpacepoints);
430     AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
431     AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
432     // FIXME: get first row number of outer sectors from a common definition instead using number
433     unsigned rowOffset=partition<2?0:63;
434     for (int i=0; i<nSpacepoints; i++) {
435       if (!pClusters->At(offset+i)) continue;
436       AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+i));
437       if (!pCluster) {
438         AliError("invalid object type, expecting AliTPCclusterMI");
439         break; // this is a problem of all objects
440       }
441       if (clusters[i].fPadRow<rowOffset) {
442         AliError(Form("invalid row number %d, expecting minimum row number %d for slice %d partition %d", clusters[i].fPadRow, rowOffset, slice, partition));
443       } else {
444       pCluster->SetRow(clusters[i].fPadRow-rowOffset);
445       }
446       pCluster->SetPad(clusters[i].fY);
447       pCluster->SetTimeBin(clusters[i].fZ);
448       pCluster->SetSigmaY2(clusters[i].fSigmaY2);
449       pCluster->SetSigmaZ2(clusters[i].fSigmaZ2);
450       pCluster->SetQ(clusters[i].fCharge);
451       pCluster->SetMax(clusters[i].fQMax);
452       if (tpcClusterLabels) {
453         if (tpcClusterLabels->find(clusters[i].fID)!=tpcClusterLabels->end()) {
454           const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusters[i].fID)->second.fClusterID;
455           for (int k=0; k<3; k++) {
456             // TODO: sort the labels according to the weight in order to assign the most likely mc label
457             // to the first component 
458             pCluster->SetLabel(mcWeights[k].fMCID, k);
459           }
460         } else {
461           AliError(Form("can not find mc label of cluster with id %0x08x", clusters[i].fID));
462         }
463       }
464     }
465     if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nSpacepoints, AliHLTComponent::DataType2Text(dt).c_str(), specification));
466   } while (pHLTOUT->SelectNextDataBlock()>=0);
467   return iResult;
468 }
469
470 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCRawClusterData(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels)
471 {
472   // read cluster data from AliHLTTPCClusterData
473
474   // FIXME: this is in large parts like ReadAliHLTTPCClusterData,
475   // make a common method
476   int iResult=0;
477   if (!pHLTOUT || !pClusters) return -EINVAL;
478   do {
479     const AliHLTUInt8_t* pBuffer=NULL;
480     AliHLTUInt32_t size=0;
481     if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
482       continue;
483     }
484     if (pBuffer==NULL || size<4) {
485       AliError("invalid cluster data block");
486       continue;
487     }
488     AliHLTComponentDataType dt=kAliHLTVoidDataType;
489     AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
490     if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
491       AliError("failed to retrieve data block description, skipping mc cluster data block ...");
492       continue;
493     }
494     const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(pBuffer);
495     Int_t nCount = (Int_t) clusterData->fCount;
496     if (clusterData->fVersion!=0) {
497       // this is encoded data of different formats
498       switch (clusterData->fVersion) {
499       case 1: 
500         iResult=ReadAliHLTTPCRawClusterDataDeflateSimple(reinterpret_cast<const AliHLTUInt8_t*>(clusterData->fClusters),
501                                                          size-sizeof(AliHLTTPCRawClusterData), nCount, specification,
502                                                          pClusters, tpcClusterLabels);
503         break;
504       default:
505         iResult=-EPROTO;
506       }
507       return iResult;
508     }
509
510     if (nCount*sizeof(AliHLTTPCRawCluster) + sizeof(AliHLTTPCRawClusterData) != size) {
511       AliError("inconsistent cluster data block size, skipping block");
512       continue;
513     }
514     const AliHLTTPCRawCluster *clusters = clusterData->fClusters;
515     int offset=pClusters->GetEntries();
516     pClusters->ExpandCreate(offset+nCount);
517     AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
518     AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
519     // FIXME: get first row number of outer sectors from a common definition instead using number
520     int rowOffset=partition<2?0:63;
521     for (int i=0; i<nCount; i++) {
522       if (!pClusters->At(offset+i)) continue;
523       AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+i));
524       if (!pCluster) {
525         AliError("invalid object type, expecting AliTPCclusterMI");
526         break; // this is a problem of all objects
527       }
528       if (fVerbosity>1) AliInfo(Form("cluster padrow %d (slice %d partition %d)", clusters[i].GetPadRow(), slice, partition));
529       if (clusters[i].GetPadRow()<rowOffset) {
530         AliError(Form("invalid row number %d, expecting minimum row number %d for slice %d partition %d", clusters[i].GetPadRow(), rowOffset, slice, partition));
531       } else {
532       pCluster->SetRow(clusters[i].GetPadRow()-rowOffset);
533       }
534       pCluster->SetPad(clusters[i].GetPad());
535       pCluster->SetTimeBin(clusters[i].GetTime());
536       pCluster->SetSigmaY2(clusters[i].GetSigmaY2());
537       pCluster->SetSigmaZ2(clusters[i].GetSigmaZ2());
538       pCluster->SetQ(clusters[i].GetCharge());
539       pCluster->SetMax(clusters[i].GetQMax());
540       if (tpcClusterLabels) {
541         UInt_t clusterID=AliHLTTPCSpacePointData::GetID(slice, partition, i);
542         if (tpcClusterLabels->find(clusterID)!=tpcClusterLabels->end()) {
543           const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusterID)->second.fClusterID;
544           for (int k=0; k<3; k++) {
545             // TODO: sort the labels according to the weight in order to assign the most likely mc label
546             // to the first component 
547             pCluster->SetLabel(mcWeights[k].fMCID, k);
548           }
549         } else {
550           AliError(Form("can not find mc label of cluster with id %0x08x", clusterID));
551         }
552       }
553     }
554     if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nCount, AliHLTComponent::DataType2Text(dt).c_str(), specification));
555   } while (pHLTOUT->SelectNextDataBlock()>=0);
556   return iResult;
557 }
558
559 int AliHLTTPCClusterAccessHLTOUT::ReadRemainingClustersCompressed(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels)
560 {
561   // read cluster data from AliHLTTPCClusterData
562   int iResult=0;
563   if (!pHLTOUT || !pClusters) return -EINVAL;
564   do {
565     const AliHLTUInt8_t* pBuffer=NULL;
566     AliHLTUInt32_t size=0;
567     if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
568       continue;
569     }
570     if (pBuffer==NULL || size<4) {
571       AliError("invalid cluster data block");
572       continue;
573     }
574     AliHLTComponentDataType dt=kAliHLTVoidDataType;
575     AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
576     if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
577       AliError("failed to retrieve data block description, skipping mc cluster data block ...");
578       continue;
579     }
580     const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(pBuffer);
581     Int_t nCount = (Int_t) clusterData->fCount;
582
583     // this is encoded data of different formats
584     switch (clusterData->fVersion) {
585     case 1: 
586       iResult=ReadAliHLTTPCRawClusterDataDeflateSimple(reinterpret_cast<const AliHLTUInt8_t*>(clusterData->fClusters),
587                                                        size-sizeof(AliHLTTPCRawClusterData), nCount, specification,
588                                                        pClusters, tpcClusterLabels);
589       break;
590     default:
591       AliError(Form("invalid cluster format version %d", clusterData->fVersion));
592       iResult=-EPROTO;
593     }
594
595     if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nCount, AliHLTComponent::DataType2Text(dt).c_str(), specification));
596   } while (pHLTOUT->SelectNextDataBlock()>=0 && iResult>=0);
597
598   return iResult;
599 }
600
601 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCRawClusterDataDeflateSimple(const AliHLTUInt8_t* pData, int dataSize,
602                                                                            int nofClusters, AliHLTUInt32_t specification,
603                                                                            TClonesArray* pClusters,
604                                                                            const AliHLTTPCClusterMCDataList *tpcClusterLabels)
605 {
606   // read cluster data from AliHLTTPCClusterData
607
608   // FIXME: quick implementation to read the compressed cluster data from HLTOUT
609   // the data definition below is the same as in AliHLTTPCDataCompressionComponent
610   // but needs to be moved to a common class (AliHLTTPCDefinitions?)
611   // Think about a decoder class supporting iterator objects for various types
612   // of cluster data
613   int iResult=0;
614   if (!pData || !pClusters) return -EINVAL;
615   AliHLTDataInflater inflater;
616   if ((iResult=inflater.InitBitDataInput(pData, dataSize))<0) {
617     return iResult;
618   }
619
620   int offset=pClusters->GetEntries();
621   pClusters->ExpandCreate(offset+nofClusters);
622   AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
623   AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
624   // the compressed format stores the difference of the local row number in
625   // the partition to the row of the last cluster
626   // add the first row in the partition to get global row number
627   // offline uses row number in physical sector, inner sector consists of
628   // partitions 0 and 1, outer sector of partition 2-5
629   int rowOffset=AliHLTTPCTransform::GetFirstRow(partition)-(partition<2?0:AliHLTTPCTransform::GetFirstRow(2));
630
631   int parameterId=0;
632   int outClusterCnt=0;
633   AliHLTUInt8_t switchBit=0;
634   AliHLTUInt64_t value=0;
635   AliTPCclusterMI* pCluster=NULL;
636   AliHLTUInt32_t lastPadRow=0;
637   while (outClusterCnt<nofClusters && inflater.InputBit(switchBit)) {
638     const AliHLTTPCDefinitions::AliClusterParameter& parameter
639       =AliHLTTPCDefinitions::fgkClusterParameterDefinitions[parameterId];
640     // in mode DeflaterSimple, the optional parameter of the cluster parameter definition
641     // corresponds to the number bits of the reduced format
642     if (!inflater.InputBits(value, switchBit?parameter.fBitLength:parameter.fOptional)) {
643       break;
644     }
645
646     if (!pCluster) {
647       if (!pClusters->At(offset+outClusterCnt)) {
648         // here we should not get anymore because of the condition outClusterCnt<nofClusters
649         return -ENOSPC;
650       }
651       pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+outClusterCnt));
652       if (!pCluster) {
653         AliError("invalid object type, expecting AliTPCclusterMI");
654         iResult=-EBADF; // this is a problem of all objects
655         break;
656       }
657     }
658     switch (parameterId) {
659     case AliHLTTPCDefinitions::kPadRow:
660       {pCluster->SetRow(value+lastPadRow+rowOffset); lastPadRow+=value;break;}
661     case AliHLTTPCDefinitions::kPad:
662       {float pad=value; pad/=parameter.fScale; pCluster->SetPad(pad); break;}
663     case AliHLTTPCDefinitions::kTime:
664       {float time=value; time/=parameter.fScale; pCluster->SetTimeBin(time); break;}
665     case AliHLTTPCDefinitions::kSigmaY2:
666       {float sigmaY2=value; sigmaY2/=parameter.fScale; pCluster->SetSigmaY2(sigmaY2); break;}
667     case AliHLTTPCDefinitions::kSigmaZ2:
668       {float sigmaZ2=value; sigmaZ2/=parameter.fScale; pCluster->SetSigmaZ2(sigmaZ2); break;}
669     case AliHLTTPCDefinitions::kCharge:
670       {pCluster->SetQ(value); break;}
671     case AliHLTTPCDefinitions::kQMax:
672       {pCluster->SetMax(value); break;}
673     }
674     if (parameterId>=AliHLTTPCDefinitions::kLast) {
675       // switch to next cluster
676       if (tpcClusterLabels) {
677         UInt_t clusterID=AliHLTTPCSpacePointData::GetID(slice, partition, outClusterCnt);
678         if (tpcClusterLabels->find(clusterID)!=tpcClusterLabels->end()) {
679           const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusterID)->second.fClusterID;
680           for (int k=0; k<3; k++) {
681             // TODO: sort the labels according to the weight in order to assign the most likely mc label
682             // to the first component 
683             pCluster->SetLabel(mcWeights[k].fMCID, k);
684           }
685         } else {
686           AliError(Form("can not find mc label of cluster with id 0x%08x", clusterID));
687         }
688       }
689       outClusterCnt++;
690       pCluster=NULL;
691       parameterId=-1;
692     }
693     parameterId++;
694   }
695   inflater.Pad8Bits();
696   if (inflater.InputBit(switchBit)) {
697     AliWarning("format error of compressed clusters, there is more data than expected");
698   }
699   inflater.CloseBitDataInput();
700   if (iResult>=0 && nofClusters!=outClusterCnt) {
701     // is this a Fatal?
702     AliError(Form("error reading compressed cluster format: expected %d, read only %d cluster(s)", nofClusters, outClusterCnt));
703     return -EPROTO;
704   }
705   return iResult;
706 }
707
708 AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::AliTPCclusterMIContainer()
709   : fClusterArrays()
710   , fRemainingClusterIds()
711   , fTrackModelClusterIds()
712   , fCurrentClusterIds(NULL)
713   , fClusterMCData()
714   , fIterator()
715
716 {
717   /// constructor
718   for (int i=0; i<72; i++) {
719     fClusterArrays.push_back(new TClonesArray("AliTPCclusterMI"));
720   }
721 }
722
723 AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::~AliTPCclusterMIContainer()
724 {
725   /// dectructor
726   for (vector<TClonesArray*>::iterator i=fClusterArrays.begin(); i!=fClusterArrays.end(); i++) {
727     if (*i) {
728       (*i)->Clear();
729       delete *i;
730     }
731   }
732 }
733
734 AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::BeginRemainingClusterBlock(int /*count*/, AliHLTUInt32_t specification)
735 {
736   /// iterator of remaining clusters block of specification
737   AliHLTUInt8_t slice=AliHLTTPCDefinitions::GetMinSliceNr(specification);
738   AliHLTUInt8_t partition=AliHLTTPCDefinitions::GetMinPatchNr(specification);
739   unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
740   if (index<fRemainingClusterIds.size())
741     fCurrentClusterIds=&fRemainingClusterIds[index];
742   else
743     fCurrentClusterIds=NULL;
744   fIterator=iterator(this);
745   return fIterator;
746 }
747
748 AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::BeginTrackModelClusterBlock(int /*count*/)
749 {
750   /// iterator of track model clusters
751   if (fTrackModelClusterIds.fIds && fTrackModelClusterIds.fSize>0)
752     fCurrentClusterIds=&fTrackModelClusterIds;
753   else
754     fCurrentClusterIds=NULL;
755   fIterator=iterator(this);
756   return fIterator;
757 }
758
759 int AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::AddClusterMCData(const AliHLTComponentBlockData* pDesc)
760 {
761   /// add cluster mc data block
762   if (!pDesc) return -EINVAL;
763   if (pDesc->fDataType==AliHLTTPCDefinitions::AliHLTDataTypeClusterMCInfo()) {
764     AliHLTUInt8_t slice=AliHLTTPCDefinitions::GetMinSliceNr(pDesc->fSpecification);
765     AliHLTUInt8_t partition=AliHLTTPCDefinitions::GetMinPatchNr(pDesc->fSpecification);
766     unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
767     if (fClusterMCData.size()<=index) {
768       if ((int)fClusterMCData.size()<AliHLTTPCTransform::GetNSlice()*AliHLTTPCTransform::GetNumberOfPatches()) {
769         fClusterMCData.resize(AliHLTTPCTransform::GetNSlice()*AliHLTTPCTransform::GetNumberOfPatches(), NULL);
770       } else {
771         fClusterMCData.resize(index+1, NULL);
772       }
773     }
774     if (pDesc->fSize<sizeof(AliHLTTPCClusterMCData)) return -EINVAL;
775     const AliHLTTPCClusterMCData* pData=reinterpret_cast<const AliHLTTPCClusterMCData*>(pDesc->fPtr);
776     unsigned nLabels = pData->fCount;
777     if (nLabels*sizeof(AliHLTTPCClusterMCLabel) + sizeof(AliHLTTPCClusterMCData) != pDesc->fSize) {
778       return -EINVAL;
779     }
780     fClusterMCData[index]=pData;
781     return 0;
782   }
783   return -ENODATA;
784 }
785
786 int AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::AddClusterIds(const AliHLTComponentBlockData* pDesc)
787 {
788   /// add cluster id block for remaining or track model clusters
789   if (!pDesc) return -EINVAL;
790   if (pDesc->fDataType==AliHLTTPCDefinitions::ClusterIdTracksDataType()) {
791     fTrackModelClusterIds.fIds=reinterpret_cast<AliHLTUInt32_t*>(pDesc->fPtr);
792     fTrackModelClusterIds.fSize=pDesc->fSize/sizeof(AliHLTUInt32_t);
793     return 0;
794   }
795   if (pDesc->fDataType==AliHLTTPCDefinitions::RemainingClusterIdsDataType()) {
796     AliHLTUInt8_t slice=AliHLTTPCDefinitions::GetMinSliceNr(pDesc->fSpecification);
797     AliHLTUInt8_t partition=AliHLTTPCDefinitions::GetMinPatchNr(pDesc->fSpecification);
798     unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
799     if (fRemainingClusterIds.size()<=index) {
800       if ((int)fRemainingClusterIds.size()<AliHLTTPCTransform::GetNSlice()*AliHLTTPCTransform::GetNumberOfPatches()) {
801         fRemainingClusterIds.resize(AliHLTTPCTransform::GetNSlice()*AliHLTTPCTransform::GetNumberOfPatches());
802       } else {
803         fRemainingClusterIds.resize(index+1);
804       }
805     }
806     fRemainingClusterIds[index].fIds=reinterpret_cast<AliHLTUInt32_t*>(pDesc->fPtr);
807     fRemainingClusterIds[index].fSize=pDesc->fSize/sizeof(AliHLTUInt32_t);
808     return 0;
809   }
810   return -ENODATA;
811 }
812
813 AliHLTUInt32_t AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::GetClusterId(int clusterNo) const
814 {
815   /// get the cluster id from the current cluster id block (optional)
816   if (!fCurrentClusterIds ||
817       (int)fCurrentClusterIds->fSize<=clusterNo ||
818       clusterNo<0)
819     return kAliHLTVoidDataSpec;
820   return fCurrentClusterIds->fIds[clusterNo];
821 }
822
823 AliTPCclusterMI* AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::NextCluster(int slice, int partition)
824 {
825   /// load next cluster from array of the sepcific sector
826   unsigned sector=partition<2?slice:slice+36;
827   if (fClusterArrays.size()<=sector ||
828       fClusterArrays[sector]==NULL) {
829     AliErrorClass(Form("no cluster array available for sector %d", sector));
830     return NULL;
831   }
832   TClonesArray& array=*(fClusterArrays[sector]);
833   int count=array.GetEntriesFast();
834   return new (array[count]) AliTPCclusterMI;
835 }
836
837 int AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::SetMC(AliTPCclusterMI* pCluster, AliHLTUInt32_t clusterId)
838 {
839   /// set MC data for the cluster
840   if (!pCluster) return -EINVAL;
841   if (clusterId==kAliHLTVoidDataSpec) return 0;
842
843   unsigned slice=AliHLTTPCSpacePointData::GetSlice(clusterId);
844   unsigned partition=AliHLTTPCSpacePointData::GetPatch(clusterId);
845   unsigned number=AliHLTTPCSpacePointData::GetNumber(clusterId);
846   if ((int)slice>=AliHLTTPCTransform::GetNSlice() ||
847       (int)partition>=AliHLTTPCTransform::GetNumberOfPatches()) return -EDOM;
848   unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
849   if (fClusterMCData.size()<=index ||
850       fClusterMCData[index]==NULL ||
851       fClusterMCData[index]->fCount<=number) return 0;
852   const AliHLTTPCClusterMCWeight* mcWeights=fClusterMCData[index]->fLabels[number].fClusterID;
853   for (int k=0; k<3; k++) {
854     // TODO: sort the labels according to the weight in order to assign the most likely mc label
855     // to the first component 
856     pCluster->SetLabel(mcWeights[k].fMCID, k);
857   }
858
859   return 0;
860 }
861
862 void  AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::Clear(Option_t* /*option*/)
863 {
864   /// internal cleanup
865   {
866     for (vector<TClonesArray*>::iterator i=fClusterArrays.begin(); i!=fClusterArrays.end(); i++)
867       if (*i) (*i)->Clear();
868   }
869   {
870     for (vector<AliClusterIdBlock>::iterator i=fRemainingClusterIds.begin(); i!=fRemainingClusterIds.end(); i++)
871       {i->fIds=NULL; i->fSize=0;}
872   }
873   fTrackModelClusterIds.fIds=NULL; fTrackModelClusterIds.fSize=0;
874   fCurrentClusterIds=NULL;
875   {
876     for (vector<const AliHLTTPCClusterMCData*>::iterator i=fClusterMCData.begin(); i!=fClusterMCData.end(); i++)
877       *i=NULL;
878   }
879 }
880
881 TObjArray* AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::GetSectorArray(unsigned sector) const
882 {
883   /// get the cluster array for a sector
884   if (fClusterArrays.size()<=sector) return NULL;
885   return fClusterArrays[sector];
886 }
887
888 void AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::Print(Option_t *option) const
889 {
890   /// inherited from TObject
891   cout << "AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer" << endl;
892   ios::fmtflags coutflags=cout.flags(); // backup cout status flags
893   bool bAll=false;
894   if ((bAll=(strcmp(option, "full")==0)) ||
895       strcmp(option, "short")==0) {
896     for (unsigned iArray=0; iArray<fClusterArrays.size(); iArray++) {
897       if (fClusterArrays[iArray]) {
898         TClonesArray* pArray=fClusterArrays[iArray];
899         cout << "  sector " << setfill(' ') << setw(2) << iArray << ": " << pArray->GetEntriesFast() << endl;
900         if (bAll) {
901           for (int iCluster=0; iCluster<pArray->GetEntriesFast(); iCluster++) {
902             if (!pArray->At(iCluster)) continue;
903             AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(pArray->At(iCluster));
904             if (!pCluster) break;
905             cout << "    AliTPCclusterMI:"
906                  << "  row="    << pCluster->GetRow() 
907                  << "  pad="    << pCluster->GetPad()
908                  << "  time="   << pCluster->GetTimeBin()
909                  << "  charge=" << pCluster->GetQ()
910                  << "  maxq="   << pCluster->GetMax()
911                  << endl;
912           }
913         }
914       }
915     }
916   }
917   cout.flags(coutflags); // restore the original flags
918 }
919
920 AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliTPCclusterMIContainer::iterator::Next(int slice, int partition)
921 {
922   // switch to next cluster
923   if (!fData) {
924     fCluster=NULL;
925     fClusterId=kAliHLTVoidDataSpec;
926     return *this;
927   }
928   if (fClusterNo>=0 && !fCluster) {
929     // end was reached before
930     return *this;
931   }
932   fCluster=fData->NextCluster(slice, partition);
933   fClusterId=fData->GetClusterId(++fClusterNo);
934   if (fCluster && fClusterId!=kAliHLTVoidDataSpec) {
935     fData->SetMC(fCluster, fClusterId);
936   }
937   // offline uses row number in physical sector, inner sector consists of
938   // partitions 0 and 1, outer sector of partition 2-5
939   fRowOffset=partition<2?0:AliHLTTPCTransform::GetFirstRow(2);
940   return *this;
941 }