Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:42

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2020-2023 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 http://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   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         .setVolume(encoded.value("volume", GeometryIdentifier::Value{0u}))
0100         .setBoundary(encoded.value("boundary", GeometryIdentifier::Value{0u}))
0101         .setLayer(encoded.value("layer", GeometryIdentifier::Value{0u}))
0102         .setApproach(encoded.value("approach", GeometryIdentifier::Value{0u}))
0103         .setSensitive(encoded.value("sensitive", GeometryIdentifier::Value{0u}))
0104         .setExtra(encoded.value("extra", GeometryIdentifier::Value{0u}));
0105   }
0106 
0107  private:
0108   static constexpr const char* kHeaderKey = "acts-geometry-hierarchy-map";
0109   static constexpr const char* kEntriesKey = "entries";
0110   /// The version of the encoded Json container format. This must be increased
0111   /// manually every time the container format changes.
0112   static constexpr int kFormatVersion = 0;
0113 
0114   std::string m_valueIdentifier;
0115 };
0116 
0117 // implementations
0118 
0119 // auxiliary struct to indicate a missing specialization of a template which
0120 // requires specialisation
0121 template <typename T, class decorator_t>
0122 struct missing_specialization : std::false_type {};
0123 
0124 // methods to adapt type decorations for the given decorator
0125 template <class T, class decorator_t>
0126 void decorateJson([[maybe_unused]] const decorator_t* decorator,
0127                   [[maybe_unused]] const T& src,
0128                   [[maybe_unused]] nlohmann::json& dest) {
0129   // this needs to be specialised
0130   static_assert(
0131       missing_specialization<T, decorator_t>::value,
0132       "Explicit specialization needed for each decorator_t and src T");
0133 }
0134 template <class T, class decorator_t>
0135 void decorateJson([[maybe_unused]] const decorator_t* decorator,
0136                   [[maybe_unused]] const T* src,
0137                   [[maybe_unused]] nlohmann::json& dest) {
0138   // this needs to be specialised
0139   static_assert(
0140       missing_specialization<T, decorator_t>::value,
0141       "Explicit specialization needed for each decorator_t and src T");
0142 }
0143 
0144 template <typename value_t, class decorator_t>
0145 nlohmann::json GeometryHierarchyMapJsonConverter<value_t, decorator_t>::toJson(
0146     const Container& container,
0147     [[maybe_unused]] const decorator_t* decorator) const {
0148   // encode header
0149   nlohmann::json encoded = nlohmann::json::object();
0150   encoded[kHeaderKey] = nlohmann::json::object();
0151   encoded[kHeaderKey]["format-version"] = kFormatVersion;
0152   encoded[kHeaderKey]["value-identifier"] = m_valueIdentifier;
0153   // encode entries
0154   nlohmann::json entries = nlohmann::json::array();
0155   for (std::size_t i = 0; i < container.size(); ++i) {
0156     auto entry = encodeIdentifier(container.idAt(i));
0157     auto value_json = nlohmann::json(container.valueAt(i));
0158     if constexpr (!std::is_same<decorator_t, void>::value) {
0159       decorateJson(decorator, container.valueAt(i), value_json);
0160     }
0161     entry["value"] = std::move(value_json);
0162     entries.push_back(std::move(entry));
0163   }
0164   encoded[kEntriesKey] = std::move(entries);
0165   return encoded;
0166 }
0167 
0168 template <typename value_t, class decorator_t>
0169 auto GeometryHierarchyMapJsonConverter<value_t, decorator_t>::fromJson(
0170     const nlohmann::json& encoded) const -> Container {
0171   // verify json format header
0172   auto header = encoded.find(kHeaderKey);
0173   if (header == encoded.end()) {
0174     throw std::invalid_argument(
0175         "Missing header entry in json geometry hierarchy map");
0176   }
0177   if (header->at("format-version").get<int>() != kFormatVersion) {
0178     throw std::invalid_argument(
0179         "Invalid format version in json geometry hierarchy map");
0180   }
0181   if (header->at("value-identifier").get<std::string>() != m_valueIdentifier) {
0182     throw std::invalid_argument(
0183         "Inconsistent value identifier in Json geometry hierarchy map");
0184   }
0185   // decode json entries
0186   if (!encoded.contains(kEntriesKey)) {
0187     throw std::invalid_argument(
0188         "Missing entries in json geometry hierarchy map");
0189   }
0190   std::vector<std::pair<GeometryIdentifier, Value>> elements;
0191   for (const auto& entry : encoded.at(kEntriesKey)) {
0192     auto id = decodeIdentifier(entry);
0193     auto value = entry.at("value").get<Value>();
0194     elements.emplace_back(id, std::move(value));
0195   }
0196   return elements;
0197 }
0198 
0199 }  // namespace Acts