File indexing completed on 2025-02-23 09:15:51
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/detail/log_level.hpp>
0011 #include <boost/test/tools/context.hpp>
0012 #include <boost/test/tools/old/interface.hpp>
0013 #include <boost/test/unit_test.hpp>
0014 #include <boost/test/unit_test_log.hpp>
0015 #include <boost/test/unit_test_parameters.hpp>
0016 #include <boost/test/unit_test_suite.hpp>
0017
0018 #include "Acts/Definitions/Algebra.hpp"
0019 #include "Acts/Definitions/Units.hpp"
0020 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0021 #include "Acts/Geometry/CuboidVolumeStack.hpp"
0022 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0023 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
0024 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0025 #include "Acts/Utilities/AxisDefinitions.hpp"
0026 #include "Acts/Utilities/Logger.hpp"
0027 #include "Acts/Utilities/ThrowAssert.hpp"
0028 #include "Acts/Utilities/Zip.hpp"
0029
0030 #include <cassert>
0031 #include <initializer_list>
0032 #include <stdexcept>
0033 #include <utility>
0034
0035 using namespace Acts::UnitLiterals;
0036
0037 namespace Acts::Test {
0038
0039 auto logger = Acts::getDefaultLogger("UnitTests", Acts::Logging::VERBOSE);
0040
0041 struct Fixture {
0042 Logging::Level m_level;
0043 Fixture() {
0044 m_level = Acts::Logging::getFailureThreshold();
0045 Acts::Logging::setFailureThreshold(Acts::Logging::FATAL);
0046 }
0047
0048 ~Fixture() { Acts::Logging::setFailureThreshold(m_level); }
0049 };
0050
0051 BOOST_FIXTURE_TEST_SUITE(Geometry, Fixture)
0052
0053 static const std::vector<VolumeAttachmentStrategy> strategies = {
0054 VolumeAttachmentStrategy::Gap,
0055 VolumeAttachmentStrategy::First,
0056 VolumeAttachmentStrategy::Second,
0057 VolumeAttachmentStrategy::Midpoint,
0058 };
0059
0060 static const std::vector<VolumeResizeStrategy> resizeStrategies = {
0061 VolumeResizeStrategy::Expand,
0062 VolumeResizeStrategy::Gap,
0063 };
0064
0065 BOOST_AUTO_TEST_SUITE(CuboidVolumeStackTest)
0066
0067 BOOST_DATA_TEST_CASE(BaselineLocal,
0068 (boost::unit_test::data::xrange(-135, 180, 45) *
0069 boost::unit_test::data::xrange(0, 2, 1) *
0070 boost::unit_test::data::make(0.8, 1.0, 1.2) *
0071 boost::unit_test::data::make(Vector3{0_mm, 0_mm, 0_mm},
0072 Vector3{20_mm, 0_mm, 0_mm},
0073 Vector3{0_mm, 20_mm, 0_mm},
0074 Vector3{20_mm, 20_mm, 0_mm},
0075 Vector3{0_mm, 0_mm, 20_mm}) *
0076 boost::unit_test::data::make(strategies) *
0077 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
0078 Acts::AxisDirection::AxisY,
0079 Acts::AxisDirection::AxisZ)),
0080 angle, rotate, shift, offset, strategy, dir) {
0081 double halfDir = 400_mm;
0082
0083 auto [dirOrth1, dirOrth2] = CuboidVolumeStack::getOrthogonalAxes(dir);
0084
0085 auto dirIdx = CuboidVolumeStack::axisToIndex(dir);
0086 auto dirOrth1Idx = CuboidVolumeStack::axisToIndex(dirOrth1);
0087
0088 auto boundDir = CuboidVolumeBounds::fromAxisDirection(dir);
0089 auto boundDirOrth1 = CuboidVolumeBounds::fromAxisDirection(dirOrth1);
0090 auto boundDirOrth2 = CuboidVolumeBounds::fromAxisDirection(dirOrth2);
0091
0092 auto bounds1 = std::make_shared<CuboidVolumeBounds>(
0093 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0094 {boundDir, halfDir},
0095 {boundDirOrth1, 100_mm},
0096 {boundDirOrth2, 400_mm}});
0097
0098 auto bounds2 = std::make_shared<CuboidVolumeBounds>(
0099 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0100 {boundDir, halfDir},
0101 {boundDirOrth1, 200_mm},
0102 {boundDirOrth2, 600_mm}});
0103
0104 auto bounds3 = std::make_shared<CuboidVolumeBounds>(
0105 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0106 {boundDir, halfDir},
0107 {boundDirOrth1, 300_mm},
0108 {boundDirOrth2, 500_mm}});
0109
0110 Transform3 base = AngleAxis3(angle * 1_degree, Vector3::Unit(dirOrth1Idx)) *
0111 Translation3(offset);
0112
0113 Translation3 translation1(Vector3::Unit(dirIdx) * (-2 * halfDir * shift));
0114 Transform3 transform1 = base * translation1;
0115 auto vol1 = std::make_shared<Volume>(transform1, bounds1);
0116
0117 Transform3 transform2 = base;
0118 auto vol2 = std::make_shared<Volume>(transform2, bounds2);
0119
0120 Translation3 translation3(Vector3::Unit(dirIdx) * (2 * halfDir * shift));
0121 Transform3 transform3 = base * translation3;
0122 auto vol3 = std::make_shared<Volume>(transform3, bounds3);
0123
0124 std::vector<Volume*> volumes = {vol1.get(), vol2.get(), vol3.get()};
0125
0126 std::rotate(volumes.begin(), volumes.begin() + rotate, volumes.end());
0127
0128 auto origVolumes = volumes;
0129
0130 std::vector<CuboidVolumeBounds> originalBounds;
0131 std::transform(volumes.begin(), volumes.end(),
0132 std::back_inserter(originalBounds), [](const auto& vol) {
0133 const auto* res =
0134 dynamic_cast<CuboidVolumeBounds*>(&vol->volumeBounds());
0135 throw_assert(res != nullptr, "");
0136 return *res;
0137 });
0138
0139 if (shift < 1.0) {
0140 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, dir, strategy,
0141 VolumeResizeStrategy::Gap, *logger),
0142 std::invalid_argument);
0143 return;
0144 }
0145 CuboidVolumeStack stack(volumes, dir, strategy, VolumeResizeStrategy::Gap,
0146 *logger);
0147
0148 auto stackBounds =
0149 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0150 BOOST_REQUIRE(stackBounds != nullptr);
0151
0152 BOOST_CHECK_CLOSE(stackBounds->get(boundDirOrth1), 300_mm, 1e-6);
0153 BOOST_CHECK_CLOSE(stackBounds->get(boundDirOrth2), 600_mm, 1e-6);
0154 BOOST_CHECK_CLOSE(stackBounds->get(boundDir), halfDir + 2 * halfDir * shift,
0155 1e-6);
0156 CHECK_CLOSE_OR_SMALL(stack.transform().matrix(), base.matrix(), 1e-10, 1e-12);
0157
0158
0159
0160 for (const auto& volume : volumes) {
0161 const auto* cuboidBounds =
0162 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0163 BOOST_REQUIRE(cuboidBounds != nullptr);
0164 BOOST_CHECK_CLOSE(cuboidBounds->get(boundDirOrth1), 300_mm, 1e-6);
0165 BOOST_CHECK_CLOSE(cuboidBounds->get(boundDirOrth2), 600_mm, 1e-6);
0166 }
0167
0168
0169 for (std::size_t i = 0; i < volumes.size() - 1; ++i) {
0170 const auto& a = volumes.at(i);
0171 const auto& b = volumes.at(i + 1);
0172
0173 BOOST_CHECK_LT((base.inverse() * a->center())[dirIdx],
0174 (base.inverse() * b->center())[dirIdx]);
0175 }
0176
0177 if (shift <= 1.0) {
0178
0179 BOOST_CHECK_EQUAL(volumes.size(), 3);
0180
0181
0182 BOOST_CHECK_EQUAL(vol1->transform().matrix(), transform1.matrix());
0183 BOOST_CHECK_EQUAL(vol2->transform().matrix(), transform2.matrix());
0184 BOOST_CHECK_EQUAL(vol3->transform().matrix(), transform3.matrix());
0185
0186 for (const auto& [volume, bounds] : zip(origVolumes, originalBounds)) {
0187 const auto* newBounds =
0188 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0189 BOOST_CHECK_CLOSE(newBounds->get(boundDir), bounds.get(boundDir), 1e-6);
0190 }
0191 } else {
0192 if (strategy == VolumeAttachmentStrategy::Gap) {
0193
0194 BOOST_CHECK_EQUAL(volumes.size(), 5);
0195 auto gap1 = volumes.at(1);
0196 auto gap2 = volumes.at(3);
0197
0198 BOOST_TEST_MESSAGE("Gap 1: " << gap1->transform().matrix());
0199 BOOST_TEST_MESSAGE("Gap 2: " << gap2->transform().matrix());
0200
0201 const auto* gapBounds1 =
0202 dynamic_cast<const CuboidVolumeBounds*>(&gap1->volumeBounds());
0203 const auto* gapBounds2 =
0204 dynamic_cast<const CuboidVolumeBounds*>(&gap2->volumeBounds());
0205
0206 double gapHlDir = (shift - 1.0) * halfDir;
0207
0208 BOOST_CHECK(std::abs(gapBounds1->get(boundDir) - gapHlDir) < 1e-12);
0209 BOOST_CHECK(std::abs(gapBounds2->get(boundDir) - gapHlDir) < 1e-12);
0210
0211 double gap1Dir = (-2 * halfDir * shift) + halfDir + gapHlDir;
0212 double gap2Dir = (2 * halfDir * shift) - halfDir - gapHlDir;
0213
0214 Translation3 gap1Translation(Vector3::Unit(dirIdx) * gap1Dir);
0215 Translation3 gap2Translation(Vector3::Unit(dirIdx) * gap2Dir);
0216
0217 Transform3 gap1Transform = base * gap1Translation;
0218 Transform3 gap2Transform = base * gap2Translation;
0219
0220 CHECK_CLOSE_OR_SMALL(gap1->transform().matrix(), gap1Transform.matrix(),
0221 1e-10, 1e-12);
0222 CHECK_CLOSE_OR_SMALL(gap2->transform().matrix(), gap2Transform.matrix(),
0223 1e-10, 1e-12);
0224
0225
0226 for (const auto& [volume, bounds] : zip(origVolumes, originalBounds)) {
0227 const auto* newBounds =
0228 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0229 BOOST_CHECK_CLOSE(newBounds->get(boundDir), bounds.get(boundDir), 1e-6);
0230 }
0231
0232
0233 BOOST_CHECK_EQUAL(vol1->transform().matrix(), transform1.matrix());
0234 BOOST_CHECK_EQUAL(vol2->transform().matrix(), transform2.matrix());
0235 BOOST_CHECK_EQUAL(vol3->transform().matrix(), transform3.matrix());
0236 } else if (strategy == VolumeAttachmentStrategy::First) {
0237
0238 BOOST_CHECK_EQUAL(volumes.size(), 3);
0239
0240 double wGap = (shift - 1.0) * halfDir * 2;
0241
0242
0243 auto newBounds1 =
0244 dynamic_cast<const CuboidVolumeBounds*>(&vol1->volumeBounds());
0245 BOOST_CHECK_CLOSE(newBounds1->get(boundDir), halfDir + wGap / 2.0, 1e-6);
0246 double pDir1 = -2 * halfDir * shift + wGap / 2.0;
0247 Translation3 expectedTranslation1(Vector3::Unit(dirIdx) * pDir1);
0248 Transform3 expectedTransform1 = base * expectedTranslation1;
0249 CHECK_CLOSE_OR_SMALL(vol1->transform().matrix(),
0250 expectedTransform1.matrix(), 1e-10, 1e-12);
0251
0252
0253 auto newBounds2 =
0254 dynamic_cast<const CuboidVolumeBounds*>(&vol2->volumeBounds());
0255 BOOST_CHECK_CLOSE(newBounds2->get(boundDir), halfDir + wGap / 2.0, 1e-6);
0256 double pDir2 = wGap / 2.0;
0257 Translation3 expectedTranslation2(Vector3::Unit(dirIdx) * pDir2);
0258 Transform3 expectedTransform2 = base * expectedTranslation2;
0259 CHECK_CLOSE_OR_SMALL(vol2->transform().matrix(),
0260 expectedTransform2.matrix(), 1e-10, 1e-12);
0261
0262
0263 auto newBounds3 =
0264 dynamic_cast<const CuboidVolumeBounds*>(&vol3->volumeBounds());
0265 BOOST_CHECK_CLOSE(newBounds3->get(boundDir), halfDir, 1e-6);
0266 double pDir3 = 2 * halfDir * shift;
0267 Translation3 expectedTranslation3(Vector3::Unit(dirIdx) * pDir3);
0268 Transform3 expectedTransform3 = base * expectedTranslation3;
0269 CHECK_CLOSE_OR_SMALL(vol3->transform().matrix(),
0270 expectedTransform3.matrix(), 1e-10, 1e-12);
0271 } else if (strategy == VolumeAttachmentStrategy::Second) {
0272
0273 BOOST_CHECK_EQUAL(volumes.size(), 3);
0274
0275 double wGap = (shift - 1.0) * halfDir * 2;
0276
0277
0278 auto newBounds1 =
0279 dynamic_cast<const CuboidVolumeBounds*>(&vol1->volumeBounds());
0280 BOOST_CHECK_CLOSE(newBounds1->get(boundDir), halfDir, 1e-6);
0281 double pDir1 = -2 * halfDir * shift;
0282 Translation3 expectedTranslation1(Vector3::Unit(dirIdx) * pDir1);
0283 Transform3 expectedTransform1 = base * expectedTranslation1;
0284 CHECK_CLOSE_OR_SMALL(vol1->transform().matrix(),
0285 expectedTransform1.matrix(), 1e-10, 1e-12);
0286
0287
0288 auto newBounds2 =
0289 dynamic_cast<const CuboidVolumeBounds*>(&vol2->volumeBounds());
0290 BOOST_CHECK_CLOSE(newBounds2->get(boundDir), halfDir + wGap / 2.0, 1e-6);
0291 double pDir2 = -wGap / 2.0;
0292 Translation3 expectedTranslation2(Vector3::Unit(dirIdx) * pDir2);
0293 Transform3 expectedTransform2 = base * expectedTranslation2;
0294 CHECK_CLOSE_OR_SMALL(vol2->transform().matrix(),
0295 expectedTransform2.matrix(), 1e-10, 1e-12);
0296
0297
0298 auto newBounds3 =
0299 dynamic_cast<const CuboidVolumeBounds*>(&vol3->volumeBounds());
0300 BOOST_CHECK_CLOSE(newBounds3->get(boundDir), halfDir + wGap / 2.0, 1e-6);
0301 double pDir3 = 2 * halfDir * shift - wGap / 2.0;
0302 Translation3 expectedTranslation3(Vector3::Unit(dirIdx) * pDir3);
0303 Transform3 expectedTransform3 = base * expectedTranslation3;
0304 CHECK_CLOSE_OR_SMALL(vol3->transform().matrix(),
0305 expectedTransform3.matrix(), 1e-10, 1e-12);
0306 } else if (strategy == VolumeAttachmentStrategy::Midpoint) {
0307
0308 BOOST_CHECK_EQUAL(volumes.size(), 3);
0309
0310 double wGap = (shift - 1.0) * halfDir * 2;
0311
0312
0313 auto newBounds1 =
0314 dynamic_cast<const CuboidVolumeBounds*>(&vol1->volumeBounds());
0315 BOOST_CHECK_CLOSE(newBounds1->get(boundDir), halfDir + wGap / 4.0, 1e-6);
0316 double pDir1 = -2 * halfDir * shift + wGap / 4.0;
0317 Translation3 expectedTranslation1(Vector3::Unit(dirIdx) * pDir1);
0318 Transform3 expectedTransform1 = base * expectedTranslation1;
0319 CHECK_CLOSE_OR_SMALL(vol1->transform().matrix(),
0320 expectedTransform1.matrix(), 1e-10, 1e-12);
0321
0322
0323 auto newBounds2 =
0324 dynamic_cast<const CuboidVolumeBounds*>(&vol2->volumeBounds());
0325 BOOST_CHECK_CLOSE(newBounds2->get(boundDir), halfDir + wGap / 2.0, 1e-6);
0326 CHECK_CLOSE_OR_SMALL(vol2->transform().matrix(), base.matrix(), 1e-10,
0327 1e-12);
0328
0329
0330 auto newBounds3 =
0331 dynamic_cast<const CuboidVolumeBounds*>(&vol3->volumeBounds());
0332 BOOST_CHECK_CLOSE(newBounds3->get(boundDir), halfDir + wGap / 4.0, 1e-6);
0333 double pDir3 = 2 * halfDir * shift - wGap / 4.0;
0334 Translation3 expectedTranslation3(Vector3::Unit(dirIdx) * pDir3);
0335 Transform3 expectedTransform3 = base * expectedTranslation3;
0336 CHECK_CLOSE_OR_SMALL(vol3->transform().matrix(),
0337 expectedTransform3.matrix(), 1e-10, 1e-12);
0338 }
0339 }
0340 }
0341
0342 BOOST_DATA_TEST_CASE(BaselineGlobal,
0343 (boost::unit_test::data::xrange(-135, 180, 45) *
0344 boost::unit_test::data::xrange(0, 2, 1) *
0345 boost::unit_test::data::make(1.0, 1.2) *
0346 boost::unit_test::data::make(Vector3{0_mm, 0_mm, 0_mm},
0347 Vector3{20_mm, 0_mm, 0_mm},
0348 Vector3{0_mm, 20_mm, 0_mm},
0349 Vector3{20_mm, 20_mm, 0_mm},
0350 Vector3{0_mm, 0_mm, 20_mm}) *
0351 boost::unit_test::data::make(strategies)),
0352 angle, rotate, shift, offset, strategy) {
0353 double halfDir = 400_mm;
0354
0355 auto bounds1 = std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, halfDir);
0356 auto bounds2 = std::make_shared<CuboidVolumeBounds>(200_mm, 600_mm, halfDir);
0357 auto bounds3 = std::make_shared<CuboidVolumeBounds>(300_mm, 500_mm, halfDir);
0358
0359 AngleAxis3 baseRotation = AngleAxis3(angle, Vector3::UnitX());
0360 Transform3 base = baseRotation * Translation3(offset);
0361
0362 Vector3 orientation = baseRotation * Vector3::UnitZ();
0363
0364 Translation3 translation1(Vector3::UnitZ() * (-2 * halfDir * shift));
0365 Transform3 transform1 = base * translation1;
0366 auto vol1Orientation = std::make_shared<Volume>(transform1, bounds1);
0367 auto vol1AxisDirection = std::make_shared<Volume>(transform1, bounds1);
0368
0369 Transform3 transform2 = base;
0370 auto vol2Orientation = std::make_shared<Volume>(transform2, bounds2);
0371 auto vol2AxisDirection = std::make_shared<Volume>(transform2, bounds2);
0372
0373 Translation3 translation3(Vector3::UnitZ() * (2 * halfDir * shift));
0374 Transform3 transform3 = base * translation3;
0375 auto vol3Orientation = std::make_shared<Volume>(transform3, bounds3);
0376 auto vol3AxisDirection = std::make_shared<Volume>(transform3, bounds3);
0377
0378 std::vector<Volume*> volumesOrientation = {
0379 vol1Orientation.get(), vol2Orientation.get(), vol3Orientation.get()};
0380 std::vector<Volume*> volumesAxisDirection = {vol1AxisDirection.get(),
0381 vol2AxisDirection.get(),
0382 vol3AxisDirection.get()};
0383
0384
0385 std::rotate(volumesOrientation.begin(), volumesOrientation.begin() + rotate,
0386 volumesOrientation.end());
0387 std::rotate(volumesAxisDirection.begin(),
0388 volumesAxisDirection.begin() + rotate,
0389 volumesAxisDirection.end());
0390
0391 CuboidVolumeStack stackOrientation(volumesOrientation, orientation, strategy,
0392 VolumeResizeStrategy::Gap, *logger);
0393 CuboidVolumeStack stackAxisDirection(volumesAxisDirection,
0394 AxisDirection::AxisZ, strategy,
0395 VolumeResizeStrategy::Gap, *logger);
0396
0397 auto stackBoundsOrientation =
0398 dynamic_cast<const CuboidVolumeBounds*>(&stackOrientation.volumeBounds());
0399 auto stackBoundsAxisDirection = dynamic_cast<const CuboidVolumeBounds*>(
0400 &stackAxisDirection.volumeBounds());
0401
0402
0403
0404 BOOST_CHECK_NE(stackBoundsOrientation, nullptr);
0405 BOOST_CHECK_NE(stackBoundsAxisDirection, nullptr);
0406 BOOST_CHECK_EQUAL(*stackBoundsOrientation, *stackBoundsAxisDirection);
0407 CHECK_CLOSE_OR_SMALL(stackOrientation.transform().matrix(),
0408 stackAxisDirection.transform().matrix(), 1e-10, 1e-12);
0409 }
0410
0411 BOOST_DATA_TEST_CASE(Asymmetric,
0412 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
0413 Acts::AxisDirection::AxisY,
0414 Acts::AxisDirection::AxisZ),
0415 dir) {
0416 double halfDir1 = 200_mm;
0417 double pDir1 = -1100_mm;
0418 double halfDir2 = 600_mm;
0419 double pDir2 = -200_mm;
0420 double halfDir3 = 400_mm;
0421 double pDir3 = 850_mm;
0422
0423 auto [dirOrth1, dirOrth2] = CuboidVolumeStack::getOrthogonalAxes(dir);
0424
0425 auto dirIdx = CuboidVolumeStack::axisToIndex(dir);
0426
0427 auto boundDir = CuboidVolumeBounds::fromAxisDirection(dir);
0428 auto boundDirOrth1 = CuboidVolumeBounds::fromAxisDirection(dirOrth1);
0429 auto boundDirOrth2 = CuboidVolumeBounds::fromAxisDirection(dirOrth2);
0430
0431 auto bounds1 = std::make_shared<CuboidVolumeBounds>(
0432 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0433 {boundDir, halfDir1},
0434 {boundDirOrth1, 100_mm},
0435 {boundDirOrth2, 400_mm}});
0436
0437 auto bounds2 = std::make_shared<CuboidVolumeBounds>(
0438 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0439 {boundDir, halfDir2},
0440 {boundDirOrth1, 200_mm},
0441 {boundDirOrth2, 600_mm}});
0442
0443 auto bounds3 = std::make_shared<CuboidVolumeBounds>(
0444 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0445 {boundDir, halfDir3},
0446 {boundDirOrth1, 300_mm},
0447 {boundDirOrth2, 500_mm}});
0448
0449 Translation3 translation1(Vector3::Unit(dirIdx) * pDir1);
0450 Transform3 transform1(translation1);
0451 auto vol1 = std::make_shared<Volume>(transform1, bounds1);
0452
0453 Translation3 translation2(Vector3::Unit(dirIdx) * pDir2);
0454 Transform3 transform2(translation2);
0455 auto vol2 = std::make_shared<Volume>(transform2, bounds2);
0456
0457 Translation3 translation3(Vector3::Unit(dirIdx) * pDir3);
0458 Transform3 transform3(translation3);
0459 auto vol3 = std::make_shared<Volume>(transform3, bounds3);
0460
0461 std::vector<Volume*> volumes = {vol2.get(), vol1.get(), vol3.get()};
0462
0463 CuboidVolumeStack stack(volumes, dir, VolumeAttachmentStrategy::Gap,
0464 VolumeResizeStrategy::Gap, *logger);
0465 BOOST_CHECK_EQUAL(volumes.size(), 5);
0466
0467 auto stackBounds =
0468 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0469 BOOST_REQUIRE(stackBounds != nullptr);
0470
0471 BOOST_CHECK_CLOSE(stackBounds->get(boundDirOrth1), 300_mm, 1e-6);
0472 BOOST_CHECK_CLOSE(stackBounds->get(boundDirOrth2), 600_mm, 1e-6);
0473 BOOST_CHECK_CLOSE(stackBounds->get(boundDir),
0474 (std::abs(pDir1 - halfDir1) + pDir3 + halfDir3) / 2.0,
0475 1e-6);
0476
0477 double midDir = (pDir1 - halfDir1 + pDir3 + halfDir3) / 2.0;
0478 Translation3 expectedTranslation(Vector3::Unit(dirIdx) * midDir);
0479 Transform3 expectedTransform = Transform3::Identity() * expectedTranslation;
0480 CHECK_CLOSE_OR_SMALL(stack.transform().matrix(), expectedTransform.matrix(),
0481 1e-10, 1e-12);
0482 }
0483
0484 BOOST_DATA_TEST_CASE(UpdateStack,
0485 (boost::unit_test::data::xrange(-135, 180, 45) *
0486 boost::unit_test::data::make(Vector3{0_mm, 0_mm, 0_mm},
0487 Vector3{20_mm, 0_mm, 0_mm},
0488 Vector3{0_mm, 20_mm, 0_mm},
0489 Vector3{20_mm, 20_mm, 0_mm},
0490 Vector3{0_mm, 0_mm, 20_mm}) *
0491 boost::unit_test::data::make(-100_mm, 0_mm, 100_mm) *
0492 boost::unit_test::data::make(resizeStrategies) *
0493 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
0494 Acts::AxisDirection::AxisY,
0495 Acts::AxisDirection::AxisZ)),
0496 angle, offset, zshift, strategy, dir) {
0497 double halfDir = 400_mm;
0498
0499 auto [dirOrth1, dirOrth2] = CuboidVolumeStack::getOrthogonalAxes(dir);
0500
0501 auto dirIdx = CuboidVolumeStack::axisToIndex(dir);
0502 auto dirOrth1Idx = CuboidVolumeStack::axisToIndex(dirOrth1);
0503
0504 auto boundDir = CuboidVolumeBounds::fromAxisDirection(dir);
0505 auto boundDirOrth1 = CuboidVolumeBounds::fromAxisDirection(dirOrth1);
0506 auto boundDirOrth2 = CuboidVolumeBounds::fromAxisDirection(dirOrth2);
0507
0508 auto bounds1 = std::make_shared<CuboidVolumeBounds>(
0509 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0510 {boundDir, halfDir},
0511 {boundDirOrth1, 100_mm},
0512 {boundDirOrth2, 600_mm}});
0513
0514 auto bounds2 = std::make_shared<CuboidVolumeBounds>(
0515 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0516 {boundDir, halfDir},
0517 {boundDirOrth1, 100_mm},
0518 {boundDirOrth2, 600_mm}});
0519
0520 auto bounds3 = std::make_shared<CuboidVolumeBounds>(
0521 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0522 {boundDir, halfDir},
0523 {boundDirOrth1, 100_mm},
0524 {boundDirOrth2, 600_mm}});
0525
0526 Vector3 shift = Vector3::Unit(dirIdx) * zshift;
0527 Transform3 base = AngleAxis3(angle * 1_degree, Vector3::Unit(dirOrth1Idx)) *
0528 Translation3(offset + shift);
0529
0530 Translation3 translation1(Vector3::Unit(dirIdx) * -2 * halfDir);
0531 Transform3 transform1 = base * translation1;
0532 auto vol1 = std::make_shared<Volume>(transform1, bounds1);
0533
0534 Transform3 transform2 = base;
0535 auto vol2 = std::make_shared<Volume>(transform2, bounds2);
0536
0537 Translation3 translation3(Vector3::Unit(dirIdx) * 2 * halfDir);
0538 Transform3 transform3 = base * translation3;
0539 auto vol3 = std::make_shared<Volume>(transform3, bounds3);
0540
0541 std::vector<Volume*> volumes = {vol1.get(), vol2.get(), vol3.get()};
0542 std::vector<Volume*> originalVolumes = volumes;
0543
0544 std::vector<Transform3> originalTransforms = {transform1, transform2,
0545 transform3};
0546
0547 CuboidVolumeStack stack(volumes, dir,
0548 VolumeAttachmentStrategy::Gap,
0549
0550 strategy, *logger);
0551
0552 const auto* originalBounds =
0553 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0554
0555 auto assertOriginalBounds = [&]() {
0556 const auto* bounds =
0557 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0558 BOOST_REQUIRE(bounds != nullptr);
0559 BOOST_CHECK_EQUAL(bounds, originalBounds);
0560 BOOST_CHECK_CLOSE(bounds->get(boundDirOrth1), 100_mm, 1e-6);
0561 BOOST_CHECK_CLOSE(bounds->get(boundDirOrth2), 600_mm, 1e-6);
0562 BOOST_CHECK_CLOSE(bounds->get(boundDir), 3 * halfDir, 1e-6);
0563 };
0564
0565 assertOriginalBounds();
0566
0567 {
0568
0569 auto bounds = std::make_shared<CuboidVolumeBounds>(
0570 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0571 stack.update(bounds, std::nullopt, *logger);
0572 assertOriginalBounds();
0573 }
0574
0575 {
0576
0577 auto bounds = std::make_shared<CuboidVolumeBounds>(
0578 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0579 bounds->set(boundDirOrth1, 20_mm);
0580 BOOST_CHECK_THROW(stack.update(bounds, std::nullopt, *logger),
0581 std::invalid_argument);
0582 assertOriginalBounds();
0583 }
0584
0585 {
0586
0587 auto bounds = std::make_shared<CuboidVolumeBounds>(
0588 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0589 bounds->set(boundDirOrth2, 200_mm);
0590 BOOST_CHECK_THROW(stack.update(bounds, std::nullopt, *logger),
0591 std::invalid_argument);
0592 assertOriginalBounds();
0593 }
0594
0595 {
0596
0597 auto bounds = std::make_shared<CuboidVolumeBounds>(
0598 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0599 bounds->set(boundDir, 2 * halfDir);
0600 BOOST_CHECK_THROW(stack.update(bounds, std::nullopt, *logger),
0601 std::invalid_argument);
0602 assertOriginalBounds();
0603 }
0604
0605 {
0606
0607 auto bounds = std::make_shared<CuboidVolumeBounds>(
0608 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0609 bounds->set(boundDirOrth1, 700_mm);
0610 stack.update(bounds, std::nullopt, *logger);
0611 const auto* updatedBounds =
0612 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0613 BOOST_REQUIRE(updatedBounds != nullptr);
0614 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth1), 700_mm, 1e-6);
0615 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth2), 600_mm, 1e-6);
0616 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 3 * halfDir, 1e-6);
0617
0618
0619 BOOST_CHECK_EQUAL(volumes.size(), 3);
0620
0621
0622 for (const auto& [volume, origTransform] :
0623 zip(volumes, originalTransforms)) {
0624 const auto* newBounds =
0625 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0626 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth1), 700_mm, 1e-6);
0627 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth2), 600_mm, 1e-6);
0628 BOOST_CHECK_CLOSE(newBounds->get(boundDir), halfDir, 1e-6);
0629
0630
0631 BOOST_CHECK_EQUAL(volume->transform().matrix(), origTransform.matrix());
0632 }
0633 }
0634 {
0635
0636 auto bounds = std::make_shared<CuboidVolumeBounds>(
0637 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0638 bounds->set(boundDirOrth2, 700_mm);
0639 stack.update(bounds, std::nullopt, *logger);
0640 const auto* updatedBounds =
0641 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0642 BOOST_REQUIRE(updatedBounds != nullptr);
0643 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth1), 700_mm, 1e-6);
0644 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth2), 700_mm, 1e-6);
0645 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 3 * halfDir, 1e-6);
0646
0647
0648 BOOST_CHECK_EQUAL(volumes.size(), 3);
0649
0650
0651 for (const auto& [volume, origTransform] :
0652 zip(volumes, originalTransforms)) {
0653 const auto* newBounds =
0654 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0655 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth1), 700_mm, 1e-6);
0656 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth2), 700_mm, 1e-6);
0657 BOOST_CHECK_CLOSE(newBounds->get(boundDir), halfDir, 1e-6);
0658
0659
0660 BOOST_CHECK_EQUAL(volume->transform().matrix(), origTransform.matrix());
0661 }
0662 }
0663
0664 {
0665
0666 auto bounds = std::make_shared<CuboidVolumeBounds>(
0667 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0668 bounds->set(boundDir, 4 * halfDir);
0669 stack.update(bounds, std::nullopt, *logger);
0670 const auto* updatedBounds =
0671 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0672 BOOST_REQUIRE(updatedBounds != nullptr);
0673 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 4 * halfDir, 1e-6);
0674 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth1), 700_mm, 1e-6);
0675 BOOST_CHECK_CLOSE(updatedBounds->get(boundDirOrth2), 700_mm, 1e-6);
0676
0677 if (strategy == VolumeResizeStrategy::Expand) {
0678
0679 BOOST_CHECK_EQUAL(volumes.size(), 3);
0680
0681
0682 auto newBounds1 =
0683 dynamic_cast<const CuboidVolumeBounds*>(&vol1->volumeBounds());
0684 BOOST_CHECK_CLOSE(newBounds1->get(boundDir), halfDir + halfDir / 2.0,
0685 1e-6);
0686 auto expectedTranslation1 =
0687 Translation3(Vector3::Unit(dirIdx) * (-2 * halfDir - halfDir / 2.0));
0688 Transform3 expectedTransform1 = base * expectedTranslation1;
0689 CHECK_CLOSE_OR_SMALL(vol1->transform().matrix(),
0690 expectedTransform1.matrix(), 1e-10, 1e-12);
0691
0692
0693 auto newBounds2 =
0694 dynamic_cast<const CuboidVolumeBounds*>(&vol2->volumeBounds());
0695 BOOST_CHECK_CLOSE(newBounds2->get(boundDir), halfDir, 1e-6);
0696 CHECK_CLOSE_OR_SMALL(vol2->transform().matrix(), transform2.matrix(),
0697 1e-10, 1e-12);
0698
0699
0700 auto newBounds3 =
0701 dynamic_cast<const CuboidVolumeBounds*>(&vol3->volumeBounds());
0702 BOOST_CHECK_CLOSE(newBounds3->get(boundDir), halfDir + halfDir / 2.0,
0703 1e-6);
0704 auto expectedTranslation3 =
0705 Translation3(Vector3::Unit(dirIdx) * (2 * halfDir + halfDir / 2.0));
0706 Transform3 expectedTransform3 = base * expectedTranslation3;
0707 CHECK_CLOSE_OR_SMALL(vol3->transform().matrix(),
0708 expectedTransform3.matrix(), 1e-10, 1e-12);
0709 } else if (strategy == VolumeResizeStrategy::Gap) {
0710
0711 BOOST_CHECK_EQUAL(volumes.size(), 5);
0712
0713 for (const auto& [volume, origTransform] :
0714 zip(originalVolumes, originalTransforms)) {
0715 const auto* newBounds =
0716 dynamic_cast<const CuboidVolumeBounds*>(&volume->volumeBounds());
0717 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth1), 700_mm, 1e-6);
0718 BOOST_CHECK_CLOSE(newBounds->get(boundDirOrth2), 700_mm, 1e-6);
0719 BOOST_CHECK_CLOSE(newBounds->get(boundDir), halfDir, 1e-6);
0720
0721 CHECK_CLOSE_OR_SMALL(volume->transform().matrix(),
0722 origTransform.matrix(), 1e-10, 1e-12);
0723 }
0724
0725 auto gap1 = volumes.front();
0726 auto gap2 = volumes.back();
0727
0728 const auto* gapBounds1 =
0729 dynamic_cast<const CuboidVolumeBounds*>(&gap1->volumeBounds());
0730 const auto* gapBounds2 =
0731 dynamic_cast<const CuboidVolumeBounds*>(&gap2->volumeBounds());
0732
0733 BOOST_CHECK_CLOSE(gapBounds1->get(boundDir), halfDir / 2.0, 1e-6);
0734 BOOST_CHECK_CLOSE(gapBounds2->get(boundDir), halfDir / 2.0, 1e-6);
0735 auto gap1Translation =
0736 Translation3(Vector3::Unit(dirIdx) * (-3 * halfDir - halfDir / 2.0));
0737 Transform3 gap1Transform = base * gap1Translation;
0738
0739 auto gap2Translation =
0740 Translation3(Vector3::Unit(dirIdx) * (3 * halfDir + halfDir / 2.0));
0741 Transform3 gap2Transform = base * gap2Translation;
0742 CHECK_CLOSE_OR_SMALL(gap1->transform().matrix(), gap1Transform.matrix(),
0743 1e-10, 1e-12);
0744 CHECK_CLOSE_OR_SMALL(gap2->transform().matrix(), gap2Transform.matrix(),
0745 1e-10, 1e-12);
0746 }
0747 }
0748 }
0749
0750 BOOST_DATA_TEST_CASE(
0751 UpdateStackOneSided,
0752 ((boost::unit_test::data::make(-1.0, 1.0) ^
0753 boost::unit_test::data::make(VolumeResizeStrategy::Gap,
0754 VolumeResizeStrategy::Expand)) *
0755 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
0756 Acts::AxisDirection::AxisY,
0757 Acts::AxisDirection::AxisZ)),
0758 f, strategy, dir) {
0759 auto [dirOrth1, dirOrth2] = CuboidVolumeStack::getOrthogonalAxes(dir);
0760
0761 auto dirIdx = CuboidVolumeStack::axisToIndex(dir);
0762 auto dirOrth1Idx = CuboidVolumeStack::axisToIndex(dirOrth1);
0763 auto dirOrth2Idx = CuboidVolumeStack::axisToIndex(dirOrth2);
0764
0765 auto boundDir = CuboidVolumeBounds::fromAxisDirection(dir);
0766 auto boundDirOrth1 = CuboidVolumeBounds::fromAxisDirection(dirOrth1);
0767 auto boundDirOrth2 = CuboidVolumeBounds::fromAxisDirection(dirOrth2);
0768
0769 auto bounds1 = std::make_shared<CuboidVolumeBounds>(
0770 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0771 {boundDir, 400_mm},
0772 {boundDirOrth1, 100_mm},
0773 {boundDirOrth2, 300_mm}});
0774
0775 auto bounds2 = std::make_shared<CuboidVolumeBounds>(
0776 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0777 {boundDir, 400_mm},
0778 {boundDirOrth1, 100_mm},
0779 {boundDirOrth2, 300_mm}});
0780
0781 auto trf = Transform3::Identity();
0782
0783 auto translation1 = Translation3(Vector3::Unit(dirIdx) * -500_mm);
0784 auto trf1 = trf * translation1;
0785 auto vol1 = std::make_shared<Volume>(trf1, bounds1);
0786
0787 auto translation2 = Translation3(Vector3::Unit(dirIdx) * 500_mm);
0788 auto trf2 = trf * translation2;
0789 auto vol2 = std::make_shared<Volume>(trf2, bounds2);
0790
0791 std::vector<Volume*> volumes = {vol1.get(), vol2.get()};
0792
0793 CuboidVolumeStack stack{volumes, dir, VolumeAttachmentStrategy::Gap, strategy,
0794 *logger};
0795 const auto* originalBounds =
0796 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0797
0798
0799 auto newBounds = std::make_shared<CuboidVolumeBounds>(
0800 dynamic_cast<const CuboidVolumeBounds&>(stack.volumeBounds()));
0801 newBounds->set(boundDir, 950_mm);
0802
0803 auto delta = Translation3(Vector3::Unit(dirIdx) * f * 50_mm);
0804 trf *= delta;
0805
0806
0807 auto checkUnchanged = [&]() {
0808 const auto* bounds =
0809 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0810 BOOST_REQUIRE(bounds != nullptr);
0811 BOOST_CHECK_EQUAL(*bounds, *originalBounds);
0812 };
0813
0814
0815 BOOST_CHECK_THROW(
0816 auto errDelta = Translation3(Vector3::Unit(dirIdx) * f * 20_mm);
0817 stack.update(newBounds, trf * errDelta, *logger), std::invalid_argument);
0818 checkUnchanged();
0819
0820
0821 BOOST_CHECK_THROW(
0822 auto errDelta = Translation3(Vector3::Unit(dirOrth1Idx) * 10_mm);
0823 stack.update(newBounds, trf * errDelta, *logger), std::invalid_argument);
0824 checkUnchanged();
0825
0826
0827 BOOST_CHECK_THROW(
0828 auto errDelta = Translation3(Vector3::Unit(dirOrth2Idx) * 10_mm);
0829 stack.update(newBounds, trf * errDelta, *logger), std::invalid_argument);
0830 checkUnchanged();
0831
0832
0833 BOOST_CHECK_THROW(
0834 stack.update(newBounds,
0835 trf * AngleAxis3{10_degree, Vector3::Unit(dirOrth1Idx)},
0836 *logger),
0837 std::invalid_argument);
0838 checkUnchanged();
0839
0840 stack.update(newBounds, trf, *logger);
0841
0842 CHECK_CLOSE_OR_SMALL(stack.transform().matrix(), trf.matrix(), 1e-10, 1e-12);
0843 const auto* bounds =
0844 dynamic_cast<const CuboidVolumeBounds*>(&stack.volumeBounds());
0845 BOOST_REQUIRE(bounds != nullptr);
0846 BOOST_CHECK_CLOSE(bounds->get(boundDir), 950_mm, 1e-6);
0847
0848
0849 for (const auto* vol : volumes) {
0850 const auto* volBounds =
0851 dynamic_cast<const CuboidVolumeBounds*>(&vol->volumeBounds());
0852 BOOST_REQUIRE(volBounds != nullptr);
0853 BOOST_CHECK_CLOSE(volBounds->get(boundDirOrth1), 100_mm, 1e-6);
0854 BOOST_CHECK_CLOSE(volBounds->get(boundDirOrth2), 300_mm, 1e-6);
0855 }
0856
0857 if (strategy == VolumeResizeStrategy::Expand) {
0858
0859 BOOST_CHECK_EQUAL(volumes.size(), 3);
0860 const Volume* vol = nullptr;
0861 if (f < 0.0) {
0862
0863 vol = volumes.front();
0864 } else {
0865
0866 vol = volumes.back();
0867 }
0868
0869 const auto* volBounds =
0870 dynamic_cast<const CuboidVolumeBounds*>(&vol->volumeBounds());
0871 BOOST_REQUIRE(volBounds != nullptr);
0872 BOOST_CHECK_CLOSE(volBounds->get(boundDir), 450_mm, 1e-6);
0873 BOOST_CHECK_EQUAL(vol->center()[dirIdx], f * 550_mm);
0874 } else if (strategy == VolumeResizeStrategy::Gap) {
0875
0876 BOOST_CHECK_EQUAL(volumes.size(), 4);
0877
0878 const Volume* gap = nullptr;
0879 if (f < 0.0) {
0880 gap = volumes.front();
0881 } else {
0882 gap = volumes.back();
0883 }
0884 const auto* gapBounds =
0885 dynamic_cast<const CuboidVolumeBounds*>(&gap->volumeBounds());
0886 BOOST_REQUIRE(gapBounds != nullptr);
0887
0888 BOOST_CHECK_CLOSE(gapBounds->get(boundDir), 50_mm, 1e-6);
0889 BOOST_CHECK_EQUAL(gap->center()[dirIdx], f * 950_mm);
0890 }
0891 }
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921 BOOST_DATA_TEST_CASE(ResizeGapMultiple,
0922 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
0923 Acts::AxisDirection::AxisY,
0924 Acts::AxisDirection::AxisZ),
0925 dir) {
0926 auto [dirOrth1, dirOrth2] = CuboidVolumeStack::getOrthogonalAxes(dir);
0927
0928 auto dirIdx = CuboidVolumeStack::axisToIndex(dir);
0929
0930 auto boundDir = CuboidVolumeBounds::fromAxisDirection(dir);
0931 auto boundDirOrth1 = CuboidVolumeBounds::fromAxisDirection(dirOrth1);
0932 auto boundDirOrth2 = CuboidVolumeBounds::fromAxisDirection(dirOrth2);
0933
0934 auto bounds = std::make_shared<CuboidVolumeBounds>(
0935 std::initializer_list<std::pair<CuboidVolumeBounds::BoundValues, double>>{
0936 {boundDir, 100}, {boundDirOrth1, 70}, {boundDirOrth2, 100}});
0937 Transform3 trf = Transform3::Identity();
0938 Volume vol{trf, bounds};
0939
0940 BOOST_TEST_CONTEXT("Positive") {
0941 std::vector<Volume*> volumes = {&vol};
0942 CuboidVolumeStack stack(volumes, dir, VolumeAttachmentStrategy::Gap,
0943 VolumeResizeStrategy::Gap, *logger);
0944
0945 BOOST_CHECK_EQUAL(volumes.size(), 1);
0946 BOOST_CHECK(stack.gaps().empty());
0947
0948 auto newBounds1 = std::make_shared<CuboidVolumeBounds>(
0949 std::initializer_list<
0950 std::pair<CuboidVolumeBounds::BoundValues, double>>{
0951 {boundDir, 200}, {boundDirOrth1, 70}, {boundDirOrth2, 100}});
0952 stack.update(newBounds1, trf * Translation3{Vector3::Unit(dirIdx) * 100},
0953 *logger);
0954 BOOST_CHECK_EQUAL(volumes.size(), 2);
0955 BOOST_CHECK_EQUAL(stack.gaps().size(), 1);
0956
0957 BOOST_CHECK_EQUAL(stack.gaps().front()->center()[dirIdx], 200.0);
0958 const auto* updatedBounds = dynamic_cast<const CuboidVolumeBounds*>(
0959 &stack.gaps().front()->volumeBounds());
0960 BOOST_REQUIRE_NE(updatedBounds, nullptr);
0961 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 100.0, 1e-6);
0962
0963 auto newBounds2 = std::make_shared<CuboidVolumeBounds>(
0964 std::initializer_list<
0965 std::pair<CuboidVolumeBounds::BoundValues, double>>{
0966 {boundDir, 300}, {boundDirOrth1, 70}, {boundDirOrth2, 100}});
0967 stack.update(newBounds2, trf * Translation3{Vector3::Unit(dirIdx) * 200},
0968 *logger);
0969
0970 BOOST_CHECK_EQUAL(volumes.size(), 2);
0971
0972 BOOST_CHECK_EQUAL(stack.gaps().size(), 1);
0973
0974 BOOST_CHECK_EQUAL(stack.gaps().front()->center()[dirIdx], 300.0);
0975 updatedBounds = dynamic_cast<const CuboidVolumeBounds*>(
0976 &stack.gaps().front()->volumeBounds());
0977 BOOST_REQUIRE_NE(updatedBounds, nullptr);
0978 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 200.0, 1e-6);
0979 }
0980
0981 BOOST_TEST_CONTEXT("Negative") {
0982 std::vector<Volume*> volumes = {&vol};
0983 CuboidVolumeStack stack(volumes, dir, VolumeAttachmentStrategy::Gap,
0984 VolumeResizeStrategy::Gap, *logger);
0985
0986 BOOST_CHECK_EQUAL(volumes.size(), 1);
0987 BOOST_CHECK(stack.gaps().empty());
0988
0989 auto newBounds1 = std::make_shared<CuboidVolumeBounds>(
0990 std::initializer_list<
0991 std::pair<CuboidVolumeBounds::BoundValues, double>>{
0992 {boundDir, 200}, {boundDirOrth1, 70}, {boundDirOrth2, 100}});
0993 stack.update(newBounds1, trf * Translation3{Vector3::Unit(dirIdx) * -100},
0994 *logger);
0995 BOOST_CHECK_EQUAL(volumes.size(), 2);
0996 BOOST_CHECK_EQUAL(stack.gaps().size(), 1);
0997
0998 BOOST_CHECK_EQUAL(stack.gaps().front()->center()[dirIdx], -200.0);
0999 const auto* updatedBounds = dynamic_cast<const CuboidVolumeBounds*>(
1000 &stack.gaps().front()->volumeBounds());
1001 BOOST_REQUIRE_NE(updatedBounds, nullptr);
1002 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 100.0, 1e-6);
1003
1004 auto newBounds2 = std::make_shared<CuboidVolumeBounds>(
1005 std::initializer_list<
1006 std::pair<CuboidVolumeBounds::BoundValues, double>>{
1007 {boundDir, 300}, {boundDirOrth1, 70}, {boundDirOrth2, 100}});
1008 stack.update(newBounds2, trf * Translation3{Vector3::Unit(dirIdx) * -200},
1009 *logger);
1010
1011 BOOST_CHECK_EQUAL(volumes.size(), 2);
1012
1013 BOOST_CHECK_EQUAL(stack.gaps().size(), 1);
1014
1015 BOOST_CHECK_EQUAL(stack.gaps().front()->center()[dirIdx], -300.0);
1016 updatedBounds = dynamic_cast<const CuboidVolumeBounds*>(
1017 &stack.gaps().front()->volumeBounds());
1018 BOOST_REQUIRE_NE(updatedBounds, nullptr);
1019 BOOST_CHECK_CLOSE(updatedBounds->get(boundDir), 200.0, 1e-6);
1020 }
1021 }
1022
1023 BOOST_DATA_TEST_CASE(InvalidDirection, boost::unit_test::data::make(strategies),
1024 strategy) {
1025 std::vector<Volume*> volumes;
1026 auto vol1 = std::make_shared<Volume>(
1027 Transform3::Identity(),
1028 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1029 volumes.push_back(vol1.get());
1030
1031
1032 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, AxisDirection::AxisR, strategy),
1033 std::invalid_argument);
1034
1035 auto vol2 = std::make_shared<Volume>(
1036 Transform3::Identity(),
1037 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1038 volumes.push_back(vol2.get());
1039
1040 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, AxisDirection::AxisR, strategy),
1041 std::invalid_argument);
1042 }
1043
1044 BOOST_DATA_TEST_CASE(InvalidInput,
1045 (boost::unit_test::data::make(strategies) *
1046 boost::unit_test::data::make(Acts::AxisDirection::AxisX,
1047 Acts::AxisDirection::AxisY,
1048 Acts::AxisDirection::AxisZ)),
1049 strategy, direction) {
1050 BOOST_TEST_CONTEXT("Empty Volume") {
1051 std::vector<Volume*> volumes;
1052 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, direction, strategy),
1053 std::invalid_argument);
1054 }
1055
1056 BOOST_TEST_CONTEXT("Volumes rotated relative to each other") {
1057
1058
1059 for (const Vector3 axis : {Vector3::UnitX(), Vector3::UnitY()}) {
1060 std::vector<Volume*> volumes;
1061 auto vol1 = std::make_shared<Volume>(
1062 Transform3{Translation3{Vector3{0_mm, 0_mm, -500_mm}}},
1063 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1064 volumes.push_back(vol1.get());
1065
1066 BOOST_TEST_MESSAGE("Axis: " << axis);
1067 auto vol2 = std::make_shared<Volume>(
1068 Transform3{Translation3{Vector3{0_mm, 0_mm, 500_mm}} *
1069 AngleAxis3(1_degree, axis)},
1070 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1071 volumes.push_back(vol2.get());
1072
1073 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, direction, strategy,
1074 VolumeResizeStrategy::Gap, *logger),
1075 std::invalid_argument);
1076 }
1077 }
1078
1079 BOOST_TEST_CONTEXT(
1080 "Volumes shifted in the orthogonal plane relative to each other") {
1081 for (const Vector3& shift :
1082 {Vector3{5_mm, 0, 0}, Vector3{0, -5_mm, 0}, Vector3{2_mm, -2_mm, 0}}) {
1083 std::vector<Volume*> volumes;
1084 auto vol1 = std::make_shared<Volume>(
1085 Transform3{Translation3{Vector3{0_mm, 0_mm, -500_mm}}},
1086 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1087 volumes.push_back(vol1.get());
1088
1089 auto vol2 = std::make_shared<Volume>(
1090 Transform3{Translation3{Vector3{0_mm, 0_mm, 500_mm} + shift}},
1091 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1092 volumes.push_back(vol2.get());
1093
1094 BOOST_CHECK_THROW(CuboidVolumeStack(volumes, direction, strategy,
1095 VolumeResizeStrategy::Gap, *logger),
1096 std::invalid_argument);
1097 }
1098 }
1099 }
1100
1101 BOOST_DATA_TEST_CASE(JoinCuboidVolumeSingle,
1102 (boost::unit_test::data::make(Acts::AxisDirection::AxisX,
1103 Acts::AxisDirection::AxisY,
1104 Acts::AxisDirection::AxisZ) *
1105 boost::unit_test::data::make(strategies)),
1106 direction, strategy) {
1107 auto vol = std::make_shared<Volume>(
1108 Transform3::Identity() * Translation3{14_mm, 24_mm, 0_mm} *
1109 AngleAxis3(73_degree, Vector3::UnitX()),
1110 std::make_shared<CuboidVolumeBounds>(100_mm, 400_mm, 400_mm));
1111
1112 std::vector<Volume*> volumes{vol.get()};
1113
1114 CuboidVolumeStack stack(volumes, direction, strategy,
1115 VolumeResizeStrategy::Gap, *logger);
1116
1117
1118
1119 BOOST_CHECK_EQUAL(volumes.size(), 1);
1120 BOOST_CHECK_EQUAL(volumes.at(0), vol.get());
1121 BOOST_CHECK_EQUAL(vol->transform().matrix(), stack.transform().matrix());
1122 BOOST_CHECK_EQUAL(vol->volumeBounds(), stack.volumeBounds());
1123 }
1124
1125 BOOST_AUTO_TEST_SUITE_END()
1126 BOOST_AUTO_TEST_SUITE_END()
1127
1128 }