File indexing completed on 2025-08-05 08:09:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Material/VolumeMaterialMapper.hpp"
0010
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Tolerance.hpp"
0013 #include "Acts/EventData/ParticleHypothesis.hpp"
0014 #include "Acts/EventData/TrackParameters.hpp"
0015 #include "Acts/Geometry/ApproachDescriptor.hpp"
0016 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0017 #include "Acts/Geometry/Layer.hpp"
0018 #include "Acts/Geometry/TrackingGeometry.hpp"
0019 #include "Acts/Material/AccumulatedVolumeMaterial.hpp"
0020 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
0021 #include "Acts/Material/IVolumeMaterial.hpp"
0022 #include "Acts/Material/InterpolatedMaterialMap.hpp"
0023 #include "Acts/Material/Material.hpp"
0024 #include "Acts/Material/MaterialGridHelper.hpp"
0025 #include "Acts/Material/MaterialInteraction.hpp"
0026 #include "Acts/Material/ProtoVolumeMaterial.hpp"
0027 #include "Acts/Propagator/AbortList.hpp"
0028 #include "Acts/Propagator/ActionList.hpp"
0029 #include "Acts/Propagator/SurfaceCollector.hpp"
0030 #include "Acts/Propagator/VolumeCollector.hpp"
0031 #include "Acts/Surfaces/SurfaceArray.hpp"
0032 #include "Acts/Utilities/BinAdjustmentVolume.hpp"
0033 #include "Acts/Utilities/BinnedArray.hpp"
0034 #include "Acts/Utilities/Grid.hpp"
0035 #include "Acts/Utilities/Result.hpp"
0036
0037 #include <cmath>
0038 #include <cstddef>
0039 #include <iosfwd>
0040 #include <ostream>
0041 #include <stdexcept>
0042 #include <string>
0043 #include <tuple>
0044 #include <type_traits>
0045 #include <vector>
0046
0047 namespace Acts {
0048 struct EndOfWorldReached;
0049 }
0050
0051 Acts::VolumeMaterialMapper::VolumeMaterialMapper(
0052 const Config& cfg, StraightLinePropagator propagator,
0053 std::unique_ptr<const Logger> slogger)
0054 : m_cfg(cfg),
0055 m_propagator(std::move(propagator)),
0056 m_logger(std::move(slogger)) {}
0057
0058 Acts::VolumeMaterialMapper::State Acts::VolumeMaterialMapper::createState(
0059 const GeometryContext& gctx, const MagneticFieldContext& mctx,
0060 const TrackingGeometry& tGeometry) const {
0061
0062 auto world = tGeometry.highestTrackingVolume();
0063
0064
0065 State mState(gctx, mctx);
0066 resolveMaterialVolume(mState, *world);
0067 collectMaterialSurfaces(mState, *world);
0068 return mState;
0069 }
0070
0071 void Acts::VolumeMaterialMapper::resolveMaterialVolume(
0072 State& mState, const TrackingVolume& tVolume) const {
0073 ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0074 << "' for material surfaces.")
0075
0076 ACTS_VERBOSE("- Insert Volume ...");
0077 checkAndInsert(mState, tVolume);
0078
0079
0080 if (tVolume.confinedVolumes()) {
0081 ACTS_VERBOSE("- Check children volume ...");
0082 for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0083
0084 resolveMaterialVolume(mState, *sVolume);
0085 }
0086 }
0087 if (!tVolume.denseVolumes().empty()) {
0088 for (auto& sVolume : tVolume.denseVolumes()) {
0089
0090 resolveMaterialVolume(mState, *sVolume);
0091 }
0092 }
0093 }
0094
0095 void Acts::VolumeMaterialMapper::checkAndInsert(
0096 State& mState, const TrackingVolume& volume) const {
0097 auto volumeMaterial = volume.volumeMaterial();
0098
0099 if (volumeMaterial != nullptr) {
0100 auto geoID = volume.geometryId();
0101 std::size_t volumeID = geoID.volume();
0102 ACTS_DEBUG("Material volume found with volumeID " << volumeID);
0103 ACTS_DEBUG(" - ID is " << geoID);
0104
0105
0106
0107 auto psm = dynamic_cast<const ProtoVolumeMaterial*>(volumeMaterial);
0108
0109 const BinUtility* bu = (psm != nullptr) ? (&psm->binUtility()) : nullptr;
0110 if (bu != nullptr) {
0111
0112 ACTS_DEBUG(" - (proto) binning is " << *bu);
0113
0114 BinUtility buAdjusted = adjustBinUtility(*bu, volume);
0115
0116 ACTS_DEBUG(" - adjusted binning is " << buAdjusted);
0117 mState.materialBin[geoID] = buAdjusted;
0118 if (bu->dimensions() == 0) {
0119 ACTS_DEBUG("Binning of dimension 0 create AccumulatedVolumeMaterial");
0120 Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
0121 mState.homogeneousGrid[geoID] = homogeneousAccumulation;
0122 } else if (bu->dimensions() == 2) {
0123 ACTS_DEBUG("Binning of dimension 2 create 2D Grid");
0124 std::function<Acts::Vector2(Acts::Vector3)> transfoGlobalToLocal;
0125 Acts::Grid2D Grid = createGrid2D(buAdjusted, transfoGlobalToLocal);
0126 mState.grid2D.insert(std::make_pair(geoID, Grid));
0127 mState.transform2D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0128 } else if (bu->dimensions() == 3) {
0129 ACTS_DEBUG("Binning of dimension 3 create 3D Grid");
0130 std::function<Acts::Vector3(Acts::Vector3)> transfoGlobalToLocal;
0131 Acts::Grid3D Grid = createGrid3D(buAdjusted, transfoGlobalToLocal);
0132 mState.grid3D.insert(std::make_pair(geoID, Grid));
0133 mState.transform3D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0134 } else {
0135 throw std::invalid_argument(
0136 "Incorrect bin dimension, only 0, 2 and 3 are accepted");
0137 }
0138 return;
0139 }
0140
0141 auto bmp2 = dynamic_cast<
0142 const InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid2D>>*>(
0143 volumeMaterial);
0144 bu = (bmp2 != nullptr) ? (&bmp2->binUtility()) : nullptr;
0145 if (bu != nullptr) {
0146
0147 ACTS_DEBUG(" - (2D grid) binning is " << *bu);
0148 mState.materialBin[geoID] = *bu;
0149 std::function<Acts::Vector2(Acts::Vector3)> transfoGlobalToLocal;
0150 Acts::Grid2D Grid = createGrid2D(*bu, transfoGlobalToLocal);
0151 mState.grid2D.insert(std::make_pair(geoID, Grid));
0152 mState.transform2D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0153 return;
0154 }
0155
0156 auto bmp3 = dynamic_cast<
0157 const InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid3D>>*>(
0158 volumeMaterial);
0159 bu = (bmp3 != nullptr) ? (&bmp3->binUtility()) : nullptr;
0160 if (bu != nullptr) {
0161
0162 ACTS_DEBUG(" - (3D grid) binning is " << *bu);
0163 mState.materialBin[geoID] = *bu;
0164 std::function<Acts::Vector3(Acts::Vector3)> transfoGlobalToLocal;
0165 Acts::Grid3D Grid = createGrid3D(*bu, transfoGlobalToLocal);
0166 mState.grid3D.insert(std::make_pair(geoID, Grid));
0167 mState.transform3D.insert(std::make_pair(geoID, transfoGlobalToLocal));
0168 return;
0169 } else {
0170
0171 ACTS_DEBUG(" - this is homogeneous material.");
0172 BinUtility buHomogeneous;
0173 mState.materialBin[geoID] = buHomogeneous;
0174 Acts::AccumulatedVolumeMaterial homogeneousAccumulation;
0175 mState.homogeneousGrid[geoID] = homogeneousAccumulation;
0176 return;
0177 }
0178 }
0179 }
0180
0181 void Acts::VolumeMaterialMapper::collectMaterialSurfaces(
0182 State& mState, const TrackingVolume& tVolume) const {
0183 ACTS_VERBOSE("Checking volume '" << tVolume.volumeName()
0184 << "' for material surfaces.")
0185
0186 ACTS_VERBOSE("- boundary surfaces ...");
0187
0188 for (auto& bSurface : tVolume.boundarySurfaces()) {
0189 if (bSurface->surfaceRepresentation().surfaceMaterial() != nullptr) {
0190 mState.surfaceMaterial[bSurface->surfaceRepresentation().geometryId()] =
0191 bSurface->surfaceRepresentation().surfaceMaterialSharedPtr();
0192 }
0193 }
0194
0195 ACTS_VERBOSE("- confined layers ...");
0196
0197 if (tVolume.confinedLayers() != nullptr) {
0198 for (auto& cLayer : tVolume.confinedLayers()->arrayObjects()) {
0199
0200 if (cLayer->layerType() != navigation) {
0201
0202 if (cLayer->surfaceRepresentation().surfaceMaterial() != nullptr) {
0203 mState.surfaceMaterial[cLayer->surfaceRepresentation().geometryId()] =
0204 cLayer->surfaceRepresentation().surfaceMaterialSharedPtr();
0205 }
0206
0207 if (cLayer->approachDescriptor() != nullptr) {
0208 for (auto& aSurface :
0209 cLayer->approachDescriptor()->containedSurfaces()) {
0210 if (aSurface != nullptr) {
0211 if (aSurface->surfaceMaterial() != nullptr) {
0212 mState.surfaceMaterial[aSurface->geometryId()] =
0213 aSurface->surfaceMaterialSharedPtr();
0214 }
0215 }
0216 }
0217 }
0218
0219 if (cLayer->surfaceArray() != nullptr) {
0220
0221 for (auto& sSurface : cLayer->surfaceArray()->surfaces()) {
0222 if (sSurface != nullptr) {
0223 if (sSurface->surfaceMaterial() != nullptr) {
0224 mState.surfaceMaterial[sSurface->geometryId()] =
0225 sSurface->surfaceMaterialSharedPtr();
0226 }
0227 }
0228 }
0229 }
0230 }
0231 }
0232 }
0233
0234 if (tVolume.confinedVolumes()) {
0235 for (auto& sVolume : tVolume.confinedVolumes()->arrayObjects()) {
0236
0237 collectMaterialSurfaces(mState, *sVolume);
0238 }
0239 }
0240 }
0241
0242 void Acts::VolumeMaterialMapper::createExtraHits(
0243 State& mState,
0244 std::pair<const GeometryIdentifier, BinUtility>& currentBinning,
0245 Acts::MaterialSlab properties, const Vector3& position,
0246 Vector3 direction) const {
0247 if (currentBinning.second.dimensions() == 0) {
0248
0249
0250 mState.homogeneousGrid[currentBinning.first].accumulate(properties);
0251 return;
0252 }
0253
0254
0255 int volumeStep =
0256 static_cast<int>(std::floor(properties.thickness() / m_cfg.mappingStep));
0257 float remainder = properties.thickness() - m_cfg.mappingStep * volumeStep;
0258 properties.scaleThickness(m_cfg.mappingStep / properties.thickness());
0259 direction = direction * (m_cfg.mappingStep / direction.norm());
0260
0261 for (int extraStep = 0; extraStep < volumeStep; extraStep++) {
0262 Vector3 extraPosition = position + extraStep * direction;
0263
0264
0265 if (currentBinning.second.dimensions() == 2) {
0266 auto grid = mState.grid2D.find(currentBinning.first);
0267 if (grid != mState.grid2D.end()) {
0268
0269 Acts::Grid2D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0270 mState.transform2D[currentBinning.first](extraPosition));
0271 grid->second.atLocalBins(index).accumulate(properties);
0272 } else {
0273 throw std::domain_error("No grid 2D was found");
0274 }
0275 } else if (currentBinning.second.dimensions() == 3) {
0276 auto grid = mState.grid3D.find(currentBinning.first);
0277 if (grid != mState.grid3D.end()) {
0278
0279 Acts::Grid3D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0280 mState.transform3D[currentBinning.first](extraPosition));
0281 grid->second.atLocalBins(index).accumulate(properties);
0282 } else {
0283 throw std::domain_error("No grid 3D was found");
0284 }
0285 }
0286 }
0287
0288 if (remainder > 0) {
0289
0290
0291 properties.scaleThickness(remainder / properties.thickness());
0292 Vector3 extraPosition = position + volumeStep * direction;
0293 if (currentBinning.second.dimensions() == 2) {
0294 auto grid = mState.grid2D.find(currentBinning.first);
0295 if (grid != mState.grid2D.end()) {
0296
0297 Acts::Grid2D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0298 mState.transform2D[currentBinning.first](extraPosition));
0299 grid->second.atLocalBins(index).accumulate(properties);
0300 } else {
0301 throw std::domain_error("No grid 2D was found");
0302 }
0303 } else if (currentBinning.second.dimensions() == 3) {
0304 auto grid = mState.grid3D.find(currentBinning.first);
0305 if (grid != mState.grid3D.end()) {
0306
0307 Acts::Grid3D::index_t index = grid->second.localBinsFromLowerLeftEdge(
0308 mState.transform3D[currentBinning.first](extraPosition));
0309 grid->second.atLocalBins(index).accumulate(properties);
0310 } else {
0311 throw std::domain_error("No grid 3D was found");
0312 }
0313 }
0314 }
0315 }
0316
0317 void Acts::VolumeMaterialMapper::finalizeMaps(State& mState) const {
0318
0319 for (auto& matBin : mState.materialBin) {
0320 ACTS_DEBUG("Create the material for volume " << matBin.first);
0321 if (matBin.second.dimensions() == 0) {
0322
0323 ACTS_DEBUG("Homogeneous material volume");
0324 Acts::Material mat = mState.homogeneousGrid[matBin.first].average();
0325 mState.volumeMaterial[matBin.first] =
0326 std::make_unique<HomogeneousVolumeMaterial>(mat);
0327 } else if (matBin.second.dimensions() == 2) {
0328
0329
0330 ACTS_DEBUG("Grid material volume");
0331 auto grid = mState.grid2D.find(matBin.first);
0332 if (grid != mState.grid2D.end()) {
0333 Acts::MaterialGrid2D matGrid = mapMaterialPoints(grid->second);
0334 MaterialMapper<Acts::MaterialGrid2D> matMap(
0335 mState.transform2D[matBin.first], matGrid);
0336 mState.volumeMaterial[matBin.first] = std::make_unique<
0337 InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid2D>>>(
0338 std::move(matMap), matBin.second);
0339 } else {
0340 throw std::domain_error("No grid 2D was found");
0341 }
0342 } else if (matBin.second.dimensions() == 3) {
0343
0344
0345 ACTS_DEBUG("Grid material volume");
0346 auto grid = mState.grid3D.find(matBin.first);
0347 if (grid != mState.grid3D.end()) {
0348 Acts::MaterialGrid3D matGrid = mapMaterialPoints(grid->second);
0349 MaterialMapper<Acts::MaterialGrid3D> matMap(
0350 mState.transform3D[matBin.first], matGrid);
0351 mState.volumeMaterial[matBin.first] = std::make_unique<
0352 InterpolatedMaterialMap<MaterialMapper<Acts::MaterialGrid3D>>>(
0353 std::move(matMap), matBin.second);
0354 } else {
0355 throw std::domain_error("No grid 3D was found");
0356 }
0357 } else {
0358 throw std::invalid_argument(
0359 "Incorrect bin dimension, only 0, 2 and 3 are accepted");
0360 }
0361 }
0362 }
0363
0364 void Acts::VolumeMaterialMapper::mapMaterialTrack(
0365 State& mState, RecordedMaterialTrack& mTrack) const {
0366 using VectorHelpers::makeVector4;
0367
0368
0369 NeutralCurvilinearTrackParameters start(
0370 makeVector4(mTrack.first.first, 0), mTrack.first.second,
0371 1 / mTrack.first.second.norm(), std::nullopt,
0372 NeutralParticleHypothesis::geantino());
0373
0374
0375 using BoundSurfaceCollector = SurfaceCollector<BoundSurfaceSelector>;
0376 using MaterialVolumeCollector = VolumeCollector<MaterialVolumeSelector>;
0377 using ActionList = ActionList<BoundSurfaceCollector, MaterialVolumeCollector>;
0378 using AbortList = AbortList<EndOfWorldReached>;
0379
0380 PropagatorOptions<ActionList, AbortList> options(mState.geoContext,
0381 mState.magFieldContext);
0382
0383
0384 const auto& result = m_propagator.propagate(start, options).value();
0385 auto mcResult = result.get<BoundSurfaceCollector::result_type>();
0386 auto mvcResult = result.get<MaterialVolumeCollector::result_type>();
0387
0388 auto mappingSurfaces = mcResult.collected;
0389 auto mappingVolumes = mvcResult.collected;
0390
0391
0392 auto& rMaterial = mTrack.second.materialInteractions;
0393 ACTS_VERBOSE("Retrieved " << rMaterial.size()
0394 << " recorded material steps to map.")
0395
0396
0397 ACTS_VERBOSE("Found " << mappingVolumes.size()
0398 << " mapping volumes for this track.");
0399 ACTS_VERBOSE("Mapping volumes are :")
0400 for (auto& mVolumes : mappingVolumes) {
0401 ACTS_VERBOSE(" - Volume : " << mVolumes.volume->geometryId()
0402 << " at position = (" << mVolumes.position.x()
0403 << ", " << mVolumes.position.y() << ", "
0404 << mVolumes.position.z() << ")");
0405
0406 mappingVolumes.push_back(mVolumes);
0407 }
0408
0409
0410 auto rmIter = rMaterial.begin();
0411 auto sfIter = mappingSurfaces.begin();
0412 auto volIter = mappingVolumes.begin();
0413
0414
0415 GeometryIdentifier lastID = GeometryIdentifier();
0416 GeometryIdentifier currentID = GeometryIdentifier();
0417 auto currentBinning = mState.materialBin.end();
0418
0419
0420 Acts::Vector3 lastPositionEnd = {0, 0, 0};
0421 Acts::Vector3 direction = {0, 0, 0};
0422
0423 if (volIter != mappingVolumes.end()) {
0424 lastPositionEnd = volIter->position;
0425 }
0426
0427
0428
0429 while (rmIter != rMaterial.end() && volIter != mappingVolumes.end()) {
0430 if (volIter != mappingVolumes.end() &&
0431 !volIter->volume->inside(rmIter->position)) {
0432
0433
0434
0435 double distVol = (volIter->position - mTrack.first.first).norm();
0436 double distMat = (rmIter->position - mTrack.first.first).norm();
0437 if (distMat - distVol > s_epsilon) {
0438
0439 ++volIter;
0440 continue;
0441 }
0442 }
0443 if (volIter != mappingVolumes.end() &&
0444 volIter->volume->inside(rmIter->position, s_epsilon)) {
0445 currentID = volIter->volume->geometryId();
0446 direction = rmIter->direction;
0447 if (!(currentID == lastID)) {
0448
0449 lastID = currentID;
0450 lastPositionEnd = volIter->position;
0451 currentBinning = mState.materialBin.find(currentID);
0452 }
0453
0454
0455 if (currentBinning != mState.materialBin.end() &&
0456 rmIter->materialSlab.thickness() > 0) {
0457
0458 float vacuumThickness = (rmIter->position - lastPositionEnd).norm();
0459 if (vacuumThickness > s_epsilon) {
0460 auto properties = Acts::MaterialSlab(vacuumThickness);
0461
0462 createExtraHits(mState, *currentBinning, properties, lastPositionEnd,
0463 direction);
0464 }
0465
0466
0467 direction =
0468 direction * (rmIter->materialSlab.thickness() / direction.norm());
0469 lastPositionEnd = rmIter->position + direction;
0470
0471 createExtraHits(mState, *currentBinning, rmIter->materialSlab,
0472 rmIter->position, direction);
0473 }
0474
0475
0476
0477 if ((rmIter + 1) == rMaterial.end() ||
0478 !volIter->volume->inside((rmIter + 1)->position, s_epsilon)) {
0479
0480 while (sfIter != mappingSurfaces.end()) {
0481 if (sfIter->surface->geometryId().volume() == lastID.volume() ||
0482 ((volIter + 1) != mappingVolumes.end() &&
0483 sfIter->surface->geometryId().volume() ==
0484 (volIter + 1)->volume->geometryId().volume())) {
0485 double distVol = (volIter->position - mTrack.first.first).norm();
0486 double distSur = (sfIter->position - mTrack.first.first).norm();
0487 if (distSur - distVol > s_epsilon) {
0488 float vacuumThickness =
0489 (sfIter->position - lastPositionEnd).norm();
0490
0491
0492 if (vacuumThickness > s_epsilon) {
0493 auto properties = Acts::MaterialSlab(vacuumThickness);
0494 createExtraHits(mState, *currentBinning, properties,
0495 lastPositionEnd, direction);
0496 lastPositionEnd = sfIter->position;
0497 }
0498 break;
0499 }
0500 }
0501 sfIter++;
0502 }
0503 }
0504 rmIter->volume = volIter->volume;
0505 rmIter->intersectionID = currentID;
0506 rmIter->intersection = rmIter->position;
0507 }
0508 ++rmIter;
0509 }
0510 }