Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TH3.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 27/10/95
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 "TROOT.h"
13 #include "TClass.h"
14 #include "THashList.h"
15 #include "TH3.h"
16 #include "TProfile2D.h"
17 #include "TH2.h"
18 #include "TF3.h"
19 #include "TVirtualPad.h"
20 #include "TVirtualHistPainter.h"
21 #include "THLimitsFinder.h"
22 #include "TRandom.h"
23 #include "TError.h"
24 #include "TMath.h"
25 #include "TObjString.h"
26 
27 ClassImp(TH3);
28 
29 /** \addtogroup Hist
30 @{
31 \class TH3C
32 \brief 3-D histogram with a byte per channel (see TH1 documentation)
33 \class TH3S
34 \brief 3-D histogram with a short per channel (see TH1 documentation)
35 \class TH3I
36 \brief 3-D histogram with an int per channel (see TH1 documentation)}
37 \class TH3F
38 \brief 3-D histogram with a float per channel (see TH1 documentation)}
39 \class TH3D
40 \brief 3-D histogram with a double per channel (see TH1 documentation)}
41 @}
42 */
43 
44 /** \class TH3
45  \ingroup Hist
46 The 3-D histogram classes derived from the 1-D histogram classes.
47 All operations are supported (fill, fit).
48 Drawing is currently restricted to one single option.
49 A cloud of points is drawn. The number of points is proportional to
50 cell content.
51 
52 - TH3C a 3-D histogram with one byte per cell (char)
53 - TH3S a 3-D histogram with two bytes per cell (short integer)
54 - TH3I a 3-D histogram with four bytes per cell (32 bits integer)
55 - TH3F a 3-D histogram with four bytes per cell (float)
56 - TH3D a 3-D histogram with eight bytes per cell (double)
57 */
58 
59 
60 ////////////////////////////////////////////////////////////////////////////////
61 /// Default constructor.
62 
63 TH3::TH3()
64 {
65  fDimension = 3;
66  fTsumwy = fTsumwy2 = fTsumwxy = 0;
67  fTsumwz = fTsumwz2 = fTsumwxz = fTsumwyz = 0;
68 }
69 
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 /// Normal constructor for fix bin size 3-D histograms.
73 
74 TH3::TH3(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
75  ,Int_t nbinsy,Double_t ylow,Double_t yup
76  ,Int_t nbinsz,Double_t zlow,Double_t zup)
77  :TH1(name,title,nbinsx,xlow,xup),
78  TAtt3D()
79 {
80  fDimension = 3;
81  if (nbinsy <= 0) {
82  Warning("TH3","nbinsy is <=0 - set to nbinsy = 1");
83  nbinsy = 1;
84  }
85  if (nbinsz <= 0) {
86  Warning("TH3","nbinsz is <=0 - set to nbinsz = 1");
87  nbinsz = 1;
88  }
89  fYaxis.Set(nbinsy,ylow,yup);
90  fZaxis.Set(nbinsz,zlow,zup);
91  fNcells = (nbinsx+2)*(nbinsy+2)*(nbinsz+2);
92  fTsumwy = fTsumwy2 = fTsumwxy = 0;
93  fTsumwz = fTsumwz2 = fTsumwxz = fTsumwyz = 0;
94 }
95 
96 
97 ////////////////////////////////////////////////////////////////////////////////
98 /// Normal constructor for variable bin size 3-D histograms.
99 
100 TH3::TH3(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
101  ,Int_t nbinsy,const Float_t *ybins
102  ,Int_t nbinsz,const Float_t *zbins)
103  :TH1(name,title,nbinsx,xbins),
104  TAtt3D()
105 {
106  fDimension = 3;
107  if (nbinsy <= 0) {Warning("TH3","nbinsy is <=0 - set to nbinsy = 1"); nbinsy = 1; }
108  if (nbinsz <= 0) nbinsz = 1;
109  if (ybins) fYaxis.Set(nbinsy,ybins);
110  else fYaxis.Set(nbinsy,0,1);
111  if (zbins) fZaxis.Set(nbinsz,zbins);
112  else fZaxis.Set(nbinsz,0,1);
113  fNcells = (nbinsx+2)*(nbinsy+2)*(nbinsz+2);
114  fTsumwy = fTsumwy2 = fTsumwxy = 0;
115  fTsumwz = fTsumwz2 = fTsumwxz = fTsumwyz = 0;
116 }
117 
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// Normal constructor for variable bin size 3-D histograms.
121 
122 TH3::TH3(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
123  ,Int_t nbinsy,const Double_t *ybins
124  ,Int_t nbinsz,const Double_t *zbins)
125  :TH1(name,title,nbinsx,xbins),
126  TAtt3D()
127 {
128  fDimension = 3;
129  if (nbinsy <= 0) {Warning("TH3","nbinsy is <=0 - set to nbinsy = 1"); nbinsy = 1; }
130  if (nbinsz <= 0) nbinsz = 1;
131  if (ybins) fYaxis.Set(nbinsy,ybins);
132  else fYaxis.Set(nbinsy,0,1);
133  if (zbins) fZaxis.Set(nbinsz,zbins);
134  else fZaxis.Set(nbinsz,0,1);
135  fNcells = (nbinsx+2)*(nbinsy+2)*(nbinsz+2);
136  fTsumwy = fTsumwy2 = fTsumwxy = 0;
137  fTsumwz = fTsumwz2 = fTsumwxz = fTsumwyz = 0;
138 }
139 
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 /// Copy constructor.
143 /// The list of functions is not copied. (Use Clone if needed)
144 
145 TH3::TH3(const TH3 &h) : TH1(), TAtt3D()
146 {
147  ((TH3&)h).Copy(*this);
148 }
149 
150 
151 ////////////////////////////////////////////////////////////////////////////////
152 /// Destructor.
153 
154 TH3::~TH3()
155 {
156 }
157 
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 /// Copy.
161 
162 void TH3::Copy(TObject &obj) const
163 {
164  TH1::Copy(obj);
165  ((TH3&)obj).fTsumwy = fTsumwy;
166  ((TH3&)obj).fTsumwy2 = fTsumwy2;
167  ((TH3&)obj).fTsumwxy = fTsumwxy;
168  ((TH3&)obj).fTsumwz = fTsumwz;
169  ((TH3&)obj).fTsumwz2 = fTsumwz2;
170  ((TH3&)obj).fTsumwxz = fTsumwxz;
171  ((TH3&)obj).fTsumwyz = fTsumwyz;
172 }
173 
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// Fill histogram with all entries in the buffer.
177 /// action = -1 histogram is reset and refilled from the buffer (called by THistPainter::Paint)
178 /// action = 0 histogram is filled from the buffer
179 /// action = 1 histogram is filled and buffer is deleted
180 /// The buffer is automatically deleted when the number of entries
181 /// in the buffer is greater than the number of entries in the histogram
182 
183 Int_t TH3::BufferEmpty(Int_t action)
184 {
185  // do we need to compute the bin size?
186  if (!fBuffer) return 0;
187  Int_t nbentries = (Int_t)fBuffer[0];
188  if (!nbentries) return 0;
189  Double_t *buffer = fBuffer;
190  if (nbentries < 0) {
191  if (action == 0) return 0;
192  nbentries = -nbentries;
193  fBuffer=0;
194  Reset("ICES");
195  fBuffer = buffer;
196  }
197  if (CanExtendAllAxes() || fXaxis.GetXmax() <= fXaxis.GetXmin() ||
198  fYaxis.GetXmax() <= fYaxis.GetXmin() ||
199  fZaxis.GetXmax() <= fZaxis.GetXmin()) {
200  //find min, max of entries in buffer
201  Double_t xmin = fBuffer[2];
202  Double_t xmax = xmin;
203  Double_t ymin = fBuffer[3];
204  Double_t ymax = ymin;
205  Double_t zmin = fBuffer[4];
206  Double_t zmax = zmin;
207  for (Int_t i=1;i<nbentries;i++) {
208  Double_t x = fBuffer[4*i+2];
209  if (x < xmin) xmin = x;
210  if (x > xmax) xmax = x;
211  Double_t y = fBuffer[4*i+3];
212  if (y < ymin) ymin = y;
213  if (y > ymax) ymax = y;
214  Double_t z = fBuffer[4*i+4];
215  if (z < zmin) zmin = z;
216  if (z > zmax) zmax = z;
217  }
218  if (fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin() || fZaxis.GetXmax() <= fZaxis.GetXmin()) {
219  THLimitsFinder::GetLimitsFinder()->FindGoodLimits(this,xmin,xmax,ymin,ymax,zmin,zmax);
220  } else {
221  fBuffer = 0;
222  Int_t keep = fBufferSize; fBufferSize = 0;
223  if (xmin < fXaxis.GetXmin()) ExtendAxis(xmin,&fXaxis);
224  if (xmax >= fXaxis.GetXmax()) ExtendAxis(xmax,&fXaxis);
225  if (ymin < fYaxis.GetXmin()) ExtendAxis(ymin,&fYaxis);
226  if (ymax >= fYaxis.GetXmax()) ExtendAxis(ymax,&fYaxis);
227  if (zmin < fZaxis.GetXmin()) ExtendAxis(zmin,&fZaxis);
228  if (zmax >= fZaxis.GetXmax()) ExtendAxis(zmax,&fZaxis);
229  fBuffer = buffer;
230  fBufferSize = keep;
231  }
232  }
233  fBuffer = 0;
234 
235  for (Int_t i=0;i<nbentries;i++) {
236  Fill(buffer[4*i+2],buffer[4*i+3],buffer[4*i+4],buffer[4*i+1]);
237  }
238  fBuffer = buffer;
239 
240  if (action > 0) { delete [] fBuffer; fBuffer = 0; fBufferSize = 0;}
241  else {
242  if (nbentries == (Int_t)fEntries) fBuffer[0] = -nbentries;
243  else fBuffer[0] = 0;
244  }
245  return nbentries;
246 }
247 
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// accumulate arguments in buffer. When buffer is full, empty the buffer
251 /// fBuffer[0] = number of entries in buffer
252 /// fBuffer[1] = w of first entry
253 /// fBuffer[2] = x of first entry
254 /// fBuffer[3] = y of first entry
255 /// fBuffer[4] = z of first entry
256 
257 Int_t TH3::BufferFill(Double_t x, Double_t y, Double_t z, Double_t w)
258 {
259  if (!fBuffer) return -3;
260  Int_t nbentries = (Int_t)fBuffer[0];
261  if (nbentries < 0) {
262  nbentries = -nbentries;
263  fBuffer[0] = nbentries;
264  if (fEntries > 0) {
265  Double_t *buffer = fBuffer; fBuffer=0;
266  Reset("ICES");
267  fBuffer = buffer;
268  }
269  }
270  if (4*nbentries+4 >= fBufferSize) {
271  BufferEmpty(1);
272  return Fill(x,y,z,w);
273  }
274  fBuffer[4*nbentries+1] = w;
275  fBuffer[4*nbentries+2] = x;
276  fBuffer[4*nbentries+3] = y;
277  fBuffer[4*nbentries+4] = z;
278  fBuffer[0] += 1;
279  return -3;
280 }
281 
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Invalid Fill method
285 
286 Int_t TH3::Fill(Double_t )
287 {
288  Error("Fill", "Invalid signature - do nothing");
289  return -1;
290 }
291 
292 
293 ////////////////////////////////////////////////////////////////////////////////
294 /// Increment cell defined by x,y,z by 1 .
295 ///
296 /// The function returns the corresponding global bin number which has its content
297 /// incremented by 1
298 
299 Int_t TH3::Fill(Double_t x, Double_t y, Double_t z)
300 {
301  if (fBuffer) return BufferFill(x,y,z,1);
302 
303  Int_t binx, biny, binz, bin;
304  fEntries++;
305  binx = fXaxis.FindBin(x);
306  biny = fYaxis.FindBin(y);
307  binz = fZaxis.FindBin(z);
308  if (binx <0 || biny <0 || binz<0) return -1;
309  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
310  if (fSumw2.fN) ++fSumw2.fArray[bin];
311  AddBinContent(bin);
312  if (binx == 0 || binx > fXaxis.GetNbins()) {
313  if (!GetStatOverflowsBehaviour()) return -1;
314  }
315 
316  if (biny == 0 || biny > fYaxis.GetNbins()) {
317  if (!GetStatOverflowsBehaviour()) return -1;
318  }
319  if (binz == 0 || binz > fZaxis.GetNbins()) {
320  if (!GetStatOverflowsBehaviour()) return -1;
321  }
322  ++fTsumw;
323  ++fTsumw2;
324  fTsumwx += x;
325  fTsumwx2 += x*x;
326  fTsumwy += y;
327  fTsumwy2 += y*y;
328  fTsumwxy += x*y;
329  fTsumwz += z;
330  fTsumwz2 += z*z;
331  fTsumwxz += x*z;
332  fTsumwyz += y*z;
333  return bin;
334 }
335 
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Increment cell defined by x,y,z by a weight w.
339 ///
340 /// If the weight is not equal to 1, the storage of the sum of squares of
341 /// weights is automatically triggered and the sum of the squares of weights is incremented
342 /// by w^2 in the cell corresponding to x,y,z.
343 ///
344 /// The function returns the corresponding global bin number which has its content
345 /// incremented by w
346 
347 Int_t TH3::Fill(Double_t x, Double_t y, Double_t z, Double_t w)
348 {
349  if (fBuffer) return BufferFill(x,y,z,w);
350 
351  Int_t binx, biny, binz, bin;
352  fEntries++;
353  binx = fXaxis.FindBin(x);
354  biny = fYaxis.FindBin(y);
355  binz = fZaxis.FindBin(z);
356  if (binx <0 || biny <0 || binz<0) return -1;
357  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
358  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
359  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
360  AddBinContent(bin,w);
361  if (binx == 0 || binx > fXaxis.GetNbins()) {
362  if (!GetStatOverflowsBehaviour()) return -1;
363  }
364  if (biny == 0 || biny > fYaxis.GetNbins()) {
365  if (!GetStatOverflowsBehaviour()) return -1;
366  }
367  if (binz == 0 || binz > fZaxis.GetNbins()) {
368  if (!GetStatOverflowsBehaviour()) return -1;
369  }
370  fTsumw += w;
371  fTsumw2 += w*w;
372  fTsumwx += w*x;
373  fTsumwx2 += w*x*x;
374  fTsumwy += w*y;
375  fTsumwy2 += w*y*y;
376  fTsumwxy += w*x*y;
377  fTsumwz += w*z;
378  fTsumwz2 += w*z*z;
379  fTsumwxz += w*x*z;
380  fTsumwyz += w*y*z;
381  return bin;
382 }
383 
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Increment cell defined by namex,namey,namez by a weight w
387 ///
388 /// If the weight is not equal to 1, the storage of the sum of squares of
389 /// weights is automatically triggered and the sum of the squares of weights is incremented
390 /// by w^2 in the corresponding cell.
391 /// The function returns the corresponding global bin number which has its content
392 /// incremented by w
393 
394 Int_t TH3::Fill(const char *namex, const char *namey, const char *namez, Double_t w)
395 {
396  Int_t binx, biny, binz, bin;
397  fEntries++;
398  binx = fXaxis.FindBin(namex);
399  biny = fYaxis.FindBin(namey);
400  binz = fZaxis.FindBin(namez);
401  if (binx <0 || biny <0 || binz<0) return -1;
402  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
403  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
404  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
405  AddBinContent(bin,w);
406  if (binx == 0 || binx > fXaxis.GetNbins()) return -1;
407  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
408  if (binz == 0 || binz > fZaxis.GetNbins()) return -1;
409  Double_t x = fXaxis.GetBinCenter(binx);
410  Double_t y = fYaxis.GetBinCenter(biny);
411  Double_t z = fZaxis.GetBinCenter(binz);
412  Double_t v = w;
413  fTsumw += v;
414  fTsumw2 += v*v;
415  fTsumwx += v*x;
416  fTsumwx2 += v*x*x;
417  fTsumwy += v*y;
418  fTsumwy2 += v*y*y;
419  fTsumwxy += v*x*y;
420  fTsumwz += v*z;
421  fTsumwz2 += v*z*z;
422  fTsumwxz += v*x*z;
423  fTsumwyz += v*y*z;
424  return bin;
425 }
426 
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// Increment cell defined by namex,y,namez by a weight w
430 ///
431 /// If the weight is not equal to 1, the storage of the sum of squares of
432 /// weights is automatically triggered and the sum of the squares of weights is incremented
433 /// by w^2 in the corresponding cell.
434 /// The function returns the corresponding global bin number which has its content
435 /// incremented by w
436 
437 Int_t TH3::Fill(const char *namex, Double_t y, const char *namez, Double_t w)
438 {
439  Int_t binx, biny, binz, bin;
440  fEntries++;
441  binx = fXaxis.FindBin(namex);
442  biny = fYaxis.FindBin(y);
443  binz = fZaxis.FindBin(namez);
444  if (binx <0 || biny <0 || binz<0) return -1;
445  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
446  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
447  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
448  AddBinContent(bin,w);
449  if (binx == 0 || binx > fXaxis.GetNbins()) return -1;
450  if (biny == 0 || biny > fYaxis.GetNbins()) {
451  if (!GetStatOverflowsBehaviour()) return -1;
452  }
453  if (binz == 0 || binz > fZaxis.GetNbins()) return -1;
454  Double_t x = fXaxis.GetBinCenter(binx);
455  Double_t z = fZaxis.GetBinCenter(binz);
456  Double_t v = w;
457  fTsumw += v;
458  fTsumw2 += v*v;
459  fTsumwx += v*x;
460  fTsumwx2 += v*x*x;
461  fTsumwy += v*y;
462  fTsumwy2 += v*y*y;
463  fTsumwxy += v*x*y;
464  fTsumwz += v*z;
465  fTsumwz2 += v*z*z;
466  fTsumwxz += v*x*z;
467  fTsumwyz += v*y*z;
468  return bin;
469 }
470 
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Increment cell defined by namex,namey,z by a weight w
474 ///
475 /// If the weight is not equal to 1, the storage of the sum of squares of
476 /// weights is automatically triggered and the sum of the squares of weights is incremented
477 /// by w^2 in the corresponding cell.
478 /// The function returns the corresponding global bin number which has its content
479 /// incremented by w
480 
481 Int_t TH3::Fill(const char *namex, const char *namey, Double_t z, Double_t w)
482 {
483  Int_t binx, biny, binz, bin;
484  fEntries++;
485  binx = fXaxis.FindBin(namex);
486  biny = fYaxis.FindBin(namey);
487  binz = fZaxis.FindBin(z);
488  if (binx <0 || biny <0 || binz<0) return -1;
489  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
490  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
491  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
492  AddBinContent(bin,w);
493  if (binx == 0 || binx > fXaxis.GetNbins()) return -1;
494  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
495  if (binz == 0 || binz > fZaxis.GetNbins()) {
496  if (!GetStatOverflowsBehaviour()) return -1;
497  }
498  Double_t x = fXaxis.GetBinCenter(binx);
499  Double_t y = fYaxis.GetBinCenter(biny);
500  Double_t v = w;
501  fTsumw += v;
502  fTsumw2 += v*v;
503  fTsumwx += v*x;
504  fTsumwx2 += v*x*x;
505  fTsumwy += v*y;
506  fTsumwy2 += v*y*y;
507  fTsumwxy += v*x*y;
508  fTsumwz += v*z;
509  fTsumwz2 += v*z*z;
510  fTsumwxz += v*x*z;
511  fTsumwyz += v*y*z;
512  return bin;
513 }
514 
515 
516 ////////////////////////////////////////////////////////////////////////////////
517 /// Increment cell defined by x,namey,namez by a weight w
518 ///
519 /// If the weight is not equal to 1, the storage of the sum of squares of
520 /// weights is automatically triggered and the sum of the squares of weights is incremented
521 /// by w^2 in the corresponding cell.
522 /// The function returns the corresponding global bin number which has its content
523 /// incremented by w
524 
525 Int_t TH3::Fill(Double_t x, const char *namey, const char *namez, Double_t w)
526 {
527  Int_t binx, biny, binz, bin;
528  fEntries++;
529  binx = fXaxis.FindBin(x);
530  biny = fYaxis.FindBin(namey);
531  binz = fZaxis.FindBin(namez);
532  if (binx <0 || biny <0 || binz<0) return -1;
533  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
534  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
535  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
536  AddBinContent(bin,w);
537  if (binx == 0 || binx > fXaxis.GetNbins()) {
538  if (!GetStatOverflowsBehaviour()) return -1;
539  }
540  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
541  if (binz == 0 || binz > fZaxis.GetNbins()) return -1;
542  Double_t y = fYaxis.GetBinCenter(biny);
543  Double_t z = fZaxis.GetBinCenter(binz);
544  Double_t v = w;
545  fTsumw += v;
546  fTsumw2 += v*v;
547  fTsumwx += v*x;
548  fTsumwx2 += v*x*x;
549  fTsumwy += v*y;
550  fTsumwy2 += v*y*y;
551  fTsumwxy += v*x*y;
552  fTsumwz += v*z;
553  fTsumwz2 += v*z*z;
554  fTsumwxz += v*x*z;
555  fTsumwyz += v*y*z;
556  return bin;
557 }
558 
559 
560 ////////////////////////////////////////////////////////////////////////////////
561 /// Increment cell defined by x,namey,z by a weight w
562 ///
563 /// If the weight is not equal to 1, the storage of the sum of squares of
564 /// weights is automatically triggered and the sum of the squares of weights is incremented
565 /// by w^2 in the corresponding cell.
566 /// The function returns the corresponding global bin number which has its content
567 /// incremented by w
568 
569 Int_t TH3::Fill(Double_t x, const char *namey, Double_t z, Double_t w)
570 {
571  Int_t binx, biny, binz, bin;
572  fEntries++;
573  binx = fXaxis.FindBin(x);
574  biny = fYaxis.FindBin(namey);
575  binz = fZaxis.FindBin(z);
576  if (binx <0 || biny <0 || binz<0) return -1;
577  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
578  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
579  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
580  AddBinContent(bin,w);
581  if (binx == 0 || binx > fXaxis.GetNbins()) {
582  if (!GetStatOverflowsBehaviour()) return -1;
583  }
584  if (biny == 0 || biny > fYaxis.GetNbins()) return -1;
585  if (binz == 0 || binz > fZaxis.GetNbins()) {
586  if (!GetStatOverflowsBehaviour()) return -1;
587  }
588  Double_t y = fYaxis.GetBinCenter(biny);
589  Double_t v = w;
590  fTsumw += v;
591  fTsumw2 += v*v;
592  fTsumwx += v*x;
593  fTsumwx2 += v*x*x;
594  fTsumwy += v*y;
595  fTsumwy2 += v*y*y;
596  fTsumwxy += v*x*y;
597  fTsumwz += v*z;
598  fTsumwz2 += v*z*z;
599  fTsumwxz += v*x*z;
600  fTsumwyz += v*y*z;
601  return bin;
602 }
603 
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 /// Increment cell defined by x,y,namez by a weight w
607 ///
608 /// If the weight is not equal to 1, the storage of the sum of squares of
609 /// weights is automatically triggered and the sum of the squares of weights is incremented
610 /// by w^2 in the corresponding cell.
611 /// The function returns the corresponding global bin number which has its content
612 /// incremented by w
613 
614 Int_t TH3::Fill(Double_t x, Double_t y, const char *namez, Double_t w)
615 {
616  Int_t binx, biny, binz, bin;
617  fEntries++;
618  binx = fXaxis.FindBin(x);
619  biny = fYaxis.FindBin(y);
620  binz = fZaxis.FindBin(namez);
621  if (binx <0 || biny <0 || binz<0) return -1;
622  bin = binx + (fXaxis.GetNbins()+2)*(biny + (fYaxis.GetNbins()+2)*binz);
623  if (!fSumw2.fN && w != 1.0 && !TestBit(TH1::kIsNotW)) Sumw2(); // must be called before AddBinContent
624  if (fSumw2.fN) fSumw2.fArray[bin] += w*w;
625  AddBinContent(bin,w);
626  if (binx == 0 || binx > fXaxis.GetNbins()) {
627  if (!GetStatOverflowsBehaviour()) return -1;
628  }
629  if (biny == 0 || biny > fYaxis.GetNbins()) {
630  if (!GetStatOverflowsBehaviour()) return -1;
631  }
632  if (binz == 0 || binz > fZaxis.GetNbins()) return -1;
633  Double_t z = fZaxis.GetBinCenter(binz);
634  Double_t v = w;
635  fTsumw += v;
636  fTsumw2 += v*v;
637  fTsumwx += v*x;
638  fTsumwx2 += v*x*x;
639  fTsumwy += v*y;
640  fTsumwy2 += v*y*y;
641  fTsumwxy += v*x*y;
642  fTsumwz += v*z;
643  fTsumwz2 += v*z*z;
644  fTsumwxz += v*x*z;
645  fTsumwyz += v*y*z;
646  return bin;
647 }
648 
649 
650 ////////////////////////////////////////////////////////////////////////////////
651 /// Fill histogram following distribution in function fname.
652 ///
653 /// The distribution contained in the function fname (TF1) is integrated
654 /// over the channel contents.
655 /// It is normalized to 1.
656 /// Getting one random number implies:
657 /// - Generating a random number between 0 and 1 (say r1)
658 /// - Look in which bin in the normalized integral r1 corresponds to
659 /// - Fill histogram channel
660 /// ntimes random numbers are generated
661 ///
662 /// N.B. By dfault this methods approximates the integral of the function in each bin with the
663 /// function value at the center of the bin, mutiplied by the bin width
664 ///
665 ///
666 /// One can also call TF1::GetRandom to get a random variate from a function.
667 
668 void TH3::FillRandom(const char *fname, Int_t ntimes)
669 {
670  Int_t bin, binx, biny, binz, ibin, loop;
671  Double_t r1, x, y,z, xv[3];
672  // Search for fname in the list of ROOT defined functions
673  TObject *fobj = gROOT->GetFunction(fname);
674  if (!fobj) { Error("FillRandom", "Unknown function: %s",fname); return; }
675  TF3 *f1 = dynamic_cast<TF3*>( fobj );
676  if (!f1) { Error("FillRandom", "Function: %s is not a TF3, is a %s",fname,fobj->IsA()->GetName()); return; }
677 
678  TAxis & xAxis = fXaxis;
679  TAxis & yAxis = fYaxis;
680  TAxis & zAxis = fZaxis;
681 
682  // in case axes of histogram are not defined use the function axis
683  if (fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin() || fZaxis.GetXmax() <= fZaxis.GetXmin() ) {
684  Double_t xmin,xmax,ymin,ymax,zmin,zmax;
685  f1->GetRange(xmin,ymin,zmin,xmax,ymax,zmax);
686  Info("FillRandom","Using function axis and range ([%g,%g],[%g,%g],[%g,%g])",xmin, xmax,ymin,ymax,zmin,zmax);
687  xAxis = *(f1->GetHistogram()->GetXaxis());
688  yAxis = *(f1->GetHistogram()->GetYaxis());
689  zAxis = *(f1->GetHistogram()->GetZaxis());
690  }
691 
692  // Allocate temporary space to store the integral and compute integral
693  Int_t nbinsx = xAxis.GetNbins();
694  Int_t nbinsy = yAxis.GetNbins();
695  Int_t nbinsz = zAxis.GetNbins();
696  Int_t nxy = nbinsx*nbinsy;
697  Int_t nbins = nbinsx*nbinsy*nbinsz;
698 
699  Double_t *integral = new Double_t[nbins+1];
700  ibin = 0;
701  integral[ibin] = 0;
702  // approximate integral with function value at bin center
703  for (binz=1;binz<=nbinsz;binz++) {
704  xv[2] = zAxis.GetBinCenter(binz);
705  for (biny=1;biny<=nbinsy;biny++) {
706  xv[1] = yAxis.GetBinCenter(biny);
707  for (binx=1;binx<=nbinsx;binx++) {
708  xv[0] = xAxis.GetBinCenter(binx);
709  ibin++;
710  Double_t fint = f1->EvalPar(xv, nullptr);
711  // uncomment this line to have the integral computation in a bin
712  // Double_t fint = f1->Integral(xAxis.GetBinLowEdge(binx), xAxis.GetBinUpEdge(binx),
713  // yAxis.GetBinLowEdge(biny), yAxis.GetBinUpEdge(biny),
714  // zAxis.GetBinLowEdge(binz), zAxis.GetBinUpEdge(binz));
715  integral[ibin] = integral[ibin-1] + fint;
716  }
717  }
718  }
719 
720  // Normalize integral to 1
721  if (integral[nbins] == 0 ) {
722  delete [] integral;
723  Error("FillRandom", "Integral = zero"); return;
724  }
725  for (bin=1;bin<=nbins;bin++) integral[bin] /= integral[nbins];
726 
727  // Start main loop ntimes
728  if (fDimension < 2) nbinsy = -1;
729  if (fDimension < 3) nbinsz = -1;
730  for (loop=0;loop<ntimes;loop++) {
731  r1 = gRandom->Rndm();
732  ibin = TMath::BinarySearch(nbins,&integral[0],r1);
733  binz = ibin/nxy;
734  biny = (ibin - nxy*binz)/nbinsx;
735  binx = 1 + ibin - nbinsx*(biny + nbinsy*binz);
736  if (nbinsz) binz++;
737  if (nbinsy) biny++;
738  x = xAxis.GetBinCenter(binx);
739  y = yAxis.GetBinCenter(biny);
740  z = zAxis.GetBinCenter(binz);
741  Fill(x,y,z, 1.);
742  }
743  delete [] integral;
744 }
745 
746 
747 ////////////////////////////////////////////////////////////////////////////////
748 /// Fill histogram following distribution in histogram h.
749 ///
750 /// The distribution contained in the histogram h (TH3) is integrated
751 /// over the channel contents.
752 /// It is normalized to 1.
753 /// Getting one random number implies:
754 /// - Generating a random number between 0 and 1 (say r1)
755 /// - Look in which bin in the normalized integral r1 corresponds to
756 /// - Fill histogram channel
757 /// ntimes random numbers are generated
758 
759 void TH3::FillRandom(TH1 *h, Int_t ntimes)
760 {
761  if (!h) { Error("FillRandom", "Null histogram"); return; }
762  if (fDimension != h->GetDimension()) {
763  Error("FillRandom", "Histograms with different dimensions"); return;
764  }
765 
766  if (h->ComputeIntegral() == 0) return;
767 
768  TH3 *h3 = (TH3*)h;
769  Int_t loop;
770  Double_t x,y,z;
771  for (loop=0;loop<ntimes;loop++) {
772  h3->GetRandom3(x,y,z);
773  Fill(x,y,z);
774  }
775 }
776 
777 ////////////////////////////////////////////////////////////////////////////////
778 /// Project slices along Z in case of a 3-D histogram, then fit each slice
779 /// with function f1 and make a 2-d histogram for each fit parameter
780 /// Only cells in the bin range [binminx,binmaxx] and [binminy,binmaxy] are considered.
781 /// if f1=0, a gaussian is assumed
782 /// Before invoking this function, one can set a subrange to be fitted along Z
783 /// via f1->SetRange(zmin,zmax)
784 /// The argument option (default="QNR") can be used to change the fit options.
785 /// "Q" means Quiet mode
786 /// "N" means do not show the result of the fit
787 /// "R" means fit the function in the specified function range
788 ///
789 /// Note that the generated histograms are added to the list of objects
790 /// in the current directory. It is the user's responsibility to delete
791 /// these histograms.
792 ///
793 /// Example: Assume a 3-d histogram h3
794 /// Root > h3->FitSlicesZ(); produces 4 TH2D histograms
795 /// with h3_0 containing parameter 0(Constant) for a Gaus fit
796 /// of each cell in X,Y projected along Z
797 /// with h3_1 containing parameter 1(Mean) for a gaus fit
798 /// with h3_2 containing parameter 2(StdDev) for a gaus fit
799 /// with h3_chi2 containing the chisquare/number of degrees of freedom for a gaus fit
800 ///
801 /// Root > h3->Fit(0,15,22,0,0,10);
802 /// same as above, but only for bins 15 to 22 along X
803 /// and only for cells in X,Y for which the corresponding projection
804 /// along Z has more than cut bins filled.
805 ///
806 /// NOTE: To access the generated histograms in the current directory, do eg:
807 /// TH2D *h3_1 = (TH2D*)gDirectory->Get("h3_1");
808 
809 void TH3::FitSlicesZ(TF1 *f1, Int_t binminx, Int_t binmaxx, Int_t binminy, Int_t binmaxy, Int_t cut, Option_t *option)
810 {
811  Int_t nbinsx = fXaxis.GetNbins();
812  Int_t nbinsy = fYaxis.GetNbins();
813  Int_t nbinsz = fZaxis.GetNbins();
814  if (binminx < 1) binminx = 1;
815  if (binmaxx > nbinsx) binmaxx = nbinsx;
816  if (binmaxx < binminx) {binminx = 1; binmaxx = nbinsx;}
817  if (binminy < 1) binminy = 1;
818  if (binmaxy > nbinsy) binmaxy = nbinsy;
819  if (binmaxy < binminy) {binminy = 1; binmaxy = nbinsy;}
820 
821  //default is to fit with a gaussian
822  if (f1 == 0) {
823  f1 = (TF1*)gROOT->GetFunction("gaus");
824  if (f1 == 0) f1 = new TF1("gaus","gaus",fZaxis.GetXmin(),fZaxis.GetXmax());
825  else f1->SetRange(fZaxis.GetXmin(),fZaxis.GetXmax());
826  }
827  const char *fname = f1->GetName();
828  Int_t npar = f1->GetNpar();
829  Double_t *parsave = new Double_t[npar];
830  f1->GetParameters(parsave);
831 
832  //Create one 2-d histogram for each function parameter
833  Int_t ipar;
834  char name[80], title[80];
835  TH2D *hlist[25];
836  const TArrayD *xbins = fXaxis.GetXbins();
837  const TArrayD *ybins = fYaxis.GetXbins();
838  for (ipar=0;ipar<npar;ipar++) {
839  snprintf(name,80,"%s_%d",GetName(),ipar);
840  snprintf(title,80,"Fitted value of par[%d]=%s",ipar,f1->GetParName(ipar));
841  if (xbins->fN == 0) {
842  hlist[ipar] = new TH2D(name, title,
843  nbinsx, fXaxis.GetXmin(), fXaxis.GetXmax(),
844  nbinsy, fYaxis.GetXmin(), fYaxis.GetXmax());
845  } else {
846  hlist[ipar] = new TH2D(name, title,
847  nbinsx, xbins->fArray,
848  nbinsy, ybins->fArray);
849  }
850  hlist[ipar]->GetXaxis()->SetTitle(fXaxis.GetTitle());
851  hlist[ipar]->GetYaxis()->SetTitle(fYaxis.GetTitle());
852  }
853  snprintf(name,80,"%s_chi2",GetName());
854  TH2D *hchi2 = new TH2D(name,"chisquare", nbinsx, fXaxis.GetXmin(), fXaxis.GetXmax()
855  , nbinsy, fYaxis.GetXmin(), fYaxis.GetXmax());
856 
857  //Loop on all cells in X,Y generate a projection along Z
858  TH1D *hpz = new TH1D("R_temp","_temp",nbinsz, fZaxis.GetXmin(), fZaxis.GetXmax());
859  Int_t bin,binx,biny,binz;
860  for (biny=binminy;biny<=binmaxy;biny++) {
861  Float_t y = fYaxis.GetBinCenter(biny);
862  for (binx=binminx;binx<=binmaxx;binx++) {
863  Float_t x = fXaxis.GetBinCenter(binx);
864  hpz->Reset();
865  Int_t nfill = 0;
866  for (binz=1;binz<=nbinsz;binz++) {
867  bin = GetBin(binx,biny,binz);
868  Float_t w = RetrieveBinContent(bin);
869  if (w == 0) continue;
870  hpz->Fill(fZaxis.GetBinCenter(binz),w);
871  hpz->SetBinError(binz,GetBinError(bin));
872  nfill++;
873  }
874  if (nfill < cut) continue;
875  f1->SetParameters(parsave);
876  hpz->Fit(fname,option);
877  Int_t npfits = f1->GetNumberFitPoints();
878  if (npfits > npar && npfits >= cut) {
879  for (ipar=0;ipar<npar;ipar++) {
880  hlist[ipar]->Fill(x,y,f1->GetParameter(ipar));
881  hlist[ipar]->SetBinError(binx,biny,f1->GetParError(ipar));
882  }
883  hchi2->SetBinContent(binx,biny,f1->GetChisquare()/(npfits-npar));
884  }
885  }
886  }
887  delete [] parsave;
888  delete hpz;
889 }
890 
891 
892 ////////////////////////////////////////////////////////////////////////////////
893 /// See comments in TH1::GetBin
894 
895 Int_t TH3::GetBin(Int_t binx, Int_t biny, Int_t binz) const
896 {
897  Int_t ofy = fYaxis.GetNbins() + 1; // code duplication unavoidable because TH3 does not inherit from TH2
898  if (biny < 0) biny = 0;
899  if (biny > ofy) biny = ofy;
900 
901  Int_t ofz = fZaxis.GetNbins() + 1; // overflow bin
902  if (binz < 0) binz = 0;
903  if (binz > ofz) binz = ofz;
904 
905  return TH1::GetBin(binx) + (fXaxis.GetNbins() + 2) * (biny + (fYaxis.GetNbins() + 2) * binz);
906 }
907 
908 
909 ////////////////////////////////////////////////////////////////////////////////
910 /// Compute first cell (binx,biny,binz) in the range [firstx,lastx](firsty,lasty][firstz,lastz] for which
911 /// diff = abs(cell_content-c) <= maxdiff
912 /// In case several cells in the specified range with diff=0 are found
913 /// the first cell found is returned in binx,biny,binz.
914 /// In case several cells in the specified range satisfy diff <=maxdiff
915 /// the cell with the smallest difference is returned in binx,biny,binz.
916 /// In all cases the function returns the smallest difference.
917 ///
918 /// NOTE1: if firstx <= 0, firstx is set to bin 1
919 /// if (lastx < firstx then firstx is set to the number of bins in X
920 /// ie if firstx=0 and lastx=0 (default) the search is on all bins in X.
921 /// if firsty <= 0, firsty is set to bin 1
922 /// if (lasty < firsty then firsty is set to the number of bins in Y
923 /// ie if firsty=0 and lasty=0 (default) the search is on all bins in Y.
924 /// if firstz <= 0, firstz is set to bin 1
925 /// if (lastz < firstz then firstz is set to the number of bins in Z
926 /// ie if firstz=0 and lastz=0 (default) the search is on all bins in Z.
927 /// NOTE2: if maxdiff=0 (default), the first cell with content=c is returned.
928 
929 Double_t TH3::GetBinWithContent3(Double_t c, Int_t &binx, Int_t &biny, Int_t &binz,
930  Int_t firstx, Int_t lastx,
931  Int_t firsty, Int_t lasty,
932  Int_t firstz, Int_t lastz,
933  Double_t maxdiff) const
934 {
935  if (fDimension != 3) {
936  binx = 0;
937  biny = 0;
938  binz = 0;
939  Error("GetBinWithContent3","function is only valid for 3-D histograms");
940  return 0;
941  }
942  if (firstx <= 0) firstx = 1;
943  if (lastx < firstx) lastx = fXaxis.GetNbins();
944  if (firsty <= 0) firsty = 1;
945  if (lasty < firsty) lasty = fYaxis.GetNbins();
946  if (firstz <= 0) firstz = 1;
947  if (lastz < firstz) lastz = fZaxis.GetNbins();
948  Int_t binminx = 0, binminy=0, binminz=0;
949  Double_t diff, curmax = 1.e240;
950  for (Int_t k=firstz;k<=lastz;k++) {
951  for (Int_t j=firsty;j<=lasty;j++) {
952  for (Int_t i=firstx;i<=lastx;i++) {
953  diff = TMath::Abs(GetBinContent(i,j,k)-c);
954  if (diff <= 0) {binx = i; biny=j; binz=k; return diff;}
955  if (diff < curmax && diff <= maxdiff) {curmax = diff, binminx=i; binminy=j;binminz=k;}
956  }
957  }
958  }
959  binx = binminx;
960  biny = binminy;
961  binz = binminz;
962  return curmax;
963 }
964 
965 
966 ////////////////////////////////////////////////////////////////////////////////
967 /// Return correlation factor between axis1 and axis2.
968 
969 Double_t TH3::GetCorrelationFactor(Int_t axis1, Int_t axis2) const
970 {
971  if (axis1 < 1 || axis2 < 1 || axis1 > 3 || axis2 > 3) {
972  Error("GetCorrelationFactor","Wrong parameters");
973  return 0;
974  }
975  if (axis1 == axis2) return 1;
976  Double_t stddev1 = GetStdDev(axis1);
977  if (stddev1 == 0) return 0;
978  Double_t stddev2 = GetStdDev(axis2);
979  if (stddev2 == 0) return 0;
980  return GetCovariance(axis1,axis2)/stddev1/stddev2;
981 }
982 
983 
984 ////////////////////////////////////////////////////////////////////////////////
985 /// Return covariance between axis1 and axis2.
986 
987 Double_t TH3::GetCovariance(Int_t axis1, Int_t axis2) const
988 {
989  if (axis1 < 1 || axis2 < 1 || axis1 > 3 || axis2 > 3) {
990  Error("GetCovariance","Wrong parameters");
991  return 0;
992  }
993  Double_t stats[kNstat];
994  GetStats(stats);
995  Double_t sumw = stats[0];
996  Double_t sumw2 = stats[1];
997  Double_t sumwx = stats[2];
998  Double_t sumwx2 = stats[3];
999  Double_t sumwy = stats[4];
1000  Double_t sumwy2 = stats[5];
1001  Double_t sumwxy = stats[6];
1002  Double_t sumwz = stats[7];
1003  Double_t sumwz2 = stats[8];
1004  Double_t sumwxz = stats[9];
1005  Double_t sumwyz = stats[10];
1006 
1007  if (sumw == 0) return 0;
1008  if (axis1 == 1 && axis2 == 1) {
1009  return TMath::Abs(sumwx2/sumw - sumwx*sumwx/sumw2);
1010  }
1011  if (axis1 == 2 && axis2 == 2) {
1012  return TMath::Abs(sumwy2/sumw - sumwy*sumwy/sumw2);
1013  }
1014  if (axis1 == 3 && axis2 == 3) {
1015  return TMath::Abs(sumwz2/sumw - sumwz*sumwz/sumw2);
1016  }
1017  if ((axis1 == 1 && axis2 == 2) || (axis1 == 2 && axis2 == 1)) {
1018  return sumwxy/sumw - sumwx/sumw*sumwy/sumw;
1019  }
1020  if ((axis1 == 1 && axis2 == 3) || (axis1 == 3 && axis2 == 1)) {
1021  return sumwxz/sumw - sumwx/sumw*sumwz/sumw;
1022  }
1023  if ((axis1 == 2 && axis2 == 3) || (axis1 == 3 && axis2 == 2)) {
1024  return sumwyz/sumw - sumwy/sumw*sumwz/sumw;
1025  }
1026  return 0;
1027 }
1028 
1029 
1030 ////////////////////////////////////////////////////////////////////////////////
1031 /// Return 3 random numbers along axis x , y and z distributed according
1032 /// the cell-contents of a 3-dim histogram
1033 
1034 void TH3::GetRandom3(Double_t &x, Double_t &y, Double_t &z)
1035 {
1036  Int_t nbinsx = GetNbinsX();
1037  Int_t nbinsy = GetNbinsY();
1038  Int_t nbinsz = GetNbinsZ();
1039  Int_t nxy = nbinsx*nbinsy;
1040  Int_t nbins = nxy*nbinsz;
1041  Double_t integral;
1042  // compute integral checking that all bins have positive content (see ROOT-5894)
1043  if (fIntegral) {
1044  if (fIntegral[nbins+1] != fEntries) integral = ComputeIntegral(true);
1045  else integral = fIntegral[nbins];
1046  } else {
1047  integral = ComputeIntegral(true);
1048  }
1049  if (integral == 0 ) { x = 0; y = 0; z = 0; return;}
1050  // case histogram has negative bins
1051  if (integral == TMath::QuietNaN() ) { x = TMath::QuietNaN(); y = TMath::QuietNaN(); z = TMath::QuietNaN(); return;}
1052 
1053  Double_t r1 = gRandom->Rndm();
1054  Int_t ibin = TMath::BinarySearch(nbins,fIntegral,(Double_t) r1);
1055  Int_t binz = ibin/nxy;
1056  Int_t biny = (ibin - nxy*binz)/nbinsx;
1057  Int_t binx = ibin - nbinsx*(biny + nbinsy*binz);
1058  x = fXaxis.GetBinLowEdge(binx+1);
1059  if (r1 > fIntegral[ibin]) x +=
1060  fXaxis.GetBinWidth(binx+1)*(r1-fIntegral[ibin])/(fIntegral[ibin+1] - fIntegral[ibin]);
1061  y = fYaxis.GetBinLowEdge(biny+1) + fYaxis.GetBinWidth(biny+1)*gRandom->Rndm();
1062  z = fZaxis.GetBinLowEdge(binz+1) + fZaxis.GetBinWidth(binz+1)*gRandom->Rndm();
1063 }
1064 
1065 
1066 ////////////////////////////////////////////////////////////////////////////////
1067 /// Fill the array stats from the contents of this histogram
1068 /// The array stats must be correctly dimensioned in the calling program.
1069 /// stats[0] = sumw
1070 /// stats[1] = sumw2
1071 /// stats[2] = sumwx
1072 /// stats[3] = sumwx2
1073 /// stats[4] = sumwy
1074 /// stats[5] = sumwy2
1075 /// stats[6] = sumwxy
1076 /// stats[7] = sumwz
1077 /// stats[8] = sumwz2
1078 /// stats[9] = sumwxz
1079 /// stats[10]= sumwyz
1080 
1081 void TH3::GetStats(Double_t *stats) const
1082 {
1083  if (fBuffer) ((TH3*)this)->BufferEmpty();
1084 
1085  Int_t bin, binx, biny, binz;
1086  Double_t w,err;
1087  Double_t x,y,z;
1088  if ((fTsumw == 0 && fEntries > 0) || fXaxis.TestBit(TAxis::kAxisRange) || fYaxis.TestBit(TAxis::kAxisRange) || fZaxis.TestBit(TAxis::kAxisRange)) {
1089  for (bin=0;bin<11;bin++) stats[bin] = 0;
1090 
1091  Int_t firstBinX = fXaxis.GetFirst();
1092  Int_t lastBinX = fXaxis.GetLast();
1093  Int_t firstBinY = fYaxis.GetFirst();
1094  Int_t lastBinY = fYaxis.GetLast();
1095  Int_t firstBinZ = fZaxis.GetFirst();
1096  Int_t lastBinZ = fZaxis.GetLast();
1097  // include underflow/overflow if TH1::StatOverflows(kTRUE) in case no range is set on the axis
1098  if (GetStatOverflowsBehaviour()) {
1099  if ( !fXaxis.TestBit(TAxis::kAxisRange) ) {
1100  if (firstBinX == 1) firstBinX = 0;
1101  if (lastBinX == fXaxis.GetNbins() ) lastBinX += 1;
1102  }
1103  if ( !fYaxis.TestBit(TAxis::kAxisRange) ) {
1104  if (firstBinY == 1) firstBinY = 0;
1105  if (lastBinY == fYaxis.GetNbins() ) lastBinY += 1;
1106  }
1107  if ( !fZaxis.TestBit(TAxis::kAxisRange) ) {
1108  if (firstBinZ == 1) firstBinZ = 0;
1109  if (lastBinZ == fZaxis.GetNbins() ) lastBinZ += 1;
1110  }
1111  }
1112  for (binz = firstBinZ; binz <= lastBinZ; binz++) {
1113  z = fZaxis.GetBinCenter(binz);
1114  for (biny = firstBinY; biny <= lastBinY; biny++) {
1115  y = fYaxis.GetBinCenter(biny);
1116  for (binx = firstBinX; binx <= lastBinX; binx++) {
1117  bin = GetBin(binx,biny,binz);
1118  x = fXaxis.GetBinCenter(binx);
1119  //w = TMath::Abs(GetBinContent(bin));
1120  w = RetrieveBinContent(bin);
1121  err = TMath::Abs(GetBinError(bin));
1122  stats[0] += w;
1123  stats[1] += err*err;
1124  stats[2] += w*x;
1125  stats[3] += w*x*x;
1126  stats[4] += w*y;
1127  stats[5] += w*y*y;
1128  stats[6] += w*x*y;
1129  stats[7] += w*z;
1130  stats[8] += w*z*z;
1131  stats[9] += w*x*z;
1132  stats[10]+= w*y*z;
1133  }
1134  }
1135  }
1136  } else {
1137  stats[0] = fTsumw;
1138  stats[1] = fTsumw2;
1139  stats[2] = fTsumwx;
1140  stats[3] = fTsumwx2;
1141  stats[4] = fTsumwy;
1142  stats[5] = fTsumwy2;
1143  stats[6] = fTsumwxy;
1144  stats[7] = fTsumwz;
1145  stats[8] = fTsumwz2;
1146  stats[9] = fTsumwxz;
1147  stats[10]= fTsumwyz;
1148  }
1149 }
1150 
1151 
1152 ////////////////////////////////////////////////////////////////////////////////
1153 /// Return integral of bin contents. Only bins in the bins range are considered.
1154 /// By default the integral is computed as the sum of bin contents in the range.
1155 /// if option "width" is specified, the integral is the sum of
1156 /// the bin contents multiplied by the bin width in x, y and in z.
1157 
1158 Double_t TH3::Integral(Option_t *option) const
1159 {
1160  return Integral(fXaxis.GetFirst(),fXaxis.GetLast(),
1161  fYaxis.GetFirst(),fYaxis.GetLast(),
1162  fZaxis.GetFirst(),fZaxis.GetLast(),option);
1163 }
1164 
1165 
1166 ////////////////////////////////////////////////////////////////////////////////
1167 /// Return integral of bin contents in range [binx1,binx2],[biny1,biny2],[binz1,binz2]
1168 /// for a 3-D histogram
1169 /// By default the integral is computed as the sum of bin contents in the range.
1170 /// if option "width" is specified, the integral is the sum of
1171 /// the bin contents multiplied by the bin width in x, y and in z.
1172 
1173 Double_t TH3::Integral(Int_t binx1, Int_t binx2, Int_t biny1, Int_t biny2,
1174  Int_t binz1, Int_t binz2, Option_t *option) const
1175 {
1176  Double_t err = 0;
1177  return DoIntegral(binx1,binx2,biny1,biny2,binz1,binz2,err,option);
1178 }
1179 
1180 
1181 ////////////////////////////////////////////////////////////////////////////////
1182 /// Return integral of bin contents in range [binx1,binx2],[biny1,biny2],[binz1,binz2]
1183 /// for a 3-D histogram. Calculates also the integral error using error propagation
1184 /// from the bin errors assuming that all the bins are uncorrelated.
1185 /// By default the integral is computed as the sum of bin contents in the range.
1186 /// if option "width" is specified, the integral is the sum of
1187 /// the bin contents multiplied by the bin width in x, y and in z.
1188 
1189 Double_t TH3::IntegralAndError(Int_t binx1, Int_t binx2, Int_t biny1, Int_t biny2,
1190  Int_t binz1, Int_t binz2,
1191  Double_t & error, Option_t *option) const
1192 {
1193  return DoIntegral(binx1,binx2,biny1,biny2,binz1,binz2,error,option,kTRUE);
1194 }
1195 
1196 ////////////////////////////////////////////////////////////////////////////////
1197 ///Not yet implemented
1198 
1199 Double_t TH3::Interpolate(Double_t) const
1200 {
1201  Error("Interpolate","This function must be called with 3 arguments for a TH3");
1202  return 0;
1203 }
1204 
1205 
1206 ////////////////////////////////////////////////////////////////////////////////
1207 ///Not yet implemented
1208 
1209 Double_t TH3::Interpolate(Double_t, Double_t) const
1210 {
1211  Error("Interpolate","This function must be called with 3 arguments for a TH3");
1212  return 0;
1213 }
1214 
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Given a point P(x,y,z), Interpolate approximates the value via trilinear interpolation
1218 /// based on the 8 nearest bin center points (corner of the cube surrounding the points)
1219 /// The Algorithm is described in http://en.wikipedia.org/wiki/Trilinear_interpolation
1220 /// The given values (x,y,z) must be between first bin center and last bin center for each coordinate:
1221 ///
1222 /// fXAxis.GetBinCenter(1) < x < fXaxis.GetBinCenter(nbinX) AND
1223 /// fYAxis.GetBinCenter(1) < y < fYaxis.GetBinCenter(nbinY) AND
1224 /// fZAxis.GetBinCenter(1) < z < fZaxis.GetBinCenter(nbinZ)
1225 
1226 Double_t TH3::Interpolate(Double_t x, Double_t y, Double_t z) const
1227 {
1228  Int_t ubx = fXaxis.FindFixBin(x);
1229  if ( x < fXaxis.GetBinCenter(ubx) ) ubx -= 1;
1230  Int_t obx = ubx + 1;
1231 
1232  Int_t uby = fYaxis.FindFixBin(y);
1233  if ( y < fYaxis.GetBinCenter(uby) ) uby -= 1;
1234  Int_t oby = uby + 1;
1235 
1236  Int_t ubz = fZaxis.FindFixBin(z);
1237  if ( z < fZaxis.GetBinCenter(ubz) ) ubz -= 1;
1238  Int_t obz = ubz + 1;
1239 
1240 
1241 // if ( IsBinUnderflow(GetBin(ubx, uby, ubz)) ||
1242 // IsBinOverflow (GetBin(obx, oby, obz)) ) {
1243  if (ubx <=0 || uby <=0 || ubz <= 0 ||
1244  obx > fXaxis.GetNbins() || oby > fYaxis.GetNbins() || obz > fZaxis.GetNbins() ) {
1245  Error("Interpolate","Cannot interpolate outside histogram domain.");
1246  return 0;
1247  }
1248 
1249  Double_t xw = fXaxis.GetBinCenter(obx) - fXaxis.GetBinCenter(ubx);
1250  Double_t yw = fYaxis.GetBinCenter(oby) - fYaxis.GetBinCenter(uby);
1251  Double_t zw = fZaxis.GetBinCenter(obz) - fZaxis.GetBinCenter(ubz);
1252 
1253  Double_t xd = (x - fXaxis.GetBinCenter(ubx)) / xw;
1254  Double_t yd = (y - fYaxis.GetBinCenter(uby)) / yw;
1255  Double_t zd = (z - fZaxis.GetBinCenter(ubz)) / zw;
1256 
1257 
1258  Double_t v[] = { GetBinContent( ubx, uby, ubz ), GetBinContent( ubx, uby, obz ),
1259  GetBinContent( ubx, oby, ubz ), GetBinContent( ubx, oby, obz ),
1260  GetBinContent( obx, uby, ubz ), GetBinContent( obx, uby, obz ),
1261  GetBinContent( obx, oby, ubz ), GetBinContent( obx, oby, obz ) };
1262 
1263 
1264  Double_t i1 = v[0] * (1 - zd) + v[1] * zd;
1265  Double_t i2 = v[2] * (1 - zd) + v[3] * zd;
1266  Double_t j1 = v[4] * (1 - zd) + v[5] * zd;
1267  Double_t j2 = v[6] * (1 - zd) + v[7] * zd;
1268 
1269 
1270  Double_t w1 = i1 * (1 - yd) + i2 * yd;
1271  Double_t w2 = j1 * (1 - yd) + j2 * yd;
1272 
1273 
1274  Double_t result = w1 * (1 - xd) + w2 * xd;
1275 
1276  return result;
1277 }
1278 
1279 
1280 ////////////////////////////////////////////////////////////////////////////////
1281 /// Statistical test of compatibility in shape between
1282 /// THIS histogram and h2, using Kolmogorov test.
1283 /// Default: Ignore under- and overflow bins in comparison
1284 ///
1285 /// option is a character string to specify options
1286 /// "U" include Underflows in test
1287 /// "O" include Overflows
1288 /// "N" include comparison of normalizations
1289 /// "D" Put out a line of "Debug" printout
1290 /// "M" Return the Maximum Kolmogorov distance instead of prob
1291 ///
1292 /// The returned function value is the probability of test
1293 /// (much less than one means NOT compatible)
1294 ///
1295 /// The KS test uses the distance between the pseudo-CDF's obtained
1296 /// from the histogram. Since in more than 1D the order for generating the pseudo-CDF is
1297 /// arbitrary, we use the pseudo-CDF's obtained from all the possible 6 combinations of the 3 axis.
1298 /// The average of all the maximum distances obtained is used in the tests.
1299 
1300 Double_t TH3::KolmogorovTest(const TH1 *h2, Option_t *option) const
1301 {
1302  TString opt = option;
1303  opt.ToUpper();
1304 
1305  Double_t prb = 0;
1306  TH1 *h1 = (TH1*)this;
1307  if (h2 == 0) return 0;
1308  const TAxis *xaxis1 = h1->GetXaxis();
1309  const TAxis *xaxis2 = h2->GetXaxis();
1310  const TAxis *yaxis1 = h1->GetYaxis();
1311  const TAxis *yaxis2 = h2->GetYaxis();
1312  const TAxis *zaxis1 = h1->GetZaxis();
1313  const TAxis *zaxis2 = h2->GetZaxis();
1314  Int_t ncx1 = xaxis1->GetNbins();
1315  Int_t ncx2 = xaxis2->GetNbins();
1316  Int_t ncy1 = yaxis1->GetNbins();
1317  Int_t ncy2 = yaxis2->GetNbins();
1318  Int_t ncz1 = zaxis1->GetNbins();
1319  Int_t ncz2 = zaxis2->GetNbins();
1320 
1321  // Check consistency of dimensions
1322  if (h1->GetDimension() != 3 || h2->GetDimension() != 3) {
1323  Error("KolmogorovTest","Histograms must be 3-D\n");
1324  return 0;
1325  }
1326 
1327  // Check consistency in number of channels
1328  if (ncx1 != ncx2) {
1329  Error("KolmogorovTest","Number of channels in X is different, %d and %d\n",ncx1,ncx2);
1330  return 0;
1331  }
1332  if (ncy1 != ncy2) {
1333  Error("KolmogorovTest","Number of channels in Y is different, %d and %d\n",ncy1,ncy2);
1334  return 0;
1335  }
1336  if (ncz1 != ncz2) {
1337  Error("KolmogorovTest","Number of channels in Z is different, %d and %d\n",ncz1,ncz2);
1338  return 0;
1339  }
1340 
1341  // Check consistency in channel edges
1342  Bool_t afunc1 = kFALSE;
1343  Bool_t afunc2 = kFALSE;
1344  Double_t difprec = 1e-5;
1345  Double_t diff1 = TMath::Abs(xaxis1->GetXmin() - xaxis2->GetXmin());
1346  Double_t diff2 = TMath::Abs(xaxis1->GetXmax() - xaxis2->GetXmax());
1347  if (diff1 > difprec || diff2 > difprec) {
1348  Error("KolmogorovTest","histograms with different binning along X");
1349  return 0;
1350  }
1351  diff1 = TMath::Abs(yaxis1->GetXmin() - yaxis2->GetXmin());
1352  diff2 = TMath::Abs(yaxis1->GetXmax() - yaxis2->GetXmax());
1353  if (diff1 > difprec || diff2 > difprec) {
1354  Error("KolmogorovTest","histograms with different binning along Y");
1355  return 0;
1356  }
1357  diff1 = TMath::Abs(zaxis1->GetXmin() - zaxis2->GetXmin());
1358  diff2 = TMath::Abs(zaxis1->GetXmax() - zaxis2->GetXmax());
1359  if (diff1 > difprec || diff2 > difprec) {
1360  Error("KolmogorovTest","histograms with different binning along Z");
1361  return 0;
1362  }
1363 
1364  // Should we include Uflows, Oflows?
1365  Int_t ibeg = 1, jbeg = 1, kbeg = 1;
1366  Int_t iend = ncx1, jend = ncy1, kend = ncz1;
1367  if (opt.Contains("U")) {ibeg = 0; jbeg = 0; kbeg = 0;}
1368  if (opt.Contains("O")) {iend = ncx1+1; jend = ncy1+1; kend = ncz1+1;}
1369 
1370  Int_t i,j,k,bin;
1371  Double_t sum1 = 0;
1372  Double_t sum2 = 0;
1373  Double_t w1 = 0;
1374  Double_t w2 = 0;
1375  for (i = ibeg; i <= iend; i++) {
1376  for (j = jbeg; j <= jend; j++) {
1377  for (k = kbeg; k <= kend; k++) {
1378  bin = h1->GetBin(i,j,k);
1379  sum1 += h1->GetBinContent(bin);
1380  sum2 += h2->GetBinContent(bin);
1381  Double_t ew1 = h1->GetBinError(bin);
1382  Double_t ew2 = h2->GetBinError(bin);
1383  w1 += ew1*ew1;
1384  w2 += ew2*ew2;
1385  }
1386  }
1387  }
1388 
1389 
1390  // Check that both scatterplots contain events
1391  if (sum1 == 0) {
1392  Error("KolmogorovTest","Integral is zero for h1=%s\n",h1->GetName());
1393  return 0;
1394  }
1395  if (sum2 == 0) {
1396  Error("KolmogorovTest","Integral is zero for h2=%s\n",h2->GetName());
1397  return 0;
1398  }
1399  // calculate the effective entries.
1400  // the case when errors are zero (w1 == 0 or w2 ==0) are equivalent to
1401  // compare to a function. In that case the rescaling is done only on sqrt(esum2) or sqrt(esum1)
1402  Double_t esum1 = 0, esum2 = 0;
1403  if (w1 > 0)
1404  esum1 = sum1 * sum1 / w1;
1405  else
1406  afunc1 = kTRUE; // use later for calculating z
1407 
1408  if (w2 > 0)
1409  esum2 = sum2 * sum2 / w2;
1410  else
1411  afunc2 = kTRUE; // use later for calculating z
1412 
1413  if (afunc2 && afunc1) {
1414  Error("KolmogorovTest","Errors are zero for both histograms\n");
1415  return 0;
1416  }
1417 
1418  // Find Kolmogorov distance
1419  // order is arbitrary take average of all possible 6 starting orders x,y,z
1420  int order[3] = {0,1,2};
1421  int binbeg[3];
1422  int binend[3];
1423  int ibin[3];
1424  binbeg[0] = ibeg; binbeg[1] = jbeg; binbeg[2] = kbeg;
1425  binend[0] = iend; binend[1] = jend; binend[2] = kend;
1426  Double_t vdfmax[6]; // there are in total 6 combinations
1427  int icomb = 0;
1428  Double_t s1 = 1./(6.*sum1);
1429  Double_t s2 = 1./(6.*sum2);
1430  Double_t rsum1=0, rsum2=0;
1431  do {
1432  // loop on bins
1433  Double_t dmax = 0;
1434  for (i = binbeg[order[0] ]; i <= binend[order[0] ]; i++) {
1435  for ( j = binbeg[order[1] ]; j <= binend[order[1] ]; j++) {
1436  for ( k = binbeg[order[2] ]; k <= binend[order[2] ]; k++) {
1437  ibin[ order[0] ] = i;
1438  ibin[ order[1] ] = j;
1439  ibin[ order[2] ] = k;
1440  bin = h1->GetBin(ibin[0],ibin[1],ibin[2]);
1441  rsum1 += s1*h1->GetBinContent(bin);
1442  rsum2 += s2*h2->GetBinContent(bin);
1443  dmax = TMath::Max(dmax, TMath::Abs(rsum1-rsum2));
1444  }
1445  }
1446  }
1447  vdfmax[icomb] = dmax;
1448  icomb++;
1449  } while (TMath::Permute(3,order) );
1450 
1451 
1452  // get average of distances
1453  Double_t dfmax = TMath::Mean(6,vdfmax);
1454 
1455  // Get Kolmogorov probability
1456  Double_t factnm;
1457  if (afunc1) factnm = TMath::Sqrt(sum2);
1458  else if (afunc2) factnm = TMath::Sqrt(sum1);
1459  else factnm = TMath::Sqrt(sum1*sum2/(sum1+sum2));
1460  Double_t z = dfmax*factnm;
1461 
1462  prb = TMath::KolmogorovProb(z);
1463 
1464  Double_t prb1 = 0, prb2 = 0;
1465  // option N to combine normalization makes sense if both afunc1 and afunc2 are false
1466  if (opt.Contains("N") && !(afunc1 || afunc2 ) ) {
1467  // Combine probabilities for shape and normalization
1468  prb1 = prb;
1469  Double_t d12 = esum1-esum2;
1470  Double_t chi2 = d12*d12/(esum1+esum2);
1471  prb2 = TMath::Prob(chi2,1);
1472  // see Eadie et al., section 11.6.2
1473  if (prb > 0 && prb2 > 0) prb = prb*prb2*(1-TMath::Log(prb*prb2));
1474  else prb = 0;
1475  }
1476 
1477  // debug printout
1478  if (opt.Contains("D")) {
1479  printf(" Kolmo Prob h1 = %s, sum1=%g\n",h1->GetName(),sum1);
1480  printf(" Kolmo Prob h2 = %s, sum2=%g\n",h2->GetName(),sum2);
1481  printf(" Kolmo Probabil = %f, Max Dist = %g\n",prb,dfmax);
1482  if (opt.Contains("N"))
1483  printf(" Kolmo Probabil = %f for shape alone, =%f for normalisation alone\n",prb1,prb2);
1484  }
1485  // This numerical error condition should never occur:
1486  if (TMath::Abs(rsum1-1) > 0.002) Warning("KolmogorovTest","Numerical problems with h1=%s\n",h1->GetName());
1487  if (TMath::Abs(rsum2-1) > 0.002) Warning("KolmogorovTest","Numerical problems with h2=%s\n",h2->GetName());
1488 
1489  if (opt.Contains("M")) return dfmax; // return average of max distance
1490 
1491  return prb;
1492 }
1493 
1494 
1495 ////////////////////////////////////////////////////////////////////////////////
1496 /// Project a 3-D histogram into a 1-D histogram along X.
1497 ///
1498 /// The projection is always of the type TH1D.
1499 /// The projection is made from the cells along the X axis
1500 /// ranging from iymin to iymax and izmin to izmax included.
1501 /// By default, underflow and overflows are included in both the Y and Z axis.
1502 /// By Setting iymin=1 and iymax=NbinsY the underflow and/or overflow in Y will be excluded
1503 /// By setting izmin=1 and izmax=NbinsZ the underflow and/or overflow in Z will be excluded
1504 ///
1505 /// if option "e" is specified, the errors are computed.
1506 /// if option "d" is specified, the projection is drawn in the current pad.
1507 /// if option "o" original axis range of the target axes will be
1508 /// kept, but only bins inside the selected range will be filled.
1509 ///
1510 /// NOTE that if a TH1D named "name" exists in the current directory or pad
1511 /// the histogram is reset and filled again with the projected contents of the TH3.
1512 ///
1513 /// implemented using Project3D
1514 
1515 TH1D *TH3::ProjectionX(const char *name, Int_t iymin, Int_t iymax,
1516  Int_t izmin, Int_t izmax, Option_t *option) const
1517 {
1518  // in case of default name append the parent name
1519  TString hname = name;
1520  if (hname == "_px") hname = TString::Format("%s%s", GetName(), name);
1521  TString title = TString::Format("%s ( Projection X )",GetTitle());
1522 
1523  // when projecting in Z outer axis are Y and Z (order is important. It is defined in the DoProject1D function)
1524  return DoProject1D(hname, title, iymin, iymax, izmin, izmax, &fXaxis, &fYaxis, &fZaxis, option);
1525 }
1526 
1527 
1528 ////////////////////////////////////////////////////////////////////////////////
1529 /// Project a 3-D histogram into a 1-D histogram along Y.
1530 ///
1531 /// The projection is always of the type TH1D.
1532 /// The projection is made from the cells along the Y axis
1533 /// ranging from ixmin to ixmax and izmin to izmax included.
1534 /// By default, underflow and overflow are included in both the X and Z axis.
1535 /// By setting ixmin=1 and ixmax=NbinsX the underflow and/or overflow in X will be excluded
1536 /// By setting izmin=1 and izmax=NbinsZ the underflow and/or overflow in Z will be excluded
1537 ///
1538 /// if option "e" is specified, the errors are computed.
1539 /// if option "d" is specified, the projection is drawn in the current pad.
1540 /// if option "o" original axis range of the target axes will be
1541 /// kept, but only bins inside the selected range will be filled.
1542 ///
1543 /// NOTE that if a TH1D named "name" exists in the current directory or pad,
1544 /// the histogram is reset and filled again with the projected contents of the TH3.
1545 ///
1546 /// implemented using Project3D
1547 
1548 TH1D *TH3::ProjectionY(const char *name, Int_t ixmin, Int_t ixmax,
1549  Int_t izmin, Int_t izmax, Option_t *option) const
1550 {
1551  TString hname = name;
1552  if (hname == "_py") hname = TString::Format("%s%s", GetName(), name);
1553  TString title = TString::Format("%s ( Projection Y )",GetTitle());
1554 
1555  // when projecting in Z outer axis are X and Y (order is important. It is defined in the DoProject1D function)
1556  return DoProject1D(hname, title, ixmin, ixmax, izmin, izmax, &fYaxis, &fXaxis, &fZaxis, option);
1557 }
1558 
1559 ////////////////////////////////////////////////////////////////////////////////
1560 /// Project a 3-D histogram into a 1-D histogram along Z.
1561 ///
1562 /// The projection is always of the type TH1D.
1563 /// The projection is made from the cells along the Z axis
1564 /// ranging from ixmin to ixmax and iymin to iymax included.
1565 /// By default, bins 1 to nx and 1 to ny are included
1566 /// By default, underflow and overflow are included in both the X and Y axis.
1567 /// By Setting ixmin=1 and ixmax=NbinsX the underflow and/or overflow in X will be excluded
1568 /// By setting iymin=1 and/or iymax=NbinsY the underflow and/or overflow in Y will be excluded
1569 ///
1570 /// if option "e" is specified, the errors are computed.
1571 /// if option "d" is specified, the projection is drawn in the current pad.
1572 /// if option "o" original axis range of the target axes will be
1573 /// kept, but only bins inside the selected range will be filled.
1574 ///
1575 /// NOTE that if a TH1D named "name" exists in the current directory or pad,
1576 /// the histogram is reset and filled again with the projected contents of the TH3.
1577 ///
1578 /// implemented using Project3D
1579 
1580 TH1D *TH3::ProjectionZ(const char *name, Int_t ixmin, Int_t ixmax,
1581  Int_t iymin, Int_t iymax, Option_t *option) const
1582 {
1583 
1584  TString hname = name;
1585  if (hname == "_pz") hname = TString::Format("%s%s", GetName(), name);
1586  TString title = TString::Format("%s ( Projection Z )",GetTitle());
1587 
1588  // when projecting in Z outer axis are X and Y (order is important. It is defined in the DoProject1D function)
1589  return DoProject1D(hname, title, ixmin, ixmax, iymin, iymax, &fZaxis, &fXaxis, &fYaxis, option);
1590 }
1591 
1592 
1593 ////////////////////////////////////////////////////////////////////////////////
1594 /// internal method performing the projection to 1D histogram
1595 /// called from TH3::Project3D
1596 
1597 TH1D *TH3::DoProject1D(const char* name, const char * title, int imin1, int imax1, int imin2, int imax2,
1598  const TAxis* projAxis, const TAxis * axis1, const TAxis * axis2, Option_t * option) const
1599 {
1600 
1601  TString opt = option;
1602  opt.ToLower();
1603 
1604  // save previous axis range and bits
1605  // Int_t iminOld1 = axis1->GetFirst();
1606  // Int_t imaxOld1 = axis1->GetLast();
1607  // Int_t iminOld2 = axis2->GetFirst();
1608  // Int_t imaxOld2 = axis2->GetLast();
1609  // Bool_t hadRange1 = axis1->TestBit(TAxis::kAxisRange);
1610  // Bool_t hadRange2 = axis2->TestBit(TAxis::kAxisRange);
1611 
1612  // need to cast-away constness to set range
1613  TAxis out1(*axis1);
1614  TAxis out2(*axis2);
1615  // const_cast<TAxis *>(axis1)->SetRange(imin1, imax1);
1616  // const_cast<TAxis*>(axis2)->SetRange(imin2,imax2);
1617  out1.SetRange(imin1, imax1);
1618  out2.SetRange(imin2, imax2);
1619 
1620  Bool_t computeErrors = GetSumw2N();
1621  if (opt.Contains("e") ) {
1622  computeErrors = kTRUE;
1623  opt.Remove(opt.First("e"),1);
1624  }
1625  Bool_t originalRange = kFALSE;
1626  if (opt.Contains('o') ) {
1627  originalRange = kTRUE;
1628  opt.Remove(opt.First("o"),1);
1629  }
1630 
1631  TH1D * h1 = DoProject1D(name, title, projAxis, &out1, &out2, computeErrors, originalRange,true,true);
1632 
1633  // // restore original range
1634  // if (axis1->TestBit(TAxis::kAxisRange)) {
1635  // if (hadRange1) const_cast<TAxis*>(axis1)->SetRange(iminOld1,imaxOld1);
1636  // if (axis2->TestBit(TAxis::kAxisRange)) const_cast<TAxis*>(axis2)->SetRange(iminOld2,imaxOld2);
1637  // // we need also to restore the original bits
1638 
1639  // draw in current pad
1640  if (h1 && opt.Contains("d")) {
1641  opt.Remove(opt.First("d"),1);
1642  TVirtualPad *padsav = gPad;
1643  TVirtualPad *pad = gROOT->GetSelectedPad();
1644  if (pad) pad->cd();
1645  if (!gPad || !gPad->FindObject(h1)) {
1646  h1->Draw(opt);
1647  } else {
1648  h1->Paint(opt);
1649  }
1650  if (padsav) padsav->cd();
1651  }
1652 
1653  return h1;
1654 }
1655 
1656 ////////////////////////////////////////////////////////////////////////////////
1657 /// internal methdod performing the projection to 1D histogram
1658 /// called from other TH3::DoProject1D
1659 
1660 TH1D *TH3::DoProject1D(const char* name, const char * title, const TAxis* projX,
1661  const TAxis * out1, const TAxis * out2,
1662  bool computeErrors, bool originalRange,
1663  bool useUF, bool useOF) const
1664 {
1665  // Create the projection histogram
1666  TH1D *h1 = 0;
1667 
1668  // Get range to use as well as bin limits
1669  // Projected range must be inside and not outside original one (ROOT-8781)
1670  Int_t ixmin = std::max(projX->GetFirst(),1);
1671  Int_t ixmax = std::min(projX->GetLast(),projX->GetNbins());
1672  Int_t nx = ixmax-ixmin+1;
1673 
1674  // Create the histogram, either reseting a preexisting one
1675  TObject *h1obj = gROOT->FindObject(name);
1676  if (h1obj && h1obj->InheritsFrom(TH1::Class())) {
1677  if (h1obj->IsA() != TH1D::Class() ) {
1678  Error("DoProject1D","Histogram with name %s must be a TH1D and is a %s",name,h1obj->ClassName());
1679  return 0;
1680  }
1681  h1 = (TH1D*)h1obj;
1682  // reset histogram and re-set the axis in any case
1683  h1->Reset();
1684  const TArrayD *bins = projX->GetXbins();
1685  if ( originalRange )
1686  {
1687  if (bins->fN == 0) {
1688  h1->SetBins(projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
1689  } else {
1690  h1->SetBins(projX->GetNbins(),bins->fArray);
1691  }
1692  } else {
1693  if (bins->fN == 0) {
1694  h1->SetBins(nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
1695  } else {
1696  h1->SetBins(nx,&bins->fArray[ixmin-1]);
1697  }
1698  }
1699  }
1700 
1701  if (!h1) {
1702  const TArrayD *bins = projX->GetXbins();
1703  if ( originalRange )
1704  {
1705  if (bins->fN == 0) {
1706  h1 = new TH1D(name,title,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
1707  } else {
1708  h1 = new TH1D(name,title,projX->GetNbins(),bins->fArray);
1709  }
1710  } else {
1711  if (bins->fN == 0) {
1712  h1 = new TH1D(name,title,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
1713  } else {
1714  h1 = new TH1D(name,title,nx,&bins->fArray[ixmin-1]);
1715  }
1716  }
1717  }
1718 
1719  // Copy the axis attributes and the axis labels if needed.
1720  h1->GetXaxis()->ImportAttributes(projX);
1721  THashList* labels = projX->GetLabels();
1722  if (labels) {
1723  TIter iL(labels);
1724  TObjString* lb;
1725  Int_t i = 1;
1726  while ((lb=(TObjString*)iL())) {
1727  h1->GetXaxis()->SetBinLabel(i,lb->String().Data());
1728  i++;
1729  }
1730  }
1731  h1->SetLineColor(this->GetLineColor());
1732  h1->SetFillColor(this->GetFillColor());
1733  h1->SetMarkerColor(this->GetMarkerColor());
1734  h1->SetMarkerStyle(this->GetMarkerStyle());
1735 
1736  // Activate errors
1737  if ( computeErrors && (h1->GetSumw2N() != h1->GetNcells() ) ) h1->Sumw2();
1738 
1739  // Set references to the axies in case out1 or out2 ar enot provided
1740  // and one can use the histogram axis given projX
1741  if (out1 == nullptr && out2 == nullptr) {
1742  if (projX == GetXaxis()) {
1743  out1 = GetYaxis();
1744  out2 = GetZaxis();
1745  } else if (projX == GetYaxis()) {
1746  out1 = GetXaxis();
1747  out2 = GetZaxis();
1748  } else {
1749  out1 = GetXaxis();
1750  out2 = GetYaxis();
1751  }
1752  }
1753  R__ASSERT(out1 != nullptr && out2 != nullptr);
1754 
1755  Int_t *refX = 0, *refY = 0, *refZ = 0;
1756  Int_t ixbin, out1bin, out2bin;
1757  if (projX == GetXaxis()) {
1758  refX = &ixbin;
1759  refY = &out1bin;
1760  refZ = &out2bin;
1761  }
1762  if (projX == GetYaxis()) {
1763  refX = &out1bin;
1764  refY = &ixbin;
1765  refZ = &out2bin;
1766  }
1767  if (projX == GetZaxis()) {
1768  refX = &out1bin;
1769  refY = &out2bin;
1770  refZ = &ixbin;
1771  }
1772  R__ASSERT (refX != 0 && refY != 0 && refZ != 0);
1773 
1774  // Fill the projected histogram excluding underflow/overflows if considered in the option
1775  // if specified in the option (by default they considered)
1776  Double_t totcont = 0;
1777 
1778  Int_t out1min = out1->GetFirst();
1779  Int_t out1max = out1->GetLast();
1780  // GetFirst(), GetLast() can return (0,0) when the range bit is set artificially (see TAxis::SetRange)
1781  //if (out1min == 0 && out1max == 0) { out1min = 1; out1max = out1->GetNbins(); }
1782  // correct for underflow/overflows
1783  if (useUF && !out1->TestBit(TAxis::kAxisRange) ) out1min -= 1;
1784  if (useOF && !out1->TestBit(TAxis::kAxisRange) ) out1max += 1;
1785  Int_t out2min = out2->GetFirst();
1786  Int_t out2max = out2->GetLast();
1787 // if (out2min == 0 && out2max == 0) { out2min = 1; out2max = out2->GetNbins(); }
1788  if (useUF && !out2->TestBit(TAxis::kAxisRange) ) out2min -= 1;
1789  if (useOF && !out2->TestBit(TAxis::kAxisRange) ) out2max += 1;
1790 
1791  for (ixbin=0;ixbin<=1+projX->GetNbins();ixbin++) {
1792  if ( projX->TestBit(TAxis::kAxisRange) && ( ixbin < ixmin || ixbin > ixmax )) continue;
1793 
1794  Double_t cont = 0;
1795  Double_t err2 = 0;
1796 
1797  // loop on the bins to be integrated (outbin should be called inbin)
1798  for (out1bin = out1min; out1bin <= out1max; out1bin++) {
1799  for (out2bin = out2min; out2bin <= out2max; out2bin++) {
1800 
1801  Int_t bin = GetBin(*refX, *refY, *refZ);
1802 
1803  // sum the bin contents and errors if needed
1804  cont += RetrieveBinContent(bin);
1805  if (computeErrors) {
1806  Double_t exyz = GetBinError(bin);
1807  err2 += exyz*exyz;
1808  }
1809  }
1810  }
1811  Int_t ix = h1->FindBin( projX->GetBinCenter(ixbin) );
1812  h1->SetBinContent(ix ,cont);
1813  if (computeErrors) h1->SetBinError(ix, TMath::Sqrt(err2) );
1814  // sum all content
1815  totcont += cont;
1816 
1817  }
1818 
1819  // since we use a combination of fill and SetBinError we need to reset and recalculate the statistics
1820  // for weighted histograms otherwise sumw2 will be wrong.
1821  // We can keep the original statistics from the TH3 if the projected sumw is consistent with original one
1822  // i.e. when no events are thrown away
1823  bool resetStats = true;
1824  double eps = 1.E-12;
1825  if (IsA() == TH3F::Class() ) eps = 1.E-6;
1826  if (fTsumw != 0 && TMath::Abs( fTsumw - totcont) < TMath::Abs(fTsumw) * eps) resetStats = false;
1827 
1828  bool resetEntries = resetStats;
1829  // entries are calculated using underflow/overflow. If excluded entries must be reset
1830  resetEntries |= !useUF || !useOF;
1831 
1832 
1833  if (!resetStats) {
1834  Double_t stats[kNstat];
1835  GetStats(stats);
1836  if ( projX == GetYaxis() ) {
1837  stats[2] = stats[4];
1838  stats[3] = stats[5];
1839  }
1840  else if ( projX == GetZaxis() ) {
1841  stats[2] = stats[7];
1842  stats[3] = stats[8];
1843  }
1844  h1->PutStats(stats);
1845  }
1846  else {
1847  // reset statistics
1848  h1->ResetStats();
1849  }
1850  if (resetEntries) {
1851  // in case of error calculation (i.e. when Sumw2() is set)
1852  // use the effective entries for the entries
1853  // since this is the only way to estimate them
1854  Double_t entries = TMath::Floor( totcont + 0.5); // to avoid numerical rounding
1855  if (computeErrors) entries = h1->GetEffectiveEntries();
1856  h1->SetEntries( entries );
1857  }
1858  else {
1859  h1->SetEntries( fEntries );
1860  }
1861 
1862  return h1;
1863 }
1864 
1865 
1866 ////////////////////////////////////////////////////////////////////////////////
1867 /// internal method performing the projection to a 2D histogram
1868 /// called from TH3::Project3D
1869 
1870 TH2D *TH3::DoProject2D(const char* name, const char * title, const TAxis* projX, const TAxis* projY,
1871  bool computeErrors, bool originalRange,
1872  bool useUF, bool useOF) const
1873 {
1874  TH2D *h2 = 0;
1875 
1876  // Get range to use as well as bin limits
1877  Int_t ixmin = std::max(projX->GetFirst(),1);
1878  Int_t ixmax = std::min(projX->GetLast(),projX->GetNbins());
1879  Int_t iymin = std::max(projY->GetFirst(),1);
1880  Int_t iymax = std::min(projY->GetLast(),projY->GetNbins());
1881 
1882  Int_t nx = ixmax-ixmin+1;
1883  Int_t ny = iymax-iymin+1;
1884 
1885  // Create the histogram, either reseting a preexisting one
1886  // or creating one from scratch.
1887  // Does an object with the same name exists?
1888  TObject *h2obj = gROOT->FindObject(name);
1889  if (h2obj && h2obj->InheritsFrom(TH1::Class())) {
1890  if ( h2obj->IsA() != TH2D::Class() ) {
1891  Error("DoProject2D","Histogram with name %s must be a TH2D and is a %s",name,h2obj->ClassName());
1892  return 0;
1893  }
1894  h2 = (TH2D*)h2obj;
1895  // reset histogram and its axes
1896  h2->Reset();
1897  const TArrayD *xbins = projX->GetXbins();
1898  const TArrayD *ybins = projY->GetXbins();
1899  if ( originalRange ) {
1900  h2->SetBins(projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
1901  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
1902  // set bins for mixed axis do not exists - need to set afterwards the variable bins
1903  if (ybins->fN != 0)
1904  h2->GetXaxis()->Set(projY->GetNbins(),&ybins->fArray[iymin-1]);
1905  if (xbins->fN != 0)
1906  h2->GetYaxis()->Set(projX->GetNbins(),&xbins->fArray[ixmin-1]);
1907  } else {
1908  h2->SetBins(ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
1909  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
1910  if (ybins->fN != 0)
1911  h2->GetXaxis()->Set(ny,&ybins->fArray[iymin-1]);
1912  if (xbins->fN != 0)
1913  h2->GetYaxis()->Set(nx,&xbins->fArray[ixmin-1]);
1914  }
1915  }
1916 
1917 
1918  if (!h2) {
1919  const TArrayD *xbins = projX->GetXbins();
1920  const TArrayD *ybins = projY->GetXbins();
1921  if ( originalRange )
1922  {
1923  if (xbins->fN == 0 && ybins->fN == 0) {
1924  h2 = new TH2D(name,title,projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
1925  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
1926  } else if (ybins->fN == 0) {
1927  h2 = new TH2D(name,title,projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
1928  ,projX->GetNbins(),&xbins->fArray[ixmin-1]);
1929  } else if (xbins->fN == 0) {
1930  h2 = new TH2D(name,title,projY->GetNbins(),&ybins->fArray[iymin-1]
1931  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
1932  } else {
1933  h2 = new TH2D(name,title,projY->GetNbins(),&ybins->fArray[iymin-1],projX->GetNbins(),&xbins->fArray[ixmin-1]);
1934  }
1935  } else {
1936  if (xbins->fN == 0 && ybins->fN == 0) {
1937  h2 = new TH2D(name,title,ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
1938  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
1939  } else if (ybins->fN == 0) {
1940  h2 = new TH2D(name,title,ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
1941  ,nx,&xbins->fArray[ixmin-1]);
1942  } else if (xbins->fN == 0) {
1943  h2 = new TH2D(name,title,ny,&ybins->fArray[iymin-1]
1944  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
1945  } else {
1946  h2 = new TH2D(name,title,ny,&ybins->fArray[iymin-1],nx,&xbins->fArray[ixmin-1]);
1947  }
1948  }
1949  }
1950 
1951  // Copy the axis attributes and the axis labels if needed.
1952  THashList* labels1 = 0;
1953  THashList* labels2 = 0;
1954  // "xy"
1955  h2->GetXaxis()->ImportAttributes(projY);
1956  h2->GetYaxis()->ImportAttributes(projX);
1957  labels1 = projY->GetLabels();
1958  labels2 = projX->GetLabels();
1959  if (labels1) {
1960  TIter iL(labels1);
1961  TObjString* lb;
1962  Int_t i = 1;
1963  while ((lb=(TObjString*)iL())) {
1964  h2->GetXaxis()->SetBinLabel(i,lb->String().Data());
1965  i++;
1966  }
1967  }
1968  if (labels2) {
1969  TIter iL(labels2);
1970  TObjString* lb;
1971  Int_t i = 1;
1972  while ((lb=(TObjString*)iL())) {
1973  h2->GetYaxis()->SetBinLabel(i,lb->String().Data());
1974  i++;
1975  }
1976  }
1977  h2->SetLineColor(this->GetLineColor());
1978  h2->SetFillColor(this->GetFillColor());
1979  h2->SetMarkerColor(this->GetMarkerColor());
1980  h2->SetMarkerStyle(this->GetMarkerStyle());
1981 
1982  // Activate errors
1983  if ( computeErrors && (h2->GetSumw2N() != h2->GetNcells()) ) h2->Sumw2();
1984 
1985  // Set references to the axis, so that the bucle has no branches.
1986  const TAxis* out = 0;
1987  if ( projX != GetXaxis() && projY != GetXaxis() ) {
1988  out = GetXaxis();
1989  } else if ( projX != GetYaxis() && projY != GetYaxis() ) {
1990  out = GetYaxis();
1991  } else {
1992  out = GetZaxis();
1993  }
1994 
1995  Int_t *refX = 0, *refY = 0, *refZ = 0;
1996  Int_t ixbin, iybin, outbin;
1997  if ( projX == GetXaxis() && projY == GetYaxis() ) { refX = &ixbin; refY = &iybin; refZ = &outbin; }
1998  if ( projX == GetYaxis() && projY == GetXaxis() ) { refX = &iybin; refY = &ixbin; refZ = &outbin; }
1999  if ( projX == GetXaxis() && projY == GetZaxis() ) { refX = &ixbin; refY = &outbin; refZ = &iybin; }
2000  if ( projX == GetZaxis() && projY == GetXaxis() ) { refX = &iybin; refY = &outbin; refZ = &ixbin; }
2001  if ( projX == GetYaxis() && projY == GetZaxis() ) { refX = &outbin; refY = &ixbin; refZ = &iybin; }
2002  if ( projX == GetZaxis() && projY == GetYaxis() ) { refX = &outbin; refY = &iybin; refZ = &ixbin; }
2003  R__ASSERT (refX != 0 && refY != 0 && refZ != 0);
2004 
2005  // Fill the projected histogram excluding underflow/overflows if considered in the option
2006  // if specified in the option (by default they considered)
2007  Double_t totcont = 0;
2008 
2009  Int_t outmin = out->GetFirst();
2010  Int_t outmax = out->GetLast();
2011  // GetFirst(), GetLast() can return (0,0) when the range bit is set artificially (see TAxis::SetRange)
2012  if (outmin == 0 && outmax == 0) { outmin = 1; outmax = out->GetNbins(); }
2013  // correct for underflow/overflows
2014  if (useUF && !out->TestBit(TAxis::kAxisRange) ) outmin -= 1;
2015  if (useOF && !out->TestBit(TAxis::kAxisRange) ) outmax += 1;
2016 
2017  for (ixbin=0;ixbin<=1+projX->GetNbins();ixbin++) {
2018  if ( projX->TestBit(TAxis::kAxisRange) && ( ixbin < ixmin || ixbin > ixmax )) continue;
2019  Int_t ix = h2->GetYaxis()->FindBin( projX->GetBinCenter(ixbin) );
2020 
2021  for (iybin=0;iybin<=1+projY->GetNbins();iybin++) {
2022  if ( projY->TestBit(TAxis::kAxisRange) && ( iybin < iymin || iybin > iymax )) continue;
2023  Int_t iy = h2->GetXaxis()->FindBin( projY->GetBinCenter(iybin) );
2024 
2025  Double_t cont = 0;
2026  Double_t err2 = 0;
2027 
2028  // loop on the bins to be integrated (outbin should be called inbin)
2029  for (outbin = outmin; outbin <= outmax; outbin++) {
2030 
2031  Int_t bin = GetBin(*refX,*refY,*refZ);
2032 
2033  // sum the bin contents and errors if needed
2034  cont += RetrieveBinContent(bin);
2035  if (computeErrors) {
2036  Double_t exyz = GetBinError(bin);
2037  err2 += exyz*exyz;
2038  }
2039 
2040  }
2041 
2042  // remember axis are inverted
2043  h2->SetBinContent(iy , ix, cont);
2044  if (computeErrors) h2->SetBinError(iy, ix, TMath::Sqrt(err2) );
2045  // sum all content
2046  totcont += cont;
2047 
2048  }
2049  }
2050 
2051  // since we use fill we need to reset and recalculate the statistics (see comment in DoProject1D )
2052  // or keep original statistics if consistent sumw2
2053  bool resetStats = true;
2054  double eps = 1.E-12;
2055  if (IsA() == TH3F::Class() ) eps = 1.E-6;
2056  if (fTsumw != 0 && TMath::Abs( fTsumw - totcont) < TMath::Abs(fTsumw) * eps) resetStats = false;
2057 
2058  bool resetEntries = resetStats;
2059  // entries are calculated using underflow/overflow. If excluded entries must be reset
2060  resetEntries |= !useUF || !useOF;
2061 
2062  if (!resetStats) {
2063  Double_t stats[kNstat];
2064  Double_t oldst[kNstat]; // old statistics
2065  for (Int_t i = 0; i < kNstat; ++i) { oldst[i] = 0; }
2066  GetStats(oldst);
2067  std::copy(oldst,oldst+kNstat,stats);
2068  // not that projX refer to Y axis and projX refer to the X axis of projected histogram
2069  // nothing to do for projection in Y vs X
2070  if ( projY == GetXaxis() && projX == GetZaxis() ) { // case XZ
2071  stats[4] = oldst[7];
2072  stats[5] = oldst[8];
2073  stats[6] = oldst[9];
2074  }
2075  if ( projY == GetYaxis() ) {
2076  stats[2] = oldst[4];
2077  stats[3] = oldst[5];
2078  if ( projX == GetXaxis() ) { // case YX
2079  stats[4] = oldst[2];
2080  stats[5] = oldst[3];
2081  }
2082  if ( projX == GetZaxis() ) { // case YZ
2083  stats[4] = oldst[7];
2084  stats[5] = oldst[8];
2085  stats[6] = oldst[10];
2086  }
2087  }
2088  else if ( projY == GetZaxis() ) {
2089  stats[2] = oldst[7];
2090  stats[3] = oldst[8];
2091  if ( projX == GetXaxis() ) { // case ZX
2092  stats[4] = oldst[2];
2093  stats[5] = oldst[3];
2094  stats[6] = oldst[9];
2095  }
2096  if ( projX == GetYaxis() ) { // case ZY
2097  stats[4] = oldst[4];
2098  stats[5] = oldst[5];
2099  stats[6] = oldst[10];
2100  }
2101  }
2102  // set the new statistics
2103  h2->PutStats(stats);
2104  }
2105  else {
2106  // recalculate the statistics
2107  h2->ResetStats();
2108  }
2109 
2110  if (resetEntries) {
2111  // use the effective entries for the entries
2112  // since this is the only way to estimate them
2113  Double_t entries = h2->GetEffectiveEntries();
2114  if (!computeErrors) entries = TMath::Floor( entries + 0.5); // to avoid numerical rounding
2115  h2->SetEntries( entries );
2116  }
2117  else {
2118  h2->SetEntries( fEntries );
2119  }
2120 
2121 
2122  return h2;
2123 }
2124 
2125 
2126 ////////////////////////////////////////////////////////////////////////////////
2127 /// Project a 3-d histogram into 1 or 2-d histograms depending on the
2128 /// option parameter, which may contain a combination of the characters x,y,z,e
2129 /// - option = "x" return the x projection into a TH1D histogram
2130 /// - option = "y" return the y projection into a TH1D histogram
2131 /// - option = "z" return the z projection into a TH1D histogram
2132 /// - option = "xy" return the x versus y projection into a TH2D histogram
2133 /// - option = "yx" return the y versus x projection into a TH2D histogram
2134 /// - option = "xz" return the x versus z projection into a TH2D histogram
2135 /// - option = "zx" return the z versus x projection into a TH2D histogram
2136 /// - option = "yz" return the y versus z projection into a TH2D histogram
2137 /// - option = "zy" return the z versus y projection into a TH2D histogram
2138 ///
2139 /// NB: the notation "a vs b" means "a" vertical and "b" horizontal
2140 ///
2141 /// option = "o" original axis range of the target axes will be
2142 /// kept, but only bins inside the selected range will be filled.
2143 ///
2144 /// If option contains the string "e", errors are computed
2145 ///
2146 /// The projection is made for the selected bins only.
2147 /// To select a bin range along an axis, use TAxis::SetRange, eg
2148 /// h3.GetYaxis()->SetRange(23,56);
2149 ///
2150 /// NOTE 1: The generated histogram is named th3name + option
2151 /// eg if the TH3* h histogram is named "myhist", then
2152 /// h->Project3D("xy"); produces a TH2D histogram named "myhist_xy"
2153 /// if a histogram of the same type already exists, it is overwritten.
2154 /// The following sequence
2155 /// h->Project3D("xy");
2156 /// h->Project3D("xy2");
2157 /// will generate two TH2D histograms named "myhist_xy" and "myhist_xy2"
2158 /// A different name can be generated by attaching a string to the option
2159 /// For example h->Project3D("name_xy") will generate an histogram with the name: h3dname_name_xy.
2160 ///
2161 /// NOTE 2: If an histogram of the same type already exists,
2162 /// the histogram is reset and filled again with the projected contents of the TH3.
2163 ///
2164 /// NOTE 3: The number of entries in the projected histogram is estimated from the number of
2165 /// effective entries for all the cells included in the projection.
2166 ///
2167 /// NOTE 4: underflow/overflow are included by default in the projection
2168 /// To exclude underflow and/or overflow (for both axis in case of a projection to a 1D histogram) use option "NUF" and/or "NOF"
2169 /// With SetRange() you can have all bins except underflow/overflow only if you set the axis bit range as
2170 /// following after having called SetRange: axis->SetRange(1, axis->GetNbins());
2171 
2172 TH1 *TH3::Project3D(Option_t *option) const
2173 {
2174  TString opt = option; opt.ToLower();
2175  Int_t pcase = 0;
2176  TString ptype;
2177  if (opt.Contains("x")) { pcase = 1; ptype = "x"; }
2178  if (opt.Contains("y")) { pcase = 2; ptype = "y"; }
2179  if (opt.Contains("z")) { pcase = 3; ptype = "z"; }
2180  if (opt.Contains("xy")) { pcase = 4; ptype = "xy"; }
2181  if (opt.Contains("yx")) { pcase = 5; ptype = "yx"; }
2182  if (opt.Contains("xz")) { pcase = 6; ptype = "xz"; }
2183  if (opt.Contains("zx")) { pcase = 7; ptype = "zx"; }
2184  if (opt.Contains("yz")) { pcase = 8; ptype = "yz"; }
2185  if (opt.Contains("zy")) { pcase = 9; ptype = "zy"; }
2186 
2187  if (pcase == 0) {
2188  Error("Project3D","No projection axis specified - return a NULL pointer");
2189  return 0;
2190  }
2191  // do not remove ptype from opt to use later in the projected histo name
2192 
2193  Bool_t computeErrors = GetSumw2N();
2194  if (opt.Contains("e") ) {
2195  computeErrors = kTRUE;
2196  opt.Remove(opt.First("e"),1);
2197  }
2198 
2199  Bool_t useUF = kTRUE;
2200  Bool_t useOF = kTRUE;
2201  if (opt.Contains("nuf") ) {
2202  useUF = kFALSE;
2203  opt.Remove(opt.Index("nuf"),3);
2204  }
2205  if (opt.Contains("nof") ) {
2206  useOF = kFALSE;
2207  opt.Remove(opt.Index("nof"),3);
2208  }
2209 
2210  Bool_t originalRange = kFALSE;
2211  if (opt.Contains('o') ) {
2212  originalRange = kTRUE;
2213  opt.Remove(opt.First("o"),1);
2214  }
2215 
2216 
2217  // Create the projection histogram
2218  TH1 *h = 0;
2219 
2220  TString name = GetName();
2221  TString title = GetTitle();
2222  name += "_"; name += opt; // opt may include a user defined name
2223  title += " "; title += ptype; title += " projection";
2224 
2225  switch (pcase) {
2226  case 1:
2227  // "x"
2228  h = DoProject1D(name, title, this->GetXaxis(), nullptr, nullptr,
2229  computeErrors, originalRange, useUF, useOF);
2230  break;
2231 
2232  case 2:
2233  // "y"
2234  h = DoProject1D(name, title, this->GetYaxis(), nullptr, nullptr,
2235  computeErrors, originalRange, useUF, useOF);
2236  break;
2237 
2238  case 3:
2239  // "z"
2240  h = DoProject1D(name, title, this->GetZaxis(), nullptr, nullptr,
2241  computeErrors, originalRange, useUF, useOF);
2242  break;
2243 
2244  case 4:
2245  // "xy"
2246  h = DoProject2D(name, title, this->GetXaxis(),this->GetYaxis(),
2247  computeErrors, originalRange, useUF, useOF);
2248  break;
2249 
2250  case 5:
2251  // "yx"
2252  h = DoProject2D(name, title, this->GetYaxis(),this->GetXaxis(),
2253  computeErrors, originalRange, useUF, useOF);
2254  break;
2255 
2256  case 6:
2257  // "xz"
2258  h = DoProject2D(name, title, this->GetXaxis(),this->GetZaxis(),
2259  computeErrors, originalRange, useUF, useOF);
2260  break;
2261 
2262  case 7:
2263  // "zx"
2264  h = DoProject2D(name, title, this->GetZaxis(),this->GetXaxis(),
2265  computeErrors, originalRange, useUF, useOF);
2266  break;
2267 
2268  case 8:
2269  // "yz"
2270  h = DoProject2D(name, title, this->GetYaxis(),this->GetZaxis(),
2271  computeErrors, originalRange, useUF, useOF);
2272  break;
2273 
2274  case 9:
2275  // "zy"
2276  h = DoProject2D(name, title, this->GetZaxis(),this->GetYaxis(),
2277  computeErrors, originalRange, useUF, useOF);
2278  break;
2279 
2280  }
2281 
2282  // draw in current pad
2283  if (h && opt.Contains("d")) {
2284  opt.Remove(opt.First("d"),1);
2285  TVirtualPad *padsav = gPad;
2286  TVirtualPad *pad = gROOT->GetSelectedPad();
2287  if (pad) pad->cd();
2288  if (!gPad || !gPad->FindObject(h)) {
2289  h->Draw(opt);
2290  } else {
2291  h->Paint(opt);
2292  }
2293  if (padsav) padsav->cd();
2294  }
2295 
2296  return h;
2297 }
2298 
2299 
2300 ////////////////////////////////////////////////////////////////////////////////
2301 /// internal function to fill the bins of the projected profile 2D histogram
2302 /// called from DoProjectProfile2D
2303 
2304 void TH3::DoFillProfileProjection(TProfile2D * p2,
2305  const TAxis & a1, const TAxis & a2, const TAxis & a3,
2306  Int_t bin1, Int_t bin2, Int_t bin3,
2307  Int_t inBin, Bool_t useWeights ) const {
2308  Double_t cont = GetBinContent(inBin);
2309  if (!cont) return;
2310  TArrayD & binSumw2 = *(p2->GetBinSumw2());
2311  if (useWeights && binSumw2.fN <= 0) useWeights = false;
2312  if (!useWeights) p2->SetBit(TH1::kIsNotW); // to use Fill for setting the bin contents of the Profile
2313  // the following fill update wrongly the fBinSumw2- need to save it before
2314  Double_t u = a1.GetBinCenter(bin1);
2315  Double_t v = a2.GetBinCenter(bin2);
2316  Double_t w = a3.GetBinCenter(bin3);
2317  Int_t outBin = p2->FindBin(u, v);
2318  if (outBin <0) return;
2319  Double_t tmp = 0;
2320  if ( useWeights ) tmp = binSumw2.fArray[outBin];
2321  p2->Fill( u , v, w, cont);
2322  if (useWeights ) binSumw2.fArray[outBin] = tmp + fSumw2.fArray[inBin];
2323 }
2324 
2325 
2326 ////////////////////////////////////////////////////////////////////////////////
2327 /// internal method to project to a 2D Profile
2328 /// called from TH3::Project3DProfile
2329 
2330 TProfile2D *TH3::DoProjectProfile2D(const char* name, const char * title, const TAxis* projX, const TAxis* projY,
2331  bool originalRange, bool useUF, bool useOF) const
2332 {
2333  // Get the ranges where we will work.
2334  Int_t ixmin = std::max(projX->GetFirst(),1);
2335  Int_t ixmax = std::min(projX->GetLast(),projX->GetNbins());
2336  Int_t iymin = std::max(projY->GetFirst(),1);
2337  Int_t iymax = std::min(projY->GetLast(),projY->GetNbins());
2338 
2339  Int_t nx = ixmax-ixmin+1;
2340  Int_t ny = iymax-iymin+1;
2341 
2342  // Create the projected profiles
2343  TProfile2D *p2 = 0;
2344 
2345  // Create the histogram, either reseting a preexisting one
2346  // Does an object with the same name exists?
2347  TObject *p2obj = gROOT->FindObject(name);
2348  if (p2obj && p2obj->InheritsFrom(TH1::Class())) {
2349  if (p2obj->IsA() != TProfile2D::Class() ) {
2350  Error("DoProjectProfile2D","Histogram with name %s must be a TProfile2D and is a %s",name,p2obj->ClassName());
2351  return 0;
2352  }
2353  p2 = (TProfile2D*)p2obj;
2354  // reset existing profile and re-set bins
2355  p2->Reset();
2356  const TArrayD *xbins = projX->GetXbins();
2357  const TArrayD *ybins = projY->GetXbins();
2358  if ( originalRange ) {
2359  p2->SetBins(projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
2360  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
2361  // set bins for mixed axis do not exists - need to set afterwards the variable bins
2362  if (ybins->fN != 0)
2363  p2->GetXaxis()->Set(projY->GetNbins(),&ybins->fArray[iymin-1]);
2364  if (xbins->fN != 0)
2365  p2->GetYaxis()->Set(projX->GetNbins(),&xbins->fArray[ixmin-1]);
2366  } else {
2367  p2->SetBins(ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
2368  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
2369  if (ybins->fN != 0)
2370  p2->GetXaxis()->Set(ny,&ybins->fArray[iymin-1]);
2371  if (xbins->fN != 0)
2372  p2->GetYaxis()->Set(nx,&xbins->fArray[ixmin-1]);
2373  }
2374  }
2375 
2376  if (!p2) {
2377  const TArrayD *xbins = projX->GetXbins();
2378  const TArrayD *ybins = projY->GetXbins();
2379  if ( originalRange ) {
2380  if (xbins->fN == 0 && ybins->fN == 0) {
2381  p2 = new TProfile2D(name,title,projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
2382  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
2383  } else if (ybins->fN == 0) {
2384  p2 = new TProfile2D(name,title,projY->GetNbins(),projY->GetXmin(),projY->GetXmax()
2385  ,projX->GetNbins(),&xbins->fArray[ixmin-1]);
2386  } else if (xbins->fN == 0) {
2387  p2 = new TProfile2D(name,title,projY->GetNbins(),&ybins->fArray[iymin-1]
2388  ,projX->GetNbins(),projX->GetXmin(),projX->GetXmax());
2389  } else {
2390  p2 = new TProfile2D(name,title,projY->GetNbins(),&ybins->fArray[iymin-1],projX->GetNbins(),&xbins->fArray[ixmin-1]);
2391  }
2392  } else {
2393  if (xbins->fN == 0 && ybins->fN == 0) {
2394  p2 = new TProfile2D(name,title,ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
2395  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
2396  } else if (ybins->fN == 0) {
2397  p2 = new TProfile2D(name,title,ny,projY->GetBinLowEdge(iymin),projY->GetBinUpEdge(iymax)
2398  ,nx,&xbins->fArray[ixmin-1]);
2399  } else if (xbins->fN == 0) {
2400  p2 = new TProfile2D(name,title,ny,&ybins->fArray[iymin-1]
2401  ,nx,projX->GetBinLowEdge(ixmin),projX->GetBinUpEdge(ixmax));
2402  } else {
2403  p2 = new TProfile2D(name,title,ny,&ybins->fArray[iymin-1],nx,&xbins->fArray[ixmin-1]);
2404  }
2405  }
2406  }
2407 
2408  // Set references to the axis, so that the loop has no branches.
2409  const TAxis* outAxis = 0;
2410  if ( projX != GetXaxis() && projY != GetXaxis() ) {
2411  outAxis = GetXaxis();
2412  } else if ( projX != GetYaxis() && projY != GetYaxis() ) {
2413  outAxis = GetYaxis();
2414  } else {
2415  outAxis = GetZaxis();
2416  }
2417 
2418  // Weights management
2419  bool useWeights = (GetSumw2N() > 0);
2420  // store sum of w2 in profile if histo is weighted
2421  if (useWeights && (p2->GetBinSumw2()->fN != p2->GetNcells() ) ) p2->Sumw2();
2422 
2423  // Set references to the bins, so that the loop has no branches.
2424  Int_t *refX = 0, *refY = 0, *refZ = 0;
2425  Int_t ixbin, iybin, outbin;
2426  if ( projX == GetXaxis() && projY == GetYaxis() ) { refX = &ixbin; refY = &iybin; refZ = &outbin; }
2427  if ( projX == GetYaxis() && projY == GetXaxis() ) { refX = &iybin; refY = &ixbin; refZ = &outbin; }
2428  if ( projX == GetXaxis() && projY == GetZaxis() ) { refX = &ixbin; refY = &outbin; refZ = &iybin; }
2429  if ( projX == GetZaxis() && projY == GetXaxis() ) { refX = &iybin; refY = &outbin; refZ = &ixbin; }
2430  if ( projX == GetYaxis() && projY == GetZaxis() ) { refX = &outbin; refY = &ixbin; refZ = &iybin; }
2431  if ( projX == GetZaxis() && projY == GetYaxis() ) { refX = &outbin; refY = &iybin; refZ = &ixbin; }
2432  R__ASSERT (refX != 0 && refY != 0 && refZ != 0);
2433 
2434  Int_t outmin = outAxis->GetFirst();
2435  Int_t outmax = outAxis->GetLast();
2436  // GetFirst, GetLast can return underflow or overflow bins
2437  // correct for underflow/overflows
2438  if (useUF && !outAxis->TestBit(TAxis::kAxisRange) ) outmin -= 1;
2439  if (useOF && !outAxis->TestBit(TAxis::kAxisRange) ) outmax += 1;
2440 
2441  TArrayD & binSumw2 = *(p2->GetBinSumw2());
2442  if (useWeights && binSumw2.fN <= 0) useWeights = false;
2443  if (!useWeights) p2->SetBit(TH1::kIsNotW);
2444 
2445  // Call specific method for the projection
2446  for (ixbin=0;ixbin<=1+projX->GetNbins();ixbin++) {
2447  if ( (ixbin < ixmin || ixbin > ixmax) && projX->TestBit(TAxis::kAxisRange)) continue;
2448  for ( iybin=0;iybin<=1+projY->GetNbins();iybin++) {
2449  if ( (iybin < iymin || iybin > iymax) && projX->TestBit(TAxis::kAxisRange)) continue;
2450 
2451  // profile output bin
2452  Int_t poutBin = p2->FindBin(projY->GetBinCenter(iybin), projX->GetBinCenter(ixbin));
2453  if (poutBin <0) continue;
2454  // loop on the bins to be integrated (outbin should be called inbin)
2455  for (outbin = outmin; outbin <= outmax; outbin++) {
2456 
2457  Int_t bin = GetBin(*refX,*refY,*refZ);
2458 
2459  //DoFillProfileProjection(p2, *projY, *projX, *outAxis, iybin, ixbin, outbin, bin, useWeights);
2460 
2461  Double_t cont = RetrieveBinContent(bin);
2462  if (!cont) continue;
2463 
2464  Double_t tmp = 0;
2465  // the following fill update wrongly the fBinSumw2- need to save it before
2466  if ( useWeights ) tmp = binSumw2.fArray[poutBin];
2467  p2->Fill( projY->GetBinCenter(iybin) , projX->GetBinCenter(ixbin), outAxis->GetBinCenter(outbin), cont);
2468  if (useWeights ) binSumw2.fArray[poutBin] = tmp + fSumw2.fArray[bin];
2469 
2470  }
2471  }
2472  }
2473 
2474  // recompute statistics for the projected profiles
2475  // forget about preserving old statistics
2476  bool resetStats = true;
2477  Double_t stats[kNstat];
2478  // reset statistics
2479  if (resetStats)
2480  for (Int_t i=0;i<kNstat;i++) stats[i] = 0;
2481 
2482  p2->PutStats(stats);
2483  Double_t entries = fEntries;
2484  // recalculate the statistics
2485  if (resetStats) {
2486  entries = p2->GetEffectiveEntries();
2487  if (!useWeights) entries = TMath::Floor( entries + 0.5); // to avoid numerical rounding
2488  p2->SetEntries( entries );
2489  }
2490 
2491  p2->SetEntries(entries);
2492 
2493  return p2;
2494 }
2495 
2496 
2497 ////////////////////////////////////////////////////////////////////////////////
2498 /// Project a 3-d histogram into a 2-d profile histograms depending
2499 /// on the option parameter
2500 /// option may contain a combination of the characters x,y,z
2501 /// option = "xy" return the x versus y projection into a TProfile2D histogram
2502 /// option = "yx" return the y versus x projection into a TProfile2D histogram
2503 /// option = "xz" return the x versus z projection into a TProfile2D histogram
2504 /// option = "zx" return the z versus x projection into a TProfile2D histogram
2505 /// option = "yz" return the y versus z projection into a TProfile2D histogram
2506 /// option = "zy" return the z versus y projection into a TProfile2D histogram
2507 /// NB: the notation "a vs b" means "a" vertical and "b" horizontal
2508 ///
2509 /// option = "o" original axis range of the target axes will be
2510 /// kept, but only bins inside the selected range will be filled.
2511 ///
2512 /// The projection is made for the selected bins only.
2513 /// To select a bin range along an axis, use TAxis::SetRange, eg
2514 /// h3.GetYaxis()->SetRange(23,56);
2515 ///
2516 /// NOTE 1: The generated histogram is named th3name + "_p" + option
2517 /// eg if the TH3* h histogram is named "myhist", then
2518 /// h->Project3D("xy"); produces a TProfile2D histogram named "myhist_pxy".
2519 /// The following sequence
2520 /// h->Project3DProfile("xy");
2521 /// h->Project3DProfile("xy2");
2522 /// will generate two TProfile2D histograms named "myhist_pxy" and "myhist_pxy2"
2523 /// So, passing additional characters in the option string one can customize the name.
2524 ///
2525 /// NOTE 2: If a profile of the same type already exists with compatible axes,
2526 /// the profile is reset and filled again with the projected contents of the TH3.
2527 /// In the case of axes incompatibility, an error is reported and a NULL pointer is returned.
2528 ///
2529 /// NOTE 3: The number of entries in the projected profile is estimated from the number of
2530 /// effective entries for all the cells included in the projection.
2531 ///
2532 /// NOTE 4: underflow/overflow are by default excluded from the projection
2533 /// (Note that this is a different default behavior compared to the projection to an histogram)
2534 /// To include the underflow and/or overflow use option "UF" and/or "OF"
2535 
2536 TProfile2D *TH3::Project3DProfile(Option_t *option) const
2537 {
2538  TString opt = option; opt.ToLower();
2539  Int_t pcase = 0;
2540  TString ptype;
2541  if (opt.Contains("xy")) { pcase = 4; ptype = "xy"; }
2542  if (opt.Contains("yx")) { pcase = 5; ptype = "yx"; }
2543  if (opt.Contains("xz")) { pcase = 6; ptype = "xz"; }
2544  if (opt.Contains("zx")) { pcase = 7; ptype = "zx"; }
2545  if (opt.Contains("yz")) { pcase = 8; ptype = "yz"; }
2546  if (opt.Contains("zy")) { pcase = 9; ptype = "zy"; }
2547 
2548  if (pcase == 0) {
2549  Error("Project3D","No projection axis specified - return a NULL pointer");
2550  return 0;
2551  }
2552  // do not remove ptype from opt to use later in the projected histo name
2553 
2554  Bool_t useUF = kFALSE;
2555  if (opt.Contains("uf") ) {
2556  useUF = kTRUE;
2557  opt.Remove(opt.Index("uf"),2);
2558  }
2559  Bool_t useOF = kFALSE;
2560  if (opt.Contains("of") ) {
2561  useOF = kTRUE;
2562  opt.Remove(opt.Index("of"),2);
2563  }
2564 
2565  Bool_t originalRange = kFALSE;
2566  if (opt.Contains('o') ) {
2567  originalRange = kTRUE;
2568  opt.Remove(opt.First("o"),1);
2569  }
2570 
2571  // Create the projected profile
2572  TProfile2D *p2 = 0;
2573  TString name = GetName();
2574  TString title = GetTitle();
2575  name += "_p"; name += opt; // opt may include a user defined name
2576  title += " profile "; title += ptype; title += " projection";
2577 
2578  // Call the method with the specific projected axes.
2579  switch (pcase) {
2580  case 4:
2581  // "xy"
2582  p2 = DoProjectProfile2D(name, title, GetXaxis(), GetYaxis(), originalRange, useUF, useOF);
2583  break;
2584 
2585  case 5:
2586  // "yx"
2587  p2 = DoProjectProfile2D(name, title, GetYaxis(), GetXaxis(), originalRange, useUF, useOF);
2588  break;
2589 
2590  case 6:
2591  // "xz"
2592  p2 = DoProjectProfile2D(name, title, GetXaxis(), GetZaxis(), originalRange, useUF, useOF);
2593  break;
2594 
2595  case 7:
2596  // "zx"
2597  p2 = DoProjectProfile2D(name, title, GetZaxis(), GetXaxis(), originalRange, useUF, useOF);
2598  break;
2599 
2600  case 8:
2601  // "yz"
2602  p2 = DoProjectProfile2D(name, title, GetYaxis(), GetZaxis(), originalRange, useUF, useOF);
2603  break;
2604 
2605  case 9:
2606  // "zy"
2607  p2 = DoProjectProfile2D(name, title, GetZaxis(), GetYaxis(), originalRange, useUF, useOF);
2608  break;
2609 
2610  }
2611 
2612  return p2;
2613 }
2614 
2615 
2616 ////////////////////////////////////////////////////////////////////////////////
2617 /// Replace current statistics with the values in array stats
2618 
2619 void TH3::PutStats(Double_t *stats)
2620 {
2621  TH1::PutStats(stats);
2622  fTsumwy = stats[4];
2623  fTsumwy2 = stats[5];
2624  fTsumwxy = stats[6];
2625  fTsumwz = stats[7];
2626  fTsumwz2 = stats[8];
2627  fTsumwxz = stats[9];
2628  fTsumwyz = stats[10];
2629 }
2630 
2631 
2632 ////////////////////////////////////////////////////////////////////////////////
2633 /// Rebin only the X axis
2634 /// see Rebin3D
2635 
2636 TH3 *TH3::RebinX(Int_t ngroup, const char *newname)
2637 {
2638  return Rebin3D(ngroup, 1, 1, newname);
2639 }
2640 
2641 
2642 ////////////////////////////////////////////////////////////////////////////////
2643 /// Rebin only the Y axis
2644 /// see Rebin3D
2645 
2646 TH3 *TH3::RebinY(Int_t ngroup, const char *newname)
2647 {
2648  return Rebin3D(1, ngroup, 1, newname);
2649 }
2650 
2651 
2652 ////////////////////////////////////////////////////////////////////////////////
2653 /// Rebin only the Z axis
2654 /// see Rebin3D
2655 
2656 TH3 *TH3::RebinZ(Int_t ngroup, const char *newname)
2657 {
2658  return Rebin3D(1, 1, ngroup, newname);
2659 
2660 }
2661 
2662 
2663 ////////////////////////////////////////////////////////////////////////////////
2664 /// Rebin this histogram grouping nxgroup/nygroup/nzgroup bins along the xaxis/yaxis/zaxis together.
2665 ///
2666 /// if newname is not blank a new temporary histogram hnew is created.
2667 /// else the current histogram is modified (default)
2668 /// The parameter nxgroup/nygroup indicate how many bins along the xaxis/yaxis of this
2669 /// have to me merged into one bin of hnew
2670 /// If the original histogram has errors stored (via Sumw2), the resulting
2671 /// histograms has new errors correctly calculated.
2672 ///
2673 /// examples: if hpxpy is an existing TH3 histogram with 40 x 40 x 40 bins
2674 /// hpxpypz->Rebin3D(); // merges two bins along the xaxis and yaxis in one in hpxpypz
2675 /// // Carefull: previous contents of hpxpy are lost
2676 /// hpxpypz->RebinX(5); //merges five bins along the xaxis in one in hpxpypz
2677 /// TH3 *hnew = hpxpypz->RebinY(5,"hnew"); // creates a new histogram hnew
2678 /// // merging 5 bins of h1 along the yaxis in one bin
2679 ///
2680 /// NOTE : If nxgroup/nygroup is not an exact divider of the number of bins,
2681 /// along the xaxis/yaxis the top limit(s) of the rebinned histogram
2682 /// is changed to the upper edge of the xbin=newxbins*nxgroup resp.
2683 /// ybin=newybins*nygroup and the corresponding bins are added to
2684 /// the overflow bin.
2685 /// Statistics will be recomputed from the new bin contents.
2686 
2687 TH3 *TH3::Rebin3D(Int_t nxgroup, Int_t nygroup, Int_t nzgroup, const char *newname)
2688 {
2689  Int_t i,j,k,xbin,ybin,zbin;
2690  Int_t nxbins = fXaxis.GetNbins();
2691  Int_t nybins = fYaxis.GetNbins();
2692  Int_t nzbins = fZaxis.GetNbins();
2693  Double_t xmin = fXaxis.GetXmin();
2694  Double_t xmax = fXaxis.GetXmax();
2695  Double_t ymin = fYaxis.GetXmin();
2696  Double_t ymax = fYaxis.GetXmax();
2697  Double_t zmin = fZaxis.GetXmin();
2698  Double_t zmax = fZaxis.GetXmax();
2699  if ((nxgroup <= 0) || (nxgroup > nxbins)) {
2700  Error("Rebin", "Illegal value of nxgroup=%d",nxgroup);
2701  return 0;
2702  }
2703  if ((nygroup <= 0) || (nygroup > nybins)) {
2704  Error("Rebin", "Illegal value of nygroup=%d",nygroup);
2705  return 0;
2706  }
2707  if ((nzgroup <= 0) || (nzgroup > nzbins)) {
2708  Error("Rebin", "Illegal value of nzgroup=%d",nzgroup);
2709  return 0;
2710  }
2711 
2712  Int_t newxbins = nxbins/nxgroup;
2713  Int_t newybins = nybins/nygroup;
2714  Int_t newzbins = nzbins/nzgroup;
2715 
2716  // Save old bin contents into a new array
2717  Double_t entries = fEntries;
2718  Double_t *oldBins = new Double_t[fNcells];
2719  for (Int_t ibin = 0; ibin < fNcells; ibin++) {
2720  oldBins[ibin] = RetrieveBinContent(ibin);
2721  }
2722  Double_t *oldSumw2 = 0;
2723  if (fSumw2.fN != 0) {
2724  oldSumw2 = new Double_t[fNcells];
2725  for (Int_t ibin = 0; ibin < fNcells; ibin++) {
2726  oldSumw2[ibin] = fSumw2.fArray[ibin];
2727  }
2728  }
2729 
2730  // create a clone of the old histogram if newname is specified
2731  TH3 *hnew = this;
2732  if (newname && strlen(newname)) {
2733  hnew = (TH3*)Clone();
2734  hnew->SetName(newname);
2735  }
2736 
2737  // save original statistics
2738  Double_t stat[kNstat];
2739  GetStats(stat);
2740  bool resetStat = false;
2741 
2742 
2743  // change axis specs and rebuild bin contents array
2744  if (newxbins*nxgroup != nxbins) {
2745  xmax = fXaxis.GetBinUpEdge(newxbins*nxgroup);
2746  resetStat = true; //stats must be reset because top bins will be moved to overflow bin
2747  }
2748  if (newybins*nygroup != nybins) {
2749  ymax = fYaxis.GetBinUpEdge(newybins*nygroup);
2750  resetStat = true; //stats must be reset because top bins will be moved to overflow bin
2751  }
2752  if (newzbins*nzgroup != nzbins) {
2753  zmax = fZaxis.GetBinUpEdge(newzbins*nzgroup);
2754  resetStat = true; //stats must be reset because top bins will be moved to overflow bin
2755  }
2756  // save the TAttAxis members (reset by SetBins) for x axis
2757  Int_t nXdivisions = fXaxis.GetNdivisions();
2758  Color_t xAxisColor = fXaxis.GetAxisColor();
2759  Color_t xLabelColor = fXaxis.GetLabelColor();
2760  Style_t xLabelFont = fXaxis.GetLabelFont();
2761  Float_t xLabelOffset = fXaxis.GetLabelOffset();
2762  Float_t xLabelSize = fXaxis.GetLabelSize();
2763  Float_t xTickLength = fXaxis.GetTickLength();
2764  Float_t xTitleOffset = fXaxis.GetTitleOffset();
2765  Float_t xTitleSize = fXaxis.GetTitleSize();
2766  Color_t xTitleColor = fXaxis.GetTitleColor();
2767  Style_t xTitleFont = fXaxis.GetTitleFont();
2768  // save the TAttAxis members (reset by SetBins) for y axis
2769  Int_t nYdivisions = fYaxis.GetNdivisions();
2770  Color_t yAxisColor = fYaxis.GetAxisColor();
2771  Color_t yLabelColor = fYaxis.GetLabelColor();
2772  Style_t yLabelFont = fYaxis.GetLabelFont();
2773  Float_t yLabelOffset = fYaxis.GetLabelOffset();
2774  Float_t yLabelSize = fYaxis.GetLabelSize();
2775  Float_t yTickLength = fYaxis.GetTickLength();
2776  Float_t yTitleOffset = fYaxis.GetTitleOffset();
2777  Float_t yTitleSize = fYaxis.GetTitleSize();
2778  Color_t yTitleColor = fYaxis.GetTitleColor();
2779  Style_t yTitleFont = fYaxis.GetTitleFont();
2780  // save the TAttAxis members (reset by SetBins) for z axis
2781  Int_t nZdivisions = fZaxis.GetNdivisions();
2782  Color_t zAxisColor = fZaxis.GetAxisColor();
2783  Color_t zLabelColor = fZaxis.GetLabelColor();
2784  Style_t zLabelFont = fZaxis.GetLabelFont();
2785  Float_t zLabelOffset = fZaxis.GetLabelOffset();
2786  Float_t zLabelSize = fZaxis.GetLabelSize();
2787  Float_t zTickLength = fZaxis.GetTickLength();
2788  Float_t zTitleOffset = fZaxis.GetTitleOffset();
2789  Float_t zTitleSize = fZaxis.GetTitleSize();
2790  Color_t zTitleColor = fZaxis.GetTitleColor();
2791  Style_t zTitleFont = fZaxis.GetTitleFont();
2792 
2793  // copy merged bin contents (ignore under/overflows)
2794  if (nxgroup != 1 || nygroup != 1 || nzgroup != 1) {
2795  if (fXaxis.GetXbins()->GetSize() > 0 || fYaxis.GetXbins()->GetSize() > 0 || fZaxis.GetXbins()->GetSize() > 0) {
2796  // variable bin sizes in x or y, don't treat both cases separately
2797  Double_t *xbins = new Double_t[newxbins+1];
2798  for (i = 0; i <= newxbins; ++i) xbins[i] = fXaxis.GetBinLowEdge(1+i*nxgroup);
2799  Double_t *ybins = new Double_t[newybins+1];
2800  for (i = 0; i <= newybins; ++i) ybins[i] = fYaxis.GetBinLowEdge(1+i*nygroup);
2801  Double_t *zbins = new Double_t[newzbins+1];
2802  for (i = 0; i <= newzbins; ++i) zbins[i] = fZaxis.GetBinLowEdge(1+i*nzgroup);
2803  hnew->SetBins(newxbins,xbins, newybins, ybins, newzbins, zbins);//changes also errors array (if any)
2804  delete [] xbins;
2805  delete [] ybins;
2806  delete [] zbins;
2807  } else {
2808  hnew->SetBins(newxbins, xmin, xmax, newybins, ymin, ymax, newzbins, zmin, zmax);//changes also errors array
2809  }
2810 
2811  Double_t binContent, binSumw2;
2812  Int_t oldxbin = 1;
2813  Int_t oldybin = 1;
2814  Int_t oldzbin = 1;
2815  Int_t bin;
2816  for (xbin = 1; xbin <= newxbins; xbin++) {
2817  oldybin=1;
2818  oldzbin=1;
2819  for (ybin = 1; ybin <= newybins; ybin++) {
2820  oldzbin=1;
2821  for (zbin = 1; zbin <= newzbins; zbin++) {
2822  binContent = 0;
2823  binSumw2 = 0;
2824  for (i = 0; i < nxgroup; i++) {
2825  if (oldxbin+i > nxbins) break;
2826  for (j =0; j < nygroup; j++) {
2827  if (oldybin+j > nybins) break;
2828  for (k =0; k < nzgroup; k++) {
2829  if (oldzbin+k > nzbins) break;
2830  //get global bin (same conventions as in TH1::GetBin(xbin,ybin)
2831  bin = oldxbin + i + (oldybin + j)*(nxbins + 2) + (oldzbin + k)*(nxbins + 2)*(nybins + 2);
2832  binContent += oldBins[bin];
2833  if (oldSumw2) binSumw2 += oldSumw2[bin];
2834  }
2835  }
2836  }
2837  Int_t ibin = hnew->GetBin(xbin,ybin,zbin); // new bin number
2838  hnew->SetBinContent(ibin, binContent);
2839  if (oldSumw2) hnew->fSumw2.fArray[ibin] = binSumw2;
2840  oldzbin += nzgroup;
2841  }
2842  oldybin += nygroup;
2843  }
2844  oldxbin += nxgroup;
2845  }
2846 
2847  // compute new underflow/overflows for the 8 vertices
2848  for (Int_t xover = 0; xover <= 1; xover++) {
2849  for (Int_t yover = 0; yover <= 1; yover++) {
2850  for (Int_t zover = 0; zover <= 1; zover++) {
2851  binContent = 0;
2852  binSumw2 = 0;
2853  // make loop in case of only underflow/overflow
2854  for (xbin = xover*oldxbin; xbin <= xover*(nxbins+1); xbin++) {
2855  for (ybin = yover*oldybin; ybin <= yover*(nybins+1); ybin++) {
2856  for (zbin = zover*oldzbin; zbin <= zover*(nzbins+1); zbin++) {
2857  bin = GetBin(xbin,ybin,zbin);
2858  binContent += oldBins[bin];
2859  if (oldSumw2) binSumw2 += oldSumw2[bin];
2860  }
2861  }
2862  }
2863  Int_t binNew = hnew->GetBin( xover *(newxbins+1),
2864  yover*(newybins+1), zover*(newzbins+1) );
2865  hnew->SetBinContent(binNew,binContent);
2866  if (oldSumw2) hnew->fSumw2.fArray[binNew] = binSumw2;
2867  }
2868  }
2869  }
2870 
2871  Double_t binContent0, binContent2, binContent3, binContent4;
2872  Double_t binError0, binError2, binError3, binError4;
2873  Int_t oldxbin2, oldybin2, oldzbin2;
2874  Int_t ufbin, ofbin, ofbin2, ofbin3, ofbin4;
2875 
2876  // recompute under/overflow contents in y for the new x and z bins
2877  oldxbin2 = 1;
2878  oldybin2 = 1;
2879  oldzbin2 = 1;
2880  for (xbin = 1; xbin<=newxbins; xbin++) {
2881  oldzbin2 = 1;
2882  for (zbin = 1; zbin<=newzbins; zbin++) {
2883  binContent0 = binContent2 = 0;
2884  binError0 = binError2 = 0;
2885  for (i=0; i<nxgroup; i++) {
2886  if (oldxbin2+i > nxbins) break;
2887  for (k=0; k<nzgroup; k++) {
2888  if (oldzbin2+k > nzbins) break;
2889  //old underflow bin (in y)
2890  ufbin = oldxbin2 + i + (nxbins+2)*(nybins+2)*(oldzbin2+k);
2891  binContent0 += oldBins[ufbin];
2892  if (oldSumw2) binError0 += oldSumw2[ufbin];
2893  for (ybin = oldybin; ybin <= nybins + 1; ybin++) {
2894  //old overflow bin (in y)
2895  ofbin = ufbin + ybin*(nxbins+2);
2896  binContent2 += oldBins[ofbin];
2897  if (oldSumw2) binError2 += oldSumw2[ofbin];
2898  }
2899  }
2900  }
2901  hnew->SetBinContent(xbin,0,zbin,binContent0);
2902  hnew->SetBinContent(xbin,newybins+1,zbin,binContent2);
2903  if (oldSumw2) {
2904  hnew->SetBinError(xbin,0,zbin,TMath::Sqrt(binError0));
2905  hnew->SetBinError(xbin,newybins+1,zbin,TMath::Sqrt(binError2) );
2906  }
2907  oldzbin2 += nzgroup;
2908  }
2909  oldxbin2 += nxgroup;
2910  }
2911 
2912  // recompute under/overflow contents in x for the new y and z bins
2913  oldxbin2 = 1;
2914  oldybin2 = 1;
2915  oldzbin2 = 1;
2916  for (ybin = 1; ybin<=newybins; ybin++) {
2917  oldzbin2 = 1;
2918  for (zbin = 1; zbin<=newzbins; zbin++) {
2919  binContent0 = binContent2 = 0;
2920  binError0 = binError2 = 0;
2921  for (j=0; j<nygroup; j++) {
2922  if (oldybin2+j > nybins) break;
2923  for (k=0; k<nzgroup; k++) {
2924  if (oldzbin2+k > nzbins) break;
2925  //old underflow bin (in y)
2926  ufbin = (oldybin2 + j)*(nxbins+2) + (nxbins+2)*(nybins+2)*(oldzbin2+k);
2927  binContent0 += oldBins[ufbin];
2928  if (oldSumw2) binError0 += oldSumw2[ufbin];
2929  for (xbin = oldxbin; xbin <= nxbins + 1; xbin++) {
2930  //old overflow bin (in x)
2931  ofbin = ufbin + xbin;
2932  binContent2 += oldBins[ofbin];
2933  if (oldSumw2) binError2 += oldSumw2[ofbin];
2934  }
2935  }
2936  }
2937  hnew->SetBinContent(0,ybin,zbin,binContent0);
2938  hnew->SetBinContent(newxbins+1,ybin,zbin,binContent2);
2939  if (oldSumw2) {
2940  hnew->SetBinError(0,ybin,zbin,TMath::Sqrt(binError0));
2941  hnew->SetBinError(newxbins+1,ybin,zbin,TMath::Sqrt(binError2) );
2942  }
2943  oldzbin2 += nzgroup;
2944  }
2945  oldybin2 += nygroup;
2946  }
2947 
2948  // recompute under/overflow contents in z for the new x and y bins
2949  oldxbin2 = 1;
2950  oldybin2 = 1;
2951  oldzbin2 = 1;
2952  for (xbin = 1; xbin<=newxbins; xbin++) {
2953  oldybin2 = 1;
2954  for (ybin = 1; ybin<=newybins; ybin++) {
2955  binContent0 = binContent2 = 0;
2956  binError0 = binError2 = 0;
2957  for (i=0; i<nxgroup; i++) {
2958  if (oldxbin2+i > nxbins) break;
2959  for (j=0; j<nygroup; j++) {
2960  if (oldybin2+j > nybins) break;
2961  //old underflow bin (in z)
2962  ufbin = oldxbin2 + i + (nxbins+2)*(oldybin2+j);
2963  binContent0 += oldBins[ufbin];
2964  if (oldSumw2) binError0 += oldSumw2[ufbin];
2965  for (zbin = oldzbin; zbin <= nzbins + 1; zbin++) {
2966  //old overflow bin (in z)
2967  ofbin = ufbin + (nxbins+2)*(nybins+2)*zbin;
2968  binContent2 += oldBins[ofbin];
2969  if (oldSumw2) binError2 += oldSumw2[ofbin];
2970  }
2971  }
2972  }
2973  hnew->SetBinContent(xbin,ybin,0,binContent0);
2974  hnew->SetBinContent(xbin,ybin,newzbins+1,binContent2);
2975  if (oldSumw2) {
2976  hnew->SetBinError(xbin,ybin,0,TMath::Sqrt(binError0));
2977  hnew->SetBinError(xbin,ybin,newzbins+1,TMath::Sqrt(binError2) );
2978  }
2979  oldybin2 += nygroup;
2980  }
2981  oldxbin2 += nxgroup;
2982  }
2983 
2984  // recompute under/overflow contents in y, z for the new x
2985  oldxbin2 = 1;
2986  oldybin2 = 1;
2987  oldzbin2 = 1;
2988  for (xbin = 1; xbin<=newxbins; xbin++) {
2989  binContent0 = 0;
2990  binContent2 = 0;
2991  binContent3 = 0;
2992  binContent4 = 0;
2993  binError0 = 0;
2994  binError2 = 0;
2995  binError3 = 0;
2996  binError4 = 0;
2997  for (i=0; i<nxgroup; i++) {
2998  if (oldxbin2+i > nxbins) break;
2999  ufbin = oldxbin2 + i; //
3000  binContent0 += oldBins[ufbin];
3001  if (oldSumw2) binError0 += oldSumw2[ufbin];
3002  for (ybin = oldybin; ybin <= nybins + 1; ybin++) {
3003  ofbin3 = ufbin+ybin*(nxbins+2);
3004  binContent3 += oldBins[ ofbin3 ];
3005  if (oldSumw2) binError3 += oldSumw2[ofbin3];
3006  for (zbin = oldzbin; zbin <= nzbins + 1; zbin++) {
3007  //old overflow bin (in z)
3008  ofbin4 = oldxbin2 + i + ybin*(nxbins+2) + (nxbins+2)*(nybins+2)*zbin;
3009  binContent4 += oldBins[ofbin4];
3010  if (oldSumw2) binError4 += oldSumw2[ofbin4];
3011  }
3012  }
3013  for (zbin = oldzbin; zbin <= nzbins + 1; zbin++) {
3014  ofbin2 = ufbin+zbin*(nxbins+2)*(nybins+2);
3015  binContent2 += oldBins[ ofbin2 ];
3016  if (oldSumw2) binError2 += oldSumw2[ofbin2];
3017  }
3018  }
3019  hnew->SetBinContent(xbin,0,0,binContent0);
3020  hnew->SetBinContent(xbin,0,newzbins+1,binContent2);
3021  hnew->SetBinContent(xbin,newybins+1,0,binContent3);
3022  hnew->SetBinContent(xbin,newybins+1,newzbins+1,binContent4);
3023  if (oldSumw2) {
3024  hnew->SetBinError(xbin,0,0,TMath::Sqrt(binError0));
3025  hnew->SetBinError(xbin,0,newzbins+1,TMath::Sqrt(binError2) );
3026  hnew->SetBinError(xbin,newybins+1,0,TMath::Sqrt(binError3) );
3027  hnew->SetBinError(xbin,newybins+1,newzbins+1,TMath::Sqrt(binError4) );
3028  }
3029  oldxbin2 += nxgroup;
3030  }
3031 
3032  // recompute under/overflow contents in x, y for the new z
3033  oldxbin2 = 1;
3034  oldybin2 = 1;
3035  oldzbin2 = 1;
3036  for (zbin = 1; zbin<=newzbins; zbin++) {
3037  binContent0 = 0;
3038  binContent2 = 0;
3039  binContent3 = 0;
3040  binContent4 = 0;
3041  binError0 = 0;
3042  binError2 = 0;
3043  binError3 = 0;
3044  binError4 = 0;
3045  for (i=0; i<nzgroup; i++) {
3046  if (oldzbin2+i > nzbins) break;
3047  ufbin = (oldzbin2 + i)*(nxbins+2)*(nybins+2); //
3048  binContent0 += oldBins[ufbin];
3049  if (oldSumw2) binError0 += oldSumw2[ufbin];
3050  for (ybin = oldybin; ybin <= nybins + 1; ybin++) {
3051  ofbin3 = ufbin+ybin*(nxbins+2);
3052  binContent3 += oldBins[ ofbin3 ];
3053  if (oldSumw2) binError3 += oldSumw2[ofbin3];
3054  for (xbin = oldxbin; xbin <= nxbins + 1; xbin++) {
3055  //old overflow bin (in z)
3056  ofbin4 = ufbin + xbin + ybin*(nxbins+2);
3057  binContent4 += oldBins[ofbin4];
3058  if (oldSumw2) binError4 += oldSumw2[ofbin4];
3059  }
3060  }
3061  for (xbin = oldxbin; xbin <= nxbins + 1; xbin++) {
3062  ofbin2 = xbin +(oldzbin2+i)*(nxbins+2)*(nybins+2);
3063  binContent2 += oldBins[ ofbin2 ];
3064  if (oldSumw2) binError2 += oldSumw2[ofbin2];
3065  }
3066  }
3067  hnew->SetBinContent(0,0,zbin,binContent0);
3068  hnew->SetBinContent(0,newybins+1,zbin,binContent3);
3069  hnew->SetBinContent(newxbins+1,0,zbin,binContent2);
3070  hnew->SetBinContent(newxbins+1,newybins+1,zbin,binContent4);
3071  if (oldSumw2) {
3072  hnew->SetBinError(0,0,zbin,TMath::Sqrt(binError0));
3073  hnew->SetBinError(0,newybins+1,zbin,TMath::Sqrt(binError3) );
3074  hnew->SetBinError(newxbins+1,0,zbin,TMath::Sqrt(binError2) );
3075  hnew->SetBinError(newxbins+1,newybins+1,zbin,TMath::Sqrt(binError4) );
3076  }
3077  oldzbin2 += nzgroup;
3078  }
3079 
3080  // recompute under/overflow contents in x, z for the new y
3081  oldxbin2 = 1;
3082  oldybin2 = 1;
3083  oldzbin2 = 1;
3084  for (ybin = 1; ybin<=newybins; ybin++) {
3085  binContent0 = 0;
3086  binContent2 = 0;
3087  binContent3 = 0;
3088  binContent4 = 0;
3089  binError0 = 0;
3090  binError2 = 0;
3091  binError3 = 0;
3092  binError4 = 0;
3093  for (i=0; i<nygroup; i++) {
3094  if (oldybin2+i > nybins) break;
3095  ufbin = (oldybin2 + i)*(nxbins+2); //
3096  binContent0 += oldBins[ufbin];
3097  if (oldSumw2) binError0 += oldSumw2[ufbin];
3098  for (xbin = oldxbin; xbin <= nxbins + 1; xbin++) {
3099  ofbin3 = ufbin+xbin;
3100  binContent3 += oldBins[ ofbin3 ];
3101  if (oldSumw2) binError3 += oldSumw2[ofbin3];
3102  for (zbin = oldzbin; zbin <= nzbins + 1; zbin++) {
3103  //old overflow bin (in z)
3104  ofbin4 = xbin + (nxbins+2)*(nybins+2)*zbin+(oldybin2+i)*(nxbins+2);
3105  binContent4 += oldBins[ofbin4];
3106  if (oldSumw2) binError4 += oldSumw2[ofbin4];
3107  }
3108  }
3109  for (zbin = oldzbin; zbin <= nzbins + 1; zbin++) {
3110  ofbin2 = (oldybin2+i)*(nxbins+2)+zbin*(nxbins+2)*(nybins+2);
3111  binContent2 += oldBins[ ofbin2 ];
3112  if (oldSumw2) binError2 += oldSumw2[ofbin2];
3113  }
3114  }
3115  hnew->SetBinContent(0,ybin,0,binContent0);
3116  hnew->SetBinContent(0,ybin,newzbins+1,binContent2);
3117  hnew->SetBinContent(newxbins+1,ybin,0,binContent3);
3118  hnew->SetBinContent(newxbins+1,ybin,newzbins+1,binContent4);
3119  if (oldSumw2) {
3120  hnew->SetBinError(0,ybin,0,TMath::Sqrt(binError0));
3121  hnew->SetBinError(0,ybin,newzbins+1,TMath::Sqrt(binError2) );
3122  hnew->SetBinError(newxbins+1,ybin,0,TMath::Sqrt(binError3) );
3123  hnew->SetBinError(newxbins+1,ybin,newzbins+1,TMath::Sqrt(binError4) );
3124  }
3125  oldybin2 += nygroup;
3126  }
3127  }
3128 
3129  // Restore x axis attributes
3130  fXaxis.SetNdivisions(nXdivisions);
3131  fXaxis.SetAxisColor(xAxisColor);
3132  fXaxis.SetLabelColor(xLabelColor);
3133  fXaxis.SetLabelFont(xLabelFont);
3134  fXaxis.SetLabelOffset(xLabelOffset);
3135  fXaxis.SetLabelSize(xLabelSize);
3136  fXaxis.SetTickLength(xTickLength);
3137  fXaxis.SetTitleOffset(xTitleOffset);
3138  fXaxis.SetTitleSize(xTitleSize);
3139  fXaxis.SetTitleColor(xTitleColor);
3140  fXaxis.SetTitleFont(xTitleFont);
3141  // Restore y axis attributes
3142  fYaxis.SetNdivisions(nYdivisions);
3143  fYaxis.SetAxisColor(yAxisColor);
3144  fYaxis.SetLabelColor(yLabelColor);
3145  fYaxis.SetLabelFont(yLabelFont);
3146  fYaxis.SetLabelOffset(yLabelOffset);
3147  fYaxis.SetLabelSize(yLabelSize);
3148  fYaxis.SetTickLength(yTickLength);
3149  fYaxis.SetTitleOffset(yTitleOffset);
3150  fYaxis.SetTitleSize(yTitleSize);
3151  fYaxis.SetTitleColor(yTitleColor);
3152  fYaxis.SetTitleFont(yTitleFont);
3153  // Restore z axis attributes
3154  fZaxis.SetNdivisions(nZdivisions);
3155  fZaxis.SetAxisColor(zAxisColor);
3156  fZaxis.SetLabelColor(zLabelColor);
3157  fZaxis.SetLabelFont(zLabelFont);
3158  fZaxis.SetLabelOffset(zLabelOffset);
3159  fZaxis.SetLabelSize(zLabelSize);
3160  fZaxis.SetTickLength(zTickLength);
3161  fZaxis.SetTitleOffset(zTitleOffset);
3162  fZaxis.SetTitleSize(zTitleSize);
3163  fZaxis.SetTitleColor(zTitleColor);
3164  fZaxis.SetTitleFont(zTitleFont);
3165 
3166  //restore statistics and entries modified by SetBinContent
3167  hnew->SetEntries(entries);
3168  if (!resetStat) hnew->PutStats(stat);
3169 
3170  delete [] oldBins;
3171  if (oldSumw2) delete [] oldSumw2;
3172  return hnew;
3173 }
3174 
3175 
3176 ////////////////////////////////////////////////////////////////////////////////
3177 /// Reset this histogram: contents, errors, etc.
3178 
3179 void TH3::Reset(Option_t *option)
3180 {
3181  TH1::Reset(option);
3182  TString opt = option;
3183  opt.ToUpper();
3184  if (opt.Contains("ICE") && !opt.Contains("S")) return;
3185  fTsumwy = 0;
3186  fTsumwy2 = 0;
3187  fTsumwxy = 0;
3188  fTsumwz = 0;
3189  fTsumwz2 = 0;
3190  fTsumwxz = 0;
3191  fTsumwyz = 0;
3192 }
3193 
3194 
3195 ////////////////////////////////////////////////////////////////////////////////
3196 /// Set bin content.
3197 
3198 void TH3::SetBinContent(Int_t bin, Double_t content)
3199 {
3200  fEntries++;
3201  fTsumw = 0;
3202  if (bin < 0) return;
3203  if (bin >= fNcells) return;
3204  UpdateBinContent(bin, content);
3205 }
3206 
3207 
3208 ////////////////////////////////////////////////////////////////////////////////
3209 /// Stream an object of class TH3.
3210 
3211 void TH3::Streamer(TBuffer &R__b)
3212 {
3213  if (R__b.IsReading()) {
3214  UInt_t R__s, R__c;
3215  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
3216  if (R__v > 2) {
3217  R__b.ReadClassBuffer(TH3::Class(), this, R__v, R__s, R__c);
3218  return;
3219  }
3220  //====process old versions before automatic schema evolution
3221  TH1::Streamer(R__b);
3222  TAtt3D::Streamer(R__b);
3223  R__b.CheckByteCount(R__s, R__c, TH3::IsA());
3224  //====end of old versions
3225 
3226  } else {
3227  R__b.WriteClassBuffer(TH3::Class(),this);
3228  }
3229 }
3230 
3231 
3232 //______________________________________________________________________________
3233 // TH3C methods
3234 // TH3C a 3-D histogram with one byte per cell (char)
3235 //______________________________________________________________________________
3236 
3237 ClassImp(TH3C);
3238 
3239 
3240 ////////////////////////////////////////////////////////////////////////////////
3241 /// Constructor.
3242 
3243 TH3C::TH3C(): TH3(), TArrayC()
3244 {
3245  SetBinsLength(27);
3246  if (fgDefaultSumw2) Sumw2();
3247 }
3248 
3249 
3250 ////////////////////////////////////////////////////////////////////////////////
3251 /// Destructor.
3252 
3253 TH3C::~TH3C()
3254 {
3255 }
3256 
3257 
3258 ////////////////////////////////////////////////////////////////////////////////
3259 /// Normal constructor for fix bin size 3-D histograms.
3260 
3261 TH3C::TH3C(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
3262  ,Int_t nbinsy,Double_t ylow,Double_t yup
3263  ,Int_t nbinsz,Double_t zlow,Double_t zup)
3264  :TH3(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,zlow,zup)
3265 {
3266  TArrayC::Set(fNcells);
3267  if (fgDefaultSumw2) Sumw2();
3268 
3269  if (xlow >= xup || ylow >= yup || zlow >= zup) SetBuffer(fgBufferSize);
3270 }
3271 
3272 
3273 ////////////////////////////////////////////////////////////////////////////////
3274 /// Normal constructor for variable bin size 3-D histograms.
3275 
3276 TH3C::TH3C(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
3277  ,Int_t nbinsy,const Float_t *ybins
3278  ,Int_t nbinsz,const Float_t *zbins)
3279  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3280 {
3281  TArrayC::Set(fNcells);
3282  if (fgDefaultSumw2) Sumw2();
3283 }
3284 
3285 
3286 ////////////////////////////////////////////////////////////////////////////////
3287 /// Normal constructor for variable bin size 3-D histograms.
3288 
3289 TH3C::TH3C(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
3290  ,Int_t nbinsy,const Double_t *ybins
3291  ,Int_t nbinsz,const Double_t *zbins)
3292  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3293 {
3294  TArrayC::Set(fNcells);
3295  if (fgDefaultSumw2) Sumw2();
3296 }
3297 
3298 
3299 ////////////////////////////////////////////////////////////////////////////////
3300 /// Copy constructor.
3301 
3302 TH3C::TH3C(const TH3C &h3c) : TH3(), TArrayC()
3303 {
3304  ((TH3C&)h3c).Copy(*this);
3305 }
3306 
3307 
3308 ////////////////////////////////////////////////////////////////////////////////
3309 /// Increment bin content by 1.
3310 
3311 void TH3C::AddBinContent(Int_t bin)
3312 {
3313  if (fArray[bin] < 127) fArray[bin]++;
3314 }
3315 
3316 
3317 ////////////////////////////////////////////////////////////////////////////////
3318 /// Increment bin content by w.
3319 
3320 void TH3C::AddBinContent(Int_t bin, Double_t w)
3321 {
3322  Int_t newval = fArray[bin] + Int_t(w);
3323  if (newval > -128 && newval < 128) {fArray[bin] = Char_t(newval); return;}
3324  if (newval < -127) fArray[bin] = -127;
3325  if (newval > 127) fArray[bin] = 127;
3326 }
3327 
3328 
3329 ////////////////////////////////////////////////////////////////////////////////
3330 /// Copy this 3-D histogram structure to newth3.
3331 
3332 void TH3C::Copy(TObject &newth3) const
3333 {
3334  TH3::Copy((TH3C&)newth3);
3335 }
3336 
3337 
3338 ////////////////////////////////////////////////////////////////////////////////
3339 /// Reset this histogram: contents, errors, etc.
3340 
3341 void TH3C::Reset(Option_t *option)
3342 {
3343  TH3::Reset(option);
3344  TArrayC::Reset();
3345  // should also reset statistics once statistics are implemented for TH3
3346 }
3347 
3348 
3349 ////////////////////////////////////////////////////////////////////////////////
3350 /// Set total number of bins including under/overflow
3351 /// Reallocate bin contents array
3352 
3353 void TH3C::SetBinsLength(Int_t n)
3354 {
3355  if (n < 0) n = (fXaxis.GetNbins()+2)*(fYaxis.GetNbins()+2)*(fZaxis.GetNbins()+2);
3356  fNcells = n;
3357  TArrayC::Set(n);
3358 }
3359 
3360 
3361 ////////////////////////////////////////////////////////////////////////////////
3362 /// When the mouse is moved in a pad containing a 3-d view of this histogram
3363 /// a second canvas shows a projection type given as option.
3364 /// To stop the generation of the projections, delete the canvas
3365 /// containing the projection.
3366 /// option may contain a combination of the characters x,y,z,e
3367 /// option = "x" return the x projection into a TH1D histogram
3368 /// option = "y" return the y projection into a TH1D histogram
3369 /// option = "z" return the z projection into a TH1D histogram
3370 /// option = "xy" return the x versus y projection into a TH2D histogram
3371 /// option = "yx" return the y versus x projection into a TH2D histogram
3372 /// option = "xz" return the x versus z projection into a TH2D histogram
3373 /// option = "zx" return the z versus x projection into a TH2D histogram
3374 /// option = "yz" return the y versus z projection into a TH2D histogram
3375 /// option = "zy" return the z versus y projection into a TH2D histogram
3376 /// option can also include the drawing option for the projection, eg to draw
3377 /// the xy projection using the draw option "box" do
3378 /// myhist.SetShowProjection("xy box");
3379 /// This function is typically called from the context menu.
3380 /// NB: the notation "a vs b" means "a" vertical and "b" horizontal
3381 
3382 void TH3::SetShowProjection(const char *option,Int_t nbins)
3383 {
3384  GetPainter();
3385 
3386  if (fPainter) fPainter->SetShowProjection(option,nbins);
3387 }
3388 
3389 
3390 ////////////////////////////////////////////////////////////////////////////////
3391 /// Stream an object of class TH3C.
3392 
3393 void TH3C::Streamer(TBuffer &R__b)
3394 {
3395  if (R__b.IsReading()) {
3396  UInt_t R__s, R__c;
3397  if (R__b.GetParent() && R__b.GetVersionOwner() < 22300) return;
3398  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
3399  if (R__v > 2) {
3400  R__b.ReadClassBuffer(TH3C::Class(), this, R__v, R__s, R__c);
3401  return;
3402  }
3403  //====process old versions before automatic schema evolution
3404  if (R__v < 2) {
3405  R__b.ReadVersion();
3406  TH1::Streamer(R__b);
3407  TArrayC::Streamer(R__b);
3408  R__b.ReadVersion(&R__s, &R__c);
3409  TAtt3D::Streamer(R__b);
3410  } else {
3411  TH3::Streamer(R__b);
3412  TArrayC::Streamer(R__b);
3413  R__b.CheckByteCount(R__s, R__c, TH3C::IsA());
3414  }
3415  //====end of old versions
3416 
3417  } else {
3418  R__b.WriteClassBuffer(TH3C::Class(),this);
3419  }
3420 }
3421 
3422 
3423 ////////////////////////////////////////////////////////////////////////////////
3424 /// Operator =
3425 
3426 TH3C& TH3C::operator=(const TH3C &h1)
3427 {
3428  if (this != &h1) ((TH3C&)h1).Copy(*this);
3429  return *this;
3430 }
3431 
3432 
3433 ////////////////////////////////////////////////////////////////////////////////
3434 /// Operator *
3435 
3436 TH3C operator*(Float_t c1, TH3C &h1)
3437 {
3438  TH3C hnew = h1;
3439  hnew.Scale(c1);
3440  hnew.SetDirectory(0);
3441  return hnew;
3442 }
3443 
3444 
3445 ////////////////////////////////////////////////////////////////////////////////
3446 /// Operator +
3447 
3448 TH3C operator+(TH3C &h1, TH3C &h2)
3449 {
3450  TH3C hnew = h1;
3451  hnew.Add(&h2,1);
3452  hnew.SetDirectory(0);
3453  return hnew;
3454 }
3455 
3456 
3457 ////////////////////////////////////////////////////////////////////////////////
3458 /// Operator -
3459 
3460 TH3C operator-(TH3C &h1, TH3C &h2)
3461 {
3462  TH3C hnew = h1;
3463  hnew.Add(&h2,-1);
3464  hnew.SetDirectory(0);
3465  return hnew;
3466 }
3467 
3468 
3469 ////////////////////////////////////////////////////////////////////////////////
3470 /// Operator *
3471 
3472 TH3C operator*(TH3C &h1, TH3C &h2)
3473 {
3474  TH3C hnew = h1;
3475  hnew.Multiply(&h2);
3476  hnew.SetDirectory(0);
3477  return hnew;
3478 }
3479 
3480 
3481 ////////////////////////////////////////////////////////////////////////////////
3482 /// Operator /
3483 
3484 TH3C operator/(TH3C &h1, TH3C &h2)
3485 {
3486  TH3C hnew = h1;
3487  hnew.Divide(&h2);
3488  hnew.SetDirectory(0);
3489  return hnew;
3490 }
3491 
3492 
3493 //______________________________________________________________________________
3494 // TH3S methods
3495 // TH3S a 3-D histogram with two bytes per cell (short integer)
3496 //______________________________________________________________________________
3497 
3498 ClassImp(TH3S);
3499 
3500 
3501 ////////////////////////////////////////////////////////////////////////////////
3502 /// Constructor.
3503 
3504 TH3S::TH3S(): TH3(), TArrayS()
3505 {
3506  SetBinsLength(27);
3507  if (fgDefaultSumw2) Sumw2();
3508 }
3509 
3510 
3511 ////////////////////////////////////////////////////////////////////////////////
3512 /// Destructor.
3513 
3514 TH3S::~TH3S()
3515 {
3516 }
3517 
3518 
3519 ////////////////////////////////////////////////////////////////////////////////
3520 /// Normal constructor for fix bin size 3-D histograms.
3521 
3522 TH3S::TH3S(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
3523  ,Int_t nbinsy,Double_t ylow,Double_t yup
3524  ,Int_t nbinsz,Double_t zlow,Double_t zup)
3525  :TH3(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,zlow,zup)
3526 {
3527  TH3S::Set(fNcells);
3528  if (fgDefaultSumw2) Sumw2();
3529 
3530  if (xlow >= xup || ylow >= yup || zlow >= zup) SetBuffer(fgBufferSize);
3531 }
3532 
3533 
3534 ////////////////////////////////////////////////////////////////////////////////
3535 /// Normal constructor for variable bin size 3-D histograms.
3536 
3537 TH3S::TH3S(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
3538  ,Int_t nbinsy,const Float_t *ybins
3539  ,Int_t nbinsz,const Float_t *zbins)
3540  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3541 {
3542  TH3S::Set(fNcells);
3543  if (fgDefaultSumw2) Sumw2();
3544 }
3545 
3546 
3547 ////////////////////////////////////////////////////////////////////////////////
3548 /// Normal constructor for variable bin size 3-D histograms.
3549 
3550 TH3S::TH3S(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
3551  ,Int_t nbinsy,const Double_t *ybins
3552  ,Int_t nbinsz,const Double_t *zbins)
3553  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3554 {
3555  TH3S::Set(fNcells);
3556  if (fgDefaultSumw2) Sumw2();
3557 }
3558 
3559 
3560 ////////////////////////////////////////////////////////////////////////////////
3561 /// Copy Constructor.
3562 
3563 TH3S::TH3S(const TH3S &h3s) : TH3(), TArrayS()
3564 {
3565  ((TH3S&)h3s).Copy(*this);
3566 }
3567 
3568 
3569 ////////////////////////////////////////////////////////////////////////////////
3570 /// Increment bin content by 1.
3571 
3572 void TH3S::AddBinContent(Int_t bin)
3573 {
3574  if (fArray[bin] < 32767) fArray[bin]++;
3575 }
3576 
3577 
3578 ////////////////////////////////////////////////////////////////////////////////
3579 /// Increment bin content by w.
3580 
3581 void TH3S::AddBinContent(Int_t bin, Double_t w)
3582 {
3583  Int_t newval = fArray[bin] + Int_t(w);
3584  if (newval > -32768 && newval < 32768) {fArray[bin] = Short_t(newval); return;}
3585  if (newval < -32767) fArray[bin] = -32767;
3586  if (newval > 32767) fArray[bin] = 32767;
3587 }
3588 
3589 
3590 ////////////////////////////////////////////////////////////////////////////////
3591 /// Copy this 3-D histogram structure to newth3.
3592 
3593 void TH3S::Copy(TObject &newth3) const
3594 {
3595  TH3::Copy((TH3S&)newth3);
3596 }
3597 
3598 
3599 ////////////////////////////////////////////////////////////////////////////////
3600 /// Reset this histogram: contents, errors, etc.
3601 
3602 void TH3S::Reset(Option_t *option)
3603 {
3604  TH3::Reset(option);
3605  TArrayS::Reset();
3606  // should also reset statistics once statistics are implemented for TH3
3607 }
3608 
3609 
3610 ////////////////////////////////////////////////////////////////////////////////
3611 /// Set total number of bins including under/overflow
3612 /// Reallocate bin contents array
3613 
3614 void TH3S::SetBinsLength(Int_t n)
3615 {
3616  if (n < 0) n = (fXaxis.GetNbins()+2)*(fYaxis.GetNbins()+2)*(fZaxis.GetNbins()+2);
3617  fNcells = n;
3618  TArrayS::Set(n);
3619 }
3620 
3621 
3622 ////////////////////////////////////////////////////////////////////////////////
3623 /// Stream an object of class TH3S.
3624 
3625 void TH3S::Streamer(TBuffer &R__b)
3626 {
3627  if (R__b.IsReading()) {
3628  UInt_t R__s, R__c;
3629  if (R__b.GetParent() && R__b.GetVersionOwner() < 22300) return;
3630  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
3631  if (R__v > 2) {
3632  R__b.ReadClassBuffer(TH3S::Class(), this, R__v, R__s, R__c);
3633  return;
3634  }
3635  //====process old versions before automatic schema evolution
3636  if (R__v < 2) {
3637  R__b.ReadVersion();
3638  TH1::Streamer(R__b);
3639  TArrayS::Streamer(R__b);
3640  R__b.ReadVersion(&R__s, &R__c);
3641  TAtt3D::Streamer(R__b);
3642  } else {
3643  TH3::Streamer(R__b);
3644  TArrayS::Streamer(R__b);
3645  R__b.CheckByteCount(R__s, R__c, TH3S::IsA());
3646  }
3647  //====end of old versions
3648 
3649  } else {
3650  R__b.WriteClassBuffer(TH3S::Class(),this);
3651  }
3652 }
3653 
3654 
3655 ////////////////////////////////////////////////////////////////////////////////
3656 /// Operator =
3657 
3658 TH3S& TH3S::operator=(const TH3S &h1)
3659 {
3660  if (this != &h1) ((TH3S&)h1).Copy(*this);
3661  return *this;
3662 }
3663 
3664 
3665 ////////////////////////////////////////////////////////////////////////////////
3666 /// Operator *
3667 
3668 TH3S operator*(Float_t c1, TH3S &h1)
3669 {
3670  TH3S hnew = h1;
3671  hnew.Scale(c1);
3672  hnew.SetDirectory(0);
3673  return hnew;
3674 }
3675 
3676 
3677 ////////////////////////////////////////////////////////////////////////////////
3678 /// Operator +
3679 
3680 TH3S operator+(TH3S &h1, TH3S &h2)
3681 {
3682  TH3S hnew = h1;
3683  hnew.Add(&h2,1);
3684  hnew.SetDirectory(0);
3685  return hnew;
3686 }
3687 
3688 
3689 ////////////////////////////////////////////////////////////////////////////////
3690 /// Operator -
3691 
3692 TH3S operator-(TH3S &h1, TH3S &h2)
3693 {
3694  TH3S hnew = h1;
3695  hnew.Add(&h2,-1);
3696  hnew.SetDirectory(0);
3697  return hnew;
3698 }
3699 
3700 
3701 ////////////////////////////////////////////////////////////////////////////////
3702 /// Operator *
3703 
3704 TH3S operator*(TH3S &h1, TH3S &h2)
3705 {
3706  TH3S hnew = h1;
3707  hnew.Multiply(&h2);
3708  hnew.SetDirectory(0);
3709  return hnew;
3710 }
3711 
3712 
3713 ////////////////////////////////////////////////////////////////////////////////
3714 /// Operator /
3715 
3716 TH3S operator/(TH3S &h1, TH3S &h2)
3717 {
3718  TH3S hnew = h1;
3719  hnew.Divide(&h2);
3720  hnew.SetDirectory(0);
3721  return hnew;
3722 }
3723 
3724 
3725 //______________________________________________________________________________
3726 // TH3I methods
3727 // TH3I a 3-D histogram with four bytes per cell (32 bits integer)
3728 //______________________________________________________________________________
3729 
3730 ClassImp(TH3I);
3731 
3732 
3733 ////////////////////////////////////////////////////////////////////////////////
3734 /// Constructor.
3735 
3736 TH3I::TH3I(): TH3(), TArrayI()
3737 {
3738  SetBinsLength(27);
3739  if (fgDefaultSumw2) Sumw2();
3740 }
3741 
3742 
3743 ////////////////////////////////////////////////////////////////////////////////
3744 /// Destructor.
3745 
3746 TH3I::~TH3I()
3747 {
3748 }
3749 
3750 
3751 ////////////////////////////////////////////////////////////////////////////////
3752 /// Normal constructor for fix bin size 3-D histograms.
3753 
3754 TH3I::TH3I(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
3755  ,Int_t nbinsy,Double_t ylow,Double_t yup
3756  ,Int_t nbinsz,Double_t zlow,Double_t zup)
3757  :TH3(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,zlow,zup)
3758 {
3759  TH3I::Set(fNcells);
3760  if (fgDefaultSumw2) Sumw2();
3761 
3762  if (xlow >= xup || ylow >= yup || zlow >= zup) SetBuffer(fgBufferSize);
3763 }
3764 
3765 
3766 ////////////////////////////////////////////////////////////////////////////////
3767 /// Normal constructor for variable bin size 3-D histograms.
3768 
3769 TH3I::TH3I(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
3770  ,Int_t nbinsy,const Float_t *ybins
3771  ,Int_t nbinsz,const Float_t *zbins)
3772  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3773 {
3774  TArrayI::Set(fNcells);
3775  if (fgDefaultSumw2) Sumw2();
3776 }
3777 
3778 
3779 ////////////////////////////////////////////////////////////////////////////////
3780 /// Normal constructor for variable bin size 3-D histograms.
3781 
3782 TH3I::TH3I(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
3783  ,Int_t nbinsy,const Double_t *ybins
3784  ,Int_t nbinsz,const Double_t *zbins)
3785  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3786 {
3787  TArrayI::Set(fNcells);
3788  if (fgDefaultSumw2) Sumw2();
3789 }
3790 
3791 
3792 ////////////////////////////////////////////////////////////////////////////////
3793 /// Copy constructor.
3794 
3795 TH3I::TH3I(const TH3I &h3i) : TH3(), TArrayI()
3796 {
3797  ((TH3I&)h3i).Copy(*this);
3798 }
3799 
3800 
3801 ////////////////////////////////////////////////////////////////////////////////
3802 /// Increment bin content by 1.
3803 
3804 void TH3I::AddBinContent(Int_t bin)
3805 {
3806  if (fArray[bin] < 2147483647) fArray[bin]++;
3807 }
3808 
3809 
3810 ////////////////////////////////////////////////////////////////////////////////
3811 /// Increment bin content by w.
3812 
3813 void TH3I::AddBinContent(Int_t bin, Double_t w)
3814 {
3815  Long64_t newval = fArray[bin] + Long64_t(w);
3816  if (newval > -2147483647 && newval < 2147483647) {fArray[bin] = Int_t(newval); return;}
3817  if (newval < -2147483647) fArray[bin] = -2147483647;
3818  if (newval > 2147483647) fArray[bin] = 2147483647;
3819 }
3820 
3821 
3822 ////////////////////////////////////////////////////////////////////////////////
3823 /// Copy this 3-D histogram structure to newth3.
3824 
3825 void TH3I::Copy(TObject &newth3) const
3826 {
3827  TH3::Copy((TH3I&)newth3);
3828 }
3829 
3830 
3831 ////////////////////////////////////////////////////////////////////////////////
3832 /// Reset this histogram: contents, errors, etc.
3833 
3834 void TH3I::Reset(Option_t *option)
3835 {
3836  TH3::Reset(option);
3837  TArrayI::Reset();
3838  // should also reset statistics once statistics are implemented for TH3
3839 }
3840 
3841 
3842 ////////////////////////////////////////////////////////////////////////////////
3843 /// Set total number of bins including under/overflow
3844 /// Reallocate bin contents array
3845 
3846 void TH3I::SetBinsLength(Int_t n)
3847 {
3848  if (n < 0) n = (fXaxis.GetNbins()+2)*(fYaxis.GetNbins()+2)*(fZaxis.GetNbins()+2);
3849  fNcells = n;
3850  TArrayI::Set(n);
3851 }
3852 
3853 
3854 ////////////////////////////////////////////////////////////////////////////////
3855 /// Operator =
3856 
3857 TH3I& TH3I::operator=(const TH3I &h1)
3858 {
3859  if (this != &h1) ((TH3I&)h1).Copy(*this);
3860  return *this;
3861 }
3862 
3863 
3864 ////////////////////////////////////////////////////////////////////////////////
3865 /// Operator *
3866 
3867 TH3I operator*(Float_t c1, TH3I &h1)
3868 {
3869  TH3I hnew = h1;
3870  hnew.Scale(c1);
3871  hnew.SetDirectory(0);
3872  return hnew;
3873 }
3874 
3875 
3876 ////////////////////////////////////////////////////////////////////////////////
3877 /// Operator +
3878 
3879 TH3I operator+(TH3I &h1, TH3I &h2)
3880 {
3881  TH3I hnew = h1;
3882  hnew.Add(&h2,1);
3883  hnew.SetDirectory(0);
3884  return hnew;
3885 }
3886 
3887 
3888 ////////////////////////////////////////////////////////////////////////////////
3889 /// Operator _
3890 
3891 TH3I operator-(TH3I &h1, TH3I &h2)
3892 {
3893  TH3I hnew = h1;
3894  hnew.Add(&h2,-1);
3895  hnew.SetDirectory(0);
3896  return hnew;
3897 }
3898 
3899 
3900 ////////////////////////////////////////////////////////////////////////////////
3901 /// Operator *
3902 
3903 TH3I operator*(TH3I &h1, TH3I &h2)
3904 {
3905  TH3I hnew = h1;
3906  hnew.Multiply(&h2);
3907  hnew.SetDirectory(0);
3908  return hnew;
3909 }
3910 
3911 
3912 ////////////////////////////////////////////////////////////////////////////////
3913 /// Operator /
3914 
3915 TH3I operator/(TH3I &h1, TH3I &h2)
3916 {
3917  TH3I hnew = h1;
3918  hnew.Divide(&h2);
3919  hnew.SetDirectory(0);
3920  return hnew;
3921 }
3922 
3923 
3924 //______________________________________________________________________________
3925 // TH3F methods
3926 // TH3F a 3-D histogram with four bytes per cell (float)
3927 //______________________________________________________________________________
3928 
3929 ClassImp(TH3F);
3930 
3931 
3932 ////////////////////////////////////////////////////////////////////////////////
3933 /// Constructor.
3934 
3935 TH3F::TH3F(): TH3(), TArrayF()
3936 {
3937  SetBinsLength(27);
3938  if (fgDefaultSumw2) Sumw2();
3939 }
3940 
3941 
3942 ////////////////////////////////////////////////////////////////////////////////
3943 /// Destructor.
3944 
3945 TH3F::~TH3F()
3946 {
3947 }
3948 
3949 
3950 ////////////////////////////////////////////////////////////////////////////////
3951 /// Normal constructor for fix bin size 3-D histograms.
3952 
3953 TH3F::TH3F(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
3954  ,Int_t nbinsy,Double_t ylow,Double_t yup
3955  ,Int_t nbinsz,Double_t zlow,Double_t zup)
3956  :TH3(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,zlow,zup)
3957 {
3958  TArrayF::Set(fNcells);
3959  if (fgDefaultSumw2) Sumw2();
3960 
3961  if (xlow >= xup || ylow >= yup || zlow >= zup) SetBuffer(fgBufferSize);
3962 }
3963 
3964 
3965 ////////////////////////////////////////////////////////////////////////////////
3966 /// Normal constructor for variable bin size 3-D histograms.
3967 
3968 TH3F::TH3F(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
3969  ,Int_t nbinsy,const Float_t *ybins
3970  ,Int_t nbinsz,const Float_t *zbins)
3971  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3972 {
3973  TArrayF::Set(fNcells);
3974  if (fgDefaultSumw2) Sumw2();
3975 }
3976 
3977 
3978 ////////////////////////////////////////////////////////////////////////////////
3979 /// Normal constructor for variable bin size 3-D histograms.
3980 
3981 TH3F::TH3F(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
3982  ,Int_t nbinsy,const Double_t *ybins
3983  ,Int_t nbinsz,const Double_t *zbins)
3984  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
3985 {
3986  TArrayF::Set(fNcells);
3987  if (fgDefaultSumw2) Sumw2();
3988 }
3989 
3990 
3991 ////////////////////////////////////////////////////////////////////////////////
3992 /// Copy constructor.
3993 
3994 TH3F::TH3F(const TH3F &h3f) : TH3(), TArrayF()
3995 {
3996  ((TH3F&)h3f).Copy(*this);
3997 }
3998 
3999 
4000 ////////////////////////////////////////////////////////////////////////////////
4001 /// Copy this 3-D histogram structure to newth3.
4002 
4003 void TH3F::Copy(TObject &newth3) const
4004 {
4005  TH3::Copy((TH3F&)newth3);
4006 }
4007 
4008 
4009 ////////////////////////////////////////////////////////////////////////////////
4010 /// Reset this histogram: contents, errors, etc.
4011 
4012 void TH3F::Reset(Option_t *option)
4013 {
4014  TH3::Reset(option);
4015  TArrayF::Reset();
4016  // should also reset statistics once statistics are implemented for TH3
4017 }
4018 
4019 
4020 ////////////////////////////////////////////////////////////////////////////////
4021 /// Set total number of bins including under/overflow
4022 /// Reallocate bin contents array
4023 
4024 void TH3F::SetBinsLength(Int_t n)
4025 {
4026  if (n < 0) n = (fXaxis.GetNbins()+2)*(fYaxis.GetNbins()+2)*(fZaxis.GetNbins()+2);
4027  fNcells = n;
4028  TArrayF::Set(n);
4029 }
4030 
4031 
4032 ////////////////////////////////////////////////////////////////////////////////
4033 /// Stream an object of class TH3F.
4034 
4035 void TH3F::Streamer(TBuffer &R__b)
4036 {
4037  if (R__b.IsReading()) {
4038  UInt_t R__s, R__c;
4039  if (R__b.GetParent() && R__b.GetVersionOwner() < 22300) return;
4040  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
4041  if (R__v > 2) {
4042  R__b.ReadClassBuffer(TH3F::Class(), this, R__v, R__s, R__c);
4043  return;
4044  }
4045  //====process old versions before automatic schema evolution
4046  if (R__v < 2) {
4047  R__b.ReadVersion();
4048  TH1::Streamer(R__b);
4049  TArrayF::Streamer(R__b);
4050  R__b.ReadVersion(&R__s, &R__c);
4051  TAtt3D::Streamer(R__b);
4052  } else {
4053  TH3::Streamer(R__b);
4054  TArrayF::Streamer(R__b);
4055  R__b.CheckByteCount(R__s, R__c, TH3F::IsA());
4056  }
4057  //====end of old versions
4058 
4059  } else {
4060  R__b.WriteClassBuffer(TH3F::Class(),this);
4061  }
4062 }
4063 
4064 
4065 ////////////////////////////////////////////////////////////////////////////////
4066 /// Operator =
4067 
4068 TH3F& TH3F::operator=(const TH3F &h1)
4069 {
4070  if (this != &h1) ((TH3F&)h1).Copy(*this);
4071  return *this;
4072 }
4073 
4074 
4075 ////////////////////////////////////////////////////////////////////////////////
4076 /// Operator *
4077 
4078 TH3F operator*(Float_t c1, TH3F &h1)
4079 {
4080  TH3F hnew = h1;
4081  hnew.Scale(c1);
4082  hnew.SetDirectory(0);
4083  return hnew;
4084 }
4085 
4086 
4087 ////////////////////////////////////////////////////////////////////////////////
4088 /// Operator +
4089 
4090 TH3F operator+(TH3F &h1, TH3F &h2)
4091 {
4092  TH3F hnew = h1;
4093  hnew.Add(&h2,1);
4094  hnew.SetDirectory(0);
4095  return hnew;
4096 }
4097 
4098 
4099 ////////////////////////////////////////////////////////////////////////////////
4100 /// Operator -
4101 
4102 TH3F operator-(TH3F &h1, TH3F &h2)
4103 {
4104  TH3F hnew = h1;
4105  hnew.Add(&h2,-1);
4106  hnew.SetDirectory(0);
4107  return hnew;
4108 }
4109 
4110 
4111 ////////////////////////////////////////////////////////////////////////////////
4112 /// Operator *
4113 
4114 TH3F operator*(TH3F &h1, TH3F &h2)
4115 {
4116  TH3F hnew = h1;
4117  hnew.Multiply(&h2);
4118  hnew.SetDirectory(0);
4119  return hnew;
4120 }
4121 
4122 
4123 ////////////////////////////////////////////////////////////////////////////////
4124 /// Operator /
4125 
4126 TH3F operator/(TH3F &h1, TH3F &h2)
4127 {
4128  TH3F hnew = h1;
4129  hnew.Divide(&h2);
4130  hnew.SetDirectory(0);
4131  return hnew;
4132 }
4133 
4134 
4135 //______________________________________________________________________________
4136 // TH3D methods
4137 // TH3D a 3-D histogram with eight bytes per cell (double)
4138 //______________________________________________________________________________
4139 
4140 ClassImp(TH3D);
4141 
4142 
4143 ////////////////////////////////////////////////////////////////////////////////
4144 /// Constructor.
4145 
4146 TH3D::TH3D(): TH3(), TArrayD()
4147 {
4148  SetBinsLength(27);
4149  if (fgDefaultSumw2) Sumw2();
4150 }
4151 
4152 
4153 ////////////////////////////////////////////////////////////////////////////////
4154 /// Destructor.
4155 
4156 TH3D::~TH3D()
4157 {
4158 }
4159 
4160 
4161 ////////////////////////////////////////////////////////////////////////////////
4162 /// Normal constructor for fix bin size 3-D histograms.
4163 
4164 TH3D::TH3D(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup
4165  ,Int_t nbinsy,Double_t ylow,Double_t yup
4166  ,Int_t nbinsz,Double_t zlow,Double_t zup)
4167  :TH3(name,title,nbinsx,xlow,xup,nbinsy,ylow,yup,nbinsz,zlow,zup)
4168 {
4169  TArrayD::Set(fNcells);
4170  if (fgDefaultSumw2) Sumw2();
4171 
4172  if (xlow >= xup || ylow >= yup || zlow >= zup) SetBuffer(fgBufferSize);
4173 }
4174 
4175 
4176 ////////////////////////////////////////////////////////////////////////////////
4177 /// Normal constructor for variable bin size 3-D histograms.
4178 
4179 TH3D::TH3D(const char *name,const char *title,Int_t nbinsx,const Float_t *xbins
4180  ,Int_t nbinsy,const Float_t *ybins
4181  ,Int_t nbinsz,const Float_t *zbins)
4182  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
4183 {
4184  TArrayD::Set(fNcells);
4185  if (fgDefaultSumw2) Sumw2();
4186 }
4187 
4188 
4189 ////////////////////////////////////////////////////////////////////////////////
4190 /// Normal constructor for variable bin size 3-D histograms.
4191 
4192 TH3D::TH3D(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins
4193  ,Int_t nbinsy,const Double_t *ybins
4194  ,Int_t nbinsz,const Double_t *zbins)
4195  :TH3(name,title,nbinsx,xbins,nbinsy,ybins,nbinsz,zbins)
4196 {
4197  TArrayD::Set(fNcells);
4198  if (fgDefaultSumw2) Sumw2();
4199 }
4200 
4201 
4202 ////////////////////////////////////////////////////////////////////////////////
4203 /// Copy constructor.
4204 
4205 TH3D::TH3D(const TH3D &h3d) : TH3(), TArrayD()
4206 {
4207  ((TH3D&)h3d).Copy(*this);
4208 }
4209 
4210 
4211 ////////////////////////////////////////////////////////////////////////////////
4212 /// Copy this 3-D histogram structure to newth3.
4213 
4214 void TH3D::Copy(TObject &newth3) const
4215 {
4216  TH3::Copy((TH3D&)newth3);
4217 }
4218 
4219 
4220 ////////////////////////////////////////////////////////////////////////////////
4221 /// Reset this histogram: contents, errors, etc.
4222 
4223 void TH3D::Reset(Option_t *option)
4224 {
4225  TH3::Reset(option);
4226  TArrayD::Reset();
4227  // should also reset statistics once statistics are implemented for TH3
4228 }
4229 
4230 
4231 ////////////////////////////////////////////////////////////////////////////////
4232 /// Set total number of bins including under/overflow
4233 /// Reallocate bin contents array
4234 
4235 void TH3D::SetBinsLength(Int_t n)
4236 {
4237  if (n < 0) n = (fXaxis.GetNbins()+2)*(fYaxis.GetNbins()+2)*(fZaxis.GetNbins()+2);
4238  fNcells = n;
4239  TArrayD::Set(n);
4240 }
4241 
4242 
4243 ////////////////////////////////////////////////////////////////////////////////
4244 /// Stream an object of class TH3D.
4245 
4246 void TH3D::Streamer(TBuffer &R__b)
4247 {
4248  if (R__b.IsReading()) {
4249  UInt_t R__s, R__c;
4250  if (R__b.GetParent() && R__b.GetVersionOwner() < 22300) return;
4251  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
4252  if (R__v > 2) {
4253  R__b.ReadClassBuffer(TH3D::Class(), this, R__v, R__s, R__c);
4254  return;
4255  }
4256  //====process old versions before automatic schema evolution
4257  if (R__v < 2) {
4258  R__b.ReadVersion();
4259  TH1::Streamer(R__b);
4260  TArrayD::Streamer(R__b);
4261  R__b.ReadVersion(&R__s, &R__c);
4262  TAtt3D::Streamer(R__b);
4263  } else {
4264  TH3::Streamer(R__b);
4265  TArrayD::Streamer(R__b);
4266  R__b.CheckByteCount(R__s, R__c, TH3D::IsA());
4267  }
4268  //====end of old versions
4269 
4270  } else {
4271  R__b.WriteClassBuffer(TH3D::Class(),this);
4272  }
4273 }
4274 
4275 
4276 ////////////////////////////////////////////////////////////////////////////////
4277 /// Operator =
4278 
4279 TH3D& TH3D::operator=(const TH3D &h1)
4280 {
4281  if (this != &h1) ((TH3D&)h1).Copy(*this);
4282  return *this;
4283 }
4284 
4285 
4286 ////////////////////////////////////////////////////////////////////////////////
4287 /// Operator *
4288 
4289 TH3D operator*(Float_t c1, TH3D &h1)
4290 {
4291  TH3D hnew = h1;
4292  hnew.Scale(c1);
4293  hnew.SetDirectory(0);
4294  return hnew;
4295 }
4296 
4297 
4298 ////////////////////////////////////////////////////////////////////////////////
4299 /// Operator +
4300 
4301 TH3D operator+(TH3D &h1, TH3D &h2)
4302 {
4303  TH3D hnew = h1;
4304  hnew.Add(&h2,1);
4305  hnew.SetDirectory(0);
4306  return hnew;
4307 }
4308 
4309 
4310 ////////////////////////////////////////////////////////////////////////////////
4311 /// Operator -
4312 
4313 TH3D operator-(TH3D &h1, TH3D &h2)
4314 {
4315  TH3D hnew = h1;
4316  hnew.Add(&h2,-1);
4317  hnew.SetDirectory(0);
4318  return hnew;
4319 }
4320 
4321 
4322 ////////////////////////////////////////////////////////////////////////////////
4323 /// Operator *
4324 
4325 TH3D operator*(TH3D &h1, TH3D &h2)
4326 {
4327  TH3D hnew = h1;
4328  hnew.Multiply(&h2);
4329  hnew.SetDirectory(0);
4330  return hnew;
4331 }
4332 
4333 
4334 ////////////////////////////////////////////////////////////////////////////////
4335 /// Operator /
4336 
4337 TH3D operator/(TH3D &h1, TH3D &h2)
4338 {
4339  TH3D hnew = h1;
4340  hnew.Divide(&h2);
4341  hnew.SetDirectory(0);
4342  return hnew;
4343 }