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