File indexing completed on 2025-01-18 09:12:44
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/GeometryContext.hpp"
0013 #include "Acts/Geometry/GeometryIdentifier.hpp"
0014 #include "Acts/Material/AccumulatedMaterialSlab.hpp"
0015 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0016 #include "Acts/Material/MaterialInteraction.hpp"
0017 #include "Acts/Material/MaterialMapper.hpp"
0018 #include "Acts/Material/MaterialSlab.hpp"
0019 #include "Acts/Material/interface/IAssignmentFinder.hpp"
0020 #include "Acts/Material/interface/ISurfaceMaterialAccumulater.hpp"
0021 #include "Acts/Propagator/SurfaceCollector.hpp"
0022 #include "Acts/Surfaces/CylinderSurface.hpp"
0023 #include "Acts/Utilities/Enumerate.hpp"
0024 #include "Acts/Utilities/VectorHelpers.hpp"
0025
0026 #include <limits>
0027
0028 namespace Acts::Test {
0029
0030 auto tContext = GeometryContext();
0031
0032
0033
0034 class IntersectSurfacesFinder : public IAssignmentFinder {
0035 public:
0036 std::vector<const Surface*> surfaces;
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 std::pair<std::vector<IAssignmentFinder::SurfaceAssignment>,
0048 std::vector<IAssignmentFinder::VolumeAssignment>>
0049 assignmentCandidates(const GeometryContext& gctx,
0050 const MagneticFieldContext& ,
0051 const Vector3& position,
0052 const Vector3& direction) const override {
0053 std::vector<IAssignmentFinder::SurfaceAssignment> surfaceAssignments;
0054 std::vector<IAssignmentFinder::VolumeAssignment> volumeAssignments;
0055
0056 for (auto& surface : surfaces) {
0057
0058 auto sMultiIntersection = surface->intersect(gctx, position, direction,
0059 BoundaryTolerance::None());
0060
0061 if (sMultiIntersection.size() == 1u &&
0062 sMultiIntersection[0u].status() >=
0063 Acts::IntersectionStatus::reachable &&
0064 sMultiIntersection[0u].pathLength() >= 0.0) {
0065 surfaceAssignments.push_back(
0066 {surface, sMultiIntersection[0u].position(), direction});
0067 continue;
0068 }
0069 if (sMultiIntersection.size() > 1u) {
0070
0071 auto closestForward = sMultiIntersection.closestForward();
0072 if (closestForward.status() >= Acts::IntersectionStatus::reachable &&
0073 closestForward.pathLength() > 0.0) {
0074 surfaceAssignments.push_back(
0075 {surface, closestForward.position(), direction});
0076 continue;
0077 }
0078 }
0079 }
0080 return {surfaceAssignments, volumeAssignments};
0081 }
0082 };
0083
0084
0085 class MaterialBlender : public ISurfaceMaterialAccumulater {
0086 public:
0087 MaterialBlender(const std::vector<std::shared_ptr<Surface>>& surfaces = {})
0088 : m_surfaces(surfaces) {}
0089
0090
0091
0092 class State final : public ISurfaceMaterialAccumulater::State {
0093 public:
0094 std::map<const Surface*, AccumulatedMaterialSlab> accumulatedMaterial;
0095 };
0096
0097
0098 std::unique_ptr<ISurfaceMaterialAccumulater::State> createState()
0099 const override {
0100 auto state = std::make_unique<State>();
0101 for (auto& surface : m_surfaces) {
0102 state->accumulatedMaterial[surface.get()] = AccumulatedMaterialSlab();
0103 }
0104 return state;
0105 };
0106
0107
0108
0109
0110
0111
0112
0113
0114 void accumulate(ISurfaceMaterialAccumulater::State& state,
0115 const std::vector<MaterialInteraction>& interactions,
0116 const std::vector<IAssignmentFinder::SurfaceAssignment>&
0117 ) const override {
0118 auto cState = static_cast<State*>(&state);
0119 for (const auto& mi : interactions) {
0120
0121 const Surface* surface = mi.surface;
0122
0123 auto accMaterial = cState->accumulatedMaterial.find(surface);
0124 if (accMaterial == cState->accumulatedMaterial.end()) {
0125 throw std::invalid_argument(
0126 "Surface material is not found, inconsistent configuration.");
0127 }
0128
0129 accMaterial->second.accumulate(mi.materialSlab);
0130 }
0131
0132 for (auto& [surface, accumulatedMaterial] : cState->accumulatedMaterial) {
0133 accumulatedMaterial.trackAverage();
0134 }
0135 };
0136
0137
0138
0139
0140
0141
0142 std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>
0143 finalizeMaterial(ISurfaceMaterialAccumulater::State& state) const override {
0144 auto cState = static_cast<State*>(&state);
0145
0146 std::map<GeometryIdentifier, std::shared_ptr<const ISurfaceMaterial>>
0147 materialMaps;
0148 for (auto& [surface, accumulatedMaterial] : cState->accumulatedMaterial) {
0149 materialMaps[surface->geometryId()] =
0150 std::make_shared<HomogeneousSurfaceMaterial>(
0151 accumulatedMaterial.totalAverage().first);
0152 }
0153 return materialMaps;
0154 }
0155
0156 private:
0157 std::vector<std::shared_ptr<Surface>> m_surfaces;
0158 };
0159
0160 BOOST_AUTO_TEST_SUITE(MaterialMapperTestSuite)
0161
0162
0163
0164
0165
0166
0167 BOOST_AUTO_TEST_CASE(MaterialMapperFlowTest) {
0168
0169 std::vector<std::shared_ptr<Surface>> surfaces = {
0170 Surface::makeShared<CylinderSurface>(Transform3::Identity(), 20.0, 100.0),
0171 Surface::makeShared<CylinderSurface>(Transform3::Identity(), 30.0, 100.0),
0172 Surface::makeShared<CylinderSurface>(Transform3::Identity(), 50.0,
0173 100.0)};
0174
0175 for (auto [is, surface] : enumerate(surfaces)) {
0176 surface->assignGeometryId(GeometryIdentifier().setSensitive(is + 1));
0177 }
0178
0179
0180 auto assigner = std::make_shared<IntersectSurfacesFinder>();
0181 assigner->surfaces = {surfaces[0].get(), surfaces[1].get(),
0182 surfaces[2].get()};
0183
0184
0185 auto accumulator = std::make_shared<MaterialBlender>(surfaces);
0186
0187
0188 MaterialMapper::Config mmConfig;
0189 mmConfig.assignmentFinder = assigner;
0190 mmConfig.surfaceMaterialAccumulater = accumulator;
0191
0192 MaterialMapper mapper(mmConfig);
0193
0194 auto state = mapper.createState();
0195 BOOST_CHECK(state.get() != nullptr);
0196 BOOST_CHECK(state->surfaceMaterialAccumulaterState.get() != nullptr);
0197
0198 std::vector<RecordedMaterialTrack> mappedTracks;
0199 std::vector<RecordedMaterialTrack> unmappedTracks;
0200
0201
0202 Vector3 position(0., 0., 0.);
0203 for (unsigned int it = 0; it < 11; ++it) {
0204 Vector3 direction =
0205 Vector3(0.9 + it * 0.02, 1.1 - it * 0.02, 0.).normalized();
0206 RecordedMaterialTrack mTrack{{position, direction}, {}};
0207 for (unsigned int im = 0; im < 60; ++im) {
0208 MaterialInteraction mi;
0209 mi.materialSlab = MaterialSlab(
0210 Material::fromMassDensity(it + 1, it + 1, it + 1, it + 1, it + 1),
0211 0.1);
0212 mi.position = position + (im + 1) * direction;
0213 mi.direction = direction;
0214 mTrack.second.materialInteractions.push_back(mi);
0215 }
0216 auto [mapped, unmapped] = mapper.mapMaterial(*state, tContext, {}, mTrack);
0217 mappedTracks.push_back(mapped);
0218 unmappedTracks.push_back(unmapped);
0219 }
0220
0221
0222 auto [surfaceMaps, volumeMaps] = mapper.finalizeMaps(*state);
0223
0224 BOOST_CHECK(surfaceMaps.size() == 3);
0225 BOOST_CHECK(volumeMaps.empty());
0226 }
0227
0228 BOOST_AUTO_TEST_CASE(MaterialMapperInvalidTest) {
0229
0230 auto assigner = std::make_shared<IntersectSurfacesFinder>();
0231
0232
0233 auto accumulator = std::make_shared<MaterialBlender>();
0234
0235
0236 MaterialMapper::Config mmConfigInvalid;
0237 mmConfigInvalid.assignmentFinder = nullptr;
0238 mmConfigInvalid.surfaceMaterialAccumulater = accumulator;
0239
0240 BOOST_CHECK_THROW(auto mapperIA = MaterialMapper(mmConfigInvalid),
0241 std::invalid_argument);
0242
0243
0244
0245 mmConfigInvalid.assignmentFinder = assigner;
0246 mmConfigInvalid.surfaceMaterialAccumulater = nullptr;
0247
0248 BOOST_CHECK_THROW(auto mapperIS = MaterialMapper(mmConfigInvalid),
0249 std::invalid_argument);
0250 }
0251
0252 BOOST_AUTO_TEST_SUITE_END()
0253
0254 }