]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/comp/AliL3Compress.cxx
Made a new abstract base class; AliL3HoughBaseTransformer for different implementations
[u/mrichter/AliRoot.git] / HLT / comp / AliL3Compress.cxx
1 //$Id$
2
3 // Author: Anders Vestbo <mailto:vestbo$fi.uib.no>
4 //*-- Copyright &copy ASV
5
6 #include <stdio.h>
7 #include <stream.h>
8 #include <stdlib.h>
9 #include <TH1.h>
10 #include <TH2.h>
11 #include <TRandom.h>
12
13 #include "AliL3Compress.h"
14 #include "AliL3TrackArray.h"
15 #include "AliL3ModelTrack.h"
16 #include "AliL3Transform.h"
17 #include "AliL3MemHandler.h"
18 #ifdef use_aliroot
19 #include "AliL3FileHandler.h"
20 #endif
21 #include "bitio.h"
22
23 //_____________________________________________________________
24 //
25 //  AliL3Compress
26 //
27 // Class for compressing and uncompressing data.
28
29 ClassImp(AliL3Compress)
30
31 AliL3Compress::AliL3Compress()
32 {
33   fTracks=0;
34   SetBitNumbers(0,0,0,0);
35   fSlice =0;
36   fPatch=0;
37   fDigits=0;
38   fDPt=0;
39 }
40
41 AliL3Compress::AliL3Compress(Int_t slice,Int_t patch,Char_t *path)
42 {
43   fSlice=slice;
44   fPatch=patch;
45   SetBitNumbers(0,0,0,0);
46   fTracks=0;
47   fDigits=0;
48   fDPt=0;
49   sprintf(fPath,"%s",path);
50 }
51
52 AliL3Compress::~AliL3Compress()
53 {
54   if(fTracks)
55     delete fTracks;
56   if(fDigits)
57     delete [] fDigits;
58   if(fDPt)
59     delete [] fDPt;
60 }
61
62 void AliL3Compress::SetBitNumbers(Int_t pad,Int_t time,Int_t charge,Int_t shape)
63 {
64   fNumPadBits=pad;
65   fNumTimeBits=time;
66   fNumChargeBits=charge;
67   fNumShapeBits=shape;
68 }
69
70 void AliL3Compress::WriteFile(AliL3TrackArray *tracks)
71 {
72   Char_t fname[100];
73   sprintf(fname,"%s/tracks_m_%d_%d.raw",fPath,fSlice,fPatch);
74   FILE *file = fopen(fname,"w");
75   Short_t ntracks = tracks->GetNTracks();
76   //cout<<"Writing "<<ntracks<<" tracks to file"<<endl;
77     
78   Int_t count=0;
79   AliL3ClusterModel *clusters=0;
80   AliL3TrackModel *model=0;
81   for(Int_t i=0; i<ntracks; i++)
82     {
83       AliL3ModelTrack *track = (AliL3ModelTrack*)tracks->GetCheckedTrack(i);
84       if(!track) continue;
85             
86       track->FillModel();
87       model = track->GetModel();
88       if(model->fNClusters==0) continue;
89       clusters = track->GetClusters();
90       //cout<<"Writing "<<(int)model->fNClusters<<" clusters"<<endl;
91       if(fwrite(model,sizeof(AliL3TrackModel),1,file)!=1) break;
92       //cout<<"Writing "<<(int)model->fNClusters<<" clusters to file"<<endl;
93       if(fwrite(clusters,model->fNClusters*sizeof(AliL3ClusterModel),1,file)!=1) break;
94       //track->Print();
95       count++;
96       
97     }
98   cout<<"Wrote "<<count<<" tracks "<<endl;
99   fclose(file);
100 }
101
102 void AliL3Compress::ReadFile(Char_t which)
103 {
104   //Read the trackfile.
105
106   Char_t fname[100];
107   if(which == 'm')
108     sprintf(fname,"%s/tracks_m_%d_%d.raw",fPath,fSlice,fPatch);
109   else if(which == 'u')
110     sprintf(fname,"%s/tracks_u_%d_%d.raw",fPath,fSlice,fPatch);
111   else
112     {
113       cerr<<"AliL3Compress::ReadFile() : Wrong option"<<endl;
114       return;
115     }
116
117   FILE *file = fopen(fname,"r");
118   if(!file)
119     {
120       cerr<<"Cannot open file "<<fname<<endl;
121       return;
122     }
123
124   if(fTracks)
125     delete fTracks;
126   fTracks = new AliL3TrackArray("AliL3ModelTrack");
127   
128   cout<<"Reading file "<<fname<<endl;
129   while(!feof(file))
130     {
131       AliL3ModelTrack *track = (AliL3ModelTrack*)fTracks->NextTrack();
132       track->Init(fSlice,fPatch);
133       AliL3TrackModel *model = track->GetModel();
134       AliL3ClusterModel *clusters = track->GetClusters();
135       //cout<<"Reading model "<<(int)model<<endl;
136       if(fread(model,sizeof(AliL3TrackModel),1,file)!=1) break;
137       //cout<<"Reading clusters "<<(int)clusters<<endl;
138       if(fread(clusters,(model->fNClusters)*sizeof(AliL3ClusterModel),1,file)!=1) break;
139       //cout<<"Filling track"<<endl;
140       track->FillTrack();
141       //track->Print();
142     }
143
144   fTracks->RemoveLast();
145   cout<<"Read "<<fTracks->GetNTracks()<<" tracks from file"<<endl;
146   fclose(file);
147 }
148
149 void AliL3Compress::CompressFile()
150 {
151   if(fNumTimeBits==0)
152     {
153       cerr<<"AliL3Compress::CompressFile() : Bitnumbers not set"<<endl;
154       return;
155     }
156   
157   Char_t fname[100];
158   sprintf(fname,"%s/tracks_c_%d_%d.raw",fPath,fSlice,fPatch);
159   BIT_FILE *output = OpenOutputBitFile(fname);
160   
161   sprintf(fname,"%s/tracks_m_%d_%d.raw",fPath,fSlice,fPatch);
162   FILE *input = fopen(fname,"r");
163   if(!input)
164     {
165       cerr<<"AliL3Compress::CompressFile() : Error opening file: "<<fname<<endl;
166       return;
167     }
168
169   AliL3TrackModel track;
170   AliL3ClusterModel cluster;
171   Int_t temp;
172   Short_t power;
173   
174   Int_t timeo,pado,chargeo,shapeo;
175   timeo=pado=chargeo=shapeo=0;
176   while(!feof(input))
177     {
178       if(fread(&track,sizeof(AliL3TrackModel),1,input)!=1) break;
179       
180       if(output->mask != 0x80) //Write the current byte to file.
181         {
182           //cerr<<"\nAliL3Compress::CompressFile() : Writing overhead bits!!!"<<endl;
183           if(putc(output->rack,output->file )!=output->rack)
184             cerr<<"AliL3Compress::ComressFile : Error writing to bitfile"<<endl;
185           output->mask=0x80;
186           output->rack=0;
187         }
188       
189       //Write track parameters:
190       fwrite(&track,sizeof(AliL3TrackModel),1,output->file);
191       for(Int_t i=0; i<track.fNClusters; i++)
192         {
193           if(fread(&cluster,sizeof(AliL3ClusterModel),1,input)!=1) break;
194           
195           //Write empty flag:
196           temp = (Int_t)cluster.fPresent;
197           OutputBit(output,temp);
198           if(!temp) continue;
199           
200           //Write time information:
201           temp = (Int_t)cluster.fDTime;
202           if(temp<0)
203             OutputBit(output,0);
204           else
205             OutputBit(output,1);
206           power = 1<<(fNumTimeBits-1);
207           if(abs(temp)>=power)
208             {
209               timeo++;
210               temp=power - 1;
211             }
212           OutputBits(output,abs(temp),(fNumTimeBits-1));
213           
214           //Write pad information:
215           temp = (Int_t)cluster.fDPad;
216           if(temp<0)
217             OutputBit(output,0);
218           else
219             OutputBit(output,1);
220           power = 1<<(fNumPadBits-1);
221           if(abs(temp)>=power)
222             {
223               pado++;
224               temp=power - 1;
225             }
226           OutputBits(output,abs(temp),(fNumPadBits-1));
227           
228           //Write charge information:
229           temp = (Int_t)cluster.fDCharge;
230           if(temp<0)
231             OutputBit(output,0);
232           else
233             OutputBit(output,1);
234           power = 1<<(fNumChargeBits-1);
235           if(abs(temp)>=power)
236             {
237               chargeo++;
238               temp=power - 1;
239             }
240           OutputBits(output,abs(temp),(fNumChargeBits-1));
241                   
242           //Write shape information:
243           temp = (Int_t)cluster.fDSigmaY2;
244           power = 1<<fNumShapeBits;
245           if(abs(temp) >= power)
246             {
247               shapeo++;
248               temp = power - 1;
249             }
250           OutputBits(output,abs(temp),fNumShapeBits);
251           
252           temp = (Int_t)cluster.fDSigmaZ2;
253           if(abs(temp) >= power)
254             {
255               shapeo++;
256               temp=power - 1;
257             }
258           OutputBits(output,abs(temp),fNumShapeBits);
259         }
260     }
261   
262   fclose(input);
263   CloseOutputBitFile(output);
264
265   cout<<endl<<"There was following number of overflows: "<<endl
266       <<"Pad "<<pado<<endl
267       <<"Time "<<timeo<<endl
268       <<"Charge "<<chargeo<<endl
269       <<"Shape "<<shapeo<<endl;
270 }
271
272 void AliL3Compress::ExpandFile()
273 {
274   if(fNumTimeBits==0)
275     {
276       cerr<<"AliL3Compress::ExpandFile() : Bitnumbers not set"<<endl;
277       return;
278     }
279   
280   Char_t fname[100];
281   sprintf(fname,"%s/tracks_c_%d_%d.raw",fPath,fSlice,fPatch);
282   BIT_FILE *input = OpenInputBitFile(fname);
283   
284   sprintf(fname,"%s/tracks_u_%d_%d.raw",fPath,fSlice,fPatch);
285   FILE *output = fopen(fname,"w");
286   if(!output)
287     {
288       cerr<<"AliL3Compress::ExpandFile() : Error opening file: "<<fname<<endl;
289       return;
290     }
291
292   AliL3TrackModel trackmodel;
293   AliL3ClusterModel *clusters=0;
294   Int_t count=0;
295   
296   clusters = new AliL3ClusterModel[(NumRows[fPatch])];
297   while(!feof(input->file))
298     {
299       input->mask=0x80;//make sure we read a new byte from file.
300       
301       //Read and write track:
302       if(fread(&trackmodel,sizeof(AliL3TrackModel),1,input->file)!=1) break;
303       fwrite(&trackmodel,sizeof(AliL3TrackModel),1,output);
304       
305       for(Int_t i=0; i<NumRows[fPatch]; i++)
306         {
307           Int_t temp,sign;
308           
309           //Read empty flag:
310           temp = InputBit(input);
311           if(!temp) 
312             {
313               clusters[i].fPresent=kFALSE;
314               continue;
315             }
316           clusters[i].fPresent=kTRUE;
317           
318           //Read time information:
319           sign=InputBit(input);
320           temp = InputBits(input,(fNumTimeBits-1));
321           if(!sign)
322             temp*=-1;
323           clusters[i].fDTime = temp;
324           
325           //Read pad information:
326           sign=InputBit(input);
327           temp = InputBits(input,(fNumPadBits-1));
328           if(!sign)
329             temp*=-1;
330           clusters[i].fDPad = temp;
331           
332           //Read charge information:
333           sign = InputBit(input);
334           temp=InputBits(input,(fNumChargeBits-1));
335           if(!sign)
336             temp*=-1;
337           clusters[i].fDCharge = temp;
338           
339           //Read shape information:
340           temp = InputBits(input,fNumShapeBits);
341           clusters[i].fDSigmaY2 = temp;
342           
343           temp = InputBits(input,fNumShapeBits);
344           clusters[i].fDSigmaZ2 = temp;
345         }
346       
347
348       count++;
349       fwrite(clusters,(trackmodel.fNClusters)*sizeof(AliL3ClusterModel),1,output);
350       
351     }
352   
353   delete [] clusters;
354   fclose(output);
355   CloseInputBitFile(input);
356 }
357
358 void AliL3Compress::CreateDigitArray(Int_t maxnumber)
359 {
360   fNUsed=0;
361   fNDigits = 0;
362   fMaxDigits=maxnumber;
363   if(fDigits) delete [] fDigits;
364   fDigits = new AliL3RandomDigitData[maxnumber];
365   if(fDPt) delete [] fDPt;
366   fDPt = new AliL3RandomDigitData*[maxnumber];
367 }
368
369 void AliL3Compress::RestoreData()
370 {
371   
372   //Read the uncompressed file:
373   ReadFile('u');
374   
375   CreateDigitArray(100000);
376   
377   Float_t pad,time,sigmaY2,sigmaZ2;
378   Int_t charge;
379   for(Int_t j=NRows[fPatch][0]; j<=NRows[fPatch][1]; j++)
380     {
381       cout<<"Building clusters on row "<<j<<endl;
382       for(Int_t i=0; i<fTracks->GetNTracks(); i++)
383         {
384           AliL3ModelTrack *track = (AliL3ModelTrack*)fTracks->GetCheckedTrack(i);
385           if(!track) continue;
386           if(!track->GetPad(j,pad) || 
387              !track->GetTime(j,time) || 
388              !track->GetClusterCharge(j,charge) ||
389              !track->GetXYWidth(j,sigmaY2) || 
390              !track->GetZWidth(j,sigmaZ2))
391             continue;
392           
393           CreateDigits(j,pad,time,charge,sigmaY2,sigmaZ2);
394         }
395     }
396   
397   QSort(fDPt,0,fNDigits);
398 }
399
400 void AliL3Compress::PrintDigits()
401 {
402   Int_t pad,time,charge,row;
403   for(Int_t i=0; i<fNDigits; i++)
404     {
405       row = fDPt[i]->fRow;
406       pad = fDPt[i]->fPad;
407       time = fDPt[i]->fTime;
408       charge = fDPt[i]->fCharge;
409       if(i>0 && row != fDPt[i-1]->fRow)
410         cout<<"---Padrow "<<row<<"---"<<endl;
411       cout<<"Pad "<<pad<<" time "<<time<<" charge "<<charge<<endl;
412     }
413 }
414
415 void AliL3Compress::WriteRestoredData()
416 {
417   Char_t fname[100];
418   
419   //Get the remaining raw data array:
420   AliL3MemHandler *mem = new AliL3MemHandler();
421   sprintf(fname,"%s/remains_%d_%d.raw",fPath,fSlice,fPatch);
422   mem->SetBinaryInput(fname);
423   UInt_t numdigits;
424   AliL3DigitRowData *origRow = mem->CompBinary2Memory(numdigits);
425   mem->CloseBinaryInput();
426   
427   //Allocate memory for the merged data:
428   UInt_t size = mem->GetAllocatedSize() + fNDigits*sizeof(AliL3DigitData);
429   cout<<"Allocating "<<size<<" bytes for merged data array "<<endl;
430   Byte_t *data = new Byte_t[size];
431   memset(data,0,size);
432   AliL3DigitRowData *tempRow = (AliL3DigitRowData*)data;
433
434   Int_t ndigits,action,charge;
435   UShort_t pad,time;
436       
437   UInt_t digit_counter;
438   Int_t row_counter=0;
439   for(Int_t i=NRows[fPatch][0]; i<=NRows[fPatch][1]; i++)
440     {
441       tempRow->fRow = i;
442       ndigits=0;
443       AliL3DigitData *origDig = origRow->fDigitData;
444       AliL3DigitData *tempDig = tempRow->fDigitData;
445       if((Int_t)origRow->fRow != i)
446         cerr<<"AliL3Compress::WriteRestoredData() : Mismatching row numbering "<<(Int_t)origRow->fRow<<" "<<i<<endl;
447
448       //cout<<"Writing row "<<i<<" with "<<(Int_t)origRow->fNDigit<<" old digits"<<endl;
449       digit_counter=0;
450       
451       while(1)
452         {
453           while(digit_counter < origRow->fNDigit)
454             {
455               pad = origDig[digit_counter].fPad;
456               time = origDig[digit_counter].fTime;
457               charge = origDig[digit_counter].fCharge;
458               digit_counter++;
459               while((action=ComparePoints(i,pad,time)) == 1)
460                 {
461                   tempDig[ndigits].fPad = fDPt[fNUsed]->fPad;
462                   tempDig[ndigits].fTime = fDPt[fNUsed]->fTime;
463                   tempDig[ndigits].fCharge = fDPt[fNUsed]->fCharge;
464                   ndigits++;
465                   fNUsed++;
466
467                 }
468               if(action == 0)
469                 {
470                   tempDig[ndigits].fPad = pad;
471                   tempDig[ndigits].fTime = time;
472                   tempDig[ndigits].fCharge = charge;
473                   ndigits++;
474                 }
475             }
476           
477           if(fNUsed >= fNDigits) 
478             break;
479           if(fDPt[fNUsed]->fRow != i) //we are on a new row
480             break;
481           tempDig[ndigits].fPad = fDPt[fNUsed]->fPad;
482           tempDig[ndigits].fTime = fDPt[fNUsed]->fTime;
483           tempDig[ndigits].fCharge = fDPt[fNUsed]->fCharge;
484           ndigits++;
485           fNUsed++;
486         }
487       //cout<<"Writing "<<ndigits<<" digits on row "<<i<<endl;
488       if(ndigits < 4)
489         {
490           row_counter++;
491           cout<<"Few digits on row "<<i<<endl;
492         }
493       tempRow->fNDigit = ndigits;
494       Int_t size = sizeof(AliL3DigitData)*tempRow->fNDigit + sizeof(AliL3DigitRowData);
495       Byte_t *byte_pt = (Byte_t*)tempRow;
496       byte_pt += size;
497       tempRow = (AliL3DigitRowData*)byte_pt;
498       mem->UpdateRowPointer(origRow);
499     }
500   
501   if(row_counter != NumRows[fPatch])
502     cerr<<"AliL3Compress::WriteRestoredData() : Written rows: "<<row_counter<<" total rows "<<NumRows[fPatch]<<endl;
503   
504   mem->Free();  
505   sprintf(fname,"%s/restored_%d_%d.raw",fPath,fSlice,fPatch);
506   mem->SetBinaryOutput(fname);
507   mem->Memory2CompBinary((UInt_t)NumRows[fPatch],(AliL3DigitRowData*)data);
508   mem->CloseBinaryOutput();
509   
510   delete [] data;
511   delete mem;
512   
513 }
514
515 void AliL3Compress::CreateDigits(Int_t row,Float_t pad,Float_t time,Int_t charge,Float_t sigmaY2,Float_t sigmaZ2)
516 {
517   //Create raw data out of the cluster.
518   
519   AliL3Transform *tr = new AliL3Transform();
520   TRandom *random = new TRandom();
521   
522   Int_t entries=1000;
523   TH1F *hist1 = new TH1F("hist1","",tr->GetNPads(row),0,tr->GetNPads(row)-1);
524   TH1F *hist2 = new TH1F("hist2","",tr->GetNTimeBins(),0,tr->GetNTimeBins()-1);
525   TH2F *hist3 = new TH2F("hist3","",tr->GetNPads(row),0,tr->GetNPads(row)-1,tr->GetNTimeBins(),0,tr->GetNTimeBins()-1);
526   
527   //Convert back the sigmas:
528   Float_t padw,timew;
529   if(fPatch < 3)
530     padw = tr->GetPadPitchWidthLow();
531   else
532     padw = tr->GetPadPitchWidthUp();
533   timew = tr->GetZWidth();
534
535   if(fPatch < 3)
536     sigmaY2 = sigmaY2/2.07;
537   sigmaY2 = sigmaY2/0.108;
538   sigmaY2 = sigmaY2/(padw*padw);
539   sigmaY2 = sigmaY2 - 1./12;
540   
541   if(fPatch < 3)
542     sigmaZ2 = sigmaZ2/1.77;
543   sigmaZ2 = sigmaZ2/0.169;
544   sigmaZ2 = sigmaZ2/(timew*timew);
545   sigmaZ2 = sigmaZ2 - 1./12;
546   
547   if(sigmaY2 <= 0 || sigmaZ2 <= 0)
548     {
549       cerr<<"AliL3Compress::CreateDigits() : Wrong sigmas : "<<sigmaY2<<" "<<sigmaZ2;
550       cerr<<" on row "<<row<<" pad "<<pad<<" time "<<time<<endl;
551       return;
552     }
553   
554   //Create the distributions in pad and time:
555   for(Int_t i=0; i<entries; i++)
556     {
557       hist1->Fill(random->Gaus(pad,sqrt(sigmaY2)));
558       hist2->Fill(random->Gaus(time,sqrt(sigmaZ2)));
559     }
560     
561   //Create the cluster:
562   Int_t bin1,bin2;
563   Double_t content1,content2,dpad,dtime;
564   for(Int_t i=0; i<hist1->GetEntries(); i++)
565     {
566       bin1 = hist1->GetBin(i);
567       content1 = hist1->GetBinContent(bin1);
568       if((Int_t)content1==0) continue;
569       content1 = charge*content1/entries;
570       dpad = hist1->GetBinCenter(bin1);
571       for(Int_t j=0; j<hist2->GetEntries(); j++)
572         {
573           bin2 = hist2->GetBin(j);
574           content2 = hist2->GetBinContent(bin2);
575           if((Int_t)content2==0) continue;
576           content2 = content1*content2/entries;
577           dtime = hist2->GetBinCenter(bin2);
578           hist3->Fill(dpad,dtime,content2);
579         }
580     }
581   
582   //Fill it into the digit array:
583   for(Int_t i=0; i<hist3->GetNbinsX(); i++)
584     {
585       for(Int_t j=0; j<hist3->GetNbinsY(); j++)
586         {
587           bin1 = hist3->GetBin(i,j);
588           content1 = hist3->GetBinContent(bin1);
589           if((Int_t)content1 < 3) continue;
590           if(content1 >= 1024)
591             content1 = 1023;
592           if(fNDigits >= fMaxDigits)
593             {
594               cerr<<"AliL3Compress::CreateDigits() : Array index out of range : "<<fNDigits<<endl;
595               return;
596             }
597           fDigits[fNDigits].fCharge=(Int_t)content1;
598           fDigits[fNDigits].fRow = row;
599           fDigits[fNDigits].fPad = (Int_t)hist3->GetXaxis()->GetBinCenter(i);
600           fDigits[fNDigits].fTime = (Int_t)hist3->GetYaxis()->GetBinCenter(j);
601           fDPt[fNDigits] = &fDigits[fNDigits];
602           fNDigits++;
603         }
604     }
605   
606   delete random;
607   delete hist1;
608   delete hist2;
609   delete hist3;
610   delete tr;
611 }
612
613 void AliL3Compress::PrintCompRatio()
614 {
615   Char_t fname[100];
616   sprintf(fname,"%s/remains_%d_%d.raw",fPath,fSlice,fPatch);
617   AliL3MemHandler *mem = new AliL3MemHandler();
618   if(!mem->SetBinaryInput(fname))
619     {
620       cerr<<"AliL3Compress::PrintCompRatio(): Error opening file: "<<fname<<endl;
621       return;
622     } 
623   UInt_t ndigits;
624   AliL3DigitRowData *rowPt = (AliL3DigitRowData*)mem->CompBinary2Memory(ndigits);
625   mem->CloseBinaryInput();
626
627   Int_t digit_counter=0;
628   for(Int_t i=NRows[fPatch][0]; i<=NRows[fPatch][1]; i++)
629     {
630       digit_counter += rowPt->fNDigit;
631       mem->UpdateRowPointer(rowPt);
632     }
633   delete mem;
634   
635   sprintf(fname,"%s/tracks_c_%d_%d.raw",fPath,fSlice,fPatch);
636   FILE *file1 = fopen(fname,"r");
637   if(!file1)
638     {
639       cerr<<"AliL3Compress::PrintCompRatio(): Error opening file: "<<fname<<endl;
640       return;
641     }
642   fseek(file1,0,SEEK_END);
643   UInt_t filesize1 = (UInt_t)ftell(file1);
644   fclose(file1);
645   
646   sprintf(fname,"%s/digits_%d_%d.raw",fPath,fSlice,fPatch);
647   FILE *file2 = fopen(fname,"r");
648   if(!file2)
649     {
650       cerr<<"AliL3Compress::PrintCompRatio(): Error opening file: "<<fname<<endl;
651       return;
652     }
653   fseek(file2,0,SEEK_END);
654   UInt_t filesize2 = (UInt_t)ftell(file2);
655   fclose(file2);
656   
657   cout<<"----------------------"<<endl;
658   cout<<"Original file size   : "<<filesize2<<endl;
659   cout<<"Compressed file size : "<<filesize1<<endl;
660   cout<<"Remaining digits     : "<<digit_counter<<endl;
661   cout<<"Compression ratio    : "<<(Float_t)(filesize1 + (10*digit_counter)/8)/(Float_t)(filesize2)<<endl;
662   
663 }
664
665 void AliL3Compress::QSort(AliL3RandomDigitData **a, Int_t first, Int_t last)
666 {
667   
668   // Sort array of AliL3RandomDigitData pointers using a quicksort algorithm.
669   // Uses CompareDigits() to compare objects.
670   // Thanks to Root!
671   
672   static AliL3RandomDigitData *tmp;
673   static int i;           // "static" to save stack space
674   int j;
675   
676   while (last - first > 1) {
677     i = first;
678     j = last;
679     for (;;) {
680       while (++i < last && CompareDigits(a[i], a[first]) < 0)
681         ;
682       while (--j > first && CompareDigits(a[j], a[first]) > 0)
683         ;
684       if (i >= j)
685         break;
686       
687       tmp  = a[i];
688       a[i] = a[j];
689       a[j] = tmp;
690     }
691     if (j == first) {
692       ++first;
693       continue;
694     }
695     tmp = a[first];
696     a[first] = a[j];
697     a[j] = tmp;
698     if (j - first < last - (j + 1)) {
699       QSort(a, first, j);
700       first = j + 1;   // QSort(j + 1, last);
701     } else {
702       QSort(a, j + 1, last);
703       last = j;        // QSort(first, j);
704     }
705   }
706 }
707
708 void AliL3Compress::WriteRootFile(Char_t *digitsfile,Char_t *rootfile)
709 {
710 #ifdef use_aliroot
711   Char_t fname[100];
712   AliL3MemHandler *mem = new AliL3MemHandler();
713   sprintf(fname,"%s/restored_%d_%d.raw",fPath,fSlice,fPatch);
714   mem->SetBinaryInput(fname);
715   UInt_t ndigits;
716   AliL3DigitRowData *rowPt = (AliL3DigitRowData*)mem->CompBinary2Memory(ndigits);
717   mem->CloseBinaryInput();
718
719   AliL3FileHandler *file = new AliL3FileHandler();
720   if(!file->SetAliInput(digitsfile))
721     {
722       cerr<<"AliL3Compress::WriteRootFile() : Error opening file: "<<digitsfile<<endl;
723       return;
724     }
725   file->Init(fSlice,fPatch,NRows[fPatch]);
726   file->AliDigits2RootFile(rowPt,rootfile);
727   file->CloseAliInput();
728
729   delete mem;
730   delete file;
731 #endif
732
733   return;
734 }