File indexing completed on 2026-08-20 08:20:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Utilities/AxisDefinitions.hpp"
0012 #include "Acts/Utilities/AxisSpec.hpp"
0013 #include "Acts/Utilities/IAxis.hpp"
0014 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0015
0016 #include <stdexcept>
0017 #include <variant>
0018
0019 using Acts::AxisSpec;
0020
0021 namespace ActsTests {
0022
0023 BOOST_AUTO_TEST_SUITE(UtilitiesSuite)
0024
0025 BOOST_AUTO_TEST_CASE(AxisSpecEquidistant) {
0026 using enum Acts::AxisBoundaryType;
0027
0028 AxisSpec af = AxisSpec::Equidistant(5, 0., 10., Bound);
0029 BOOST_CHECK(!af.isDeferred());
0030 BOOST_CHECK(af.isEquidistant());
0031 BOOST_CHECK(!af.isVariable());
0032 BOOST_CHECK(!af.direction().has_value());
0033 BOOST_CHECK(af.boundaryType() == Bound);
0034 BOOST_CHECK_EQUAL(af.nBins(), 5);
0035 BOOST_CHECK(af.asEquidistant().min == 0.);
0036 BOOST_CHECK(af.asEquidistant().max == 10.);
0037 BOOST_CHECK_THROW(af.asVariable(), std::bad_variant_access);
0038
0039 auto axis = af.buildAxis({});
0040 BOOST_CHECK(axis->isEquidistant());
0041 BOOST_CHECK_EQUAL(axis->getBoundaryType(), Bound);
0042 BOOST_CHECK_EQUAL(axis->getNBins(), 5);
0043 CHECK_CLOSE_ABS(axis->getMin(), 0., 1e-15);
0044 CHECK_CLOSE_ABS(axis->getMax(), 10., 1e-15);
0045 BOOST_CHECK(!axis->getDirection().has_value());
0046
0047
0048 BOOST_CHECK_NO_THROW(af.buildAxis({.min = 0., .max = 10.}));
0049 BOOST_CHECK_THROW(af.buildAxis({.min = 0., .max = 1.}),
0050 std::invalid_argument);
0051 BOOST_CHECK_THROW(af.buildAxis({.boundaryType = Closed}),
0052 std::invalid_argument);
0053
0054
0055 BOOST_CHECK_THROW(AxisSpec::Equidistant(5, 1., 0., Bound),
0056 std::invalid_argument);
0057 BOOST_CHECK_THROW(AxisSpec::Equidistant(0, 0., 1., Bound),
0058 std::invalid_argument);
0059 }
0060
0061 BOOST_AUTO_TEST_CASE(AxisSpecVariable) {
0062 using enum Acts::AxisBoundaryType;
0063
0064 AxisSpec af = AxisSpec::Variable({0., 1., 4., 10.}, Open);
0065 BOOST_CHECK(!af.isDeferred());
0066 BOOST_CHECK(!af.isEquidistant());
0067 BOOST_CHECK(af.isVariable());
0068 BOOST_CHECK(af.boundaryType() == Open);
0069 BOOST_CHECK_EQUAL(af.nBins(), 3);
0070
0071 auto axis = af.buildAxis({});
0072 BOOST_CHECK(axis->isVariable());
0073 BOOST_CHECK_EQUAL(axis->getBoundaryType(), Open);
0074 std::vector<double> expectedEdges = {0., 1., 4., 10.};
0075 BOOST_CHECK(axis->getBinEdges() == expectedEdges);
0076
0077
0078 BOOST_CHECK_THROW(af.buildAxis({.min = 0., .max = 1.}),
0079 std::invalid_argument);
0080
0081
0082 AxisSpec afOpen = AxisSpec::Variable({0., 1., 4., 10.});
0083 BOOST_CHECK(afOpen.isDeferred());
0084 BOOST_CHECK_THROW(afOpen.buildAxis({}), std::domain_error);
0085 BOOST_CHECK_EQUAL(
0086 afOpen.buildAxis({.boundaryType = Bound})->getBoundaryType(), Bound);
0087
0088
0089 BOOST_CHECK_THROW(AxisSpec::Variable({0.}, Bound), std::invalid_argument);
0090 BOOST_CHECK_THROW(AxisSpec::Variable({0., 1., 1.}, Bound),
0091 std::invalid_argument);
0092 BOOST_CHECK_THROW(AxisSpec::Variable({0., 2., 1.}, Bound),
0093 std::invalid_argument);
0094 }
0095
0096 BOOST_AUTO_TEST_CASE(AxisSpecDeferredEquidistant) {
0097 using enum Acts::AxisBoundaryType;
0098
0099 AxisSpec af = AxisSpec::DeferredEquidistant(20);
0100 BOOST_CHECK(af.isDeferred());
0101 BOOST_CHECK(af.isEquidistant());
0102 BOOST_CHECK(!af.boundaryType().has_value());
0103 BOOST_CHECK_EQUAL(af.nBins(), 20);
0104 BOOST_CHECK_EQUAL(af.asEquidistant().nBins, 20);
0105
0106
0107 BOOST_CHECK_THROW(af.buildAxis({}), std::domain_error);
0108 BOOST_CHECK_THROW(af.buildAxis({.min = -2., .max = 2.}), std::domain_error);
0109
0110 auto axis = af.buildAxis({.min = -2., .max = 2., .boundaryType = Closed});
0111 BOOST_CHECK(axis->isEquidistant());
0112 BOOST_CHECK_EQUAL(axis->getBoundaryType(), Closed);
0113 BOOST_CHECK_EQUAL(axis->getNBins(), 20);
0114 CHECK_CLOSE_ABS(axis->getMin(), -2., 1e-15);
0115 CHECK_CLOSE_ABS(axis->getMax(), 2., 1e-15);
0116
0117
0118 BOOST_CHECK_THROW(
0119 af.buildAxis({.min = 2., .max = -2., .boundaryType = Bound}),
0120 std::invalid_argument);
0121
0122
0123 AxisSpec afRanged = AxisSpec::Equidistant(4, 0., 8.);
0124 BOOST_CHECK(afRanged.isDeferred());
0125 auto ranged = afRanged.buildAxis({.boundaryType = Bound});
0126 CHECK_CLOSE_ABS(ranged->getMin(), 0., 1e-15);
0127 CHECK_CLOSE_ABS(ranged->getMax(), 8., 1e-15);
0128
0129
0130 BOOST_CHECK_THROW(AxisSpec::DeferredEquidistant(0), std::invalid_argument);
0131 }
0132
0133 BOOST_AUTO_TEST_CASE(AxisSpecDeferredVariable) {
0134 using enum Acts::AxisBoundaryType;
0135
0136 AxisSpec af = AxisSpec::DeferredVariable({0., 0.1, 0.5, 1.});
0137 BOOST_CHECK(af.isDeferred());
0138 BOOST_CHECK(af.isVariable());
0139 BOOST_CHECK_EQUAL(af.nBins(), 3);
0140
0141 BOOST_CHECK(af.isDeferredVariable());
0142 BOOST_CHECK_THROW(af.buildAxis({}), std::domain_error);
0143
0144
0145 auto axis = af.buildAxis({.min = 10., .max = 30., .boundaryType = Bound});
0146 BOOST_CHECK(axis->isVariable());
0147 auto edges = axis->getBinEdges();
0148 BOOST_CHECK_EQUAL(edges.size(), 4);
0149 CHECK_CLOSE_ABS(edges[0], 10., 1e-15);
0150 CHECK_CLOSE_ABS(edges[1], 12., 1e-15);
0151 CHECK_CLOSE_ABS(edges[2], 20., 1e-15);
0152 CHECK_CLOSE_ABS(edges[3], 30., 1e-15);
0153
0154
0155 BOOST_CHECK_THROW(AxisSpec::DeferredVariable({0., 0.5}),
0156 std::invalid_argument);
0157 BOOST_CHECK_THROW(AxisSpec::DeferredVariable({0.1, 1.}),
0158 std::invalid_argument);
0159 BOOST_CHECK_THROW(AxisSpec::DeferredVariable({0., 0.5, 0.4, 1.}),
0160 std::invalid_argument);
0161 BOOST_CHECK_THROW(AxisSpec::DeferredVariable({1.}), std::invalid_argument);
0162 }
0163
0164 BOOST_AUTO_TEST_CASE(AxisSpecFromAxis) {
0165 using enum Acts::AxisBoundaryType;
0166
0167 auto eqAxis = Acts::IAxis::createEquidistant(Bound, -1., 1., 8,
0168 Acts::AxisDirection::AxisZ);
0169 AxisSpec af = AxisSpec::FromAxis(*eqAxis);
0170 BOOST_CHECK(!af.isDeferred());
0171 BOOST_CHECK(af.isEquidistant());
0172 BOOST_CHECK(af.direction() == Acts::AxisDirection::AxisZ);
0173
0174 BOOST_CHECK(*af.buildAxis({}) == *eqAxis);
0175
0176 auto varAxis = Acts::IAxis::createVariable(Closed, {0., 2., 3.});
0177 AxisSpec afVar = AxisSpec::FromAxis(*varAxis);
0178 BOOST_CHECK(afVar.isVariable());
0179 BOOST_CHECK(!afVar.direction().has_value());
0180 BOOST_CHECK(*afVar.buildAxis({}) == *varAxis);
0181 }
0182
0183 BOOST_AUTO_TEST_CASE(AxisSpecDirectionHandling) {
0184 using enum Acts::AxisBoundaryType;
0185 using enum Acts::AxisDirection;
0186
0187 AxisSpec af = AxisSpec::DeferredEquidistant(10, AxisPhi);
0188 BOOST_CHECK(af.direction() == AxisPhi);
0189
0190
0191 auto axis = af.buildAxis(
0192 {.min = 0., .max = 1., .boundaryType = Bound, .direction = AxisPhi});
0193 BOOST_CHECK(axis->getDirection() == AxisPhi);
0194
0195
0196 BOOST_CHECK_THROW(
0197 af.buildAxis(
0198 {.min = 0., .max = 1., .boundaryType = Bound, .direction = AxisZ}),
0199 std::invalid_argument);
0200
0201
0202 AxisSpec afFree = AxisSpec::DeferredEquidistant(10);
0203 auto axisFree = afFree.buildAxis(
0204 {.min = 0., .max = 1., .boundaryType = Bound, .direction = AxisZ});
0205 BOOST_CHECK(axisFree->getDirection() == AxisZ);
0206
0207
0208 AxisSpec afDir = afFree.withDirection(AxisRPhi);
0209 BOOST_CHECK(afDir.direction() == AxisRPhi);
0210 BOOST_CHECK(afFree != afDir);
0211
0212
0213 AxisSpec afFull = AxisSpec::Equidistant(4, 0., 1., Bound, AxisX);
0214 BOOST_CHECK_THROW(afFull.buildAxis({.direction = AxisY}),
0215 std::invalid_argument);
0216 BOOST_CHECK(afFull.buildAxis({.direction = AxisX})->getDirection() == AxisX);
0217 BOOST_CHECK(afFull.buildAxis({})->getDirection() == AxisX);
0218 }
0219
0220 BOOST_AUTO_TEST_CASE(AxisSpecToDeferred) {
0221 using enum Acts::AxisBoundaryType;
0222
0223
0224 AxisSpec af =
0225 AxisSpec::Equidistant(12, -3., 3., Closed, Acts::AxisDirection::AxisPhi);
0226 AxisSpec deferred = af.toDeferred();
0227 BOOST_CHECK(deferred.isDeferred());
0228 BOOST_CHECK(deferred.isEquidistant());
0229 BOOST_CHECK_EQUAL(deferred.nBins(), 12);
0230 BOOST_CHECK(deferred.direction() == Acts::AxisDirection::AxisPhi);
0231
0232
0233 AxisSpec afVar = AxisSpec::Variable({10., 12., 20., 30.}, Bound);
0234 AxisSpec deferredVar = afVar.toDeferred();
0235 BOOST_CHECK(deferredVar.isDeferred());
0236 const auto& normalizedEdges =
0237 deferredVar.asDeferredVariable().normalizedEdges;
0238 BOOST_CHECK_EQUAL(normalizedEdges.size(), 4);
0239 BOOST_CHECK_EQUAL(normalizedEdges.front(), 0.);
0240 BOOST_CHECK_EQUAL(normalizedEdges.back(), 1.);
0241 CHECK_CLOSE_ABS(normalizedEdges[1], 0.1, 1e-15);
0242 CHECK_CLOSE_ABS(normalizedEdges[2], 0.5, 1e-15);
0243
0244
0245 AxisSpec afDef = AxisSpec::DeferredEquidistant(7);
0246 BOOST_CHECK(afDef.toDeferred() == afDef);
0247 }
0248
0249 BOOST_AUTO_TEST_CASE(AxisSpecEqualityAndStreams) {
0250 using enum Acts::AxisBoundaryType;
0251
0252 AxisSpec a = AxisSpec::Equidistant(10, 0., 1., Bound);
0253 AxisSpec b = AxisSpec::Equidistant(10, 0., 1., Bound);
0254 AxisSpec c = AxisSpec::Equidistant(10, 0., 2., Bound);
0255 BOOST_CHECK(a == b);
0256 BOOST_CHECK(a != c);
0257 BOOST_CHECK(a != AxisSpec::DeferredEquidistant(10));
0258 BOOST_CHECK(a != a.withDirection(Acts::AxisDirection::AxisX));
0259
0260 BOOST_CHECK_EQUAL(a.toString(),
0261 "AxisSpec: 10 bins, equidistant within [0, 1], Bound");
0262 BOOST_CHECK_EQUAL(
0263 AxisSpec::DeferredEquidistant(5, Acts::AxisDirection::AxisZ).toString(),
0264 "AxisSpec: 5 bins in AxisZ, equidistant within deferred range, "
0265 "deferred boundary type");
0266 }
0267
0268 BOOST_AUTO_TEST_SUITE_END()
0269
0270 }