Skip to content

Commit

Permalink
v0.2.0 (#26)
Browse files Browse the repository at this point in the history
* refactoring, new features, more examples

* v0.2.0 edit

* fixed project.toml in test

* removed fmizoo-version-dep

* fixed dependencies

* minor modification at bouncng ball

* removed FMI.jl testing dependency

* minor modification in examples

* excluding tests that fail in CI (working locally)

* added dependencies in example projects

* minor test modification
  • Loading branch information
ThummeTo authored May 3, 2023
1 parent 666ae26 commit 3482e5d
Show file tree
Hide file tree
Showing 18 changed files with 1,023 additions and 232 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FMIExport"
uuid = "31b88311-cab6-44ed-ba9c-fe5a9abbd67a"
authors = ["TT <[email protected]>", "LM <[email protected]>"]
version = "0.1.13"
version = "0.2.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand All @@ -11,5 +11,5 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[compat]
EzXML = "1.1.0"
FMICore = "0.16"
FMICore = "0.17.1"
julia = "1.6"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

2\. Install [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl):
```julia-repl
(@v1.6) pkg> add FMIExport
(@v1.x) pkg> add FMIExport
```

3\. If you want to check that everything works correctly, you can run the tests bundled with [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl):
```julia-repl
(@v1.6) pkg> test FMIExport
(@v1.x) pkg> test FMIExport
```

4\. Have a look inside the [examples folder](https://github.com/ThummeTo/FMIExport.jl/tree/examples/examples) in the examples branch or the [examples section](https://thummeto.github.io/FMIExport.jl/dev/examples/overview/) of the documentation. All examples are available as Julia-Script (*.jl*), Jupyter-Notebook (*.ipynb*) and Markdown (*.md*).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ version = "0.1.0"
[deps]
FMIBuild = "226f0e26-6dd6-4589-ada7-1d32f6e1d800"
FMIExport = "31b88311-cab6-44ed-ba9c-fe5a9abbd67a"

[compat]
FMIBuild = "0.1.15"
FMIExport = "0.2.0"
julia = "1.6"
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,87 @@
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

using FMIExport
using FMIExport
using FMIExport.FMICore: fmi2True, fmi2False

FMU_FCT_INIT = function()
m = 1.0 # ball mass
r = 0.0 # ball radius
d = 0.7 # ball collision damping
v_min = 1e-1 # ball minimum velocity
g = -9.81 # gravity constant
g = 9.81 # gravity constant
sticking = fmi2False

s = 1.0 # ball position
v = 0.0 # ball velocity
a = 0.0 # ball acceleration

t = 0.0
x = [s, v]
= [v, a]
x_c = [s, v]
ẋ_c = [v, a]
x_d = [sticking]
u = []
p = [m, r, d, v_min, g]

return (t, x, ẋ, u, p)
return (t, x_c, ẋ_c, x_d, u, p)
end

FMU_FCT_EVALUATE = function(t, x, ẋ, u, p)
m, r, d, v_min, g = (p...,)
s, v = (x...,)
_, a = (ẋ...,)

if s <= r && v < 0.0
s = r
v = -v*d

# stop bouncing to prevent high frequency bouncing (and maybe tunneling the floor)
if v < v_min
v = 0.0
g = 0.0
FMU_FCT_EVALUATE = function(t, x_c, ẋ_c, x_d, u, p, eventMode)
m, r, d, v_min, g = p
s, v = x_c
sticking = x_d[1]
_, a = ẋ_c

eps = 1e-10

if sticking == fmi2True
a = 0.0
else
if eventMode
if s < r && v < 0.0
s = r + eps # so that indicator is not triggered again
v = -v*d

# stop bouncing to prevent high frequency bouncing (and maybe tunneling the floor)
if abs(v) < v_min
sticking = fmi2True
v = 0.0
end
end
end
end

a = (m * g) / m # the system's physical equation
a = (m * -g) / m # the system's physical equation
end

x = [s, v]
= [v, a]
x_c = [s, v]
ẋ_c = [v, a]
x_d = [sticking]
p = [m, r, d, v_min, g]

return (x, ẋ, p)
return (x_c, ẋ_c, x_d, p) # evaluation can't change discrete state!
end

FMU_FCT_OUTPUT = function(t, x, ẋ, u, p)
m, r, d, v_min, g = (p...,)
s, v = (x...,)
_, a = (ẋ...,)
FMU_FCT_OUTPUT = function(t, x_c, ẋ_c, x_d, u, p)
m, r, d, v_min, g = p
s, v = x_c
_, a = ẋ_c
sticking = x_d[1]

y = [s]

return y
end

FMU_FCT_EVENT = function(t, x, ẋ, u, p)
m, r, d, v_min, g = (p...,)
s, v = (x...,)
_, a = (ẋ...,)

z1 = (s-r) # event 1: ball hits ground
FMU_FCT_EVENT = function(t, x_c, ẋ_c, x_d, u, p)
m, r, d, v_min, g = p
s, v = x_c
_, a = ẋ_c
sticking = x_d[1]

if s==r && v==0.0
if sticking == fmi2True
z1 = 1.0 # event 1: ball stay-on-ground
else
z1 = (s-r) # event 1: ball hits ground
end

z = [z1]
Expand All @@ -84,12 +99,20 @@ FMIBUILD_CONSTRUCTOR = function(resPath="")
outputFct=FMU_FCT_OUTPUT,
eventFct=FMU_FCT_EVENT)

fmu.modelDescription.modelName = "BouncingBall"

# modes
fmi2ModelDescriptionAddModelExchange(fmu.modelDescription, "BouncingBall")

# states [2]
fmi2AddStateAndDerivative(fmu, "ball.s"; stateDescr="Absolute position of ball center of mass", derivativeDescr="Absolute velocity of ball center of mass")
fmi2AddStateAndDerivative(fmu, "ball.v"; stateDescr="Absolute velocity of ball center of mass", derivativeDescr="Absolute acceleration of ball center of mass")

# discrete state [1]
fmi2AddIntegerDiscreteState(fmu, "sticking"; description="Indicator (boolean) if the mass is sticking on the ground, as soon as abs(v) < v_min")

# outputs [1]
fmi2AddRealOutput(fmu, "ball.s"; description="Absolute position of ball center of mass")
fmi2AddRealOutput(fmu, "ball.s_out"; description="Absolute position of ball center of mass")

# parameters [5]
fmi2AddRealParameter(fmu, "m"; description="Mass of ball")
Expand All @@ -116,10 +139,10 @@ fmi2Save(fmu, fmu_save_path) # <= this must be excluded during export, becaus

### some tests ###
# using FMI
# comp = fmiInstantiate!(fmu; loggingOn=true)
# solution = fmiSimulateME(comp, 0.0, 10.0; dtmax=0.1)
# fmiPlot(fmu, solution)
# fmiFreeInstance!(comp)
# fmu.executionConfig.loggingOn = true
# solution = fmiSimulateME(fmu, (0.0, 5.0); dtmax=0.1)
# using Plots
# fmiPlot(solution)

# The following line is a end-marker for excluded code for the FMU compilation process!
### FMIBUILD_NO_EXPORT_END ###
15 changes: 15 additions & 0 deletions example/FMI2/Manipulation/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name = "Manipulation"
uuid = "a60229a6-2119-4702-9088-6d2bb886a221"
authors = ["TT <[email protected]>"]
version = "0.1.0"

[deps]
FMIBuild = "226f0e26-6dd6-4589-ada7-1d32f6e1d800"
FMIExport = "31b88311-cab6-44ed-ba9c-fe5a9abbd67a"
FMIImport = "9fcbc62e-52a0-44e9-a616-1359a0008194"
FMIZoo = "724179cf-c260-40a9-bd27-cccc6fe2f195"

[compat]
FMIBuild = "0.1.15"
FMIExport = "0.2.0"
julia = "1.6"
92 changes: 92 additions & 0 deletions example/FMI2/Manipulation/src/Manipulation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

using FMIExport: fmi2SetFctGetReal, fmi2CreateEmbedded
using FMIExport.FMICore: fmi2Real, fmi2Component, fmi2StatusOK, fmi2ValueReference
using FMIExport.FMICore: fmi2CausalityParameter, fmi2VariabilityTunable, fmi2InitialExact
using FMIImport: fmi2Load
import FMIExport

originalGetReal = nothing # function pointer to the original fmi2GetReal c-function

# custom function for fmi2GetReal!(fmi2Component, Union{Array{fmi2ValueReference}, Ptr{fmi2ValueReference}}, Csize_t, value::Union{Array{fmi2Real}, Ptr{fmi2Real}}::fmi2Status
# for information on how the FMI2-functions are structured, have a look inside FMICore.jl/src/FMI2_c.jl or the FMI2.0.3-specification on fmi-standard.org
function myGetReal!(c::fmi2Component, vr::Union{Array{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{Array{fmi2Real}, Ptr{fmi2Real}})
global originalGetReal

# first, we do what the original function does
status = FMIExport.FMICore.fmi2GetReal!(originalGetReal, c, vr, nvr, value)

# if we have a pointer to an array, we must interprete it as array to access elements
if isa(value, Ptr{fmi2Real})
value = unsafe_wrap(Array{fmi2Real}, value, nvr, own=false)
end
if isa(vr, Ptr{fmi2ValueReference})
vr = unsafe_wrap(Array{fmi2ValueReference}, vr, nvr, own=false)
end

# now, we add noise (just for fun!)
for i in 1:nvr
if vr[i] == 335544320 # value reference for "positionSensor.s"
value[i] += (-0.5 + rand())*0.25
end
end

# ... and we return the original status
return status
end

# this function is called, as soon as the DLL is loaded and Julia is initialized
# must return a FMU2-instance to work with
FMIBUILD_CONSTRUCTOR = function(resPath)
global originalGetReal

# loads an existing FMU inside the FMU
fmu = fmi2Load(joinpath(resPath, "SpringDamperPendulum1D.fmu"))

# create a FMU that embedds the existing FMU
fmu = fmi2CreateEmbedded(fmu)

fmu.modelDescription.modelName = "Manipulation"
fmu.modelDescription.modelExchange.modelIdentifier = "Manipulation"
fmu.modelDescription.coSimulation = nothing

# deactivate special features, because they are not implemented yet
fmu.modelDescription.modelExchange.canGetAndSetFMUstate=false
fmu.modelDescription.modelExchange.canSerializeFMUstate=false
fmu.modelDescription.modelExchange.providesDirectionalDerivative=false

# save, where the original `fmi2GetReal` function was stored, so we can access it in our new function
originalGetReal = fmu.cGetReal

# now we overwrite the original function
fmi2SetFctGetReal(fmu, myGetReal!)

return fmu
end

### FMIBUILD_NO_EXPORT_BEGIN ###
# The line above is a start-marker for excluded code for the FMU compilation process!

import FMIZoo

tmpDir = mktempdir(; prefix="fmibuildjl_test_", cleanup=false)
@info "Saving example files at: $(tmpDir)"
fmu_save_path = joinpath(tmpDir, "Manipulation.fmu")

sourceFMU = FMIZoo.get_model_filename("SpringDamperPendulum1D", "Dymola", "2022x")
fmu = FMIBUILD_CONSTRUCTOR(dirname(sourceFMU))
import FMIBuild:fmi2Save # <= this must be excluded during export, because FMIBuild cannot execute itself (but it is able to build)
fmi2Save(fmu, fmu_save_path; resources=Dict(sourceFMU=>"SpringDamperPendulum1D.fmu")) # <= this must be excluded during export, because fmi2Save would start an infinte build loop with itself

# some tests
# using FMI
# fmu.executionConfig.loggingOn = true
# solution = fmiSimulateME(fmu, (0.0, 5.0); dtmax=0.1, recordValues=[fmi2ValueReference(335544320)])
# using Plots
# fmiPlot(solution)

# The following line is a end-marker for excluded code for the FMU compilation process!
### FMIBUILD_NO_EXPORT_END ###
15 changes: 15 additions & 0 deletions example/FMI2/NeuralFMU/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name = "NeuralFMU"
uuid = "a60229a6-2119-4702-9088-6d2bb886a221"
authors = ["TT <[email protected]>"]
version = "0.1.0"

[deps]
FMIBuild = "226f0e26-6dd6-4589-ada7-1d32f6e1d800"
FMIExport = "31b88311-cab6-44ed-ba9c-fe5a9abbd67a"
FMIImport = "9fcbc62e-52a0-44e9-a616-1359a0008194"
FMIZoo = "724179cf-c260-40a9-bd27-cccc6fe2f195"

[compat]
FMIBuild = "0.1.15"
FMIExport = "0.2.0"
julia = "1.6"
Loading

2 comments on commit 3482e5d

@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/82842

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.2.0 -m "<description of version>" 3482e5d88197d17c4c43421a5c8b612850332b1b
git push origin v0.2.0

Please sign in to comment.