File indexing completed on 2025-08-06 08:11:20
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Definitions/Direction.hpp"
0014 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/GeometryContext.hpp"
0016 #include "Acts/Geometry/VolumeBounds.hpp"
0017 #include "Acts/Surfaces/CylinderBounds.hpp"
0018 #include "Acts/Surfaces/RadialBounds.hpp"
0019 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0020 #include "Acts/Utilities/BinningType.hpp"
0021 #include "Acts/Utilities/BoundingBox.hpp"
0022
0023 #include <algorithm>
0024 #include <array>
0025 #include <cmath>
0026 #include <memory>
0027 #include <stdexcept>
0028 #include <vector>
0029
0030 namespace bdata = boost::unit_test::data;
0031
0032 namespace Acts {
0033 namespace Test {
0034 BOOST_AUTO_TEST_SUITE(Geometry)
0035
0036 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsConstruction) {
0037 double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
0038
0039
0040 CylinderVolumeBounds solidCylinder(0., rmax, halfz);
0041 BOOST_CHECK_EQUAL(solidCylinder.orientedSurfaces().size(), 3);
0042
0043
0044 CylinderVolumeBounds solidCylinderSector(0., rmax, halfz, halfphi);
0045 BOOST_CHECK_EQUAL(solidCylinderSector.orientedSurfaces().size(), 5);
0046
0047
0048 CylinderVolumeBounds tubeCylinder(rmin, rmax, halfz);
0049 BOOST_CHECK_EQUAL(tubeCylinder.orientedSurfaces().size(), 4);
0050
0051
0052 CylinderVolumeBounds tubeCylinderSector(rmin, rmax, halfz, halfphi);
0053 BOOST_CHECK_EQUAL(tubeCylinderSector.orientedSurfaces().size(), 6);
0054
0055 CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
0056
0057
0058 double rmed = 0.5 * (rmin + rmax);
0059 double rthickness = (rmax - rmin);
0060 CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
0061 CylinderVolumeBounds fromCylinder(cBounds, rthickness);
0062 BOOST_CHECK_EQUAL(original, fromCylinder);
0063
0064
0065 RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
0066 CylinderVolumeBounds fromDisc(rBounds, 2 * halfz);
0067 BOOST_CHECK_EQUAL(original, fromDisc);
0068
0069
0070 CylinderVolumeBounds copied(original);
0071 BOOST_CHECK_EQUAL(original, copied);
0072
0073
0074 CylinderVolumeBounds assigned = original;
0075 BOOST_CHECK_EQUAL(original, assigned);
0076 }
0077
0078 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsRecreation) {
0079 double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
0080
0081 CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
0082 std::array<double, CylinderVolumeBounds::eSize> values{};
0083 std::vector<double> valvector = original.values();
0084 std::copy_n(valvector.begin(), CylinderVolumeBounds::eSize, values.begin());
0085 CylinderVolumeBounds recreated(values);
0086 BOOST_CHECK_EQUAL(original, recreated);
0087 }
0088
0089 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsExceptions) {
0090 double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
0091
0092
0093 BOOST_CHECK_THROW(CylinderVolumeBounds(-rmin, rmax, halfz, halfphi, avgphi),
0094 std::logic_error);
0095
0096
0097 BOOST_CHECK_THROW(CylinderVolumeBounds(rmin, -rmax, halfz, halfphi, avgphi),
0098 std::logic_error);
0099
0100
0101 BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, avgphi),
0102 std::logic_error);
0103
0104
0105 BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, 0., halfphi, avgphi),
0106 std::logic_error);
0107
0108
0109 BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, -halfz, halfphi, avgphi),
0110 std::logic_error);
0111
0112
0113 BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, -4., avgphi),
0114 std::logic_error);
0115
0116
0117 BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, 4.),
0118 std::logic_error);
0119
0120
0121 double rmed = 0.5 * (rmin + rmax);
0122 CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
0123 RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
0124
0125
0126 BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, -1.), std::logic_error);
0127
0128
0129 BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, 1000.), std::logic_error);
0130
0131
0132 BOOST_CHECK_THROW(CylinderVolumeBounds(rBounds, -1), std::logic_error);
0133 }
0134
0135 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsAccess) {
0136 double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
0137 CylinderVolumeBounds cvBounds(rmin, rmax, halfz, halfphi, avgphi);
0138
0139
0140 BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMinR), rmin);
0141 BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMaxR), rmax);
0142 BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfLengthZ), halfz);
0143 BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfPhiSector),
0144 halfphi);
0145 BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eAveragePhi), avgphi);
0146 }
0147
0148
0149 BOOST_DATA_TEST_CASE(
0150 CylinderVolumeBoundsOrientedSurfaces,
0151 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 1,
0152 bdata::distribution =
0153 std::uniform_real_distribution<double>(-M_PI, M_PI))) ^
0154 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 2,
0155 bdata::distribution =
0156 std::uniform_real_distribution<double>(-M_PI,
0157 M_PI))) ^
0158 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 3,
0159 bdata::distribution =
0160 std::uniform_real_distribution<double>(-M_PI,
0161 M_PI))) ^
0162 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 4,
0163 bdata::distribution =
0164 std::uniform_real_distribution<double>(-10., 10.))) ^
0165 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 5,
0166 bdata::distribution =
0167 std::uniform_real_distribution<double>(-10., 10.))) ^
0168 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 6,
0169 bdata::distribution =
0170 std::uniform_real_distribution<double>(-10., 10.))) ^
0171 bdata::xrange(100),
0172 alpha, beta, gamma, posX, posY, posZ, index) {
0173 (void)index;
0174
0175
0176 GeometryContext tgContext = GeometryContext();
0177
0178
0179 const Vector3 pos(posX, posY, posZ);
0180
0181 AngleAxis3 rotX(alpha, Vector3(1., 0., 0.));
0182
0183 AngleAxis3 rotY(beta, Vector3(0., 1., 0.));
0184
0185 AngleAxis3 rotZ(gamma, Vector3(0., 0., 1.));
0186
0187
0188 double rmin = 1.;
0189 double rmax = 2.;
0190 double halfz = 3.;
0191 CylinderVolumeBounds cylBounds(rmin, rmax, halfz);
0192
0193 auto transform = Transform3(Translation3(pos));
0194 transform *= rotZ;
0195 transform *= rotY;
0196 transform *= rotX;
0197
0198 auto boundarySurfaces = cylBounds.orientedSurfaces(transform);
0199
0200
0201
0202 CHECK_CLOSE_REL(
0203 (pos - boundarySurfaces.at(0).surface->center(tgContext)).norm(),
0204 cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
0205 CHECK_CLOSE_REL(
0206 (pos - boundarySurfaces.at(1).surface->center(tgContext)).norm(),
0207 cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
0208
0209 double posDiscPosZ =
0210 (transform.inverse() * boundarySurfaces.at(1).surface->center(tgContext))
0211 .z();
0212 double centerPosZ = (transform.inverse() * pos).z();
0213 double negDiscPosZ =
0214 (transform.inverse() * boundarySurfaces.at(0).surface->center(tgContext))
0215 .z();
0216
0217 BOOST_CHECK_LT(centerPosZ, posDiscPosZ);
0218 BOOST_CHECK_GT(centerPosZ, negDiscPosZ);
0219
0220
0221 CHECK_CLOSE_ABS(
0222 negDiscPosZ + cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
0223 centerPosZ, 1e-12);
0224 CHECK_CLOSE_ABS(
0225 posDiscPosZ - cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
0226 centerPosZ, 1e-12);
0227
0228
0229
0230 CHECK_CLOSE_REL(
0231 transform.rotation().col(2).dot(boundarySurfaces.at(1).surface->normal(
0232 tgContext, Acts::Vector2(0., 0.))),
0233 1., 1e-12);
0234
0235
0236 CHECK_CLOSE_REL(
0237 transform.rotation().col(2).dot(boundarySurfaces.at(0).surface->normal(
0238 tgContext, Acts::Vector2(0., 0.))),
0239 1., 1e-12);
0240
0241 CHECK_CLOSE_REL(boundarySurfaces.at(3).surface->center(tgContext), pos,
0242 1e-12);
0243 CHECK_CLOSE_REL(boundarySurfaces.at(2).surface->center(tgContext), pos,
0244 1e-12);
0245 }
0246
0247 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsBoundingBox) {
0248 GeometryContext tgContext = GeometryContext();
0249
0250 float tol = 1e-4;
0251
0252 CylinderVolumeBounds cvb(0., 5, 10);
0253 auto bb = cvb.boundingBox();
0254
0255 Transform3 rot;
0256 rot = AngleAxis3(M_PI / 2., Vector3::UnitX());
0257
0258 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0259 BOOST_CHECK_EQUAL(bb.max(), Vector3(5, 5, 10));
0260 BOOST_CHECK_EQUAL(bb.min(), Vector3(-5, -5, -10));
0261
0262 bb = cvb.boundingBox(&rot);
0263 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0264 CHECK_CLOSE_ABS(bb.max(), Vector3(5, 10, 5), tol);
0265 CHECK_CLOSE_ABS(bb.min(), Vector3(-5, -10, -5), tol);
0266
0267 cvb = CylinderVolumeBounds(5, 8, 12);
0268 bb = cvb.boundingBox();
0269 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0270 BOOST_CHECK_EQUAL(bb.max(), Vector3(8, 8, 12));
0271 BOOST_CHECK_EQUAL(bb.min(), Vector3(-8, -8, -12));
0272
0273 double angle = M_PI / 8.;
0274 cvb = CylinderVolumeBounds(5, 8, 13, angle);
0275 bb = cvb.boundingBox();
0276 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0277 CHECK_CLOSE_ABS(bb.max(), Vector3(8, 8 * std::sin(angle), 13), tol);
0278 CHECK_CLOSE_ABS(bb.min(),
0279 Vector3(5 * std::cos(angle), -8 * std::sin(angle), -13), tol);
0280
0281 rot = AngleAxis3(M_PI / 2., Vector3::UnitZ());
0282 bb = cvb.boundingBox(&rot);
0283 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0284 CHECK_CLOSE_ABS(bb.max(), Vector3(8 * std::sin(angle), 8, 13), tol);
0285 CHECK_CLOSE_ABS(bb.min(),
0286 Vector3(-8 * std::sin(angle), 5 * std::cos(angle), -13), tol);
0287
0288 rot = AngleAxis3(M_PI / 2., Vector3(-2, 4, 5).normalized());
0289 bb = cvb.boundingBox(&rot);
0290 BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0291 CHECK_CLOSE_ABS(bb.max(), Vector3(8.40007, 15.2828, 3.88911), tol);
0292 CHECK_CLOSE_ABS(bb.min(), Vector3(-7.27834, -8.12028, -14.2182), tol);
0293 }
0294
0295 BOOST_AUTO_TEST_CASE(CylinderVolumeOrientedBoundaries) {
0296 GeometryContext tgContext = GeometryContext();
0297
0298 CylinderVolumeBounds cvb(5, 10, 20);
0299
0300 auto cvbOrientedSurfaces = cvb.orientedSurfaces(Transform3::Identity());
0301 BOOST_CHECK_EQUAL(cvbOrientedSurfaces.size(), 4);
0302
0303 auto geoCtx = GeometryContext();
0304 Vector3 xaxis(1., 0., 0.);
0305 Vector3 yaxis(0., 1., 0.);
0306 Vector3 zaxis(0., 0., 1.);
0307
0308 for (auto& os : cvbOrientedSurfaces) {
0309 auto onSurface = os.surface->binningPosition(geoCtx, binR);
0310 auto locPos =
0311 os.surface->globalToLocal(geoCtx, onSurface, Vector3::Zero()).value();
0312 auto osNormal = os.surface->normal(geoCtx, locPos);
0313
0314 Vector3 insideCvb = onSurface + os.direction * osNormal;
0315 Vector3 outsideCvb = onSurface - os.direction * osNormal;
0316
0317 BOOST_CHECK(cvb.inside(insideCvb));
0318 BOOST_CHECK(!cvb.inside(outsideCvb));
0319
0320
0321 auto rot = os.surface->transform(geoCtx).rotation();
0322 BOOST_CHECK(rot.col(0).isApprox(xaxis));
0323 BOOST_CHECK(rot.col(1).isApprox(yaxis));
0324 BOOST_CHECK(rot.col(2).isApprox(zaxis));
0325 }
0326 }
0327
0328 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsSetValues) {
0329 CylinderVolumeBounds cyl(100, 300, 200);
0330
0331 BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eMinR, 400),
0332 std::invalid_argument);
0333 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 100);
0334
0335 cyl.set(CylinderVolumeBounds::eMinR, 200);
0336 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 200);
0337
0338 BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eMaxR, 50),
0339 std::invalid_argument);
0340 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 300);
0341
0342 cyl.set(CylinderVolumeBounds::eMaxR, 250);
0343 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 250);
0344
0345 BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eHalfLengthZ, -200),
0346 std::invalid_argument);
0347 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 200);
0348
0349 cyl.set(CylinderVolumeBounds::eHalfLengthZ, 250);
0350 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 250);
0351
0352 cyl.set(CylinderVolumeBounds::eHalfLengthZ, 150);
0353 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 150);
0354
0355 BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eHalfPhiSector, -M_PI),
0356 std::invalid_argument);
0357 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector), M_PI);
0358
0359 BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eHalfPhiSector, 1.5 * M_PI),
0360 std::invalid_argument);
0361 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector), M_PI);
0362
0363 cyl.set(CylinderVolumeBounds::eHalfPhiSector, M_PI / 2);
0364 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector), M_PI / 2);
0365
0366 for (auto bValue :
0367 {CylinderVolumeBounds::eAveragePhi, CylinderVolumeBounds::eBevelMaxZ,
0368 CylinderVolumeBounds::eBevelMinZ}) {
0369 BOOST_CHECK_THROW(cyl.set(bValue, -1.5 * M_PI), std::invalid_argument);
0370 BOOST_CHECK_EQUAL(cyl.get(bValue), 0);
0371
0372 BOOST_CHECK_THROW(cyl.set(bValue, 1.5 * M_PI), std::invalid_argument);
0373 BOOST_CHECK_EQUAL(cyl.get(bValue), 0);
0374
0375 cyl.set(bValue, 0.5 * M_PI);
0376 BOOST_CHECK_EQUAL(cyl.get(bValue), 0.5 * M_PI);
0377 cyl.set(bValue, -0.5 * M_PI);
0378 BOOST_CHECK_EQUAL(cyl.get(bValue), -0.5 * M_PI);
0379 }
0380
0381 cyl = CylinderVolumeBounds(100, 300, 200);
0382 auto previous = cyl.values();
0383
0384 BOOST_CHECK_THROW(cyl.set({
0385 {CylinderVolumeBounds::eMinR, 50},
0386 {CylinderVolumeBounds::eMaxR, 200},
0387 {CylinderVolumeBounds::eHalfLengthZ, -1},
0388 }),
0389 std::logic_error);
0390 auto act = cyl.values();
0391 BOOST_CHECK_EQUAL_COLLECTIONS(previous.begin(), previous.end(), act.begin(),
0392 act.end());
0393
0394 cyl.set({
0395 {CylinderVolumeBounds::eMinR, 50},
0396 {CylinderVolumeBounds::eMaxR, 200},
0397 {CylinderVolumeBounds::eHalfLengthZ, 150},
0398 });
0399
0400 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 50);
0401 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 200);
0402 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 150);
0403 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector), M_PI);
0404 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eAveragePhi), 0);
0405 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eBevelMinZ), 0);
0406 BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eBevelMaxZ), 0);
0407 }
0408
0409 BOOST_AUTO_TEST_SUITE_END()
0410 }
0411 }