File indexing completed on 2025-07-06 07:52:55
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Plugins/Detray/DetrayMaterialConverter.hpp"
0010
0011 #include "Acts/Detector/Detector.hpp"
0012 #include "Acts/Material/BinnedSurfaceMaterial.hpp"
0013 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0014 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0015 #include "Acts/Plugins/Detray/DetrayConversionUtils.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/Utilities/BinUtility.hpp"
0018 #include "Acts/Utilities/BinningType.hpp"
0019 #include "Acts/Utilities/Helpers.hpp"
0020
0021 #include <numbers>
0022 #include <stdexcept>
0023
0024 namespace {
0025
0026 struct MaterialSurfaceSelector {
0027 std::vector<const Acts::Surface*> surfaces = {};
0028
0029
0030 void operator()(const Acts::Surface* surface) {
0031 if (surface->surfaceMaterial() != nullptr &&
0032 !rangeContainsValue(surfaces, surface)) {
0033 surfaces.push_back(surface);
0034 }
0035 }
0036 };
0037
0038 }
0039
0040 detray::io::material_slab_payload
0041 Acts::DetrayMaterialConverter::convertMaterialSlab(
0042 const MaterialSlab& materialSlab) {
0043 detray::io::material_slab_payload slab;
0044
0045 const auto& material = materialSlab.material();
0046 slab.thickness = materialSlab.thickness();
0047 slab.mat = detray::io::material_payload{
0048 {material.X0(), material.L0(), material.Ar(), material.Z(),
0049 material.massDensity(), material.molarDensity(), 0.}};
0050 slab.type = detray::io::material_id::slab;
0051 return slab;
0052 }
0053
0054 detray::io::detector_homogeneous_material_payload
0055 Acts::DetrayMaterialConverter::convertHomogeneousSurfaceMaterial(
0056 const DetrayConversionUtils::Cache& cCache,
0057 const Experimental::Detector& detector, const Logger& logger) {
0058 detray::io::detector_homogeneous_material_payload materialPayload;
0059
0060 for (const auto volume : detector.volumes()) {
0061 auto volumeIndex = cCache.volumeLinks.find(volume->geometryId());
0062 if (volumeIndex != cCache.volumeLinks.end()) {
0063
0064 detray::io::material_volume_payload volumePayload;
0065 detray::io::single_link_payload volumeLink;
0066 volumeLink.link = volumeIndex->second;
0067 volumePayload.volume_link = volumeLink;
0068
0069 MaterialSurfaceSelector selector;
0070 volume->visitSurfaces(selector);
0071 ACTS_DEBUG("DetrayMaterialConverter: found "
0072 << selector.surfaces.size()
0073 << " surfaces/portals with material in volume "
0074 << volume->name());
0075 for (const auto surface : selector.surfaces) {
0076 const auto* surfaceMaterial = surface->surfaceMaterial();
0077 auto homogeneousMaterial =
0078 dynamic_cast<const HomogeneousSurfaceMaterial*>(surfaceMaterial);
0079 if (homogeneousMaterial != nullptr) {
0080
0081 auto materialSlab = homogeneousMaterial->materialSlab();
0082 detray::io::material_slab_payload slabPayload =
0083 convertMaterialSlab(materialSlab);
0084
0085 auto vIndex = cCache.volumeIndex(volume);
0086 auto localSurfaceLinks = cCache.localSurfaceLinks.find(vIndex);
0087 if (localSurfaceLinks != cCache.localSurfaceLinks.end()) {
0088
0089 auto surfaceIndices =
0090 localSurfaceLinks->second.equal_range(surface->geometryId());
0091
0092
0093 for (auto itr = surfaceIndices.first; itr != surfaceIndices.second;
0094 ++itr) {
0095
0096 slabPayload.surface.link = itr->second;
0097 volumePayload.mat_slabs.push_back(slabPayload);
0098 }
0099 } else {
0100 ACTS_WARNING(
0101 "DetrayMaterialConverter: no local surface links found");
0102 }
0103 }
0104 }
0105 materialPayload.volumes.push_back(volumePayload);
0106 } else {
0107 ACTS_WARNING("DetrayMaterialConverter: volume " << volume->name()
0108 << " not found in cache");
0109 }
0110 }
0111 return materialPayload;
0112 }
0113
0114 detray::io::grid_payload<detray::io::material_slab_payload,
0115 detray::io::material_id>
0116 Acts::DetrayMaterialConverter::convertGridSurfaceMaterial(
0117 const ISurfaceMaterial& material, const Logger& logger) {
0118 detray::io::grid_payload<detray::io::material_slab_payload,
0119 detray::io::material_id>
0120 materialGrid;
0121
0122
0123
0124 auto homogeneousMaterial =
0125 dynamic_cast<const HomogeneousSurfaceMaterial*>(&material);
0126 if (homogeneousMaterial != nullptr) {
0127 ACTS_DEBUG(
0128 "DetrayMaterialConverter: found homogeneous surface material, ignored "
0129 "as this should be handled by the homogeneous material conversion.");
0130 return materialGrid;
0131 }
0132
0133 auto binnedMaterial = dynamic_cast<const BinnedSurfaceMaterial*>(&material);
0134 if (binnedMaterial != nullptr) {
0135 ACTS_VERBOSE("DetrayMaterialConverter: found binned surface material");
0136
0137
0138 bool swapped = false;
0139
0140
0141
0142 BinUtility bUtility = binnedMaterial->binUtility();
0143
0144 if (bUtility.dimensions() == 1u) {
0145 if (bUtility.binningData()[0u].binvalue == AxisDirection::AxisX) {
0146
0147 bUtility += BinUtility(1u, std::numeric_limits<float>::lowest(),
0148 std::numeric_limits<float>::max(),
0149 BinningOption::closed, AxisDirection::AxisY);
0150 } else if (bUtility.binningData()[0u].binvalue == AxisDirection::AxisY) {
0151
0152 BinUtility nbUtility(1u, std::numeric_limits<float>::lowest(),
0153 std::numeric_limits<float>::max(),
0154 BinningOption::closed, AxisDirection::AxisX);
0155 nbUtility += bUtility;
0156 bUtility = std::move(nbUtility);
0157 swapped = true;
0158 } else if (bUtility.binningData()[0u].binvalue == AxisDirection::AxisR) {
0159
0160 bUtility += BinUtility(1u, -std::numbers::pi, std::numbers::pi, closed,
0161 AxisDirection::AxisPhi);
0162 } else if (bUtility.binningData()[0u].binvalue == AxisDirection::AxisZ) {
0163
0164 BinUtility nbUtility(1u, -std::numbers::pi, std::numbers::pi, closed,
0165 AxisDirection::AxisPhi);
0166 nbUtility += bUtility;
0167 bUtility = std::move(nbUtility);
0168 swapped = true;
0169 } else {
0170 std::invalid_argument("Unsupported binning for Detray");
0171 }
0172 } else if (bUtility.dimensions() == 2u &&
0173 bUtility.binningData()[0u].binvalue == AxisDirection::AxisZ &&
0174 bUtility.binningData()[1u].binvalue == AxisDirection::AxisPhi) {
0175 BinUtility nbUtility(bUtility.binningData()[1u]);
0176 nbUtility += BinUtility{bUtility.binningData()[0u]};
0177 bUtility = std::move(nbUtility);
0178 swapped = true;
0179 }
0180
0181 AxisDirection bVal0 = bUtility.binningData()[0u].binvalue;
0182 AxisDirection bVal1 = bUtility.binningData()[1u].binvalue;
0183
0184
0185 detray::io::material_id gridIndexType = detray::io::material_id::unknown;
0186 if (bVal0 == AxisDirection::AxisR && bVal1 == AxisDirection::AxisPhi) {
0187 gridIndexType = detray::io::material_id::ring2_map;
0188 } else if (bVal0 == AxisDirection::AxisPhi &&
0189 bVal1 == AxisDirection::AxisZ) {
0190 gridIndexType = detray::io::material_id::concentric_cylinder2_map;
0191 } else if (bVal0 == AxisDirection::AxisX && bVal1 == AxisDirection::AxisY) {
0192 gridIndexType = detray::io::material_id::rectangle2_map;
0193 } else {
0194 std::runtime_error(
0195 "DetrayMaterialConverter: Unsupported binning for Detray");
0196 }
0197
0198 detray::io::typed_link_payload<detray::io::material_id> linkPayload{
0199 gridIndexType, 0u};
0200 materialGrid.grid_link = linkPayload;
0201
0202
0203 for (const auto& bData : bUtility.binningData()) {
0204 auto axisPayload = DetrayConversionUtils::convertBinningData(bData);
0205 materialGrid.axes.push_back(axisPayload);
0206 }
0207
0208
0209 auto materialMatrix = binnedMaterial->fullMaterial();
0210 for (std::size_t ib1 = 0; ib1 < materialMatrix.size(); ++ib1) {
0211 for (std::size_t ib0 = 0; ib0 < materialMatrix[0u].size(); ++ib0) {
0212
0213 std::size_t lb0 = swapped ? ib1 : ib0;
0214 std::size_t lb1 = swapped ? ib0 : ib1;
0215 detray::io::material_slab_payload slab =
0216 convertMaterialSlab(materialMatrix[ib1][ib0]);
0217 detray::io::grid_bin_payload<detray::io::material_slab_payload> slabBin{
0218 {static_cast<unsigned int>(lb0), static_cast<unsigned int>(lb1)},
0219 {slab}};
0220
0221 materialGrid.bins.push_back(slabBin);
0222 }
0223 }
0224 return materialGrid;
0225 }
0226
0227 if (dynamic_cast<const Acts::ProtoSurfaceMaterial*>(&material) != nullptr ||
0228 dynamic_cast<const Acts::ProtoGridSurfaceMaterial*>(&material) !=
0229 nullptr) {
0230 ACTS_WARNING(
0231 "DetrayMaterialConverter: ProtoSurfaceMaterial and "
0232 "ProtoGridSurfaceMaterial are not being translated, consider to switch "
0233 "material conversion off.");
0234 return materialGrid;
0235 }
0236
0237 throw std::invalid_argument(
0238 "DetrayMaterialConverter: unknown surface material type detected.");
0239 }
0240
0241 detray::io::detector_grids_payload<detray::io::material_slab_payload,
0242 detray::io::material_id>
0243 Acts::DetrayMaterialConverter::convertGridSurfaceMaterial(
0244 const DetrayConversionUtils::Cache& cCache,
0245 const Experimental::Detector& detector, const Logger& logger) {
0246
0247 detray::io::detector_grids_payload<detray::io::material_slab_payload,
0248 detray::io::material_id>
0249 materialGrids;
0250
0251 using DetrayMaterialGrid =
0252 detray::io::grid_payload<detray::io::material_slab_payload,
0253 detray::io::material_id>;
0254
0255
0256 for (const auto& volume : detector.volumes()) {
0257
0258 MaterialSurfaceSelector selector;
0259 volume->visitSurfaces(selector);
0260 ACTS_VERBOSE("DetrayMaterialConverter: found "
0261 << selector.surfaces.size()
0262 << " surfaces/portals with material in volume "
0263 << volume->name());
0264
0265 auto volumeIndex = cCache.volumeLinks.find(volume->geometryId());
0266 if (volumeIndex != cCache.volumeLinks.end()) {
0267 std::vector<DetrayMaterialGrid> volumeMaterialGrids = {};
0268
0269 for (const auto& surface : selector.surfaces) {
0270
0271 auto vIndex = cCache.volumeIndex(volume);
0272 auto localSurfaceLinks = cCache.localSurfaceLinks.find(vIndex);
0273 if (localSurfaceLinks != cCache.localSurfaceLinks.end()) {
0274
0275 auto surfaceIndices =
0276 localSurfaceLinks->second.equal_range(surface->geometryId());
0277
0278 ACTS_VERBOSE(
0279 "DetrayMaterialConverter: assigning to "
0280 << std::distance(surfaceIndices.first, surfaceIndices.second)
0281 << " surfaces with material in volume " << volume->name());
0282 DetrayMaterialGrid materialGrid =
0283 convertGridSurfaceMaterial(*surface->surfaceMaterial(), logger);
0284
0285 if (materialGrid.axes.empty() || materialGrid.bins.empty()) {
0286 continue;
0287 }
0288
0289
0290
0291 for (auto itr = surfaceIndices.first; itr != surfaceIndices.second;
0292 ++itr) {
0293
0294 materialGrid.owner_link =
0295 detray::io::single_link_payload{itr->second};
0296
0297 volumeMaterialGrids.push_back(materialGrid);
0298 }
0299 }
0300 }
0301
0302 materialGrids.grids.insert({volumeIndex->second, volumeMaterialGrids});
0303 } else {
0304 ACTS_WARNING(
0305 "DetrayMaterialConverter: volume not found in cache, should not "
0306 "happen.");
0307 }
0308 }
0309
0310 return materialGrids;
0311 }