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