Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TProfile2D.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 16/04/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TProfile2D.h"
13 #include "TBuffer.h"
14 #include "TMath.h"
15 #include "THLimitsFinder.h"
16 #include "Riostream.h"
17 #include "TVirtualPad.h"
18 #include "TError.h"
19 #include "TClass.h"
20 
21 #include "TProfileHelper.h"
22 
23 Bool_t TProfile2D::fgApproximate = kFALSE;
24 
25 ClassImp(TProfile2D);
26 
27 /** \class TProfile2D
28  \ingroup Hist
29  Profile2D histograms are used to display the mean
30  value of Z and its RMS for each cell in X,Y.
31  Profile2D histograms are in many cases an
32  elegant replacement of three-dimensional histograms : the inter-relation of three
33  measured quantities X, Y and Z can always be visualized by a three-dimensional
34  histogram or scatter-plot; its representation on the line-printer is not particularly
35  satisfactory, except for sparse data. If Z is an unknown (but single-valued)
36  approximate function of X,Y this function is displayed by a profile2D histogram with
37  much better precision than by a scatter-plot.
38 
39  The following formulae show the cumulated contents (capital letters) and the values
40  displayed by the printing or plotting routines (small letters) of the elements for cell I, J.
41 
42  H(I,J) = sum Z E(I,J) = sum Z
43  l(I,J) = sum l L(I,J) = sum l
44  h(I,J) = H(I,J)/L(I,J) s(I,J) = sqrt(E(I,J)/L(I,J)- h(I,J)**2)
45  e(I,J) = s(I,J)/sqrt(L(I,J))
46 
47  In the special case where s(I,J) is zero (eg, case of 1 entry only in one cell)
48  the bin error e(I,J) is computed from the average of the s(I,J) for all cells
49  if the static function TProfile2D::Approximate has been called.
50  This simple/crude approximation was suggested in order to keep the cell
51  during a fit operation. But note that this approximation is not the default behaviour.
52 
53  Example of a profile2D histogram
54  ~~~~{.cpp}
55  {
56  auto c1 = new TCanvas("c1","Profile histogram example",200,10,700,500);
57  auto hprof2d = new TProfile2D("hprof2d","Profile of pz versus px and py",40,-4,4,40,-4,4,0,20);
58  Float_t px, py, pz;
59  for ( Int_t i=0; i<25000; i++) {
60  gRandom->Rannor(px,py);
61  pz = px*px + py*py;
62  hprof2d->Fill(px,py,pz,1);
63  }
64  hprof2d->Draw();
65  }
66  ~~~~
67 */
68 
69 ////////////////////////////////////////////////////////////////////////////////
70 /// Default constructor for Profile2D histograms.
71 
72 TProfile2D::TProfile2D() : TH2D()
73 {
74  fTsumwz = fTsumwz2 = 0;
75  fScaling = kFALSE;
76  BuildOptions(0,0,"");
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Default destructor for Profile2D histograms.
81 
82 TProfile2D::~TProfile2D()
83 {
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Normal Constructor for Profile histograms.
88 ///
89 /// The first eight parameters are similar to TH2D::TH2D.
90 /// All values of z are accepted at filling time.
91 /// To fill a profile2D histogram, one must use TProfile2D::Fill function.
92 ///
93 /// Note that when filling the profile histogram the function Fill
94 /// checks if the variable z is between fZmin and fZmax.
95 /// If a minimum or maximum value is set for the Z scale before filling,
96 /// then all values below zmin or above zmax will be discarded.
97 /// Setting the minimum or maximum value for the Z scale before filling
98 /// has the same effect as calling the special TProfile2D constructor below
99 /// where zmin and zmax are specified.
100 ///
101 /// H(I,J) is printed as the cell contents. The errors computed are s(I,J) if CHOPT='S'
102 /// (spread option), or e(I,J) if CHOPT=' ' (error on mean).
103 ///
104 /// See TProfile2D::BuildOptions for explanation of parameters
105 ///
106 /// see other constructors below with all possible combinations of
107 /// fix and variable bin size like in TH2D.
108 
109 TProfile2D::TProfile2D(const char *name,const char *title,Int_t nx,Double_t xlow,Double_t xup,Int_t ny,Double_t ylow,Double_t yup,Option_t *option)
110 : TH2D(name,title,nx,xlow,xup,ny,ylow,yup)
111 {
112  BuildOptions(0,0,option);
113  if (xlow >= xup || ylow >= yup) SetBuffer(fgBufferSize);
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Create a 2-D Profile with variable bins in X and fix bins in Y.
118 
119 TProfile2D::TProfile2D(const char *name,const char *title,Int_t nx,const Double_t *xbins,Int_t ny,Double_t ylow,Double_t yup,Option_t *option)
120 : TH2D(name,title,nx,xbins,ny,ylow,yup)
121 {
122  BuildOptions(0,0,option);
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Create a 2-D Profile with fix bins in X and variable bins in Y.
127 
128 TProfile2D::TProfile2D(const char *name,const char *title,Int_t nx,Double_t xlow,Double_t xup,Int_t ny,const Double_t *ybins,Option_t *option)
129 : TH2D(name,title,nx,xlow,xup,ny,ybins)
130 {
131  BuildOptions(0,0,option);
132 }
133 
134 ////////////////////////////////////////////////////////////////////////////////
135 /// Create a 2-D Profile with variable bins in X and variable bins in Y.
136 
137 TProfile2D::TProfile2D(const char *name,const char *title,Int_t nx,const Double_t *xbins,Int_t ny,const Double_t *ybins,Option_t *option)
138 : TH2D(name,title,nx,xbins,ny,ybins)
139 {
140  BuildOptions(0,0,option);
141 }
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// Constructor for Profile2D histograms with range in z.
145 ///
146 /// The first eight parameters are similar to TH2D::TH2D.
147 /// Only the values of Z between ZMIN and ZMAX will be considered at filling time.
148 /// zmin and zmax will also be the maximum and minimum values
149 /// on the z scale when drawing the profile2D.
150 ///
151 /// See TProfile2D::BuildOptions for more explanations on errors
152 
153 TProfile2D::TProfile2D(const char *name,const char *title,Int_t nx,Double_t xlow,Double_t xup,Int_t ny, Double_t ylow,Double_t yup,Double_t zlow,Double_t zup,Option_t *option)
154 : TH2D(name,title,nx,xlow,xup,ny,ylow,yup)
155 {
156  BuildOptions(zlow,zup,option);
157  if (xlow >= xup || ylow >= yup) SetBuffer(fgBufferSize);
158 }
159 
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 /// Set Profile2D histogram structure and options.
163 ///
164 /// - zmin: minimum value allowed for z
165 /// - zmax: maximum value allowed for z
166 /// if (zmin = zmax = 0) there are no limits on the allowed z values (zmin = -inf, zmax = +inf)
167 ///
168 /// - option: this is the option for the computation of the t error of the profile ( TProfile2D::GetBinError )
169 /// possible values for the options are documented in TProfile2D::SetErrorOption
170 ///
171 /// See TProfile::BuildOptions for a detailed description
172 
173 void TProfile2D::BuildOptions(Double_t zmin, Double_t zmax, Option_t *option)
174 {
175 
176  SetErrorOption(option);
177 
178  // create extra profile data structure (bin entries/ y^2 and sum of weight square)
179  TProfileHelper::BuildArray(this);
180 
181  fZmin = zmin;
182  fZmax = zmax;
183  fScaling = kFALSE;
184  fTsumwz = fTsumwz2 = 0;
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Copy constructor.
189 
190 TProfile2D::TProfile2D(const TProfile2D &profile) : TH2D()
191 {
192  ((TProfile2D&)profile).Copy(*this);
193 }
194 
195 TProfile2D &TProfile2D::operator=(const TProfile2D &profile)
196 {
197  ((TProfile2D &)profile).Copy(*this);
198  return *this;
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Performs the operation: `this = this + c1*f1` .
203 
204 Bool_t TProfile2D::Add(TF1 *, Double_t , Option_t*)
205 {
206  Error("Add","Function not implemented for TProfile2D");
207  return kFALSE;
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 /// Performs the operation: `this = this + c1*h1` .
212 
213 Bool_t TProfile2D::Add(const TH1 *h1, Double_t c1)
214 {
215  if (!h1) {
216  Error("Add","Attempt to add a non-existing profile");
217  return kFALSE;
218  }
219  if (!h1->InheritsFrom(TProfile2D::Class())) {
220  Error("Add","Attempt to add a non-profile2D object");
221  return kFALSE;
222  }
223 
224  return TProfileHelper::Add(this, this, h1, 1, c1);
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 /// Replace contents of this profile2D by the addition of h1 and h2.
229 ///
230 /// `this = c1*h1 + c2*h2`
231 
232 Bool_t TProfile2D::Add(const TH1 *h1, const TH1 *h2, Double_t c1, Double_t c2)
233 {
234  if (!h1 || !h2) {
235  Error("Add","Attempt to add a non-existing profile");
236  return kFALSE;
237  }
238  if (!h1->InheritsFrom(TProfile2D::Class())) {
239  Error("Add","Attempt to add a non-profile2D object");
240  return kFALSE;
241  }
242  if (!h2->InheritsFrom(TProfile2D::Class())) {
243  Error("Add","Attempt to add a non-profile2D object");
244  return kFALSE;
245  }
246  return TProfileHelper::Add(this, h1, h2, c1, c2);
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// Static function, set the fgApproximate flag.
251 ///
252 /// When the flag is true, the function GetBinError
253 /// will approximate the bin error with the average profile error on all bins
254 /// in the following situation only
255 /// - the number of bins in the profile2D is less than 10404 (eg 100x100)
256 /// - the bin number of entries is small ( <5)
257 /// - the estimated bin error is extremely small compared to the bin content
258 /// (see TProfile2D::GetBinError)
259 
260 void TProfile2D::Approximate(Bool_t approx)
261 {
262  fgApproximate = approx;
263 }
264 
265 ////////////////////////////////////////////////////////////////////////////////
266 /// Fill histogram with all entries in the buffer.
267 ///
268 /// - action = -1 histogram is reset and refilled from the buffer (called by THistPainter::Paint)
269 /// - action = 0 histogram is filled from the buffer
270 /// - action = 1 histogram is filled and buffer is deleted
271 /// The buffer is automatically deleted when the number of entries
272 /// in the buffer is greater than the number of entries in the histogram
273 
274 Int_t TProfile2D::BufferEmpty(Int_t action)
275 {
276  // do we need to compute the bin size?
277  if (!fBuffer) return 0;
278  Int_t nbentries = (Int_t)fBuffer[0];
279  if (!nbentries) return 0;
280  Double_t *buffer = fBuffer;
281  if (nbentries < 0) {
282  if (action == 0) return 0;
283  nbentries = -nbentries;
284  fBuffer=0;
285  Reset("ICES"); // reset without deleting the functions
286  fBuffer = buffer;
287  }
288  if (CanExtendAllAxes() || fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin()) {
289  //find min, max of entries in buffer
290  Double_t xmin = fBuffer[2];
291  Double_t xmax = xmin;
292  Double_t ymin = fBuffer[3];
293  Double_t ymax = ymin;
294  for (Int_t i=1;i<nbentries;i++) {
295  Double_t x = fBuffer[4*i+2];
296  if (x < xmin) xmin = x;
297  if (x > xmax) xmax = x;
298  Double_t y = fBuffer[4*i+3];
299  if (y < ymin) ymin = y;
300  if (y > ymax) ymax = y;
301  }
302  if (fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin()) {
303  THLimitsFinder::GetLimitsFinder()->FindGoodLimits(this,xmin,xmax,ymin,ymax);
304  } else {
305  fBuffer = 0;
306  Int_t keep = fBufferSize; fBufferSize = 0;
307  if (xmin < fXaxis.GetXmin()) ExtendAxis(xmin,&fXaxis);
308  if (xmax >= fXaxis.GetXmax()) ExtendAxis(xmax,&fXaxis);
309  if (ymin < fYaxis.GetXmin()) ExtendAxis(ymin,&fYaxis);
310  if (ymax >= fYaxis.GetXmax()) ExtendAxis(ymax,&fYaxis);
311  fBuffer = buffer;
312  fBufferSize = keep;
313  }
314  }
315 
316  fBuffer = 0;
317  for (Int_t i=0;i<nbentries;i++) {
318  Fill(buffer[4*i+2],buffer[4*i+3],buffer[4*i+4],buffer[4*i+1]);
319  }
320  fBuffer = buffer;
321 
322  if (action > 0) { delete [] fBuffer; fBuffer = 0; fBufferSize = 0;}
323  else {
324  if (nbentries == (Int_t)fEntries) fBuffer[0] = -nbentries;
325  else fBuffer[0] = 0;
326  }
327  return nbentries;
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Accumulate arguments in buffer.
332 ///
333 /// When buffer is full, empty the buffer.
334 ///
335 /// - fBuffer[0] = number of entries in buffer
336 /// - fBuffer[1] = w of first entry
337 /// - fBuffer[2] = x of first entry
338 /// - fBuffer[3] = y of first entry
339 /// - fBuffer[4] = z of first entry
340 
341 Int_t TProfile2D::BufferFill(Double_t x, Double_t y, Double_t z, Double_t w)
342 {
343  if (!fBuffer) return -3;
344  Int_t nbentries = (Int_t)fBuffer[0];
345  if (nbentries < 0) {
346  nbentries = -nbentries;
347  fBuffer[0] = nbentries;
348  if (fEntries > 0) {
349  Double_t *buffer = fBuffer; fBuffer=0;
350  Reset("ICES"); // reset without deleting the functions
351  fBuffer = buffer;
352  }
353  }
354  if (4*nbentries+4 >= fBufferSize) {
355  BufferEmpty(1);
356  return Fill(x,y,z,w);
357  }
358  fBuffer[4*nbentries+1] = w;
359  fBuffer[4*nbentries+2] = x;
360  fBuffer[4*nbentries+3] = y;
361  fBuffer[4*nbentries+4] = z;
362  fBuffer[0] += 1;
363  return -2;
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Copy a Profile2D histogram to a new profile2D histogram.
368 
369 void TProfile2D::Copy(TObject &obj) const
370 {
371  try {
372  TProfile2D & pobj = dynamic_cast<TProfile2D&>(obj);
373 
374  TH2D::Copy(pobj);
375  fBinEntries.Copy(pobj.fBinEntries);
376  fBinSumw2.Copy(pobj.fBinSumw2);
377  for (int bin=0;bin<fNcells;bin++) {
378  pobj.fArray[bin] = fArray[bin];
379  pobj.fSumw2.fArray[bin] = fSumw2.fArray[bin];
380  }
381  pobj.fZmin = fZmin;
382  pobj.fZmax = fZmax;
383  pobj.fScaling = fScaling;
384  pobj.fErrorMode = fErrorMode;
385  pobj.fTsumwz = fTsumwz;
386  pobj.fTsumwz2 = fTsumwz2;
387 
388  } catch(...) {
389  Fatal("Copy","Cannot copy a TProfile2D in a %s",obj.IsA()->GetName());
390  }
391 
392 }
393 
394 ////////////////////////////////////////////////////////////////////////////////
395 /// Performs the operation: `this = this/(c1*f1)` .
396 /// This function is not implemented
397 
398 Bool_t TProfile2D::Divide(TF1 *, Double_t )
399 {
400  Error("Divide","Function not implemented for TProfile2D");
401  return kFALSE;
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 /// Divide this profile2D by h1.
406 ///
407 /// `this = this/h1`
408 ///
409 ///This function return kFALSE if the divide operation failed
410 
411 Bool_t TProfile2D::Divide(const TH1 *h1)
412 {
413 
414  if (!h1) {
415  Error("Divide","Attempt to divide a non-existing profile2D");
416  return kFALSE;
417  }
418  if (!h1->InheritsFrom(TProfile2D::Class())) {
419  Error("Divide","Attempt to divide a non-profile2D object");
420  return kFALSE;
421  }
422  TProfile2D *p1 = (TProfile2D*)h1;
423 
424  // delete buffer if it is there since it will become invalid
425  if (fBuffer) BufferEmpty(1);
426 
427  // Check profile compatibility
428  Int_t nx = GetNbinsX();
429  if (nx != p1->GetNbinsX()) {
430  Error("Divide","Attempt to divide profiles with different number of bins");
431  return kFALSE;
432  }
433  Int_t ny = GetNbinsY();
434  if (ny != p1->GetNbinsY()) {
435  Error("Divide","Attempt to divide profiles with different number of bins");
436  return kFALSE;
437  }
438 
439  // Reset statistics
440  fEntries = fTsumw = fTsumw2 = fTsumwx = fTsumwx2 = 0;
441 
442  // Loop on bins (including underflows/overflows)
443  Int_t bin,binx,biny;
444  Double_t *cu1 = p1->GetW();
445  Double_t *er1 = p1->GetW2();
446  Double_t *en1 = p1->GetB();
447  Double_t c0,c1,w,z,x,y;
448  for (binx =0;binx<=nx+1;binx++) {
449  for (biny =0;biny<=ny+1;biny++) {
450  bin = biny*(fXaxis.GetNbins()+2) + binx;
451  c0 = fArray[bin];
452  c1 = cu1[bin];
453  if (c1) w = c0/c1;
454  else w = 0;
455  fArray[bin] = w;
456  z = TMath::Abs(w);
457  x = fXaxis.GetBinCenter(binx);
458  y = fYaxis.GetBinCenter(biny);
459  fEntries++;
460  fTsumw += z;
461  fTsumw2 += z*z;
462  fTsumwx += z*x;
463  fTsumwx2 += z*x*x;
464  fTsumwy += z*y;
465  fTsumwy2 += z*y*y;
466  fTsumwxy += z*x*y;
467  fTsumwz += z;
468  fTsumwz2 += z*z;
469  Double_t e0 = fSumw2.fArray[bin];
470  Double_t e1 = er1[bin];
471  Double_t c12= c1*c1;
472  if (!c1) fSumw2.fArray[bin] = 0;
473  else fSumw2.fArray[bin] = (e0*c1*c1 + e1*c0*c0)/(c12*c12);
474  if (!en1[bin]) fBinEntries.fArray[bin] = 0;
475  else fBinEntries.fArray[bin] /= en1[bin];
476  }
477  }
478  // maintaining the correct sum of weights square is not supported when dividing
479  // bin error resulting from division of profile needs to be checked
480  if (fBinSumw2.fN) {
481  Warning("Divide","Cannot preserve during the division of profiles the sum of bin weight square");
482  fBinSumw2 = TArrayD();
483  }
484  return kTRUE;
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Replace contents of this profile2D by the division of h1 by h2.
489 ///
490 /// `this = c1*h1/(c2*h2)`
491 ///
492 /// This function return kFALSE if the divide operation failed
493 
494 Bool_t TProfile2D::Divide(const TH1 *h1, const TH1 *h2, Double_t c1, Double_t c2, Option_t *option)
495 {
496  TString opt = option;
497  opt.ToLower();
498  Bool_t binomial = kFALSE;
499  if (opt.Contains("b")) binomial = kTRUE;
500  if (!h1 || !h2) {
501  Error("Divide","Attempt to divide a non-existing profile2D");
502  return kFALSE;
503  }
504  if (!h1->InheritsFrom(TProfile2D::Class())) {
505  Error("Divide","Attempt to divide a non-profile2D object");
506  return kFALSE;
507  }
508  TProfile2D *p1 = (TProfile2D*)h1;
509  if (!h2->InheritsFrom(TProfile2D::Class())) {
510  Error("Divide","Attempt to divide a non-profile2D object");
511  return kFALSE;
512  }
513  TProfile2D *p2 = (TProfile2D*)h2;
514 
515  // delete buffer if it is there since it will become invalid
516  if (fBuffer) BufferEmpty(1);
517 
518  // Check histogram compatibility
519  Int_t nx = GetNbinsX();
520  if (nx != p1->GetNbinsX() || nx != p2->GetNbinsX()) {
521  Error("Divide","Attempt to divide profiles with different number of bins");
522  return kFALSE;
523  }
524  Int_t ny = GetNbinsY();
525  if (ny != p1->GetNbinsY() || ny != p2->GetNbinsY()) {
526  Error("Divide","Attempt to divide profiles with different number of bins");
527  return kFALSE;
528  }
529  if (!c2) {
530  Error("Divide","Coefficient of dividing profile cannot be zero");
531  return kFALSE;
532  }
533 
534  // Reset statistics
535  fEntries = fTsumw = fTsumw2 = fTsumwx = fTsumwx2 = 0;
536 
537  // Loop on bins (including underflows/overflows)
538  Int_t bin,binx,biny;
539  Double_t *cu1 = p1->GetW();
540  Double_t *cu2 = p2->GetW();
541  Double_t *er1 = p1->GetW2();
542  Double_t *er2 = p2->GetW2();
543  Double_t *en1 = p1->GetB();
544  Double_t *en2 = p2->GetB();
545  Double_t b1,b2,w,z,x,y,ac1,ac2;
546  ac1 = TMath::Abs(c1);
547  ac2 = TMath::Abs(c2);
548  for (binx =0;binx<=nx+1;binx++) {
549  for (biny =0;biny<=ny+1;biny++) {
550  bin = biny*(fXaxis.GetNbins()+2) + binx;
551  b1 = cu1[bin];
552  b2 = cu2[bin];
553  if (b2) w = c1*b1/(c2*b2);
554  else w = 0;
555  fArray[bin] = w;
556  z = TMath::Abs(w);
557  x = fXaxis.GetBinCenter(binx);
558  y = fYaxis.GetBinCenter(biny);
559  fEntries++;
560  fTsumw += z;
561  fTsumw2 += z*z;
562  fTsumwx += z*x;
563  fTsumwx2 += z*x*x;
564  fTsumwy += z*y;
565  fTsumwy2 += z*y*y;
566  fTsumwxy += z*x*y;
567  fTsumwz += z;
568  fTsumwz2 += z*z;
569  Double_t e1 = er1[bin];
570  Double_t e2 = er2[bin];
571  //Double_t b22= b2*b2*d2;
572  Double_t b22= b2*b2*TMath::Abs(c2);
573  if (!b2) fSumw2.fArray[bin] = 0;
574  else {
575  if (binomial) {
576  fSumw2.fArray[bin] = TMath::Abs(w*(1-w)/(c2*b2));
577  } else {
578  fSumw2.fArray[bin] = ac1*ac2*(e1*b2*b2 + e2*b1*b1)/(b22*b22);
579  }
580  }
581  if (!en2[bin]) fBinEntries.fArray[bin] = 0;
582  else fBinEntries.fArray[bin] = en1[bin]/en2[bin];
583  }
584  }
585  return kTRUE;
586 }
587 
588 ////////////////////////////////////////////////////////////////////////////////
589 /// Fill a Profile2D histogram (no weights).
590 
591 Int_t TProfile2D::Fill(Double_t x, Double_t y, Double_t z)
592 {
593  if (fBuffer) return BufferFill(x,y,z,1);
594 
595  Int_t bin,binx,biny;
596 
597  if (fZmin != fZmax) {
598  if (z <fZmin || z> fZmax || TMath::IsNaN(z) ) return -1;
599  }
600 
601  fEntries++;
602  binx =fXaxis.FindBin(x);
603  biny =fYaxis.FindBin(y);
604  if (binx <0 || biny <0) return -1;
605  bin = GetBin(binx, biny);
606  fArray[bin] += z;
607  fSumw2.fArray[bin] += z*z;
608  fBinEntries.fArray[bin] += 1;
609  if (fBinSumw2.fN) fBinSumw2.fArray[bin] += 1;
610  if (binx == 0 || binx > fXaxis.GetNbins()) {
611  if (!GetStatOverflowsBehaviour()) return -1;
612  }
613  if (biny == 0 || biny > fYaxis.GetNbins()) {
614  if (!GetStatOverflowsBehaviour()) return -1;
615  }
616  ++fTsumw;
617  ++fTsumw2;
618  fTsumwx += x;
619  fTsumwx2 += x*x;
620  fTsumwy += y;
621  fTsumwy2 += y*y;
622  fTsumwxy += x*y;
623  fTsumwz += z;
624  fTsumwz2 += z*z;
625  return bin;
626 }
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// Fill a Profile2D histogram (no weights).
630 
631 Int_t TProfile2D::Fill(Double_t x, const char *namey, Double_t z)
632 {
633  Int_t bin,binx,biny;
634 
635  if (fZmin != fZmax) {
636  if (z <fZmin || z> fZmax || TMath::IsNaN(z)) return -1;
637  }
638 
639  fEntries++;
640  binx =fXaxis.FindBin(x);
641  biny =fYaxis.FindBin(namey);
642  if (binx <0 || biny <0) return -1;
643  bin = biny*(fXaxis.GetNbins()+2) + binx;
644  AddBinContent(bin, z);
645  fSumw2.fArray[bin] += (Double_t)z*z;
646  fBinEntries.fArray[bin] += 1;
647  if (fBinSumw2.fN) fBinSumw2.fArray[bin] += 1;
648  if (binx == 0 || binx > fXaxis.GetNbins()) {
649  if (!GetStatOverflowsBehaviour()) return -1;
650  }
651  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
652  Double_t y = fYaxis.GetBinCenter(biny);
653  ++fTsumw;
654  ++fTsumw2;
655  fTsumwx += x;
656  fTsumwx2 += x*x;
657  fTsumwy += y;
658  fTsumwy2 += y*y;
659  fTsumwxy += x*y;
660  fTsumwz += z;
661  fTsumwz2 += z*z;
662  return bin;
663 }
664 
665 ////////////////////////////////////////////////////////////////////////////////
666 /// Fill a Profile2D histogram (no weights).
667 
668 Int_t TProfile2D::Fill(const char *namex, const char *namey, Double_t z)
669 {
670  Int_t bin,binx,biny;
671 
672  if (fZmin != fZmax) {
673  if (z <fZmin || z> fZmax || TMath::IsNaN(z) ) return -1;
674  }
675 
676  fEntries++;
677  binx =fXaxis.FindBin(namex);
678  biny =fYaxis.FindBin(namey);
679  if (binx <0 || biny <0) return -1;
680  bin = biny*(fXaxis.GetNbins()+2) + binx;
681  AddBinContent(bin, z);
682  fSumw2.fArray[bin] += (Double_t)z*z;
683  fBinEntries.fArray[bin] += 1;
684  if (fBinSumw2.fN) fBinSumw2.fArray[bin] += 1;
685  if (binx == 0 || binx > fXaxis.GetNbins()) return -1;
686  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
687  Double_t x = fYaxis.GetBinCenter(binx);
688  Double_t y = fYaxis.GetBinCenter(biny);
689  ++fTsumw;
690  ++fTsumw2;
691  fTsumwx += x;
692  fTsumwx2 += x*x;
693  fTsumwy += y;
694  fTsumwy2 += y*y;
695  fTsumwxy += x*y;
696  fTsumwz += z;
697  fTsumwz2 += z*z;
698  return bin;
699 }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// Fill a Profile2D histogram (no weights).
703 
704 Int_t TProfile2D::Fill(const char *namex, Double_t y, Double_t z)
705 {
706  Int_t bin,binx,biny;
707 
708  if (fZmin != fZmax) {
709  if (z <fZmin || z> fZmax || TMath::IsNaN(z)) return -1;
710  }
711 
712  fEntries++;
713  binx =fXaxis.FindBin(namex);
714  biny =fYaxis.FindBin(y);
715  if (binx <0 || biny <0) return -1;
716  bin = biny*(fXaxis.GetNbins()+2) + binx;
717  AddBinContent(bin, z);
718  fSumw2.fArray[bin] += (Double_t)z*z;
719  fBinEntries.fArray[bin] += 1;
720  if (fBinSumw2.fN) fBinSumw2.fArray[bin] += 1;
721  if (binx == 0 || binx > fXaxis.GetNbins()) return -1;
722  if (biny == 0 || biny > fYaxis.GetNbins()) {
723  if (!GetStatOverflowsBehaviour()) return -1;
724  }
725  Double_t x = fYaxis.GetBinCenter(binx);
726  ++fTsumw;
727  ++fTsumw2;
728  fTsumwx += x;
729  fTsumwx2 += x*x;
730  fTsumwy += y;
731  fTsumwy2 += y*y;
732  fTsumwxy += x*y;
733  fTsumwz += z;
734  fTsumwz2 += z*z;
735  return bin;
736 }
737 
738 ////////////////////////////////////////////////////////////////////////////////
739 /// Fill a Profile2D histogram with weights.
740 
741 Int_t TProfile2D::Fill(Double_t x, Double_t y, Double_t z, Double_t w)
742 {
743  if (fBuffer) return BufferFill(x,y,z,w);
744 
745  Int_t bin,binx,biny;
746 
747  if (fZmin != fZmax) {
748  if (z <fZmin || z> fZmax || TMath::IsNaN(z)) return -1;
749  }
750 
751  Double_t u= w;
752  fEntries++;
753  binx =fXaxis.FindBin(x);
754  biny =fYaxis.FindBin(y);
755  if (binx <0 || biny <0) return -1;
756  bin = biny*(fXaxis.GetNbins()+2) + binx;
757  AddBinContent(bin, u*z);
758  fSumw2.fArray[bin] += u*z*z;
759  if (!fBinSumw2.fN && u != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before accumulating the entries
760  if (fBinSumw2.fN) fBinSumw2.fArray[bin] += u*u;
761  fBinEntries.fArray[bin] += u;
762  if (binx == 0 || binx > fXaxis.GetNbins()) {
763  if (!GetStatOverflowsBehaviour()) return -1;
764  }
765  if (biny == 0 || biny > fYaxis.GetNbins()) {
766  if (!GetStatOverflowsBehaviour()) return -1;
767  }
768  fTsumw += u;
769  fTsumw2 += u*u;
770  fTsumwx += u*x;
771  fTsumwx2 += u*x*x;
772  fTsumwy += u*y;
773  fTsumwy2 += u*y*y;
774  fTsumwxy += u*x*y;
775  fTsumwz += u*z;
776  fTsumwz2 += u*z*z;
777  return bin;
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 /// Return bin content of a Profile2D histogram.
782 
783 Double_t TProfile2D::GetBinContent(Int_t bin) const
784 {
785  if (fBuffer) ((TProfile2D*)this)->BufferEmpty();
786 
787  if (bin < 0 || bin >= fNcells) return 0;
788  if (fBinEntries.fArray[bin] == 0) return 0;
789  if (!fArray) return 0;
790  return fArray[bin]/fBinEntries.fArray[bin];
791 }
792 
793 ////////////////////////////////////////////////////////////////////////////////
794 /// Return bin entries of a Profile2D histogram.
795 
796 Double_t TProfile2D::GetBinEntries(Int_t bin) const
797 {
798  if (fBuffer) ((TProfile2D*)this)->BufferEmpty();
799 
800  if (bin < 0 || bin >= fNcells) return 0;
801  return fBinEntries.fArray[bin];
802 }
803 
804 ////////////////////////////////////////////////////////////////////////////////
805 /// Return bin effective entries for a weighted filled Profile histogram.
806 /// In case of an unweighted profile, it is equivalent to the number of entries per bin
807 /// The effective entries is defined as the square of the sum of the weights divided by the
808 /// sum of the weights square.
809 /// TProfile::Sumw2() must be called before filling the profile with weights.
810 /// Only by calling this method the sum of the square of the weights per bin is stored.
811 
812 Double_t TProfile2D::GetBinEffectiveEntries(Int_t bin)
813 {
814  return TProfileHelper::GetBinEffectiveEntries(this, bin);
815 }
816 
817 ////////////////////////////////////////////////////////////////////////////////
818 /// Return bin error of a Profile2D histogram.
819 ///
820 /// ### Computing errors: A moving field
821 ///
822 /// The computation of errors for a TProfile2D has evolved with the versions
823 /// of ROOT. The difficulty is in computing errors for bins with low statistics.
824 /// - prior to version 3.10, we had no special treatment of low statistic bins.
825 /// As a result, these bins had huge errors. The reason is that the
826 /// expression eprim2 is very close to 0 (rounding problems) or 0.
827 /// - The algorithm is modified/protected for the case
828 /// when a TProfile2D is projected (ProjectionX). The previous algorithm
829 /// generated a N^2 problem when projecting a TProfile2D with a large number of
830 /// bins (eg 100000).
831 /// - in version 3.10/02, a new static function TProfile::Approximate
832 /// is introduced to enable or disable (default) the approximation.
833 /// (see also comments in TProfile::GetBinError)
834 
835 Double_t TProfile2D::GetBinError(Int_t bin) const
836 {
837  return TProfileHelper::GetBinError((TProfile2D*)this, bin);
838 }
839 
840 ////////////////////////////////////////////////////////////////////////////////
841 /// Return option to compute profile2D errors.
842 
843 Option_t *TProfile2D::GetErrorOption() const
844 {
845  if (fErrorMode == kERRORSPREAD) return "s";
846  if (fErrorMode == kERRORSPREADI) return "i";
847  if (fErrorMode == kERRORSPREADG) return "g";
848  return "";
849 }
850 
851 ////////////////////////////////////////////////////////////////////////////////
852 /// Fill the array stats from the contents of this profile.
853 /// The array stats must be correctly dimensioned in the calling program.
854 ///
855 /// - stats[0] = sumw
856 /// - stats[1] = sumw2
857 /// - stats[2] = sumwx
858 /// - stats[3] = sumwx2
859 /// - stats[4] = sumwy
860 /// - stats[5] = sumwy2
861 /// - stats[6] = sumwxy
862 /// - stats[7] = sumwz
863 /// - stats[8] = sumwz2
864 ///
865 /// If no axis-subrange is specified (via TAxis::SetRange), the array stats
866 /// is simply a copy of the statistics quantities computed at filling time.
867 /// If a sub-range is specified, the function recomputes these quantities
868 /// from the bin contents in the current axis range.
869 
870 void TProfile2D::GetStats(Double_t *stats) const
871 {
872  if (fBuffer) ((TProfile2D*)this)->BufferEmpty();
873 
874  // Loop on bins
875  if (fTsumw == 0 || fXaxis.TestBit(TAxis::kAxisRange) || fYaxis.TestBit(TAxis::kAxisRange)) {
876  Int_t bin, binx, biny;
877  Double_t w, w2;
878  Double_t x,y;
879  for (bin=0;bin<9;bin++) stats[bin] = 0;
880  if (!fBinEntries.fArray) return;
881  Int_t firstBinX = fXaxis.GetFirst();
882  Int_t lastBinX = fXaxis.GetLast();
883  Int_t firstBinY = fYaxis.GetFirst();
884  Int_t lastBinY = fYaxis.GetLast();
885  // include underflow/overflow if TH1::StatOverflows(kTRUE) in case no range is set on the axis
886  if (GetStatOverflowsBehaviour()) {
887  if ( !fXaxis.TestBit(TAxis::kAxisRange) ) {
888  if (firstBinX == 1) firstBinX = 0;
889  if (lastBinX == fXaxis.GetNbins() ) lastBinX += 1;
890  }
891  if ( !fYaxis.TestBit(TAxis::kAxisRange) ) {
892  if (firstBinY == 1) firstBinY = 0;
893  if (lastBinY == fYaxis.GetNbins() ) lastBinY += 1;
894  }
895  }
896  for (biny = firstBinY; biny <= lastBinY; biny++) {
897  y = fYaxis.GetBinCenter(biny);
898  for (binx = firstBinX; binx <= lastBinX; binx++) {
899  bin = GetBin(binx,biny);
900  w = fBinEntries.fArray[bin];
901  w2 = (fBinSumw2.fN ? fBinSumw2.fArray[bin] : w );
902  x = fXaxis.GetBinCenter(binx);
903  stats[0] += w;
904  stats[1] += w2;
905  stats[2] += w*x;
906  stats[3] += w*x*x;
907  stats[4] += w*y;
908  stats[5] += w*y*y;
909  stats[6] += w*x*y;
910  stats[7] += fArray[bin];
911  stats[8] += fSumw2.fArray[bin];
912  }
913  }
914  } else {
915  stats[0] = fTsumw;
916  stats[1] = fTsumw2;
917  stats[2] = fTsumwx;
918  stats[3] = fTsumwx2;
919  stats[4] = fTsumwy;
920  stats[5] = fTsumwy2;
921  stats[6] = fTsumwxy;
922  stats[7] = fTsumwz;
923  stats[8] = fTsumwz2;
924  }
925 }
926 
927 ////////////////////////////////////////////////////////////////////////////////
928 /// Reduce the number of bins for this axis to the number of bins having a label.
929 
930 void TProfile2D::LabelsDeflate(Option_t *ax)
931 {
932  TProfileHelper::LabelsDeflate(this, ax);
933 }
934 
935 ////////////////////////////////////////////////////////////////////////////////
936 /// Double the number of bins for axis.
937 /// Refill histogram
938 /// This function is called by TAxis::FindBin(const char *label)
939 
940 void TProfile2D::LabelsInflate(Option_t *ax)
941 {
942  TProfileHelper::LabelsInflate(this, ax);
943 }
944 
945 ////////////////////////////////////////////////////////////////////////////////
946 /// Set option(s) to draw axis with labels.
947 ///
948 /// option might have the following values:
949 ///
950 /// - "a" sort by alphabetic order
951 /// - ">" sort by decreasing values
952 /// - "<" sort by increasing values
953 /// - "h" draw labels horizontal
954 /// - "v" draw labels vertical
955 /// - "u" draw labels up (end of label right adjusted)
956 /// - "d" draw labels down (start of label left adjusted)
957 
958 void TProfile2D::LabelsOption(Option_t *option, Option_t *ax)
959 {
960 
961  TAxis *axis = GetXaxis();
962  if (ax[0] == 'y' || ax[0] == 'Y') axis = GetYaxis();
963  THashList *labels = axis->GetLabels();
964  if (!labels) {
965  Warning("LabelsOption","Cannot sort. No labels");
966  return;
967  }
968  TString opt = option;
969  opt.ToLower();
970  if (opt.Contains("h")) {
971  axis->SetBit(TAxis::kLabelsHori);
972  axis->ResetBit(TAxis::kLabelsVert);
973  axis->ResetBit(TAxis::kLabelsDown);
974  axis->ResetBit(TAxis::kLabelsUp);
975  }
976  if (opt.Contains("v")) {
977  axis->SetBit(TAxis::kLabelsVert);
978  axis->ResetBit(TAxis::kLabelsHori);
979  axis->ResetBit(TAxis::kLabelsDown);
980  axis->ResetBit(TAxis::kLabelsUp);
981  }
982  if (opt.Contains("u")) {
983  axis->SetBit(TAxis::kLabelsUp);
984  axis->ResetBit(TAxis::kLabelsVert);
985  axis->ResetBit(TAxis::kLabelsDown);
986  axis->ResetBit(TAxis::kLabelsHori);
987  }
988  if (opt.Contains("d")) {
989  axis->SetBit(TAxis::kLabelsDown);
990  axis->ResetBit(TAxis::kLabelsVert);
991  axis->ResetBit(TAxis::kLabelsHori);
992  axis->ResetBit(TAxis::kLabelsUp);
993  }
994  Int_t sort = -1;
995  if (opt.Contains("a")) sort = 0;
996  if (opt.Contains(">")) sort = 1;
997  if (opt.Contains("<")) sort = 2;
998  if (sort < 0) return;
999 
1000  Int_t nx = fXaxis.GetNbins()+2;
1001  Int_t ny = fYaxis.GetNbins()+2;
1002  Int_t n = TMath::Min(axis->GetNbins(), labels->GetSize());
1003  Int_t *a = new Int_t[n+2];
1004  Int_t i,j,k,bin;
1005  Double_t *sumw = new Double_t[nx*ny];
1006  Double_t *errors = new Double_t[nx*ny];
1007  Double_t *ent = new Double_t[nx*ny];
1008  THashList *labold = new THashList(labels->GetSize(),1);
1009  TIter nextold(labels);
1010  TObject *obj;
1011  while ((obj=nextold())) {
1012  labold->Add(obj);
1013  }
1014  labels->Clear();
1015  if (sort > 0) {
1016  //---sort by values of bins
1017  Double_t *pcont = new Double_t[n+2];
1018  for (i=0;i<=n;i++) pcont[i] = 0;
1019  for (i=1;i<nx;i++) {
1020  for (j=1;j<ny;j++) {
1021  bin = i+nx*j;
1022  sumw[bin] = fArray[bin];
1023  errors[bin] = fSumw2.fArray[bin];
1024  ent[bin] = fBinEntries.fArray[bin];
1025  if (axis == GetXaxis()) k = i;
1026  else k = j;
1027  if (fBinEntries.fArray[bin] != 0) pcont[k-1] += fArray[bin]/fBinEntries.fArray[bin];
1028  }
1029  }
1030  if (sort ==1) TMath::Sort(n,pcont,a,kTRUE); //sort by decreasing values
1031  else TMath::Sort(n,pcont,a,kFALSE); //sort by increasing values
1032  delete [] pcont;
1033  for (i=0;i<n;i++) {
1034  obj = labold->At(a[i]);
1035  labels->Add(obj);
1036  obj->SetUniqueID(i+1);
1037  }
1038  for (i=1;i<nx;i++) {
1039  for (j=1;j<ny;j++) {
1040  bin = i+nx*j;
1041  if (axis == GetXaxis()) {
1042  fArray[bin] = sumw[a[i-1]+1+nx*j];
1043  fSumw2.fArray[bin] = errors[a[i-1]+1+nx*j];
1044  fBinEntries.fArray[bin] = ent[a[i-1]+1+nx*j];
1045  } else {
1046  fArray[bin] = sumw[i+nx*(a[j-1]+1)];
1047  fSumw2.fArray[bin] = errors[i+nx*(a[j-1]+1)];
1048  fBinEntries.fArray[bin] = ent[i+nx*(a[j-1]+1)];
1049  }
1050  }
1051  }
1052  } else {
1053  //---alphabetic sort
1054  const UInt_t kUsed = 1<<18;
1055  TObject *objk=0;
1056  a[0] = 0;
1057  a[n+1] = n+1;
1058  for (i=1;i<=n;i++) {
1059  const char *label = "zzzzzzzzzzzz";
1060  for (j=1;j<=n;j++) {
1061  obj = labold->At(j-1);
1062  if (!obj) continue;
1063  if (obj->TestBit(kUsed)) continue;
1064  //use strcasecmp for case non-sensitive sort (may be an option)
1065  if (strcmp(label,obj->GetName()) < 0) continue;
1066  objk = obj;
1067  a[i] = j;
1068  label = obj->GetName();
1069  }
1070  if (objk) {
1071  objk->SetUniqueID(i);
1072  labels->Add(objk);
1073  objk->SetBit(kUsed);
1074  }
1075  }
1076  for (i=1;i<=n;i++) {
1077  obj = labels->At(i-1);
1078  if (!obj) continue;
1079  obj->ResetBit(kUsed);
1080  }
1081  for (i=0;i<nx;i++) {
1082  for (j=0;j<ny;j++) {
1083  bin = i+nx*j;
1084  sumw[bin] = fArray[bin];
1085  errors[bin] = fSumw2.fArray[bin];
1086  ent[bin] = fBinEntries.fArray[bin];
1087  }
1088  }
1089  for (i=0;i<nx;i++) {
1090  for (j=0;j<ny;j++) {
1091  bin = i+nx*j;
1092  if (axis == GetXaxis()) {
1093  fArray[bin] = sumw[a[i]+nx*j];
1094  fSumw2.fArray[bin] = errors[a[i]+nx*j];
1095  fBinEntries.fArray[bin] = ent[a[i]+nx*j];
1096  } else {
1097  fArray[bin] = sumw[i+nx*a[j]];
1098  fSumw2.fArray[bin] = errors[i+nx*a[j]];
1099  fBinEntries.fArray[bin] = ent[i+nx*a[j]];
1100  }
1101  }
1102  }
1103  }
1104  delete labold;
1105  if (a) delete [] a;
1106  if (sumw) delete [] sumw;
1107  if (errors) delete [] errors;
1108  if (ent) delete [] ent;
1109 }
1110 
1111 ////////////////////////////////////////////////////////////////////////////////
1112 /// Merge all histograms in the collection in this histogram.
1113 /// This function computes the min/max for the axes,
1114 /// compute a new number of bins, if necessary,
1115 /// add bin contents, errors and statistics.
1116 /// If overflows are present and limits are different the function will fail.
1117 /// The function returns the total number of entries in the result histogram
1118 /// if the merge is successful, -1 otherwise.
1119 ///
1120 /// IMPORTANT remark. The 2 axis x and y may have different number
1121 /// of bins and different limits, BUT the largest bin width must be
1122 /// a multiple of the smallest bin width and the upper limit must also
1123 /// be a multiple of the bin width.
1124 
1125 Long64_t TProfile2D::Merge(TCollection *li)
1126 {
1127  return TProfileHelper::Merge(this, li);
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// Performs the operation: this = this*c1*f1
1132 
1133 Bool_t TProfile2D::Multiply(TF1 *, Double_t )
1134 {
1135  Error("Multiply","Function not implemented for TProfile2D");
1136  return kFALSE;
1137 }
1138 
1139 ////////////////////////////////////////////////////////////////////////////////
1140 /// Multiply this profile2D by h1.
1141 ///
1142 /// `this = this*h1`
1143 
1144 Bool_t TProfile2D::Multiply(const TH1 *)
1145 {
1146  Error("Multiply","Multiplication of profile2D histograms not implemented");
1147  return kFALSE;
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// Replace contents of this profile2D by multiplication of h1 by h2.
1152 ///
1153 /// `this = (c1*h1)*(c2*h2)`
1154 
1155 Bool_t TProfile2D::Multiply(const TH1 *, const TH1 *, Double_t, Double_t, Option_t *)
1156 {
1157  Error("Multiply","Multiplication of profile2D histograms not implemented");
1158  return kFALSE;
1159 }
1160 
1161 ////////////////////////////////////////////////////////////////////////////////
1162 /// Project this profile2D into a 2-D histogram along X,Y.
1163 ///
1164 /// The projection is always of the type TH2D.
1165 ///
1166 /// - if option "E" is specified the errors of the projected histogram are computed and set
1167 /// to be equal to the errors of the profile.
1168 /// Option "E" is defined as the default one in the header file.
1169 /// - if option "" is specified the histogram errors are simply the sqrt of its content
1170 /// - if option "B" is specified, the content of bin of the returned histogram
1171 /// will be equal to the GetBinEntries(bin) of the profile,
1172 /// - if option "C=E" the bin contents of the projection are set to the
1173 /// bin errors of the profile
1174 /// - if option "W" is specified the bin content of the projected histogram is set to the
1175 /// product of the bin content of the profile and the entries.
1176 /// With this option the returned histogram will be equivalent to the one obtained by
1177 /// filling directly a TH2D using the 3-rd value as a weight.
1178 /// This option makes sense only for profile filled with all weights =1.
1179 /// When the profile is weighted (filled with weights different than 1) the
1180 /// bin error of the projected histogram (obtained using this option "W") cannot be
1181 /// correctly computed from the information stored in the profile. In that case the
1182 /// obtained histogram contains as bin error square the weighted sum of the square of the
1183 /// profiled observable (TProfile2D::fSumw2[bin] )
1184 
1185 TH2D *TProfile2D::ProjectionXY(const char *name, Option_t *option) const
1186 {
1187 
1188  TString opt = option;
1189  opt.ToLower();
1190 
1191  // Create the projection histogram
1192  // name of projected histogram is by default name of original histogram + _pxy
1193  TString pname(name);
1194  if (pname.IsNull() || pname == "_pxy")
1195  pname = TString(GetName() ) + TString("_pxy");
1196 
1197 
1198  Int_t nx = fXaxis.GetNbins();
1199  Int_t ny = fYaxis.GetNbins();
1200  const TArrayD *xbins = fXaxis.GetXbins();
1201  const TArrayD *ybins = fYaxis.GetXbins();
1202  TH2D * h1 = 0;
1203  if (xbins->fN == 0 && ybins->fN == 0) {
1204  h1 = new TH2D(pname,GetTitle(),nx,fXaxis.GetXmin(),fXaxis.GetXmax(),ny,fYaxis.GetXmin(),fYaxis.GetXmax());
1205  } else if (xbins->fN == 0) {
1206  h1 = new TH2D(pname,GetTitle(),nx,fXaxis.GetXmin(),fXaxis.GetXmax(),ny, ybins->GetArray() );
1207  } else if (ybins->fN == 0) {
1208  h1 = new TH2D(pname,GetTitle(),nx,xbins->GetArray(),ny,fYaxis.GetXmin(),fYaxis.GetXmax());
1209  } else {
1210  h1 = new TH2D(pname,GetTitle(),nx,xbins->GetArray(),ny,ybins->GetArray() );
1211  }
1212  Bool_t computeErrors = kFALSE;
1213  Bool_t cequalErrors = kFALSE;
1214  Bool_t binEntries = kFALSE;
1215  Bool_t binWeight = kFALSE;
1216  if (opt.Contains("b")) binEntries = kTRUE;
1217  if (opt.Contains("e")) computeErrors = kTRUE;
1218  if (opt.Contains("w")) binWeight = kTRUE;
1219  if (opt.Contains("c=e")) {cequalErrors = kTRUE; computeErrors=kFALSE;}
1220  if (computeErrors || binWeight || (binEntries && fBinSumw2.fN) ) h1->Sumw2();
1221 
1222  // Fill the projected histogram
1223  Int_t bin,binx, biny;
1224  Double_t cont;
1225  for (binx =0;binx<=nx+1;binx++) {
1226  for (biny =0;biny<=ny+1;biny++) {
1227  bin = GetBin(binx,biny);
1228 
1229  if (binEntries) cont = GetBinEntries(bin);
1230  else if (cequalErrors) cont = GetBinError(bin);
1231  else if (binWeight) cont = GetBinContent(bin) * GetBinEntries(bin);
1232  else cont = GetBinContent(bin); // default case
1233 
1234  h1->SetBinContent(bin ,cont);
1235 
1236  // if option E projected histogram errors are same as profile
1237  if (computeErrors ) h1->SetBinError(bin , GetBinError(bin) );
1238  // in case of option W bin error is deduced from bin sum of z**2 values of profile
1239  // this is correct only if the profile is unweighted
1240  if (binWeight) h1->GetSumw2()->fArray[bin] = fSumw2.fArray[bin];
1241  // in case of bin entries and profile is weighted, we need to set also the bin error
1242  if (binEntries && fBinSumw2.fN ) {
1243  R__ASSERT( h1->GetSumw2() );
1244  h1->GetSumw2()->fArray[bin] = fBinSumw2.fArray[bin];
1245  }
1246  }
1247  }
1248  h1->SetEntries(fEntries);
1249  return h1;
1250 }
1251 
1252 ////////////////////////////////////////////////////////////////////////////////
1253 /// Project a 2-D histogram into a profile histogram along X.
1254 ///
1255 /// The projection is made from the channels along the Y axis
1256 /// ranging from firstybin to lastybin included.
1257 /// The result is a 1D profile which contains the combination of all the considered bins along Y
1258 /// By default, bins 1 to ny are included
1259 /// When all bins are included, the number of entries in the projection
1260 /// is set to the number of entries of the 2-D histogram, otherwise
1261 /// the number of entries is incremented by 1 for all non empty cells.
1262 ///
1263 /// The option can also be used to specify the projected profile error type.
1264 /// Values which can be used are 's', 'i', or 'g'. See TProfile::BuildOptions for details
1265 
1266 TProfile *TProfile2D::ProfileX(const char *name, Int_t firstybin, Int_t lastybin, Option_t *option) const
1267 {
1268  return DoProfile(true, name, firstybin, lastybin, option);
1269 }
1270 
1271 ////////////////////////////////////////////////////////////////////////////////
1272 /// Project a 2-D histogram into a profile histogram along X
1273 ///
1274 /// The projection is made from the channels along the X axis
1275 /// ranging from firstybin to lastybin included.
1276 /// The result is a 1D profile which contains the combination of all the considered bins along X
1277 /// By default, bins 1 to ny are included
1278 /// When all bins are included, the number of entries in the projection
1279 /// is set to the number of entries of the 2-D histogram, otherwise
1280 /// the number of entries is incremented by 1 for all non empty cells.
1281 ///
1282 /// The option can also be used to specify the projected profile error type.
1283 /// Values which can be used are 's', 'i', or 'g'. See TProfile::BuildOptions for details
1284 
1285 TProfile *TProfile2D::ProfileY(const char *name, Int_t firstxbin, Int_t lastxbin, Option_t *option) const
1286 {
1287  return DoProfile(false, name, firstxbin, lastxbin, option);
1288 }
1289 
1290 ////////////////////////////////////////////////////////////////////////////////
1291 /// Implementation of ProfileX or ProfileY for a TProfile2D.
1292 ///
1293 /// Do correctly the combination of the bin averages when doing the projection
1294 
1295 TProfile * TProfile2D::DoProfile(bool onX, const char *name, Int_t firstbin, Int_t lastbin, Option_t *option) const {
1296  TString opt = option;
1297  opt.ToLower();
1298  bool originalRange = opt.Contains("o");
1299 
1300  TString expectedName = ( onX ? "_pfx" : "_pfy" );
1301 
1302  TString pname(name);
1303  if (pname.IsNull() || name == expectedName)
1304  pname = TString(GetName() ) + expectedName;
1305 
1306  const TAxis& outAxis = ( onX ? fXaxis : fYaxis );
1307  const TArrayD *bins = outAxis.GetXbins();
1308  Int_t firstOutBin = outAxis.GetFirst();
1309  Int_t lastOutBin = outAxis.GetLast();
1310 
1311  TProfile * p1 = 0;
1312  // case of fixed bins
1313  if (bins->fN == 0) {
1314  if (originalRange)
1315  p1 = new TProfile(pname,GetTitle(), outAxis.GetNbins(), outAxis.GetXmin(), outAxis.GetXmax(), opt );
1316  else
1317  p1 = new TProfile(pname,GetTitle(), lastOutBin-firstOutBin+1,
1318  outAxis.GetBinLowEdge(firstOutBin),outAxis.GetBinUpEdge(lastOutBin), opt);
1319  } else {
1320  // case of variable bins
1321  if (originalRange )
1322  p1 = new TProfile(pname,GetTitle(),outAxis.GetNbins(),bins->fArray,opt);
1323  else
1324  p1 = new TProfile(pname,GetTitle(),lastOutBin-firstOutBin+1,&bins->fArray[firstOutBin-1],opt);
1325 
1326  }
1327 
1328  if (fBinSumw2.fN) p1->Sumw2();
1329 
1330  // make projection in a 2D first
1331  TH2D * h2dW = ProjectionXY("h2temp-W","W");
1332  TH2D * h2dN = ProjectionXY("h2temp-N","B");
1333 
1334  h2dW->SetDirectory(0); h2dN->SetDirectory(0);
1335 
1336 
1337  TString opt1 = (originalRange) ? "o" : "";
1338  TH1D * h1W = (onX) ? h2dW->ProjectionX("h1temp-W",firstbin,lastbin,opt1) : h2dW->ProjectionY("h1temp-W",firstbin,lastbin,opt1);
1339  TH1D * h1N = (onX) ? h2dN->ProjectionX("h1temp-N",firstbin,lastbin,opt1) : h2dN->ProjectionY("h1temp-N",firstbin,lastbin,opt1);
1340  h1W->SetDirectory(0); h1N->SetDirectory(0);
1341 
1342 
1343  // fill the bin content
1344  R__ASSERT( h1W->fN == p1->fN );
1345  R__ASSERT( h1N->fN == p1->fN );
1346  R__ASSERT( h1W->GetSumw2()->fN != 0); // h1W should always be a weighted histogram since h2dW is
1347  for (int i = 0; i < p1->fN ; ++i) {
1348  p1->fArray[i] = h1W->GetBinContent(i); // array of profile is sum of all values
1349  p1->GetSumw2()->fArray[i] = h1W->GetSumw2()->fArray[i]; // array of content square of profile is weight square of the W projected histogram
1350  p1->SetBinEntries(i, h1N->GetBinContent(i) );
1351  if (fBinSumw2.fN) p1->GetBinSumw2()->fArray[i] = h1N->GetSumw2()->fArray[i]; // sum of weight squares are stored to compute errors in h1N histogram
1352  }
1353  // delete the created histograms
1354  delete h2dW;
1355  delete h2dN;
1356  delete h1W;
1357  delete h1N;
1358 
1359  // Also we need to set the entries since they have not been correctly calculated during the projection
1360  // we can only set them to the effective entries
1361  p1->SetEntries( p1->GetEffectiveEntries() );
1362 
1363  return p1;
1364 }
1365 
1366 
1367 ////////////////////////////////////////////////////////////////////////////////
1368 /// Replace current statistics with the values in array stats
1369 
1370 void TProfile2D::PutStats(Double_t *stats)
1371 {
1372  fTsumw = stats[0];
1373  fTsumw2 = stats[1];
1374  fTsumwx = stats[2];
1375  fTsumwx2 = stats[3];
1376  fTsumwy = stats[4];
1377  fTsumwy2 = stats[5];
1378  fTsumwxy = stats[6];
1379  fTsumwz = stats[7];
1380  fTsumwz2 = stats[8];
1381 }
1382 
1383 ////////////////////////////////////////////////////////////////////////////////
1384 /// Reset contents of a Profile2D histogram.
1385 
1386 void TProfile2D::Reset(Option_t *option)
1387 {
1388  TH2D::Reset(option);
1389  fBinEntries.Reset();
1390  fBinSumw2.Reset();
1391  TString opt = option;
1392  opt.ToUpper();
1393  if (opt.Contains("ICE") && !opt.Contains("S")) return;
1394  fTsumwz = fTsumwz2 = 0;
1395 }
1396 
1397 
1398 ////////////////////////////////////////////////////////////////////////////////
1399 /// Profile histogram is resized along axis such that x is in the axis range.
1400 ///
1401 /// The new axis limits are recomputed by doubling iteratively
1402 /// the current axis range until the specified value x is within the limits.
1403 /// The algorithm makes a copy of the histogram, then loops on all bins
1404 /// of the old histogram to fill the extended histogram.
1405 /// Takes into account errors (Sumw2) if any.
1406 /// The axis must be extendable before invoking this function.
1407 ///
1408 /// Ex: `h->GetXaxis()->SetCanExtend(kTRUE)`
1409 
1410 void TProfile2D::ExtendAxis(Double_t x, TAxis *axis)
1411 {
1412  TProfile2D* hold = TProfileHelper::ExtendAxis(this, x, axis);
1413  if ( hold ) {
1414  fTsumwz = hold->fTsumwz;
1415  fTsumwz2 = hold->fTsumwz2;
1416  delete hold;
1417  }
1418 }
1419 
1420 ////////////////////////////////////////////////////////////////////////////////
1421 /// Rebin this histogram grouping nxgroup/nygroup bins along the xaxis/yaxis together.
1422 ///
1423 /// if newname is not blank a new profile hnew is created.
1424 /// else the current histogram is modified (default)
1425 /// The parameter nxgroup/nygroup indicate how many bins along the xaxis/yaxis of this
1426 /// have to be merged into one bin of hnew
1427 /// If the original profile has errors stored (via Sumw2), the resulting
1428 /// profile has new errors correctly calculated.
1429 ///
1430 /// examples: if hpxpy is an existing TProfile2D profile with 40 x 40 bins
1431 /// ~~~ {.cpp}
1432 /// hpxpy->Rebin2D(); // merges two bins along the xaxis and yaxis in one
1433 /// // Carefull: previous contents of hpxpy are lost
1434 /// hpxpy->Rebin2D(3,5); // merges 3 bins along the xaxis and 5 bins along the yaxis in one
1435 /// // Carefull: previous contents of hpxpy are lost
1436 /// hpxpy->RebinX(5); //merges five bins along the xaxis in one in hpxpy
1437 /// TProfile2D *hnew = hpxpy->RebinY(5,"hnew"); // creates a new profile hnew
1438 /// // merging 5 bins of hpxpy along the yaxis in one bin
1439 /// ~~~
1440 ///
1441 /// NOTE : If nxgroup/nygroup is not an exact divider of the number of bins,
1442 /// along the xaxis/yaxis the top limit(s) of the rebinned profile
1443 /// is changed to the upper edge of the xbin=newxbins*nxgroup resp.
1444 /// ybin=newybins*nygroup and the remaining bins are added to
1445 /// the overflow bin.
1446 /// Statistics will be recomputed from the new bin contents.
1447 
1448 TProfile2D * TProfile2D::Rebin2D(Int_t nxgroup ,Int_t nygroup,const char * newname ) {
1449  //something to do?
1450  if((nxgroup != 1) || (nygroup != 1)){
1451  Int_t nxbins = fXaxis.GetNbins();
1452  Int_t nybins = fYaxis.GetNbins();
1453  Double_t xmin = fXaxis.GetXmin();
1454  Double_t xmax = fXaxis.GetXmax();
1455  Double_t ymin = fYaxis.GetXmin();
1456  Double_t ymax = fYaxis.GetXmax();
1457  if ((nxgroup <= 0) || (nxgroup > nxbins)) {
1458  Error("Rebin", "Illegal value of nxgroup=%d",nxgroup);
1459  return 0;
1460  }
1461  if ((nygroup <= 0) || (nygroup > nybins)) {
1462  Error("Rebin", "Illegal value of nygroup=%d",nygroup);
1463  return 0;
1464  }
1465 
1466  Int_t newxbins = nxbins/nxgroup;
1467  Int_t newybins = nybins/nygroup;
1468 
1469  //warning if bins are added to the overflow bin
1470  if(newxbins*nxgroup != nxbins) {
1471  Warning("Rebin", "nxgroup=%d should be an exact divider of nxbins=%d",nxgroup,nxbins);
1472  }
1473  if(newybins*nygroup != nybins) {
1474  Warning("Rebin", "nygroup=%d should be an exact divider of nybins=%d",nygroup,nybins);
1475  }
1476 
1477  //save old bin contents in new arrays
1478  Double_t *oldBins = new Double_t[(nxbins+2)*(nybins+2)];
1479  Double_t *oldCount = new Double_t[(nxbins+2)*(nybins+2)];
1480  Double_t *oldErrors = new Double_t[(nxbins+2)*(nybins+2)];
1481  Double_t *oldBinw2 = (fBinSumw2.fN ? new Double_t[(nxbins+2)*(nybins+2)] : 0 );
1482  Double_t *cu1 = GetW();
1483  Double_t *er1 = GetW2();
1484  Double_t *en1 = GetB();
1485  Double_t *ew1 = GetB2();
1486  for(Int_t ibin=0; ibin < (nxbins+2)*(nybins+2); ibin++){
1487  oldBins[ibin] = cu1[ibin];
1488  oldCount[ibin] = en1[ibin];
1489  oldErrors[ibin] = er1[ibin];
1490  if (ew1 && fBinSumw2.fN) oldBinw2[ibin] = ew1[ibin];
1491  }
1492 
1493  // create a clone of the old profile if newname is specified
1494  TProfile2D *hnew = this;
1495  if(newname && strlen(newname) > 0) {
1496  hnew = (TProfile2D*)Clone(newname);
1497  }
1498 
1499  // in case of nxgroup/nygroup not an exact divider of nxbins/nybins,
1500  // top limit is changed (see NOTE in method comment)
1501  if(newxbins*nxgroup != nxbins) {
1502  xmax = fXaxis.GetBinUpEdge(newxbins*nxgroup);
1503  hnew->fTsumw = 0; //stats must be reset because top bins will be moved to overflow bin
1504  }
1505  if(newybins*nygroup != nybins) {
1506  ymax = fYaxis.GetBinUpEdge(newybins*nygroup);
1507  hnew->fTsumw = 0; //stats must be reset because top bins will be moved to overflow bin
1508  }
1509 
1510  //rebin the axis
1511  if((fXaxis.GetXbins()->GetSize() > 0) || (fYaxis.GetXbins()->GetSize() > 0)){
1512  Double_t* xbins = new Double_t[newxbins+1];
1513  Double_t* ybins = new Double_t[newybins+1];
1514  for(Int_t i=0; i < newxbins+1; i++)
1515  xbins[i] = fXaxis.GetBinLowEdge(1+i*nxgroup);
1516  for(Int_t j=0; j < newybins+1; j++)
1517  ybins[j] = fYaxis.GetBinLowEdge(1+j*nygroup);
1518  hnew->SetBins(newxbins,xbins,newybins,ybins);
1519  delete [] xbins;
1520  delete [] ybins;
1521  }
1522  //fixed bin size
1523  else{
1524  hnew->SetBins(newxbins,xmin,xmax,newybins,ymin,ymax);
1525  }
1526 
1527  //merge bins
1528  Double_t *cu2 = hnew->GetW();
1529  Double_t *er2 = hnew->GetW2();
1530  Double_t *en2 = hnew->GetB();
1531  Double_t *ew2 = hnew->GetB2();
1532  Double_t binContent, binCount, binError, binSumw2;
1533  //connection between x and y bin number and linear global bin number:
1534  //global bin = xbin + (nxbins+2) * ybin
1535  Int_t oldxbin = 1;
1536  Int_t oldybin = 1;
1537  //global bin number
1538  Int_t bin;
1539  for(Int_t xbin = 1; xbin <= newxbins; xbin++){
1540  oldybin = 1;
1541  for(Int_t ybin = 1; ybin <= newybins; ybin++){
1542  binContent = 0;
1543  binCount = 0;
1544  binError = 0;
1545  binSumw2 = 0;
1546  for(Int_t i=0; i < nxgroup; i++){
1547  if(oldxbin + i > nxbins) break;
1548  for(Int_t j=0; j < nygroup; j++){
1549  if(oldybin + j > nybins) break;
1550  bin = oldxbin + i + (nxbins+2)*(oldybin+j);
1551  binContent += oldBins[bin];
1552  binCount += oldCount[bin];
1553  binError += oldErrors[bin];
1554  if(fBinSumw2.fN) binSumw2 += oldBinw2[bin];
1555  }
1556  }
1557  bin = xbin + (newxbins + 2)*ybin;
1558  cu2[bin] = binContent;
1559  er2[bin] = binError;
1560  en2[bin] = binCount;
1561  if(fBinSumw2.fN) ew2[bin] = binSumw2;
1562  oldybin += nygroup;
1563  }
1564  oldxbin += nxgroup;
1565  }
1566 
1567  //copy the underflow bin in x and y (0,0)
1568  cu2[0] = oldBins[0];
1569  er2[0] = oldErrors[0];
1570  en2[0] = oldCount[0];
1571  if(fBinSumw2.fN) ew2[0] = oldBinw2[0];
1572  //calculate overflow bin in x and y (newxbins+1,newybins+1)
1573  //therefore the oldxbin and oldybin from above are needed!
1574  binContent = 0;
1575  binCount = 0;
1576  binError = 0;
1577  binSumw2 = 0;
1578  for(Int_t i=oldxbin; i <= nxbins+1; i++){
1579  for(Int_t j=oldybin; j <= nybins+1; j++){
1580  //global bin number
1581  bin = i + (nxbins+2)*j;
1582  binContent += oldBins[bin];
1583  binCount += oldCount[bin];
1584  binError += oldErrors[bin];
1585  if(fBinSumw2.fN) binSumw2 += oldBinw2[bin];
1586  }
1587  }
1588  bin = (newxbins+2)*(newybins+2)-1;
1589  cu2[bin] = binContent;
1590  er2[bin] = binError;
1591  en2[bin] = binCount;
1592  if(fBinSumw2.fN) ew2[bin] = binSumw2;
1593  //calculate overflow bin in x and underflow bin in y (newxbins+1,0)
1594  binContent = 0;
1595  binCount = 0;
1596  binError = 0;
1597  binSumw2 = 0;
1598  for(Int_t i=oldxbin; i <= nxbins+1; i++){
1599  bin = i;
1600  binContent += oldBins[bin];
1601  binCount += oldCount[bin];
1602  binError += oldErrors[bin];
1603  if(fBinSumw2.fN) binSumw2 += oldBinw2[bin];
1604  }
1605  bin = newxbins + 1;
1606  cu2[bin] = binContent;
1607  er2[bin] = binError;
1608  en2[bin] = binCount;
1609  if(fBinSumw2.fN) ew2[bin] = binSumw2;
1610  //calculate underflow bin in x and overflow bin in y (0,newybins+1)
1611  binContent = 0;
1612  binCount = 0;
1613  binError = 0;
1614  binSumw2 = 0;
1615  for(Int_t i=oldybin; i <= nybins+1; i++){
1616  bin = i*(nxbins + 2);
1617  binContent += oldBins[bin];
1618  binCount += oldCount[bin];
1619  binError += oldErrors[bin];
1620  if(fBinSumw2.fN) binSumw2 += oldBinw2[bin];
1621  }
1622  bin = (newxbins + 2)*(newybins + 1);
1623  cu2[bin] = binContent;
1624  er2[bin] = binError;
1625  en2[bin] = binCount;
1626  if(fBinSumw2.fN) ew2[bin] = binSumw2;
1627  //calculate under/overflow contents in y for the new x bins
1628  Double_t binContentuf, binCountuf, binErroruf, binSumw2uf;
1629  Double_t binContentof, binCountof, binErrorof, binSumw2of;
1630  Int_t ufbin, ofbin;
1631  Int_t oldxbin2 = 1;
1632  for(Int_t xbin = 1; xbin <= newxbins; xbin++){
1633  binContentuf = 0;
1634  binCountuf = 0;
1635  binErroruf = 0;
1636  binSumw2uf = 0;
1637  binContentof = 0;
1638  binCountof = 0;
1639  binErrorof = 0;
1640  binSumw2of = 0;
1641  for(Int_t i = 0; i < nxgroup; i++){
1642  //index of under/overflow bin for y in old binning
1643  ufbin = (oldxbin2 + i);
1644  binContentuf += oldBins[ufbin];
1645  binCountuf += oldCount[ufbin];
1646  binErroruf += oldErrors[ufbin];
1647  if(fBinSumw2.fN) binSumw2uf += oldBinw2[ufbin];
1648  for(Int_t j = oldybin; j <= nybins+1; j++)
1649  {
1650  ofbin = ufbin + j*(nxbins + 2);
1651  binContentof += oldBins[ofbin];
1652  binCountof += oldCount[ofbin];
1653  binErrorof += oldErrors[ofbin];
1654  if(fBinSumw2.fN) binSumw2of += oldBinw2[ofbin];
1655  }
1656  }
1657  //index of under/overflow bin for y in new binning
1658  ufbin = xbin;
1659  ofbin = ufbin + (newybins + 1)*(newxbins + 2);
1660  cu2[ufbin] = binContentuf;
1661  er2[ufbin] = binErroruf;
1662  en2[ufbin] = binCountuf;
1663  if(fBinSumw2.fN) ew2[ufbin] = binSumw2uf;
1664  cu2[ofbin] = binContentof;
1665  er2[ofbin] = binErrorof;
1666  en2[ofbin] = binCountof;
1667  if(fBinSumw2.fN) ew2[ofbin] = binSumw2of;
1668 
1669  oldxbin2 += nxgroup;
1670  }
1671  //calculate under/overflow contents in x for the new y bins
1672  Int_t oldybin2 = 1;
1673  for(Int_t ybin = 1; ybin <= newybins; ybin++){
1674  binContentuf = 0;
1675  binCountuf = 0;
1676  binErroruf = 0;
1677  binSumw2uf = 0;
1678  binContentof = 0;
1679  binCountof = 0;
1680  binErrorof = 0;
1681  binSumw2of = 0;
1682  for(Int_t i = 0; i < nygroup; i++){
1683  //index of under/overflow bin for x in old binning
1684  ufbin = (oldybin2 + i)*(nxbins+2);
1685  binContentuf += oldBins[ufbin];
1686  binCountuf += oldCount[ufbin];
1687  binErroruf += oldErrors[ufbin];
1688  if(fBinSumw2.fN) binSumw2uf += oldBinw2[ufbin];
1689  for(Int_t j = oldxbin; j <= nxbins+1; j++)
1690  {
1691  ofbin = j + ufbin;
1692  binContentof += oldBins[ofbin];
1693  binCountof += oldCount[ofbin];
1694  binErrorof += oldErrors[ofbin];
1695  if(fBinSumw2.fN) binSumw2of += oldBinw2[ofbin];
1696  }
1697  }
1698  //index of under/overflow bin for x in new binning
1699  ufbin = ybin * (newxbins + 2);
1700  ofbin = newxbins + 1 + ufbin;
1701  cu2[ufbin] = binContentuf;
1702  er2[ufbin] = binErroruf;
1703  en2[ufbin] = binCountuf;
1704  if(fBinSumw2.fN) ew2[ufbin] = binSumw2uf;
1705  cu2[ofbin] = binContentof;
1706  er2[ofbin] = binErrorof;
1707  en2[ofbin] = binCountof;
1708  if(fBinSumw2.fN) ew2[ofbin] = binSumw2of;
1709 
1710  oldybin2 += nygroup;
1711  }
1712 
1713  delete [] oldBins;
1714  delete [] oldCount;
1715  delete [] oldErrors;
1716  if (oldBinw2) delete [] oldBinw2;
1717 
1718  return hnew;
1719  }
1720  //nxgroup == nygroup == 1
1721  else{
1722  if((newname) && (strlen(newname) > 0))
1723  return (TProfile2D*)Clone(newname);
1724  else
1725  return this;
1726  }
1727 }
1728 
1729 ////////////////////////////////////////////////////////////////////////////////
1730 /// Rebin only the X axis.
1731 /// see Rebin2D
1732 
1733 TProfile2D * TProfile2D::RebinX(Int_t ngroup,const char * newname ) {
1734  return Rebin2D(ngroup,1,newname);
1735 }
1736 
1737 ////////////////////////////////////////////////////////////////////////////////
1738 /// Rebin only the Y axis.
1739 /// see Rebin2D
1740 
1741 TProfile2D * TProfile2D::RebinY(Int_t ngroup,const char * newname ) {
1742  return Rebin2D(1,ngroup,newname);
1743 }
1744 
1745 ////////////////////////////////////////////////////////////////////////////////
1746 /// Save primitive as a C++ statement(s) on output stream out.
1747 ///
1748 /// Note the following restrictions in the code generated:
1749 /// - variable bin size not implemented
1750 /// - SetErrorOption not implemented
1751 
1752 void TProfile2D::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1753 {
1754  char quote = '"';
1755  out <<" "<<std::endl;
1756  out <<" "<<ClassName()<<" *";
1757 
1758  out << GetName() << " = new " << ClassName() << "(" << quote
1759  << GetName() << quote << "," << quote<< GetTitle() << quote
1760  << "," << GetXaxis()->GetNbins();
1761  out << "," << GetXaxis()->GetXmin()
1762  << "," << GetXaxis()->GetXmax();
1763  out << "," << GetYaxis()->GetNbins();
1764  out << "," << GetYaxis()->GetXmin()
1765  << "," << GetYaxis()->GetXmax();
1766  out << "," << fZmin
1767  << "," << fZmax;
1768  out << ");" << std::endl;
1769 
1770 
1771  // save bin entries
1772  Int_t bin;
1773  for (bin=0;bin<fNcells;bin++) {
1774  Double_t bi = GetBinEntries(bin);
1775  if (bi) {
1776  out<<" "<<GetName()<<"->SetBinEntries("<<bin<<","<<bi<<");"<<std::endl;
1777  }
1778  }
1779  //save bin contents
1780  for (bin=0;bin<fNcells;bin++) {
1781  Double_t bc = fArray[bin];
1782  if (bc) {
1783  out<<" "<<GetName()<<"->SetBinContent("<<bin<<","<<bc<<");"<<std::endl;
1784  }
1785  }
1786  // save bin errors
1787  if (fSumw2.fN) {
1788  for (bin=0;bin<fNcells;bin++) {
1789  Double_t be = TMath::Sqrt(fSumw2.fArray[bin]);
1790  if (be) {
1791  out<<" "<<GetName()<<"->SetBinError("<<bin<<","<<be<<");"<<std::endl;
1792  }
1793  }
1794  }
1795 
1796  TH1::SavePrimitiveHelp(out, GetName(), option);
1797 }
1798 
1799 ////////////////////////////////////////////////////////////////////////////////
1800 /// Multiply this profile2D by a constant c1.
1801 ///
1802 /// `this = c1*this
1803 ///
1804 /// This function uses the services of TProfile2D::Add
1805 
1806 void TProfile2D::Scale(Double_t c1, Option_t * option)
1807 {
1808  TProfileHelper::Scale(this, c1, option);
1809 }
1810 
1811 ////////////////////////////////////////////////////////////////////////////////
1812 /// Set the number of entries in bin.
1813 
1814 void TProfile2D::SetBinEntries(Int_t bin, Double_t w)
1815 {
1816  TProfileHelper::SetBinEntries(this, bin, w);
1817 }
1818 
1819 ////////////////////////////////////////////////////////////////////////////////
1820 /// Redefine x and y axis parameters.
1821 
1822 void TProfile2D::SetBins(Int_t nx, Double_t xmin, Double_t xmax, Int_t ny, Double_t ymin, Double_t ymax)
1823 {
1824  TH1::SetBins(nx,xmin, xmax,ny, ymin,ymax);
1825  fBinEntries.Set(fNcells);
1826  if (fBinSumw2.fN) fBinSumw2.Set(fNcells);
1827 }
1828 
1829 ////////////////////////////////////////////////////////////////////////////////
1830 /// Redefine x and y axis parameters for variable bin sizes.
1831 
1832 void TProfile2D::SetBins(Int_t nx, const Double_t *xbins, Int_t ny, const Double_t *ybins)
1833 {
1834  TH1::SetBins(nx,xbins,ny,ybins);
1835  fBinEntries.Set(fNcells);
1836  if (fBinSumw2.fN) fBinSumw2.Set(fNcells);
1837 }
1838 
1839 ////////////////////////////////////////////////////////////////////////////////
1840 /// Set total number of bins including under/overflow.
1841 /// Reallocate bin contents array
1842 
1843 void TProfile2D::SetBinsLength(Int_t n)
1844 {
1845  TH2D::SetBinsLength(n);
1846  TProfileHelper::BuildArray(this);
1847 }
1848 
1849 ////////////////////////////////////////////////////////////////////////////////
1850 /// Set the buffer size in units of 8 bytes (double).
1851 
1852 void TProfile2D::SetBuffer(Int_t buffersize, Option_t *)
1853 {
1854  if (fBuffer) {
1855  BufferEmpty();
1856  delete [] fBuffer;
1857  fBuffer = 0;
1858  }
1859  if (buffersize <= 0) {
1860  fBufferSize = 0;
1861  return;
1862  }
1863  if (buffersize < 100) buffersize = 100;
1864  fBufferSize = 1 + 4*buffersize;
1865  fBuffer = new Double_t[fBufferSize];
1866  memset(fBuffer,0,sizeof(Double_t)*fBufferSize);
1867 }
1868 
1869 ////////////////////////////////////////////////////////////////////////////////
1870 /// Set option to compute profile2D errors.
1871 ///
1872 /// The computation of the bin errors is based on the parameter option:
1873 /// - ' ' (Default) The bin errors are the standard error on the mean of the bin profiled values (Z),
1874 /// i.e. the standard error of the bin contents.
1875 /// Note that if TProfile::Approximate() is called, an approximation is used when
1876 /// the spread in Z is 0 and the number of bin entries is > 0
1877 /// - 's' The bin errors are the standard deviations of the Z bin values
1878 /// Note that if TProfile::Approximate() is called, an approximation is used when
1879 /// the spread in Z is 0 and the number of bin entries is > 0
1880 /// - 'i' Errors are as in default case (standard errors of the bin contents)
1881 /// The only difference is for the case when the spread in Z is zero.
1882 /// In this case for N > 0 the error is 1./SQRT(12.*N)
1883 /// - 'g' Errors are 1./SQRT(W) for W not equal to 0 and 0 for W = 0.
1884 /// W is the sum in the bin of the weights of the profile.
1885 /// This option is for combining measurements z +/- dz,
1886 /// and the profile is filled with values y and weights z = 1/dz**2
1887 ///
1888 /// See TProfile::BuildOptions for a detailed explanation of all options
1889 
1890 void TProfile2D::SetErrorOption(Option_t *option)
1891 {
1892  TProfileHelper::SetErrorOption(this, option);
1893 }
1894 
1895 ////////////////////////////////////////////////////////////////////////////////
1896 /// Stream an object of class TProfile2D.
1897 
1898 void TProfile2D::Streamer(TBuffer &R__b)
1899 {
1900  if (R__b.IsReading()) {
1901  UInt_t R__s, R__c;
1902  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
1903  if (R__v > 2) {
1904  R__b.ReadClassBuffer(TProfile2D::Class(), this, R__v, R__s, R__c);
1905  return;
1906  }
1907  //====process old versions before automatic schema evolution
1908  TH2D::Streamer(R__b);
1909  fBinEntries.Streamer(R__b);
1910  Int_t errorMode;
1911  R__b >> errorMode;
1912  fErrorMode = (EErrorType)errorMode;
1913  if (R__v < 2) {
1914  Float_t zmin,zmax;
1915  R__b >> zmin; fZmin = zmin;
1916  R__b >> zmax; fZmax = zmax;
1917  } else {
1918  R__b >> fZmin;
1919  R__b >> fZmax;
1920  }
1921  R__b.CheckByteCount(R__s, R__c, TProfile2D::IsA());
1922  //====end of old versions
1923 
1924  } else {
1925  R__b.WriteClassBuffer(TProfile2D::Class(),this);
1926  }
1927 }
1928 
1929 ////////////////////////////////////////////////////////////////////////////////
1930 /// Create/Delete structure to store sum of squares of weights per bin.
1931 ///
1932 /// This is needed to compute the correct statistical quantities
1933 /// of a profile filled with weights
1934 ///
1935 /// This function is automatically called when the histogram is created
1936 /// if the static function TH1::SetDefaultSumw2 has been called before.
1937 /// If flag is false the structure is deleted
1938 
1939 void TProfile2D::Sumw2(Bool_t flag)
1940 {
1941  TProfileHelper::Sumw2(this, flag);
1942 }