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