Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:55

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Utilities/Axis.hpp"
0013 #include "Acts/Utilities/AxisDefinitions.hpp"
0014 
0015 #include <cstddef>
0016 #include <vector>
0017 
0018 namespace Acts::Test {
0019 BOOST_AUTO_TEST_SUITE(Axes)
0020 
0021 BOOST_AUTO_TEST_CASE(equidistant_axis) {
0022   Axis a(0.0, 10.0, 10u);
0023 
0024   // general binning properties
0025   BOOST_CHECK_EQUAL(a.getNBins(), 10u);
0026   BOOST_CHECK_EQUAL(a.getMax(), 10.);
0027   BOOST_CHECK_EQUAL(a.getMin(), 0.);
0028   BOOST_CHECK_EQUAL(a.getBinWidth(), 1.);
0029 
0030   // bin index calculation
0031   BOOST_CHECK_EQUAL(a.getBin(-0.3), 0u);
0032   BOOST_CHECK_EQUAL(a.getBin(-0.), 1u);
0033   BOOST_CHECK_EQUAL(a.getBin(0.), 1u);
0034   BOOST_CHECK_EQUAL(a.getBin(0.7), 1u);
0035   BOOST_CHECK_EQUAL(a.getBin(1), 2u);
0036   BOOST_CHECK_EQUAL(a.getBin(1.2), 2u);
0037   BOOST_CHECK_EQUAL(a.getBin(2.), 3u);
0038   BOOST_CHECK_EQUAL(a.getBin(2.7), 3u);
0039   BOOST_CHECK_EQUAL(a.getBin(3.), 4u);
0040   BOOST_CHECK_EQUAL(a.getBin(3.6), 4u);
0041   BOOST_CHECK_EQUAL(a.getBin(4.), 5u);
0042   BOOST_CHECK_EQUAL(a.getBin(4.98), 5u);
0043   BOOST_CHECK_EQUAL(a.getBin(5.), 6u);
0044   BOOST_CHECK_EQUAL(a.getBin(5.12), 6u);
0045   BOOST_CHECK_EQUAL(a.getBin(6.), 7u);
0046   BOOST_CHECK_EQUAL(a.getBin(6.00001), 7u);
0047   BOOST_CHECK_EQUAL(a.getBin(7.), 8u);
0048   BOOST_CHECK_EQUAL(a.getBin(7.5), 8u);
0049   BOOST_CHECK_EQUAL(a.getBin(8.), 9u);
0050   BOOST_CHECK_EQUAL(a.getBin(8.1), 9u);
0051   BOOST_CHECK_EQUAL(a.getBin(9.), 10u);
0052   BOOST_CHECK_EQUAL(a.getBin(9.999), 10u);
0053   BOOST_CHECK_EQUAL(a.getBin(10.), 11u);
0054   BOOST_CHECK_EQUAL(a.getBin(100.3), 11u);
0055 
0056   // lower bin boundaries
0057   BOOST_CHECK_EQUAL(a.getBinLowerBound(1), 0.);
0058   BOOST_CHECK_EQUAL(a.getBinLowerBound(2), 1.);
0059   BOOST_CHECK_EQUAL(a.getBinLowerBound(3), 2.);
0060   BOOST_CHECK_EQUAL(a.getBinLowerBound(4), 3.);
0061   BOOST_CHECK_EQUAL(a.getBinLowerBound(5), 4.);
0062   BOOST_CHECK_EQUAL(a.getBinLowerBound(6), 5.);
0063   BOOST_CHECK_EQUAL(a.getBinLowerBound(7), 6.);
0064   BOOST_CHECK_EQUAL(a.getBinLowerBound(8), 7.);
0065   BOOST_CHECK_EQUAL(a.getBinLowerBound(9), 8.);
0066   BOOST_CHECK_EQUAL(a.getBinLowerBound(10), 9.);
0067 
0068   // upper bin boundaries
0069   BOOST_CHECK_EQUAL(a.getBinUpperBound(1), 1.);
0070   BOOST_CHECK_EQUAL(a.getBinUpperBound(2), 2.);
0071   BOOST_CHECK_EQUAL(a.getBinUpperBound(3), 3.);
0072   BOOST_CHECK_EQUAL(a.getBinUpperBound(4), 4.);
0073   BOOST_CHECK_EQUAL(a.getBinUpperBound(5), 5.);
0074   BOOST_CHECK_EQUAL(a.getBinUpperBound(6), 6.);
0075   BOOST_CHECK_EQUAL(a.getBinUpperBound(7), 7.);
0076   BOOST_CHECK_EQUAL(a.getBinUpperBound(8), 8.);
0077   BOOST_CHECK_EQUAL(a.getBinUpperBound(9), 9.);
0078   BOOST_CHECK_EQUAL(a.getBinUpperBound(10), 10.);
0079 
0080   // bin centers
0081   BOOST_CHECK_EQUAL(a.getBinCenter(1), 0.5);
0082   BOOST_CHECK_EQUAL(a.getBinCenter(2), 1.5);
0083   BOOST_CHECK_EQUAL(a.getBinCenter(3), 2.5);
0084   BOOST_CHECK_EQUAL(a.getBinCenter(4), 3.5);
0085   BOOST_CHECK_EQUAL(a.getBinCenter(5), 4.5);
0086   BOOST_CHECK_EQUAL(a.getBinCenter(6), 5.5);
0087   BOOST_CHECK_EQUAL(a.getBinCenter(7), 6.5);
0088   BOOST_CHECK_EQUAL(a.getBinCenter(8), 7.5);
0089   BOOST_CHECK_EQUAL(a.getBinCenter(9), 8.5);
0090   BOOST_CHECK_EQUAL(a.getBinCenter(10), 9.5);
0091 
0092   // inside check
0093   BOOST_CHECK(!a.isInside(-0.2));
0094   BOOST_CHECK(a.isInside(0.));
0095   BOOST_CHECK(a.isInside(3.));
0096   BOOST_CHECK(!a.isInside(10.));
0097   BOOST_CHECK(!a.isInside(12.));
0098 }
0099 
0100 BOOST_AUTO_TEST_CASE(variable_axis) {
0101   Axis a({0, 0.5, 3, 4.5, 6});
0102 
0103   // general binning properties
0104   BOOST_CHECK_EQUAL(a.getNBins(), 4u);
0105   BOOST_CHECK_EQUAL(a.getMax(), 6.);
0106   BOOST_CHECK_EQUAL(a.getMin(), 0.);
0107 
0108   // bin index calculation
0109   BOOST_CHECK_EQUAL(a.getBin(-0.3), 0u);
0110   BOOST_CHECK_EQUAL(a.getBin(-0.), 1u);
0111   BOOST_CHECK_EQUAL(a.getBin(0.), 1u);
0112   BOOST_CHECK_EQUAL(a.getBin(0.3), 1u);
0113   BOOST_CHECK_EQUAL(a.getBin(0.5), 2u);
0114   BOOST_CHECK_EQUAL(a.getBin(1.2), 2u);
0115   BOOST_CHECK_EQUAL(a.getBin(2.7), 2u);
0116   BOOST_CHECK_EQUAL(a.getBin(3.), 3u);
0117   BOOST_CHECK_EQUAL(a.getBin(4.49999), 3u);
0118   BOOST_CHECK_EQUAL(a.getBin(4.5), 4u);
0119   BOOST_CHECK_EQUAL(a.getBin(5.12), 4u);
0120   BOOST_CHECK_EQUAL(a.getBin(6.), 5u);
0121   BOOST_CHECK_EQUAL(a.getBin(6.00001), 5u);
0122   BOOST_CHECK_EQUAL(a.getBin(7.5), 5u);
0123 
0124   // lower bin boundaries
0125   BOOST_CHECK_EQUAL(a.getBinLowerBound(1), 0.);
0126   BOOST_CHECK_EQUAL(a.getBinLowerBound(2), 0.5);
0127   BOOST_CHECK_EQUAL(a.getBinLowerBound(3), 3.);
0128   BOOST_CHECK_EQUAL(a.getBinLowerBound(4), 4.5);
0129 
0130   // upper bin boundaries
0131   BOOST_CHECK_EQUAL(a.getBinUpperBound(1), 0.5);
0132   BOOST_CHECK_EQUAL(a.getBinUpperBound(2), 3.);
0133   BOOST_CHECK_EQUAL(a.getBinUpperBound(3), 4.5);
0134   BOOST_CHECK_EQUAL(a.getBinUpperBound(4), 6.);
0135 
0136   // bin centers
0137   BOOST_CHECK_EQUAL(a.getBinCenter(1), 0.25);
0138   BOOST_CHECK_EQUAL(a.getBinCenter(2), 1.75);
0139   BOOST_CHECK_EQUAL(a.getBinCenter(3), 3.75);
0140   BOOST_CHECK_EQUAL(a.getBinCenter(4), 5.25);
0141 
0142   // inside check
0143   BOOST_CHECK(!a.isInside(-0.2));
0144   BOOST_CHECK(a.isInside(0.));
0145   BOOST_CHECK(a.isInside(3.));
0146   BOOST_CHECK(!a.isInside(6.));
0147   BOOST_CHECK(!a.isInside(12.));
0148 }
0149 
0150 BOOST_AUTO_TEST_CASE(open_axis) {
0151   Axis<AxisType::Equidistant, AxisBoundaryType::Bound> a(0, 10, 10);
0152 
0153   // normal inside
0154   BOOST_CHECK_EQUAL(a.getBin(0.5), 1u);
0155   BOOST_CHECK_EQUAL(a.getBin(9.5), 10u);
0156 
0157   // out of bounds, but is open
0158   // -> should clamp
0159   BOOST_CHECK_EQUAL(a.getBin(-0.5), 1u);
0160   BOOST_CHECK_EQUAL(a.getBin(10.5), 10u);
0161 
0162   Axis<AxisType::Variable, AxisBoundaryType::Bound> b(
0163       {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
0164 
0165   // normal inside
0166   BOOST_CHECK_EQUAL(b.getBin(0.5), 1u);
0167   BOOST_CHECK_EQUAL(b.getBin(9.5), 10u);
0168 
0169   // out of bounds, but is open
0170   // -> should clamp
0171   BOOST_CHECK_EQUAL(b.getBin(-0.5), 1u);
0172   BOOST_CHECK_EQUAL(b.getBin(10.5), 10u);
0173 }
0174 
0175 BOOST_AUTO_TEST_CASE(closed_axis) {
0176   Axis<AxisType::Equidistant, AxisBoundaryType::Closed> a(0, 10, 10);
0177 
0178   // normal inside
0179   BOOST_CHECK_EQUAL(a.getBin(0.5), 1u);
0180   BOOST_CHECK_EQUAL(a.getBin(9.5), 10u);
0181 
0182   // out of bounds, but is closed
0183   // -> should wrap to opposite side bin
0184   BOOST_CHECK_EQUAL(a.getBin(-0.5), 10u);
0185   BOOST_CHECK_EQUAL(a.getBin(10.5), 1u);
0186 
0187   Axis<AxisType::Variable, AxisBoundaryType::Closed> b(
0188       {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
0189 
0190   // normal inside
0191   BOOST_CHECK_EQUAL(b.getBin(0.5), 1u);
0192   BOOST_CHECK_EQUAL(b.getBin(9.5), 10u);
0193 
0194   // out of bounds, but is closed
0195   // -> should wrap to opposite side bin
0196   BOOST_CHECK_EQUAL(b.getBin(-0.5), 10u);
0197   BOOST_CHECK_EQUAL(b.getBin(10.5), 1u);
0198 }
0199 
0200 BOOST_AUTO_TEST_CASE(neighborhood) {
0201   using bins_t = std::vector<std::size_t>;
0202   Axis<AxisType::Equidistant, AxisBoundaryType::Open> a1(0.0, 1.0, 10u);
0203 
0204   BOOST_CHECK(a1.neighborHoodIndices(0, 1).collect() == bins_t({0, 1}));
0205   BOOST_CHECK(a1.neighborHoodIndices(1, 1).collect() == bins_t({0, 1, 2}));
0206   BOOST_CHECK(a1.neighborHoodIndices(11, 1).collect() == bins_t({10, 11}));
0207   BOOST_CHECK(a1.neighborHoodIndices(10, 1).collect() == bins_t({9, 10, 11}));
0208   BOOST_CHECK(a1.neighborHoodIndices(5, 1).collect() == bins_t({4, 5, 6}));
0209   BOOST_CHECK(a1.neighborHoodIndices(5, {-1, 0}).collect() == bins_t({4, 5}));
0210   BOOST_CHECK(a1.neighborHoodIndices(5, {0, 1}).collect() == bins_t({5, 6}));
0211 
0212   BOOST_CHECK(a1.neighborHoodIndices(0, 2).collect() == bins_t({0, 1, 2}));
0213   BOOST_CHECK(a1.neighborHoodIndices(1, 2).collect() == bins_t({0, 1, 2, 3}));
0214   BOOST_CHECK(a1.neighborHoodIndices(11, 2).collect() == bins_t({9, 10, 11}));
0215   BOOST_CHECK(a1.neighborHoodIndices(10, 2).collect() ==
0216               bins_t({8, 9, 10, 11}));
0217   BOOST_CHECK(a1.neighborHoodIndices(5, 2).collect() ==
0218               bins_t({3, 4, 5, 6, 7}));
0219 
0220   Axis<AxisType::Variable, AxisBoundaryType::Open> a2(
0221       {0.0, 2.0, 4.0, 9.0, 10.0});
0222   BOOST_CHECK(a2.neighborHoodIndices(0, 1).collect() == bins_t({0, 1}));
0223   BOOST_CHECK(a2.neighborHoodIndices(1, 1).collect() == bins_t({0, 1, 2}));
0224   BOOST_CHECK(a2.neighborHoodIndices(5, 1).collect() == bins_t({4, 5}));
0225   BOOST_CHECK(a2.neighborHoodIndices(4, 1).collect() == bins_t({3, 4, 5}));
0226   BOOST_CHECK(a2.neighborHoodIndices(4, {-1, 0}).collect() == bins_t({3, 4}));
0227   BOOST_CHECK(a2.neighborHoodIndices(2, 1).collect() == bins_t({1, 2, 3}));
0228   BOOST_CHECK(a2.neighborHoodIndices(2, {0, 1}).collect() == bins_t({2, 3}));
0229 
0230   BOOST_CHECK(a2.neighborHoodIndices(0, 2).collect() == bins_t({0, 1, 2}));
0231   BOOST_CHECK(a2.neighborHoodIndices(1, 2).collect() == bins_t({0, 1, 2, 3}));
0232   BOOST_CHECK(a2.neighborHoodIndices(5, 2).collect() == bins_t({3, 4, 5}));
0233   BOOST_CHECK(a2.neighborHoodIndices(4, 2).collect() == bins_t({2, 3, 4, 5}));
0234   BOOST_CHECK(a2.neighborHoodIndices(3, 2).collect() ==
0235               bins_t({1, 2, 3, 4, 5}));
0236 
0237   Axis<AxisType::Equidistant, AxisBoundaryType::Bound> a3(0.0, 1.0, 10u);
0238 
0239   BOOST_CHECK(a3.neighborHoodIndices(0, 1).collect() == bins_t({}));
0240   BOOST_CHECK(a3.neighborHoodIndices(1, 1).collect() == bins_t({1, 2}));
0241   BOOST_CHECK(a3.neighborHoodIndices(11, 1).collect() == bins_t({}));
0242   BOOST_CHECK(a3.neighborHoodIndices(10, 1).collect() == bins_t({9, 10}));
0243   BOOST_CHECK(a3.neighborHoodIndices(10, {0, 1}).collect() == bins_t({10}));
0244   BOOST_CHECK(a3.neighborHoodIndices(5, 1).collect() == bins_t({4, 5, 6}));
0245   BOOST_CHECK(a3.neighborHoodIndices(5, {-1, 0}).collect() == bins_t({4, 5}));
0246   BOOST_CHECK(a3.neighborHoodIndices(5, {0, 1}).collect() == bins_t({5, 6}));
0247 
0248   BOOST_CHECK(a3.neighborHoodIndices(0, 2).collect() == bins_t({}));
0249   BOOST_CHECK(a3.neighborHoodIndices(1, 2).collect() == bins_t({1, 2, 3}));
0250   BOOST_CHECK(a3.neighborHoodIndices(11, 2).collect() == bins_t({}));
0251   BOOST_CHECK(a3.neighborHoodIndices(10, 2).collect() == bins_t({8, 9, 10}));
0252   BOOST_CHECK(a3.neighborHoodIndices(5, 2).collect() ==
0253               bins_t({3, 4, 5, 6, 7}));
0254 
0255   Axis<AxisType::Equidistant, AxisBoundaryType::Closed> a4(0.0, 1.0, 10u);
0256 
0257   BOOST_CHECK(a4.neighborHoodIndices(0, 1).collect() == bins_t({}));
0258   BOOST_CHECK(a4.neighborHoodIndices(1, 1).collect() == bins_t({10, 1, 2}));
0259   BOOST_CHECK(a4.neighborHoodIndices(11, 1).collect() == bins_t({}));
0260   BOOST_CHECK(a4.neighborHoodIndices(10, 1).collect() == bins_t({9, 10, 1}));
0261   BOOST_CHECK(a4.neighborHoodIndices(10, {0, 1}).collect() == bins_t({10, 1}));
0262   BOOST_CHECK(a4.neighborHoodIndices(5, 1).collect() == bins_t({4, 5, 6}));
0263   BOOST_CHECK(a4.neighborHoodIndices(5, {-1, 0}).collect() == bins_t({4, 5}));
0264   BOOST_CHECK(a4.neighborHoodIndices(5, {0, 1}).collect() == bins_t({5, 6}));
0265 
0266   BOOST_CHECK(a4.neighborHoodIndices(0, 2).collect() == bins_t({}));
0267   BOOST_CHECK(a4.neighborHoodIndices(1, 2).collect() ==
0268               bins_t({9, 10, 1, 2, 3}));
0269   BOOST_CHECK(a4.neighborHoodIndices(11, 2).collect() == bins_t({}));
0270   BOOST_CHECK(a4.neighborHoodIndices(10, 2).collect() ==
0271               bins_t({8, 9, 10, 1, 2}));
0272   BOOST_CHECK(a4.neighborHoodIndices(5, 2).collect() ==
0273               bins_t({3, 4, 5, 6, 7}));
0274   BOOST_CHECK(a4.neighborHoodIndices(3, 2).collect() ==
0275               bins_t({1, 2, 3, 4, 5}));
0276 
0277   Axis<AxisType::Variable, AxisBoundaryType::Bound> a5(
0278       {0.0, 2.0, 4.0, 9.0, 9.5, 10.0});
0279   BOOST_CHECK(a5.neighborHoodIndices(0, 1).collect() == bins_t({}));
0280   BOOST_CHECK(a5.neighborHoodIndices(1, 1).collect() == bins_t({1, 2}));
0281   BOOST_CHECK(a5.neighborHoodIndices(6, 1).collect() == bins_t({}));
0282   BOOST_CHECK(a5.neighborHoodIndices(5, 1).collect() == bins_t({4, 5}));
0283   BOOST_CHECK(a5.neighborHoodIndices(5, {0, 1}).collect() == bins_t({5}));
0284   BOOST_CHECK(a5.neighborHoodIndices(2, 1).collect() == bins_t({1, 2, 3}));
0285   BOOST_CHECK(a5.neighborHoodIndices(2, {-1, 0}).collect() == bins_t({1, 2}));
0286   BOOST_CHECK(a5.neighborHoodIndices(2, {0, 1}).collect() == bins_t({2, 3}));
0287 
0288   BOOST_CHECK(a5.neighborHoodIndices(0, 2).collect() == bins_t({}));
0289   BOOST_CHECK(a5.neighborHoodIndices(1, 2).collect() == bins_t({1, 2, 3}));
0290   BOOST_CHECK(a5.neighborHoodIndices(6, 2).collect() == bins_t({}));
0291   BOOST_CHECK(a5.neighborHoodIndices(5, 2).collect() == bins_t({3, 4, 5}));
0292   BOOST_CHECK(a5.neighborHoodIndices(3, 2).collect() ==
0293               bins_t({1, 2, 3, 4, 5}));
0294 
0295   Axis<AxisType::Variable, AxisBoundaryType::Closed> a6(
0296       {0.0, 2.0, 4.0, 9.0, 9.5, 10.0});
0297   BOOST_CHECK(a6.neighborHoodIndices(0, 1).collect() == bins_t({}));
0298   BOOST_CHECK(a6.neighborHoodIndices(1, 1).collect() == bins_t({5, 1, 2}));
0299   BOOST_CHECK(a6.neighborHoodIndices(6, 1).collect() == bins_t({}));
0300   BOOST_CHECK(a6.neighborHoodIndices(5, 1).collect() == bins_t({4, 5, 1}));
0301   BOOST_CHECK(a6.neighborHoodIndices(5, {0, 1}).collect() == bins_t({5, 1}));
0302   BOOST_CHECK(a6.neighborHoodIndices(2, 1).collect() == bins_t({1, 2, 3}));
0303   BOOST_CHECK(a6.neighborHoodIndices(2, {-1, 0}).collect() == bins_t({1, 2}));
0304   BOOST_CHECK(a6.neighborHoodIndices(2, {0, 1}).collect() == bins_t({2, 3}));
0305 
0306   BOOST_CHECK(a6.neighborHoodIndices(0, 2).collect() == bins_t({}));
0307   BOOST_CHECK(a6.neighborHoodIndices(1, 2).collect() ==
0308               bins_t({4, 5, 1, 2, 3}));
0309   BOOST_CHECK(a6.neighborHoodIndices(6, 2).collect() == bins_t({}));
0310   BOOST_CHECK(a6.neighborHoodIndices(5, 2).collect() ==
0311               bins_t({3, 4, 5, 1, 2}));
0312   BOOST_CHECK(a6.neighborHoodIndices(3, 2).collect() ==
0313               bins_t({1, 2, 3, 4, 5}));
0314   BOOST_CHECK(a6.neighborHoodIndices(3, {0, 2}).collect() == bins_t({3, 4, 5}));
0315 
0316   BOOST_CHECK(a6.neighborHoodIndices(1, 3).collect() ==
0317               bins_t({1, 2, 3, 4, 5}));
0318   BOOST_CHECK(a6.neighborHoodIndices(5, 3).collect() ==
0319               bins_t({1, 2, 3, 4, 5}));
0320 }
0321 
0322 BOOST_AUTO_TEST_CASE(wrapBin) {
0323   Axis<AxisType::Equidistant, AxisBoundaryType::Open> a1(0.0, 1.0, 10u);
0324   BOOST_CHECK_EQUAL(a1.wrapBin(0), 0u);
0325   BOOST_CHECK_EQUAL(a1.wrapBin(1), 1u);
0326   BOOST_CHECK_EQUAL(a1.wrapBin(-1), 0u);
0327   BOOST_CHECK_EQUAL(a1.wrapBin(10), 10u);
0328   BOOST_CHECK_EQUAL(a1.wrapBin(11), 11u);
0329   BOOST_CHECK_EQUAL(a1.wrapBin(12), 11u);
0330 
0331   Axis<AxisType::Equidistant, AxisBoundaryType::Bound> a2(0.0, 1.0, 10u);
0332   BOOST_CHECK_EQUAL(a2.wrapBin(0), 1u);
0333   BOOST_CHECK_EQUAL(a2.wrapBin(1), 1u);
0334   BOOST_CHECK_EQUAL(a2.wrapBin(-1), 1u);
0335   BOOST_CHECK_EQUAL(a2.wrapBin(10), 10u);
0336   BOOST_CHECK_EQUAL(a2.wrapBin(11), 10u);
0337   BOOST_CHECK_EQUAL(a2.wrapBin(12), 10u);
0338 
0339   Axis<AxisType::Equidistant, AxisBoundaryType::Closed> a3(0.0, 1.0, 10u);
0340   BOOST_CHECK_EQUAL(a3.wrapBin(0), 10u);
0341   BOOST_CHECK_EQUAL(a3.wrapBin(1), 1u);
0342   BOOST_CHECK_EQUAL(a3.wrapBin(-1), 9u);
0343   BOOST_CHECK_EQUAL(a3.wrapBin(10), 10u);
0344   BOOST_CHECK_EQUAL(a3.wrapBin(11), 1u);
0345   BOOST_CHECK_EQUAL(a3.wrapBin(12), 2u);
0346 
0347   Axis<AxisType::Variable, AxisBoundaryType::Open> a4(
0348       {0.0, 2.0, 4.0, 9.0, 10.0});
0349   BOOST_CHECK_EQUAL(a4.wrapBin(0), 0u);
0350   BOOST_CHECK_EQUAL(a4.wrapBin(1), 1u);
0351   BOOST_CHECK_EQUAL(a4.wrapBin(-1), 0u);
0352   BOOST_CHECK_EQUAL(a4.wrapBin(4), 4u);
0353   BOOST_CHECK_EQUAL(a4.wrapBin(5), 5u);
0354   BOOST_CHECK_EQUAL(a4.wrapBin(6), 5u);
0355 
0356   Axis<AxisType::Variable, AxisBoundaryType::Bound> a5(
0357       {0.0, 2.0, 4.0, 9.0, 9.5, 10.0});
0358   BOOST_CHECK_EQUAL(a5.wrapBin(0), 1u);
0359   BOOST_CHECK_EQUAL(a5.wrapBin(1), 1u);
0360   BOOST_CHECK_EQUAL(a5.wrapBin(-1), 1u);
0361   BOOST_CHECK_EQUAL(a5.wrapBin(4), 4u);
0362   BOOST_CHECK_EQUAL(a5.wrapBin(5), 5u);
0363   BOOST_CHECK_EQUAL(a5.wrapBin(6), 5u);
0364 
0365   Axis<AxisType::Variable, AxisBoundaryType::Closed> a6(
0366       {0.0, 2.0, 4.0, 9.0, 9.5, 10.0});
0367   BOOST_CHECK_EQUAL(a6.wrapBin(0), 5u);
0368   BOOST_CHECK_EQUAL(a6.wrapBin(1), 1u);
0369   BOOST_CHECK_EQUAL(a6.wrapBin(-1), 4u);
0370   BOOST_CHECK_EQUAL(a6.wrapBin(4), 4u);
0371   BOOST_CHECK_EQUAL(a6.wrapBin(5), 5u);
0372   BOOST_CHECK_EQUAL(a6.wrapBin(6), 1u);
0373   BOOST_CHECK_EQUAL(a6.wrapBin(7), 2u);
0374 }
0375 
0376 BOOST_AUTO_TEST_CASE(AxisTypeDeduction) {
0377   auto eqOpen = Axis{0.0, 10., 10};
0378   static_assert(
0379       std::is_same_v<decltype(eqOpen),
0380                      Axis<AxisType::Equidistant, AxisBoundaryType::Open>>);
0381   auto eqBound = Axis{AxisBound, 0.0, 10., 10};
0382   static_assert(
0383       std::is_same_v<decltype(eqBound),
0384                      Axis<AxisType::Equidistant, AxisBoundaryType::Bound>>);
0385   auto eqClosed = Axis{AxisClosed, 0.0, 10., 10};
0386   static_assert(
0387       std::is_same_v<decltype(eqClosed),
0388                      Axis<AxisType::Equidistant, AxisBoundaryType::Closed>>);
0389 
0390   auto varOpen = Axis{{0, 1, 2., 3, 4}};
0391   static_assert(
0392       std::is_same_v<decltype(varOpen),
0393                      Axis<AxisType::Variable, AxisBoundaryType::Open>>);
0394   auto varBound = Axis{AxisBound, {0, 1, 2., 3, 4}};
0395   static_assert(
0396       std::is_same_v<decltype(varBound),
0397                      Axis<AxisType::Variable, AxisBoundaryType::Bound>>);
0398   auto varClosed = Axis{AxisClosed, {0, 1, 2., 3, 4}};
0399   static_assert(
0400       std::is_same_v<decltype(varClosed),
0401                      Axis<AxisType::Variable, AxisBoundaryType::Closed>>);
0402 }
0403 
0404 BOOST_AUTO_TEST_CASE(AxisVisit) {
0405   using enum AxisBoundaryType;
0406   using enum AxisType;
0407 
0408   auto eqOpen = Axis{0.0, 10., 10};
0409   eqOpen.visit([](const auto& axis) {
0410     BOOST_CHECK((
0411         std::is_same_v<std::decay_t<decltype(axis)>, Axis<Equidistant, Open>>));
0412   });
0413 
0414   auto eqBound = Axis{AxisBound, 0.0, 10., 10};
0415   eqBound.visit([](const auto& axis) {
0416     BOOST_CHECK((std::is_same_v<std::decay_t<decltype(axis)>,
0417                                 Axis<Equidistant, Bound>>));
0418   });
0419 
0420   auto eqClosed = Axis{AxisClosed, 0.0, 10., 10};
0421   eqClosed.visit([](const auto& axis) {
0422     BOOST_CHECK((std::is_same_v<std::decay_t<decltype(axis)>,
0423                                 Axis<Equidistant, Closed>>));
0424   });
0425 
0426   auto varOpen = Axis{{0, 1, 2., 3, 4}};
0427   varOpen.visit([](const auto& axis) {
0428     BOOST_CHECK(
0429         (std::is_same_v<std::decay_t<decltype(axis)>, Axis<Variable, Open>>));
0430   });
0431 
0432   auto varBound = Axis{AxisBound, {0, 1, 2., 3, 4}};
0433   varBound.visit([](const auto& axis) {
0434     BOOST_CHECK(
0435         (std::is_same_v<std::decay_t<decltype(axis)>, Axis<Variable, Bound>>));
0436   });
0437 
0438   auto varClosed = Axis{AxisClosed, {0, 1, 2., 3, 4}};
0439   varClosed.visit([](const auto& axis) {
0440     BOOST_CHECK(
0441         (std::is_same_v<std::decay_t<decltype(axis)>, Axis<Variable, Closed>>));
0442   });
0443 
0444   std::vector<double> edges =
0445       varClosed.visit([](const auto& axis) { return axis.getBinEdges(); });
0446   BOOST_CHECK_EQUAL(edges.size(), varClosed.getBinEdges().size());
0447 
0448   // Test return values from visit method with type-dependent values
0449   int typeValue = eqOpen.visit([](const auto& axis) {
0450     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0451                                  Axis<Equidistant, Open>>) {
0452       return 1;
0453     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0454                                         Axis<Equidistant, Bound>>) {
0455       return 2;
0456     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0457                                         Axis<Equidistant, Closed>>) {
0458       return 3;
0459     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0460                                         Axis<Variable, Open>>) {
0461       return 4;
0462     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0463                                         Axis<Variable, Bound>>) {
0464       return 5;
0465     } else {
0466       return 6;  // Variable, Closed
0467     }
0468   });
0469   BOOST_CHECK_EQUAL(typeValue, 1);  // Should be Equidistant, Open
0470 
0471   typeValue = eqBound.visit([](const auto& axis) {
0472     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0473                                  Axis<Equidistant, Open>>) {
0474       return 1;
0475     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0476                                         Axis<Equidistant, Bound>>) {
0477       return 2;
0478     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0479                                         Axis<Equidistant, Closed>>) {
0480       return 3;
0481     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0482                                         Axis<Variable, Open>>) {
0483       return 4;
0484     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0485                                         Axis<Variable, Bound>>) {
0486       return 5;
0487     } else {
0488       return 6;  // Variable, Closed
0489     }
0490   });
0491   BOOST_CHECK_EQUAL(typeValue, 2);  // Should be Equidistant, Bound
0492 
0493   typeValue = eqClosed.visit([](const auto& axis) {
0494     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0495                                  Axis<Equidistant, Open>>) {
0496       return 1;
0497     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0498                                         Axis<Equidistant, Bound>>) {
0499       return 2;
0500     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0501                                         Axis<Equidistant, Closed>>) {
0502       return 3;
0503     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0504                                         Axis<Variable, Open>>) {
0505       return 4;
0506     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0507                                         Axis<Variable, Bound>>) {
0508       return 5;
0509     } else {
0510       return 6;  // Variable, Closed
0511     }
0512   });
0513   BOOST_CHECK_EQUAL(typeValue, 3);  // Should be Equidistant, Closed
0514 
0515   typeValue = varOpen.visit([](const auto& axis) {
0516     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0517                                  Axis<Equidistant, Open>>) {
0518       return 1;
0519     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0520                                         Axis<Equidistant, Bound>>) {
0521       return 2;
0522     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0523                                         Axis<Equidistant, Closed>>) {
0524       return 3;
0525     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0526                                         Axis<Variable, Open>>) {
0527       return 4;
0528     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0529                                         Axis<Variable, Bound>>) {
0530       return 5;
0531     } else {
0532       return 6;  // Variable, Closed
0533     }
0534   });
0535   BOOST_CHECK_EQUAL(typeValue, 4);  // Should be Variable, Open
0536 
0537   typeValue = varBound.visit([](const auto& axis) {
0538     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0539                                  Axis<Equidistant, Open>>) {
0540       return 1;
0541     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0542                                         Axis<Equidistant, Bound>>) {
0543       return 2;
0544     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0545                                         Axis<Equidistant, Closed>>) {
0546       return 3;
0547     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0548                                         Axis<Variable, Open>>) {
0549       return 4;
0550     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0551                                         Axis<Variable, Bound>>) {
0552       return 5;
0553     } else {
0554       return 6;  // Variable, Closed
0555     }
0556   });
0557   BOOST_CHECK_EQUAL(typeValue, 5);  // Should be Variable, Bound
0558 
0559   typeValue = varClosed.visit([](const auto& axis) {
0560     if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0561                                  Axis<Equidistant, Open>>) {
0562       return 1;
0563     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0564                                         Axis<Equidistant, Bound>>) {
0565       return 2;
0566     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0567                                         Axis<Equidistant, Closed>>) {
0568       return 3;
0569     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0570                                         Axis<Variable, Open>>) {
0571       return 4;
0572     } else if constexpr (std::is_same_v<std::decay_t<decltype(axis)>,
0573                                         Axis<Variable, Bound>>) {
0574       return 5;
0575     } else {
0576       return 6;  // Variable, Closed
0577     }
0578   });
0579   BOOST_CHECK_EQUAL(typeValue, 6);  // Should be Variable, Closed
0580 
0581   // Test return value using axis properties
0582   double minValue =
0583       eqOpen.visit([](const auto& axis) { return axis.getMin(); });
0584   BOOST_CHECK_EQUAL(minValue, 0.0);
0585 
0586   double maxValue =
0587       eqBound.visit([](const auto& axis) { return axis.getMax(); });
0588   BOOST_CHECK_EQUAL(maxValue, 10.0);
0589 
0590   std::size_t nBins =
0591       varClosed.visit([](const auto& axis) { return axis.getNBins(); });
0592   BOOST_CHECK_EQUAL(nBins, 4u);
0593 }
0594 
0595 BOOST_AUTO_TEST_CASE(Output) {
0596   std::stringstream ss;
0597 
0598   Axis a{AxisBound, 0.0, 10., 10};
0599   Axis b{AxisBound, {0.0, 10., 11}};
0600 
0601   ss << a;
0602 
0603   BOOST_CHECK_EQUAL(ss.str(), "Axis<Equidistant, Bound>(0, 10, 10)");
0604 
0605   ss.str("");
0606 
0607   const IAxis& ia = a;
0608 
0609   ss << ia;
0610 
0611   BOOST_CHECK_EQUAL(ss.str(), "Axis<Equidistant, Bound>(0, 10, 10)");
0612 
0613   ss.str("");
0614 
0615   ss << b;
0616 
0617   BOOST_CHECK_EQUAL(ss.str(), "Axis<Variable, Bound>(0, 10, 11)");
0618 }
0619 
0620 BOOST_AUTO_TEST_CASE(Equality) {
0621   Axis a{AxisBound, 0.0, 10., 10};
0622   Axis b{AxisClosed, 0.0, 10., 10};
0623 
0624   BOOST_CHECK_EQUAL(a, a);
0625   BOOST_CHECK_NE(a, b);
0626 
0627   const IAxis& ia = a;
0628   const IAxis& ib = b;
0629 
0630   BOOST_CHECK_EQUAL(ia, ia);
0631   BOOST_CHECK_NE(ia, ib);
0632   BOOST_CHECK_NE(ia, b);
0633   BOOST_CHECK_NE(a, ib);
0634   BOOST_CHECK_EQUAL(a, ia);
0635   BOOST_CHECK_EQUAL(b, ib);
0636 }
0637 
0638 BOOST_AUTO_TEST_SUITE_END()
0639 
0640 }  // namespace Acts::Test