Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-10 07:48:59

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/Utilities/GridAccessHelpers.hpp"
0012 #include "Acts/Utilities/GridAxisGenerators.hpp"
0013 #include "Acts/Utilities/IAxis.hpp"
0014 #include "ActsPlugins/Json/GridJsonConverter.hpp"
0015 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0016 
0017 #include <array>
0018 #include <fstream>
0019 #include <memory>
0020 #include <numbers>
0021 #include <vector>
0022 
0023 #include <nlohmann/json.hpp>
0024 
0025 using namespace Acts;
0026 
0027 namespace ActsTests {
0028 
0029 BOOST_AUTO_TEST_SUITE(JsonSuite)
0030 
0031 BOOST_AUTO_TEST_CASE(Grid1DSingleEntry) {
0032   // Bound equidistant
0033   using EqBound = GridAxisGenerators::EqBound;
0034 
0035   EqBound eqBound{{0., 5.}, 5};
0036   // Create the grid with the provided axis generator
0037   using GridTypeEQB = typename EqBound::template grid_type<std::size_t>;
0038   GridTypeEQB eqBoundGrid(eqBound());
0039 
0040   eqBoundGrid.at(1u) = 1u;
0041   eqBoundGrid.at(2u) = 2u;
0042   eqBoundGrid.at(3u) = 3u;
0043   eqBoundGrid.at(4u) = 4u;
0044   eqBoundGrid.at(5u) = 5u;
0045 
0046   auto p1 = typename GridTypeEQB::point_t{0.5};
0047   BOOST_CHECK_EQUAL(eqBoundGrid.atPosition(p1), 1u);
0048   auto p2 = typename GridTypeEQB::point_t{1.5};
0049   BOOST_CHECK_EQUAL(eqBoundGrid.atPosition(p2), 2u);
0050   auto p3 = typename GridTypeEQB::point_t{2.5};
0051   BOOST_CHECK_EQUAL(eqBoundGrid.atPosition(p3), 3u);
0052   auto p4 = typename GridTypeEQB::point_t{3.5};
0053   BOOST_CHECK_EQUAL(eqBoundGrid.atPosition(p4), 4u);
0054   auto p5 = typename GridTypeEQB::point_t{4.5};
0055   BOOST_CHECK_EQUAL(eqBoundGrid.atPosition(p5), 5u);
0056 
0057   nlohmann::json eqBoundJson = GridJsonConverter::toJson(eqBoundGrid);
0058 
0059   auto eqBoundGridRead =
0060       GridJsonConverter::fromJson<EqBound, std::size_t>(eqBoundJson, eqBound);
0061 
0062   BOOST_CHECK_EQUAL(eqBoundGridRead.at(1u), 1u);
0063   BOOST_CHECK_EQUAL(eqBoundGridRead.at(2u), 2u);
0064   BOOST_CHECK_EQUAL(eqBoundGridRead.at(3u), 3u);
0065   BOOST_CHECK_EQUAL(eqBoundGridRead.at(4u), 4u);
0066   BOOST_CHECK_EQUAL(eqBoundGridRead.at(5u), 5u);
0067 
0068   // Bound variable
0069   using VarBound = GridAxisGenerators::VarBound;
0070 
0071   VarBound varBound{{10., 11., 22., 333., 4444., 55555.}};
0072   // Create the grid with the provided axis generator
0073   using GridTypeEQV = typename VarBound::template grid_type<std::size_t>;
0074   GridTypeEQV varBoundGrid(varBound());
0075 
0076   varBoundGrid.at(1u) = 1u;
0077   varBoundGrid.at(2u) = 2u;
0078   varBoundGrid.at(3u) = 3u;
0079   varBoundGrid.at(4u) = 4u;
0080   varBoundGrid.at(5u) = 5u;
0081 
0082   nlohmann::json varBoundJson = GridJsonConverter::toJson(varBoundGrid);
0083 
0084   auto varBoundGridRead = GridJsonConverter::fromJson<VarBound, std::size_t>(
0085       varBoundJson, varBound);
0086 
0087   BOOST_CHECK_EQUAL(varBoundGridRead.at(1u), 1u);
0088   BOOST_CHECK_EQUAL(varBoundGridRead.at(2u), 2u);
0089   BOOST_CHECK_EQUAL(varBoundGridRead.at(3u), 3u);
0090   BOOST_CHECK_EQUAL(varBoundGridRead.at(4u), 4u);
0091   BOOST_CHECK_EQUAL(varBoundGridRead.at(5u), 5u);
0092 
0093   // Closed equidistant
0094   using EqClosed = GridAxisGenerators::EqClosed;
0095 
0096   EqClosed eqClosed{{0., 5.}, 5};
0097   // Create the grid with the provided axis generator
0098   using GridTypeEQC = typename EqClosed::template grid_type<std::size_t>;
0099   GridTypeEQC eqClosedGrid(eqClosed());
0100 
0101   eqClosedGrid.at(1u) = 1u;
0102   eqClosedGrid.at(2u) = 2u;
0103   eqClosedGrid.at(3u) = 3u;
0104   eqClosedGrid.at(4u) = 4u;
0105   eqClosedGrid.at(5u) = 5u;
0106 
0107   nlohmann::json eqClosedJson = GridJsonConverter::toJson(eqClosedGrid);
0108 
0109   auto eqClosedGridRead = GridJsonConverter::fromJson<EqClosed, std::size_t>(
0110       eqClosedJson, eqClosed);
0111 
0112   BOOST_CHECK_EQUAL(eqClosedGridRead.at(1u), 1u);
0113   BOOST_CHECK_EQUAL(eqClosedGridRead.at(2u), 2u);
0114   BOOST_CHECK_EQUAL(eqClosedGridRead.at(3u), 3u);
0115   BOOST_CHECK_EQUAL(eqClosedGridRead.at(4u), 4u);
0116   BOOST_CHECK_EQUAL(eqClosedGridRead.at(5u), 5u);
0117 }
0118 
0119 BOOST_AUTO_TEST_CASE(Grid1DArrayEntry) {
0120   // Bound equidistant
0121   using EqBound = GridAxisGenerators::EqBound;
0122 
0123   EqBound eqBound{{0., 5.}, 5};
0124   // Create the grid with the provided axis generator
0125   using GridTypeEQB =
0126       typename EqBound::template grid_type<std::array<std::size_t, 2u>>;
0127   GridTypeEQB eqBoundGrid(eqBound());
0128 
0129   eqBoundGrid.at(1u) = {1u, 1u};
0130   eqBoundGrid.at(2u) = {2u, 2u};
0131   eqBoundGrid.at(3u) = {3u, 3u};
0132   eqBoundGrid.at(4u) = {4u, 4u};
0133   eqBoundGrid.at(5u) = {5u, 5u};
0134 
0135   nlohmann::json eqBoundJson = GridJsonConverter::toJson(eqBoundGrid);
0136 
0137   auto eqBoundGridRead =
0138       GridJsonConverter::fromJson<EqBound, std::array<std::size_t, 2u>>(
0139           eqBoundJson, eqBound);
0140 
0141   BOOST_CHECK((eqBoundGridRead.at(1u) == std::array<std::size_t, 2u>{1u, 1u}));
0142   BOOST_CHECK((eqBoundGridRead.at(2u) == std::array<std::size_t, 2u>{2u, 2u}));
0143   BOOST_CHECK((eqBoundGridRead.at(3u) == std::array<std::size_t, 2u>{3u, 3u}));
0144   BOOST_CHECK((eqBoundGridRead.at(4u) == std::array<std::size_t, 2u>{4u, 4u}));
0145   BOOST_CHECK((eqBoundGridRead.at(5u) == std::array<std::size_t, 2u>{5u, 5u}));
0146 }
0147 
0148 BOOST_AUTO_TEST_CASE(Grid2DSingleEntryBound) {
0149   using EqBoundEqBound = GridAxisGenerators::EqBoundEqBound;
0150 
0151   EqBoundEqBound eqBound2{{0., 5.}, 5, {0., 2.}, 2};
0152   // Create the grid with the provided axis generator
0153   using GridTypeEQB2 = typename EqBoundEqBound::template grid_type<std::size_t>;
0154   GridTypeEQB2 eqBound2Grid(eqBound2());
0155 
0156   // Let's write in local coordinates
0157   using GridPoint = typename GridTypeEQB2::point_t;
0158 
0159   // First row access
0160   GridPoint p11{0.5, 0.5};
0161   GridPoint p12{1.5, 0.5};
0162   GridPoint p13{2.5, 0.5};
0163   GridPoint p14{3.5, 0.5};
0164   GridPoint p15{4.5, 0.5};
0165   eqBound2Grid.atPosition(p11) = 11u;
0166   eqBound2Grid.atPosition(p12) = 12u;
0167   eqBound2Grid.atPosition(p13) = 13u;
0168   eqBound2Grid.atPosition(p14) = 14u;
0169   eqBound2Grid.atPosition(p15) = 15u;
0170 
0171   // Second row access
0172   GridPoint p21{0.5, 1.5};
0173   GridPoint p22{1.5, 1.5};
0174   GridPoint p23{2.5, 1.5};
0175   GridPoint p24{3.5, 1.5};
0176   GridPoint p25{4.5, 1.5};
0177   eqBound2Grid.atPosition(p21) = 21u;
0178   eqBound2Grid.atPosition(p22) = 22u;
0179   eqBound2Grid.atPosition(p23) = 23u;
0180   eqBound2Grid.atPosition(p24) = 24u;
0181   eqBound2Grid.atPosition(p25) = 25u;
0182 
0183   nlohmann::json eqBound2Json = GridJsonConverter::toJson(eqBound2Grid);
0184 
0185   auto eqBound2JsonRead =
0186       GridJsonConverter::fromJson<EqBoundEqBound, std::size_t>(eqBound2Json,
0187                                                                eqBound2);
0188 
0189   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p11), 11u);
0190   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p12), 12u);
0191   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p13), 13u);
0192   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p14), 14u);
0193   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p15), 15u);
0194   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p21), 21u);
0195   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p22), 22u);
0196   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p23), 23u);
0197   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p24), 24u);
0198   BOOST_CHECK_EQUAL(eqBound2JsonRead.atPosition(p25), 25u);
0199 }
0200 
0201 BOOST_AUTO_TEST_CASE(Grid2DSingleEntryBoundClosed) {
0202   using EqBoundEqClosed = GridAxisGenerators::EqBoundEqClosed;
0203 
0204   EqBoundEqClosed eqBoundEqClosed{
0205       {-6., 6.}, 3, {-std::numbers::pi, std::numbers::pi}, 3};
0206   // Create the grid with the provided axis generator
0207   using GridTypeEQBEQC =
0208       typename EqBoundEqClosed::template grid_type<std::size_t>;
0209   GridTypeEQBEQC eqBoundEqClosedGrid(eqBoundEqClosed());
0210 
0211   // Let's write in local coordinates
0212   using GridPoint = typename GridTypeEQBEQC::point_t;
0213 
0214   // First row access
0215   GridPoint p11{-5, -2.};
0216   GridPoint p12{0., -2};
0217   GridPoint p13{5, -2};
0218   eqBoundEqClosedGrid.atPosition(p11) = 11u;
0219   eqBoundEqClosedGrid.atPosition(p12) = 12u;
0220   eqBoundEqClosedGrid.atPosition(p13) = 13u;
0221 
0222   // Middle row access
0223   GridPoint p21{-5., 0.};
0224   GridPoint p22{0., 0.};
0225   GridPoint p23{5., 0.};
0226   eqBoundEqClosedGrid.atPosition(p21) = 21u;
0227   eqBoundEqClosedGrid.atPosition(p22) = 22u;
0228   eqBoundEqClosedGrid.atPosition(p23) = 23u;
0229 
0230   // Last row access
0231   GridPoint p31{-5., 2.};
0232   GridPoint p32{0., 2.};
0233   GridPoint p33{5., 2.};
0234   eqBoundEqClosedGrid.atPosition(p31) = 31u;
0235   eqBoundEqClosedGrid.atPosition(p32) = 32u;
0236   eqBoundEqClosedGrid.atPosition(p33) = 33u;
0237 
0238   nlohmann::json eqBoundEqClosedJson =
0239       GridJsonConverter::toJson(eqBoundEqClosedGrid);
0240 
0241   auto eqBoundEqClosedJsonRead =
0242       GridJsonConverter::fromJson<EqBoundEqClosed, std::size_t>(
0243           eqBoundEqClosedJson, eqBoundEqClosed);
0244 
0245   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p11), 11u);
0246   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p12), 12u);
0247   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p13), 13u);
0248 
0249   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p21), 21u);
0250   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p22), 22u);
0251   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p23), 23u);
0252 
0253   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p31), 31u);
0254   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p32), 32u);
0255   BOOST_CHECK_EQUAL(eqBoundEqClosedJsonRead.atPosition(p33), 33u);
0256 }
0257 
0258 namespace {
0259 template <typename ReferenceType, typename CheckTypeUniquePtr>
0260 bool checkType(const ReferenceType& /**unused*/,
0261                const CheckTypeUniquePtr& g2l) {
0262   return (dynamic_cast<const ReferenceType*>(g2l.get()) != nullptr);
0263 }
0264 
0265 template <typename SubspactTuple>
0266 void checkGlobalSubspaceTuple(const SubspactTuple& sstuple) {
0267   // Test without transform
0268   std::vector<nlohmann::json> jsspace;
0269   std::apply(
0270       [&](auto&&... vals) {
0271         (jsspace.push_back(GridAccessJsonConverter::toJson(vals)), ...);
0272       },
0273       sstuple);
0274 
0275   // Test that none of them are empty
0276   for (auto& jss : jsspace) {
0277     BOOST_CHECK(!jss.empty());
0278   }
0279 
0280   // Read back in
0281   std::vector<std::unique_ptr<const GridAccess::IGlobalToGridLocal>> sspaceRead;
0282   for (auto& jss : jsspace) {
0283     sspaceRead.push_back(
0284         GridAccessJsonConverter::globalToGridLocalFromJson(jss));
0285     if (jss["accessors"].size() == 1u) {
0286       auto delegate =
0287           GridAccessJsonConverter::globalToGridLocal1DimDelegateFromJson(jss);
0288       BOOST_CHECK(delegate.connected());
0289     } else if (jss["accessors"].size() == 2u) {
0290       auto delegate =
0291           GridAccessJsonConverter::globalToGridLocal2DimDelegateFromJson(jss);
0292       BOOST_CHECK(delegate.connected());
0293     } else {
0294       BOOST_CHECK(false);
0295     }
0296   }
0297 
0298   // Test that none of them are empty
0299   for (auto& ssp : sspaceRead) {
0300     BOOST_CHECK(ssp != nullptr);
0301   }
0302 
0303   // Check that the type is correct
0304   std::size_t irn = 0;
0305   bool good = true;
0306   std::apply(
0307       [&](auto&&... vals) {
0308         ((good = good && checkType(vals, sspaceRead[irn++])), ...);
0309       },
0310       sstuple);
0311   BOOST_CHECK(good);
0312 
0313   Transform3 tTransform;
0314   tTransform.pretranslate(Vector3{0., 0., 100.});
0315 
0316   // Test with transform
0317   std::vector<nlohmann::json> jsspaceTransform;
0318   std::apply(
0319       [&](const auto&... vals) {
0320         (jsspaceTransform.push_back(GridAccessJsonConverter::toJson(
0321              GridAccess::Affine3Transformed<std::decay_t<decltype(vals)>>(
0322                  vals, tTransform))),
0323          ...);
0324       },
0325       sstuple);
0326 
0327   // Test that none of them are empty & everyone has a stransform
0328   for (auto& jss : jsspaceTransform) {
0329     BOOST_CHECK(!jss.empty());
0330     BOOST_CHECK(jss.find("transform") != jss.end());
0331   }
0332 
0333   // Read back in
0334   std::vector<std::unique_ptr<const GridAccess::IGlobalToGridLocal>>
0335       sspaceTransformRead;
0336   for (auto& jss : jsspaceTransform) {
0337     sspaceTransformRead.push_back(
0338         GridAccessJsonConverter::globalToGridLocalFromJson(jss));
0339   }
0340 
0341   // Test that none of them are empty
0342   for (auto& ssp : sspaceTransformRead) {
0343     BOOST_CHECK(ssp != nullptr);
0344   }
0345 
0346   // Check that the type is correct
0347   irn = 0;
0348   good = true;
0349   std::apply(
0350       [&](const auto&... vals) {
0351         ((good =
0352               good &&
0353               checkType(
0354                   GridAccess::Affine3Transformed<std::decay_t<decltype(vals)>>(
0355                       vals, tTransform),
0356                   sspaceTransformRead[irn++])),
0357          ...);
0358       },
0359       sstuple);
0360   BOOST_CHECK(good);
0361 }
0362 
0363 }  // namespace
0364 
0365 BOOST_AUTO_TEST_CASE(GlobalSubSpaceTests1D) {
0366   // One dimensional sub spaces
0367   const std::tuple<GridAccess::GlobalSubspace<AxisDirection::AxisX>,
0368                    GridAccess::GlobalSubspace<AxisDirection::AxisY>,
0369                    GridAccess::GlobalSubspace<AxisDirection::AxisZ>,
0370                    GridAccess::GlobalSubspace<AxisDirection::AxisR>,
0371                    GridAccess::GlobalSubspace<AxisDirection::AxisPhi>,
0372                    GridAccess::GlobalSubspace<AxisDirection::AxisEta>>
0373       sspace1D;
0374 
0375   // Check the tuple for 1D
0376   checkGlobalSubspaceTuple(sspace1D);
0377 }
0378 
0379 BOOST_AUTO_TEST_CASE(GlobalSubSpaceTests2D) {
0380   // Two dimensional sub spaces
0381   const std::tuple<
0382       GridAccess::GlobalSubspace<AxisDirection::AxisX, AxisDirection::AxisY>,
0383       GridAccess::GlobalSubspace<AxisDirection::AxisY, AxisDirection::AxisX>,
0384       GridAccess::GlobalSubspace<AxisDirection::AxisX, AxisDirection::AxisZ>,
0385       GridAccess::GlobalSubspace<AxisDirection::AxisZ, AxisDirection::AxisX>,
0386       GridAccess::GlobalSubspace<AxisDirection::AxisY, AxisDirection::AxisZ>,
0387       GridAccess::GlobalSubspace<AxisDirection::AxisZ, AxisDirection::AxisY>,
0388       GridAccess::GlobalSubspace<AxisDirection::AxisR, AxisDirection::AxisPhi>,
0389       GridAccess::GlobalSubspace<AxisDirection::AxisPhi, AxisDirection::AxisR>,
0390       GridAccess::GlobalSubspace<AxisDirection::AxisZ, AxisDirection::AxisPhi>,
0391       GridAccess::GlobalSubspace<AxisDirection::AxisPhi, AxisDirection::AxisZ>>
0392       sspace2D = {};
0393 
0394   // Check the tuple for 2D
0395   checkGlobalSubspaceTuple(sspace2D);
0396 }
0397 
0398 BOOST_AUTO_TEST_CASE(LocalSubspaceTests) {
0399   const std::tuple<GridAccess::LocalSubspace<0u>, GridAccess::LocalSubspace<1u>,
0400                    GridAccess::LocalSubspace<0u, 1u>,
0401                    GridAccess::LocalSubspace<1u, 0u>>
0402       lspace1D;
0403 
0404   // Write them to json
0405   std::vector<nlohmann::json> jlspace;
0406   std::apply(
0407       [&](auto&&... vals) {
0408         (jlspace.push_back(GridAccessJsonConverter::toJson(vals)), ...);
0409       },
0410       lspace1D);
0411 
0412   // Check that none of them is empty
0413   for (auto& jls : jlspace) {
0414     BOOST_CHECK(!jls.empty());
0415   }
0416 
0417   std::vector<std::unique_ptr<const GridAccess::IBoundToGridLocal>> lspaceRead;
0418   for (auto& jls : jlspace) {
0419     lspaceRead.push_back(
0420         GridAccessJsonConverter::boundToGridLocalFromJson(jls));
0421     if (jls["accessors"].size() == 1u) {
0422       auto delegate =
0423           GridAccessJsonConverter::boundToGridLocal1DimDelegateFromJson(jls);
0424       BOOST_CHECK(delegate.connected());
0425     } else if (jls["accessors"].size() == 2u) {
0426       auto delegate =
0427           GridAccessJsonConverter::boundToGridLocal2DimDelegateFromJson(jls);
0428       BOOST_CHECK(delegate.connected());
0429     } else {
0430       BOOST_CHECK(false);
0431     }
0432   }
0433 
0434   // Test that none of them are empty
0435   for (auto& lsp : lspaceRead) {
0436     BOOST_CHECK(lsp != nullptr);
0437   }
0438 
0439   // Check that the type is correct
0440   std::size_t irn = 0;
0441   bool good = true;
0442   std::apply(
0443       [&](auto&&... vals) {
0444         ((good = good && checkType(vals, lspaceRead[irn++])), ...);
0445       },
0446       lspace1D);
0447   BOOST_CHECK(good);
0448 }
0449 
0450 BOOST_AUTO_TEST_CASE(BoundCylinderToZPhiTest) {
0451   GridAccess::BoundCylinderToZPhi boundCylinderToZPhi(100., 10.);
0452 
0453   nlohmann::json jboundCylinderToZPhi =
0454       GridAccessJsonConverter::toJson(boundCylinderToZPhi);
0455 
0456   // Check it is not empty
0457   BOOST_CHECK(!jboundCylinderToZPhi.empty());
0458 
0459   auto boundCylinderToZPhiRead =
0460       GridAccessJsonConverter::boundToGridLocalFromJson(jboundCylinderToZPhi);
0461 
0462   // Check that it is not empty
0463   BOOST_REQUIRE(boundCylinderToZPhiRead != nullptr);
0464 
0465   const GridAccess::BoundCylinderToZPhi* bct =
0466       dynamic_cast<const GridAccess::BoundCylinderToZPhi*>(
0467           boundCylinderToZPhiRead.get());
0468 
0469   auto delegate = GridAccessJsonConverter::boundToGridLocal2DimDelegateFromJson(
0470       jboundCylinderToZPhi);
0471   BOOST_CHECK(delegate.connected());
0472 
0473   BOOST_REQUIRE(bct != nullptr);
0474   CHECK_CLOSE_ABS(bct->radius, 100., 1e-5);
0475   CHECK_CLOSE_ABS(bct->shift, 10., 1e-5);
0476 }
0477 
0478 BOOST_AUTO_TEST_CASE(AxisJsonConverterEquidistantBound) {
0479   auto axis = IAxis::createEquidistant(AxisBoundaryType::Bound, -5., 5., 10);
0480   nlohmann::json j = AxisJsonConverter::toJson(*axis);
0481   auto read = AxisJsonConverter::fromJson(j);
0482   BOOST_REQUIRE(read != nullptr);
0483   BOOST_CHECK_EQUAL(read->getBoundaryType(), AxisBoundaryType::Bound);
0484   BOOST_CHECK_EQUAL(read->getNBins(), 10u);
0485   BOOST_CHECK_EQUAL(read->getMin(), -5.);
0486   BOOST_CHECK_EQUAL(read->getMax(), 5.);
0487   BOOST_CHECK(read->isEquidistant());
0488 }
0489 
0490 BOOST_AUTO_TEST_CASE(AxisJsonConverterEquidistantClosed) {
0491   auto axis = IAxis::createEquidistant(AxisBoundaryType::Closed,
0492                                        -std::numbers::pi, std::numbers::pi, 36);
0493   nlohmann::json j = AxisJsonConverter::toJson(*axis);
0494   auto read = AxisJsonConverter::fromJson(j);
0495   BOOST_REQUIRE(read != nullptr);
0496   BOOST_CHECK_EQUAL(read->getBoundaryType(), AxisBoundaryType::Closed);
0497   BOOST_CHECK_EQUAL(read->getNBins(), 36u);
0498   BOOST_CHECK(read->isEquidistant());
0499 }
0500 
0501 BOOST_AUTO_TEST_CASE(AxisJsonConverterVariableBound) {
0502   // Exercises the "boundaries" key — the fix changed from reading "edges"
0503   std::vector<double> edges = {0., 10., 25., 60., 130.};
0504   auto axis = IAxis::createVariable(AxisBoundaryType::Bound, edges);
0505   nlohmann::json j = AxisJsonConverter::toJson(*axis);
0506   BOOST_CHECK_EQUAL(j.at("type").get<AxisType>(), AxisType::Variable);
0507   BOOST_CHECK(j.contains("boundaries"));
0508   BOOST_CHECK(!j.contains("edges"));
0509   auto read = AxisJsonConverter::fromJson(j);
0510   BOOST_REQUIRE(read != nullptr);
0511   BOOST_CHECK_EQUAL(read->getBoundaryType(), AxisBoundaryType::Bound);
0512   BOOST_CHECK_EQUAL(read->getNBins(), edges.size() - 1);
0513   BOOST_CHECK(!read->isEquidistant());
0514   BOOST_CHECK(read->getBinEdges() == edges);
0515 }
0516 
0517 BOOST_AUTO_TEST_SUITE_END()
0518 
0519 }  // namespace ActsTests