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: Kenneth Aamodt <Kenneth.Aamodt@student.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 AliHLTTPCZeroSuppressionComponent.cxx
20 @author Kenneth Aamodt
22 @brief The TPC ZeroSuppression component
25 // see header file for class documentation //
27 // refer to README to build package //
29 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt //
34 #include "AliHLTTPCZeroSuppressionComponent.h"
35 #include "AliHLTTPCDigitReaderDecoder.h"
36 #include "AliHLTTPCTransform.h"
37 #include "AliHLTTPCDefinitions.h"
38 #include "AliHLTTPCDigitData.h"
39 #include "AliHLTTPCMapping.h"
45 #include "AliHLTAltroEncoder.h"
46 #include "AliRawDataHeader.h"
48 /** ROOT macro for the implementation of ROOT specific class methods */
49 ClassImp(AliHLTTPCZeroSuppressionComponent)
51 AliHLTTPCZeroSuppressionComponent::AliHLTTPCZeroSuppressionComponent()
55 fNumberOfPadsInRow(NULL),
61 fEndTimeBin(AliHLTTPCTransform::GetNTimeBins()),
65 fMinimumNumberOfSignals(AliHLTTPCTransform::GetNTimeBins()/2),
68 fVectorInitialized(kFALSE),
69 fValueBelowAverage(5),
72 fGetActivePads(kFALSE),
73 fSkipSendingZSData(kFALSE),
77 // see header file for class documentation
79 // refer to README to build package
81 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
84 AliHLTTPCZeroSuppressionComponent::~AliHLTTPCZeroSuppressionComponent()
86 // see header file for class documentation
87 if(fVectorInitialized){
88 DeInitializePadArray();
90 if(fNumberOfPadsInRow){
91 delete [] fNumberOfPadsInRow;
92 fNumberOfPadsInRow=NULL;
100 // Public functions to implement AliHLTComponent's interface.
101 // These functions are required for the registration process
103 const char* AliHLTTPCZeroSuppressionComponent::GetComponentID()
105 // see header file for class documentation
106 return "TPCZeroSuppression";
109 void AliHLTTPCZeroSuppressionComponent::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
111 // see header file for class documentation
113 list.push_back( kAliHLTDataTypeDDLRaw | kAliHLTDataOriginTPC );
116 AliHLTComponentDataType AliHLTTPCZeroSuppressionComponent::GetOutputDataType()
118 // see header file for class documentation
119 return kAliHLTMultipleDataType;
120 //return kAliHLTDataTypeDDLRaw;
121 // return AliHLTTPCDefinitions::fgkUnpackedRawDataType;
124 int AliHLTTPCZeroSuppressionComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& tgtList)
126 // see header file for class documentation
128 tgtList.push_back(kAliHLTDataTypeDDLRaw);
129 tgtList.push_back(kAliHLTDataTypeHwAddr16);
130 return tgtList.size();
133 void AliHLTTPCZeroSuppressionComponent::GetOutputDataSize( unsigned long& constBase, double& inputMultiplier )
135 // see header file for class documentation
140 AliHLTComponent* AliHLTTPCZeroSuppressionComponent::Spawn()
142 // see header file for class documentation
143 return new AliHLTTPCZeroSuppressionComponent();
146 int AliHLTTPCZeroSuppressionComponent::DoInit( int argc, const char** argv )
148 // see header file for class documentation
155 // -- zero suppression threshold
156 if ( !strcmp( argv[i], "-signal-threshold" ) || !strcmp( argv[i], "signal-threshold" ) ) {
157 fSignalThreshold = strtoul( argv[i+1], &cpErr ,0);
159 HLTError("Cannot convert signal-threshold specifier '%s'.", argv[i+1]);
166 // -- checking for nsigma-threshold, used in 2007 December run in ZeroSuppression
167 if ( !strcmp( argv[i], "-rms-threshold" ) || !strcmp( argv[i], "rms-threshold" ) ) {
168 fNRMSThreshold = strtoul( argv[i+1], &cpErr ,0);
170 HLTError("Cannot convert rms-threshold specifier '%s'. Must be integer", argv[i+1]);
177 // -- number of timebins
178 if ( !strcmp( argv[i], "-ntimebins" ) || !strcmp( argv[i], "ntimebins" ) ) {
179 fNTimeBins = strtoul( argv[i+1], &cpErr ,0);
181 HLTError("Cannot convert ntimebins specifier '%s'.", argv[i+1]);
189 if ( !strcmp( argv[i], "-start-timebin" ) || !strcmp( argv[i], "start-timebin" ) ) {
190 fStartTimeBin = strtoul( argv[i+1], &cpErr ,0);
192 HLTError("Cannot convert start-timebin specifier '%s'.", argv[i+1]);
200 if ( !strcmp( argv[i], "-end-timebin" ) || !strcmp( argv[i], "end-timebin" ) ) {
201 if(strtoul( argv[i+1], &cpErr ,0)<=(UInt_t)AliHLTTPCTransform::GetNTimeBins()){
202 fEndTimeBin = strtoul( argv[i+1], &cpErr ,0);
205 HLTError("Cannot convert end-timebin specifier '%s'.", argv[i+1]);
212 // -- timebins to keep left of signal
213 if ( !strcmp( argv[i], "-timebin-left" ) || !strcmp( argv[i], "timebin-left" ) ) {
214 fLeftTimeBin = strtoul( argv[i+1], &cpErr ,0);
216 HLTError("Cannot convert timebin-left specifier '%s'.", argv[i+1]);
223 // -- timebin to keep right of signal
224 if ( !strcmp( argv[i], "-timebin-right" ) || !strcmp( argv[i], "timebin-right" ) ) {
225 fRightTimeBin = strtoul( argv[i+1], &cpErr ,0);
227 HLTError("Cannot convert timebin-right specifier '%s'.", argv[i+1]);
234 // -- value below average to subtract
235 if ( !strcmp( argv[i], "-value-below-average" ) || !strcmp( argv[i], "value-below-average" ) ) {
236 fValueBelowAverage = strtoul( argv[i+1], &cpErr ,0);
238 HLTError("Cannot convert value-below-average specifier '%s'.", argv[i+1]);
245 // -- pad occupancy limit
246 if ( !strcmp( argv[i], "-occupancy-limit" ) || !strcmp( argv[i], "occupancy-limit" ) ) {
247 fMinimumNumberOfSignals = strtoul( argv[i+1], &cpErr ,0);
249 HLTError("Cannot convert occupancy-limit specifier '%s'.", argv[i+1]);
256 // -- checking for rcu format
257 if ( !strcmp( argv[i], "oldrcuformat" ) ) {
258 fOldRCUFormat = strtoul( argv[i+1], &cpErr ,0);
260 HLTError("Cannot convert oldrcuformat specifier '%s'. Should be 0(off) or 1(on), must be integer", argv[i+1]);
267 // -- checking for pad sorting
268 if ( !strcmp( argv[i], "-sort-pads" ) || !strcmp( argv[i], "sort-pads" ) ) {
269 fSortPads = strtoul( argv[i+1], &cpErr ,0);
271 HLTError("Cannot convert sort-pads specifier '%s'. Should be 0(off) or 1(on), must be integer", argv[i+1]);
278 // -- checking for skipZSdatashipping
279 if ( !strcmp( argv[i], "-skip-sending-data" ) ) {
280 fSkipSendingZSData = kTRUE;
285 // -- checking for hw address shipping
286 if ( !strcmp( argv[i], "-send-hw-list" ) ) {
292 Logging(kHLTLogError, "HLT::TPCClusterFinder::DoInit", "Unknown Option", "Unknown option '%s'", argv[i] );
297 if(fSkipSendingZSData == kTRUE && fSendHWList == kFALSE){
298 HLTError("Component will have no output, check your configuration.");
301 HLTDebug("using AliHLTTPCDigitReaderDecoder");
302 fDigitReader = new AliHLTTPCDigitReaderDecoder();
304 fHwAddressList.clear();
309 int AliHLTTPCZeroSuppressionComponent::DoDeinit()
311 // see header file for class documentation
315 Int_t AliHLTTPCZeroSuppressionComponent::DeInitializePadArray()
317 // see header file for class documentation
318 if(fVectorInitialized){
319 for(Int_t i=0;i<fNumberOfRows;i++){
320 for(Int_t j=0;j<fNumberOfPadsInRow[i];j++){
321 delete fRowPadVector[i][j];
322 fRowPadVector[i][j]=NULL;
324 fRowPadVector[i].clear();
326 fRowPadVector.clear();
331 void AliHLTTPCZeroSuppressionComponent::InitializePadArray(){
332 // see header file for class documentation
334 HLTFatal("Patch is not set");
338 fFirstRow = AliHLTTPCTransform::GetFirstRow(fCurrentPatch);
339 fLastRow = AliHLTTPCTransform::GetLastRow(fCurrentPatch);
341 fNumberOfRows=fLastRow-fFirstRow+1;
342 fNumberOfPadsInRow= new Int_t[fNumberOfRows];
344 memset( fNumberOfPadsInRow, 0, sizeof(Int_t)*(fNumberOfRows));
346 for(Int_t i=0;i<fNumberOfRows;i++){
347 fNumberOfPadsInRow[i]=AliHLTTPCTransform::GetNPads(i+fFirstRow);
348 AliHLTTPCPadVector tmpRow;
349 for(Int_t j=0;j<fNumberOfPadsInRow[i];j++){
350 AliHLTTPCPad *tmpPad = new AliHLTTPCPad();
352 tmpRow.push_back(tmpPad);
354 fRowPadVector.push_back(tmpRow);
356 fVectorInitialized=kTRUE;
360 int AliHLTTPCZeroSuppressionComponent::DoEvent( const AliHLTComponentEventData& evtData,
361 const AliHLTComponentBlockData* blocks,
362 AliHLTComponentTriggerData& /*trigData*/, AliHLTUInt8_t* outputPtr,
363 AliHLTUInt32_t& size,
364 vector<AliHLTComponentBlockData>& outputBlocks )
366 // see header file for class documentation
368 if (!fDigitReader) return -ENODEV;
370 AliHLTUInt32_t capacity=size;
372 if (!IsDataEvent()) return 0;
374 // HLTInfo("Entered DoEvent in AliHLTTPCZeroSuppressionComponent");
376 // == init iter (pointer to datablock)
377 const AliHLTComponentBlockData* iter = NULL;
379 // HLTInfo("Number of blocks: ",evtData.fBlockCnt);
381 fHwAddressList.clear();
383 for ( ndx = 0; ndx < evtData.fBlockCnt; ndx++ )
387 HLTDebug("Event 0x%08LX (%Lu) received datatype: %s - required datatype: %s",
388 evtData.fEventID, evtData.fEventID,
389 DataType2Text( iter->fDataType).c_str(),
390 DataType2Text(kAliHLTDataTypeDDLRaw | kAliHLTDataOriginTPC).c_str());
392 if ( iter->fDataType != (kAliHLTDataTypeDDLRaw | kAliHLTDataOriginTPC)){
396 UInt_t slice = AliHLTTPCDefinitions::GetMinSliceNr( *iter );
397 UInt_t patch = AliHLTTPCDefinitions::GetMinPatchNr( *iter );
399 if(!fVectorInitialized){
401 InitializePadArray();
404 if(fDigitReader->InitBlock(iter->fPtr,iter->fSize,patch,slice)<0){
405 HLTWarning("Decoder failed to initialize, event aborted.");
408 AliHLTTPCMapping mapping(patch);
410 int nTotalChannels=0;
411 int nSkippedChannels=0;
412 short lowestOccupancy=-1;
413 float sumOccupancy=0;
415 //Here the reading of the data and the zerosuppression takes place
416 while(fDigitReader->NextChannel()){//Pad
417 Int_t row=fDigitReader->GetRow();
418 Int_t pad=fDigitReader->GetPad();
419 if(row==1000 || pad==1000){
422 if(row>=fNumberOfRows||row<0){
425 else if(pad>=fNumberOfPadsInRow[row]||pad<0){
429 AliHLTTPCPad *tmpPad = fRowPadVector[row][pad];
430 tmpPad->SetDataToDefault();
432 //reading data to pad
433 while(fDigitReader->NextBunch()){
434 const UInt_t *bunchData= fDigitReader->GetSignals();
435 Int_t time=fDigitReader->GetTime();
436 for(Int_t i=0;i<fDigitReader->GetBunchSize();i++){
437 if(bunchData[i]>0){// disregarding 0 data.
438 if(time+i>=fStartTimeBin && time+i<=fEndTimeBin){
439 tmpPad->SetDataSignal(time+i,bunchData[i]);
446 if (lowestOccupancy<0 || (unsigned short)lowestOccupancy>tmpPad->GetNAddedSignals())
447 lowestOccupancy=tmpPad->GetNAddedSignals();
448 sumOccupancy+=tmpPad->GetNAddedSignals();
450 if(tmpPad->GetNAddedSignals()>=(UInt_t)fMinimumNumberOfSignals){
451 tmpPad->ZeroSuppress(fNRMSThreshold, fSignalThreshold, fMinimumNumberOfSignals, fStartTimeBin, fEndTimeBin, fLeftTimeBin, fRightTimeBin, fValueBelowAverage);
452 if(tmpPad->GetNAddedSignals()>0){
453 assert((int)mapping.GetRow(fDigitReader->GetAltroBlockHWaddr())==row);
454 assert((int)mapping.GetPad(fDigitReader->GetAltroBlockHWaddr())==pad);
455 fHwAddressList.push_back((AliHLTUInt16_t)fDigitReader->GetAltroBlockHWaddr());
461 if (nSkippedChannels>0) {
462 HLTWarning("skipped %d of %d channels because of low occupancy: average %.2f, lowest %d, threshold %d",
463 nSkippedChannels, nTotalChannels, sumOccupancy/nTotalChannels, lowestOccupancy, fMinimumNumberOfSignals);
466 AliHLTUInt32_t dataOffsetBeforeHW=0;
468 if(fSkipSendingZSData == kFALSE && iter->fSize>sizeof(AliRawDataHeader)) {
470 AliHLTAltroEncoder *altroEncoder = new AliHLTAltroEncoder;
471 altroEncoder->SetBuffer(outputPtr,capacity); //tests if one overwrite the buffer is done in the encoder
473 // set CDH from the beginning of buffer
474 altroEncoder->SetCDH((AliHLTUInt8_t*)iter->fPtr,sizeof(AliRawDataHeader));
476 UChar_t *RCUTrailer=NULL;
477 Int_t RCUTrailerSize=fDigitReader->GetRCUTrailerSize();
478 if (RCUTrailerSize<=0 || !fDigitReader->GetRCUTrailerData( RCUTrailer )) {
479 if(RCUTrailer==NULL){
480 HLTWarning("can not find RCU trailer for data block %s 0x%08x: skipping data block",
481 DataType2Text(iter->fDataType).c_str(), iter->fSpecification);
485 altroEncoder->SetRCUTrailer(RCUTrailer, RCUTrailerSize);
487 for(unsigned int channel=0; channel<fHwAddressList.size(); channel++){
488 int row=mapping.GetRow(fHwAddressList[channel]);
489 int pad=mapping.GetPad(fHwAddressList[channel]);
491 AliHLTTPCPad * zeroSuppressedPad= fRowPadVector[row][pad];
494 if(zeroSuppressedPad->GetNAddedSignals()>0){
495 while(zeroSuppressedPad->GetNextGoodSignal(currentTime, bunchSize)){
496 for(Int_t i=0;i<bunchSize;i++){
497 if (altroEncoder->AddSignal((AliHLTUInt16_t)(zeroSuppressedPad->GetDataSignal(currentTime+i)),(AliHLTUInt16_t)(currentTime+i))<0) {
498 // Matthias 01.10.2008: there is a problem with certain real data which produces the same
499 // bunch multiple times, needs investigation. I found an examplary case in run 53465
500 // (08000053465011.450.root) equipment 981.
501 // needs to be followed up.
502 // addon 02.10.2008 I just corrected a bug concerning the loop over the active channels.
503 // A double loop over all rows and pads also considered pads which had not even been
504 // filled, and thus not properly cleaned. Maybe the bug above is related to that.
505 HLTWarning("can not add channel: slice %d, partition %d, hw address %d, row %d, pad %d, time %d, bunch size %d",
506 slice, patch, fHwAddressList[channel], row, pad, currentTime+i, bunchSize);
511 altroEncoder->SetChannel(fHwAddressList[channel]);
516 int sizeOfData=altroEncoder->SetLength();
519 HLTError("data encoding failed");
523 if(sizeOfData>(int)capacity){
524 HLTWarning("Buffer too small too add the altrodata: %d of %d byte(s) already used", sizeOfData, capacity);
529 //Push back the zerosuppressed altro data to the output
530 if(true/* condition was deprecated but keep for the sake of formatting*/){
531 AliHLTComponentBlockData bd;
534 bd.fSize = sizeOfData;
535 bd.fDataType = kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC;
536 bd.fSpecification = iter->fSpecification;
537 outputBlocks.push_back( bd );
539 //Push back the list of hardware addresses to the output
540 dataOffsetBeforeHW=sizeOfData;
544 AliHLTUInt32_t sizeOfHWArray = 0;
545 if(fSendHWList == kTRUE){
547 if(true/* condition was deprecated but keep for the sake of formatting*/){
548 sizeOfHWArray = fHwAddressList.size()*sizeof(AliHLTUInt16_t);
550 if(dataOffsetBeforeHW+sizeOfHWArray>capacity){
551 HLTWarning("Buffer too small too add the active channels: %d of %d byte(s) already used", dataOffsetBeforeHW + sizeOfHWArray, capacity);
556 AliHLTUInt16_t*outputHWPtr=(AliHLTUInt16_t*)(outputPtr+dataOffsetBeforeHW);
557 memcpy(outputHWPtr,&fHwAddressList[0],sizeOfHWArray);
558 AliHLTComponentBlockData bdHW;
559 FillBlockData( bdHW );
560 bdHW.fOffset = dataOffsetBeforeHW;
561 bdHW.fSize = sizeOfHWArray;
562 bdHW.fDataType = kAliHLTDataTypeHwAddr16|kAliHLTDataOriginTPC;
563 bdHW.fSpecification = iter->fSpecification;
564 outputBlocks.push_back( bdHW );
567 size = dataOffsetBeforeHW+sizeOfHWArray;
568 fDigitReader->Reset();
572 fDigitReader->Reset();