/************************************************************************** * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$ */ // This class contains the implementation of the // compression and decompression algorithms // Compression is performed reading the Altro data block (called packet) backward. // Similarly decompression is also done backward so that the final file is restored // after the compression and decompression phase. #include #include #include #include #include #include "AliAltroBuffer.h" #include "AliTPCHNode.h" #include "AliTPCHTable.h" #include "AliTPCCompression.h" ClassImp(AliTPCCompression) ////////////////////////////////////////////////////////////////////////////////////////////////// AliTPCCompression::AliTPCCompression(){ //Defaul constructor fDimBuffer=sizeof(UInt_t)*8; fFreeBitsBuffer=fDimBuffer; fReadBits=0; fPos=0; fBuffer=0; fVerbose=0; fFillWords=0; fPointBuffer=0; return; } ////////////////////////////////////////////////////////////////////////////////////////////////// AliTPCCompression::AliTPCCompression(const AliTPCCompression &source) :TObject(source){ //Constructor this->fDimBuffer=source.fDimBuffer; this->fFreeBitsBuffer=source.fFreeBitsBuffer; this->fReadBits=source.fReadBits; this->fPos=source.fPos; this->fBuffer=source.fBuffer; this->fVerbose=source.fVerbose; this->fFillWords=source.fFillWords; this->fPointBuffer=source.fPointBuffer; return; } ////////////////////////////////////////////////////////////////////////////////////////////////// AliTPCCompression& AliTPCCompression::operator=(const AliTPCCompression &source){ //Redefinition of the assignment operator this->fDimBuffer=source.fDimBuffer; this->fFreeBitsBuffer=source.fFreeBitsBuffer; this->fReadBits=source.fReadBits; this->fPos=source.fPos; this->fBuffer=source.fBuffer; this->fVerbose=source.fVerbose; this->fFillWords=source.fFillWords; this->fPointBuffer=source.fPointBuffer; return *this; } ////////////////////////////////////////////////////////////////////////////////////////////////// void AliTPCCompression::NextTable(Int_t Val,Int_t &NextTableType,Int_t &BunchLen,Int_t &Count)const{ //Depending on the data type (5 types of data) a specific table is called /* Table index: 0==> Bunch length value 1==> Time Bin value 2==> 1-samples bunch 3==> Central samples 4==> Border samples */ switch (NextTableType){ case 0:{ BunchLen=Val-2; NextTableType=1; break; }//end case 0 case 1:{ if (BunchLen==1)NextTableType=2; else{ NextTableType=4; Count=1; } break; }//end case 1 case 2:{ NextTableType=0; break; }//end case 2 case 3:{ Count++; if (Count==(BunchLen-1)){ NextTableType=4; } break; }//end case 3 case 4:{ if (Count==1){ if (BunchLen>2) NextTableType=3; else Count++; } else NextTableType=0; break; }//end case 4 }//end switch return; } ///////////////////////////////////////////////////////////////////////////////////////////////////// Int_t AliTPCCompression::FillTables(const char* fSource,AliTPCHTable* table[],Int_t /*NumTables*/){ //This method is used to compute the frequencies of the symbols in the source file AliAltroBuffer buff(fSource,0); UInt_t countWords=0; UInt_t countTrailer=0; Int_t numWords,padNum,rowNum,secNum=0; Int_t value=0; UInt_t stat[5]={0,0,0,0,0}; Int_t endFill=0; Int_t end=1; while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum)){ if(end){ endFill=buff.GetFillWordsNum(); end=0; }//endif countTrailer++; if (numWords%4){ fFillWords+=4-numWords%4; for(Int_t j=0;j<(4-numWords%4);j++){ value=buff.GetNextBackWord(); }//end for }//end if Int_t packet[1024]; Int_t timePos[345]; Int_t tp=0; for(Int_t i=0;i<345;i++)timePos[i]=0; for(Int_t i=0;i<1024;i++)packet[i]=0; Int_t nextTableType=0; Int_t bunchLen=0; Int_t count=0; for(Int_t i=0;i=0;i--){ Int_t timPos=timePos[i]; Int_t bunchLen=packet[timPos-1]-2; temp=packet[timPos]; packet[timPos]=packet[timPos]-previousTime-bunchLen; previousTime=temp; } nextTableType=0; count=0; bunchLen=0; for(Int_t i=0;iSetFrequency(value); stat[nextTableType]++; NextTable(value,nextTableType,bunchLen,count); countWords++; }//end for }//end while cout<<"Number of words: "<Size(); //Table dimension is written into a file fTable.write((char*)(&dim),sizeof(Int_t)); //One table is written into a file for(Int_t i=0;iCodeLen()[i]; // UInt_t code=(UInt_t)table[k]->Code()[i]; Double_t code=table[k]->Code()[i]; fTable.write((char*)(&codeLen),sizeof(UChar_t)); //fTable.write((char*)(&code),sizeof(UInt_t)); fTable.write((char*)(&code),sizeof(Double_t)); } //end for fTable.close(); }//end for return 0; } //////////////////////////////////////////////////////////////////////////////////////// Int_t AliTPCCompression::CreateTableFormula(Double_t beta,UInt_t M,Int_t dim,Int_t Type){ // Type = 0 for Bunch length // Type = 1 for Time Gap UInt_t freq; Double_t sum=0; Double_t min=10; Double_t alpha=0; Double_t a=0; AliTPCHTable *table=new AliTPCHTable(dim); freq=1; Double_t freqArray[1024]; for(Int_t i=0;i<1024;i++){ freqArray[i]=0; } alpha=M*0.000000602+0.0104; if (fVerbose) cout<<"alpha "<=3)//minimum bunch length table->SetValFrequency(x,a*freqArray[x]*1000); else table->SetValFrequency(x,0); else //Time table table->SetValFrequency(x,a*freqArray[x]); } table->BuildHTable(); ofstream fTable; char filename[15]; sprintf(filename,"Table%d.dat",Type); #ifndef __DECCXX fTable.open(filename,ios::binary); #else fTable.open(filename); #endif Int_t dimTable=table->Size(); //Table dimension is written into a file fTable.write((char*)(&dimTable),sizeof(Int_t)); //One table is written into a file for(Int_t i=0;iCodeLen()[i]; Double_t code=table->Code()[i]; fTable.write((char*)(&codeLen),sizeof(UChar_t)); fTable.write((char*)(&code),sizeof(Double_t)); } //end for fTable.close(); delete table; return 0; } //////////////////////////////////////////////////////////////////////////////////////// Int_t AliTPCCompression::CreateTables(const char* fSource,Int_t NumTables){ //Tables manager /* Table index: 0==> Bunch length values 1==> Time Bin values 2==> 1-samples bunch 3==> Central samples 4==> Border samples */ Int_t n=10;// 10 bits per symbol AliTPCHTable ** table = new AliTPCHTable*[NumTables]; //The table is inizialized with the rigth number of rows for(Int_t i=0;iSetVerbose(fVerbose); } //The frequencies are calculated and the tables are filled if (fVerbose) cout<<"Filling tables...\n"; //The get the frequencies FillTables(fSource,table,NumTables); //This part will be used in the table optimization phase for(Int_t i=0;iCompleteTable(i); } if(fVerbose){ cout<<"Entropy of Bunch length table........."<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<NormalizeFrequencies(); table[1]->NormalizeFrequencies(); table[2]->NormalizeFrequencies(); table[3]->NormalizeFrequencies(); table[4]->NormalizeFrequencies(); //Tables are saved in a sequence of text file and using the macro Histo.C is it possible to get //a series of histograms rappresenting the frequency distribution table[0]->StoreFrequencies("BunchLenFreq.txt"); table[1]->StoreFrequencies("TimeFreq.txt"); table[2]->StoreFrequencies("Sample1Freq.txt"); table[3]->StoreFrequencies("SCentralFreq.txt"); table[4]->StoreFrequencies("SBorderFreq.txt"); if (fVerbose) cout<<"Creating Tables..\n"; //One Huffman tree is created for each table starting from the frequencies of the symbols for(Int_t i=0;iBuildHTable(); if (fVerbose==2){ cout<<"Number of elements inside the table:"<GetWordsNumber(); switch(i){ case 0:{ cout<<" (Bunch Length)"<PrintTable(); } } //The tables are saved ad binary files StoreTables(table,NumTables); //The tables stored in memory are deleted; for(Int_t i=0;iGetenv("ALICE_ROOT")){ fTable.clear(); sprintf(filename,"%s/RAW/Table%d.dat",gSystem->Getenv("ALICE_ROOT"),k); #ifndef __DECCXX fTable.open(filename,ios::binary); #else fTable.open(filename); #endif } if(!fTable){ Error("RetrieveTables", "File doesn't exist: %s", filename); return 1; } fTable.read((char*)(&dim),sizeof(Int_t)); if (fVerbose) cout<<"Table dimension: "<SetCodeLen(codeLen,i); // fTable.read((char*)(&code),sizeof(UInt_t)); fTable.read((char*)(&code),sizeof(Double_t)); table[k]->SetCode(Mirror((UInt_t)code,codeLen),i); }//end for fTable.close(); }//end for if (fVerbose) cout<<"Trees generated \n"; //At this point the trees are been built return 0; } Int_t AliTPCCompression::CreateTablesFromTxtFiles(Int_t NumTable){ //This method creates a set of binary tables, needed by the Huffman //algorith, starting from a set of frequencies tables stored in form of //txt files if (fVerbose) cout<<"Retrieving frequencies from txt files \n"; ifstream fTable; char filename[15]; //Tables are read from the files (Each codeword has been "Mirrored") AliTPCHTable **table = new AliTPCHTable*[NumTable]; for(Int_t k=0;k>freq; if (fTable.good()){ if (freq<0){ cout<<"Frequency cannot be negative !!!\n"; exit(1); } table[k]->SetValFrequency(symbol,freq); } symbol++; }//end while fTable.clear(); fTable.close(); }//end for fStat.open("Statistics",ios::app); fStat<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<GetEntropy()<BuildHTable(); }//end for //The tables are saved ad binary files StoreTables(table,NumTable); //The tables stored in memory are deleted; for(Int_t i=0;i>(len-fFreeBitsBuffer); fBuffer=fBuffer|temp; f.write((char*)(&fBuffer),sizeof(UInt_t)); fFreeBitsBuffer=fDimBuffer-(len-fFreeBitsBuffer); val=val<>fFreeBitsBuffer; fBuffer=val; }//end else return; } ////////////////////////////////////////////////////////////////////////////////////////////////// void AliTPCCompression::Flush(){ //The last buffer cannot be completely full so to save it //into the output file it is first necessary to fill it with an hexadecimal pattern if(fFreeBitsBuffer>i; specular=specular<<1; specular=specular|bit; mask=mask<<1; } return specular; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Int_t AliTPCCompression::CompressDataOptTables(Int_t NumTable,const char* fSource,const char* fDest){ //This method compress an Altro format file using a general set of tables stored as binary files to be provided if (fVerbose){ cout<<" BackWord COMPRESSION "<=0;i--){ Int_t timPos=timePos[i]; Int_t bunchLen=packet[timPos-1]-2; temp=packet[timPos]; packet[timPos]=packet[timPos]-previousTime-bunchLen; previousTime=temp; }//end for nextTableType=0; count=0; bunchLen=0; Int_t timeBin=0; for(Int_t i=0;i1){ //UInt_t val=(UInt_t)table[nextTableType]->Code()[value]; // val is the code Double_t val=table[nextTableType]->Code()[value]; // val is the code UChar_t len=table[nextTableType]->CodeLen()[value]; // len is the length (number of bits)of val stat[nextTableType]+=len; numElem[nextTableType]++; StoreValue((UInt_t)val,len); storedWords++; }//end if NextTable(value,nextTableType,bunchLen,count); if(nextTableType==0){ // UInt_t val=(UInt_t)table[1]->Code()[timeBin]; // val is the code Double_t val=table[1]->Code()[timeBin]; // val is the code UChar_t len=table[1]->CodeLen()[timeBin]; // len is the length (number of bits)of val stat[1]+=len; numElem[1]++; StoreValue((UInt_t)val,len); // val=(UInt_t)table[nextTableType]->Code()[(bunchLen+2)]; // val is the code val=table[nextTableType]->Code()[(bunchLen+2)]; // val is the code len=table[nextTableType]->CodeLen()[(bunchLen+2)]; // len is the length (number of bits)of val StoreValue((UInt_t)val,len); stat[nextTableType]+=len; numElem[nextTableType]++; storedWords+=2; } }//end for //Trailer StoreValue(numWords,10); StoreValue(padNum,10); StoreValue(rowNum,10); StoreValue(secNum,9); StoreValue(1,1); storedWords+=4; trailerNumbers++; }//end while StoreValue(numPackets,32); if(fVerbose) cout<<"Number of strored packets: "<Getenv("ALICE_ROOT")){ fTable.clear(); sprintf(filename,"%s/RAW/Table%d.dat",gSystem->Getenv("ALICE_ROOT"),k); #ifndef __DECCXX fTable.open(filename,ios::binary); #else fTable.open(filename); #endif } if(!fTable){ Error("CreateTreesFromFile", "File doesn't exist: %s", filename); return 1; } fTable.read((char*)(&dim),sizeof(Int_t)); if (fVerbose) cout<<"Table dimension: "<GetRight(); if(!node){ node=new AliTPCHNode(); temp->SetRight(node); }//end if }//end if else{ node=node->GetLeft(); if(!node){ node=new AliTPCHNode(); temp->SetLeft(node); }//end if }//end else }//end for if(codeLen){ node->SetSymbol(i); node->SetFrequency(codeLen); }//end if }//end for fTable.close(); }//end for if (fVerbose) cout<<"Trees generated \n"; //At this point the trees are been built return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////// void AliTPCCompression::DeleteHuffmanTree(AliTPCHNode* node){ //This function deletes all the nodes of an Huffman tree //In an Huffman tree any internal node has always two children if (node){ DeleteHuffmanTree(node->GetLeft()); DeleteHuffmanTree(node->GetRight()); // cout<GetSymbol()<<" "<<(Int_t)node->GetFrequency()<GetSymbol()<<" "<GetFrequency()<GetLeft()); VisitHuffmanTree(node->GetRight()); } } ////////////////////////////////////////////////////////////////////////////////////////////////// UInt_t AliTPCCompression::ReadWord(Int_t NumberOfBit){ //This method retrieves a word of a specific number of bits from the file through the internal buffer UInt_t result=0; UInt_t bit=0; for (Int_t i=0;i>fReadBits; fReadBits++; bit=bit<>1; }//end for return result; } ////////////////////////////////////////////////////////////////////////////////////////////////// inline UInt_t AliTPCCompression::ReadBitFromWordBuffer(){ //This method retrieves a word of a specific number of bits from the file through the buffer UInt_t result=0; if (fReadBits==32){ fPointBuffer--; fBuffer=*fPointBuffer; fReadBits=0; }//end if result=fBuffer&0x1; fReadBits++; fBuffer=fBuffer>>1; return result; } ////////////////////////////////////////////////////////////////////////////////////////////////// void AliTPCCompression::ReadTrailer(Int_t &WordsNumber,Int_t &PadNumber,Int_t &RowNumber,Int_t &SecNumber,Bool_t Memory){ //It retrieves a trailer if(Memory){ ReadBitFromWordBuffer(); SecNumber=ReadWordBuffer(9); RowNumber=ReadWordBuffer(10); PadNumber=ReadWordBuffer(10); WordsNumber=ReadWordBuffer(10); } else{ ReadWord(1); SecNumber=ReadWord(9); RowNumber=ReadWord(10); PadNumber=ReadWord(10); WordsNumber=ReadWord(10); } return; } ////////////////////////////////////////////////////////////////////////////////////////////////// inline UInt_t AliTPCCompression::GetDecodedWordBuffer(AliTPCHNode* root){ //This method retrieves a decoded word. AliTPCHNode *node=root; UInt_t symbol=0; Bool_t decoded=0; while(!decoded){ UInt_t bit=ReadBitFromWordBuffer(); if(bit) node=node->GetRight(); else node=node->GetLeft(); if (!(node->GetLeft())){ symbol=node->GetSymbol(); decoded=1; } }//end while return symbol; } inline UInt_t AliTPCCompression::GetDecodedWord(AliTPCHNode* root){ //This method retrieves a decoded word. AliTPCHNode *node=root; UInt_t symbol=0; Bool_t decoded=0; while(!decoded){ UInt_t bit=ReadWord(1); if(bit) node=node->GetRight(); else node=node->GetLeft(); if (!(node->GetLeft())){ symbol=node->GetSymbol(); decoded=1; } }//end while return symbol; } ////////////////////////////////////////////////////////////////////////////////////////////////// Int_t AliTPCCompression::DecompressDataOptTables(Int_t NumTables,const char* fname, const char* fDest){ //This method decompress a file using separate Huffman tables if(fVerbose){ cout<<" DECOMPRESSION:"<1) bufferFile.FillBuffer(symbol); NextTable(symbol,nextTableType,bunchLen,count); if(nextTableType==0){ bufferFile.FillBuffer(time); bufferFile.FillBuffer(bunchLen+2); bunchLen=0; } }//end for bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber); }//end while if(fVerbose){ cout<<"Number of decoded words:"<>1; fReadBits++; }//end while UInt_t packetNumber=ReadWordBuffer(sizeof(UInt_t)*8); //32 bits if (fVerbose){ cout<<"First one has been found "<SetPadID(padNumber,rowNumber,secNumber,DDL); k++; wordsRead+=4; Int_t previousTime=-1; Int_t time=0; Int_t nextTableType=0; Int_t bunchLen=0; Int_t count=0; Int_t timeDigit=0; for(Int_t i=0;i1){ // //ftxt<SetDigits(symbol,timeDigit); } NextTable(symbol,nextTableType,bunchLen,count); if(nextTableType==0){ // //ftxt<