Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.12.3 #185

Merged
merged 5 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FMI"
uuid = "14a09403-18e3-468f-ad8a-74f8dda2d9ac"
authors = ["TT <[email protected]>", "LM <[email protected]>", "JK <[email protected]>"]
version = "0.12.2"
version = "0.12.3"

[deps]
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
Expand All @@ -17,7 +17,7 @@ ThreadPools = "b189fb0b-2eb5-4ed4-bc0c-d34c51242431"
DiffEqCallbacks = "2.26.0"
DifferentialEquations = "7.7.0"
FMIExport = "0.2.0"
FMIImport = "0.15.5"
FMIImport = "0.15.6"
ProgressMeter = "1.7.0"
Requires = "1.3.0"
ThreadPools = "2.1.1"
Expand Down
50 changes: 44 additions & 6 deletions src/FMI2/sim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ function time_choice(c::FMU2Component, integrator, tStart, tStop)

#@info "TC"

c.solution.evals_timechoice += 1

if c.eventInfo.nextEventTimeDefined == fmi2True

if c.eventInfo.nextEventTime >= tStart && c.eventInfo.nextEventTime <= tStop
Expand All @@ -47,6 +49,8 @@ function condition(c::FMU2Component, out::AbstractArray{<:Real}, x, t, integrato

@assert c.state == fmi2ComponentStateContinuousTimeMode "condition(...): Must be called in mode continuous time."

c.solution.evals_condition += 1

t = undual(t)
x = undual(x)

Expand All @@ -66,6 +70,8 @@ function affectFMU!(c::FMU2Component, integrator, idx, inputFunction, inputValue

@assert c.state == fmi2ComponentStateContinuousTimeMode "affectFMU!(...): Must be in continuous time mode!"

c.solution.evals_affect += 1

# there are fx-evaluations before the event is handled, reset the FMU state to the current integrator step
fmi2SetContinuousStates(c, integrator.u; force=true)
fmi2SetTime(c, integrator.t; force=true)
Expand Down Expand Up @@ -112,6 +118,9 @@ function stepCompleted(c::FMU2Component, x, t, integrator, inputFunction, inputV

@assert c.state == fmi2ComponentStateContinuousTimeMode "stepCompleted(...): Must be in continuous time mode."
#@info "Step completed"

c.solution.evals_stepcompleted += 1

if progressMeter !== nothing
stat = 1000.0*(t-tStart)/(tStop-tStart)
if !isnan(stat)
Expand Down Expand Up @@ -140,10 +149,14 @@ function saveValues(c::FMU2Component, recordValues, x, t, integrator, inputFunct

@assert c.state == fmi2ComponentStateContinuousTimeMode "saveValues(...): Must be in continuous time mode."

c.solution.evals_savevalues += 1

#x_old = fmi2GetContinuousStates(c)
#t_old = c.t

fmi2SetContinuousStates(c, x)
if !c.fmu.isZeroState
fmi2SetContinuousStates(c, x)
end
fmi2SetTime(c, t)
if inputFunction != nothing
fmi2SetReal(c, inputValues, inputFunction(c, x, t))
Expand All @@ -152,7 +165,7 @@ function saveValues(c::FMU2Component, recordValues, x, t, integrator, inputFunct
#fmi2SetContinuousStates(c, x_old)
#fmi2SetTime(c, t_old)

return (fmiGetReal(c, recordValues)...,)
return (fmiGet(c, recordValues)...,)
end

function fx(c::FMU2Component,
Expand All @@ -161,7 +174,13 @@ function fx(c::FMU2Component,
p::AbstractArray,
t::Real)

_, dx = c(;dx=dx, x=x, t=t)
c.solution.evals_fx_inplace += 1

if c.fmu.executionConfig.concat_y_dx
dx[:] = c(;dx=dx, x=x, t=t)
else
_, dx[:] = c(;dx=dx, x=x, t=t)
end

return dx
end
Expand All @@ -171,7 +190,15 @@ function fx(c::FMU2Component,
p::AbstractArray,
t::Real)

_, dx = c(;x=x, t=t)
c.solution.evals_fx_outofplace += 1

dx = nothing

if c.fmu.executionConfig.concat_y_dx
dx = c(;x=x, t=t)
else
_, dx = c(;x=x, t=t)
end

return dx
end
Expand Down Expand Up @@ -216,7 +243,7 @@ State- and Time-Events are handled correctly.
Via the optional keyword arguemnts `inputValues` and `inputFunction`, a custom input function `f(c, u, t)`, `f(c, t)`, `f(u, t)`, `f(c, u)` or `f(t)` with `c` current component, `u` current state and `t` current time can be defined, that should return a array of values for `fmi2SetReal(..., inputValues, inputFunction(...))`.

Keywords:
- solver: Any Julia-supported ODE-solver (default is Tsit5)
- solver: Any Julia-supported ODE-solver (default is the DifferentialEquations.jl default solver, currently `AutoTsit5(Rosenbrock23())`)
- customFx: [deprecated] Ability to give a custom state derivative function ẋ=f(x,t)
- recordValues: Array of variables (strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues`
- saveat: Time points to save values at (interpolated)
Expand Down Expand Up @@ -332,6 +359,11 @@ function fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tsp
c, x0 = prepareSolveFMU(fmu, c, fmi2TypeModelExchange, instantiate, freeInstance, terminate, reset, setup, parameters, t_start, t_stop, nothing; x0=x0, inputs=inputs, handleEvents=FMI.handleEvents)
fmusol = c.solution

# Zero state FMU: add dummy state
if c.fmu.isZeroState
x0 = [0.0]
end

# from here on, we are in event mode, if `setup=false` this is the job of the user
#@assert c.state == fmi2ComponentStateEventMode "FMU needs to be in event mode after setup."

Expand Down Expand Up @@ -385,7 +417,8 @@ function fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tsp
end

if savingValues
fmusol.values = SavedValues(Float64, Tuple{collect(Float64 for i in 1:length(recordValues))...})
dtypes = collect(fmi2DataTypeForValueReference(c.fmu.modelDescription, vr) for vr in recordValues)
fmusol.values = SavedValues(Float64, Tuple{dtypes...})
fmusol.valueReferences = copy(recordValues)

if saveat === nothing
Expand Down Expand Up @@ -432,6 +465,11 @@ function fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tsp
@warn "FMU simulation failed with solver return code `$(fmusol.states.retcode)`, please check log for hints."
end

# ZeroStateFMU: remove dummy state
if c.fmu.isZeroState
c.solution.states = nothing
end

# cleanup progress meter
if showProgress
ProgressMeter.finish!(progressMeter)
Expand Down
44 changes: 44 additions & 0 deletions test/FMI2/sim_zero_state.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

using DifferentialEquations: Tsit5

t_start = 0.0
t_stop = 8.0
solver = Tsit5()
dtmax = 0.01

function extForce_t(t)
[sin(t)]
end

myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"])

# make a dummy zero-state FMU by overwriting the state field (ToDo: Use an actual zero state FMU from FMIZoo.jl)
myFMU.modelDescription.stateValueReferences = []
myFMU.modelDescription.derivativeValueReferences = []
myFMU.modelDescription.numberOfEventIndicators = 0
myFMU.isZeroState = true

comp = fmiInstantiate!(myFMU; loggingOn=false)
@test comp != 0

# choose FMU or FMUComponent
fmuStruct = nothing
envFMUSTRUCT = ENV["FMUSTRUCT"]
if envFMUSTRUCT == "FMU"
fmuStruct = myFMU
elseif envFMUSTRUCT == "FMUCOMPONENT"
fmuStruct = comp
end
@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`"

solution = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=solver, dtmax=dtmax, recordValues=["a"], inputValueReferences=myFMU.modelDescription.inputValueReferences, inputFunction=extForce_t)
@test isnothing(solution.states)

@test solution.values.t[1] == t_start
@test solution.values.t[end] == t_stop

fmiUnload(myFMU)
5 changes: 5 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ function runtestsFMI2(exportingTool)
include("FMI2/cs_me.jl")
end

@info "Simulation FMU without states (sim_zero_state.jl)"
@testset "Simulation FMU without states" begin
include("FMI2/sim_zero_state.jl")
end

@info "Loading/Saving simulation results (load_save.jl)"
@testset "Loading/Saving simulation results" begin
include("FMI2/load_save.jl")
Expand Down