]> git.uio.no Git - u/mrichter/AliRoot.git/blob - TPC/AliTPCCompression.cxx
dc031e3d13a72ec8fc67e0948cc4e403d4d5f215
[u/mrichter/AliRoot.git] / TPC / AliTPCCompression.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
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  **************************************************************************/
15 /* $Id$ */
16
17 // This class contains the implementation of the 
18 // compression and decompression algorithms 
19 // Compression is performed reading the Altro data block (called packet) backward.
20 // Similarly decompression is also done backward so that the final file is restored
21 // after the compression and decompression phase.
22
23
24 #include <TObjArray.h>
25 #include "Riostream.h"
26 #include "TMath.h"
27 #include "AliTPCCompression.h"
28 #include "AliTPCBuffer160.h"
29 #include "AliTPCHuffman.h"
30
31 ClassImp(AliTPCCompression)
32 //////////////////////////////////////////////////////////////////////////////////////////////////
33 AliTPCCompression::AliTPCCompression(){
34   //Defaul constructor
35   fDimBuffer=sizeof(ULong_t)*8;
36   fFreeBitsBuffer=fDimBuffer;
37   fReadBits=0;
38   fPos=0;
39   fBuffer=0;
40   fVerbose=0;
41   fFillWords=0;
42   return;
43 }
44 //////////////////////////////////////////////////////////////////////////////////////////////////
45 AliTPCCompression::AliTPCCompression(const AliTPCCompression &source){
46   //Constructor
47   this->fDimBuffer=source.fDimBuffer;
48   this->fFreeBitsBuffer=source.fFreeBitsBuffer;
49   this->fReadBits=source.fReadBits;
50   this->fPos=source.fPos;
51   this->fBuffer=source.fBuffer;
52   this->fVerbose=source.fVerbose;
53   this->fFillWords=source.fFillWords;
54   return;
55 }
56 //////////////////////////////////////////////////////////////////////////////////////////////////
57 AliTPCCompression&  AliTPCCompression::operator=(const AliTPCCompression &source){
58   //Redefinition of the assignment operator
59   this->fDimBuffer=source.fDimBuffer;
60   this->fFreeBitsBuffer=source.fFreeBitsBuffer;
61   this->fReadBits=source.fReadBits;
62   this->fPos=source.fPos;
63   this->fBuffer=source.fBuffer;
64   this->fVerbose=source.fVerbose;
65   this->fFillWords=source.fFillWords;
66   return *this;
67
68 //////////////////////////////////////////////////////////////////////////////////////////////////
69 void AliTPCCompression::NextTable(Int_t Val,Int_t &NextTableType,Int_t &BunchLen,Int_t &Count)const{
70   //Depending on the data type (5 types of data) a specific table is called
71   /*
72     Table index:
73     0==> Bunch length value     
74     1==> Time Bin value 
75     2==> 1-samples bunch
76     3==> Central samples
77     4==> Border samples
78   */  
79   switch (NextTableType){
80   case 0:{
81     BunchLen=Val-2;
82     NextTableType=1;
83     break;
84   }//end case 0
85   case 1:{
86     if (BunchLen==1)NextTableType=2;
87     else{
88       NextTableType=4;
89       Count=1;
90     }
91     break;
92   }//end case 1
93   case 2:{
94     NextTableType=0;
95     break;
96   }//end case 2
97   case 3:{
98     Count++;
99     if (Count==(BunchLen-1)){
100       NextTableType=4;
101     }
102     break;
103   }//end case 3
104   case 4:{
105     if (Count==1){
106       if (BunchLen>2)
107         NextTableType=3;
108       else
109         Count++;
110     }
111     else
112       NextTableType=0;
113     break;
114   }//end case 4
115   }//end switch
116   return;
117 }
118
119 /////////////////////////////////////////////////////////////////////////////////////////////////////
120
121 /////////////////////////////////////////////////////////////////////////////////////////////////////
122
123 Int_t AliTPCCompression::FillTables(const char* fSource,AliTPCHTable* table[],const Int_t NumTables){
124   //This method is used to compute the frequencies of the symbols in the source file
125   AliTPCBuffer160 buff(fSource,0);
126   ULong_t countWords=0;
127   ULong_t countTrailer=0;
128   Int_t numWords,padNum,rowNum,secNum=0;
129   Int_t value=0;
130   ULong_t stat[5]={0,0,0,0,0};
131   Int_t endFill=0;
132   Int_t end=1;
133   while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
134     if(end){
135       endFill=buff.GetFillWordsNum();
136       end=0;
137     }//endif
138     countTrailer++;
139     if (numWords%4){
140       fFillWords+=4-numWords%4;
141       for(Int_t j=0;j<(4-numWords%4);j++){
142         value=buff.GetNextBackWord();
143       }//end for
144     }//end if
145     
146     Int_t packet[1024];
147     Int_t timePos[345];
148     Int_t tp=0;
149     for(Int_t i=0;i<345;i++)timePos[i]=0;
150     for(Int_t i=0;i<1024;i++)packet[i]=0;
151     
152     Int_t nextTableType=0;
153     Int_t bunchLen=0;
154     Int_t count=0;
155     for(Int_t i=0;i<numWords;i++){
156       value=buff.GetNextBackWord();
157       packet[i]=value;
158       if(nextTableType==1){
159         timePos[tp]=i;
160         tp++;
161       }
162       NextTable(value,nextTableType,bunchLen,count);
163     }//end for
164     //computing the Time gap between two bunches
165     Int_t temp=0;
166     tp--;
167     Int_t previousTime=packet[timePos[tp]];
168     for(Int_t i=tp-1;i>=0;i--){
169       Int_t timPos=timePos[i];
170       Int_t bunchLen=packet[timPos-1]-2;
171       temp=packet[timPos];
172       packet[timPos]=packet[timPos]-previousTime-bunchLen;
173       previousTime=temp;
174     }
175     nextTableType=0;
176     count=0;
177     bunchLen=0;
178     for(Int_t i=0;i<numWords;i++){
179       value=packet[i];
180       table[nextTableType]->SetFrequency(value);
181       stat[nextTableType]++;
182       NextTable(value,nextTableType,bunchLen,count);
183       countWords++;
184     }//end for
185   }//end while
186   cout<<"Number of words:       "<<countWords<<endl;
187   cout<<"Number of trailers:    "<<countTrailer<<endl;
188   cout<<"Number of fill words   "<<fFillWords+endFill<<endl;
189   cout<<"Total number of words: "<<countWords+countTrailer*4+fFillWords<<endl;
190   //STATISTICS  
191   fStat.open("Statistics");
192   fStat<<"Number of words:..........................................."<<countWords<<endl;
193   fStat<<"Number of trailers (4 10 bits words in each one)..........."<<countTrailer<<endl;
194   fStat<<"Number of fill words:......................................"<<fFillWords+endFill<<endl;
195   fStat<<"Total number of words:....................................."<<countWords+countTrailer*4+fFillWords+endFill<<endl;
196   fStat<<"-----------------------------------------"<<endl;
197   fStat<<"Number of Bunches............."<<stat[0]<<endl;
198   fStat<<"Number of Time bin............"<<stat[1]<<endl;
199   fStat<<"Number of One Samples Bunch..."<<stat[2]<<endl;
200   fStat<<"Number of Central Samples....."<<stat[3]<<endl;
201   fStat<<"Number of Border Samples......"<<stat[4]<<endl;
202   fStat<<"-----------------------------------------"<<endl;
203   ULong_t fileDimension=(ULong_t)TMath::Ceil(double((countTrailer*4+countWords+fFillWords+endFill)*10/8));
204   fStat<<"Total file Size in bytes.."<<fileDimension<<endl;
205   Double_t percentage=TMath::Ceil((fFillWords+endFill)*125)/fileDimension;
206   fStat<<"Fill Words................"<<(ULong_t)TMath::Ceil((fFillWords+endFill)*10/8)<<" bytes   "<<percentage<<"%"<<endl;  
207   percentage=(Double_t)countTrailer*500/fileDimension;
208   fStat<<"Trailer..................."<<countTrailer*5<<" bytes   "<<percentage<<"%"<<endl;
209
210   percentage=(Double_t)((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])) *125/fileDimension;
211   fStat<<"Data......................"<<(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])*10/8)<<" bytes   "<<percentage<<"%"<<endl;
212
213   percentage=(Double_t)(stat[0]*125)/fileDimension;
214   fStat<<"Bunch....................."<<(ULong_t)TMath::Ceil(stat[0]*10/8)<<" bytes  "<<percentage<<"%"<<endl;  //  
215   percentage=(Double_t)(stat[1]*125)/fileDimension;
216   fStat<<"Time......................"<<(ULong_t)TMath::Ceil(stat[1]*10/8)<<" bytes  "<<percentage<<"%"<<endl;  //  
217
218
219   percentage=(Double_t)((stat[2]+stat[3]+stat[4])) *125/fileDimension;
220   fStat<<"Amplitude values.........."<<(ULong_t)TMath::Ceil((stat[2]+stat[3]+stat[4])*10/8)<<" bytes  "<<percentage<<"%"<<endl;
221   percentage=(Double_t)(stat[2]*125)/fileDimension;
222   fStat<<"     One Samples..............."<<(ULong_t)TMath::Ceil(stat[2]*10/8)<<" bytes  "<<percentage<<"%"<<endl;  //  
223   percentage=(Double_t)(stat[3]*125)/fileDimension;
224   fStat<<"     Central Samples..........."<<(ULong_t)TMath::Ceil(stat[3]*10/8)<<" bytes  "<<percentage<<"%"<<endl;  //  
225   percentage=(Double_t)(stat[4]*125)/fileDimension;
226   fStat<<"     Border Samples............"<<(ULong_t)TMath::Ceil(stat[4]*10/8)<<" bytes  "<<percentage<<"%"<<endl;  //  
227   fStat.close();
228   return 0;
229 }
230 ////////////////////////////////////////////////////////////////////////////////////////
231 Int_t AliTPCCompression::StoreTables(AliTPCHTable* table[],const Int_t NumTable){
232   //This method stores the tables in a sequence of binary file
233   char filename[15];
234   ofstream fTable;
235   for(Int_t k=0;k<NumTable;k++){
236     sprintf(filename,"Table%d.dat",k);
237 #ifndef __DECCXX 
238     fTable.open(filename,ios::binary);
239 #else
240     fTable.open(filename);
241 #endif
242     Int_t dim=table[k]->Size();
243     //Table dimension is written into a file
244     fTable.write((char*)(&dim),sizeof(Int_t));
245     //One table is written into a file
246     for(Int_t i=0;i<dim;i++){
247       UChar_t codeLen=table[k]->CodeLen()[i];
248       //      ULong_t code=(ULong_t)table[k]->Code()[i];
249       Double_t code=table[k]->Code()[i];
250       fTable.write((char*)(&codeLen),sizeof(UChar_t));
251       //fTable.write((char*)(&code),sizeof(ULong_t));
252       fTable.write((char*)(&code),sizeof(Double_t));
253     } //end for
254     fTable.close();
255   }//end for
256   return 0;
257 }
258 ////////////////////////////////////////////////////////////////////////////////////////
259 Int_t AliTPCCompression::CreateTables(const char* fSource,const Int_t NumTables){
260   //Tables manager
261   /*
262     Table index:
263     0==> Bunch length values     
264     1==> Time Bin values 
265     2==> 1-samples bunch
266     3==> Central samples
267     4==> Border samples
268   */
269   Int_t n=10;// 10 bits per symbol 
270   AliTPCHTable ** table = new AliTPCHTable*[NumTables];
271   //The table is inizialized with the rigth number of rows 
272   for(Int_t i=0;i<NumTables;i++){table[i]=new  AliTPCHTable((Int_t)(TMath::Power(2,n)));}
273   //The frequencies are calculated and the tables are filled
274   if (fVerbose)
275     cout<<"Filling tables...\n";
276   //The get the frequencies 
277   FillTables(fSource,table,NumTables);
278
279   //This part will be used in the table optimization phase
280   /*
281   for(Int_t i=0;i<NumTables;i++){
282     table[i]->CompleteTable(i);
283   }
284   */
285   if(fVerbose){
286     cout<<"Entropy of Bunch length table........."<<table[0]->GetEntropy()<<endl;
287     cout<<"Entropy of Time bin table............."<<table[1]->GetEntropy()<<endl;
288     cout<<"Entropy of one Sample bunch table....."<<table[2]->GetEntropy()<<endl;
289     cout<<"Entropy of Central Sample table......."<<table[3]->GetEntropy()<<endl;
290     cout<<"Entropy Border Samples table.........."<<table[4]->GetEntropy()<<endl;
291   }
292   fStat.open("Statistics",ios::app);
293   fStat<<endl;
294   fStat<<"----------------- ENTROPY for castomized tables --------------------------"<<endl;
295   fStat<<"Entropy of Bunch length table......."<<table[0]->GetEntropy()<<endl;
296   fStat<<"Entropy of Time bin table..........."<<table[1]->GetEntropy()<<endl;
297   fStat<<"Entropy of one Sample bunch table..."<<table[2]->GetEntropy()<<endl;
298   fStat<<"Entropy of Central Sample table....."<<table[3]->GetEntropy()<<endl;
299   fStat<<"Entropy Border Samples table........"<<table[4]->GetEntropy()<<endl;
300   fStat.close();
301  
302   if (fVerbose)
303     cout<<"Tables filled \n";
304   //Tables are saved in a sequence of text file and using the macro Histo.C is it possible to get
305   //a series of histograms rappresenting the frequency distribution
306   table[0]->StoreFrequencies("BunchLenFreq.txt");
307   table[1]->StoreFrequencies("TimeFreq.txt");
308   table[2]->StoreFrequencies("Sample1Freq.txt");
309   table[3]->StoreFrequencies("SCentralFreq.txt");
310   table[4]->StoreFrequencies("SBorderFreq.txt");
311   if (fVerbose)
312     cout<<"Creating Tables..\n";
313   //One Huffman tree is created for each table starting from the frequencies of the symbols
314   for(Int_t i=0;i<NumTables;i++){
315     table[i]->BuildHTable();
316     if (fVerbose==2){
317       cout<<"Number of elements inside the table:"<<table[i]->GetWordsNumber();
318       switch(i){
319       case 0:{
320         cout<<" (Bunch Length)"<<endl;
321         break;
322       }
323       case 1:{
324         cout<<" (Time Bin)"<<endl;
325         break;
326       }
327       case 2:{
328         cout<<" (1 Samples Bunch)"<<endl;
329         break;
330       }
331       case 3:{
332         cout<<" (Central Samples)"<<endl;
333         break;
334       }
335       case 4:{
336         cout<<" (Border Samples)"<<endl;
337         break;
338       }
339       }//end switch
340       table[i]->PrintTable();
341     }
342   }
343   //The tables are saved ad binary files
344   StoreTables(table,NumTables);
345   //The tables stored in memory are deleted; 
346   for(Int_t i=0;i<NumTables;i++)delete table[i];
347   delete [] table;
348   return 0;
349 }
350 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
351 Int_t AliTPCCompression::RetrieveTables(AliTPCHTable* table[],Int_t NumTable){
352   //This method retrieve the Huffman tables from a sequence of binary files
353   if (fVerbose)
354     cout<<"Retrieving tables from files \n";
355   //  ULong_t code;
356   Double_t code;
357   UChar_t codeLen;
358   ifstream fTable;  
359   char filename[15];
360   //The following for loop is used to generate the Huffman trees acording to the tables
361   for(Int_t k=0;k<NumTable;k++){
362     Int_t dim;//this variable contains the table dimension
363     sprintf(filename,"Table%d.dat",k); 
364 #ifndef __DECCXX 
365     fTable.open(filename,ios::binary);
366 #else
367     fTable.open(filename);
368 #endif
369     fTable.read((char*)(&dim),sizeof(Int_t));
370     if (fVerbose)
371       cout<<"Table dimension: "<<dim<<endl;
372     table[k]=new AliTPCHTable(dim);
373     for(Int_t i=0;i<dim;i++){
374       fTable.read((char*)(&codeLen),sizeof(UChar_t));
375       table[k]->SetCodeLen(codeLen,i);
376       //      fTable.read((char*)(&code),sizeof(ULong_t));
377       fTable.read((char*)(&code),sizeof(Double_t));
378       table[k]->SetCode(Mirror((ULong_t)code,codeLen),i);
379     }//end for 
380     fTable.close();
381   }//end for 
382   if (fVerbose)
383     cout<<"Trees generated \n";
384   //At this point the trees are been built
385   return 0;
386 }
387 ////////////////////////////////////////////////////////////////////////////////////////
388 /*                               COMPRESSION                                          */
389 ////////////////////////////////////////////////////////////////////////////////////////
390
391 void AliTPCCompression::StoreValue(ULong_t val,UChar_t len){
392   //This method stores the value "val" of "len" bits into the internal buffer "fBuffer"
393   if (len<=fFreeBitsBuffer){           // val is not splitted in two buffer
394     fFreeBitsBuffer-=len;
395     fBuffer=fBuffer<<len;
396     fBuffer=fBuffer|val;    
397     if(!fFreeBitsBuffer){              // if the buffer is full it is written into a file 
398       f.write((char*)(&fBuffer),sizeof(ULong_t));       
399       fFreeBitsBuffer=fDimBuffer;
400       fBuffer=0;
401     }
402   }//end if
403   else{                               //val has to be splitted in two buffers
404     fBuffer=fBuffer<<fFreeBitsBuffer;
405     ULong_t temp;
406     temp=val;
407     temp=temp>>(len-fFreeBitsBuffer);
408     fBuffer=fBuffer|temp;
409     f.write((char*)(&fBuffer),sizeof(ULong_t));
410     fFreeBitsBuffer=fDimBuffer-(len-fFreeBitsBuffer);
411     val=val<<fFreeBitsBuffer;
412     val=val>>fFreeBitsBuffer;
413     fBuffer=val;
414   }//end else
415   return;
416 }
417 //////////////////////////////////////////////////////////////////////////////////////////////////
418 void AliTPCCompression::Flush(){
419   //The last buffer cannot be completely full so to save it 
420   //into the output file it is first necessary to fill it with an hexadecimal pattern
421   if(fFreeBitsBuffer<fDimBuffer){
422     fBuffer=fBuffer<<fFreeBitsBuffer;
423     f.write((char*)(&fBuffer),sizeof(ULong_t));  
424   }//end if
425   return;
426 }
427 //////////////////////////////////////////////////////////////////////////////////////////////////
428 ULong_t AliTPCCompression::Mirror(ULong_t val,UChar_t len)const{
429   //This method inverts the digits of the number "val" and length "len"
430   //indicates the number of digits of the number considered in binary notation
431   ULong_t specular=0;
432   ULong_t mask=0x1;
433   ULong_t bit;
434   for(Int_t i=0;i<len;i++){
435     bit=val&mask;
436     bit=bit>>i;
437     specular=specular<<1;
438     specular=specular|bit;
439     mask=mask<<1;
440   }
441   return specular;
442 }
443 //////////////////////////////////////////////////////////////////////////////////////////////////
444 Int_t AliTPCCompression::CompressData(AliTPCHTable* table[],Int_t NumTable,const char* fSource,const char* fDest){
445   //This method is used to compress the data stored in the Altro format file using specific tables
446   //calculated considering the frequencies of the symbol of the file that has to be compressed
447   cout<<" COMPRESSION "<<endl;
448   cout<<"compression of the file "<<fSource<<" Output File: "<<fDest<<endl;
449   //the output file is open
450 #ifndef __DECCXX 
451   f.open(fDest,ios::binary|ios::out);
452 #else
453   f.open(fDest,ios::out);
454 #endif
455   //Tables are written into the output file
456   for(Int_t k=0;k<NumTable;k++){
457     Int_t dim=table[k]->Size();
458     //Table dimension is written into a file
459     f.write((char*)(&dim),sizeof(Int_t));
460     //One table is written into a file
461     for(Int_t i=0;i<dim;i++){
462       UChar_t codeLen=table[k]->CodeLen()[i];
463       ULong_t code=(ULong_t)table[k]->Code()[i];
464       f.write((char*)(&codeLen),sizeof(UChar_t));
465       f.write((char*)(&code),sizeof(ULong_t));
466     } //end for
467   }//end for
468
469   // Source file is open
470   AliTPCBuffer160 buff(fSource,0);
471   //coded words are written into the output file
472   Int_t numWords,padNum,rowNum,secNum=0;
473   ULong_t storedWords=0;
474   Int_t value=0;
475   ULong_t numPackets=0;
476   while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
477     numPackets++;
478     if (numWords%4){
479       for(Int_t j=0;j<(4-numWords%4);j++){
480         value=buff.GetNextBackWord();
481       }//end for
482     }//end if
483
484     Int_t packet[1024];
485     Int_t timePos[345];
486     Int_t tp=0;
487     for(Int_t i=0;i<345;i++)timePos[i]=0;
488     for(Int_t i=0;i<1024;i++)packet[i]=0;
489
490     Int_t nextTableType=0;
491     Int_t bunchLen=0;
492     Int_t count=0;
493     for(Int_t i=0;i<numWords;i++){
494       value=buff.GetNextBackWord();
495       packet[i]=value;
496       if(nextTableType==1){
497         timePos[tp]=i;
498         tp++;
499       }
500       NextTable(value,nextTableType,bunchLen,count);
501     }//end for
502     //computing the Time gap between two bunches
503     Int_t temp=0;
504     tp--;
505     Int_t previousTime=packet[timePos[tp]];
506     for(Int_t i=tp-1;i>=0;i--){
507       Int_t timPos=timePos[i];
508       Int_t bunchLen=packet[timPos-1]-2;
509       temp=packet[timPos];
510       packet[timPos]=packet[timPos]-previousTime-bunchLen;
511       previousTime=temp;
512     }//end for
513     nextTableType=0;
514     count=0;
515     bunchLen=0;
516     Int_t timeBin=0;
517     //All the words for one pad are compressed and stored in the compress file
518     for(Int_t i=0;i<numWords;i++){
519       value=packet[i];
520       if(nextTableType==1)timeBin=value;
521       if(nextTableType>1){
522         //      ULong_t val=(ULong_t)table[nextTableType]->Code()[value];     // val is the code
523         Double_t val=table[nextTableType]->Code()[value];     // val is the code
524         UChar_t len=table[nextTableType]->CodeLen()[value];  // len is the length (number of bits)of val
525         StoreValue(Mirror((ULong_t)val,len),len);
526         storedWords++;
527       }//end if
528       NextTable(value,nextTableType,bunchLen,count);
529       if(nextTableType==0){
530         //      ULong_t val=(ULong_t)table[1]->Code()[timeBin];     // val is the code
531         Double_t val=table[1]->Code()[timeBin];     // val is the code
532         UChar_t len=table[1]->CodeLen()[timeBin];  // len is the length (number of bits)of val
533         StoreValue(Mirror((ULong_t)val,len),len);
534         //val=(ULong_t)table[nextTableType]->Code()[(bunchLen+2)];     // val is the code
535         val=table[nextTableType]->Code()[(bunchLen+2)];     // val is the code
536         len=table[nextTableType]->CodeLen()[(bunchLen+2)];  // len is the length (number of bits)of val
537         StoreValue(Mirror((ULong_t)val,len),len);
538         storedWords+=2;
539       }
540     }//end for
541     //Trailer
542     StoreValue(numWords,10);
543     StoreValue(padNum,10);
544     StoreValue(rowNum,10);
545     StoreValue(secNum,9);
546     StoreValue(1,1);
547     storedWords+=4;
548   }//end  while
549   StoreValue(numPackets,32);
550   cout<<"Number of strored packet: "<<numPackets<<endl;
551   StoreValue(1,1);
552   //The last buffen cannot be completely full
553   Flush();
554   cout<<"Number of stored words: "<<storedWords<<endl;
555   f.close();
556   return 0;
557 }
558
559 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
560 Int_t AliTPCCompression::CompressDataOptTables(Int_t NumTable,const char* fSource,const char* fDest){
561   //This method compress an Altro format file using a general set of tables stored as binary files to be provided
562   if (fVerbose){
563     cout<<" BackWord COMPRESSION "<<endl;
564     cout<<"compression of the file "<<fSource<<" Output File: "<<fDest<<endl;
565   }
566   //Tables are read from the files (Each codeword has been "Mirrored")
567   AliTPCHTable **table = new AliTPCHTable*[NumTable];
568   RetrieveTables(table,NumTable);
569   //the output file is open
570 #ifndef __DECCXX 
571   f.open(fDest,ios::binary|ios::out);
572 #else
573   f.open(fDest,ios::out);
574 #endif
575   // Source file is open
576   AliTPCBuffer160 buff(fSource,0);
577   //coded words are written into a file
578   Int_t numWords,padNum,rowNum,secNum=0;
579   ULong_t  storedWords=0;
580   Int_t    value=0;
581   ULong_t  numPackets=0;
582   Double_t stat[5]={0.,0.,0.,0.,0.};
583   ULong_t  trailerNumbers=0;
584   Double_t numElem[5]={0,0,0,0,0};
585   Double_t fillWords=0.;
586   fStat.open("Statistics",ios::app);
587   fStat<<endl;
588   fStat<<"-------------------COMPRESSION STATISTICS----------"<<endl;
589   Int_t end=1;
590   while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
591     if(end){
592       fillWords=buff.GetFillWordsNum();
593       end=0;
594     }//endif
595
596     numPackets++;
597     if (numWords%4){
598       fillWords+=4-numWords%4;
599       for(Int_t j=0;j<(4-numWords%4);j++){
600         value=buff.GetNextBackWord();
601       }//end for
602     }//end if
603
604     Int_t packet[1024];
605     Int_t timePos[345];
606     Int_t tp=0;
607     for(Int_t i=0;i<345;i++)timePos[i]=0;
608     for(Int_t i=0;i<1024;i++)packet[i]=0;
609
610     Int_t nextTableType=0;
611     Int_t bunchLen=0;
612     Int_t count=0;
613     for(Int_t i=0;i<numWords;i++){
614       value=buff.GetNextBackWord();
615       packet[i]=value;
616       if(nextTableType==1){
617         timePos[tp]=i;
618         tp++;
619       }
620       NextTable(value,nextTableType,bunchLen,count);
621     }//end for
622     //computing the Time gap between two bunches
623     Int_t temp=0;
624     tp--;
625     Int_t previousTime=packet[timePos[tp]];
626     for(Int_t i=tp-1;i>=0;i--){
627       Int_t timPos=timePos[i];
628       Int_t bunchLen=packet[timPos-1]-2;
629       temp=packet[timPos];
630       packet[timPos]=packet[timPos]-previousTime-bunchLen;
631       previousTime=temp;
632     }//end for
633
634     nextTableType=0;
635     count=0;
636     bunchLen=0;
637     Int_t timeBin=0;
638     for(Int_t i=0;i<numWords;i++){
639       value=packet[i];
640       if(nextTableType==1)timeBin=value;
641       if(nextTableType>1){
642         //ULong_t val=(ULong_t)table[nextTableType]->Code()[value];     // val is the code
643         Double_t val=table[nextTableType]->Code()[value];     // val is the code
644         UChar_t len=table[nextTableType]->CodeLen()[value];  // len is the length (number of bits)of val
645         stat[nextTableType]+=len;
646         numElem[nextTableType]++;
647         StoreValue((ULong_t)val,len);
648         storedWords++;
649       }//end if
650       NextTable(value,nextTableType,bunchLen,count);
651       if(nextTableType==0){
652         //      ULong_t val=(ULong_t)table[1]->Code()[timeBin];     // val is the code
653         Double_t val=table[1]->Code()[timeBin];     // val is the code
654         UChar_t len=table[1]->CodeLen()[timeBin];  // len is the length (number of bits)of val
655         stat[1]+=len;
656         numElem[1]++;
657         StoreValue((ULong_t)val,len);
658         //      val=(ULong_t)table[nextTableType]->Code()[(bunchLen+2)];     // val is the code
659         val=table[nextTableType]->Code()[(bunchLen+2)];     // val is the code
660         len=table[nextTableType]->CodeLen()[(bunchLen+2)];  // len is the length (number of bits)of val
661         StoreValue((ULong_t)val,len);
662         stat[nextTableType]+=len;
663         numElem[nextTableType]++;
664         storedWords+=2;
665       }
666     }//end for
667     //Trailer
668     StoreValue(numWords,10);
669     StoreValue(padNum,10);
670     StoreValue(rowNum,10);
671     StoreValue(secNum,9);
672     StoreValue(1,1);
673     storedWords+=4;
674     trailerNumbers++;
675   }//end  while
676   StoreValue(numPackets,32);
677   if(fVerbose)
678     cout<<"Number of strored packets: "<<numPackets<<endl;
679   StoreValue(1,1);
680   //The last buffen cannot be completely full
681   Flush();
682   if(fVerbose)
683     cout<<"Number of stored words: "<<storedWords<<endl;
684   f.close();
685   //Tables are deleted
686   for(Int_t i=0;i<NumTable;i++){
687     delete table[i];
688   }//end for
689   delete [] table;
690   Double_t dimension=(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)+trailerNumbers*5;
691   fStat<<"Trailer Dimension in bytes......"<<trailerNumbers*5<<endl;
692   fStat<<"Data Dimension in bytes........."<<(ULong_t)TMath::Ceil((stat[0]+stat[1]+stat[2]+stat[3]+stat[4])/8)<<endl;
693   fStat<<"Compressed file dimension......."<<(ULong_t)dimension<<endl;
694   /*
695   fStat<<(ULong_t)trailerNumbers<<endl;
696   fStat<<(ULong_t)fillWords<<endl;
697   fStat<<(ULong_t)numElem[0]<<endl;
698   fStat<<(ULong_t)numElem[1]<<endl;
699   fStat<<(ULong_t)numElem[2]<<endl;
700   fStat<<(ULong_t)numElem[3]<<endl;
701   fStat<<(ULong_t)numElem[4]<<endl;
702   */
703   fillWords=(fillWords+numElem[0]+numElem[1]+numElem[2]+numElem[3]+numElem[4]+trailerNumbers*4)*10/8;
704   fStat<<"Original file dimension........."<<(ULong_t)fillWords<<endl;
705
706   Double_t ratio=(dimension/fillWords)*100;
707   fStat<<"Compression ratio (Compressed/Uncompressed)..."<<ratio<<"%"<<endl;
708   fStat<<endl;
709   fStat<<"Bunch length size in bytes......"<<(ULong_t)TMath::Ceil(stat[0]/8)<<" Comppression.."<<(stat[0]/numElem[0])*10<<"%"<<endl;
710   
711   fStat<<"Time gap size in bytes.........."<<(ULong_t)TMath::Ceil(stat[1]/8)<<" Comppression.."<<(stat[1]/numElem[1])*10<<"%"<<endl;
712   fStat<<"Amplitude values in bytes......."<<(ULong_t)TMath::Ceil((stat[2]+stat[3]+stat[4])/8)<<" Comppression.."<<
713     ((stat[2]+stat[3]+stat[4])/(numElem[2]+numElem[3]+numElem[4]))*10<<"%"<<endl;
714   fStat<<"     One Samples in bytes............"<<(ULong_t)TMath::Ceil(stat[2]/8)<<" Comppression.."<<(stat[2]/numElem[2])*10<<"%"<<endl;
715   fStat<<"     Central Samples size in bytes..."<<(ULong_t)TMath::Ceil(stat[3]/8)<<" Comppression.."<<(stat[3]/numElem[3])*10<<"%"<<endl;
716   fStat<<"     Border Samples size in bytes...."<<(ULong_t)TMath::Ceil(stat[4]/8)<<" Comppression.."<<(stat[4]/numElem[4])*10<<"%"<<endl;
717   fStat<<endl;
718   fStat<<"Average number of bits per word"<<endl;
719   fStat<<"Bunch length ......"<<stat[0]/numElem[0]<<endl;
720   fStat<<"Time gap .........."<<stat[1]/numElem[1]<<endl;
721   fStat<<"One Samples........"<<stat[2]/numElem[2]<<endl;
722   fStat<<"Central Samples ..."<<stat[3]/numElem[3]<<endl;
723   fStat<<"Border Samples....."<<stat[4]/numElem[4]<<endl;
724   fStat.close();
725   return 0;
726 }
727
728 ////////////////////////////////////////////////////////////////////////////////////////
729
730 ////////////////////////////////////////////////////////////////////////////////////////
731 /*                               DECOMPRESSION                                        */
732 ////////////////////////////////////////////////////////////////////////////////////////
733 void AliTPCCompression::CreateTrees(AliTPCHNode *RootNode[],const Int_t NumTables){
734   //The first part of the compressed file cotains the tables
735   //The following for loop is used to generate the Huffman trees acording to the tables
736   if(fVerbose)
737     cout<<"Creating the Huffman trees \n";
738   AliTPCHNode *node=0;
739   //  ULong_t code;
740   Double_t code;
741   UChar_t codeLen;
742   //loop over the numbero of tables
743   for(Int_t k=0;k<NumTables;k++){
744     RootNode[k]=new AliTPCHNode(); //RootNode is the root of the tree
745     Int_t dim;//this variable contains the table dimension
746     f.read((char*)(&dim),sizeof(Int_t));
747     if (fVerbose)
748       cout<<"Table dimension: "<<dim<<endl;
749     //loop over the words of a table
750     for(Int_t i=0;i<dim;i++){
751       f.read((char*)(&codeLen),sizeof(UChar_t));
752       //f.read((char*)(&code),sizeof(ULong_t));
753       f.read((char*)(&code),sizeof(Double_t));
754       node=RootNode[k];
755       for(Int_t j=1;j<=codeLen;j++){
756         ULong_t bit,val=0;
757         val=(ULong_t)TMath::Power(2,codeLen-j);
758         bit=(ULong_t)code&val; 
759         AliTPCHNode *temp=node;
760         if(bit){
761           node=node->GetRight();
762           if(!node){
763             node=new AliTPCHNode();
764             temp->SetRight(node);
765           }//end if
766         }//end if
767         else{
768           node=node->GetLeft();
769           if(!node){
770             node=new AliTPCHNode();
771             temp->SetLeft(node);
772           }//end if
773         }//end else
774       }//end for
775       if(codeLen){
776         node->SetSymbol(i);
777         node->SetFrequency(codeLen);
778       }//end if
779       //cout<<node->GetSymbol()<<"  "<<(Int_t)node->GetFrequency()<<endl;
780     }//end for 
781   }//end for 
782   if (fVerbose)
783     cout<<"Trees generated \n";
784   //At this point the trees are been built
785 }
786 //////////////////////////////////////////////////////////////////////////////////////////////////
787 void AliTPCCompression::CreateTreesFromFile(AliTPCHNode *RootNode[],const 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 
790   if(fVerbose)
791     cout<<"Creating the Huffman trees \n";
792   AliTPCHNode *node=0;
793   // ULong_t code;
794   Double_t code;
795   UChar_t codeLen;
796   ifstream fTable;  
797   char filename[15];
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); 
804 #ifndef __DECCXX 
805     fTable.open(filename,ios::binary);
806 #else
807     fTable.open(filename);
808 #endif
809     fTable.read((char*)(&dim),sizeof(Int_t));
810     if (fVerbose)
811       cout<<"Table dimension: "<<dim<<endl;
812     //loop over the words of one table
813     for(Int_t i=0;i<dim;i++){
814       fTable.read((char*)(&codeLen),sizeof(UChar_t));
815       //fTable.read((char*)(&code),sizeof(ULong_t));
816       fTable.read((char*)(&code),sizeof(Double_t));
817       node=RootNode[k];
818       for(Int_t j=1;j<=codeLen;j++){
819         ULong_t bit,val=0;
820         val=(ULong_t)TMath::Power(2,codeLen-j);
821         bit=(ULong_t)code&val; 
822         AliTPCHNode *temp=node;
823         if(bit){
824           node=node->GetRight();
825           if(!node){
826             node=new AliTPCHNode();
827             temp->SetRight(node);
828           }//end if 
829         }//end if
830         else{
831           node=node->GetLeft();
832           if(!node){
833             node=new AliTPCHNode();
834             temp->SetLeft(node);
835           }//end if
836         }//end else
837       }//end for
838       if(codeLen){
839         node->SetSymbol(i);
840         node->SetFrequency(codeLen);
841       }//end if
842     }//end for 
843     fTable.close();
844   }//end for 
845   if (fVerbose)
846     cout<<"Trees generated \n";
847   //At this point the trees are been built
848 }
849 //////////////////////////////////////////////////////////////////////////////////////////////////
850 void AliTPCCompression::DeleteHuffmanTree(AliTPCHNode* node){
851   //This function deletes all the nodes of an Huffman tree
852   //In an Huffman tree any internal node has always two children 
853   if (node){
854     DeleteHuffmanTree(node->GetLeft());
855     DeleteHuffmanTree(node->GetRight());
856     //    cout<<node->GetSymbol()<<"  "<<(Int_t)node->GetFrequency()<<endl;
857     delete node;
858   }
859 }
860 //////////////////////////////////////////////////////////////////////////////////////////////////
861 void AliTPCCompression::VisitHuffmanTree(AliTPCHNode* node){
862   //This function realizes an in order visit of a binary tree 
863   if (node){
864     cout<<node->GetSymbol()<<" "<<node->GetFrequency()<<endl;
865     VisitHuffmanTree(node->GetLeft());
866     VisitHuffmanTree(node->GetRight());
867   }
868 }
869 //////////////////////////////////////////////////////////////////////////////////////////////////
870 ULong_t AliTPCCompression::ReadWord(Int_t NumberOfBit){
871   //This method retrieves a word of a specific number of bits from the file through the internal buffer 
872   ULong_t result=0;
873   ULong_t bit=0;
874   for (Int_t i=0;i<NumberOfBit;i++){
875     if (fReadBits==32){
876       fPos-=sizeof(ULong_t);
877       f.seekg(fPos);
878       f.read((char*)(&fBuffer),sizeof(ULong_t));
879       fReadBits=0;
880     }//end if
881     ULong_t mask=0;
882     mask=(ULong_t)TMath::Power(2,fReadBits);
883     bit=fBuffer&mask;
884     bit=bit>>fReadBits;
885     fReadBits++;
886     bit=bit<<i;
887     result=result|bit;
888   }//end for
889   return result;
890 }
891 //////////////////////////////////////////////////////////////////////////////////////////////////
892 void AliTPCCompression::ReadTrailer(Int_t &WordsNumber,Int_t &PadNumber,Int_t &RowNumber,Int_t &SecNumber){
893   //It retrieves a trailer 
894   ReadWord(1);
895   SecNumber=ReadWord(9);
896   RowNumber=ReadWord(10);
897   PadNumber=ReadWord(10);
898   WordsNumber=ReadWord(10);
899   return;
900 }
901 //////////////////////////////////////////////////////////////////////////////////////////////////
902 ULong_t AliTPCCompression::GetDecodedWord(AliTPCHNode* root){
903   //This method retrieves a decoded word.
904   AliTPCHNode *node=root;
905   ULong_t symbol=0;
906   Bool_t decoded=0;
907   while(!decoded){
908     ULong_t bit=ReadWord(1);
909     if(bit)
910       node=node->GetRight();
911     else
912       node=node->GetLeft();
913     if (!(node->GetLeft())){
914       symbol=node->GetSymbol();
915       decoded=1;
916     }
917   }//end while
918   return symbol;
919 }
920 //////////////////////////////////////////////////////////////////////////////////////////////////
921 Int_t AliTPCCompression::DecompressData(Int_t NumTables,const char* fname,char* fDest){
922   //Decompression method 
923   cout<<"   DECOMPRESSION:"<<endl;
924   cout<<"Source File "<<fname<<" Destination File "<<fDest<<endl;
925 #ifndef __DECCXX 
926   f.open(fname,ios::binary|ios::in);
927 #else
928   f.open(fname,ios::in);
929 #endif
930   if(!f){cout<<"File doesn't exist\n";return -1;}
931   AliTPCHNode ** rootNode = new AliTPCHNode*[NumTables];
932   //Creation of the Huffman trees
933   CreateTrees(rootNode,NumTables);
934   //to go to the end of the file
935   f.seekg(0,ios::end);
936   //to get the file dimension in byte
937   fPos=f.tellg();
938   fPos-=sizeof(ULong_t);
939   f.seekg(fPos);
940   fReadBits=0;
941   fBuffer=0;
942   f.read((char*)(&fBuffer),sizeof(ULong_t));
943   Int_t bit=0;
944   ULong_t mask=0x1;
945   while(!bit){
946     bit=fBuffer&mask;
947     mask=mask<<1;
948     fReadBits++;
949   }
950   ULong_t packetNumber=ReadWord(sizeof(ULong_t)*8);
951   cout<<"Number of Packect: "<<packetNumber<<endl;
952   AliTPCBuffer160 bufferFile(fDest,1);
953   ULong_t k=0;
954   ULong_t wordsRead=0; //number of read coded words 
955   while(k<packetNumber){
956     Int_t numWords,padNumber,rowNumber,secNumber=0;
957     ReadTrailer(numWords,padNumber,rowNumber,secNumber);
958     k++;
959     wordsRead+=4;
960     Int_t previousTime=-1;
961     Int_t time=0;
962     Int_t nextTableType=0;
963     Int_t bunchLen=0;
964     Int_t count=0;
965     for(Int_t i=0;i<numWords;i++){
966       ULong_t symbol=GetDecodedWord(rootNode[nextTableType]);
967       wordsRead++;
968       //Time reconstruction
969       if (nextTableType==1){
970         if (previousTime!=-1){
971           previousTime=symbol+previousTime+bunchLen;
972         }
973         else previousTime=symbol;
974         time=previousTime;
975       }
976       if(nextTableType>1)
977         bufferFile.FillBuffer(symbol);
978       NextTable(symbol,nextTableType,bunchLen,count); 
979       if(nextTableType==0){
980         bufferFile.FillBuffer(time);
981         bufferFile.FillBuffer(bunchLen+2);
982         bunchLen=0;
983       }
984     }//end for
985     bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber);
986   }//end while
987   cout<<"Number of decoded words:"<<wordsRead<<endl;
988   f.close();
989   //The trees are deleted 
990   for(Int_t j=0;j<NumTables;j++){
991       DeleteHuffmanTree(rootNode[j]);
992   }//end for
993   delete [] rootNode; 
994   return 0; 
995 }
996
997 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
998
999 Int_t AliTPCCompression::DecompressDataOptTables(Int_t NumTables,const char* fname,char* fDest){
1000   //This method decompress a file using separate Huffman tables
1001   if(fVerbose){
1002     cout<<"   DECOMPRESSION:"<<endl;
1003     cout<<"Source File "<<fname<<" Destination File "<<fDest<<endl; 
1004   }
1005   AliTPCHNode ** rootNode = new AliTPCHNode*[NumTables];
1006   //Creation of the Huffman trees
1007   CreateTreesFromFile(rootNode,NumTables);
1008 #ifndef __DECCXX
1009   f.open(fname,ios::binary|ios::in);
1010 #else
1011   f.open(fname,ios::in);
1012 #endif
1013   if(!f){cout<<"File doesn't exist\n";return -1;}
1014   //to go to the end of the file
1015   f.seekg(0,ios::end);
1016   //to get the file dimension in byte
1017   fPos=f.tellg();
1018   fPos-=sizeof(ULong_t);
1019   f.seekg(fPos);
1020   fReadBits=0;
1021   fBuffer=0;
1022   f.read((char*)(&fBuffer),sizeof(ULong_t));
1023   Int_t bit=0;
1024   ULong_t mask=0x1;
1025   while(!bit){
1026     bit=fBuffer&mask;
1027     mask=mask<<1;
1028     fReadBits++;
1029   }
1030   ULong_t packetNumber=ReadWord(sizeof(ULong_t)*8);
1031   if(fVerbose){
1032     cout<<"Number of Packect: "<<packetNumber<<endl;
1033   }
1034   AliTPCBuffer160 bufferFile(fDest,1);
1035   ULong_t k=0;
1036   ULong_t wordsRead=0; //number of read coded words 
1037   while(k<packetNumber){
1038     Int_t numWords,padNumber,rowNumber,secNumber=0;
1039     ReadTrailer(numWords,padNumber,rowNumber,secNumber);
1040     k++;
1041     wordsRead+=4;
1042     Int_t previousTime=-1;
1043     Int_t time=0;
1044     Int_t nextTableType=0;
1045     Int_t bunchLen=0;
1046     Int_t count=0;
1047     for(Int_t i=0;i<numWords;i++){
1048       ULong_t symbol=GetDecodedWord(rootNode[nextTableType]);
1049       wordsRead++;
1050       //Time reconstruction
1051       if (nextTableType==1){
1052         if (previousTime!=-1){
1053           previousTime=symbol+previousTime+bunchLen;
1054         }
1055         else previousTime=symbol;
1056         time=previousTime;
1057       }
1058       if(nextTableType>1)
1059         bufferFile.FillBuffer(symbol);
1060       NextTable(symbol,nextTableType,bunchLen,count); 
1061       if(nextTableType==0){
1062         bufferFile.FillBuffer(time);
1063         bufferFile.FillBuffer(bunchLen+2);
1064         bunchLen=0;
1065       }
1066     }//end for
1067     bufferFile.WriteTrailer(numWords,padNumber,rowNumber,secNumber);
1068   }//end while
1069   if(fVerbose){
1070     cout<<"Number of decoded words:"<<wordsRead<<endl;
1071   }
1072   f.close();
1073   //The trees are deleted 
1074   for(Int_t j=0;j<NumTables;j++){
1075       DeleteHuffmanTree(rootNode[j]);
1076   }//end for
1077   delete [] rootNode;
1078   return 0; 
1079 }
1080
1081 ///////////////////////////////////////////////////////////////////////////////////////////
1082
1083 void AliTPCCompression::ReadAltroFormat(char* fileOut,char* fileIn)const{
1084   //This method creates a text file containing the same information stored in 
1085   //an Altro file. The information in the text file is organized pad by pad and 
1086   //and for each pad it consists in a sequence of bunches (Bunch length +2,
1087   //Time bin of the last amplitude sample in the bunch, amplitude values)
1088   //It is used mainly for debugging
1089   ofstream ftxt(fileOut);
1090   AliTPCBuffer160 buff(fileIn,0);
1091   Int_t numWords,padNum,rowNum,secNum=0;
1092   Int_t value=0;
1093   while(buff.ReadTrailerBackward(numWords,padNum,rowNum,secNum) !=-1 ){
1094     ftxt<<"W:"<<numWords<<" P:"<<padNum<<" R:"<<rowNum<<" S:"<<secNum<<endl;
1095     if (numWords%4){
1096       for(Int_t j=0;j<(4-numWords%4);j++){
1097         value=buff.GetNextBackWord();
1098       }//end for
1099     }//end if
1100     for(Int_t i=0;i<numWords;i++){
1101       value=buff.GetNextBackWord();
1102       ftxt<<value<<endl;
1103     }//end for
1104   }//end while
1105   ftxt.close();
1106   return;
1107 }
1108
1109 //////////////////////////////////////////////////////////////////////////////////////////