Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-11 09:40:22

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