|
3 | 3 | #include "TProfile.h" // ProjectionX |
4 | 4 | #include "TProfile2D.h" // ProjectionX |
5 | 5 | #include "THashList.h" // GetLabels |
| 6 | +#include <limits> |
| 7 | +#include "TMath.h" |
6 | 8 |
|
7 | 9 | #include "gtest/gtest.h" |
8 | 10 |
|
@@ -85,3 +87,243 @@ TEST(Projections, Issue_6658_Profile2D) |
85 | 87 | EXPECT_EQ(xaxis_2d_nbins, xaxis_pxy_nbins); |
86 | 88 | expect_list_eq_names(*labels_2d, *labels_pxy); |
87 | 89 | } |
| 90 | + |
| 91 | +// Test projection from TH3D for correct output on user range on projected axis |
| 92 | +TEST(Projections, RangesAndOptionO) |
| 93 | +{ |
| 94 | + TH3D h("h", "h", 3, 0., 3., 3, 0., 3., 3, 0., 3.); |
| 95 | + |
| 96 | + for (int ix = 1; ix <= 3; ++ix) { |
| 97 | + for (int iy = 1; iy <= 3; ++iy) { |
| 98 | + for (int iz = 1; iz <= 3; ++iz) { |
| 99 | + auto bin = h.GetBin(ix, iy, iz); |
| 100 | + h.SetBinContent(bin, 100 * ix + 10 * iy + iz); |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + h.GetXaxis()->SetRange(2, 3); |
| 106 | + auto expectedForX = [](int ix) { |
| 107 | + double s = 0.; |
| 108 | + for (int iy = 1; iy <= 3; ++iy) |
| 109 | + for (int iz = 1; iz <= 3; ++iz) |
| 110 | + s += 100 * ix + 10 * iy + iz; |
| 111 | + return s; |
| 112 | + }; |
| 113 | + auto x2 = expectedForX(2); |
| 114 | + auto x3 = expectedForX(3); |
| 115 | + |
| 116 | + { |
| 117 | + auto px = h.Project3D("x"); |
| 118 | + EXPECT_EQ(px->GetNbinsX(), 2); // selected length |
| 119 | + EXPECT_DOUBLE_EQ(px->GetBinContent(1), x2); |
| 120 | + EXPECT_DOUBLE_EQ(px->GetBinContent(2), x3); |
| 121 | + } |
| 122 | + |
| 123 | + { |
| 124 | + auto pxo = h.Project3D("xo"); |
| 125 | + ASSERT_NE(pxo, nullptr); |
| 126 | + EXPECT_EQ(pxo->GetNbinsX(), 3); // original length |
| 127 | + EXPECT_DOUBLE_EQ(pxo->GetBinContent(1), 0.0); // outside selection |
| 128 | + EXPECT_DOUBLE_EQ(pxo->GetBinContent(2), x2); |
| 129 | + EXPECT_DOUBLE_EQ(pxo->GetBinContent(3), x3); |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +// Test projection from TH3D for correct output on user range on integrated axis |
| 134 | +TEST(Projections, SelectionAcrossNonTargetAxis) |
| 135 | +{ |
| 136 | + TH3D h("h", "h", 3, 0., 3., 3, 0., 3., 3, 0., 3.); |
| 137 | + |
| 138 | + for (int ix = 1; ix <= 3; ++ix) { |
| 139 | + for (int iy = 1; iy <= 3; ++iy) { |
| 140 | + for (int iz = 1; iz <= 3; ++iz) { |
| 141 | + auto bin = h.GetBin(ix, iy, iz); |
| 142 | + h.SetBinContent(bin, 100 * ix + 10 * iy + iz); |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + h.GetYaxis()->SetRange(2, 3); |
| 148 | + |
| 149 | + auto px = h.Project3D("x"); |
| 150 | + |
| 151 | + auto expectedForX = [](int ix) { |
| 152 | + double s = 0.; |
| 153 | + for (int iy = 2; iy <= 3; ++iy) |
| 154 | + for (int iz = 1; iz <= 3; ++iz) |
| 155 | + s += 100 * ix + 10 * iy + iz; |
| 156 | + return s; |
| 157 | + }; |
| 158 | + |
| 159 | + EXPECT_DOUBLE_EQ(px->GetBinContent(1), expectedForX(1)); |
| 160 | + EXPECT_DOUBLE_EQ(px->GetBinContent(2), expectedForX(2)); |
| 161 | + EXPECT_DOUBLE_EQ(px->GetBinContent(3), expectedForX(3)); |
| 162 | +} |
| 163 | + |
| 164 | +// Test TH2D projection for correctness for user ranges on both axes |
| 165 | +TEST(Projections, ProjectionYRange) |
| 166 | +{ |
| 167 | + Double_t xedges[] = {0, 1, 2}; |
| 168 | + Double_t yedges[] = {-2, -1, 0, 1, 2}; |
| 169 | + TH2D h("h", "h;X;Y", 2, xedges, 4, yedges); |
| 170 | + |
| 171 | + for (int ix = 1; ix <= 3; ++ix) { |
| 172 | + for (int iy = 1; iy <= 4; ++iy) { |
| 173 | + auto bin = h.GetBin(ix, iy); |
| 174 | + h.SetBinContent(bin, 10 * ix + iy); |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + h.GetXaxis()->SetRange(1, 2); |
| 179 | + h.GetYaxis()->SetRange(2, 4); |
| 180 | + |
| 181 | + auto py = h.ProjectionY(); |
| 182 | + |
| 183 | + auto expectedForY = [](int iy) { |
| 184 | + double s = 0.; |
| 185 | + for (int ix = 1; ix <= 2; ++ix) |
| 186 | + s += 10 * ix + iy; |
| 187 | + return s; |
| 188 | + }; |
| 189 | + |
| 190 | + EXPECT_DOUBLE_EQ(py->GetBinContent(0), 0.0); |
| 191 | + EXPECT_DOUBLE_EQ(py->GetBinContent(1), expectedForY(2)); |
| 192 | + EXPECT_DOUBLE_EQ(py->GetBinContent(2), expectedForY(3)); |
| 193 | + EXPECT_DOUBLE_EQ(py->GetBinContent(3), expectedForY(4)); |
| 194 | + EXPECT_DOUBLE_EQ(py->GetBinContent(4), 0.0); |
| 195 | +} |
| 196 | +// Test TH2D projection for correct flow inclusion for default options |
| 197 | +TEST(Projections, UFOF) |
| 198 | +{ |
| 199 | + TH2D h2("h2", "", 3, 0, 3, 4, 0, 4); |
| 200 | + h2.Sumw2(); |
| 201 | + for (int bx = 0; bx <= 4; ++bx) { |
| 202 | + for (int by = 0; by <= 5; ++by) { |
| 203 | + h2.SetBinContent(bx, by, 10 * bx + by); |
| 204 | + h2.SetBinError(bx, by, 1.0); |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + auto hpx = h2.ProjectionX(); |
| 209 | + for (int bx = 0; bx <= 4; ++bx) { |
| 210 | + const double exp = 60 * bx + 15; |
| 211 | + double got = hpx->GetBinContent(bx); |
| 212 | + EXPECT_DOUBLE_EQ(got, exp); |
| 213 | + double e = hpx->GetBinError(bx); |
| 214 | + EXPECT_DOUBLE_EQ(e, TMath::Sqrt(6.0)); |
| 215 | + } |
| 216 | +} |
| 217 | +// Test TH2D projection for correct flow exclusion for specified user range |
| 218 | +TEST(Projections, UFOFWithRange) |
| 219 | +{ |
| 220 | + TH2D h2("h2", "", 5, 0, 5, 4, 0, 4); |
| 221 | + h2.Sumw2(); |
| 222 | + for (int bx = 0; bx <= 6; ++bx) |
| 223 | + for (int by = 0; by <= 5; ++by) { |
| 224 | + h2.SetBinContent(bx, by, 100 * bx + by); |
| 225 | + h2.SetBinError(bx, by, 2.0); |
| 226 | + } |
| 227 | + |
| 228 | + h2.GetXaxis()->SetRange(2, 4); |
| 229 | + |
| 230 | + auto hpx = h2.ProjectionX("hpx_ranged", 1, 4, ""); |
| 231 | + EXPECT_EQ(hpx->GetXaxis()->GetNbins(), 3); |
| 232 | + for (int i = 0; i < 3; ++i) { |
| 233 | + int outbin = 2 + i; |
| 234 | + double exp = 0; |
| 235 | + for (int by = 1; by <= 4; ++by) |
| 236 | + exp += 100 * outbin + by; |
| 237 | + double got = hpx->GetBinContent(i + 1); |
| 238 | + EXPECT_DOUBLE_EQ(got, exp); |
| 239 | + EXPECT_DOUBLE_EQ(hpx->GetBinError(i + 1), 4.0); |
| 240 | + } |
| 241 | + EXPECT_DOUBLE_EQ(hpx->GetBinContent(0), 0); |
| 242 | + EXPECT_DOUBLE_EQ(hpx->GetBinContent(4), 0); |
| 243 | +} |
| 244 | + |
| 245 | +// Test TH2D projection correctness with option "o" |
| 246 | +TEST(Projections, OriginalRange) |
| 247 | +{ |
| 248 | + TH2D h2("h2", "", 6, 0, 6, 3, 0, 3); |
| 249 | + for (int bx = 0; bx <= 7; ++bx) |
| 250 | + for (int by = 0; by <= 4; ++by) |
| 251 | + h2.SetBinContent(bx, by, bx + 10 * by); |
| 252 | + |
| 253 | + h2.GetXaxis()->SetRange(2, 5); |
| 254 | + |
| 255 | + auto hpx = h2.ProjectionX("h_o", 1, 3, "o"); |
| 256 | + EXPECT_EQ(hpx->GetXaxis()->GetNbins(), 6); |
| 257 | + for (int bx = 1; bx <= 6; ++bx) { |
| 258 | + double got = hpx->GetBinContent(bx); |
| 259 | + if (bx < 2 || bx > 5) { |
| 260 | + EXPECT_EQ(got, 0.0); |
| 261 | + continue; |
| 262 | + } |
| 263 | + double exp = 0; |
| 264 | + for (int by = 1; by <= 3; ++by) |
| 265 | + exp += bx + 10 * by; |
| 266 | + EXPECT_DOUBLE_EQ(got, exp); |
| 267 | + } |
| 268 | +} |
| 269 | + |
| 270 | +// Test TH2D projection with variable bins and user range along projected axis |
| 271 | +TEST(Projections, VarBinsRange) |
| 272 | +{ |
| 273 | + double edgesX[] = {0, 0.5, 1.5, 3.0, 5.0}; |
| 274 | + TH2D h("h", "", 4, edgesX, 2, 0, 2); |
| 275 | + |
| 276 | + for (int bx = 0; bx <= 5; ++bx) |
| 277 | + for (int by = 0; by <= 3; ++by) |
| 278 | + h.SetBinContent(bx, by, 100 * bx + by); |
| 279 | + |
| 280 | + h.GetXaxis()->SetRange(2, 3); |
| 281 | + |
| 282 | + auto hpx = h.ProjectionX("hpx_var", 1, 2, ""); |
| 283 | + EXPECT_EQ(hpx->GetXaxis()->GetNbins(), 2); |
| 284 | + EXPECT_DOUBLE_EQ(hpx->GetXaxis()->GetBinLowEdge(1), edgesX[1]); |
| 285 | + EXPECT_DOUBLE_EQ(hpx->GetXaxis()->GetBinUpEdge(2), edgesX[3]); |
| 286 | + |
| 287 | + for (int i = 0; i < 2; ++i) { |
| 288 | + int outbin = 2 + i; |
| 289 | + double exp = 0; |
| 290 | + for (int by = 1; by <= 2; ++by) |
| 291 | + exp += 100 * outbin + by; |
| 292 | + double got = hpx->GetBinContent(i + 1); |
| 293 | + EXPECT_DOUBLE_EQ(got, exp); |
| 294 | + } |
| 295 | +} |
| 296 | + |
| 297 | +// https://github.com/root-project/issues/20174 |
| 298 | +TEST(Projections, ProjectionYInfiniteUpperEdge) |
| 299 | +{ |
| 300 | + Double_t xedges[] = {0., 1.}; |
| 301 | + Double_t yedges[] = {1., std::numeric_limits<double>::infinity()}; |
| 302 | + TH2D h("h_inf", "h_inf;X;Y", 1, xedges, 1, yedges); |
| 303 | + h.SetBinContent(1, 1, 11.); |
| 304 | + auto projY = h.ProjectionY(); |
| 305 | + EXPECT_EQ(projY->GetBinContent(1), h.Integral(1, 1, 1, 1)); |
| 306 | +} |
| 307 | +TEST(Projections, ProjectionYInfiniteLowerEdge) |
| 308 | +{ |
| 309 | + Double_t xedges[] = {0, 1.}; |
| 310 | + Double_t yedges[] = {-std::numeric_limits<double>::infinity(), 1}; |
| 311 | + TH2D h("h_inf", "h_inf;X;Y", 1, xedges, 1, yedges); |
| 312 | + h.SetBinContent(1, 1, 11.); |
| 313 | + auto projY = h.ProjectionY(); |
| 314 | + EXPECT_EQ(projY->GetBinContent(1), h.Integral(1, 1, 1, 1)); |
| 315 | +} |
| 316 | + |
| 317 | +TEST(Projections, Projection3DInfiniteEdges) |
| 318 | +{ |
| 319 | + Double_t xedges[] = {0, 1.}; |
| 320 | + Double_t yedges[] = {-std::numeric_limits<double>::infinity(), 1}; |
| 321 | + Double_t zedges[] = {0, std::numeric_limits<double>::infinity()}; |
| 322 | + TH3D h("h_inf", "h_inf;X;Y;Z", 1, xedges, 1, yedges, 1, zedges); |
| 323 | + h.SetBinContent(1, 1, 1, 11.); |
| 324 | + auto projY = h.Project3D("zy"); |
| 325 | + EXPECT_EQ(projY->GetBinContent(projY->GetBin(1, 1)), h.Integral(1, 1, 1, 1, 1, 1)); |
| 326 | + |
| 327 | + auto projx = h.Project3D("x"); |
| 328 | + EXPECT_EQ(projx->GetBinContent(projx->GetBin(1)), h.Integral(1, 1, 1, 1, 1, 1)); |
| 329 | +} |
0 commit comments