Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-23 08:21:10

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/SurfaceJsonConverter.hpp"
0010 
0011 #include "Acts/Surfaces/AnnulusBounds.hpp"
0012 #include "Acts/Surfaces/ConeBounds.hpp"
0013 #include "Acts/Surfaces/ConeSurface.hpp"
0014 #include "Acts/Surfaces/ConvexPolygonBounds.hpp"
0015 #include "Acts/Surfaces/CylinderBounds.hpp"
0016 #include "Acts/Surfaces/CylinderSurface.hpp"
0017 #include "Acts/Surfaces/DiamondBounds.hpp"
0018 #include "Acts/Surfaces/DiscSurface.hpp"
0019 #include "Acts/Surfaces/DiscTrapezoidBounds.hpp"
0020 #include "Acts/Surfaces/EllipseBounds.hpp"
0021 #include "Acts/Surfaces/InfiniteBounds.hpp"
0022 #include "Acts/Surfaces/LineBounds.hpp"
0023 #include "Acts/Surfaces/PerigeeSurface.hpp"
0024 #include "Acts/Surfaces/PlaneSurface.hpp"
0025 #include "Acts/Surfaces/PointBounds.hpp"
0026 #include "Acts/Surfaces/PointSurface.hpp"
0027 #include "Acts/Surfaces/RadialBounds.hpp"
0028 #include "Acts/Surfaces/RectangleBounds.hpp"
0029 #include "Acts/Surfaces/StrawSurface.hpp"
0030 #include "Acts/Surfaces/Surface.hpp"
0031 #include "Acts/Surfaces/SurfaceBounds.hpp"
0032 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0033 #include "ActsPlugins/Json/GeometryIdentifierJsonConverter.hpp"
0034 #include "ActsPlugins/Json/GeometryJsonKeys.hpp"
0035 #include "ActsPlugins/Json/SurfaceBoundsJsonConverter.hpp"
0036 #include "ActsPlugins/Json/SurfaceMaterialJsonConverter.hpp"
0037 
0038 #include <memory>
0039 
0040 namespace {
0041 
0042 // @brief Get string representation of the surface bounds kind
0043 //
0044 // @return string representation of the surface bounds kind
0045 template <typename bounds_t>
0046 std::string getSurfaceBoundsKind() {
0047   if (std::is_same_v<bounds_t, Acts::EllipseBounds>) {
0048     return "Ellipse";
0049   } else if (std::is_same_v<bounds_t, Acts::RectangleBounds>) {
0050     return "Rectangle";
0051   } else if (std::is_same_v<bounds_t, Acts::TrapezoidBounds>) {
0052     return "Trapezoid";
0053   } else if (std::is_same_v<bounds_t, Acts::DiamondBounds>) {
0054     return "Diamond";
0055   } else if (std::is_same_v<bounds_t, Acts::AnnulusBounds>) {
0056     return "Annulus";
0057   } else if (std::is_same_v<bounds_t, Acts::RadialBounds>) {
0058     return "Radial";
0059   } else if (std::is_same_v<bounds_t, Acts::DiscTrapezoidBounds>) {
0060     return "DiscTrapezoid";
0061   } else if (std::is_same_v<bounds_t, Acts::CylinderBounds>) {
0062     return "Cylinder";
0063   } else if (std::is_same_v<bounds_t, Acts::ConeBounds>) {
0064     return "Cone";
0065   } else if (std::is_same_v<bounds_t, Acts::LineBounds>) {
0066     return "Line";
0067   } else if (std::is_same_v<bounds_t, Acts::PointBounds>) {
0068     return "Point";
0069   } else if (std::is_same_v<bounds_t, Acts::ConvexPolygonBoundsBase>) {
0070     // Single kind for every Acts::ConvexPolygonBounds<N> specialization
0071     // (including PolygonDynamic), routed via the abstract base class so the
0072     // TypeDispatcher only needs one registration.
0073     return "ConvexPolygon";
0074   } else if (std::is_same_v<bounds_t, Acts::SurfaceBounds>) {
0075     return "DefaultBounds";
0076   } else if (std::is_same_v<bounds_t, Acts::InfiniteBounds>) {
0077     return "Infinite";
0078   } else {
0079     throw std::invalid_argument("Unknown surface bounds kind");
0080   }
0081 }
0082 
0083 // @brief Get string representation of the surface kind
0084 //
0085 // @return string representation of the surface kind
0086 template <typename surface_t>
0087 std::string getSurfaceKind() {
0088   if (std::is_same_v<surface_t, Acts::PlaneSurface>) {
0089     return "Plane";
0090   } else if (std::is_same_v<surface_t, Acts::DiscSurface>) {
0091     return "Disc";
0092   } else if (std::is_same_v<surface_t, Acts::CylinderSurface>) {
0093     return "Cylinder";
0094   } else if (std::is_same_v<surface_t, Acts::ConeSurface>) {
0095     return "Cone";
0096   } else if (std::is_same_v<surface_t, Acts::StrawSurface>) {
0097     return "Straw";
0098   } else if (std::is_same_v<surface_t, Acts::PerigeeSurface>) {
0099     return "Perigee";
0100   } else if (std::is_same_v<surface_t, Acts::PointSurface>) {
0101     return "Point";
0102   } else {
0103     throw std::invalid_argument("Unknown surface kind");
0104   }
0105 }
0106 
0107 // @brief Type-based surface bounds json encoding
0108 //
0109 // @tparam bounds_t surface bounds type
0110 //
0111 // @param bounds surface bounds to be converted
0112 //
0113 // @return json representation of the surface bounds
0114 template <typename bounds_t>
0115 nlohmann::json surfaceBoundsToJsonT(const bounds_t& bounds) {
0116   nlohmann::json jBounds = Acts::SurfaceBoundsJsonConverter::toJson(bounds);
0117   jBounds["kind"] = getSurfaceBoundsKind<bounds_t>();
0118   return jBounds;
0119 }
0120 
0121 // @brief Type-based surface json encoding
0122 //
0123 // @tparam surface_t surface type
0124 //
0125 // @param bounds surface to be converted
0126 // @param gctx geometry context
0127 // @param opt surface json conversion options
0128 //
0129 // @return json representation of the surface bounds
0130 template <typename surface_t>
0131 nlohmann::json surfaceToJsonT(const surface_t& surface,
0132                               const Acts::GeometryContext& gctx,
0133                               const Acts::SurfaceJsonConverter::Options& opt) {
0134   nlohmann::json jSurface;
0135   const auto sTransform = surface.localToGlobalTransform(gctx);
0136 
0137   jSurface["transform"] =
0138       Acts::Transform3JsonConverter::toJson(sTransform, opt.transformOptions);
0139   jSurface["type"] = surface.type();
0140   jSurface["geo_id"] = nlohmann::json(surface.geometryId());
0141   jSurface["sensitive"] = surface.isSensitive();
0142   if (surface.hasMaterial() && opt.writeMaterial) {
0143     jSurface[Acts::jsonKey().materialkey] =
0144         Acts::SurfaceMaterialJsonConverter::toJson(*surface.surfaceMaterial());
0145   }
0146   jSurface["kind"] = getSurfaceKind<surface_t>();
0147   return jSurface;
0148 }
0149 
0150 // @brief Type-based surface json decoding
0151 //
0152 // @tparam surface_t surface type
0153 //
0154 // @param j json encoding of the surface
0155 //
0156 // @return shared pointer to the decoded surface
0157 template <typename surface_t>
0158 std::shared_ptr<Acts::Surface> surfaceFromJsonT(const nlohmann::json& j) {
0159   nlohmann::json jTransform = j["transform"];
0160   Acts::Transform3 sTransform =
0161       Acts::Transform3JsonConverter::fromJson(jTransform);
0162   return Acts::Surface::makeShared<surface_t>(sTransform);
0163 }
0164 
0165 // @brief Type-based surface json decoding
0166 //
0167 // @tparam surface_t surface type
0168 // @tparam bounds_t surface bounds type
0169 //
0170 // @param j json encoding of the surface
0171 //
0172 // @return shared pointer to the decoded surface
0173 template <typename surface_t, typename bounds_t>
0174 std::shared_ptr<Acts::Surface> surfaceFromJsonT(const nlohmann::json& j) {
0175   nlohmann::json jTransform = j["transform"];
0176   Acts::Transform3 sTransform =
0177       Acts::Transform3JsonConverter::fromJson(jTransform);
0178   nlohmann::json jBounds = j["bounds"];
0179   auto sBounds = Acts::SurfaceBoundsJsonConverter::fromJson<bounds_t>(jBounds);
0180   return Acts::Surface::makeShared<surface_t>(sTransform, std::move(sBounds));
0181 }
0182 
0183 }  // namespace
0184 
0185 void Acts::to_json(nlohmann::json& j,
0186                    const Acts::SurfaceAndMaterialWithContext& surface) {
0187   toJson(j, std::get<0>(surface), std::get<2>(surface));
0188   const auto& material = std::get<1>(surface);
0189   if (material != nullptr) {
0190     j[jsonKey().materialkey] = SurfaceMaterialJsonConverter::toJson(*material);
0191   }
0192 }
0193 
0194 void Acts::to_json(nlohmann::json& j, const Acts::Surface& surface) {
0195   Acts::GeometryContext gctx =
0196       Acts::GeometryContext::dangerouslyDefaultConstruct();
0197   j = SurfaceJsonConverter::toJson(gctx, surface);
0198 }
0199 
0200 void Acts::to_json(nlohmann::json& j,
0201                    const std::shared_ptr<const Acts::Surface>& surface) {
0202   Acts::GeometryContext gctx =
0203       Acts::GeometryContext::dangerouslyDefaultConstruct();
0204   j = SurfaceJsonConverter::toJson(gctx, *surface);
0205 }
0206 
0207 void Acts::toJson(nlohmann::json& j,
0208                   const std::shared_ptr<const Acts::Surface>& surface,
0209                   const Acts::GeometryContext& gctx) {
0210   j = SurfaceJsonConverter::toJson(gctx, *surface);
0211 }
0212 
0213 Acts::SurfaceJsonConverter::Config
0214 Acts::SurfaceJsonConverter::Config::defaultConfig() {
0215   Config cfg;
0216 
0217   // Encoders
0218   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<PlaneSurface>);
0219   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<DiscSurface>);
0220   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<CylinderSurface>);
0221   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<ConeSurface>);
0222   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<StrawSurface>);
0223   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<PerigeeSurface>);
0224   cfg.surfaceEncoder.registerFunction(surfaceToJsonT<PointSurface>);
0225 
0226   cfg.surfaceBoundsEncoder.registerFunction(
0227       surfaceBoundsToJsonT<EllipseBounds>);
0228   cfg.surfaceBoundsEncoder.registerFunction(
0229       surfaceBoundsToJsonT<RectangleBounds>);
0230   cfg.surfaceBoundsEncoder.registerFunction(
0231       surfaceBoundsToJsonT<TrapezoidBounds>);
0232   cfg.surfaceBoundsEncoder.registerFunction(
0233       surfaceBoundsToJsonT<DiamondBounds>);
0234   cfg.surfaceBoundsEncoder.registerFunction(
0235       surfaceBoundsToJsonT<AnnulusBounds>);
0236   cfg.surfaceBoundsEncoder.registerFunction(surfaceBoundsToJsonT<RadialBounds>);
0237   cfg.surfaceBoundsEncoder.registerFunction(
0238       surfaceBoundsToJsonT<DiscTrapezoidBounds>);
0239   cfg.surfaceBoundsEncoder.registerFunction(
0240       surfaceBoundsToJsonT<CylinderBounds>);
0241   cfg.surfaceBoundsEncoder.registerFunction(surfaceBoundsToJsonT<ConeBounds>);
0242   cfg.surfaceBoundsEncoder.registerFunction(surfaceBoundsToJsonT<LineBounds>);
0243   cfg.surfaceBoundsEncoder.registerFunction(surfaceBoundsToJsonT<PointBounds>);
0244   cfg.surfaceBoundsEncoder.registerFunction(
0245       surfaceBoundsToJsonT<InfiniteBounds>);
0246   // ConvexPolygonBounds is templated on the vertex count N. Registering the
0247   // abstract ConvexPolygonBoundsBase lets a single encoder handle every
0248   // specialization (ConvexPolygonBounds<3>, <4>, <6>, ..., <PolygonDynamic>);
0249   // the runtime dynamic_cast inside TypeDispatcher resolves them all to the
0250   // same handler. This fixes the regression introduced by PR #5195 where TGeo
0251   // shapes that produce ConvexPolygonBounds<4> (e.g. TGeoTrap / TGeoArb8) made
0252   // the JsonSurfacesWriter throw "No function registered for type:
0253   // Acts::ConvexPolygonBounds<4>".
0254   cfg.surfaceBoundsEncoder.registerFunction(
0255       surfaceBoundsToJsonT<ConvexPolygonBoundsBase>);
0256 
0257   // Decoders
0258   cfg.surfaceDecoder.registerKind(
0259       getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<EllipseBounds>(),
0260       surfaceFromJsonT<PlaneSurface, EllipseBounds>);
0261   cfg.surfaceDecoder.registerKind(
0262       getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<RectangleBounds>(),
0263       surfaceFromJsonT<PlaneSurface, RectangleBounds>);
0264   cfg.surfaceDecoder.registerKind(
0265       getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<TrapezoidBounds>(),
0266       surfaceFromJsonT<PlaneSurface, TrapezoidBounds>);
0267   cfg.surfaceDecoder.registerKind(
0268       getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<DiamondBounds>(),
0269       surfaceFromJsonT<PlaneSurface, DiamondBounds>);
0270   cfg.surfaceDecoder.registerKind(
0271       getSurfaceKind<PlaneSurface>() + getSurfaceBoundsKind<InfiniteBounds>(),
0272       surfaceFromJsonT<PlaneSurface>);
0273   // Custom decoder for ConvexPolygonBounds: the number of vertices is encoded
0274   // only via the size of the "values" array (2 doubles per vertex), so we
0275   // build a dynamically-sized polygon. The kind string ("PlaneConvexPolygon")
0276   // is the same one the encoder writes, since getSurfaceBoundsKind returns
0277   // "ConvexPolygon" for any ConvexPolygonBounds<N>.
0278   cfg.surfaceDecoder.registerKind(
0279       getSurfaceKind<PlaneSurface>() +
0280           getSurfaceBoundsKind<ConvexPolygonBoundsBase>(),
0281       [](const nlohmann::json& j) -> std::shared_ptr<Surface> {
0282         Transform3 sTransform =
0283             Transform3JsonConverter::fromJson(j["transform"]);
0284         std::vector<double> bVector = j["bounds"]["values"];
0285         if (bVector.size() < 6 || bVector.size() % 2 != 0) {
0286           throw std::invalid_argument(
0287               "Invalid ConvexPolygonBounds 'values' array: need an even "
0288               "number of entries (>= 6) encoding at least 3 (x, y) vertices");
0289         }
0290         std::vector<Vector2> vertices;
0291         vertices.reserve(bVector.size() / 2);
0292         for (std::size_t i = 0; i < bVector.size(); i += 2) {
0293           vertices.emplace_back(bVector[i], bVector[i + 1]);
0294         }
0295         auto sBounds =
0296             std::make_shared<const ConvexPolygonBounds<PolygonDynamic>>(
0297                 vertices);
0298         return Surface::makeShared<PlaneSurface>(sTransform,
0299                                                  std::move(sBounds));
0300       });
0301 
0302   cfg.surfaceDecoder.registerKind(
0303       getSurfaceKind<DiscSurface>() + getSurfaceBoundsKind<AnnulusBounds>(),
0304       surfaceFromJsonT<DiscSurface, AnnulusBounds>);
0305   cfg.surfaceDecoder.registerKind(
0306       getSurfaceKind<DiscSurface>() + getSurfaceBoundsKind<RadialBounds>(),
0307       surfaceFromJsonT<DiscSurface, RadialBounds>);
0308   cfg.surfaceDecoder.registerKind(
0309       getSurfaceKind<DiscSurface>() +
0310           getSurfaceBoundsKind<DiscTrapezoidBounds>(),
0311       surfaceFromJsonT<DiscSurface, DiscTrapezoidBounds>);
0312 
0313   cfg.surfaceDecoder.registerKind(
0314       getSurfaceKind<CylinderSurface>() +
0315           getSurfaceBoundsKind<CylinderBounds>(),
0316       surfaceFromJsonT<CylinderSurface, CylinderBounds>);
0317   cfg.surfaceDecoder.registerKind(
0318       getSurfaceKind<ConeSurface>() + getSurfaceBoundsKind<ConeBounds>(),
0319       surfaceFromJsonT<ConeSurface, ConeBounds>);
0320   cfg.surfaceDecoder.registerKind(
0321       getSurfaceKind<StrawSurface>() + getSurfaceBoundsKind<LineBounds>(),
0322       surfaceFromJsonT<StrawSurface, LineBounds>);
0323 
0324   cfg.surfaceDecoder.registerKind(
0325       getSurfaceKind<PerigeeSurface>() + getSurfaceBoundsKind<InfiniteBounds>(),
0326       surfaceFromJsonT<PerigeeSurface>);
0327 
0328   cfg.surfaceDecoder.registerKind(
0329       getSurfaceKind<PointSurface>() + getSurfaceBoundsKind<PointBounds>(),
0330       surfaceFromJsonT<PointSurface, PointBounds>);
0331   cfg.surfaceDecoder.registerKind(
0332       getSurfaceKind<PointSurface>() + getSurfaceBoundsKind<InfiniteBounds>(),
0333       surfaceFromJsonT<PointSurface>);
0334   return cfg;
0335 }
0336 
0337 Acts::SurfaceJsonConverter::Config Acts::SurfaceJsonConverter::m_cfg =
0338     Acts::SurfaceJsonConverter::Config::defaultConfig();
0339 
0340 std::shared_ptr<Acts::Surface> Acts::SurfaceJsonConverter::fromJson(
0341     const nlohmann::json& j) {
0342   std::shared_ptr<Acts::Surface> mutableSf = nullptr;
0343   mutableSf = m_cfg.surfaceDecoder(j);
0344 
0345   if (j.find("geo_id") != j.end() && !j["geo_id"].empty()) {
0346     GeometryIdentifier geoID = j["geo_id"].get<GeometryIdentifier>();
0347     mutableSf->assignGeometryId(geoID);
0348   } else {
0349     mutableSf->assignGeometryId(GeometryIdentifier(0));
0350   }
0351   mutableSf->assignIsSensitive(j["sensitive"].get<bool>());
0352 
0353   if (j.find(jsonKey().materialkey) != j.end() &&
0354       !j[jsonKey().materialkey].empty()) {
0355     mutableSf->assignSurfaceMaterial(
0356         SurfaceMaterialJsonConverter::fromJson(j[jsonKey().materialkey]));
0357   }
0358   return mutableSf;
0359 }
0360 
0361 nlohmann::json Acts::SurfaceJsonConverter::toJson(const GeometryContext& gctx,
0362                                                   const Surface& surface,
0363                                                   const Options& options) {
0364   nlohmann::json jSurface = m_cfg.surfaceEncoder(surface, gctx, options);
0365   nlohmann::json jBounds = m_cfg.surfaceBoundsEncoder(surface.bounds());
0366   jSurface["bounds"] = jBounds;
0367   jSurface["kind"] =
0368       jSurface["kind"].get<std::string>() + jBounds["kind"].get<std::string>();
0369   return jSurface;
0370 }