Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ThummeTo/FMIImport.jl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.6.3
Choose a base ref
...
head repository: ThummeTo/FMIImport.jl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.7.0
Choose a head ref
  • 2 commits
  • 13 files changed
  • 2 contributors

Commits on Mar 18, 2022

  1. Copy the full SHA
    a40b51e View commit details
  2. Disable Callbacks (#12)

    * Disable Callbacks
    
    * modified logging.jl
    
    * fixed typo
    
    * fixed  damaged test
    
    * fixed test
    
    * fixed test
    ThummeTo authored Mar 18, 2022
    2
    Copy the full SHA
    6e412b7 View commit details
Showing with 412 additions and 205 deletions.
  1. +17 −0 .github/workflows/CompatHelper.yml
  2. +2 −2 Project.toml
  3. +9 −5 src/FMI2_c.jl
  4. +41 −21 src/FMI2_ext.jl
  5. +14 −2 src/FMI2_int.jl
  6. +209 −96 src/FMI2_md.jl
  7. +2 −0 test/Project.toml
  8. +9 −12 test/dir_ders.jl
  9. +17 −27 test/getter_setter.jl
  10. +69 −0 test/logging.jl
  11. +13 −34 test/model_description.jl
  12. +9 −3 test/runtests.jl
  13. +1 −3 test/state.jl
17 changes: 17 additions & 0 deletions .github/workflows/CompatHelper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: CompatHelper
on:
schedule:
- cron: 0 0 * * *
workflow_dispatch:
jobs:
CompatHelper:
runs-on: ubuntu-latest
steps:
- name: Install CompatHelper
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
- name: Run CompatHelper
run: julia -e 'using CompatHelper; CompatHelper.main()'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }}

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 <tobias.thummerer@informatik.uni-augsburg.de>", "LM <lars.mikelsons@informatik.uni-augsburg.de>", "JK <josef.kircher@student.uni-augsburg.de>"]
version = "0.6.3"
version = "0.7.0"

[deps]
EzXML = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615"
@@ -11,6 +11,6 @@ ZipFile = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"

