@@ -14,25 +14,46 @@ macro statuscheck(expr)
1414 fnname = fn. args[2 ]
1515
1616 instance = expr. args[2 ]
17-
17+ is_v2 = startswith (" fmi2" , string (fnname))
18+
19+ fmiTrue = is_v2 ? FMI. fmi2True : FMI. fmi3True
20+ fmiStatusOK = is_v2 ? FMI. fmi2StatusOK : FMI. fmi3StatusOK
21+ fmiStatusWarning = is_v2 ? FMI. fmi2StatusWarning : FMI. fmi3StatusWarning
22+ fmiStatusFatal = is_v2 ? FMI. fmi2StatusFatal : FMI. fmi3StatusFatal
23+ fmiTerminate = is_v2 ? FMI. fmi2Terminate : FMI. fmi3Terminate
24+ fmiFreeInstance! = is_v2 ? FMI. fmi2FreeInstance! : FMI. fmi3FreeInstance!
1825 return quote
1926 status = $ expr
2027 fnname = $ fnname
21- if status != = nothing && ((status isa Tuple && status[1 ] == FMI . fmi2True ) ||
22- (! (status isa Tuple) && status != FMI . fmi2StatusOK &&
23- status != FMI . fmi2StatusWarning ))
24- if status != FMI . fmi2StatusFatal
25- FMI . fmi2Terminate (wrapper. instance)
28+ if status != = nothing && ((status isa Tuple && status[1 ] == $ fmiTrue ) ||
29+ (! (status isa Tuple) && status != $ fmiStatusOK &&
30+ status != $ fmiStatusWarning ))
31+ if status != $ fmiStatusFatal
32+ $ fmiTerminate (wrapper. instance)
2633 end
27- FMI . fmi2FreeInstance ! (wrapper. instance)
34+ $ fmiFreeInstance ! (wrapper. instance)
2835 wrapper. instance = nothing
2936 error (" FMU Error in $fnname : status $status " )
3037 end
3138 end |> esc
3239end
3340
34- function MTK. FMIComponent (:: Val{2} ; fmu = nothing , tolerance = 1e-6 ,
35- communication_step_size = nothing , type, name)
41+ @static if ! hasmethod (FMI. getValueReferencesAndNames, Tuple{FMI. fmi3ModelDescription})
42+ function FMI. getValueReferencesAndNames (
43+ md:: FMI.fmi3ModelDescription ; vrs = md. valueReferences)
44+ dict = Dict {FMI.fmi3ValueReference, Array{String}} ()
45+ for vr in vrs
46+ dict[vr] = FMI. valueReferenceToString (md, vr)
47+ end
48+ return dict
49+ end
50+ end
51+
52+ function MTK. FMIComponent (:: Val{Ver} ; fmu = nothing , tolerance = 1e-6 ,
53+ communication_step_size = nothing , type, name) where {Ver}
54+ if Ver != 2 && Ver != 3
55+ throw (ArgumentError (" FMI Version must be `2` or `3`" ))
56+ end
3657 if type == :CS && communication_step_size === nothing
3758 throw (ArgumentError (" `communication_step_size` must be specified for Co-Simulation FMUs." ))
3859 end
@@ -90,16 +111,23 @@ function MTK.FMIComponent(::Val{2}; fmu = nothing, tolerance = 1e-6,
90111
91112 input_value_references = UInt32[value_references[var] for var in inputs]
92113 param_value_references = UInt32[value_references[var] for var in params]
93- @parameters wrapper:: FMI2InstanceWrapper = FMI2InstanceWrapper (
94- fmu, param_value_references, input_value_references, tolerance)
114+
115+ if Ver == 2
116+ @parameters wrapper:: FMI2InstanceWrapper = FMI2InstanceWrapper (
117+ fmu, param_value_references, input_value_references, tolerance)
118+ else
119+ @parameters wrapper:: FMI3InstanceWrapper = FMI3InstanceWrapper (
120+ fmu, param_value_references, input_value_references)
121+ end
95122
96123 output_value_references = UInt32[value_references[var] for var in outputs]
97124 buffer_length = length (diffvars) + length (outputs)
98125
99126 initialization_eqs = Equation[]
100127
101128 if type == :ME
102- _functor = FMI2MEFunctor (zeros (buffer_length), output_value_references)
129+ FunctorT = Ver == 2 ? FMI2MEFunctor : FMI3MEFunctor
130+ _functor = FunctorT (zeros (buffer_length), output_value_references)
103131 @parameters (functor:: (typeof(_functor) ))(.. )[1 : buffer_length] = _functor
104132 call_expr = functor (
105133 wrapper, __mtk_internal_u, __mtk_internal_x, __mtk_internal_p, t)
@@ -109,14 +137,14 @@ function MTK.FMIComponent(::Val{2}; fmu = nothing, tolerance = 1e-6,
109137 push! (diffeqs, var ~ call_expr[i])
110138 end
111139
112- finalize_affect = MTK. FunctionalAffect (fmi2Finalize !, [], [wrapper], [])
113- step_affect = MTK. FunctionalAffect (fmi2MEStep !, [], [wrapper], [])
140+ finalize_affect = MTK. FunctionalAffect (fmiFinalize !, [], [wrapper], [])
141+ step_affect = MTK. FunctionalAffect (fmiMEStep !, [], [wrapper], [])
114142 instance_management_callback = MTK. SymbolicDiscreteCallback (
115143 (t != t - 1 ), step_affect; finalize = finalize_affect)
116144
117145 push! (params, wrapper, functor)
118146 push! (states, __mtk_internal_u)
119- elseif type == :CS
147+ elseif type == :CS && Ver == 2
120148 state_value_references = UInt32[value_references[var] for var in diffvars]
121149 state_and_output_value_references = vcat (
122150 state_value_references, output_value_references)
@@ -142,7 +170,7 @@ function MTK.FMIComponent(::Val{2}; fmu = nothing, tolerance = 1e-6,
142170 end
143171 initialize_affect = MTK. ImperativeAffect (fmi2CSInitialize!; observed = cb_observed,
144172 modified = cb_modified, ctx = _functor)
145- finalize_affect = MTK. FunctionalAffect (fmi2Finalize !, [], [wrapper], [])
173+ finalize_affect = MTK. FunctionalAffect (fmiFinalize !, [], [wrapper], [])
146174 step_affect = MTK. ImperativeAffect (
147175 fmi2CSStep!; observed = cb_observed, modified = cb_modified, ctx = _functor)
148176 instance_management_callback = MTK. SymbolicDiscreteCallback (
@@ -250,6 +278,63 @@ function reset_instance!(wrapper::FMI2InstanceWrapper)
250278 wrapper. instance = nothing
251279end
252280
281+ mutable struct FMI3InstanceWrapper
282+ const fmu:: FMI.FMU3
283+ const param_value_references:: Vector{UInt32}
284+ const input_value_references:: Vector{UInt32}
285+ instance:: Union{FMI.FMU3Instance{FMI.FMU3}, Nothing}
286+ end
287+
288+ function FMI3InstanceWrapper (fmu, params, inputs)
289+ FMI3InstanceWrapper (fmu, params, inputs, nothing )
290+ end
291+
292+ function get_instance_common! (wrapper:: FMI3InstanceWrapper , states, inputs, params, t)
293+ if ! isempty (params)
294+ @statuscheck FMI. fmi3SetFloat64 (wrapper. instance, wrapper. param_value_references,
295+ params)
296+ end
297+ @statuscheck FMI. fmi3EnterInitializationMode (
298+ wrapper. instance, FMI. fmi3False, zero (FMI. fmi3Float64), t, FMI. fmi3False, t)
299+ if ! isempty (inputs)
300+ @statuscheck FMI. fmi3SetFloat64 (
301+ wrapper. instance, wrapper. input_value_references, inputs)
302+ end
303+
304+ return wrapper. instance
305+ end
306+
307+ function get_instance_ME! (wrapper:: FMI3InstanceWrapper , states, inputs, params, t)
308+ if wrapper. instance === nothing
309+ wrapper. instance = FMI. fmi3InstantiateModelExchange! (wrapper. fmu):: FMI.FMU3Instance
310+ get_instance_common! (wrapper, states, inputs, params, t)
311+ @statuscheck FMI. fmi3ExitInitializationMode (wrapper. instance)
312+ eventInfo = FMI. fmi3UpdateDiscreteStates (wrapper. instance)
313+ @assert eventInfo[1 ] == FMI. fmi2False
314+ # TODO : Support FMU events
315+ @statuscheck FMI. fmi3EnterContinuousTimeMode (wrapper. instance)
316+ end
317+
318+ return wrapper. instance
319+ end
320+
321+ function complete_step! (wrapper:: FMI3InstanceWrapper )
322+ wrapper. instance === nothing && return
323+ enterEventMode = Ref (FMI. fmi3False)
324+ terminateSimulation = Ref (FMI. fmi3False)
325+ @statuscheck FMI. fmi3CompletedIntegratorStep! (
326+ wrapper. instance, FMI. fmi3True, enterEventMode, terminateSimulation)
327+ @assert enterEventMode[] == FMI. fmi3False
328+ @assert terminateSimulation[] == FMI. fmi3False
329+ end
330+
331+ function reset_instance! (wrapper:: FMI3InstanceWrapper )
332+ wrapper. instance === nothing && return
333+ FMI. fmi3Terminate (wrapper. instance)
334+ FMI. fmi3FreeInstance! (wrapper. instance)
335+ wrapper. instance = nothing
336+ end
337+
253338struct FMI2MEFunctor{T}
254339 return_buffer:: Vector{T}
255340 output_value_references:: Vector{UInt32}
@@ -284,13 +369,46 @@ function (fn::FMI2MEFunctor)(wrapper::FMI2InstanceWrapper, states, inputs, param
284369 return [states_buffer; outputs_buffer]
285370end
286371
287- function fmi2MEStep! (integrator, u, p, ctx)
372+ struct FMI3MEFunctor{T}
373+ return_buffer:: Vector{T}
374+ output_value_references:: Vector{UInt32}
375+ end
376+
377+ @register_array_symbolic (fn:: FMI3MEFunctor )(
378+ wrapper:: FMI3InstanceWrapper , states:: Vector{<:Real} ,
379+ inputs:: Vector{<:Real} , params:: Vector{<:Real} , t:: Real ) begin
380+ size = (length (states) + length (fn. output_value_references),)
381+ eltype = eltype (states)
382+ ndims = 1
383+ end
384+
385+ function update_instance_ME! (wrapper:: FMI3InstanceWrapper , states, inputs, t)
386+ instance = wrapper. instance
387+ @statuscheck FMI. fmi3SetTime (instance, t)
388+ @statuscheck FMI. fmi3SetContinuousStates (instance, states)
389+ if ! isempty (inputs)
390+ @statuscheck FMI. fmi3SetFloat64 (instance, wrapper. input_value_references, inputs)
391+ end
392+ end
393+
394+ function (fn:: FMI3MEFunctor )(wrapper:: FMI3InstanceWrapper , states, inputs, params, t)
395+ instance = get_instance_ME! (wrapper, states, inputs, params, t)
396+ update_instance_ME! (wrapper, states, inputs, t)
397+
398+ states_buffer = zeros (length (states))
399+ @statuscheck FMI. fmi3GetContinuousStateDerivatives! (instance, states_buffer)
400+ outputs_buffer = zeros (length (fn. output_value_references))
401+ FMI. fmi3GetFloat64! (instance, fn. output_value_references, outputs_buffer)
402+ return [states_buffer; outputs_buffer]
403+ end
404+
405+ function fmiMEStep! (integrator, u, p, ctx)
288406 wrapper_idx = p[1 ]
289407 wrapper = integrator. ps[wrapper_idx]
290408 complete_step! (wrapper)
291409end
292410
293- function fmi2Finalize ! (integrator, u, p, ctx)
411+ function fmiFinalize ! (integrator, u, p, ctx)
294412 wrapper_idx = p[1 ]
295413 wrapper = integrator. ps[wrapper_idx]
296414 reset_instance! (wrapper)
0 commit comments