Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-31 08:18:27

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 <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Geometry/GeometryHierarchyMap.hpp"
0012 #include "Acts/Geometry/GeometryIdentifier.hpp"
0013 #include "ActsPlugins/Json/GeometryHierarchyMapJsonConverter.hpp"
0014 #include "ActsTests/CommonHelpers/DataDirectory.hpp"
0015 
0016 #include <algorithm>
0017 #include <fstream>
0018 #include <initializer_list>
0019 #include <stdexcept>
0020 #include <string>
0021 #include <vector>
0022 
0023 #include <nlohmann/json.hpp>
0024 
0025 using namespace Acts;
0026 
0027 using nlohmann::json;
0028 
0029 namespace {
0030 
0031 // helper function to create geometry ids.
0032 GeometryIdentifier makeId(int volume = 0, int layer = 0, int sensitive = 0) {
0033   return GeometryIdentifier().withVolume(volume).withLayer(layer).withSensitive(
0034       sensitive);
0035 }
0036 
0037 // example element for the container
0038 
0039 struct Thing {
0040   double x = 1.0;
0041   int y = 23;
0042 
0043   friend constexpr bool operator==(const Thing& lhs, const Thing& rhs) {
0044     return (lhs.x == rhs.x) && (lhs.y == rhs.y);
0045   }
0046 };
0047 
0048 // custom Json encoder/decoder. naming is mandated by nlohmann::json and thus
0049 // can not match our naming guidelines.
0050 
0051 void to_json(json& j, const Thing& t) {
0052   j = json{{"x", t.x}, {"y", t.y}};
0053 }
0054 
0055 void from_json(const json& j, Thing& t) {
0056   j.at("x").get_to(t.x);
0057   j.at("y").get_to(t.y);
0058 }
0059 
0060 std::ostream& operator<<(std::ostream& os, const Thing& t) {
0061   os << nlohmann::json(t);
0062   return os;
0063 }
0064 
0065 class ThingDecorator {
0066  public:
0067   void decorate(const Thing* a_thing, nlohmann::json& a_json) const {
0068     if (a_thing != nullptr) {
0069       a_json["product"] = a_thing->x * a_thing->y;
0070     }
0071   }
0072 };
0073 
0074 using Container = GeometryHierarchyMap<Thing>;
0075 using Converter = GeometryHierarchyMapJsonConverter<Thing, ThingDecorator>;
0076 
0077 }  // namespace
0078 
0079 template <>
0080 void Acts::decorateJson<Thing>(const ThingDecorator* decorator,
0081                                const Thing& src, nlohmann::json& dest) {
0082   if (decorator != nullptr) {
0083     decorator->decorate(&src, dest);
0084   }
0085 }
0086 
0087 BOOST_TEST_DONT_PRINT_LOG_VALUE(json::iterator)
0088 BOOST_TEST_DONT_PRINT_LOG_VALUE(Container::Iterator)
0089 
0090 namespace ActsTests {
0091 
0092 BOOST_AUTO_TEST_SUITE(JsonSuite)
0093 
0094 BOOST_AUTO_TEST_CASE(ToJson) {
0095   ThingDecorator decorator;
0096   Container c = {
0097       {makeId(1), {2.0, -3}},
0098       {makeId(2, 3), {-4.5, 5}},
0099       {makeId(4, 5, 6), {7.25, -8}},
0100   };
0101   json j = Converter("thing").toJson(c, &decorator);
0102 
0103   BOOST_CHECK(j.is_object());
0104   // check header
0105   auto header = j.find("acts-geometry-hierarchy-map");
0106   BOOST_CHECK_NE(header, j.end());
0107   BOOST_CHECK(header->is_object());
0108   BOOST_CHECK(header->at("format-version").is_number_integer());
0109   BOOST_CHECK_EQUAL(header->at("format-version").get<int>(), 0);
0110   BOOST_CHECK(header->at("value-identifier").is_string());
0111   BOOST_CHECK_EQUAL(header->at("value-identifier").get<std::string>(), "thing");
0112   // check entries
0113   auto entries = j.find("entries");
0114   BOOST_CHECK_NE(entries, j.end());
0115   BOOST_CHECK(entries->is_array());
0116   BOOST_CHECK_EQUAL(entries->size(), 3u);
0117 }
0118 
0119 BOOST_AUTO_TEST_CASE(FromJson) {
0120   json j = {
0121       {
0122           "acts-geometry-hierarchy-map",
0123           {
0124               {"format-version", 0},
0125               {"value-identifier", "thing"},
0126           },
0127       },
0128       {
0129           "entries",
0130           {
0131               {
0132                   {"volume", 2},
0133                   {"layer", 3},
0134                   {"value", {{"x", 4.0}, {"y", 4}}},
0135               },
0136               {
0137                   {"volume", 5},
0138                   {"layer", 6},
0139                   {"sensitive", 7},
0140                   {"value", {{"x", 3.0}, {"y", 3}}},
0141               },
0142           },
0143       },
0144   };
0145   Container c = Converter("thing").fromJson(j);
0146 
0147   BOOST_CHECK(!c.empty());
0148   BOOST_CHECK_EQUAL(c.size(), 2);
0149   {
0150     auto it = c.find(makeId(2, 3));
0151     BOOST_CHECK_NE(it, c.end());
0152     BOOST_CHECK_EQUAL(it->x, 4.0);
0153     BOOST_CHECK_EQUAL(it->y, 4);
0154   }
0155   {
0156     auto it = c.find(makeId(5, 6, 7));
0157     BOOST_CHECK_NE(it, c.end());
0158     BOOST_CHECK_EQUAL(it->x, 3.0);
0159     BOOST_CHECK_EQUAL(it->y, 3);
0160   }
0161 }
0162 
0163 BOOST_AUTO_TEST_CASE(FromJsonMissingHeader) {
0164   json j = {
0165       {"entries", {}},
0166   };
0167   BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0168                     std::invalid_argument);
0169 }
0170 
0171 BOOST_AUTO_TEST_CASE(FromJsonInvalidFormatVersion) {
0172   json j = {
0173       {
0174           "acts-geometry-hierarchy-map",
0175           {
0176               {"format-version", -1},
0177               {"value-identifier", "an-identifier"},
0178           },
0179       },
0180       {"entries", {}},
0181   };
0182   BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0183                     std::invalid_argument);
0184 }
0185 
0186 BOOST_AUTO_TEST_CASE(FromJsonInvalidValueIdentifier) {
0187   json j = {
0188       {
0189           "acts-geometry-hierarchy-map",
0190           {
0191               {"format-version", 0},
0192               {"value-identifier", "an-identifier"},
0193           },
0194       },
0195       {"entries", {}},
0196   };
0197   BOOST_CHECK_THROW(Converter("not-the-identifier").fromJson(j),
0198                     std::invalid_argument);
0199 }
0200 
0201 BOOST_AUTO_TEST_CASE(FromJsonMissingEntries) {
0202   json j = {
0203       {
0204           "acts-geometry-hierarchy-map",
0205           {
0206               {"format-version", 0},
0207               {"value-identifier", "an-identifier"},
0208           },
0209       },
0210   };
0211   BOOST_CHECK_THROW(Converter("an-identifier").fromJson(j),
0212                     std::invalid_argument);
0213 }
0214 
0215 BOOST_AUTO_TEST_CASE(Roundtrip) {
0216   ThingDecorator decorator;
0217   Container c0 = {
0218       {makeId(1), {2.0, -3}},
0219       {makeId(2, 3), {-4.5, 5}},
0220       {makeId(4, 5, 6), {7.25, -8}},
0221   };
0222   auto j = Converter("the-identifier").toJson(c0, &decorator);
0223   auto c1 = Converter("the-identifier").fromJson(j);
0224 
0225   BOOST_CHECK_EQUAL(c0.size(), c1.size());
0226   for (auto i = std::min(c0.size(), c1.size()); 0 < i--;) {
0227     BOOST_CHECK_EQUAL(c0.idAt(i), c1.idAt(i));
0228     BOOST_CHECK_EQUAL(c0.valueAt(i), c1.valueAt(i));
0229   }
0230 }
0231 
0232 BOOST_AUTO_TEST_CASE(FromFile) {
0233   // read json data from file
0234   auto path = ActsTests::getDataPath("geometry-hierarchy-map.json");
0235   auto file = std::ifstream(path, std::ifstream::in | std::ifstream::binary);
0236   BOOST_CHECK(file.good());
0237   json j;
0238   file >> j;
0239   BOOST_CHECK(file.good());
0240   // convert json to container
0241   Container c = Converter("thing").fromJson(j);
0242   // check container content
0243   BOOST_CHECK(!c.empty());
0244   BOOST_CHECK_EQUAL(c.size(), 4);
0245   BOOST_CHECK_NE(c.find(makeId()), c.end());
0246   BOOST_CHECK_NE(c.find(makeId(1, 2)), c.end());
0247   BOOST_CHECK_NE(c.find(makeId(3)), c.end());
0248   BOOST_CHECK_NE(c.find(makeId(3, 4)), c.end());
0249 }
0250 
0251 BOOST_AUTO_TEST_SUITE_END()
0252 
0253 }  // namespace ActsTests