This commit was generated by cvs2svn to compensate for changes in r23278,
[u/mrichter/AliRoot.git] / CORRFW / AliCFGrid.cxx
1 /* $Id$ */
2
3 //--------------------------------------------------------------------//
4 //                                                                    //
5 // AliCFGrid Class                                                 //
6 // Class to accumulate data on an N-dimensional grid, to be used      //
7 // as input to get corrections for Reconstruction & Trigger efficiency// 
8 //                                                                    //
9 // -- Author : S.Arcelli                                              //
10 // Still to be done:                                                  //
11 // --Implement methods to merge cells                                 //
12 // --Interpolate among bins in a range                                // 
13 //--------------------------------------------------------------------//
14 //
15 //
16 #include <AliLog.h>
17 #include "AliCFGrid.h"
18 #include "TMath.h"
19 #include "TROOT.h"
20 #include "TH1F.h"
21 #include "TH2F.h"
22 #include "TH3F.h"
23
24 //____________________________________________________________________
25 ClassImp(AliCFGrid)
26
27 //____________________________________________________________________
28 AliCFGrid::AliCFGrid() : 
29   AliCFFrame(),
30   fSumW2(kFALSE),
31   fNunflTot(0),
32   fNovflTot(0),
33   fNentriesTot(0),
34   fNunfl(0x0),
35   fNovfl(0x0),
36   fData(0x0),
37   fErr2(0x0)
38 {
39   // default constructor
40 }
41 //____________________________________________________________________
42 AliCFGrid::AliCFGrid(const Char_t* name, const Char_t* title) : 
43   AliCFFrame(name,title),
44   fSumW2(kFALSE),
45   fNunflTot(0),
46   fNovflTot(0),
47   fNentriesTot(0),
48   fNunfl(0x0),
49   fNovfl(0x0),
50   fData(0x0),
51   fErr2(0x0)
52 {
53   // default constructor
54 }
55
56 //____________________________________________________________________
57 AliCFGrid::AliCFGrid(const Char_t* name, const Char_t* title, const Int_t nVarIn, const Int_t * nBinIn, const Float_t *binLimitsIn) :  
58   AliCFFrame(name,title,nVarIn,nBinIn,binLimitsIn),
59   fSumW2(kFALSE),
60   fNunflTot(0),
61   fNovflTot(0),
62   fNentriesTot(0),
63   fNunfl(0x0),
64   fNovfl(0x0),
65   fData(0x0),
66   fErr2(0x0)
67 {
68   //
69   // main constructor
70   //
71
72
73   //The underflows
74   fNunfl=new Float_t[fNVar];
75   fNovfl= new Float_t[fNVar];
76
77
78   // the grid
79  
80   fData = new Float_t[fNDim]; //num
81
82   //Initialization
83  
84   for(Int_t i = 0;i<fNDim;i++)fData[i]=0;
85
86   fNunflTot =0;
87   fNovflTot =0;
88   fNentriesTot =0;
89   for(Int_t j=0;j<fNVar;j++){
90     fNunfl[j] =0;
91     fNovfl[j] =0;
92   }
93 }
94
95 //____________________________________________________________________
96 AliCFGrid::AliCFGrid(const AliCFGrid& c) : 
97   AliCFFrame(),
98   fSumW2(kFALSE),
99   fNunflTot(0),
100   fNovflTot(0),
101   fNentriesTot(0),
102   fNunfl(0x0),
103   fNovfl(0x0),
104   fData(0x0),
105   fErr2(0x0)
106 {
107   //
108   // copy constructor
109   //
110   ((AliCFGrid &)c).Copy(*this);
111 }
112
113 //____________________________________________________________________
114 AliCFGrid::~AliCFGrid()
115 {
116   //
117   // destructor
118   //
119   delete fData;
120   if(fSumW2)delete fErr2;
121   delete fNunfl;
122   delete fNovfl;
123
124 }
125
126 //____________________________________________________________________
127 AliCFGrid &AliCFGrid::operator=(const AliCFGrid &c)
128 {
129   //
130   // assigment operator
131   //
132   if (this != &c)
133     ((AliCFGrid &) c).Copy(*this);
134   return *this;
135
136 //____________________________________________________________________
137 Float_t AliCFGrid::GetElement(Int_t bin) const
138 {
139   //
140   // Returns grid element bin
141   //
142   if(bin>=fNDim){
143     AliInfo(Form(" element index outside the grid, return -1"));
144     return -1.;
145   }
146   return fData[bin];
147 }
148 //____________________________________________________________________
149 Float_t AliCFGrid::GetElement(Int_t *bin) const
150 {
151  //
152   // Get the content in a bin corresponding to a set of bin indexes
153   //
154     Int_t ind =GetBinIndex(bin);
155     return GetElement(ind);
156 }  
157 //____________________________________________________________________
158 Float_t AliCFGrid::GetElement(Float_t *var) const
159 {
160   //
161   // Get the content in a bin corresponding to a set of input variables
162   //
163   Int_t unfl=0;  
164   Int_t ovfl=0;  
165   for(Int_t i=0;i<fNVar;i++){
166     Int_t nbins=fNVarBins[i]+1;
167     Float_t *bins=new Float_t[nbins];
168     for(Int_t ibin =0;ibin<nbins;ibin++){
169      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
170     }
171
172     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
173
174     //underflows
175
176     if(var[i] < bins[0]){
177       unfl=1;
178     }
179
180     //overflows
181
182     if(var[i] > bins[nbins-1]){
183       ovfl=1;
184     }
185     delete [] bins;
186   }
187
188   if(!(ovfl==1 || unfl==1)){
189     return GetElement(fIndex);
190   }
191   else{
192     AliInfo(Form(" input variables outside the grid, return -1"));
193     return -1.;
194   }
195
196 //____________________________________________________________________
197 Float_t AliCFGrid::GetElementError(Int_t iel) const
198 {
199   //
200   // Return the squared error on grid element iel
201   //
202   if(iel>=fNDim){
203     AliInfo(Form(" element index outside the grid, return -1"));
204     return -1.;
205   }
206   if(fSumW2)return fErr2[iel];
207   return fData[iel];
208 }
209 //____________________________________________________________________
210 Float_t AliCFGrid::GetElementError(Int_t *bin) const
211 {
212   //
213   // Get the squared error in a bin corresponding to a set of bin indeces
214   //
215     Int_t ind =GetBinIndex(bin);
216     return GetElementError(ind);
217
218 }
219 //____________________________________________________________________
220 Float_t AliCFGrid::GetElementError(Float_t *var) const
221 {
222   //
223   // Get the squared error in a bin corresponding to a set of input variables
224   //
225   Int_t unfl=0;  
226   Int_t ovfl=0;  
227   for(Int_t i=0;i<fNVar;i++){
228     Int_t nbins=fNVarBins[i]+1;
229     Float_t *bins=new Float_t[nbins];
230     for(Int_t ibin =0;ibin<nbins;ibin++){
231      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
232     }
233
234     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
235     //underflows
236
237     if(var[i] < bins[0]){
238       unfl=1;
239     }
240
241     //overflows
242
243     if(var[i] > bins[nbins-1]){
244       ovfl=1;
245     }
246     delete [] bins;
247   }
248
249   if(!(ovfl==1 || unfl==1)){
250     return GetElementError(fIndex);
251   }
252   else{
253     AliInfo(Form(" input variables outside the grid, return -1"));
254     return -1.;
255   }
256
257 //____________________________________________________________________
258 void AliCFGrid::SetElement(Int_t iel, Float_t val)
259 {
260   //
261   // Sets grid element iel to val
262   //
263   if(iel>=fNDim){
264     AliInfo(Form(" element index outside the grid, no value set"));
265   }else {
266     fData[iel]=val;
267   }
268 }
269 //____________________________________________________________________
270 void AliCFGrid::SetElement(Int_t *bin, Float_t val)
271 {
272   //
273   // Sets grid element of bin indeces bin to val
274   //
275     Int_t ind =GetBinIndex(bin);
276     SetElement(ind,val);
277 }
278 //____________________________________________________________________
279 void AliCFGrid::SetElement(Float_t *var, Float_t val) 
280 {
281   //
282   // Set the content in a bin to value val corresponding to a set of input variables
283   //
284   Int_t unfl=0;  
285   Int_t ovfl=0;  
286   for(Int_t i=0;i<fNVar;i++){
287     Int_t nbins=fNVarBins[i]+1;
288     Float_t *bins=new Float_t[nbins];
289     for(Int_t ibin =0;ibin<nbins;ibin++){
290      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
291     }
292
293     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
294     //underflows
295
296     if(var[i] < bins[0]){
297       unfl=1;
298     }
299
300     //overflows
301
302     if(var[i] > bins[nbins-1]){
303       ovfl=1;
304     }
305     delete [] bins;
306   }
307
308   if(!(ovfl==1 || unfl==1)){
309     SetElement(fIndex,val);
310   }
311   else{
312     AliInfo(Form(" input variables outside the grid, no value set"));
313   }
314
315 //____________________________________________________________________
316 void AliCFGrid::SetElementError(Int_t iel, Float_t val) 
317 {
318   //
319   // Set squared error to val on grid element iel
320   //
321   if(iel>=fNDim){
322     AliInfo(Form(" element index outside the grid, no value set"));
323     return;
324   }
325   if(!fErr2)SumW2();
326   fErr2[iel]=val;   
327 }
328 //____________________________________________________________________
329 void AliCFGrid::SetElementError(Int_t *bin, Float_t val) 
330 {
331   //
332   // Set squared error to val on grid element of bin indeces bin
333   //
334     Int_t ind =GetBinIndex(bin);
335     SetElementError(ind,val);
336 }
337 //____________________________________________________________________
338 void AliCFGrid::SetElementError(Float_t *var, Float_t val)
339 {
340   //
341   // Set squared error to val in a bin corresponding to a set of input variables
342   //
343   Int_t unfl=0;  
344   Int_t ovfl=0;  
345   for(Int_t i=0;i<fNVar;i++){
346     Int_t nbins=fNVarBins[i]+1;
347     Float_t *bins=new Float_t[nbins];
348     for(Int_t ibin =0;ibin<nbins;ibin++){
349      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
350     }
351
352     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
353     //underflows
354
355     if(var[i] < bins[0]){
356       unfl=1;
357     }
358
359     //overflows
360
361     if(var[i] > bins[nbins-1]){
362       ovfl=1;
363     }
364     delete [] bins;
365   }
366
367   if(!(ovfl==1 || unfl==1)){
368     SetElementError(fIndex,val);
369   }
370   else{
371     AliInfo(Form(" input variables outside the grid, no value set"));
372   }
373
374 //____________________________________________________________________
375 void AliCFGrid::Scale(Int_t iel, Float_t *fact)
376 {
377   //
378   //scale content of a certain cell by (positive) fact (with error)
379   //
380   if(iel>=fNDim){
381     AliInfo(Form(" element index outside the grid, no scaling"));
382     return;
383   }
384   Float_t el,del,elsc,delsc;  
385   if(GetElement(iel)>0 && fact[0]>0){
386     el=GetElement(iel);
387     del=TMath::Sqrt(GetElementError(iel));
388     elsc=el*fact[0];
389     delsc=TMath::Sqrt(del*del/el/el
390                     +fact[1]*fact[1]/fact[0]/fact[0])
391       *elsc;
392     SetElement(iel,elsc);
393     if(fSumW2)SetElementError(iel,delsc*elsc);
394   }
395 }
396 //____________________________________________________________________
397 void AliCFGrid::Scale(Int_t *bin, Float_t *fact)
398 {
399   //
400   //scale content of a certain cell by (positive) fact (with error)
401   //
402   Int_t iel=GetBinIndex(bin);
403   Scale(iel,fact);
404 }
405 //____________________________________________________________________
406 void AliCFGrid::Scale(Float_t *var, Float_t *fact) 
407 {
408   //
409   //scale content of a certain cell by (positive) fact (with error)
410   //
411   Int_t unfl=0;  
412   Int_t ovfl=0;  
413   for(Int_t i=0;i<fNVar;i++){
414     Int_t nbins=fNVarBins[i]+1;
415     Float_t *bins=new Float_t[nbins];
416     for(Int_t ibin =0;ibin<nbins;ibin++){
417      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
418     }
419
420     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
421     //underflows
422
423     if(var[i] < bins[0]){
424       unfl=1;
425     }
426
427     //overflows
428
429     if(var[i] > bins[nbins-1]){
430       ovfl=1;
431     }
432     delete [] bins;
433   }
434
435   if(!(ovfl==1 || unfl==1)){
436     Int_t iel=GetBinIndex(fIndex);
437     Scale(iel,fact);
438   }
439   else{
440     AliInfo(Form(" input variables outside the grid, no scaling done"));
441   }
442 }
443 //____________________________________________________________________
444 void AliCFGrid::Scale( Float_t *fact) 
445 {
446   //
447   //scale contents of the whole grid by fact
448   //
449   for(Int_t iel=0;iel<fNDim;iel++){
450     Scale(iel,fact);
451   }
452 }
453 //____________________________________________________________________
454 void AliCFGrid::Fill(Float_t *var, Float_t weight)
455 {
456
457   //
458   // Fill the grid,
459   // given a set of values of the input variable, 
460   // with weight (by default w=1)
461   //
462
463   Int_t unfl=0;  
464   Int_t ovfl=0;  
465   for(Int_t i=0;i<fNVar;i++){
466     Int_t nbins=fNVarBins[i]+1;
467     Float_t *bins=new Float_t[nbins];
468     for(Int_t ibin =0;ibin<nbins;ibin++){
469      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
470     }
471
472     fIndex[i] = TMath::BinarySearch(nbins,bins,var[i]);
473     //underflows
474
475     if(var[i] < bins[0]){
476       unfl=1;
477       fNunfl[i]++;
478     }
479
480     //overflows
481
482     if(var[i] > bins[nbins-1]){
483       ovfl=1;
484       fNovfl[i]++;
485     }
486     delete [] bins;
487   }
488
489   // Total number of entries, overflows and underflows
490
491   fNentriesTot++;
492   if(unfl)fNunflTot++;
493   if(ovfl)fNovflTot++;
494
495   //if not ovfl/unfl, fill the element  
496   if(!(ovfl==1 || unfl==1)){
497     Int_t ind =GetBinIndex(fIndex);
498     fData[ind]+=weight;
499     if(fSumW2)fErr2[ind]+=(weight*weight);
500   }
501
502 //____________________________________________________________________
503 Float_t AliCFGrid::GetOverFlows( Int_t ivar) const {
504   //
505   // Get overflows in variable var 
506   //
507   return fNovfl[ivar];
508
509 //____________________________________________________________________
510 Float_t AliCFGrid::GetOverFlows() const {
511   //
512   // Get overflows 
513   //
514   return fNovflTot;
515
516 //____________________________________________________________________
517 Float_t AliCFGrid::GetUnderFlows( Int_t ivar) const {
518   //
519   // Get overflows in variable var 
520   //
521   return fNunfl[ivar];
522
523 //____________________________________________________________________
524 Float_t AliCFGrid::GetUnderFlows() const {
525   //
526   // Get overflows 
527   //
528   return fNunflTot;
529
530 //____________________________________________________________________
531 Float_t AliCFGrid::GetEntries( ) const {
532   //
533   // Get total entries (in grid + over/underflows) 
534   //
535   return fNentriesTot;
536
537 //____________________________________________________________________
538 Int_t AliCFGrid::GetEmptyBins() const {
539   //
540   // Get empty bins 
541   //
542   Int_t val=0;
543   for(Int_t i=0;i<fNDim;i++){
544     if(fData[i]<=0)val++;     
545   }
546   return val;
547
548 //_____________________________________________________________________
549 Int_t AliCFGrid::GetEmptyBins( Float_t *varMin, Float_t* varMax ) const 
550 {
551   //
552   // Get empty bins in a range
553   //
554
555   Int_t *indexMin=new Int_t[fNVar];
556   Int_t *indexMax=new Int_t[fNVar];
557
558   //Find out the min and max bins
559
560   for(Int_t i=0;i<fNVar;i++){
561     Float_t xmin=varMin[i]; // the min values  
562     Float_t xmax=varMax[i]; // the min values  
563     Int_t nbins=fNVarBins[i]+1;
564     Float_t *bins=new Float_t[nbins];
565     for(Int_t ibin =0;ibin<nbins;ibin++){
566      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
567     }
568     indexMin[i] = TMath::BinarySearch(nbins,bins,xmin);
569     indexMax[i] = TMath::BinarySearch(nbins,bins,xmax);
570     if(xmax>=bins[nbins-1]){
571       indexMax[i]=indexMax[i]-1;
572     }  
573     delete [] bins;
574   }
575
576   Int_t val=0;
577   for(Int_t i=0;i<fNDim;i++){
578     for (Int_t j=0;j<fNVar;j++)fIndex[j]=GetBinIndex(j,i);
579     Bool_t isIn=kTRUE;
580     for (Int_t j=0;j<fNVar;j++){
581       if(!(fIndex[j]>=indexMin[j] && fIndex[j]<=indexMax[j]))isIn=kFALSE;   
582     }
583     if(isIn && fData[i]<=0)val++;     
584   }
585   AliInfo(Form(" the empty bins = %i ",val)); 
586
587   delete [] indexMin;
588   delete [] indexMax;
589   return val;
590
591 //____________________________________________________________________
592 Int_t AliCFGrid::CheckEfficiencyStats(Float_t thr) const
593 {
594   //
595   // Count the cells below a certain threshold
596   //
597   Int_t ncellsLow=0;
598   for(Int_t i=0;i<fNDim;i++){
599     if(GetElement(i)<thr)ncellsLow++;
600   }
601   return ncellsLow;
602 }
603 //_____________________________________________________________________
604 Float_t AliCFGrid::GetIntegral() const 
605 {
606   //
607   // Get full Integral
608   //
609   Float_t val=0;
610   for(Int_t i=0;i<fNDim;i++){
611     val+=fData[i];     
612   }
613   return val;  
614
615 //_____________________________________________________________________
616 Float_t AliCFGrid::GetIntegral(Int_t *binMin, Int_t* binMax ) const 
617 {
618   //
619   // Get Integral in a range of bin indeces (extremes included)
620   //
621
622   Float_t val=0;
623   for(Int_t i=0;i<fNVar;i++){
624     if((binMin[i]<0) || (binMax[i]>=fNVarBins[i]) || (binMin[i]>binMax[i])){
625       AliInfo(Form(" Bin indeces in variable %i outside allowed range or in reverse order, please check!", i));
626       return val;
627     }
628   }
629   val=GetSum(0,binMin,binMax);
630   return val;
631
632 //_____________________________________________________________________
633 Float_t AliCFGrid::GetIntegral(Float_t *varMin, Float_t* varMax ) const 
634 {
635   //
636   // Get Integral in a range (extremes included)
637   //
638
639   Int_t *indexMin=new Int_t[fNVar];
640   Int_t *indexMax=new Int_t[fNVar];
641
642   //Find out the min and max bins
643
644   for(Int_t i=0;i<fNVar;i++){
645     Float_t xmin=varMin[i]; // the min values  
646     Float_t xmax=varMax[i]; // the min values  
647     Int_t nbins=fNVarBins[i]+1;
648     Float_t *bins=new Float_t[nbins];
649     for(Int_t ibin =0;ibin<nbins;ibin++){
650      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
651     }
652     indexMin[i] = TMath::BinarySearch(nbins,bins,xmin);
653     indexMax[i] = TMath::BinarySearch(nbins,bins,xmax);
654     if(xmax>=bins[nbins-1]){
655       indexMax[i]=indexMax[i]-1;
656     }  
657     delete [] bins;
658   }
659
660   Float_t val=GetIntegral(indexMin,indexMax);
661
662   delete [] indexMin;
663   delete [] indexMax;
664
665   return val;
666
667 //___________________________________________________________________
668 TH1F *AliCFGrid::Project(Int_t ivar) const
669 {
670   //
671   // Make a 1D projection along variable ivar 
672
673
674   Int_t nbins =fNVarBins[ivar];
675   Float_t *bins = new Float_t[nbins+1];    
676   for (Int_t i=0;i<=fNVar;i++){
677   }
678   for(Int_t ibin =0;ibin<nbins+1;ibin++){
679     bins[ibin] = fVarBinLimits[ibin+fOffset[ivar]];
680   }
681
682   char pname[40];
683   sprintf(pname,"%s%s_%i",GetName(),"_proj1D_var", ivar);
684   char htitle[40];
685   sprintf(htitle,"%s%s_%i",GetName(),"_proj1D_var", ivar);
686
687   TH1F *proj1D=0;
688
689   //check if a projection with identical name exist
690   TObject *obj = gROOT->FindObject(pname);
691   if (obj && obj->InheritsFrom("TH1F")) {
692     proj1D = (TH1F*)obj;
693     proj1D->Reset();
694   }
695
696   if(!proj1D){
697     proj1D =new TH1F(pname,htitle, nbins, bins);
698   }  
699
700   delete [] bins;
701   Float_t sum=0;
702   Float_t *data= new Float_t[nbins];
703   Float_t *err= new Float_t[nbins];
704   
705   for(Int_t ibin=0;ibin<nbins;ibin++)data[ibin]=0;
706   for(Int_t ibin=0;ibin<nbins;ibin++)err[ibin]=0;
707   for(Int_t iel=0;iel<fNDim;iel++){
708       data[GetBinIndex(ivar,iel)]+=fData[iel];
709       if(fSumW2)err[GetBinIndex(ivar,iel)]+=fErr2[iel];
710   }
711
712   for(Int_t ibin =0;ibin<nbins;ibin++){
713     proj1D->SetBinContent(ibin+1,data[ibin]);
714     proj1D->SetBinError(ibin+1,TMath::Sqrt(data[ibin]));
715     if(fSumW2)proj1D->SetBinError(ibin+1,TMath::Sqrt(err[ibin]));
716     sum+=data[ibin];
717   }
718
719   delete [] data;
720   delete [] err;
721   proj1D->SetBinContent(nbins+1,GetOverFlows(ivar));
722   proj1D->SetBinContent(0,GetUnderFlows(ivar));
723   proj1D->SetEntries(GetEntries());
724   return proj1D;
725
726
727 //___________________________________________________________________
728 TH2F *AliCFGrid::Project(Int_t ivar1, Int_t ivar2) const
729 {
730   //
731   // Make a 2D projection along variable ivar 
732
733   Int_t nbins1 =fNVarBins[ivar1];
734   Int_t nbins2 =fNVarBins[ivar2];
735
736   Float_t *bins1 = new Float_t[nbins1+1];         
737   Float_t *bins2 = new Float_t[nbins2+1];     
738
739   for(Int_t ibin =0;ibin<nbins1+1;ibin++){
740     bins1[ibin] = fVarBinLimits[ibin+fOffset[ivar1]];
741   }
742   for(Int_t ibin =0;ibin<nbins2+1;ibin++){
743     bins2[ibin] = fVarBinLimits[ibin+fOffset[ivar2]];
744   }
745
746   char pname[40];
747   sprintf(pname,"%s%s_%i_%i",GetName(),"_proj2D_var",ivar1,ivar2);
748   char htitle[40];
749   sprintf(htitle,"%s%s_%i_%i",GetName(),"_proj2D_var",ivar1,ivar2);
750
751   TH2F *proj2D=0;
752
753   //check if a projection with identical name exist
754   TObject *obj = gROOT->FindObject(pname);
755   if (obj && obj->InheritsFrom("TH2F")) {
756     proj2D = (TH2F*)obj;
757     proj2D->Reset();
758   }
759
760   if(!proj2D){
761     proj2D =new TH2F(pname,htitle, nbins1, bins1,nbins2,bins2);
762   }  
763
764   delete [] bins1;
765   delete [] bins2;
766
767
768   Float_t sum=0;
769   Float_t **data=new Float_t*[nbins1];
770   Float_t *data2=new Float_t[nbins1*nbins2];
771   Float_t **err=new Float_t*[nbins1];
772   Float_t *err2=new Float_t[nbins1*nbins2];
773   for(Int_t i=0;i<nbins1;i++)data[i] = data2+i*nbins2;
774   for(Int_t i=0;i<nbins1;i++)err[i] = err2+i*nbins2;
775
776   for(Int_t ibin1 =0;ibin1<nbins1;ibin1++){
777     for(Int_t ibin2 =0;ibin2<nbins2;ibin2++){
778       data[ibin1][ibin2]=0;
779       err[ibin1][ibin2]=0;
780     }
781   }
782
783   for(Int_t iel=0;iel<fNDim;iel++){
784     data[GetBinIndex(ivar1,iel)][GetBinIndex(ivar2,iel)]+=fData[iel];
785     if(fSumW2)err[GetBinIndex(ivar1,iel)][GetBinIndex(ivar2,iel)]+=fErr2[iel];
786   }
787
788   for(Int_t ibin1 =0;ibin1<nbins1;ibin1++){
789     for(Int_t ibin2 =0;ibin2<nbins2;ibin2++){
790       proj2D->SetBinContent(ibin1+1,ibin2+1,data[ibin1][ibin2]);
791       proj2D->SetBinError(ibin1+1,ibin2+1,TMath::Sqrt(data[ibin1][ibin2]));
792       if(fSumW2)proj2D->SetBinError(ibin1+1,ibin2+1,TMath::Sqrt(err[ibin1][ibin2]));
793       sum+=data[ibin1][ibin2];
794     }
795
796   } 
797   delete data;
798   delete data2;
799   delete err;
800   delete err2;
801   proj2D->SetBinContent(0,nbins2/2,GetUnderFlows(ivar1));
802   proj2D->SetBinContent(nbins1+1,nbins2/2,GetOverFlows(ivar1));
803   proj2D->SetBinContent(nbins1/2,0,GetUnderFlows(ivar2));
804   proj2D->SetBinContent(nbins1/2,nbins2+1,GetOverFlows(ivar2));
805   proj2D->SetEntries(GetEntries());
806   return proj2D;
807
808 //___________________________________________________________________
809 TH3F *AliCFGrid::Project(Int_t ivar1, Int_t ivar2, Int_t ivar3) const
810 {
811   //
812   // Make a 3D projection along variable ivar 
813
814   Int_t nbins1 =fNVarBins[ivar1];
815   Int_t nbins2 =fNVarBins[ivar2];
816   Int_t nbins3 =fNVarBins[ivar3];
817
818   Float_t *bins1 = new Float_t[nbins1+1];         
819   Float_t *bins2 = new Float_t[nbins2+1];     
820   Float_t *bins3 = new Float_t[nbins3+1];     
821
822   for(Int_t ibin =0;ibin<nbins1+1;ibin++){
823     bins1[ibin] = fVarBinLimits[ibin+fOffset[ivar1]];
824   }
825   for(Int_t ibin =0;ibin<nbins2+1;ibin++){
826     bins2[ibin] = fVarBinLimits[ibin+fOffset[ivar2]];
827   }
828   for(Int_t ibin =0;ibin<nbins3+1;ibin++){
829     bins3[ibin] = fVarBinLimits[ibin+fOffset[ivar3]];
830   }
831
832   char pname[40];
833   sprintf(pname,"%s%s_%i_%i_%i",GetName(),"_proj3D_var",ivar1,ivar2,ivar3);
834   char htitle[40];
835   sprintf(htitle,"%s%s_%i_%i_%i",GetName(),"_proj3D_var",ivar1,ivar2,ivar3);
836
837   TH3F *proj3D=0;
838
839   //check if a projection with identical name exist
840   TObject *obj = gROOT->FindObject(pname);
841   if (obj && obj->InheritsFrom("TH3F")) {
842     proj3D = (TH3F*)obj;
843     proj3D->Reset();
844   }
845
846   if(!proj3D){
847     proj3D =new TH3F(pname,htitle, nbins1,bins1,nbins2,bins2,nbins3,bins3);
848   }  
849
850   delete [] bins1;
851   delete [] bins2;
852   delete [] bins3;
853
854
855   Float_t sum=0;
856   Float_t ***data=new Float_t**[nbins1];
857   Float_t **data2=new Float_t*[nbins1*nbins2];
858   Float_t *data3=new Float_t[nbins1*nbins2*nbins3];
859   Float_t ***err=new Float_t**[nbins1];
860   Float_t **err2=new Float_t*[nbins1*nbins2];
861   Float_t *err3=new Float_t[nbins1*nbins2*nbins3];
862   for(Int_t i=0;i<nbins1;i++)data[i] = data2+i*nbins2;
863   for(Int_t i=0;i<nbins1;i++)err[i] = err2+i*nbins2;
864   for(Int_t i=0;i<nbins1;i++){
865     for(Int_t j=0;j<nbins2;j++){
866       data[i][j] = data3+i*nbins2*nbins3+j*nbins3;
867       err[i][j] = err3+i*nbins2*nbins3+j*nbins3;
868     }
869   }
870   for(Int_t ibin1 =0;ibin1<nbins1;ibin1++){
871     for(Int_t ibin2 =0;ibin2<nbins2;ibin2++){
872       for(Int_t ibin3 =0;ibin3<nbins3;ibin3++){
873         data[ibin1][ibin2][ibin3]=0;
874         err[ibin1][ibin2][ibin3]=0;
875       }
876     }
877   }
878   
879   for(Int_t iel=0;iel<fNDim;iel++){
880     data[GetBinIndex(ivar1,iel)][GetBinIndex(ivar2,iel)][GetBinIndex(ivar3,iel)]+=fData[iel];
881     if(fSumW2)err[GetBinIndex(ivar1,iel)][GetBinIndex(ivar2,iel)][GetBinIndex(ivar3,iel)]+=fErr2[iel];
882   }
883
884   for(Int_t ibin1 =0;ibin1<nbins1;ibin1++){
885     for(Int_t ibin2 =0;ibin2<nbins2;ibin2++){
886       for(Int_t ibin3 =0;ibin3<nbins3;ibin3++){
887         proj3D->SetBinContent(ibin1+1,ibin2+1,ibin3+1,data[ibin1][ibin2][ibin3]);
888         proj3D->SetBinError(ibin1+1,ibin2+1,ibin3+1,TMath::Sqrt(data[ibin1][ibin2][ibin3]));
889         if(fSumW2)proj3D->SetBinError(ibin1+1,ibin2+1,ibin3+1,TMath::Sqrt(err[ibin1][ibin2][ibin3]));
890         sum+=data[ibin1][ibin2][ibin3];
891       }
892     }
893   } 
894
895   delete data;
896   delete data2;
897   delete data3;
898   delete err;
899   delete err2;
900   delete err3;
901   proj3D->SetEntries(GetEntries());
902   return proj3D;
903
904
905 //___________________________________________________________________
906 TH1F *AliCFGrid::Slice(Int_t ivar, Float_t *varMin, Float_t* varMax) const
907 {
908   //
909   // Make a slice along variable ivar in range [varMin,varMax]
910
911
912   Int_t nbins =fNVarBins[ivar];
913   Float_t *bins = new Float_t[nbins+1];    
914   for (Int_t i=0;i<=fNVar;i++){
915   }
916   for(Int_t ibin =0;ibin<nbins+1;ibin++){
917     bins[ibin] = fVarBinLimits[ibin+fOffset[ivar]];
918   }
919
920   char pname[40];
921   sprintf(pname,"%s%s_%i",GetName(),"_proj1D_var", ivar);
922   char htitle[40];
923   sprintf(htitle,"%s%s_%i",GetName(),"_proj1D_var", ivar);
924
925   TH1F *proj1D=0;
926
927   //check if a projection with identical name exist
928   TObject *obj = gROOT->FindObject(pname);
929   if (obj && obj->InheritsFrom("TH1F")) {
930     proj1D = (TH1F*)obj;
931     proj1D->Reset();
932   }
933
934   if(!proj1D){
935     proj1D =new TH1F(pname,htitle, nbins, bins);
936   }  
937
938   delete [] bins;
939
940
941   Int_t *indexMin=new Int_t[fNVar];
942   Int_t *indexMax=new Int_t[fNVar];
943
944
945   //Find out the min and max bins
946
947   for(Int_t i=0;i<fNVar;i++){
948     Float_t xmin=varMin[i]; // the min values  
949     Float_t xmax=varMax[i]; // the min values  
950     Int_t nbins=fNVarBins[i]+1;
951     Float_t *bins=new Float_t[nbins];
952     for(Int_t ibin =0;ibin<nbins;ibin++){
953      bins[ibin] = fVarBinLimits[ibin+fOffset[i]];
954     }
955     indexMin[i] = TMath::BinarySearch(nbins,bins,xmin);
956     indexMax[i] = TMath::BinarySearch(nbins,bins,xmax);
957     if(xmax>=bins[nbins-1]){
958       indexMax[i]=indexMax[i]-1;
959     }  
960     delete [] bins;
961   }
962
963   Float_t sum=0;
964   Float_t *data= new Float_t[nbins];
965   for(Int_t ibin=0;ibin<nbins;ibin++)data[ibin]=0;
966
967   Int_t *index= new Int_t[fNVar];
968   Int_t ielmin=GetBinIndex(indexMin);
969   Int_t ielmax=GetBinIndex(indexMax);
970   for(Int_t iel=ielmin;iel<=ielmax;iel++){
971     GetBinIndex(iel,index);
972     Bool_t isIn=kTRUE;
973     for (Int_t j=0;j<fNVar;j++){
974       if(!(index[j]>=indexMin[j] && index[j]<=indexMax[j]))isIn=kFALSE;   
975       break;
976     }
977     if(isIn)data[GetBinIndex(ivar,iel)]+=fData[iel];
978   }
979
980   delete [] index;
981
982
983   for(Int_t ibin =0;ibin<nbins;ibin++){
984     proj1D->SetBinContent(ibin+1,data[ibin]);
985     proj1D->SetBinError(ibin+1,TMath::Sqrt(data[ibin]));
986     sum+=data[ibin];
987   }
988
989   delete [] data;
990
991   proj1D->SetEntries(sum);
992   return proj1D;
993
994
995 //____________________________________________________________________
996 Long64_t AliCFGrid::Merge(TCollection* list)
997 {
998   // Merge a list of AliCorrection objects with this (needed for
999   // PROOF). 
1000   // Returns the number of merged objects (including this).
1001
1002   if (!list)
1003     return 0;
1004   
1005   if (list->IsEmpty())
1006     return 1;
1007
1008   TIterator* iter = list->MakeIterator();
1009   TObject* obj;
1010   
1011   Int_t count = 0;
1012   while ((obj = iter->Next())) {
1013     AliCFGrid* entry = dynamic_cast<AliCFGrid*> (obj);
1014     if (entry == 0) 
1015       continue;
1016     this->Add(entry);
1017     count++;
1018   }
1019
1020   return count+1;
1021 }
1022
1023 //____________________________________________________________________
1024 void AliCFGrid::Add(AliCFGrid* aGrid, Float_t c)
1025 {
1026   //
1027   //add aGrid to the current one
1028   //
1029
1030   if(aGrid->GetNVar()!=fNVar){
1031     AliInfo("Different number of variables, cannot add the grids");
1032     return;
1033   } 
1034   if(aGrid->GetNDim()!=fNDim){
1035     AliInfo("Different number of dimensions, cannot add the grids!");
1036     return;
1037   } 
1038   
1039   if(!fSumW2  && aGrid->GetSumW2())SumW2();
1040
1041   for(Int_t iel=0;iel<fNDim;iel++){
1042     fData[iel]+=(c*aGrid->GetElement(iel));
1043     if(fSumW2){
1044       Float_t err=TMath::Sqrt(aGrid->GetElementError(iel));  
1045       fErr2[iel]+=c*c*err*err;
1046     }
1047   }
1048
1049   //Add entries, overflows and underflows
1050
1051   fNentriesTot+= c*aGrid->GetEntries();
1052   fNunflTot+= c*aGrid->GetUnderFlows();
1053   fNovflTot+= c*aGrid->GetOverFlows();
1054   for(Int_t j=0;j<fNVar;j++){
1055     fNunfl[j]+= c*aGrid->GetUnderFlows(j);
1056     fNovfl[j]+= c*aGrid->GetUnderFlows(j);
1057   }
1058 }
1059 //____________________________________________________________________
1060 void AliCFGrid::Add(AliCFGrid* aGrid1, AliCFGrid* aGrid2, Float_t c1,Float_t c2)
1061 {
1062   //
1063   //add aGrid1 and aGrid2
1064   //
1065
1066   if(fNVar!=aGrid1->GetNVar()|| fNVar!=aGrid2->GetNVar()){
1067     AliInfo("Different number of variables, cannot add the grids");
1068     return;
1069   } 
1070   if(fNDim!=aGrid1->GetNDim()|| fNDim!=aGrid2->GetNDim()){
1071     AliInfo("Different number of dimensions, cannot add the grids!");
1072     return;
1073   } 
1074   
1075   if(!fSumW2  && (aGrid1->GetSumW2() || aGrid2->GetSumW2()))SumW2();
1076
1077   Float_t cont1,cont2,err1,err2;  
1078
1079   for(Int_t iel=0;iel<fNDim;iel++){
1080     cont1=aGrid1->GetElement(iel);
1081     cont2=aGrid2->GetElement(iel);
1082     SetElement(iel,c1*cont1+c2*cont2);
1083     if(fSumW2){
1084       err1=TMath::Sqrt(aGrid1->GetElementError(iel));
1085       err2=TMath::Sqrt(aGrid2->GetElementError(iel));
1086       SetElementError(iel,c1*c1*err1*err1+c2*c2*err2*err2);
1087     }
1088   }
1089
1090   //Add entries, overflows and underflows
1091
1092   fNentriesTot= c1*aGrid1->GetEntries()+c2*aGrid2->GetEntries();
1093   fNunflTot= c1*aGrid1->GetUnderFlows()+c2*aGrid2->GetUnderFlows();
1094   fNovflTot= c1*aGrid1->GetOverFlows()+c2*aGrid2->GetOverFlows();
1095   for(Int_t j=0;j<fNVar;j++){
1096     fNunfl[j]= c1*aGrid1->GetUnderFlows(j)+c2*aGrid2->GetUnderFlows(j);
1097     fNovfl[j]= c1*aGrid1->GetUnderFlows(j)+c2*aGrid2->GetUnderFlows(j);
1098   }
1099 }
1100 //____________________________________________________________________
1101 void AliCFGrid::Multiply(AliCFGrid* aGrid, Float_t c)
1102 {
1103   //
1104   //multiply grid aGrid by the current one
1105   //
1106
1107   if(aGrid->GetNVar()!=fNVar){
1108     AliInfo("Different number of variables, cannot multiply the grids");
1109     return;
1110   } 
1111   if(aGrid->GetNDim()!=fNDim){
1112     AliInfo("Different number of dimensions, cannot multiply the grids!");
1113     return;
1114   } 
1115   
1116   if(!fSumW2  && aGrid->GetSumW2())SumW2();
1117   
1118   Float_t cont1,cont2,err1,err2;  
1119
1120   for(Int_t iel=0;iel<fNDim;iel++){
1121     cont1=GetElement(iel);  
1122     cont2=c*aGrid->GetElement(iel);  
1123     SetElement(iel,cont1*cont2);
1124     if(fSumW2){
1125       err1=TMath::Sqrt(GetElementError(iel));  
1126       err2=TMath::Sqrt(aGrid->GetElementError(iel));  
1127       SetElementError(iel,c*c*(cont2*cont2*err1*err1+cont1*cont1*err2*err2));
1128     }
1129   }
1130
1131   //Set entries to the number of bins, preserve original overflows and underflows
1132
1133   fNentriesTot=fNDim;
1134   fNunflTot=GetUnderFlows();
1135   fNovflTot=GetOverFlows();
1136   for(Int_t j=0;j<fNVar;j++){
1137     fNunfl[j]= GetUnderFlows(j);
1138     fNovfl[j]= GetUnderFlows(j);
1139   }
1140 }
1141 //____________________________________________________________________
1142 void AliCFGrid::Multiply(AliCFGrid* aGrid1,AliCFGrid* aGrid2, Float_t c1,Float_t c2)
1143 {
1144   //
1145   //multiply grids aGrid1 and aGrid2
1146   //
1147
1148   if(fNVar!=aGrid1->GetNVar()|| fNVar!=aGrid2->GetNVar()){
1149     AliInfo("Different number of variables, cannot multiply the grids");
1150     return;
1151   } 
1152   if(fNDim!=aGrid1->GetNDim()|| fNDim!=aGrid2->GetNDim()){
1153     AliInfo("Different number of dimensions, cannot multiply the grids!");
1154     return;
1155   } 
1156   
1157   if(!fSumW2  && (aGrid1->GetSumW2() || aGrid2->GetSumW2()))SumW2();
1158
1159   Float_t cont1,cont2,err1,err2;  
1160   for(Int_t iel=0;iel<fNDim;iel++){
1161     cont1=c1*aGrid1->GetElement(iel);  
1162     cont2=c2*aGrid2->GetElement(iel);  
1163     SetElement(iel,cont1*cont2);
1164     if(fSumW2){
1165       err1=TMath::Sqrt(aGrid1->GetElementError(iel));  
1166       err2=TMath::Sqrt(aGrid2->GetElementError(iel));  
1167       SetElementError(iel,c1*c1*c2*c2*(cont2*cont2*err1*err1+cont1*cont1*err2*err2));
1168     }
1169   }
1170
1171   //Set entries to the number of bins, preserve original overflows and underflows
1172
1173   fNentriesTot=fNDim;
1174   fNunflTot=GetUnderFlows();
1175   fNovflTot=GetOverFlows();
1176   for(Int_t j=0;j<fNVar;j++){
1177     fNunfl[j]= GetUnderFlows(j);
1178     fNovfl[j]= GetUnderFlows(j);
1179   }
1180 }
1181 //____________________________________________________________________
1182 void AliCFGrid::Divide(AliCFGrid* aGrid, Float_t c, Option_t *option)
1183 {
1184   //
1185   //divide current grid by grid aGrid
1186   //
1187
1188   TString opt = option;
1189   opt.ToUpper();
1190
1191   if(aGrid->GetNVar()!=fNVar){
1192     AliInfo("Different number of variables, cannot divide the grids");
1193     return;
1194   } 
1195   if(aGrid->GetNDim()!=fNDim){
1196     AliInfo("Different number of dimensions, cannot divide the grids!");
1197     return;
1198   } 
1199  if(!c){AliInfo(Form("c is %f, cannot divide!",c)); return;} 
1200   
1201   if(!fSumW2  && aGrid->GetSumW2())SumW2();
1202
1203   Float_t cont1,cont2,err1,err2,r,den;
1204   for(Int_t iel=0;iel<fNDim;iel++){
1205     cont1=GetElement(iel);  
1206     cont2=aGrid->GetElement(iel);
1207     if(cont2)SetElement(iel,cont1/(c*cont2));
1208     else SetElement(iel,0);
1209     if(fSumW2){
1210       err1=TMath::Sqrt(GetElementError(iel));  
1211       err2=TMath::Sqrt(aGrid->GetElementError(iel));  
1212       if(!cont2){SetElementError(iel,0.); continue;}
1213       if (opt.Contains("B")){
1214         if(cont1!=cont2){
1215           r=cont1/cont2;            
1216           SetElementError(iel,TMath::Abs(((1-2.*r)*err1*err1+r*r*err2*err2)/(cont2*cont2)));
1217         }else{
1218           SetElementError(iel,0.);
1219         }
1220       }else{
1221         den=cont2*cont2*cont2*c*c;
1222         SetElementError(iel,(cont2*cont2*err1*err1+cont1*cont1*err2*err2)/den);
1223       }
1224     }
1225   }
1226
1227   //Set entries to the number of bins, preserve original overflows and underflows
1228
1229   fNentriesTot=fNDim;
1230   fNunflTot=GetUnderFlows();
1231   fNovflTot=GetOverFlows();
1232   for(Int_t j=0;j<fNVar;j++){
1233     fNunfl[j]= GetUnderFlows(j);
1234     fNovfl[j]= GetUnderFlows(j);
1235   }
1236 }
1237 //____________________________________________________________________
1238 void AliCFGrid::Divide(AliCFGrid* aGrid1, AliCFGrid* aGrid2, Float_t c1,Float_t c2, Option_t *option)
1239 {
1240   //
1241   //divide grids aGrid1,aGrid2
1242   //
1243
1244   TString opt = option;
1245   opt.ToUpper();
1246
1247   if(fNVar!=aGrid1->GetNVar()|| fNVar!=aGrid2->GetNVar()){
1248     AliInfo("Different number of variables, cannot divide the grids");
1249     return;
1250   }
1251   if(fNDim!=aGrid1->GetNDim()|| fNDim!=aGrid2->GetNDim()){
1252     AliInfo("Different number of dimensions, cannot divide the grids!");
1253     return;
1254   }
1255   if(!c2){AliInfo(Form("c2 is %f, cannot divide!",c2)); return;} 
1256   
1257   if(!fSumW2  && (aGrid1->GetSumW2() || aGrid2->GetSumW2()))SumW2();
1258
1259   Float_t cont1,cont2,err1,err2,r,den;
1260  
1261   for(Int_t iel=0;iel<fNDim;iel++){
1262     cont1=aGrid1->GetElement(iel);  
1263     cont2=aGrid2->GetElement(iel);  
1264     if(cont2)SetElement(iel,c1*cont1/(c2*cont2));
1265     else SetElement(iel,0);
1266      if(fSumW2){
1267       err1=TMath::Sqrt(aGrid1->GetElementError(iel));  
1268       err2=TMath::Sqrt(aGrid2->GetElementError(iel));  
1269       if(!cont2){SetElementError(iel,0.); continue;}
1270       if (opt.Contains("B")){
1271         if(cont1!=cont2){
1272           r=cont1/cont2;            
1273           SetElementError(iel,TMath::Abs(((1.-2.*r)*err1*err1+r*r*err2*err2)/(cont2*cont2)));
1274         }else{
1275           SetElementError(iel,0.);
1276         }
1277       }else{
1278         den=cont2*cont2*cont2*cont2*c2*c2;
1279         SetElementError(iel,c1*c1*(cont2*cont2*err1*err1+cont1*cont1*err2*err2)/den);
1280       }
1281     }
1282   }
1283
1284   //Set entries to the number of bins, preserve original overflows and underflows
1285
1286   fNentriesTot=fNDim;
1287   fNunflTot=GetUnderFlows();
1288   fNovflTot=GetOverFlows();
1289   for(Int_t j=0;j<fNVar;j++){
1290     fNunfl[j]= GetUnderFlows(j);
1291     fNovfl[j]= GetUnderFlows(j);
1292   }
1293 }
1294 //____________________________________________________________________
1295 void AliCFGrid::SumW2()
1296 {
1297   //
1298   //set calculation of the squared sum of the weighted entries
1299   //
1300   if(!fSumW2){
1301     fErr2=new Float_t [fNDim];
1302     //init....
1303     for(Int_t iel=0;iel<fNDim;iel++){
1304       fErr2[iel]=fData[iel];
1305     }
1306   }
1307
1308   fSumW2=kTRUE;
1309 }
1310 //_____________________________________________________________________
1311 Float_t AliCFGrid::GetSum(Int_t ivar, Int_t *binMin, Int_t* binMax) const 
1312 {
1313   //
1314   // recursively add over nested loops.... 
1315   //
1316   static Float_t val;
1317   if(ivar==0)val=0.;
1318   for(Int_t ibin=binMin[ivar];ibin<=binMax[ivar];ibin++){
1319     fIndex[ivar]=ibin;
1320     if(ivar<fNVar-1) {
1321       val=GetSum(ivar+1,binMin,binMax);
1322     }
1323     else {
1324       Int_t iel=GetBinIndex(fIndex);
1325       val+=fData[iel];
1326     }
1327   }
1328
1329   return val;
1330 }
1331 //____________________________________________________________________
1332 void AliCFGrid::Copy(TObject& c) const
1333 {
1334   //
1335   // copy function
1336   //
1337   AliCFGrid& target = (AliCFGrid &) c;
1338
1339   target.fNVar=fNVar;
1340   target.fNDim=fNDim;
1341   target.fSumW2=fSumW2;
1342   target.fNVarBinLimits=fNVarBinLimits;
1343   target.fNunflTot = fNunflTot;
1344   target.fNovflTot = fNovflTot;
1345   target.fNentriesTot = fNentriesTot;
1346   if (fNVarBins)
1347     target.fNVarBins = fNVarBins;
1348   if (fVarBinLimits)
1349     target.fVarBinLimits = fVarBinLimits;
1350   if (fNunfl)
1351     target.fNunfl = fNunfl;
1352   if (fNunfl)
1353     target.fNunfl = fNunfl;
1354   if (fNovfl)
1355     target.fNovfl = fNovfl;
1356   if (fProduct)
1357     target.fProduct = fProduct;
1358   if (fOffset)
1359     target.fOffset = fOffset;
1360   if (fData)
1361     target.fData = fData;
1362   if (fErr2)
1363     target.fErr2 = fErr2;
1364   
1365 }