3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project *
5 //* ALICE Experiment at CERN, All rights reserved. *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> *
8 //* for The ALICE HLT Project. *
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 //**************************************************************************
19 /// @file AliHLTTPCClusterAccessHLTOUT.h
20 /// @author Matthias Richter
22 /// @brief Interface to HLT TPC clusters
25 #include "AliHLTTPCClusterAccessHLTOUT.h"
26 #include "AliHLTTPCDefinitions.h"
27 #include "AliHLTTPCClusterDataFormat.h"
28 #include "AliHLTTPCRawCluster.h"
29 #include "AliHLTTPCTransform.h"
30 #include "AliHLTOUT.h"
31 #include "AliHLTComponent.h"
32 #include "AliHLTErrorGuard.h"
33 #include "AliHLTDataInflater.h"
34 #include "AliHLTTPCDefinitions.h"
36 #include "AliHLTSystem.h"
37 #include "AliHLTPluginBase.h"
38 #include "AliTPCclusterMI.h"
39 #include "TClonesArray.h"
44 /** ROOT macro for the implementation of ROOT specific class methods */
45 ClassImp(AliHLTTPCClusterAccessHLTOUT)
47 AliHLTTPCClusterAccessHLTOUT::AliHLTTPCClusterAccessHLTOUT()
52 // see header file for class documentation
54 // refer to README to build package
56 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
59 AliHLTTPCClusterAccessHLTOUT::~AliHLTTPCClusterAccessHLTOUT()
69 void AliHLTTPCClusterAccessHLTOUT::Execute(const char *method, const char *params, Int_t *error)
71 /// inherited from TObject: abstract command interface
72 if (strcmp(method, "read")==0) {
73 int iResult=ProcessClusters(params);
74 if (error) *error=iResult;
77 if (strcmp(method, "verbosity")==0) {
81 int value=strtol(params, &dummy, 0);
85 AliError("invalid argument for command 'verbosity', expecting string with number");
90 if (error) *error=iResult;
95 TObject* AliHLTTPCClusterAccessHLTOUT::FindObject(const char *name) const
97 /// inherited from TObject: return the cluster array if name id "clusterarray"
98 if (strcmp(name, "clusterarray")==0) return fClusters;
99 return TObject::FindObject(name);
102 void AliHLTTPCClusterAccessHLTOUT::Clear(Option_t * /*option*/)
104 /// inherited from TObject: cleanup
105 if (fClusters) fClusters->Clear();
108 void AliHLTTPCClusterAccessHLTOUT::Print(Option_t */*option*/) const
110 /// inherited from TObject
111 if (!fClusters) return;
112 for (int i=0; i<fClusters->GetEntriesFast(); i++) {
113 if (!fClusters->At(i)) continue;
114 AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(fClusters->At(i));
115 if (!pCluster) break;
116 cout << "AliTPCclusterMI:"
117 << " row=" << pCluster->GetRow()
118 << " pad=" << pCluster->GetPad()
119 << " time=" << pCluster->GetTimeBin()
120 << " charge=" << pCluster->GetQ()
121 << " maxq=" << pCluster->GetMax()
126 int AliHLTTPCClusterAccessHLTOUT::ProcessClusters(const char* params)
128 /// process the cluster data from HLTOUT and fill array
129 /// the cluster data can be in many different formats, e.g.
130 /// raw or compressed
132 TString strparams(params);
133 int minSlice=0, maxSlice=35, minPart=0, maxPart=5;
134 std::auto_ptr<TObjArray> tokens(strparams.Tokenize(" "));
135 if (!tokens.get()) return -ENOMEM;
136 for (int i=0; i< tokens->GetEntriesFast(); i++) {
137 if (!tokens->At(i)) continue;
138 TString argument=tokens->At(i)->GetName();
139 if (argument.BeginsWith("sector=")) {
140 argument.ReplaceAll("sector=", "");
141 int sector=argument.Atoi();
142 // the offline code enumerates first the 36 inner (partitions 0+1) and then 36 outer
143 // sectors (partitions 2-5)
144 if (fVerbosity>0) AliInfo(Form("processing HLT clusters for sector %d", sector));
145 if (sector<36) { // inner sectors
146 minSlice=maxSlice=sector;
147 minPart=0; maxPart=1;
148 } else { // outer sectors
149 minSlice=maxSlice=sector-36;
150 minPart=2; maxPart=5;
156 fClusters=new TClonesArray("AliTPCclusterMI");
158 if (!fClusters) return -ENOMEM;
160 AliHLTSystem* pSystem=AliHLTPluginBase::GetInstance();
162 AliError("can not access HLT system");
165 AliHLTOUT* pHLTOUT=pSystem->RequestHLTOUT();
167 AliError("can not access HLTOUT");
171 for (int slice=minSlice; slice<=maxSlice; slice++) {
172 for (int part=minPart; part<=maxPart; part++) {
173 if (fVerbosity>0) AliInfo(Form("processing HLT clusters for slice %d partitions %d", slice, part));
174 AliHLTUInt32_t spec=slice<<24 | slice<<16 | part<<8 | part;
175 AliHLTTPCClusterMCDataList tpcClusterLabels;
176 bool bHaveLabels=false;
177 if (pHLTOUT->SelectFirstDataBlock(AliHLTTPCDefinitions::fgkAliHLTDataTypeClusterMCInfo, spec)>=0) {
178 iResult=ReadAliHLTTPCClusterMCData(pHLTOUT, tpcClusterLabels);
182 if (pHLTOUT->SelectFirstDataBlock(AliHLTTPCDefinitions::RemainingClustersCompressedDataType(), spec)>=0) {
183 iResult=ReadRemainingClustersCompressed(pHLTOUT, fClusters, bHaveLabels?&tpcClusterLabels:NULL);
184 } else if (pHLTOUT->SelectFirstDataBlock(AliHLTTPCDefinitions::fgkRawClustersDataType, spec)>=0) {
185 iResult=ReadAliHLTTPCRawClusterData(pHLTOUT, fClusters, bHaveLabels?&tpcClusterLabels:NULL);
186 } else if (pHLTOUT->SelectFirstDataBlock(AliHLTTPCDefinitions::fgkClustersDataType, spec)>=0) {
187 ALIHLTERRORGUARD(1, "HLTOUT data contains tarnsformed TPC clusters instead of raw TPC clusters, can not create clusters for reconstruction");
192 pSystem->ReleaseHLTOUT(pHLTOUT);
196 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCClusterMCData(AliHLTOUT* pHLTOUT, AliHLTTPCClusterMCDataList &tpcClusterLabels) const
198 // read cluster data from AliHLTTPCClusterData
200 if (!pHLTOUT) return -EINVAL;
202 const AliHLTUInt8_t* pBuffer=NULL;
203 AliHLTUInt32_t size=0;
204 if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
207 if (pBuffer==NULL || size<4) {
208 AliError("invalid cluster mc data block");
211 const AliHLTTPCClusterMCData* clusterMCData = reinterpret_cast<const AliHLTTPCClusterMCData*>(pBuffer);
212 Int_t nLabels = (Int_t) clusterMCData->fCount;
213 if (nLabels*sizeof(AliHLTTPCClusterMCLabel) + sizeof(AliHLTTPCClusterMCData) != size) {
214 AliError("inconsistent cluster mc data block size, skipping block");
217 // id of the cluster is
218 AliHLTComponentDataType dt=kAliHLTVoidDataType;
219 AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
220 if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
221 AliError("failed to retrieve data block description, skipping mc cluster data block ...");
224 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
225 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
226 if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(specification) ||
227 partition!=AliHLTTPCDefinitions::GetMaxPatchNr(specification)) {
228 AliError(Form("can not read cluster mc data block with data of multiple partitions, skipping block %s %08x",
229 AliHLTComponent::DataType2Text(dt).c_str(), specification));
232 const AliHLTTPCClusterMCLabel *labels = clusterMCData->fLabels;
233 for (int i=0; i<nLabels; i++) {
234 AliHLTUInt32_t id=AliHLTTPCSpacePointData::GetID(slice, partition, i);
235 if (tpcClusterLabels.find(id)==tpcClusterLabels.end()) {
237 tpcClusterLabels[id]=labels[i];
239 AliError(Form("cluster with ID 0x%08x already existing, skipping cluster %d of data block 0x%08x",
240 id, i, specification));
243 } while (pHLTOUT->SelectNextDataBlock()>=0);
247 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCClusterData(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels) const
249 // read cluster data from AliHLTTPCClusterData
251 if (!pHLTOUT || !pClusters) return -EINVAL;
253 const AliHLTUInt8_t* pBuffer=NULL;
254 AliHLTUInt32_t size=0;
255 if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
258 if (pBuffer==NULL || size<4) {
259 AliError("invalid cluster data block");
262 AliHLTComponentDataType dt=kAliHLTVoidDataType;
263 AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
264 if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
265 AliError("failed to retrieve data block description, skipping mc cluster data block ...");
268 const AliHLTTPCClusterData* clusterData = reinterpret_cast<const AliHLTTPCClusterData*>(pBuffer);
269 Int_t nSpacepoints = (Int_t) clusterData->fSpacePointCnt;
270 if (nSpacepoints*sizeof(AliHLTTPCSpacePointData) + sizeof(AliHLTTPCClusterData) != size) {
271 AliError("inconsistent cluster data block size, skipping block");
274 const AliHLTTPCSpacePointData *clusters = clusterData->fSpacePoints;
275 int offset=pClusters->GetEntries();
276 pClusters->ExpandCreate(offset+nSpacepoints);
277 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
278 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
279 // FIXME: get first row number of outer sectors from a common definition instead using number
280 unsigned rowOffset=partition<2?0:63;
281 for (int i=0; i<nSpacepoints; i++) {
282 if (!pClusters->At(offset+i)) continue;
283 AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+i));
285 AliError("invalid object type, expecting AliTPCclusterMI");
286 break; // this is a problem of all objects
288 if (clusters[i].fPadRow<rowOffset) {
289 AliError(Form("invalid row number %d, expecting minimum row number %d for slice %d partition %d", clusters[i].fPadRow, rowOffset, slice, partition));
291 pCluster->SetRow(clusters[i].fPadRow-rowOffset);
293 pCluster->SetPad(clusters[i].fY);
294 pCluster->SetTimeBin(clusters[i].fZ);
295 pCluster->SetSigmaY2(clusters[i].fSigmaY2);
296 pCluster->SetSigmaZ2(clusters[i].fSigmaZ2);
297 pCluster->SetQ(clusters[i].fCharge);
298 pCluster->SetMax(clusters[i].fQMax);
299 if (tpcClusterLabels) {
300 if (tpcClusterLabels->find(clusters[i].fID)!=tpcClusterLabels->end()) {
301 const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusters[i].fID)->second.fClusterID;
302 for (int k=0; k<3; k++) {
303 // TODO: sort the labels according to the weight in order to assign the most likely mc label
304 // to the first component
305 pCluster->SetLabel(mcWeights[k].fMCID, k);
308 AliError(Form("can not find mc label of cluster with id %0x08x", clusters[i].fID));
312 if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nSpacepoints, AliHLTComponent::DataType2Text(dt).c_str(), specification));
313 } while (pHLTOUT->SelectNextDataBlock()>=0);
317 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCRawClusterData(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels)
319 // read cluster data from AliHLTTPCClusterData
321 // FIXME: this is in large parts like ReadAliHLTTPCClusterData,
322 // make a common method
324 if (!pHLTOUT || !pClusters) return -EINVAL;
326 const AliHLTUInt8_t* pBuffer=NULL;
327 AliHLTUInt32_t size=0;
328 if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
331 if (pBuffer==NULL || size<4) {
332 AliError("invalid cluster data block");
335 AliHLTComponentDataType dt=kAliHLTVoidDataType;
336 AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
337 if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
338 AliError("failed to retrieve data block description, skipping mc cluster data block ...");
341 const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(pBuffer);
342 Int_t nCount = (Int_t) clusterData->fCount;
343 if (clusterData->fVersion!=0) {
344 // this is encoded data of different formats
345 switch (clusterData->fVersion) {
347 iResult=ReadAliHLTTPCRawClusterDataDeflateSimple(reinterpret_cast<const AliHLTUInt8_t*>(clusterData->fClusters),
348 size-sizeof(AliHLTTPCRawClusterData), nCount, specification,
349 pClusters, tpcClusterLabels);
357 if (nCount*sizeof(AliHLTTPCRawCluster) + sizeof(AliHLTTPCRawClusterData) != size) {
358 AliError("inconsistent cluster data block size, skipping block");
361 const AliHLTTPCRawCluster *clusters = clusterData->fClusters;
362 int offset=pClusters->GetEntries();
363 pClusters->ExpandCreate(offset+nCount);
364 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
365 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
366 // FIXME: get first row number of outer sectors from a common definition instead using number
367 int rowOffset=partition<2?0:63;
368 for (int i=0; i<nCount; i++) {
369 if (!pClusters->At(offset+i)) continue;
370 AliTPCclusterMI* pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+i));
372 AliError("invalid object type, expecting AliTPCclusterMI");
373 break; // this is a problem of all objects
375 if (fVerbosity>1) AliInfo(Form("cluster padrow %d (slice %d partition %d)", clusters[i].GetPadRow(), slice, partition));
376 if (clusters[i].GetPadRow()<rowOffset) {
377 AliError(Form("invalid row number %d, expecting minimum row number %d for slice %d partition %d", clusters[i].GetPadRow(), rowOffset, slice, partition));
379 pCluster->SetRow(clusters[i].GetPadRow()-rowOffset);
381 pCluster->SetPad(clusters[i].GetPad());
382 pCluster->SetTimeBin(clusters[i].GetTime());
383 pCluster->SetSigmaY2(clusters[i].GetSigmaY2());
384 pCluster->SetSigmaZ2(clusters[i].GetSigmaZ2());
385 pCluster->SetQ(clusters[i].GetCharge());
386 pCluster->SetMax(clusters[i].GetQMax());
387 if (tpcClusterLabels) {
388 UInt_t clusterID=AliHLTTPCSpacePointData::GetID(slice, partition, i);
389 if (tpcClusterLabels->find(clusterID)!=tpcClusterLabels->end()) {
390 const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusterID)->second.fClusterID;
391 for (int k=0; k<3; k++) {
392 // TODO: sort the labels according to the weight in order to assign the most likely mc label
393 // to the first component
394 pCluster->SetLabel(mcWeights[k].fMCID, k);
397 AliError(Form("can not find mc label of cluster with id %0x08x", clusterID));
401 if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nCount, AliHLTComponent::DataType2Text(dt).c_str(), specification));
402 } while (pHLTOUT->SelectNextDataBlock()>=0);
406 int AliHLTTPCClusterAccessHLTOUT::ReadRemainingClustersCompressed(AliHLTOUT* pHLTOUT, TClonesArray* pClusters, const AliHLTTPCClusterMCDataList *tpcClusterLabels)
408 // read cluster data from AliHLTTPCClusterData
410 if (!pHLTOUT || !pClusters) return -EINVAL;
412 const AliHLTUInt8_t* pBuffer=NULL;
413 AliHLTUInt32_t size=0;
414 if ((iResult=pHLTOUT->GetDataBuffer(pBuffer, size))<0) {
417 if (pBuffer==NULL || size<4) {
418 AliError("invalid cluster data block");
421 AliHLTComponentDataType dt=kAliHLTVoidDataType;
422 AliHLTUInt32_t specification=kAliHLTVoidDataSpec;
423 if (pHLTOUT->GetDataBlockDescription(dt, specification)<0) {
424 AliError("failed to retrieve data block description, skipping mc cluster data block ...");
427 const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(pBuffer);
428 Int_t nCount = (Int_t) clusterData->fCount;
430 // this is encoded data of different formats
431 switch (clusterData->fVersion) {
433 iResult=ReadAliHLTTPCRawClusterDataDeflateSimple(reinterpret_cast<const AliHLTUInt8_t*>(clusterData->fClusters),
434 size-sizeof(AliHLTTPCRawClusterData), nCount, specification,
435 pClusters, tpcClusterLabels);
438 AliError(Form("invalid cluster format version %d", clusterData->fVersion));
442 if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) from block %s 0x%08x", nCount, AliHLTComponent::DataType2Text(dt).c_str(), specification));
443 } while (pHLTOUT->SelectNextDataBlock()>=0 && iResult>=0);
448 int AliHLTTPCClusterAccessHLTOUT::ReadAliHLTTPCRawClusterDataDeflateSimple(const AliHLTUInt8_t* pData, int dataSize,
449 int nofClusters, AliHLTUInt32_t specification,
450 TClonesArray* pClusters,
451 const AliHLTTPCClusterMCDataList *tpcClusterLabels)
453 // read cluster data from AliHLTTPCClusterData
455 // FIXME: quick implementation to read the compressed cluster data from HLTOUT
456 // the data definition below is the same as in AliHLTTPCDataCompressionComponent
457 // but needs to be moved to a common class (AliHLTTPCDefinitions?)
458 // Think about a decoder class supporting iterator objects for various types
461 if (!pData || !pClusters) return -EINVAL;
462 AliHLTDataInflater inflater;
463 if ((iResult=inflater.InitBitDataInput(pData, dataSize))<0) {
467 int offset=pClusters->GetEntries();
468 pClusters->ExpandCreate(offset+nofClusters);
469 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(specification);
470 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(specification);
471 // the compressed format stores the difference of the local row number in
472 // the partition to the row of the last cluster
473 // add the first row in the partition to get global row number
474 // offline uses row number in physical sector, inner sector consists of
475 // partitions 0 and 1, outer sector of partition 2-5
476 int rowOffset=AliHLTTPCTransform::GetFirstRow(partition)-(partition<2?0:AliHLTTPCTransform::GetFirstRow(2));
480 AliHLTUInt8_t switchBit=0;
481 AliHLTUInt64_t value=0;
482 AliTPCclusterMI* pCluster=NULL;
483 AliHLTUInt32_t lastPadRow=0;
484 while (outClusterCnt<nofClusters && inflater.InputBit(switchBit)) {
485 const AliHLTTPCDefinitions::AliClusterParameter& parameter
486 =AliHLTTPCDefinitions::fgkClusterParameterDefinitions[parameterId];
487 // in mode DeflaterSimple, the optional parameter of the cluster parameter definition
488 // corresponds to the number bits of the reduced format
489 if (!inflater.InputBits(value, switchBit?parameter.fBitLength:parameter.fOptional)) {
494 if (!pClusters->At(offset+outClusterCnt)) {
495 // here we should not get anymore because of the condition outClusterCnt<nofClusters
498 pCluster=dynamic_cast<AliTPCclusterMI*>(pClusters->At(offset+outClusterCnt));
500 AliError("invalid object type, expecting AliTPCclusterMI");
501 iResult=-EBADF; // this is a problem of all objects
505 switch (parameterId) {
506 case AliHLTTPCDefinitions::kPadRow:
507 {pCluster->SetRow(value+lastPadRow+rowOffset); lastPadRow+=value;break;}
508 case AliHLTTPCDefinitions::kPad:
509 {float pad=value; pad/=parameter.fScale; pCluster->SetPad(pad); break;}
510 case AliHLTTPCDefinitions::kTime:
511 {float time=value; time/=parameter.fScale; pCluster->SetTimeBin(time); break;}
512 case AliHLTTPCDefinitions::kSigmaY2:
513 {float sigmaY2=value; sigmaY2/=parameter.fScale; pCluster->SetSigmaY2(sigmaY2); break;}
514 case AliHLTTPCDefinitions::kSigmaZ2:
515 {float sigmaZ2=value; sigmaZ2/=parameter.fScale; pCluster->SetSigmaZ2(sigmaZ2); break;}
516 case AliHLTTPCDefinitions::kCharge:
517 {pCluster->SetQ(value); break;}
518 case AliHLTTPCDefinitions::kQMax:
519 {pCluster->SetMax(value); break;}
521 if (parameterId>=AliHLTTPCDefinitions::kLast) {
522 // switch to next cluster
523 if (tpcClusterLabels) {
524 UInt_t clusterID=AliHLTTPCSpacePointData::GetID(slice, partition, outClusterCnt);
525 if (tpcClusterLabels->find(clusterID)!=tpcClusterLabels->end()) {
526 const AliHLTTPCClusterMCWeight* mcWeights=tpcClusterLabels->find(clusterID)->second.fClusterID;
527 for (int k=0; k<3; k++) {
528 // TODO: sort the labels according to the weight in order to assign the most likely mc label
529 // to the first component
530 pCluster->SetLabel(mcWeights[k].fMCID, k);
533 AliError(Form("can not find mc label of cluster with id 0x%08x", clusterID));
543 if (inflater.InputBit(switchBit)) {
544 AliWarning("format error of compressed clusters, there is more data than expected");
546 inflater.CloseBitDataInput();
547 if (iResult>=0 && nofClusters!=outClusterCnt) {
549 AliError(Form("error reading compressed cluster format: expected %d, read only %d cluster(s)", nofClusters, outClusterCnt));