ATLAS Offline Software
Loading...
Searching...
No Matches
JetToolHelpers/Root/RootHelpers.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "TH1.h"
8#include "TMath.h"
9
10namespace RootHelpers
11{
12
13 double Interpolate2D(const TH1* histo, const double x, const double y, const int xAxis, const int yAxis, const int otherDimBin)
14 {
15 // Copied from ROOT directly and trivially modified, all credit to ROOT authors of TH1, TH2, and TH3 Interpolate methods
16 // Function was implemented to handle edge cases in the 3D interpolation by using 2D interpolation with the third dimension fixed
17
18 // Determine the two axes to be used for the interpolation
19 const TAxis* fXaxis = xAxis == 1 ? histo->GetXaxis() : xAxis == 2 ? histo->GetYaxis() : xAxis == 3 ? histo->GetZaxis() : nullptr;
20 const TAxis* fYaxis = yAxis == 1 ? histo->GetXaxis() : yAxis == 2 ? histo->GetYaxis() : yAxis == 3 ? histo->GetZaxis() : nullptr;
21
22 if (!fXaxis || !fYaxis)
23 {
24 histo->Error("Interpolate2D","Failed to parse axes from inputs");
25 return 0;
26 }
27
28 // =========================================================
29 // The code below is a copy of the TH2::Interpolate function
30 // =========================================================
31 Double_t f=0;
32 Double_t x1=0,x2=0,y1=0,y2=0;
33 Double_t dx,dy;
34 Int_t bin_x = fXaxis->FindFixBin(x);
35 Int_t bin_y = fYaxis->FindFixBin(y);
36 if(bin_x<1 || bin_x>fXaxis->GetNbins() || bin_y<1 || bin_y>fYaxis->GetNbins()) {
37 histo->Error("Interpolate","Cannot interpolate outside histogram domain. (x: %f vs [%f,%f], y: %f vs [%f,%f])",x,fXaxis->GetBinLowEdge(1),fXaxis->GetBinLowEdge(fXaxis->GetNbins()+1),y,fYaxis->GetBinLowEdge(1),fYaxis->GetBinLowEdge(fYaxis->GetNbins()+1));
38 return 0;
39 }
40 Int_t quadrant = 0; // CCW from UR 1,2,3,4
41 // which quadrant of the bin (bin_P) are we in?
42 dx = fXaxis->GetBinUpEdge(bin_x)-x;
43 dy = fYaxis->GetBinUpEdge(bin_y)-y;
44 if (dx<=fXaxis->GetBinWidth(bin_x)/2 && dy<=fYaxis->GetBinWidth(bin_y)/2)
45 quadrant = 1; // upper right
46 if (dx>fXaxis->GetBinWidth(bin_x)/2 && dy<=fYaxis->GetBinWidth(bin_y)/2)
47 quadrant = 2; // upper left
48 if (dx>fXaxis->GetBinWidth(bin_x)/2 && dy>fYaxis->GetBinWidth(bin_y)/2)
49 quadrant = 3; // lower left
50 if (dx<=fXaxis->GetBinWidth(bin_x)/2 && dy>fYaxis->GetBinWidth(bin_y)/2)
51 quadrant = 4; // lower right
52 switch(quadrant) {
53 case 1:
54 x1 = fXaxis->GetBinCenter(bin_x);
55 y1 = fYaxis->GetBinCenter(bin_y);
56 x2 = fXaxis->GetBinCenter(bin_x+1);
57 y2 = fYaxis->GetBinCenter(bin_y+1);
58 break;
59 case 2:
60 x1 = fXaxis->GetBinCenter(bin_x-1);
61 y1 = fYaxis->GetBinCenter(bin_y);
62 x2 = fXaxis->GetBinCenter(bin_x);
63 y2 = fYaxis->GetBinCenter(bin_y+1);
64 break;
65 case 3:
66 x1 = fXaxis->GetBinCenter(bin_x-1);
67 y1 = fYaxis->GetBinCenter(bin_y-1);
68 x2 = fXaxis->GetBinCenter(bin_x);
69 y2 = fYaxis->GetBinCenter(bin_y);
70 break;
71 case 4:
72 x1 = fXaxis->GetBinCenter(bin_x);
73 y1 = fYaxis->GetBinCenter(bin_y-1);
74 x2 = fXaxis->GetBinCenter(bin_x+1);
75 y2 = fYaxis->GetBinCenter(bin_y);
76 break;
77 }
78 Int_t bin_x1 = fXaxis->FindFixBin(x1);
79 if(bin_x1<1) bin_x1=1;
80 Int_t bin_x2 = fXaxis->FindFixBin(x2);
81 if(bin_x2>fXaxis->GetNbins()) bin_x2=fXaxis->GetNbins();
82 Int_t bin_y1 = fYaxis->FindFixBin(y1);
83 if(bin_y1<1) bin_y1=1;
84 Int_t bin_y2 = fYaxis->FindFixBin(y2);
85 if(bin_y2>fYaxis->GetNbins()) bin_y2=fYaxis->GetNbins();
86
87 Double_t q11;
88 Double_t q12;
89 Double_t q21;
90 Double_t q22;
91
92 // ===========================================================================
93 // The code to find q11, q12, q21 and q22 was adjusted w.r.t. TH2::Interpolate
94 // to account for using 3D histograms with one fixed dimension
95 // ===========================================================================
96
97 // X,Y variable and Z fixed
98 if (xAxis == 1 && yAxis == 2){
99 q11 = histo->GetBinContent(histo->GetBin(bin_x1,bin_y1,otherDimBin));
100 q12 = histo->GetBinContent(histo->GetBin(bin_x1,bin_y2,otherDimBin));
101 q21 = histo->GetBinContent(histo->GetBin(bin_x2,bin_y1,otherDimBin));
102 q22 = histo->GetBinContent(histo->GetBin(bin_x2,bin_y2,otherDimBin));
103 }
104 // X,Z variable and Y fixed
105 else if (xAxis == 1 && yAxis == 3){
106 q11 = histo->GetBinContent(histo->GetBin(bin_x1,otherDimBin,bin_y1));
107 q12 = histo->GetBinContent(histo->GetBin(bin_x1,otherDimBin,bin_y2));
108 q21 = histo->GetBinContent(histo->GetBin(bin_x2,otherDimBin,bin_y1));
109 q22 = histo->GetBinContent(histo->GetBin(bin_x2,otherDimBin,bin_y2));
110 }
111 // Y,Z variable and X fixed
112 else if (xAxis == 2 && yAxis == 3){
113 q11 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_x1,bin_y1));
114 q12 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_x1,bin_y2));
115 q21 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_x2,bin_y1));
116 q22 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_x2,bin_y2));
117 }
118 // Y,X variable and Z fixed
119 else if (xAxis == 2 && yAxis == 1){
120 q11 = histo->GetBinContent(histo->GetBin(bin_y1,bin_x1,otherDimBin));
121 q12 = histo->GetBinContent(histo->GetBin(bin_y1,bin_x2,otherDimBin));
122 q21 = histo->GetBinContent(histo->GetBin(bin_y2,bin_x1,otherDimBin));
123 q22 = histo->GetBinContent(histo->GetBin(bin_y2,bin_x2,otherDimBin));
124 }
125 // Z,X variable and Y fixed
126 else if (xAxis == 3 && yAxis == 1){
127 q11 = histo->GetBinContent(histo->GetBin(bin_y1,otherDimBin,bin_x1));
128 q12 = histo->GetBinContent(histo->GetBin(bin_y1,otherDimBin,bin_x2));
129 q21 = histo->GetBinContent(histo->GetBin(bin_y2,otherDimBin,bin_x1));
130 q22 = histo->GetBinContent(histo->GetBin(bin_y2,otherDimBin,bin_x2));
131 }
132 // Z,Y variable and X fixed
133 else if (xAxis == 3 && yAxis == 2){
134 q11 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_y1,bin_x1));
135 q12 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_y1,bin_x2));
136 q21 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_y2,bin_x1));
137 q22 = histo->GetBinContent(histo->GetBin(otherDimBin,bin_y2,bin_x2));
138 }
139 else{
140 histo->Error("Interpolate2D","Unsupported axis combination: (x,y)=(%d,%d) with one bin fixed",xAxis,yAxis);
141 return 0;
142 }
143
144 Double_t d = 1.0*(x2-x1)*(y2-y1);
145 f = 1.0*q11/d*(x2-x)*(y2-y)+1.0*q21/d*(x-x1)*(y2-y)+1.0*q12/d*(x2-x)*(y-y1)+1.0*q22/d*(x-x1)*(y-y1);
146 return f;
147 }
148
149 double Interpolate(const TH1* histo, const double x, const double y, const double z)
150 {
151
152 // =======================================================================================
153 // The ROOT Interpolate function throws an error when the provided value is:
154 // - below the bin center of the first bin on a given axis
155 // - above the bin center of the last bin on a given axis
156 // We want to support these edge cases in our calibrations
157 // =======================================================================================
158 // If no edge cases are identified, we use TH3::Interpolate() from ROOT
159 // If an edge case is found, we use 2D interpolation with the third dimension fixed:
160 // - Edge cases were previously tried with weights set including the under/overflow bins
161 // (to follow what TH2::Interpolate() does for boundaries)
162 // - In some cases, it performed quite poorly
163 // =======================================================================================
164
165 const TAxis* fXaxis = histo->GetXaxis();
166 const TAxis* fYaxis = histo->GetYaxis();
167 const TAxis* fZaxis = histo->GetZaxis();
168
169 // Find the bin by bin edges
170 Int_t ubx = fXaxis->FindFixBin(x);
171 Int_t uby = fYaxis->FindFixBin(y);
172 Int_t ubz = fZaxis->FindFixBin(z);
173
174 // Check if the value(s) are outside of the bin range(s)
175 if ( ubx < 1 || ubx > histo->GetNbinsX() || uby < 1 || uby > histo->GetNbinsY() || ubz < 1 || ubz > histo->GetNbinsZ() )
176 {
177 histo->Error("Interpolate","Cannot interpolate outside histogram domain. (x: %f vs [%f,%f], y: %f vs [%f,%f], z: %f vs [%f,%f])",x,fXaxis->GetBinLowEdge(1),fXaxis->GetBinLowEdge(histo->GetNbinsX()+1),y,fYaxis->GetBinLowEdge(1),fYaxis->GetBinLowEdge(histo->GetNbinsY()+1),z,fZaxis->GetBinLowEdge(1),fZaxis->GetBinLowEdge(histo->GetNbinsZ()+1));
178 return 0;
179 }
180
181 // Check for edge cases:
182 if( (ubx == 1 && x < fXaxis->GetBinCenter(ubx)) || (ubx == fXaxis->GetNbins() && x > fXaxis->GetBinCenter(ubx)))
183 return RootHelpers::Interpolate2D(histo,y,z,2,3,ubx);
184 else if( (uby == 1 && y < fYaxis->GetBinCenter(uby)) || (uby == fYaxis->GetNbins() && y > fYaxis->GetBinCenter(uby)))
185 return RootHelpers::Interpolate2D(histo,x,z,1,3,uby);
186 else if( (ubz == 1 && z < fZaxis->GetBinCenter(ubz)) || (ubz == fZaxis->GetNbins() && z > fZaxis->GetBinCenter(ubz)))
187 return RootHelpers::Interpolate2D(histo,x,y,1,2,ubz);
188
189 // If no edge cases identified, use ROOT TH3::Interpolate function
190 return histo->Interpolate(x,y,z);
191 }
192
193} // end RootHelpers namespace
#define y
#define x
#define z
double Interpolate(const TH1 *histo, const double x)
double Interpolate2D(const TH1 *histo, const double x, const double y, const int xAxis, const int yAxis, const int otherDimBin)
Helper function for edge cases in 3D interpolation by interpolating in 2D and keeping the third axis ...