Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/pyfmi/fmi_algorithm_drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,22 @@ def __init__(self,
solver_options = self.solver_options)
number_of_diagnostics_variables = len(_diagnostics_vars)

#See if there is an time event at start time
#Check for events at start time
if isinstance(self.model, FMUModelME1):
event_info = self.model.get_event_info()
if event_info.upcomingTimeEvent and event_info.nextEventTime == model.time:
self.model.event_update()
elif isinstance(self.model, (FMUModelME2, CoupledFMUModelME2, FMUModelME3)):
if not self.options['initialize']:
self.model.enter_event_mode()
self.model.event_update()
self.model.enter_continuous_time_mode()
else:
event_info = self.model.get_event_info()
if event_info.nextEventTimeDefined and abs(event_info.nextEventTime - model.time) <= 1e-14:
self.model.enter_event_mode()
self.model.event_update()
self.model.enter_continuous_time_mode()

if abs(start_time - model.time) > 1e-14:
logging_module.warning('The simulation start time (%f) and the current time in the model (%f) is different. Is the simulation start time correctly set?'%(start_time, model.time))
Expand Down
3 changes: 3 additions & 0 deletions src/pyfmi/test_util.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ class Dummy_FMUModelME2(_ForTestingFMUModelME2):
def event_update(self, *args, **kwargs):
pass

def enter_event_mode(self, *args, **kwargs):
pass

def enter_continuous_time_mode(self, *args, **kwargs):
pass

Expand Down
19 changes: 18 additions & 1 deletion tests/test_fmi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,4 +1126,21 @@ def test_no_state_fmu_eval_failure_caught(fmu_path):
fmu = load_fmu(fmu_path)
expected_err = "The right-hand side function had repeated recoverable errors"
with pytest.raises(CVodeError, match = re.escape(expected_err)):
fmu.simulate()
fmu.simulate()

def test_consecutive_simulation_with_initialize_false():
"""Test that consecutive simulate() calls with initialize=False work.

The initialize=False path invokes enter_event_mode + event_update +
enter_continuous_time_mode before resuming integration. Regression
test to ensure this does not crash or corrupt the FMU state.
"""
fmu = load_fmu(REFERENCE_FMU_FMI2_PATH / "Feedthrough.fmu")

fmu.set('Int32_input', 42)
fmu.simulate(0, 0.1, options={"ncp": 1})
assert fmu.get('Int32_output')[0] == 42

# Continue without re-initializing — exercises the fix
fmu.simulate(0.1, 0.2, options={"ncp": 1, "initialize": False})
assert fmu.get('Int32_output')[0] == 42
17 changes: 17 additions & 0 deletions tests/test_fmi3_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,20 @@ def test_dynamic_diagnostics_no_time_per_step_should_not_set_cpu_time(self):
res = model.simulate(options = opts)

assert "@Diagnostics.cpu_time" not in res.keys()

def test_consecutive_simulation_with_initialize_false(self):
"""Test that consecutive simulate() calls with initialize=False work.

The initialize=False path invokes enter_event_mode + event_update +
enter_continuous_time_mode before resuming integration. Regression
test to ensure this does not crash or corrupt the FMU state.
"""
fmu = load_fmu(FMI3_REF_FMU_PATH / "Feedthrough.fmu")

fmu.set('Int32_input', 42)
fmu.simulate(0, 0.1, options={"ncp": 1})
assert fmu.get('Int32_output')[0] == 42

# Continue without re-initializing — exercises the fix
fmu.simulate(0.1, 0.2, options={"ncp": 1, "initialize": False})
assert fmu.get('Int32_output')[0] == 42
Loading