File indexing completed on 2026-05-19 07:35:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/Json/MaterialMapJsonConverter.hpp"
0010
0011 #include "Acts/Definitions/Tolerance.hpp"
0012 #include "Acts/Geometry/ApproachDescriptor.hpp"
0013 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0014 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0015 #include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0018 #include "Acts/Geometry/GeometryIdentifier.hpp"
0019 #include "Acts/Geometry/Layer.hpp"
0020 #include "Acts/Geometry/TrackingGeometry.hpp"
0021 #include "Acts/Geometry/TrackingVolume.hpp"
0022 #include "Acts/Geometry/VolumeBounds.hpp"
0023 #include "Acts/Material/ISurfaceMaterial.hpp"
0024 #include "Acts/Material/IVolumeMaterial.hpp"
0025 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0026 #include "Acts/Material/ProtoVolumeMaterial.hpp"
0027 #include "Acts/Surfaces/AnnulusBounds.hpp"
0028 #include "Acts/Surfaces/CylinderBounds.hpp"
0029 #include "Acts/Surfaces/RadialBounds.hpp"
0030 #include "Acts/Surfaces/RectangleBounds.hpp"
0031 #include "Acts/Surfaces/Surface.hpp"
0032 #include "Acts/Surfaces/SurfaceArray.hpp"
0033 #include "Acts/Surfaces/SurfaceBounds.hpp"
0034 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0035 #include "Acts/Utilities/BinUtility.hpp"
0036 #include "Acts/Utilities/BinningType.hpp"
0037 #include "ActsPlugins/Json/ITrackingGeometryJsonDecorator.hpp"
0038 #include "ActsPlugins/Json/IVolumeMaterialJsonDecorator.hpp"
0039 #include "ActsPlugins/Json/MaterialJsonConverter.hpp"
0040 #include "ActsPlugins/Json/SurfaceJsonConverter.hpp"
0041 #include "ActsPlugins/Json/VolumeJsonConverter.hpp"
0042
0043 #include <algorithm>
0044 #include <cstddef>
0045 #include <map>
0046 #include <numbers>
0047
0048 namespace Acts {
0049
0050
0051 template <>
0052 inline void decorateJson<Acts::SurfaceAndMaterialWithContext>(
0053 const ITrackingGeometryJsonDecorator* decorator,
0054 const Acts::SurfaceAndMaterialWithContext& src, nlohmann::json& dest) {
0055 if (decorator != nullptr && std::get<0>(src) != nullptr) {
0056 decorator->decorate(*std::get<0>(src), dest);
0057 }
0058 }
0059 template <>
0060 inline void decorateJson<Acts::TrackingVolumeAndMaterial>(
0061 const ITrackingGeometryJsonDecorator* decorator,
0062 const Acts::TrackingVolumeAndMaterial& src, nlohmann::json& dest) {
0063 if (decorator != nullptr && src.first != nullptr) {
0064 decorator->decorate(*src.first, dest);
0065 }
0066 }
0067
0068 template <>
0069 inline void decorateJson<Acts::IVolumeMaterial>(
0070 const IVolumeMaterialJsonDecorator* decorator,
0071 const Acts::IVolumeMaterial* src, nlohmann::json& dest) {
0072 if (decorator != nullptr && src != nullptr) {
0073 decorator->decorate(*src, dest);
0074 }
0075 }
0076 template <>
0077 inline void decorateJson<Acts::ISurfaceMaterial>(
0078 const IVolumeMaterialJsonDecorator* decorator,
0079 const Acts::ISurfaceMaterial* src, nlohmann::json& dest) {
0080 if (decorator != nullptr && src != nullptr) {
0081 decorator->decorate(*src, dest);
0082 }
0083 }
0084 }
0085
0086 namespace {
0087
0088 Acts::SurfaceAndMaterialWithContext defaultSurfaceMaterial(
0089 const std::shared_ptr<const Acts::Surface>& surface,
0090 const Acts::GeometryContext& context) {
0091 if (surface->surfaceMaterialSharedPtr() != nullptr) {
0092 return {surface, surface->surfaceMaterialSharedPtr(), context};
0093 }
0094 Acts::BinUtility bUtility;
0095
0096 const Acts::SurfaceBounds& surfaceBounds = surface->bounds();
0097 const Acts::RadialBounds* radialBounds =
0098 dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
0099 const Acts::CylinderBounds* cylinderBounds =
0100 dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
0101 const Acts::AnnulusBounds* annulusBounds =
0102 dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds);
0103 const Acts::RectangleBounds* rectangleBounds =
0104 dynamic_cast<const Acts::RectangleBounds*>(&surfaceBounds);
0105 const Acts::TrapezoidBounds* trapezoidBounds =
0106 dynamic_cast<const Acts::TrapezoidBounds*>(&surfaceBounds);
0107
0108 if (radialBounds != nullptr) {
0109 bUtility += Acts::BinUtility(
0110 1,
0111 radialBounds->get(Acts::RadialBounds::eAveragePhi) -
0112 radialBounds->get(Acts::RadialBounds::eHalfPhiSector),
0113 radialBounds->get(Acts::RadialBounds::eAveragePhi) +
0114 radialBounds->get(Acts::RadialBounds::eHalfPhiSector),
0115 (radialBounds->get(Acts::RadialBounds::eHalfPhiSector) -
0116 std::numbers::pi) < Acts::s_epsilon
0117 ? Acts::closed
0118 : Acts::open,
0119 Acts::AxisDirection::AxisPhi);
0120 bUtility += Acts::BinUtility(1, radialBounds->rMin(), radialBounds->rMax(),
0121 Acts::open, Acts::AxisDirection::AxisR);
0122 }
0123 if (cylinderBounds != nullptr) {
0124 bUtility += Acts::BinUtility(
0125 1,
0126 cylinderBounds->get(Acts::CylinderBounds::eAveragePhi) -
0127 cylinderBounds->get(Acts::CylinderBounds::eHalfPhiSector),
0128 cylinderBounds->get(Acts::CylinderBounds::eAveragePhi) +
0129 cylinderBounds->get(Acts::CylinderBounds::eHalfPhiSector),
0130 (cylinderBounds->get(Acts::CylinderBounds::eHalfPhiSector) -
0131 std::numbers::pi) < Acts::s_epsilon
0132 ? Acts::closed
0133 : Acts::open,
0134 Acts::AxisDirection::AxisPhi);
0135 bUtility += Acts::BinUtility(
0136 1, -1 * cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ),
0137 cylinderBounds->get(Acts::CylinderBounds::eHalfLengthZ), Acts::open,
0138 Acts::AxisDirection::AxisZ);
0139 }
0140 if (annulusBounds != nullptr) {
0141 bUtility +=
0142 Acts::BinUtility(1, annulusBounds->get(Acts::AnnulusBounds::eMinPhiRel),
0143 annulusBounds->get(Acts::AnnulusBounds::eMaxPhiRel),
0144 Acts::open, Acts::AxisDirection::AxisPhi);
0145 bUtility += Acts::BinUtility(1, static_cast<float>(annulusBounds->rMin()),
0146 static_cast<float>(annulusBounds->rMax()),
0147 Acts::open, Acts::AxisDirection::AxisR);
0148 }
0149 if (rectangleBounds != nullptr) {
0150 bUtility +=
0151 Acts::BinUtility(1, rectangleBounds->get(Acts::RectangleBounds::eMinX),
0152 rectangleBounds->get(Acts::RectangleBounds::eMaxX),
0153 Acts::open, Acts::AxisDirection::AxisX);
0154 bUtility +=
0155 Acts::BinUtility(1, rectangleBounds->get(Acts::RectangleBounds::eMinY),
0156 rectangleBounds->get(Acts::RectangleBounds::eMaxY),
0157 Acts::open, Acts::AxisDirection::AxisY);
0158 }
0159 if (trapezoidBounds != nullptr) {
0160 double halfLengthX =
0161 std::max(trapezoidBounds->get(Acts::TrapezoidBounds::eHalfLengthXnegY),
0162 trapezoidBounds->get(Acts::TrapezoidBounds::eHalfLengthXposY));
0163 bUtility += Acts::BinUtility(1, -1 * halfLengthX, halfLengthX, Acts::open,
0164 Acts::AxisDirection::AxisX);
0165 bUtility += Acts::BinUtility(
0166 1, -1 * trapezoidBounds->get(Acts::TrapezoidBounds::eHalfLengthY),
0167 trapezoidBounds->get(Acts::TrapezoidBounds::eHalfLengthY), Acts::open,
0168 Acts::AxisDirection::AxisY);
0169 }
0170 return {surface, std::make_shared<Acts::ProtoSurfaceMaterial>(bUtility),
0171 context};
0172 }
0173
0174 Acts::TrackingVolumeAndMaterial defaultVolumeMaterial(
0175 const Acts::TrackingVolume* volume) {
0176 Acts::BinUtility bUtility;
0177 if (volume->volumeMaterialPtr() != nullptr) {
0178 return {volume, volume->volumeMaterialPtr()};
0179 }
0180
0181 auto cyBounds = dynamic_cast<const Acts::CylinderVolumeBounds*>(
0182 &(volume->volumeBounds()));
0183 auto cutcylBounds = dynamic_cast<const Acts::CutoutCylinderVolumeBounds*>(
0184 &(volume->volumeBounds()));
0185 auto cuBounds =
0186 dynamic_cast<const Acts::CuboidVolumeBounds*>(&(volume->volumeBounds()));
0187
0188 if (cyBounds != nullptr) {
0189 bUtility +=
0190 Acts::BinUtility(1, cyBounds->get(Acts::CylinderVolumeBounds::eMinR),
0191 cyBounds->get(Acts::CylinderVolumeBounds::eMaxR),
0192 Acts::open, Acts::AxisDirection::AxisR);
0193 bUtility += Acts::BinUtility(
0194 1, -cyBounds->get(Acts::CylinderVolumeBounds::eHalfPhiSector),
0195 cyBounds->get(Acts::CylinderVolumeBounds::eHalfPhiSector),
0196 (cyBounds->get(Acts::CylinderVolumeBounds::eHalfPhiSector) -
0197 std::numbers::pi) < Acts::s_epsilon
0198 ? Acts::closed
0199 : Acts::open,
0200 Acts::AxisDirection::AxisPhi);
0201 bUtility += Acts::BinUtility(
0202 1, -cyBounds->get(Acts::CylinderVolumeBounds::eHalfLengthZ),
0203 cyBounds->get(Acts::CylinderVolumeBounds::eHalfLengthZ), Acts::open,
0204 Acts::AxisDirection::AxisZ);
0205 }
0206 if (cutcylBounds != nullptr) {
0207 bUtility += Acts::BinUtility(
0208 1, cutcylBounds->get(Acts::CutoutCylinderVolumeBounds::eMinR),
0209 cutcylBounds->get(Acts::CutoutCylinderVolumeBounds::eMaxR), Acts::open,
0210 Acts::AxisDirection::AxisR);
0211 bUtility += Acts::BinUtility(1, -std::numbers::pi_v<float>,
0212 std::numbers::pi_v<float>, Acts::closed,
0213 Acts::AxisDirection::AxisPhi);
0214 bUtility += Acts::BinUtility(
0215 1, -cutcylBounds->get(Acts::CutoutCylinderVolumeBounds::eHalfLengthZ),
0216 cutcylBounds->get(Acts::CutoutCylinderVolumeBounds::eHalfLengthZ),
0217 Acts::open, Acts::AxisDirection::AxisZ);
0218 } else if (cuBounds != nullptr) {
0219 bUtility += Acts::BinUtility(
0220 1, -cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthX),
0221 cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthX), Acts::open,
0222 Acts::AxisDirection::AxisX);
0223 bUtility += Acts::BinUtility(
0224 1, -cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthY),
0225 cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthY), Acts::open,
0226 Acts::AxisDirection::AxisY);
0227 bUtility += Acts::BinUtility(
0228 1, -cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthZ),
0229 cuBounds->get(Acts::CuboidVolumeBounds::eHalfLengthZ), Acts::open,
0230 Acts::AxisDirection::AxisZ);
0231 }
0232 return {volume, std::make_shared<Acts::ProtoVolumeMaterial>(bUtility)};
0233 }
0234 }
0235
0236 Acts::MaterialMapJsonConverter::MaterialMapJsonConverter(
0237 const Acts::MaterialMapJsonConverter::Config& config,
0238 Acts::Logging::Level level)
0239 : m_cfg(config),
0240 m_logger{getDefaultLogger("MaterialMapJsonConverter", level)},
0241 m_volumeMaterialConverter(m_volumeName),
0242 m_volumeConverter(m_volumeName),
0243 m_surfaceMaterialConverter(m_surfaceName),
0244 m_surfaceConverter(m_surfaceName) {}
0245
0246
0247
0248 nlohmann::json Acts::MaterialMapJsonConverter::materialMapsToJson(
0249 const TrackingGeometryMaterial& maps,
0250 const IVolumeMaterialJsonDecorator* decorator) {
0251 VolumeMaterialMaps volumeMap = maps.second;
0252 std::vector<std::pair<GeometryIdentifier, const IVolumeMaterial*>>
0253 mapVolumeInit;
0254 for (const auto& [key, value] : volumeMap) {
0255 mapVolumeInit.push_back({key, value.get()});
0256 }
0257 GeometryHierarchyMap<const IVolumeMaterial*> hierarchyVolumeMap(
0258 mapVolumeInit);
0259 nlohmann::json materialVolume =
0260 m_volumeMaterialConverter.toJson(hierarchyVolumeMap, decorator);
0261 SurfaceMaterialMaps surfaceMap = maps.first;
0262 std::vector<std::pair<GeometryIdentifier, const ISurfaceMaterial*>>
0263 mapSurfaceInit;
0264 for (const auto& [key, value] : surfaceMap) {
0265 mapSurfaceInit.push_back({key, value.get()});
0266 }
0267 GeometryHierarchyMap<const ISurfaceMaterial*> hierarchySurfaceMap(
0268 mapSurfaceInit);
0269 nlohmann::json materialSurface =
0270 m_surfaceMaterialConverter.toJson(hierarchySurfaceMap, decorator);
0271 nlohmann::json materialMap;
0272 materialMap["Volumes"] = materialVolume;
0273 materialMap["Surfaces"] = materialSurface;
0274 return materialMap;
0275 }
0276
0277 Acts::TrackingGeometryMaterial
0278 Acts::MaterialMapJsonConverter::jsonToMaterialMaps(
0279 const nlohmann::json& materialmap) {
0280 nlohmann::json materialVolume = materialmap["Volumes"];
0281 GeometryHierarchyMap<const IVolumeMaterial*> hierarchyVolumeMap =
0282 m_volumeMaterialConverter.fromJson(materialVolume);
0283 VolumeMaterialMaps volumeMap;
0284 for (std::size_t i = 0; i < hierarchyVolumeMap.size(); i++) {
0285 std::shared_ptr<const IVolumeMaterial> volumePointer(
0286 hierarchyVolumeMap.valueAt(i));
0287 volumeMap.insert({hierarchyVolumeMap.idAt(i), std::move(volumePointer)});
0288 }
0289 nlohmann::json materialSurface = materialmap["Surfaces"];
0290 GeometryHierarchyMap<const ISurfaceMaterial*> hierarchySurfaceMap =
0291 m_surfaceMaterialConverter.fromJson(materialSurface);
0292 SurfaceMaterialMaps surfaceMap;
0293 for (std::size_t i = 0; i < hierarchySurfaceMap.size(); i++) {
0294 std::shared_ptr<const ISurfaceMaterial> surfacePointer(
0295 hierarchySurfaceMap.valueAt(i));
0296 surfaceMap.insert({hierarchySurfaceMap.idAt(i), std::move(surfacePointer)});
0297 }
0298
0299 Acts::TrackingGeometryMaterial maps = {surfaceMap, volumeMap};
0300
0301
0302 return maps;
0303 }
0304
0305 nlohmann::json Acts::MaterialMapJsonConverter::trackingGeometryToJson(
0306 const Acts::TrackingGeometry& tGeometry,
0307 const ITrackingGeometryJsonDecorator* decorator) {
0308 std::vector<std::pair<GeometryIdentifier, Acts::TrackingVolumeAndMaterial>>
0309 volumeHierarchy;
0310 std::vector<
0311 std::pair<GeometryIdentifier, Acts::SurfaceAndMaterialWithContext>>
0312 surfaceHierarchy;
0313 convertToHierarchy(volumeHierarchy, surfaceHierarchy,
0314 tGeometry.highestTrackingVolume());
0315 GeometryHierarchyMap<Acts::TrackingVolumeAndMaterial> hierarchyVolumeMap(
0316 volumeHierarchy);
0317 nlohmann::json jsonVolumes =
0318 m_volumeConverter.toJson(hierarchyVolumeMap, decorator);
0319 GeometryHierarchyMap<Acts::SurfaceAndMaterialWithContext> hierarchySurfaceMap(
0320 surfaceHierarchy);
0321 nlohmann::json jsonSurfaces =
0322 m_surfaceConverter.toJson(hierarchySurfaceMap, decorator);
0323 nlohmann::json hierarchyMap;
0324 hierarchyMap["Volumes"] = jsonVolumes;
0325 hierarchyMap["Surfaces"] = jsonSurfaces;
0326 return hierarchyMap;
0327 }
0328
0329 void Acts::MaterialMapJsonConverter::convertToHierarchy(
0330 std::vector<std::pair<GeometryIdentifier, Acts::TrackingVolumeAndMaterial>>&
0331 volumeHierarchy,
0332 std::vector<
0333 std::pair<GeometryIdentifier, Acts::SurfaceAndMaterialWithContext>>&
0334 surfaceHierarchy,
0335 const Acts::TrackingVolume* tVolume) {
0336 auto sameId = [tVolume](const auto& pair) {
0337 return (tVolume->geometryId() == pair.first);
0338 };
0339 if (std::ranges::any_of(volumeHierarchy, sameId)) {
0340
0341 return;
0342 }
0343 if ((tVolume->volumeMaterial() != nullptr ||
0344 m_cfg.processNonMaterial == true) &&
0345 m_cfg.processVolumes == true) {
0346 volumeHierarchy.push_back(
0347 {tVolume->geometryId(), defaultVolumeMaterial(tVolume)});
0348 }
0349
0350 if (tVolume->confinedVolumes() != nullptr) {
0351
0352 auto& volumes = tVolume->confinedVolumes()->arrayObjects();
0353
0354 for (auto& vol : volumes) {
0355
0356 convertToHierarchy(volumeHierarchy, surfaceHierarchy, vol.get());
0357 }
0358 }
0359
0360 if (m_cfg.processDenseVolumes && !tVolume->denseVolumes().empty()) {
0361
0362 for (auto& vol : tVolume->denseVolumes()) {
0363
0364 convertToHierarchy(volumeHierarchy, surfaceHierarchy, vol.get());
0365 }
0366 }
0367 if (tVolume->confinedLayers() != nullptr) {
0368
0369 auto& layers = tVolume->confinedLayers()->arrayObjects();
0370
0371 for (auto& lay : layers) {
0372 if (m_cfg.processRepresenting == true) {
0373 auto& layRep = lay->surfaceRepresentation();
0374 if ((layRep.surfaceMaterial() != nullptr ||
0375 m_cfg.processNonMaterial == true) &&
0376 layRep.geometryId() != GeometryIdentifier()) {
0377 surfaceHierarchy.push_back(
0378 {layRep.geometryId(),
0379 defaultSurfaceMaterial(layRep.getSharedPtr(), m_cfg.context)});
0380 }
0381 }
0382 if (lay->approachDescriptor() != nullptr &&
0383 m_cfg.processApproaches == true) {
0384 for (auto& asf : lay->approachDescriptor()->containedSurfaces()) {
0385 if (asf->surfaceMaterial() != nullptr ||
0386 m_cfg.processNonMaterial == true) {
0387 surfaceHierarchy.push_back(
0388 {asf->geometryId(),
0389 defaultSurfaceMaterial(asf->getSharedPtr(), m_cfg.context)});
0390 }
0391 }
0392 }
0393 if (lay->surfaceArray() != nullptr && m_cfg.processSensitives == true) {
0394 for (auto& ssf : lay->surfaceArray()->surfaces()) {
0395 if (ssf->surfaceMaterial() != nullptr ||
0396 m_cfg.processNonMaterial == true) {
0397 auto sp = ssf->getSharedPtr();
0398 auto sm = defaultSurfaceMaterial(sp, m_cfg.context);
0399 auto id = ssf->geometryId();
0400
0401 std::pair p{id, sm};
0402 surfaceHierarchy.push_back(p);
0403 }
0404 }
0405 }
0406 }
0407 }
0408
0409 for (auto& bsurf : tVolume->boundarySurfaces()) {
0410
0411 auto& bssfRep = bsurf->surfaceRepresentation();
0412 if (bssfRep.geometryId().volume() == tVolume->geometryId().volume() &&
0413 m_cfg.processBoundaries == true) {
0414 if (bssfRep.surfaceMaterial() != nullptr ||
0415 m_cfg.processNonMaterial == true) {
0416 surfaceHierarchy.push_back(
0417 {bssfRep.geometryId(),
0418 defaultSurfaceMaterial(bssfRep.getSharedPtr(), m_cfg.context)});
0419 }
0420 }
0421 }
0422 }