GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
GCube.cxx
Go to the documentation of this file.
1#include "GCube.h"
2
3#include "TROOT.h"
4#include "THashList.h"
5#include "THLimitsFinder.h"
6#include "TVirtualHistPainter.h"
7#include "TObjString.h"
8#include "TVirtualPad.h"
9#include "TMath.h"
10#include "TPad.h"
11#include "TF1.h"
12#include "TF2.h"
13#include "TF3.h"
14#include "TRandom.h"
15#include "TClass.h"
16
17#include <iostream>
18
19// Internal exceptions for the CheckConsistency method
20class DifferentDimension : public std::exception {
21};
22class DifferentNumberOfBins : public std::exception {
23};
24class DifferentAxisLimits : public std::exception {
25};
26class DifferentBinLimits : public std::exception {
27};
28class DifferentLabels : public std::exception {
29};
30
31// we have to repeat the code from the default constructor here, because calling the TH1 constructor and the GCube
32// default constructor gives an error
33GCube::GCube(const char* name, const char* title, Int_t nbins, Double_t low, Double_t up)
34 : TH1(name, title, nbins, low, up)
35{
36 fYaxis.Set(nbins, low, up);
37 // TH1 constructor sets fNcells to nbins+2
38 // we need (nbins+2)*((nbins+2)+1)*((nbins+2)+2)/6 cells
39 fNcells = (fNcells * (nbins + 3) * (nbins + 4)) / 6;
40}
41
42GCube::GCube(const char* name, const char* title, Int_t nbins, const Double_t* bins)
43 : TH1(name, title, nbins, bins)
44{
45 fYaxis.Set(nbins, bins);
46 // TH1 constructor sets fNcells to nbins+2
47 // we need (nbins+2)*((nbins+2)+1)*((nbins+2)+2)/6 cells
48 fNcells = (fNcells * (nbins + 3) * (nbins + 4)) / 6;
49}
50
51GCube::GCube(const char* name, const char* title, Int_t nbins, const Float_t* bins)
52 : TH1(name, title, nbins, bins)
53{
54 fYaxis.Set(nbins, bins);
55 // TH1 constructor sets fNcells to nbins+2
56 // we need (nbins+2)*((nbins+2)+1)*((nbins+2)+2)/6 cells
57 fNcells = (fNcells * (nbins + 3) * (nbins + 4)) / 6;
58}
59
60GCube::GCube(const GCube& rhs) : TH1() // NOLINT(readability-redundant-member-init)
61{
62 rhs.Copy(*this);
63}
64
65GCube::GCube(GCube&& rhs) noexcept : TH1() // NOLINT(readability-redundant-member-init)
66{
67 rhs.Copy(*this);
68}
69
70Int_t GCube::BufferEmpty(Int_t action)
71{
72 /// Fill histogram with all entries in the buffer.
73 /// action = -1 histogram is reset and refilled from the buffer (called by THistPainter::Paint)
74 /// action = 0 histogram is filled from the buffer
75 /// action = 1 histogram is filled and buffer is deleted
76 /// The buffer is automatically deleted when the number of entries
77 /// in the buffer is greater than the number of entries in the histogram
78 if(fBuffer == nullptr) {
79 return 0;
80 }
81
82 auto nbEntries = static_cast<Int_t>(fBuffer[0]);
83 if(nbEntries == 0) {
84 return 0;
85 }
86 if(nbEntries < 0 && action == 0) {
87 return 0; // histogram has been already filled from the buffer
88 }
89 Double_t* buffer = fBuffer;
90 if(nbEntries < 0) {
91 nbEntries = -nbEntries;
92 fBuffer = nullptr;
93 Reset("ICES");
94 fBuffer = buffer;
95 }
96
97 if(CanExtendAllAxes() || fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin() ||
98 fZaxis.GetXmax() <= fZaxis.GetXmin()) {
99 // find min, max of entries in buffer
100 // for the symmetric matrix x- and y-range are the same
101 Double_t min = fBuffer[2];
102 Double_t max = min;
103 if(fBuffer[3] < min) {
104 min = fBuffer[3];
105 }
106 if(fBuffer[3] > max) {
107 max = fBuffer[3];
108 }
109 for(Int_t i = 1; i < nbEntries; ++i) {
110 Double_t x = fBuffer[4 * i + 2];
111 if(x < min) {
112 min = x;
113 }
114 if(x > max) {
115 max = x;
116 }
117 Double_t y = fBuffer[4 * i + 3];
118 if(y < min) {
119 min = y;
120 }
121 if(y > max) {
122 max = y;
123 }
124 Double_t z = fBuffer[4 * i + 4];
125 if(z < min) {
126 min = z;
127 }
128 if(z > max) {
129 max = z;
130 }
131 }
132 if(fXaxis.GetXmax() <= fXaxis.GetXmin() || fYaxis.GetXmax() <= fYaxis.GetXmin() ||
133 fZaxis.GetXmax() <= fZaxis.GetXmin()) {
134 THLimitsFinder::GetLimitsFinder()->FindGoodLimits(this, min, max, min, max, min, max);
135 } else {
136 fBuffer = nullptr;
137 Int_t keep = fBufferSize;
138 fBufferSize = 0;
139 if(min < fXaxis.GetXmin()) {
140 RebinAxis(min, &fXaxis);
141 }
142 if(max >= fXaxis.GetXmax()) {
143 RebinAxis(max, &fXaxis);
144 }
145 if(min < fYaxis.GetXmin()) {
146 RebinAxis(min, &fYaxis);
147 }
148 if(max >= fYaxis.GetXmax()) {
149 RebinAxis(max, &fYaxis);
150 }
151 if(min < fZaxis.GetXmin()) {
152 RebinAxis(min, &fZaxis);
153 }
154 if(max >= fZaxis.GetXmax()) {
155 RebinAxis(max, &fZaxis);
156 }
157 fBuffer = buffer;
158 fBufferSize = keep;
159 }
160 }
161
162 fBuffer = nullptr;
163 for(Int_t i = 0; i < nbEntries; ++i) {
164 Fill(buffer[4 * i + 2], buffer[4 * i + 3], buffer[4 * i + 4], buffer[4 * i + 1]);
165 }
166 fBuffer = buffer;
167
168 if(action > 0) {
169 delete[] fBuffer;
170 fBuffer = nullptr;
171 fBufferSize = 0;
172 } else {
173 if(nbEntries == static_cast<Int_t>(fEntries)) {
174 fBuffer[0] = -nbEntries;
175 } else {
176 fBuffer[0] = 0;
177 }
178 }
179 return nbEntries;
180}
181
182Int_t GCube::BufferFill(Double_t x, Double_t y, Double_t z, Double_t w)
183{
184 if(fBuffer == nullptr) {
185 return -3;
186 }
187
188 auto nbEntries = static_cast<Int_t>(fBuffer[0]);
189 if(nbEntries < 0) {
190 nbEntries = -nbEntries;
191 fBuffer[0] = nbEntries;
192 if(fEntries > 0) {
193 Double_t* buffer = fBuffer;
194 fBuffer = nullptr;
195 Reset("ICES");
196 fBuffer = buffer;
197 }
198 }
199 if(4 * nbEntries + 4 >= fBufferSize) {
200 BufferEmpty(1);
201 return Fill(x, y, w);
202 }
203 fBuffer[4 * nbEntries + 1] = w;
204 fBuffer[4 * nbEntries + 2] = x;
205 fBuffer[4 * nbEntries + 3] = y;
206 fBuffer[4 * nbEntries + 4] = z;
207 fBuffer[0] += 1;
208
209 return -3;
210}
211
212void GCube::Copy(TObject& obj) const
213{
214 // Copy.
215
216 TH1::Copy(obj);
217 static_cast<GCube&>(obj).fTsumwy = fTsumwy;
218 static_cast<GCube&>(obj).fTsumwy2 = fTsumwy2;
219 static_cast<GCube&>(obj).fTsumwxy = fTsumwxy;
220 static_cast<GCube&>(obj).fMatrix = nullptr;
221}
222
223Double_t GCube::DoIntegral(Int_t binx1, Int_t binx2, Int_t biny1, Int_t biny2, Int_t binz1, Int_t binz2,
224 Double_t& error, Option_t* option, Bool_t doError) const
225{
226 // internal function compute integral and optionally the error between the limits
227 // specified by the bin number values working for all histograms (1D, 2D and 3D)
228
229 Int_t nbinsx = GetNbinsX();
230 if(binx1 < 0) {
231 binx1 = 0;
232 }
233 if(binx2 > nbinsx + 1 || binx2 < binx1) {
234 binx2 = nbinsx + 1;
235 }
236 if(GetDimension() > 1) {
237 Int_t nbinsy = GetNbinsY();
238 if(biny1 < 0) {
239 biny1 = 0;
240 }
241 if(biny2 > nbinsy + 1 || biny2 < biny1) {
242 biny2 = nbinsy + 1;
243 }
244 } else {
245 biny1 = 0;
246 biny2 = 0;
247 }
248 if(GetDimension() > 2) {
249 Int_t nbinsz = GetNbinsZ();
250 if(binz1 < 0) {
251 binz1 = 0;
252 }
253 if(binz2 > nbinsz + 1 || binz2 < binz1) {
254 binz2 = nbinsz + 1;
255 }
256 } else {
257 binz1 = 0;
258 binz2 = 0;
259 }
260
261 // - Loop on bins in specified range
262 TString opt = option;
263 opt.ToLower();
264 Bool_t width = kFALSE;
265 if(opt.Contains("width")) {
266 width = kTRUE;
267 }
268
269 Double_t dx = 1.;
270 Double_t dy = 1.;
271 Double_t dz = 1.;
272 Double_t integral = 0;
273 Double_t igerr2 = 0;
274 for(Int_t binx = binx1; binx <= binx2; ++binx) {
275 if(width) {
276 dx = fXaxis.GetBinWidth(binx);
277 }
278 for(Int_t biny = biny1; biny <= biny2; ++biny) {
279 if(width) {
280 dy = fYaxis.GetBinWidth(biny);
281 }
282 for(Int_t binz = binz1; binz <= binz2; ++binz) {
283 if(width) {
284 dz = fZaxis.GetBinWidth(binz);
285 }
286 Int_t bin = GetBin(binx, biny, binz);
287 if(width) {
288 integral += GetBinContent(bin) * dx * dy * dz;
289 } else {
290 integral += GetBinContent(bin);
291 }
292 if(doError) {
293 if(width) {
294 igerr2 += GetBinError(bin) * GetBinError(bin) * dx * dx * dy * dy * dz * dz;
295 } else {
296 igerr2 += GetBinError(bin) * GetBinError(bin);
297 }
298 }
299 }
300 }
301 }
302
303 if(doError) {
304 error = TMath::Sqrt(igerr2);
305 }
306 return integral;
307}
308
309Int_t GCube::Fill(Double_t)
310{
311 // Invalid Fill method
312 Error("Fill", "Invalid signature - do nothing");
313 return -1;
314}
315
316Int_t GCube::Fill(Double_t x, Double_t y, Double_t z)
317{
318 /// Increment cell defined by x,y,z by 1.
319 if(fBuffer != nullptr) {
320 return BufferFill(x, y, z, 1);
321 }
322
323 Int_t binx = 0;
324 Int_t biny = 0;
325 Int_t binz = 0;
326 fEntries++;
327 // go through all orderings of x,y,z to find right combination
328 if(z <= y && y <= x) {
329 // z, y, x
330 binx = fXaxis.FindBin(x);
331 biny = fYaxis.FindBin(y);
332 binz = fZaxis.FindBin(z);
333 } else if(z <= x && y <= x) {
334 // y, z, x
335 binx = fXaxis.FindBin(x);
336 biny = fZaxis.FindBin(z);
337 binz = fYaxis.FindBin(y);
338 } else if(y <= x) { // at this stage we know that z > y and z > x if y <= x
339 // y, x, z
340 binx = fZaxis.FindBin(z);
341 biny = fXaxis.FindBin(x);
342 binz = fYaxis.FindBin(y);
343 } else if(z <= x) { // at this stage we know that y > x
344 // z, x, y
345 binx = fYaxis.FindBin(y);
346 biny = fXaxis.FindBin(x);
347 binz = fZaxis.FindBin(z);
348 } else if(z <= y) { // at this stage we know that y > x
349 // x, z, y
350 binx = fYaxis.FindBin(y);
351 biny = fZaxis.FindBin(z);
352 binz = fXaxis.FindBin(x);
353 } else {
354 // x, y, z
355 binx = fZaxis.FindBin(z);
356 biny = fYaxis.FindBin(y);
357 binz = fXaxis.FindBin(x);
358 }
359
360 if(binx < 0 || biny < 0 || binz < 0) {
361 return -1;
362 }
363 Int_t bin = biny * (2 * fXaxis.GetNbins() - biny + 3) / 2 + binx - binz +
364 (fXaxis.GetNbins() + 2) * (fXaxis.GetNbins() + 3) * (fXaxis.GetNbins() + 4) / 6 -
365 (fXaxis.GetNbins() + 2 - binz) * (fXaxis.GetNbins() + 3 - binz) * (fXaxis.GetNbins() + 4 - binz) / 6 - biny;
366 std::cout << "binx,y,z = " << binx << "," << biny << "," << binz << " => bin = " << bin << std::endl;
367 bin = static_cast<Int_t>(binx + biny * (fXaxis.GetNbins() - (biny + 1.) / 2.) +
368 binz * (binz / 2. * (binz / 3. - fXaxis.GetNbins() + 3.) + fXaxis.GetNbins() * (3 + fXaxis.GetNbins() / 2.) +
369 10. / 3.));
370 std::cout << "binx,y,z = " << binx << "," << biny << "," << binz << " => bin = " << bin << std::endl;
371 AddBinContent(bin);
372 if(fSumw2.fN != 0) {
373 ++fSumw2.fArray[bin];
374 }
375 if(binx == 0 || binx > fXaxis.GetNbins()) {
376 if(!fgStatOverflows) {
377 return -1;
378 }
379 }
380 if(biny == 0 || biny > fYaxis.GetNbins()) {
381 if(!fgStatOverflows) {
382 return -1;
383 }
384 }
385 if(binz == 0 || binz > fZaxis.GetNbins()) {
386 if(!fgStatOverflows) {
387 return -1;
388 }
389 }
390 // not sure if these summed weights are calculated correct
391 // as of now this is the method used in TH3
392 ++fTsumw;
393 ++fTsumw2;
394 fTsumwx += x;
395 fTsumwx2 += x * x;
396 fTsumwy += y;
397 fTsumwy2 += y * y;
398 fTsumwxy += x * y;
399 fTsumwz += z;
400 fTsumwz2 += z * z;
401 fTsumwxz += x * z;
402 fTsumwyz += y * z;
403
404 return bin;
405}
406
407Int_t GCube::Fill(Double_t x, Double_t y, Double_t z, Double_t w)
408{
409 /// Increment cell defined by x,y,z by w.
410 if(fBuffer != nullptr) {
411 return BufferFill(x, y, z, 1);
412 }
413
414 Int_t binx = 0;
415 Int_t biny = 0;
416 Int_t binz = 0;
417 fEntries++;
418 // go through all orderings of x,y,z to find right combination
419 if(z <= y && y <= x) {
420 // z, y, x
421 binx = fXaxis.FindBin(x);
422 biny = fYaxis.FindBin(y);
423 binz = fZaxis.FindBin(z);
424 } else if(z <= x && y <= x) {
425 // y, z, x
426 binx = fXaxis.FindBin(x);
427 biny = fZaxis.FindBin(z);
428 binz = fYaxis.FindBin(y);
429 } else if(y <= x) { // at this stage we know that z > y and z > x if y <= x
430 // y, x, z
431 binx = fZaxis.FindBin(z);
432 biny = fXaxis.FindBin(x);
433 binz = fYaxis.FindBin(y);
434 } else if(z <= x) { // at this stage we know that y > x
435 // z, x, y
436 binx = fYaxis.FindBin(y);
437 biny = fXaxis.FindBin(x);
438 binz = fZaxis.FindBin(z);
439 } else if(z <= y) { // at this stage we know that y > x
440 // x, z, y
441 binx = fYaxis.FindBin(y);
442 biny = fZaxis.FindBin(z);
443 binz = fXaxis.FindBin(x);
444 } else {
445 // x, y, z
446 binx = fZaxis.FindBin(z);
447 biny = fYaxis.FindBin(y);
448 binz = fXaxis.FindBin(x);
449 }
450
451 if(binx < 0 || biny < 0 || binz < 0) {
452 return -1;
453 }
454 auto bin = static_cast<Int_t>(binx + biny * (fXaxis.GetNbins() - (biny + 1.) / 2.) +
455 binz * (binz / 2. * (binz / 3. - fXaxis.GetNbins() + 3.) + fXaxis.GetNbins() * (3 + fXaxis.GetNbins() / 2.) +
456 10. / 3.));
457 AddBinContent(bin, w);
458 if(fSumw2.fN != 0) {
459 fSumw2.fArray[bin] += w * w;
460 }
461 if(binx == 0 || binx > fXaxis.GetNbins()) {
462 if(!fgStatOverflows) {
463 return -1;
464 }
465 }
466 if(biny == 0 || biny > fYaxis.GetNbins()) {
467 if(!fgStatOverflows) {
468 return -1;
469 }
470 }
471 if(binz == 0 || binz > fZaxis.GetNbins()) {
472 if(!fgStatOverflows) {
473 return -1;
474 }
475 }
476 // not sure if these summed weights are calculated correct
477 // as of now this is the method used in TH3
478 fTsumw += w;
479 fTsumw2 += w * w;
480 fTsumwx += w * x;
481 fTsumwx2 += w * x * x;
482 fTsumwy += w * y;
483 fTsumwy2 += w * y * y;
484 fTsumwxy += w * x * y;
485 fTsumwz += w * z;
486 fTsumwz2 += w * z * z;
487 fTsumwxz += w * x * z;
488 fTsumwyz += w * y * z;
489
490 return bin;
491}
492
493Int_t GCube::Fill(const char* namex, const char* namey, const char* namez, Double_t w)
494{
495 // Increment cell defined by namex,namey,namez by a weight w
496 //
497 // if x or/and y is less than the low-edge of the corresponding axis first bin,
498 // the Underflow cell is incremented.
499 // if x or/and y is greater than the upper edge of corresponding axis last bin,
500 // the Overflow cell is incremented.
501 //
502 // If the storage of the sum of squares of weights has been triggered,
503 // via the function Sumw2, then the sum of the squares of weights is incremented
504 // by w^2 in the cell corresponding to x,y.
505 //
506
507 Int_t binx = 0;
508 Int_t biny = 0;
509 Int_t binz = 0;
510 fEntries++;
511 binx = fXaxis.FindBin(namex);
512 biny = fYaxis.FindBin(namey);
513 binz = fZaxis.FindBin(namez);
514 if(binx < 0 || biny < 0 || binz < 0) {
515 return -1;
516 }
517 // sort so that binx >= biny >= binz
518 if(binx < biny) {
519 std::swap(binx, biny);
520 }
521 if(binx < binz) {
522 std::swap(binx, binz);
523 }
524 if(biny < binz) {
525 std::swap(biny, binz);
526 }
527
528 auto bin = static_cast<Int_t>(binx + biny * (fXaxis.GetNbins() - (biny + 1.) / 2.) +
529 binz * (binz / 2. * (binz / 3. - fXaxis.GetNbins() + 3.) + fXaxis.GetNbins() * (3 + fXaxis.GetNbins() / 2.) +
530 10. / 3.));
531 AddBinContent(bin, w);
532 if(fSumw2.fN != 0) {
533 fSumw2.fArray[bin] += w * w;
534 }
535 if(binx == 0 || binx > fXaxis.GetNbins()) {
536 return -1;
537 }
538 if(biny == 0 || biny > fYaxis.GetNbins()) {
539 return -1;
540 }
541 Double_t x = fXaxis.GetBinCenter(binx);
542 Double_t y = fYaxis.GetBinCenter(biny);
543 Double_t z = fYaxis.GetBinCenter(binz);
544 fTsumw += w;
545 fTsumw2 += w * w;
546 fTsumwx += w * x;
547 fTsumwx2 += w * x * x;
548 fTsumwy += w * y;
549 fTsumwy2 += w * y * y;
550 fTsumwxy += w * x * y;
551 fTsumwz += w * z;
552 fTsumwz2 += w * z * z;
553 fTsumwxz += w * x * z;
554 fTsumwyz += w * y * z;
555 return bin;
556}
557
558void GCube::FillRandom(const char* fname, Int_t ntimes, TRandom* rng)
559{
560 ///*-*-*-*-*-*-*Fill histogram following distribution in function fname*-*-*-*
561 ///*-* =======================================================
562 ///*-*
563 ///*-* The distribution contained in the function fname (TF2) is integrated
564 ///*-* over the channel contents.
565 ///*-* It is normalized to 1.
566 ///*-* Getting one random number implies:
567 ///*-* - Generating a random number between 0 and 1 (say r1)
568 ///*-* - Look in which bin in the normalized integral r1 corresponds to
569 ///*-* - Fill histogram channel
570 ///*-* ntimes random numbers are generated
571 ///*-*
572 ///*-* One can also call TF2::GetRandom2 to get a random variate from a function.
573 ///*-*
574 ///*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*
575
576 //*-*- Search for fname in the list of ROOT defined functions
577 TObject* fobj = gROOT->GetFunction(fname);
578 if(fobj == nullptr) {
579 Error("FillRandom", "Unknown function: %s", fname);
580 return;
581 }
582 auto* f1 = static_cast<TF3*>(fobj);
583 if(f1 == nullptr) {
584 Error("FillRandom", "Function: %s is not a TF3", fname);
585 return;
586 }
587
588 //*-*- Allocate temporary space to store the integral and compute integral
589 Int_t nbinsx = GetNbinsX();
590 Int_t nbinsy = GetNbinsY();
591 Int_t nbinsz = GetNbinsZ();
592 Int_t nxy = nbinsx * nbinsy;
593 Int_t nbins = nxy * nbinsz;
594
595 auto* integral = new Double_t[nbins + 1];
596 Int_t ibin = 0;
597 integral[ibin] = 0;
598 for(Int_t binz = 1; binz <= nbinsz; ++binz) {
599 for(Int_t biny = 1; biny <= nbinsy; ++biny) {
600 for(Int_t binx = 1; binx <= nbinsx; ++binx) {
601 ++ibin;
602 Double_t fint = f1->Integral(fXaxis.GetBinLowEdge(binx), fXaxis.GetBinUpEdge(binx), fYaxis.GetBinLowEdge(biny),
603 fYaxis.GetBinUpEdge(biny), fZaxis.GetBinLowEdge(binz), fZaxis.GetBinUpEdge(binz));
604 integral[ibin] = integral[ibin - 1] + fint;
605 }
606 }
607 }
608
609 //*-*- Normalize integral to 1
610 if(integral[nbins] == 0) {
611 delete[] integral;
612 Error("FillRandom", "Integral = zero");
613 return;
614 }
615 for(Int_t bin = 1; bin <= nbins; ++bin) {
616 integral[bin] /= integral[nbins];
617 }
618
619 //*-*--------------Start main loop ntimes
620 for(int loop = 0; loop < ntimes; ++loop) {
621 Double_t r1 = (rng != nullptr) ? rng->Rndm(loop) : gRandom->Rndm(loop);
622 ibin = TMath::BinarySearch(nbins, &integral[0], r1);
623 Int_t binz = ibin / nxy;
624 Int_t biny = (ibin - nxy * binz) / nbinsx;
625 Int_t binx = 1 + ibin - nbinsx * (biny + nbinsy * binz);
626 ++biny;
627 Double_t x = fXaxis.GetBinCenter(binx);
628 Double_t y = fYaxis.GetBinCenter(biny);
629 Double_t z = fZaxis.GetBinCenter(binz);
630 Fill(x, y, z);
631 }
632 delete[] integral;
633}
634
635#if ROOT_VERSION_CODE < ROOT_VERSION(6, 24, 0)
636void GCube::FillRandom(TH1* h, Int_t ntimes, TRandom*)
637#else
638void GCube::FillRandom(TH1* h, Int_t ntimes, TRandom* rng)
639#endif
640{
641 ///*-*-*-*-*-*-*Fill histogram following distribution in histogram h*-*-*-*
642 ///*-* ====================================================
643 ///*-*
644 ///*-* The distribution contained in the histogram h (TH2) is integrated
645 ///*-* over the channel contents.
646 ///*-* It is normalized to 1.
647 ///*-* Getting one random number implies:
648 ///*-* - Generating a random number between 0 and 1 (say r1)
649 ///*-* - Look in which bin in the normalized integral r1 corresponds to
650 ///*-* - Fill histogram channel
651 ///*-* ntimes random numbers are generated
652 ///*-*
653 ///*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*
654
655 if(h == nullptr) {
656 Error("FillRandom", "Null histogram");
657 return;
658 }
659 if(fDimension != h->GetDimension()) {
660 Error("FillRandom", "Histograms with different dimensions");
661 return;
662 }
663
664 if(h->ComputeIntegral() == 0) {
665 return;
666 }
667
668 Double_t x = 0.;
669 Double_t y = 0.;
670 Double_t z = 0.;
671 auto* h3 = static_cast<TH3*>(h);
672 for(int loop = 0; loop < ntimes; ++loop) {
673#if ROOT_VERSION_CODE < ROOT_VERSION(6, 24, 0)
674 h3->GetRandom3(x, y, z);
675#else
676 h3->GetRandom3(x, y, z, rng);
677#endif
678 Fill(x, y, z);
679 }
680}
681
682Int_t GCube::FindFirstBinAbove(Double_t threshold, Int_t axis, Int_t firstBin, Int_t lastBin) const
683{
684 /// find first bin with content > threshold for axis (1=x, 2=y, 3=z)
685 /// if no bins with content > threshold is found the function returns -1.
686
687 if(axis < 1 || axis > 3) {
688 Warning("FindFirstBinAbove", "Invalid axis number : %d, axis x assumed\n", axis);
689 axis = 1;
690 }
691 Int_t nbinsx = fXaxis.GetNbins();
692 if(lastBin > firstBin && lastBin < nbinsx) { nbinsx = lastBin; }
693 Int_t nbinsy = fYaxis.GetNbins();
694 if(lastBin > firstBin && lastBin < nbinsy) { nbinsy = lastBin; }
695 Int_t nbinsz = fZaxis.GetNbins();
696 if(lastBin > firstBin && lastBin < nbinsz) { nbinsz = lastBin; }
697 if(axis == 1) {
698 for(Int_t binx = firstBin; binx <= nbinsx; ++binx) {
699 for(Int_t biny = firstBin; biny <= nbinsy; ++biny) {
700 for(Int_t binz = firstBin; binz <= nbinsz; ++binz) {
701 if(GetBinContent(binx, biny, binz) > threshold) {
702 return binx;
703 }
704 }
705 }
706 }
707 } else if(axis == 2) {
708 for(Int_t biny = firstBin; biny <= nbinsy; ++biny) {
709 for(Int_t binx = firstBin; binx <= nbinsx; ++binx) {
710 for(Int_t binz = firstBin; binz <= nbinsz; ++binz) {
711 if(GetBinContent(binx, biny, binz) > threshold) {
712 return biny;
713 }
714 }
715 }
716 }
717 } else {
718 for(Int_t binz = firstBin; binz <= nbinsz; ++binz) {
719 for(Int_t binx = firstBin; binx <= nbinsx; ++binx) {
720 for(Int_t biny = firstBin; biny <= nbinsy; ++biny) {
721 if(GetBinContent(binx, biny, binz) > threshold) {
722 return binz;
723 }
724 }
725 }
726 }
727 }
728 return -1;
729}
730
731Int_t GCube::FindLastBinAbove(Double_t threshold, Int_t axis, Int_t firstBin, Int_t lastBin) const
732{
733 // find last bin with content > threshold for axis (1=x, 2=y, 3=z)
734 // if no bins with content > threshold is found the function returns -1.
735
736 if(axis < 1 || axis > 3) {
737 Warning("FindLastBinAbove", "Invalid axis number : %d, axis x assumed\n", axis);
738 axis = 1;
739 }
740 Int_t nbinsx = fXaxis.GetNbins();
741 if(lastBin > firstBin && lastBin < nbinsx) { nbinsx = lastBin; }
742 Int_t nbinsy = fYaxis.GetNbins();
743 if(lastBin > firstBin && lastBin < nbinsy) { nbinsy = lastBin; }
744 Int_t nbinsz = fZaxis.GetNbins();
745 if(lastBin > firstBin && lastBin < nbinsz) { nbinsz = lastBin; }
746 if(axis == 1) {
747 for(Int_t binx = nbinsx; binx >= firstBin; --binx) {
748 for(Int_t biny = firstBin; biny <= nbinsy; ++biny) {
749 for(Int_t binz = firstBin; binz <= nbinsz; ++binz) {
750 if(GetBinContent(binx, biny, binz) > threshold) {
751 return binx;
752 }
753 }
754 }
755 }
756 } else if(axis == 2) {
757 for(Int_t biny = nbinsy; biny >= firstBin; --biny) {
758 for(Int_t binx = firstBin; binx <= nbinsx; ++binx) {
759 for(Int_t binz = firstBin; binz <= nbinsz; ++binz) {
760 if(GetBinContent(binx, biny, binz) > threshold) {
761 return biny;
762 }
763 }
764 }
765 }
766 } else {
767 for(Int_t binz = nbinsz; binz >= firstBin; --binz) {
768 for(Int_t binx = firstBin; binx <= nbinsx; ++binx) {
769 for(Int_t biny = firstBin; biny <= nbinsy; ++biny) {
770 if(GetBinContent(binx, biny, binz) > threshold) {
771 return binz;
772 }
773 }
774 }
775 }
776 }
777 return -1;
778}
779
780////////////////////////////////////////////////////////////////////////////////
781/// Project slices along Z in case of a 3-D histogram, then fit each slice
782/// with function f1 and make a 2-d histogram for each fit parameter
783/// Only cells in the bin range [binminx,binmaxx] and [binminy,binmaxy] are considered.
784/// if f1=0, a gaussian is assumed
785/// Before invoking this function, one can set a subrange to be fitted along Z
786/// via f1->SetRange(zmin,zmax)
787/// The argument option (default="QNR") can be used to change the fit options.
788/// "Q" means Quiet mode
789/// "N" means do not show the result of the fit
790/// "R" means fit the function in the specified function range
791///
792/// Note that the generated histograms are added to the list of objects
793/// in the current directory. It is the user's responsability to delete
794/// these histograms.
795///
796/// Example: Assume a 3-d histogram h3
797/// Root > h3->FitSlicesZ(); produces 4 TH2D histograms
798/// with h3_0 containing parameter 0(Constant) for a Gaus fit
799/// of each cell in X,Y projected along Z
800/// with h3_1 containing parameter 1(Mean) for a gaus fit
801/// with h3_2 containing parameter 2(StdDev) for a gaus fit
802/// with h3_chi2 containing the chisquare/number of degrees of freedom for a gaus fit
803///
804/// Root > h3->Fit(0,15,22,0,0,10);
805/// same as above, but only for bins 15 to 22 along X
806/// and only for cells in X,Y for which the corresponding projection
807/// along Z has more than cut bins filled.
808///
809/// NOTE: To access the generated histograms in the current directory, do eg:
810/// TH2D *h3_1 = (TH2D*)gDirectory->Get("h3_1");
811
812void GCube::FitSlicesZ(TF1* f1, Int_t binminx, Int_t binmaxx, Int_t binminy, Int_t binmaxy, Int_t cut, Option_t* option)
813{
814 Int_t nbinsx = fXaxis.GetNbins();
815 Int_t nbinsy = fYaxis.GetNbins();
816 Int_t nbinsz = fZaxis.GetNbins();
817 if(binminx < 1) {
818 binminx = 1;
819 }
820 if(binmaxx > nbinsx) {
821 binmaxx = nbinsx;
822 }
823 if(binmaxx < binminx) {
824 binminx = 1;
825 binmaxx = nbinsx;
826 }
827 if(binminy < 1) {
828 binminy = 1;
829 }
830 if(binmaxy > nbinsy) {
831 binmaxy = nbinsy;
832 }
833 if(binmaxy < binminy) {
834 binminy = 1;
835 binmaxy = nbinsy;
836 }
837
838 // default is to fit with a gaussian
839 if(f1 == nullptr) {
840 f1 = static_cast<TF1*>(gROOT->GetFunction("gaus"));
841 if(f1 == nullptr) {
842 f1 = new TF1("gaus", "gaus", fZaxis.GetXmin(), fZaxis.GetXmax());
843 } else {
844 f1->SetRange(fZaxis.GetXmin(), fZaxis.GetXmax());
845 }
846 }
847 const char* fname = f1->GetName();
848 Int_t npar = f1->GetNpar();
849 auto* parsave = new Double_t[npar];
850 f1->GetParameters(parsave);
851
852 // Create one 2-d histogram for each function parameter
853 std::array<char, 80> name;
854 std::array<char, 80> title;
855 std::vector<TH2D*> hlist(npar);
856 const TArrayD* xbins = fXaxis.GetXbins();
857 const TArrayD* ybins = fYaxis.GetXbins();
858 for(Int_t ipar = 0; ipar < npar; ++ipar) {
859 snprintf(name.data(), name.size(), "%s_%d", GetName(), ipar);
860 snprintf(title.data(), title.size(), "Fitted value of par[%d]=%s", ipar, f1->GetParName(ipar));
861 if(xbins->fN == 0) {
862 hlist[ipar] = new TH2D(name.data(), title.data(), nbinsx, fXaxis.GetXmin(), fXaxis.GetXmax(), nbinsy, fYaxis.GetXmin(), fYaxis.GetXmax());
863 } else {
864 hlist[ipar] = new TH2D(name.data(), title.data(), nbinsx, xbins->fArray, nbinsy, ybins->fArray);
865 }
866 hlist[ipar]->GetXaxis()->SetTitle(fXaxis.GetTitle());
867 hlist[ipar]->GetYaxis()->SetTitle(fYaxis.GetTitle());
868 }
869 snprintf(name.data(), name.size(), "%s_chi2", GetName());
870 auto* hchi2 = new TH2D(name.data(), "chisquare", nbinsx, fXaxis.GetXmin(), fXaxis.GetXmax(), nbinsy, fYaxis.GetXmin(), fYaxis.GetXmax());
871
872 // Loop on all cells in X,Y generate a projection along Z
873 auto* hpz = new TH1D("R_temp", "_temp", nbinsz, fZaxis.GetXmin(), fZaxis.GetXmax());
874 for(Int_t biny = binminy; biny <= binmaxy; biny++) {
875 Double_t y = fYaxis.GetBinCenter(biny);
876 for(Int_t binx = binminx; binx <= binmaxx; binx++) {
877 Double_t x = fXaxis.GetBinCenter(binx);
878 hpz->Reset();
879 Int_t nfill = 0;
880 for(Int_t binz = 1; binz <= nbinsz; binz++) {
881 Int_t bin = GetBin(binx, biny, binz);
882 Double_t w = RetrieveBinContent(bin);
883 if(w == 0) {
884 continue;
885 }
886 hpz->Fill(fZaxis.GetBinCenter(binz), w);
887 hpz->SetBinError(binz, GetBinError(bin));
888 nfill++;
889 }
890 if(nfill < cut) {
891 continue;
892 }
893 f1->SetParameters(parsave);
894 hpz->Fit(fname, option);
895 Int_t npfits = f1->GetNumberFitPoints();
896 if(npfits > npar && npfits >= cut) {
897 for(Int_t ipar = 0; ipar < npar; ipar++) {
898 hlist[ipar]->Fill(x, y, f1->GetParameter(ipar));
899 hlist[ipar]->SetBinError(binx, biny, f1->GetParError(ipar));
900 }
901 hchi2->SetBinContent(binx, biny, f1->GetChisquare() / (npfits - npar));
902 }
903 }
904 }
905 delete[] parsave;
906 delete hpz;
907}
908
909Int_t GCube::GetBin(Int_t binx, Int_t biny, Int_t binz) const
910{
911 Int_t n = fXaxis.GetNbins() + 2;
912 if(binx < 0) {
913 binx = 0;
914 }
915 if(binx >= n) {
916 binx = n - 1;
917 }
918 if(biny < 0) {
919 biny = 0;
920 }
921 if(biny >= n) {
922 biny = n - 1;
923 }
924 if(binz < 0) {
925 binz = 0;
926 }
927 if(binz >= n) {
928 binz = n - 1;
929 }
930 // sort so that binx >= biny >= binz
931 if(binx < biny) {
932 std::swap(binx, biny);
933 }
934 if(binx < binz) {
935 std::swap(binx, binz);
936 }
937 if(biny < binz) {
938 std::swap(biny, binz);
939 }
940
941 return static_cast<Int_t>(binx + biny * (fXaxis.GetNbins() - (biny + 1.) / 2.) +
942 binz * (binz / 2. * (binz / 3. - fXaxis.GetNbins() + 3.) + fXaxis.GetNbins() * (3 + fXaxis.GetNbins() / 2.) +
943 10. / 3.));
944}
945
946Double_t GCube::GetBinWithContent2(Double_t c, Int_t& binx, Int_t& biny, Int_t& binz, Int_t firstxbin, Int_t lastxbin,
947 Int_t firstybin, Int_t lastybin, Int_t firstzbin, Int_t lastzbin,
948 Double_t maxdiff) const
949{
950 // compute first cell (binx,biny,binz) in the range [firstxbin,lastxbin][firstybin,lastybin][firstzbin,lastzbin]
951 // for which diff = abs(cell_content-c) <= maxdiff
952 // In case several cells in the specified range with diff=0 are found
953 // the first cell found is returned in binx,biny,binz.
954 // In case several cells in the specified range satisfy diff <=maxdiff
955 // the cell with the smallest difference is returned in binx,biny,binz.
956 // In all cases the function returns the smallest difference.
957 //
958 // NOTE1: if firstxbin < 0, firstxbin is set to 1
959 // if(lastxbin < firstxbin then lastxbin is set to the number of bins in X
960 // ie if firstxbin=1 and lastxbin=0 (default) the search is on all bins in X except
961 // for X's under- and overflow bins.
962 // if firstybin < 0, firstybin is set to 1
963 // if(lastybin < firstybin then lastybin is set to the number of bins in Y
964 // ie if firstybin=1 and lastybin=0 (default) the search is on all bins in Y except
965 // for Y's under- and overflow bins.
966 // if firstzbin < 0, firstzbin is set to 1
967 // if(lastzbin < firstzbin then lastzbin is set to the number of bins in Z
968 // ie if firstzbin=1 and lastzbin=0 (default) the search is on all bins in Z except
969 // for Z's under- and overflow bins.
970 // NOTE2: if maxdiff=0 (default), the first cell with content=c is returned.
971
972 if(fDimension != 3) {
973 binx = -1;
974 biny = -1;
975 binz = -1;
976 Error("GetBinWithContent2", "function is only valid for 3-D histograms");
977 return 0;
978 }
979 if(firstxbin < 0) {
980 firstxbin = 1;
981 }
982 if(lastxbin < firstxbin) {
983 lastxbin = fXaxis.GetNbins();
984 }
985 if(firstybin < 0) {
986 firstybin = 1;
987 }
988 if(lastybin < firstybin) {
989 lastybin = fYaxis.GetNbins();
990 }
991 if(firstzbin < 0) {
992 firstzbin = 1;
993 }
994 if(lastzbin < firstzbin) {
995 lastzbin = fZaxis.GetNbins();
996 }
997 Double_t curmax = 1.e240;
998 for(Int_t k = firstzbin; k <= lastzbin; k++) {
999 for(Int_t j = firstybin; j <= lastybin; j++) {
1000 for(Int_t i = firstxbin; i <= lastxbin; i++) {
1001 Double_t diff = TMath::Abs(GetBinContent(i, j, k) - c);
1002 if(diff <= 0) {
1003 binx = i;
1004 biny = j;
1005 binz = k;
1006 return diff;
1007 }
1008 if(diff < curmax && diff <= maxdiff) {
1009 binx = i;
1010 biny = j;
1011 binz = k;
1012 curmax = diff;
1013 }
1014 }
1015 }
1016 }
1017 return curmax;
1018}
1019
1020Double_t GCube::GetCorrelationFactor(Int_t axis1, Int_t axis2) const
1021{
1022 ///*-*-*-*-*-*-*-*Return correlation factor between axis1 and axis2*-*-*-*-*
1023 ///*-* ====================================================
1024 if(axis1 < 1 || axis2 < 1 || axis1 > 3 || axis2 > 3) {
1025 Error("GetCorrelationFactor", "Wrong parameters");
1026 return 0;
1027 }
1028 if(axis1 == axis2) {
1029 return 1;
1030 }
1031 Double_t stddev1 = GetStdDev(axis1);
1032 if(stddev1 == 0) {
1033 return 0;
1034 }
1035 Double_t stddev2 = GetStdDev(axis2);
1036 if(stddev2 == 0) {
1037 return 0;
1038 }
1039 return GetCovariance(axis1, axis2) / stddev1 / stddev2;
1040}
1041
1042Double_t GCube::GetCovariance(Int_t axis1, Int_t axis2) const
1043{
1044 ///*-*-*-*-*-*-*-*Return covariance between axis1 and axis2*-*-*-*-*
1045 ///*-* ====================================================
1046
1047 if(axis1 < 1 || axis2 < 1 || axis1 > 3 || axis2 > 3) {
1048 Error("GetCovariance", "Wrong parameters");
1049 return 0;
1050 }
1051 std::array<Double_t, kNstat> stats;
1052 GetStats(stats.data());
1053 Double_t sumw = stats[0];
1054 Double_t sumw2 = stats[1];
1055 Double_t sumwx = stats[2];
1056 Double_t sumwx2 = stats[3];
1057 Double_t sumwy = stats[4];
1058 Double_t sumwy2 = stats[5];
1059 Double_t sumwxy = stats[6];
1060 Double_t sumwz = stats[7];
1061 Double_t sumwz2 = stats[8];
1062 Double_t sumwxz = stats[9];
1063 Double_t sumwyz = stats[10];
1064
1065 if(sumw == 0) {
1066 return 0;
1067 }
1068 if(axis1 == 1 && axis2 == 1) {
1069 return TMath::Abs(sumwx2 / sumw - sumwx * sumwx / sumw2);
1070 }
1071 if(axis1 == 2 && axis2 == 2) {
1072 return TMath::Abs(sumwy2 / sumw - sumwy * sumwy / sumw2);
1073 }
1074 if(axis1 == 3 && axis2 == 3) {
1075 return TMath::Abs(sumwz2 / sumw - sumwz * sumwz / sumw2);
1076 }
1077 if((axis1 == 1 && axis2 == 2) || (axis1 == 2 && axis2 == 1)) {
1078 return sumwxy / sumw - sumwx / sumw * sumwy / sumw;
1079 }
1080 if((axis1 == 1 && axis2 == 3) || (axis1 == 3 && axis2 == 1)) {
1081 return sumwxz / sumw - sumwx / sumw * sumwz / sumw;
1082 }
1083 if((axis1 == 2 && axis2 == 3) || (axis1 == 3 && axis2 == 2)) {
1084 return sumwyz / sumw - sumwy / sumw * sumwz / sumw;
1085 }
1086 return 0;
1087}
1088
1089void GCube::GetRandom3(Double_t& x, Double_t& y, Double_t& z)
1090{
1091 // return 3 random numbers along axis x, y, and z distributed according
1092 // the cellcontents of a 3-dim histogram
1093 // return a NaN if the histogram has a bin with negative content
1094
1095 Int_t nbinsx = GetNbinsX();
1096 Int_t nbinsy = GetNbinsY();
1097 Int_t nbinsz = GetNbinsZ();
1098 Int_t nxy = nbinsx * nbinsy;
1099 Int_t nbins = nxy * nbinsz;
1100 Double_t integral = 0.;
1101 // compute integral checking that all bins have positive content (see ROOT-5894)
1102 if(fIntegral != nullptr) {
1103 if(fIntegral[nbins + 1] != fEntries) {
1104 integral = ComputeIntegral(true);
1105 } else {
1106 integral = fIntegral[nbins];
1107 }
1108 } else {
1109 integral = ComputeIntegral(true);
1110 }
1111 if(integral == 0) {
1112 x = 0;
1113 y = 0;
1114 z = 0;
1115 return;
1116 }
1117 // case histogram has negative bins
1118 if(integral == TMath::QuietNaN()) {
1119 x = TMath::QuietNaN();
1120 y = TMath::QuietNaN();
1121 z = TMath::QuietNaN();
1122 return;
1123 }
1124
1125 Double_t r1 = gRandom->Rndm();
1126 Int_t ibin = TMath::BinarySearch(nbins, fIntegral, r1);
1127 Int_t binz = ibin / nxy;
1128 Int_t biny = (ibin - nxy * binz) / nbinsx;
1129 Int_t binx = ibin - nbinsx * (biny + nbinsy * binz);
1130 x = fXaxis.GetBinLowEdge(binx + 1);
1131 if(r1 > fIntegral[ibin]) {
1132 x += fXaxis.GetBinWidth(binx + 1) * (r1 - fIntegral[ibin]) / (fIntegral[ibin + 1] - fIntegral[ibin]);
1133 }
1134 y = fYaxis.GetBinLowEdge(biny + 1) + fYaxis.GetBinWidth(biny + 1) * gRandom->Rndm();
1135 z = fZaxis.GetBinLowEdge(binz + 1) + fZaxis.GetBinWidth(binz + 1) * gRandom->Rndm();
1136}
1137
1138void GCube::GetStats(Double_t* stats) const
1139{
1140 /// fill the array stats from the contents of this histogram
1141 /// The array stats must be correctly dimensionned in the calling program.
1142 /// stats[0] = sumw
1143 /// stats[1] = sumw2
1144 /// stats[2] = sumwx
1145 /// stats[3] = sumwx2
1146 /// stats[4] = sumwy
1147 /// stats[5] = sumwy2
1148 /// stats[6] = sumwxy
1149 /// stats[7] = sumwz
1150 /// stats[8] = sumwz2
1151 /// stats[9] = sumwxz
1152 /// stats[10] = sumwyz
1153 ///
1154 /// If no axis-subranges are specified (via TAxis::SetRange), the array stats
1155 /// is simply a copy of the statistics quantities computed at filling time.
1156 /// If sub-ranges are specified, the function recomputes these quantities
1157 /// from the bin contents in the current axis ranges.
1158 ///
1159 /// Note that the mean value/RMS is computed using the bins in the currently
1160 /// defined ranges (see TAxis::SetRange). By default the ranges include
1161 /// all bins from 1 to nbins included, excluding underflows and overflows.
1162 /// To force the underflows and overflows in the computation, one must
1163 /// call the static function TH1::StatOverflows(kTRUE) before filling
1164 /// the histogram.
1165
1166 if(fBuffer != nullptr) {
1167 const_cast<GCube*>(this)->BufferEmpty(); // NOLINT(cppcoreguidelines-pro-type-const-cast)
1168 }
1169
1170 if((fTsumw == 0 && fEntries > 0) || fXaxis.TestBit(TAxis::kAxisRange) || fYaxis.TestBit(TAxis::kAxisRange) ||
1171 fZaxis.TestBit(TAxis::kAxisRange)) {
1172 for(Int_t bin = 0; bin < 7; ++bin) {
1173 stats[bin] = 0;
1174 }
1175
1176 Int_t firstBinX = fXaxis.GetFirst();
1177 Int_t lastBinX = fXaxis.GetLast();
1178 Int_t firstBinY = fYaxis.GetFirst();
1179 Int_t lastBinY = fYaxis.GetLast();
1180 Int_t firstBinZ = fZaxis.GetFirst();
1181 Int_t lastBinZ = fZaxis.GetLast();
1182 // include underflow/overflow if TH1::StatOverflows(kTRUE) in case no range is set on the axis
1183 if(fgStatOverflows) {
1184 if(!fXaxis.TestBit(TAxis::kAxisRange)) {
1185 if(firstBinX == 1) {
1186 firstBinX = 0;
1187 }
1188 if(lastBinX == fXaxis.GetNbins()) {
1189 lastBinX += 1;
1190 }
1191 }
1192 if(!fYaxis.TestBit(TAxis::kAxisRange)) {
1193 if(firstBinY == 1) {
1194 firstBinY = 0;
1195 }
1196 if(lastBinY == fYaxis.GetNbins()) {
1197 lastBinY += 1;
1198 }
1199 }
1200 if(!fZaxis.TestBit(TAxis::kAxisRange)) {
1201 if(firstBinZ == 1) {
1202 firstBinZ = 0;
1203 }
1204 if(lastBinZ == fZaxis.GetNbins()) {
1205 lastBinZ += 1;
1206 }
1207 }
1208 }
1209 for(Int_t binz = firstBinZ; binz <= lastBinZ; ++binz) {
1210 Double_t z = fZaxis.GetBinCenter(binz);
1211 for(Int_t biny = firstBinY; biny <= lastBinY; ++biny) {
1212 Double_t y = fYaxis.GetBinCenter(biny);
1213 for(Int_t binx = firstBinX; binx <= lastBinX; ++binx) {
1214 Int_t bin = GetBin(binx, biny, binz);
1215 Double_t x = fXaxis.GetBinCenter(binx);
1216 Double_t w = GetBinContent(bin);
1217 Double_t err = TMath::Abs(GetBinError(bin));
1218 stats[0] += w;
1219 stats[1] += err * err;
1220 stats[2] += w * x;
1221 stats[3] += w * x * x;
1222 stats[4] += w * y;
1223 stats[5] += w * y * y;
1224 stats[6] += w * x * y;
1225 stats[7] += w * z;
1226 stats[8] += w * z * z;
1227 stats[9] += w * x * z;
1228 stats[10] += w * y * z;
1229 }
1230 }
1231 }
1232 } else {
1233 stats[0] = fTsumw;
1234 stats[1] = fTsumw2;
1235 stats[2] = fTsumwx;
1236 stats[3] = fTsumwx2;
1237 stats[4] = fTsumwy;
1238 stats[5] = fTsumwy2;
1239 stats[6] = fTsumwxy;
1240 stats[7] = fTsumwz;
1241 stats[8] = fTsumwz2;
1242 stats[9] = fTsumwxz;
1243 stats[10] = fTsumwyz;
1244 }
1245}
1246
1247Double_t GCube::Integral(Option_t* option) const
1248{
1249 // Return integral of bin contents. Only bins in the bins range are considered.
1250 // By default the integral is computed as the sum of bin contents in the range.
1251 // if option "width" is specified, the integral is the sum of
1252 // the bin contents multiplied by the bin width in x and in y.
1253
1254 return Integral(fXaxis.GetFirst(), fXaxis.GetLast(), fYaxis.GetFirst(), fYaxis.GetLast(), fZaxis.GetFirst(),
1255 fZaxis.GetLast(), option);
1256}
1257
1258Double_t GCube::Integral(Int_t firstxbin, Int_t lastxbin, Int_t firstybin, Int_t lastybin, Int_t firstzbin,
1259 Int_t lastzbin, Option_t* option) const
1260{
1261 // Return integral of bin contents in range [firstxbin,lastxbin],[firstybin,lastybin],[firstzbin,lastzbin]
1262 // for a 3-D histogram
1263 // By default the integral is computed as the sum of bin contents in the range.
1264 // if option "width" is specified, the integral is the sum of
1265 // the bin contents multiplied by the bin width in x, y, and z.
1266 double err = 0;
1267 return DoIntegral(firstxbin, lastxbin, firstybin, lastybin, firstzbin, lastzbin, err, option);
1268}
1269
1270Double_t GCube::IntegralAndError(Int_t firstxbin, Int_t lastxbin, Int_t firstybin, Int_t lastybin, Int_t firstzbin,
1271 Int_t lastzbin, Double_t& error, Option_t* option) const
1272{
1273 // Return integral of bin contents in range [firstxbin,lastxbin],[firstybin,lastybin],[firstzbin,lastzbin]
1274 // for a 3-D histogram. Calculates also the integral error using error propagation
1275 // from the bin errors assumming that all the bins are uncorrelated.
1276 // By default the integral is computed as the sum of bin contents in the range.
1277 // if option "width" is specified, the integral is the sum of
1278 // the bin contents multiplied by the bin width in x, y, and z.
1279
1280 return DoIntegral(firstxbin, lastxbin, firstybin, lastybin, firstzbin, lastzbin, error, option, kTRUE);
1281}
1282
1283#if ROOT_VERSION_CODE < ROOT_VERSION(6, 20, 0)
1284Double_t GCube::Interpolate(Double_t)
1285#else
1286Double_t GCube::Interpolate(Double_t) const
1287#endif
1288{
1289 // illegal for a TH3
1290 Error("Interpolate", "This function must be called with 3 arguments for a TH3");
1291 return 0;
1292}
1293
1294#if ROOT_VERSION_CODE < ROOT_VERSION(6, 20, 0)
1295Double_t GCube::Interpolate(Double_t, Double_t)
1296#else
1297Double_t GCube::Interpolate(Double_t, Double_t) const
1298#endif
1299{
1300 // illegal for a TH3
1301 Error("Interpolate", "This function must be called with 3 arguments for a TH3");
1302 return 0;
1303}
1304
1305#if ROOT_VERSION_CODE < ROOT_VERSION(6, 20, 0)
1306Double_t GCube::Interpolate(Double_t x, Double_t y, Double_t z)
1307#else
1308Double_t GCube::Interpolate(Double_t x, Double_t y, Double_t z) const
1309#endif
1310{
1311 /// Given a point P(x,y,z), Interpolate approximates the value via trilinear interpolation
1312 /// based on the 8 nearest bin center points ( corner of the cube surronding the points)
1313 /// The Algorithm is described in http://en.wikipedia.org/wiki/Trilinear_interpolation
1314 /// The given values (x,y,z) must be between first bin center and last bin center for each coordinate:
1315 ///
1316 /// fXAxis.GetBinCenter(1) < x < fXaxis.GetBinCenter(nbinX) AND
1317 /// fYAxis.GetBinCenter(1) < y < fYaxis.GetBinCenter(nbinY) AND
1318 /// fZAxis.GetBinCenter(1) < z < fZaxis.GetBinCenter(nbinZ)
1319
1320 Int_t ubx = fXaxis.FindBin(x);
1321 if(x < fXaxis.GetBinCenter(ubx)) {
1322 ubx -= 1;
1323 }
1324 Int_t obx = ubx + 1;
1325
1326 Int_t uby = fYaxis.FindBin(y);
1327 if(y < fYaxis.GetBinCenter(uby)) {
1328 uby -= 1;
1329 }
1330 Int_t oby = uby + 1;
1331
1332 Int_t ubz = fZaxis.FindBin(z);
1333 if(z < fZaxis.GetBinCenter(ubz)) {
1334 ubz -= 1;
1335 }
1336 Int_t obz = ubz + 1;
1337
1338 if(ubx <= 0 || uby <= 0 || ubz <= 0 || obx > fXaxis.GetNbins() || oby > fYaxis.GetNbins() ||
1339 obz > fZaxis.GetNbins()) {
1340 Error("Interpolate", "Cannot interpolate outside histogram domain.");
1341 return 0;
1342 }
1343
1344 Double_t xw = fXaxis.GetBinCenter(obx) - fXaxis.GetBinCenter(ubx);
1345 Double_t yw = fYaxis.GetBinCenter(oby) - fYaxis.GetBinCenter(uby);
1346 Double_t zw = fZaxis.GetBinCenter(obz) - fZaxis.GetBinCenter(ubz);
1347
1348 Double_t xd = (x - fXaxis.GetBinCenter(ubx)) / xw;
1349 Double_t yd = (y - fYaxis.GetBinCenter(uby)) / yw;
1350 Double_t zd = (z - fZaxis.GetBinCenter(ubz)) / zw;
1351
1352 std::array<Double_t, 8> v = {GetBinContent(ubx, uby, ubz), GetBinContent(ubx, uby, obz), GetBinContent(ubx, oby, ubz),
1353 GetBinContent(ubx, oby, obz), GetBinContent(obx, uby, ubz), GetBinContent(obx, uby, obz),
1354 GetBinContent(obx, oby, ubz), GetBinContent(obx, oby, obz)};
1355
1356 Double_t i1 = v[0] * (1 - zd) + v[1] * zd;
1357 Double_t i2 = v[2] * (1 - zd) + v[3] * zd;
1358 Double_t j1 = v[4] * (1 - zd) + v[5] * zd;
1359 Double_t j2 = v[6] * (1 - zd) + v[7] * zd;
1360
1361 Double_t w1 = i1 * (1 - yd) + i2 * yd;
1362 Double_t w2 = j1 * (1 - yd) + j2 * yd;
1363
1364 Double_t result = w1 * (1 - xd) + w2 * xd;
1365
1366 return result;
1367}
1368
1369Double_t GCube::KolmogorovTest(const TH1* h2, Option_t* option) const
1370{
1371 /// Statistical test of compatibility in shape between
1372 /// THIS histogram and h3, using Kolmogorov test.
1373 /// Default: Ignore under- and overflow bins in comparison
1374 ///
1375 /// option is a character string to specify options
1376 /// "U" include Underflows in test
1377 /// "O" include Overflows
1378 /// "N" include comparison of normalizations
1379 /// "D" Put out a line of "Debug" printout
1380 /// "M" Return the Maximum Kolmogorov distance instead of prob
1381 ///
1382 /// The returned function value is the probability of test
1383 /// (much less than one means NOT compatible)
1384 ///
1385 /// The KS test uses the distance between the pseudo-CDF's obtained
1386 /// from the histogram. Since in more than 1D the order for generating the pseudo-CDF is
1387 /// arbitrary, we use the pseudo-CDF's obtained from all the possible 6 combinatons of the 3 axis.
1388 /// The average of all the maximum distances obtained is used in the tests.
1389 ///
1390 /// Code adapted by Rene Brun from original HBOOK routine HDIFF
1391
1392 TString opt = option;
1393 opt.ToUpper();
1394
1395 Double_t prb = 0;
1396 auto* h1 = const_cast<TH1*>(static_cast<const TH1*>(this)); // NOLINT(cppcoreguidelines-pro-type-const-cast)
1397 if(h2 == nullptr) {
1398 return 0;
1399 }
1400 TAxis* xaxis1 = h1->GetXaxis();
1401 auto* xaxis2 = const_cast<TAxis*>(h2->GetXaxis()); // NOLINT(cppcoreguidelines-pro-type-const-cast)
1402 Int_t nc1 = xaxis1->GetNbins();
1403 Int_t nc2 = xaxis2->GetNbins();
1404
1405 // Check consistency of dimensions
1406 if(h1->GetDimension() != 3 || h2->GetDimension() != 3) {
1407 Error("KolmogorovTest", "Histograms must be 3-D\n");
1408 return 0;
1409 }
1410
1411 // Check consistency in number of channels
1412 if(nc1 != nc2 || nc1 < 1) {
1413 Error("KolmogorovTest", "Number of channels is different, %d and %d\n", nc1, nc2);
1414 return 0;
1415 }
1416
1417 // Check consistency in channel edges
1418 Bool_t afunc1 = kFALSE;
1419 Bool_t afunc2 = kFALSE;
1420 Double_t difprec = 1e-5;
1421 Double_t diff1 = TMath::Abs(xaxis1->GetXmin() - xaxis2->GetXmin());
1422 Double_t diff2 = TMath::Abs(xaxis1->GetXmax() - xaxis2->GetXmax());
1423 if(diff1 > difprec || diff2 > difprec) {
1424 Error("KolmogorovTest", "histograms with different binning along X");
1425 return 0;
1426 }
1427
1428 // Should we include Uflows, Oflows?
1429 Int_t ibeg = 1;
1430 Int_t iend = nc1;
1431 if(opt.Contains("U")) {
1432 ibeg = 0;
1433 }
1434 if(opt.Contains("O")) {
1435 iend = nc1 + 1;
1436 }
1437
1438 Double_t sum1 = 0;
1439 Double_t sum2 = 0;
1440 Double_t w1 = 0;
1441 Double_t w2 = 0;
1442 for(Int_t i = ibeg; i <= iend; ++i) {
1443 for(Int_t j = ibeg; j <= iend; ++j) {
1444 for(Int_t k = ibeg; k <= iend; ++k) {
1445 sum1 += h1->GetBinContent(i, j, k);
1446 sum2 += h2->GetBinContent(i, j, k);
1447 Double_t ew1 = h1->GetBinError(i, j, k);
1448 Double_t ew2 = h2->GetBinError(i, j, k);
1449 w1 += ew1 * ew1;
1450 w2 += ew2 * ew2;
1451 }
1452 }
1453 }
1454
1455 // Check that both scatterplots contain events
1456 if(sum1 == 0) {
1457 Error("KolmogorovTest", "Integral is zero for h1=%s\n", h1->GetName());
1458 return 0;
1459 }
1460 if(sum2 == 0) {
1461 Error("KolmogorovTest", "Integral is zero for h2=%s\n", h2->GetName());
1462 return 0;
1463 }
1464 // calculate the effective entries.
1465 // the case when errors are zero (w1 == 0 or w2 ==0) are equivalent to
1466 // compare to a function. In that case the rescaling is done only on sqrt(esum2) or sqrt(esum1)
1467 Double_t esum1 = 0.;
1468 Double_t esum2 = 0.;
1469 if(w1 > 0) {
1470 esum1 = sum1 * sum1 / w1;
1471 } else {
1472 afunc1 = kTRUE; // use later for calculating z
1473 }
1474
1475 if(w2 > 0) {
1476 esum2 = sum2 * sum2 / w2;
1477 } else {
1478 afunc2 = kTRUE; // use later for calculating z
1479 }
1480
1481 if(afunc2 && afunc1) {
1482 Error("KolmogorovTest", "Errors are zero for both histograms\n");
1483 return 0;
1484 }
1485
1486 // Find Kolmogorov distance
1487 // order is arbitrary take average of all possible 6 starting orders x,y,z
1488 std::array<int, 3> order = {0, 1, 2};
1489 std::array<int, 3> binbeg;
1490 std::array<int, 3> binend;
1491 std::array<int, 3> ibin;
1492 binbeg[0] = ibeg;
1493 binbeg[1] = ibeg;
1494 binbeg[2] = ibeg;
1495 binend[0] = iend;
1496 binend[1] = iend;
1497 binend[2] = iend;
1498 std::array<Double_t, 6> vdfmax; // there are in total 6 combinations
1499 int icomb = 0;
1500 Double_t s1 = 1. / (6. * sum1);
1501 Double_t s2 = 1. / (6. * sum2);
1502 Double_t rsum1 = 0.;
1503 Double_t rsum2 = 0.;
1504 do {
1505 // loop on bins
1506 Double_t dmax = 0;
1507 for(Int_t i = binbeg[order[0]]; i <= binend[order[0]]; i++) {
1508 for(Int_t j = binbeg[order[1]]; j <= binend[order[1]]; j++) {
1509 for(Int_t k = binbeg[order[2]]; k <= binend[order[2]]; k++) {
1510 ibin[order[0]] = i;
1511 ibin[order[1]] = j;
1512 ibin[order[2]] = k;
1513 int bin = h1->GetBin(ibin[0], ibin[1], ibin[2]);
1514 rsum1 += s1 * h1->GetBinContent(bin);
1515 rsum2 += s2 * h2->GetBinContent(bin);
1516 dmax = TMath::Max(dmax, TMath::Abs(rsum1 - rsum2));
1517 }
1518 }
1519 }
1520 vdfmax[icomb] = dmax;
1521 icomb++;
1522 } while(TMath::Permute(3, order.data()));
1523
1524 // get average of distances
1525 Double_t dfmax = TMath::Mean(vdfmax.size(), vdfmax.data());
1526
1527 // Get Kolmogorov probability
1528 Double_t factnm = 0.;
1529 if(afunc1) {
1530 factnm = TMath::Sqrt(sum2);
1531 } else if(afunc2) {
1532 factnm = TMath::Sqrt(sum1);
1533 } else {
1534 factnm = TMath::Sqrt(sum1 * sum2 / (sum1 + sum2));
1535 }
1536 Double_t z = dfmax * factnm;
1537
1538 prb = TMath::KolmogorovProb(z);
1539
1540 Double_t prb1 = 0.;
1541 Double_t prb2 = 0.;
1542 // option N to combine normalization makes sense if both afunc1 and afunc2 are false
1543 if(opt.Contains("N") && !(afunc1 || afunc2)) {
1544 // Combine probabilities for shape and normalization
1545 prb1 = prb;
1546 Double_t d12 = esum1 - esum2;
1547 Double_t chi2 = d12 * d12 / (esum1 + esum2);
1548 prb2 = TMath::Prob(chi2, 1);
1549 // see Eadie et al., section 11.6.2
1550 if(prb > 0 && prb2 > 0) {
1551 prb = prb * prb2 * (1 - TMath::Log(prb * prb2));
1552 } else {
1553 prb = 0;
1554 }
1555 }
1556
1557 // debug printout
1558 if(opt.Contains("D")) {
1559 std::cout << " Kolmo Prob h1 = " << h1->GetName() << ", sum1 = " << sum1 << std::endl;
1560 std::cout << " Kolmo Prob h2 = " << h2->GetName() << ", sum2 = " << sum2 << std::endl;
1561 std::cout << " Kolmo Probabil = " << prb << ", Max dist = " << dfmax << std::endl;
1562 if(opt.Contains("N")) {
1563 std::cout << " Kolmo Probabil = " << prb1 << " for shape alone, " << prb2 << " for normalisation alone" << std::endl;
1564 }
1565 }
1566 // This numerical error condition should never occur:
1567 if(TMath::Abs(rsum1 - 1) > 0.002) {
1568 Warning("KolmogorovTest", "Numerical problems with h1=%s\n", h1->GetName());
1569 }
1570 if(TMath::Abs(rsum2 - 1) > 0.002) {
1571 Warning("KolmogorovTest", "Numerical problems with h2=%s\n", h2->GetName());
1572 }
1573
1574 if(opt.Contains("M")) {
1575 return dfmax; // return avergae of max distance
1576 }
1577
1578 return prb;
1579}
1580
1581Long64_t GCube::Merge(TCollection* list)
1582{
1583 /// Add all histograms in the collection to this histogram.
1584 /// This function computes the min/max for the axes,
1585 /// compute a new number of bins, if necessary,
1586 /// add bin contents, errors and statistics.
1587 /// If overflows are present and limits are different the function will fail.
1588 /// The function returns the total number of entries in the result histogram
1589 /// if the merge is successfull, -1 otherwise.
1590 ///
1591 /// IMPORTANT remark. The 2 axis x and y may have different number
1592 /// of bins and different limits, BUT the largest bin width must be
1593 /// a multiple of the smallest bin width and the upper limit must also
1594 /// be a multiple of the bin width.
1595
1596 if(list == nullptr) {
1597 return 0;
1598 }
1599 if(list->IsEmpty()) {
1600 return static_cast<Long64_t>(GetEntries());
1601 }
1602
1603 TList inlist;
1604 inlist.AddAll(list);
1605
1606 TAxis newXAxis;
1607 TAxis newYAxis;
1608 TAxis newZAxis;
1609 Bool_t initialLimitsFound = kFALSE;
1610 Bool_t allSameLimits = kTRUE;
1611 Bool_t allHaveLimits = kTRUE;
1612 Bool_t firstNonEmptyHist = kTRUE;
1613
1614 TIter next(&inlist);
1615 GCube* h = this;
1616 do {
1617 // skip empty histgrams
1618 if(h->fTsumw == 0 && h->GetEntries() == 0) {
1619 continue;
1620 }
1621
1622 Bool_t hasLimits = h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax();
1623 allHaveLimits = allHaveLimits && hasLimits;
1624
1625 if(hasLimits) {
1626 h->BufferEmpty();
1627
1628 // this is done in case the first histograms are empty and
1629 // the histogram have different limits
1630 if(firstNonEmptyHist) {
1631 // set axis limits in the case the first histogram did not have limits
1632 if(h != this) {
1633 if(!SameLimitsAndNBins(fXaxis, *(h->GetXaxis()))) {
1634 fXaxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
1635 }
1636 if(!SameLimitsAndNBins(fYaxis, *(h->GetYaxis()))) {
1637 fYaxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
1638 }
1639 if(!SameLimitsAndNBins(fZaxis, *(h->GetZaxis()))) {
1640 fZaxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(), h->GetZaxis()->GetXmax());
1641 }
1642 }
1643 firstNonEmptyHist = kFALSE;
1644 }
1645
1646 if(!initialLimitsFound) {
1647 // this is executed the first time an histogram with limits is found
1648 // to set some initial values on the new axes
1649 initialLimitsFound = kTRUE;
1650 newXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
1651 newYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
1652 newZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(), h->GetYaxis()->GetXmax());
1653 } else {
1654 // check first if histograms have same bins
1655 if(!SameLimitsAndNBins(newXAxis, *(h->GetXaxis())) || !SameLimitsAndNBins(newYAxis, *(h->GetYaxis())) ||
1656 !SameLimitsAndNBins(newZAxis, *(h->GetZaxis()))) {
1657 allSameLimits = kFALSE;
1658 // recompute in this case the optimal limits
1659 // The condition to works is that the histogram have same bin with
1660 // and one common bin edge
1661 if(!RecomputeAxisLimits(newXAxis, *(h->GetXaxis()))) {
1662 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
1663 "first: (%d, %f, %f), second: (%d, %f, %f)",
1664 newXAxis.GetNbins(), newXAxis.GetXmin(), newXAxis.GetXmax(), h->GetXaxis()->GetNbins(),
1665 h->GetXaxis()->GetXmin(), h->GetXaxis()->GetXmax());
1666 return -1;
1667 }
1668 if(!RecomputeAxisLimits(newYAxis, *(h->GetYaxis()))) {
1669 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
1670 "first: (%d, %f, %f), second: (%d, %f, %f)",
1671 newYAxis.GetNbins(), newYAxis.GetXmin(), newYAxis.GetXmax(), h->GetYaxis()->GetNbins(),
1672 h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax());
1673 return -1;
1674 }
1675 if(!RecomputeAxisLimits(newZAxis, *(h->GetZaxis()))) {
1676 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
1677 "first: (%d, %f, %f), second: (%d, %f, %f)",
1678 newZAxis.GetNbins(), newZAxis.GetXmin(), newZAxis.GetXmax(), h->GetZaxis()->GetNbins(),
1679 h->GetZaxis()->GetXmin(), h->GetZaxis()->GetXmax());
1680 return -1;
1681 }
1682 }
1683 }
1684 }
1685 } while((h = static_cast<GCube*>(next())) != nullptr);
1686 if(h == nullptr && ((*next) != nullptr)) {
1687 Error("Merge", "Attempt to merge object of class: %s to a %s", (*next)->ClassName(), ClassName());
1688 return -1;
1689 }
1690 next.Reset();
1691
1692 // In the case of histogram with different limits
1693 // newX(Y)Axis will now have the new found limits
1694 // but one needs first to clone this histogram to perform the merge
1695 // The clone is not needed when all histograms have the same limits
1696 GCube* hclone = nullptr;
1697 if(!allSameLimits) {
1698 // We don't want to add the clone to gDirectory,
1699 // so remove our kMustCleanup bit temporarily
1700 Bool_t mustCleanup = TestBit(kMustCleanup);
1701 if(mustCleanup) {
1702 ResetBit(kMustCleanup);
1703 }
1704 hclone = static_cast<GCube*>(IsA()->New());
1705 hclone->SetDirectory(nullptr);
1706 Copy(*hclone);
1707 if(mustCleanup) {
1708 SetBit(kMustCleanup);
1709 }
1710 BufferEmpty(1); // To remove buffer.
1711 Reset(); // BufferEmpty sets limits so we can't use it later.
1712 SetEntries(0);
1713 inlist.AddFirst(hclone);
1714 }
1715
1716 if(!allSameLimits && initialLimitsFound) {
1717 SetBins(newXAxis.GetNbins(), newXAxis.GetXmin(), newXAxis.GetXmax(), newYAxis.GetNbins(), newYAxis.GetXmin(),
1718 newYAxis.GetXmax(), newZAxis.GetNbins(), newZAxis.GetXmin(), newZAxis.GetXmax());
1719 }
1720
1721 if(!allHaveLimits) {
1722 // fill this histogram with all the data from buffers of histograms without limits
1723 while((h = static_cast<GCube*>(next())) != nullptr) {
1724 if(h->GetXaxis()->GetXmin() >= h->GetXaxis()->GetXmax() && (h->fBuffer != nullptr)) {
1725 // no limits
1726 auto nbentries = static_cast<Int_t>(h->fBuffer[0]);
1727 for(Int_t i = 0; i < nbentries; i++) {
1728 Fill(h->fBuffer[4 * i + 2], h->fBuffer[4 * i + 3], h->fBuffer[4 * i + 4], h->fBuffer[4 * i + 1]);
1729 }
1730 // Entries from buffers have to be filled one by one
1731 // because FillN doesn't resize histograms.
1732 }
1733 }
1734 if(!initialLimitsFound) {
1735 if(hclone != nullptr) {
1736 inlist.Remove(hclone);
1737 delete hclone;
1738 }
1739 return static_cast<Long64_t>(GetEntries()); // all histograms have been processed
1740 }
1741 next.Reset();
1742 }
1743
1744 // merge bin contents and errors
1745 std::array<Double_t, kNstat> stats;
1746 std::array<Double_t, kNstat> totstats;
1747 for(Int_t i = 0; i < kNstat; ++i) {
1748 totstats[i] = stats[i] = 0;
1749 }
1750 GetStats(totstats.data());
1751 Double_t nentries = GetEntries();
1752 Int_t ix = 0;
1753 Int_t iy = 0;
1754 Int_t iz = 0;
1755 Bool_t canExtend = CanExtendAllAxes();
1756 SetCanExtend(TH1::kNoAxis); // reset, otherwise setting the under/overflow will extend the axis
1757
1758 while((h = static_cast<GCube*>(next())) != nullptr) {
1759 // process only if the histogram has limits; otherwise it was processed before
1760 if(h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax()) {
1761 // import statistics
1762 h->GetStats(stats.data());
1763 for(Int_t i = 0; i < kNstat; ++i) {
1764 totstats[i] += stats[i];
1765 }
1766 nentries += h->GetEntries();
1767
1768 Int_t nx = h->GetXaxis()->GetNbins();
1769 Int_t ny = h->GetYaxis()->GetNbins();
1770 Int_t nz = h->GetZaxis()->GetNbins();
1771
1772 // mantain loop in separate binz, biny and binz to avoid
1773 // callinig FindBin(x,y,z) for every bin
1774 for(Int_t binz = 0; binz <= nz + 1; ++binz) {
1775 if(!allSameLimits) {
1776 iz = fZaxis.FindBin(h->GetZaxis()->GetBinCenter(binz));
1777 } else {
1778 iz = binz;
1779 }
1780
1781 for(Int_t biny = 0; biny <= ny + 1; ++biny) {
1782 if(!allSameLimits) {
1783 iy = fYaxis.FindBin(h->GetYaxis()->GetBinCenter(biny));
1784 } else {
1785 iy = biny;
1786 }
1787 for(Int_t binx = 0; binx <= nx + 1; ++binx) {
1788 Int_t bin = binx + (nx + 2) * (biny + (ny + 2) * binz);
1789 Double_t cu = h->GetBinContent(bin);
1790 if(!allSameLimits) {
1791 // look at non-empty unerflow/overflows
1792 if(cu != 0 && (h->IsBinUnderflow(bin) || h->IsBinOverflow(bin))) {
1793 Error("Merge", "Cannot merge histograms - the histograms have"
1794 " different limits and undeflows/overflows are present."
1795 " The initial histogram is now broken!");
1796 return -1;
1797 }
1798 ix = fXaxis.FindBin(h->GetXaxis()->GetBinCenter(binx));
1799 } else {
1800 // case histograms with the same limits
1801 ix = binx;
1802 }
1803 Int_t ibin = GetBin(ix, iy, iz);
1804
1805 if(ibin < 0) {
1806 continue;
1807 }
1808 AddBinContent(ibin, cu);
1809 if(fSumw2.fN != 0) {
1810 Double_t error1 = h->GetBinError(bin);
1811 fSumw2.fArray[ibin] += error1 * error1;
1812 }
1813 }
1814 }
1815 }
1816 }
1817 }
1818 if(canExtend) {
1819 SetCanExtend(static_cast<UInt_t>(canExtend));
1820 }
1821
1822 // copy merged stats
1823 PutStats(totstats.data());
1824 SetEntries(nentries);
1825 if(hclone != nullptr) {
1826 inlist.Remove(hclone);
1827 delete hclone;
1828 }
1829 return static_cast<Long64_t>(nentries);
1830}
1831
1832TH1D* GCube::Projection(const char* name, Int_t firstBiny, Int_t lastBiny, Int_t firstBinz, Int_t lastBinz,
1833 Option_t* option) const
1834{
1835 /// method for performing projection
1836 const char* expectedName = "_pr";
1837
1838 TString opt = option;
1839 TString cut;
1840 Int_t i1 = opt.Index("[");
1841 if(i1 >= 0) {
1842 Int_t i2 = opt.Index("]");
1843 cut = opt(i1, i2 - i1 + 1);
1844 }
1845 opt.ToLower(); // must be called after having parsed the cut name
1846 bool originalRange = opt.Contains("o");
1847
1848 Int_t firstXBin = fXaxis.GetFirst();
1849 Int_t lastXBin = fXaxis.GetLast();
1850
1851 if(firstXBin == 0 && lastXBin == 0) {
1852 firstXBin = 1;
1853 lastXBin = fXaxis.GetNbins();
1854 }
1855
1856 if(lastBiny < firstBiny && fYaxis.TestBit(TAxis::kAxisRange)) {
1857 firstBiny = fYaxis.GetFirst();
1858 lastBiny = fYaxis.GetLast();
1859 // For special case of TAxis::SetRange, when first == 1 and last
1860 // = N and the range bit has been set, the TAxis will return 0
1861 // for both.
1862 if(firstBiny == 0 && lastBiny == 0) {
1863 firstBiny = 1;
1864 lastBiny = fYaxis.GetNbins();
1865 }
1866 }
1867 if(firstBiny < 0) {
1868 firstBiny = 0;
1869 }
1870 if(lastBiny < 0) {
1871 lastBiny = fYaxis.GetLast() + 1;
1872 }
1873 if(lastBiny > fYaxis.GetLast() + 1) {
1874 lastBiny = fYaxis.GetLast() + 1;
1875 }
1876
1877 if(lastBinz < firstBinz && fZaxis.TestBit(TAxis::kAxisRange)) {
1878 firstBinz = fZaxis.GetFirst();
1879 lastBinz = fZaxis.GetLast();
1880 // For special case of TAxis::SetRange, when first == 1 and last
1881 // = N and the range bit has been set, the TAxis will return 0
1882 // for both.
1883 if(firstBinz == 0 && lastBinz == 0) {
1884 firstBinz = 1;
1885 lastBinz = fZaxis.GetNbins();
1886 }
1887 }
1888 if(firstBinz < 0) {
1889 firstBinz = 0;
1890 }
1891 if(lastBinz < 0) {
1892 lastBinz = fZaxis.GetLast() + 1;
1893 }
1894 if(lastBinz > fZaxis.GetLast() + 1) {
1895 lastBinz = fZaxis.GetLast() + 1;
1896 }
1897
1898 // Create the projection histogram
1899 char* pname = const_cast<char*>(name); // NOLINT(cppcoreguidelines-pro-type-const-cast)
1900 if(name != nullptr && strcmp(name, expectedName) == 0) {
1901 auto nch = strlen(GetName()) + 4;
1902 pname = new char[nch];
1903 snprintf(pname, nch, "%s%s", GetName(), name);
1904 }
1905 TH1D* h1 = nullptr;
1906 // check if histogram with identical name exist
1907 // if compatible reset and re-use previous histogram
1908 // (see https://savannah.cern.ch/bugs/?54340)
1909 TObject* h1obj = gROOT->FindObject(pname);
1910 if((h1obj != nullptr) && h1obj->InheritsFrom(TH1::Class())) {
1911 if(h1obj->IsA() != TH1D::Class()) {
1912 Error("DoProjection", "Histogram with name %s must be a TH1D and is a %s", name, h1obj->ClassName());
1913 return nullptr;
1914 }
1915 h1 = static_cast<TH1D*>(h1obj);
1916 // reset the existing histogram and set always the new binning for the axis
1917 // This avoid problems when the histogram already exists and the histograms is rebinned or its range has changed
1918 // (see https://savannah.cern.ch/bugs/?94101 or https://savannah.cern.ch/bugs/?95808 )
1919 h1->Reset();
1920 const TArrayD* xbins = fXaxis.GetXbins();
1921 if(xbins->fN == 0) {
1922 if(originalRange) {
1923 h1->SetBins(fXaxis.GetNbins(), fXaxis.GetXmin(), fXaxis.GetXmax());
1924 } else {
1925 h1->SetBins(lastXBin - firstXBin + 1, fXaxis.GetBinLowEdge(firstXBin), fXaxis.GetBinUpEdge(lastXBin));
1926 }
1927 } else {
1928 // case variable bins
1929 if(originalRange) {
1930 h1->SetBins(fXaxis.GetNbins(), xbins->fArray);
1931 } else {
1932 h1->SetBins(lastXBin - firstXBin + 1, &(xbins->fArray[firstXBin - 1]));
1933 }
1934 }
1935 }
1936
1937 if(h1 == nullptr) {
1938 const TArrayD* bins = fXaxis.GetXbins();
1939 if(bins->fN == 0) {
1940 if(originalRange) {
1941 h1 = new TH1D(pname, GetTitle(), fXaxis.GetNbins(), fXaxis.GetXmin(), fXaxis.GetXmax());
1942 } else {
1943 h1 = new TH1D(pname, GetTitle(), lastXBin - firstXBin + 1, fXaxis.GetBinLowEdge(firstXBin),
1944 fXaxis.GetBinUpEdge(lastXBin));
1945 }
1946 } else {
1947 // case variable bins
1948 if(originalRange) {
1949 h1 = new TH1D(pname, GetTitle(), fXaxis.GetNbins(), bins->fArray);
1950 } else {
1951 h1 = new TH1D(pname, GetTitle(), lastXBin - firstXBin + 1, &(bins->fArray[firstXBin - 1]));
1952 }
1953 }
1954 if(opt.Contains("e") || (GetSumw2N() != 0)) {
1955 h1->Sumw2();
1956 }
1957 }
1958 if(pname != name) {
1959 delete[] pname;
1960 }
1961
1962 // Copy the axis attributes and the axis labels if needed.
1963 h1->GetXaxis()->ImportAttributes(&fXaxis);
1964 THashList* labels = const_cast<TAxis*>(&fXaxis)->GetLabels(); // NOLINT(cppcoreguidelines-pro-type-const-cast)
1965 if(labels != nullptr) {
1966 TIter iL(labels);
1967 TObjString* lb = nullptr;
1968 Int_t i = 1;
1969 while((lb = static_cast<TObjString*>(iL())) != nullptr) {
1970 h1->GetXaxis()->SetBinLabel(i, lb->String().Data());
1971 i++;
1972 }
1973 }
1974
1975 h1->SetLineColor(GetLineColor());
1976 h1->SetFillColor(GetFillColor());
1977 h1->SetMarkerColor(GetMarkerColor());
1978 h1->SetMarkerStyle(GetMarkerStyle());
1979
1980 // Fill the projected histogram
1981 Double_t totcont = 0.;
1982 Bool_t computeErrors = h1->GetSumw2N() != 0;
1983
1984 // implement filling of projected histogram
1985 // xbin is bin number of xAxis (the projected axis). Loop is done on all bin of TH2 histograms
1986 // inbin is the axis being integrated. Loop is done only on the selected bins
1987 for(Int_t xbin = 0; xbin <= fXaxis.GetNbins() + 1; ++xbin) {
1988 Double_t err2 = 0;
1989 Double_t cont = 0;
1990 if(fXaxis.TestBit(TAxis::kAxisRange) && (xbin < firstXBin || xbin > lastXBin)) {
1991 continue;
1992 }
1993
1994 for(Int_t ybin = firstBiny; ybin <= lastBiny; ++ybin) {
1995 for(Int_t zbin = firstBinz; zbin <= lastBinz; ++zbin) {
1996 // sum bin content and error if needed
1997 cont += GetBinContent(xbin, ybin, zbin);
1998 if(computeErrors) {
1999 Double_t exy = GetBinError(xbin, ybin, zbin);
2000 err2 += exy * exy;
2001 }
2002 }
2003 }
2004 // find corresponding bin number in h1 for xbin
2005 Int_t binOut = h1->GetXaxis()->FindBin(fXaxis.GetBinCenter(xbin));
2006 h1->SetBinContent(binOut, cont);
2007 if(computeErrors) {
2008 h1->SetBinError(binOut, TMath::Sqrt(err2));
2009 }
2010 // sum all content
2011 totcont += cont;
2012 }
2013
2014 // check if we can re-use the original statistics from the previous histogram
2015 bool reuseStats = false;
2016 if(((!fgStatOverflows && firstBiny == 1 && lastBiny == fYaxis.GetLast()) ||
2017 (fgStatOverflows && firstBiny == 0 && lastBiny == fYaxis.GetLast() + 1)) &&
2018 ((!fgStatOverflows && firstBinz == 1 && lastBinz == fZaxis.GetLast()) ||
2019 (fgStatOverflows && firstBinz == 0 && lastBinz == fZaxis.GetLast() + 1))) {
2020 reuseStats = true;
2021 } else {
2022 // also if total content match we can re-use
2023 double eps = 1.E-12;
2024 if(IsA() == GCubeF::Class()) {
2025 eps = 1.E-6;
2026 }
2027 if(fTsumw != 0 && TMath::Abs(fTsumw - totcont) < TMath::Abs(fTsumw) * eps) {
2028 reuseStats = true;
2029 }
2030 }
2031 // retrieve the statistics and set in projected histogram if we can re-use it
2032 bool reuseEntries = reuseStats;
2033 // can re-use entries if underflow/overflow are included
2034 reuseEntries &= static_cast<int>(firstBiny == 0 && lastBiny == fYaxis.GetLast() + 1 && firstBinz == 0 &&
2035 lastBinz == fYaxis.GetLast() + 1);
2036 if(reuseStats) {
2037 std::array<Double_t, kNstat> stat;
2038 GetStats(stat.data());
2039 h1->PutStats(stat.data());
2040 } else {
2041 // the statistics is automatically recalulated since it is reset by the call to SetBinContent
2042 // we just need to set the entries since they have not been correctly calculated during the projection
2043 // we can only set them to the effective entries
2044 h1->SetEntries(h1->GetEffectiveEntries());
2045 }
2046 if(reuseEntries) {
2047 h1->SetEntries(fEntries);
2048 } else {
2049 // re-compute the entries
2050 // in case of error calculation (i.e. when Sumw2() is set)
2051 // use the effective entries for the entries
2052 // since this is the only way to estimate them
2053 Double_t entries = TMath::Floor(totcont + 0.5); // to avoid numerical rounding
2054 if(h1->GetSumw2N() != 0) {
2055 entries = h1->GetEffectiveEntries();
2056 }
2057 h1->SetEntries(entries);
2058 }
2059
2060 if(opt.Contains("d")) {
2061 TVirtualPad* padsav = gPad;
2062 TVirtualPad* pad = gROOT->GetSelectedPad();
2063 if(pad != nullptr) {
2064 pad->cd();
2065 }
2066 opt.Remove(opt.First("d"), 1);
2067 // remove also other options
2068 if(opt.Contains("e")) {
2069 opt.Remove(opt.First("e"), 1);
2070 }
2071 if(!gPad || !gPad->FindObject(h1)) {
2072 h1->Draw(opt);
2073 } else {
2074 h1->Paint(opt);
2075 }
2076 if(padsav != nullptr) {
2077 padsav->cd();
2078 }
2079 }
2080
2081 return h1;
2082}
2083
2084void GCube::PutStats(Double_t* stats)
2085{
2086 // Replace current statistics with the values in array stats
2087 TH1::PutStats(stats);
2088 fTsumwy = stats[4];
2089 fTsumwy2 = stats[5];
2090 fTsumwxy = stats[6];
2091 fTsumwz = stats[7];
2092 fTsumwz2 = stats[8];
2093 fTsumwxz = stats[9];
2094 fTsumwyz = stats[10];
2095}
2096
2097GCube* GCube::Rebin3D(Int_t ngroup, const char* newname)
2098{
2099 /// -*-*-*Rebin this histogram grouping ngroup/ngroup bins along the xaxis/yaxis/zaxis together*-*-*-*-
2100 /// =================================================================================
2101 /// if newname is not blank a new temporary histogram hnew is created.
2102 /// else the current histogram is modified (default)
2103 /// The parameter ngroup indicates how many bins along the xaxis/yaxis/zaxis of this
2104 /// have to me merged into one bin of hnew
2105 /// If the original histogram has errors stored (via Sumw2), the resulting
2106 /// histograms has new errors correctly calculated.
2107 ///
2108 /// examples: if hpxpy is an existing GCube histogram with 40 x 40 x 40 bins
2109 /// hpxpy->Rebin3D(); // merges two bins along the xaxis, yaxis, and zaxis in one in hpxpy
2110 /// // Carefull: previous contents of hpxpy are lost
2111 /// hpxpy->Rebin3D(5); //merges five bins along the xaxis, yaxis, and zaxis in one in hpxpy
2112 /// GCube* hnew = hpxpy->Rebin3D(5,"hnew"); // creates a new histogram hnew
2113 /// // merging 5 bins of h1 along the xaxis, yaxis, and zaxis in one bin
2114 ///
2115 /// NOTE : If ngroup is not an exact divider of the number of bins,
2116 /// along the xaxis/yaxis/zaxis the top limit(s) of the rebinned histogram
2117 /// is changed to the upper edge of the bin=newbins*ngroup
2118 /// and the corresponding bins are added to
2119 /// the overflow bin.
2120 /// Statistics will be recomputed from the new bin contents.
2121
2122 Int_t nbins = fXaxis.GetNbins();
2123 Double_t min = fXaxis.GetXmin();
2124 Double_t max = fXaxis.GetXmax();
2125 if((ngroup <= 0) || (ngroup > nbins)) {
2126 Error("Rebin", "Illegal value of ngroup=%d", ngroup);
2127 return nullptr;
2128 }
2129
2130 Int_t newbins = nbins / ngroup;
2131
2132 // Save old bin contents into a new array
2133 Double_t entries = fEntries;
2134 auto* oldBins = new Double_t[(nbins + 2) * (nbins + 3) * (nbins + 4) / 6];
2135 for(Int_t xbin = 0; xbin < nbins + 2; xbin++) {
2136 for(Int_t ybin = 0; ybin <= xbin; ybin++) {
2137 for(Int_t zbin = 0; zbin <= ybin; zbin++) {
2138 Int_t bin = GetBin(xbin, ybin, zbin);
2139 oldBins[bin] = GetBinContent(bin);
2140 }
2141 }
2142 }
2143 Double_t* oldErrors = nullptr;
2144 if(fSumw2.fN != 0) {
2145 oldErrors = new Double_t[(nbins + 2) * (nbins + 3) * (nbins + 4) / 6];
2146 for(Int_t xbin = 0; xbin < nbins + 2; xbin++) {
2147 for(Int_t ybin = 0; ybin <= xbin; ybin++) {
2148 for(Int_t zbin = 0; zbin <= ybin; zbin++) {
2149 Int_t bin = GetBin(xbin, ybin, zbin);
2150 oldErrors[bin] = GetBinError(bin);
2151 }
2152 }
2153 }
2154 }
2155
2156 // create a clone of the old histogram if newname is specified
2157 GCube* hnew = this;
2158 if(newname != nullptr && (strlen(newname) != 0u)) {
2159 hnew = static_cast<GCube*>(Clone());
2160 hnew->SetName(newname);
2161 }
2162
2163 // save original statistics
2164 std::array<Double_t, kNstat> stat;
2165 GetStats(stat.data());
2166
2167 bool resetStat = false;
2168
2169 // change axis specs and rebuild bin contents array
2170 if(newbins * ngroup != nbins) {
2171 max = fXaxis.GetBinUpEdge(newbins * ngroup);
2172 resetStat = true; // stats must be reset because top bins will be moved to overflow bin
2173 }
2174 // save the TAttAxis members (reset by SetBins) for x axis
2175 Int_t nXdivisions = fXaxis.GetNdivisions();
2176 Color_t xAxisColor = fXaxis.GetAxisColor();
2177 Color_t xLabelColor = fXaxis.GetLabelColor();
2178 Style_t xLabelFont = fXaxis.GetLabelFont();
2179 Float_t xLabelOffset = fXaxis.GetLabelOffset();
2180 Float_t xLabelSize = fXaxis.GetLabelSize();
2181 Float_t xTickLength = fXaxis.GetTickLength();
2182 Float_t xTitleOffset = fXaxis.GetTitleOffset();
2183 Float_t xTitleSize = fXaxis.GetTitleSize();
2184 Color_t xTitleColor = fXaxis.GetTitleColor();
2185 Style_t xTitleFont = fXaxis.GetTitleFont();
2186 // save the TAttAxis members (reset by SetBins) for y axis
2187 Int_t nYdivisions = fYaxis.GetNdivisions();
2188 Color_t yAxisColor = fYaxis.GetAxisColor();
2189 Color_t yLabelColor = fYaxis.GetLabelColor();
2190 Style_t yLabelFont = fYaxis.GetLabelFont();
2191 Float_t yLabelOffset = fYaxis.GetLabelOffset();
2192 Float_t yLabelSize = fYaxis.GetLabelSize();
2193 Float_t yTickLength = fYaxis.GetTickLength();
2194 Float_t yTitleOffset = fYaxis.GetTitleOffset();
2195 Float_t yTitleSize = fYaxis.GetTitleSize();
2196 Color_t yTitleColor = fYaxis.GetTitleColor();
2197 Style_t yTitleFont = fYaxis.GetTitleFont();
2198 // save the TAttAxis members (reset by SetBins) for z axis
2199 Int_t nZdivisions = fZaxis.GetNdivisions();
2200 Color_t zAxisColor = fZaxis.GetAxisColor();
2201 Color_t zLabelColor = fZaxis.GetLabelColor();
2202 Style_t zLabelFont = fZaxis.GetLabelFont();
2203 Float_t zLabelOffset = fZaxis.GetLabelOffset();
2204 Float_t zLabelSize = fZaxis.GetLabelSize();
2205 Float_t zTickLength = fZaxis.GetTickLength();
2206 Float_t zTitleOffset = fZaxis.GetTitleOffset();
2207 Float_t zTitleSize = fZaxis.GetTitleSize();
2208 Color_t zTitleColor = fZaxis.GetTitleColor();
2209 Style_t zTitleFont = fZaxis.GetTitleFont();
2210
2211 // copy merged bin contents (ignore under/overflows)
2212 if(ngroup != 1) {
2213 if(fXaxis.GetXbins()->GetSize() > 0 || fYaxis.GetXbins()->GetSize() > 0 || fZaxis.GetXbins()->GetSize() > 0) {
2214 // variable bin sizes in x or y, don't treat both cases separately
2215 auto* bins = new Double_t[newbins + 1];
2216 for(Int_t i = 0; i <= newbins; ++i) {
2217 bins[i] = fXaxis.GetBinLowEdge(1 + i * ngroup);
2218 }
2219 hnew->SetBins(newbins, bins, newbins, bins); // changes also errors array (if any)
2220 delete[] bins;
2221 } else {
2222 hnew->SetBins(newbins, min, max, newbins, min, max); // changes also errors array
2223 }
2224
2225 Int_t oldxbin = 1;
2226 Int_t oldybin = 1;
2227 Int_t bin = 0;
2228 for(Int_t xbin = 1; xbin <= newbins; ++xbin) {
2229 oldybin = 1;
2230 for(Int_t ybin = 1; ybin <= xbin; ++ybin) {
2231 Double_t binContent = 0;
2232 Double_t binError = 0;
2233 for(Int_t i = 0; i < ngroup; ++i) {
2234 if(oldxbin + i > nbins) {
2235 break;
2236 }
2237 for(Int_t j = 0; j < ngroup; ++j) {
2238 if(oldybin + j > nbins) {
2239 break;
2240 }
2241 // get global bin (same conventions as in GCube::GetBin(xbin,ybin)
2242 if(oldybin + j <= oldxbin + i) {
2243 bin = oldxbin + i + (oldybin + j) * (2 * fXaxis.GetNbins() - (oldybin + j) + 3) / 2;
2244 } else {
2245 bin = oldybin + j + (oldxbin + i) * (2 * fXaxis.GetNbins() - (oldxbin + i) + 3) / 2;
2246 }
2247 binContent += oldBins[bin];
2248 if(oldErrors != nullptr) {
2249 binError += oldErrors[bin] * oldErrors[bin];
2250 }
2251 }
2252 }
2253 hnew->SetBinContent(xbin, ybin, binContent);
2254 if(oldErrors != nullptr) {
2255 hnew->SetBinError(xbin, ybin, TMath::Sqrt(binError));
2256 }
2257 oldybin += ngroup;
2258 }
2259 oldxbin += ngroup;
2260 }
2261
2262 // Recompute correct underflows and overflows.
2263
2264 // copy old underflow bin in x and y (0,0)
2265 hnew->SetBinContent(0, 0, oldBins[0]);
2266 if(oldErrors != nullptr) {
2267 hnew->SetBinError(0, 0, oldErrors[0]);
2268 }
2269
2270 // calculate new overflow bin in x and y (newbins+1,newbins+1)
2271 Double_t binContent = 0.;
2272 Double_t binError = 0.;
2273 for(Int_t xbin = oldxbin; xbin <= nbins + 1; ++xbin) {
2274 for(Int_t ybin = oldybin; ybin <= xbin; ++ybin) {
2275 bin = xbin + ybin * (2 * nbins - ybin + 3) / 2;
2276 binContent += oldBins[bin];
2277 if(oldErrors != nullptr) {
2278 binError += oldErrors[bin] * oldErrors[bin];
2279 }
2280 }
2281 }
2282 hnew->SetBinContent(newbins + 1, newbins + 1, binContent);
2283 if(oldErrors != nullptr) {
2284 hnew->SetBinError(newbins + 1, newbins + 1, TMath::Sqrt(binError));
2285 }
2286
2287 // calculate new underflow bin in x and overflow in y (0,newbins+1)
2288 binContent = 0.;
2289 binError = 0.;
2290 for(Int_t ybin = oldybin; ybin <= nbins + 1; ++ybin) {
2291 bin = ybin * (2 * nbins - ybin + 3) / 2;
2292 binContent += oldBins[bin];
2293 if(oldErrors != nullptr) {
2294 binError += oldErrors[bin] * oldErrors[bin];
2295 }
2296 }
2297 hnew->SetBinContent(0, newbins + 1, binContent);
2298 if(oldErrors != nullptr) {
2299 hnew->SetBinError(0, newbins + 1, TMath::Sqrt(binError));
2300 }
2301
2302 // calculate new overflow bin in x and underflow in y (newbins+1,0)
2303 binContent = 0.;
2304 binError = 0.;
2305 for(Int_t xbin = oldxbin; xbin <= nbins + 1; ++xbin) {
2306 bin = xbin;
2307 binContent += oldBins[bin];
2308 if(oldErrors != nullptr) {
2309 binError += oldErrors[bin] * oldErrors[bin];
2310 }
2311 }
2312 hnew->SetBinContent(newbins + 1, 0, binContent);
2313 if(oldErrors != nullptr) {
2314 hnew->SetBinError(newbins + 1, 0, TMath::Sqrt(binError));
2315 }
2316
2317 // recompute under/overflow contents in y for the new x bins
2318 Int_t oldxbin2 = 1;
2319 for(Int_t xbin = 1; xbin <= newbins; ++xbin) {
2320 Double_t binContent0 = 0.;
2321 Double_t binContent2 = 0.;
2322 Double_t binError0 = 0.;
2323 Double_t binError2 = 0.;
2324 for(Int_t i = 0; i < ngroup; ++i) {
2325 if(oldxbin2 + i > nbins) {
2326 break;
2327 }
2328 // old underflow bin (in y)
2329 Int_t ufbin = oldxbin2 + i;
2330 binContent0 += oldBins[ufbin];
2331 if(oldErrors != nullptr) {
2332 binError0 += oldErrors[ufbin] * oldErrors[ufbin];
2333 }
2334 for(Int_t ybin = oldybin; ybin <= nbins + 1; ++ybin) {
2335 // old overflow bin (in y)
2336 Int_t ofbin = ufbin + ybin * (nbins + 2);
2337 binContent2 += oldBins[ofbin];
2338 if(oldErrors != nullptr) {
2339 binError2 += oldErrors[ofbin] * oldErrors[ofbin];
2340 }
2341 }
2342 }
2343 hnew->SetBinContent(xbin, 0, binContent0);
2344 hnew->SetBinContent(xbin, newbins + 1, binContent2);
2345 if(oldErrors != nullptr) {
2346 hnew->SetBinError(xbin, 0, TMath::Sqrt(binError0));
2347 hnew->SetBinError(xbin, newbins + 1, TMath::Sqrt(binError2));
2348 }
2349 oldxbin2 += ngroup;
2350 }
2351
2352 // recompute under/overflow contents in x for the new y bins
2353 Int_t oldybin2 = 1;
2354 for(Int_t ybin = 1; ybin <= newbins; ++ybin) {
2355 Double_t binContent0 = 0.;
2356 Double_t binContent2 = 0.;
2357 Double_t binError0 = 0.;
2358 Double_t binError2 = 0.;
2359 for(Int_t i = 0; i < ngroup; ++i) {
2360 if(oldybin2 + i > nbins) {
2361 break;
2362 }
2363 // old underflow bin (in x)
2364 Int_t ufbin = (oldybin2 + i) * (nbins + 2);
2365 binContent0 += oldBins[ufbin];
2366 if(oldErrors != nullptr) {
2367 binError0 += oldErrors[ufbin] * oldErrors[ufbin];
2368 }
2369 for(Int_t xbin = oldxbin; xbin <= nbins + 1; ++xbin) {
2370 Int_t ofbin = ufbin + xbin;
2371 binContent2 += oldBins[ofbin];
2372 if(oldErrors != nullptr) {
2373 binError2 += oldErrors[ofbin] * oldErrors[ofbin];
2374 }
2375 }
2376 }
2377 hnew->SetBinContent(0, ybin, binContent0);
2378 hnew->SetBinContent(newbins + 1, ybin, binContent2);
2379 if(oldErrors != nullptr) {
2380 hnew->SetBinError(0, ybin, TMath::Sqrt(binError0));
2381 hnew->SetBinError(newbins + 1, ybin, TMath::Sqrt(binError2));
2382 }
2383 oldybin2 += ngroup;
2384 }
2385 }
2386
2387 // Restore x axis attributes
2388 fXaxis.SetNdivisions(nXdivisions);
2389 fXaxis.SetAxisColor(xAxisColor);
2390 fXaxis.SetLabelColor(xLabelColor);
2391 fXaxis.SetLabelFont(xLabelFont);
2392 fXaxis.SetLabelOffset(xLabelOffset);
2393 fXaxis.SetLabelSize(xLabelSize);
2394 fXaxis.SetTickLength(xTickLength);
2395 fXaxis.SetTitleOffset(xTitleOffset);
2396 fXaxis.SetTitleSize(xTitleSize);
2397 fXaxis.SetTitleColor(xTitleColor);
2398 fXaxis.SetTitleFont(xTitleFont);
2399 // Restore y axis attributes
2400 fYaxis.SetNdivisions(nYdivisions);
2401 fYaxis.SetAxisColor(yAxisColor);
2402 fYaxis.SetLabelColor(yLabelColor);
2403 fYaxis.SetLabelFont(yLabelFont);
2404 fYaxis.SetLabelOffset(yLabelOffset);
2405 fYaxis.SetLabelSize(yLabelSize);
2406 fYaxis.SetTickLength(yTickLength);
2407 fYaxis.SetTitleOffset(yTitleOffset);
2408 fYaxis.SetTitleSize(yTitleSize);
2409 fYaxis.SetTitleColor(yTitleColor);
2410 fYaxis.SetTitleFont(yTitleFont);
2411 // Restore z axis attributes
2412 fZaxis.SetNdivisions(nZdivisions);
2413 fZaxis.SetAxisColor(zAxisColor);
2414 fZaxis.SetLabelColor(zLabelColor);
2415 fZaxis.SetLabelFont(zLabelFont);
2416 fZaxis.SetLabelOffset(zLabelOffset);
2417 fZaxis.SetLabelSize(zLabelSize);
2418 fZaxis.SetTickLength(zTickLength);
2419 fZaxis.SetTitleOffset(zTitleOffset);
2420 fZaxis.SetTitleSize(zTitleSize);
2421 fZaxis.SetTitleColor(zTitleColor);
2422 fZaxis.SetTitleFont(zTitleFont);
2423
2424 // restore statistics and entries modified by SetBinContent
2425 hnew->SetEntries(entries);
2426 if(!resetStat) {
2427 hnew->PutStats(stat.data());
2428 }
2429
2430 delete[] oldBins;
2431 delete[] oldErrors;
2432 return hnew;
2433}
2434
2435void GCube::Reset(Option_t* option)
2436{
2437 //*-*-*-*-*-*-*-*Reset this histogram: contents, errors, etc*-*-*-*-*-*-*-*
2438 //*-* ===========================================
2439
2440 TH1::Reset(option);
2441 TString opt = option;
2442 opt.ToUpper();
2443
2444 if(opt.Contains("ICE") && !opt.Contains("S")) {
2445 return;
2446 }
2447 fTsumwy = 0;
2448 fTsumwy2 = 0;
2449 fTsumwxy = 0;
2450 if(Matrix() != nullptr) {
2451 try {
2452 delete Matrix();
2453 } catch(std::exception& e) {
2454 }
2455 Matrix(nullptr);
2456 }
2457}
2458
2459void GCube::SetShowProjection(const char* option, Int_t nbins)
2460{
2461 /// When the mouse is moved in a pad containing a 3-d view of this histogram
2462 /// a second canvas shows a projection type given as option.
2463 /// To stop the generation of the projections, delete the canvas
2464 /// containing the projection.
2465 /// option may contain a combination of the characters x,y,z,e
2466 /// option = "x" return the x projection into a TH1D histogram
2467 /// option = "y" return the y projection into a TH1D histogram
2468 /// option = "z" return the z projection into a TH1D histogram
2469 /// option = "xy" return the x versus y projection into a TH2D histogram
2470 /// option = "yx" return the y versus x projection into a TH2D histogram
2471 /// option = "xz" return the x versus z projection into a TH2D histogram
2472 /// option = "zx" return the z versus x projection into a TH2D histogram
2473 /// option = "yz" return the y versus z projection into a TH2D histogram
2474 /// option = "zy" return the z versus y projection into a TH2D histogram
2475 /// option can also include the drawing option for the projection, eg to draw
2476 /// the xy projection using the draw option "box" do
2477 /// myhist.SetShowProjection("xy box");
2478 /// This function is typically called from the context menu.
2479 /// NB: the notation "a vs b" means "a" vertical and "b" horizontal
2480
2481 GetPainter();
2482 if(fPainter != nullptr) {
2483 fPainter->SetShowProjection(option, nbins);
2484 }
2485}
2486
2487TH1* GCube::ShowBackground(Int_t niter, Option_t* option)
2488{
2489 // This function calculates the background spectrum in this histogram.
2490 // The background is returned as a histogram.
2491 // to be implemented (may be)
2492
2493 return reinterpret_cast<TH1*>(gROOT->ProcessLineFast( // NOLINT(performance-no-int-to-ptr)
2494 Form(R"(TSpectrum2::StaticBackground((TH1*)0x%lx,%d,"%s"))", reinterpret_cast<ULong_t>(this), niter, option)));
2495}
2496
2497Int_t GCube::ShowPeaks(Double_t sigma, Option_t* option, Double_t threshold)
2498{
2499 // Interface to TSpectrum2::Search
2500 // the function finds peaks in this histogram where the width is > sigma
2501 // and the peak maximum greater than threshold*maximum bin content of this.
2502 // for more detauils see TSpectrum::Search.
2503 // note the difference in the default value for option compared to TSpectrum2::Search
2504 // option="" by default (instead of "goff")
2505
2506 return static_cast<Int_t>(gROOT->ProcessLineFast(
2507 Form(R"(TSpectrum2::StaticSearch((TH1*)0x%lx,%g,"%s",%g))", reinterpret_cast<ULong_t>(this), sigma, option, threshold)));
2508}
2509
2510void GCube::Smooth(Int_t ntimes, Option_t* option)
2511{
2512 // Smooth bin contents of this 2-d histogram using kernel algorithms
2513 // similar to the ones used in the raster graphics community.
2514 // Bin contents in the active range are replaced by their smooth values.
2515 // If Errors are defined via Sumw2, they are also scaled and computed.
2516 // However, note the resulting errors will be correlated between different-bins, so
2517 // the errors should not be used blindly to perform any calculation involving several bins,
2518 // like fitting the histogram. One would need to compute also the bin by bin correlation matrix.
2519 //
2520 // 3 kernels are proposed k5a, k5b and k3a.
2521 // k5a and k5b act on 5x5 cells (i-2,i-1,i,i+1,i+2, and same for j)
2522 // k5b is a bit more stronger in smoothing
2523 // k3a acts only on 3x3 cells (i-1,i,i+1, and same for j).
2524 // By default the kernel "k5a" is used. You can select the kernels "k5b" or "k3a"
2525 // via the option argument.
2526 // If TAxis::SetRange has been called on the x or/and y axis, only the bins
2527 // in the specified range are smoothed.
2528 // In the current implementation if the first argument is not used (default value=1).
2529 //
2530 // implementation by David McKee (dmckee@bama.ua.edu). Extended by Rene Brun
2531
2532 std::array<std::array<Double_t, 5>, 5> k5a = {{{0, 0, 1, 0, 0}, {0, 2, 2, 2, 0}, {1, 2, 5, 2, 1}, {0, 2, 2, 2, 0}, {0, 0, 1, 0, 0}}};
2533 std::array<std::array<Double_t, 5>, 5> k5b = {{{0, 1, 2, 1, 0}, {1, 2, 4, 2, 1}, {2, 4, 8, 4, 2}, {1, 2, 4, 2, 1}, {0, 1, 2, 1, 0}}};
2534 std::array<std::array<Double_t, 3>, 3> k3a = {{{0, 1, 0}, {1, 2, 1}, {0, 1, 0}}};
2535
2536 if(ntimes > 1) {
2537 Warning("Smooth", "Currently only ntimes=1 is supported");
2538 }
2539 TString opt = option;
2540 opt.ToLower();
2541 Int_t ksize_x = k5a.size();
2542 Int_t ksize_y = k5a.size();
2543 Double_t* kernel = k5a.data()->data();
2544 if(opt.Contains("k5b")) {
2545 kernel = k5b.data()->data();
2546 }
2547 if(opt.Contains("k3a")) {
2548 kernel = k3a.data()->data();
2549 ksize_x = k3a.size();
2550 ksize_y = k3a.size();
2551 }
2552
2553 // find i,j ranges
2554 Int_t ifirst = fXaxis.GetFirst();
2555 Int_t ilast = fXaxis.GetLast();
2556 Int_t jfirst = fYaxis.GetFirst();
2557 Int_t jlast = fYaxis.GetLast();
2558
2559 // Determine the size of the bin buffer(s) needed
2560 Double_t nentries = fEntries;
2561 Int_t nx = GetNbinsX();
2562 Int_t ny = GetNbinsY();
2563 Int_t bufSize = (nx + 2) * (ny + 2);
2564 auto* buf = new Double_t[bufSize];
2565 Double_t* ebuf = nullptr;
2566 if(fSumw2.fN != 0) {
2567 ebuf = new Double_t[bufSize];
2568 }
2569
2570 // Copy all the data to the temporary buffers
2571 for(Int_t i = ifirst; i <= ilast; ++i) {
2572 for(Int_t j = jfirst; j <= jlast; ++j) {
2573 Int_t bin = GetBin(i, j);
2574 buf[bin] = GetBinContent(bin);
2575 if(ebuf != nullptr) {
2576 ebuf[bin] = GetBinError(bin);
2577 }
2578 }
2579 }
2580
2581 // Kernel tail sizes (kernel sizes must be odd for this to work!)
2582 Int_t x_push = (ksize_x - 1) / 2;
2583 Int_t y_push = (ksize_y - 1) / 2;
2584
2585 // main work loop
2586 for(Int_t i = ifirst; i <= ilast; ++i) {
2587 for(Int_t j = jfirst; j <= jlast; ++j) {
2588 Double_t content = 0.0;
2589 Double_t error = 0.0;
2590 Double_t norm = 0.0;
2591
2592 for(Int_t n = 0; n < ksize_x; ++n) {
2593 for(Int_t m = 0; m < ksize_y; ++m) {
2594 Int_t xb = i + (n - x_push);
2595 Int_t yb = j + (m - y_push);
2596 if((xb >= 1) && (xb <= nx) && (yb >= 1) && (yb <= ny)) {
2597 Int_t bin = GetBin(xb, yb);
2598 Double_t k = kernel[n * ksize_y + m];
2599 if(k != 0.0) {
2600 norm += k;
2601 content += k * buf[bin];
2602 if(ebuf != nullptr) {
2603 error += k * k * ebuf[bin] * ebuf[bin];
2604 }
2605 }
2606 }
2607 }
2608 }
2609
2610 if(norm != 0.0) {
2611 SetBinContent(i, j, content / norm);
2612 if(ebuf != nullptr) {
2613 error /= (norm * norm);
2614 SetBinError(i, j, sqrt(error));
2615 }
2616 }
2617 }
2618 }
2619 fEntries = nentries;
2620
2621 delete[] buf;
2622 delete[] ebuf;
2623}
2624
2625//------------------------------------------------------------
2626// GCubeF methods (float = four bytes per cell)
2627//------------------------------------------------------------
2628
2630{
2631 SetBinsLength(9);
2632 if(fgDefaultSumw2) {
2633 Sumw2();
2634 }
2635}
2636
2637GCubeF::GCubeF(const char* name, const char* title, Int_t nbins, Double_t low, Double_t up)
2638 : GCube(name, title, nbins, low, up)
2639{
2640 TArrayF::Set(fNcells);
2641 if(fgDefaultSumw2) {
2642 Sumw2();
2643 }
2644
2645 if(low >= up) {
2646 SetBuffer(fgBufferSize);
2647 }
2648}
2649
2650GCubeF::GCubeF(const char* name, const char* title, Int_t nbins, const Double_t* bins) : GCube(name, title, nbins, bins)
2651{
2652 TArrayF::Set(fNcells);
2653 if(fgDefaultSumw2) {
2654 Sumw2();
2655 }
2656}
2657
2658GCubeF::GCubeF(const char* name, const char* title, Int_t nbins, const Float_t* bins) : GCube(name, title, nbins, bins)
2659{
2660 TArrayF::Set(fNcells);
2661 if(fgDefaultSumw2) {
2662 Sumw2();
2663 }
2664}
2665
2667 : GCube(rhs), TArrayF(rhs)
2668{
2669 rhs.Copy(*this);
2670}
2671
2672GCubeF::GCubeF(GCubeF&& rhs) noexcept
2673 : GCube(std::move(rhs)), TArrayF(rhs)
2674{
2675 rhs.Copy(*this);
2676}
2677
2678GCubeF::~GCubeF() = default;
2679
2680TH2F* GCubeF::GetMatrix(bool force)
2681{
2682 if(Matrix() != nullptr && !force) {
2683 return static_cast<TH2F*>(Matrix());
2684 }
2685 if(force) {
2686 delete Matrix();
2687 }
2688
2689 Matrix(new TH2F(Form("%s_mat", GetName()), GetTitle(), fXaxis.GetNbins(), fXaxis.GetXmin(), fXaxis.GetXmax(), fYaxis.GetNbins(), fYaxis.GetXmin(), fYaxis.GetXmax()));
2690 // copy cell contents (including all overflow and underflow cells)
2691 for(int i = 0; i < fXaxis.GetNbins() + 2; ++i) {
2692 for(int j = 0; j < fXaxis.GetNbins() + 2; ++j) {
2693 for(int k = 0; k < fXaxis.GetNbins() + 2; ++k) {
2694 Matrix()->SetBinContent(i, j, k, GetBinContent(i, j, k));
2695 }
2696 }
2697 }
2698 return static_cast<TH2F*>(Matrix());
2699}
2700
2701void GCubeF::Copy(TObject& rh) const
2702{
2703 GCube::Copy(static_cast<GCubeF&>(rh));
2704}
2705
2706TH1* GCubeF::DrawCopy(Option_t* option, const char* name_postfix) const
2707{
2708 // Draw copy.
2709
2710 TString opt = option;
2711 opt.ToLower();
2712 if(gPad != nullptr && !opt.Contains("same")) {
2713 gPad->Clear();
2714 }
2715 TString newName = (name_postfix) != nullptr ? TString::Format("%s%s", GetName(), name_postfix) : "";
2716 TH1* newth1 = static_cast<TH1*>(Clone(newName));
2717 newth1->SetDirectory(nullptr);
2718 newth1->SetBit(kCanDelete);
2719 newth1->AppendPad(option);
2720 return newth1;
2721}
2722
2723Double_t GCubeF::GetBinContent(Int_t bin) const
2724{
2725 // Get bin content.
2726
2727 if(fBuffer != nullptr) {
2728 const_cast<GCubeF*>(this)->BufferEmpty(); // NOLINT(cppcoreguidelines-pro-type-const-cast)
2729 }
2730 if(bin < 0) {
2731 bin = 0;
2732 }
2733 if(bin >= fNcells) {
2734 bin = fNcells - 1;
2735 }
2736 if(fArray == nullptr) {
2737 return 0;
2738 }
2739 return static_cast<Double_t>(fArray[bin]);
2740}
2741
2742void GCubeF::Reset(Option_t* option)
2743{
2744 //*-*-*-*-*-*-*-*Reset this histogram: contents, errors, etc*-*-*-*-*-*-*-*
2745 //*-* ===========================================
2746
2747 GCube::Reset(option);
2748 TArrayF::Reset();
2749}
2750
2751void GCubeF::SetBinContent(Int_t bin, Double_t content)
2752{
2753 // Set bin content
2754 fEntries++;
2755 fTsumw = 0;
2756 if(bin < 0) {
2757 return;
2758 }
2759 if(bin >= fNcells) {
2760 return;
2761 }
2762 fArray[bin] = static_cast<Float_t>(content);
2763}
2764
2766{
2767 // Set total number of bins including under/overflow
2768 // Reallocate bin contents array
2769
2770 if(n < 0) {
2771 n = (fXaxis.GetNbins() + 2) * (fYaxis.GetNbins() + 2);
2772 }
2773 fNcells = n;
2774 TArrayF::Set(n);
2775}
2776
2778{
2779 // Operator =
2780
2781 if(this != &h1) {
2782 h1.Copy(*this);
2783 }
2784 return *this;
2785}
2786
2788{
2789 // Operator =
2790
2791 if(this != &h1) {
2792 h1.Copy(*this);
2793 }
2794 return *this;
2795}
2796
2797GCubeF operator*(Float_t c1, GCubeF& h1)
2798{
2799 // Operator *
2800
2801 GCubeF hnew = h1;
2802 hnew.Scale(c1);
2803 hnew.SetDirectory(nullptr);
2804 return hnew;
2805}
2806
2808{
2809 // Operator +
2810
2811 GCubeF hnew = h1;
2812 hnew.Add(&h2, 1);
2813 hnew.SetDirectory(nullptr);
2814 return hnew;
2815}
2816
2818{
2819 // Operator -
2820
2821 GCubeF hnew = h1;
2822 hnew.Add(&h2, -1);
2823 hnew.SetDirectory(nullptr);
2824 return hnew;
2825}
2826
2828{
2829 // Operator *
2830
2831 GCubeF hnew = h1;
2832 hnew.Multiply(&h2);
2833 hnew.SetDirectory(nullptr);
2834 return hnew;
2835}
2836
2838{
2839 // Operator /
2840
2841 GCubeF hnew = h1;
2842 hnew.Divide(&h2);
2843 hnew.SetDirectory(nullptr);
2844 return hnew;
2845}
2846
2847//------------------------------------------------------------
2848// GCubeD methods (double = eight bytes per cell)
2849//------------------------------------------------------------
2850
2852{
2853 SetBinsLength(9);
2854 if(fgDefaultSumw2) {
2855 Sumw2();
2856 }
2857}
2858
2859GCubeD::GCubeD(const char* name, const char* title, Int_t nbins, Double_t low, Double_t up)
2860 : GCube(name, title, nbins, low, up)
2861{
2862 TArrayD::Set(fNcells);
2863 if(fgDefaultSumw2) {
2864 Sumw2();
2865 }
2866
2867 if(low >= up) {
2868 SetBuffer(fgBufferSize);
2869 }
2870}
2871
2872GCubeD::GCubeD(const char* name, const char* title, Int_t nbins, const Double_t* bins) : GCube(name, title, nbins, bins)
2873{
2874 TArrayD::Set(fNcells);
2875 if(fgDefaultSumw2) {
2876 Sumw2();
2877 }
2878}
2879
2880GCubeD::GCubeD(const char* name, const char* title, Int_t nbins, const Float_t* bins) : GCube(name, title, nbins, bins)
2881{
2882 TArrayD::Set(fNcells);
2883 if(fgDefaultSumw2) {
2884 Sumw2();
2885 }
2886}
2887
2889 : GCube(rhs), TArrayD(rhs)
2890{
2891 rhs.Copy(*this);
2892}
2893
2894GCubeD::GCubeD(GCubeD&& rhs) noexcept
2895 : GCube(std::move(rhs)), TArrayD(rhs)
2896{
2897 rhs.Copy(*this);
2898}
2899
2900GCubeD::~GCubeD() = default;
2901
2902TH2D* GCubeD::GetMatrix(bool force)
2903{
2904 if(Matrix() != nullptr && !force) {
2905 return static_cast<TH2D*>(Matrix());
2906 }
2907 if(force) {
2908 delete Matrix();
2909 }
2910
2911 Matrix(new TH2D(Form("%s_mat", GetName()), Form("%s;%s;%s", GetTitle(), fXaxis.GetTitle(), fYaxis.GetTitle()),
2912 fXaxis.GetNbins(), fXaxis.GetXmin(), fXaxis.GetXmax(), fYaxis.GetNbins(), fYaxis.GetXmin(),
2913 fYaxis.GetXmax()));
2914 // copy cell contents (including all overflow and underflow cells)
2915 for(int i = 0; i < fXaxis.GetNbins() + 2; ++i) {
2916 for(int j = 0; j < fXaxis.GetNbins() + 2; ++j) {
2917 for(int k = 0; k < fXaxis.GetNbins() + 2; ++k) {
2918 Matrix()->SetBinContent(i, j, k, GetBinContent(i, j, k));
2919 }
2920 }
2921 }
2922 return static_cast<TH2D*>(Matrix());
2923}
2924
2925void GCubeD::Copy(TObject& rh) const
2926{
2927 GCube::Copy(static_cast<GCubeD&>(rh));
2928}
2929
2930TH1* GCubeD::DrawCopy(Option_t* option, const char* name_postfix) const
2931{
2932 // Draw copy.
2933
2934 TString opt = option;
2935 opt.ToLower();
2936 if(gPad != nullptr && !opt.Contains("same")) {
2937 gPad->Clear();
2938 }
2939 TString newName = (name_postfix) != nullptr ? TString::Format("%s%s", GetName(), name_postfix) : "";
2940 TH1* newth1 = static_cast<TH1*>(Clone(newName));
2941 newth1->SetDirectory(nullptr);
2942 newth1->SetBit(kCanDelete);
2943 newth1->AppendPad(option);
2944 return newth1;
2945}
2946
2947Double_t GCubeD::GetBinContent(Int_t bin) const
2948{
2949 // Get bin content.
2950 if(fBuffer != nullptr) {
2951 const_cast<GCubeD*>(this)->BufferEmpty(); // NOLINT(cppcoreguidelines-pro-type-const-cast)
2952 }
2953 if(bin < 0) {
2954 bin = 0;
2955 }
2956 if(bin >= fNcells) {
2957 bin = fNcells - 1;
2958 }
2959 if(fArray == nullptr) {
2960 return 0;
2961 }
2962 return static_cast<Double_t>(fArray[bin]);
2963}
2964
2965void GCubeD::Reset(Option_t* option)
2966{
2967 //*-*-*-*-*-*-*-*Reset this histogram: contents, errors, etc*-*-*-*-*-*-*-*
2968 //*-* ===========================================
2969
2970 GCube::Reset(option);
2971 TArrayD::Reset();
2972}
2973
2974void GCubeD::SetBinContent(Int_t bin, Double_t content)
2975{
2976 // Set bin content
2977 fEntries++;
2978 fTsumw = 0;
2979 if(bin < 0) {
2980 return;
2981 }
2982 if(bin >= fNcells) {
2983 return;
2984 }
2985 fArray[bin] = static_cast<Float_t>(content);
2986}
2987
2989{
2990 // Set total number of bins including under/overflow
2991 // Reallocate bin contents array
2992
2993 if(n < 0) {
2994 n = (fXaxis.GetNbins() + 2) * (fYaxis.GetNbins() + 2);
2995 }
2996 fNcells = n;
2997 TArrayD::Set(n);
2998}
2999
3001{
3002 // Operator =
3003
3004 if(this != &h1) {
3005 h1.Copy(*this);
3006 }
3007 return *this;
3008}
3009
3011{
3012 // Operator =
3013
3014 if(this != &h1) {
3015 h1.Copy(*this);
3016 }
3017 return *this;
3018}
3019
3020GCubeD operator*(Float_t c1, GCubeD& h1)
3021{
3022 // Operator *
3023
3024 GCubeD hnew = h1;
3025 hnew.Scale(c1);
3026 hnew.SetDirectory(nullptr);
3027 return hnew;
3028}
3029
3031{
3032 // Operator +
3033
3034 GCubeD hnew = h1;
3035 hnew.Add(&h2, 1);
3036 hnew.SetDirectory(nullptr);
3037 return hnew;
3038}
3039
3041{
3042 // Operator -
3043
3044 GCubeD hnew = h1;
3045 hnew.Add(&h2, -1);
3046 hnew.SetDirectory(nullptr);
3047 return hnew;
3048}
3049
3051{
3052 // Operator *
3053
3054 GCubeD hnew = h1;
3055 hnew.Multiply(&h2);
3056 hnew.SetDirectory(nullptr);
3057 return hnew;
3058}
3059
3061{
3062 // Operator /
3063
3064 GCubeD hnew = h1;
3065 hnew.Divide(&h2);
3066 hnew.SetDirectory(nullptr);
3067 return hnew;
3068}
3069
3070//------------------------------------------------------------
GCubeF operator-(GCubeF &h1, GCubeF &h2)
Definition GCube.cxx:2817
GCubeF operator/(GCubeF &h1, GCubeF &h2)
Definition GCube.cxx:2837
GCubeF operator+(GCubeF &h1, GCubeF &h2)
Definition GCube.cxx:2807
GCubeF operator*(Float_t c1, GCubeF &h1)
Definition GCube.cxx:2797
TH1 * DrawCopy(Option_t *option="", const char *name_postfix="_copy") const override
Definition GCube.cxx:2930
void Reset(Option_t *option="") override
Definition GCube.cxx:2965
void SetBinsLength(Int_t n=-1) override
Definition GCube.cxx:2988
GCubeD()
Definition GCube.cxx:2851
GCubeD & operator=(const GCubeD &h1)
Definition GCube.cxx:3000
TH2D * GetMatrix(bool force=false)
Definition GCube.cxx:2902
void Copy(TObject &rh) const override
Definition GCube.cxx:2925
void SetBinContent(Int_t bin, Double_t content) override
Definition GCube.cxx:2974
Double_t GetBinContent(Int_t bin) const override
Definition GCube.cxx:2947
GCubeF & operator=(const GCubeF &h1)
Definition GCube.cxx:2777
void Reset(Option_t *option="") override
Definition GCube.cxx:2742
GCubeF()
Definition GCube.cxx:2629
TH1 * DrawCopy(Option_t *option="", const char *name_postfix="_copy") const override
Definition GCube.cxx:2706
void SetBinsLength(Int_t n=-1) override
Definition GCube.cxx:2765
TH2F * GetMatrix(bool force=false)
Definition GCube.cxx:2680
Double_t GetBinContent(Int_t bin) const override
Definition GCube.cxx:2723
void Copy(TObject &rh) const override
Definition GCube.cxx:2701
void SetBinContent(Int_t bin, Double_t content) override
Definition GCube.cxx:2751
Definition GCube.h:13
TH2 * fMatrix
! Transient pointer to the 2D-Matrix used in Draw() or GetMatrix()
Definition GCube.h:117
Int_t Fill(Double_t) override
Definition GCube.cxx:309
virtual Double_t GetCovariance(Int_t axis1=1, Int_t axis2=2) const
Definition GCube.cxx:1042
Double_t fTsumwxz
Definition GCube.h:115
Double_t fTsumwz
Definition GCube.h:113
virtual GCube * Rebin3D(Int_t ngroup=2, const char *newname="")
Definition GCube.cxx:2097
Int_t ShowPeaks(Double_t sigma=2, Option_t *option="", Double_t threshold=0.05) override
Definition GCube.cxx:2497
TH2 * Matrix()
Definition GCube.h:107
virtual void FitSlicesZ(TF1 *f1=nullptr, Int_t binminx=0, Int_t binmaxx=-1, Int_t binminy=0, Int_t binmaxy=-1, Int_t cut=0, Option_t *option="QNR")
Definition GCube.cxx:812
Double_t fTsumwy2
Definition GCube.h:111
void FillRandom(const char *fname, Int_t ntimes=5000, TRandom *rng=nullptr) override
Definition GCube.cxx:558
void Smooth(Int_t ntimes=1, Option_t *option="") override
Definition GCube.cxx:2510
Double_t Interpolate(Double_t) const override
Definition GCube.cxx:1286
virtual Double_t IntegralAndError(Int_t firstxbin, Int_t lastxbin, Int_t firstybin, Int_t lastybin, Int_t firstzbin, Int_t lastzbin, Double_t &error, Option_t *option="") const
Definition GCube.cxx:1270
Int_t GetBin(Int_t binx, Int_t biny=0, Int_t binz=0) const override
Definition GCube.cxx:909
virtual void SetShowProjection(const char *option="xy", Int_t nbins=1)
Definition GCube.cxx:2459
GCube()=default
Double_t fTsumwy
Definition GCube.h:110
virtual void GetRandom3(Double_t &x, Double_t &y, Double_t &z)
Definition GCube.cxx:1089
TH1 * ShowBackground(Int_t niter=20, Option_t *option="same") override
Definition GCube.cxx:2487
Int_t FindLastBinAbove(Double_t threshold=0, Int_t axis=1, Int_t firstBin=1, Int_t lastBin=-1) const override
Definition GCube.cxx:731
void PutStats(Double_t *stats) override
Definition GCube.cxx:2084
Double_t Integral(Option_t *option="") const override
Definition GCube.cxx:1247
virtual Double_t GetCorrelationFactor(Int_t axis1=1, Int_t axis2=2) const
Definition GCube.cxx:1020
void GetStats(Double_t *stats) const override
Definition GCube.cxx:1138
void Reset(Option_t *option="") override
Definition GCube.cxx:2435
Int_t BufferEmpty(Int_t action=0) override
Definition GCube.cxx:70
virtual TH1D * Projection(const char *name="_pr", Int_t firstBiny=0, Int_t lastBiny=-1, Int_t firstBinz=0, Int_t lastBinz=-1, Option_t *option="") const
Definition GCube.cxx:1832
Double_t DoIntegral(Int_t binx1, Int_t binx2, Int_t biny1, Int_t biny2, Int_t binz1, Int_t binz2, Double_t &error, Option_t *option, Bool_t doError=kFALSE) const override
Definition GCube.cxx:223
Long64_t Merge(TCollection *list) override
Definition GCube.cxx:1581
Double_t KolmogorovTest(const TH1 *h2, Option_t *option="") const override
Definition GCube.cxx:1369
Double_t fTsumwz2
Definition GCube.h:114
Int_t FindFirstBinAbove(Double_t threshold=0, Int_t axis=1, Int_t firstBin=1, Int_t lastBin=-1) const override
Definition GCube.cxx:682
Int_t BufferFill(Double_t, Double_t) override
Definition GCube.h:27
Double_t fTsumwyz
Definition GCube.h:116
void Copy(TObject &obj) const override
Definition GCube.cxx:212
Double_t fTsumwxy
Definition GCube.h:112
virtual Double_t GetBinWithContent2(Double_t c, Int_t &binx, Int_t &biny, Int_t &binz, Int_t firstxbin=1, Int_t lastxbin=-1, Int_t firstybin=1, Int_t lastybin=-1, Int_t firstzbin=1, Int_t lastzbin=-1, Double_t maxdiff=0) const
Definition GCube.cxx:946