Skip to content

Commit

Permalink
formatted by JuliaFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
0815Creeper committed Dec 16, 2024
1 parent 8c1f976 commit 33a61a2
Show file tree
Hide file tree
Showing 13 changed files with 808 additions and 395 deletions.
86 changes: 57 additions & 29 deletions examples/FMI2/BouncingBall/src/BouncingBall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
# https://github.com/modelica/Reference-FMUs/blob/main/BouncingBall/model.c

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

EPS = 1e-8

FMU_FCT_INIT = function()
FMU_FCT_INIT = function ()
m = 1.0 # ball mass
r = 0.0 # ball radius
d = 0.7 # ball collision damping
Expand All @@ -23,8 +23,8 @@ FMU_FCT_INIT = function()
v = 0.0 # ball velocity
a = 0.0 # ball acceleration

t = 0.0
x_c = [s, v]
t = 0.0
x_c = [s, v]
ẋ_c = [v, a]
x_d = [sticking]
u = []
Expand All @@ -33,7 +33,7 @@ FMU_FCT_INIT = function()
return (t, x_c, ẋ_c, x_d, u, p)
end

FMU_FCT_EVALUATE = function(t, x_c, ẋ_c, x_d, u, p, eventMode)
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]
Expand All @@ -44,10 +44,10 @@ FMU_FCT_EVALUATE = function(t, x_c, ẋ_c, x_d, u, p, eventMode)
elseif sticking == fmi2False

if eventMode
h = s-r
h = s - r
if h <= 0 && v < 0
s = r + EPS # so that indicator is not triggered again
v = -v*d
v = -v * d

# stop bouncing to prevent high frequency bouncing (and maybe tunneling the floor)
if abs(v) < v_min
Expand All @@ -73,7 +73,7 @@ FMU_FCT_EVALUATE = function(t, x_c, ẋ_c, x_d, u, p, eventMode)
return (x_c, ẋ_c, x_d, p)
end

FMU_FCT_OUTPUT = function(t, x_c, ẋ_c, x_d, u, p)
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
Expand All @@ -84,22 +84,22 @@ FMU_FCT_OUTPUT = function(t, x_c, ẋ_c, x_d, u, p)
return y
end

FMU_FCT_EVENT = function(t, x_c, ẋ_c, x_d, u, p)
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]

# helpers
z1 = 0.0 # first event indicator
h = s-r # ball height
h = s - r # ball height

if sticking == fmi2True
z1 = 1.0 # event 1: ball stay-on-ground
else
if h > -EPS && h <= 0 && v > 0
z1 = -EPS
else
else
z1 = h
end
end
Expand All @@ -111,33 +111,61 @@ 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="")
fmu = fmi2CreateSimple(initializationFct=FMU_FCT_INIT,
evaluationFct=FMU_FCT_EVALUATE,
outputFct=FMU_FCT_OUTPUT,
eventFct=FMU_FCT_EVENT)
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 = "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")
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")
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_out"; 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")
fmi2AddRealParameter(fmu, "r"; description="Radius of ball")
fmi2AddRealParameter(fmu, "d"; description="Collision damping constant (velocity fraction after hitting the ground)")
fmi2AddRealParameter(fmu, "v_min"; description="Minimal ball velocity to enter on-ground-state")
fmi2AddRealParameter(fmu, "g"; description="Gravity constant")
fmi2AddRealParameter(fmu, "m"; description = "Mass of ball")
fmi2AddRealParameter(fmu, "r"; description = "Radius of ball")
fmi2AddRealParameter(
fmu,
"d";
description = "Collision damping constant (velocity fraction after hitting the ground)",
)
fmi2AddRealParameter(
fmu,
"v_min";
description = "Minimal ball velocity to enter on-ground-state",
)
fmi2AddRealParameter(fmu, "g"; description = "Gravity constant")

fmi2AddEventIndicator(fmu)

Expand All @@ -147,18 +175,18 @@ end
### FMIBUILD_NO_EXPORT_BEGIN ###
# The line above is a start-marker for excluded code for the FMU compilation process!

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

fmu = FMIBUILD_CONSTRUCTOR()
using FMIBuild: saveFMU # <= this must be excluded during export, because FMIBuild cannot execute itself (but it is able to build)
saveFMU(fmu, fmu_save_path; debug=true, compress=false) # <= this must be excluded during export, because saveFMU would start an infinite build loop with itself (debug=true allows debug messages, but is slow during execution!)
saveFMU(fmu, fmu_save_path; debug = true, compress = false) # <= this must be excluded during export, because saveFMU would start an infinite build loop with itself (debug=true allows debug messages, but is slow during execution!)

### some tests ###
using FMI, DifferentialEquations
fmu.executionConfig.loggingOn = true
solution = simulate(fmu, (0.0, 3.0); recordValues=["sticking"])
solution = simulate(fmu, (0.0, 3.0); recordValues = ["sticking"])
using Plots
plot(solution)

Expand Down
40 changes: 23 additions & 17 deletions examples/FMI2/Manipulation/src/Manipulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,48 @@

using FMIExport: fmi2SetFctGetReal, fmi2CreateEmbedded
using FMIExport.FMIBase.FMICore: fmi2Real, fmi2Component, fmi2StatusOK, fmi2ValueReference
using FMIExport.FMIBase.FMICore: fmi2CausalityParameter, fmi2VariabilityTunable, fmi2InitialExact
using FMIExport.FMIBase.FMICore:
fmi2CausalityParameter, fmi2VariabilityTunable, fmi2InitialExact
using FMIImport: loadFMU
import FMIExport
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}})
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.FMIBase.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)
value = unsafe_wrap(Array{fmi2Real}, value, nvr, own = false)
end
if isa(vr, Ptr{fmi2ValueReference})
vr = unsafe_wrap(Array{fmi2ValueReference}, vr, nvr, own=false)
vr = unsafe_wrap(Array{fmi2ValueReference}, vr, nvr, own = false)
end

# now, we add noise (just for fun!)
for i in 1:nvr
for i = 1:nvr
if vr[i] == 335544320 # value reference for "positionSensor.s"
value[i] += (-0.5 + rand())*0.25
value[i] += (-0.5 + rand()) * 0.25
end
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)
FMIBUILD_CONSTRUCTOR = function (resPath)
global originalGetReal

# loads an existing FMU inside the FMU
Expand All @@ -54,9 +60,9 @@ FMIBUILD_CONSTRUCTOR = function(resPath)
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
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
Expand All @@ -72,14 +78,14 @@ end

import FMIZoo

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

sourceFMU = FMIZoo.get_model_filename("SpringDamperPendulum1D", "Dymola", "2022x")
fmu = FMIBUILD_CONSTRUCTOR(dirname(sourceFMU))
import FMIBuild:saveFMU # <= this must be excluded during export, because FMIBuild cannot execute itself (but it is able to build)
saveFMU(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
import FMIBuild: saveFMU # <= this must be excluded during export, because FMIBuild cannot execute itself (but it is able to build)
saveFMU(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
Expand Down
Loading

0 comments on commit 33a61a2

Please sign in to comment.