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