Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:21:26

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 #pragma once
0010 
0011 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0012 #include "Acts/Plugins/Json/ActsJson.hpp"
0013 
0014 #include <stdexcept>
0015 #include <string>
0016 #include <type_traits>
0017 
0018 namespace Acts {
0019 
0020 /// Convert a geometry hierarchy map to/from Json.
0021 ///
0022 /// @tparam value_t value type stored in the geometry hierarchy map
0023 ///
0024 /// The value type is expected to be directly convertible to/from a Json object.
0025 /// It has to be either a fundamental type or appropriate `to_json(json&, const
0026 /// value_t&)` and `from_json(const json&, value_t&)` functions must be
0027 /// available. See the relevant [nlohmann::json documentation][1] for further
0028 /// information.
0029 ///
0030 /// A user-defined identifier is stored in the encoded Json object that is used
0031 /// to identify which value type is stored in the file. The identifier is
0032 /// checked for consistency when decoding the Json object.
0033 ///
0034 /// [1]: https://nlohmann.github.io/json/features/arbitrary_types/
0035 template <typename value_t,
0036           class decorator_t = void /* e.g. ITrackingGeometryJsonDecorator */>
0037 class GeometryHierarchyMapJsonConverter {
0038  public:
0039   using Value = value_t;
0040   using Container = GeometryHierarchyMap<value_t>;
0041 
0042   /// Construct the converter.
0043   ///
0044   /// @param valueIdentifier user-defined identifier for the stored value
0045   explicit GeometryHierarchyMapJsonConverter(std::string valueIdentifier)
0046       : m_valueIdentifier(std::move(valueIdentifier)) {
0047     if (m_valueIdentifier.empty()) {
0048       throw std::invalid_argument("Value identifier must be non-empty");
0049     }
0050   }
0051 
0052   /// Encode the geometry hierarchy map into a Json object.
0053   ///
0054   /// @param container Geometry hierarchy map that should be encoded
0055   /// @param decorator nullptr or a decorator to add extra values to the json
0056   /// output
0057   /// @return Encoded Json object
0058   nlohmann::json toJson(const Container& container,
0059                         const decorator_t* decorator) const;
0060 
0061   /// Decode a Json object into a geometry hierarchy map.
0062   ///
0063   /// @param encoded Json object that should be decoded
0064   /// @return Decoded geometry hierarchy map
0065   /// @throw std::invalid_argument in case of format errors
0066   Container fromJson(const nlohmann::json& encoded) const;
0067 
0068   /// Encode the geometry identifier
0069   /// @param id is the geometry identifier that will be encoded
0070   static nlohmann::json encodeIdentifier(const GeometryIdentifier& id) {
0071     nlohmann::json encoded;
0072     // only store non-zero identifiers
0073     if (id.volume() != 0u) {
0074       encoded["volume"] = id.volume();
0075     }
0076     if (id.boundary() != 0u) {
0077       encoded["boundary"] = id.boundary();
0078     }
0079     if (id.layer() != 0u) {
0080       encoded["layer"] = id.layer();
0081     }
0082     if (id.approach() != 0u) {
0083       encoded["approach"] = id.approach();
0084     }
0085     if (id.sensitive() != 0u) {
0086       encoded["sensitive"] = id.sensitive();
0087     }
0088     if (id.extra() != 0u) {
0089       encoded["extra"] = id.extra();
0090     }
0091     return encoded;
0092   }
0093 
0094   /// @brief  Decode a geometry identifier from a json object
0095   /// @param encoded is the json object that carries the encoded identifier
0096   /// @return a valid geometry Identifier
0097   static GeometryIdentifier decodeIdentifier(const nlohmann::json& encoded) {
0098     return GeometryIdentifier()
0099         .withVolume(encoded.value("volume", GeometryIdentifier::Value{0u}))
0100         .withBoundary(encoded.value("boundary", GeometryIdentifier::Value{0u}))
0101         .withLayer(encoded.value("layer", GeometryIdentifier::Value{0u}))
0102         .withApproach(encoded.value("approach", GeometryIdentifier::Value{0u}))
0103         .withSensitive(
0104             encoded.value("sensitive", GeometryIdentifier::Value{0u}))
0105         .withExtra(encoded.value("extra", GeometryIdentifier::Value{0u}));
0106   }
0107 
0108  private:
0109   static constexpr const char* kHeaderKey = "acts-geometry-hierarchy-map";
0110   static constexpr const char* kEntriesKey = "entries";
0111   /// The version of the encoded Json container format. This must be increased
0112   /// manually every time the container format changes.
0113   static constexpr int kFormatVersion = 0;
0114 
0115   std::string m_valueIdentifier;
0116 };
0117 
0118 // implementations
0119 
0120 // auxiliary struct to indicate a missing specialization of a template which
0121 // requires specialisation
0122 template <typename T, class decorator_t>
0123 struct missing_specialization : std::false_type {};
0124 
0125 // methods to adapt type decorations for the given decorator
0126 template <class T, class decorator_t>
0127 void decorateJson([[maybe_unused]] const decorator_t* decorator,
0128                   [[maybe_unused]] const T& src,
0129                   [[maybe_unused]] nlohmann::json& dest) {
0130   // this needs to be specialised
0131   static_assert(
0132       missing_specialization<T, decorator_t>::value,
0133       "Explicit specialization needed for each decorator_t and src T");
0134 }
0135 template <class T, class decorator_t>
0136 void decorateJson([[maybe_unused]] const decorator_t* decorator,
0137                   [[maybe_unused]] const T* src,
0138                   [[maybe_unused]] nlohmann::json& dest) {
0139   // this needs to be specialised
0140   static_assert(
0141       missing_specialization<T, decorator_t>::value,
0142       "Explicit specialization needed for each decorator_t and src T");
0143 }
0144 
0145 template <typename value_t, class decorator_t>
0146 nlohmann::json GeometryHierarchyMapJsonConverter<value_t, decorator_t>::toJson(
0147     const Container& container,
0148     [[maybe_unused]] const decorator_t* decorator) const {
0149   // encode header
0150   nlohmann::json encoded = nlohmann::json::object();
0151   encoded[kHeaderKey] = nlohmann::json::object();
0152   encoded[kHeaderKey]["format-version"] = kFormatVersion;
0153   encoded[kHeaderKey]["value-identifier"] = m_valueIdentifier;
0154   // encode entries
0155   nlohmann::json entries = nlohmann::json::array();
0156   for (std::size_t i = 0; i < container.size(); ++i) {
0157     auto entry = encodeIdentifier(container.idAt(i));
0158     auto value_json = nlohmann::json(container.valueAt(i));
0159     if constexpr (!std::is_same_v<decorator_t, void>) {
0160       decorateJson(decorator, container.valueAt(i), value_json);
0161     }
0162     entry["value"] = std::move(value_json);
0163     entries.push_back(std::move(entry));
0164   }
0165   encoded[kEntriesKey] = std::move(entries);
0166   return encoded;
0167 }
0168 
0169 template <typename value_t, class decorator_t>
0170 auto GeometryHierarchyMapJsonConverter<value_t, decorator_t>::fromJson(
0171     const nlohmann::json& encoded) const -> Container {
0172   // verify json format header
0173   auto header = encoded.find(kHeaderKey);
0174   if (header == encoded.end()) {
0175     throw std::invalid_argument(
0176         "Missing header entry in json geometry hierarchy map");
0177   }
0178   if (header->at("format-version").get<int>() != kFormatVersion) {
0179     throw std::invalid_argument(
0180         "Invalid format version in json geometry hierarchy map");
0181   }
0182   if (header->at("value-identifier").get<std::string>() != m_valueIdentifier) {
0183     throw std::invalid_argument(
0184         "Inconsistent value identifier in Json geometry hierarchy map");
0185   }
0186   // decode json entries
0187   if (!encoded.contains(kEntriesKey)) {
0188     throw std::invalid_argument(
0189         "Missing entries in json geometry hierarchy map");
0190   }
0191   std::vector<std::pair<GeometryIdentifier, Value>> elements;
0192   for (const auto& entry : encoded.at(kEntriesKey)) {
0193     auto id = decodeIdentifier(entry);
0194     auto value = entry.at("value").get<Value>();
0195     elements.emplace_back(id, std::move(value));
0196   }
0197   return elements;
0198 }
0199 
0200 }  // namespace Acts