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