Skip to content

Commit

Permalink
Non URI file scheme equal type name support (#688)
Browse files Browse the repository at this point in the history
* Removed file scheme check

* Allow proxyfmu URI scheme

* Removed URI authority check

* Check model relative path for OspModelDescription with fmuproxy

* Fixed fmuproxy model path

* File path fix

* Added logging for debugging

* Fix prototype

* Absolute path query file support

* Added some tests

* Final testing implementation with logging

* Temporary removal of Linux file query uri tests

* Edited invalid tests

* Reintroduced non Windows tests

* Non Windows tests corrections

* UNIX filesystem compatible function rewrite

* Removed scheme assertion

* Changed input parameter from baseUri to baseParentUri

* Moved file_query_uri_to_path function from uri to osp_config_parser

* Removed unused proxyfmu client dependency for tests

Co-authored-by: msteinsto <magnus.steinsto@dnv.com>
  • Loading branch information
msteinsto and msteinsto authored Mar 29, 2022
1 parent 7dfc2ee commit 194a5da
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 14 deletions.
4 changes: 2 additions & 2 deletions include/cosim/uri.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ uri path_to_file_uri(const cosim::filesystem::path& path);
*
* \param [in] fileUri
* An URI where the scheme component is equal to `file` and the `authority`
* component is either empty or equel to `localhost` (but not undefined).
* component is either empty or equal to `localhost` (but not undefined).
*
* \returns
* The path that corresponds to `fileUri`.
Expand All @@ -275,4 +275,4 @@ cosim::filesystem::path file_uri_to_path(const uri& fileUri);


} // namespace cosim
#endif // header guard
#endif // header guard
31 changes: 19 additions & 12 deletions src/cosim/osp_config_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,20 @@ void connect_vector_sum_functions(
}
}

cosim::filesystem::path file_query_uri_to_path(
const cosim::uri& baseParentUri,
const cosim::uri& queryUri)
{
const auto query = queryUri.query();
if (query && query->find("file=") < query->size()) {
if (query->find("file=file:///") < query->size()) {
return file_uri_to_path(std::string(query->substr(5)));
}
return file_uri_to_path(std::string(baseParentUri.view()) + "/" + std::string(query->substr(5)));
}
return file_uri_to_path(baseParentUri);
}

} // namespace

