diff --git a/.gitignore b/.gitignore index fc6f72e2355847d30f07b61dddbd8fcd335bc342..f87582a8dbebcfc9f9c5b2aaf646b5ca737d4d29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ +__pycache__ +.devcontainer .dll +.env +.pytest_cache .so +.venv .vscode -.pytest_cache -__pycache__ -generator.log -*.orig *.bkp -.devcontainer \ No newline at end of file +*.orig +build +deps +generator.log +MODULE.* diff --git a/NOTICE.md b/NOTICE.md index 812ea2b8495990a7992c6ab61414b6853340f264..c623d498457ee69dac7734cc1dc381ea634e7644 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -78,6 +78,12 @@ Yase units_nhh * License: MIT +nlohmann (JSON for Modern C++) + * License: MIT License + * Homepage: https://nlohmann.github.io/json/ + * Repository: https://github.com/nlohmann/json + * Version: 3.9.1 + MantleAPI * License: EPL 2.0 diff --git a/README.md b/README.md index c4eebab56e737b841c2557daf6c18b8996a938a4..79ebdf6cbfd0adcef63c5b3359e04f9b4b2324d7 100644 --- a/README.md +++ b/README.md @@ -251,17 +251,29 @@ Converts `NET_ASAM_OPENSCENARIO::v1_3::ITrajectoryRef` object type to [mantle_ap Converts `NET_ASAM_OPENSCENARIO::v1_3::ITransitionDynamics` object type to [mantle_api::TransitionDynamics](https://gitlab.eclipse.org/eclipse/openpass/mantle-api/-/blob/master/include/MantleAPI/Traffic/control_strategy.h) **Note**: Right now the property `followingMode` is not considered. +# Customizations w.r.t ASAM OpenSCENARIO Standard + +## Property Parsing + +The OpenSCENARIO standard does not impose strict requirements on the format of custom properties, allowing for flexibility in their definition. +To facilitate this, the OpenScenarioEngine uses JSON to parse string-type properties into an internal object format. +This approach enables the definition of complex properties, such as distributions, which can be used within actions. +For example, a velocity distribution might be defined and used in a `TrafficAreaAction`. + +For more information on how to define these properties, refer to the documentation an provided schemas in [doc/json_properties](./doc/json_properties). + # Dependencies | Dependency | Commit | Version | License | | ---------- | ------ | ------- | ------- | +| [CPM](https://github.com/cpm-cmake/CPM.cmake) | 03705fc | 0.36.0 | MIT License | +| [googletest](https://github.com/google/googletest) | f8d7d77 | 1.14.0 | BSD-3-Clause License | +| [JSON for Modern C++](https://github.com/nlohmann/json) | db78ac1 | 3.9.1 | MIT License | | [MantleAPI](https://gitlab.eclipse.org/eclipse/openpass/mantle-api) | 5541bf1a | 14.0.0 | EPL 2.0 | +| [openpass/stochastics-library](https://gitlab.eclipse.org/eclipse/openpass/stochastics-library) | 6c9dde71 | 0.11.0 | EPL 2.0 | | [OpenSCENARIO API](https://github.com/RA-Consulting-GmbH/openscenario.api.test/) | 5980e88 | 1.4.0 | Apache 2.0 | -| [YASE](https://gitlab.eclipse.org/eclipse/openpass/yase) | d0c0e58d | | EPL 2.0 | | [Units](https://github.com/nholthaus/units) | e27eed9 | 2.3.4 | MIT License | -| [googletest](https://github.com/google/googletest) | f8d7d77 | 1.14.0 | BSD-3-Clause License | -| [CPM](https://github.com/cpm-cmake/CPM.cmake) | 03705fc | 0.36.0 | MIT License | -| [openpass/stochastics-library](https://gitlab.eclipse.org/eclipse/openpass/stochastics-library) | 6c9dde71 | 0.11.0 | EPL 2.0 | +| [YASE](https://gitlab.eclipse.org/eclipse/openpass/yase) | d0c0e58d | | EPL 2.0 | # Issues diff --git a/doc/json_properties/exponential_distribution.json b/doc/json_properties/exponential_distribution.json new file mode 100644 index 0000000000000000000000000000000000000000..1d294b3804a8a4dd95588b3308e67969c7936198 --- /dev/null +++ b/doc/json_properties/exponential_distribution.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExponentialDistribution", + "type": "object", + "properties": { + "lowerLimit": { + "type": "number", + "description": "Lower limit" + }, + "upperLimit": { + "type": "number", + "description": "Upper limit" + }, + "expectedValue": { + "type": "number", + "description": "Reciprocal of the rate parameter lambda" + } + }, + "required": ["lowerLimit", "upperLimit", "expectedValue"] +} \ No newline at end of file diff --git a/doc/json_properties/gamma_distribution.json b/doc/json_properties/gamma_distribution.json new file mode 100644 index 0000000000000000000000000000000000000000..479cb799d5d330b5df429f41d009083c1eb25ed4 --- /dev/null +++ b/doc/json_properties/gamma_distribution.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "GammaDistribution", + "type": "object", + "properties": { + "lowerLimit": { + "type": "number", + "description": "Lower limit", + "minimum": 0.0 + }, + "upperLimit": { + "type": "number", + "description": "Upper limit", + "minimum": 0.0 + }, + "expectedValue": { + "type": "number", + "description": "Expected value (mean) of the distribution, calculated as alpha / beta", + "minimum": 0.0 + }, + "variance": { + "type": "number", + "description": "Variance of the distribution, calculated as alpha / beta^2", + "minimum": 0.0 + } + }, + "required": ["lowerLimit", "upperLimit", "expectedValue", "variance"] +} \ No newline at end of file diff --git a/doc/json_properties/lognormal_distribution.json b/doc/json_properties/lognormal_distribution.json new file mode 100644 index 0000000000000000000000000000000000000000..1d294b3804a8a4dd95588b3308e67969c7936198 --- /dev/null +++ b/doc/json_properties/lognormal_distribution.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExponentialDistribution", + "type": "object", + "properties": { + "lowerLimit": { + "type": "number", + "description": "Lower limit" + }, + "upperLimit": { + "type": "number", + "description": "Upper limit" + }, + "expectedValue": { + "type": "number", + "description": "Reciprocal of the rate parameter lambda" + } + }, + "required": ["lowerLimit", "upperLimit", "expectedValue"] +} \ No newline at end of file diff --git a/doc/json_properties/normal_distrubution.json b/doc/json_properties/normal_distrubution.json new file mode 100644 index 0000000000000000000000000000000000000000..3021ae8e4df0ccd86bc1f7e027bd4fbd8f6aae36 --- /dev/null +++ b/doc/json_properties/normal_distrubution.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "NormalDistribution", + "type": "object", + "properties": { + "lowerLimit": { + "type": "number", + "description": "Lower limit", + "minimum": 0.0 + }, + "upperLimit": { + "type": "number", + "description": "Upper limit", + "minimum": 0.0 + }, + "expectedValue": { + "type": "number", + "description": "Expected value", + "minimum": 0.0 + }, + "variance": { + "type": "number", + "description": "Variance (square of standard deviation)", + "minimum": 0.0 + } + }, + "required": ["lowerLimit", "upperLimit", "expectedValue", "variance"] +} \ No newline at end of file diff --git a/doc/json_properties/readme.md b/doc/json_properties/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..6e9be80b292b999c99babe3b973addd24e764024 --- /dev/null +++ b/doc/json_properties/readme.md @@ -0,0 +1,40 @@ +# JSON Property Strings + +The OpenSCENARIO standard does not impose strict requirements on the format of custom properties, allowing for flexibility in their definition. +To facilitate this, the OpenScenarioEngine uses JSON to parse string-type properties into an internal object format. +This approach enables the definition of complex properties, such as distributions, which can be used within actions. +For example, a velocity distribution might be defined and used in a `TrafficAreaAction`. + +This folder contains JSON schemas for property strings used by the **OpenScenarioEngine**. +While these schemas are not enforced, they serve as a reference for how to properly define properties, such as distributions, in a way that they are correctly parsed. + +## General Usage + +```xml + <Property name="SomeProp" value="{ 'type': 'InterpretableType', 'value': 'InterpretableString'" /> +``` + +## Available Distribution Types + +- [ExponentialDistribution](./exponential_distribution.json) +- [ǸormalDistribution](./normal_distribution.json) +- [GammaDistribution](./gamma_distribution.json) +- [LogNormalDistribution](./lognormal_distribution.json) +- [UniformDistribution](./uniform_distribution.json) + +**Example** + +```xml + <Property + name="velocity" + value="{ + 'type': 'NormalDistribution', + 'value': + { + 'lowerLimit': 19.265, + 'upperLimit': 43.685, + 'expectedValue': 31.475, + 'variance': 37.271025 + } + }" /> +``` diff --git a/doc/json_properties/uniform_distribution.json b/doc/json_properties/uniform_distribution.json new file mode 100644 index 0000000000000000000000000000000000000000..1532d5e29bd2d66f9669b75510632687cc2574f9 --- /dev/null +++ b/doc/json_properties/uniform_distribution.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "UniformDistribution", + "type": "object", + "properties": { + "lowerLimit": { + "type": "number", + "description": "Lower limit", + "minimum": 0.0 + }, + "upperLimit": { + "type": "number", + "description": "Upper limit", + "minimum": 0.0 + } + }, + "required": ["lowerLimit", "upperLimit"] +} \ No newline at end of file diff --git a/engine/.gitignore b/engine/.gitignore index 193cf2701b37526f5038785366ad7fa9ef81e512..f3febcbe90eae591aecd37cb396dffba711ee955 100644 --- a/engine/.gitignore +++ b/engine/.gitignore @@ -4,3 +4,4 @@ build bin bazel-* +external diff --git a/engine/BUILD.bazel b/engine/BUILD.bazel index cbc396a17cf882360e9f72672fcad7fd57c626e9..b3f3450b48b16ffebdf936210318161a8f712e6a 100644 --- a/engine/BUILD.bazel +++ b/engine/BUILD.bazel @@ -28,6 +28,7 @@ cc_library( ], visibility = ["//visibility:public"], deps = [ + "@//third_party/nlohmann_json", "@mantle_api", "@open_scenario_parser", "@stochastics_library", @@ -178,9 +179,10 @@ cc_test( data = [":open_scenario_engine_test_data"], tags = ["test"], deps = [ - ":test_utils", ":open_scenario_engine", ":open_scenario_engine_test_utils", + ":test_utils", + "@//third_party/nlohmann_json", "@googletest//:gtest_main", "@mantle_api//:test_utils", ], diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 72cdb526066e9a2acdf6761fd0c7abbdf8132bf3..74ad6e9656f6f7b393b939cba894f7b0d566e291 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -23,11 +23,11 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -# YASE -find_package(Yase REQUIRED) - -# units https://github.com/nholthaus/units (dependency of MantleAPI) +find_package(MantleAPI REQUIRED) +find_package(nlohmann_json REQUIRED) +find_package(Stochastics REQUIRED) find_package(units REQUIRED) +find_package(Yase REQUIRED) # googlemock include(CPM) @@ -39,12 +39,6 @@ CPMAddPackage( OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt ON" ) -# MantleAPI https://gitlab.eclipse.org/eclipse/simopenpass/scenario_api -find_package(MantleAPI REQUIRED) - - -find_package(Stochastics REQUIRED) - # see https://stackoverflow.com/a/58495612 set(CMAKE_INSTALL_RPATH $ORIGIN) @@ -70,12 +64,17 @@ target_include_directories( $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include> ) -target_link_libraries(${PROJECT_NAME} PUBLIC openscenario_api::shared - antlr4_runtime::shared - Yase::agnostic_behavior_tree - units::units - MantleAPI::MantleAPI - PRIVATE Stochastics::Stochastics) +target_link_libraries(${PROJECT_NAME} + PUBLIC + antlr4_runtime::shared + MantleAPI::MantleAPI + units::units + openscenario_api::shared + PRIVATE + nlohmann_json::nlohmann_json + Stochastics::Stochastics + Yase::agnostic_behavior_tree +) if(USE_CCACHE) find_program(CCACHE_FOUND ccache) @@ -224,9 +223,12 @@ target_sources( ${CMAKE_CURRENT_LIST_DIR}/tests/TrafficSignalParsing/TreeGenerationTest.cpp ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/ConstantsTest.cpp ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/ControllerCreatorTest.cpp + ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/DistributionTest.cpp ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/EllipseTest.cpp ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/EntityCreatorTest.cpp ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/EntityUtilsTest.cpp + ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/JsonParsingTest.cpp + ${CMAKE_CURRENT_LIST_DIR}/tests/Utils/PropertyInterpreterTest.cpp ) add_custom_command(TARGET ${PROJECT_NAME}Test @@ -250,11 +252,14 @@ target_include_directories( target_link_libraries( ${PROJECT_NAME}Test - PRIVATE ${PROJECT_NAME} - Stochastics::Stochastics - antlr4_runtime::shared - GTest::gmock_main - pthread + PRIVATE + ${PROJECT_NAME} + antlr4_runtime::shared + GTest::gmock_main + nlohmann_json::nlohmann_json + pthread + Stochastics::Stochastics + Yase::agnostic_behavior_tree ) add_test(NAME ${PROJECT_NAME}Test COMMAND ${PROJECT_NAME}Test) diff --git a/engine/WORKSPACE b/engine/WORKSPACE index 91062dc5d72b33746b7bffd6b379bac978ff168f..5622781fa20638e25e6480b7cc104a0ecc8967c4 100644 --- a/engine/WORKSPACE +++ b/engine/WORKSPACE @@ -1,13 +1,5 @@ workspace(name = "open_scenario_engine") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("//third_party:deps.bzl", "osc_engine_deps") +load("//third_party:dependencies.bzl", "third_party_deps") -http_archive( - name = "googletest", - sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2", - strip_prefix = "googletest-release-1.12.1", - url = "https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz", -) - -osc_engine_deps() +third_party_deps() diff --git a/engine/cmake/generated_files.cmake b/engine/cmake/generated_files.cmake index 6644cd17f76486878a73b74112c053f759d08b2b..be6db1011e9ef42c114525cbe3f664527f5be9cb 100644 --- a/engine/cmake/generated_files.cmake +++ b/engine/cmake/generated_files.cmake @@ -242,6 +242,9 @@ list(APPEND ${PROJECT_NAME}_SOURCES src/Utils/EntityUtils.cpp src/Utils/EventPrioritizer.cpp src/Utils/Logger.cpp + src/Utils/PropertyInterpretation/DistributionInterpreter.cpp + src/Utils/PropertyInterpreter.cpp + src/Utils/JsonParsing.cpp src/Utils/TrafficSignalBuilder.cpp ) @@ -610,5 +613,17 @@ list(APPEND ${PROJECT_NAME}_HEADERS src/Utils/IControllerService.h src/Utils/IEventPrioritizer.h src/Utils/Logger.h + src/Utils/PropertyInterpretation/DistributionInterpreter.h + src/Utils/PropertyInterpretation/Distributions.h + src/Utils/PropertyInterpretation/Distributions/ExponentialDistribution.h + src/Utils/PropertyInterpretation/Distributions/GammaDistribution.h + src/Utils/PropertyInterpretation/Distributions/LogNormalDistribution.h + src/Utils/PropertyInterpretation/Distributions/NormalDistribution.h + src/Utils/PropertyInterpretation/Distributions/UniformDistribution.h + src/Utils/PropertyInterpretation/Interpreter.h + src/Utils/PropertyInterpretation/JsonInterpreter.h + src/Utils/PropertyInterpretation/RawValueRelay.h + src/Utils/PropertyInterpreter.h + src/Utils/JsonParsing.h src/Utils/TrafficSignalBuilder.h ) diff --git a/engine/src/Utils/JsonParsing.cpp b/engine/src/Utils/JsonParsing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc26d3b5dd6a9e7eb92429a6315ce0f21be7fd64 --- /dev/null +++ b/engine/src/Utils/JsonParsing.cpp @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#include "JsonParsing.h" + +#include <regex> + +namespace OpenScenarioEngine::v1_3 +{ + +namespace detail +{ + +/// Replace all occurrences of a string in a string +/// @param input String to search in +/// @param search String to search for +/// @param replace String to replace with +/// @return String with all occurrences of search replaced with replace +std::string Replace(std::string_view input, const std::string& search, const std::string& replace) +{ + std::regex search_regex(search); + return std::regex_replace(std::string(input), search_regex, replace); +} + +} // namespace detail + +namespace json +{ + +std::optional<nlohmann::json> TryParse(std::string_view property) +{ + if (auto j = nlohmann::json::parse(std::string(property), nullptr, false); + !j.is_discarded()) + { + return j; + } + + using namespace std::string_literals; + for (const std::string& search : {"""s, "'"s}) + { + const auto modified_property = detail::Replace(property, search, "\""); + if (auto j = nlohmann::json::parse(modified_property, nullptr, false); + !j.is_discarded()) + { + return j; + } + } + + return std::nullopt; +} + +} // namespace json +} // namespace OpenScenarioEngine::v1_3 diff --git a/engine/src/Utils/JsonParsing.h b/engine/src/Utils/JsonParsing.h new file mode 100644 index 0000000000000000000000000000000000000000..99435d4e2e01455ccc7fd8de1cb8fd881fa56382 --- /dev/null +++ b/engine/src/Utils/JsonParsing.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> +#include <optional> +#include <regex> +#include <string> +#include <string_view> + +#include "Utils/Logger.h" + +namespace OpenScenarioEngine::v1_3 +{ + +namespace json +{ + +/// Try to parse a JSON object from a string +/// +/// In a first attempt, this function tries to parse the string as it is. +/// But as the main use case for the parser is interpreting XML properties +/// as JSON objects and the JSON standard requires double quotes for strings, +/// the XML parser will try to escape double quotes in the XML file using " +/// or try with single quotes (not JSON standard, but we support it). +/// @param value Value to be parsed +/// @return Parsed JSON object or nullopt if parsing failed +std::optional<nlohmann::json> TryParse(std::string_view value); + +/// Deserialize a string into a object using nlohmann::json +/// @tparam DeserializedType Type of the object to deserialize (e.g. a distribution) +/// @param value String to deserialize +/// @return Deserialized object of type T or empty optional if deserialization failed +template <typename DeserializedType> +std::optional<DeserializedType> Deserialize(std::string_view value) +{ + try + { + if (auto j = TryParse(value)) + { + return j->get<DeserializedType>(); + } + Logger::Error("JsonParser: \'" + std::string(value) + "' is not a valid JSON object"); + } + catch (const nlohmann::json::out_of_range&) + { + Logger::Error("JsonParser: \'" + std::string(value) + "' JSON object does not match expected object"); + } + + return std::nullopt; +} + +} // namespace json + +} // namespace OpenScenarioEngine::v1_3 diff --git a/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.cpp b/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..479a44cc6217ccfaee1128788eac7632774e397c --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.cpp @@ -0,0 +1,65 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#include "DistributionInterpreter.h" + +#include <Stochastics/StochasticsInterface.h> + +#include <algorithm> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +double sample(StochasticsInterface &stochastics, const ExponentialDistribution &distribution) +{ + return std::clamp( + stochastics.GetExponentialDistributed( + distribution.expectedValue != 0.0 ? 1.0 / distribution.expectedValue : 0.0), + distribution.lowerLimit, + distribution.upperLimit); +} + +double sample(StochasticsInterface &stochastics, const GammaDistribution &distribution) +{ + return std::clamp( + stochastics.GetGammaDistributed( + distribution.expectedValue, std::sqrt(std::abs(distribution.variance))), + distribution.lowerLimit, + distribution.upperLimit); +} + +double sample(StochasticsInterface &stochastics, const LogNormalDistribution &distribution) +{ + return std::clamp( + stochastics.GetLogNormalDistributed( + distribution.expectedValue, std::sqrt(std::abs(distribution.variance))), + distribution.lowerLimit, + distribution.upperLimit); +} + +double sample(StochasticsInterface &stochastics, const NormalDistribution &distribution) +{ + return std::clamp( + stochastics.GetNormalDistributed( + distribution.expectedValue, std::sqrt(std::abs(distribution.variance))), + distribution.lowerLimit, + distribution.upperLimit); +} + +double sample(StochasticsInterface &stochastics, const UniformDistribution &distribution) +{ + return std::clamp( + stochastics.GetUniformDistributed( + distribution.lowerLimit, distribution.upperLimit), + distribution.lowerLimit, + distribution.upperLimit); +} + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation \ No newline at end of file diff --git a/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.h b/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.h new file mode 100644 index 0000000000000000000000000000000000000000..7b16b8361a5e0bbe960c22c895e72718c0494ca3 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/DistributionInterpreter.h @@ -0,0 +1,104 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#pragma once + +#include "Utils/Logger.h" +#include "Utils/PropertyInterpretation/Distributions.h" +#include "Utils/PropertyInterpretation/JsonInterpreter.h" + +class StochasticsInterface; + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Sample from an exponential distribution +/// @param stochastics Stochastics interface +/// @param distribution Definition of the distribution +/// @return sampled value +double sample(StochasticsInterface &stochastics, const ExponentialDistribution &distribution); + +/// Sample from a gamma distribution +/// @param stochastics Stochastics interface +/// @param distribution Definition of the distribution +/// @return sampled value +double sample(StochasticsInterface &stochastics, const GammaDistribution &distribution); + +/// Sample from a log normal distribution +/// @param stochastics Stochastics interface +/// @param distribution Definition of the distribution +/// @return sampled value +double sample(StochasticsInterface &stochastics, const LogNormalDistribution &distribution); + +/// Sample from a normal distribution +/// @param stochastics Stochastics interface +/// @param distribution Definition of the distribution +/// @return sampled value +double sample(StochasticsInterface &stochastics, const NormalDistribution &distribution); + +/// Sample from a uniform distribution +/// @param stochastics Stochastics interface +/// @param distribution Definition of the distribution +/// @return sampled value +double sample(StochasticsInterface &stochastics, const UniformDistribution &distribution); + +/// Interpreter for distributions +/// @tparam Distribution Wrapped distribution type +template <typename Distribution> +struct DistributionInterpreter : public JsonInterpreter<Distribution> +{ + using JsonInterpreter<Distribution>::value_; ///!< Internal representation + + /// Binds Interpreter to stochastics interface + /// @param stochastics Stochastics interface + constexpr DistributionInterpreter(StochasticsInterface &stochastics) noexcept + : stochastics_{stochastics} + { + } + + /// Sample from the distribution + /// @return string interpretation of the internal representation, empty if json interpretation failed + std::string to_string() + { + if (value_) + { + return std::to_string(sample(stochastics_, *value_)); + } + Logger::Error("DistributionInterpreter: No distribution value available."); + return ""; + } + + StochasticsInterface &stochastics_; +}; + +/// Interpret a json object using a custom interpreter +/// @note Specialize for custom behavor +/// @tparam T Type of the interpreter +/// @tparam Payload Type of the payload +/// @param interpreter Interpreter to interpret the payload +/// @param payload Payload to interpret +template <typename T, typename Payload> +void interpret(DistributionInterpreter<T> &interpreter, const Payload &payload) +{ + interpreter.interpret(payload); +} + +/// Convert internal representation to string +/// @note Specialize for custom behavor +/// @tparam T Type of the interpreter +/// @param interpreter Interpreter to convert to string +/// @return string interpretation of the internal representation +template <typename T> +std::string to_string(DistributionInterpreter<T> &interpreter) +{ + return interpreter.to_string(); +} + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation \ No newline at end of file diff --git a/engine/src/Utils/PropertyInterpretation/Distributions.h b/engine/src/Utils/PropertyInterpretation/Distributions.h new file mode 100644 index 0000000000000000000000000000000000000000..c4919f77944624ec0e3a0d03830fb54a85e8e918 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions.h @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include "Distributions/ExponentialDistribution.h" +#include "Distributions/GammaDistribution.h" +#include "Distributions/LogNormalDistribution.h" +#include "Distributions/NormalDistribution.h" +#include "Distributions/UniformDistribution.h" diff --git a/engine/src/Utils/PropertyInterpretation/Distributions/ExponentialDistribution.h b/engine/src/Utils/PropertyInterpretation/Distributions/ExponentialDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..7605671fca9d935e08424c371f132ccdd08b6cb0 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions/ExponentialDistribution.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Exponential distribution +struct ExponentialDistribution +{ + double lowerLimit; ///!< Lower limit + double upperLimit; ///!< Upper limit + double expectedValue; ///!< Reciprocal of the rate parameter lambda +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ExponentialDistribution, + lowerLimit, + upperLimit, + expectedValue); + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation diff --git a/engine/src/Utils/PropertyInterpretation/Distributions/GammaDistribution.h b/engine/src/Utils/PropertyInterpretation/Distributions/GammaDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..1e382fe7fa405eeecc94cc325bb82677cad9ee3a --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions/GammaDistribution.h @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Gamma distribution +/// +/// The gamma distribution is a two-parameter family of continuous probability distributions. +/// It is characterized by a shape parameter (alpha) and a rate parameter (beta). +/// The expected value and variance of the gamma distribution are related to these parameters as follows: +/// - Expected Value = alpha / beta +/// - Variance = alpha / beta^2 +struct GammaDistribution +{ + double lowerLimit; ///!< Lower limit + double upperLimit; ///!< Upper limit + double expectedValue; ///!< Expected value (mean) of the distribution, calculated as alpha / beta + double variance; ///!< Variance of the distribution, calculated as alpha / beta^2 +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GammaDistribution, + lowerLimit, + upperLimit, + expectedValue, + variance); + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation diff --git a/engine/src/Utils/PropertyInterpretation/Distributions/LogNormalDistribution.h b/engine/src/Utils/PropertyInterpretation/Distributions/LogNormalDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..ba2397ae5f5833ee116bcbc02b080f12f6e48655 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions/LogNormalDistribution.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// LogNormalDistribution +struct LogNormalDistribution +{ + double lowerLimit; ///!< Lower limit + double upperLimit; ///!< Upper limit + double expectedValue; ///!< Expected value + double variance; ///!< Variance (square of standard deviation) +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LogNormalDistribution, + lowerLimit, + upperLimit, + expectedValue, + variance); + +} // namespace OpenScenarioEngine::v1_3 \ No newline at end of file diff --git a/engine/src/Utils/PropertyInterpretation/Distributions/NormalDistribution.h b/engine/src/Utils/PropertyInterpretation/Distributions/NormalDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..d2a572f42b729b2a262b7fc4e60a833292156aed --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions/NormalDistribution.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Normal distribution +struct NormalDistribution +{ + double lowerLimit; ///!< Lower limit + double upperLimit; ///!< Upper limit + double expectedValue; ///!< Expected value + double variance; ///!< Variance (square of standard deviation) +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NormalDistribution, + lowerLimit, + upperLimit, + expectedValue, + variance); + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation diff --git a/engine/src/Utils/PropertyInterpretation/Distributions/UniformDistribution.h b/engine/src/Utils/PropertyInterpretation/Distributions/UniformDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..05b4b14582ff2b1146a1156ffc638203d0423afe --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Distributions/UniformDistribution.h @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Uniform distribution +struct UniformDistribution +{ + double lowerLimit; ///!< Lower limit + double upperLimit; ///!< Upper limit +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(UniformDistribution, + lowerLimit, + upperLimit); + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation diff --git a/engine/src/Utils/PropertyInterpretation/Interpreter.h b/engine/src/Utils/PropertyInterpretation/Interpreter.h new file mode 100644 index 0000000000000000000000000000000000000000..0df771c44ac3bfa069099df320a28e59cd029823 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/Interpreter.h @@ -0,0 +1,123 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#pragma once + +#include <map> +#include <memory> +#include <nlohmann/json.hpp> +#include <string> +#include <utility> +#include <vector> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Type-erased base for custom interpreter +class Interpreter +{ + /// Concept for custom interpreter + struct InterpreterConcept + { + /// Destructor + virtual ~InterpreterConcept() {} + + /// Interpret json object and hide internal representation + /// @param j json object to interpret + virtual void do_interpret(const nlohmann::json &j) = 0; + + /// Convert internal representation to string + virtual std::string do_to_string() = 0; + + /// Clone the interpreter + virtual std::unique_ptr<InterpreterConcept> clone() const = 0; + }; + + /// Model for custom interpreter + /// @tparam InterpreterT Actual interpreter type which shall be type-erased + template <typename InterpreterT> + struct InterpreterModel : public InterpreterConcept + { + InterpreterModel(InterpreterT interpreter) + : interpreter_{std::move(interpreter)} + { + } + + std::unique_ptr<InterpreterConcept> clone() const override + { + return std::make_unique<InterpreterModel>(*this); + } + + /// Relay to free function parse, which must be implemented for each custom interpreter + /// @param j json object to interpret + void do_interpret(const nlohmann::json &j) override + { + interpret(interpreter_, j); + } + + /// Relay to free function to_string, which must be implemented for each custom interpreter + /// @return string interpretation of the internal representation + std::string do_to_string() override + { + return to_string(interpreter_); + } + + InterpreterT interpreter_; ///!< Actual interpreter + }; + + /// Free function to interpret json object (injects interpret into the base class) + /// @param interpreter interpreter to interpret the json object + /// @param j json object to interpret + friend void interpret(Interpreter &interpreter, const nlohmann::json &j) + { + interpreter.pimpl_->do_interpret(j); + } + + /// Free function to convert internal representation to string (injects to_string into the base class) + /// @param interpreter interpreter used to convert to string + /// @return string interpretation of the internal representation + friend std::string to_string(Interpreter &interpreter) + { + return interpreter.pimpl_->do_to_string(); + } + + std::unique_ptr<InterpreterConcept> pimpl_; ///!< Type-erased interpreter + +public: + /// Constructor to create a type erased custom interpreter + /// @tparam InterpreterT Actual interpreter type + /// @param interpreter Actual interpreter + template <typename InterpreterT> + Interpreter(InterpreterT interpreter) + : pimpl_{std::make_unique<InterpreterModel<InterpreterT>>(std::move(interpreter))} + { + } + + /// Copy constructor + /// @param other + Interpreter(const Interpreter &other) + : pimpl_{other.pimpl_->clone()} + { + } + + /// Copy assignment operator + /// @param other + /// @return New interpreter + Interpreter &operator=(const Interpreter &other) + { + other.pimpl_->clone().swap(pimpl_); + return *this; + } + + Interpreter(Interpreter &&) = default; ///!< Move constructor + Interpreter &operator=(Interpreter &&) = default; ///!< Move assignment operator +}; + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation diff --git a/engine/src/Utils/PropertyInterpretation/JsonInterpreter.h b/engine/src/Utils/PropertyInterpretation/JsonInterpreter.h new file mode 100644 index 0000000000000000000000000000000000000000..be2baa763b3e3bb194dc2d09cb55851fcc74e6b6 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/JsonInterpreter.h @@ -0,0 +1,43 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#pragma once + +#include <nlohmann/json.hpp> +#include <optional> +#include <string> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Interpreter for json objects +/// @tparam T Type for deserialization +template <typename T> +struct JsonInterpreter +{ + /// Interpret and store the json object + /// @note If the json object cannot be interpreted, the internal value will be std::nullopt + /// @param j json object to interpret + void interpret(const nlohmann::json &j) + { + try + { + value_ = j.get<T>(); + } + catch (const nlohmann::json::out_of_range &) + { + value_ = std::nullopt; + } + } + + std::optional<T> value_; +}; + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation \ No newline at end of file diff --git a/engine/src/Utils/PropertyInterpretation/RawValueRelay.h b/engine/src/Utils/PropertyInterpretation/RawValueRelay.h new file mode 100644 index 0000000000000000000000000000000000000000..26246b483fe72ab89b91c69fd8d0b311c0018656 --- /dev/null +++ b/engine/src/Utils/PropertyInterpretation/RawValueRelay.h @@ -0,0 +1,43 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#pragma once + +#include <string> +#include <utility> + +namespace OpenScenarioEngine::v1_3::PropertyInterpretation +{ + +/// Default interpreter if no custom interpreter is available or can be resolved +struct RawValueRelay +{ + std::string value_; +}; + +/// Void operation needed for type-erased interpreter stage +/// @tparam ...DontCare Catches all parameters, if any +/// @param raw_value_relay Actual intepreter +/// @param ... ignored +template <typename... DontCare> +void interpret(const RawValueRelay &raw_value_relay, DontCare...) +{ + std::ignore = raw_value_relay; +} + +/// Return the internal representation without doing anything +/// @param raw_value_relay Actual interpreter +/// @return stored string +std::string to_string(const RawValueRelay &raw_value_relay) +{ + return raw_value_relay.value_; +} + +} // namespace OpenScenarioEngine::v1_3::PropertyInterpretation \ No newline at end of file diff --git a/engine/src/Utils/PropertyInterpreter.cpp b/engine/src/Utils/PropertyInterpreter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4071c9124a7bce4a8a76500e1072b6c542ab1258 --- /dev/null +++ b/engine/src/Utils/PropertyInterpreter.cpp @@ -0,0 +1,71 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#include "PropertyInterpreter.h" + +#include <algorithm> + +#include "Utils/JsonParsing.h" +#include "Utils/PropertyInterpretation/DistributionInterpreter.h" +#include "Utils/PropertyInterpretation/RawValueRelay.h" + +namespace OpenScenarioEngine::v1_3 +{ + +using namespace PropertyInterpretation; + +namespace detail +{ +std::pair<std::string, nlohmann::json> GetTypeAndValue(const std::string &property_value) +{ + if (auto j = json::TryParse(property_value); + j.has_value() && j->contains("type") && j->contains("value")) + { + return {j->at("type").get<std::string>(), j->at("value")}; + } + return {"", nlohmann::json{}}; +} + +} // namespace detail + +void PropertyInterpreter::Init( + const std::map<std::string, std::string> &properties) +{ + interpreter_mapping_.clear(); + for (const auto &[property_key, property_value] : properties) + { + const auto [json_type, json_value] = detail::GetTypeAndValue(property_value); + + const auto interpreter_iter = interpreter_prototypes_.find(json_type); + auto [interpreter, _] = interpreter_mapping_.try_emplace( + property_key, + interpreter_iter != interpreter_prototypes_.end() + ? interpreter_iter->second + : RawValueRelay{property_value}); + interpret(interpreter->second, json_value); + } +} + +std::map<std::string, std::string> PropertyInterpreter::GenerateParameters( + const std::map<std::string, std::string> &key_replacements) +{ + std::map<std::string, std::string> parameters; + for (auto &[key, value] : interpreter_mapping_) + { + auto iter = key_replacements.find(key); + parameters.emplace(iter == std::end(key_replacements) + ? key + : iter->second, + to_string(value)); + } + return parameters; +} + +} // namespace OpenScenarioEngine::v1_3 diff --git a/engine/src/Utils/PropertyInterpreter.h b/engine/src/Utils/PropertyInterpreter.h new file mode 100644 index 0000000000000000000000000000000000000000..e115d6300746d94f2ed51abee4e8b3cb86cc0adc --- /dev/null +++ b/engine/src/Utils/PropertyInterpreter.h @@ -0,0 +1,55 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#pragma once + +#include <map> +#include <string> +#include <utility> + +#include "Utils/PropertyInterpretation/Interpreter.h" + +namespace OpenScenarioEngine::v1_3 +{ + +/// Utility class to interpret properties, e.g. custom json distribution definitions +/// +/// This class can take a map of properties and interpret them using custom interpreters. +/// Each property is interpreted by a custom interpreter based the value of the property. +/// If a json object is found, the "type" field is used to determine the interpreter. +/// In such a case, the "value" field is relayed to the interpreter for interpretation. +/// If no interpreter is found or the json has no field "type" and "value", the property +/// is treated as a raw value (= string). +class PropertyInterpreter +{ +public: + using Interpreters = std::map<std::string, PropertyInterpretation::Interpreter>; + + /// Constructor to create a property interpreter + /// @param interpreter_prototypes Prototypes for custom interpreters + PropertyInterpreter(Interpreters interpreter_prototypes) + : interpreter_prototypes_{std::move(interpreter_prototypes)} {} + + /// Initialize the property interpreter for a given set of properties + /// @param properties Properties to interpret + void Init(const std::map<std::string, std::string> &properties); + + /// Generate parameters from the interpreted properties, given at initialization + /// @note Might return different values at every call, e.g. for stochastic properties + /// @param key_replacements defines a mapping from original keys to new keys + /// @return interpreted parameter map + std::map<std::string, std::string> GenerateParameters( + const std::map<std::string, std::string> &key_replacements = {}); + +private: + Interpreters interpreter_prototypes_{}; ///!< Available custom interpreters + Interpreters interpreter_mapping_{}; ///!< Property to interpreter relation +}; +} // namespace OpenScenarioEngine::v1_3 diff --git a/engine/tests/Utils/DistributionTest.cpp b/engine/tests/Utils/DistributionTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51c4ce2bc8535ac23ae0bd926883bc3f77b6bf9b --- /dev/null +++ b/engine/tests/Utils/DistributionTest.cpp @@ -0,0 +1,160 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "TestUtils/MockStochastics.h" +#include "Utils/PropertyInterpretation/DistributionInterpreter.h" +#include "Utils/PropertyInterpretation/Distributions.h" + +using namespace OpenScenarioEngine::v1_3; +using namespace OpenScenarioEngine::v1_3::PropertyInterpretation; +using namespace testing; + +class DistributionTest : public Test +{ +protected: + MockStochastics stochastics; +}; + +struct DistributionTestParams +{ + double lowerLimit; + double upperLimit; + double sampledValue; + double expectedValue; +}; + +class ExponentialDistributionTest : public DistributionTest, public WithParamInterface<DistributionTestParams> +{ +}; + +TEST_P(ExponentialDistributionTest, GivenExponentialDistribution_WhenSampleIsCalled_ThenReturnsClampedValue) +{ + auto params = GetParam(); + ExponentialDistribution distribution{params.lowerLimit, params.upperLimit, 2.0}; + ON_CALL(stochastics, GetExponentialDistributed(1.0 / 2.0)) + .WillByDefault(Return(params.sampledValue)); + + double result = sample(stochastics, distribution); + + EXPECT_THAT(result, DoubleEq(params.expectedValue)); +} + +INSTANTIATE_TEST_SUITE_P( + ExponentialDistributionTests, + ExponentialDistributionTest, + ::testing::Values( + DistributionTestParams{0.0, 10.0, 5.0, 5.0}, // regular test + DistributionTestParams{0.0, 10.0, -1.0, 0.0}, // lowerLimit test + DistributionTestParams{0.0, 10.0, 15.0, 10.0}, // upperLimit test + DistributionTestParams{0.0, 10.0, 0.0, 0.0} // division by zero test for expectedValue + )); + +class GammaDistributionTest : public DistributionTest, public WithParamInterface<DistributionTestParams> +{ +}; + +TEST_P(GammaDistributionTest, GivenGammaDistribution_WhenSampleIsCalled_ThenReturnsClampedValue) +{ + auto params = GetParam(); + GammaDistribution distribution{params.lowerLimit, params.upperLimit, 2.0, 4.0}; + ON_CALL(stochastics, GetGammaDistributed(2.0, std::sqrt(4.0))) + .WillByDefault(Return(params.sampledValue)); + + double result = sample(stochastics, distribution); + + EXPECT_THAT(result, DoubleEq(params.expectedValue)); +} + +INSTANTIATE_TEST_SUITE_P( + GammaDistributionTests, + GammaDistributionTest, + ::testing::Values( + DistributionTestParams{0.0, 10.0, 5.0, 5.0}, // regular test + DistributionTestParams{0.0, 10.0, -1.0, 0.0}, // lowerLimit test + DistributionTestParams{0.0, 10.0, 15.0, 10.0} // upperLimit test + )); + +class LogNormalDistributionTest : public DistributionTest, public WithParamInterface<DistributionTestParams> +{ +}; + +TEST_P(LogNormalDistributionTest, GivenLogNormalDistribution_WhenSampleIsCalled_ThenReturnsClampedValue) +{ + auto params = GetParam(); + LogNormalDistribution distribution{params.lowerLimit, params.upperLimit, 2.0, 4.0}; + ON_CALL(stochastics, GetLogNormalDistributed(2.0, std::sqrt(4.0))) + .WillByDefault(Return(params.sampledValue)); + + double result = sample(stochastics, distribution); + + EXPECT_THAT(result, DoubleEq(params.expectedValue)); +} + +INSTANTIATE_TEST_SUITE_P( + LogNormalDistributionTests, + LogNormalDistributionTest, + ::testing::Values( + DistributionTestParams{0.0, 10.0, 5.0, 5.0}, // regular test + DistributionTestParams{0.0, 10.0, -1.0, 0.0}, // lowerLimit test + DistributionTestParams{0.0, 10.0, 15.0, 10.0} // upperLimit test + )); + +class NormalDistributionTest : public DistributionTest, public WithParamInterface<DistributionTestParams> +{ +}; + +TEST_P(NormalDistributionTest, GivenNormalDistribution_WhenSampleIsCalled_ThenReturnsClampedValue) +{ + auto params = GetParam(); + NormalDistribution distribution{params.lowerLimit, params.upperLimit, 2.0, 4.0}; + ON_CALL(stochastics, GetNormalDistributed(2.0, std::sqrt(4.0))) + .WillByDefault(Return(params.sampledValue)); + + double result = sample(stochastics, distribution); + + EXPECT_THAT(result, DoubleEq(params.expectedValue)); +} + +INSTANTIATE_TEST_SUITE_P( + NormalDistributionTests, + NormalDistributionTest, + ::testing::Values( + DistributionTestParams{0.0, 10.0, 5.0, 5.0}, // regular test + DistributionTestParams{0.0, 10.0, -1.0, 0.0}, // lowerLimit test + DistributionTestParams{0.0, 10.0, 15.0, 10.0} // upperLimit test + )); + +class UniformDistributionTest : public DistributionTest, public WithParamInterface<DistributionTestParams> +{ +}; + +TEST_P(UniformDistributionTest, GivenUniformDistribution_WhenSampleIsCalled_ThenReturnsClampedValue) +{ + auto params = GetParam(); + UniformDistribution distribution{params.lowerLimit, params.upperLimit}; + ON_CALL(stochastics, GetUniformDistributed(params.lowerLimit, params.upperLimit)) + .WillByDefault(Return(params.sampledValue)); + + double result = sample(stochastics, distribution); + + EXPECT_THAT(result, DoubleEq(params.expectedValue)); +} + +INSTANTIATE_TEST_SUITE_P( + UniformDistributionTests, + UniformDistributionTest, + ::testing::Values( + DistributionTestParams{0.0, 10.0, 5.0, 5.0}, // regular test + DistributionTestParams{0.0, 10.0, -1.0, 0.0}, // lowerLimit test + DistributionTestParams{0.0, 10.0, 15.0, 10.0} // upperLimit test + )); diff --git a/engine/tests/Utils/JsonParsingTest.cpp b/engine/tests/Utils/JsonParsingTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6287007017aceed8edda587d693a42c3f167dbf --- /dev/null +++ b/engine/tests/Utils/JsonParsingTest.cpp @@ -0,0 +1,80 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "Utils/JsonParsing.h" + +using testing::DoubleEq; +using testing::Eq; + +using namespace OpenScenarioEngine::v1_3; + +struct DeserializationTestType +{ + int a; + double b; + std::string c; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DeserializationTestType, a, b, c); + +TEST(JsonParsingTest, GivenPropertyString_WhenStringUsesDoubleQuotes_ThenReturnsObject) +{ + auto deserializationTestType = json::Deserialize<DeserializationTestType>( + R"({"a": 1, "b": 2.34, "c": "test"})"); + + ASSERT_TRUE(deserializationTestType.has_value()); + EXPECT_THAT(deserializationTestType->a, Eq(1)); + EXPECT_THAT(deserializationTestType->b, DoubleEq(2.34)); + EXPECT_THAT(deserializationTestType->c, Eq("test")); +} + +TEST(JsonParsingTest, GivenPropertyString_WhenStringUsesSingleQuotes_ThenReturnsObject) +{ + auto deserializationTestType = json::Deserialize<DeserializationTestType>( + R"({'a': 1, 'b': 2.34, 'c': 'test'})"); + + ASSERT_TRUE(deserializationTestType.has_value()); + EXPECT_THAT(deserializationTestType->a, Eq(1)); + EXPECT_THAT(deserializationTestType->b, DoubleEq(2.34)); + EXPECT_THAT(deserializationTestType->c, Eq("test")); +} + +TEST(JsonParsingTest, GivenPropertyString_WhenStringUsesExcapedXmlQuotes_ThenReturnsObject) +{ + auto deserializationTestType = json::Deserialize<DeserializationTestType>( + R"({"a": 1, "b": 2.34, "c": "test"})"); + + ASSERT_TRUE(deserializationTestType.has_value()); + EXPECT_THAT(deserializationTestType->a, Eq(1)); + EXPECT_THAT(deserializationTestType->b, DoubleEq(2.34)); + EXPECT_THAT(deserializationTestType->c, Eq("test")); +} + +TEST(JsonParsingTest, GivenPropertyStringWithMoreFieldsThanNeccessary_WhenParsed_ReturnsObject) +{ + auto deserializationTestType = json::Deserialize<DeserializationTestType>( + R"({"a": 1, "b": 2.34, "c": "test", "d": 4})"); + + ASSERT_TRUE(deserializationTestType.has_value()); + EXPECT_THAT(deserializationTestType->a, Eq(1)); + EXPECT_THAT(deserializationTestType->b, DoubleEq(2.34)); + EXPECT_THAT(deserializationTestType->c, Eq("test")); +} + +TEST(JsonParsingTest, GivenPropertyString_WhenStringIsInvalid_ThenReturnsEmpty) +{ + auto deserializationTestType = json::Deserialize<DeserializationTestType>( + R"({a: 1, b: 2.34, c: test})"); + + ASSERT_FALSE(deserializationTestType.has_value()); +} \ No newline at end of file diff --git a/engine/tests/Utils/PropertyInterpreterTest.cpp b/engine/tests/Utils/PropertyInterpreterTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f17a955f0a1bc697b9c2e1dd957cf6930645f9e2 --- /dev/null +++ b/engine/tests/Utils/PropertyInterpreterTest.cpp @@ -0,0 +1,165 @@ +/******************************************************************************** + * Copyright (c) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "TestUtils/MockStochastics.h" +#include "Utils/PropertyInterpretation/DistributionInterpreter.h" +#include "Utils/PropertyInterpretation/Distributions.h" +#include "Utils/PropertyInterpreter.h" + +using namespace OpenScenarioEngine::v1_3; +using namespace OpenScenarioEngine::v1_3::PropertyInterpretation; +using namespace testing; + +struct PropertyInterpreterTest : public Test +{ + void SetUp() override + { + ON_CALL(stochastics_, GetUniformDistributed(0, 1)).WillByDefault(Return(0.123)); + // mean = 2, stddev = 3 ==> sqrt(variance = 9) + ON_CALL(stochastics_, GetNormalDistributed(2, 3)).WillByDefault(Return(2.345)); + } + + PropertyInterpreter::Interpreters GetInterpreterPrototypes() + { + return { + {"UniformDistribution", DistributionInterpreter<UniformDistribution>{stochastics_}}, + {"NormalDistribution", DistributionInterpreter<NormalDistribution>{stochastics_}}}; + } + + NiceMock<MockStochastics> stochastics_; +}; + +TEST_F(PropertyInterpreterTest, GivenProperties_WhenCallingPropertyInterpreter_ThenInterpretsResults) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", R"({"type": "UniformDistribution", "value": {"lowerLimit": 0, "upperLimit": 1} })"}, + {"prop1", R"({"type": "NormalDistribution", "value": {"lowerLimit": 0, "upperLimit": 10, "expectedValue": 2, "variance": 9} })"}, + {"prop2", "RAW_PROPERTY"}}); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(3)); + EXPECT_EQ(result["prop0"], "0.123000"); + EXPECT_EQ(result["prop1"], "2.345000"); + EXPECT_EQ(result["prop2"], "RAW_PROPERTY"); +} + +TEST_F(PropertyInterpreterTest, GivenPropertiesWithExtendedFields_WhenCalled_ThenInterpretsValues) +{ + std::map<std::string, std::string> test_properties{ + {"extended", R"( + { + "filter": ["extra"], + "mapping": "custom_property", + "type": "UniformDistribution", + "value": {"lowerLimit": 0, "upperLimit": 1} + })"}}; + + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init(test_properties); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["extended"], "0.123000"); +} + +TEST_F(PropertyInterpreterTest, GivenPropertyWithoutType_WhenCallingPropertyInterpreter_ThenReturnsRawValue) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", R"({"value": {"lowerLimit": 0, "upperLimit": 1} })"}}); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["prop0"], R"({"value": {"lowerLimit": 0, "upperLimit": 1} })"); +} + +TEST_F(PropertyInterpreterTest, GivenPropertyWithoutValue_WhenCallingPropertyInterpreter_ThenReturnsRawValue) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", R"({"type": "UniformDistribution"})"}}); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["prop0"], R"({"type": "UniformDistribution"})"); +} + +TEST_F(PropertyInterpreterTest, GivenInvalidJson_WhenCallingPropertyInterpreter_ThenReturnsRawValue) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", "invalid_json"}}); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["prop0"], "invalid_json"); +} + +TEST_F(PropertyInterpreterTest, GivenUnsupportedType_WhenCallingPropertyInterpreter_ThenReturnsRawValue) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", R"({"type": "UnsupportedType", "value": {"lowerLimit": 0, "upperLimit": 1} })"}}); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["prop0"], R"({"type": "UnsupportedType", "value": {"lowerLimit": 0, "upperLimit": 1} })"); +} + +TEST_F(PropertyInterpreterTest, GivenEmptyProperties_WhenCallingPropertyInterpreter_ThenReturnsEmptyResult) +{ + std::map<std::string, std::string> properties_under_test{}; + + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init(properties_under_test); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::IsEmpty()); +} + +TEST_F(PropertyInterpreterTest, GivenKeyReplacements_WhenCallingPropertyInterpreter_ThenReturnsReplacedKeys) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + property_interpreter.Init( + {{"prop0", R"({"type": "UniformDistribution", "value": {"lowerLimit": 0, "upperLimit": 1} })"}}); + + std::map<std::string, std::string> key_replacements{{"prop0", "replaced_key"}}; + auto result = property_interpreter.GenerateParameters(key_replacements); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["replaced_key"], "0.123000"); +} + +TEST_F(PropertyInterpreterTest, GivenUninitializedInterpreter_WhenCallingGenerate_ThenDoesNothing) +{ + PropertyInterpreter property_interpreter(GetInterpreterPrototypes()); + auto result = property_interpreter.GenerateParameters(); + ASSERT_THAT(result, testing::IsEmpty()); +} + +TEST_F(PropertyInterpreterTest, GivenPropertyInterpreter_WhenCopied_ThenHoldsState) +{ + auto generateInterpreter = [](auto prototypes) -> PropertyInterpreter + { + PropertyInterpreter interpreter(prototypes); + interpreter.Init({{"prop0", "RAW_PROPERTY"}}); + return interpreter; + }; + + auto property_interpreter = generateInterpreter(GetInterpreterPrototypes()); + auto result = property_interpreter.GenerateParameters(); + + ASSERT_THAT(result, testing::SizeIs(1)); + EXPECT_EQ(result["prop0"], "RAW_PROPERTY"); +} \ No newline at end of file diff --git a/engine/third_party/dependencies.bzl b/engine/third_party/dependencies.bzl new file mode 100644 index 0000000000000000000000000000000000000000..180f0fdbc5f18c69fb7b3b522a4826708c049bff --- /dev/null +++ b/engine/third_party/dependencies.bzl @@ -0,0 +1,21 @@ +"""A module defining the third party dependencies for instantiating in WORKSPACE""" + +load("@open_scenario_engine//third_party/boost:boost.bzl", "boost_deps") +load("@open_scenario_engine//third_party/googletest:googletest.bzl", "googletest") +load("@open_scenario_engine//third_party/mantle_api:mantle_api.bzl", "mantle_api") +load("@open_scenario_engine//third_party/nlohmann_json:nlohmann_json.bzl", "nlohmann_json") +load("@open_scenario_engine//third_party/open_scenario_parser:open_scenario_parser.bzl", "open_scenario_parser") +load("@open_scenario_engine//third_party/stochastics_library:stochastics_library.bzl", "stochastics_library") +load("@open_scenario_engine//third_party/units:units.bzl", "units_nhh") +load("@open_scenario_engine//third_party/yase:yase.bzl", "yase") + +def third_party_deps(): + """Load dependencies""" + boost_deps() + googletest() + mantle_api() + nlohmann_json() + open_scenario_parser() + stochastics_library() + units_nhh() + yase() diff --git a/engine/third_party/deps.bzl b/engine/third_party/deps.bzl deleted file mode 100644 index 1f832f8a4118020d008720161d4fea8b2b7e8350..0000000000000000000000000000000000000000 --- a/engine/third_party/deps.bzl +++ /dev/null @@ -1,18 +0,0 @@ -load("@//third_party/boost:boost.bzl", "boost_deps") -load("@//third_party/mantle_api:mantle_api.bzl", "mantle_api") -load("@//third_party/open_scenario_parser:open_scenario_parser.bzl", "open_scenario_parser") -load("@//third_party/stochastics_library:stochastics_library.bzl", "stochastics_library") -load("@//third_party/units:units.bzl", "units_nhh") -load("@//third_party/yase:yase.bzl", "yase") - - - -def osc_engine_deps(): - """Load dependencies""" - boost_deps() - mantle_api() - open_scenario_parser() - stochastics_library() - units_nhh() - yase() - diff --git a/engine/third_party/googletest/BUILD.bazel b/engine/third_party/googletest/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..5219fee534cc6b3f5bcfaf335fabe5b75695f2e5 --- /dev/null +++ b/engine/third_party/googletest/BUILD.bazel @@ -0,0 +1,11 @@ +alias( + name = "googletest", + actual = "@googletest//:gtest", + visibility = ["//visibility:public"], +) + +alias( + name = "main", + actual = "@googletest//:gtest_main", + visibility = ["//visibility:public"], +) diff --git a/engine/third_party/googletest/gcc_printer_patch.patch b/engine/third_party/googletest/gcc_printer_patch.patch new file mode 100644 index 0000000000000000000000000000000000000000..a84e6ef6379e4fc65e73f95c0fec0cc9c1edeaf4 --- /dev/null +++ b/engine/third_party/googletest/gcc_printer_patch.patch @@ -0,0 +1,22 @@ +--- a/googletest/include/gtest/gtest-printers.h ++++ b/googletest/include/gtest/gtest-printers.h +@@ -205,12 +205,13 @@ struct StreamPrinter { + // Don't accept member pointers here. We'd print them via implicit + // conversion to bool, which isn't useful. + typename = typename std::enable_if< +- !std::is_member_pointer<T>::value>::type, +- // Only accept types for which we can find a streaming operator via +- // ADL (possibly involving implicit conversions). +- typename = decltype(std::declval<std::ostream&>() +- << std::declval<const T&>())> +- static void PrintValue(const T& value, ::std::ostream* os) { ++ !std::is_member_pointer<T>::value>::type> ++ // Only accept types for which we can find a streaming operator via ++ // ADL (possibly involving implicit conversions). ++ // (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name ++ // lookup properly when we do it in the template parameter list.) ++ static auto PrintValue(const T& value, ::std::ostream* os) ++ -> decltype((void)(*os << value)) { + // Call streaming operator found by ADL, possibly with implicit conversions + // of the arguments. + *os << value; diff --git a/engine/third_party/googletest/googletest.bzl b/engine/third_party/googletest/googletest.bzl new file mode 100644 index 0000000000000000000000000000000000000000..96cf4768c0a1281d25441734db96c633ca97795d --- /dev/null +++ b/engine/third_party/googletest/googletest.bzl @@ -0,0 +1,20 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") + +_VERSION = "1.12.1" + +def googletest(): + maybe( + http_archive, + name = "googletest", + url = "https://github.com/google/googletest/archive/refs/tags/release-{}.tar.gz".format(_VERSION), + sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2", + strip_prefix = "googletest-release-{}".format(_VERSION), + patches = [ + # Gtest >= 1.11.0 is impacted by a GCC compiler bug regarding template deduction. + # See: https://github.com/google/googletest/issues/3552 + # We backport the upstream fix to this until we reach a gtest version incorporating it by itself. + Label("//:third_party/googletest/gcc_printer_patch.patch"), + ], + patch_args = ["-p1"], + ) diff --git a/engine/third_party/nlohmann_json/BUILD.bazel b/engine/third_party/nlohmann_json/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..73a292eeb8340b378e07c9aff861d586c8b230b0 --- /dev/null +++ b/engine/third_party/nlohmann_json/BUILD.bazel @@ -0,0 +1,5 @@ +alias( + name = "nlohmann_json", + actual = "@nlohmann_json", + visibility = ["//visibility:public"], +) diff --git a/engine/third_party/nlohmann_json/nlohmann_json.BUILD b/engine/third_party/nlohmann_json/nlohmann_json.BUILD new file mode 100644 index 0000000000000000000000000000000000000000..d615d420b39e1e47744a892682c7220b64583a65 --- /dev/null +++ b/engine/third_party/nlohmann_json/nlohmann_json.BUILD @@ -0,0 +1,7 @@ + +cc_library( + name = "nlohmann_json", + hdrs = ["single_include/nlohmann/json.hpp"], + includes = ["single_include"], + visibility = ["//visibility:public"], +) diff --git a/engine/third_party/nlohmann_json/nlohmann_json.bzl b/engine/third_party/nlohmann_json/nlohmann_json.bzl new file mode 100644 index 0000000000000000000000000000000000000000..5d2c07b93920d2df4a8a43024006920f6ecaeed4 --- /dev/null +++ b/engine/third_party/nlohmann_json/nlohmann_json.bzl @@ -0,0 +1,13 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") + +_VERSION = "3.9.1" + +def nlohmann_json(): + maybe( + http_archive, + name = "nlohmann_json", + build_file = Label("//:third_party/nlohmann_json/nlohmann_json.BUILD"), + url = "https://github.com/nlohmann/json/releases/download/v{version}/include.zip".format(version = _VERSION), + sha256 = "6bea5877b1541d353bd77bdfbdb2696333ae5ed8f9e8cc22df657192218cad91", + ) diff --git a/utils/ci/conan/conanfile.txt b/utils/ci/conan/conanfile.txt index 2cd59264a312b987d035dff89046a1b764f15989..059e3c1ae668001a89672522fab0323b2dfe7004 100644 --- a/utils/ci/conan/conanfile.txt +++ b/utils/ci/conan/conanfile.txt @@ -1,9 +1,10 @@ [requires] -units/2.3.4@openscenarioengine/testing mantleapi/v14.0.0@openscenarioengine/testing -yase/d0c0e58d17358044cc9018c74308b45f6097ecfb@openscenarioengine/testing +nlohmann_json/v3.9.1@openscenarioengine/testing openscenario_api/v1.4.0@openscenarioengine/testing stochastics/0.11.0@openscenarioengine/testing +units/2.3.4@openscenarioengine/testing +yase/d0c0e58d17358044cc9018c74308b45f6097ecfb@openscenarioengine/testing [options] diff --git a/utils/ci/conan/recipe/nlohmann_json/all/conandata.yml b/utils/ci/conan/recipe/nlohmann_json/all/conandata.yml new file mode 100644 index 0000000000000000000000000000000000000000..346f60a21df16777d69b8c6c743fabc7c6c37079 --- /dev/null +++ b/utils/ci/conan/recipe/nlohmann_json/all/conandata.yml @@ -0,0 +1,18 @@ +################################################################################ +# Copyright (c) 2024-2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0. +# +# SPDX-License-Identifier: EPL-2.0 +################################################################################ + +################################################################################ +# conan data file for building nlohmann_json with Conan +################################################################################ + +sources: + "v3.9.1": + url: https://github.com/nlohmann/json/archive/refs/tags/v3.9.1.tar.gz + sha256: "4cf0df69731494668bdd6460ed8cb269b68de9c19ad8c27abc24cd72605b2d5b" diff --git a/utils/ci/conan/recipe/nlohmann_json/all/conanfile.py b/utils/ci/conan/recipe/nlohmann_json/all/conanfile.py new file mode 100644 index 0000000000000000000000000000000000000000..b3da81e2e9fbdc7f396d5d2bbe168b5cd1c81dd8 --- /dev/null +++ b/utils/ci/conan/recipe/nlohmann_json/all/conanfile.py @@ -0,0 +1,60 @@ +################################################################################ +# Copyright (c) 2024-2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0. +# +# SPDX-License-Identifier: EPL-2.0 +################################################################################ + +################################################################################ +# Install file for building nlohmann_json with Conan +################################################################################ + +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeToolchain +from conan.tools.files import rm, copy, rmdir +from conan.tools.files import get, copy +import os + +required_conan_version = ">=1.53" + +class NlohmannJSONConan(ConanFile): + name = "nlohmann_json" + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], + "fPIC": [True, False]} + + default_options = {"shared": False, + "fPIC": True} + + exports_sources = "*" + no_copy_source = False + short_paths = True + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def generate(self): + tc = CMakeToolchain(self) + tc.generate() + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def build(self): + cmake = CMake(self) + cmake.configure() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + self.cpp_info.set_property("cmake_find_mode", "none") diff --git a/utils/ci/conan/recipe/nlohmann_json/config.yml b/utils/ci/conan/recipe/nlohmann_json/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..84d55e7384f5e0fdab103c8830e74000dcfd99b1 --- /dev/null +++ b/utils/ci/conan/recipe/nlohmann_json/config.yml @@ -0,0 +1,17 @@ +################################################################################ +# Copyright (c) 2024-2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0. +# +# SPDX-License-Identifier: EPL-2.0 +################################################################################ + +################################################################################ +# config file for building nlohmann_json with Conan +################################################################################ + +versions: + "v3.9.1": + folder: "all" diff --git a/utils/ci/scripts/20_configure.sh b/utils/ci/scripts/20_configure.sh index 303502a8c14b9bcf1c4b3f4e5403d56df6472b51..673e138463374d3082697709af0c83beb3fbf2f4 100755 --- a/utils/ci/scripts/20_configure.sh +++ b/utils/ci/scripts/20_configure.sh @@ -1,7 +1,7 @@ #!/bin/bash ################################################################################ -# Copyright (c) 2023-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2023-2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License 2.0 which is available at @@ -31,6 +31,7 @@ mkdir -p "$MYDIR/../../../../build" cd "$MYDIR/../../../../build" || exit 1 DEPS=( + "$PWD/../deps/direct_deploy/nlohmann_json" "$PWD/../deps/direct_deploy/units" "$PWD/../deps/direct_deploy/mantleapi" "$PWD/../deps/direct_deploy/stochastics"