File indexing completed on 2025-08-05 08:09:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Material/SurfaceMaterialMapper.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Direction.hpp"
0013 #include "Acts/Definitions/Tolerance.hpp"
0014 #include "Acts/EventData/ParticleHypothesis.hpp"
0015 #include "Acts/EventData/TrackParameters.hpp"
0016 #include "Acts/Geometry/ApproachDescriptor.hpp"
0017 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0018 #include "Acts/Geometry/Layer.hpp"
0019 #include "Acts/Geometry/TrackingGeometry.hpp"
0020 #include "Acts/Material/BinnedSurfaceMaterial.hpp"
0021 #include "Acts/Material/ISurfaceMaterial.hpp"
0022 #include "Acts/Material/MaterialInteraction.hpp"
0023 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0024 #include "Acts/Propagator/AbortList.hpp"
0025 #include "Acts/Propagator/ActionList.hpp"
0026 #include "Acts/Propagator/Navigator.hpp"
0027 #include "Acts/Propagator/Propagator.hpp"
0028 #include "Acts/Propagator/SurfaceCollector.hpp"
0029 #include "Acts/Propagator/VolumeCollector.hpp"
0030 #include "Acts/Surfaces/SurfaceArray.hpp"
0031 #include "Acts/Utilities/BinAdjustment.hpp"
0032 #include "Acts/Utilities/BinUtility.hpp"
0033 #include "Acts/Utilities/BinnedArray.hpp"
0034 #include "Acts/Utilities/Result.hpp"
0035
0036 #include <cstddef>
0037 #include <ostream>
0038 #include <string>
0039 #include <tuple>
0040 #include <utility>
0041 #include <vector>
0042
0043 namespace Acts {
0044 struct EndOfWorldReached;
0045 }
0046
0047 Acts::SurfaceMaterialMapper::SurfaceMaterialMapper(
0048 const Config& cfg, StraightLinePropagator propagator,
0049 std::unique_ptr<const Logger> slogger)
0050 : m_cfg(cfg),
0051 m_propagator(std::move(propagator)),
0052 m_logger(std::move(slogger)) {}
0053
0054 Acts::SurfaceMaterialMapper::State Acts::SurfaceMaterialMapper::createState(
0055 const GeometryContext& gctx, const MagneticFieldContext& mctx,
0056 const TrackingGeometry& tGeometry) const {
0057
0058 auto world = tGeometry.highestTrackingVolume();
0059
0060
0061 State mState(gctx, mctx);
0062 resolveMaterialSurfaces(mState, *world);
0063 collectMaterialVolumes(mState, *world);
0064
0065 ACTS_DEBUG(mState.accumulatedMaterial.size()
0066 << " Surfaces with PROXIES collected ... ");
0067 for (auto& smg : mState.accumulatedMaterial) {
0068 ACTS_VERBOSE(" -> Surface in with id " << smg.first);
0069 }
0070 return mState;
0071 }
0072
0073 void Acts::SurfaceMaterialMapper::resolveMaterialSurfaces(
0074 State& mState, const TrackingVolume& tVolume) const {
0075 ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0076 << "' for material surfaces.")
0077
0078 ACTS_VERBOSE("- boundary surfaces ...");
0079
0080 for (auto& bSurface : tVolume.boundarySurfaces()) {
0081 checkAndInsert(mState, bSurface->surfaceRepresentation());
0082 }
0083
0084 ACTS_VERBOSE("- confined layers ...");
0085
0086 if (tVolume.confinedLayers() != nullptr) {
0087 for (auto& cLayer : tVolume.confinedLayers()->arrayObjects()) {
0088
0089 if (cLayer->layerType() != navigation) {
0090
0091 checkAndInsert(mState, cLayer->surfaceRepresentation());
0092
0093 if (cLayer->approachDescriptor() != nullptr) {
0094 for (auto& aSurface :
0095 cLayer->approachDescriptor()->containedSurfaces()) {
0096 if (aSurface != nullptr) {
0097 checkAndInsert(mState, *aSurface);
0098 }
0099 }
0100 }
0101
0102 if (cLayer->surfaceArray() != nullptr) {
0103
0104 for (auto& sSurface : cLayer->surfaceArray()->surfaces()) {
0105 if (sSurface != nullptr) {
0106 checkAndInsert(mState, *sSurface);
0107 }
0108 }
0109 }
0110 }
0111 }
0112 }
0113
0114 if (tVolume.confinedVolumes()) {
0115 for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0116
0117 resolveMaterialSurfaces(mState, *sVolume);
0118 }
0119 }
0120 }
0121
0122 void Acts::SurfaceMaterialMapper::checkAndInsert(State& mState,
0123 const Surface& surface) const {
0124 auto surfaceMaterial = surface.surfaceMaterial();
0125
0126 if (surfaceMaterial != nullptr) {
0127 if (m_cfg.computeVariance) {
0128 mState.inputSurfaceMaterial[surface.geometryId()] =
0129 surface.surfaceMaterialSharedPtr();
0130 }
0131 auto geoID = surface.geometryId();
0132 std::size_t volumeID = geoID.volume();
0133 ACTS_DEBUG("Material surface found with volumeID " << volumeID);
0134 ACTS_DEBUG(" - surfaceID is " << geoID);
0135
0136
0137
0138 auto psm = dynamic_cast<const ProtoSurfaceMaterial*>(surfaceMaterial);
0139
0140
0141 const BinUtility* bu = (psm != nullptr) ? (&psm->binning()) : nullptr;
0142 if (bu != nullptr) {
0143
0144 ACTS_DEBUG(" - (proto) binning is " << *bu);
0145
0146 BinUtility buAdjusted = adjustBinUtility(*bu, surface, mState.geoContext);
0147
0148 ACTS_DEBUG(" - adjusted binning is " << buAdjusted);
0149 mState.accumulatedMaterial[geoID] =
0150 AccumulatedSurfaceMaterial(buAdjusted);
0151 return;
0152 }
0153
0154
0155 auto bmp = dynamic_cast<const BinnedSurfaceMaterial*>(surfaceMaterial);
0156 bu = (bmp != nullptr) ? (&bmp->binUtility()) : nullptr;
0157
0158 if (bu != nullptr) {
0159
0160 ACTS_DEBUG(" - binning is " << *bu);
0161 mState.accumulatedMaterial[geoID] = AccumulatedSurfaceMaterial(*bu);
0162 } else {
0163
0164 ACTS_DEBUG(" - this is homogeneous material.");
0165 mState.accumulatedMaterial[geoID] = AccumulatedSurfaceMaterial();
0166 }
0167 }
0168 }
0169
0170 void Acts::SurfaceMaterialMapper::collectMaterialVolumes(
0171 State& mState, const TrackingVolume& tVolume) const {
0172 ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0173 << "' for material surfaces.")
0174 ACTS_VERBOSE("- Insert Volume ...");
0175 if (tVolume.volumeMaterial() != nullptr) {
0176 mState.volumeMaterial[tVolume.geometryId()] =
0177 tVolume.volumeMaterialSharedPtr();
0178 }
0179
0180
0181 if (tVolume.confinedVolumes()) {
0182 ACTS_VERBOSE("- Check children volume ...");
0183 for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0184
0185 collectMaterialVolumes(mState, *sVolume);
0186 }
0187 }
0188 if (!tVolume.denseVolumes().empty()) {
0189 for (auto& sVolume : tVolume.denseVolumes()) {
0190
0191 collectMaterialVolumes(mState, *sVolume);
0192 }
0193 }
0194 }
0195
0196 void Acts::SurfaceMaterialMapper::finalizeMaps(State& mState) const {
0197
0198 for (auto& accMaterial : mState.accumulatedMaterial) {
0199 ACTS_DEBUG("Finalizing map for Surface " << accMaterial.first);
0200 mState.surfaceMaterial[accMaterial.first] =
0201 accMaterial.second.totalAverage();
0202 }
0203 }
0204
0205 void Acts::SurfaceMaterialMapper::mapMaterialTrack(
0206 State& mState, RecordedMaterialTrack& mTrack) const {
0207
0208 auto& rMaterial = mTrack.second.materialInteractions;
0209 ACTS_VERBOSE("Retrieved " << rMaterial.size()
0210 << " recorded material steps to map.")
0211
0212
0213
0214 if (rMaterial.begin()->intersectionID != GeometryIdentifier()) {
0215 ACTS_VERBOSE(
0216 "Material surfaces are associated with the material interaction. The "
0217 "association interaction/surfaces won't be performed again.");
0218 mapSurfaceInteraction(mState, rMaterial);
0219 return;
0220 } else {
0221 ACTS_VERBOSE(
0222 "Material interactions need to be associated with surfaces. Collecting "
0223 "all surfaces on the trajectory.");
0224 mapInteraction(mState, mTrack);
0225 return;
0226 }
0227 }
0228 void Acts::SurfaceMaterialMapper::mapInteraction(
0229 State& mState, RecordedMaterialTrack& mTrack) const {
0230
0231 auto& rMaterial = mTrack.second.materialInteractions;
0232 std::map<GeometryIdentifier, unsigned int> assignedMaterial;
0233 using VectorHelpers::makeVector4;
0234
0235 NeutralCurvilinearTrackParameters start(
0236 makeVector4(mTrack.first.first, 0), mTrack.first.second,
0237 1 / mTrack.first.second.norm(), std::nullopt,
0238 NeutralParticleHypothesis::geantino());
0239
0240
0241 using MaterialSurfaceCollector = SurfaceCollector<MaterialSurface>;
0242 using MaterialVolumeCollector = VolumeCollector<MaterialVolume>;
0243 using ActionList =
0244 ActionList<MaterialSurfaceCollector, MaterialVolumeCollector>;
0245 using AbortList = AbortList<EndOfWorldReached>;
0246
0247 PropagatorOptions<ActionList, AbortList> options(mState.geoContext,
0248 mState.magFieldContext);
0249
0250
0251 const auto& result = m_propagator.propagate(start, options).value();
0252 auto mcResult = result.get<MaterialSurfaceCollector::result_type>();
0253 auto mvcResult = result.get<MaterialVolumeCollector::result_type>();
0254
0255 auto mappingSurfaces = mcResult.collected;
0256 auto mappingVolumes = mvcResult.collected;
0257
0258
0259 ACTS_VERBOSE("Found " << mappingSurfaces.size()
0260 << " mapping surfaces for this track.");
0261 ACTS_VERBOSE("Mapping surfaces are :")
0262 for (auto& mSurface : mappingSurfaces) {
0263 ACTS_VERBOSE(" - Surface : " << mSurface.surface->geometryId()
0264 << " at position = (" << mSurface.position.x()
0265 << ", " << mSurface.position.y() << ", "
0266 << mSurface.position.z() << ")");
0267 assignedMaterial[mSurface.surface->geometryId()] = 0;
0268 }
0269
0270
0271
0272
0273
0274
0275 auto rmIter = rMaterial.begin();
0276 auto sfIter = mappingSurfaces.begin();
0277 auto volIter = mappingVolumes.begin();
0278
0279
0280 GeometryIdentifier lastID = GeometryIdentifier();
0281 GeometryIdentifier currentID = GeometryIdentifier();
0282 Vector3 currentPos(0., 0., 0);
0283 float currentPathCorrection = 1.;
0284 auto currentAccMaterial = mState.accumulatedMaterial.end();
0285
0286
0287 using MapBin =
0288 std::pair<AccumulatedSurfaceMaterial*, std::array<std::size_t, 3>>;
0289 using MaterialBin = std::pair<AccumulatedSurfaceMaterial*,
0290 std::shared_ptr<const ISurfaceMaterial>>;
0291 std::map<AccumulatedSurfaceMaterial*, std::array<std::size_t, 3>>
0292 touchedMapBins;
0293 std::map<AccumulatedSurfaceMaterial*, std::shared_ptr<const ISurfaceMaterial>>
0294 touchedMaterialBin;
0295 if (sfIter != mappingSurfaces.end() &&
0296 sfIter->surface->surfaceMaterial()->mappingType() ==
0297 Acts::MappingType::PostMapping) {
0298 ACTS_WARNING(
0299 "The first mapping surface is a PostMapping one. Some material from "
0300 "before the PostMapping surface will be mapped onto it ");
0301 }
0302
0303
0304 while (rmIter != rMaterial.end() && sfIter != mappingSurfaces.end()) {
0305
0306 if (volIter != mappingVolumes.end() &&
0307 !volIter->volume->inside(rmIter->position)) {
0308 double distVol = (volIter->position - mTrack.first.first).norm();
0309 double distMat = (rmIter->position - mTrack.first.first).norm();
0310
0311 if (distMat - distVol > s_epsilon) {
0312
0313 ++volIter;
0314 continue;
0315 }
0316 }
0317
0318 if (volIter != mappingVolumes.end() &&
0319 volIter->volume->inside(rmIter->position)) {
0320 ++rmIter;
0321 continue;
0322 }
0323
0324 if (sfIter != mappingSurfaces.end() - 1) {
0325 int mappingType = sfIter->surface->surfaceMaterial()->mappingType();
0326 int nextMappingType =
0327 (sfIter + 1)->surface->surfaceMaterial()->mappingType();
0328
0329 if (mappingType == Acts::MappingType::PreMapping ||
0330 mappingType == Acts::MappingType::Sensor) {
0331
0332 if ((rmIter->position - mTrack.first.first).norm() >
0333 (sfIter->position - mTrack.first.first).norm()) {
0334 if (nextMappingType == Acts::MappingType::PostMapping) {
0335 ACTS_WARNING(
0336 "PreMapping or Sensor surface followed by PostMapping. Some "
0337 "material "
0338 "from before the PostMapping surface will be mapped onto it");
0339 }
0340 ++sfIter;
0341 continue;
0342 }
0343 } else if (mappingType == Acts::MappingType::Default ||
0344 mappingType == Acts::MappingType::PostMapping) {
0345 switch (nextMappingType) {
0346 case Acts::MappingType::PreMapping:
0347 case Acts::MappingType::Default: {
0348
0349 if ((rmIter->position - sfIter->position).norm() >
0350 (rmIter->position - (sfIter + 1)->position).norm()) {
0351 ++sfIter;
0352 continue;
0353 }
0354 break;
0355 }
0356 case Acts::MappingType::PostMapping: {
0357
0358 if ((rmIter->position - sfIter->position).norm() >
0359 ((sfIter + 1)->position - sfIter->position).norm()) {
0360 ++sfIter;
0361 continue;
0362 }
0363 break;
0364 }
0365 case Acts::MappingType::Sensor: {
0366
0367 if ((rmIter == rMaterial.end() - 1) ||
0368 ((rmIter + 1)->position - sfIter->position).norm() >
0369 ((sfIter + 1)->position - sfIter->position).norm()) {
0370 ++sfIter;
0371 continue;
0372 }
0373 break;
0374 }
0375 default: {
0376 ACTS_ERROR("Incorrect mapping type for the next surface : "
0377 << (sfIter + 1)->surface->geometryId());
0378 }
0379 }
0380 } else {
0381 ACTS_ERROR("Incorrect mapping type for surface : "
0382 << sfIter->surface->geometryId());
0383 }
0384 }
0385
0386
0387 currentID = sfIter->surface->geometryId();
0388
0389 if (!(currentID == lastID)) {
0390
0391 lastID = currentID;
0392 currentPos = (sfIter)->position;
0393 currentPathCorrection = sfIter->surface->pathCorrection(
0394 mState.geoContext, currentPos, sfIter->direction);
0395 currentAccMaterial = mState.accumulatedMaterial.find(currentID);
0396 }
0397
0398 auto tBin = currentAccMaterial->second.accumulate(
0399 currentPos, rmIter->materialSlab, currentPathCorrection);
0400 if (touchedMapBins.find(&(currentAccMaterial->second)) ==
0401 touchedMapBins.end()) {
0402 touchedMapBins.insert(MapBin(&(currentAccMaterial->second), tBin));
0403 }
0404 if (m_cfg.computeVariance) {
0405 touchedMaterialBin[&(currentAccMaterial->second)] =
0406 mState.inputSurfaceMaterial[currentID];
0407 }
0408 ++assignedMaterial[currentID];
0409
0410
0411 rmIter->surface = sfIter->surface;
0412 rmIter->intersection = sfIter->position;
0413 rmIter->intersectionID = currentID;
0414 rmIter->pathCorrection = currentPathCorrection;
0415
0416 ++rmIter;
0417 }
0418
0419 ACTS_VERBOSE("Surfaces have following number of assigned hits :")
0420 for (auto& [key, value] : assignedMaterial) {
0421 ACTS_VERBOSE(" + Surface : " << key << " has " << value << " hits.");
0422 }
0423
0424
0425 for (auto tmapBin : touchedMapBins) {
0426 std::vector<std::array<std::size_t, 3>> trackBins = {tmapBin.second};
0427 if (m_cfg.computeVariance) {
0428
0429 auto binnedMaterial = dynamic_cast<const BinnedSurfaceMaterial*>(
0430 touchedMaterialBin[tmapBin.first].get());
0431 if (binnedMaterial != nullptr) {
0432 tmapBin.first->trackVariance(
0433 trackBins,
0434 binnedMaterial->fullMaterial()[trackBins[0][1]][trackBins[0][0]]);
0435 }
0436 }
0437 tmapBin.first->trackAverage(trackBins);
0438 }
0439
0440
0441 if (m_cfg.emptyBinCorrection) {
0442
0443
0444
0445 for (auto& mSurface : mappingSurfaces) {
0446 auto mgID = mSurface.surface->geometryId();
0447
0448
0449 if (assignedMaterial[mgID] == 0) {
0450 auto missedMaterial = mState.accumulatedMaterial.find(mgID);
0451 if (m_cfg.computeVariance) {
0452 missedMaterial->second.trackVariance(
0453 mSurface.position,
0454 mState.inputSurfaceMaterial[currentID]->materialSlab(
0455 mSurface.position),
0456 true);
0457 }
0458 missedMaterial->second.trackAverage(mSurface.position, true);
0459
0460
0461 Acts::MaterialInteraction noMaterial;
0462 noMaterial.surface = mSurface.surface;
0463 noMaterial.intersection = mSurface.position;
0464 noMaterial.intersectionID = mgID;
0465 rMaterial.push_back(noMaterial);
0466 }
0467 }
0468 }
0469 }
0470
0471 void Acts::SurfaceMaterialMapper::mapSurfaceInteraction(
0472 State& mState, std::vector<MaterialInteraction>& rMaterial) const {
0473 using MapBin =
0474 std::pair<AccumulatedSurfaceMaterial*, std::array<std::size_t, 3>>;
0475 std::map<AccumulatedSurfaceMaterial*, std::array<std::size_t, 3>>
0476 touchedMapBins;
0477 std::map<AccumulatedSurfaceMaterial*, std::shared_ptr<const ISurfaceMaterial>>
0478 touchedMaterialBin;
0479
0480
0481 auto rmIter = rMaterial.begin();
0482 while (rmIter != rMaterial.end()) {
0483
0484 GeometryIdentifier currentID = rmIter->intersectionID;
0485 Vector3 currentPos = rmIter->intersection;
0486 auto currentAccMaterial = mState.accumulatedMaterial.find(currentID);
0487
0488
0489 auto tBin = currentAccMaterial->second.accumulate(
0490 currentPos, rmIter->materialSlab, rmIter->pathCorrection);
0491 if (touchedMapBins.find(&(currentAccMaterial->second)) ==
0492 touchedMapBins.end()) {
0493 touchedMapBins.insert(MapBin(&(currentAccMaterial->second), tBin));
0494 }
0495 if (m_cfg.computeVariance) {
0496 touchedMaterialBin[&(currentAccMaterial->second)] =
0497 mState.inputSurfaceMaterial[currentID];
0498 }
0499 ++rmIter;
0500 }
0501
0502
0503 for (auto tmapBin : touchedMapBins) {
0504 std::vector<std::array<std::size_t, 3>> trackBins = {tmapBin.second};
0505 if (m_cfg.computeVariance) {
0506
0507 auto binnedMaterial = dynamic_cast<const BinnedSurfaceMaterial*>(
0508 touchedMaterialBin[tmapBin.first].get());
0509 if (binnedMaterial != nullptr) {
0510 tmapBin.first->trackVariance(
0511 trackBins,
0512 binnedMaterial->fullMaterial()[trackBins[0][1]][trackBins[0][0]],
0513 true);
0514 }
0515 }
0516
0517
0518 tmapBin.first->trackAverage(trackBins, true);
0519 }
0520 }