-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adding json conversion and unit test for
ProtoAxis
(#4045)
This PR adds json writing/reading to the new ProtoAxis. It supersedes #4038
- Loading branch information
1 parent
0340320
commit 429e34d
Showing
5 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
Plugins/Json/include/Acts/Plugins/Json/ProtoAxisJsonConverter.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// This file is part of the ACTS project. | ||
// | ||
// Copyright (C) 2016 CERN for the benefit of the ACTS project | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
#pragma once | ||
|
||
#include "Acts/Plugins/Json/ActsJson.hpp" | ||
#include "Acts/Utilities/ProtoAxis.hpp" | ||
|
||
#include <nlohmann/json.hpp> | ||
|
||
/// Custom Json encoder/decoders. Naming is mandated by nlohmann::json and thus | ||
/// can not match our naming guidelines. | ||
/// | ||
/// This uses a custom API and nomenclature as it would | ||
/// otherwise require the ProtoAxis to have a default | ||
/// constructor which is deleted | ||
namespace Acts::ProtoAxisJsonConverter { | ||
|
||
/// Write the ProtoAxis to a json object | ||
/// | ||
/// @param pa the proto axis to be written out | ||
nlohmann::json toJson(const ProtoAxis& pa); | ||
|
||
/// Create a ProtoAxis from a json object | ||
/// | ||
/// @param j the json object to be read from | ||
Acts::ProtoAxis fromJson(const nlohmann::json& j); | ||
|
||
} // namespace Acts::ProtoAxisJsonConverter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// This file is part of the ACTS project. | ||
// | ||
// Copyright (C) 2016 CERN for the benefit of the ACTS project | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
#include "Acts/Plugins/Json/ProtoAxisJsonConverter.hpp" | ||
|
||
#include "Acts/Plugins/Json/GridJsonConverter.hpp" | ||
#include "Acts/Plugins/Json/UtilitiesJsonConverter.hpp" | ||
#include "Acts/Utilities/AxisDefinitions.hpp" | ||
|
||
nlohmann::json Acts::ProtoAxisJsonConverter::toJson(const Acts::ProtoAxis& pa) { | ||
nlohmann::json j; | ||
j["axis_dir"] = pa.getAxisDirection(); | ||
j["axis"] = AxisJsonConverter::toJson(pa.getAxis()); | ||
j["autorange"] = pa.isAutorange(); | ||
return j; | ||
} | ||
|
||
Acts::ProtoAxis Acts::ProtoAxisJsonConverter::fromJson( | ||
const nlohmann::json& j) { | ||
auto axisDir = j.at("axis_dir").get<Acts::AxisDirection>(); | ||
auto axisBoundaryType = | ||
j.at("axis").at("boundary_type").get<Acts::AxisBoundaryType>(); | ||
if (auto axisType = j.at("axis").at("type").get<Acts::AxisType>(); | ||
axisType == AxisType::Equidistant) { | ||
auto nbins = j.at("axis").at("bins").get<std::size_t>(); | ||
if (nbins == 0) { | ||
throw std::invalid_argument("Number of bins must be positive"); | ||
} | ||
|
||
if (j.at("autorange").get<bool>()) { | ||
return ProtoAxis(axisDir, axisBoundaryType, nbins); | ||
} | ||
auto min = j.at("axis").at("range").at(0).get<double>(); | ||
auto max = j.at("axis").at("range").at(1).get<double>(); | ||
if (min >= max) { | ||
throw std::invalid_argument("Invalid range: min must be less than max"); | ||
} | ||
return ProtoAxis(axisDir, axisBoundaryType, min, max, nbins); | ||
} | ||
auto binEdges = j.at("axis").at("boundaries").get<std::vector<double>>(); | ||
if (binEdges.size() < 2) { | ||
throw std::invalid_argument("At least two bin edges required"); | ||
} | ||
if (!std::ranges::is_sorted(binEdges)) { | ||
throw std::invalid_argument("Bin edges must be sorted in ascending order"); | ||
} | ||
return ProtoAxis(axisDir, axisBoundaryType, binEdges); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
Tests/UnitTests/Plugins/Json/ProtoAxisJsonConverterTests.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
// This file is part of the ACTS project. | ||
// | ||
// Copyright (C) 2016 CERN for the benefit of the ACTS project | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
#include <boost/test/data/test_case.hpp> | ||
#include <boost/test/unit_test.hpp> | ||
|
||
#include "Acts/Plugins/Json/ActsJson.hpp" | ||
#include "Acts/Plugins/Json/ProtoAxisJsonConverter.hpp" | ||
#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp" | ||
#include "Acts/Utilities/Axis.hpp" | ||
#include "Acts/Utilities/AxisDefinitions.hpp" | ||
#include "Acts/Utilities/ProtoAxis.hpp" | ||
|
||
BOOST_AUTO_TEST_SUITE(ProtoAxisJsonConversion) | ||
|
||
BOOST_AUTO_TEST_CASE(EquidistantProtoAxisJsonConversion) { | ||
using enum Acts::AxisBoundaryType; | ||
using enum Acts::AxisDirection; | ||
using enum Acts::AxisType; | ||
|
||
// Bound, equidistant axis | ||
Acts::ProtoAxis epab(AxisX, Bound, 0.0, 1.0, 10); | ||
|
||
nlohmann::json jProtoAxis = Acts::ProtoAxisJsonConverter::toJson(epab); | ||
|
||
BOOST_CHECK(jProtoAxis.contains("axis")); | ||
BOOST_CHECK(jProtoAxis.contains("axis_dir")); | ||
BOOST_CHECK(jProtoAxis.contains("autorange")); | ||
|
||
Acts::ProtoAxis epabRead = Acts::ProtoAxisJsonConverter::fromJson(jProtoAxis); | ||
|
||
BOOST_CHECK_EQUAL(epabRead.getAxisDirection(), epab.getAxisDirection()); | ||
BOOST_CHECK_EQUAL(epabRead.getAxis(), epab.getAxis()); | ||
BOOST_CHECK_EQUAL(epabRead.isAutorange(), epab.isAutorange()); | ||
BOOST_CHECK_EQUAL(epabRead.toString(), epab.toString()); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(AutorangeProtoAxisJsonConversion) { | ||
using enum Acts::AxisBoundaryType; | ||
using enum Acts::AxisDirection; | ||
using enum Acts::AxisType; | ||
|
||
// Bound, equidistant axis, autorange | ||
Acts::ProtoAxis epa(AxisX, Bound, 10); | ||
|
||
nlohmann::json jProtoAxis = Acts::ProtoAxisJsonConverter::toJson(epa); | ||
|
||
BOOST_CHECK(jProtoAxis.contains("axis")); | ||
BOOST_CHECK(jProtoAxis.contains("axis_dir")); | ||
BOOST_CHECK(jProtoAxis.contains("autorange")); | ||
|
||
Acts::ProtoAxis epaRead = Acts::ProtoAxisJsonConverter::fromJson(jProtoAxis); | ||
|
||
BOOST_CHECK_EQUAL(epaRead.getAxisDirection(), epa.getAxisDirection()); | ||
BOOST_CHECK_EQUAL(epaRead.getAxis(), epa.getAxis()); | ||
BOOST_CHECK_EQUAL(epaRead.isAutorange(), epa.isAutorange()); | ||
BOOST_CHECK_EQUAL(epaRead.toString(), epa.toString()); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(VariableProtoAxisJsonConversion) { | ||
using enum Acts::AxisBoundaryType; | ||
using enum Acts::AxisDirection; | ||
using enum Acts::AxisType; | ||
|
||
// Bound, variable axis | ||
Acts::ProtoAxis vpab(AxisX, Bound, {0.0, 1.0, 10}); | ||
|
||
nlohmann::json jProtoAxis = Acts::ProtoAxisJsonConverter::toJson(vpab); | ||
BOOST_CHECK(jProtoAxis.contains("axis")); | ||
BOOST_CHECK(jProtoAxis.contains("axis_dir")); | ||
BOOST_CHECK(jProtoAxis.contains("autorange")); | ||
|
||
Acts::ProtoAxis vpabRead = Acts::ProtoAxisJsonConverter::fromJson(jProtoAxis); | ||
|
||
BOOST_CHECK_EQUAL(vpabRead.getAxisDirection(), vpab.getAxisDirection()); | ||
BOOST_CHECK_EQUAL(vpabRead.getAxis(), vpab.getAxis()); | ||
BOOST_CHECK_EQUAL(vpabRead.isAutorange(), vpab.isAutorange()); | ||
BOOST_CHECK_EQUAL(vpabRead.toString(), vpab.toString()); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(InvalidAndValidInputJson) { | ||
// valid eq axis input | ||
nlohmann::json jValidEqAxis = {{"bins", 10}, | ||
{"boundary_type", "Bound"}, | ||
{"range", std::array<double, 2>{0.0, 1.0}}, | ||
{"type", "Equidistant"}}; | ||
|
||
// Valid input first | ||
nlohmann::json jValidEq = { | ||
{"axis", jValidEqAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
|
||
BOOST_CHECK_NO_THROW(Acts::ProtoAxisJsonConverter::fromJson(jValidEq)); | ||
|
||
// Invalid input - zero bins | ||
nlohmann::json jInvalidEqAxis = jValidEqAxis; | ||
jInvalidEqAxis["bins"] = 0; | ||
|
||
nlohmann::json jInvalidEq = { | ||
{"axis", jInvalidEqAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
|
||
BOOST_CHECK_THROW(Acts::ProtoAxisJsonConverter::fromJson(jInvalidEq), | ||
std::invalid_argument); | ||
|
||
// Invalid input - auto range without bins | ||
jInvalidEq = { | ||
{"axis", jInvalidEqAxis}, {"axis_dir", "AxisX"}, {"autorange", true}}; | ||
BOOST_CHECK_THROW(Acts::ProtoAxisJsonConverter::fromJson(jInvalidEq), | ||
std::invalid_argument); | ||
|
||
// Invalid input - min >= max | ||
jInvalidEqAxis = jValidEqAxis; | ||
jInvalidEqAxis["range"] = std::array<double, 2>{1.0, 0.0}; | ||
|
||
jInvalidEq = { | ||
{"axis", jInvalidEqAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
|
||
BOOST_CHECK_THROW(Acts::ProtoAxisJsonConverter::fromJson(jInvalidEq), | ||
std::invalid_argument); | ||
|
||
nlohmann::json jValidVarAxis = { | ||
{"boundary_type", "Bound"}, | ||
{"boundaries", std::vector<double>{0.0, 0.25, 0.75, 1.0}}, | ||
{"type", "Variable"}}; | ||
|
||
// Valid input first | ||
nlohmann::json jValidVar = { | ||
{"axis", jValidVarAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
BOOST_CHECK_NO_THROW(Acts::ProtoAxisJsonConverter::fromJson(jValidVar)); | ||
|
||
// Invalid input - less than two edges | ||
nlohmann::json jInvalidVarAxis = jValidVarAxis; | ||
jInvalidVarAxis["boundaries"] = std::vector<double>{0.0}; | ||
|
||
nlohmann::json jInvalidVar = { | ||
{"axis", jInvalidVarAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
BOOST_CHECK_THROW(Acts::ProtoAxisJsonConverter::fromJson(jInvalidVar), | ||
std::invalid_argument); | ||
|
||
// Invalid input - non-increasing edges | ||
jInvalidVarAxis = jValidVarAxis; | ||
jInvalidVarAxis["boundaries"] = std::vector<double>{0.0, 0.75, 0.25, 1.0}; | ||
|
||
jInvalidVar = { | ||
{"axis", jInvalidVarAxis}, {"axis_dir", "AxisX"}, {"autorange", false}}; | ||
|
||
BOOST_CHECK_THROW(Acts::ProtoAxisJsonConverter::fromJson(jInvalidVar), | ||
std::invalid_argument); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |