Skip to content

Commit 106d494

Browse files
authored
Adding support for end time (#721)
* adding support for end time * slightly modified test * remove iostreams * updated to std::optional * std::optional all the way * small fix
1 parent f8d17b1 commit 106d494

9 files changed

Lines changed: 167 additions & 8 deletions

File tree

.github/workflows/ci-cmake.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
name: CMake
1515
runs-on: ${{ matrix.os }}
1616
env:
17-
CC: gcc-${{ matrix.compiler_version }}
17+
CC: gcc-${{ matrix.compiler_version }}
1818
CXX: g++-${{ matrix.compiler_version }}
1919
strategy:
2020
fail-fast: false

data/xsd/OspSystemStructure.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<xs:complexType>
1111
<xs:sequence>
1212
<xs:element name="StartTime" minOccurs="0" default="0.0" type="xs:double"/>
13+
<xs:element name="EndTime" minOccurs="0" type="xs:double"/>
1314
<xs:element name="BaseStepSize" minOccurs="0" type="xs:double"/>
1415
<xs:element name="Algorithm" minOccurs="0" default="fixedStep" type="xs:string"/>
1516
<xs:element name="Simulators" type="osp:simulators"/>

include/cosim/osp_config_parser.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct osp_config
2727
/// The default start time for a simulation
2828
time_point start_time;
2929

30+
/// The optional end time for a simulation
31+
std::optional<time_point> end_time = std::nullopt;
32+
3033
/// The default/recommended step size for a simulation
3134
duration step_size;
3235

src/cosim/osp_config_parser.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include <unordered_map>
2828
#include <utility>
2929
#include <vector>
30+
#include <iostream>
31+
#include <optional>
3032

3133

3234
namespace cosim
@@ -119,6 +121,7 @@ class osp_config_parser
119121
std::string description;
120122
double stepSize = 0.1;
121123
double startTime = 0.0;
124+
std::optional<double> endTime;
122125
};
123126

124127
const SimulationInformation& get_simulation_information() const;
@@ -431,6 +434,11 @@ osp_config_parser::osp_config_parser(
431434
simulationInformation_.startTime = boost::lexical_cast<double>(tc(stNodes->item(0)->getTextContent()).get());
432435
}
433436

437+
auto etNodes = rootElement->getElementsByTagName(tc("EndTime").get());
438+
if (etNodes->getLength() > 0) {
439+
simulationInformation_.endTime = boost::lexical_cast<double>(tc(etNodes->item(0)->getTextContent()).get());
440+
}
441+
434442
auto connectionsElement = static_cast<xercesc::DOMElement*>(rootElement->getElementsByTagName(tc("Connections").get())->item(0));
435443
if (connectionsElement) {
436444
auto variableConnectionsElement = connectionsElement->getElementsByTagName(tc("VariableConnection").get());
@@ -914,21 +922,31 @@ osp_config load_osp_config(
914922
const auto configFile = cosim::filesystem::is_regular_file(absolutePath)
915923
? absolutePath
916924
: absolutePath / "OspSystemStructure.xml";
917-
const auto baseURI = path_to_file_uri(configFile);
918925

926+
const auto baseURI = path_to_file_uri(configFile);
919927
const auto parser = osp_config_parser(configFile);
920-
921928
const auto& simInfo = parser.get_simulation_information();
929+
922930
if (simInfo.stepSize <= 0.0) {
923931
std::ostringstream oss;
924932
oss << "Configured base step size [" << simInfo.stepSize << "] must be nonzero and positive";
925933
BOOST_LOG_SEV(log::logger(), log::error) << oss.str();
926934
throw std::invalid_argument(oss.str());
927935
}
928936

937+
if (simInfo.endTime.has_value() && simInfo.startTime > simInfo.endTime.value()) {
938+
std::ostringstream oss;
939+
oss << "Configured start time [" << simInfo.startTime << "] is larger than configured end time [" << simInfo.endTime.value() << "]";
940+
BOOST_LOG_SEV(log::logger(), log::error) << oss.str();
941+
throw std::invalid_argument(oss.str());
942+
}
943+
929944
osp_config config;
930945
config.start_time = to_time_point(simInfo.startTime);
931946
config.step_size = to_duration(simInfo.stepSize);
947+
if (simInfo.endTime.has_value()) {
948+
config.end_time = to_time_point(simInfo.endTime.value());
949+
}
932950

933951
auto simulators = parser.get_elements();
934952

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(tests
1212
"trend_buffer_test"
1313
"scenario_manager_test"
1414
"synchronized_xy_series_test"
15+
"config_end_time_test"
1516
)
1617

1718
set(unittests

tests/config_end_time_test.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <cosim/algorithm/fixed_step_algorithm.hpp>
2+
#include <cosim/fs_portability.hpp>
3+
#include <cosim/log/simple.hpp>
4+
#include <cosim/observer/last_value_observer.hpp>
5+
#include <cosim/orchestration.hpp>
6+
#include <cosim/osp_config_parser.hpp>
7+
8+
#include <cstdlib>
9+
#include <exception>
10+
#include <iostream>
11+
12+
#define REQUIRE(test) \
13+
if (!(test)) throw std::runtime_error("Requirement not satisfied: " #test)
14+
15+
16+
void test(const cosim::filesystem::path& configPath)
17+
{
18+
auto resolver = cosim::default_model_uri_resolver();
19+
const auto config = cosim::load_osp_config(configPath, *resolver);
20+
auto execution = cosim::execution(
21+
config.start_time,
22+
std::make_shared<cosim::fixed_step_algorithm>(config.step_size));
23+
24+
const auto entityMaps = cosim::inject_system_structure(
25+
execution, config.system_structure, config.initial_values);
26+
27+
REQUIRE(entityMaps.simulators.size() == 4);
28+
29+
auto obs = std::make_shared<cosim::last_value_observer>();
30+
execution.add_observer(obs);
31+
32+
if (config.end_time.has_value()) {
33+
REQUIRE(config.end_time.value().time_since_epoch().count() / 1e9 == 0.001);
34+
auto result = execution.simulate_until(config.end_time);
35+
REQUIRE(result);
36+
} else {
37+
auto result = execution.simulate_until(cosim::to_time_point(0.001));
38+
REQUIRE(result);
39+
}
40+
}
41+
42+
int main()
43+
{
44+
try {
45+
cosim::log::setup_simple_console_logging();
46+
cosim::log::set_global_output_level(cosim::log::info);
47+
48+
const auto testDataDir = std::getenv("TEST_DATA_DIR");
49+
REQUIRE(testDataDir);
50+
51+
test(cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure.xml");
52+
test(cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_EndTime.xml");
53+
} catch (const std::exception& e) {
54+
std::cerr << "Error: " << e.what();
55+
return 1;
56+
}
57+
return 0;
58+
}

tests/data/msmi/OspSystemStructure.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
xsi:schemaLocation="http://opensimulationplatform.com/MSMI/OSPSystemStructure ../../../data/xsd/OspSystemStructure.xsd"
55
xmlns="http://opensimulationplatform.com/MSMI/OSPSystemStructure"
66
version="0.1">
7-
<StartTime>0.0</StartTime>
7+
<StartTime>0.01</StartTime>
88
<BaseStepSize>1e-4</BaseStepSize>
99
<Algorithm>fixedStep</Algorithm>
1010
<Simulators>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<OspSystemStructure
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://opensimulationplatform.com/MSMI/OSPSystemStructure ../../../data/xsd/OspSystemStructure.xsd"
5+
xmlns="http://opensimulationplatform.com/MSMI/OSPSystemStructure"
6+
version="0.1">
7+
<StartTime>0.0</StartTime>
8+
<EndTime>0.001</EndTime>
9+
<BaseStepSize>1e-4</BaseStepSize>
10+
<Algorithm>fixedStep</Algorithm>
11+
<Simulators>
12+
<Simulator name="CraneController" source="../ssp/demo/CraneController.fmu" stepSize="2e-4">
13+
<InitialValues>
14+
<InitialValue variable="cl1_min">
15+
<Real value="2.2"/>
16+
</InitialValue>
17+
<InitialValue variable="cl1_max">
18+
<Real value="3.8"/>
19+
</InitialValue>
20+
</InitialValues>
21+
</Simulator>
22+
<Simulator name="KnuckleBoomCrane" source="../ssp/demo/KnuckleBoomCrane.fmu" stepSize="2.03e-4">
23+
<InitialValues/>
24+
</Simulator>
25+
<Simulator name="TrueIdentity" source="../fmi1/identity.fmu" stepSize="2.03e-4">
26+
<InitialValues>
27+
<InitialValue variable="booleanIn">
28+
<Boolean value="true"/>
29+
</InitialValue>
30+
</InitialValues>
31+
</Simulator>
32+
<Simulator name="OneIdentity" source="../fmi1/identity.fmu" stepSize="2.03e-4">
33+
<InitialValues>
34+
<InitialValue variable="booleanIn">
35+
<Boolean value="true"/>
36+
</InitialValue>
37+
</InitialValues>
38+
</Simulator>
39+
</Simulators>
40+
<Functions>
41+
<LinearTransformation name="myScaling" factor="0.1" offset="123.4"/>
42+
<Sum name="mySum" inputCount="3"/>
43+
</Functions>
44+
<Connections>
45+
<SignalConnection>
46+
<Variable simulator="KnuckleBoomCrane" name="p_Crane.f[1]"/>
47+
<Signal function="mySum" name="in[0]"/>
48+
</SignalConnection>
49+
50+
<VariableConnection>
51+
<Variable simulator="CraneController" name="p_Crane.e[1]"/>
52+
<Variable simulator="KnuckleBoomCrane" name="p_Crane.e[1]"/>
53+
</VariableConnection>
54+
55+
<SignalConnection>
56+
<Variable simulator="KnuckleBoomCrane" name="p_Crane.f[2]"/>
57+
<Signal function="mySum" name="in[1]"/>
58+
</SignalConnection>
59+
<SignalConnection>
60+
<Variable simulator="KnuckleBoomCrane" name="p_Crane.f[3]"/>
61+
<Signal function="mySum" name="in[2]"/>
62+
</SignalConnection>
63+
<SignalConnection>
64+
<Signal function="mySum" name="out"/>
65+
<Variable simulator="CraneController" name="p_Crane.f[1]"/>
66+
</SignalConnection>
67+
68+
<SignalConnection>
69+
<Variable simulator="TrueIdentity" name="realOut"/>
70+
<Signal function="myScaling" name="in"/>
71+
</SignalConnection>
72+
<SignalConnection>
73+
<Signal function="myScaling" name="out"/>
74+
<Variable simulator="OneIdentity" name="realIn"/>
75+
</SignalConnection>
76+
</Connections>
77+
</OspSystemStructure>

tests/osp_config_parser_test.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,21 @@ void test(const cosim::filesystem::path& configPath, size_t expectedNumConnectio
2222

2323
const auto entityMaps = cosim::inject_system_structure(
2424
execution, config.system_structure, config.initial_values);
25+
2526
REQUIRE(entityMaps.simulators.size() == 4);
2627
REQUIRE(boost::size(config.system_structure.connections()) == expectedNumConnections);
2728

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

31-
auto result = execution.simulate_until(cosim::to_time_point(1e-3));
32+
auto result = execution.simulate_until(cosim::to_time_point(0.01));
3233
REQUIRE(result);
3334

3435
const auto simIndex = entityMaps.simulators.at("CraneController");
35-
const auto varReference =
36-
config.system_structure.get_variable_description({"CraneController", "cl1_min"}).reference;
36+
const auto varReference1 = config.system_structure.get_variable_description({"CraneController", "cl1_min"}).reference;
3737
double realValue = -1.0;
38-
obs->get_real(simIndex, gsl::make_span(&varReference, 1), gsl::make_span(&realValue, 1));
38+
39+
obs->get_real(simIndex, gsl::make_span(&varReference1, 1), gsl::make_span(&realValue, 1));
3940

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

0 commit comments

Comments
 (0)