Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:03:36

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 "Acts/Plugins/Json/DetectorJsonConverter.hpp"
0010 
0011 #include "Acts/Detector/Detector.hpp"
0012 #include "Acts/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/Portal.hpp"
0014 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0015 #include "Acts/Plugins/Json/DetectorVolumeFinderJsonConverter.hpp"
0016 #include "Acts/Plugins/Json/DetectorVolumeJsonConverter.hpp"
0017 #include "Acts/Plugins/Json/DetrayJsonHelper.hpp"
0018 #include "Acts/Plugins/Json/IndexedSurfacesJsonConverter.hpp"
0019 #include "Acts/Plugins/Json/MaterialJsonConverter.hpp"
0020 #include "Acts/Plugins/Json/PortalJsonConverter.hpp"
0021 #include "Acts/Plugins/Json/VolumeBoundsJsonConverter.hpp"
0022 #include "Acts/Utilities/Enumerate.hpp"
0023 #include "Acts/Utilities/Helpers.hpp"
0024 
0025 #include <algorithm>
0026 #include <chrono>
0027 #include <format>
0028 #include <map>
0029 #include <memory>
0030 #include <set>
0031 #include <string>
0032 
0033 nlohmann::json Acts::DetectorJsonConverter::toJson(
0034     const GeometryContext& gctx, const Experimental::Detector& detector,
0035     const Options& options) {
0036   // Get the time stamp
0037   auto now = std::chrono::system_clock::now();
0038   std::string dateString = std::format("{:%Y-%m-%d %H:%M:%S}", now);
0039 
0040   nlohmann::json jDetector;
0041 
0042   std::size_t nSurfaces = 0;
0043   std::vector<const Experimental::Portal*> portals;
0044 
0045   for (const auto* volume : detector.volumes()) {
0046     nSurfaces += volume->surfaces().size();
0047     for (const auto& portal : volume->portals()) {
0048       if (!rangeContainsValue(portals, portal)) {
0049         portals.push_back(portal);
0050       }
0051     }
0052   }
0053 
0054   // Write the actual data objects
0055   nlohmann::json jData;
0056   jData["name"] = detector.name();
0057 
0058   // The portals are written first
0059   auto volumes = detector.volumes();
0060   nlohmann::json jPortals;
0061 
0062   for (const auto& portal : portals) {
0063     auto jPortal = PortalJsonConverter::toJson(
0064         gctx, *portal, volumes, options.volumeOptions.portalOptions);
0065     jPortals.push_back(jPortal);
0066   }
0067   jData["portals"] = jPortals;
0068 
0069   // The volumes are written next, with portals already defined, the volumes
0070   // will only index those
0071   nlohmann::json jVolumes;
0072   for (const auto& volume : volumes) {
0073     auto jVolume = DetectorVolumeJsonConverter::toJson(
0074         gctx, *volume, volumes, portals, options.volumeOptions);
0075     jVolumes.push_back(jVolume);
0076   }
0077   jData["volumes"] = jVolumes;
0078   jData["volume_finder"] = DetectorVolumeFinderJsonConverter::toJson(
0079       detector.detectorVolumeFinder());
0080 
0081   // Write the header
0082   nlohmann::json jHeader;
0083   jHeader["detector"] = detector.name();
0084   jHeader["type"] = "acts";
0085   jHeader["date"] = dateString;
0086   jHeader["surface_count"] = nSurfaces;
0087   jHeader["portal_count"] = portals.size();
0088   jHeader["volume_count"] = detector.volumes().size();
0089   jDetector["header"] = jHeader;
0090   jDetector["data"] = jData;
0091   return jDetector;
0092 }
0093 
0094 nlohmann::json Acts::DetectorJsonConverter::toJsonDetray(
0095     const GeometryContext& gctx, const Experimental::Detector& detector,
0096     const Options& options) {
0097   // Get the time stamp
0098   auto now = std::chrono::system_clock::now();
0099   std::string dateString = std::format("{:%Y-%m-%d %H:%M:%S}", now);
0100 
0101   nlohmann::json jFile;
0102 
0103   nlohmann::json jCommonHeader;
0104   jCommonHeader["detector"] = detector.name();
0105   jCommonHeader["date"] = dateString;
0106   jCommonHeader["version"] = "detray - 0.44.0";
0107   jCommonHeader["tag"] = "geometry";
0108 
0109   // Three sub sections are created
0110   // (1) Geometry
0111   nlohmann::json jGeometry;
0112   nlohmann::json jGeometryData;
0113   nlohmann::json jGeometryHeader;
0114   nlohmann::json jGeometryVolumes;
0115   // (2) Surface grids
0116   nlohmann::json jSurfaceGrids;
0117   nlohmann::json jSurfaceGridsData;
0118   nlohmann::json jSurfaceGridsInfoCollection;
0119   nlohmann::json jSurfaceGridsHeader;
0120   // (3) Material
0121   nlohmann::json jMaterial;
0122   nlohmann::json jMaterialData;
0123   nlohmann::json jMaterialHeader;
0124   nlohmann::json jMaterialGrids;
0125 
0126   // Counters:
0127   std::size_t nSurfaces = 0;
0128   std::size_t nGrids = 0;
0129 
0130   // Main loop over volumes
0131   for (auto [iv, volume] : enumerate(detector.volumes())) {
0132     // Write the volume information
0133     nlohmann::json jVolume;
0134     jVolume["name"] = volume->name();
0135 
0136     // Write the transform and bounds information
0137     jVolume["transform"] = Transform3JsonConverter::toJson(
0138         volume->transform(gctx), options.volumeOptions.transformOptions);
0139     jVolume["bounds"] =
0140         VolumeBoundsJsonConverter::toJson(volume->volumeBounds());
0141     auto volumeBoundsType = volume->volumeBounds().type();
0142     if (volumeBoundsType == VolumeBounds::BoundsType::eCylinder) {
0143       jVolume["type"] = 0u;
0144     } else if (volumeBoundsType == VolumeBounds::BoundsType::eCuboid) {
0145       jVolume["type"] = 4u;
0146     } else {
0147       throw std::runtime_error("Unsupported volume bounds type");
0148     }
0149     // Link to itself
0150     jVolume["index"] = iv;
0151 
0152     // Acceleration link if there
0153     nlohmann::json jSurfacesDelegate = IndexedSurfacesJsonConverter::toJson(
0154         volume->internalNavigation(), true);
0155     if (!jSurfacesDelegate.is_null()) {
0156       // Colplete the grid json for detray usage
0157       jSurfacesDelegate["owner_link"] = iv;
0158       // jSurfacesDelegate["acc_link"] =
0159       nlohmann::json jSurfaceGridsCollection;
0160       jSurfaceGridsCollection.push_back(jSurfacesDelegate);
0161 
0162       nlohmann::json jSurfaceGridsInfo;
0163       jSurfaceGridsInfo["volume_link"] = iv;
0164       jSurfaceGridsInfo["grid_data"] = jSurfaceGridsCollection;
0165       jSurfaceGridsInfoCollection.push_back(jSurfaceGridsInfo);
0166     }
0167 
0168     // Grids per volume
0169     nlohmann::json jMaterialVolumeGrids;
0170     nlohmann::json jMaterialVolumeGridsData;
0171     jMaterialVolumeGrids["volume_link"] = iv;
0172     std::map<std::size_t, std::size_t> gridLinks;
0173 
0174     // Write the surfaces - patch bounds & augment with self links
0175     std::size_t sIndex = 0;
0176     nlohmann::json jSurfaces;
0177     for (const auto& s : volume->surfaces()) {
0178       auto jSurface = SurfaceJsonConverter::toJsonDetray(
0179           gctx, *s, options.volumeOptions.surfaceOptions);
0180       DetrayJsonHelper::addVolumeLink(jSurface["mask"], iv);
0181       jSurface["index_in_coll"] = sIndex;
0182       jSurfaces.push_back(jSurface);
0183 
0184       // Check for material
0185       if (s->surfaceMaterial() != nullptr) {
0186         nlohmann::json jSurfaceMaterial = MaterialJsonConverter::toJsonDetray(
0187             *s->surfaceMaterial(), *s, sIndex, gridLinks);
0188         if (!jSurfaceMaterial.empty()) {
0189           ++nGrids;
0190           jMaterialVolumeGridsData.push_back(jSurfaceMaterial);
0191         }
0192       }
0193       ++sIndex;
0194     }
0195 
0196     // Write the portals - we need oriented surfaces for this
0197     auto orientedSurfaces =
0198         volume->volumeBounds().orientedSurfaces(volume->transform(gctx));
0199     // Write the portals - they will end up in the surface container
0200     for (const auto& [ip, p] : enumerate(volume->portals())) {
0201       auto [jPortalSurfaces, portalSubSplits] = (toJsonDetray(
0202           gctx, *p, ip, *volume, orientedSurfaces, detector.volumes(),
0203           options.volumeOptions.portalOptions));
0204       std::size_t splitSurfaceIdx = 0;
0205       for (auto& jSurface : jPortalSurfaces) {
0206         jSurface["index_in_coll"] = sIndex;
0207         jSurfaces.push_back(jSurface);
0208         const Surface* pSurface =
0209             portalSubSplits.empty() ? (&p->surface())
0210                                     : portalSubSplits[splitSurfaceIdx++].get();
0211         // Check for material
0212         if (p->surface().surfaceMaterial() != nullptr) {
0213           nlohmann::json jSurfaceMaterial = MaterialJsonConverter::toJsonDetray(
0214               *p->surface().surfaceMaterial(), *pSurface, sIndex, gridLinks);
0215           if (!jSurfaceMaterial.empty()) {
0216             ++nGrids;
0217             jMaterialVolumeGridsData.push_back(jSurfaceMaterial);
0218           }
0219         }
0220         ++sIndex;
0221       }
0222     }
0223     // If material was found, keep it
0224     if (!jMaterialVolumeGridsData.empty()) {
0225       jMaterialVolumeGrids["grid_data"] = {jMaterialVolumeGridsData};
0226       jMaterialGrids.push_back(jMaterialVolumeGrids);
0227     }
0228 
0229     // Surfaces go into the volume
0230     jVolume["surfaces"] = jSurfaces;
0231     nSurfaces += jSurfaces.size();
0232     jGeometryVolumes.push_back(jVolume);
0233   }
0234 
0235   jGeometryData["volumes"] = jGeometryVolumes;
0236   jGeometryData["volume_grid"] = DetectorVolumeFinderJsonConverter::toJson(
0237       detector.detectorVolumeFinder(), true);
0238 
0239   // Collect it (1) - Geometry
0240   jGeometryHeader["type"] = "detray";
0241   jGeometryHeader["common"] = jCommonHeader;
0242   jGeometryHeader["surface_count"] = nSurfaces;
0243   jGeometryHeader["volume_count"] = detector.volumes().size();
0244   jGeometry["header"] = jGeometryHeader;
0245   jGeometry["data"] = jGeometryData;
0246   jFile["geometry"] = jGeometry;
0247 
0248   // Collect it (2) - Grid
0249   jCommonHeader["tag"] = "surface_grids";
0250   jSurfaceGridsHeader["common"] = jCommonHeader;
0251   jSurfaceGridsData["grids"] = jSurfaceGridsInfoCollection;
0252   jSurfaceGridsHeader["grid_count"] = jSurfaceGridsInfoCollection.size();
0253   jSurfaceGrids["header"] = jSurfaceGridsHeader;
0254   jSurfaceGrids["data"] = jSurfaceGridsData;
0255   jFile["surface_grids"] = jSurfaceGrids;
0256 
0257   // Collect it (3) - Material
0258   jCommonHeader["tag"] = "material_maps";
0259   jMaterialHeader["common"] = jCommonHeader;
0260   jMaterialData["grids"] = jMaterialGrids;
0261   jMaterialHeader["grid_count"] = nGrids;
0262   jMaterial["header"] = jMaterialHeader;
0263   jMaterial["data"] = jMaterialData;
0264   jFile["material"] = jMaterial;
0265 
0266   return jFile;
0267 }
0268 
0269 std::shared_ptr<Acts::Experimental::Detector>
0270 Acts::DetectorJsonConverter::fromJson(const GeometryContext& gctx,
0271                                       const nlohmann::json& jDetector) {
0272   // Read back all the data
0273   auto jData = jDetector["data"];
0274   auto jVolumes = jData["volumes"];
0275   auto jPortals = jData["portals"];
0276   const std::string name = jData["name"];
0277 
0278   std::vector<std::shared_ptr<Experimental::DetectorVolume>> volumes;
0279   std::vector<std::shared_ptr<Experimental::Portal>> portals;
0280 
0281   for (const auto& jVolume : jVolumes) {
0282     auto volume = DetectorVolumeJsonConverter::fromJson(gctx, jVolume);
0283     volumes.push_back(volume);
0284   }
0285 
0286   for (const auto& jPortal : jPortals) {
0287     auto portal = PortalJsonConverter::fromJson(gctx, jPortal, volumes);
0288     portals.push_back(portal);
0289   }
0290 
0291   // Patch all the portals of the volumes
0292   for (auto [iv, v] : enumerate(volumes)) {
0293     // Get the Volumes and update the portals with the loaded ones
0294     auto jVolume = jVolumes[iv];
0295     std::vector<std::size_t> portalLinks = jVolume["portal_links"];
0296     for (auto [ip, ipl] : enumerate(portalLinks)) {
0297       auto portal = portals[ipl];
0298       v->updatePortal(portal, ip);
0299     }
0300   }
0301   return Experimental::Detector::makeShared(name, volumes,
0302                                             Experimental::tryRootVolumes());
0303 }