Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-19 07:35:19

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 // specialisations of decoration helper function
0050 // to pick correct objects from the container object
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 }  // namespace Acts
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   // Check which type of bounds is associated to the surface
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   // Check which type of bound is associated to the volume
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 }  // namespace
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 /// Convert method
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   // Return the filled maps
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     // this volume was already visited
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   // there are confined volumes
0350   if (tVolume->confinedVolumes() != nullptr) {
0351     // get through the volumes
0352     auto& volumes = tVolume->confinedVolumes()->arrayObjects();
0353     // loop over the volumes
0354     for (auto& vol : volumes) {
0355       // recursive call
0356       convertToHierarchy(volumeHierarchy, surfaceHierarchy, vol.get());
0357     }
0358   }
0359   // there are dense volumes
0360   if (m_cfg.processDenseVolumes && !tVolume->denseVolumes().empty()) {
0361     // loop over the volumes
0362     for (auto& vol : tVolume->denseVolumes()) {
0363       // recursive call
0364       convertToHierarchy(volumeHierarchy, surfaceHierarchy, vol.get());
0365     }
0366   }
0367   if (tVolume->confinedLayers() != nullptr) {
0368     // get the layers
0369     auto& layers = tVolume->confinedLayers()->arrayObjects();
0370     // loop over the layers
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   // Let's finally check the boundaries
0409   for (auto& bsurf : tVolume->boundarySurfaces()) {
0410     // the surface representation
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 }