@@ -3799,12 +3799,18 @@ cdef class FMUModelCS3(FMUModelBase3):
37993799 FMUModelBase3 .__init__ (self , fmu , log_file_name , log_level ,
38003800 _unzipped_dir , _connect_dll , allow_unzipped_fmu )
38013801
3802+ self .do_step_terminated = False
3803+
38023804 if self .get_capability_flags ().get ('needsExecutionTool' , False ):
38033805 raise FMUException ("The FMU specifies 'needsExecutionTool=true' which implies that it requires an external execution tool to simulate, this is not supported." )
38043806
38053807 if _connect_dll :
38063808 self .instantiate ()
38073809
3810+ def reset (self ):
3811+ FMUModelBase3 .reset (self )
3812+ self .do_step_terminated = False
3813+
38083814 def _get_fmu_kind (self ):
38093815 if self ._fmu_kind & FMIL3 .fmi3_fmu_kind_cs :
38103816 return FMIL3 .fmi3_fmu_kind_cs
@@ -3861,6 +3867,7 @@ cdef class FMUModelCS3(FMUModelBase3):
38613867 if status != FMIL .jm_status_success :
38623868 raise FMUException ('Failed to instantiate the model. See the log for possibly more information.' )
38633869
3870+ self ._instantiated_with_early_return = earlyReturnAllowed
38643871 self ._allocated_fmu = 1
38653872
38663873 cpdef _get_time (self ):
@@ -3888,6 +3895,173 @@ cdef class FMUModelCS3(FMUModelBase3):
38883895 doc = "Property for accessing the current time of the simulation."
38893896 )
38903897
3898+ cpdef FMIL3 .fmi3_status_t do_step (self , FMIL3 .fmi3_float64_t current_t , FMIL3 .fmi3_float64_t step_size , new_step = True ):
3899+ """
3900+ Performs an integrator step.
3901+
3902+ Parameters::
3903+
3904+ current_t --
3905+ The current communication point (current time) of
3906+ the master.
3907+
3908+ step_size --
3909+ The length of the step to be taken.
3910+
3911+ new_step --
3912+ True the last step was accepted by the master and
3913+ False if not.
3914+
3915+ Returns::
3916+
3917+ status --
3918+ The status of function which can be checked against
3919+ FMI_OK, FMI_WARNING, FMI_DISCARD, FMI_ERROR, FMI_FATAL.
3920+
3921+ Calls the underlying low-level function fmi3DoStep.
3922+ The `do_step_terminated` class attribute tracks the fmi3DoStep return
3923+ for `terminateSimulation`.
3924+ """
3925+ cdef FMIL3 .fmi3_status_t status
3926+ cdef FMIL3 .fmi3_boolean_t new_s
3927+ cdef FMIL3 .fmi3_boolean_t eventHandlingNeeded
3928+ cdef FMIL3 .fmi3_boolean_t terminate
3929+ cdef FMIL3 .fmi3_boolean_t earlyReturn
3930+ cdef FMIL3 .fmi3_float64_t lastSuccessfulTime
3931+
3932+ if new_step :
3933+ new_s = FMIL3 .fmi3_true
3934+ else :
3935+ new_s = FMIL3 .fmi3_false
3936+
3937+ log_open = self ._log_open ()
3938+ if not log_open and self .get_log_level () > 2 :
3939+ self ._open_log_file ()
3940+
3941+ self ._log_handler .capi_start_callback (self ._max_log_size_msg_sent , self ._current_log_size )
3942+ status = FMIL3 .fmi3_import_do_step (
3943+ self ._fmu ,
3944+ current_t ,
3945+ step_size ,
3946+ new_s ,
3947+ & eventHandlingNeeded ,
3948+ & terminate ,
3949+ & earlyReturn ,
3950+ & lastSuccessfulTime
3951+ )
3952+ self ._log_handler .capi_end_callback (self ._max_log_size_msg_sent , self ._current_log_size )
3953+
3954+ if not log_open and self .get_log_level () > 2 :
3955+ self ._close_log_file ()
3956+
3957+ if status != FMIL3 .fmi3_status_ok :
3958+ return status
3959+ # On a fully completed step the reached time is current_t + step_size;
3960+ # lastSuccessfulTime is only meaningful when the FMU returns early.
3961+ if terminate :
3962+ self .time = lastSuccessfulTime
3963+ self .do_step_terminated = True
3964+ elif self ._instantiated_with_early_return and earlyReturn :
3965+ self .time = lastSuccessfulTime
3966+ else :
3967+ self .time = current_t + step_size
3968+
3969+ return status
3970+
3971+ def simulate (self ,
3972+ start_time = "Default" ,
3973+ final_time = "Default" ,
3974+ input = (),
3975+ algorithm = 'FMICSAlg' ,
3976+ options = {}):
3977+ """
3978+ Compact function for model simulation.
3979+
3980+ The simulation method depends on which algorithm is used, this can be
3981+ set with the function argument 'algorithm'. Options for the algorithm
3982+ are passed as option classes or as pure dicts. See
3983+ FMUModel.simulate_options for more details.
3984+
3985+ The default algorithm for this function is FMICSAlg.
3986+
3987+ Parameters::
3988+
3989+ start_time --
3990+ Start time for the simulation.
3991+ Default: Start time defined in the default experiment from
3992+ the ModelDescription file.
3993+
3994+ final_time --
3995+ Final time for the simulation.
3996+ Default: Stop time defined in the default experiment from
3997+ the ModelDescription file.
3998+
3999+ input --
4000+ Input signal for the simulation. The input should be a 2-tuple
4001+ consisting of first the names of the input variable(s) and then
4002+ the data matrix.
4003+ Default: Empty tuple.
4004+
4005+ algorithm --
4006+ The algorithm which will be used for the simulation is specified
4007+ by passing the algorithm class as string or class object in this
4008+ argument. 'algorithm' can be any class which implements the
4009+ abstract class AlgorithmBase (found in algorithm_drivers.py). In
4010+ this way it is possible to write own algorithms and use them
4011+ with this function.
4012+ Default: 'FMICSAlg'
4013+
4014+ options --
4015+ The options that should be used in the algorithm. For details on
4016+ the options do:
4017+
4018+ >> myModel = load_fmu(...)
4019+ >> opts = myModel.simulate_options()
4020+ >> opts?
4021+
4022+ Valid values are:
4023+ - A dict which gives AssimuloFMIAlgOptions with
4024+ default values on all options except the ones
4025+ listed in the dict. Empty dict will thus give all
4026+ options with default values.
4027+ - An options object.
4028+ Default: Empty dict
4029+
4030+ Returns::
4031+
4032+ Result object, subclass of common.algorithm_drivers.ResultBase.
4033+ """
4034+ if start_time == "Default" :
4035+ start_time = self .get_default_experiment_start_time ()
4036+ if final_time == "Default" :
4037+ final_time = self .get_default_experiment_stop_time ()
4038+
4039+ return self ._exec_simulate_algorithm (start_time ,
4040+ final_time ,
4041+ input ,
4042+ 'pyfmi.fmi_algorithm_drivers' ,
4043+ algorithm ,
4044+ options )
4045+
4046+ def simulate_options (self , algorithm = 'FMICSAlg' ):
4047+ """
4048+ Get an instance of the simulate options class, filled with default
4049+ values. If called without argument then the options class for the
4050+ default simulation algorithm will be returned.
4051+
4052+ Parameters::
4053+
4054+ algorithm --
4055+ The algorithm for which the options class should be fetched.
4056+ Possible values are: 'FMICSAlg'.
4057+ Default: 'FMICSAlg'
4058+
4059+ Returns::
4060+
4061+ Options class for the algorithm specified with default values.
4062+ """
4063+ return self ._default_options ('pyfmi.fmi_algorithm_drivers' , algorithm )
4064+
38914065 def get_capability_flags (self ) - > dict :
38924066 """
38934067 Returns a dictionary with the capability flags of the FMU.
@@ -3934,6 +4108,19 @@ cdef class FMUModelCS3(FMUModelBase3):
39344108
39354109 return capabilities
39364110
4111+ def _provides_directional_derivatives (self ) - > bool :
4112+ """
4113+ Check capability to provide directional derivatives.
4114+ """
4115+ return bool (FMIL3 .fmi3_import_get_capability (self ._fmu , FMIL3 .fmi3_cs_providesDirectionalDerivatives ))
4116+
4117+ def _supports_get_set_FMU_state (self ) - > bool :
4118+ """
4119+ Check support for getting and setting the FMU-state.
4120+ """
4121+ return bool (FMIL3 .fmi3_import_get_capability (self ._fmu , FMIL3 .fmi3_cs_canGetAndSetFMUState ))
4122+
4123+
39374124cdef class FMUModelME3 (FMUModelBase3 ):
39384125 """
39394126 FMI3 ModelExchange model loaded from a dll
0 commit comments