diff --git a/CHANGELOG b/CHANGELOG index 763a8b76..6b6fb1df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ --- CHANGELOG --- --- PyFMI-FUTURE --- + * Fixed a crash with the `Master` algorithm option `block_initialization`. --- PyFMI-2.20.0 --- * Fixed so FMU `reset` resets to log_level that it was loaded with. diff --git a/src/pyfmi/master.pyx b/src/pyfmi/master.pyx index 9d963f6c..cc62ae20 100644 --- a/src/pyfmi/master.pyx +++ b/src/pyfmi/master.pyx @@ -875,6 +875,9 @@ cdef class Master: return xd cpdef np.ndarray get_specific_connection_outputs_discrete(self, model, np.ndarray mask, np.ndarray yout): + if len(mask) == 0: + # quick return; nothing to get; prevents index array in array slicing + return cdef int j = 0 ytmp = model.get(np.array(self.models_dict[model]["local_output_discrete"])[mask]) for i, flag in enumerate(mask): @@ -883,6 +886,9 @@ cdef class Master: j = j + 1 cpdef np.ndarray get_specific_connection_outputs(self, model, np.ndarray mask, np.ndarray yout): + if len(mask) == 0: + # quick return; nothing to get; prevents index array in array slicing + return cdef int j = 0 cdef np.ndarray ytmp = (model).get_real(self.models_dict[model]["local_output_vref_array"][mask]) for i, flag in enumerate(mask): @@ -1015,6 +1021,9 @@ cdef class Master: model.set(self.models_dict[model]["local_input_discrete"], u[i:inext]) cpdef set_specific_connection_inputs(self, model, np.ndarray mask, np.ndarray u): + if len(mask) == 0: + # quick return; nothing to set; prevents index array in array slicing + return cdef int i = self.models_dict[model]["global_index_inputs"] cdef int inext = i + self.models_dict[model]["local_input_len"] cdef np.ndarray usliced = u[i:inext] @@ -1023,6 +1032,9 @@ cdef class Master: (model).set_real(self.models_dict[model]["local_input_vref_array"][mask], usliced[mask]) cpdef set_specific_connection_inputs_discrete(self, model, np.ndarray mask, np.ndarray u): + if len(mask) == 0: + # quick return; nothing to set; prevents index array in array slicing + return cdef int i = self.models_dict[model]["global_index_inputs_discrete"] cdef int inext = i + self.models_dict[model]["local_input_discrete_len"] cdef np.ndarray usliced = u[i:inext] diff --git a/tests/test_fmi_master.py b/tests/test_fmi_master.py index 99bc8154..59bb4014 100644 --- a/tests/test_fmi_master.py +++ b/tests/test_fmi_master.py @@ -449,6 +449,24 @@ def test_external_inputs(self, input_traj): np.testing.assert_array_equal(res[0]["Float64_discrete_output"], [0, 0, 0, 0, 0, 0]) np.testing.assert_array_equal(res[1]["Float64_discrete_output"], [0, 2, 4, 6, 8, 10]) + def test_block_initialization(self): + """Basic smoke-test for the 'block_initialization' option.""" + fmu1 = FMUModelCS2(os.path.join(FMI2_REF_FMU_PATH, "Feedthrough.fmu")) + fmu2 = FMUModelCS2(os.path.join(FMI2_REF_FMU_PATH, "Feedthrough.fmu")) + fmu3 = FMUModelCS2(os.path.join(FMI2_REF_FMU_PATH, "Feedthrough.fmu")) + + models = [fmu1, fmu2, fmu3] + # some inputs/outputs are intentionally left unconnected + connections = [ + (fmu1, "Float64_continuous_output", fmu2, "Float64_continuous_input"), + (fmu2, "Float64_discrete_output", fmu3, "Float64_discrete_input"), + ] + master = Master(models, connections) + + opts = master.simulate_options() + opts["block_initialization"] = True + master.simulate(0, 1, options=opts) + class Test_Master_Result_Downsampling: """Tests related to the 'result_downsampling' option of the Master algorithm.""" @classmethod