I don't want to bombard you with issues, you can also guide me to some documents to improve my general understanding of the FMI if they are helpful for the practical implementation in FMIExport.
I'm trying to create an FMU with a simple PT1 model. I tried to stay as close as possible to the bouncing ball example. I added an event although there are no events, but if I don't define an eventFct then an error is thrown. There are also no discrete states.
From the error message (below) I figure that there might be something wrong with FMU_FCT_OUTPUT, but I don't understand what exactly is happening. Help is much appreciated.
Code:
using FMIExport
using FMIExport.FMICore: fmi2True, fmi2False
FMU_FCT_INIT = function()
T = 1.0 # time constant
t = 0.0
x = [0.0]
ẋ = [0.0]
x_d = []
u = [0.0]
p = [T]
return (t, x, ẋ, x_d, u, p)
end
FMU_FCT_EVALUATE = function(t, x, ẋ, x_d, u, p, eventMode)
T = (p...,)
old_state = (x...,)
derivative = (u[0] - old_state)/T
x = [old_state]
ẋ = [derivative]
p = [T]
x_d = []
return (x, ẋ, x_d, p)
end
FMU_FCT_OUTPUT = function(t, x, ẋ, x_d, u, p)
state = (x...,)
y = [state]
return y
end
FMU_FCT_EVENT = function(t, x_c, ẋ_c, x_d, u, p)
return [0.0]
end
FMIBUILD_CONSTRUCTOR = function(resPath=".")
fmu = fmi2CreateSimple(initializationFct=FMU_FCT_INIT,
evaluationFct=FMU_FCT_EVALUATE,
outputFct=FMU_FCT_OUTPUT,
eventFct=FMU_FCT_EVENT)
fmu.modelDescription.modelName = "PT1"
# modes
fmi2ModelDescriptionAddModelExchange(fmu.modelDescription, "PT1")
fmi2AddStateAndDerivative(fmu, "PT1.state"; stateDescr="state", derivativeDescr="state derivative")
fmi2AddRealOutput(fmu, "PT1.state"; description="state")
fmi2AddRealParameter(fmu, "T"; description="Time constant")
fmi2AddEventIndicator(fmu)
return fmu
end
tmpDir = mktempdir(; prefix="fmibuildjl_test_", cleanup=false)
@info "Saving example files at: $(tmpDir)"
fmu_save_path = joinpath(tmpDir, "BouncingBall.fmu")
fmu = FMIBUILD_CONSTRUCTOR()
Error:
ERROR: MethodError: Cannot convert
an object of type
Tuple{Float64} to an object of type
Union{Float64, Int32}
Closest candidates are:
convert(::Type{T}, ::Union{Static.StaticBool{N}, Static.StaticFloat64{N}, Static.StaticInt{N}} where N) where T<:Number
@ Static C:\Users\seberlein.julia\packages\Static\dLrtk\src\Static.jl:414
convert(::Type{<:Number}, ::SciMLOperators.AddedScalarOperator)
@ SciMLOperators C:\Users\seberlein.julia\packages\SciMLOperators\hFLNz\src\scalar.jl:243
convert(::Type{T}, ::AbstractChar) where T<:Number
@ Base char.jl:185
...
Stacktrace:
[1] setindex!(h::Dict{UInt32, Union{Float64, Int32}}, v0::Tuple{Float64}, key::UInt32)
@ Base .\dict.jl:369
[2] applyValues(_component::Ptr{Nothing}, xc::Vector{Float64}, ẋc::Vector{Float64}, xd::Vector{Any}, u::Vector{Float64}, y::Vector{Tuple{Float64}}, p::Vector{Float64})
@ FMIExport C:\Users\seberlein.julia\packages\FMIExport\j8bGN\src\FMI2_simple.jl:113
[3] reset(_component::Ptr{Nothing})
@ FMIExport C:\Users\seberlein.julia\packages\FMIExport\j8bGN\src\FMI2_simple.jl:45
[4] simple_fmi2Instantiate(instanceName::Ptr{UInt8}, fmuType::UInt32, fmuGUID::Ptr{UInt8}, fmuResourceLocation::Ptr{UInt8}, functions::Ptr{FMICore.fmi2CallbackFunctions}, visible::Int32, loggingOn::Int32)
@ FMIExport C:\Users\seberlein.julia\packages\FMIExport\j8bGN\src\FMI2_simple.jl:170
[5] fmi2Instantiate(cfunc::Ptr{Nothing}, instanceName::Ptr{UInt8}, fmuType::UInt32, fmuGUID::Ptr{UInt8}, fmuResourceLocation::Ptr{UInt8}, functions::Ptr{FMICore.fmi2CallbackFunctions}, visible::Int32, loggingOn::Int32)
@ FMICore C:\Users\seberlein.julia\packages\FMICore\l1OAc\src\FMI2\cfunc.jl:20
[6] (::FMIImport.var"#74#75"{String, UInt32, Bool, Bool, Bool, FMU2, String, FMICore.fmi2CallbackFunctions, FMICore.FMU2ComponentEnvironment})()
@ FMIImport C:\Users\seberlein.julia\packages\FMIImport\7xJzL\src\FMI2\ext.jl:509
[7] lock(f::FMIImport.var"#74#75"{String, UInt32, Bool, Bool, Bool, FMU2, String, FMICore.fmi2CallbackFunctions, FMICore.FMU2ComponentEnvironment}, l::ReentrantLock)
@ Base .\lock.jl:229
[8] fmi2Instantiate!(fmu::FMU2; instanceName::String, type::UInt32, pushComponents::Bool, visible::Bool, loggingOn::Bool, externalCallbacks::Bool, logStatusOK::Bool, logStatusWarning::Bool, logStatusDiscard::Bool, logStatusError::Bool, logStatusFatal::Bool, logStatusPending::Bool)
@ FMIImport C:\Users\seberlein.julia\packages\FMIImport\7xJzL\src\FMI2\ext.jl:506
[9] fmi2Instantiate!
@ C:\Users\seberlein.julia\packages\FMIImport\7xJzL\src\FMI2\ext.jl:447 [inlined]
[10] (::FMIImport.var"#12#13"{Nothing, Bool, typeof(FMIImport.handleEvents), FMU2, UInt32, Nothing, Float64, Float64, Nothing})()
@ FMIImport C:\Users\seberlein.julia\packages\FMIImport\7xJzL\src\FMI2\prep.jl:67
[11] ignore_derivatives
@ C:\Users\seberlein.julia\packages\ChainRulesCore\7MWx2\src\ignore_derivatives.jl:26 [inlined]
[12] #prepareSolveFMU#11
@ C:\Users\seberlein.julia\packages\FMIImport\7xJzL\src\FMI2\prep.jl:39 [inlined]
[13] fmi2SimulateME(fmu::FMU2, c::Nothing, tspan::Tuple{Float64, Float64}; tolerance::Nothing, dt::Nothing, solver::Nothing, customFx::Nothing, recordValues::Nothing, recordEventIndicators::Nothing, recordEigenvalues::Bool, saveat::Nothing, x0::Nothing, setup::Nothing, reset::Nothing, instantiate::Nothing, freeInstance::Nothing, terminate::Nothing, inputValueReferences::Nothing, inputFunction::Nothing, parameters::Nothing, dtmax::Float64, callbacksBefore::Vector{Any}, callbacksAfter::Vector{Any}, showProgress::Bool, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ FMI C:\Users\seberlein.julia\packages\FMI\iK3kv\src\FMI2\sim.jl:453
[14] fmi2SimulateME
@ C:\Users\seberlein.julia\packages\FMI\iK3kv\src\FMI2\sim.jl:363 [inlined]
[15] #fmi2SimulateME#8
@ C:\Users\seberlein.julia\packages\FMI\iK3kv\src\FMI2\comp_wraps.jl:38 [inlined]
[16] fmi2SimulateME
@ C:\Users\seberlein.julia\packages\FMI\iK3kv\src\FMI2\comp_wraps.jl:37 [inlined]
[17] #fmiSimulateME#292
@ C:\Users\seberlein.julia\packages\FMI\iK3kv\src\FMI.jl:851 [inlined]
[18] top-level scope
@ d:\User\seberlein\Julia\FMI\src\simple_PT1_example.jl:68