@@ -14,25 +14,46 @@ macro statuscheck(expr)
14
14
fnname = fn. args[2 ]
15
15
16
16
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!
18
25
return quote
19
26
status = $ expr
20
27
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)
26
33
end
27
- FMI . fmi2FreeInstance ! (wrapper. instance)
34
+ $ fmiFreeInstance ! (wrapper. instance)
28
35
wrapper. instance = nothing
29
36
error (" FMU Error in $fnname : status $status " )
30
37
end
31
38
end |> esc
32
39
end
33
40
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
36
57
if type == :CS && communication_step_size === nothing
37
58
throw (ArgumentError (" `communication_step_size` must be specified for Co-Simulation FMUs." ))
38
59
end
@@ -90,16 +111,23 @@ function MTK.FMIComponent(::Val{2}; fmu = nothing, tolerance = 1e-6,
90
111
91
112
input_value_references = UInt32[value_references[var] for var in inputs]
92
113
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
95
122
96
123
output_value_references = UInt32[value_references[var] for var in outputs]
97
124
buffer_length = length (diffvars) + length (outputs)
98
125
99
126
initialization_eqs = Equation[]
100
127
101
128
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)
103
131
@parameters (functor:: (typeof(_functor) ))(.. )[1 : buffer_length] = _functor
104
132
call_expr = functor (
105
133
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,
109
137
push! (diffeqs, var ~ call_expr[i])
110
138
end
111
139
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], [])
114
142
instance_management_callback = MTK. SymbolicDiscreteCallback (
115
143
(t != t - 1 ), step_affect; finalize = finalize_affect)
116
144
117
145
push! (params, wrapper, functor)
118
146
push! (states, __mtk_internal_u)
119
- elseif type == :CS
147
+ elseif type == :CS && Ver == 2
120
148
state_value_references = UInt32[value_references[var] for var in diffvars]
121
149
state_and_output_value_references = vcat (
122
150
state_value_references, output_value_references)
@@ -142,7 +170,7 @@ function MTK.FMIComponent(::Val{2}; fmu = nothing, tolerance = 1e-6,
142
170
end
143
171
initialize_affect = MTK. ImperativeAffect (fmi2CSInitialize!; observed = cb_observed,
144
172
modified = cb_modified, ctx = _functor)
145
- finalize_affect = MTK. FunctionalAffect (fmi2Finalize !, [], [wrapper], [])
173
+ finalize_affect = MTK. FunctionalAffect (fmiFinalize !, [], [wrapper], [])
146
174
step_affect = MTK. ImperativeAffect (
147
175
fmi2CSStep!; observed = cb_observed, modified = cb_modified, ctx = _functor)
148
176
instance_management_callback = MTK. SymbolicDiscreteCallback (
@@ -250,6 +278,63 @@ function reset_instance!(wrapper::FMI2InstanceWrapper)
250
278
wrapper. instance = nothing
251
279
end
252
280
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
+
253
338
struct FMI2MEFunctor{T}
254
339
return_buffer:: Vector{T}
255
340
output_value_references:: Vector{UInt32}
@@ -284,13 +369,46 @@ function (fn::FMI2MEFunctor)(wrapper::FMI2InstanceWrapper, states, inputs, param
284
369
return [states_buffer; outputs_buffer]
285
370
end
286
371
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)
288
406
wrapper_idx = p[1 ]
289
407
wrapper = integrator. ps[wrapper_idx]
290
408
complete_step! (wrapper)
291
409
end
292
410
293
- function fmi2Finalize ! (integrator, u, p, ctx)
411
+ function fmiFinalize ! (integrator, u, p, ctx)
294
412
wrapper_idx = p[1 ]
295
413
wrapper = integrator. ps[wrapper_idx]
296
414
reset_instance! (wrapper)
0 commit comments