3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE 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 "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"
36 #include "AliHLTSystem.h"
37 #include "AliHLTPluginBase.h"
38 #include "AliTPCclusterMI.h"
39 #include "AliTPCClustersRow.h"
40 #include "AliTPCParam.h"
41 #include "TClonesArray.h"
49 /** ROOT macro for the implementation of ROOT specific class methods */
50 ClassImp(AliHLTTPCClusterAccessHLTOUT)
52 AliHLTTPCClusterAccessHLTOUT::AliHLTTPCClusterAccessHLTOUT()
60 // see header file for class documentation
62 // refer to README to build package
64 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
67 AliHLTTPCClusterAccessHLTOUT::~AliHLTTPCClusterAccessHLTOUT()
81 // FIXME: a copy of the TPCParam object is not possible because there is
82 // no appropriate copy constructor or assignment operator, using as
89 void AliHLTTPCClusterAccessHLTOUT::Execute(const char *method, const char *params, Int_t *error)
91 /// inherited from TObject: abstract command interface
92 if (strcmp(method, "read")==0) {
93 int iResult=ProcessClusters(params);
94 if (error) *error=iResult;
97 if (strcmp(method, "verbosity")==0) {
101 int value=strtol(params, &dummy, 0);
105 AliError("invalid argument for command 'verbosity', expecting string with number");
110 if (error) *error=iResult;
115 TObject* AliHLTTPCClusterAccessHLTOUT::FindObject(const char *name) const
117 /// inherited from TObject: return the cluster array if name id "clusterarray"
118 if (strcmp(name, "clusterarray")==0) {
119 if (fCurrentSector<0) return NULL;
120 return fClusters->GetSectorArray(fCurrentSector);
122 return TObject::FindObject(name);
125 void AliHLTTPCClusterAccessHLTOUT::Copy(TObject &object) const
127 /// inherited from TObject: supports writing of data to AliTPCClustersRow
128 AliTPCClustersRow* rowcl=dynamic_cast<AliTPCClustersRow*>(&object);
130 int index=rowcl->GetID();
132 AliFatal("TPCParam object not initialized, use 'Copy()' funtion to initialize");
137 if (!fTPCParam->AdjustSectorRow(index, sector, row)) {
138 AliFatal(Form("failed to get sector and row for index %d", index));
141 fClusters->FillSectorArray(rowcl->GetArray(), sector, row);
144 AliTPCParam* tpcparam=dynamic_cast<AliTPCParam*>(&object);
146 // FIXME: can nor make a copy of the TPCparam object because
147 // there is no appropriate copy constructor or assignment operator
148 const_cast<AliHLTTPCClusterAccessHLTOUT*>(this)->fTPCParam=tpcparam;
151 return TObject::Copy(object);
155 void AliHLTTPCClusterAccessHLTOUT::Clear(Option_t * option)
157 /// inherited from TObject: cleanup
158 if (strcmp(option, "event")==0) {
159 if (fClusters) fClusters->Clear();
164 void AliHLTTPCClusterAccessHLTOUT::Print(Option_t *option) const
166 /// inherited from TObject
167 if (fClusters) fClusters->Print(option);
170 int AliHLTTPCClusterAccessHLTOUT::ProcessClusters(const char* params)
172 /// process the cluster data from HLTOUT and fill array
173 /// the cluster data can be in many different formats, e.g.
174 /// raw or compressed
176 TString strparams(params);
178 std::auto_ptr<TObjArray> tokens(strparams.Tokenize(" "));
179 if (!tokens.get()) return -ENOMEM;
180 for (int i=0; i< tokens->GetEntriesFast(); i++) {
181 if (!tokens->At(i)) continue;
182 TString argument=tokens->At(i)->GetName();
183 // the offline code enumerates first the 36 inner (partitions 0+1) and then 36 outer
184 // sectors (partitions 2-5)
185 if (argument.BeginsWith("sector=")) {
186 argument.ReplaceAll("sector=", "");
187 sector=argument.Atoi();
191 AliError("invalid argument, please specify \"sector=sectorno\"");
195 AliError(Form("invalid sector number %d", sector));
200 fClusters=new AliRawClusterContainer;
202 if (!fClusters) return -ENOMEM;
204 if (fCurrentSector>=0) {
205 // cluster container already filled
206 fCurrentSector=sector;
207 // TObjArray* pArray=fClusters->GetSectorArray(fCurrentSector);
209 // AliError(Form("can not get cluster array for sector %d", sector));
212 // if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) for sector %d", pArray->GetEntriesFast() ,sector));
213 return 0; //pArray->GetEntriesFast();
216 // fill the cluster container
217 AliHLTSystem* pSystem=AliHLTPluginBase::GetInstance();
219 AliError("can not access HLT system");
222 AliHLTOUT* pHLTOUT=pSystem->RequestHLTOUT();
224 AliError("can not access HLTOUT");
229 fpDecoder=new AliHLTTPCDataCompressionDecoder;
233 AliError("failed to create decoder instance");
237 AliHLTTPCDataCompressionDecoder& decoder=*fpDecoder;
239 decoder.SetVerbosity(fVerbosity);
241 bool bNextBlock=false;
242 // add cluster id and mc information data blocks
243 for (bNextBlock=(pHLTOUT->SelectFirstDataBlock()>=0);
244 bNextBlock; bNextBlock=(pHLTOUT->SelectNextDataBlock()>=0)) {
245 AliHLTComponentBlockData desc;
246 // FIXME: extend HLTOUT to get the full descriptor
247 const AliHLTUInt8_t* buffer=NULL;
248 if ((iResult=pHLTOUT->GetDataBuffer(buffer, desc.fSize))<0) {
251 desc.fPtr=(void*)buffer;
252 if (pHLTOUT->GetDataBlockDescription(desc.fDataType, desc.fSpecification)<0) {
255 if (desc.fDataType==AliHLTTPCDefinitions::DataCompressionDescriptorDataType()) {
257 if ((iResult=decoder.AddCompressionDescriptor(&desc))<0) {
261 if (desc.fDataType==AliHLTTPCDefinitions::AliHLTDataTypeClusterMCInfo()) {
262 // add mc information
263 if ((iResult=decoder.AddClusterMCData(&desc))<0) {
267 if (desc.fDataType==AliHLTTPCDefinitions::RemainingClusterIdsDataType() ||
268 desc.fDataType==AliHLTTPCDefinitions::ClusterIdTracksDataType()) {
270 if ((iResult=decoder.AddClusterIds(&desc))<0) {
276 bool bHavePartitionRawData=false;
277 bool bHavePartitionCompressedData=false;
278 vector<bool> bHavePartitionData(216, false);
282 int nExtractedClusters=0;
283 for (bNextBlock=(pHLTOUT->SelectFirstDataBlock()>=0);
284 bNextBlock; bNextBlock=(pHLTOUT->SelectNextDataBlock()>=0)) {
285 decoder.SetPadShift(0.0);
286 AliHLTComponentBlockData desc;
287 // FIXME: extend HLTOUT to get the full descriptor with one call
288 const AliHLTUInt8_t* buffer=NULL;
289 if ((iResult=pHLTOUT->GetDataBuffer(buffer, desc.fSize))<0) {
292 desc.fPtr=(void*)buffer;
293 if (pHLTOUT->GetDataBlockDescription(desc.fDataType, desc.fSpecification)<0) {
296 if (!TestBit(kSkipPartitionClusters) &&
297 (desc.fDataType==AliHLTTPCDefinitions::RawClustersDataType())) {
298 // This is a special handling of data blocks produced with v5-01-Release
299 // The pad shift by 0.5 was not included in the data but was applied in the
300 // unpacking in this class. Changed in r51306, the next tag containing this
301 // change in the online system is v5-01-Rev-07. There are only very few runs
302 // of Sep 2011 with recorded clusters not containing the 0.5 shift
303 // There was also a chenge in the data type of the compressed partition
304 // cluster blocks which helps to identify the blocks which need the pad shift
306 if (desc.fSize<sizeof(AliHLTTPCRawClusterData)) continue;
307 const AliHLTTPCRawClusterData* clusterData = reinterpret_cast<const AliHLTTPCRawClusterData*>(buffer);
308 if (!clusterData) continue;
309 if (clusterData->fVersion==1) {
310 // compressed clusters without the pad shift
311 // no raw clusters (version==0) have ever been recorded
312 decoder.SetPadShift(0.5);
314 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(desc.fSpecification);
315 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(desc.fSpecification);
316 if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(desc.fSpecification) ||
317 partition!=AliHLTTPCDefinitions::GetMaxPatchNr(desc.fSpecification)) {
318 AliFatal(Form("inconsistent cluster data: can not handle blocks containing multiple partitions, "
319 "block specification 0x%08x", desc.fSpecification));
321 iResult=decoder.ReadClustersPartition(fClusters->BeginRemainingClusterBlock(0, desc.fSpecification),
322 reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
324 desc.fSpecification);
325 if (iResult>=0) nExtractedClusters+=iResult;
327 AliFatal(Form("processing of cluster block 0x%08x failed with error code %d", desc.fSpecification, iResult));
329 unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
330 if (index>=bHavePartitionData.size()) bHavePartitionData.resize(index, false);
331 if (bHavePartitionData[index]) {
332 AliFatal(Form("inconsistent cluster data: multiple data blocks of identical specification indicate a failure "
333 "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
334 "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
335 "block specification 0x%08x", desc.fSpecification));
337 bHavePartitionData[index]=true;
338 if (bHavePartitionCompressedData) {
339 AliFatal(Form("inconsistent cluster data: both compressed and raw cluster blocks present in HLTOUT, indicates a failure "
340 "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
341 "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
342 "block specification 0x%08x", desc.fSpecification));
344 bHavePartitionRawData=true;
346 } else if (!TestBit(kSkipPartitionClusters) &&
347 (desc.fDataType==AliHLTTPCDefinitions::RemainingClustersCompressedDataType())) {
348 AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(desc.fSpecification);
349 AliHLTUInt8_t partition = AliHLTTPCDefinitions::GetMinPatchNr(desc.fSpecification);
350 if (slice!=AliHLTTPCDefinitions::GetMaxSliceNr(desc.fSpecification) ||
351 partition!=AliHLTTPCDefinitions::GetMaxPatchNr(desc.fSpecification)) {
352 AliFatal(Form("inconsistent cluster data: can not handle blocks containing multiple partitions, "
353 "block specification 0x%08x", desc.fSpecification));
355 iResult=decoder.ReadClustersPartition(fClusters->BeginRemainingClusterBlock(0, desc.fSpecification),
356 reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
358 desc.fSpecification);
359 if (iResult>0) nExtractedClusters+=iResult;
360 unsigned index=slice*AliHLTTPCTransform::GetNumberOfPatches()+partition;
361 if (index>=bHavePartitionData.size()) bHavePartitionData.resize(index, false);
362 if (bHavePartitionData[index]) {
363 AliFatal(Form("inconsistent cluster data: multiple data blocks of identical specification indicate a failure "
364 "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
365 "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
366 "block specification 0x%08x", desc.fSpecification));
368 bHavePartitionData[index]=true;
369 bHavePartitionData[index]=true;
370 if (bHavePartitionRawData) {
371 AliFatal(Form("inconsistent cluster data: both compressed and raw cluster blocks present in HLTOUT, indicates a failure "
372 "in the production of the data. Probably an HLT emulation chain is executed in the reconstruction "
373 "and produces data in addition to HLTOUT. Option 'ignore-hltout' is required in that case; "
374 "block specification 0x%08x", desc.fSpecification));
376 bHavePartitionCompressedData=true;
378 } else if (!TestBit(kSkipTrackClusters) &&
379 desc.fDataType==AliHLTTPCDefinitions::ClusterTracksCompressedDataType()) {
380 iResult=decoder.ReadTrackModelClustersCompressed(fClusters->BeginTrackModelClusterBlock(0),
381 reinterpret_cast<AliHLTUInt8_t*>(desc.fPtr),
383 desc.fSpecification);
388 pSystem->ReleaseHLTOUT(pHLTOUT);
390 if (iResult<0) return iResult;
391 // if (fVerbosity>0) {
392 // int nConvertedClusters=0;
393 // for (int s=0; s<72; s++) {
394 // TObjArray* pArray=fClusters->GetSectorArray(s);
395 // if (!pArray) continue;
396 // nConvertedClusters+=pArray->GetEntriesFast();
398 // AliInfo(Form("extracted HLT clusters: %d, converted HLT clusters: %d", nExtractedClusters, nConvertedClusters));
401 fCurrentSector=sector;
402 // TObjArray* pArray=fClusters->GetSectorArray(fCurrentSector);
404 // AliError(Form("can not get cluster array for sector %d", sector));
407 // if (fVerbosity>0) AliInfo(Form("converted %d cluster(s) for sector %d", pArray->GetEntriesFast() ,sector));
408 return 0; //pArray->GetEntriesFast();
411 AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::AliRawClusterContainer()
413 , fSectorArray(new TClonesArray(AliTPCclusterMI::Class()))
418 for (int i=0; i<72; i++) {
419 fClusterMaps.push_back(new AliRawClusterEntryVector);
420 fClusterMaps.back()->reserve(30000);
424 AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::~AliRawClusterContainer()
428 for (vector<AliRawClusterEntryVector*>::iterator i=fClusterMaps.begin(); i!=fClusterMaps.end(); i++) {
435 fSectorArray->Clear();
441 AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::BeginPartitionClusterBlock(int count, AliHLTUInt32_t specification)
443 /// iterator of remaining clusters block of specification
445 // reserve space in the array of all clusters
446 // reserve space in the map of the partition
447 unsigned index=AliHLTTPCDefinitions::GetMinSliceNr(specification);
448 AliHLTUInt8_t partition=AliHLTTPCDefinitions::GetMinPatchNr(specification);
449 if (partition>=2) index+=36;
450 if (index<fClusterMaps.size() &&
451 fClusterMaps[index]!=NULL &&
452 fClusterMaps[index]->size()+count>fClusterMaps[index]->capacity()) {
453 fClusterMaps[index]->reserve(fClusterMaps[index]->size()+count);
456 fIterator=iterator(this);
460 AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::BeginTrackModelClusterBlock(int /*count*/)
462 /// iterator of track model clusters
463 fIterator=iterator(this);
467 AliHLTTPCClusterAccessHLTOUT::AliRawClusterEntry* AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::NextCluster(int slice, int partition)
469 /// load next cluster from array of the sepcific sector
470 unsigned sector=partition<2?slice:slice+36;
471 if (fClusterMaps.size()<=sector ||
472 fClusterMaps[sector]==NULL) {
473 AliErrorClass(Form("no cluster array available for sector %d", sector));
476 AliRawClusterEntryVector& map=*(fClusterMaps[sector]);
477 map.push_back(AliRawClusterEntry());
481 void AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::Clear(Option_t* /*option*/)
485 for (vector<AliRawClusterEntryVector*>::iterator i=fClusterMaps.begin(); i!=fClusterMaps.end(); i++)
486 if (*i) (*i)->clear();
488 if (fSectorArray) fSectorArray->Clear();
491 TObjArray* AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::GetSectorArray(unsigned sector) const
493 /// get the cluster array for a sector
494 if (fClusterMaps.size()<=sector) return NULL;
496 FillSectorArray(fSectorArray, sector)<0) {
497 fSectorArray->Clear();
502 int AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::FillSectorArray(TClonesArray* pSectorArray, unsigned sector, int row) const
504 /// fill the cluster array for a sector and specific row if specified
505 if (!pSectorArray) return -EINVAL;
506 if (fClusterMaps.size()<=sector) return -ERANGE;
507 pSectorArray->Clear();
509 AliRawClusterEntryVector& map=*fClusterMaps[sector];
511 for (unsigned i=0; i<map.size(); i++) {
512 if (row>=0 && map[i].fCluster.GetPadRow()!=row) continue;
513 AliTPCclusterMI* pCluster=new ((*pSectorArray)[nFilled]) AliTPCclusterMI;
514 if (!pCluster) break;
516 pCluster->SetRow(map[i].fCluster.GetPadRow());
517 pCluster->SetPad(map[i].fCluster.GetPad());
518 pCluster->SetTimeBin(map[i].fCluster.GetTime());
519 pCluster->SetSigmaY2(map[i].fCluster.GetSigmaY2());
520 pCluster->SetSigmaZ2(map[i].fCluster.GetSigmaZ2());
521 pCluster->SetQ(map[i].fCluster.GetCharge());
522 pCluster->SetMax(map[i].fCluster.GetQMax());
524 for (int k=0; k<3; k++) {
525 // TODO: sort the labels according to the weight in order to assign the most likely mc label
526 // to the first component
527 pCluster->SetLabel(map[i].fMC.fClusterID[k].fMCID, k);
535 void AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::Print(Option_t *option) const
537 /// inherited from TObject
538 cout << "AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer" << endl;
539 ios::fmtflags coutflags=cout.flags(); // backup cout status flags
541 if ((bAll=(strcmp(option, "full")==0)) ||
542 strcmp(option, "short")==0) {
543 for (unsigned iArray=0; iArray<fClusterMaps.size(); iArray++) {
544 if (fClusterMaps[iArray]) {
545 AliRawClusterEntryVector& map=*fClusterMaps[iArray];
546 cout << " sector " << setfill(' ') << setw(2) << iArray << ": " << map.size() << endl;
548 for (unsigned iCluster=0; iCluster<map.size(); iCluster++) {
549 AliHLTTPCRawCluster &cluster = map[iCluster].fCluster;
550 cout << " AliTPCclusterMI:"
551 << " row=" << cluster.GetPadRow()
552 << " pad=" << cluster.GetPad()
553 << " time=" << cluster.GetTime()
554 << " charge=" << cluster.GetCharge()
555 << " maxq=" << cluster.GetQMax()
562 cout.flags(coutflags); // restore the original flags
565 AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::iterator& AliHLTTPCClusterAccessHLTOUT::AliRawClusterContainer::iterator::Next(int slice, int partition)
567 // switch to next cluster
572 if (fClusterNo>=0 && !fEntry) {
573 // end was reached before
576 fEntry=fData->NextCluster(slice, partition);
578 // offline uses row number in physical sector, inner sector consists of
579 // partitions 0 and 1, outer sector of partition 2-5
580 fRowOffset=partition<2?0:AliHLTTPCTransform::GetFirstRow(2);