Skip to content

Commit

Permalink
v0.16.4 (#110)
Browse files Browse the repository at this point in the history
* performance improvements

* optimizations

* WIP
  • Loading branch information
ThummeTo authored Feb 3, 2024
1 parent ef9a560 commit 8a13201
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 12 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FMIImport"
uuid = "9fcbc62e-52a0-44e9-a616-1359a0008194"
authors = ["TT <[email protected]>", "LM <[email protected]>", "JK <[email protected]>"]
version = "0.16.3"
version = "0.16.4"

[deps]
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
Expand All @@ -14,7 +14,7 @@ ZipFile = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"
[compat]
Downloads = "1"
EzXML = "1.1.0"
FMICore = "0.19.0"
FMICore = "0.20.0"
Libdl = "1"
RelocatableFolders = "1"
ZipFile = "0.10.0"
Expand Down
30 changes: 26 additions & 4 deletions src/FMI2/c.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import FMICore: fmi2DoStep, fmi2CancelStep, fmi2GetStatus!, fmi2GetRealStatus!,
import FMICore: fmi2SetTime, fmi2SetContinuousStates, fmi2EnterEventMode, fmi2NewDiscreteStates!, fmi2EnterContinuousTimeMode, fmi2CompletedIntegratorStep!
import FMICore: fmi2GetDerivatives!, fmi2GetEventIndicators!, fmi2GetContinuousStates!, fmi2GetNominalsOfContinuousStates!

using FMICore: invalidate!, check_invalidate!

"""
Source: FMISpec2.0.2[p.21]: 2.1.5 Creation, Destruction and Logging of FMU Instances
Expand Down Expand Up @@ -116,12 +114,17 @@ Removes the component from the FMUs component list.
See Also [`fmi2FreeInstance!`](@ref).
"""
lk_fmi2FreeInstance = ReentrantLock()
function fmi2FreeInstance!(c::FMU2Component; popComponent::Bool = true)
function fmi2FreeInstance!(c::FMU2Component; popComponent::Bool=true, doccall::Bool=true)

global lk_fmi2FreeInstance

compAddr = c.compAddr

# invalidate all active snapshots
while length(c.snapshots) > 0
FMICore.freeSnapshot!(c.snapshots[end])
end

@assert c.threadid == Threads.threadid() "Thread #$(Threads.threadid()) tried to free component with address $(c.compAddr), but doesn't own it.\nThe component is owned by thread $(c.threadid)"

if popComponent
Expand All @@ -138,7 +141,9 @@ function fmi2FreeInstance!(c::FMU2Component; popComponent::Bool = true)
end
end

fmi2FreeInstance!(c.fmu.cFreeInstance, compAddr)
if doccall
fmi2FreeInstance!(c.fmu.cFreeInstance, compAddr)
end

nothing
end
Expand Down Expand Up @@ -1144,6 +1149,23 @@ function fmi2GetDirectionalDerivative!(c::FMU2Component,
return status
end

# for AD primitives
function fmi2GetDirectionalDerivative!(c::FMU2Component,
vUnknown_ref::AbstractArray{fmi2ValueReference},
nUnknown::Csize_t,
vKnown_ref::AbstractArray{fmi2ValueReference},
nKnown::Csize_t,
dvKnown::AbstractArray{fmi2Real},
dvUnknown::AbstractArray{<:Real})

logWarning(c.fmu, "fmi2GetDirectionalDerivative! is called on `dvUnknown::AbstractArray{<:Real}`, this is slow.\nConsider using `Float64` instead.", 1)

_dvUnknown = zeros(fmi2Real, length(dvUnknown))
status = fmi2GetDirectionalDerivative!(c::FMU2Component, vUnknown_ref, nUnknown, vKnown_ref, nKnown, dvKnown, _dvUnknown)
dvUnknown[:] = _dvUnknown
return status
end

# Functions specificly for isCoSimulation
"""
fmi2SetRealInputDerivatives(c::FMU2Component,
Expand Down
81 changes: 76 additions & 5 deletions src/FMI2/ext.jl
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ function fmi2Reload(fmu::FMU2)
end

"""
fmi2Unload(fmu::FMU2, cleanUp::Bool = true)
fmi2Unload(fmu::FMU2, cleanUp::Bool=true; secure_pointers::Bool=true)
Unload a FMU.
Free the allocated memory, close the binaries and remove temporary zip and unziped FMU model description.
Expand All @@ -598,15 +598,25 @@ Free the allocated memory, close the binaries and remove temporary zip and unzip
# Keywords
- `secure_pointers=true` whether pointers to C-functions should be overwritten with dummies with Julia assertions, instead of pointing to dead memory (slower, but more user safe)
"""
function fmi2Unload(fmu::FMU2, cleanUp::Bool = true; secure_pointers::Bool=true)
function fmi2Unload(fmu::FMU2, cleanUp::Bool=true; secure_pointers::Bool=true)

while length(fmu.components) > 0
fmi2FreeInstance!(fmu.components[end])
c = fmu.components[end]

# release allocated memory for snapshots (they might be used elsewhere too)
# if !isnothing(c.solution)
# for iter in c.solution.snapshots
# t, snapshot = iter
# cleanup!(c, snapshot)
# end
# end

fmi2FreeInstance!(c)
end

# the components are removed from the component list via call to fmi2FreeInstance!
@assert length(fmu.components) == 0 "fmi2Unload(...): Failure during deleting components, $(length(fmu.components)) remaining in stack."

if secure_pointers
unloadBinary(fmu)
end
Expand Down Expand Up @@ -1171,7 +1181,7 @@ More detailed:
function fmi2Set(comp::FMU2Component, vrs::fmi2ValueReferenceFormat, srcArray::AbstractArray; filter=nothing)
vrs = prepareValueReference(comp, vrs)

@assert length(vrs) == length(srcArray) "fmi2Set(...): Number of value references doesn't match number of `srcArray` elements."
@assert length(vrs) == length(srcArray) "fmi2Set(...): Number of value references [$(length(vrs))] doesn't match number of `srcArray` elements [$(length(srcArray))]."

retcodes = zeros(fmi2Status, length(vrs)) # fmi2StatusOK

Expand Down Expand Up @@ -1585,3 +1595,64 @@ function fmi2SampleJacobian!(c::FMU2Component,

nothing
end

"""
fmi2SetDiscreteStates(c::FMU2Component,
x::Union{AbstractArray{Float32},AbstractArray{Float64}})
Set a new (discrete) state vector and reinitialize chaching of variables that depend on states.
# Arguments
[ToDo]
"""
function fmi2SetDiscreteStates(c::FMU2Component, xd::AbstractArray{Union{fmi2Real, fmi2Integer, fmi2Boolean}})

if length(c.fmu.modelDescription.discreteStateValueReferences) <= 0
return fmi2StatusOK
end

status = fmi2Set(c, c.fmu.modelDescription.discreteStateValueReferences, xd)
if status == fmi2StatusOK
fast_copy!(c, :x_d, xd)
end
return status
end

"""
fmi2GetDiscreteStates!(c::FMU2Component,
x::Union{AbstractArray{Float32},AbstractArray{Float64}})
Set a new (discrete) state vector and reinitialize chaching of variables that depend on states.
# Arguments
[ToDo]
"""
function fmi2GetDiscreteStates!(c::FMU2Component, xd::AbstractArray{Union{fmi2Real, fmi2Integer, fmi2Boolean}})

if length(c.fmu.modelDescription.discreteStateValueReferences) <= 0
return fmi2StatusOK
end

status = fmi2Get!(c, c.fmu.modelDescription.discreteStateValueReferences, xd)
if status == fmi2StatusOK
fast_copy!(c, :x_d, xd)
end
return status
end

"""
fmi2GetDiscreteStates(c::FMU2Component,
x::Union{AbstractArray{Float32},AbstractArray{Float64}})
Set a new (discrete) state vector and reinitialize chaching of variables that depend on states.
# Arguments
[ToDo]
"""
function fmi2GetDiscreteStates(c::FMU2Component)

ndx = length(c.fmu.modelDescription.discreteStateValueReferences)
xd = Vector{Union{fmi2Real, fmi2Integer, fmi2Boolean}}()
fmi2GetDiscreteStates!(c, xd)
return xd
end
19 changes: 18 additions & 1 deletion src/FMI2/prep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ function prepareSolveFMU(fmu::FMU2,
#@assert retcode == fmi2StatusOK "fmi2Simulate(...): Setting initial state failed with return code $(retcode)."
retcodes = fmi2Set(c, fmu.modelDescription.stateValueReferences, x0; filter=setInInitialization)
@assert all(retcodes .== fmi2StatusOK) "fmi2Simulate(...): Setting initial inputs failed with return code $(retcodes)."

# safe start state in component
c.x = copy(x0)
end

# exit setup (hard)
Expand Down Expand Up @@ -173,6 +176,20 @@ function handleEvents(c::FMU2Component)

@assert c.state == fmi2ComponentStateEventMode "handleEvents(...): Must be in event mode!"

# invalidate all cached jacobians/gradients
invalidate!(c.∂ẋ_∂x)
invalidate!(c.∂ẋ_∂u)
invalidate!(c.∂ẋ_∂p)
invalidate!(c.∂y_∂x)
invalidate!(c.∂y_∂u)
invalidate!(c.∂y_∂p)
invalidate!(c.∂e_∂x)
invalidate!(c.∂e_∂u)
invalidate!(c.∂e_∂p)
invalidate!(c.∂ẋ_∂t)
invalidate!(c.∂y_∂t)
invalidate!(c.∂e_∂t)

#@debug "Handle Events..."

# trigger the loop
Expand Down Expand Up @@ -354,7 +371,7 @@ function finishSolveFMU(fmu::FMU2, c::FMU2Component, freeInstance::Union{Nothing

# freeInstance (hard)
if freeInstance
fmi2FreeInstance!(c; popComponent=popComponent)
fmi2FreeInstance!(c; popComponent=popComponent) # , doccall=freeInstance
c = nothing
end
end
Expand Down
2 changes: 2 additions & 0 deletions src/FMIImport.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ using FMICore.Requires
import FMICore.ChainRulesCore: ignore_derivatives

using RelocatableFolders
using FMICore: invalidate!, check_invalidate!

# functions that have (currently) no better place

Expand Down Expand Up @@ -54,6 +55,7 @@ export fmi2GetFMUstate!, fmi2SetFMUstate, fmi2FreeFMUstate!, fmi2SerializedFMUst
export fmi2GetDirectionalDerivative!, fmi2SetRealInputDerivatives, fmi2GetRealOutputDerivatives
export fmi2DoStep, fmi2CancelStep, fmi2GetStatus!, fmi2GetRealStatus!, fmi2GetIntegerStatus!, fmi2GetBooleanStatus!, fmi2GetStringStatus!
export fmi2SetTime, fmi2SetContinuousStates, fmi2EnterEventMode, fmi2NewDiscreteStates!, fmi2EnterContinuousTimeMode, fmi2CompletedIntegratorStep!
export fmi2SetDiscreteStates, fmi2GetDiscreteStates!, fmi2GetDiscreteStates
export fmi2GetDerivatives!, fmi2GetEventIndicators!, fmi2GetContinuousStates!, fmi2GetNominalsOfContinuousStates!, fmi2GetRealOutputDerivatives!

# FMI2_convert.jl
Expand Down

2 comments on commit 8a13201

@ThummeTo
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/100187

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.16.4 -m "<description of version>" 8a13201abb504a55a3d8e34caef578ff80a69a6c
git push origin v0.16.4

Please sign in to comment.