From b756af5056904e412820ca99e8efd91d054d69de Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 6 Apr 2021 14:09:43 +0200 Subject: [PATCH 01/42] wip proxy integration --- CMakeLists.txt | 7 +- cmake/FindPROXY_FMU.cmake | 36 +++ cmake/FindTHRIFT.cmake | 39 ---- cmake/project-config.cmake.in | 4 - conanfile.py | 13 +- src/CMakeLists.txt | 56 +---- src/cosim/fmuproxy/fmuproxy_client.cpp | 111 --------- src/cosim/fmuproxy/fmuproxy_client.hpp | 48 ---- src/cosim/fmuproxy/fmuproxy_helper.hpp | 122 ---------- .../fmuproxy/fmuproxy_uri_sub_resolver.cpp | 76 ------ .../fmuproxy/fmuproxy_uri_sub_resolver.hpp | 42 ---- src/cosim/fmuproxy/remote_fmu.cpp | 41 ---- src/cosim/fmuproxy/remote_slave.cpp | 192 --------------- src/cosim/fmuproxy/service.thrift | 218 ------------------ src/cosim/fmuproxy/thrift_state.cpp | 30 --- src/cosim/fmuproxy/thrift_state.hpp | 50 ---- src/cosim/orchestration.cpp | 10 +- .../proxy/proxy_file_uri_sub_resolver.cpp | 31 +++ .../proxy/proxy_file_uri_sub_resolver.hpp | 36 +++ src/cosim/proxy/remote_fmu.cpp | 79 +++++++ src/cosim/{fmuproxy => proxy}/remote_fmu.hpp | 32 +-- src/cosim/proxy/remote_slave.cpp | 161 +++++++++++++ .../{fmuproxy => proxy}/remote_slave.hpp | 18 +- tests/CMakeLists.txt | 10 +- 24 files changed, 378 insertions(+), 1084 deletions(-) create mode 100644 cmake/FindPROXY_FMU.cmake delete mode 100644 cmake/FindTHRIFT.cmake delete mode 100644 src/cosim/fmuproxy/fmuproxy_client.cpp delete mode 100644 src/cosim/fmuproxy/fmuproxy_client.hpp delete mode 100644 src/cosim/fmuproxy/fmuproxy_helper.hpp delete mode 100644 src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.cpp delete mode 100644 src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.hpp delete mode 100644 src/cosim/fmuproxy/remote_fmu.cpp delete mode 100644 src/cosim/fmuproxy/remote_slave.cpp delete mode 100644 src/cosim/fmuproxy/service.thrift delete mode 100644 src/cosim/fmuproxy/thrift_state.cpp delete mode 100644 src/cosim/fmuproxy/thrift_state.hpp create mode 100644 src/cosim/proxy/proxy_file_uri_sub_resolver.cpp create mode 100644 src/cosim/proxy/proxy_file_uri_sub_resolver.hpp create mode 100644 src/cosim/proxy/remote_fmu.cpp rename src/cosim/{fmuproxy => proxy}/remote_fmu.hpp (55%) create mode 100644 src/cosim/proxy/remote_slave.cpp rename src/cosim/{fmuproxy => proxy}/remote_slave.hpp (84%) diff --git a/CMakeLists.txt b/CMakeLists.txt index accd606a7..4f8537e4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,6 @@ option(LIBCOSIM_BUILD_APIDOC "Build API documentation (requires Doxygen)" ON) option(LIBCOSIM_BUILD_PRIVATE_APIDOC "Build private API documentation (only used if LIBCOSIM_BUILD_APIDOC=ON)" OFF) option(LIBCOSIM_STANDALONE_INSTALLATION "Whether to build for a standalone installation (Linux only; sets a relative RPATH)" OFF) option(LIBCOSIM_USING_CONAN "Whether Conan is used for package management" OFF) -option(LIBCOSIM_WITH_FMUPROXY "Whether or not to build with fmuproxy integration" OFF) -option(LIBCOSIM_TEST_FMUPROXY "Whether or not to run fmuproxy tests (only if LIBCOSIM_BUILD_TESTS=ON and LIBCOSIM_WITH_FMUPROXY=ON)" ON) # ============================================================================== # Global internal configuration @@ -115,9 +113,7 @@ find_package(FMILibrary REQUIRED) find_package(LIBZIP REQUIRED) find_package(YAML_CPP REQUIRED) find_package(XercesC REQUIRED) -if(LIBCOSIM_WITH_FMUPROXY) - find_package(THRIFT 0.13.0 REQUIRED) -endif() +find_package(PROXY_FMU REQUIRED) # ============================================================================== # Targets @@ -209,7 +205,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/cmake/FindFMILibrary.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindLIBZIP.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindMS_GSL.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindTHRIFT.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindYAML_CPP.cmake" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}" diff --git a/cmake/FindPROXY_FMU.cmake b/cmake/FindPROXY_FMU.cmake new file mode 100644 index 000000000..14d36d8c1 --- /dev/null +++ b/cmake/FindPROXY_FMU.cmake @@ -0,0 +1,36 @@ +# Find proxy-fmu +# +# Find the native proxy-server headers and libraries. +# +# PROXY_FMU_INCLUDE_DIRS - where to find proxy-fmu/... +# PROXY_FMU_LIBRARIES - List of libraries when using proxy-server. +# PROXY_FMU_FOUND - True if proxy-fmu found. +# + +find_path(PROXY_FMU_INCLUDE_DIR NAMES proxyfmu/client/proxy_fmu.hpp) +mark_as_advanced(PROXY_FMU_INCLUDE_DIR) + +find_library(PROXY_FMU_LIBRARY NAMES proxy-client) +mark_as_advanced(PROXY_FMU_LIBRARY) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROXY_FMU + REQUIRED_VARS PROXY_FMU_LIBRARY PROXY_FMU_INCLUDE_DIR) + +if (PROXY_FMU_FOUND) + + set(PROXY_FMU_INCLUDE_DIRS ${PROXY_FMU_INCLUDE_DIR}) + + if (NOT PROXY_FMU_LIBRARIES) + set(PROXY_FMU_LIBRARIES ${PROXY_FMU_LIBRARY}) + endif() + + if (NOT TARGET proxy-server) + add_library(proxy-server UNKNOWN IMPORTED) + set_target_properties(proxy-server PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${PROXY_FMU_INCLUDE_DIR}") + set_property(TARGET proxy-server APPEND PROPERTY + IMPORTED_LOCATION "${PROXY_FMU_LIBRARY}") + endif() + +endif() diff --git a/cmake/FindTHRIFT.cmake b/cmake/FindTHRIFT.cmake deleted file mode 100644 index 3e6939988..000000000 --- a/cmake/FindTHRIFT.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# Find Thrift -# -# Find the native Thrift headers and libraries. -# -# THRIFT_INCLUDE_DIRS - where to find thrift/thrift.h -# THRIFT_LIBRARIES - List of libraries when using Thrift. -# THRIFT_FOUND - True if Thrift found. -# - -find_path(THRIFT_INCLUDE_DIR NAMES thrift/Thrift.h) -mark_as_advanced(THRIFT_INCLUDE_DIR) - -find_library(THRIFT_LIBRARY NAMES thrift thriftd thriftmd thriftmdd) -mark_as_advanced(THRIFT_LIBRARY) - -find_program(THRIFT_EXECUTABLE NAMES thrift) -mark_as_advanced(THRIFT_EXECUTABLE) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(THRIFT - REQUIRED_VARS THRIFT_LIBRARY THRIFT_INCLUDE_DIR) - -if (THRIFT_FOUND) - - set(THRIFT_INCLUDE_DIRS ${THRIFT_INCLUDE_DIR}) - - if (NOT THRIFT_LIBRARIES) - set(THRIFT_LIBRARIES ${THRIFT_LIBRARY}) - endif() - - if (NOT TARGET thrift::thrift) - add_library(thrift::thrift UNKNOWN IMPORTED) - set_target_properties(thrift::thrift PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${THRIFT_INCLUDE_DIR}") - set_property(TARGET thrift::thrift APPEND PROPERTY - IMPORTED_LOCATION "${THRIFT_LIBRARY}") - endif() - -endif() diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in index 50632d6d4..424ca0fa4 100644 --- a/cmake/project-config.cmake.in +++ b/cmake/project-config.cmake.in @@ -13,8 +13,4 @@ find_dependency(LIBZIP REQUIRED) find_dependency(YAML_CPP REQUIRED) find_dependency(XercesC REQUIRED) -if(@LIBCOSIM_WITH_FMUPROXY@) - find_dependency(THRIFT REQUIRED) -endif() - list(REMOVE_AT CMAKE_MODULE_PATH -1) diff --git a/conanfile.py b/conanfile.py index 26326bf79..963882804 100755 --- a/conanfile.py +++ b/conanfile.py @@ -21,12 +21,11 @@ class LibcosimConan(ConanFile): "ms-gsl/2.1.0", "libzip/1.7.3", "yaml-cpp/0.6.3", - "xerces-c/3.2.2" + "xerces-c/3.2.2", + "proxy-fmu/0.1.0" ) - options = {"fmuproxy": [True, False]} default_options = ( - "fmuproxy=False", "boost:shared=True", "fmilibrary:shared=True", "libzip:shared=True", @@ -42,17 +41,15 @@ def imports(self): self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) - def requirements(self): - if self.options.fmuproxy: - self.requires("thrift/0.13.0") + # def requirements(self): + # if self.options.fmuproxy: + # self.requires("thrift/0.13.0") def configure_cmake(self): cmake = CMake(self) cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" cmake.definitions["LIBCOSIM_BUILD_APIDOC"] = "OFF" cmake.definitions["LIBCOSIM_BUILD_TESTS"] = "OFF" - if self.options.fmuproxy: - cmake.definitions["LIBCOSIM_WITH_FMUPROXY"] = "ON" cmake.configure() return cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37fef551b..f2281f5d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,9 @@ set(privateHeaders "cosim/fmi/glue.hpp" "cosim/fmi/windows.hpp" "cosim/observer/slave_value_provider.hpp" + "cosim/proxy/proxy_file_uri_sub_resolver.hpp" + "cosim/proxy/remote_fmu.hpp" + "cosim/proxy/remote_slave.hpp" "cosim/slave_simulator.hpp" "cosim/ssp/ssp_parser.hpp" "cosim/utility/concurrency.hpp" @@ -87,6 +90,9 @@ set(sources "cosim/observer/time_series_observer.cpp" "cosim/orchestration.cpp" "cosim/osp_config_parser.cpp" + "cosim/proxy/proxy_file_uri_sub_resolver.cpp" + "cosim/proxy/remote_fmu.cpp" + "cosim/proxy/remote_slave.cpp" "cosim/scenario_parser.cpp" "cosim/slave_simulator.cpp" "cosim/ssp/ssp_loader.cpp" @@ -103,24 +109,6 @@ set(generatedSources "cosim/lib_info.cpp" ) -if(LIBCOSIM_WITH_FMUPROXY) - list(APPEND privateHeaders - "cosim/fmuproxy/fmuproxy_client.hpp" - "cosim/fmuproxy/fmuproxy_helper.hpp" - "cosim/fmuproxy/fmuproxy_uri_sub_resolver.hpp" - "cosim/fmuproxy/remote_fmu.hpp" - "cosim/fmuproxy/remote_slave.hpp" - "cosim/fmuproxy/thrift_state.hpp" - ) - list(APPEND sources - "cosim/fmuproxy/fmuproxy_client.cpp" - "cosim/fmuproxy/fmuproxy_uri_sub_resolver.cpp" - "cosim/fmuproxy/remote_slave.cpp" - "cosim/fmuproxy/remote_fmu.cpp" - "cosim/fmuproxy/thrift_state.cpp" - ) -endif() - # ============================================================================== # Code generation # ============================================================================== @@ -150,30 +138,6 @@ add_custom_command( ) list(APPEND generatedFiles "${ospSystemStructureHeader}") -# Generate FMU-proxy classes from Thrift service definitions -if(LIBCOSIM_WITH_FMUPROXY) - if(NOT THRIFT_EXECUTABLE) - message(FATAL_ERROR "The thrift compiler was not found. Cannot build with FMU-Proxy support.") - endif() - set(thriftServiceDefinition "${CMAKE_CURRENT_SOURCE_DIR}/cosim/fmuproxy/service.thrift") - set(thriftGenerated - "${generatedSourcesDir}/FmuService.h" - "${generatedSourcesDir}/FmuService.cpp" - "${generatedSourcesDir}/service_types.h" - "${generatedSourcesDir}/service_types.cpp" - ) - add_custom_command( - OUTPUT ${thriftGenerated} - COMMAND "${THRIFT_EXECUTABLE}" - "--gen" "cpp:no_skeleton" - "-out" "${generatedSourcesDir}" - "${thriftServiceDefinition}" - DEPENDS "${thriftServiceDefinition}" - ) - add_library(fmuproxy-service OBJECT ${thriftGenerated}) - set_target_properties(fmuproxy-service PROPERTIES POSITION_INDEPENDENT_CODE ON) - list(APPEND generatedFiles "$") -endif() # ============================================================================== # Target definition @@ -210,14 +174,6 @@ target_link_libraries(cosim yaml-cpp ) -if(LIBCOSIM_WITH_FMUPROXY) - target_compile_definitions(cosim PRIVATE "HAS_FMUPROXY") - target_link_libraries(cosim - PUBLIC - thrift::thrift - ) -endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_link_libraries(cosim INTERFACE "atomic") endif() diff --git a/src/cosim/fmuproxy/fmuproxy_client.cpp b/src/cosim/fmuproxy/fmuproxy_client.cpp deleted file mode 100644 index 248cc4913..000000000 --- a/src/cosim/fmuproxy/fmuproxy_client.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 -#include -#include -#include - -#include - -#include -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4245 4706) -#endif - -#include -#include -#include - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -using namespace fmuproxy::thrift; -using namespace apache::thrift::transport; -using namespace apache::thrift::protocol; - -namespace fs = boost::filesystem; - -namespace -{ - -void read_data(const std::string& fileName, std::string& data) -{ - FILE* file = fopen(fileName.c_str(), "rb"); - if (file == nullptr) return; - fseek(file, 0, SEEK_END); - const auto size = ftell(file); - fclose(file); - - file = fopen(fileName.c_str(), "rb"); - data.resize(size); -#if defined(__GNUC__) - size_t read __attribute__((unused)) = fread(data.data(), sizeof(unsigned char), size, file); -#else - fread(data.data(), sizeof(unsigned char), size, file); -#endif - fclose(file); -} - -} // namespace - -cosim::fmuproxy::fmuproxy_client::fmuproxy_client( - const std::string& host, - const unsigned int port) -{ - std::shared_ptr socket(new TSocket(host, port)); - std::shared_ptr transport(new TFramedTransport(socket)); - std::shared_ptr protocol(new TBinaryProtocol(transport)); - std::shared_ptr<::fmuproxy::thrift::FmuServiceIf> client; - - client = std::make_shared(protocol); - - try { - transport->open(); - } catch (TTransportException&) { - std::string msg = "Failed to connect to remote FMU @ " + host + ":" + std::to_string(port); - COSIM_PANIC_M(msg.c_str()); - } - state_ = std::make_shared(client, transport); -} - -std::shared_ptr -cosim::fmuproxy::fmuproxy_client::from_url(const std::string& url) -{ - BOOST_LOG_SEV(log::logger(), log::debug) << "fmu-proxy will load FMU from url '" << url << "'"; - FmuId fmuId; - state_->client_->load_from_url(fmuId, url); - return from_guid(fmuId); -} - -std::shared_ptr -cosim::fmuproxy::fmuproxy_client::from_file(const std::string& file) -{ - BOOST_LOG_SEV(log::logger(), log::debug) << "fmu-proxy will load FMU from file '" << file << "'"; - - if (!fs::exists(file)) { - std::string msg = "No such file '" + file + "'!"; - COSIM_PANIC_M(msg.c_str()); - } - - const auto name = fs::path(file).stem().string(); - - std::string data; - read_data(file, data); - - FmuId fmuId; - state_->client_->load_from_file(fmuId, name, data); - return from_guid(fmuId); -} - -std::shared_ptr -cosim::fmuproxy::fmuproxy_client::from_guid(const std::string& guid) -{ - return std::make_shared(guid, state_); -} diff --git a/src/cosim/fmuproxy/fmuproxy_client.hpp b/src/cosim/fmuproxy/fmuproxy_client.hpp deleted file mode 100644 index add5e370e..000000000 --- a/src/cosim/fmuproxy/fmuproxy_client.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * \file - * Defines the FMU-proxy client - * - * \copyright - * 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/. - */ -#ifndef COSIM_FMUPROXY_FMUPROXYCLIENT_HPP -#define COSIM_FMUPROXY_FMUPROXYCLIENT_HPP - -#include "FmuService.h" - -#include - -#include - -namespace cosim -{ - -namespace fmuproxy -{ - -class fmuproxy_client -{ - -public: - fmuproxy_client( - const std::string& host, - unsigned int port); - - std::shared_ptr from_url(const std::string& url); - - std::shared_ptr from_file(const std::string& file); - - std::shared_ptr from_guid(const std::string& guid); - -private: - std::shared_ptr state_; -}; - -} // namespace fmuproxy - -} // namespace cosim - - -#endif diff --git a/src/cosim/fmuproxy/fmuproxy_helper.hpp b/src/cosim/fmuproxy/fmuproxy_helper.hpp deleted file mode 100644 index a1283a7bf..000000000 --- a/src/cosim/fmuproxy/fmuproxy_helper.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/** - * \file - * - * \copyright - * 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/. - */ -#ifndef COSIM_FMUPROXY_FMUPROXY_HELPER_HPP -#define COSIM_FMUPROXY_FMUPROXY_HELPER_HPP - -#include "service_types.h" - -#include "cosim/error.hpp" -#include "cosim/model_description.hpp" - -#include - - -namespace -{ - -inline cosim::variable_causality parse_causality(const std::string& c) -{ - if (c == "input") { - return cosim::variable_causality::input; - } else if (c == "output") { - return cosim::variable_causality::output; - } else if (c == "parameter") { - return cosim::variable_causality::parameter; - } else if (c == "calculated_parameter") { - return cosim::variable_causality::calculated_parameter; - } else if (c == "local" || c == "independent" || c == "unknown" || c == "") { - return cosim::variable_causality::local; - } else { - const auto err = "Failed to parse causality: '" + c + "'"; - COSIM_PANIC_M(err.c_str()); - } -} - -inline cosim::variable_variability parse_variability(const std::string& v) -{ - if (v == "constant") { - return cosim::variable_variability::constant; - } else if (v == "discrete") { - return cosim::variable_variability::discrete; - } else if (v == "fixed") { - return cosim::variable_variability::fixed; - } else if (v == "tunable") { - return cosim::variable_variability::tunable; - } else if (v == "continuous" || v == "unknown" || v == "") { - return cosim::variable_variability::continuous; - } else { - const auto err = "Failed to parse variability: '" + v + "'"; - COSIM_PANIC_M(err.c_str()); - } -} - -inline cosim::variable_type get_type(const fmuproxy::thrift::ScalarVariable& v) -{ - if (v.attribute.__isset.integer_attribute) { - return cosim::variable_type::integer; - } else if (v.attribute.__isset.real_attribute) { - return cosim::variable_type::real; - } else if (v.attribute.__isset.string_attribute) { - return cosim::variable_type::string; - } else if (v.attribute.__isset.boolean_attribute) { - return cosim::variable_type::boolean; - } else if (v.attribute.__isset.enumeration_attribute) { - return cosim::variable_type::enumeration; - } else { - const auto err = "Failed to get type of variable: '" + v.name + "'"; - COSIM_PANIC_M(err.c_str()); - } -} - -inline cosim::variable_description convert(const fmuproxy::thrift::ScalarVariable& v) -{ - cosim::variable_description var; - var.name = v.name; - var.reference = (cosim::value_reference)v.value_reference; - var.causality = parse_causality(v.causality); - var.variability = parse_variability(v.variability); - var.type = get_type(v); - if (v.attribute.__isset.integer_attribute) { - var.start = v.attribute.integer_attribute.start; - } else if (v.attribute.__isset.real_attribute) { - var.start = v.attribute.real_attribute.start; - } else if (v.attribute.__isset.string_attribute) { - var.start = v.attribute.string_attribute.start; - } else if (v.attribute.__isset.boolean_attribute) { - var.start = v.attribute.boolean_attribute.start; - } else if (v.attribute.__isset.enumeration_attribute) { - var.start = v.attribute.enumeration_attribute.start; - } - return var; -} - -inline std::vector convert(fmuproxy::thrift::ModelVariables& vars) -{ - std::vector modelVariables; - for (const auto& v : vars) { - modelVariables.push_back(convert(v)); - } - return modelVariables; -} - -inline std::shared_ptr convert(fmuproxy::thrift::ModelDescription& md) -{ - auto modelDescription = std::make_shared(); - modelDescription->name = md.modelName; - modelDescription->author = md.author; - modelDescription->uuid = md.guid; - modelDescription->version = md.version; - modelDescription->description = md.description; - modelDescription->variables = convert(md.model_variables); - return modelDescription; -} - -} // namespace - -#endif diff --git a/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.cpp b/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.cpp deleted file mode 100644 index e298e6875..000000000 --- a/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include - -// examples of uri to resolve -//fmu-proxy://127.0.0.1:9090?guid=2213kjhlkh4lhksdkj -//fmu-proxy://127.0.0.1:9090?url=http://example.com/my_model.fmu -//fmu-proxy://127.0.0.1:9090?file=models/my_model.fmu - -namespace -{ - -std::pair parse_authority(std::string_view auth) -{ - const auto colon = auth.find(":"); - const auto host = std::string(auth.substr(0, colon)); - const auto port = std::stoi(std::string(auth.substr(colon + 1))); - return {host, port}; -} - -} // namespace - -std::shared_ptr cosim::fmuproxy::fmuproxy_uri_sub_resolver::lookup_model( - const cosim::uri& baseUri, - const cosim::uri& modelUriReference) -{ - const auto& mur = modelUriReference; - const auto query = mur.query(); - if (query) { - if (query->find("file=file:///") < query->size()) { - const auto newQuery = "file=" + std::string(query->substr(13)); - return model_uri_sub_resolver::lookup_model( - baseUri, uri(mur.scheme(), mur.authority(), mur.path(), newQuery, mur.fragment())); - } else if (query->find("file=") < query->size()) { - const auto pathToAppend = cosim::file_uri_to_path(baseUri).parent_path().string(); - const auto newQuery = "file=" + pathToAppend + "/" + std::string(query->substr(5)); - return model_uri_sub_resolver::lookup_model( - baseUri, uri(mur.scheme(), mur.authority(), mur.path(), newQuery, mur.fragment())); - } - } - return model_uri_sub_resolver::lookup_model(baseUri, mur); -} - -std::shared_ptr cosim::fmuproxy::fmuproxy_uri_sub_resolver::lookup_model(const cosim::uri& modelUri) -{ - assert(modelUri.scheme().has_value()); - if (*modelUri.scheme() != "fmu-proxy") return nullptr; - COSIM_INPUT_CHECK(modelUri.authority()); - COSIM_INPUT_CHECK(modelUri.query()); - - const auto query = *modelUri.query(); - const auto auth = parse_authority(*modelUri.authority()); - auto client = cosim::fmuproxy::fmuproxy_client(auth.first, auth.second); - - if (query.substr(0, 5) == "guid=") { - const auto guid = std::string(query.substr(5)); - return client.from_guid(guid); - } else if (query.substr(0, 5) == "file=") { - const auto file = std::string(query.substr(5)); - return client.from_file(file); - } else if (query.substr(0, 4) == "url=") { - const auto url = std::string(query.substr(4)); - return client.from_url(url); - } else { - return nullptr; - } -} diff --git a/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.hpp b/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.hpp deleted file mode 100644 index a54882458..000000000 --- a/src/cosim/fmuproxy/fmuproxy_uri_sub_resolver.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * \file - * - * \copyright - * 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/. - */ -#ifndef COSIM_FMUPROXY_URI_SUB_RESOLVER_HPP -#define COSIM_FMUPROXY_URI_SUB_RESOLVER_HPP - -#include - -namespace cosim -{ - -namespace fmuproxy -{ - -/** - * Class for resolving fmu-proxy URI schemes. - * - * Supports file, url and guid (pre-loaded on server) FMUs - * - * From file: `fmu-proxy://127.0.0.1:9090?file=models/my_model.fmu` - * From url: `fmu-proxy://127.0.0.1:9090?url=http://example.com/my_model.fmu` - * From guid: `fmu-proxy://127.0.0.1:9090?guid={ads4ffsa4523fgg8}` - */ -class fmuproxy_uri_sub_resolver : public model_uri_sub_resolver -{ - -public: - std::shared_ptr lookup_model(const uri& baseUri, const uri& modelUriReference) override; - - std::shared_ptr lookup_model(const cosim::uri& uri) override; -}; - -} // namespace fmuproxy - -} // namespace cosim - -#endif diff --git a/src/cosim/fmuproxy/remote_fmu.cpp b/src/cosim/fmuproxy/remote_fmu.cpp deleted file mode 100644 index 09d584787..000000000 --- a/src/cosim/fmuproxy/remote_fmu.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 -#include -#include -#include - -using namespace fmuproxy::thrift; -using namespace apache::thrift::transport; -using namespace apache::thrift::protocol; - -cosim::fmuproxy::remote_fmu::remote_fmu( - const FmuId& fmuId, - std::shared_ptr state) - : fmuId_(fmuId) - , state_(std::move(state)) -{ - ::fmuproxy::thrift::ModelDescription md = ModelDescription(); - state_->client().get_model_description(md, fmuId); - modelDescription_ = convert(md); -} - -std::shared_ptr cosim::fmuproxy::remote_fmu::description() const noexcept -{ - return modelDescription_; -} - -std::shared_ptr cosim::fmuproxy::remote_fmu::instantiate_slave() -{ - InstanceId instanceId; - state_->client().create_instance(instanceId, fmuId_); - return std::make_shared(instanceId, state_, modelDescription_); -} - -std::shared_ptr cosim::fmuproxy::remote_fmu::instantiate(std::string_view) -{ - return cosim::make_background_thread_slave(instantiate_slave()); -} diff --git a/src/cosim/fmuproxy/remote_slave.cpp b/src/cosim/fmuproxy/remote_slave.cpp deleted file mode 100644 index 3736e8b26..000000000 --- a/src/cosim/fmuproxy/remote_slave.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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 -#include -#include - -#include - - -cosim::fmuproxy::remote_slave::remote_slave(std::string instanceId, - std::shared_ptr state, - std::shared_ptr modelDescription) - : terminated_(false) - , instanceId_(std::move(instanceId)) - , state_(std::move(state)) - , modelDescription_(std::move(modelDescription)) -{ } - -cosim::model_description cosim::fmuproxy::remote_slave::model_description() const -{ - return *modelDescription_; -} - -void cosim::fmuproxy::remote_slave::setup(cosim::time_point startTime, std::optional stopTime, - std::optional relativeTolerance) -{ - startTime_ = startTime; - - double start = to_double_time_point(startTime); - double stop = to_double_time_point(stopTime.value_or(cosim::to_time_point(0))); - double tolerance = relativeTolerance.value_or(0); - - ::fmuproxy::thrift::Status::type status; - status = state_->client().setup_experiment(instanceId_, start, stop, tolerance); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - status = state_->client().enter_initialization_mode(instanceId_); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -void cosim::fmuproxy::remote_slave::start_simulation() -{ - auto status = state_->client().exit_initialization_mode(instanceId_); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -void cosim::fmuproxy::remote_slave::end_simulation() -{ - if (!terminated_) { - auto status = state_->client().terminate(instanceId_); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - terminated_ = true; - } -} - -cosim::step_result cosim::fmuproxy::remote_slave::do_step(cosim::time_point, cosim::duration deltaT) -{ - - double dt = to_double_duration(deltaT, startTime_); - - ::fmuproxy::thrift::StepResult result; - state_->client().step(result, instanceId_, dt); - if (result.status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - return cosim::step_result::complete; -} - -void cosim::fmuproxy::remote_slave::get_real_variables(gsl::span variables, - gsl::span values) const -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::RealRead read; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - state_->client().read_real(read, instanceId_, vr); - if (read.status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - for (unsigned int i = 0; i < read.value.size(); i++) { - values[i] = read.value[i]; - } -} - -void cosim::fmuproxy::remote_slave::get_integer_variables(gsl::span variables, - gsl::span values) const -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::IntegerRead read; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - state_->client().read_integer(read, instanceId_, vr); - if (read.status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - for (unsigned int i = 0; i < read.value.size(); i++) { - values[i] = read.value[i]; - } -} - -void cosim::fmuproxy::remote_slave::get_boolean_variables(gsl::span variables, - gsl::span values) const -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::BooleanRead read; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - state_->client().read_boolean(read, instanceId_, vr); - if (read.status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } - for (unsigned int i = 0; i < read.value.size(); i++) { - values[i] = read.value[i]; - } -} - -void cosim::fmuproxy::remote_slave::get_string_variables(gsl::span variables, - gsl::span values) const -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::StringRead read; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - state_->client().read_string(read, instanceId_, vr); - for (unsigned int i = 0; i < read.value.size(); i++) { - values[i] = read.value[i]; - } -} - -void cosim::fmuproxy::remote_slave::set_real_variables(gsl::span variables, - gsl::span values) -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - auto status = state_->client().write_real(instanceId_, vr, std::vector(values.begin(), values.end())); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -void cosim::fmuproxy::remote_slave::set_integer_variables(gsl::span variables, - gsl::span values) -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - auto status = state_->client().write_integer(instanceId_, vr, std::vector(values.begin(), values.end())); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -void cosim::fmuproxy::remote_slave::set_boolean_variables(gsl::span variables, - gsl::span values) -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - auto status = state_->client().write_boolean(instanceId_, vr, std::vector(values.begin(), values.end())); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -void cosim::fmuproxy::remote_slave::set_string_variables(gsl::span variables, - gsl::span values) -{ - COSIM_INPUT_CHECK(variables.size() == values.size()); - if (variables.empty()) return; - ::fmuproxy::thrift::ValueReferences vr(variables.begin(), variables.end()); - auto status = state_->client().write_string(instanceId_, vr, std::vector(values.begin(), values.end())); - if (status != ::fmuproxy::thrift::Status::OK_STATUS) { - COSIM_PANIC(); - } -} - -cosim::fmuproxy::remote_slave::~remote_slave() -{ - end_simulation(); - state_->client().freeInstance(instanceId_); -} diff --git a/src/cosim/fmuproxy/service.thrift b/src/cosim/fmuproxy/service.thrift deleted file mode 100644 index 00381ae13..000000000 --- a/src/cosim/fmuproxy/service.thrift +++ /dev/null @@ -1,218 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2019 Norwegian University of Technology (NTNU) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -namespace cpp fmuproxy.thrift -namespace java no.ntnu.ihb.fmuproxy.thrift - -typedef string FmuId -typedef string InstanceId -typedef i64 ValueReference -typedef i64 FmuState -typedef list DirectionalDerivative -typedef list ValueReferences -typedef list IntArray -typedef list RealArray -typedef list StringArray -typedef list BooleanArray - - -enum Status { - OK_STATUS = 0, - WARNING_STATUS = 1, - DISCARD_STATUS = 2, - ERROR_STATUS = 3, - FATAL_STATUS = 4, - PENDING_STATUS = 5 -} - -struct IntegerAttribute { - 1: i32 min, - 2: i32 max, - 3: i32 start, - 4: string quantity -} - -struct RealAttribute { - 1: double min, - 2: double max, - 3: double start, - 4: string quantity -} - -struct StringAttribute { - 1: string start -} - -struct BooleanAttribute { - 1: bool start -} - -struct EnumerationAttribute { - 1: i32 min, - 2: i32 max, - 3: i32 start, - 4: string quantity -} - -union ScalarVariableAttribute { - 1: IntegerAttribute integer_attribute, - 2: RealAttribute real_attribute, - 3: StringAttribute string_attribute, - 4: BooleanAttribute boolean_attribute, - 5: EnumerationAttribute enumeration_attribute -} - -struct ScalarVariable { - 1: string name, - 2: ValueReference value_reference, - 3: optional string description, - 4: optional string initial, - 5: optional string causality, - 6: optional string variability, - 7: ScalarVariableAttribute attribute -} - -typedef list ModelVariables - -struct Unknown { - 1: i32 index, - 2: list dependencies, - 3: list dependencies_kind -} - -struct ModelStructure { - 1: list outputs, - 2: list derivatives, - 3: list initial_unknowns -} - -struct DefaultExperiment { - 1: double startTime, - 2: double stopTime, - 3: double tolerance, - 4: double stepSize -} - -struct StepResult { - 1: Status status, - 2: double simulation_time -} - -struct IntegerRead { - 1: list value, - 2: Status status -} - -struct RealRead { - 1: list value, - 2: Status status -} - -struct StringRead { - 1: list value, - 2: Status status -} - -struct BooleanRead { - 1: list value, - 2: Status status -} - -struct ModelDescription { - 1: string guid, - 2: string fmi_version, - 3: string modelName, - 4: optional string license, - 5: optional string copyright, - 6: optional string author, - 7: optional string version, - 8: optional string description, - 9: optional string generation_tool, - 10: optional string generation_date_and_time, - 11: optional DefaultExperiment default_experiment, - 12: optional string variable_naming_convention, - 13: ModelVariables model_variables, - 14: ModelStructure model_structure, - - 15: string model_identifier, - 16: bool can_get_and_set_fmu_state, - 17: bool can_serialize_fmu_state, - 18: bool provides_directional_derivative, - 19: bool can_handle_variable_communication_step_size, - 20: bool can_interpolate_inputs, - 21: i32 max_output_derivative_order -} - -exception NoSuchFmuException { - 1: string message -} - -exception NoSuchInstanceException { - 1: string message -} - -exception NoSuchVariableException { - 1: string message -} - -exception UnsupportedOperationException { - 1: string message -} - -struct DirectionalDerivativeResult { - 1: DirectionalDerivative dv_unknown_ref - 2: Status status -} - -service FmuService { - - FmuId load_from_url(1: string url) - FmuId load_from_file(1: string name, 2: binary data) - - ModelDescription get_model_description(1: FmuId fmuId) throws (1: NoSuchFmuException ex) - - InstanceId create_instance(1: FmuId fmuId) throws (1: UnsupportedOperationException ex1, 2: NoSuchFmuException ex2) - - Status setup_experiment(1: InstanceId instanceId, 2: double start, 3: double stop, 4: double tolerance) throws (1: NoSuchInstanceException ex) - Status enter_initialization_mode(1: InstanceId instanceId) throws (1: NoSuchInstanceException ex) - Status exit_initialization_mode(1: InstanceId instanceId) throws (1: NoSuchInstanceException ex) - - StepResult step(1: InstanceId instanceId, 2: double stepSize) throws (1: NoSuchInstanceException ex) - Status reset(1: InstanceId instanceId) throws (1: NoSuchInstanceException ex) - Status terminate(1: InstanceId instanceId) throws (1: NoSuchInstanceException ex) - void freeInstance(1: InstanceId instanceId) throws (1: NoSuchInstanceException ex) - - IntegerRead read_integer(1: InstanceId instanceId, 2: ValueReferences vr) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - RealRead read_real(1: InstanceId instanceId, 2: ValueReferences vr) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - StringRead read_string(1: InstanceId instanceId, 2: ValueReferences vr) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - BooleanRead read_boolean(1: InstanceId instanceId, 2: ValueReferences vr) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - - Status write_integer(1: InstanceId instanceId, 2: ValueReferences vr, 3: IntArray value) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - Status write_real(1: InstanceId instanceId, 2: ValueReferences vr, 3: RealArray value) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - Status write_string(1: InstanceId instanceId, 2: ValueReferences vr, 3: StringArray value) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - Status write_boolean(1: InstanceId instanceId, 2: ValueReferences vr, 3: BooleanArray value) throws (1: NoSuchInstanceException ex1, 2: NoSuchVariableException ex2) - - DirectionalDerivativeResult get_directional_derivative(1: InstanceId instanceId, 2: ValueReferences vUnknownRef, 3: ValueReferences vKnownRef, 4: list dvKnownRef) throws (1: NoSuchInstanceException ex1, 2: UnsupportedOperationException ex2) - -} diff --git a/src/cosim/fmuproxy/thrift_state.cpp b/src/cosim/fmuproxy/thrift_state.cpp deleted file mode 100644 index d2065e623..000000000 --- a/src/cosim/fmuproxy/thrift_state.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - -#include - -cosim::fmuproxy::thrift_state::thrift_state(std::shared_ptr<::fmuproxy::thrift::FmuServiceIf> client_, - std::shared_ptr transport_) - : client_(std::move(client_)) - , transport_(std::move(transport_)) -{ } - -::fmuproxy::thrift::FmuServiceIf& cosim::fmuproxy::thrift_state::client() -{ - return *client_; -} -apache::thrift::transport::TTransport& cosim::fmuproxy::thrift_state::transport() -{ - return *transport_; -} - -cosim::fmuproxy::thrift_state::~thrift_state() -{ - if (transport_->isOpen()) { - transport_->close(); - } -} diff --git a/src/cosim/fmuproxy/thrift_state.hpp b/src/cosim/fmuproxy/thrift_state.hpp deleted file mode 100644 index 876394b20..000000000 --- a/src/cosim/fmuproxy/thrift_state.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/** - * \file - * - * \copyright - * 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/. - */ -#ifndef COSIM_FMUPROXY_SHARED_THRIFT_STATE_HPP -#define COSIM_FMUPROXY_SHARED_THRIFT_STATE_HPP - -#include "FmuService.h" - -#include - -namespace cosim -{ - -namespace fmuproxy -{ - -class remote_fmu; -class fmuproxy_client; - -class thrift_state -{ - - friend class remote_fmu; - friend class fmuproxy_client; - -public: - thrift_state(std::shared_ptr<::fmuproxy::thrift::FmuServiceIf> client_, - std::shared_ptr transport_); - - ::fmuproxy::thrift::FmuServiceIf& client(); - - apache::thrift::transport::TTransport& transport(); - - ~thrift_state(); - -private: - const std::shared_ptr<::fmuproxy::thrift::FmuServiceIf> client_; - const std::shared_ptr transport_; -}; - -} // namespace fmuproxy - -} // namespace cosim - -#endif diff --git a/src/cosim/orchestration.cpp b/src/cosim/orchestration.cpp index 304f364fd..5830de48a 100644 --- a/src/cosim/orchestration.cpp +++ b/src/cosim/orchestration.cpp @@ -4,15 +4,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "cosim/orchestration.hpp" +#include "cosim/proxy/proxy_file_uri_sub_resolver.hpp" #include "cosim/error.hpp" #include "cosim/fmi/fmu.hpp" #include "cosim/log/logger.hpp" -#ifdef HAS_FMUPROXY -# include -#endif - namespace cosim { @@ -147,10 +144,7 @@ std::shared_ptr default_model_uri_resolver( resolver->add_sub_resolver( std::make_shared()); } -#ifdef HAS_FMUPROXY - resolver->add_sub_resolver( - std::make_shared()); -#endif + resolver->add_sub_resolver(std::make_shared()); return resolver; } diff --git a/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp new file mode 100644 index 000000000..5e9feb087 --- /dev/null +++ b/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp @@ -0,0 +1,31 @@ +/* + * 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 +#include + +#include "cosim/log/logger.hpp" + +#include + +#include + +std::shared_ptr cosim::proxy::proxy_file_uri_sub_resolver::lookup_model(const cosim::uri& modelUri) +{ + assert(modelUri.scheme().has_value()); + if (*modelUri.scheme() != "proxy-file") return nullptr; + if (modelUri.authority().has_value() && + !(modelUri.authority()->empty() || *modelUri.authority() == "localhost")) { + return nullptr; + } + if (modelUri.query().has_value() || modelUri.fragment().has_value()) { + BOOST_LOG_SEV(log::logger(), log::warning) + << "Query and/or fragment component(s) in a file:// URI were ignored: " + << modelUri; + } + const auto path = file_uri_to_path(modelUri); + if (path.extension() != ".fmu") return nullptr; + return std::make_shared(std::filesystem::path(path.string())); +} diff --git a/src/cosim/proxy/proxy_file_uri_sub_resolver.hpp b/src/cosim/proxy/proxy_file_uri_sub_resolver.hpp new file mode 100644 index 000000000..8e03a65b2 --- /dev/null +++ b/src/cosim/proxy/proxy_file_uri_sub_resolver.hpp @@ -0,0 +1,36 @@ +/** + * \file + * + * \copyright + * 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/. + */ +#ifndef COSIM_PROXY_FILE_URI_SUB_RESOLVER_HPP +#define COSIM_PROXY_FILE_URI_SUB_RESOLVER_HPP + +#include + +namespace cosim +{ + +namespace proxy +{ + +/** + * Class for resolving fmu-proxy URI schemes. + * + * From file: 'proxy-file:///models/my_model.fmu' + */ +class proxy_file_uri_sub_resolver : public model_uri_sub_resolver +{ + +public: + std::shared_ptr lookup_model(const cosim::uri& uri) override; +}; + +} // namespace proxy + +} // namespace cosim + +#endif diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp new file mode 100644 index 000000000..3e6d6edc1 --- /dev/null +++ b/src/cosim/proxy/remote_fmu.cpp @@ -0,0 +1,79 @@ +/* + * 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 +#include +#include + +namespace +{ + +cosim::variable_type get_type(const proxyfmu::fmi::scalar_variable& v) +{ + if (v.is_integer()) { + return cosim::variable_type::integer; + } else if (v.is_real()) { + return cosim::variable_type::real; + } else if (v.is_string()) { + return cosim::variable_type::string; + } else if (v.is_boolean()) { + return cosim::variable_type::boolean; + } else { + throw std::runtime_error("Unsupported variable type"); + } +} + +cosim::variable_causality get_causality(const proxyfmu::fmi::scalar_variable&) +{ + //TODO + return cosim::variable_causality::local; +} + +cosim::variable_variability get_variability(const proxyfmu::fmi::scalar_variable&) +{ + //TODO + return cosim::variable_variability::continuous; +} + +std::unique_ptr parse_model_description(const proxyfmu::fmi::model_description& md) +{ + auto _md = std::make_unique(); + _md->uuid = md.guid; + _md->name = md.model_name; + _md->description = md.description; + _md->author = md.author; + + auto vars = md.model_variables; + for (auto& var : vars) { + cosim::variable_description vd; + vd.name = var.name; + vd.reference = var.vr; + vd.type = get_type(var); + vd.causality = get_causality(var); + vd.variability = get_variability(var); + _md->variables.push_back(vd); + } + + return _md; +} + +} // namespace + +cosim::proxy::remote_fmu::remote_fmu(const std::filesystem::path& fmuPath) + : fmu_(proxyfmu::fmi::loadFmu(fmuPath)) + , modelDescription_(parse_model_description(fmu_->get_model_description())) +{ +} + +std::shared_ptr cosim::proxy::remote_fmu::description() const noexcept +{ + return modelDescription_; +} + +std::shared_ptr cosim::proxy::remote_fmu::instantiate(std::string_view /*instanceName*/) +{ + auto slave = std::make_shared(fmu_->new_instance(""), modelDescription_); + return cosim::make_background_thread_slave(slave); +} diff --git a/src/cosim/fmuproxy/remote_fmu.hpp b/src/cosim/proxy/remote_fmu.hpp similarity index 55% rename from src/cosim/fmuproxy/remote_fmu.hpp rename to src/cosim/proxy/remote_fmu.hpp index 964d8b874..11fe4a9c4 100644 --- a/src/cosim/fmuproxy/remote_fmu.hpp +++ b/src/cosim/proxy/remote_fmu.hpp @@ -6,53 +6,39 @@ * 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/. */ -#ifndef COSIM_FMUPROXY_REMOTE_FMU_HPP -#define COSIM_FMUPROXY_REMOTE_FMU_HPP - -#ifdef _WIN32 -//must be included before -# include -#endif - -#include "FmuService.h" +#ifndef COSIM_PROXY_REMOTE_FMU_HPP +#define COSIM_PROXY_REMOTE_FMU_HPP #include -#include #include #include +#include #include +#include namespace cosim { -namespace fmuproxy +namespace proxy { -class fmuproxy_client; - class remote_fmu : public cosim::model { - friend class fmuproxy_client; - public: - remote_fmu(const ::fmuproxy::thrift::FmuId& fmuId, - std::shared_ptr state); + explicit remote_fmu(const std::filesystem::path& fmuPath); std::shared_ptr description() const noexcept override; - std::shared_ptr instantiate_slave(); - - std::shared_ptr instantiate(std::string_view name = "") override; + std::shared_ptr instantiate(std::string_view name) override; private: - const std::string fmuId_; - std::shared_ptr state_; + std::unique_ptr fmu_; std::shared_ptr modelDescription_; }; -} // namespace fmuproxy +} // namespace proxy } // namespace cosim diff --git a/src/cosim/proxy/remote_slave.cpp b/src/cosim/proxy/remote_slave.cpp new file mode 100644 index 000000000..abc433f30 --- /dev/null +++ b/src/cosim/proxy/remote_slave.cpp @@ -0,0 +1,161 @@ +/* + * 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 +#include + +#include + + +cosim::proxy::remote_slave::remote_slave( + std::unique_ptr slave, + std::shared_ptr modelDescription) + : terminated_(false) + , slave_(std::move(slave)) + , modelDescription_(std::move(modelDescription)) +{ } + +cosim::model_description cosim::proxy::remote_slave::model_description() const +{ + return *modelDescription_; +} + +void cosim::proxy::remote_slave::setup(cosim::time_point startTime, std::optional stopTime, + std::optional relativeTolerance) +{ + startTime_ = startTime; + + double start = to_double_time_point(startTime); + double stop = to_double_time_point(stopTime.value_or(cosim::to_time_point(0))); + double tolerance = relativeTolerance.value_or(0); + + slave_->setup_experiment(start, stop, tolerance); + slave_->enter_initialization_mode(); +} + +void cosim::proxy::remote_slave::start_simulation() +{ + slave_->exit_initialization_mode(); +} + +void cosim::proxy::remote_slave::end_simulation() +{ + if (!terminated_) { + slave_->terminate(); + terminated_ = true; + } +} + +cosim::step_result cosim::proxy::remote_slave::do_step(cosim::time_point currentTime, cosim::duration deltaT) +{ + slave_->step(to_double_time_point(currentTime), to_double_duration(deltaT, startTime_)); + return cosim::step_result::complete; +} + +void cosim::proxy::remote_slave::get_real_variables(gsl::span variables, + gsl::span values) const +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + auto data = std::vector(vr.size()); + slave_->get_real(vr, data); + for (unsigned int i = 0; i < data.size(); i++) { + values[i] = data[i]; + } +} + +void cosim::proxy::remote_slave::get_integer_variables(gsl::span variables, + gsl::span values) const +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + auto data = std::vector(vr.size()); + slave_->get_integer(vr, data); + for (unsigned int i = 0; i < data.size(); i++) { + values[i] = data[i]; + } +} + +void cosim::proxy::remote_slave::get_boolean_variables(gsl::span variables, + gsl::span values) const +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + auto data = std::vector(vr.size()); + slave_->get_boolean(vr, data); + for (unsigned int i = 0; i < data.size(); i++) { + values[i] = data[i]; + } +} + +void cosim::proxy::remote_slave::get_string_variables(gsl::span variables, + gsl::span values) const +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + auto data = std::vector(vr.size()); + slave_->get_string(vr, data); + for (unsigned int i = 0; i < data.size(); i++) { + values[i] = data[i]; + } +} + +void cosim::proxy::remote_slave::set_real_variables(gsl::span variables, + gsl::span values) +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + const auto _values = std::vector(values.begin(), values.end()); + slave_->set_real(vr, _values); +} + +void cosim::proxy::remote_slave::set_integer_variables(gsl::span variables, + gsl::span values) +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + const auto _values = std::vector(values.begin(), values.end()); + slave_->set_integer(vr, _values); +} + +void cosim::proxy::remote_slave::set_boolean_variables(gsl::span variables, + gsl::span values) +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + const auto _values = std::vector(values.begin(), values.end()); + slave_->set_boolean(vr, _values); +} + +void cosim::proxy::remote_slave::set_string_variables(gsl::span variables, + gsl::span values) +{ + COSIM_INPUT_CHECK(variables.size() == values.size()); + if (variables.empty()) return; + + const auto vr = std::vector(variables.begin(), variables.end()); + const auto _values = std::vector(values.begin(), values.end()); + slave_->set_string(vr, _values); +} + +cosim::proxy::remote_slave::~remote_slave() +{ + remote_slave::end_simulation(); + slave_->freeInstance(); +} diff --git a/src/cosim/fmuproxy/remote_slave.hpp b/src/cosim/proxy/remote_slave.hpp similarity index 84% rename from src/cosim/fmuproxy/remote_slave.hpp rename to src/cosim/proxy/remote_slave.hpp index 9d6dd82e9..22ab0dcf3 100644 --- a/src/cosim/fmuproxy/remote_slave.hpp +++ b/src/cosim/proxy/remote_slave.hpp @@ -6,30 +6,27 @@ * 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/. */ -#ifndef COSIM_FMUPROXY_REMOTE_SLAVE_HPP -#define COSIM_FMUPROXY_REMOTE_SLAVE_HPP - -#include "FmuService.h" +#ifndef COSIM_PROXY_REMOTE_SLAVE_HPP +#define COSIM_PROXY_REMOTE_SLAVE_HPP #include -#include #include #include +#include #include namespace cosim { -namespace fmuproxy +namespace proxy { class remote_slave : public slave { public: - remote_slave(std::string instanceId, - std::shared_ptr state, + remote_slave(std::unique_ptr slave, std::shared_ptr modelDescription); cosim::model_description model_description() const override; @@ -65,13 +62,12 @@ class remote_slave : public slave private: bool terminated_; - std::string instanceId_; cosim::time_point startTime_; - std::shared_ptr state_; + std::unique_ptr slave_; std::shared_ptr modelDescription_; }; -} // namespace fmuproxy +} // namespace proxy } // namespace cosim diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b7790d1df..c3b16e43e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,11 +15,11 @@ set(tests "synchronized_xy_series_test" ) -if(LIBCOSIM_WITH_FMUPROXY AND LIBCOSIM_TEST_FMUPROXY) - list(APPEND tests - "ssp_loader_fmuproxy_test" - ) -endif() +#if(LIBCOSIM_WITH_FMUPROXY AND LIBCOSIM_TEST_FMUPROXY) +# list(APPEND tests +# "ssp_loader_fmuproxy_test" +# ) +#endif() set(unittests "async_slave_unittest" From 39a9e128cbec47787048917661d5c2e97c93d6b5 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 6 Apr 2021 14:23:00 +0200 Subject: [PATCH 02/42] link against proxy --- cmake/FindPROXY_FMU.cmake | 13 ++++++++----- src/CMakeLists.txt | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cmake/FindPROXY_FMU.cmake b/cmake/FindPROXY_FMU.cmake index 14d36d8c1..b0a5486f5 100644 --- a/cmake/FindPROXY_FMU.cmake +++ b/cmake/FindPROXY_FMU.cmake @@ -10,19 +10,22 @@ find_path(PROXY_FMU_INCLUDE_DIR NAMES proxyfmu/client/proxy_fmu.hpp) mark_as_advanced(PROXY_FMU_INCLUDE_DIR) -find_library(PROXY_FMU_LIBRARY NAMES proxy-client) -mark_as_advanced(PROXY_FMU_LIBRARY) +find_library(PROXY_FMI_LIBRARY NAMES fmi) +mark_as_advanced(PROXY_FMI_LIBRARY) + +find_library(PROXY_CLIENT_LIBRARY NAMES proxy-client) +mark_as_advanced(PROXY_CLIENT_LIBRARY) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROXY_FMU - REQUIRED_VARS PROXY_FMU_LIBRARY PROXY_FMU_INCLUDE_DIR) + REQUIRED_VARS PROXY_FMI_LIBRARY PROXY_CLIENT_LIBRARY PROXY_FMU_INCLUDE_DIR) if (PROXY_FMU_FOUND) set(PROXY_FMU_INCLUDE_DIRS ${PROXY_FMU_INCLUDE_DIR}) if (NOT PROXY_FMU_LIBRARIES) - set(PROXY_FMU_LIBRARIES ${PROXY_FMU_LIBRARY}) + set(PROXY_FMU_LIBRARIES ${PROXY_FMI_LIBRARY} ${PROXY_CLIENT_LIBRARY}) endif() if (NOT TARGET proxy-server) @@ -30,7 +33,7 @@ if (PROXY_FMU_FOUND) set_target_properties(proxy-server PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PROXY_FMU_INCLUDE_DIR}") set_property(TARGET proxy-server APPEND PROPERTY - IMPORTED_LOCATION "${PROXY_FMU_LIBRARY}") + IMPORTED_LOCATION "${PROXY_CLIENT_LIBRARY}") endif() endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2281f5d9..780aa44bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -169,6 +169,7 @@ target_link_libraries(cosim gsl PRIVATE ${FMILibrary_LIBRARIES} + ${PROXY_FMU_LIBRARIES} libzip::libzip XercesC::XercesC yaml-cpp From b33356b20bd545a7d128e3af4356d7d8443932b6 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 6 Apr 2021 17:15:37 +0200 Subject: [PATCH 03/42] wip --- .github/workflows/ci-conan.yml | 7 +-- README.md | 10 ---- conanfile.py | 4 -- src/CMakeLists.txt | 4 +- src/cosim/orchestration.cpp | 4 +- .../proxy/proxy_file_uri_sub_resolver.cpp | 31 ----------- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 51 +++++++++++++++++++ ...esolver.hpp => proxy_uri_sub_resolver.hpp} | 3 +- src/cosim/proxy/remote_fmu.cpp | 43 ++++++++++++---- tests/CMakeLists.txt | 7 +-- .../{fmuproxy => proxy}/SystemStructure.ssd | 4 +- ...oxy_test.cpp => ssp_loader_proxy_test.cpp} | 2 +- 12 files changed, 95 insertions(+), 75 deletions(-) delete mode 100644 src/cosim/proxy/proxy_file_uri_sub_resolver.cpp create mode 100644 src/cosim/proxy/proxy_uri_sub_resolver.cpp rename src/cosim/proxy/{proxy_file_uri_sub_resolver.hpp => proxy_uri_sub_resolver.hpp} (80%) rename tests/data/ssp/demo/{fmuproxy => proxy}/SystemStructure.ssd (96%) rename tests/{ssp_loader_fmuproxy_test.cpp => ssp_loader_proxy_test.cpp} (96%) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 800495494..9c3fdc924 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -24,7 +24,6 @@ jobs: build_type: [Debug, Release] compiler_version: [7, 8, 9] compiler_libcxx: [libstdc++11] - option_fmuproxy: ['fmuproxy=True', 'fmuproxy=False'] steps: - uses: actions/checkout@v2 @@ -44,7 +43,7 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -s compiler.libcxx=${{ matrix.compiler_libcxx }} -o ${{ matrix.option_fmuproxy }} -b missing . osp/${CHANNEL} + conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -s compiler.libcxx=${{ matrix.compiler_libcxx }} -b missing . osp/${CHANNEL} - name: Conan upload run: | conan upload --all -c -r osp '*' @@ -61,12 +60,10 @@ jobs: os: [windows-2016] build_type: [Debug, Release] compiler_version: [15] - option_fmuproxy: ['fmuproxy=True', 'fmuproxy=False'] exclude: - os: windows-2016 build_type: Debug - option_fmuproxy: 'fmuproxy=True' steps: - uses: actions/checkout@v2 @@ -87,6 +84,6 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -o ${{ matrix.option_fmuproxy }} -b missing . osp/${CHANNEL} + conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -b missing . osp/${CHANNEL} - name: Conan upload run: conan upload --all -c -r osp '*' diff --git a/README.md b/README.md index 54bc27167..dbddccf20 100644 --- a/README.md +++ b/README.md @@ -89,16 +89,6 @@ Then, acquire dependencies with Conan: `--settings compiler.libcxx=libstdc++11` to this command; see Step 1 for more information.) -#### FMU-Proxy -To include FMU-Proxy support, run conan install with the additional option: -```bash --o fmuproxy=True -``` -Note that it currently must be built in Release mode e.g. -```bash -conan install .. -s build_type=Release --build=missing -o fmuproxy=True -``` - Now, we can run CMake to generate the build system. (If you have not installed Doxygen at this point, append `-DLIBCOSIM_BUILD_APIDOC=OFF` to the next command to disable API documentation generation.) diff --git a/conanfile.py b/conanfile.py index 963882804..841ce98be 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,10 +41,6 @@ def imports(self): self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) - # def requirements(self): - # if self.options.fmuproxy: - # self.requires("thrift/0.13.0") - def configure_cmake(self): cmake = CMake(self) cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 780aa44bb..5e0832b29 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,7 +54,7 @@ set(privateHeaders "cosim/fmi/glue.hpp" "cosim/fmi/windows.hpp" "cosim/observer/slave_value_provider.hpp" - "cosim/proxy/proxy_file_uri_sub_resolver.hpp" + "cosim/proxy/proxy_uri_sub_resolver.hpp" "cosim/proxy/remote_fmu.hpp" "cosim/proxy/remote_slave.hpp" "cosim/slave_simulator.hpp" @@ -90,7 +90,7 @@ set(sources "cosim/observer/time_series_observer.cpp" "cosim/orchestration.cpp" "cosim/osp_config_parser.cpp" - "cosim/proxy/proxy_file_uri_sub_resolver.cpp" + "cosim/proxy/proxy_uri_sub_resolver.cpp" "cosim/proxy/remote_fmu.cpp" "cosim/proxy/remote_slave.cpp" "cosim/scenario_parser.cpp" diff --git a/src/cosim/orchestration.cpp b/src/cosim/orchestration.cpp index 5830de48a..3467ba838 100644 --- a/src/cosim/orchestration.cpp +++ b/src/cosim/orchestration.cpp @@ -4,11 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "cosim/orchestration.hpp" -#include "cosim/proxy/proxy_file_uri_sub_resolver.hpp" #include "cosim/error.hpp" #include "cosim/fmi/fmu.hpp" #include "cosim/log/logger.hpp" +#include "cosim/proxy/proxy_uri_sub_resolver.hpp" namespace cosim { @@ -144,7 +144,7 @@ std::shared_ptr default_model_uri_resolver( resolver->add_sub_resolver( std::make_shared()); } - resolver->add_sub_resolver(std::make_shared()); + resolver->add_sub_resolver(std::make_shared()); return resolver; } diff --git a/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp deleted file mode 100644 index 5e9feb087..000000000 --- a/src/cosim/proxy/proxy_file_uri_sub_resolver.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 -#include - -#include "cosim/log/logger.hpp" - -#include - -#include - -std::shared_ptr cosim::proxy::proxy_file_uri_sub_resolver::lookup_model(const cosim::uri& modelUri) -{ - assert(modelUri.scheme().has_value()); - if (*modelUri.scheme() != "proxy-file") return nullptr; - if (modelUri.authority().has_value() && - !(modelUri.authority()->empty() || *modelUri.authority() == "localhost")) { - return nullptr; - } - if (modelUri.query().has_value() || modelUri.fragment().has_value()) { - BOOST_LOG_SEV(log::logger(), log::warning) - << "Query and/or fragment component(s) in a file:// URI were ignored: " - << modelUri; - } - const auto path = file_uri_to_path(modelUri); - if (path.extension() != ".fmu") return nullptr; - return std::make_shared(std::filesystem::path(path.string())); -} diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp new file mode 100644 index 000000000..c3a11092f --- /dev/null +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -0,0 +1,51 @@ +/* + * 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 "cosim/log/logger.hpp" +#include +#include +#include + +#include + +std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model( + const cosim::uri& baseUri, + const cosim::uri& modelUriReference) +{ + const auto& mur = modelUriReference; + const auto query = mur.query(); + if (query) { + if (query->find("file=file:///") < query->size()) { + const auto newQuery = "file=" + std::string(query->substr(13)); + return model_uri_sub_resolver::lookup_model( + baseUri, uri(mur.scheme(), mur.authority(), mur.path(), newQuery, mur.fragment())); + } else if (query->find("file=") < query->size()) { + const auto pathToAppend = cosim::file_uri_to_path(baseUri).parent_path().string(); + const auto newQuery = "file=" + pathToAppend + "/" + std::string(query->substr(5)); + return model_uri_sub_resolver::lookup_model( + baseUri, uri(mur.scheme(), mur.authority(), mur.path(), newQuery, mur.fragment())); + } + } + return model_uri_sub_resolver::lookup_model(baseUri, mur); +} + +std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model(const cosim::uri& modelUri) +{ + assert(modelUri.scheme().has_value()); + if (*modelUri.scheme() != "proxy-fmu") return nullptr; + //COSIM_INPUT_CHECK(modelUri.authority()); + //COSIM_INPUT_CHECK(modelUri.query()); + + const auto query = modelUri.path(); + if (query.substr(12, 5) == "file=") { + const auto file = std::string(query.substr(12)); + return std::make_shared(file); + } else if (query.substr(12, 4) == "url=") { + //TODO + return nullptr; + } else { + return nullptr; + } +} \ No newline at end of file diff --git a/src/cosim/proxy/proxy_file_uri_sub_resolver.hpp b/src/cosim/proxy/proxy_uri_sub_resolver.hpp similarity index 80% rename from src/cosim/proxy/proxy_file_uri_sub_resolver.hpp rename to src/cosim/proxy/proxy_uri_sub_resolver.hpp index 8e03a65b2..0fb8d34a6 100644 --- a/src/cosim/proxy/proxy_file_uri_sub_resolver.hpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.hpp @@ -22,10 +22,11 @@ namespace proxy * * From file: 'proxy-file:///models/my_model.fmu' */ -class proxy_file_uri_sub_resolver : public model_uri_sub_resolver +class proxy_uri_sub_resolver : public model_uri_sub_resolver { public: + std::shared_ptr lookup_model(const uri& baseUri, const uri& modelUriReference) override; std::shared_ptr lookup_model(const cosim::uri& uri) override; }; diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 3e6d6edc1..4b0871434 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -25,28 +25,49 @@ cosim::variable_type get_type(const proxyfmu::fmi::scalar_variable& v) } } -cosim::variable_causality get_causality(const proxyfmu::fmi::scalar_variable&) +cosim::variable_causality get_causality(const proxyfmu::fmi::scalar_variable& v) { - //TODO - return cosim::variable_causality::local; + if (v.name == "output") { + return cosim::variable_causality::output; + } else if (v.name == "input") { + return cosim::variable_causality::input; + } else if (v.name == "parameter") { + return cosim::variable_causality::parameter; + } else if (v.name == "calculated_parameter") { + return cosim::variable_causality::calculated_parameter; + } else if (v.name == "local") { + return cosim::variable_causality::local; + } else { + return cosim::variable_causality::local; + } } -cosim::variable_variability get_variability(const proxyfmu::fmi::scalar_variable&) +cosim::variable_variability get_variability(const proxyfmu::fmi::scalar_variable& v) { - //TODO - return cosim::variable_variability::continuous; + if (v.name == "discrete") { + return cosim::variable_variability::discrete; + } else if (v.name == "fixed") { + return cosim::variable_variability::fixed; + } else if (v.name == "tunable") { + return cosim::variable_variability::tunable; + } else if (v.name == "constant") { + return cosim::variable_variability::constant; + } else if (v.name == "continuous") { + return cosim::variable_variability::continuous; + } else { + return cosim::variable_variability::continuous; + } } std::unique_ptr parse_model_description(const proxyfmu::fmi::model_description& md) { auto _md = std::make_unique(); _md->uuid = md.guid; + _md->author = md.author; _md->name = md.model_name; _md->description = md.description; - _md->author = md.author; - auto vars = md.model_variables; - for (auto& var : vars) { + for (auto& var : md.model_variables) { cosim::variable_description vd; vd.name = var.name; vd.reference = var.vr; @@ -72,8 +93,8 @@ std::shared_ptr cosim::proxy::remote_fmu::descri return modelDescription_; } -std::shared_ptr cosim::proxy::remote_fmu::instantiate(std::string_view /*instanceName*/) +std::shared_ptr cosim::proxy::remote_fmu::instantiate(std::string_view instanceName) { - auto slave = std::make_shared(fmu_->new_instance(""), modelDescription_); + auto slave = std::make_shared(fmu_->new_instance(std::string(instanceName)), modelDescription_); return cosim::make_background_thread_slave(slave); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c3b16e43e..145ebb1af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,18 +9,13 @@ set(tests "multi_fixed_step_algorithm_test" "osp_config_parser_test" "ramp_modifier_test" + "ssp_loader_proxy_test" "time_series_observer_test" "trend_buffer_test" "scenario_manager_test" "synchronized_xy_series_test" ) -#if(LIBCOSIM_WITH_FMUPROXY AND LIBCOSIM_TEST_FMUPROXY) -# list(APPEND tests -# "ssp_loader_fmuproxy_test" -# ) -#endif() - set(unittests "async_slave_unittest" "function_unittest" diff --git a/tests/data/ssp/demo/fmuproxy/SystemStructure.ssd b/tests/data/ssp/demo/proxy/SystemStructure.ssd similarity index 96% rename from tests/data/ssp/demo/fmuproxy/SystemStructure.ssd rename to tests/data/ssp/demo/proxy/SystemStructure.ssd index ca8500420..9a2ddbd66 100644 --- a/tests/data/ssp/demo/fmuproxy/SystemStructure.ssd +++ b/tests/data/ssp/demo/proxy/SystemStructure.ssd @@ -9,7 +9,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/tests/ssp_loader_fmuproxy_test.cpp b/tests/ssp_loader_proxy_test.cpp similarity index 96% rename from tests/ssp_loader_fmuproxy_test.cpp rename to tests/ssp_loader_proxy_test.cpp index f06727044..e7e785c4b 100644 --- a/tests/ssp_loader_fmuproxy_test.cpp +++ b/tests/ssp_loader_proxy_test.cpp @@ -17,7 +17,7 @@ int main() const auto testDataDir = std::getenv("TEST_DATA_DIR"); REQUIRE(testDataDir); - boost::filesystem::path sspFile = boost::filesystem::path(testDataDir) / "ssp" / "demo" / "fmuproxy"; + boost::filesystem::path sspFile = boost::filesystem::path(testDataDir) / "ssp" / "demo" / "proxy"; cosim::ssp_loader loader; const auto config = loader.load(sspFile); From 93dcba3a02faa737037b322832578e2bdac2ff82 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 6 Apr 2021 18:25:10 +0200 Subject: [PATCH 04/42] sucess --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 26 ++++++++++++++----- src/cosim/proxy/proxy_uri_sub_resolver.hpp | 2 +- src/cosim/proxy/remote_fmu.cpp | 20 +++++++------- tests/data/ssp/demo/proxy/SystemStructure.ssd | 4 +-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index c3a11092f..1e7ea9be7 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -8,7 +8,17 @@ #include #include -#include +std::pair parse_authority(std::string_view auth) +{ + const auto colonIdx = auth.find(':'); + if (colonIdx == std::string::npos) { + return {std::string(auth), -1}; + } else { + const auto host = std::string(auth.substr(0, colonIdx)); + const auto port = std::stoi(std::string(auth.substr(colonIdx + 1))); + return {host, port}; + } +} std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model( const cosim::uri& baseUri, @@ -35,14 +45,16 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model { assert(modelUri.scheme().has_value()); if (*modelUri.scheme() != "proxy-fmu") return nullptr; - //COSIM_INPUT_CHECK(modelUri.authority()); - //COSIM_INPUT_CHECK(modelUri.query()); + COSIM_INPUT_CHECK(modelUri.authority()); + COSIM_INPUT_CHECK(modelUri.query()); - const auto query = modelUri.path(); - if (query.substr(12, 5) == "file=") { - const auto file = std::string(query.substr(12)); + const auto auth = parse_authority(*modelUri.authority()); + const auto query = *modelUri.query(); + if (query.substr(0, 5) == "file=") { + const auto file = std::filesystem::path(std::string(query.substr(5))); + assert(std::filesystem::exists(file)); return std::make_shared(file); - } else if (query.substr(12, 4) == "url=") { + } else if (query.substr(0, 4) == "url=") { //TODO return nullptr; } else { diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.hpp b/src/cosim/proxy/proxy_uri_sub_resolver.hpp index 0fb8d34a6..9e7385c67 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.hpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.hpp @@ -20,7 +20,7 @@ namespace proxy /** * Class for resolving fmu-proxy URI schemes. * - * From file: 'proxy-file:///models/my_model.fmu' + * From file: 'proxy-file:///localhost?models/my_model.fmu' */ class proxy_uri_sub_resolver : public model_uri_sub_resolver { diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 4b0871434..76805bcba 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -27,15 +27,15 @@ cosim::variable_type get_type(const proxyfmu::fmi::scalar_variable& v) cosim::variable_causality get_causality(const proxyfmu::fmi::scalar_variable& v) { - if (v.name == "output") { + if (v.causality == "output") { return cosim::variable_causality::output; - } else if (v.name == "input") { + } else if (v.causality == "input") { return cosim::variable_causality::input; - } else if (v.name == "parameter") { + } else if (v.causality == "parameter") { return cosim::variable_causality::parameter; - } else if (v.name == "calculated_parameter") { + } else if (v.causality == "calculated_parameter") { return cosim::variable_causality::calculated_parameter; - } else if (v.name == "local") { + } else if (v.causality == "local") { return cosim::variable_causality::local; } else { return cosim::variable_causality::local; @@ -44,15 +44,15 @@ cosim::variable_causality get_causality(const proxyfmu::fmi::scalar_variable& v) cosim::variable_variability get_variability(const proxyfmu::fmi::scalar_variable& v) { - if (v.name == "discrete") { + if (v.variability == "discrete") { return cosim::variable_variability::discrete; - } else if (v.name == "fixed") { + } else if (v.variability == "fixed") { return cosim::variable_variability::fixed; - } else if (v.name == "tunable") { + } else if (v.variability == "tunable") { return cosim::variable_variability::tunable; - } else if (v.name == "constant") { + } else if (v.variability == "constant") { return cosim::variable_variability::constant; - } else if (v.name == "continuous") { + } else if (v.variability == "continuous") { return cosim::variable_variability::continuous; } else { return cosim::variable_variability::continuous; diff --git a/tests/data/ssp/demo/proxy/SystemStructure.ssd b/tests/data/ssp/demo/proxy/SystemStructure.ssd index 9a2ddbd66..4db85db00 100644 --- a/tests/data/ssp/demo/proxy/SystemStructure.ssd +++ b/tests/data/ssp/demo/proxy/SystemStructure.ssd @@ -9,7 +9,7 @@ - + @@ -41,7 +41,7 @@ - + From a551450c79a8d9387aea32f5890bcacc6a56ef9e Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 6 Apr 2021 19:41:09 +0200 Subject: [PATCH 05/42] update --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 2 +- src/cosim/proxy/remote_fmu.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index 1e7ea9be7..8e070c58e 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -51,7 +51,7 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model const auto auth = parse_authority(*modelUri.authority()); const auto query = *modelUri.query(); if (query.substr(0, 5) == "file=") { - const auto file = std::filesystem::path(std::string(query.substr(5))); + const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); assert(std::filesystem::exists(file)); return std::make_shared(file); } else if (query.substr(0, 4) == "url=") { diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 76805bcba..e437669e7 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -64,10 +64,10 @@ std::unique_ptr parse_model_description(const proxyfmu auto _md = std::make_unique(); _md->uuid = md.guid; _md->author = md.author; - _md->name = md.model_name; + _md->name = md.modelName; _md->description = md.description; - for (auto& var : md.model_variables) { + for (auto& var : md.modelVariables) { cosim::variable_description vd; vd.name = var.name; vd.reference = var.vr; From b6c882b340ee757bfb6fdadf6508115a8cd310dc Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:31:43 +0200 Subject: [PATCH 06/42] adding cmake option for proxy and misc fixes --- .github/workflows/ci-conan.yml | 7 +++++-- CMakeLists.txt | 8 ++++++-- cmake/project-config.cmake.in | 4 ++++ conanfile.py | 9 ++++++++- src/CMakeLists.txt | 25 ++++++++++++++++++------- src/cosim/orchestration.cpp | 7 ++++++- tests/CMakeLists.txt | 7 ++++++- tools/housekeeping | 3 --- tools/tmp_cleanup | 3 +++ 9 files changed, 56 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 9c3fdc924..1dbb58122 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -24,6 +24,7 @@ jobs: build_type: [Debug, Release] compiler_version: [7, 8, 9] compiler_libcxx: [libstdc++11] + option_fmuproxy: ['proxyfmu=True', 'proxyfmu=False'] steps: - uses: actions/checkout@v2 @@ -43,7 +44,7 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -s compiler.libcxx=${{ matrix.compiler_libcxx }} -b missing . osp/${CHANNEL} + conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -s compiler.libcxx=${{ matrix.compiler_libcxx }} -o ${{ matrix.option_proxyfmu }} -b missing . osp/${CHANNEL} - name: Conan upload run: | conan upload --all -c -r osp '*' @@ -60,10 +61,12 @@ jobs: os: [windows-2016] build_type: [Debug, Release] compiler_version: [15] + option_fmuproxy: ['proxyfmu=True', 'proxyfmu=False'] exclude: - os: windows-2016 build_type: Debug + option_fmuproxy: 'proxyfmu=True' steps: - uses: actions/checkout@v2 @@ -84,6 +87,6 @@ jobs: SHORT_REFNAME="${REFNAME:0:40}" CHANNEL="testing-${SHORT_REFNAME//\//_}" fi - conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -b missing . osp/${CHANNEL} + conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -o ${{ matrix.option_proxyfmu }} -b missing . osp/${CHANNEL} - name: Conan upload run: conan upload --all -c -r osp '*' diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f8537e4f..ed6c186d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option(LIBCOSIM_BUILD_APIDOC "Build API documentation (requires Doxygen)" ON) option(LIBCOSIM_BUILD_PRIVATE_APIDOC "Build private API documentation (only used if LIBCOSIM_BUILD_APIDOC=ON)" OFF) option(LIBCOSIM_STANDALONE_INSTALLATION "Whether to build for a standalone installation (Linux only; sets a relative RPATH)" OFF) option(LIBCOSIM_USING_CONAN "Whether Conan is used for package management" OFF) +option(LIBCOSIM_USING_PROXY_FMU "Whether or not to build with proxy-fmu integration" OFF) # ============================================================================== # Global internal configuration @@ -113,7 +114,9 @@ find_package(FMILibrary REQUIRED) find_package(LIBZIP REQUIRED) find_package(YAML_CPP REQUIRED) find_package(XercesC REQUIRED) -find_package(PROXY_FMU REQUIRED) +if(LIBCOSIM_USING_PROXY_FMU) + find_package(PROXY_FMU REQUIRED) +endif() # ============================================================================== # Targets @@ -144,7 +147,7 @@ if(LIBCOSIM_BUILD_APIDOC) set(DOXYGEN_JAVADOC_AUTOBRIEF "YES") set(DOXYGEN_QT_AUTOBRIEF "YES") set(DOXYGEN_MULTILINE_CPP_IS_BRIEF "YES") - set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp" "*.c" "*/fmuproxy/*service*") + set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp" "*.c") set(doxygenInputs "${CMAKE_SOURCE_DIR}/docs" "${CMAKE_SOURCE_DIR}/include") if(LIBCOSIM_BUILD_PRIVATE_APIDOC) list(APPEND doxygenInputs @@ -206,6 +209,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/cmake/FindLIBZIP.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindMS_GSL.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindYAML_CPP.cmake" + "${CMAKE_SOURCE_DIR}/cmake/FindPROXY_FMU_.cmake" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}" ) diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in index 424ca0fa4..7a3f5e3b4 100644 --- a/cmake/project-config.cmake.in +++ b/cmake/project-config.cmake.in @@ -13,4 +13,8 @@ find_dependency(LIBZIP REQUIRED) find_dependency(YAML_CPP REQUIRED) find_dependency(XercesC REQUIRED) +if(@LIBCOSIM_USING_PROXY_FMU@) + find_dependency(PROXY_FMU REQUIRED) +endif() + list(REMOVE_AT CMAKE_MODULE_PATH -1) diff --git a/conanfile.py b/conanfile.py index c7f141c8e..9ca609ea4 100755 --- a/conanfile.py +++ b/conanfile.py @@ -22,12 +22,13 @@ class LibcosimConan(ConanFile): "libzip/1.7.3", "yaml-cpp/0.6.3", "xerces-c/3.2.2", - "proxy-fmu/0.1.0" # conflict resolution "openssl/1.1.1k" ) + options = {"proxyfmu": [True, False]} default_options = ( + "proxyfmu=False", "boost:shared=True", "fmilibrary:shared=True", "libzip:shared=True", @@ -38,6 +39,10 @@ class LibcosimConan(ConanFile): def set_version(self): self.version = tools.load(path.join(self.recipe_folder, "version.txt")).strip() + def requirements(self): + if self.options.proxyfmu: + self.requires("proxy-fmu/0.1.0") + def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") self.copy("*.dll", dst=binDir, keep_path=False) @@ -48,6 +53,8 @@ def configure_cmake(self): cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" cmake.definitions["LIBCOSIM_BUILD_APIDOC"] = "OFF" cmake.definitions["LIBCOSIM_BUILD_TESTS"] = "OFF" + if self.options.proxyfmu: + cmake.definitions["LIBCOSIM_WITH_PROXYFMU"] = "ON" cmake.configure() return cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e0832b29..af3dc63fa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,9 +54,6 @@ set(privateHeaders "cosim/fmi/glue.hpp" "cosim/fmi/windows.hpp" "cosim/observer/slave_value_provider.hpp" - "cosim/proxy/proxy_uri_sub_resolver.hpp" - "cosim/proxy/remote_fmu.hpp" - "cosim/proxy/remote_slave.hpp" "cosim/slave_simulator.hpp" "cosim/ssp/ssp_parser.hpp" "cosim/utility/concurrency.hpp" @@ -90,9 +87,6 @@ set(sources "cosim/observer/time_series_observer.cpp" "cosim/orchestration.cpp" "cosim/osp_config_parser.cpp" - "cosim/proxy/proxy_uri_sub_resolver.cpp" - "cosim/proxy/remote_fmu.cpp" - "cosim/proxy/remote_slave.cpp" "cosim/scenario_parser.cpp" "cosim/slave_simulator.cpp" "cosim/ssp/ssp_loader.cpp" @@ -109,6 +103,19 @@ set(generatedSources "cosim/lib_info.cpp" ) +if(LIBCOSIM_USING_PROXY_FMU) + list(APPEND privateHeaders + "cosim/proxy/proxy_uri_sub_resolver.hpp" + "cosim/proxy/remote_fmu.hpp" + "cosim/proxy/remote_slave.hpp" + ) + list(APPEND sources + "cosim/proxy/proxy_uri_sub_resolver.cpp" + "cosim/proxy/remote_fmu.cpp" + "cosim/proxy/remote_slave.cpp" + ) +endif() + # ============================================================================== # Code generation # ============================================================================== @@ -169,12 +176,16 @@ target_link_libraries(cosim gsl PRIVATE ${FMILibrary_LIBRARIES} - ${PROXY_FMU_LIBRARIES} libzip::libzip XercesC::XercesC yaml-cpp ) +if(LIBCOSIM_USING_PROXY_FMU) + target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") + target_link_libraries(cosim PRIVATE ${PROXY_FMU_LIBRARIES}) +endif () + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_link_libraries(cosim INTERFACE "atomic") endif() diff --git a/src/cosim/orchestration.cpp b/src/cosim/orchestration.cpp index 3467ba838..89048cd9e 100644 --- a/src/cosim/orchestration.cpp +++ b/src/cosim/orchestration.cpp @@ -8,7 +8,10 @@ #include "cosim/error.hpp" #include "cosim/fmi/fmu.hpp" #include "cosim/log/logger.hpp" -#include "cosim/proxy/proxy_uri_sub_resolver.hpp" + +#ifdef HAS_PROXYFMU +# include "cosim/proxy/proxy_uri_sub_resolver.hpp" +#endif namespace cosim { @@ -144,7 +147,9 @@ std::shared_ptr default_model_uri_resolver( resolver->add_sub_resolver( std::make_shared()); } +#ifdef HAS_PROXYFMU resolver->add_sub_resolver(std::make_shared()); +#endif return resolver; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 145ebb1af..51ce636f3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,13 +9,18 @@ set(tests "multi_fixed_step_algorithm_test" "osp_config_parser_test" "ramp_modifier_test" - "ssp_loader_proxy_test" "time_series_observer_test" "trend_buffer_test" "scenario_manager_test" "synchronized_xy_series_test" ) +if(LIBCOSIM_WITH_PROXYFMU) + list(APPEND tests + "ssp_loader_proxy_test" + ) +endif() + set(unittests "async_slave_unittest" "function_unittest" diff --git a/tools/housekeeping b/tools/housekeeping index f294212a0..186e0d13b 100755 --- a/tools/housekeeping +++ b/tools/housekeeping @@ -12,9 +12,6 @@ set -o errexit -o nounset -o pipefail # Regex to select files for clang-format readonly clangFormattableFiles='\.(h|c|hpp|cpp)$' -# Regex to exclude files from clang-format -readonly excludeFromClangFormat='(include/cse/fmuproxy|src/cpp/fmuproxy)/(fmu_service|service_types)' - # Per-file corrections for f in $(git ls-files); do # Ensure that only executable files have executable permissions diff --git a/tools/tmp_cleanup b/tools/tmp_cleanup index 9a9525940..47e4ab84a 100755 --- a/tools/tmp_cleanup +++ b/tools/tmp_cleanup @@ -14,6 +14,9 @@ rm -rf libcosim_* # FMI4j (fmu-proxy) rm -rf fmi4j_* +# proxy-fmu +rm -rf proxy_fmu_* + # Other known FMI related files # sintef vessel model FMU From 29421a32a5bb043eae161404b6f81e9babeda651 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:37:08 +0200 Subject: [PATCH 07/42] fix option name --- CMakeLists.txt | 4 ++-- cmake/project-config.cmake.in | 2 +- src/CMakeLists.txt | 4 ++-- tests/CMakeLists.txt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed6c186d6..0078b57d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ option(LIBCOSIM_BUILD_APIDOC "Build API documentation (requires Doxygen)" ON) option(LIBCOSIM_BUILD_PRIVATE_APIDOC "Build private API documentation (only used if LIBCOSIM_BUILD_APIDOC=ON)" OFF) option(LIBCOSIM_STANDALONE_INSTALLATION "Whether to build for a standalone installation (Linux only; sets a relative RPATH)" OFF) option(LIBCOSIM_USING_CONAN "Whether Conan is used for package management" OFF) -option(LIBCOSIM_USING_PROXY_FMU "Whether or not to build with proxy-fmu integration" OFF) +option(LIBCOSIM_WITH_PROXYFMU "Whether or not to build with proxy-fmu integration" OFF) # ============================================================================== # Global internal configuration @@ -114,7 +114,7 @@ find_package(FMILibrary REQUIRED) find_package(LIBZIP REQUIRED) find_package(YAML_CPP REQUIRED) find_package(XercesC REQUIRED) -if(LIBCOSIM_USING_PROXY_FMU) +if(LIBCOSIM_WITH_PROXYFMU) find_package(PROXY_FMU REQUIRED) endif() diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in index 7a3f5e3b4..e1659e418 100644 --- a/cmake/project-config.cmake.in +++ b/cmake/project-config.cmake.in @@ -13,7 +13,7 @@ find_dependency(LIBZIP REQUIRED) find_dependency(YAML_CPP REQUIRED) find_dependency(XercesC REQUIRED) -if(@LIBCOSIM_USING_PROXY_FMU@) +if(@LIBCOSIM_WITH_PROXYFMU@) find_dependency(PROXY_FMU REQUIRED) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af3dc63fa..8d7e7d5e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,7 +103,7 @@ set(generatedSources "cosim/lib_info.cpp" ) -if(LIBCOSIM_USING_PROXY_FMU) +if(LIBCOSIM_WITH_PROXYFMU) list(APPEND privateHeaders "cosim/proxy/proxy_uri_sub_resolver.hpp" "cosim/proxy/remote_fmu.hpp" @@ -181,7 +181,7 @@ target_link_libraries(cosim yaml-cpp ) -if(LIBCOSIM_USING_PROXY_FMU) +if(LIBCOSIM_WITH_PROXYFMU) target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") target_link_libraries(cosim PRIVATE ${PROXY_FMU_LIBRARIES}) endif () diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 51ce636f3..d874f4dc8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,7 @@ set(tests if(LIBCOSIM_WITH_PROXYFMU) list(APPEND tests - "ssp_loader_proxy_test" + "ssp_loader_proxy_test" ) endif() From 9b9b13c0e2c2560b1c5463031b0fe74a7bf69b1b Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:40:24 +0200 Subject: [PATCH 08/42] add newline --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index 8e070c58e..afb8d5d3d 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -60,4 +60,4 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model } else { return nullptr; } -} \ No newline at end of file +} From d8a94065fb615edb36ea9d321b3223c65060f52f Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:40:31 +0200 Subject: [PATCH 09/42] fix option name --- .github/workflows/ci-conan.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 1dbb58122..fdaa87816 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -61,12 +61,12 @@ jobs: os: [windows-2016] build_type: [Debug, Release] compiler_version: [15] - option_fmuproxy: ['proxyfmu=True', 'proxyfmu=False'] + option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] exclude: - os: windows-2016 build_type: Debug - option_fmuproxy: 'proxyfmu=True' + option_proxyfmu: 'proxyfmu=True' steps: - uses: actions/checkout@v2 From 9a49a27f86ee2e234f4fb655e8899507a395dce7 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:51:44 +0200 Subject: [PATCH 10/42] typo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0078b57d0..3adfe7797 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,7 +209,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/cmake/FindLIBZIP.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindMS_GSL.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindYAML_CPP.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindPROXY_FMU_.cmake" + "${CMAKE_SOURCE_DIR}/cmake/FindPROXY_FMU.cmake" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}" ) From 77ba5c7cfa9c90053329c9a5812f58de7f74624e Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 09:59:22 +0200 Subject: [PATCH 11/42] fix option name --- .github/workflows/ci-conan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index fdaa87816..1125c02d0 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -24,7 +24,7 @@ jobs: build_type: [Debug, Release] compiler_version: [7, 8, 9] compiler_libcxx: [libstdc++11] - option_fmuproxy: ['proxyfmu=True', 'proxyfmu=False'] + option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] steps: - uses: actions/checkout@v2 From c3e6e57152f3bede36aff3f7a181f6992dd4faa1 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 7 Apr 2021 14:56:08 +0200 Subject: [PATCH 12/42] update target --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 9ca609ea4..14f922122 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,7 +41,7 @@ def set_version(self): def requirements(self): if self.options.proxyfmu: - self.requires("proxy-fmu/0.1.0") + self.requires("proxy-fmu/0.1.0@osp/testing") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") From 9af60ffeb1418fd7125eb8095f08ac2ee6d6f16f Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 10 Apr 2021 01:17:02 +0200 Subject: [PATCH 13/42] actually use remote proxy feature.. --- CMakeLists.txt | 2 +- cmake/FindFMILibrary.cmake | 43 ++++++++++++---------- conanfile.py | 2 +- src/CMakeLists.txt | 2 +- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 8 +++- src/cosim/proxy/remote_fmu.cpp | 8 +++- src/cosim/proxy/remote_fmu.hpp | 3 +- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3adfe7797..fc3203ed2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ find_package(LIBZIP REQUIRED) find_package(YAML_CPP REQUIRED) find_package(XercesC REQUIRED) if(LIBCOSIM_WITH_PROXYFMU) - find_package(PROXY_FMU REQUIRED) + find_package(PROXYFMU CONFIG REQUIRED) endif() # ============================================================================== diff --git a/cmake/FindFMILibrary.cmake b/cmake/FindFMILibrary.cmake index e2dbe04c3..530e7572d 100644 --- a/cmake/FindFMILibrary.cmake +++ b/cmake/FindFMILibrary.cmake @@ -28,7 +28,6 @@ # FMILibrary_LIBRARY - Path to static library. # FMILibrary_SHARED_LIBRARY - Path to shared/import library. # -cmake_minimum_required (VERSION 2.8.11) # Find static library, and use its path prefix to provide a HINTS option to the # other find_*() commands. @@ -97,31 +96,35 @@ unset (_FMILibrary_hints) # Create the IMPORTED targets. if (FMILibrary_LIBRARY) - add_library ("fmilib::static" STATIC IMPORTED) - set_target_properties ("fmilib::static" PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_DL_LIBS}" - IMPORTED_LOCATION "${FMILibrary_LIBRARY}" - INTERFACE_COMPILE_DEFINITIONS "FMILibrary_STATIC_LIB_ONLY" - INTERFACE_INCLUDE_DIRECTORIES "${FMILibrary_INCLUDE_DIRS}") + if (NOT TARGET fmilib::static) + add_library ("fmilib::static" STATIC IMPORTED) + set_target_properties ("fmilib::static" PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_DL_LIBS}" + IMPORTED_LOCATION "${FMILibrary_LIBRARY}" + INTERFACE_COMPILE_DEFINITIONS "FMILibrary_STATIC_LIB_ONLY" + INTERFACE_INCLUDE_DIRECTORIES "${FMILibrary_INCLUDE_DIRS}") + endif() endif () if (FMILibrary_SHARED_LIBRARY) - add_library ("fmilib::shared" SHARED IMPORTED) - set_target_properties ("fmilib::shared" PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - INTERFACE_INCLUDE_DIRECTORIES "${FMILibrary_INCLUDE_DIRS}") - if (WIN32) + if (NOT TARGET fmilib::shared) + add_library ("fmilib::shared" SHARED IMPORTED) set_target_properties ("fmilib::shared" PROPERTIES - IMPORTED_IMPLIB "${FMILibrary_SHARED_LIBRARY}") - if (FMILibrary_DLL) + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + INTERFACE_INCLUDE_DIRECTORIES "${FMILibrary_INCLUDE_DIRS}") + if (WIN32) set_target_properties ("fmilib::shared" PROPERTIES - IMPORTED_LOCATION "${FMILibrary_DLL}") + IMPORTED_IMPLIB "${FMILibrary_SHARED_LIBRARY}") + if (FMILibrary_DLL) + set_target_properties ("fmilib::shared" PROPERTIES + IMPORTED_LOCATION "${FMILibrary_DLL}") + endif () + else () # not WIN32 + set_target_properties ("fmilib::shared" PROPERTIES + IMPORTED_LOCATION "${FMILibrary_SHARED_LIBRARY}") endif () - else () # not WIN32 - set_target_properties ("fmilib::shared" PROPERTIES - IMPORTED_LOCATION "${FMILibrary_SHARED_LIBRARY}") - endif () + endif() endif () # Set the FMILibrary_LIBRARIES variable. diff --git a/conanfile.py b/conanfile.py index 14f922122..904809519 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,7 +41,7 @@ def set_version(self): def requirements(self): if self.options.proxyfmu: - self.requires("proxy-fmu/0.1.0@osp/testing") + self.requires("proxy-fmu/0.2.0@osp/testing-feature_remote") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d7e7d5e8..382bc4bff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,7 +183,7 @@ target_link_libraries(cosim if(LIBCOSIM_WITH_PROXYFMU) target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") - target_link_libraries(cosim PRIVATE ${PROXY_FMU_LIBRARIES}) + target_link_libraries(cosim PRIVATE PROXYFMU::proxy-client) endif () if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index afb8d5d3d..c8ddf3648 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -7,6 +7,7 @@ #include #include #include +#include std::pair parse_authority(std::string_view auth) { @@ -53,7 +54,12 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model if (query.substr(0, 5) == "file=") { const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); assert(std::filesystem::exists(file)); - return std::make_shared(file); + if (auth.first == "localhost") { + return std::make_shared(file); + } else { + return std::make_shared(file, proxyfmu::remote_info(auth.first, auth.second)); + } + } else if (query.substr(0, 4) == "url=") { //TODO return nullptr; diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index e437669e7..bbb315e9d 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -6,6 +6,10 @@ #include #include #include +#include + +using namespace proxyfmu; +using namespace proxyfmu::client; namespace { @@ -82,8 +86,8 @@ std::unique_ptr parse_model_description(const proxyfmu } // namespace -cosim::proxy::remote_fmu::remote_fmu(const std::filesystem::path& fmuPath) - : fmu_(proxyfmu::fmi::loadFmu(fmuPath)) +cosim::proxy::remote_fmu::remote_fmu(const std::filesystem::path& fmuPath, const std::optional& remote) + : fmu_(std::make_unique(fmuPath, remote)) , modelDescription_(parse_model_description(fmu_->get_model_description())) { } diff --git a/src/cosim/proxy/remote_fmu.hpp b/src/cosim/proxy/remote_fmu.hpp index 11fe4a9c4..5944e7b23 100644 --- a/src/cosim/proxy/remote_fmu.hpp +++ b/src/cosim/proxy/remote_fmu.hpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace cosim { @@ -27,7 +28,7 @@ class remote_fmu : public cosim::model { public: - explicit remote_fmu(const std::filesystem::path& fmuPath); + explicit remote_fmu(const std::filesystem::path& fmuPath, const std::optional& remote = std::nullopt); std::shared_ptr description() const noexcept override; From eb88472e3db4e74ab00692b196474dc6e8e16fd0 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 10 Apr 2021 01:51:34 +0200 Subject: [PATCH 14/42] copy proxy_server.exe --- conanfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conanfile.py b/conanfile.py index 904809519..339d7a72d 100755 --- a/conanfile.py +++ b/conanfile.py @@ -45,6 +45,7 @@ def requirements(self): def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") + self.copy("proxy_server.exe", dst=binDir, src="bin", keep_path=False) self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) From 1710002b4579332b349268b8212f24ce966f7045 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 10 Apr 2021 20:09:10 +0200 Subject: [PATCH 15/42] update --- conanfile.py | 2 +- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 5 ++--- src/cosim/proxy/remote_fmu.cpp | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conanfile.py b/conanfile.py index 339d7a72d..d8b8bd209 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,7 +41,7 @@ def set_version(self): def requirements(self): if self.options.proxyfmu: - self.requires("proxy-fmu/0.2.0@osp/testing-feature_remote") + self.requires("proxy-fmu/0.2.0@osp/testing") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index c8ddf3648..d214c9ae5 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -7,9 +7,8 @@ #include #include #include -#include -std::pair parse_authority(std::string_view auth) +std::pair parse_authority(std::string_view auth) { const auto colonIdx = auth.find(':'); if (colonIdx == std::string::npos) { @@ -54,7 +53,7 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model if (query.substr(0, 5) == "file=") { const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); assert(std::filesystem::exists(file)); - if (auth.first == "localhost") { + if (auth.first == "localhost" && auth.second == -1) { return std::make_shared(file); } else { return std::make_shared(file, proxyfmu::remote_info(auth.first, auth.second)); diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index bbb315e9d..6d2996afb 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -99,6 +99,7 @@ std::shared_ptr cosim::proxy::remote_fmu::descri std::shared_ptr cosim::proxy::remote_fmu::instantiate(std::string_view instanceName) { - auto slave = std::make_shared(fmu_->new_instance(std::string(instanceName)), modelDescription_); + auto proxySlave = fmu_->new_instance(std::string(instanceName)); + auto slave = std::make_shared(std::move(proxySlave), modelDescription_); return cosim::make_background_thread_slave(slave); } From 9dd2a9c63bb508ebebeb85ee4e9085fa2c1d0b5a Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 12 Apr 2021 20:16:01 +0200 Subject: [PATCH 16/42] updated namespace --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 382bc4bff..7f2b39eeb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,7 +183,7 @@ target_link_libraries(cosim if(LIBCOSIM_WITH_PROXYFMU) target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") - target_link_libraries(cosim PRIVATE PROXYFMU::proxy-client) + target_link_libraries(cosim PRIVATE proxyfmu::proxy-client) endif () if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") From ef930b5ee3071a48f736fa4eb02a2f8634b896e1 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 12 Apr 2021 20:16:13 +0200 Subject: [PATCH 17/42] check status --- src/cosim/proxy/remote_slave.cpp | 60 +++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/cosim/proxy/remote_slave.cpp b/src/cosim/proxy/remote_slave.cpp index abc433f30..8ab95a224 100644 --- a/src/cosim/proxy/remote_slave.cpp +++ b/src/cosim/proxy/remote_slave.cpp @@ -31,13 +31,22 @@ void cosim::proxy::remote_slave::setup(cosim::time_point startTime, std::optiona double stop = to_double_time_point(stopTime.value_or(cosim::to_time_point(0))); double tolerance = relativeTolerance.value_or(0); - slave_->setup_experiment(start, stop, tolerance); - slave_->enter_initialization_mode(); + auto status = slave_->setup_experiment(start, stop, tolerance); + if (!status) { + COSIM_PANIC(); + } + status = slave_->enter_initialization_mode(); + if (!status) { + COSIM_PANIC(); + } } void cosim::proxy::remote_slave::start_simulation() { - slave_->exit_initialization_mode(); + auto status = slave_->exit_initialization_mode(); + if (!status) { + COSIM_PANIC(); + } } void cosim::proxy::remote_slave::end_simulation() @@ -50,7 +59,10 @@ void cosim::proxy::remote_slave::end_simulation() cosim::step_result cosim::proxy::remote_slave::do_step(cosim::time_point currentTime, cosim::duration deltaT) { - slave_->step(to_double_time_point(currentTime), to_double_duration(deltaT, startTime_)); + auto status = slave_->step(to_double_time_point(currentTime), to_double_duration(deltaT, startTime_)); + if (!status) { + COSIM_PANIC(); + } return cosim::step_result::complete; } @@ -62,7 +74,10 @@ void cosim::proxy::remote_slave::get_real_variables(gsl::span(variables.begin(), variables.end()); auto data = std::vector(vr.size()); - slave_->get_real(vr, data); + auto status = slave_->get_real(vr, data); + if (!status) { + COSIM_PANIC(); + } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; } @@ -76,7 +91,10 @@ void cosim::proxy::remote_slave::get_integer_variables(gsl::span(variables.begin(), variables.end()); auto data = std::vector(vr.size()); - slave_->get_integer(vr, data); + auto status = slave_->get_integer(vr, data); + if (!status) { + COSIM_PANIC(); + } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; } @@ -90,7 +108,10 @@ void cosim::proxy::remote_slave::get_boolean_variables(gsl::span(variables.begin(), variables.end()); auto data = std::vector(vr.size()); - slave_->get_boolean(vr, data); + auto status = slave_->get_boolean(vr, data); + if (!status) { + COSIM_PANIC(); + } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; } @@ -104,7 +125,10 @@ void cosim::proxy::remote_slave::get_string_variables(gsl::span(variables.begin(), variables.end()); auto data = std::vector(vr.size()); - slave_->get_string(vr, data); + auto status = slave_->get_string(vr, data); + if (!status) { + COSIM_PANIC(); + } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; } @@ -118,7 +142,10 @@ void cosim::proxy::remote_slave::set_real_variables(gsl::span(variables.begin(), variables.end()); const auto _values = std::vector(values.begin(), values.end()); - slave_->set_real(vr, _values); + auto status = slave_->set_real(vr, _values); + if (!status) { + COSIM_PANIC(); + } } void cosim::proxy::remote_slave::set_integer_variables(gsl::span variables, @@ -129,7 +156,10 @@ void cosim::proxy::remote_slave::set_integer_variables(gsl::span(variables.begin(), variables.end()); const auto _values = std::vector(values.begin(), values.end()); - slave_->set_integer(vr, _values); + auto status = slave_->set_integer(vr, _values); + if (!status) { + COSIM_PANIC(); + } } void cosim::proxy::remote_slave::set_boolean_variables(gsl::span variables, @@ -140,7 +170,10 @@ void cosim::proxy::remote_slave::set_boolean_variables(gsl::span(variables.begin(), variables.end()); const auto _values = std::vector(values.begin(), values.end()); - slave_->set_boolean(vr, _values); + auto status = slave_->set_boolean(vr, _values); + if (!status) { + COSIM_PANIC(); + } } void cosim::proxy::remote_slave::set_string_variables(gsl::span variables, @@ -151,7 +184,10 @@ void cosim::proxy::remote_slave::set_string_variables(gsl::span(variables.begin(), variables.end()); const auto _values = std::vector(values.begin(), values.end()); - slave_->set_string(vr, _values); + auto status = slave_->set_string(vr, _values); + if (!status) { + COSIM_PANIC(); + } } cosim::proxy::remote_slave::~remote_slave() From a99531ef5b5d1d9ad6a64c21703e4e2bfb754a7f Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 13 Apr 2021 14:59:22 +0200 Subject: [PATCH 18/42] change uri --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 2 +- tests/data/ssp/demo/proxy/SystemStructure.ssd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index d214c9ae5..b8ec06ede 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -44,7 +44,7 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model(const cosim::uri& modelUri) { assert(modelUri.scheme().has_value()); - if (*modelUri.scheme() != "proxy-fmu") return nullptr; + if (*modelUri.scheme() != "proxyfmu") return nullptr; COSIM_INPUT_CHECK(modelUri.authority()); COSIM_INPUT_CHECK(modelUri.query()); diff --git a/tests/data/ssp/demo/proxy/SystemStructure.ssd b/tests/data/ssp/demo/proxy/SystemStructure.ssd index 4db85db00..bee51c61d 100644 --- a/tests/data/ssp/demo/proxy/SystemStructure.ssd +++ b/tests/data/ssp/demo/proxy/SystemStructure.ssd @@ -9,7 +9,7 @@ - + @@ -41,7 +41,7 @@ - + From 44f0d52c423406ccdfafa0eb68059130ba4f3dd6 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 14 Apr 2021 09:27:34 +0200 Subject: [PATCH 19/42] update --- conanfile.py | 4 ++-- src/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index d8b8bd209..5e8ed8079 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,11 +41,11 @@ def set_version(self): def requirements(self): if self.options.proxyfmu: - self.requires("proxy-fmu/0.2.0@osp/testing") + self.requires("proxyfmu/0.2.0@osp/testing") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") - self.copy("proxy_server.exe", dst=binDir, src="bin", keep_path=False) + self.copy("proxyfmu.exe", dst=binDir, src="bin", keep_path=False) self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7f2b39eeb..834f78f70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,7 +183,7 @@ target_link_libraries(cosim if(LIBCOSIM_WITH_PROXYFMU) target_compile_definitions(cosim PRIVATE "HAS_PROXYFMU") - target_link_libraries(cosim PRIVATE proxyfmu::proxy-client) + target_link_libraries(cosim PRIVATE proxyfmu::proxyfmu-client) endif () if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") From 2835d6a859fccf5bad39b6f1f27409992a795c20 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 09:56:27 +0200 Subject: [PATCH 20/42] Update readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index dbddccf20..485065cce 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,16 @@ Then, acquire dependencies with Conan: `--settings compiler.libcxx=libstdc++11` to this command; see Step 1 for more information.) +#### proxyfmu +To include proxyfmu support, run conan install with the additional option: +```bash +-o proxyfmu=True +``` +Note that it currently must be built in Release mode e.g. +```bash +conan install .. -s build_type=Release --build=missing -o proxyfmu=True +``` + Now, we can run CMake to generate the build system. (If you have not installed Doxygen at this point, append `-DLIBCOSIM_BUILD_APIDOC=OFF` to the next command to disable API documentation generation.) From 8f47dd63b8e6ef70021e950e9bceb1e3ee4066ae Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 10:44:53 +0200 Subject: [PATCH 21/42] Update conanfile.py --- conanfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 5e8ed8079..522660ed2 100755 --- a/conanfile.py +++ b/conanfile.py @@ -30,7 +30,6 @@ class LibcosimConan(ConanFile): default_options = ( "proxyfmu=False", "boost:shared=True", - "fmilibrary:shared=True", "libzip:shared=True", "yaml-cpp:shared=True", "xerces-c:shared=True" From f80a4fe5365a42915ef8663ef064b2284464e595 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 11:04:50 +0200 Subject: [PATCH 22/42] Update conanfile.py --- conanfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conanfile.py b/conanfile.py index 522660ed2..5e8ed8079 100755 --- a/conanfile.py +++ b/conanfile.py @@ -30,6 +30,7 @@ class LibcosimConan(ConanFile): default_options = ( "proxyfmu=False", "boost:shared=True", + "fmilibrary:shared=True", "libzip:shared=True", "yaml-cpp:shared=True", "xerces-c:shared=True" From f0d6fd23ca2f78f8fc6592dd782c95ba96695359 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 11:25:02 +0200 Subject: [PATCH 23/42] gcc7 filesystem fix --- src/cosim/proxy/remote_fmu.cpp | 2 +- src/cosim/proxy/remote_fmu.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 6d2996afb..71709c411 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -86,7 +86,7 @@ std::unique_ptr parse_model_description(const proxyfmu } // namespace -cosim::proxy::remote_fmu::remote_fmu(const std::filesystem::path& fmuPath, const std::optional& remote) +cosim::proxy::remote_fmu::remote_fmu(const proxyfmu::filesystem::path& fmuPath, const std::optional& remote) : fmu_(std::make_unique(fmuPath, remote)) , modelDescription_(parse_model_description(fmu_->get_model_description())) { diff --git a/src/cosim/proxy/remote_fmu.hpp b/src/cosim/proxy/remote_fmu.hpp index 5944e7b23..eff9c4fd7 100644 --- a/src/cosim/proxy/remote_fmu.hpp +++ b/src/cosim/proxy/remote_fmu.hpp @@ -13,9 +13,9 @@ #include #include -#include #include #include +#include #include namespace cosim @@ -28,7 +28,7 @@ class remote_fmu : public cosim::model { public: - explicit remote_fmu(const std::filesystem::path& fmuPath, const std::optional& remote = std::nullopt); + explicit remote_fmu(const proxyfmu::filesystem::path& fmuPath, const std::optional& remote = std::nullopt); std::shared_ptr description() const noexcept override; From 784f1a0a08941c3fc874c99cbff122f8f3d64d88 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 11:26:50 +0200 Subject: [PATCH 24/42] exclude debug for proxyfmu --- .github/workflows/ci-conan.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 1125c02d0..f1185d532 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -26,6 +26,11 @@ jobs: compiler_libcxx: [libstdc++11] option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] + exclude: + - os: ubuntu-18.04 + build_type: Debug + option_proxyfmu: 'proxyfmu=True' + steps: - uses: actions/checkout@v2 - name: Install prerequisites From 480dfff3bcedbd17233accff198afb5c59c50abd Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 15 Apr 2021 12:49:03 +0200 Subject: [PATCH 25/42] Custom find is not used --- CMakeLists.txt | 1 - cmake/FindPROXY_FMU.cmake | 39 ----------------------------------- cmake/project-config.cmake.in | 2 +- 3 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 cmake/FindPROXY_FMU.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index fc3203ed2..ac32af4a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,7 +209,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/cmake/FindLIBZIP.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindMS_GSL.cmake" "${CMAKE_SOURCE_DIR}/cmake/FindYAML_CPP.cmake" - "${CMAKE_SOURCE_DIR}/cmake/FindPROXY_FMU.cmake" DESTINATION "${LIBCOSIM_CMAKE_INSTALL_DIR}" ) diff --git a/cmake/FindPROXY_FMU.cmake b/cmake/FindPROXY_FMU.cmake deleted file mode 100644 index b0a5486f5..000000000 --- a/cmake/FindPROXY_FMU.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# Find proxy-fmu -# -# Find the native proxy-server headers and libraries. -# -# PROXY_FMU_INCLUDE_DIRS - where to find proxy-fmu/... -# PROXY_FMU_LIBRARIES - List of libraries when using proxy-server. -# PROXY_FMU_FOUND - True if proxy-fmu found. -# - -find_path(PROXY_FMU_INCLUDE_DIR NAMES proxyfmu/client/proxy_fmu.hpp) -mark_as_advanced(PROXY_FMU_INCLUDE_DIR) - -find_library(PROXY_FMI_LIBRARY NAMES fmi) -mark_as_advanced(PROXY_FMI_LIBRARY) - -find_library(PROXY_CLIENT_LIBRARY NAMES proxy-client) -mark_as_advanced(PROXY_CLIENT_LIBRARY) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROXY_FMU - REQUIRED_VARS PROXY_FMI_LIBRARY PROXY_CLIENT_LIBRARY PROXY_FMU_INCLUDE_DIR) - -if (PROXY_FMU_FOUND) - - set(PROXY_FMU_INCLUDE_DIRS ${PROXY_FMU_INCLUDE_DIR}) - - if (NOT PROXY_FMU_LIBRARIES) - set(PROXY_FMU_LIBRARIES ${PROXY_FMI_LIBRARY} ${PROXY_CLIENT_LIBRARY}) - endif() - - if (NOT TARGET proxy-server) - add_library(proxy-server UNKNOWN IMPORTED) - set_target_properties(proxy-server PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${PROXY_FMU_INCLUDE_DIR}") - set_property(TARGET proxy-server APPEND PROPERTY - IMPORTED_LOCATION "${PROXY_CLIENT_LIBRARY}") - endif() - -endif() diff --git a/cmake/project-config.cmake.in b/cmake/project-config.cmake.in index e1659e418..63e908676 100644 --- a/cmake/project-config.cmake.in +++ b/cmake/project-config.cmake.in @@ -14,7 +14,7 @@ find_dependency(YAML_CPP REQUIRED) find_dependency(XercesC REQUIRED) if(@LIBCOSIM_WITH_PROXYFMU@) - find_dependency(PROXY_FMU REQUIRED) + find_dependency(PROXYFMU CONFIG REQUIRED) endif() list(REMOVE_AT CMAKE_MODULE_PATH -1) From 8f9d4efcc5e33934ed5ae7b75ee0ce0640f3cab9 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Fri, 16 Apr 2021 10:18:39 +0200 Subject: [PATCH 26/42] add unittests --- src/cosim/proxy/remote_fmu.cpp | 15 ++++ tests/CMakeLists.txt | 12 +-- tests/proxyfmu_unittest.cpp | 135 ++++++++++++++++++++++++++++++++ tests/ssp_loader_proxy_test.cpp | 38 --------- 4 files changed, 156 insertions(+), 44 deletions(-) create mode 100644 tests/proxyfmu_unittest.cpp delete mode 100644 tests/ssp_loader_proxy_test.cpp diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 71709c411..0ec775085 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -78,6 +78,21 @@ std::unique_ptr parse_model_description(const proxyfmu vd.type = get_type(var); vd.causality = get_causality(var); vd.variability = get_variability(var); + + if (var.is_real()) { + const auto type = std::get(var.typeAttribute); + vd.start = type.start; + } else if (var.is_integer()) { + const auto type = std::get(var.typeAttribute); + vd.start = type.start; + } else if (var.is_boolean()) { + const auto type = std::get(var.typeAttribute); + vd.start = type.start; + } else if (var.is_string()) { + const auto type = std::get(var.typeAttribute); + vd.start = type.start; + } + _md->variables.push_back(vd); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d874f4dc8..b5f33eaa8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,12 +15,6 @@ set(tests "synchronized_xy_series_test" ) -if(LIBCOSIM_WITH_PROXYFMU) - list(APPEND tests - "ssp_loader_proxy_test" - ) -endif() - set(unittests "async_slave_unittest" "function_unittest" @@ -38,6 +32,12 @@ set(unittests "utility_zip_unittest" ) +if(LIBCOSIM_WITH_PROXYFMU) + list(APPEND unittests + "proxyfmu_unittest" + ) +endif() + include("AddTestExecutable") foreach(test IN LISTS tests) add_test_executable( diff --git a/tests/proxyfmu_unittest.cpp b/tests/proxyfmu_unittest.cpp new file mode 100644 index 000000000..bbb804db7 --- /dev/null +++ b/tests/proxyfmu_unittest.cpp @@ -0,0 +1,135 @@ +#define BOOST_TEST_MODULE proxyfmu unittests + +#include +#include +#include + +#include + +#include + +using namespace cosim; + +BOOST_AUTO_TEST_CASE(test_ssp) +{ + log::setup_simple_console_logging(); + log::set_global_output_level(log::info); + + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + BOOST_REQUIRE(testDataDir != nullptr); + boost::filesystem::path sspFile = boost::filesystem::path(testDataDir) / "ssp" / "demo" / "proxy"; + + ssp_loader loader; + const auto config = loader.load(sspFile); + auto exec = execution(config.start_time, config.algorithm); + const auto entityMaps = inject_system_structure( + exec, + config.system_structure, + config.parameter_sets.at("")); + BOOST_CHECK(entityMaps.simulators.size() == 2); + + auto result = exec.simulate_until(to_time_point(1e-3)); + BOOST_REQUIRE(result.get()); +} + +BOOST_AUTO_TEST_CASE(test_fmi1) +{ + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + BOOST_TEST_REQUIRE(!!testDataDir); + + auto path = proxyfmu::filesystem::path(testDataDir) / "fmi1" / "identity.fmu"; + auto fmu = proxy::remote_fmu(path); + + const auto d = fmu.description(); + BOOST_TEST(d->name == "no.viproma.demo.identity"); + BOOST_TEST(d->uuid.size() == 36U); + BOOST_TEST(d->description == + "Has one input and one output of each type, and outputs are always set equal to inputs"); + BOOST_TEST(d->author == "Lars Tandle Kyllingstad"); + + value_reference + realIn = 0, + integerIn = 0, booleanIn = 0, stringIn = 0, + realOut = 0, integerOut = 0, booleanOut = 0, stringOut = 0; + for (const auto& v : d->variables) { + if (v.name == "realIn") { + realIn = v.reference; + } else if (v.name == "integerIn") { + integerIn = v.reference; + } else if (v.name == "booleanIn") { + booleanIn = v.reference; + } else if (v.name == "stringIn") { + stringIn = v.reference; + } else if (v.name == "realOut") { + realOut = v.reference; + } else if (v.name == "integerOut") { + integerOut = v.reference; + } else if (v.name == "booleanOut") { + booleanOut = v.reference; + } else if (v.name == "stringOut") { + stringOut = v.reference; + } + + if (v.name == "realIn") { + BOOST_TEST(v.type == variable_type::real); + BOOST_TEST(v.variability == variable_variability::discrete); + BOOST_TEST(v.causality == variable_causality::input); + double start = std::get(*v.start); + BOOST_TEST(start == 0.0); + } else if (v.name == "stringOut") { + BOOST_TEST(v.type == variable_type::string); + BOOST_TEST(v.variability == variable_variability::discrete); + BOOST_TEST(v.causality == variable_causality::output); + BOOST_TEST(!v.start.has_value()); + } else if (v.name == "booleanIn") { + BOOST_TEST(v.type == variable_type::boolean); + BOOST_TEST(v.variability == variable_variability::discrete); + BOOST_TEST(v.causality == variable_causality::input); + bool start = std::get(*v.start); + BOOST_TEST(start == false); + } + } + + const auto tStart = time_point(); + const auto tMax = to_time_point(1.0); + const auto dt = to_duration(0.1); + + auto instance = fmu.instantiate("testSlave"); + instance->setup(tStart, tMax, std::nullopt).get(); + instance->start_simulation().get(); + + double realVal = 0.0; + int integerVal = 0; + bool booleanVal = false; + std::string stringVal; + + for (auto t = tStart; t < tMax; t += dt) { + + auto vars = instance->get_variables( + gsl::make_span(&realOut, 1), + gsl::make_span(&integerOut, 1), + gsl::make_span(&booleanOut, 1), + gsl::make_span(&stringOut, 1)).get(); + + BOOST_TEST(vars.real[0] == realVal); + BOOST_TEST(vars.integer[0] == integerVal); + BOOST_TEST(vars.boolean[0] == booleanVal); + BOOST_TEST(vars.string[0] == stringVal); + + realVal += 1.0; + integerVal += 1; + booleanVal = !booleanVal; + stringVal += 'a'; + + instance->do_step(t, dt).get(); + + instance->set_variables( + gsl::make_span(&realIn, 1), gsl::make_span(&realVal, 1), + gsl::make_span(&integerIn, 1), gsl::make_span(&integerVal, 1), + gsl::make_span(&booleanIn, 1), gsl::make_span(&booleanVal, 1), + gsl::make_span(&stringIn, 1), gsl::make_span(&stringVal, 1)).get(); + + } + + instance->end_simulation().get(); +} diff --git a/tests/ssp_loader_proxy_test.cpp b/tests/ssp_loader_proxy_test.cpp deleted file mode 100644 index e7e785c4b..000000000 --- a/tests/ssp_loader_proxy_test.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#include - -#include -#include - -#define REQUIRE(test) \ - if (!(test)) throw std::runtime_error("Requirement not satisfied: " #test) - -int main() -{ - try { - cosim::log::setup_simple_console_logging(); - cosim::log::set_global_output_level(cosim::log::info); - - const auto testDataDir = std::getenv("TEST_DATA_DIR"); - REQUIRE(testDataDir); - boost::filesystem::path sspFile = boost::filesystem::path(testDataDir) / "ssp" / "demo" / "proxy"; - - cosim::ssp_loader loader; - const auto config = loader.load(sspFile); - auto exec = cosim::execution(config.start_time, config.algorithm); - const auto entityMaps = cosim::inject_system_structure( - exec, - config.system_structure, - config.parameter_sets.at("")); - REQUIRE(entityMaps.simulators.size() == 2); - - auto result = exec.simulate_until(cosim::to_time_point(1e-3)); - REQUIRE(result.get()); - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what(); - return 1; - } - return 0; -} From 2884f1a97a27a02a1ca1abfe50e64b5ea67903c6 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 17 Apr 2021 15:27:29 +0200 Subject: [PATCH 27/42] no need for minmax check anymore --- src/cosim/algorithm/fixed_step_algorithm.cpp | 3 --- src/cosim/utility/concurrency.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/cosim/algorithm/fixed_step_algorithm.cpp b/src/cosim/algorithm/fixed_step_algorithm.cpp index 7545eb7ad..36360559a 100644 --- a/src/cosim/algorithm/fixed_step_algorithm.cpp +++ b/src/cosim/algorithm/fixed_step_algorithm.cpp @@ -3,9 +3,6 @@ * 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/. */ -#if defined(WIN32) && !defined(NOMINMAX) -# define NOMINMAX -#endif #include "cosim/algorithm/fixed_step_algorithm.hpp" #include "cosim/error.hpp" diff --git a/src/cosim/utility/concurrency.cpp b/src/cosim/utility/concurrency.cpp index fed086e30..78621c5d1 100644 --- a/src/cosim/utility/concurrency.cpp +++ b/src/cosim/utility/concurrency.cpp @@ -3,10 +3,6 @@ * 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/. */ -#if defined(_WIN32) && !defined(NOMINMAX) -# define NOMINMAX -#endif - #include "cosim/utility/concurrency.hpp" #include From d15b8eacbdb85379d77335ce69ae30f7f7db5f61 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 17 Apr 2021 15:27:47 +0200 Subject: [PATCH 28/42] add fmi2 test for proxyfmu --- tests/proxyfmu_unittest.cpp | 74 +++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/tests/proxyfmu_unittest.cpp b/tests/proxyfmu_unittest.cpp index bbb804db7..e7dbd70f0 100644 --- a/tests/proxyfmu_unittest.cpp +++ b/tests/proxyfmu_unittest.cpp @@ -1,8 +1,8 @@ #define BOOST_TEST_MODULE proxyfmu unittests #include -#include #include +#include #include @@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_fmi1) BOOST_TEST(d->name == "no.viproma.demo.identity"); BOOST_TEST(d->uuid.size() == 36U); BOOST_TEST(d->description == - "Has one input and one output of each type, and outputs are always set equal to inputs"); + "Has one input and one output of each type, and outputs are always set equal to inputs"); BOOST_TEST(d->author == "Lars Tandle Kyllingstad"); value_reference @@ -106,10 +106,11 @@ BOOST_AUTO_TEST_CASE(test_fmi1) for (auto t = tStart; t < tMax; t += dt) { auto vars = instance->get_variables( - gsl::make_span(&realOut, 1), - gsl::make_span(&integerOut, 1), - gsl::make_span(&booleanOut, 1), - gsl::make_span(&stringOut, 1)).get(); + gsl::make_span(&realOut, 1), + gsl::make_span(&integerOut, 1), + gsl::make_span(&booleanOut, 1), + gsl::make_span(&stringOut, 1)) + .get(); BOOST_TEST(vars.real[0] == realVal); BOOST_TEST(vars.integer[0] == integerVal); @@ -124,12 +125,63 @@ BOOST_AUTO_TEST_CASE(test_fmi1) instance->do_step(t, dt).get(); instance->set_variables( - gsl::make_span(&realIn, 1), gsl::make_span(&realVal, 1), - gsl::make_span(&integerIn, 1), gsl::make_span(&integerVal, 1), - gsl::make_span(&booleanIn, 1), gsl::make_span(&booleanVal, 1), - gsl::make_span(&stringIn, 1), gsl::make_span(&stringVal, 1)).get(); - + gsl::make_span(&realIn, 1), gsl::make_span(&realVal, 1), + gsl::make_span(&integerIn, 1), gsl::make_span(&integerVal, 1), + gsl::make_span(&booleanIn, 1), gsl::make_span(&booleanVal, 1), + gsl::make_span(&stringIn, 1), gsl::make_span(&stringVal, 1)) + .get(); } instance->end_simulation().get(); } + +BOOST_AUTO_TEST_CASE(test_fmi2) +{ + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + BOOST_TEST_REQUIRE(!!testDataDir); + + auto path = proxyfmu::filesystem::path(testDataDir) / "fmi2" / "WaterTank_Control.fmu"; + auto fmu = proxy::remote_fmu(path); + + const auto d = fmu.description(); + BOOST_TEST(d->name == "WaterTank.Control"); + BOOST_TEST(d->uuid == "{ad6d7bad-97d1-4fb9-ab3e-00a0d051e42c}"); + BOOST_TEST(d->description.empty()); + BOOST_TEST(d->author.empty()); + BOOST_TEST(d->version.empty()); + + auto instance = fmu.instantiate("testSlave"); + instance->setup( + cosim::to_time_point(0.0), + cosim::to_time_point(1.0), + std::nullopt) + .get(); + + bool foundValve = false; + bool foundMinlevel = false; + for (const auto& v : d->variables) { + if (v.name == "valve") { + foundValve = true; + BOOST_TEST(v.variability == variable_variability::continuous); + BOOST_TEST(v.causality == variable_causality::output); + double start = std::get(*v.start); + BOOST_TEST(start == 0.0); + const auto varID = v.reference; + double varVal = -1.0; + varVal = instance->get_variables(gsl::make_span(&varID, 1), {}, {}, {}).get().real[0]; + BOOST_TEST(varVal == 0.0); + } else if (v.name == "minlevel") { + foundMinlevel = true; + BOOST_TEST(v.variability == variable_variability::fixed); + BOOST_TEST(v.causality == variable_causality::parameter); + double start = std::get(*v.start); + BOOST_TEST(start == 1.0); + const auto varID = v.reference; + double varVal = -1.0; + varVal = instance->get_variables(gsl::make_span(&varID, 1), {}, {}, {}).get().real[0]; + BOOST_TEST(varVal == 1.0); + } + } + BOOST_TEST(foundValve); + BOOST_TEST(foundMinlevel); +} From dea41029ce0cc6f47f271733ac19ee3dd31b6a7a Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 17 Apr 2021 15:53:05 +0200 Subject: [PATCH 29/42] add test for fmi2 --- tests/proxyfmu_unittest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/proxyfmu_unittest.cpp b/tests/proxyfmu_unittest.cpp index e7dbd70f0..527280b81 100644 --- a/tests/proxyfmu_unittest.cpp +++ b/tests/proxyfmu_unittest.cpp @@ -184,4 +184,7 @@ BOOST_AUTO_TEST_CASE(test_fmi2) } BOOST_TEST(foundValve); BOOST_TEST(foundMinlevel); + + instance->start_simulation().get(); + instance->end_simulation().get(); } From 48397360aacce9e4547f33b5a4ec0a3c37ed4de7 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 19 Apr 2021 14:03:16 +0200 Subject: [PATCH 30/42] Remove CI excludes --- .github/workflows/ci-conan.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index f5f0f7884..d02826148 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -26,11 +26,6 @@ jobs: compiler_libcxx: [libstdc++11] option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] - exclude: - - os: ubuntu-18.04 - build_type: Debug - option_proxyfmu: 'proxyfmu=True' - steps: - uses: actions/checkout@v2 - name: Install prerequisites @@ -70,11 +65,6 @@ jobs: compiler_version: [15] option_proxyfmu: ['proxyfmu=True', 'proxyfmu=False'] - exclude: - - os: windows-2016 - build_type: Debug - option_proxyfmu: 'proxyfmu=True' - steps: - uses: actions/checkout@v2 - name: Install prerequisites From 95bac9935874cdd4409b796a17d7878c21d34da2 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 19 Apr 2021 14:08:57 +0200 Subject: [PATCH 31/42] fix reference to std::filesystem in debug mode --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index b8ec06ede..87eb88f8c 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -52,7 +52,7 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model const auto query = *modelUri.query(); if (query.substr(0, 5) == "file=") { const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); - assert(std::filesystem::exists(file)); + assert(proxyfmu::filesystem::exists(file)); if (auth.first == "localhost" && auth.second == -1) { return std::make_shared(file); } else { From b918e2613c8673373dfa2ca9fae0435eec65f8c1 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 19 Apr 2021 14:09:42 +0200 Subject: [PATCH 32/42] Update readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 485065cce..ec327093b 100644 --- a/README.md +++ b/README.md @@ -94,10 +94,6 @@ To include proxyfmu support, run conan install with the additional option: ```bash -o proxyfmu=True ``` -Note that it currently must be built in Release mode e.g. -```bash -conan install .. -s build_type=Release --build=missing -o proxyfmu=True -``` Now, we can run CMake to generate the build system. (If you have not installed Doxygen at this point, append `-DLIBCOSIM_BUILD_APIDOC=OFF` to the next command From 73f8d871c861661cee018524352533df6d4af6fb Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 5 May 2021 15:24:23 +0200 Subject: [PATCH 33/42] Update proxyfmu version --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 5e8ed8079..5be74e0f6 100755 --- a/conanfile.py +++ b/conanfile.py @@ -41,7 +41,7 @@ def set_version(self): def requirements(self): if self.options.proxyfmu: - self.requires("proxyfmu/0.2.0@osp/testing") + self.requires("proxyfmu/0.2.1@osp/testing") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") From ec99217950b05b1d6bddaff933176b9d97deae24 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 11 May 2021 09:34:54 +0200 Subject: [PATCH 34/42] cleanup --- .clang-format | 2 +- src/cosim/proxy/remote_fmu.cpp | 1 + src/cosim/proxy/remote_fmu.hpp | 3 ++- src/cosim/proxy/remote_slave.hpp | 1 + tools/housekeeping | 1 - 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.clang-format b/.clang-format index 22dc3d690..f45326c16 100644 --- a/.clang-format +++ b/.clang-format @@ -28,7 +28,7 @@ IncludeBlocks: Regroup IncludeCategories: - Regex: '^[<"]cosim[/.]' Priority: 20 - - Regex: '^[<"](boost|event2|fmilib|gsl|nlohmann|xercesc|zip)[/.]' + - Regex: '^[<"](boost|event2|fmilib|gsl|nlohmann|proxyfmu|xercesc|zip)[/.]' Priority: 30 - Regex: '^"' Priority: 10 diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 0ec775085..751b00a96 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -6,6 +6,7 @@ #include #include #include + #include using namespace proxyfmu; diff --git a/src/cosim/proxy/remote_fmu.hpp b/src/cosim/proxy/remote_fmu.hpp index eff9c4fd7..e26793b9e 100644 --- a/src/cosim/proxy/remote_fmu.hpp +++ b/src/cosim/proxy/remote_fmu.hpp @@ -13,11 +13,12 @@ #include #include -#include #include #include #include +#include + namespace cosim { diff --git a/src/cosim/proxy/remote_slave.hpp b/src/cosim/proxy/remote_slave.hpp index 22ab0dcf3..c75374e17 100644 --- a/src/cosim/proxy/remote_slave.hpp +++ b/src/cosim/proxy/remote_slave.hpp @@ -14,6 +14,7 @@ #include #include + #include namespace cosim diff --git a/tools/housekeeping b/tools/housekeeping index 186e0d13b..10ffe4d44 100755 --- a/tools/housekeeping +++ b/tools/housekeeping @@ -31,5 +31,4 @@ done echo "running clang-format" git ls-files \ | egrep "$clangFormattableFiles" \ - | egrep -v "$excludeFromClangFormat" \ | xargs -r clang-format -i -style=file From bf3e0797f0f70097e02a8e92eef733ffa555c985 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 11 May 2021 09:46:50 +0200 Subject: [PATCH 35/42] throw on bad file and remove empty url code path --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index 87eb88f8c..9e8d10794 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -5,6 +5,7 @@ */ #include "cosim/log/logger.hpp" #include +#include #include #include @@ -52,16 +53,15 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model const auto query = *modelUri.query(); if (query.substr(0, 5) == "file=") { const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); - assert(proxyfmu::filesystem::exists(file)); + if (!proxyfmu::filesystem::exists(file)) { + throw error(make_error_code(errc::bad_file), "No such file: " + file.string()); + } if (auth.first == "localhost" && auth.second == -1) { return std::make_shared(file); } else { return std::make_shared(file, proxyfmu::remote_info(auth.first, auth.second)); } - } else if (query.substr(0, 4) == "url=") { - //TODO - return nullptr; } else { return nullptr; } From 77dd4a480eb344af8728dc0e4ab1d436f5ffb64f Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Tue, 11 May 2021 10:50:28 +0200 Subject: [PATCH 36/42] add more tests --- tests/CMakeLists.txt | 11 ++- ....cpp => proxyfmu_integration_unittest.cpp} | 2 +- tests/proxyfmu_library_unittest.cpp | 92 +++++++++++++++++++ 3 files changed, 102 insertions(+), 3 deletions(-) rename tests/{proxyfmu_unittest.cpp => proxyfmu_integration_unittest.cpp} (99%) create mode 100644 tests/proxyfmu_library_unittest.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b5f33eaa8..e91361715 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,7 +34,8 @@ set(unittests if(LIBCOSIM_WITH_PROXYFMU) list(APPEND unittests - "proxyfmu_unittest" + "proxyfmu_integration_unittest" + "proxyfmu_library_unittest" ) endif() @@ -50,11 +51,17 @@ foreach(test IN LISTS tests) endforeach() foreach(test IN LISTS unittests) + + set(dependencies cosim "Boost::unit_test_framework" "Boost::timer") + if (LIBCOSIM_WITH_PROXYFMU) + list(APPEND dependencies "proxyfmu::proxyfmu-client") + endif() + add_test_executable( "cpp_${test}" FOLDER "C++ unit tests" SOURCES "${test}.cpp" - DEPENDENCIES cosim "Boost::unit_test_framework" "Boost::timer" + DEPENDENCIES ${dependencies} DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/data" ) target_include_directories("cpp_${test}" PRIVATE "$") diff --git a/tests/proxyfmu_unittest.cpp b/tests/proxyfmu_integration_unittest.cpp similarity index 99% rename from tests/proxyfmu_unittest.cpp rename to tests/proxyfmu_integration_unittest.cpp index 527280b81..bde2e4bf6 100644 --- a/tests/proxyfmu_unittest.cpp +++ b/tests/proxyfmu_integration_unittest.cpp @@ -1,4 +1,4 @@ -#define BOOST_TEST_MODULE proxyfmu unittests +#define BOOST_TEST_MODULE proxyfmu_integration unittests #include #include diff --git a/tests/proxyfmu_library_unittest.cpp b/tests/proxyfmu_library_unittest.cpp new file mode 100644 index 000000000..76901c3e4 --- /dev/null +++ b/tests/proxyfmu_library_unittest.cpp @@ -0,0 +1,92 @@ +#define BOOST_TEST_MODULE proxyfmu_library unittests + +#include +#include + +using namespace proxyfmu; +using namespace proxyfmu::fmi; + +namespace +{ + +void test(fmu& fmu) +{ + const auto d = fmu.get_model_description(); + BOOST_TEST(d.modelName == "no.viproma.demo.identity"); + BOOST_TEST(d.description == + "Has one input and one output of each type, and outputs are always set equal to inputs"); + BOOST_TEST(d.author == "Lars Tandle Kyllingstad"); + + auto slave = fmu.new_instance("instance"); + BOOST_REQUIRE(slave->setup_experiment()); + BOOST_REQUIRE(slave->enter_initialization_mode()); + BOOST_REQUIRE(slave->exit_initialization_mode()); + + std::vector vr{0}; + + std::vector realVal{0.0}; + std::vector integerVal{0}; + std::vector booleanVal{false}; + std::vector stringVal{""}; + + std::vector realRef(1); + std::vector integerRef(1); + std::vector booleanRef(1); + std::vector stringRef(1); + + double t = 0.0; + double tEnd = 1.0; + double dt = 0.1; + + while (t <= tEnd) { + + slave->get_real(vr, realRef); + slave->get_integer(vr, integerRef); + slave->get_boolean(vr, booleanRef); + slave->get_string(vr, stringRef); + + BOOST_TEST(realVal[0] == realRef[0]); + BOOST_TEST(integerVal[0] == integerRef[0]); + BOOST_TEST(booleanVal[0] == booleanRef[0]); + BOOST_TEST(stringVal[0] == stringRef[0]); + + BOOST_REQUIRE(slave->step(t, dt)); + + realVal[0] += 1.0; + integerVal[0] += 1; + booleanVal[0] = !booleanVal[0]; + stringVal[0] += 'a'; + + slave->set_real(vr, realVal); + slave->set_integer(vr, integerVal); + slave->set_boolean(vr, booleanVal); + slave->set_string(vr, stringVal); + + t += dt; + } + + BOOST_REQUIRE(slave->terminate()); + slave->freeInstance(); +} + +} // namespace + +BOOST_AUTO_TEST_CASE(proxyfmu_fmi_test_identity) +{ + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + BOOST_TEST_REQUIRE(!!testDataDir); + + auto fmuPath = proxyfmu::filesystem::path(testDataDir) / "fmi1" / "identity.fmu"; + auto fmu = loadFmu(fmuPath); + test(*fmu); +} + +BOOST_AUTO_TEST_CASE(proxyfmu_client_test_identity) +{ + const auto testDataDir = std::getenv("TEST_DATA_DIR"); + BOOST_TEST_REQUIRE(!!testDataDir); + + auto fmuPath = proxyfmu::filesystem::path(testDataDir) / "fmi1" / "identity.fmu"; + auto fmu = client::proxy_fmu(fmuPath); + test(fmu); +} \ No newline at end of file From 0bf69541a265dd17039ee79ef85f6120ecff8972 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Wed, 12 May 2021 08:34:38 +0200 Subject: [PATCH 37/42] copy booter and unix executables for proxyfmu to bin --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 5be74e0f6..eb2558fee 100755 --- a/conanfile.py +++ b/conanfile.py @@ -45,7 +45,7 @@ def requirements(self): def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") - self.copy("proxyfmu.exe", dst=binDir, src="bin", keep_path=False) + self.copy("proxyfmu*", dst=binDir, src="bin", keep_path=False) self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) From 2d4ef4521ce570bf260bfe2eacd3dcec4eddb9e6 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Mon, 31 May 2021 09:04:48 +0200 Subject: [PATCH 38/42] replace use of panic with exception --- src/cosim/proxy/remote_slave.cpp | 36 +++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/cosim/proxy/remote_slave.cpp b/src/cosim/proxy/remote_slave.cpp index 8ab95a224..11444721b 100644 --- a/src/cosim/proxy/remote_slave.cpp +++ b/src/cosim/proxy/remote_slave.cpp @@ -4,11 +4,23 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include +#include #include #include +namespace +{ + +void bad_status_throw(const std::string& method) +{ + std::string reason("Bad status returned from remote slave during call to '" + method + "'."); + throw cosim::error(make_error_code(cosim::errc::model_error), reason); +} + +} // namespace + cosim::proxy::remote_slave::remote_slave( std::unique_ptr slave, std::shared_ptr modelDescription) @@ -33,11 +45,11 @@ void cosim::proxy::remote_slave::setup(cosim::time_point startTime, std::optiona auto status = slave_->setup_experiment(start, stop, tolerance); if (!status) { - COSIM_PANIC(); + bad_status_throw("setup_experiment"); } status = slave_->enter_initialization_mode(); if (!status) { - COSIM_PANIC(); + bad_status_throw("enter_initialization_mode"); } } @@ -45,7 +57,7 @@ void cosim::proxy::remote_slave::start_simulation() { auto status = slave_->exit_initialization_mode(); if (!status) { - COSIM_PANIC(); + bad_status_throw("exit_initialization_mode"); } } @@ -61,7 +73,7 @@ cosim::step_result cosim::proxy::remote_slave::do_step(cosim::time_point current { auto status = slave_->step(to_double_time_point(currentTime), to_double_duration(deltaT, startTime_)); if (!status) { - COSIM_PANIC(); + bad_status_throw("step"); } return cosim::step_result::complete; } @@ -76,7 +88,7 @@ void cosim::proxy::remote_slave::get_real_variables(gsl::span(vr.size()); auto status = slave_->get_real(vr, data); if (!status) { - COSIM_PANIC(); + bad_status_throw("get_real"); } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; @@ -93,7 +105,7 @@ void cosim::proxy::remote_slave::get_integer_variables(gsl::span(vr.size()); auto status = slave_->get_integer(vr, data); if (!status) { - COSIM_PANIC(); + bad_status_throw("get_integer"); } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; @@ -110,7 +122,7 @@ void cosim::proxy::remote_slave::get_boolean_variables(gsl::span(vr.size()); auto status = slave_->get_boolean(vr, data); if (!status) { - COSIM_PANIC(); + bad_status_throw("get_boolean"); } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; @@ -127,7 +139,7 @@ void cosim::proxy::remote_slave::get_string_variables(gsl::span(vr.size()); auto status = slave_->get_string(vr, data); if (!status) { - COSIM_PANIC(); + bad_status_throw("get_string"); } for (unsigned int i = 0; i < data.size(); i++) { values[i] = data[i]; @@ -144,7 +156,7 @@ void cosim::proxy::remote_slave::set_real_variables(gsl::span(values.begin(), values.end()); auto status = slave_->set_real(vr, _values); if (!status) { - COSIM_PANIC(); + bad_status_throw("set_real"); } } @@ -158,7 +170,7 @@ void cosim::proxy::remote_slave::set_integer_variables(gsl::span(values.begin(), values.end()); auto status = slave_->set_integer(vr, _values); if (!status) { - COSIM_PANIC(); + bad_status_throw("set_integer"); } } @@ -172,7 +184,7 @@ void cosim::proxy::remote_slave::set_boolean_variables(gsl::span(values.begin(), values.end()); auto status = slave_->set_boolean(vr, _values); if (!status) { - COSIM_PANIC(); + bad_status_throw("set_boolean"); } } @@ -186,7 +198,7 @@ void cosim::proxy::remote_slave::set_string_variables(gsl::span(values.begin(), values.end()); auto status = slave_->set_string(vr, _values); if (!status) { - COSIM_PANIC(); + bad_status_throw("set_string"); } } From 9484ec5173a187f14fbde16e09be40600d11157a Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Thu, 3 Jun 2021 15:44:29 +0200 Subject: [PATCH 39/42] use cosim::filesystem --- src/cosim/proxy/proxy_uri_sub_resolver.cpp | 4 ++-- src/cosim/proxy/remote_fmu.cpp | 2 +- src/cosim/proxy/remote_fmu.hpp | 2 +- tests/proxyfmu_integration_unittest.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cosim/proxy/proxy_uri_sub_resolver.cpp b/src/cosim/proxy/proxy_uri_sub_resolver.cpp index 9e8d10794..15007414d 100644 --- a/src/cosim/proxy/proxy_uri_sub_resolver.cpp +++ b/src/cosim/proxy/proxy_uri_sub_resolver.cpp @@ -52,8 +52,8 @@ std::shared_ptr cosim::proxy::proxy_uri_sub_resolver::lookup_model const auto auth = parse_authority(*modelUri.authority()); const auto query = *modelUri.query(); if (query.substr(0, 5) == "file=") { - const auto file = proxyfmu::filesystem::path(std::string(query.substr(5))); - if (!proxyfmu::filesystem::exists(file)) { + const auto file = cosim::filesystem::path(std::string(query.substr(5))); + if (!cosim::filesystem::exists(file)) { throw error(make_error_code(errc::bad_file), "No such file: " + file.string()); } if (auth.first == "localhost" && auth.second == -1) { diff --git a/src/cosim/proxy/remote_fmu.cpp b/src/cosim/proxy/remote_fmu.cpp index 751b00a96..7702e55f7 100644 --- a/src/cosim/proxy/remote_fmu.cpp +++ b/src/cosim/proxy/remote_fmu.cpp @@ -102,7 +102,7 @@ std::unique_ptr parse_model_description(const proxyfmu } // namespace -cosim::proxy::remote_fmu::remote_fmu(const proxyfmu::filesystem::path& fmuPath, const std::optional& remote) +cosim::proxy::remote_fmu::remote_fmu(const cosim::filesystem::path& fmuPath, const std::optional& remote) : fmu_(std::make_unique(fmuPath, remote)) , modelDescription_(parse_model_description(fmu_->get_model_description())) { diff --git a/src/cosim/proxy/remote_fmu.hpp b/src/cosim/proxy/remote_fmu.hpp index e26793b9e..7b6a80f02 100644 --- a/src/cosim/proxy/remote_fmu.hpp +++ b/src/cosim/proxy/remote_fmu.hpp @@ -29,7 +29,7 @@ class remote_fmu : public cosim::model { public: - explicit remote_fmu(const proxyfmu::filesystem::path& fmuPath, const std::optional& remote = std::nullopt); + explicit remote_fmu(const cosim::filesystem::path& fmuPath, const std::optional& remote = std::nullopt); std::shared_ptr description() const noexcept override; diff --git a/tests/proxyfmu_integration_unittest.cpp b/tests/proxyfmu_integration_unittest.cpp index bde2e4bf6..d3bc710bd 100644 --- a/tests/proxyfmu_integration_unittest.cpp +++ b/tests/proxyfmu_integration_unittest.cpp @@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(test_ssp) const auto testDataDir = std::getenv("TEST_DATA_DIR"); BOOST_REQUIRE(testDataDir != nullptr); - boost::filesystem::path sspFile = boost::filesystem::path(testDataDir) / "ssp" / "demo" / "proxy"; + cosim::filesystem::path sspFile = cosim::filesystem::path(testDataDir) / "ssp" / "demo" / "proxy"; ssp_loader loader; const auto config = loader.load(sspFile); From 7b530418610ad71b49f2821a72b68fa6426e277b Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 14 Aug 2021 09:42:27 +0200 Subject: [PATCH 40/42] testing --- .github/workflows/ci-conan.yml | 2 ++ conanfile.py | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index d02826148..b361b86a2 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -85,5 +85,7 @@ jobs: CHANNEL="testing-${SHORT_REFNAME//\//_}" fi conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -o ${{ matrix.option_proxyfmu }} -b missing . osp/${CHANNEL} + env: + COSIM_RUN_TESTS_ON_CONAN_BUILD: true - name: Conan upload run: conan upload --all -c -r osp '*' diff --git a/conanfile.py b/conanfile.py index 8c42ecbc8..500690e09 100755 --- a/conanfile.py +++ b/conanfile.py @@ -1,6 +1,6 @@ import os -from conans import ConanFile, CMake, tools +from conans import ConanFile, CMake, RunEnvironment, tools from os import path @@ -37,16 +37,21 @@ class LibcosimConan(ConanFile): "xerces-c:shared=True" ) + @staticmethod + def is_tests_enabled(): + return os.getenv("COSIM_RUN_TESTS_ON_CONAN_BUILD", "False").lower() in ("true", "1") + def set_version(self): self.version = tools.load(path.join(self.recipe_folder, "version.txt")).strip() def requirements(self): if self.options.proxyfmu: - self.requires("proxyfmu/0.2.1@osp/testing") + self.requires("proxyfmu/0.2.2@osp/testing") def imports(self): binDir = os.path.join("output", str(self.settings.build_type).lower(), "bin") self.copy("proxyfmu*", dst=binDir, src="bin", keep_path=False) + self.copy("proxyfmu*", dst="tests", src="bin", keep_path=False) self.copy("*.dll", dst=binDir, keep_path=False) self.copy("*.pdb", dst=binDir, keep_path=False) @@ -54,7 +59,7 @@ def configure_cmake(self): cmake = CMake(self) cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" cmake.definitions["LIBCOSIM_BUILD_APIDOC"] = "OFF" - cmake.definitions["LIBCOSIM_BUILD_TESTS"] = "OFF" + cmake.definitions["LIBCOSIM_BUILD_TESTS"] = is_tests_enabled() if self.options.proxyfmu: cmake.definitions["LIBCOSIM_WITH_PROXYFMU"] = "ON" cmake.configure() @@ -63,6 +68,11 @@ def configure_cmake(self): def build(self): cmake = self.configure_cmake() cmake.build() + if is_tests_enabled(): + env_run = RunEnvironment(self) + with tools.environment_append(env_run.vars): + cmake.test(output_on_failure=True) + def package(self): cmake = self.configure_cmake() From a1d1611cff89f9e7130184ad3ce705e9165874f1 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 14 Aug 2021 09:44:38 +0200 Subject: [PATCH 41/42] testing --- conanfile.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/conanfile.py b/conanfile.py index 500690e09..7447072b6 100755 --- a/conanfile.py +++ b/conanfile.py @@ -37,8 +37,7 @@ class LibcosimConan(ConanFile): "xerces-c:shared=True" ) - @staticmethod - def is_tests_enabled(): + def is_tests_enabled(self): return os.getenv("COSIM_RUN_TESTS_ON_CONAN_BUILD", "False").lower() in ("true", "1") def set_version(self): @@ -59,7 +58,7 @@ def configure_cmake(self): cmake = CMake(self) cmake.definitions["LIBCOSIM_USING_CONAN"] = "ON" cmake.definitions["LIBCOSIM_BUILD_APIDOC"] = "OFF" - cmake.definitions["LIBCOSIM_BUILD_TESTS"] = is_tests_enabled() + cmake.definitions["LIBCOSIM_BUILD_TESTS"] = self.is_tests_enabled() if self.options.proxyfmu: cmake.definitions["LIBCOSIM_WITH_PROXYFMU"] = "ON" cmake.configure() @@ -68,7 +67,7 @@ def configure_cmake(self): def build(self): cmake = self.configure_cmake() cmake.build() - if is_tests_enabled(): + if self.is_tests_enabled(): env_run = RunEnvironment(self) with tools.environment_append(env_run.vars): cmake.test(output_on_failure=True) From 038c3cad1c8889862bb873b502aa7f7a27c2f226 Mon Sep 17 00:00:00 2001 From: Lars Ivar Hatledal Date: Sat, 14 Aug 2021 09:57:26 +0200 Subject: [PATCH 42/42] testing --- .github/workflows/ci-conan.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index b361b86a2..af0eef603 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -17,6 +17,7 @@ jobs: env: CC: gcc-${{ matrix.compiler_version }} CXX: g++-${{ matrix.compiler_version }} + COSIM_RUN_TESTS_ON_CONAN_BUILD: true strategy: fail-fast: false matrix: @@ -85,7 +86,5 @@ jobs: CHANNEL="testing-${SHORT_REFNAME//\//_}" fi conan create -s build_type=${{ matrix.build_type }} -s compiler.version=${{ matrix.compiler_version }} -o ${{ matrix.option_proxyfmu }} -b missing . osp/${CHANNEL} - env: - COSIM_RUN_TESTS_ON_CONAN_BUILD: true - name: Conan upload run: conan upload --all -c -r osp '*'