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