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"
29 #include "AliTPCCompression.h"
30 #include "AliTPCBuffer160.h"
31 #include "AliTPCHuffman.h"
33 ClassImp(AliTPCCompression)
34 //////////////////////////////////////////////////////////////////////////////////////////////////
35 AliTPCCompression::AliTPCCompression(){
37 fDimBuffer=sizeof(ULong_t)*8;
38 fFreeBitsBuffer=fDimBuffer;
46 //////////////////////////////////////////////////////////////////////////////////////////////////
47 AliTPCCompression::AliTPCCompression(const AliTPCCompression &source){
49 this->fDimBuffer=source.fDimBuffer;
50 this->fFreeBitsBuffer=source.fFreeBitsBuffer;
51 this->fReadBits=source.fReadBits;
52 this->fPos=source.fPos;
53 this->fBuffer=source.fBuffer;
54 this->fVerbose=source.fVerbose;
55 this->fFillWords=source.fFillWords;
58 //////////////////////////////////////////////////////////////////////////////////////////////////
59 AliTPCCompression& AliTPCCompression::operator=(const AliTPCCompression &source){
60 //Redefinition of the assignment operator
61 this->fDimBuffer=source.fDimBuffer;
62 this->fFreeBitsBuffer=source.fFreeBitsBuffer;
63 this->fReadBits=source.fReadBits;
64 this->fPos=source.fPos;
65 this->fBuffer=source.fBuffer;
66 this->fVerbose=source.fVerbose;
67 this->fFillWords=source.fFillWords;
70 //////////////////////////////////////////////////////////////////////////////////////////////////
71 void AliTPCCompression::NextTable(Int_t Val,Int_t &NextTableType,Int_t &BunchLen,Int_t &Count)const{
72 //Depending on the data type (5 types of data) a specific table is called
75 0==> Bunch length value
81 switch (NextTableType){
88 if (BunchLen==1)NextTableType=2;
101 if (Count==(BunchLen-1)){
121 /////////////////////////////////////////////////////////////////////////////////////////////////////
123 /////////////////////////////////////////////////////////////////////////////////////////////////////
125 Int_t AliTPCCompression::FillTables(const char* fSource,AliTPCHTable* table[],const Int_t NumTables){
126 //This method is used to compute the frequencies of the symbols in the source file
127 AliTPCBuffer160 buff(fSource,0);
128 ULong_t countWords=0;
129 ULong_t countTrailer=0;
130 Int_t numWords,padNum,rowNum,secNum=0;
132 ULong_t stat[5]={0,0,0,0,0};
135 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
137 endFill=buff.GetFillWordsNum();
142 fFillWords+=4-numWords%4;
143 for(Int_t j=0;j<(4-numWords%4);j++){
144 value=buff.GetNextBackWord();
151 for(Int_t i=0;i<345;i++)timePos[i]=0;
152 for(Int_t i=0;i<1024;i++)packet[i]=0;
154 Int_t nextTableType=0;
157 for(Int_t i=0;i<numWords;i++){
158 value=buff.GetNextBackWord();
160 if(nextTableType==1){
164 NextTable(value,nextTableType,bunchLen,count);
166 //computing the Time gap between two bunches
169 Int_t previousTime=packet[timePos[tp]];
170 for(Int_t i=tp-1;i>=0;i--){
171 Int_t timPos=timePos[i];
172 Int_t bunchLen=packet[timPos-1]-2;
174 packet[timPos]=packet[timPos]-previousTime-bunchLen;
180 for(Int_t i=0;i<numWords;i++){
182 table[nextTableType]->SetFrequency(value);
183 stat[nextTableType]++;
184 NextTable(value,nextTableType,bunchLen,count);
188 cout<<"Number of words: "<<countWords<<endl;
189 cout<<"Number of trailers: "<<countTrailer<<endl;
190 cout<<"Number of fill words "<<fFillWords+endFill<<endl;
191 cout<<"Total number of words: "<<countWords+countTrailer*4+fFillWords<<endl;
193 fStat.open("Statistics");
194 fStat<<"Number of words:..........................................."<<countWords<<endl;
195 fStat<<"Number of trailers (4 10 bits words in each one)..........."<<countTrailer<<endl;
196 fStat<<"Number of fill words:......................................"<<fFillWords+endFill<<endl;
197 fStat<<"Total number of words:....................................."<<countWords+countTrailer*4+fFillWords+endFill<<endl;
198 fStat<<"-----------------------------------------"<<endl;
199 fStat<<"Number of Bunches............."<<stat[0]<<endl;
200 fStat<<"Number of Time bin............"<<stat[1]<<endl;
201 fStat<<"Number of One Samples Bunch..."<<stat[2]<<endl;
202 fStat<<"Number of Central Samples....."<<stat[3]<<endl;
203 fStat<<"Number of Border Samples......"<<stat[4]<<endl;
204 fStat<<"-----------------------------------------"<<endl;
205 ULong_t fileDimension=(ULong_t)TMath::Ceil(double((countTrailer*4+countWords+fFillWords+endFill)*10/8));
206 fStat<<"Total file Size in bytes.."<<fileDimension<<endl;
207 Double_t percentage=TMath::Ceil((fFillWords+endFill)*125)/fileDimension;
208 fStat<<"Fill Words................"<<(ULong_t)TMath::Ceil((fFillWords+endFill)*10/8)<<" bytes "<<percentage<<"%"<<endl;
209 percentage=(Double_t)countTrailer*500/fileDimension;
210 fStat<<"Trailer..................."<<countTrailer*5<<" bytes "<<percentage<<"%"<<endl;
212 percentage=(Double_t)((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])) *125/fileDimension;
213 fStat<<"Data......................"<<(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])*10/8)<<" bytes "<<percentage<<"%"<<endl;
215 percentage=(Double_t)(stat[0]*125)/fileDimension;
216 fStat<<"Bunch....................."<<(ULong_t)TMath::Ceil(stat[0]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
217 percentage=(Double_t)(stat[1]*125)/fileDimension;
218 fStat<<"Time......................"<<(ULong_t)TMath::Ceil(stat[1]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
221 percentage=(Double_t)((stat[2]+stat[3]+stat[4])) *125/fileDimension;
222 fStat<<"Amplitude values.........."<<(ULong_t)TMath::Ceil((stat[2]+stat[3]+stat[4])*10/8)<<" bytes "<<percentage<<"%"<<endl;
223 percentage=(Double_t)(stat[2]*125)/fileDimension;
224 fStat<<" One Samples..............."<<(ULong_t)TMath::Ceil(stat[2]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
225 percentage=(Double_t)(stat[3]*125)/fileDimension;
226 fStat<<" Central Samples..........."<<(ULong_t)TMath::Ceil(stat[3]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
227 percentage=(Double_t)(stat[4]*125)/fileDimension;
228 fStat<<" Border Samples............"<<(ULong_t)TMath::Ceil(stat[4]*10/8)<<" bytes "<<percentage<<"%"<<endl; //
232 ////////////////////////////////////////////////////////////////////////////////////////
233 Int_t AliTPCCompression::StoreTables(AliTPCHTable* table[],const Int_t NumTable){
234 //This method stores the tables in a sequence of binary file
237 for(Int_t k=0;k<NumTable;k++){
238 sprintf(filename,"Table%d.dat",k);
240 fTable.open(filename,ios::binary);
242 fTable.open(filename);
244 Int_t dim=table[k]->Size();
245 //Table dimension is written into a file
246 fTable.write((char*)(&dim),sizeof(Int_t));
247 //One table is written into a file
248 for(Int_t i=0;i<dim;i++){
249 UChar_t codeLen=table[k]->CodeLen()[i];
250 // ULong_t code=(ULong_t)table[k]->Code()[i];
251 Double_t code=table[k]->Code()[i];
252 fTable.write((char*)(&codeLen),sizeof(UChar_t));
253 //fTable.write((char*)(&code),sizeof(ULong_t));
254 fTable.write((char*)(&code),sizeof(Double_t));
260 ////////////////////////////////////////////////////////////////////////////////////////
261 Int_t AliTPCCompression::CreateTableFormula(Double_t beta,ULong_t M,Int_t dim,Int_t Type){
262 // Type = 0 for Bunch length
263 // Type = 1 for Time Gap
269 AliTPCHTable *Table=new AliTPCHTable(dim);
272 Double_t FreqArray[1024];
273 for(Int_t i=0;i<1024;i++){
276 alpha=M*0.000000602+0.0104;
278 cout<<"alpha "<<alpha<<endl;
279 for(Int_t x=0;x<dim;x++){
281 FreqArray[x]=TMath::Power((x+1),-beta)*TMath::Exp(-alpha*(x+1));
283 FreqArray[x]=TMath::Power((x+1),-beta);
285 if (FreqArray[x]<min)min=FreqArray[x];
288 cout<<"Minimun Value "<<min<<endl;
291 cout<<"A Value: "<<A<<endl;
292 for(Int_t x=0;x<dim;x++){
293 if (Type==0)//Bunch length
294 if (x>=3)//minimum bunch length
295 Table->SetValFrequency(x,A*FreqArray[x]*1000);
297 Table->SetValFrequency(x,0);
299 Table->SetValFrequency(x,A*FreqArray[x]);
301 Table->BuildHTable();
304 sprintf(filename,"Table%d.dat",Type);
305 fTable.open(filename,ios::binary);
306 Int_t dimTable=Table->Size();
307 //Table dimension is written into a file
308 fTable.write((char*)(&dimTable),sizeof(Int_t));
309 //One table is written into a file
310 for(Int_t i=0;i<dimTable;i++){
311 UChar_t CodeLen=Table->CodeLen()[i];
312 Double_t Code=Table->Code()[i];
313 fTable.write((char*)(&CodeLen),sizeof(UChar_t));
314 fTable.write((char*)(&Code),sizeof(Double_t));
320 ////////////////////////////////////////////////////////////////////////////////////////
321 Int_t AliTPCCompression::CreateTables(const char* fSource,const Int_t NumTables){
325 0==> Bunch length values
331 Int_t n=10;// 10 bits per symbol
332 AliTPCHTable ** table = new AliTPCHTable*[NumTables];
333 //The table is inizialized with the rigth number of rows
334 for(Int_t i=0;i<NumTables;i++){
335 table[i]=new AliTPCHTable((Int_t)(TMath::Power(2,n)));
336 table[i]->SetVerbose(fVerbose);
338 //The frequencies are calculated and the tables are filled
340 cout<<"Filling tables...\n";
341 //The get the frequencies
342 FillTables(fSource,table,NumTables);
344 //This part will be used in the table optimization phase
346 for(Int_t i=0;i<NumTables;i++){
347 table[i]->CompleteTable(i);
351 cout<<"Entropy of Bunch length table........."<<table[0]->GetEntropy()<<endl;
352 cout<<"Entropy of Time bin table............."<<table[1]->GetEntropy()<<endl;
353 cout<<"Entropy of one Sample bunch table....."<<table[2]->GetEntropy()<<endl;
354 cout<<"Entropy of Central Sample table......."<<table[3]->GetEntropy()<<endl;
355 cout<<"Entropy Border Samples table.........."<<table[4]->GetEntropy()<<endl;
357 fStat.open("Statistics",ios::app);
359 fStat<<"----------------- ENTROPY for castomized tables --------------------------"<<endl;
360 fStat<<"Entropy of Bunch length table......."<<table[0]->GetEntropy()<<endl;
361 fStat<<"Entropy of Time bin table..........."<<table[1]->GetEntropy()<<endl;
362 fStat<<"Entropy of one Sample bunch table..."<<table[2]->GetEntropy()<<endl;
363 fStat<<"Entropy of Central Sample table....."<<table[3]->GetEntropy()<<endl;
364 fStat<<"Entropy Border Samples table........"<<table[4]->GetEntropy()<<endl;
368 cout<<"Tables filled \n";
370 //Frequencies normalization
371 table[0]->NormalizeFrequencies();
372 table[1]->NormalizeFrequencies();
373 table[2]->NormalizeFrequencies();
374 table[3]->NormalizeFrequencies();
375 table[4]->NormalizeFrequencies();
377 //Tables are saved in a sequence of text file and using the macro Histo.C is it possible to get
378 //a series of histograms rappresenting the frequency distribution
379 table[0]->StoreFrequencies("BunchLenFreq.txt");
380 table[1]->StoreFrequencies("TimeFreq.txt");
381 table[2]->StoreFrequencies("Sample1Freq.txt");
382 table[3]->StoreFrequencies("SCentralFreq.txt");
383 table[4]->StoreFrequencies("SBorderFreq.txt");
385 cout<<"Creating Tables..\n";
386 //One Huffman tree is created for each table starting from the frequencies of the symbols
387 for(Int_t i=0;i<NumTables;i++){
388 table[i]->BuildHTable();
390 cout<<"Number of elements inside the table:"<<table[i]->GetWordsNumber();
393 cout<<" (Bunch Length)"<<endl;
397 cout<<" (Time Bin)"<<endl;
401 cout<<" (1 Samples Bunch)"<<endl;
405 cout<<" (Central Samples)"<<endl;
409 cout<<" (Border Samples)"<<endl;
413 table[i]->PrintTable();
416 //The tables are saved ad binary files
417 StoreTables(table,NumTables);
418 //The tables stored in memory are deleted;
419 for(Int_t i=0;i<NumTables;i++)delete table[i];
423 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
424 Int_t AliTPCCompression::RetrieveTables(AliTPCHTable* table[],Int_t NumTable){
425 //This method retrieve the Huffman tables from a sequence of binary files
427 cout<<"Retrieving tables from files \n";
433 //The following for loop is used to generate the Huffman trees acording to the tables
434 for(Int_t k=0;k<NumTable;k++){
435 Int_t dim;//this variable contains the table dimension
436 sprintf(filename,"Table%d.dat",k);
438 fTable.open(filename,ios::binary);
440 fTable.open(filename);
442 if(!fTable){cout<<"File doesn't exist:"<<filename<<endl; exit(1);}
443 fTable.read((char*)(&dim),sizeof(Int_t));
445 cout<<"Table dimension: "<<dim<<endl;
446 table[k]=new AliTPCHTable(dim);
447 for(Int_t i=0;i<dim;i++){
448 fTable.read((char*)(&codeLen),sizeof(UChar_t));
449 table[k]->SetCodeLen(codeLen,i);
450 // fTable.read((char*)(&code),sizeof(ULong_t));
451 fTable.read((char*)(&code),sizeof(Double_t));
452 table[k]->SetCode(Mirror((ULong_t)code,codeLen),i);
457 cout<<"Trees generated \n";
458 //At this point the trees are been built
462 Int_t AliTPCCompression::CreateTablesFromTxtFiles(Int_t NumTable){
463 //This method creates a set of binary tables, needed by the Huffman
464 //algorith, starting from a set of frequencies tables stored in form of
467 cout<<"Retrieving frequencies from txt files \n";
470 //Tables are read from the files (Each codeword has been "Mirrored")
471 AliTPCHTable **table = new AliTPCHTable*[NumTable];
472 for(Int_t k=0;k<NumTable;k++){
473 sprintf(filename,"Table%d.txt",k);
474 cout<<filename<<endl;
475 fTable.open(filename);
476 if(!fTable){cout<<"File doesn't exist: "<<filename<<endl; exit(1);}
479 table[k]=new AliTPCHTable(1024);
480 while(!fTable.eof()){
484 cout<<"Frequency cannot be negative !!!\n";
487 table[k]->SetValFrequency(symbol,freq);
494 fStat.open("Statistics",ios::app);
496 fStat<<"----------------- ENTROPY for external txt tables --------------------------"<<endl;
497 fStat<<"Entropy of Bunch length table......."<<table[0]->GetEntropy()<<endl;
498 fStat<<"Entropy of Time bin table..........."<<table[1]->GetEntropy()<<endl;
499 fStat<<"Entropy of one Sample bunch table..."<<table[2]->GetEntropy()<<endl;
500 fStat<<"Entropy of Central Sample table....."<<table[3]->GetEntropy()<<endl;
501 fStat<<"Entropy Border Samples table........"<<table[4]->GetEntropy()<<endl;
503 for(Int_t k=0;k<NumTable;k++){
504 table[k]->BuildHTable();
506 //The tables are saved ad binary files
507 StoreTables(table,NumTable);
508 //The tables stored in memory are deleted;
509 for(Int_t i=0;i<NumTable;i++)delete table[i];
514 ////////////////////////////////////////////////////////////////////////////////////////
516 ////////////////////////////////////////////////////////////////////////////////////////
518 void AliTPCCompression::StoreValue(ULong_t val,UChar_t len){
519 //This method stores the value "val" of "len" bits into the internal buffer "fBuffer"
520 if (len<=fFreeBitsBuffer){ // val is not splitted in two buffer
521 fFreeBitsBuffer-=len;
522 fBuffer=fBuffer<<len;
524 if(!fFreeBitsBuffer){ // if the buffer is full it is written into a file
525 f.write((char*)(&fBuffer),sizeof(ULong_t));
526 fFreeBitsBuffer=fDimBuffer;
530 else{ //val has to be splitted in two buffers
531 fBuffer=fBuffer<<fFreeBitsBuffer;
534 temp=temp>>(len-fFreeBitsBuffer);
535 fBuffer=fBuffer|temp;
536 f.write((char*)(&fBuffer),sizeof(ULong_t));
537 fFreeBitsBuffer=fDimBuffer-(len-fFreeBitsBuffer);
538 val=val<<fFreeBitsBuffer;
539 val=val>>fFreeBitsBuffer;
544 //////////////////////////////////////////////////////////////////////////////////////////////////
545 void AliTPCCompression::Flush(){
546 //The last buffer cannot be completely full so to save it
547 //into the output file it is first necessary to fill it with an hexadecimal pattern
548 if(fFreeBitsBuffer<fDimBuffer){
549 fBuffer=fBuffer<<fFreeBitsBuffer;
550 f.write((char*)(&fBuffer),sizeof(ULong_t));
554 //////////////////////////////////////////////////////////////////////////////////////////////////
555 ULong_t AliTPCCompression::Mirror(ULong_t val,UChar_t len)const{
556 //This method inverts the digits of the number "val" and length "len"
557 //indicates the number of digits of the number considered in binary notation
561 for(Int_t i=0;i<len;i++){
564 specular=specular<<1;
565 specular=specular|bit;
570 //////////////////////////////////////////////////////////////////////////////////////////////////
571 Int_t AliTPCCompression::CompressData(AliTPCHTable* table[],Int_t NumTable,const char* fSource,const char* fDest){
572 //This method is used to compress the data stored in the Altro format file using specific tables
573 //calculated considering the frequencies of the symbol of the file that has to be compressed
574 cout<<" COMPRESSION "<<endl;
575 cout<<"compression of the file "<<fSource<<" Output File: "<<fDest<<endl;
576 //the output file is open
578 f.open(fDest,ios::binary|ios::out);
580 f.open(fDest,ios::out);
582 //Tables are written into the output file
583 for(Int_t k=0;k<NumTable;k++){
584 Int_t dim=table[k]->Size();
585 //Table dimension is written into a file
586 f.write((char*)(&dim),sizeof(Int_t));
587 //One table is written into a file
588 for(Int_t i=0;i<dim;i++){
589 UChar_t codeLen=table[k]->CodeLen()[i];
590 ULong_t code=(ULong_t)table[k]->Code()[i];
591 f.write((char*)(&codeLen),sizeof(UChar_t));
592 f.write((char*)(&code),sizeof(ULong_t));
596 // Source file is open
597 AliTPCBuffer160 buff(fSource,0);
598 //coded words are written into the output file
599 Int_t numWords,padNum,rowNum,secNum=0;
600 ULong_t storedWords=0;
602 ULong_t numPackets=0;
603 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
606 for(Int_t j=0;j<(4-numWords%4);j++){
607 value=buff.GetNextBackWord();
614 for(Int_t i=0;i<345;i++)timePos[i]=0;
615 for(Int_t i=0;i<1024;i++)packet[i]=0;
617 Int_t nextTableType=0;
620 for(Int_t i=0;i<numWords;i++){
621 value=buff.GetNextBackWord();
623 if(nextTableType==1){
627 NextTable(value,nextTableType,bunchLen,count);
629 //computing the Time gap between two bunches
632 Int_t previousTime=packet[timePos[tp]];
633 for(Int_t i=tp-1;i>=0;i--){
634 Int_t timPos=timePos[i];
635 Int_t bunchLen=packet[timPos-1]-2;
637 packet[timPos]=packet[timPos]-previousTime-bunchLen;
644 //All the words for one pad are compressed and stored in the compress file
645 for(Int_t i=0;i<numWords;i++){
647 if(nextTableType==1)timeBin=value;
649 // ULong_t val=(ULong_t)table[nextTableType]->Code()[value]; // val is the code
650 Double_t val=table[nextTableType]->Code()[value]; // val is the code
651 UChar_t len=table[nextTableType]->CodeLen()[value]; // len is the length (number of bits)of val
652 StoreValue(Mirror((ULong_t)val,len),len);
655 NextTable(value,nextTableType,bunchLen,count);
656 if(nextTableType==0){
657 // ULong_t val=(ULong_t)table[1]->Code()[timeBin]; // val is the code
658 Double_t val=table[1]->Code()[timeBin]; // val is the code
659 UChar_t len=table[1]->CodeLen()[timeBin]; // len is the length (number of bits)of val
660 StoreValue(Mirror((ULong_t)val,len),len);
661 //val=(ULong_t)table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
662 val=table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
663 len=table[nextTableType]->CodeLen()[(bunchLen+2)]; // len is the length (number of bits)of val
664 StoreValue(Mirror((ULong_t)val,len),len);
669 StoreValue(numWords,10);
670 StoreValue(padNum,10);
671 StoreValue(rowNum,10);
672 StoreValue(secNum,9);
676 StoreValue(numPackets,32);
677 cout<<"Number of strored packet: "<<numPackets<<endl;
679 //The last buffen cannot be completely full
681 cout<<"Number of stored words: "<<storedWords<<endl;
686 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
687 Int_t AliTPCCompression::CompressDataOptTables(Int_t NumTable,const char* fSource,const char* fDest){
688 //This method compress an Altro format file using a general set of tables stored as binary files to be provided
690 cout<<" BackWord COMPRESSION "<<endl;
691 cout<<"compression of the file "<<fSource<<" Output File: "<<fDest<<endl;
693 //Tables are read from the files (Each codeword has been "Mirrored")
694 AliTPCHTable **table = new AliTPCHTable*[NumTable];
695 RetrieveTables(table,NumTable);
696 //the output file is open
698 f.open(fDest,ios::binary|ios::out);
700 f.open(fDest,ios::out);
702 // Source file is open
703 AliTPCBuffer160 buff(fSource,0);
704 //coded words are written into a file
705 Int_t numWords,padNum,rowNum,secNum=0;
706 ULong_t storedWords=0;
708 ULong_t numPackets=0;
709 Double_t stat[5]={0.,0.,0.,0.,0.};
710 ULong_t trailerNumbers=0;
711 Double_t numElem[5]={0,0,0,0,0};
712 Double_t fillWords=0.;
713 fStat.open("Statistics",ios::app);
715 fStat<<"-------------------COMPRESSION STATISTICS----------"<<endl;
717 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
719 fillWords=buff.GetFillWordsNum();
725 fillWords+=4-numWords%4;
726 for(Int_t j=0;j<(4-numWords%4);j++){
727 value=buff.GetNextBackWord();
734 for(Int_t i=0;i<345;i++)timePos[i]=0;
735 for(Int_t i=0;i<1024;i++)packet[i]=0;
737 Int_t nextTableType=0;
740 for(Int_t i=0;i<numWords;i++){
741 value=buff.GetNextBackWord();
743 if(nextTableType==1){
747 NextTable(value,nextTableType,bunchLen,count);
749 //computing the Time gap between two bunches
752 Int_t previousTime=packet[timePos[tp]];
753 for(Int_t i=tp-1;i>=0;i--){
754 Int_t timPos=timePos[i];
755 Int_t bunchLen=packet[timPos-1]-2;
757 packet[timPos]=packet[timPos]-previousTime-bunchLen;
765 for(Int_t i=0;i<numWords;i++){
767 if(nextTableType==1)timeBin=value;
769 //ULong_t val=(ULong_t)table[nextTableType]->Code()[value]; // val is the code
770 Double_t val=table[nextTableType]->Code()[value]; // val is the code
771 UChar_t len=table[nextTableType]->CodeLen()[value]; // len is the length (number of bits)of val
772 stat[nextTableType]+=len;
773 numElem[nextTableType]++;
774 StoreValue((ULong_t)val,len);
777 NextTable(value,nextTableType,bunchLen,count);
778 if(nextTableType==0){
779 // ULong_t val=(ULong_t)table[1]->Code()[timeBin]; // val is the code
780 Double_t val=table[1]->Code()[timeBin]; // val is the code
781 UChar_t len=table[1]->CodeLen()[timeBin]; // len is the length (number of bits)of val
784 StoreValue((ULong_t)val,len);
785 // val=(ULong_t)table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
786 val=table[nextTableType]->Code()[(bunchLen+2)]; // val is the code
787 len=table[nextTableType]->CodeLen()[(bunchLen+2)]; // len is the length (number of bits)of val
788 StoreValue((ULong_t)val,len);
789 stat[nextTableType]+=len;
790 numElem[nextTableType]++;
795 StoreValue(numWords,10);
796 StoreValue(padNum,10);
797 StoreValue(rowNum,10);
798 StoreValue(secNum,9);
803 StoreValue(numPackets,32);
805 cout<<"Number of strored packets: "<<numPackets<<endl;
807 //The last buffen cannot be completely full
810 cout<<"Number of stored words: "<<storedWords<<endl;
813 for(Int_t i=0;i<NumTable;i++){
817 Double_t dimension=(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)+trailerNumbers*5;
818 fStat<<"Trailer Dimension in bytes......"<<trailerNumbers*5<<endl;
819 fStat<<"Data Dimension in bytes........."<<(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)<<endl;
820 fStat<<"Compressed file dimension......."<<(ULong_t)dimension<<endl;
822 fStat<<(ULong_t)trailerNumbers<<endl;
823 fStat<<(ULong_t)fillWords<<endl;
824 fStat<<(ULong_t)numElem[0]<<endl;
825 fStat<<(ULong_t)numElem[1]<<endl;
826 fStat<<(ULong_t)numElem[2]<<endl;
827 fStat<<(ULong_t)numElem[3]<<endl;
828 fStat<<(ULong_t)numElem[4]<<endl;
830 fillWords=(fillWords+numElem[0]+numElem[1]+numElem[2]+numElem[3]+numElem[4]+trailerNumbers*4)*10/8;
831 fStat<<"Original file dimension........."<<(ULong_t)fillWords<<endl;
833 Double_t ratio=(dimension/fillWords)*100;
834 fStat<<"Compression ratio (Compressed/Uncompressed)..."<<ratio<<"%"<<endl;
837 fStat<<"Bunch length size in bytes......"<<(ULong_t)TMath::Ceil(stat[0]/8)<<" Comppression.."<<(stat[0]/numElem[0])*10<<"%"<<endl;
839 fStat<<"Time gap size in bytes.........."<<(ULong_t)TMath::Ceil(stat[1]/8)<<" Comppression.."<<(stat[1]/numElem[1])*10<<"%"<<endl;
840 if (numElem[2]+numElem[3]+numElem[4])
841 fStat<<"Amplitude values in bytes......."<<(ULong_t)TMath::Ceil((stat[2]+stat[3]+stat[4])/8)<<" Comppression.."<<
842 ((stat[2]+stat[3]+stat[4])/(numElem[2]+numElem[3]+numElem[4]))*10<<"%"<<endl;
844 fStat<<" One Samples in bytes............"<<(ULong_t)TMath::Ceil(stat[2]/8)<<" Comppression.."<<(stat[2]/numElem[2])*10<<"%"<<endl;
846 fStat<<" Central Samples size in bytes..."<<(ULong_t)TMath::Ceil(stat[3]/8)<<" Comppression.."<<(stat[3]/numElem[3])*10<<"%"<<endl;
848 fStat<<" Border Samples size in bytes...."<<(ULong_t)TMath::Ceil(stat[4]/8)<<" Comppression.."<<(stat[4]/numElem[4])*10<<"%"<<endl;
850 fStat<<"Average number of bits per word"<<endl;
852 fStat<<"Bunch length ......"<<stat[0]/numElem[0]<<endl;
854 fStat<<"Time gap .........."<<stat[1]/numElem[1]<<endl;
856 fStat<<"One Samples........"<<stat[2]/numElem[2]<<endl;
858 fStat<<"Central Samples ..."<<stat[3]/numElem[3]<<endl;
860 fStat<<"Border Samples....."<<stat[4]/numElem[4]<<endl;
865 ////////////////////////////////////////////////////////////////////////////////////////
867 ////////////////////////////////////////////////////////////////////////////////////////
869 ////////////////////////////////////////////////////////////////////////////////////////
870 void AliTPCCompression::CreateTrees(AliTPCHNode *RootNode[],const Int_t NumTables){
871 //The first part of the compressed file cotains the tables
872 //The following for loop is used to generate the Huffman trees acording to the tables
874 cout<<"Creating the Huffman trees \n";
879 //loop over the numbero of tables
880 for(Int_t k=0;k<NumTables;k++){
881 RootNode[k]=new AliTPCHNode(); //RootNode is the root of the tree
882 Int_t dim;//this variable contains the table dimension
883 f.read((char*)(&dim),sizeof(Int_t));
885 cout<<"Table dimension: "<<dim<<endl;
886 //loop over the words of a table
887 for(Int_t i=0;i<dim;i++){
888 f.read((char*)(&codeLen),sizeof(UChar_t));
889 //f.read((char*)(&code),sizeof(ULong_t));
890 f.read((char*)(&code),sizeof(Double_t));
892 for(Int_t j=1;j<=codeLen;j++){
894 val=(ULong_t)TMath::Power(2,codeLen-j);
895 bit=(ULong_t)code&val;
896 AliTPCHNode *temp=node;
898 node=node->GetRight();
900 node=new AliTPCHNode();
901 temp->SetRight(node);
905 node=node->GetLeft();
907 node=new AliTPCHNode();
914 node->SetFrequency(codeLen);
916 //cout<<node->GetSymbol()<<" "<<(Int_t)node->GetFrequency()<<endl;
920 cout<<"Trees generated \n";
921 //At this point the trees are been built
923 //////////////////////////////////////////////////////////////////////////////////////////////////
924 void AliTPCCompression::CreateTreesFromFile(AliTPCHNode *RootNode[],const Int_t NumTables){
925 //For each table this method builds the associate Huffman tree starting from the codeword and
926 //the codelength of each symbol
928 cout<<"Creating the Huffman trees \n";
935 //The following for loop is used to generate the Huffman trees acording to the tables
936 //loop over the tables
937 for(Int_t k=0;k<NumTables;k++){
938 RootNode[k]=new AliTPCHNode(); //RootNode is the root of the tree
939 Int_t dim=0;//this variable contains the table dimension
940 sprintf(filename,"Table%d.dat",k);
942 fTable.open(filename,ios::binary);
944 fTable.open(filename);
946 fTable.read((char*)(&dim),sizeof(Int_t));
948 cout<<"Table dimension: "<<dim<<endl;
949 //loop over the words of one table
950 for(Int_t i=0;i<dim;i++){
951 fTable.read((char*)(&codeLen),sizeof(UChar_t));
952 //fTable.read((char*)(&code),sizeof(ULong_t));
953 fTable.read((char*)(&code),sizeof(Double_t));
955 for(Int_t j=1;j<=codeLen;j++){
957 val=(ULong_t)TMath::Power(2,codeLen-j);
958 bit=(ULong_t)code&val;
959 AliTPCHNode *temp=node;
961 node=node->GetRight();
963 node=new AliTPCHNode();
964 temp->SetRight(node);
968 node=node->GetLeft();
970 node=new AliTPCHNode();
977 node->SetFrequency(codeLen);
983 cout<<"Trees generated \n";
984 //At this point the trees are been built
986 //////////////////////////////////////////////////////////////////////////////////////////////////
987 void AliTPCCompression::DeleteHuffmanTree(AliTPCHNode* node){
988 //This function deletes all the nodes of an Huffman tree
989 //In an Huffman tree any internal node has always two children
991 DeleteHuffmanTree(node->GetLeft());
992 DeleteHuffmanTree(node->GetRight());
993 // cout<<node->GetSymbol()<<" "<<(Int_t)node->GetFrequency()<<endl;
997 //////////////////////////////////////////////////////////////////////////////////////////////////
998 void AliTPCCompression::VisitHuffmanTree(AliTPCHNode* node){
999 //This function realizes an in order visit of a binary tree
1001 cout<<node->GetSymbol()<<" "<<node->GetFrequency()<<endl;
1002 VisitHuffmanTree(node->GetLeft());
1003 VisitHuffmanTree(node->GetRight());
1006 //////////////////////////////////////////////////////////////////////////////////////////////////
1007 ULong_t AliTPCCompression::ReadWord(Int_t NumberOfBit){
1008 //This method retrieves a word of a specific number of bits from the file through the internal buffer
1011 for (Int_t i=0;i<NumberOfBit;i++){
1013 fPos-=sizeof(ULong_t);
1015 f.read((char*)(&fBuffer),sizeof(ULong_t));
1019 mask=(ULong_t)TMath::Power(2,fReadBits);
1028 //////////////////////////////////////////////////////////////////////////////////////////////////
1029 void AliTPCCompression::ReadTrailer(Int_t &WordsNumber,Int_t &PadNumber,Int_t &RowNumber,Int_t &SecNumber){
1030 //It retrieves a trailer
1032 SecNumber=ReadWord(9);
1033 RowNumber=ReadWord(10);
1034 PadNumber=ReadWord(10);
1035 WordsNumber=ReadWord(10);
1038 //////////////////////////////////////////////////////////////////////////////////////////////////
1039 ULong_t AliTPCCompression::GetDecodedWord(AliTPCHNode* root){
1040 //This method retrieves a decoded word.
1041 AliTPCHNode *node=root;
1045 ULong_t bit=ReadWord(1);
1047 node=node->GetRight();
1049 node=node->GetLeft();
1050 if (!(node->GetLeft())){
1051 symbol=node->GetSymbol();
1057 //////////////////////////////////////////////////////////////////////////////////////////////////
1058 Int_t AliTPCCompression::DecompressData(Int_t NumTables,const char* fname,char* fDest){
1059 //Decompression method
1060 cout<<" DECOMPRESSION:"<<endl;
1061 cout<<"Source File "<<fname<<" Destination File "<<fDest<<endl;
1063 f.open(fname,ios::binary|ios::in);
1065 f.open(fname,ios::in);
1067 if(!f){cout<<"File doesn't exist:"<<fname<<endl;;return -1;}
1068 AliTPCHNode ** rootNode = new AliTPCHNode*[NumTables];
1069 //Creation of the Huffman trees
1070 CreateTrees(rootNode,NumTables);
1071 //to go to the end of the file
1072 f.seekg(0,ios::end);
1073 //to get the file dimension in byte
1075 fPos-=sizeof(ULong_t);
1079 f.read((char*)(&fBuffer),sizeof(ULong_t));
1087 ULong_t packetNumber=ReadWord(sizeof(ULong_t)*8);
1088 cout<<"Number of Packect: "<<packetNumber<<endl;
1089 AliTPCBuffer160 bufferFile(fDest,1);
1091 ULong_t wordsRead=0; //number of read coded words
1092 while(k<packetNumber){
1093 Int_t numWords,padNumber,rowNumber,secNumber=0;
1094 ReadTrailer(numWords,padNumber,rowNumber,secNumber);
1097 Int_t previousTime=-1;
1099 Int_t nextTableType=0;
1102 for(Int_t i=0;i<numWords;i++){
1103 ULong_t symbol=GetDecodedWord(rootNode[nextTableType]);
1105 //Time reconstruction
1106 if (nextTableType==1){
1107 if (previousTime!=-1){
1108 previousTime=symbol+previousTime+bunchLen;
1110 else previousTime=symbol;
1114 bufferFile.FillBuffer(symbol);
1115 NextTable(symbol,nextTableType,bunchLen,count);
1116 if(nextTableType==0){
1117 bufferFile.FillBuffer(time);
1118 bufferFile.FillBuffer(bunchLen+2);
1122 bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber);
1124 cout<<"Number of decoded words:"<<wordsRead<<endl;
1126 //The trees are deleted
1127 for(Int_t j=0;j<NumTables;j++){
1128 DeleteHuffmanTree(rootNode[j]);
1134 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1136 Int_t AliTPCCompression::DecompressDataOptTables(Int_t NumTables,const char* fname,char* fDest){
1137 //This method decompress a file using separate Huffman tables
1139 cout<<" DECOMPRESSION:"<<endl;
1140 cout<<"Source File "<<fname<<" Destination File "<<fDest<<endl;
1142 AliTPCHNode ** rootNode = new AliTPCHNode*[NumTables];
1143 //Creation of the Huffman trees
1144 CreateTreesFromFile(rootNode,NumTables);
1146 f.open(fname,ios::binary|ios::in);
1148 f.open(fname,ios::in);
1150 if(!f){cout<<"File doesn't exist:"<<fname<<endl;;return -1;}
1151 //to go to the end of the file
1152 f.seekg(0,ios::end);
1153 //to get the file dimension in byte
1155 fPos-=sizeof(ULong_t);
1159 f.read((char*)(&fBuffer),sizeof(ULong_t));
1167 ULong_t packetNumber=ReadWord(sizeof(ULong_t)*8);
1169 cout<<"Number of Packect: "<<packetNumber<<endl;
1171 AliTPCBuffer160 bufferFile(fDest,1);
1173 ULong_t wordsRead=0; //number of read coded words
1174 while(k<packetNumber){
1175 Int_t numWords,padNumber,rowNumber,secNumber=0;
1176 ReadTrailer(numWords,padNumber,rowNumber,secNumber);
1179 Int_t previousTime=-1;
1181 Int_t nextTableType=0;
1184 for(Int_t i=0;i<numWords;i++){
1185 ULong_t symbol=GetDecodedWord(rootNode[nextTableType]);
1187 //Time reconstruction
1188 if (nextTableType==1){
1189 if (previousTime!=-1){
1190 previousTime=symbol+previousTime+bunchLen;
1192 else previousTime=symbol;
1196 bufferFile.FillBuffer(symbol);
1197 NextTable(symbol,nextTableType,bunchLen,count);
1198 if(nextTableType==0){
1199 bufferFile.FillBuffer(time);
1200 bufferFile.FillBuffer(bunchLen+2);
1204 bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber);
1207 cout<<"Number of decoded words:"<<wordsRead<<endl;
1210 //The trees are deleted
1211 for(Int_t j=0;j<NumTables;j++){
1212 DeleteHuffmanTree(rootNode[j]);
1218 ///////////////////////////////////////////////////////////////////////////////////////////
1220 void AliTPCCompression::ReadAltroFormat(char* fileOut,char* fileIn)const{
1221 //This method creates a text file containing the same information stored in
1222 //an Altro file. The information in the text file is organized pad by pad and
1223 //and for each pad it consists in a sequence of bunches (Bunch length +2,
1224 //Time bin of the last amplitude sample in the bunch, amplitude values)
1225 //It is used mainly for debugging
1226 ofstream ftxt(fileOut);
1227 AliTPCBuffer160 buff(fileIn,0);
1228 Int_t numWords,padNum,rowNum,secNum=0;
1230 if (fVerbose) cout<<"Creating a txt file from an Altro Format file"<<endl;
1231 while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
1232 ftxt<<"S:"<<secNum<<" R:"<<rowNum<<" P:"<<padNum<<" W:"<<numWords<<endl;
1234 for(Int_t j=0;j<(4-numWords%4);j++){
1235 value=buff.GetNextBackWord();
1238 for(Int_t i=0;i<numWords;i++){
1239 value=buff.GetNextBackWord();
1247 //////////////////////////////////////////////////////////////////////////////////////////