Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:51:18

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/Material/GridSurfaceMaterial.hpp"
0012 #include "Acts/Material/GridSurfaceMaterialFactory.hpp"
0013 #include "Acts/Material/Material.hpp"
0014 #include "Acts/Material/MaterialSlab.hpp"
0015 #include "Acts/Utilities/GridAxisGenerators.hpp"
0016 #include "Acts/Utilities/ProtoAxis.hpp"
0017 #include "Acts/Utilities/VectorHelpers.hpp"
0018 
0019 #include <numbers>
0020 #include <vector>
0021 
0022 // this is a global access to the x coordinate
0023 class GlobalAccessX final : public Acts::GridAccess::IGlobalToGridLocal {
0024  public:
0025   std::array<double, 1u> g2X(const Acts::Vector3& global) const {
0026     return {global.x()};
0027   }
0028 };
0029 
0030 class LocalAccessX final : public Acts::GridAccess::IBoundToGridLocal {
0031  public:
0032   std::array<double, 1u> l2X(const Acts::Vector2& local) const {
0033     return {local.x()};
0034   }
0035 };
0036 
0037 class GlobalAccessPhi final : public Acts::GridAccess::IGlobalToGridLocal {
0038  public:
0039   std::array<double, 1u> g2Phi(const Acts::Vector3& global) const {
0040     return {std::atan2(global.y(), global.x())};
0041   }
0042 };
0043 
0044 class LocalAccessPhi final : public Acts::GridAccess::IBoundToGridLocal {
0045  public:
0046   std::array<double, 1u> l2Phi(const Acts::Vector2& local) const {
0047     return {std::atan2(local.y(), local.x())};
0048   }
0049 };
0050 
0051 class GlobalAccessXY final : public Acts::GridAccess::IGlobalToGridLocal {
0052  public:
0053   std::array<double, 2u> g2XY(const Acts::Vector3& global) const {
0054     return {global.x(), global.y()};
0055   }
0056 };
0057 
0058 class LocalAccessXY final : public Acts::GridAccess::IBoundToGridLocal {
0059  public:
0060   std::array<double, 2u> l2XY(const Acts::Vector2& local) const {
0061     return {local.x(), local.y()};
0062   }
0063 };
0064 
0065 class GlobalToZPhi final : public Acts::GridAccess::IGlobalToGridLocal {
0066  public:
0067   double zShift = 0.;
0068 
0069   explicit GlobalToZPhi(double shift) : zShift(shift) {}
0070 
0071   std::array<double, 2u> g2ZPhi(const Acts::Vector3& global) const {
0072     return {global.z() + zShift, Acts::VectorHelpers::phi(global)};
0073   }
0074 };
0075 
0076 // Local on cylinder surface is rPhi, z
0077 class LocalToZPhi final : public Acts::GridAccess::IBoundToGridLocal {
0078  public:
0079   double radius = 1.;
0080 
0081   explicit LocalToZPhi(double r) : radius(r) {}
0082 
0083   std::array<double, 2u> l2ZPhi(const Acts::Vector2& local) const {
0084     return {local[1u], local[0u] / radius};
0085   }
0086 };
0087 
0088 BOOST_AUTO_TEST_SUITE(Material)
0089 
0090 // This test covers some wrongly configured cases
0091 BOOST_AUTO_TEST_CASE(GridIndexedMaterial_invalid_bound2Grid_Unconnected) {
0092   std::vector<Acts::MaterialSlab> material;
0093 
0094   using EqBound = Acts::GridAxisGenerators::EqBound;
0095   using EqGrid = EqBound::grid_type<std::size_t>;
0096 
0097   EqBound eqBound{{0., 5.}, 5};
0098   EqGrid eqGrid{eqBound()};
0099 
0100   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX;
0101 
0102   auto globalX = std::make_unique<const GlobalAccessX>();
0103   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX;
0104   gToX.connect<&GlobalAccessX::g2X>(std::move(globalX));
0105 
0106   BOOST_CHECK_THROW(
0107       auto ism = Acts::IndexedSurfaceMaterial<EqGrid>(
0108           std::move(eqGrid), Acts::IndexedMaterialAccessor{std::move(material)},
0109           std::move(bToX), std::move(gToX)),
0110       std::invalid_argument);
0111 }
0112 
0113 // This test covers some wrongly configured cases
0114 BOOST_AUTO_TEST_CASE(GridIndexedMaterial_invalid_global2Grid_Unconnected) {
0115   std::vector<Acts::MaterialSlab> material;
0116 
0117   using EqBound = Acts::GridAxisGenerators::EqBound;
0118   using EqGrid = EqBound::grid_type<std::size_t>;
0119 
0120   EqBound eqBound{{0., 5.}, 5};
0121   EqGrid eqGrid{eqBound()};
0122 
0123   auto localX = std::make_unique<const LocalAccessX>();
0124   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX;
0125   bToX.connect<&LocalAccessX::l2X>(std::move(localX));
0126 
0127   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX;
0128 
0129   BOOST_CHECK_THROW(
0130       auto ism = Acts::IndexedSurfaceMaterial<EqGrid>(
0131           std::move(eqGrid), Acts::IndexedMaterialAccessor{std::move(material)},
0132           std::move(bToX), std::move(gToX)),
0133       std::invalid_argument);
0134 }
0135 
0136 // This test covers the locally indexed grid material in 1D
0137 BOOST_AUTO_TEST_CASE(GridMaterial1D) {
0138   std::vector<Acts::MaterialSlab> material;
0139   material.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0140   material.emplace_back(
0141       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0142   material.emplace_back(
0143       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0144   material.emplace_back(
0145       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0146   material.emplace_back(
0147       Acts::Material::fromMolarDensity(31.0, 32.0, 33.0, 34.0, 35.0), 4.0);
0148 
0149   // Bound, equidistant axis
0150   Acts::ProtoAxis pAxisX(Acts::AxisBoundaryType::Bound, 0.0, 5.0, 5);
0151 
0152   auto localX = std::make_unique<const LocalAccessX>();
0153   Acts::GridAccess::BoundToGridLocal1DimDelegate bToX;
0154   bToX.connect<&LocalAccessX::l2X>(std::move(localX));
0155 
0156   auto globalX = std::make_unique<const GlobalAccessX>();
0157   Acts::GridAccess::GlobalToGridLocal1DimDelegate gToX;
0158   gToX.connect<&GlobalAccessX::g2X>(std::move(globalX));
0159 
0160   auto ismX = Acts::GridSurfaceMaterialFactory::create(
0161       pAxisX, Acts::GridMaterialAccessor{}, std::move(bToX), std::move(gToX),
0162       material);
0163 
0164   BOOST_CHECK(ismX != nullptr);
0165 
0166   // Global access test
0167   Acts::Vector3 g0(0.5, 0., 0.);
0168   Acts::Vector3 g1(1.5, 0., 0.);
0169   Acts::Vector3 g2(2.5, 0., 0.);
0170   Acts::Vector3 g3(3.5, 0., 0.);
0171   Acts::Vector3 g4(4.5, 0., 0.);
0172 
0173   const Acts::MaterialSlab& mg0 = ismX->materialSlab(g0);
0174   const Acts::MaterialSlab& mg1 = ismX->materialSlab(g1);
0175   const Acts::MaterialSlab& mg2 = ismX->materialSlab(g2);
0176   const Acts::MaterialSlab& mg3 = ismX->materialSlab(g3);
0177   const Acts::MaterialSlab& mg4 = ismX->materialSlab(g4);
0178 
0179   BOOST_CHECK(mg0.material().isVacuum());
0180   BOOST_CHECK_EQUAL(mg1.material().X0(), 1.);
0181   BOOST_CHECK_EQUAL(mg2.material().X0(), 11.);
0182   BOOST_CHECK_EQUAL(mg3.material().X0(), 21.);
0183   BOOST_CHECK_EQUAL(mg4.material().X0(), 31.);
0184 
0185   // Try the same with Closed access
0186   // Bound, equidistant axis
0187   Acts::ProtoAxis pAxisPhi(Acts::AxisBoundaryType::Closed, -std::numbers::pi,
0188                            std::numbers::pi, 8);
0189 
0190   auto localPhi = std::make_unique<const LocalAccessPhi>();
0191   Acts::GridAccess::BoundToGridLocal1DimDelegate bToPhi;
0192   bToPhi.connect<&LocalAccessPhi::l2Phi>(std::move(localPhi));
0193 
0194   auto globalPhi = std::make_unique<const GlobalAccessPhi>();
0195   Acts::GridAccess::GlobalToGridLocal1DimDelegate gToPhi;
0196   gToPhi.connect<&GlobalAccessPhi::g2Phi>(std::move(globalPhi));
0197 
0198   std::vector<Acts::MaterialSlab> materialPhi;
0199   materialPhi.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0200   materialPhi.emplace_back(
0201       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0202   materialPhi.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0203   materialPhi.emplace_back(
0204       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0205   materialPhi.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0206   materialPhi.emplace_back(
0207       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0208   materialPhi.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0209   materialPhi.emplace_back(
0210       Acts::Material::fromMolarDensity(31.0, 32.0, 33.0, 34.0, 35.0), 4.0);
0211 
0212   auto ismPhi = Acts::GridSurfaceMaterialFactory::create(
0213       pAxisPhi, Acts::GridMaterialAccessor{}, std::move(bToPhi),
0214       std::move(gToPhi), materialPhi);
0215 
0216   BOOST_CHECK(ismPhi != nullptr);
0217 
0218   for (std::size_t i = 0; i < 8; ++i) {
0219     double alpha = -std::numbers::pi + (i + 0.5) * std::numbers::pi / 4.;
0220     Acts::Vector2 query{std::cos(alpha), std::sin(alpha)};
0221     const Acts::MaterialSlab& m = ismPhi->materialSlab(query);
0222     if (i % 2 == 0) {
0223       BOOST_CHECK(m.material().isVacuum());
0224     } else {
0225       BOOST_CHECK_EQUAL(m.material().X0(), materialPhi[i].material().X0());
0226     }
0227   }
0228 }
0229 
0230 // This test covers the locally indexed grid material in 1D
0231 BOOST_AUTO_TEST_CASE(GridMaterial2D) {
0232   std::vector<std::vector<Acts::MaterialSlab>> material2x3;
0233   // This is a material matrix 2 bins in x and 3 bins in y
0234   std::vector<Acts::MaterialSlab> materialRow0;
0235   materialRow0.emplace_back(
0236       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0237   materialRow0.emplace_back(
0238       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0239   materialRow0.emplace_back(
0240       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0241   std::vector<Acts::MaterialSlab> materialRow1;
0242   materialRow1.emplace_back(
0243       Acts::Material::fromMolarDensity(2.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0244   materialRow1.emplace_back(
0245       Acts::Material::fromMolarDensity(12.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0246   materialRow1.emplace_back(
0247       Acts::Material::fromMolarDensity(22.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0248   // This gives a row major matrix
0249   material2x3.push_back(std::move(materialRow0));
0250   material2x3.push_back(std::move(materialRow1));
0251 
0252   BOOST_CHECK(material2x3[0][0].material().X0() == 1.);
0253   BOOST_CHECK(material2x3[0][1].material().X0() == 11.);
0254   BOOST_CHECK(material2x3[0][2].material().X0() == 21.);
0255   BOOST_CHECK(material2x3[1][0].material().X0() == 2.);
0256   BOOST_CHECK(material2x3[1][1].material().X0() == 12.);
0257   BOOST_CHECK(material2x3[1][2].material().X0() == 22.);
0258 
0259   Acts::ProtoAxis pAxisX(Acts::AxisBoundaryType::Bound, -1.0, 1.0, 2);
0260   Acts::ProtoAxis pAxisY(Acts::AxisBoundaryType::Bound, -1.5, 1.5, 3);
0261 
0262   std::vector<std::vector<Acts::MaterialSlab>> materialXY = material2x3;
0263 
0264   auto localXY = std::make_unique<const LocalAccessXY>();
0265   Acts::GridAccess::BoundToGridLocal2DimDelegate bToXY;
0266   bToXY.connect<&LocalAccessXY::l2XY>(std::move(localXY));
0267 
0268   auto globalXY = std::make_unique<const GlobalAccessXY>();
0269   Acts::GridAccess::GlobalToGridLocal2DimDelegate gToXY;
0270   gToXY.connect<&GlobalAccessXY::g2XY>(std::move(globalXY));
0271 
0272   auto ismXY = Acts::GridSurfaceMaterialFactory::create(
0273       pAxisX, pAxisY, Acts::GridMaterialAccessor{}, std::move(bToXY),
0274       std::move(gToXY), materialXY);
0275 
0276   BOOST_CHECK(ismXY != nullptr);
0277 
0278   // Global access test
0279   Acts::Vector3 g00(-0.5, -1.5, 0.);
0280   Acts::Vector3 g01(-0.5, 0., 0.);
0281   Acts::Vector3 g02(-0.5, 1.5, 0.);
0282   Acts::Vector3 g10(0.5, -1.5, 0.);
0283   Acts::Vector3 g11(0.5, 0., 0.);
0284   Acts::Vector3 g12(0.5, 1.5, 0.);
0285 
0286   const Acts::MaterialSlab& mg00 = ismXY->materialSlab(g00);
0287   const Acts::MaterialSlab& mg01 = ismXY->materialSlab(g01);
0288   const Acts::MaterialSlab& mg02 = ismXY->materialSlab(g02);
0289   const Acts::MaterialSlab& mg10 = ismXY->materialSlab(g10);
0290   const Acts::MaterialSlab& mg11 = ismXY->materialSlab(g11);
0291   const Acts::MaterialSlab& mg12 = ismXY->materialSlab(g12);
0292 
0293   BOOST_CHECK_EQUAL(mg00.material().X0(), 1.);
0294   BOOST_CHECK_EQUAL(mg01.material().X0(), 11.);
0295   BOOST_CHECK_EQUAL(mg02.material().X0(), 21.);
0296   BOOST_CHECK_EQUAL(mg10.material().X0(), 2.);
0297   BOOST_CHECK_EQUAL(mg11.material().X0(), 12.);
0298   BOOST_CHECK_EQUAL(mg12.material().X0(), 22.);
0299 
0300   // Let's try a ZPhi model as well
0301   auto materialZPhi = material2x3;
0302 
0303   Acts::ProtoAxis pAxisZ(Acts::AxisBoundaryType::Bound, -1.0, 1.0, 2);
0304   Acts::ProtoAxis pAxisPhi(Acts::AxisBoundaryType::Closed, -std::numbers::pi,
0305                            std::numbers::pi, 3);
0306 
0307   auto localZPhi = std::make_unique<const LocalToZPhi>(1.);
0308   Acts::GridAccess::BoundToGridLocal2DimDelegate bToZPhi;
0309   bToZPhi.connect<&LocalToZPhi::l2ZPhi>(std::move(localZPhi));
0310 
0311   auto globalZPhi = std::make_unique<const GlobalToZPhi>(0.);
0312   Acts::GridAccess::GlobalToGridLocal2DimDelegate gToZPhi;
0313   gToZPhi.connect<&GlobalToZPhi::g2ZPhi>(std::move(globalZPhi));
0314 
0315   auto ismZPhi = Acts::GridSurfaceMaterialFactory::create(
0316       pAxisZ, pAxisPhi, Acts::GridMaterialAccessor{}, std::move(bToZPhi),
0317       std::move(gToZPhi), materialZPhi);
0318 
0319   BOOST_CHECK(ismZPhi != nullptr);
0320 
0321   // Local access test - trick here is also to
0322   // see BoundtoGridLocal switches from r*phi, z -> phi,z
0323   Acts::Vector2 l00(-0.5 * std::numbers::pi, -0.5);
0324   Acts::Vector2 l01(0., -0.5);
0325   Acts::Vector2 l02(0.5 * std::numbers::pi, -0.5);
0326   Acts::Vector2 l10(-0.5 * std::numbers::pi, 0.5);
0327   Acts::Vector2 l11(0., 0.5);
0328   Acts::Vector2 l12(0.5 * std::numbers::pi, 0.5);
0329 
0330   const Acts::MaterialSlab& ml00 = ismZPhi->materialSlab(l00);
0331   const Acts::MaterialSlab& ml01 = ismZPhi->materialSlab(l01);
0332   const Acts::MaterialSlab& ml02 = ismZPhi->materialSlab(l02);
0333   const Acts::MaterialSlab& ml10 = ismZPhi->materialSlab(l10);
0334   const Acts::MaterialSlab& ml11 = ismZPhi->materialSlab(l11);
0335   const Acts::MaterialSlab& ml12 = ismZPhi->materialSlab(l12);
0336 
0337   BOOST_CHECK_EQUAL(ml00.material().X0(), 1.);
0338   BOOST_CHECK_EQUAL(ml01.material().X0(), 11.);
0339   BOOST_CHECK_EQUAL(ml02.material().X0(), 21.);
0340   BOOST_CHECK_EQUAL(ml10.material().X0(), 2.);
0341   BOOST_CHECK_EQUAL(ml11.material().X0(), 12.);
0342   BOOST_CHECK_EQUAL(ml12.material().X0(), 22.);
0343 
0344   // Test the closed character of the phi axis
0345   Acts::Vector2 l03(1.05 * std::numbers::pi, -0.5);
0346   const Acts::MaterialSlab& ml03 = ismZPhi->materialSlab(l03);
0347   BOOST_CHECK(ml03.material().X0() == ml00.material().X0());
0348 }
0349 
0350 // This test covers the locally indexed grid material in 1D
0351 BOOST_AUTO_TEST_CASE(GridIndexedMaterial1D) {
0352   std::vector<Acts::MaterialSlab> material;
0353   material.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0354   material.emplace_back(
0355       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0356   material.emplace_back(
0357       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0358   material.emplace_back(
0359       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0360 
0361   using EqBound = Acts::GridAxisGenerators::EqBound;
0362   using EqGrid = EqBound::grid_type<std::size_t>;
0363   using Point = EqGrid::point_t;
0364 
0365   EqBound eqBound{{0., 5.}, 5};
0366   EqGrid eqGrid{eqBound()};
0367 
0368   eqGrid.atPosition(Point{0.5}) = 1u;  // material 1
0369   eqGrid.atPosition(Point{1.5}) = 0u;  // vacuum
0370   eqGrid.atPosition(Point{2.5}) = 2u;  // material 2
0371   eqGrid.atPosition(Point{3.5}) = 2u;  // material 2
0372   eqGrid.atPosition(Point{4.5}) = 3u;  // material 3
0373 
0374   auto localX = std::make_unique<const LocalAccessX>();
0375   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX;
0376   bToX.connect<&LocalAccessX::l2X>(std::move(localX));
0377 
0378   auto globalX = std::make_unique<const GlobalAccessX>();
0379   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX;
0380   gToX.connect<&GlobalAccessX::g2X>(std::move(globalX));
0381 
0382   Acts::IndexedSurfaceMaterial<EqGrid> ism(
0383       std::move(eqGrid), Acts::IndexedMaterialAccessor{std::move(material)},
0384       std::move(bToX), std::move(gToX));
0385 
0386   // Global access test
0387   Acts::Vector3 g0(0.5, 0., 0.);
0388   Acts::Vector3 g1(1.5, 0., 0.);
0389   Acts::Vector3 g2(2.5, 0., 0.);
0390   Acts::Vector3 g3(3.5, 0., 0.);
0391   Acts::Vector3 g4(4.5, 0., 0.);
0392 
0393   const Acts::MaterialSlab& mg0 = ism.materialSlab(g0);
0394   const Acts::MaterialSlab& mg1 = ism.materialSlab(g1);
0395   const Acts::MaterialSlab& mg2 = ism.materialSlab(g2);
0396   const Acts::MaterialSlab& mg3 = ism.materialSlab(g3);
0397   const Acts::MaterialSlab& mg4 = ism.materialSlab(g4);
0398 
0399   BOOST_CHECK_EQUAL(mg0.material().X0(), 1.);
0400   BOOST_CHECK(mg1.material().isVacuum());
0401   BOOST_CHECK_EQUAL(mg2.material().X0(), 11.);
0402   BOOST_CHECK_EQUAL(mg3.material().X0(), 11.);
0403   BOOST_CHECK_EQUAL(mg4.material().X0(), 21.);
0404 
0405   // Local access test
0406   Acts::Vector2 l0(0.5, 0.);
0407   Acts::Vector2 l1(1.5, 0.);
0408   Acts::Vector2 l2(2.5, 0.);
0409   Acts::Vector2 l3(3.5, 0.);
0410   Acts::Vector2 l4(4.5, 0.);
0411 
0412   const Acts::MaterialSlab& ml0 = ism.materialSlab(l0);
0413   const Acts::MaterialSlab& ml1 = ism.materialSlab(l1);
0414   const Acts::MaterialSlab& ml2 = ism.materialSlab(l2);
0415   const Acts::MaterialSlab& ml3 = ism.materialSlab(l3);
0416   const Acts::MaterialSlab& ml4 = ism.materialSlab(l4);
0417 
0418   BOOST_CHECK_EQUAL(ml0.material().X0(), 1.);
0419   BOOST_CHECK(ml1.material().isVacuum());
0420   BOOST_CHECK_EQUAL(ml2.material().X0(), 11.);
0421   BOOST_CHECK_EQUAL(ml3.material().X0(), 11.);
0422   BOOST_CHECK_EQUAL(ml4.material().X0(), 21.);
0423 
0424   // Now scale it - and access again
0425   ism.scale(2.);
0426   const Acts::MaterialSlab& sml0 = ism.materialSlab(l0);
0427   const Acts::MaterialSlab& sml1 = ism.materialSlab(l1);
0428   const Acts::MaterialSlab& sml2 = ism.materialSlab(l2);
0429   const Acts::MaterialSlab& sml3 = ism.materialSlab(l3);
0430   const Acts::MaterialSlab& sml4 = ism.materialSlab(l4);
0431 
0432   BOOST_CHECK_EQUAL(sml0.thickness(), 2.);
0433   BOOST_CHECK(sml1.material().isVacuum());
0434   BOOST_CHECK_EQUAL(sml2.thickness(), 4.);
0435   BOOST_CHECK_EQUAL(sml3.thickness(), 4.);
0436   BOOST_CHECK_EQUAL(sml4.thickness(), 6.);
0437 
0438   // Now test with the protoAxis creation method
0439 
0440   std::vector<Acts::MaterialSlab> materialStorage;
0441   materialStorage.emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0442   materialStorage.emplace_back(
0443       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0444   materialStorage.emplace_back(
0445       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0446   materialStorage.emplace_back(
0447       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0448 
0449   std::vector<std::size_t> indexPayload = {0u, 1u, 2u, 3u, 0u, 3u, 2u, 1u, 0u};
0450 
0451   auto indexedAccessor =
0452       Acts::IndexedMaterialAccessor{std::move(materialStorage)};
0453 
0454   // An X proto axis
0455   Acts::ProtoAxis pAxisX(Acts::AxisBoundaryType::Bound, 0.0, 9.0, 9);
0456 
0457   auto localXidx = std::make_unique<const LocalAccessX>();
0458   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToXidx;
0459   bToXidx.connect<&LocalAccessX::l2X>(std::move(localXidx));
0460 
0461   auto globalXidx = std::make_unique<const GlobalAccessX>();
0462   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToXidx;
0463   gToXidx.connect<&GlobalAccessX::g2X>(std::move(globalXidx));
0464 
0465   auto ismXidx = Acts::GridSurfaceMaterialFactory::create(
0466       pAxisX, std::move(indexedAccessor), std::move(bToXidx),
0467       std::move(gToXidx), indexPayload);
0468 
0469   // Check construction
0470   BOOST_CHECK(ismXidx != nullptr);
0471   // The vacuum (==0) indexed entries
0472   BOOST_CHECK(ismXidx->materialSlab(Acts::Vector3{0.5, 0., 0.}).isVacuum());
0473   BOOST_CHECK(ismXidx->materialSlab(Acts::Vector3{4.5, 0., 0.}).isVacuum());
0474   BOOST_CHECK(ismXidx->materialSlab(Acts::Vector3{8.5, 0., 0.}).isVacuum());
0475   // The material 1 (==1) indexed entries
0476   BOOST_CHECK_EQUAL(
0477       ismXidx->materialSlab(Acts::Vector3{1.5, 0., 0.}).material().X0(), 1.);
0478   BOOST_CHECK_EQUAL(
0479       ismXidx->materialSlab(Acts::Vector3{7.5, 0., 0.}).material().X0(), 1.);
0480   // The material 2 (==2) indexed entries
0481   BOOST_CHECK_EQUAL(
0482       ismXidx->materialSlab(Acts::Vector3{2.5, 0., 0.}).material().X0(), 11.);
0483   BOOST_CHECK_EQUAL(
0484       ismXidx->materialSlab(Acts::Vector3{6.5, 0., 0.}).material().X0(), 11.);
0485   // The material 3 (==3) indexed entries
0486   BOOST_CHECK_EQUAL(
0487       ismXidx->materialSlab(Acts::Vector3{3.5, 0., 0.}).material().X0(), 21.);
0488   BOOST_CHECK_EQUAL(
0489       ismXidx->materialSlab(Acts::Vector3{5.5, 0., 0.}).material().X0(), 21.);
0490 }
0491 
0492 // This test covers the locally indexed grid material in 2D
0493 BOOST_AUTO_TEST_CASE(GridIndexedMaterial2D) {
0494   std::vector<Acts::MaterialSlab> material;
0495   material.emplace_back(Acts::Material::Vacuum(), 1.0);  // vacuum
0496   material.emplace_back(
0497       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0498   material.emplace_back(
0499       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 1.0);
0500   material.emplace_back(
0501       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 1.0);
0502 
0503   //  Test (1) with explicit grid creation
0504   std::vector<Acts::MaterialSlab> materialT1 = material;
0505   using EqBoundEqClosed = Acts::GridAxisGenerators::EqBoundEqClosed;
0506   using EqEqGrid = EqBoundEqClosed::grid_type<std::size_t>;
0507   using Point = EqEqGrid::point_t;
0508 
0509   // 2 bins in z, 4 bins in phi
0510   EqBoundEqClosed eqeqBound{
0511       {-1., 1.}, 2, {-std::numbers::pi, std::numbers::pi}, 4};
0512   EqEqGrid eqeqGrid{eqeqBound()};
0513 
0514   eqeqGrid.atPosition(Point{-0.5, -std::numbers::pi * 0.75}) =
0515       1u;                                                          // material 1
0516   eqeqGrid.atPosition(Point{-0.5, -std::numbers::pi / 4.}) = 1u;   // material 1
0517   eqeqGrid.atPosition(Point{-0.5, std::numbers::pi / 4.}) = 0u;    // vacuum
0518   eqeqGrid.atPosition(Point{-0.5, std::numbers::pi * 0.75}) = 2u;  // material 2
0519 
0520   eqeqGrid.atPosition(Point{0.5, -std::numbers::pi * 0.75}) = 0u;  // vacuum
0521   eqeqGrid.atPosition(Point{0.5, -std::numbers::pi / 4.}) = 3u;    // material 3
0522   eqeqGrid.atPosition(Point{0.5, std::numbers::pi / 4.}) = 3u;     // material 3
0523   eqeqGrid.atPosition(Point{0.5, std::numbers::pi * 0.75}) = 0u;   // vacuum
0524 
0525   // With radius 20
0526   auto boundToGridT1 = std::make_unique<const LocalToZPhi>(20.);
0527   Acts::IndexedSurfaceMaterial<EqEqGrid>::BoundToGridLocalDelegate bToZPhiT1;
0528   bToZPhiT1.connect<&LocalToZPhi::l2ZPhi>(std::move(boundToGridT1));
0529 
0530   // With z shift 10
0531   auto globalToGridT1 = std::make_unique<const GlobalToZPhi>(10.);
0532   Acts::IndexedSurfaceMaterial<EqEqGrid>::GlobalToGridLocalDelegate gToZphiT1;
0533   gToZphiT1.connect<&GlobalToZPhi::g2ZPhi>(std::move(globalToGridT1));
0534 
0535   // Create the indexed material grid
0536   Acts::IndexedSurfaceMaterial<EqEqGrid> ism(
0537       std::move(eqeqGrid), Acts::IndexedMaterialAccessor{std::move(materialT1)},
0538       std::move(bToZPhiT1), std::move(gToZphiT1));
0539 
0540   // Test with proto grid greation
0541   auto materialT2 = material;
0542 
0543   auto boundToGridT2 = std::make_unique<const LocalToZPhi>(20.);
0544   Acts::GridAccess::BoundToGridLocal2DimDelegate bToZPhiT2;
0545   bToZPhiT2.connect<&LocalToZPhi::l2ZPhi>(std::move(boundToGridT2));
0546 
0547   auto globalToGridT2 = std::make_unique<const GlobalToZPhi>(10.);
0548   Acts::GridAccess::GlobalToGridLocal2DimDelegate gToZphiT2;
0549   gToZphiT2.connect<&GlobalToZPhi::g2ZPhi>(std::move(globalToGridT2));
0550 
0551   Acts::ProtoAxis pAxisZ(Acts::AxisBoundaryType::Bound, -1.0, 1.0, 2);
0552   Acts::ProtoAxis pAxisPhi(Acts::AxisBoundaryType::Closed, -std::numbers::pi,
0553                            std::numbers::pi, 4);
0554 
0555   std::vector<std::vector<std::size_t>> indexPayload = {
0556       std::vector<std::size_t>{1u, 1u, 0u, 2u},
0557       std::vector<std::size_t>{0u, 3u, 3u, 0u}};
0558 
0559   auto ismZPhi = Acts::GridSurfaceMaterialFactory::create(
0560       pAxisZ, pAxisPhi, Acts::IndexedMaterialAccessor{std::move(materialT2)},
0561       std::move(bToZPhiT2), std::move(gToZphiT2), indexPayload);
0562 
0563   // Global access test, both should give material 1
0564   Acts::Vector3 g0(-0.5, -0.5, -10.5);
0565   const Acts::MaterialSlab& mg0T1 = ism.materialSlab(g0);
0566   const Acts::MaterialSlab& mg0T2 = ismZPhi->materialSlab(g0);
0567   BOOST_CHECK_EQUAL(mg0T1.material().X0(), 1.);
0568   BOOST_CHECK_EQUAL(mg0T2.material().X0(), 1.);
0569 
0570   Acts::Vector3 g1(0.5, -0.5, -11.5);  // checking out of bound access
0571   const Acts::MaterialSlab& mg1T1 = ism.materialSlab(g1);
0572   const Acts::MaterialSlab& mg1T2 = ismZPhi->materialSlab(g1);
0573   BOOST_CHECK_EQUAL(mg1T1.material().X0(), 1.);
0574   BOOST_CHECK_EQUAL(mg1T2.material().X0(), 1.);
0575 
0576   Acts::Vector3 g2(0.5, 0.5, -10.5);
0577   const Acts::MaterialSlab& mg2T1 = ism.materialSlab(g2);
0578   const Acts::MaterialSlab& mg2T2 = ismZPhi->materialSlab(g2);
0579   BOOST_CHECK(mg2T1.material().isVacuum());  // vacuum
0580   BOOST_CHECK(mg2T2.material().isVacuum());  // vacuum
0581 
0582   Acts::Vector3 g3(0.5, 0.5,
0583                    -9.5);  // should be material 3, same phi but different z
0584   const Acts::MaterialSlab& mg3T1 = ism.materialSlab(g3);
0585   const Acts::MaterialSlab& mg3T2 = ismZPhi->materialSlab(g3);
0586   BOOST_CHECK_EQUAL(mg3T1.material().X0(), 21.);
0587   BOOST_CHECK_EQUAL(mg3T2.material().X0(), 21.);
0588 }
0589 
0590 // This test covers the globally indexed grid material with non-shared material
0591 BOOST_AUTO_TEST_CASE(GridGloballyIndexedMaterialNonShared) {
0592   auto material = std::make_shared<std::vector<Acts::MaterialSlab>>();
0593 
0594   material->emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0595   material->emplace_back(
0596       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0597   material->emplace_back(
0598       Acts::Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0599   material->emplace_back(
0600       Acts::Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0601   material->emplace_back(
0602       Acts::Material::fromMolarDensity(31.0, 22.0, 23.0, 24.0, 25.0), 4.0);
0603 
0604   using EqBound = Acts::GridAxisGenerators::EqBound;
0605   using EqGrid = EqBound::grid_type<std::size_t>;
0606   using Point = EqGrid::point_t;
0607 
0608   EqBound eqBound{{0., 5.}, 5};
0609   EqGrid eqGrid{eqBound()};
0610 
0611   eqGrid.atPosition(Point{0.5}) = 1u;  // material 1
0612   eqGrid.atPosition(Point{1.5}) = 0u;  // vacuum
0613   eqGrid.atPosition(Point{2.5}) = 2u;  // material 2
0614   eqGrid.atPosition(Point{3.5}) = 2u;  // material 2
0615   eqGrid.atPosition(Point{4.5}) = 3u;  // material 3
0616 
0617   auto localX = std::make_unique<const LocalAccessX>();
0618   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX;
0619   bToX.connect<&LocalAccessX::l2X>(std::move(localX));
0620 
0621   auto globalX = std::make_unique<const GlobalAccessX>();
0622   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX;
0623   gToX.connect<&GlobalAccessX::g2X>(std::move(globalX));
0624 
0625   Acts::GloballyIndexedSurfaceMaterial<EqGrid> ism(
0626       std::move(eqGrid), Acts::GloballyIndexedMaterialAccessor{material, false},
0627       std::move(bToX), std::move(gToX));
0628 
0629   // Local access test
0630   Acts::Vector2 l0(0.5, 0.);
0631   Acts::Vector2 l1(1.5, 0.);
0632   Acts::Vector2 l2(2.5, 0.);
0633   Acts::Vector2 l3(3.5, 0.);
0634   Acts::Vector2 l4(4.5, 0.);
0635 
0636   const Acts::MaterialSlab& ml0 = ism.materialSlab(l0);
0637   const Acts::MaterialSlab& ml1 = ism.materialSlab(l1);
0638   const Acts::MaterialSlab& ml2 = ism.materialSlab(l2);
0639   const Acts::MaterialSlab& ml3 = ism.materialSlab(l3);
0640   const Acts::MaterialSlab& ml4 = ism.materialSlab(l4);
0641 
0642   BOOST_CHECK_EQUAL(ml0.material().X0(), 1.);
0643   BOOST_CHECK(ml1.material().isVacuum());
0644   BOOST_CHECK_EQUAL(ml2.material().X0(), 11.);
0645   BOOST_CHECK_EQUAL(ml3.material().X0(), 11.);
0646   BOOST_CHECK_EQUAL(ml4.material().X0(), 21.);
0647 
0648   EqBound eqBound1{{0., 5.}, 1};
0649   EqGrid eqGrid1{eqBound1()};
0650 
0651   auto localX1 = std::make_unique<const LocalAccessX>();
0652   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX1;
0653   bToX1.connect<&LocalAccessX::l2X>(std::move(localX1));
0654 
0655   auto globalX1 = std::make_unique<const GlobalAccessX>();
0656   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX1;
0657   gToX1.connect<&GlobalAccessX::g2X>(std::move(globalX1));
0658 
0659   eqGrid1.atPosition(Point{2.5}) = 4u;  // material 4
0660 
0661   Acts::GloballyIndexedSurfaceMaterial<EqGrid> ism1(
0662       std::move(eqGrid1),
0663       Acts::GloballyIndexedMaterialAccessor{material, false}, std::move(bToX1),
0664       std::move(gToX1));
0665 
0666   Acts::Vector2 l0g1(2.5, 0.);
0667   const Acts::MaterialSlab& ml0g1 = ism1.materialSlab(l0g1);
0668   BOOST_CHECK_EQUAL(ml0g1.material().X0(), 31.);
0669 
0670   // Scale
0671   ism1.scale(2.);
0672   const Acts::MaterialSlab& sml0g1 = ism1.materialSlab(l0g1);
0673   BOOST_CHECK_EQUAL(sml0g1.thickness(), 8.);
0674 
0675   // First one stays unscaled
0676   const Acts::MaterialSlab& sml0 = ism.materialSlab(l0);
0677   BOOST_CHECK_EQUAL(sml0.thickness(), 1.);
0678 }
0679 
0680 // This test covers the globally indexed grid material with shared
0681 BOOST_AUTO_TEST_CASE(GridGloballyIndexedMaterialShared) {
0682   auto material = std::make_shared<std::vector<Acts::MaterialSlab>>();
0683 
0684   material->emplace_back(Acts::Material::Vacuum(), 0.0);  // vacuum
0685   material->emplace_back(
0686       Acts::Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.0);
0687 
0688   using EqBound = Acts::GridAxisGenerators::EqBound;
0689   using EqGrid = EqBound::grid_type<std::size_t>;
0690   using Point = EqGrid::point_t;
0691 
0692   EqBound eqBound0{{0., 5.}, 1};
0693   EqGrid eqGrid0{eqBound0()};
0694 
0695   eqGrid0.atPosition(Point{2.5}) = 1u;  // material 1
0696   auto localX0 = std::make_unique<const LocalAccessX>();
0697   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX0;
0698   bToX0.connect<&LocalAccessX::l2X>(std::move(localX0));
0699 
0700   auto globalX0 = std::make_unique<const GlobalAccessX>();
0701   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX0;
0702   gToX0.connect<&GlobalAccessX::g2X>(std::move(globalX0));
0703 
0704   Acts::GloballyIndexedSurfaceMaterial<EqGrid> ism0(
0705       std::move(eqGrid0), Acts::GloballyIndexedMaterialAccessor{material, true},
0706       std::move(bToX0), std::move(gToX0));
0707 
0708   EqBound eqBound1{{0., 5.}, 1};
0709   EqGrid eqGrid1{eqBound1()};
0710 
0711   eqGrid1.atPosition(Point{2.5}) = 1u;  // material 1
0712   auto localX1 = std::make_unique<const LocalAccessX>();
0713   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX1;
0714   bToX1.connect<&LocalAccessX::l2X>(std::move(localX1));
0715 
0716   auto globalX1 = std::make_unique<const GlobalAccessX>();
0717   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX1;
0718   gToX1.connect<&GlobalAccessX::g2X>(std::move(globalX1));
0719 
0720   Acts::GloballyIndexedSurfaceMaterial<EqGrid> ism1(
0721       std::move(eqGrid1), Acts::GloballyIndexedMaterialAccessor{material, true},
0722       std::move(bToX1), std::move(gToX1));
0723 
0724   Acts::Vector2 l0(2.5, 0.);
0725 
0726   // check grid material 0
0727   const Acts::MaterialSlab& ml0 = ism0.materialSlab(l0);
0728   BOOST_CHECK_EQUAL(ml0.material().X0(), 1.);
0729 
0730   const Acts::MaterialSlab& ml0g1 = ism1.materialSlab(l0);
0731   BOOST_CHECK_EQUAL(ml0g1.material().X0(), 1.);
0732 
0733   // scaling shared material should throw a std::invalid_argument
0734   BOOST_CHECK_THROW(ism1.scale(2.), std::invalid_argument);
0735 }
0736 
0737 // This test covers the grid material (non-indexed accessor)
0738 //
0739 // In this setup, the material is not indexed, but filled directly
0740 // into the grid structure.
0741 BOOST_AUTO_TEST_CASE(GridSurfaceMaterialTests) {
0742   using EqBound = Acts::GridAxisGenerators::EqBound;
0743   using EqGrid = EqBound::grid_type<Acts::MaterialSlab>;
0744   using Point = EqGrid::point_t;
0745 
0746   EqBound eqBound{{0., 5.}, 5};
0747   EqGrid eqGrid{eqBound()};
0748 
0749   eqGrid.atPosition(Point{0.5}) = Acts::MaterialSlab::Vacuum(0.0);
0750   eqGrid.atPosition(Point{1.5}) = Acts::MaterialSlab::Vacuum(1.0);
0751   eqGrid.atPosition(Point{2.5}) = Acts::MaterialSlab::Vacuum(2.0);
0752   eqGrid.atPosition(Point{3.5}) = Acts::MaterialSlab::Vacuum(3.0);
0753   eqGrid.atPosition(Point{4.5}) = Acts::MaterialSlab::Vacuum(4.0);
0754 
0755   auto localX = std::make_unique<const LocalAccessX>();
0756   Acts::IndexedSurfaceMaterial<EqGrid>::BoundToGridLocalDelegate bToX;
0757   bToX.connect<&LocalAccessX::l2X>(std::move(localX));
0758 
0759   auto globalX = std::make_unique<const GlobalAccessX>();
0760   Acts::IndexedSurfaceMaterial<EqGrid>::GlobalToGridLocalDelegate gToX;
0761   gToX.connect<&GlobalAccessX::g2X>(std::move(globalX));
0762 
0763   Acts::GridSurfaceMaterial<EqGrid> gsm(std::move(eqGrid),
0764                                         Acts::GridMaterialAccessor{},
0765                                         std::move(bToX), std::move(gToX));
0766 
0767   // Global access test
0768   Acts::Vector3 g0(0.5, 0., 0.);
0769   Acts::Vector3 g1(1.5, 0., 0.);
0770   Acts::Vector3 g2(2.5, 0., 0.);
0771   Acts::Vector3 g3(3.5, 0., 0.);
0772   Acts::Vector3 g4(4.5, 0., 0.);
0773 
0774   const Acts::MaterialSlab& mg0 = gsm.materialSlab(g0);
0775   const Acts::MaterialSlab& mg1 = gsm.materialSlab(g1);
0776   const Acts::MaterialSlab& mg2 = gsm.materialSlab(g2);
0777   const Acts::MaterialSlab& mg3 = gsm.materialSlab(g3);
0778   const Acts::MaterialSlab& mg4 = gsm.materialSlab(g4);
0779 
0780   BOOST_CHECK_EQUAL(mg0.thickness(), 0.);
0781   BOOST_CHECK_EQUAL(mg1.thickness(), 1.);
0782   BOOST_CHECK_EQUAL(mg2.thickness(), 2.);
0783   BOOST_CHECK_EQUAL(mg3.thickness(), 3.);
0784   BOOST_CHECK_EQUAL(mg4.thickness(), 4.);
0785 
0786   // Local access test
0787   Acts::Vector2 l0(0.5, 0.);
0788   Acts::Vector2 l1(1.5, 0.);
0789   Acts::Vector2 l2(2.5, 0.);
0790   Acts::Vector2 l3(3.5, 0.);
0791   Acts::Vector2 l4(4.5, 0.);
0792 
0793   const Acts::MaterialSlab& ml0 = gsm.materialSlab(l0);
0794   const Acts::MaterialSlab& ml1 = gsm.materialSlab(l1);
0795   const Acts::MaterialSlab& ml2 = gsm.materialSlab(l2);
0796   const Acts::MaterialSlab& ml3 = gsm.materialSlab(l3);
0797   const Acts::MaterialSlab& ml4 = gsm.materialSlab(l4);
0798 
0799   BOOST_CHECK_EQUAL(ml0.thickness(), 0.);
0800   BOOST_CHECK_EQUAL(ml1.thickness(), 1.);
0801   BOOST_CHECK_EQUAL(ml2.thickness(), 2.);
0802   BOOST_CHECK_EQUAL(ml3.thickness(), 3.);
0803   BOOST_CHECK_EQUAL(ml4.thickness(), 4.);
0804 
0805   // Now scale it - and access again
0806   gsm.scale(2.);
0807 
0808   const Acts::MaterialSlab& sml0 = gsm.materialSlab(l0);
0809   const Acts::MaterialSlab& sml1 = gsm.materialSlab(l1);
0810   const Acts::MaterialSlab& sml2 = gsm.materialSlab(l2);
0811   const Acts::MaterialSlab& sml3 = gsm.materialSlab(l3);
0812   const Acts::MaterialSlab& sml4 = gsm.materialSlab(l4);
0813 
0814   BOOST_CHECK_EQUAL(sml0.thickness(), 0.);
0815   BOOST_CHECK_EQUAL(sml1.thickness(), 2.);
0816   BOOST_CHECK_EQUAL(sml2.thickness(), 4.);
0817   BOOST_CHECK_EQUAL(sml3.thickness(), 6.);
0818   BOOST_CHECK_EQUAL(sml4.thickness(), 8.);
0819 }
0820 
0821 BOOST_AUTO_TEST_SUITE_END()