Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-22 07:53:17

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/DetectorElementBase.hpp"
0014 #include "Acts/Geometry/Extent.hpp"
0015 #include "Acts/Geometry/GeometryContext.hpp"
0016 #include "Acts/Geometry/ProtoLayer.hpp"
0017 #include "Acts/Surfaces/PlaneSurface.hpp"
0018 #include "Acts/Surfaces/RectangleBounds.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 #include "Acts/Utilities/BinningType.hpp"
0021 #include "Acts/Utilities/RangeXD.hpp"
0022 #include "ActsTests/CommonHelpers/DetectorElementStub.hpp"
0023 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0024 
0025 #include <cmath>
0026 #include <memory>
0027 #include <numbers>
0028 #include <sstream>
0029 #include <string>
0030 #include <vector>
0031 
0032 using namespace Acts;
0033 
0034 namespace ActsTests {
0035 
0036 GeometryContext tgContext = GeometryContext();
0037 
0038 BOOST_AUTO_TEST_SUITE(GeometrySuite)
0039 
0040 // Test both const and non-const versions
0041 template <bool IsConst>
0042 void testProtoLayer() {
0043   using enum AxisDirection;
0044   using TestProtoLayer = detail::ProtoLayerT<IsConst>;
0045   using SurfacePtr = typename TestProtoLayer::SurfacePtr;
0046 
0047   // Create a proto layer with 4 surfaces on the x/y grid
0048   auto recBounds = std::make_shared<RectangleBounds>(3., 6.);
0049 
0050   // Planar definitions to help construct the boundary surfaces
0051   static const Transform3 planeYZ =
0052       AngleAxis3(std::numbers::pi / 2., Vector3::UnitY()) *
0053       AngleAxis3(std::numbers::pi / 2., Vector3::UnitZ()) *
0054       Transform3::Identity();
0055   static const Transform3 planeZX =
0056       AngleAxis3(-std::numbers::pi / 2., Vector3::UnitX()) *
0057       AngleAxis3(-std::numbers::pi / 2., Vector3::UnitZ()) *
0058       Transform3::Identity();
0059 
0060   std::vector<
0061       std::shared_ptr<std::conditional_t<IsConst, const Surface, Surface>>>
0062       surfaceStore;
0063   surfaceStore.reserve(100);
0064 
0065   auto createProtoLayer = [&](const Transform3& trf,
0066                               bool shared = false) -> TestProtoLayer {
0067     auto atNegX = Surface::makeShared<PlaneSurface>(
0068         Transform3(trf * Translation3(Vector3(-3., 0., 0.)) * planeYZ),
0069         recBounds);
0070 
0071     auto atPosX = Surface::makeShared<PlaneSurface>(
0072         Transform3(trf * Translation3(Vector3(3., 0., 0.)) * planeYZ),
0073         recBounds);
0074 
0075     auto atNegY = Surface::makeShared<PlaneSurface>(
0076         Transform3(trf * Translation3(Vector3(0., -3, 0.)) * planeZX),
0077         recBounds);
0078 
0079     auto atPosY = Surface::makeShared<PlaneSurface>(
0080         Transform3(trf * Translation3(Vector3(0., 3., 0.)) * planeZX),
0081         recBounds);
0082 
0083     std::vector<
0084         std::shared_ptr<std::conditional_t<IsConst, const Surface, Surface>>>
0085         sharedSurfaces = {atNegX, atNegY, atPosX, atPosY};
0086     surfaceStore.insert(surfaceStore.begin(), sharedSurfaces.begin(),
0087                         sharedSurfaces.end());
0088     if (!shared) {
0089       std::vector<SurfacePtr> surfaces = {atNegX.get(), atNegY.get(),
0090                                           atPosX.get(), atPosY.get()};
0091 
0092       return TestProtoLayer(tgContext, surfaces);
0093     }
0094     return TestProtoLayer(tgContext, sharedSurfaces);
0095   };
0096 
0097   // Test 0 - check constructor with surfaces and shared surfaces
0098   auto pLayerSf = createProtoLayer(Transform3::Identity());
0099   auto pLayerSfShared = createProtoLayer(Transform3::Identity());
0100 
0101   BOOST_CHECK(pLayerSf.extent.range() == pLayerSfShared.extent.range());
0102   BOOST_CHECK(pLayerSf.envelope == pLayerSfShared.envelope);
0103 
0104   // CHECK That you have 4 surfaces
0105   BOOST_CHECK_EQUAL(pLayerSf.surfaces().size(), 4);
0106   // Add one surface from a detector element (to test thickness)
0107   auto rB = std::make_shared<RectangleBounds>(30., 60.);
0108 
0109   // Create the detector element
0110   auto addSurface =
0111       Surface::makeShared<PlaneSurface>(Transform3::Identity(), rB);
0112 
0113   pLayerSf.add(tgContext, *addSurface);
0114   // CHECK That if you now have 5 surfaces
0115   BOOST_CHECK_EQUAL(pLayerSf.surfaces().size(), 5);
0116 
0117   // That should invalidate the ranges
0118   BOOST_CHECK(!(pLayerSf.extent.range() == pLayerSfShared.extent.range()));
0119 
0120   // Test 1 - identity transform
0121   auto protoLayer = createProtoLayer(Transform3::Identity());
0122 
0123   CHECK_CLOSE_ABS(protoLayer.range(AxisX), 12., 1e-8);
0124   CHECK_CLOSE_ABS(protoLayer.medium(AxisX), 0., 1e-8);
0125   CHECK_CLOSE_ABS(protoLayer.min(AxisX), -6., 1e-8);
0126   CHECK_CLOSE_ABS(protoLayer.max(AxisX), 6., 1e-8);
0127   CHECK_CLOSE_ABS(protoLayer.range(AxisY), 6., 1e-8);
0128   CHECK_CLOSE_ABS(protoLayer.medium(AxisY), 0., 1e-8);
0129   CHECK_CLOSE_ABS(protoLayer.min(AxisY), -3., 1e-8);
0130   CHECK_CLOSE_ABS(protoLayer.max(AxisY), 3., 1e-8);
0131   CHECK_CLOSE_ABS(protoLayer.range(AxisZ), 12., 1e-8);
0132   CHECK_CLOSE_ABS(protoLayer.medium(AxisZ), 0., 1e-8);
0133   CHECK_CLOSE_ABS(protoLayer.min(AxisZ), -6., 1e-8);
0134   CHECK_CLOSE_ABS(protoLayer.max(AxisZ), 6., 1e-8);
0135   CHECK_CLOSE_ABS(protoLayer.max(AxisR), std::hypot(3, 6), 1e-8);
0136   CHECK_CLOSE_ABS(protoLayer.min(AxisR), 3., 1e-8);
0137 
0138   // Test 2 - rotate around Z-Axis, should leave R, Z untouched,
0139   // only preserves medium values
0140   auto protoLayerRot = createProtoLayer(AngleAxis3(-0.345, Vector3::UnitZ()) *
0141                                         Transform3::Identity());
0142 
0143   BOOST_CHECK_NE(protoLayer.min(AxisX), -6.);
0144   CHECK_CLOSE_ABS(protoLayerRot.medium(AxisX), 0., 1e-8);
0145   CHECK_CLOSE_ABS(protoLayerRot.medium(AxisY), 0., 1e-8);
0146   CHECK_CLOSE_ABS(protoLayerRot.range(AxisZ), 12., 1e-8);
0147   CHECK_CLOSE_ABS(protoLayerRot.medium(AxisZ), 0., 1e-8);
0148   CHECK_CLOSE_ABS(protoLayerRot.min(AxisZ), -6., 1e-8);
0149   CHECK_CLOSE_ABS(protoLayerRot.max(AxisZ), 6., 1e-8);
0150   CHECK_CLOSE_ABS(protoLayerRot.min(AxisR), 3., 1e-8);
0151   CHECK_CLOSE_ABS(protoLayerRot.max(AxisR), std::hypot(3, 6), 1e-8);
0152 
0153   std::stringstream sstream;
0154   protoLayerRot.toStream(sstream);
0155   std::string oString = R"(ProtoLayer with dimensions (min/max)
0156 Extent in space :
0157   - value :     AxisX | range = [-6.66104, 6.66104]
0158   - value :     AxisY | range = [-4.85241, 4.85241]
0159   - value :     AxisZ | range = [-6, 6]
0160   - value :     AxisR | range = [3, 6.7082]
0161   - value :   AxisPhi | range = [-3.02295, 2.33295]
0162   - value :  AxisRPhi | range = [-20.2785, 15.6499]
0163   - value : AxisTheta | range = [0.61548, 2.52611]
0164   - value :   AxisEta | range = [-1.14622, 1.14622]
0165   - value :   AxisMag | range = [7.34847, 7.34847]
0166 )";
0167   BOOST_CHECK_EQUAL(sstream.str(), oString);
0168 }
0169 
0170 BOOST_AUTO_TEST_CASE(ProtoLayerTests) {
0171   testProtoLayer<true>();  // Test const version
0172 }
0173 
0174 BOOST_AUTO_TEST_CASE(ProtoLayerTestsNonConst) {
0175   testProtoLayer<false>();  // Test non-const version
0176 }
0177 
0178 BOOST_AUTO_TEST_CASE(OrientedLayer) {
0179   using enum AxisDirection;
0180   using namespace UnitLiterals;
0181 
0182   Transform3 base = Transform3::Identity();
0183 
0184   auto recBounds = std::make_shared<RectangleBounds>(3_mm, 6_mm);
0185 
0186   std::vector<std::unique_ptr<DetectorElementBase>> detectorElements;
0187 
0188   auto makeFan = [&](double yrot, double thickness = 0) {
0189     detectorElements.clear();
0190 
0191     std::size_t nSensors = 8;
0192     double deltaPhi = 2 * std::numbers::pi / nSensors;
0193     double r = 20_mm;
0194     std::vector<std::shared_ptr<const Surface>> surfaces;
0195     for (std::size_t i = 0; i < nSensors; i++) {
0196       // Create a fan of sensors
0197 
0198       Transform3 trf = base * AngleAxis3{yrot, Vector3::UnitY()} *
0199                        AngleAxis3{deltaPhi * i, Vector3::UnitZ()} *
0200                        Translation3(Vector3::UnitX() * r);
0201 
0202       auto& element = detectorElements.emplace_back(
0203           std::make_unique<DetectorElementStub>(trf, recBounds, thickness));
0204 
0205       surfaces.push_back(element->surface().getSharedPtr());
0206     }
0207     return surfaces;
0208   };
0209 
0210   std::vector<std::shared_ptr<const Surface>> surfaces = makeFan(0_degree);
0211 
0212   ProtoLayer protoLayer(tgContext, surfaces);
0213 
0214   BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
0215   BOOST_CHECK_CLOSE(protoLayer.min(AxisX), -23_mm, 1e-8);
0216   BOOST_CHECK_CLOSE(protoLayer.max(AxisX), 23_mm, 1e-8);
0217   BOOST_CHECK_CLOSE(protoLayer.min(AxisY), -23_mm, 1e-8);
0218   BOOST_CHECK_CLOSE(protoLayer.max(AxisY), 23_mm, 1e-8);
0219   BOOST_CHECK_CLOSE(protoLayer.min(AxisZ), 0_mm, 1e-8);
0220   BOOST_CHECK_CLOSE(protoLayer.max(AxisZ), 0_mm, 1e-8);
0221   BOOST_CHECK_CLOSE(protoLayer.min(AxisR), 17_mm, 1e-8);
0222   BOOST_CHECK_CLOSE(protoLayer.max(AxisR), 23.769728648_mm, 1e-8);
0223 
0224   surfaces = makeFan(45_degree);
0225 
0226   // Do NOT provide rotation matrix: sizing will be affected
0227   protoLayer = {tgContext, surfaces};
0228 
0229   BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
0230   BOOST_CHECK_CLOSE(protoLayer.min(AxisX), -16.26345596_mm, 1e-4);
0231   BOOST_CHECK_CLOSE(protoLayer.max(AxisX), 16.26345596_mm, 1e-4);
0232   BOOST_CHECK_CLOSE(protoLayer.min(AxisY), -23_mm, 1e-8);
0233   BOOST_CHECK_CLOSE(protoLayer.max(AxisY), 23_mm, 1e-8);
0234   BOOST_CHECK_CLOSE(protoLayer.min(AxisZ), -16.26345596_mm, 1e-4);
0235   BOOST_CHECK_CLOSE(protoLayer.max(AxisZ), 16.26345596_mm, 1e-4);
0236 
0237   protoLayer = {tgContext, surfaces,
0238                 Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()};
0239 
0240   BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
0241   BOOST_CHECK_CLOSE(protoLayer.range(AxisX), 46_mm, 1e-8);
0242   BOOST_CHECK_CLOSE(protoLayer.min(AxisX), -23_mm, 1e-8);
0243   BOOST_CHECK_CLOSE(protoLayer.max(AxisX), 23_mm, 1e-8);
0244   BOOST_CHECK_CLOSE(protoLayer.range(AxisY), 46_mm, 1e-8);
0245   BOOST_CHECK_CLOSE(protoLayer.min(AxisY), -23_mm, 1e-8);
0246   BOOST_CHECK_CLOSE(protoLayer.max(AxisY), 23_mm, 1e-8);
0247   CHECK_SMALL(protoLayer.range(AxisZ), 1e-14);
0248   CHECK_SMALL(protoLayer.min(AxisZ), 1e-14);
0249   CHECK_SMALL(protoLayer.max(AxisZ), 1e-14);
0250 
0251   surfaces = makeFan(0_degree, 10_mm);
0252 
0253   protoLayer = {tgContext, surfaces};
0254 
0255   BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
0256   BOOST_CHECK_CLOSE(protoLayer.range(AxisX), 46_mm, 1e-8);
0257   BOOST_CHECK_CLOSE(protoLayer.min(AxisX), -23_mm, 1e-8);
0258   BOOST_CHECK_CLOSE(protoLayer.max(AxisX), 23_mm, 1e-8);
0259   BOOST_CHECK_CLOSE(protoLayer.range(AxisY), 46_mm, 1e-8);
0260   BOOST_CHECK_CLOSE(protoLayer.min(AxisY), -23_mm, 1e-8);
0261   BOOST_CHECK_CLOSE(protoLayer.max(AxisY), 23_mm, 1e-8);
0262   BOOST_CHECK_CLOSE(protoLayer.range(AxisZ), 10_mm, 1e-8);
0263   BOOST_CHECK_CLOSE(protoLayer.min(AxisZ), -5_mm, 1e-8);
0264   BOOST_CHECK_CLOSE(protoLayer.max(AxisZ), 5_mm, 1e-8);
0265 
0266   surfaces = makeFan(45_degree, 10_mm);
0267 
0268   protoLayer = {tgContext, surfaces,
0269                 Transform3{AngleAxis3{45_degree, Vector3::UnitY()}}.inverse()};
0270 
0271   BOOST_CHECK_EQUAL(protoLayer.surfaces().size(), 8);
0272   BOOST_CHECK_CLOSE(protoLayer.range(AxisX), 46_mm, 1e-8);
0273   BOOST_CHECK_CLOSE(protoLayer.min(AxisX), -23_mm, 1e-8);
0274   BOOST_CHECK_CLOSE(protoLayer.max(AxisX), 23_mm, 1e-8);
0275   BOOST_CHECK_CLOSE(protoLayer.range(AxisY), 46_mm, 1e-8);
0276   BOOST_CHECK_CLOSE(protoLayer.min(AxisY), -23_mm, 1e-8);
0277   BOOST_CHECK_CLOSE(protoLayer.max(AxisY), 23_mm, 1e-8);
0278   BOOST_CHECK_CLOSE(protoLayer.range(AxisZ), 10_mm, 1e-8);
0279   BOOST_CHECK_CLOSE(protoLayer.min(AxisZ), -5_mm, 1e-8);
0280   BOOST_CHECK_CLOSE(protoLayer.max(AxisZ), 5_mm, 1e-8);
0281 }
0282 
0283 BOOST_AUTO_TEST_SUITE_END()
0284 
0285 }  // namespace ActsTests