1 /**************************************************************************
2 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
19 // This class contains the implementation of the
20 // compression and decompression algorithms
21 // Compression is performed reading the Altro data block (called packet) backward.
22 // Similarly decompression is also done backward so that the final file is restored
23 // after the compression and decompression phase.
26 #include <TObjArray.h>
27 #include <Riostream.h>
30 #include "AliAltroBuffer.h"
31 #include "AliTPCHNode.h"
32 #include "AliTPCHTable.h"
33 #include "AliTPCCompression.h"
35 ClassImp(AliTPCCompression)
36 //////////////////////////////////////////////////////////////////////////////////////////////////
37 AliTPCCompression::AliTPCCompression(){
39 fDimBuffer=sizeof(UInt_t)*8;
40 fFreeBitsBuffer=fDimBuffer;
49 //////////////////////////////////////////////////////////////////////////////////////////////////
50 AliTPCCompression::AliTPCCompression(const AliTPCCompression &source)
53 this->fDimBuffer=source.fDimBuffer;
54 this->fFreeBitsBuffer=source.fFreeBitsBuffer;
55 this->fReadBits=source.fReadBits;
56 this->fPos=source.fPos;
57 this->fBuffer=source.fBuffer;
58 this->fVerbose=source.fVerbose;
59 this->fFillWords=source.fFillWords;
60 this->fPointBuffer=source.fPointBuffer;
63 //////////////////////////////////////////////////////////////////////////////////////////////////
64 AliTPCCompression& AliTPCCompression::operator=(const AliTPCCompression &source){
65 //Redefinition of the assignment operator
66 this->fDimBuffer=source.fDimBuffer;
67 this->fFreeBitsBuffer=source.fFreeBitsBuffer;
68 this->fReadBits=source.fReadBits;
69 this->fPos=source.fPos;
70 this->fBuffer=source.fBuffer;
71 this->fVerbose=source.fVerbose;
72 this->fFillWords=source.fFillWords;
73 this->fPointBuffer=source.fPointBuffer;
76 //////////////////////////////////////////////////////////////////////////////////////////////////
77 void AliTPCCompression::NextTable(Int_t Val,Int_t &NextTableType,Int_t &BunchLen,Int_t &Count)const{
78 //Depending on the data type (5 types of data) a specific table is called
81 0==> Bunch length value
87 switch (NextTableType){
94 if (BunchLen==1)NextTableType=2;
107 if (Count==(BunchLen-1)){
128 /////////////////////////////////////////////////////////////////////////////////////////////////////
130 Int_t AliTPCCompression::FillTables(const char* fSource,AliTPCHTable* table[],Int_t /*NumTables*/){
131 //This method is used to compute the frequencies of the symbols in the source file
132 AliAltroBuffer buff(fSource,0);
134 UInt_t countTrailer=0;
135 Int_t numWords,padNum,rowNum,secNum=0;
137 UInt_t stat[5]={0,0,0,0,0};
140 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum)){
142 endFill=buff.GetFillWordsNum();
147 fFillWords+=4-numWords%4;
148 for(Int_t j=0;j<(4-numWords%4);j++){
149 value=buff.GetNextBackWord();
156 for(Int_t i=0;i<345;i++)timePos[i]=0;
157 for(Int_t i=0;i<1024;i++)packet[i]=0;
159 Int_t nextTableType=0;
162 for(Int_t i=0;i<numWords;i++){
163 value=buff.GetNextBackWord();
165 if(nextTableType==1){
169 NextTable(value,nextTableType,bunchLen,count);
171 //computing the Time gap between two bunches
174 Int_t previousTime=packet[timePos[tp]];
175 for(Int_t i=tp-1;i>=0;i--){
176 Int_t timPos=timePos[i];
177 Int_t bunchLen=packet[timPos-1]-2;
179 packet[timPos]=packet[timPos]-previousTime-bunchLen;
185 for(Int_t i=0;i<numWords;i++){
187 table[nextTableType]->SetFrequency(value);
188 stat[nextTableType]++;
189 NextTable(value,nextTableType,bunchLen,count);
193 cout<<"Number of words: "<<countWords<<endl;
194 cout<<"Number of trailers: "<<countTrailer<<endl;
195 cout<<"Number of fill words "<<fFillWords+endFill<<endl;
196 cout<<"Total number of words: "<<countWords+countTrailer*4+fFillWords<<endl;
198 fStat.open("Statistics");
199 fStat<<"Number of words:..........................................."<<countWords<<endl;
200 fStat<<"Number of trailers (4 10 bits words in each one)..........."<<countTrailer<<endl;
201 fStat<<"Number of fill words:......................................"<<fFillWords+endFill<<endl;
202 fStat<<"Total number of words:....................................."<<countWords+countTrailer*4+fFillWords+endFill<<endl;
203 fStat<<"-----------------------------------------"<<endl;
204 fStat<<"Number of Bunches............."<<stat[0]<<endl;
205 fStat<<"Number of Time bin............"<<stat[1]<<endl;
206 fStat<<"Number of One Samples Bunch..."<<stat[2]<<endl;
207 fStat<<"Number of Central Samples....."<<stat[3]<<endl;
208 fStat<<"Number of Border Samples......"<<stat[4]<<endl;
209 fStat<<"-----------------------------------------"<<endl;
210 UInt_t fileDimension=(UInt_t)TMath::Ceil(double((countTrailer*4+countWords+fFillWords+endFill)*10/8));
211 fStat<<"Total file Size in bytes.."<<fileDimension<<endl;
212 Double_t percentage=TMath::Ceil((fFillWords+endFill)*125)/fileDimension;
213 fStat<<"Fill Words................"<<(UInt_t)TMath::Ceil((fFillWords+endFill)*10/8)<<" bytes "<<percentage<<"%"<<endl;
214 percentage=(Double_t)countTrailer*500/fileDimension;
215 fStat<<"Trailer..................."<<countTrailer*5<<" bytes "<<percentage<<"%"<<endl;
217 percentage=(Double_t)((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])) *125/fileDimension;
218 fStat<<"Data......................"<<(UInt_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])*10/8)<<" bytes "<<percentage<<"%"<<endl;
220 percentage=(Double_t)(stat[0]*125)/fileDimension;
221 fStat<<"Bunch....................."<<(UInt_t)TMath::Ceil(stat[0]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
222 percentage=(Double_t)(stat[1]*125)/fileDimension;
223 fStat<<"Time......................"<<(UInt_t)TMath::Ceil(stat[1]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
226 percentage=(Double_t)((stat[2]+stat[3]+stat[4])) *125/fileDimension;
227 fStat<<"Amplitude values.........."<<(UInt_t)TMath::Ceil((stat[2]+stat[3]+stat[4])*10/8)<<" bytes "<<percentage<<"%"<<endl;
228 percentage=(Double_t)(stat[2]*125)/fileDimension;
229 fStat<<" One Samples..............."<<(UInt_t)TMath::Ceil(stat[2]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
230 percentage=(Double_t)(stat[3]*125)/fileDimension;
231 fStat<<" Central Samples..........."<<(UInt_t)TMath::Ceil(stat[3]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
232 percentage=(Double_t)(stat[4]*125)/fileDimension;
233 fStat<<" Border Samples............"<<(UInt_t)TMath::Ceil(stat[4]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
237 ////////////////////////////////////////////////////////////////////////////////////////
238 Int_t AliTPCCompression::StoreTables(AliTPCHTable* table[],const Int_t NumTable){
239 //This method stores the tables in a sequence of binary file
242 for(Int_t k=0;k<NumTable;k++){
243 sprintf(filename,"Table%d.dat",k);
245 fTable.open(filename,ios::binary);
247 fTable.open(filename);
249 Int_t dim=table[k]->Size();
250 //Table dimension is written into a file
251 fTable.write((char*)(&dim),sizeof(Int_t));
252 //One table is written into a file
253 for(Int_t i=0;i<dim;i++){
254 UChar_t codeLen=table[k]->CodeLen()[i];
255 // UInt_t code=(UInt_t)table[k]->Code()[i];
256 Double_t code=table[k]->Code()[i];
257 fTable.write((char*)(&codeLen),sizeof(UChar_t));
258 //fTable.write((char*)(&code),sizeof(UInt_t));
259 fTable.write((char*)(&code),sizeof(Double_t));
265 ////////////////////////////////////////////////////////////////////////////////////////
266 Int_t AliTPCCompression::CreateTableFormula(Double_t beta,UInt_t M,Int_t dim,Int_t Type){
267 // Type = 0 for Bunch length
268 // Type = 1 for Time Gap
274 AliTPCHTable *table=new AliTPCHTable(dim);
277 Double_t freqArray[1024];
278 for(Int_t i=0;i<1024;i++){
281 alpha=M*0.000000602+0.0104;
283 cout<<"alpha "<<alpha<<endl;
284 for(Int_t x=0;x<dim;x++){
286 freqArray[x]=TMath::Power((x+1),-beta)*TMath::Exp(-alpha*(x+1));
288 freqArray[x]=TMath::Power((x+1),-beta);
290 if (freqArray[x]<min)min=freqArray[x];
293 cout<<"Minimun Value "<<min<<endl;
296 cout<<"a Value: "<<a<<endl;
297 for(Int_t x=0;x<dim;x++){
298 if (Type==0)//Bunch length
299 if (x>=3)//minimum bunch length
300 table->SetValFrequency(x,a*freqArray[x]*1000);
302 table->SetValFrequency(x,0);
304 table->SetValFrequency(x,a*freqArray[x]);
306 table->BuildHTable();
309 sprintf(filename,"Table%d.dat",Type);
311 fTable.open(filename,ios::binary);
313 fTable.open(filename);
315 Int_t dimTable=table->Size();
316 //Table dimension is written into a file
317 fTable.write((char*)(&dimTable),sizeof(Int_t));
318 //One table is written into a file
319 for(Int_t i=0;i<dimTable;i++){
320 UChar_t codeLen=table->CodeLen()[i];
321 Double_t code=table->Code()[i];
322 fTable.write((char*)(&codeLen),sizeof(UChar_t));
323 fTable.write((char*)(&code),sizeof(Double_t));
329 ////////////////////////////////////////////////////////////////////////////////////////
330 Int_t AliTPCCompression::CreateTables(const char* fSource,Int_t NumTables){
334 0==> Bunch length values
340 Int_t n=10;// 10 bits per symbol
341 AliTPCHTable ** table = new AliTPCHTable*[NumTables];
342 //The table is inizialized with the rigth number of rows
343 for(Int_t i=0;i<NumTables;i++){
344 table[i]=new AliTPCHTable((Int_t)(TMath::Power(2,n)));
345 table[i]->SetVerbose(fVerbose);
347 //The frequencies are calculated and the tables are filled
349 cout<<"Filling tables...\n";
350 //The get the frequencies
351 FillTables(fSource,table,NumTables);
353 //This part will be used in the table optimization phase
355 for(Int_t i=0;i<NumTables;i++){
356 table[i]->CompleteTable(i);
360 cout<<"Entropy of Bunch length table........."<<table[0]->GetEntropy()<<endl;
361 cout<<"Entropy of Time bin table............."<<table[1]->GetEntropy()<<endl;
362 cout<<"Entropy of one Sample bunch table....."<<table[2]->GetEntropy()<<endl;
363 cout<<"Entropy of Central Sample table......."<<table[3]->GetEntropy()<<endl;
364 cout<<"Entropy Border Samples table.........."<<table[4]->GetEntropy()<<endl;
366 fStat.open("Statistics",ios::app);
368 fStat<<"----------------- ENTROPY for castomized tables --------------------------"<<endl;
369 fStat<<"Entropy of Bunch length table......."<<table[0]->GetEntropy()<<endl;
370 fStat<<"Entropy of Time bin table..........."<<table[1]->GetEntropy()<<endl;
371 fStat<<"Entropy of one Sample bunch table..."<<table[2]->GetEntropy()<<endl;
372 fStat<<"Entropy of Central Sample table....."<<table[3]->GetEntropy()<<endl;
373 fStat<<"Entropy Border Samples table........"<<table[4]->GetEntropy()<<endl;
377 cout<<"Tables filled \n";
379 //Frequencies normalization
380 table[0]->NormalizeFrequencies();
381 table[1]->NormalizeFrequencies();
382 table[2]->NormalizeFrequencies();
383 table[3]->NormalizeFrequencies();
384 table[4]->NormalizeFrequencies();
386 //Tables are saved in a sequence of text file and using the macro Histo.C is it possible to get
387 //a series of histograms rappresenting the frequency distribution
388 table[0]->StoreFrequencies("BunchLenFreq.txt");
389 table[1]->StoreFrequencies("TimeFreq.txt");
390 table[2]->StoreFrequencies("Sample1Freq.txt");
391 table[3]->StoreFrequencies("SCentralFreq.txt");
392 table[4]->StoreFrequencies("SBorderFreq.txt");
394 cout<<"Creating Tables..\n";
395 //One Huffman tree is created for each table starting from the frequencies of the symbols
396 for(Int_t i=0;i<NumTables;i++){
397 table[i]->BuildHTable();
399 cout<<"Number of elements inside the table:"<<table[i]->GetWordsNumber();
402 cout<<" (Bunch Length)"<<endl;
406 cout<<" (Time Bin)"<<endl;
410 cout<<" (1 Samples Bunch)"<<endl;
414 cout<<" (Central Samples)"<<endl;
418 cout<<" (Border Samples)"<<endl;
422 table[i]->PrintTable();
425 //The tables are saved ad binary files
426 StoreTables(table,NumTables);
427 //The tables stored in memory are deleted;
428 for(Int_t i=0;i<NumTables;i++)delete table[i];
432 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
433 Int_t AliTPCCompression::RetrieveTables(AliTPCHTable* table[],Int_t NumTable){
434 //This method retrieve the Huffman tables from a sequence of binary files
436 cout<<"Retrieving tables from files \n";
442 //The following for loop is used to generate the Huffman trees acording to the tables
443 for(Int_t k=0;k<NumTable;k++){
444 Int_t dim;//this variable contains the table dimension
445 sprintf(filename,"Table%d.dat",k);
447 fTable.open(filename,ios::binary);
449 fTable.open(filename);
451 if(!fTable && gSystem->Getenv("ALICE_ROOT")){
453 sprintf(filename,"%s/RAW/Table%d.dat",gSystem->Getenv("ALICE_ROOT"),k);
455 fTable.open(filename,ios::binary);
457 fTable.open(filename);
461 Error("RetrieveTables", "File doesn't exist: %s", filename);
464 fTable.read((char*)(&dim),sizeof(Int_t));
466 cout<<"Table dimension: "<<dim<<endl;
467 table[k]=new AliTPCHTable(dim);
468 for(Int_t i=0;i<dim;i++){
469 fTable.read((char*)(&codeLen),sizeof(UChar_t));
470 table[k]->SetCodeLen(codeLen,i);
471 // fTable.read((char*)(&code),sizeof(UInt_t));
472 fTable.read((char*)(&code),sizeof(Double_t));
473 table[k]->SetCode(Mirror((UInt_t)code,codeLen),i);
478 cout<<"Trees generated \n";
479 //At this point the trees are been built
483 Int_t AliTPCCompression::CreateTablesFromTxtFiles(Int_t NumTable){
484 //This method creates a set of binary tables, needed by the Huffman
485 //algorith, starting from a set of frequencies tables stored in form of
488 cout<<"Retrieving frequencies from txt files \n";
491 //Tables are read from the files (Each codeword has been "Mirrored")
492 AliTPCHTable **table = new AliTPCHTable*[NumTable];
493 for(Int_t k=0;k<NumTable;k++){
494 sprintf(filename,"Table%d.txt",k);
495 cout<<filename<<endl;
496 fTable.open(filename);
498 Error("CreateTablesFromTxtFiles", "File doesn't exist: %s", filename);
503 table[k]=new AliTPCHTable(1024);
504 while(!fTable.eof()){
508 cout<<"Frequency cannot be negative !!!\n";
511 table[k]->SetValFrequency(symbol,freq);
518 fStat.open("Statistics",ios::app);
520 fStat<<"----------------- ENTROPY for external txt tables --------------------------"<<endl;
521 fStat<<"Entropy of Bunch length table......."<<table[0]->GetEntropy()<<endl;
522 fStat<<"Entropy of Time bin table..........."<<table[1]->GetEntropy()<<endl;
523 fStat<<"Entropy of one Sample bunch table..."<<table[2]->GetEntropy()<<endl;
524 fStat<<"Entropy of Central Sample table....."<<table[3]->GetEntropy()<<endl;
525 fStat<<"Entropy Border Samples table........"<<table[4]->GetEntropy()<<endl;
527 for(Int_t k=0;k<NumTable;k++){
528 table[k]->BuildHTable();
530 //The tables are saved ad binary files
531 StoreTables(table,NumTable);
532 //The tables stored in memory are deleted;
533 for(Int_t i=0;i<NumTable;i++)delete table[i];
538 ////////////////////////////////////////////////////////////////////////////////////////
540 ////////////////////////////////////////////////////////////////////////////////////////
542 void AliTPCCompression::StoreValue(UInt_t val,UChar_t len){
543 //This method stores the value "val" of "len" bits into the internal buffer "fBuffer"
544 if (len<=fFreeBitsBuffer){ // val is not splitted in two buffer
545 fFreeBitsBuffer-=len;
546 fBuffer=fBuffer<<len;
548 if(!fFreeBitsBuffer){ // if the buffer is full it is written into a file
549 f.write((char*)(&fBuffer),sizeof(UInt_t));
550 fFreeBitsBuffer=fDimBuffer;
554 else{ //val has to be splitted in two buffers
555 fBuffer=fBuffer<<fFreeBitsBuffer;
558 temp=temp>>(len-fFreeBitsBuffer);
559 fBuffer=fBuffer|temp;
560 f.write((char*)(&fBuffer),sizeof(UInt_t));
561 fFreeBitsBuffer=fDimBuffer-(len-fFreeBitsBuffer);
562 val=val<<fFreeBitsBuffer;
563 val=val>>fFreeBitsBuffer;
568 //////////////////////////////////////////////////////////////////////////////////////////////////
569 void AliTPCCompression::Flush(){
570 //The last buffer cannot be completely full so to save it
571 //into the output file it is first necessary to fill it with an hexadecimal pattern
572 if(fFreeBitsBuffer<fDimBuffer){
573 fBuffer=fBuffer<<fFreeBitsBuffer;
574 f.write((char*)(&fBuffer),sizeof(UInt_t));
578 //////////////////////////////////////////////////////////////////////////////////////////////////
579 UInt_t AliTPCCompression::Mirror(UInt_t val,UChar_t len)const{
580 //This method inverts the digits of the number "val" and length "len"
581 //indicates the number of digits of the number considered in binary notation
585 for(Int_t i=0;i<len;i++){
588 specular=specular<<1;
589 specular=specular|bit;
595 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
596 Int_t AliTPCCompression::CompressDataOptTables(Int_t NumTable,const char* fSource,const char* fDest){
597 //This method compress an Altro format file using a general set of tables stored as binary files to be provided
599 cout<<" BackWord COMPRESSION "<<endl;
600 cout<<"compression of the file "<<fSource<<" Output File: "<<fDest<<endl;
602 //Tables are read from the files (Each codeword has been "Mirrored")
603 AliTPCHTable **table = new AliTPCHTable*[NumTable];
604 for(Int_t i=0;i<NumTable;i++) table[i] = NULL;
605 if (RetrieveTables(table,NumTable) != 0) {
606 for(Int_t i=0;i<NumTable;i++) delete table[i];
610 //the output file is open
613 f.open(fDest,ios::binary|ios::out);
615 f.open(fDest,ios::out);
617 // Source file is open
618 AliAltroBuffer buff(fSource,0);
619 //coded words are written into a file
620 Int_t numWords,padNum,rowNum,secNum=0;
621 UInt_t storedWords=0;
624 Double_t stat[5]={0.,0.,0.,0.,0.};
625 UInt_t trailerNumbers=0;
626 Double_t numElem[5]={0,0,0,0,0};
627 Double_t fillWords=0.;
629 fStat.open("Statistics",ios::app);
631 fStat<<"-------------------COMPRESSION STATISTICS----------"<<endl;
633 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum)){
635 fillWords=buff.GetFillWordsNum();
641 fillWords+=4-numWords%4;
642 for(Int_t j=0;j<(4-numWords%4);j++){
643 value=buff.GetNextBackWord();
650 for(Int_t i=0;i<345;i++)timePos[i]=0;
651 for(Int_t i=0;i<1024;i++)packet[i]=0;
653 Int_t nextTableType=0;
656 for(Int_t i=0;i<numWords;i++){
657 value=buff.GetNextBackWord();
659 if(nextTableType==1){
663 NextTable(value,nextTableType,bunchLen,count);
665 //computing the Time gap between two bunches
668 Int_t previousTime=packet[timePos[tp]];
669 for(Int_t i=tp-1;i>=0;i--){
670 Int_t timPos=timePos[i];
671 Int_t bunchLen=packet[timPos-1]-2;
673 packet[timPos]=packet[timPos]-previousTime-bunchLen;
681 for(Int_t i=0;i<numWords;i++){
683 if(nextTableType==1)timeBin=value;
685 //UInt_t val=(UInt_t)table[nextTableType]->Code()[value]; // val is the code
686 Double_t val=table[nextTableType]->Code()[value]; // val is the code
687 UChar_t len=table[nextTableType]->CodeLen()[value]; // len is the length (number of bits)of val
688 stat[nextTableType]+=len;
689 numElem[nextTableType]++;
690 StoreValue((UInt_t)val,len);
693 NextTable(value,nextTableType,bunchLen,count);
694 if(nextTableType==0){
695 // UInt_t val=(UInt_t)table[1]->Code()[timeBin]; // val is the code
696 Double_t val=table[1]->Code()[timeBin]; // val is the code
697 UChar_t len=table[1]->CodeLen()[timeBin]; // len is the length (number of bits)of val
700 StoreValue((UInt_t)val,len);
701 // val=(UInt_t)table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
702 val=table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
703 len=table[nextTableType]->CodeLen()[(bunchLen+2)]; // len is the length (number of bits)of val
704 StoreValue((UInt_t)val,len);
705 stat[nextTableType]+=len;
706 numElem[nextTableType]++;
711 StoreValue(numWords,10);
712 StoreValue(padNum,10);
713 StoreValue(rowNum,10);
714 StoreValue(secNum,9);
719 StoreValue(numPackets,32);
721 cout<<"Number of strored packets: "<<numPackets<<endl;
723 //The last buffen cannot be completely full
726 cout<<"Number of stored words: "<<storedWords<<endl;
729 for(Int_t i=0;i<NumTable;i++){
733 Double_t dimension=(UInt_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)+trailerNumbers*5;
734 fStat<<"Trailer Dimension in bytes......"<<trailerNumbers*5<<endl;
735 fStat<<"Data Dimension in bytes........."<<(UInt_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)<<endl;
736 fStat<<"Compressed file dimension......."<<(UInt_t)dimension<<endl;
738 fStat<<(UInt_t)trailerNumbers<<endl;
739 fStat<<(UInt_t)fillWords<<endl;
740 fStat<<(UInt_t)numElem[0]<<endl;
741 fStat<<(UInt_t)numElem[1]<<endl;
742 fStat<<(UInt_t)numElem[2]<<endl;
743 fStat<<(UInt_t)numElem[3]<<endl;
744 fStat<<(UInt_t)numElem[4]<<endl;
746 fillWords=(fillWords+numElem[0]+numElem[1]+numElem[2]+numElem[3]+numElem[4]+trailerNumbers*4)*10/8;
747 fStat<<"Original file dimension........."<<(UInt_t)fillWords<<endl;
749 Double_t ratio=(dimension/fillWords)*100;
750 fStat<<"Compression ratio (Compressed/Uncompressed)..."<<ratio<<"%"<<endl;
753 fStat<<"Bunch length size in bytes......"<<(UInt_t)TMath::Ceil(stat[0]/8)<<" Comppression.."<<(stat[0]/numElem[0])*10<<"%"<<endl;
755 fStat<<"Time gap size in bytes.........."<<(UInt_t)TMath::Ceil(stat[1]/8)<<" Comppression.."<<(stat[1]/numElem[1])*10<<"%"<<endl;
756 if (numElem[2]+numElem[3]+numElem[4])
757 fStat<<"Amplitude values in bytes......."<<(UInt_t)TMath::Ceil((stat[2]+stat[3]+stat[4])/8)<<" Comppression.."<<
758 ((stat[2]+stat[3]+stat[4])/(numElem[2]+numElem[3]+numElem[4]))*10<<"%"<<endl;
760 fStat<<" One Samples in bytes............"<<(UInt_t)TMath::Ceil(stat[2]/8)<<" Comppression.."<<(stat[2]/numElem[2])*10<<"%"<<endl;
762 fStat<<" Central Samples size in bytes..."<<(UInt_t)TMath::Ceil(stat[3]/8)<<" Comppression.."<<(stat[3]/numElem[3])*10<<"%"<<endl;
764 fStat<<" Border Samples size in bytes...."<<(UInt_t)TMath::Ceil(stat[4]/8)<<" Comppression.."<<(stat[4]/numElem[4])*10<<"%"<<endl;
766 fStat<<"Average number of bits per word"<<endl;
768 fStat<<"Bunch length ......"<<stat[0]/numElem[0]<<endl;
770 fStat<<"Time gap .........."<<stat[1]/numElem[1]<<endl;
772 fStat<<"One Samples........"<<stat[2]/numElem[2]<<endl;
774 fStat<<"Central Samples ..."<<stat[3]/numElem[3]<<endl;
776 fStat<<"Border Samples....."<<stat[4]/numElem[4]<<endl;
781 ////////////////////////////////////////////////////////////////////////////////////////
783 ////////////////////////////////////////////////////////////////////////////////////////
785 ////////////////////////////////////////////////////////////////////////////////////////
787 Int_t AliTPCCompression::CreateTreesFromFile(AliTPCHNode *RootNode[],Int_t NumTables){
788 //For each table this method builds the associate Huffman tree starting from the codeword and
789 //the codelength of each symbol
791 cout<<"Creating the Huffman trees \n";
798 //The following for loop is used to generate the Huffman trees acording to the tables
799 //loop over the tables
800 for(Int_t k=0;k<NumTables;k++){
801 RootNode[k]=new AliTPCHNode(); //RootNode is the root of the tree
802 Int_t dim=0;//this variable contains the table dimension
803 sprintf(filename,"Table%d.dat",k);
805 fTable.open(filename,ios::binary);
807 fTable.open(filename);
809 if(!fTable && gSystem->Getenv("ALICE_ROOT")){
811 sprintf(filename,"%s/RAW/Table%d.dat",gSystem->Getenv("ALICE_ROOT"),k);
813 fTable.open(filename,ios::binary);
815 fTable.open(filename);
819 Error("CreateTreesFromFile", "File doesn't exist: %s", filename);
822 fTable.read((char*)(&dim),sizeof(Int_t));
824 cout<<"Table dimension: "<<dim<<endl;
825 //loop over the words of one table
826 for(Int_t i=0;i<dim;i++){
827 fTable.read((char*)(&codeLen),sizeof(UChar_t));
828 //fTable.read((char*)(&code),sizeof(UInt_t));
829 fTable.read((char*)(&code),sizeof(Double_t));
831 for(Int_t j=1;j<=codeLen;j++){
833 val=(UInt_t)TMath::Power(2,codeLen-j);
834 bit=(UInt_t)code&val;
835 AliTPCHNode *temp=node;
837 node=node->GetRight();
839 node=new AliTPCHNode();
840 temp->SetRight(node);
844 node=node->GetLeft();
846 node=new AliTPCHNode();
853 node->SetFrequency(codeLen);
859 cout<<"Trees generated \n";
860 //At this point the trees are been built
863 //////////////////////////////////////////////////////////////////////////////////////////////////
864 void AliTPCCompression::DeleteHuffmanTree(AliTPCHNode* node){
865 //This function deletes all the nodes of an Huffman tree
866 //In an Huffman tree any internal node has always two children
868 DeleteHuffmanTree(node->GetLeft());
869 DeleteHuffmanTree(node->GetRight());
870 // cout<<node->GetSymbol()<<" "<<(Int_t)node->GetFrequency()<<endl;
874 //////////////////////////////////////////////////////////////////////////////////////////////////
875 void AliTPCCompression::VisitHuffmanTree(AliTPCHNode* node){
876 //This function realizes an in order visit of a binary tree
878 cout<<node->GetSymbol()<<" "<<node->GetFrequency()<<endl;
879 VisitHuffmanTree(node->GetLeft());
880 VisitHuffmanTree(node->GetRight());
883 //////////////////////////////////////////////////////////////////////////////////////////////////
884 UInt_t AliTPCCompression::ReadWord(Int_t NumberOfBit){
885 //This method retrieves a word of a specific number of bits from the file through the internal buffer
888 for (Int_t i=0;i<NumberOfBit;i++){
890 fPos-=sizeof(UInt_t);
892 f.read((char*)(&fBuffer),sizeof(UInt_t));
896 mask=(UInt_t)TMath::Power(2,fReadBits);
905 //////////////////////////////////////////////////////////////////////////////////////////////////
906 UInt_t AliTPCCompression::ReadWordBuffer(Int_t NumberOfBit){
907 //This method retrieves a word of a specific number of bits from the file through the buffer
910 for (Int_t i=0;i<NumberOfBit;i++){
914 for(Int_t i=0;i<4;i++){
925 mask=(UInt_t)TMath::Power(2,fReadBits);
935 //////////////////////////////////////////////////////////////////////////////////////////////////
936 void AliTPCCompression::ReadTrailer(Int_t &WordsNumber,Int_t &PadNumber,Int_t &RowNumber,Int_t &SecNumber,Bool_t Memory){
937 //It retrieves a trailer
940 SecNumber=ReadWordBuffer(9);
941 RowNumber=ReadWordBuffer(10);
942 PadNumber=ReadWordBuffer(10);
943 WordsNumber=ReadWordBuffer(10);
947 SecNumber=ReadWord(9);
948 RowNumber=ReadWord(10);
949 PadNumber=ReadWord(10);
950 WordsNumber=ReadWord(10);
954 //////////////////////////////////////////////////////////////////////////////////////////////////
955 UInt_t AliTPCCompression::GetDecodedWord(AliTPCHNode* root,Bool_t Memory){
956 //This method retrieves a decoded word.
957 AliTPCHNode *node=root;
963 bit=ReadWordBuffer(1);
967 node=node->GetRight();
969 node=node->GetLeft();
970 if (!(node->GetLeft())){
971 symbol=node->GetSymbol();
977 //////////////////////////////////////////////////////////////////////////////////////////////////
979 Int_t AliTPCCompression::DecompressDataOptTables(Int_t NumTables,const char* fname, const char* fDest){
980 //This method decompress a file using separate Huffman tables
982 cout<<" DECOMPRESSION:"<<endl;
983 cout<<"Source File "<<fname<<" Destination File "<<fDest<<endl;
985 AliTPCHNode ** rootNode = new AliTPCHNode*[NumTables];
986 for(Int_t i=0;i<NumTables;i++) rootNode[i] = NULL;
987 //Creation of the Huffman trees
988 if (CreateTreesFromFile(rootNode,NumTables) != 0) {
989 for(Int_t i=0;i<NumTables;i++) {
990 if (rootNode[i]) DeleteHuffmanTree(rootNode[i]);
997 f.open(fname,ios::binary|ios::in);
999 f.open(fname,ios::in);
1002 Error("DecompressDataOptTables", "File doesn't exist:",fname);
1005 //to go to the end of the file
1006 f.seekg(0,ios::end);
1007 //to get the file dimension in byte
1009 fPos-=sizeof(UInt_t);
1013 f.read((char*)(&fBuffer),sizeof(UInt_t));
1021 UInt_t packetNumber=ReadWord(sizeof(UInt_t)*8);
1023 cout<<"Number of Packect: "<<packetNumber<<endl;
1025 AliAltroBuffer bufferFile(fDest,1);
1027 UInt_t wordsRead=0; //number of read coded words
1028 while(k<packetNumber){
1029 Int_t numWords,padNumber,rowNumber,secNumber=0;
1030 ReadTrailer(numWords,padNumber,rowNumber,secNumber,kFALSE);
1033 Int_t previousTime=-1;
1035 Int_t nextTableType=0;
1038 for(Int_t i=0;i<numWords;i++){
1039 UInt_t symbol=GetDecodedWord(rootNode[nextTableType],kFALSE);
1041 //Time reconstruction
1042 if (nextTableType==1){
1043 if (previousTime!=-1){
1044 previousTime=symbol+previousTime+bunchLen;
1046 else previousTime=symbol;
1050 bufferFile.FillBuffer(symbol);
1051 NextTable(symbol,nextTableType,bunchLen,count);
1052 if(nextTableType==0){
1053 bufferFile.FillBuffer(time);
1054 bufferFile.FillBuffer(bunchLen+2);
1058 bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber);
1061 cout<<"Number of decoded words:"<<wordsRead<<endl;
1064 //The trees are deleted
1065 for(Int_t j=0;j<NumTables;j++){
1066 DeleteHuffmanTree(rootNode[j]);
1072 //////////////////////////////////////////////////////////////////////////////////////////////////
1073 Int_t AliTPCCompression::Decompress(AliTPCHNode *RootNode[],Int_t /*NumTables*/,char* PointBuffer,UInt_t BufferSize,UShort_t out[],UInt_t &dim){
1074 //This method decompress a file using separate Huffman tables
1076 fPointBuffer=PointBuffer+BufferSize-4;
1080 for(Int_t i=0;i<4;i++){
1086 fBuffer=fBuffer|val;
1095 UInt_t packetNumber=ReadWordBuffer(sizeof(UInt_t)*8); //32 bits
1097 cout<<"First one has been found "<<endl;
1098 cout<<"Number of packets:"<<packetNumber<<endl;
1101 UInt_t wordsRead=0; //number of read coded words
1102 while(k<packetNumber){
1103 Int_t numWords,padNumber,rowNumber,secNumber=0;
1104 ReadTrailer(numWords,padNumber,rowNumber,secNumber,kTRUE);
1113 //ftxt<<"S:"<<secNumber<<" R:"<<rowNumber<<" P:"<<padNumber<<" W:"<<numWords<<endl;
1114 // padDigits->SetPadID(padNumber,rowNumber,secNumber,DDL);
1117 Int_t previousTime=-1;
1119 Int_t nextTableType=0;
1123 for(Int_t i=0;i<numWords;i++){
1124 UInt_t symbol=GetDecodedWord(RootNode[nextTableType],kTRUE);
1126 //Time reconstruction
1127 if (nextTableType==1){
1128 if (previousTime!=-1){
1129 previousTime=symbol+previousTime+bunchLen;
1131 else previousTime=symbol;
1133 out[dim]=bunchLen+2;
1137 timeDigit=time-bunchLen;
1139 if(nextTableType>1){
1141 //ftxt<<symbol<<endl;
1145 //padDigits->SetDigits(symbol,timeDigit);
1147 NextTable(symbol,nextTableType,bunchLen,count);
1148 if(nextTableType==0){
1151 // ftxt<<(bunchLen+2)<<endl;
1159 //////////////////////////////////////////////////////////////////////////////////////////////////
1160 Int_t AliTPCCompression::DestroyTables(AliTPCHNode *RootNode[],Int_t NumTables){
1161 //The trees are deleted
1162 for(Int_t j=0;j<NumTables;j++){
1163 DeleteHuffmanTree(RootNode[j]);
1166 cout<<"Huffman trees destroyed"<<endl;
1169 //////////////////////////////////////////////////////////////////////////////////////////////////
1171 void AliTPCCompression::ReadAltroFormat(char* fileOut,char* fileIn)const{
1172 //This method creates a text file containing the same information stored in
1173 //an Altro file. The information in the text file is organized pad by pad and
1174 //and for each pad it consists in a sequence of bunches (Bunch length +2,
1175 //Time bin of the last amplitude sample in the bunch, amplitude values)
1176 //It is used mainly for debugging
1177 ofstream ftxt(fileOut);
1178 AliAltroBuffer buff(fileIn,0);
1179 Int_t numWords,padNum,rowNum,secNum=0;
1181 if (fVerbose) cout<<"Creating a txt file from an Altro Format file"<<endl;
1182 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum)){
1183 ftxt<<"S:"<<secNum<<" R:"<<rowNum<<" P:"<<padNum<<" W:"<<numWords<<endl;
1185 for(Int_t j=0;j<(4-numWords%4);j++){
1186 value=buff.GetNextBackWord();
1189 for(Int_t i=0;i<numWords;i++){
1190 value=buff.GetNextBackWord();
1198 //////////////////////////////////////////////////////////////////////////////////////////