[compat]
EzXML = "^1.1"
FMICore = "0.6.3"
FMICore = "0.7.0"
ZipFile = "0.9.4"
julia = "1.6"
14 changes: 9 additions & 5 deletions src/FMI2_c.jl
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ Source: FMISpec2.0.2[p.21]: 2.1.5 Creation, Destruction and Logging of FMU Insta
Function that is called in the FMU, usually if an fmi2XXX function, does not behave as desired. If “logger” is called with “status = fmi2OK”, then the message is a pure information message. “instanceName” is the instance name of the model that calls this function. “category” is the category of the message. The meaning of “category” is defined by the modeling environment that generated the FMU. Depending on this modeling environment, none, some or all allowed values of “category” for this FMU are defined in the modelDescription.xml file via element “<fmiModelDescription><LogCategories>”, see section 2.2.4. Only messages are provided by function logger that have a category according to a call to fmi2SetDebugLogging (see below). Argument “message” is provided in the same way and with the same format control as in function “printf” from the C standard library. [Typically, this function prints the message and stores it optionally in a log file.]
"""
function fmi2CallbackLogger(componentEnvironment::fmi2ComponentEnvironment,
function fmi2CallbackLogger(_componentEnvironment::Ptr{FMU2ComponentEnvironment},
instanceName::Ptr{Cchar},
status::Cuint,
category::Ptr{Cchar},
@@ -36,16 +36,20 @@ function fmi2CallbackLogger(componentEnvironment::fmi2ComponentEnvironment,
_category = unsafe_string(category)
_status = fmi2StatusToString(status)
_instanceName = unsafe_string(instanceName)
componentEnvironment = unsafe_load(_componentEnvironment)

if status == fmi2StatusOK
if status == fmi2StatusOK && componentEnvironment.logStatusOK
@info "[$_status][$_category][$_instanceName]: $_message"
elseif status == fmi2StatusWarning
elseif (status == fmi2StatusWarning && componentEnvironment.logStatusWarning) ||
(status == fmi2StatusPending && componentEnvironment.logStatusPending)
@warn "[$_status][$_category][$_instanceName]: $_message"
else
elseif (status == fmi2StatusDiscard && componentEnvironment.logStatusDiscard) ||
(status == fmi2StatusError && componentEnvironment.logStatusError) ||
(status == fmi2StatusFatal && componentEnvironment.logStatusFatal)
@error "[$_status][$_category][$_instanceName]: $_message"
end

nothing
return nothing
end

# (cfmi2CallbackLogger, fmi2CallbackLogger) = Cfunction{ fmi2ComponentEnvironment, Ptr{Cchar}, Cuint, Ptr{Cchar}, Tuple{Ptr{Cchar}, Vararg} }() do componentEnvironment::fmi2ComponentEnvironment, instanceName::Ptr{Cchar}, status::Cuint, category::Ptr{Cchar}, message::Tuple{Ptr{Cchar}, Vararg}
62 changes: 41 additions & 21 deletions src/FMI2_ext.jl
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@
using Libdl
using ZipFile

DEFAULT_SAMPLE_STEP = 1e-8

"""
Create a copy of the .fmu file as a .zip folder and unzips it.
Returns the paths to the zipped and unzipped folders.
@@ -289,10 +291,25 @@ For more information call ?fmi2Instantiate
- `visible` if the FMU should be started with graphic interface, if supported (default=`false`)
- `loggingOn` if the FMU should log and display function calls (default=`false`)
- `externalCallbacks` if an external DLL should be used for the fmi2CallbackFunctions, this may improve readability of logging messages (default=`false`)
- `logStatusOK` whether to log status of kind `fmi2OK` (default=`true`)
- `logStatusWarning whether to log status of kind `fmi2Warning` (default=`true`)
- `logStatusDiscard whether to log status of kind `fmi2Discard` (default=`true`)
- `logStatusError whether to log status of kind `fmi2Error` (default=`true`)
- `logStatusFatal whether to log status of kind `fmi2Fatal` (default=`true`)
- `logStatusPending whether to log status of kind `fmi2Pending` (default=`true`)
"""
function fmi2Instantiate!(fmu::FMU2; visible::Bool = false, loggingOn::Bool = false, externalCallbacks::Bool = false)

ptrLogger = @cfunction(fmi2CallbackLogger, Cvoid, (Ptr{Cvoid}, Ptr{Cchar}, Cuint, Ptr{Cchar}, Ptr{Cchar}))
function fmi2Instantiate!(fmu::FMU2; visible::Bool = false, loggingOn::Bool = false, externalCallbacks::Bool = false,
logStatusOK::Bool=true, logStatusWarning::Bool=true, logStatusDiscard::Bool=true, logStatusError::Bool=true, logStatusFatal::Bool=true, logStatusPending::Bool=true)

compEnv = FMU2ComponentEnvironment()
compEnv.logStatusOK = logStatusOK
compEnv.logStatusWarning = logStatusWarning
compEnv.logStatusDiscard = logStatusDiscard
compEnv.logStatusError = logStatusError
compEnv.logStatusFatal = logStatusFatal
compEnv.logStatusPending = logStatusPending

ptrLogger = @cfunction(fmi2CallbackLogger, Cvoid, (Ptr{FMU2ComponentEnvironment}, Ptr{Cchar}, Cuint, Ptr{Cchar}, Ptr{Cchar}))
if externalCallbacks
if fmu.callbackLibHandle == C_NULL
@assert Sys.iswindows() && Sys.WORD_SIZE == 64 "`externalCallbacks=true` is only supported for Windows 64-bit."
@@ -303,11 +320,12 @@ function fmi2Instantiate!(fmu::FMU2; visible::Bool = false, loggingOn::Bool = fa
ptrAllocateMemory = @cfunction(fmi2CallbackAllocateMemory, Ptr{Cvoid}, (Csize_t, Csize_t))
ptrFreeMemory = @cfunction(fmi2CallbackFreeMemory, Cvoid, (Ptr{Cvoid},))
ptrStepFinished = C_NULL # ToDo
fmu.callbackFunctions = fmi2CallbackFunctions(ptrLogger, ptrAllocateMemory, ptrFreeMemory, ptrStepFinished, C_NULL)
ptrComponentEnvironment = Ptr{FMU2ComponentEnvironment}(pointer_from_objref(compEnv))
callbackFunctions = fmi2CallbackFunctions(ptrLogger, ptrAllocateMemory, ptrFreeMemory, ptrStepFinished, ptrComponentEnvironment)

guidStr = "$(fmu.modelDescription.guid)"

compAddr = fmi2Instantiate(fmu.cInstantiate, pointer(fmu.instanceName), fmu.type, pointer(guidStr), pointer(fmu.fmuResourceLocation), Ptr{fmi2CallbackFunctions}(pointer_from_objref(fmu.callbackFunctions)), fmi2Boolean(visible), fmi2Boolean(loggingOn))
compAddr = fmi2Instantiate(fmu.cInstantiate, pointer(fmu.instanceName), fmu.type, pointer(guidStr), pointer(fmu.fmuResourceLocation), Ptr{fmi2CallbackFunctions}(pointer_from_objref(callbackFunctions)), fmi2Boolean(visible), fmi2Boolean(loggingOn))

if compAddr == Ptr{Cvoid}(C_NULL)
@error "fmi2Instantiate!(...): Instantiation failed!"
@@ -329,6 +347,8 @@ function fmi2Instantiate!(fmu::FMU2; visible::Bool = false, loggingOn::Bool = fa
else
component = FMU2Component(compAddr, fmu)
component.jacobianFct = fmi2GetJacobian!
component.componentEnvironment = compEnv
component.callbackFunctions = callbackFunctions
push!(fmu.components, component)
end

@@ -375,7 +395,7 @@ This function samples the directional derivative by manipulating corresponding v
function fmi2SampleDirectionalDerivative(c::fmi2Component,
vUnknown_ref::Array{fmi2ValueReference},
vKnown_ref::Array{fmi2ValueReference},
steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*DEFAULT_SAMPLE_STEP)

dvUnknown = zeros(fmi2Real, length(vUnknown_ref), length(vKnown_ref))

@@ -391,7 +411,7 @@ function fmi2SampleDirectionalDerivative!(c::fmi2Component,
vUnknown_ref::Array{fmi2ValueReference},
vKnown_ref::Array{fmi2ValueReference},
dvUnknown::AbstractArray,
steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*DEFAULT_SAMPLE_STEP)

for i in 1:length(vKnown_ref)
vKnown = vKnown_ref[i]
@@ -427,7 +447,7 @@ If sampling is used, sampling step size can be set (for each direction individua
function fmi2GetJacobian(comp::FMU2Component,
rdx::Array{fmi2ValueReference},
rx::Array{fmi2ValueReference};
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*DEFAULT_SAMPLE_STEP)
mat = zeros(fmi2Real, length(rdx), length(rx))
fmi2GetJacobian!(mat, comp, rdx, rx; steps=steps)
return mat
@@ -446,7 +466,7 @@ function fmi2GetJacobian!(jac::Matrix{fmi2Real},
comp::FMU2Component,
rdx::Array{fmi2ValueReference},
rx::Array{fmi2ValueReference};
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*DEFAULT_SAMPLE_STEP)

@assert size(jac) == (length(rdx), length(rx)) ["fmi2GetJacobian!: Dimension missmatch between `jac` $(size(jac)), `rdx` ($length(rdx)) and `rx` ($length(rx))."]

@@ -505,7 +525,7 @@ If sampling is used, sampling step size can be set (for each direction individua
function fmi2GetFullJacobian(comp::FMU2Component,
rdx::Array{fmi2ValueReference},
rx::Array{fmi2ValueReference};
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*DEFAULT_SAMPLE_STEP)
mat = zeros(fmi2Real, length(rdx), length(rx))
fmi2GetFullJacobian!(mat, comp, rdx, rx; steps=steps)
return mat
@@ -524,7 +544,7 @@ function fmi2GetFullJacobian!(jac::Matrix{fmi2Real},
comp::FMU2Component,
rdx::Array{fmi2ValueReference},
rx::Array{fmi2ValueReference};
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*1e-5)
steps::Array{fmi2Real} = ones(fmi2Real, length(rdx)).*DEFAULT_SAMPLE_STEP)
@assert size(jac) == (length(rdx),length(rx)) "fmi2GetFullJacobian!: Dimension missmatch between `jac` $(size(jac)), `rdx` ($length(rdx)) and `rx` ($length(rx))."

@warn "`fmi2GetFullJacobian!` is for benchmarking only, please use `fmi2GetJacobian`."
@@ -555,19 +575,19 @@ function fmi2Get!(comp::FMU2Component, vrs::fmi2ValueReferenceFormat, dstArray::
mv = fmi2ModelVariablesForValueReference(comp.fmu.modelDescription, vr)
mv = mv[1]

if mv.datatype.datatype == fmi2Real
if mv._Real != nothing
#@assert isa(dstArray[i], Real) "fmi2Get!(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Real`, is `$(typeof(dstArray[i]))`."
dstArray[i] = fmi2GetReal(comp, vr)
elseif mv.datatype.datatype == fmi2Integer
elseif mv._Integer != nothing
#@assert isa(dstArray[i], Union{Real, Integer}) "fmi2Get!(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Integer`, is `$(typeof(dstArray[i]))`."
dstArray[i] = fmi2GetInteger(comp, vr)
elseif mv.datatype.datatype == fmi2Boolean
elseif mv._Boolean != nothing
#@assert isa(dstArray[i], Union{Real, Bool}) "fmi2Get!(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Bool`, is `$(typeof(dstArray[i]))`."
dstArray[i] = fmi2GetBoolean(comp, vr)
elseif mv.datatype.datatype == fmi2String
elseif mv._String != nothing
#@assert isa(dstArray[i], String) "fmi2Get!(...): Unknown data type for value reference `$(vr)` at index $(i), should be `String`, is `$(typeof(dstArray[i]))`."
dstArray[i] = fmi2GetString(comp, vr)
elseif mv.datatype.datatype == fmi2Enum
elseif mv._Enumeration != nothing
@warn "fmi2Get!(...): Currently not implemented for fmi2Enum."
else
@assert isa(dstArray[i], Real) "fmi2Get!(...): Unknown data type for value reference `$(vr)` at index $(i), is `$(mv.datatype.datatype)`."
@@ -594,19 +614,19 @@ function fmi2Set(comp::FMU2Component, vrs::fmi2ValueReferenceFormat, srcArray::A
mv = fmi2ModelVariablesForValueReference(comp.fmu.modelDescription, vr)
mv = mv[1]

if mv.datatype.datatype == fmi2Real
if mv._Real != nothing
@assert isa(srcArray[i], Real) "fmi2Set(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Real`, is `$(typeof(srcArray[i]))`."
fmi2SetReal(comp, vr, srcArray[i])
elseif mv.datatype.datatype == fmi2Integer
elseif mv._Integer != nothing
@assert isa(srcArray[i], Union{Real, Integer}) "fmi2Set(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Integer`, is `$(typeof(srcArray[i]))`."
fmi2SetInteger(comp, vr, Integer(srcArray[i]))
elseif mv.datatype.datatype == fmi2Boolean
elseif mv._Boolean != nothing
@assert isa(srcArray[i], Union{Real, Bool}) "fmi2Set(...): Unknown data type for value reference `$(vr)` at index $(i), should be `Bool`, is `$(typeof(srcArray[i]))`."
fmi2SetBoolean(comp, vr, Bool(srcArray[i]))
elseif mv.datatype.datatype == fmi2String
elseif mv._String != nothing
@assert isa(srcArray[i], String) "fmi2Set(...): Unknown data type for value reference `$(vr)` at index $(i), should be `String`, is `$(typeof(srcArray[i]))`."
fmi2SetString(comp, vr, srcArray[i])
elseif mv.datatype.datatype == fmi2Enum
elseif mv._Enumeration != nothing
@warn "fmi2Set(...): Currently not implemented for fmi2Enum."
else
@assert false "fmi2Set(...): Unknown data type for value reference `$(vr)` at index $(i), is `$(mv.datatype.datatype)`."
16 changes: 14 additions & 2 deletions src/FMI2_int.jl
Original file line number Diff line number Diff line change
@@ -712,10 +712,22 @@ function fmi2GetStartValue(c::FMU2Component, vrs::fmi2ValueReferenceFormat)
mvs = fmi2ModelVariablesForValueReference(c.fmu.modelDescription, vr)

if length(mvs) == 0
@warn "fmi2GetStartValue(...) found no model variable with value reference $(vr)."
@warn "fmi2GetStartValue(...): Found no model variable with value reference $(vr)."
end

push!(starts, mvs[1].datatype.start)
if mvs[1]._Real != nothing
push!(starts, mvs[1]._Real.start)
elseif mvs[1]._Integer != nothing
push!(starts, mvs[1]._Integer.start)
elseif mvs[1]._Boolean != nothing
push!(starts, mvs[1]._Boolean.start)
elseif mvs[1]._String != nothing
push!(starts, mvs[1]._String.start)
elseif mvs[1]._Enumeration != nothing
push!(starts, mvs[1]._Enumeration.start)
else
@assert false "fmi2GetStartValue(...): Value reference $(vr) has no data type."
end
end

if length(vrs) == 1
Loading