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