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