osp_config load_osp_config(
Expand Down Expand Up @@ -938,19 +952,12 @@ osp_config load_osp_config(
const auto modelUri = resolve_reference(baseURI, simulator.source);
cosim::filesystem::path msmiFilePath;

if (modelUri.scheme() == "file") {
msmiFilePath = file_uri_to_path(modelUri).remove_filename() / msmiFileName;
if (cosim::filesystem::exists(msmiFilePath)) {
emds.emplace(simulator.name, msmiFilePath);
} else {
msmiFilePath = configFile.parent_path() / msmiFileName;
if (cosim::filesystem::exists(msmiFilePath)) {
emds.emplace(simulator.name, msmiFilePath);
}
}
msmiFilePath = (modelUri.scheme() == "file")
? file_uri_to_path(modelUri).remove_filename() / msmiFileName
: file_query_uri_to_path(cosim::path_to_file_uri(cosim::file_uri_to_path(baseURI).parent_path()), modelUri).remove_filename() / msmiFileName;
if (cosim::filesystem::exists(msmiFilePath)) {
emds.emplace(simulator.name, msmiFilePath);
} else {
// Makes it possible to keep OspModelDescription at configuration path
// even when there are FMUs with other URI than file (fmu-proxy).
msmiFilePath = configFile.parent_path() / msmiFileName;
if (cosim::filesystem::exists(msmiFilePath)) {
emds.emplace(simulator.name, msmiFilePath);
Expand Down
3 changes: 3 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ if(LIBCOSIM_WITH_PROXYFMU)
"proxyfmu_integration_unittest"
"proxyfmu_library_unittest"
)
list(APPEND tests
"proxyfmu_osp_config_parser_test"
)
endif()

include("AddTestExecutable")
Expand Down
45 changes: 45 additions & 0 deletions tests/data/msmi/OspSystemStructure_proxyfmu.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<OspSystemStructure
xmlns="http://opensimulationplatform.com/MSMI/OSPSystemStructure"
version="0.1">
<StartTime>0.0</StartTime>
<BaseStepSize>1e-4</BaseStepSize>
<Algorithm>fixedStep</Algorithm>
<Simulators>
<Simulator name="CraneController" source="proxyfmu://localhost?file=../ssp/demo/CraneController.fmu" stepSize="2e-4">
<InitialValues>
<InitialValue variable="cl1_min">
<Real value="2.2"/>
</InitialValue>
<InitialValue variable="cl1_max">
<Real value="3.8"/>
</InitialValue>
</InitialValues>
</Simulator>
<Simulator name="KnuckleBoomCrane" source="proxyfmu://localhost?file=../ssp/demo/KnuckleBoomCrane.fmu" stepSize="2e-4"/>
<Simulator name="TrueIdentity" source="proxyfmu://localhost?file=../fmi1/identity.fmu" stepSize="2.03e-4">
<InitialValues>
<InitialValue variable="booleanIn">
<Boolean value="true"/>
</InitialValue>
</InitialValues>
</Simulator>
<Simulator name="OneIdentity" source="proxyfmu://localhost?file=../fmi1/identity.fmu" stepSize="2.03e-4">
<InitialValues>
<InitialValue variable="booleanIn">
<Boolean value="1"/>
</InitialValue>
</InitialValues>
</Simulator>
</Simulators>
<Connections>
<VariableGroupConnection>
<VariableGroup simulator="KnuckleBoomCrane" name="actuatorLimits"/>
<VariableGroup simulator="CraneController" name="actuatorLimits"/>
</VariableGroupConnection>
<VariableGroupConnection>
<VariableGroup simulator="KnuckleBoomCrane" name="linear mechanical port"/>
<VariableGroup simulator="CraneController" name="linear mechanical port"/>
</VariableGroupConnection>
</Connections>
</OspSystemStructure>
58 changes: 58 additions & 0 deletions tests/proxyfmu_osp_config_parser_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <cosim/algorithm/fixed_step_algorithm.hpp>
#include <cosim/fs_portability.hpp>
#include <cosim/log/simple.hpp>
#include <cosim/observer/last_value_observer.hpp>
#include <cosim/orchestration.hpp>
#include <cosim/osp_config_parser.hpp>

#include <cstdlib>
#include <exception>


#define REQUIRE(test) \
if (!(test)) throw std::runtime_error("Requirement not satisfied: " #test)

void test(const cosim::filesystem::path& configPath, size_t expectedNumConnections)
{
auto resolver = cosim::default_model_uri_resolver();
const auto config = cosim::load_osp_config(configPath, *resolver);
auto execution = cosim::execution(
config.start_time,
std::make_shared<cosim::fixed_step_algorithm>(config.step_size));

const auto entityMaps = cosim::inject_system_structure(
execution, config.system_structure, config.initial_values);
REQUIRE(entityMaps.simulators.size() == 4);
REQUIRE(boost::size(config.system_structure.connections()) == expectedNumConnections);

auto obs = std::make_shared<cosim::last_value_observer>();
execution.add_observer(obs);

auto result = execution.simulate_until(cosim::to_time_point(1e-3));
REQUIRE(result.get());

const auto simIndex = entityMaps.simulators.at("CraneController");
const auto varReference =
config.system_structure.get_variable_description({"CraneController", "cl1_min"}).reference;
double realValue = -1.0;
obs->get_real(simIndex, gsl::make_span(&varReference, 1), gsl::make_span(&realValue, 1));

double magicNumberFromConf = 2.2;
REQUIRE(std::fabs(realValue - magicNumberFromConf) < 1e-9);
}

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);
test(cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_proxyfmu.xml", 9);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what();
return 1;
}
return 0;
}

0 comments on commit 194a5da

Please sign in to comment.