From f8b987474f84c5430a08f7bc151607ef14e56d61 Mon Sep 17 00:00:00 2001 From: ThummeTo <83663542+ThummeTo@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:42:20 +0200 Subject: [PATCH] v1.0.0 (#63) * refactoring for FMIBase.jl * PkgEval test * WIP --- Project.toml | 6 +- README.md | 6 +- src/FMI2/cconst.jl | 57 +-- src/FMI2/cfunc.jl | 10 +- src/FMI2/cfunc_unload.jl | 3 +- src/FMI2/convert.jl | 234 --------- src/FMI2/ctype.jl | 26 +- src/FMI2/eval.jl | 295 ------------ src/FMI2/io.jl | 207 -------- src/FMI2/struct.jl | 802 ------------------------------- src/FMI3/cconst.jl | 341 ++++++++++--- src/FMI3/cfunc.jl | 8 +- src/FMI3/convert.jl | 331 ------------- src/FMI3/ctype.jl | 62 +-- src/FMI3/struct.jl | 500 ------------------- src/FMICore.jl | 58 +-- src/error_msg.jl | 6 - src/extensions/FMISensitivity.jl | 65 --- src/jacobian.jl | 17 - src/logging.jl | 40 -- src/printing.jl | 60 --- src/sense.jl | 97 ---- src/snapshot.jl | 162 ------- src/types.jl | 107 ----- test/eval.jl | 7 +- test/runtests.jl | 4 +- 26 files changed, 369 insertions(+), 3142 deletions(-) delete mode 100644 src/FMI2/convert.jl delete mode 100644 src/FMI2/eval.jl delete mode 100644 src/FMI2/io.jl delete mode 100644 src/FMI2/struct.jl delete mode 100644 src/FMI3/convert.jl delete mode 100644 src/FMI3/struct.jl delete mode 100644 src/error_msg.jl delete mode 100644 src/extensions/FMISensitivity.jl delete mode 100644 src/jacobian.jl delete mode 100644 src/logging.jl delete mode 100644 src/printing.jl delete mode 100644 src/sense.jl delete mode 100644 src/snapshot.jl delete mode 100644 src/types.jl diff --git a/Project.toml b/Project.toml index 6a1fc37..14d7277 100644 --- a/Project.toml +++ b/Project.toml @@ -1,15 +1,11 @@ name = "FMICore" uuid = "8af89139-c281-408e-bce2-3005eb87462f" authors = ["TT ", "LM ", "JK "] -version = "0.20.1" +version = "1.0.0" [deps] -ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" [compat] -ChainRulesCore = "1.16" Dates = "1" -Requires = "1.3.0" julia = "1.6" diff --git a/README.md b/README.md index 70481a4..ed9f594 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ ## What is FMICore.jl? [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) implements the low-level equivalents of the C-functions and C-data types of the FMI-standard ([fmi-standard.org](http://fmi-standard.org/)) for the Julia programming language. -[*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) provides the foundation for the Julia packages [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl) and [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl). [![Dev Docs](https://img.shields.io/badge/docs-dev-blue.svg)](https://ThummeTo.github.io/FMI.jl/dev) [![Run Tests](https://github.com/ThummeTo/FMICore.jl/actions/workflows/Test.yml/badge.svg)](https://github.com/ThummeTo/FMICore.jl/actions/workflows/Test.yml) @@ -31,14 +30,15 @@ To keep dependencies nice and clean, the original package [*FMI.jl*](https://git - [*FMI.jl*](https://github.com/ThummeTo/FMI.jl): High level loading, manipulating, saving or building entire FMUs from scratch - [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl): Importing FMUs into Julia - [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl): Exporting stand-alone FMUs from Julia Code +- [*FMIBase.jl*](https://github.com/ThummeTo/FMIBase.jl): Common concepts for import and export of FMUs - [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl): C-code wrapper for the FMI-standard - [*FMISensitivity.jl*](https://github.com/ThummeTo/FMISensitivity.jl): Static and dynamic sensitivities over FMUs - [*FMIBuild.jl*](https://github.com/ThummeTo/FMIBuild.jl): Compiler/Compilation dependencies for FMIExport.jl -- [*FMIFlux.jl*](https://github.com/ThummeTo/FMIFlux.jl): Machine Learning with FMUs (differentiation over FMUs) +- [*FMIFlux.jl*](https://github.com/ThummeTo/FMIFlux.jl): Machine Learning with FMUs - [*FMIZoo.jl*](https://github.com/ThummeTo/FMIZoo.jl): A collection of testing and example FMUs ## What Platforms are supported? -[*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) is tested (and testing) under Julia Versions *v1.6 LTS* and *v1 latest* on Windows *latest*, Ubuntu *latest* and MacOS *latest*. `x64` and `x86` architectures are tested. +[*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) is tested (and testing) under Julia Versions *v1.6 LTS* and *v1 latest* on Windows *latest* (`x64` and `x86`) and Ubuntu *latest* (`x64`). MacOS is not CI-tested but should work with Mac-FMUs. ## How to cite? Tobias Thummerer, Lars Mikelsons and Josef Kircher. 2021. **NeuralFMU: towards structural integration of FMUs into neural networks.** Martin Sjölund, Lena Buffoni, Adrian Pop and Lennart Ochel (Ed.). Proceedings of 14th Modelica Conference 2021, Linköping, Sweden, September 20-24, 2021. Linköping University Electronic Press, Linköping (Linköping Electronic Conference Proceedings ; 181), 297-306. [DOI: 10.3384/ecp21181297](https://doi.org/10.3384/ecp21181297) diff --git a/src/FMI2/cconst.jl b/src/FMI2/cconst.jl index 4d71f97..13f16bd 100644 --- a/src/FMI2/cconst.jl +++ b/src/FMI2/cconst.jl @@ -32,18 +32,6 @@ const fmi2Component = Ptr{Cvoid} const fmi2ComponentEnvironment = Ptr{Cvoid} export fmi2Char, fmi2String, fmi2Boolean, fmi2Real, fmi2Integer, fmi2Byte, fmi2ValueReference, fmi2FMUstate, fmi2Component, fmi2ComponentEnvironment -# wildcards for how a user can pass a fmi2ValueReference -fmi2ValueReferenceFormat = Union{Nothing, String, AbstractArray{String,1}, fmi2ValueReference, AbstractArray{fmi2ValueReference,1}, Int64, AbstractArray{Int64,1}, Symbol} -export fmi2ValueReferenceFormat - -const fmi2Status = Cuint -const fmi2StatusOK = Cuint(0) -const fmi2StatusWarning = Cuint(1) -const fmi2StatusDiscard = Cuint(2) -const fmi2StatusError = Cuint(3) -const fmi2StatusFatal = Cuint(4) -const fmi2StatusPending = Cuint(5) - """ Source: FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions @@ -60,7 +48,13 @@ This can be done if the capability flag canGetAndSetFMUstate is true and fmi2Get - fmi2Fatal – the model computations are irreparably corrupted for all FMU instances. [For example, due to a run-time exception such as access violation or integer division by zero during the execution of an fmi function]. Function “logger” was called in the FMU (see below), and it is expected that this function has shown the prepared information message to the user. It is not possible to call any other function for any of the FMU instances. - fmi2Pending – this status is returned only from the co-simulation interface, if the slave executes the function in an asynchronous way. That means the slave starts to compute but returns immediately. The master has to call fmi2GetStatus(..., fmi2DoStepStatus) to determine if the slave has finished the computation. Can be returned only by fmi2DoStep and by fmi2GetStatus (see section 4.2.3). """ -fmi2Status, fmi2StatusOK, fmi2StatusWarning, fmi2StatusDiscard, fmi2StatusError, fmi2StatusFatal, fmi2StatusPending +const fmi2Status = Cuint +const fmi2StatusOK = Cuint(0) +const fmi2StatusWarning = Cuint(1) +const fmi2StatusDiscard = Cuint(2) +const fmi2StatusError = Cuint(3) +const fmi2StatusFatal = Cuint(4) +const fmi2StatusPending = Cuint(5) export fmi2Status, fmi2StatusOK, fmi2StatusWarning, fmi2StatusDiscard, fmi2StatusError, fmi2StatusFatal, fmi2StatusPending """ @@ -126,17 +120,24 @@ const fmi2InitialApprox = Cuint(1) const fmi2InitialCalculated = Cuint(2) export fmi2Initial, fmi2InitialExact, fmi2InitialApprox, fmi2InitialCalculated -const fmi2True = fmi2Boolean(true) -const fmi2False = fmi2Boolean(false) """ Source: FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions To simplify porting, no C types are used in the function interfaces, but the alias types are defined in this section. All definitions in this section are provided in the header file “fmi2TypesPlatform.h”. """ -fmi2True, fmi2False +const fmi2True = fmi2Boolean(true) +const fmi2False = fmi2Boolean(false) export fmi2True, fmi2False +""" +ToDo +""" +const fmi2VariableNamingConvention = Cuint +const fmi2VariableNamingConventionFlat = Cuint(0) +const fmi2VariableNamingConventionStructured = Cuint(1) +export fmi2VariableNamingConvention, fmi2VariableNamingConventionFlat, fmi2VariableNamingConventionStructured + """ Source: FMISpec2.0.2[p.19]: 2.1.5 Creation, Destruction and Logging of FMU Instances @@ -161,14 +162,14 @@ const fmi2StatusKindLastSuccessfulTime = Cuint(2) const fmi2StatusKindTerminated = Cuint(3) export fmi2StatusKind, fmi2StatusKindDoStepStatus, fmi2StatusKindPendingStatus, fmi2StatusKindLastSuccessfulTime, fmi2StatusKindTerminated -# Custom helper, not part of the FMI-Spec. """ Types of dependency: - `fmi2DependencyKindDependent`: no particular structure, f(v) - `fmi2DependencyKindConstant`: constant factor, c*v (for Real valued variables only) - `fmi2DependencyKindFixed`: tunable factor, p*v (for Real valued variables only) -- `fmi2DependencyKindDependent`: discrete factor, d*v (for Real valued variables only) +- `fmi2DependencyKindTunable` [ToDo] +- `fmi2DependencyKindDiscrete` [ToDo] Source: FMI2.0.3 Spec for fmi2VariableDependency [p.60] """ @@ -178,22 +179,4 @@ const fmi2DependencyKindConstant = Cuint(1) const fmi2DependencyKindFixed = Cuint(2) const fmi2DependencyKindTunable = Cuint(3) const fmi2DependencyKindDiscrete = Cuint(4) -export fmi2DependencyKind, fmi2DependencyKindDependent, fmi2DependencyKindConstant, fmi2DependencyKindFixed, fmi2DependencyKindTunable, fmi2DependencyKindDiscrete - -# Custom helper, not part of the FMI-Spec. -const fmi2VariableNamingConvention = Cuint -const fmi2VariableNamingConventionFlat = Cuint(0) -const fmi2VariableNamingConventionStructured = Cuint(1) -export fmi2VariableNamingConvention, fmi2VariableNamingConventionFlat, fmi2VariableNamingConventionStructured - -# this is a custom type to catch the internal mode of the component -const fmi2ComponentState = Cuint -const fmi2ComponentStateInstantiated = Cuint(0) # after instantiation -const fmi2ComponentStateInitializationMode = Cuint(1) # after finishing initialization -const fmi2ComponentStateEventMode = Cuint(2) -const fmi2ComponentStateContinuousTimeMode = Cuint(3) -const fmi2ComponentStateTerminated = Cuint(4) -const fmi2ComponentStateError = Cuint(5) -const fmi2ComponentStateFatal = Cuint(6) -export fmi2ComponentState, fmi2ComponentStateInstantiated, fmi2ComponentStateInitializationMode, fmi2ComponentStateEventMode, fmi2ComponentStateContinuousTimeMode, fmi2ComponentStateTerminated, fmi2ComponentStateError, fmi2ComponentStateFatal - +export fmi2DependencyKind, fmi2DependencyKindDependent, fmi2DependencyKindConstant, fmi2DependencyKindFixed, fmi2DependencyKindTunable, fmi2DependencyKindDiscrete \ No newline at end of file diff --git a/src/FMI2/cfunc.jl b/src/FMI2/cfunc.jl index e6b1ef0..66c8bee 100644 --- a/src/FMI2/cfunc.jl +++ b/src/FMI2/cfunc.jl @@ -35,13 +35,13 @@ If a null pointer is provided for “c”, the function call is ignored (does no Removes the component from the FMUs component list. """ -function fmi2FreeInstance!(cfunc::Ptr{Cvoid}, c::fmi2Component) +function fmi2FreeInstance(cfunc::Ptr{Cvoid}, c::fmi2Component) ccall(cfunc, Cvoid, (fmi2Component,), c) @debug "fmi2FreeInstance(c: $(c)) → [nothing]" return nothing end -export fmi2FreeInstance! +export fmi2FreeInstance """ Source: FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files @@ -320,15 +320,15 @@ Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and setting the complete FMU state fmi2FreeFMUstate frees all memory and other resources allocated with the fmi2GetFMUstate call for this FMUstate. """ -function fmi2FreeFMUstate!(cfunc::Ptr{Cvoid}, c::fmi2Component, FMUstate::Ref{fmi2FMUstate}) +function fmi2FreeFMUstate(cfunc::Ptr{Cvoid}, c::fmi2Component, FMUstate::Ref{fmi2FMUstate}) status = ccall(cfunc, fmi2Status, (fmi2Component, Ptr{fmi2FMUstate}), c, FMUstate) - @debug "fmi2FreeFMUstate!(c: $(c), FMUstate: $(FMUstate)) → $(status)" + @debug "fmi2FreeFMUstate(c: $(c), FMUstate: $(FMUstate)) → $(status)" return status end -export fmi2FreeFMUstate! +export fmi2FreeFMUstate """ Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State diff --git a/src/FMI2/cfunc_unload.jl b/src/FMI2/cfunc_unload.jl index f1ff23c..fd24fd3 100644 --- a/src/FMI2/cfunc_unload.jl +++ b/src/FMI2/cfunc_unload.jl @@ -153,4 +153,5 @@ function unload_fmi2GetNominalsOfContinuousStates(_component::fmi2Component, _x_ return fmi2StatusFatal end -# ToDo: Add CS functions! \ No newline at end of file +# ToDo: Add CS functions! +# ToDo: This shoudl be doable with a macro like @unloaded_version fmi2GetContinuousStates \ No newline at end of file diff --git a/src/FMI2/convert.jl b/src/FMI2/convert.jl deleted file mode 100644 index 90bd34b..0000000 --- a/src/FMI2/convert.jl +++ /dev/null @@ -1,234 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -""" - - fmi2StatusToString(status::Union{fmi2Status, Integer}) - -Converts `fmi2Status` `status` into a String ("OK", "Warning", "Discard", "Error", "Fatal", "Pending"). -""" -function fmi2StatusToString(status::Union{fmi2Status, Integer}) - if status == fmi2StatusOK - return "OK" - elseif status == fmi2StatusWarning - return "Warning" - elseif status == fmi2StatusDiscard - return "Discard" - elseif status == fmi2StatusError - return "Error" - elseif status == fmi2StatusFatal - return "Fatal" - elseif status == fmi2StatusPending - return "Pending" - else - @assert false "fmi2StatusToString($(status)): Unknown FMU status `$(status)`." - end -end -export fmi2StatusToString - -""" - - fmi2StringToStatus(s) - -Converts a String `s` to fmi2Status. -""" -function fmi2StatusToString(s::AbstractString) - if s == "OK" - return fmi2StatusOK - elseif s == "Warning" - return fmi2StatusWarning - elseif s == "Discard" - return fmi2StatusDiscard - elseif s == "Error" - return fmi2StatusError - elseif s == "Fatal" - return fmi2StatusFatal - elseif s == "Pending" - return fmi2StatusPending - else - @assert false "fmi2StatusToString($(s)): Unknown FMU status `$(s)`." - end -end -export fmi2StatusToString - -""" - - fmi2CausalityToString(c::fmi2Causality) - -Converts [`fmi2Causality`](@ref) `c` to the corresponding String ("parameter", "calculatedParameter", "input", "output", "local", "independent"). -""" -function fmi2CausalityToString(c::fmi2Causality) - if c == fmi2CausalityParameter - return "parameter" - elseif c == fmi2CausalityCalculatedParameter - return "calculatedParameter" - elseif c == fmi2CausalityInput - return "input" - elseif c == fmi2CausalityOutput - return "output" - elseif c == fmi2CausalityLocal - return "local" - elseif c == fmi2CausalityIndependent - return "independent" - else - @assert false "fmi2CausalityToString($(c)): Unknown causality." - end -end -export fmi2CausalityToString - -""" - - fmi2StringToCausality(s::AbstractString) - -Converts `s` ("parameter", "calculatedParameter", "input", "output", "local", "independent") to the corresponding [`fmi2Causality`](@ref). -""" -function fmi2StringToCausality(s::AbstractString) - if s == "parameter" - return fmi2CausalityParameter - elseif s == "calculatedParameter" - return fmi2CausalityCalculatedParameter - elseif s == "input" - return fmi2CausalityInput - elseif s == "output" - return fmi2CausalityOutput - elseif s == "local" - return fmi2CausalityLocal - elseif s == "independent" - return fmi2CausalityIndependent - else - @assert false "fmi2StringToCausality($(s)): Unknown causality." - end -end -export fmi2StringToCausality - -""" - - fmi2VariabilityToString(c::fmi2Variability) - -Converts [`fmi2Variability`](@ref) `c` to the corresponding String ("constant", "fixed", "tunable", "discrete", "continuous"). -""" -function fmi2VariabilityToString(c::fmi2Variability) - if c == fmi2VariabilityConstant - return "constant" - elseif c == fmi2VariabilityFixed - return "fixed" - elseif c == fmi2VariabilityTunable - return "tunable" - elseif c == fmi2VariabilityDiscrete - return "discrete" - elseif c == fmi2VariabilityContinuous - return "continuous" - else - @assert false "fmi2VariabilityToString($(c)): Unknown variability." - end -end -export fmi2VariabilityToString - -""" - - fmi2StringToVariability(s::AbstractString) - -Converts `s` ("constant", "fixed", "tunable", "discrete", "continuous") to the corresponding [`fmi2Variability`](@ref). -""" -function fmi2StringToVariability(s::AbstractString) - if s == "constant" - return fmi2VariabilityConstant - elseif s == "fixed" - return fmi2VariabilityFixed - elseif s == "tunable" - return fmi2VariabilityTunable - elseif s == "discrete" - return fmi2VariabilityDiscrete - elseif s == "continuous" - return fmi2VariabilityContinuous - else - @assert false "fmi2StringToVariability($(s)): Unknown variability." - end -end -export fmi2StringToVariability - -""" - - fmi2InitialToString(c::fmi2Initial) - -Converts [`fmi2Initial`](@ref) `c` to the corresponding String ("approx", "exact", "calculated"). -""" -function fmi2InitialToString(c::fmi2Initial) - if c == fmi2InitialApprox - return "approx" - elseif c == fmi2InitialExact - return "exact" - elseif c == fmi2InitialCalculated - return "calculated" - else - @assert false "fmi2InitialToString($(c)): Unknown initial." - end -end -export fmi2InitialToString - -""" - - fmi2StringToInitial(s::AbstractString) - -Converts `s` ("approx", "exact", "calculated") to the corresponding [`fmi2Initial`](@ref). -""" -function fmi2StringToInitial(s::AbstractString) - if s == "approx" - return fmi2InitialApprox - elseif s == "exact" - return fmi2InitialExact - elseif s == "calculated" - return fmi2InitialCalculated - else - @assert false "fmi2StringToInitial($(s)): Unknown initial." - end -end -export fmi2StringToInitial - -""" - - fmi2DependencyKindToString(c::fmi2DependencyKind) - -Converts [`fmi2DependencyKind`](@ref) `c` to the corresponding String ("dependent", "constant", "fixed", "tunable", "discrete") -""" -function fmi2DependencyKindToString(dk::fmi2DependencyKind) - if dk == fmi2DependencyKindDependent - return "dependent" - elseif dk == fmi2DependencyKindConstant - return "constant" - elseif dk == fmi2DependencyKindFixed - return "fixed" - elseif dk == fmi2DependencyKindTunable - return "tunable" - elseif dk == fmi2DependencyKindDiscrete - return "discrete" - else - @assert false "fmi2DependencyKindToString($(c)): Unknown dependency kind." - end -end -export fmi2DependencyKindToString - -""" - - fmi2StringToDependencyKind(s::AbstractString) - -Converts `s` ("dependent", "constant", "fixed", "tunable", "discrete") to the corresponding [`fmi2DependencyKind`](@ref) -""" -function fmi2StringToDependencyKind(s::AbstractString) - if s == "dependent" - return fmi2DependencyKindDependent - elseif s == "constant" - return fmi2DependencyKindConstant - elseif s == "fixed" - return fmi2DependencyKindFixed - elseif s == "tunable" - return fmi2DependencyKindTunable - elseif s == "discrete" - return fmi2DependencyKindDiscrete - else - @assert false "fmi2StringToDependencyKind($(s)): Unknown dependency kind." - end -end -export fmi2StringToDependencyKind \ No newline at end of file diff --git a/src/FMI2/ctype.jl b/src/FMI2/ctype.jl index bdf2867..bcde73d 100644 --- a/src/FMI2/ctype.jl +++ b/src/FMI2/ctype.jl @@ -87,6 +87,7 @@ export fmi2VariableDependency # Custom helper, not part of the FMI-Spec. fmi2Unknown = fmi2VariableDependency +export fmi2Unknown # custom abstract types, not part of the FMI-spec abstract type fmi2Attributes end # Attributes used in fmi2XXXAttributes @@ -729,12 +730,12 @@ end """ Source: FMISpec2.0.3[p.35]: 2.2.2 Definition of Units (UnitDefinitions) - BaseUnit( + fmi2BaseUnit( kg=0, m=0, s=0, A=0, K=0, mol=0, cd=0, rad=0, factor=1.0, offset=0.0) Type for the optional “BaseUnit” field of an `fmi2Unit`. """ -mutable struct BaseUnit +mutable struct fmi2BaseUnit # exponents of SI units kg::Union{Integer, Nothing} # kilogram m::Union{Integer, Nothing} # meter @@ -748,7 +749,7 @@ mutable struct BaseUnit factor::Union{Real, Nothing} offset::Union{Real, Nothing} - function BaseUnit(kg::Union{Integer, Nothing}=nothing, + function fmi2BaseUnit(kg::Union{Integer, Nothing}=nothing, m::Union{Integer, Nothing}=nothing, s::Union{Integer, Nothing}=nothing, A::Union{Integer, Nothing}=nothing, @@ -762,9 +763,9 @@ mutable struct BaseUnit return new(kg, m, s, A, K, mol, cd, rad, factor, offset) end end -const SI_UNITS = (:kg, :m, :s, :A, :K, :mol, :cd, :rad) +export fmi2BaseUnit -function Base.show(io::IO, unit::BaseUnit) +function Base.show(io::IO, unit::fmi2BaseUnit) if get(io, :compact, false) print(io, "BaseUnit") else @@ -784,21 +785,22 @@ end """ Source: FMISpec2.0.3[p.35]: 2.2.2 Definition of Units (UnitDefinitions) - DisplayUnit(name, factor=1.0, offset=0.0) + fmi2DisplayUnit(name, factor=1.0, offset=0.0) Type for the optional “DisplayUnit” field(s) of an `fmi2Unit`. """ -mutable struct DisplayUnit +mutable struct fmi2DisplayUnit # mandatory name::String # optional factor::Real offset::Real - function DisplayUnit(name::String, factor::Real=1.0, offset::Real=0.0) + function fmi2DisplayUnit(name::String, factor::Real=1.0, offset::Real=0.0) return new(name, factor, offset) end end +export fmi2DisplayUnit """ Source: FMISpec2.0.3[p.35]: 2.2.2 Definition of Units (UnitDefinitions) @@ -809,10 +811,10 @@ mutable struct fmi2Unit # mandatory name::String # optional - baseUnit::Union{BaseUnit,Nothing} - displayUnits::Union{Vector{DisplayUnit},Nothing} + baseUnit::Union{fmi2BaseUnit,Nothing} + displayUnits::Union{Vector{fmi2DisplayUnit},Nothing} - function fmi2Unit(name::String, baseUnit::Union{BaseUnit,Nothing}=nothing, displayUnits::Union{Vector{DisplayUnit},Nothing}=nothing) + function fmi2Unit(name::String, baseUnit::Union{fmi2BaseUnit,Nothing}=nothing, displayUnits::Union{Vector{fmi2DisplayUnit},Nothing}=nothing) return new(name, baseUnit, displayUnits) end end @@ -823,7 +825,7 @@ Source: FMISpec2.0.2[p.34]: 2.2.1 Definition of an FMU (fmiModelDescription) The “ModelVariables” element of fmiModelDescription is the central part of the model description. It provides the static information of all exposed variables. """ -mutable struct fmi2ModelDescription +mutable struct fmi2ModelDescription <: fmiModelDescription # attributes (mandatory) fmiVersion::String modelName::String diff --git a/src/FMI2/eval.jl b/src/FMI2/eval.jl deleted file mode 100644 index 7cdf3b3..0000000 --- a/src/FMI2/eval.jl +++ /dev/null @@ -1,295 +0,0 @@ -# -# Copyright (c) 2022 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in the file `eval.jl`? -# - calling function for FMU2 and FMU2Component - -import FMICore: fmi2ValueReference -import ChainRulesCore: ignore_derivatives - -""" - - (fmu::FMU2)(;dx::AbstractVector{<:Real}, - y::AbstractVector{<:Real}, - y_refs::AbstractVector{<:fmi2ValueReference}, - x::AbstractVector{<:Real}, - u::AbstractVector{<:Real}, - u_refs::AbstractVector{<:fmi2ValueReference}, - p::AbstractVector{<:Real}, - p_refs::AbstractVector{<:fmi2ValueReference}, - ec::AbstractVector{<:Real}, - t::Real) - -Evaluates a `FMU2` by setting the component state `x`, inputs `u` and/or time `t`. If no component is available, one is allocated. The result of the evaluation might be the system output `y` and/or state-derivative `dx`. -Not all options are available for any FMU type, e.g. setting state is not supported for CS-FMUs. Assertions will be generated for wrong use. - -# Keywords -- `dx`: An array to store the state-derivatives in. If not provided but necessary, a suitable array is allocated and returned. Not supported by CS-FMUs. -- `y`: An array to store the system outputs in. If not provided but requested, a suitable array is allocated and returned. -- `y_refs`: An array of value references to indicate which system outputs shall be returned. -- `x`: An array containing the states to be set. Not supported by CS-FMUs. -- `u`: An array containing the inputs to be set. -- `u_refs`: An array of value references to indicate which system inputs want to be set. -- `p`: An array of FMU parameters to be set. -- `p_refs`: An array of parameter references to indicate which system parameter sensitivities need to be determined. -- `ec`: An array of real valued implicit event conditions ("event indicators") -- `t`: A scalar value holding the system time to be set. - -# Returns (as Tuple) -- `y::Union{AbstractVector{<:Real}, Nothing}`: The system output `y` (if requested, otherwise `nothing`). -- `dx::Union{AbstractVector{<:Real}, Nothing}`: The system state-derivaitve (if ME-FMU, otherwise `nothing`). -- `ec::Union{AbstractVector{<:Real}, Nothing}`: The system event indicators (if ME-FMU, otherwise `nothing`). -""" -function (fmu::FMU2)(; dx_refs::Union{Symbol, AbstractVector{<:fmi2ValueReference}}=:none, - kwargs...) - - if dx_refs == :all - dx_refs = fmu.modelDescription.derivativeValueReferences - elseif dx_refs == :none - dx_refs = EMPTY_fmi2ValueReference - else - @assert !isa(dx_refs, Symbol) "Given `dx_refs` is unknown symbol `$(dx_refs)`, supported are `:all` or `:none`." - end - - @assert hasCurrentComponent(fmu) "Calling FMU, but no FMU2Component allocated." - c = getCurrentComponent(fmu) - - return (c)(; dx_refs=dx_refs, kwargs...) -end - -""" - - (c::FMU2Component)(;dx::AbstractVector{<:Real}, - y::AbstractVector{<:Real}, - y_refs::AbstractVector{<:fmi2ValueReference}, - x::AbstractVector{<:Real}, - u::AbstractVector{<:Real}, - u_refs::AbstractVector{<:fmi2ValueReference}, - p::AbstractVector{<:Real}, - p_refs::AbstractVector{<:fmi2ValueReference}, - ec::AbstractVector{<:Real}, - t::Real) - -Evaluates a `FMU2Component` by setting the component state `x`, inputs `u` and/or time `t`. The result of the evaluation might be the system output `y` and/or state-derivative `dx`. -Not all options are available for any FMU type, e.g. setting state is not supported for CS-FMUs. Assertions will be generated for wrong use. - -# Keywords -- `dx`: An array to store the state-derivatives in. If not provided but necessary, a suitable array is allocated and returned. Not supported by CS-FMUs. -- `y`: An array to store the system outputs in. If not provided but requested, a suitable array is allocated and returned. -- `y_refs`: An array of value references to indicate which system outputs shall be returned. -- `x`: An array containing the states to be set. Not supported by CS-FMUs. -- `u`: An array containing the inputs to be set. -- `u_refs`: An array of value references to indicate which system inputs want to be set. -- `p`: An array of FMU parameters to be set. -- `p_refs`: An array of parameter references to indicate which system parameter sensitivities need to be determined. -- `ec`: An array of real valued implicit event conditions ("event indicators") -- `t`: A scalar value holding the system time to be set. - -# Returns (as Tuple) -- `y::Union{AbstractVector{<:Real}, Nothing}`: The system output `y` (if requested, otherwise `nothing`). -- `dx::Union{AbstractVector{<:Real}, Nothing}`: The system state-derivaitve (if ME-FMU, otherwise `nothing`). -- `ec::Union{AbstractVector{<:Real}, Nothing}`: The system event indicators (if ME-FMU, otherwise `nothing`). -""" -function (c::FMU2Component)(dx::AbstractVector{<:Real}, - dx_refs::AbstractVector{<:fmi2ValueReference}, - y::AbstractVector{<:Real}, - y_refs::AbstractVector{<:fmi2ValueReference}, - x::AbstractVector{<:Real}, - u::AbstractVector{<:Real}, - u_refs::AbstractVector{<:fmi2ValueReference}, - p::AbstractVector{<:Real}, - p_refs::AbstractVector{<:fmi2ValueReference}, - ec::AbstractVector{<:Real}, - ec_idcs::AbstractVector{<:fmi2ValueReference}, - t::Real) - - len_x = length(x) - len_y = length(y) - len_ec = length(ec) - len_dx = length(dx) - len_u = length(u) - len_p = length(p) - - len_y_refs = length(y_refs) - len_ec_idcs = length(ec_idcs) - len_dx_refs = length(dx_refs) - len_u_refs = length(u_refs) - len_p_refs = length(p_refs) - - # CS and ME - if len_y != len_y_refs - if y === c.default_y - c.default_y = zeros(fmi2Real, len_y_refs) - logInfo(c.fmu, "Automatically allocated `y` for given `y_refs` [$(len_y_refs)].") - y = c.default_y - len_y = length(y) - end - end - - if len_ec != len_ec_idcs - if ec === c.default_ec - c.default_ec = zeros(fmi2Real, len_ec_idcs) - logInfo(c.fmu, "Automatically allocated `ec` for given `ec_idcs` [$(len_ec_idcs)].") - ec = c.default_ec - len_ec = length(ec) - end - end - - if len_dx != len_dx_refs - if dx === c.default_dx - c.default_dx = zeros(fmi2Real, len_dx_refs) - logInfo(c.fmu, "Automatically allocated `dx` for given `dx_refs` [$(len_dx_refs)].") - dx = c.default_dx - len_dx = length(dx) - end - end - - @assert (len_dx == len_dx_refs) || (len_dx == length(c.fmu.modelDescription.derivativeValueReferences)) "Length of `dx` [$(len_dx)] must match:\n- number of given derivative references `dx_refs` [$(len_dx_refs)] or\n- absolute number of derivatives [$(length(c.fmu.modelDescription.derivativeValueReferences))]." - @assert (len_y == len_y_refs) "Length of `y` [$(len_y)] must match length of `y_refs` [$(len_y_refs)]." - @assert (len_u == len_u_refs) "Length of `u` [$(len_u)] must match length of `u_refs` [$(len_u_refs)]." - @assert (len_p == len_p_refs) "Length of `p` [$(len_p)] must match length of `p_refs` [$(len_p_refs)]." - @assert (len_ec == len_ec_idcs) || (length(ec) == c.fmu.modelDescription.numberOfEventIndicators) "Length of `ec` [$(len_ec)] must match:\n- number of given event indicators `ec_idcs` [$(len_ec_idcs)] or\n- absolute number of event indicators [$(c.fmu.modelDescription.numberOfEventIndicators)]." - - # Model-Exchange only - # if !isnothing(c.fmu.modelDescription.modelExchange) - # if c.type == fmi2TypeModelExchange::fmi2Type - # end - # end - - # Co-Simulation only - if !isnothing(c.fmu.modelDescription.coSimulation) - if c.type == fmi2TypeCoSimulation::fmi2Type - @assert len_ec <= 0 "Keyword `ec != []` is invalid for CS-FMUs. Setting a buffer for event indicators is not possible in CS." - @assert len_dx <= 0 "Keyword `dx != []` is invalid for CS-FMUs. Setting a state-derivative is not possible in CS." - @assert len_x <= 0 "Keyword `x != []` is invalid for CS-FMUs. Setting a state is not possible in CS." - @assert t < 0.0 "Keyword `t != []` is invalid for CS-FMUs. Setting explicit time is not possible in CS." - end - end - - @debug "dispatching on eval! $((c.cRef, dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t))" - - # [Note] not necessary: - #c.output = FMU2ADOutput{Real}(; initType=Real) - - c.output.buffer = eval!(c.cRef, dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t) - c.output.len_dx = len_dx_refs - c.output.len_y = len_y_refs - c.output.len_ec = len_ec_idcs - - @assert !any(collect(isa(c.output.buffer[i], Int64) for i in 1:length(c.output.buffer))) "Fuuuuu $(c.output.buffer)" - - return c.output -end - -function (c::FMU2Component)(;dx::AbstractVector{<:Real}=c.default_dx, - dx_refs::AbstractVector{<:fmi2ValueReference}=c.default_dx_refs, - y::AbstractVector{<:Real}=c.default_y, - y_refs::AbstractVector{<:fmi2ValueReference}=c.default_y_refs, - x::AbstractVector{<:Real}=EMPTY_fmi2Real, - u::AbstractVector{<:Real}=EMPTY_fmi2Real, - u_refs::AbstractVector{<:fmi2ValueReference}=EMPTY_fmi2ValueReference, - p::AbstractVector{<:Real}=c.default_p, - p_refs::AbstractVector{<:fmi2ValueReference}=c.default_p_refs, - ec::AbstractVector{<:Real}=c.default_ec, - ec_idcs::AbstractVector{<:fmi2ValueReference}=c.default_ec_idcs, - t::Real=c.default_t) - (c)(dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t) -end - -function eval!(cRef, dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t) - @assert isa(x, AbstractArray{fmi2Real}) "eval!(...): Wrong dispatched: `x` is `$(typeof(x))`.\nThis is most likely because you tried differentiating (AD) over a FMU.\nIf so, you need to `import FMISensitivity` first." - @assert isa(u, AbstractArray{fmi2Real}) "eval!(...): Wrong dispatched: `u` is `$(typeof(u))`.\nThis is most likely because you tried differentiating (AD) over a FMU.\nIf so, you need to `import FMISensitivity` first." - @assert isa(t, fmi2Real) "eval!(...): Wrong dispatched: `t` is `$(typeof(t))`.\nThis is most likely because you tried differentiating (AD) over a FMU.\nIf so, you need to `import FMISensitivity` first." - @assert isa(p, AbstractArray{fmi2Real}) "eval!(...): Wrong dispatched: `p` is `$(typeof(p))`.\nThis is most likely because you tried differentiating (AD) over a FMU.\nIf so, you need to `import FMISensitivity` first." - @assert false "Fatal error, no dispatch implemented!\nPlease open an issue with MWE and attach error message:\neval!($(typeof(cRef)), $(typeof(dx)), $(typeof(y)), $(typeof(y_refs)), $(typeof(x)), $(typeof(u)), $(typeof(u_refs)), $(typeof(p)), $(typeof(p_refs)), $(typeof(t)))" -end - -function eval!(cRef::UInt64, - dx::AbstractVector{<:fmi2Real}, - dx_refs::AbstractVector{<:fmi2ValueReference}, - y::AbstractVector{<:fmi2Real}, - y_refs::AbstractVector{<:fmi2ValueReference}, - x::AbstractVector{<:fmi2Real}, - u::AbstractVector{<:fmi2Real}, - u_refs::AbstractVector{<:fmi2ValueReference}, - p::AbstractVector{<:fmi2Real}, - p_refs::AbstractVector{<:fmi2ValueReference}, - ec::AbstractVector{<:fmi2Real}, - ec_idcs::AbstractVector{<:fmi2ValueReference}, - t::fmi2Real) - - @debug "eval! $((cRef, dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t))" - - c = unsafe_pointer_to_objref(Ptr{Nothing}(cRef)) - - # set state - if length(x) > 0 && !c.fmu.isZeroState - fmi2SetContinuousStates(c, x) - end - - # set time - if t >= 0.0 - fmi2SetTime(c, t) - end - - # set input - if length(u) > 0 - fmi2SetReal(c, u_refs, u) - end - - # set parameters DURING simulation, this is very uncommon, but can be necessary if "tunable" parameters are optimized during simulation - if length(p) > 0 && c.fmu.executionConfig.set_p_every_step - fmi2SetReal(c, p_refs, p) - end - - # get derivative - if length(dx) > 0 - getDerivatives!(c, dx, dx_refs) - end - - # get output - if length(y) > 0 - getOutputs!(c, y, y_refs) - end - - # get event indicators - if length(ec) > 0 - getEventIndicators!(c, ec, ec_idcs) - end - - # [Note] not necessary - # c.eval_output = FMU2EvaluationOutput{Float64}() - - c.eval_output.y = y - c.eval_output.dx = dx - c.eval_output.ec = ec - - return c.eval_output -end - -# [ToDo] Implement dx_refs to grab only specific derivatives -function getDerivatives!(c::FMU2Component, dx::AbstractArray{<:fmi2Real}, dx_refs::AbstractArray{<:fmi2ValueReference}) - if c.fmu.isZeroState - dx[:] = [1.0] - else - fmi2GetDerivatives!(c, dx) - end - return nothing -end - -function getOutputs!(c::FMU2Component, y::AbstractArray{<:fmi2Real}, y_refs::AbstractArray{<:fmi2ValueReference}) - fmi2GetReal!(c, y_refs, y) - return nothing -end - -function getEventIndicators!(c::FMU2Component, ec::AbstractArray{<:fmi2Real}, ec_idcs::AbstractArray{<:fmi2ValueReference}) - if length(ec_idcs) == c.fmu.modelDescription.numberOfEventIndicators || length(ec_idcs) == 0 # pick ALL event indicators - fmi2GetEventIndicators!(c, ec) - else # pick only some specific ones - fmi2GetEventIndicators!(c, c.eventIndicatorBuffer) - ec[:] = c.eventIndicatorBuffer[ec_idcs] - end - return nothing -end diff --git a/src/FMI2/io.jl b/src/FMI2/io.jl deleted file mode 100644 index c8cb8f7..0000000 --- a/src/FMI2/io.jl +++ /dev/null @@ -1,207 +0,0 @@ -# -# Copyright (c) 2022 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. - -mutable struct FMU2EvaluationOutput{T} <: AbstractArray{Float64, 1} - dx::AbstractArray{T,1} - y::AbstractArray{T,1} - ec::AbstractArray{T,1} - - function FMU2EvaluationOutput{T}(dx::AbstractArray, y::AbstractArray, ec::AbstractArray) where {T} - return new{T}(dx, y, ec) - end - - function FMU2EvaluationOutput(dx::AbstractArray{T}, y::AbstractArray{T}, ec::AbstractArray{T}) where {T} - return FMU2EvaluationOutput{T}(dx, y, ec) - end - - function FMU2EvaluationOutput{T}(; initType::DataType=T) where {T} - return FMU2EvaluationOutput{T}(Array{initType,1}(), Array{initType,1}(), Array{initType,1}()) - end - - function FMU2EvaluationOutput() - return FMU2EvaluationOutput{fmi2Real}(EMPTY_fmi2Real, EMPTY_fmi2Real, EMPTY_fmi2Real) - end -end - -import ChainRulesCore: ZeroTangent, NoTangent - -function Base.setproperty!(out::FMU2EvaluationOutput, var::Symbol, value::ZeroTangent) - return Base.setproperty!(out, var, EMPTY_fmi2Real) -end - -function Base.setproperty!(out::FMU2EvaluationOutput, var::Symbol, value::NoTangent) - return Base.setproperty!(out, var, EMPTY_fmi2Real) -end - -function Base.length(out::FMU2EvaluationOutput) - len_dx = length(out.dx) - len_y = length(out.y) - len_ec = length(out.ec) - return len_dx+len_y+len_ec -end - -function Base.getindex(out::FMU2EvaluationOutput, ind::Int) - @assert ind >= 1 "`getindex` for index $(ind) <= 0 not supported." - - len_dx = length(out.dx) - if ind <= len_dx - return out.dx[ind] - end - ind -= len_dx - - len_y = length(out.y) - if ind <= len_y - return out.y[ind] - end - ind -= len_y - - len_ec = length(out.ec) - if ind <= len_ec - return out.ec[ind] - end - ind -= len_ec - - @assert false "`getindex` for index $(ind+len_y+len_dx+len_ec) out of bounds [$(length(out))]." -end - -function Base.getindex(out::FMU2EvaluationOutput, ind::UnitRange) - # [ToDo] Could be improved. - return collect(Base.getindex(out, i) for i in ind) -end - -function Base.setindex!(out::FMU2EvaluationOutput, v, index::Int) - - @assert !isa(v, Int64) "setindex! on Int64 not allowed!" - - len_dx = length(out.dx) - if index <= len_dx - return setindex!(out.dx, v, index) - end - index -= len_dx - - len_y = length(out.y) - if index <= len_y - return setindex!(out.y, v, index) - end - index -= len_y - - len_ec = length(out.ec) - if index <= len_ec - return setindex!(out.ec, v, index) - end - index -= len_ec - - @assert false "`setindex!` for index $(ind+len_y+len_dx+len_ec) out of bounds [$(length(out))]." -end - -function Base.size(out::FMU2EvaluationOutput) - return (length(out),) -end - -function Base.IndexStyle(::FMU2EvaluationOutput) - return IndexLinear() -end - -function Base.unaliascopy(out::FMU2EvaluationOutput) - return FMU2EvaluationOutput(copy(out.dx), copy(out.y), copy(out.ec)) -end - -##### - -mutable struct FMU2ADOutput{T} <: AbstractArray{Real,1} - buffer::AbstractArray{<:T,1} - - len_dx::Int - len_y::Int - len_ec::Int - - show_dx::Bool - show_y::Bool - show_ec::Bool - - function FMU2ADOutput{T}(; initType::DataType=T) where {T} - return new{T}(Array{initType,1}(), 0, 0, 0, true, true, false) - end - - function FMU2ADOutput() - return FMU2ADOutput{fmi2Real}() - end -end - -import ChainRulesCore: ZeroTangent, NoTangent - -function Base.setproperty!(out::FMU2ADOutput, var::Symbol, value::ZeroTangent) - return Base.setproperty!(out, var, EMPTY_fmi2Real) -end - -function Base.setproperty!(out::FMU2ADOutput, var::Symbol, value::NoTangent) - return Base.setproperty!(out, var, EMPTY_fmi2Real) -end - -function Base.hasproperty(::FMU2ADOutput, var::Symbol) - return var ∈ (:dx, :y, :ec, :buffer, :len_dx, :len_y, :len_ex, :ec_visible) -end - -function Base.getproperty(out::FMU2ADOutput, var::Symbol) - - if var == :dx - return @view(out.buffer[1:out.len_dx]) - elseif var == :y - return @view(out.buffer[out.len_dx+1:out.len_dx+out.len_y]) - elseif var == :ec - return @view(out.buffer[out.len_dx+out.len_y+1:end]) - else - return Base.getfield(out, var) - end -end - -function Base.length(out::FMU2ADOutput) - len_dx = out.show_dx ? out.len_dx : 0 - len_y = out.show_y ? out.len_y : 0 - len_ec = out.show_ec ? out.len_ec : 0 - return len_dx+len_y+len_ec -end - -function Base.getindex(out::FMU2ADOutput, ind::Int) - return getindex(out.buffer, ind) -end - -function Base.getindex(out::FMU2ADOutput, ind::UnitRange) - # [ToDo] Could be improved. - return collect(Base.getindex(out, i) for i in ind) -end - -function Base.setindex!(out::FMU2ADOutput, v, index::Int) - return setindex!(out.buffer, v, index) -end - -function Base.size(out::FMU2ADOutput) - return (length(out),) -end - -function Base.IndexStyle(::FMU2ADOutput) - return IndexLinear() -end - -function Base.unaliascopy(out::FMU2ADOutput) - return FMU2ADOutput(copy(out.buffer), out.len_dx, out.len_y, out.len_ec, out.show_dx, out.show_y, out.show_ec) -end - -##### - -mutable struct FMU2EvaluationInput <: AbstractVector{Real} - - x::AbstractArray{<:Real} - u::AbstractVector{<:Real} - p::AbstractVector{<:Real} - t::Real - - function FMU2EvaluationInput(x::AbstractArray{<:Real}, u::AbstractArray{<:Real}, p::AbstractArray{<:Real}, t::Real) - return new(x, u, p, t) - end - - function FMU2EvaluationInput() - return FMU2EvaluationInput(EMPTY_fmi2Real, EMPTY_fmi2Real, EMPTY_fmi2Real, 0.0) - end -end \ No newline at end of file diff --git a/src/FMI2/struct.jl b/src/FMI2/struct.jl deleted file mode 100644 index a05e821..0000000 --- a/src/FMI2/struct.jl +++ /dev/null @@ -1,802 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in this file: -# - the `fmi2ComponentState`--enum which mirrors the internal FMU state (state-machine, not the system state) -# - the `FMU2ComponentEnvironment`- and `FMU2Component`-struct -# - the `FMU2`-struct -# - string/enum-converters for FMI-attribute-structs (e.g. `fmi2StatusToString`, ...) - -# default values for function calls -const EMPTY_fmi2Real = zeros(fmi2Real, 0) -const EMPTY_fmi2ValueReference = zeros(fmi2ValueReference, 0) - -""" -Container for event related information. -""" -struct FMU2Event <: FMUEvent - t::Creal # event time point - indicator::UInt # index of event indicator ("0" for time events) - - x_left::Union{Array{Creal, 1}, Nothing} # state before the event - x_right::Union{Array{Creal, 1}, Nothing} # state after the event (if discontinuous) - - indicatorValue::Union{Creal, Nothing} # value of the event indicator that triggered the event (should be really close to zero) - - function FMU2Event(t::Creal, - indicator::UInt = 0, - x_left::Union{Array{Creal, 1}, Nothing} = nothing, - x_right::Union{Array{Creal, 1}, Nothing} = nothing, - indicatorValue::Union{Creal, Nothing} = nothing) - inst = new(t, indicator, x_left, x_right, indicatorValue) - return inst - end -end -export FMU2Event - -""" -Overload the Base.show() function for custom printing of the FMU2. -""" -function Base.show(io::IO, e::FMU2Event) - timeEvent = (e.indicator == 0) - stateChange = (e.x_left != e.x_right) - if timeEvent - print(io, "Time-Event @ $(e.t)s (state-change: $(stateChange))") - else - print(io, "State-Event #$(e.indicator) @ $(e.t)s (state-change: $(stateChange))") - end -end - -""" -The mutable struct representing a specific Solution of a FMI2 FMU. -""" -mutable struct FMU2Solution{C} <: FMUSolution where {C} - component::C # FMU2Component - snapshots::Vector{FMUSnapshot} - success::Bool - - states # ToDo: ODESolution - - values # ToDo: DataType - valueReferences::Union{Array, Nothing} # ToDo: Array{fmi2ValueReference} - - # record events - events::Array{FMU2Event, 1} - - # record event indicators - recordEventIndicators::Union{Array{Int, 1}, Nothing} - eventIndicators # ToDo: DataType - - # record eigenvalues - eigenvalues # ToDo: DataType - - evals_∂ẋ_∂x::Integer - evals_∂y_∂x::Integer - evals_∂e_∂x::Integer - evals_∂ẋ_∂u::Integer - evals_∂y_∂u::Integer - evals_∂e_∂u::Integer - evals_∂ẋ_∂t::Integer - evals_∂y_∂t::Integer - evals_∂e_∂t::Integer - evals_∂ẋ_∂p::Integer - evals_∂y_∂p::Integer - evals_∂e_∂p::Integer - evals_∂xr_∂xl::Integer - - evals_fx_inplace::Integer - evals_fx_outofplace::Integer - evals_condition::Integer - evals_affect::Integer - evals_stepcompleted::Integer - evals_timechoice::Integer - evals_savevalues::Integer - evals_saveeventindicators::Integer - evals_saveeigenvalues::Integer - - function FMU2Solution{C}() where {C} - inst = new{C}() - - inst.snapshots = [] - inst.success = false - inst.states = nothing - inst.values = nothing - inst.valueReferences = nothing - - inst.events = [] - - inst.recordEventIndicators = nothing - inst.eigenvalues = nothing - - inst.evals_∂ẋ_∂x = 0 - inst.evals_∂y_∂x = 0 - inst.evals_∂e_∂x = 0 - inst.evals_∂ẋ_∂u = 0 - inst.evals_∂y_∂u = 0 - inst.evals_∂e_∂u = 0 - inst.evals_∂ẋ_∂t = 0 - inst.evals_∂y_∂t = 0 - inst.evals_∂e_∂t = 0 - inst.evals_∂ẋ_∂p = 0 - inst.evals_∂y_∂p = 0 - inst.evals_∂e_∂p = 0 - inst.evals_∂xr_∂xl = 0 - - inst.evals_fx_inplace = 0 - inst.evals_fx_outofplace = 0 - inst.evals_condition = 0 - inst.evals_affect = 0 - inst.evals_stepcompleted = 0 - inst.evals_timechoice = 0 - inst.evals_savevalues = 0 - inst.evals_saveeventindicators = 0 - inst.evals_saveeigenvalues = 0 - - return inst - end - - function FMU2Solution(component::C) where {C} - inst = FMU2Solution{C}() - inst.component = component - - return inst - end -end -export FMU2Solution - -""" -Overload the Base.show() function for custom printing of the FMU2. -""" -function Base.show(io::IO, sol::FMU2Solution) - print(io, "Model name:\n\t$(sol.component.fmu.modelDescription.modelName)\nSuccess:\n\t$(sol.success)\n") - - print(io, "f(x)-Evaluations:\n") - print(io, "\tIn-place: $(sol.evals_fx_inplace)\n") - print(io, "\tOut-of-place: $(sol.evals_fx_outofplace)\n") - print(io, "Jacobian-Evaluations:\n") - print(io, "\t∂ẋ_∂p: $(sol.evals_∂ẋ_∂p)\n") - print(io, "\t∂ẋ_∂x: $(sol.evals_∂ẋ_∂x)\n") - print(io, "\t∂ẋ_∂u: $(sol.evals_∂ẋ_∂u)\n") - print(io, "\t∂y_∂p: $(sol.evals_∂y_∂p)\n") - print(io, "\t∂y_∂x: $(sol.evals_∂y_∂x)\n") - print(io, "\t∂y_∂u: $(sol.evals_∂y_∂u)\n") - print(io, "\t∂e_∂p: $(sol.evals_∂e_∂p)\n") - print(io, "\t∂e_∂x: $(sol.evals_∂e_∂x)\n") - print(io, "\t∂e_∂u: $(sol.evals_∂e_∂u)\n") - print(io, "\t∂xr_∂xl: $(sol.evals_∂xr_∂xl)\n") - print(io, "Gradient-Evaluations:\n") - print(io, "\t∂ẋ_∂t: $(sol.evals_∂ẋ_∂t)\n") - print(io, "\t∂y_∂t: $(sol.evals_∂y_∂t)\n") - print(io, "\t∂e_∂t: $(sol.evals_∂e_∂t)\n") - print(io, "Callback-Evaluations:\n") - print(io, "\tCondition (event-indicators): $(sol.evals_condition)\n") - print(io, "\tTime-Choice (event-instances): $(sol.evals_timechoice)\n") - print(io, "\tAffect (event-handling): $(sol.evals_affect)\n") - print(io, "\tSave values: $(sol.evals_savevalues)\n") - print(io, "\tSteps completed: $(sol.evals_stepcompleted)\n") - - if !isnothing(sol.states) - print(io, "States [$(length(sol.states))]:\n") - if length(sol.states.u) > 10 - for i in 1:9 - print(io, "\t$(sol.states.t[i])\t$(sol.states.u[i])\n") - end - print(io, "\t...\n\t$(sol.states.t[end])\t$(sol.states.u[end])\n") - else - for i in 1:length(sol.states) - print(io, "\t$(sol.states.t[i])\t$(sol.states.u[i])\n") - end - end - end - - if !isnothing(sol.values) - print(io, "Values [$(length(sol.values.saveval))]:\n") - if length(sol.values.saveval) > 10 - for i in 1:9 - print(io, "\t$(sol.values.t[i])\t$(sol.values.saveval[i])\n") - end - print(io, "\t...\n\t$(sol.values.t[end])\t$(sol.values.saveval[end])\n") - else - for i in 1:length(sol.values.saveval) - print(io, "\t$(sol.values.t[i])\t$(sol.values.saveval[i])\n") - end - end - end - - if !isnothing(sol.events) - print(io, "Events [$(length(sol.events))]:\n") - if length(sol.events) > 10 - for i in 1:9 - print(io, "\t$(sol.events[i])\n") - end - print(io, "\t...\n\t$(sol.events[end])\n") - else - for i in 1:length(sol.events) - print(io, "\t$(sol.events[i])\n") - end - end - end - -end - -""" -Source: FMISpec 2.0.3 [p.16f] - -This is a pointer to a data structure in the simulation environment that calls the FMU. Using this -pointer, data from the modelDescription.xml file [(for example, mapping of valueReferences to -variable names)] can be transferred between the simulation environment and the logger function -(see [FMISpec 2.0.3] section 2.1.5). -""" -mutable struct FMU2ComponentEnvironment - logStatusOK::Bool - logStatusWarning::Bool - logStatusDiscard::Bool - logStatusError::Bool - logStatusFatal::Bool - logStatusPending::Bool - - function FMU2ComponentEnvironment() - inst = new() - inst.logStatusOK = true - inst.logStatusWarning = true - inst.logStatusDiscard = true - inst.logStatusError = true - inst.logStatusFatal = true - inst.logStatusPending = true - return inst - end -end -export FMU2ComponentEnvironment - -""" -The mutable struct represents an allocated instance of an FMU in the FMI 2.0.2 Standard. -""" -mutable struct FMU2Component{F} <: FMUInstance - compAddr::fmi2Component - cRef::UInt64 - fmu::F - state::fmi2ComponentState - componentEnvironment::FMU2ComponentEnvironment - problem # ToDo: ODEProblem, but this is not a dependency of FMICore.jl nor FMIImport.jl ... - type::Union{fmi2Type, Nothing} - solution::FMU2Solution - force::Bool - threadid::Integer - - loggingOn::fmi2Boolean - visible::fmi2Boolean - callbackFunctions::fmi2CallbackFunctions - instanceName::String - continuousStatesChanged::fmi2Boolean - eventInfo::Union{fmi2EventInfo, Nothing} - - t::fmi2Real # the system time - t_offset::fmi2Real # time offset between simulation environment and FMU - x::Union{Array{fmi2Real, 1}, Nothing} # the system states (or sometimes u) - x_d::Union{Array{Union{fmi2Real, fmi2Integer, fmi2Boolean}, 1}, Nothing} # the system discrete states - ẋ::Union{Array{fmi2Real, 1}, Nothing} # the system state derivative (or sometimes u̇) - ẍ::Union{Array{fmi2Real, 1}, Nothing} # the system state second derivative - #u::Union{Array{fmi2Real, 1}, Nothing} # the system inputs - #y::Union{Array{fmi2Real, 1}, Nothing} # the system outputs - #p::Union{Array{fmi2Real, 1}, Nothing} # the system parameters - z::Union{Array{fmi2Real, 1}, Nothing} # the system event indicators - z_prev::Union{Array{fmi2Real, 1}, Nothing} # the last system event indicators - - values::Dict{fmi2ValueReference, Union{fmi2Real, fmi2Integer, fmi2Boolean}} - - x_vrs::Array{fmi2ValueReference, 1} # the system state value references - ẋ_vrs::Array{fmi2ValueReference, 1} # the system state derivative value references - u_vrs::Array{fmi2ValueReference, 1} # the system input value references - y_vrs::Array{fmi2ValueReference, 1} # the system output value references - p_vrs::Array{fmi2ValueReference, 1} # the system parameter value references - - # sensitivities - ∂ẋ_∂x #::Union{J, Nothing} - ∂ẋ_∂u #::Union{J, Nothing} - ∂ẋ_∂p #::Union{J, Nothing} - ∂ẋ_∂t #::Union{G, Nothing} - - ∂y_∂x #::Union{J, Nothing} - ∂y_∂u #::Union{J, Nothing} - ∂y_∂p #::Union{J, Nothing} - ∂y_∂t #::Union{G, Nothing} - - ∂e_∂x #::Union{J, Nothing} - ∂e_∂u #::Union{J, Nothing} - ∂e_∂p #::Union{J, Nothing} - ∂e_∂t #::Union{G, Nothing} - - ∂xr_∂xl #::Union{J, Nothing} - - # performance (pointers to prevent repeating allocations) - _enterEventMode::Array{fmi2Boolean, 1} - _ptr_enterEventMode::Ptr{fmi2Boolean} - _terminateSimulation::Array{fmi2Boolean, 1} - _ptr_terminateSimulation::Ptr{fmi2Boolean} - - # misc - skipNextDoStep::Bool # allows skipping the next `fmi2DoStep` like it is not called - progressMeter # progress plot - output::FMU2ADOutput - rrule_input::FMU2EvaluationInput # input buffer (for rrules) - eval_output::FMU2EvaluationOutput # output buffer with multiple arrays that behaves like a single array (to allow for single value return functions, necessary for propper AD) - frule_output::FMU2EvaluationOutput - - eventIndicatorBuffer::AbstractArray{<:fmi2Real} - - # parameters that need sensitivities and/or are catched by optimizers (like in FMIFlux.jl) - default_t::Real - default_p_refs::AbstractVector{<:fmi2ValueReference} - default_p::AbstractVector{<:Real} - default_ec_idcs::AbstractVector{<:fmi2ValueReference} - default_dx_refs::AbstractVector{<:fmi2ValueReference} - default_u::AbstractVector{<:Real} - default_y_refs::AbstractVector{<:fmi2ValueReference} - - # deprecated - default_y::AbstractVector{<:Real} - default_ec::AbstractVector{<:Real} - default_dx::AbstractVector{<:Real} - - # a container for all created snapshots, so that we can properly release them at unload - snapshots::Vector{FMUSnapshot} - - # constructor - function FMU2Component{F}() where {F} - inst = new{F}() - inst.cRef = UInt64(pointer_from_objref(inst)) - inst.state = fmi2ComponentStateInstantiated - inst.t = -Inf - inst.t_offset = 0.0 - inst.eventInfo = fmi2EventInfo() - inst.problem = nothing - inst.type = nothing - inst.threadid = Threads.threadid() - - inst.output = FMU2ADOutput{Real}(; initType=Float64) - inst.eval_output = FMU2EvaluationOutput{Float64}() - inst.rrule_input = FMU2EvaluationInput() - inst.frule_output = FMU2EvaluationOutput{Float64}() - - inst.loggingOn = fmi2False - inst.visible = fmi2False - inst.instanceName = "" - inst.continuousStatesChanged = fmi2False - - inst.x = nothing - inst.x_d = nothing - inst.ẋ = nothing - inst.ẍ = nothing - inst.z = nothing - inst.z_prev = nothing - - inst.values = Dict{fmi2ValueReference, Union{fmi2Real, fmi2Integer, fmi2Boolean}}() - inst.x_vrs = Array{fmi2ValueReference, 1}() - inst.ẋ_vrs = Array{fmi2ValueReference, 1}() - inst.u_vrs = Array{fmi2ValueReference, 1}() - inst.y_vrs = Array{fmi2ValueReference, 1}() - inst.p_vrs = Array{fmi2ValueReference, 1}() - - inst.∂ẋ_∂x = nothing - inst.∂ẋ_∂u = nothing - inst.∂ẋ_∂p = nothing - inst.∂ẋ_∂t = nothing - - inst.∂y_∂x = nothing - inst.∂y_∂u = nothing - inst.∂y_∂p = nothing - inst.∂y_∂t = nothing - - inst.∂e_∂x = nothing - inst.∂e_∂u = nothing - inst.∂e_∂p = nothing - inst.∂e_∂t = nothing - - inst.∂xr_∂xl = nothing - - # initialize further variables - inst.skipNextDoStep = false - inst.progressMeter = nothing - - # performance (pointers to prevent repeating allocations) - inst._enterEventMode = zeros(fmi2Boolean, 1) - inst._terminateSimulation = zeros(fmi2Boolean, 1) - inst._ptr_enterEventMode = pointer(inst._enterEventMode) - inst._ptr_terminateSimulation = pointer(inst._terminateSimulation) - - inst.default_t = -1.0 - inst.default_p_refs = EMPTY_fmi2ValueReference - inst.default_p = EMPTY_fmi2Real - inst.default_ec_idcs = EMPTY_fmi2ValueReference - inst.default_u = EMPTY_fmi2Real - inst.default_y_refs = EMPTY_fmi2ValueReference - inst.default_dx_refs = EMPTY_fmi2ValueReference - - inst.snapshots = [] - - # deprecated - inst.default_ec = EMPTY_fmi2Real - inst.default_y = EMPTY_fmi2Real - inst.default_dx = EMPTY_fmi2Real - - return inst - end - - function FMU2Component(fmu::F) where {F} - inst = FMU2Component{F}() - inst.fmu = fmu - inst.eventIndicatorBuffer = zeros(fmi2Real, fmu.modelDescription.numberOfEventIndicators) - - inst.default_t = inst.fmu.default_t - inst.default_p_refs = inst.fmu.default_p_refs === EMPTY_fmi2ValueReference ? inst.fmu.default_p_refs : copy(inst.fmu.default_p_refs) - inst.default_p = inst.fmu.default_p === EMPTY_fmi2Real ? inst.fmu.default_p : copy(inst.fmu.default_p) - inst.default_ec = inst.fmu.default_ec === EMPTY_fmi2Real ? inst.fmu.default_ec : copy(inst.fmu.default_ec) - inst.default_ec_idcs = inst.fmu.default_ec_idcs === EMPTY_fmi2ValueReference ? inst.fmu.default_ec_idcs : copy(inst.fmu.default_ec_idcs) - inst.default_u = inst.fmu.default_u === EMPTY_fmi2Real ? inst.fmu.default_u : copy(inst.fmu.default_u) - inst.default_y = inst.fmu.default_y === EMPTY_fmi2Real ? inst.fmu.default_y : copy(inst.fmu.default_y) - inst.default_y_refs = inst.fmu.default_y_refs === EMPTY_fmi2ValueReference ? inst.fmu.default_y_refs : copy(inst.fmu.default_y_refs) - inst.default_dx = inst.fmu.default_dx === EMPTY_fmi2Real ? inst.fmu.default_dx : copy(inst.fmu.default_dx) - inst.default_dx_refs = inst.fmu.default_dx_refs === EMPTY_fmi2ValueReference ? inst.fmu.default_dx_refs : copy(inst.fmu.default_dx_refs) - - return inst - end - - function FMU2Component(compAddr::fmi2Component, fmu::F) where {F} - inst = FMU2Component(fmu) - inst.compAddr = compAddr - - return inst - end -end -export FMU2Component - -""" -Overload the Base.show() function for custom printing of the FMU2Component. -""" -Base.show(io::IO, c::FMU2Component) = print(io, -"FMU: $(c.fmu.modelDescription.modelName) -InstanceName: $(isdefined(c, :instanceName) ? c.instanceName : "[not defined]") -Address: $(c.compAddr) -State: $(c.state) -Logging: $(c.loggingOn) -FMU time: $(c.t) -FMU states: $(c.x)" -) - -""" -A mutable struct representing the excution configuration of a FMU. -For FMUs that have issues with calls like `fmi2Reset` or `fmi2FreeInstance`, this is pretty useful. -""" -mutable struct FMU2ExecutionConfiguration <: FMUExecutionConfiguration - terminate::Bool # call fmi2Terminate before every training step / simulation - reset::Bool # call fmi2Reset before every training step / simulation - setup::Bool # call setup functions before every training step / simulation - instantiate::Bool # call fmi2Instantiate before every training step / simulation - freeInstance::Bool # call fmi2FreeInstance after every training step / simulation - - loggingOn::Bool - externalCallbacks::Bool - - force::Bool # default value for forced actions - - handleStateEvents::Bool # handle state events during simulation/training - handleTimeEvents::Bool # handle time events during simulation/training - - assertOnError::Bool # wheter an exception is thrown if a fmi2XXX-command fails (>= fmi2StatusError) - assertOnWarning::Bool # wheter an exception is thrown if a fmi2XXX-command warns (>= fmi2StatusWarning) - - autoTimeShift::Bool # wheter to shift all time-related functions for simulation intervals not starting at 0.0 - inplace_eval::Bool # wheter FMU/Component evaluation should happen in place - - sensealg # algorithm for sensitivity estimation over solve call ([ToDo] Datatype/Nothing) - rootSearchInterpolationPoints::UInt # number of root search interpolation points - useVectorCallbacks::Bool # whether to vector (faster) or scalar (slower) callbacks - - maxNewDiscreteStateCalls::UInt # max calls for fmi2NewDiscreteStates before throwing an exception - maxStateEventsPerSecond::UInt # max state events allowed to occur per second (more is interpreted as event chattering) - - eval_t_gradients::Bool # if time gradients ∂ẋ_∂t and ∂y_∂t should be sampled (not part of the FMI standard) - JVPBuiltInDerivatives::Bool # use built-in directional derivatives for JVP-sensitivities over FMU without caching the jacobian (because this is done in the FMU, but not per default) - - sensitivity_strategy::Symbol # build up strategy for jacobians/gradients, available is `:FMIDirectionalDerivative`, `:FiniteDiff` - - set_p_every_step::Bool # whether parameters are set for every simulation step - this is uncommon, because parameters are (often) set just one time: during/after intialization - - # deprecated - concat_eval::Bool # wheter FMU/Component evaluation should return a tuple (y, dx, ec) or a conacatenation [y..., dx..., ec...] - isolatedStateDependency - - function FMU2ExecutionConfiguration() - inst = new() - - inst.terminate = true - inst.reset = true - inst.setup = true - inst.instantiate = false - inst.freeInstance = false - - inst.force = false - - inst.loggingOn = false - inst.externalCallbacks = true - - inst.handleStateEvents = true - inst.handleTimeEvents = true - - inst.assertOnError = false - inst.assertOnWarning = false - - inst.autoTimeShift = false - - inst.sensealg = nothing # auto - - inst.rootSearchInterpolationPoints = 10 - inst.useVectorCallbacks = true - - inst.maxNewDiscreteStateCalls = 100 - inst.maxStateEventsPerSecond = 100 - - inst.eval_t_gradients = false - inst.JVPBuiltInDerivatives = false - inst.sensitivity_strategy = :FMIDirectionalDerivative - - inst.set_p_every_step = false - - # deprecated - inst.concat_eval = true - inst.isolatedStateDependency = false - - return inst - end -end -export FMU2ExecutionConfiguration - -# default for a "healthy" FMU - this is the fastetst -FMU2_EXECUTION_CONFIGURATION_RESET = FMU2ExecutionConfiguration() -FMU2_EXECUTION_CONFIGURATION_RESET.terminate = true -FMU2_EXECUTION_CONFIGURATION_RESET.reset = true -FMU2_EXECUTION_CONFIGURATION_RESET.setup = true -FMU2_EXECUTION_CONFIGURATION_RESET.instantiate = false -FMU2_EXECUTION_CONFIGURATION_RESET.freeInstance = false -export FMU2_EXECUTION_CONFIGURATION_RESET - -# if your FMU has a problem with "fmi2Reset" - this is default -FMU2_EXECUTION_CONFIGURATION_NO_RESET = FMU2ExecutionConfiguration() -FMU2_EXECUTION_CONFIGURATION_NO_RESET.terminate = false -FMU2_EXECUTION_CONFIGURATION_NO_RESET.reset = false -FMU2_EXECUTION_CONFIGURATION_NO_RESET.setup = true -FMU2_EXECUTION_CONFIGURATION_NO_RESET.instantiate = true -FMU2_EXECUTION_CONFIGURATION_NO_RESET.freeInstance = true -export FMU2_EXECUTION_CONFIGURATION_NO_RESET - -# if your FMU has a problem with "fmi2Reset" and "fmi2FreeInstance" - this is for weak FMUs (but slower) -FMU2_EXECUTION_CONFIGURATION_NO_FREEING = FMU2ExecutionConfiguration() -FMU2_EXECUTION_CONFIGURATION_NO_FREEING.terminate = false -FMU2_EXECUTION_CONFIGURATION_NO_FREEING.reset = false -FMU2_EXECUTION_CONFIGURATION_NO_FREEING.setup = true -FMU2_EXECUTION_CONFIGURATION_NO_FREEING.instantiate = true -FMU2_EXECUTION_CONFIGURATION_NO_FREEING.freeInstance = false -export FMU2_EXECUTION_CONFIGURATION_NO_FREEING - -# do nothing, this is useful e.g. for set/get state applications -FMU2_EXECUTION_CONFIGURATION_NOTHING = FMU2ExecutionConfiguration() -FMU2_EXECUTION_CONFIGURATION_NOTHING.terminate = false -FMU2_EXECUTION_CONFIGURATION_NOTHING.reset = false -FMU2_EXECUTION_CONFIGURATION_NOTHING.setup = false -FMU2_EXECUTION_CONFIGURATION_NOTHING.instantiate = false -FMU2_EXECUTION_CONFIGURATION_NOTHING.freeInstance = false -export FMU2_EXECUTION_CONFIGURATION_NOTHING - -FMU2_EXECUTION_CONFIGURATIONS = (FMU2_EXECUTION_CONFIGURATION_NO_FREEING, FMU2_EXECUTION_CONFIGURATION_NO_RESET, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NOTHING) -export FMU2_EXECUTION_CONFIGURATIONS - -""" -The mutable struct representing a FMU (and a container for all its instances) in the FMI 2.0.2 Standard. -Also contains the paths to the FMU and ZIP folder as well als all the FMI 2.0.2 function pointers. -""" -mutable struct FMU2 <: FMU - modelName::String - fmuResourceLocation::String - logLevel::FMULogLevel - - modelDescription::fmi2ModelDescription - - type::fmi2Type - components::Array{FMU2Component, 1} - - # c-functions - cInstantiate::Ptr{Cvoid} - cGetTypesPlatform::Ptr{Cvoid} - cGetVersion::Ptr{Cvoid} - cFreeInstance::Ptr{Cvoid} - cSetDebugLogging::Ptr{Cvoid} - cSetupExperiment::Ptr{Cvoid} - cEnterInitializationMode::Ptr{Cvoid} - cExitInitializationMode::Ptr{Cvoid} - cTerminate::Ptr{Cvoid} - cReset::Ptr{Cvoid} - cGetReal::Ptr{Cvoid} - cSetReal::Ptr{Cvoid} - cGetInteger::Ptr{Cvoid} - cSetInteger::Ptr{Cvoid} - cGetBoolean::Ptr{Cvoid} - cSetBoolean::Ptr{Cvoid} - cGetString::Ptr{Cvoid} - cSetString::Ptr{Cvoid} - cGetFMUstate::Ptr{Cvoid} - cSetFMUstate::Ptr{Cvoid} - cFreeFMUstate::Ptr{Cvoid} - cSerializedFMUstateSize::Ptr{Cvoid} - cSerializeFMUstate::Ptr{Cvoid} - cDeSerializeFMUstate::Ptr{Cvoid} - cGetDirectionalDerivative::Ptr{Cvoid} - - # Co Simulation function calls - cSetRealInputDerivatives::Ptr{Cvoid} - cGetRealOutputDerivatives::Ptr{Cvoid} - cDoStep::Ptr{Cvoid} - cCancelStep::Ptr{Cvoid} - cGetStatus::Ptr{Cvoid} - cGetRealStatus::Ptr{Cvoid} - cGetIntegerStatus::Ptr{Cvoid} - cGetBooleanStatus::Ptr{Cvoid} - cGetStringStatus::Ptr{Cvoid} - - # Model Exchange function calls - cEnterContinuousTimeMode::Ptr{Cvoid} - cGetContinuousStates::Ptr{Cvoid} - cGetDerivatives::Ptr{Cvoid} - cSetTime::Ptr{Cvoid} - cSetContinuousStates::Ptr{Cvoid} - cCompletedIntegratorStep::Ptr{Cvoid} - cEnterEventMode::Ptr{Cvoid} - cNewDiscreteStates::Ptr{Cvoid} - cGetEventIndicators::Ptr{Cvoid} - cGetNominalsOfContinuousStates::Ptr{Cvoid} - - # paths of zipped and unzipped FMU folders - path::String - binaryPath::String - zipPath::String - - # execution configuration - executionConfig::FMU2ExecutionConfiguration - - # events - hasStateEvents::Union{Bool, Nothing} - hasTimeEvents::Union{Bool, Nothing} - isZeroState::Bool - - # c-libraries - libHandle::Ptr{Nothing} - callbackLibHandle::Ptr{Nothing} # for external callbacks - cFunctionPtrs::Dict{String, Ptr{Nothing}} - - # multi-threading - threadComponents::Dict{Integer, Union{FMU2Component, Nothing}} - - # indices of event indicators to be handled, if `nothing` all are handled - handleEventIndicators::Union{Vector{fmi2ValueReference}, Nothing} - - # START: experimental section (to FMIFlux.jl) - probably deprecated soon - dependencies::Matrix{Union{fmi2DependencyKind, Nothing}} - # END: experimental section - - # parameters that need sensitivities and/or are catched by optimizers (like in FMIFlux.jl) - default_t::Real - default_p_refs::AbstractVector{<:fmi2ValueReference} - default_p::AbstractVector{<:Real} - default_ec::AbstractVector{<:Real} - default_ec_idcs::AbstractVector{<:fmi2ValueReference} - default_dx::AbstractVector{<:Real} - default_dx_refs::AbstractVector{<:fmi2ValueReference} - default_u::AbstractVector{<:Real} - default_y::AbstractVector{<:Real} - default_y_refs::AbstractVector{<:fmi2ValueReference} - - # Constructor - function FMU2(logLevel::FMULogLevel=FMULogLevelWarn) - inst = new() - inst.components = [] - - inst.callbackLibHandle = C_NULL - inst.modelName = "" - inst.logLevel = logLevel - - inst.hasStateEvents = nothing - inst.hasTimeEvents = nothing - - inst.executionConfig = FMU2_EXECUTION_CONFIGURATION_NO_RESET - inst.threadComponents = Dict{Integer, Union{FMU2Component, Nothing}}() - inst.cFunctionPtrs = Dict{String, Ptr{Nothing}}() - - inst.handleEventIndicators = nothing - - # parameters that need sensitivities and/or are catched by optimizers (like in FMIFlux.jl) - inst.default_t = -1.0 - inst.default_p_refs = EMPTY_fmi2ValueReference - inst.default_p = EMPTY_fmi2Real - inst.default_ec = EMPTY_fmi2Real - inst.default_ec_idcs = EMPTY_fmi2ValueReference - inst.default_u = EMPTY_fmi2Real - inst.default_y = EMPTY_fmi2Real - inst.default_y_refs = EMPTY_fmi2ValueReference - inst.default_dx = EMPTY_fmi2Real - inst.default_dx_refs = EMPTY_fmi2ValueReference - - return inst - end -end -export FMU2 - -""" -Overload the Base.show() function for custom printing of the FMU2. -""" -function Base.show(io::IO, fmu::FMU2) - print(io, "Model name:\t$(fmu.modelDescription.modelName)\nType:\t\t$(fmu.type)") -end - -""" - ToDo: Doc String -""" -function hasCurrentComponent(fmu::FMU2) - tid = Threads.threadid() - return haskey(fmu.threadComponents, tid) && fmu.threadComponents[tid] != nothing -end -export hasCurrentComponent - -""" - ToDo: Doc String -""" -function getCurrentComponent(fmu::FMU2) - tid = Threads.threadid() - @assert hasCurrentComponent(fmu) ["No FMU instance allocated (in current thread with ID `$(tid)`), have you already called `fmi2Instantiate!`?"] - return fmu.threadComponents[tid] -end -export getCurrentComponent - -""" - ToDo: Doc String -""" -struct FMU2InputFunction{F, T} - fct!::F - vrs::Vector{fmi2ValueReference} - buffer::Vector{<:T} - - function FMU2InputFunction{T}(fct, vrs::Array{fmi2ValueReference}) where {T} - buffer = zeros(T, length(vrs)) - - _fct = nothing - - if hasmethod(fct, Tuple{T, AbstractArray{<:T,1}}) - _fct = (c, x, t, u) -> fct(t, u) - elseif hasmethod(fct, Tuple{Union{FMU2Component, Nothing}, T, AbstractArray{<:T,1}}) - _fct = (c, x, t, u) -> fct(c, t, u) - elseif hasmethod(fct, Tuple{Union{FMU2Component, Nothing}, AbstractArray{<:T,1}, AbstractArray{<:T,1}}) - _fct = (c, x, t, u) -> fct(c, x, u) - elseif hasmethod(fct, Tuple{AbstractArray{<:T,1}, T, AbstractArray{<:T,1}}) - _fct = (c, x, t, u) -> fct(x, t, u) - else - _fct = fct - end - @assert hasmethod(_fct, Tuple{FMU2Component, Union{AbstractArray{<:T,1}, Nothing}, T, AbstractArray{<:T,1}}) "The given input function does not fit the needed input function pattern for FMUs, which are: \n- `inputFunction!(t::T, u::AbstractArray{<:T})`\n- `inputFunction!(comp::FMU2Component, t::T, u::AbstractArray{<:T})`\n- `inputFunction!(comp::FMU2Component, x::Union{AbstractArray{<:T,1}, Nothing}, u::AbstractArray{<:T})`\n- `inputFunction!(x::Union{AbstractArray{<:T,1}, Nothing}, t::T, u::AbstractArray{<:T})`\n- `inputFunction!(comp::FMU2Component, x::Union{AbstractArray{<:T,1}, Nothing}, t::T, u::AbstractArray{<:T})`\nwhere T=$(T)" - - return new{typeof(_fct), T}(_fct, vrs, buffer) - end - - function FMU2InputFunction(fct, vrs::Array{fmi2ValueReference}) - return FMU2InputFunction{fmi2Real}(fct, vrs) - end -end -export FMU2InputFunction - -""" - ToDo: Doc String -""" -function eval!(ipf::FMU2InputFunction, c, x, t) - ipf.fct!(c, x, t, ipf.buffer) - return ipf.buffer -end -export eval! diff --git a/src/FMI3/cconst.jl b/src/FMI3/cconst.jl index 8c1eb46..1071b93 100644 --- a/src/FMI3/cconst.jl +++ b/src/FMI3/cconst.jl @@ -3,50 +3,167 @@ # Licensed under the MIT license. See LICENSE file in the project root for details. # +""" + fmi3Float32 (alias for Cfloat) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3Float32 = Cfloat +export fmi3Float32 + +""" + fmi3Float64 (alias for Cdouble) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3Float64 = Cdouble -const fmi3Int8 = Cchar -const fmi3UInt8 = Cuchar -const fmi3Int16 = Cshort -const fmi3UInt16 = Cushort -const fmi3Int32 = Cint -const fmi3UInt32 = Cuint -const fmi3Int64 = Clonglong -const fmi3UInt64 = Culonglong -const fmi3Boolean = Cuchar -const fmi3Char = Cuchar # changed to `Cuchar` to work with pointer function +export fmi3Float64 + +""" + fmi3Int8 (alias for Cchar) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Int8 = Cchar # = int8_t +export fmi3Int8 + +""" + fmi3UInt8 (alias for Cuchar) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3UInt8 = Cuchar # = uint8_t +export fmi3UInt8 + +""" + fmi3Int16 (alias for Cshort) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Int16 = Cshort # = int16_t +export fmi3Int16 + +""" + fmi3UInt16 (alias for Cushort) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3UInt16 = Cushort # = uint16_t +export fmi3UInt16 + +""" + fmi3Int32 (alias for Cint) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Int32 = Cint # = int32_t +export fmi3Int32 + +""" + fmi3UInt32 (alias for Cuint) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3UInt32 = Cuint # = uint32_t +export fmi3UInt32 + +""" + fmi3Int64 (alias for Clonglong) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Int64 = Clonglong # = int64_t +export fmi3Int64 + +""" + fmi3UInt64 (alias for Culonglong) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3UInt64 = Culonglong # = uint64_t +export fmi3UInt64 + +""" + fmi3Boolean (alias for Cuchar) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Boolean = Cuchar # = bool +export fmi3Boolean + +""" + fmi3Char (alias for Cuchar) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Char = Cuchar # [Note] changed to `Cuchar` to work with pointer function +export fmi3Char + +""" + fmi3String (alias for Ptr{fmi3Char}) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3String = Ptr{fmi3Char} +export fmi3String + +""" + fmi3Byte (alias for Cuchar) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3Byte = Cuchar +export fmi3Byte + +""" + fmi3Binary (alias for Ptr{fmi3Byte}) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3Binary = Ptr{fmi3Byte} +export fmi3Binary + +""" + fmi3ValueReference (alias for Cuint) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3ValueReference = Cuint +export fmi3ValueReference + +""" + fmi3FMUState (alias for Ptr{Cvoid}) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" const fmi3FMUState = Ptr{Cvoid} -const fmi3Instance = Ptr{Cvoid} -const fmi3InstanceEnvironment = Ptr{Cvoid} -const fmi3Clock = Cint +export fmi3FMUState """ + fmi3Instance (alias for Ptr{Cvoid}) + Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Instance = Ptr{Cvoid} +export fmi3Instance -To simplify porting, no C types are used in the function interfaces, but the alias types are defined in this section. -All definitions in this section are provided in the header file fmi3PlatformTypes.h. It is required to use this definition for all binary FMUs. """ -fmi3Float32, fmi3Float64, fmi3Int8, fmi3UInt8, fmi3Int16, fmi3UInt16, fmi3Int32, fmi3UInt32, fmi3Int64, fmi3UInt64 -export fmi3Float32, fmi3Float64, fmi3Int8, fmi3UInt8, fmi3Int16, fmi3UInt16, fmi3Int32, fmi3UInt32, fmi3Int64, fmi3UInt64 -export fmi3Boolean, fmi3Char, fmi3String, fmi3Byte, fmi3Binary, fmi3ValueReference, fmi3FMUState, fmi3Instance, fmi3InstanceEnvironment, fmi3Clock + fmi3InstanceEnvironment (alias for Ptr{Cvoid}) -# wildcards for how a user can pass a fmi3ValueReference -fmi3ValueReferenceFormat = Union{Nothing, String, AbstractArray{String,1}, fmi3ValueReference, AbstractArray{fmi3ValueReference,1}, Int64, AbstractArray{Int64,1}} -export fmi3ValueReferenceFormat +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3InstanceEnvironment = Ptr{Cvoid} +export fmi3InstanceEnvironment -const fmi3Status = Cuint -const fmi3StatusOK = Cuint(0) -const fmi3StatusWarning = Cuint(1) -const fmi3StatusDiscard = Cuint(2) -const fmi3StatusError = Cuint(3) -const fmi3StatusFatal = Cuint(4) +""" + fmi3Clock (alias for Cint) + +Source: FMISpec3.0-dev, Version D5ef1c1:2.2.2. Platform Dependent Definitions +""" +const fmi3Clock = Cint +export fmi3Clock """ -Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions Defines the status flag (an enumeration of type fmi3Status defined in file fmi3FunctionTypes.h) that is returned by functions to indicate the success of the function call: The status has the following meaning: - fmi3OK: The call was successful. The output argument values are defined. @@ -56,12 +173,59 @@ The status has the following meaning: [Examples for usage of fmi3Discard are handling of min/max violation, or signal numerical problems during model evaluation forcing smaller step sizes.] - fmi3Error: The call failed. The output argument values are undefined and the simulation cannot be continued. Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings. If a function returns fmi3Error, it is possible to restore a previously retrieved FMU state by calling fmi3SetFMUState. Otherwise fmi3FreeInstance or fmi3Reset must be called. When detecting illegal arguments or a function call not allowed in the current state according to the respective state machine, the FMU must return fmi3Error. Other instances of this FMU are not affected by the error. - fmi3Fatal: The state of all instances of the model is irreparably corrupted. [For example, due to a runtime exception such as access violation or integer division by zero during the execution of an FMI function.] Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings, if still possible. It is not allowed to call any other function for any instance of the FMU. + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions +""" +const fmi3Status = Cuint +export fmi3Status + +""" +fmi3OK: The call was successful. The output argument values are defined. + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions +""" +const fmi3StatusOK = Cuint(0) +export fmi3StatusOK + +""" +fmi3Warning: A non-critical problem was detected, but the computation can continue. The output argument values are defined. Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings. +[In certain applications, e.g. in a prototyping environment, warnings may be acceptable. For production environments warnings should be treated like errors unless they can be safely ignored.] + + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions +""" +const fmi3StatusWarning = Cuint(1) +export fmi3StatusWarning + +""" +fmi3Discard: The call was not successful and the FMU is in the same state as before the call. The output argument values are not defined, but the computation can continue. Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings. Advanced simulation algorithms can try alternative approaches to drive the simulation by calling the function with different arguments or calling another function. Otherwise the simulation algorithm has to treat this return code like fmi3Error and has to terminate the simulation. +[Examples for usage of fmi3Discard are handling of min/max violation, or signal numerical problems during model evaluation forcing smaller step sizes.] + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions +""" +const fmi3StatusDiscard = Cuint(2) +export fmi3StatusDiscard + +""" +fmi3Error: The call failed. The output argument values are undefined and the simulation cannot be continued. Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings. If a function returns fmi3Error, it is possible to restore a previously retrieved FMU state by calling fmi3SetFMUState. Otherwise fmi3FreeInstance or fmi3Reset must be called. When detecting illegal arguments or a function call not allowed in the current state according to the respective state machine, the FMU must return fmi3Error. Other instances of this FMU are not affected by the error. + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions +""" +const fmi3StatusError = Cuint(3) +export fmi3StatusError + +""" +fmi3Fatal: The state of all instances of the model is irreparably corrupted. [For example, due to a runtime exception such as access violation or integer division by zero during the execution of an FMI function.] Function logMessage should be called by the FMU with further information before returning this status, respecting the current logging settings, if still possible. It is not allowed to call any other function for any instance of the FMU. + +Source: FMISpec3.0, Version D5ef1c1: 2.2.3. Status Returned by Functions """ -fmi3Status, fmi3StatusOK, fmi3StatusWarning, fmi3StatusDiscard, fmi3StatusError, fmi3StatusFatal -export fmi3Status, fmi3StatusOK, fmi3StatusWarning, fmi3StatusDiscard, fmi3StatusError, fmi3StatusFatal +const fmi3StatusFatal = Cuint(4) +export fmi3StatusFatal """ A not further specified annotation struct. + +Source: [ToDo] """ mutable struct fmi3Annotation # No implementation @@ -103,16 +267,52 @@ The causality of variables of type Clock must be either input or output. Added prefix "fmi3" to help with redefinition of constans in enums. """ -const fmi3Causality = Cuint -const fmi3CausalityParameter = Cuint(0) -const fmi3CausalityCalculatedParameter = Cuint(1) -const fmi3CausalityInput = Cuint(2) -const fmi3CausalityOutput = Cuint(3) -const fmi3CausalityLocal = Cuint(4) -const fmi3CausalityIndependent = Cuint(5) -const fmi3CausalityStructuralParameter = Cuint(6) -export fmi3Causality, fmi3CausalityParameter, fmi3CausalityCalculatedParameter, fmi3CausalityInput, fmi3CausalityOutput, fmi3CausalityLocal, fmi3CausalityIndependent, fmi3CausalityStructuralParameter +const fmi3Causality = Cuint +export fmi3Causality + +""" +[TODO] +""" +const fmi3CausalityParameter = Cuint(0) +export fmi3CausalityParameter + +""" +[TODO] +""" +const fmi3CausalityCalculatedParameter = Cuint(1) +export fmi3CausalityCalculatedParameter + +""" +[TODO] +""" +const fmi3CausalityInput = Cuint(2) +export fmi3CausalityInput + +""" +[TODO] +""" +const fmi3CausalityOutput = Cuint(3) +export fmi3CausalityOutput + +""" +[TODO] +""" +const fmi3CausalityLocal = Cuint(4) +export fmi3CausalityLocal + +""" +[TODO] +""" +const fmi3CausalityIndependent = Cuint(5) +export fmi3CausalityIndependent +""" +[TODO] +""" +const fmi3CausalityStructuralParameter = Cuint(6) +export fmi3CausalityStructuralParameter + +# [ToDo] refactor custom doc-strings for every element """ Source: FMISpec3.0, Version D5ef1c1: 2.4.7.4. Variable Attributes Enumeration that defines the time dependency of the variable, in other words, it defines the time instants when a variable can change its value. [The purpose of this attribute is to define when a result value needs to be inquired and to be stored. For example, discrete variables change their values only at event instants (ME) or at a communication point (CS and SE) and it is therefore only necessary to inquire them with fmi3Get{VariableType} and store them at event times.] Allowed values of this enumeration: @@ -145,6 +345,7 @@ const fmi3VariabilityDiscrete = Cuint(3) const fmi3VariabilityContinuous = Cuint(4) export fmi3Variability, fmi3VariabilityConstant, fmi3VariabilityFixed, fmi3VariabilityTunable, fmi3VariabilityDiscrete, fmi3VariabilityContinuous +# [ToDo] refactor custom doc-strings for every element """ Source: FMISpec3.0, Version D5ef1c1:2.4.7.5. Type specific properties Enumeration that defines how the variable is initialized, i.e. if a fmi3Set{VariableType} is allowed and how the FMU internally treats this value in Instantiated and Initialization Mode. @@ -172,15 +373,27 @@ const fmi3InitialApprox = Cuint(1) const fmi3InitialCalculated = Cuint(2) export fmi3Initial, fmi3InitialExact, fmi3InitialApprox, fmi3InitialCalculated +""" + fmi2False + +Equals a binary `false` in FMI3. + +Source: [TODO] +""" const fmi3False = fmi3Boolean(false) -const fmi3True = fmi3Boolean(true) +export fmi3False """ -`fmi3Boolean` TODO + fmi2True + +Equals a binary `true` in FMI3. + +Source: [TODO] """ -fmi3False, fmi3True -export fmi3False, fmi3True +const fmi3True = fmi3Boolean(true) +export fmi3True +# [ToDo] refactor custom doc-strings for every element """ Source: FMISpec3.0, Version D5ef1c1: 2.3.1. Super State: FMU State Setable @@ -195,6 +408,7 @@ const fmi3TypeCoSimulation = Cuint(1) const fmi3TypeScheduledExecution = Cuint(2) export fmi3Type, fmi3TypeModelExchange, fmi3TypeCoSimulation, fmi3TypeScheduledExecution +# [ToDo] refactor custom doc-strings for every element """ Source: FMISpec3.0, Version D5ef1c1: 2.2.9.4. Scheduled Execution Enumeration that defines the IntervalQualifiers which describe how to treat the intervals and intervalCounters arguments. They have the following meaning: @@ -210,32 +424,31 @@ const fmi3IntervalQualifierIntervalUnchanged = Cuint(1) const fmi3IntervalQualifierIntervalChanged = Cuint(2) export fmi3IntervalQualifier, fmi3IntervalQualifierIntervalNotYetKnown, fmi3IntervalQualifierIntervalUnchanged, fmi3IntervalQualifierIntervalChanged -const fmi3VariableNamingConvention = Cuint -const fmi3VariableNamingConventionFlat = Cuint(0) -const fmi3VariableNamingConventionStructured = Cuint(1) +""" +[TODO] + +Source: FMISpec3.0, Version D5ef1c1: 2.4.7.5.1. Variable Naming Conventions +""" +const fmi3VariableNamingConvention = Cuint +export fmi3VariableNamingConvention + +""" +[TODO] +Source: FMISpec3.0, Version D5ef1c1: 2.4.7.5.1. Variable Naming Conventions """ +const fmi3VariableNamingConventionFlat = Cuint(0) +export fmi3VariableNamingConventionFlat + +""" +[TODO] + Source: FMISpec3.0, Version D5ef1c1: 2.4.7.5.1. Variable Naming Conventions """ -fmi3VariableNamingConvention, fmi3VariableNamingConventionFlat, fmi3VariableNamingConventionStructured -export fmi3VariableNamingConvention, fmi3VariableNamingConventionFlat, fmi3VariableNamingConventionStructured - -# this is a custom type to catch the internal state of the instance -const fmi3InstanceState = Cuint -const fmi3InstanceStateInstantiated = Cuint(0) # after instantiation -const fmi3InstanceStateInitializationMode = Cuint(1) # after finishing initialization -const fmi3InstanceStateEventMode = Cuint(2) -const fmi3InstanceStateStepMode = Cuint(3) -const fmi3InstanceStateClockActivationMode = Cuint(4) -const fmi3InstanceStateContinuousTimeMode = Cuint(5) -const fmi3InstanceStateConfigurationMode = Cuint(6) -const fmi3InstanceStateReconfigurationMode = Cuint(7) -const fmi3InstanceStateTerminated = Cuint(8) -const fmi3InstanceStateError = Cuint(9) -const fmi3InstanceStateFatal = Cuint(10) -export fmi3InstanceState, fmi3InstanceStateInstantiated, fmi3InstanceStateInitializationMode, fmi3InstanceStateEventMode, fmi3InstanceStateStepMode, fmi3InstanceStateClockActivationMode, fmi3InstanceStateContinuousTimeMode -export fmi3InstanceStateConfigurationMode, fmi3InstanceStateReconfigurationMode, fmi3InstanceStateTerminated, fmi3InstanceStateError, fmi3InstanceStateFatal +const fmi3VariableNamingConventionStructured = Cuint(1) +export fmi3VariableNamingConventionStructured +# [ToDo] doc-string format """ Source: FMISpec3.0, Version D5ef1c1: 2.2.10. Dependencies of Variables diff --git a/src/FMI3/cfunc.jl b/src/FMI3/cfunc.jl index af8af3e..f5d66e5 100644 --- a/src/FMI3/cfunc.jl +++ b/src/FMI3/cfunc.jl @@ -112,13 +112,13 @@ Source: FMISpec3.0, Version D5ef1c1: 2.3.1. Super State: FMU State Setable Disposes the given instance, unloads the loaded model, and frees all the allocated memory and other resources that have been allocated by the functions of the FMU interface. If a NULL pointer is provided for argument instance, the function call is ignored (does not have an effect). """ -function fmi3FreeInstance!(cfunc::Ptr{Nothing}, c::fmi3Instance) +function fmi3FreeInstance(cfunc::Ptr{Nothing}, c::fmi3Instance) ccall(cfunc, Cvoid, (Ptr{Cvoid},), c) @debug "fmi3FreeInstance(c: $(c)) → [nothing]" return nothing end -export fmi3FreeInstance! +export fmi3FreeInstance """ Source: FMISpec3.0, Version D5ef1c1: 2.3.1. Super State: FMU State Setable @@ -717,7 +717,7 @@ Source: FMISpec3.0, Version D5ef1c1: 2.2.6.4. Getting and Setting the Complete F fmi3FreeFMUstate frees all memory and other resources allocated with the fmi3GetFMUstate call for this FMUstate. """ -function fmi3FreeFMUState!(cfunc::Ptr{Nothing}, c::fmi3Instance, FMUstate::Ref{fmi3FMUState}) +function fmi3FreeFMUState(cfunc::Ptr{Nothing}, c::fmi3Instance, FMUstate::Ref{fmi3FMUState}) status = ccall(cfunc, fmi3Status, (fmi3Instance, Ptr{fmi3FMUState}), @@ -725,7 +725,7 @@ function fmi3FreeFMUState!(cfunc::Ptr{Nothing}, c::fmi3Instance, FMUstate::Ref{f @debug "fmi3FreeFMUState!(c: $(c), FMUstate: $(FMUstate)) → $(status)" return status end -export fmi3FreeFMUState! +export fmi3FreeFMUState """ Source: FMISpec3.0, Version D5ef1c1: 2.2.6.4. Getting and Setting the Complete FMU State diff --git a/src/FMI3/convert.jl b/src/FMI3/convert.jl deleted file mode 100644 index fc09aef..0000000 --- a/src/FMI3/convert.jl +++ /dev/null @@ -1,331 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -""" - - fmi3StatusToString(status::Union{fmi3Status, Integer}) - -Converts `fmi3Status` `status` into a String ("OK", "Warning", "Discard", "Error", "Fatal", "Unknown"). -""" -function fmi3StatusToString(status::Union{fmi3Status, Integer}) - if status == fmi3StatusOK - return "OK" - elseif status == fmi3StatusWarning - return "Warning" - elseif status == fmi3StatusDiscard - return "Discard" - elseif status == fmi3StatusError - return "Error" - elseif status == fmi3StatusFatal - return "Fatal" - else - return "Unknown" - end -end -export fmi3StatusToString - -""" - fmi3CausalityToString(c::fmi3Causality) - -Convert [`fmi3Causality`](@ref) `c` to the corresponding String ("parameter", "calculatedParameter", "structuralParameter", "input", "output", "local", "independent"). -""" -function fmi3StringToStatus(s::AbstractString) - if s == "OK" - return fmi3StatusOK - elseif s == "Warning" - return fmi3StatusWarning - elseif s == "Discard" - return fmi3StatusDiscard - elseif s == "Error" - return fmi3StatusError - elseif s == "Fatal" - return fmi3StatusFatal - else - return "Unknown" - end -end -export fmi3StringToStatus - -""" -ToDo. -""" -function fmi3CausalityToString(c::fmi3Causality) - if c == fmi3CausalityParameter - return "parameter" - elseif c == fmi3CausalityCalculatedParameter - return "calculatedParameter" - elseif c == fmi3CausalityInput - return "input" - elseif c == fmi3CausalityOutput - return "output" - elseif c == fmi3CausalityLocal - return "local" - elseif c == fmi3CausalityIndependent - return "independent" - elseif c == fmi3CausalityStructuralParameter - return "structuralParameter" - else - @assert false "fmi3CausalityToString(...): Unknown causality." - end -end -export fmi3CausalityToString - -""" - fmi3StringToCausality(s::AbstractString) - -Convert `s` ("parameter", "calculatedParameter", "structuralParameter", "input", "output", "local", "independent") to the corresponding [`fmi3Causality`](@ref). -""" -function fmi3StringToCausality(s::AbstractString) - if s == "parameter" - return fmi3CausalityParameter - elseif s == "calculatedParameter" - return fmi3CausalityCalculatedParameter - elseif s == "input" - return fmi3CausalityInput - elseif s == "output" - return fmi3CausalityOutput - elseif s == "local" - return fmi3CausalityLocal - elseif s == "independent" - return fmi3CausalityIndependent - elseif s == "structuralParameter" - return fmi3CausalityStructuralParameter - else - @assert false "fmi3StringToCausality($(s)): Unknown causality." - end -end -export fmi3StringToCausality - -""" - fmi3VariabilityToString(c::fmi3Variability) - -Convert [`fmi3Variability`](@ref) `c` to the corresponding String ("constant", "fixed", "tunable", "discrete", "continuous"). -""" -function fmi3VariabilityToString(c::fmi3Variability) - if c == fmi3VariabilityConstant - return "constant" - elseif c == fmi3VariabilityFixed - return "fixed" - elseif c == fmi3VariabilityTunable - return "tunable" - elseif c == fmi3VariabilityDiscrete - return "discrete" - elseif c == fmi3VariabilityContinuous - return "continuous" - else - @assert false "fmi3VariabilityToString(...): Unknown variability." - end -end -export fmi3VariabilityToString - -""" - fmi3StringToVariability(s::AbstractString) - -Convert `s` ("constant", "fixed", "tunable", "discrete", "continuous") to the corresponding [`fmi3Variability`](@ref). -""" -function fmi3StringToVariability(s::AbstractString) - if s == "constant" - return fmi3VariabilityConstant - elseif s == "fixed" - return fmi3VariabilityFixed - elseif s == "tunable" - return fmi3VariabilityTunable - elseif s == "discrete" - return fmi3VariabilityDiscrete - elseif s == "continuous" - return fmi3VariabilityContinuous - else - @assert false "fmi3StringToVariability($(s)): Unknown variability." - end -end -export fmi3StringToVariability - -""" - fmi3InitialToString(c::fmi3Initial) - -Convert [`fmi3Initial`](@ref) `c` to the corresponding String ("approx", "exact", "calculated"). -""" -function fmi3InitialToString(c::fmi3Initial) - if c == fmi3InitialApprox - return "approx" - elseif c == fmi3InitialExact - return "exact" - elseif c == fmi3InitialCalculated - return "calculated" - else - @assert false "fmi3InitialToString(...): Unknown initial." - end -end -export fmi3InitialToString - -""" - fmi3StringToInitial(s::AbstractString) - -Convert `s` ("approx", "exact", "calculated") to the corresponding [`fmi3Initial`](@ref). -""" -function fmi3StringToInitial(s::AbstractString) - if s == "approx" - return fmi3InitialApprox - elseif s == "exact" - return fmi3InitialExact - elseif s == "calculated" - return fmi3InitialCalculated - else - @assert false "fmi3StringToInitial($(s)): Unknown initial." - end -end -export fmi3StringToInitial - -""" - fmi3DependencyKindToString(c::fmi3DependencyKind) - -Convert [`fmi3DependencyKind`](@ref) `c` to the corresponding String ("independent", "dependent", "constant", "fixed", "tunable", "discrete"). -""" -function fmi3DependencyKindToString(c::fmi3DependencyKind) - if c == fmi3DependencyKindIndependent - return "independent" - elseif c == fmi3DependencyKindConstant - return "constant" - elseif c == fmi3DependencyKindFixed - return "fixed" - elseif c == fmi3DependencyKindTunable - return "tunable" - elseif c == fmi3DependencyKindDiscrete - return "discrete" - elseif c == fmi3DependencyKindDependent - return "dependent" - else - @assert false "fmi3DependencyKindToString(...): Unknown dependencyKind." - end -end -export fmi3DependencyKindToString - -""" - fmi3StringToDependencyKind(s::AbstractString) - -Convert `s` ("independent", "dependent", "constant", "fixed", "tunable", "discrete") to the corresponding [`fmi3DependencyKind`](@ref). -""" -function fmi3StringToDependencyKind(s::AbstractString) - if s == "independent" - return fmi3DependencyKindIndependent - elseif s == "constant" - return fmi3DependencyKindConstant - elseif s == "fixed" - return fmi3DependencyKindFixed - elseif s == "tunable" - return fmi3DependencyKindTunable - elseif s == "discrete" - return fmi3DependencyKindDiscrete - elseif s == "dependent" - return fmi3DependencyKindDependent - else - @assert false "fmi3StringToDependencyKind($(s)): Unknown dependencyKind." - end -end -export fmi3StringToDependencyKind - -""" - fmi3VariableNamingConventionToString(c::fmi3VariableNamingConvention) - -Convert [`fmi3VariableNamingConvention`](@ref) `c` to the corresponding String ("flat", "structured"). -""" -function fmi3VariableNamingConventionToString(c::fmi3VariableNamingConvention) - if c == fmi3VariableNamingConventionFlat - return "flat" - elseif c == fmi3VariableNamingConventionStructured - return "structured" - else - @assert false "fmi3VariableNamingConventionToString(...): Unknown variableNamingConvention." - end -end -export fmi3VariableNamingConventionToString - -""" - fmi3StringToVariableNamingConvention(s::AbstractString) - -Convert `s` ("flat", "structured") to the corresponding [`fmi3VariableNamingConvention`](@ref). -""" -function fmi3StringToVariableNamingConvention(s::AbstractString) - if s == "flat" - return fmi3VariableNamingConventionFlat - elseif s == "structured" - return fmi3VariableNamingConventionStructured - else - @assert false "fmi3StringToVariableNamingConvention($(s)): Unknown variableNamingConvention." - end -end -export fmi3StringToVariableNamingConvention - -""" - fmi3TypeToString(c::fmi3Type) - -Convert [`fmi3Type`](@ref) `c` to the corresponding String ("coSimulation", "modelExchange", "scheduledExecution"). -""" -function fmi3TypeToString(c::fmi3Type) - if c == fmi3TypeCoSimulation - return "coSimulation" - elseif c == fmi3TypeModelExchange - return "modelExchange" - elseif c == fmi3TypeScheduledExecution - return "scheduledExecution" - else - @assert false "fmi3TypeToString(...): Unknown type." - end -end -export fmi3TypeToString - -""" - fmi3StringToType(s::AbstractString) - -Convert `s` ("coSimulation", "modelExchange", "scheduledExecution") to the corresponding [`fmi3Type`](@ref). -""" -function fmi3StringToType(s::AbstractString) - if s == "coSimulation" - return fmi3TypeCoSimulation - elseif s == "modelExchange" - return fmi3TypeModelExchange - elseif s == "scheduledExecution" - return fmi3TypeScheduledExecution - else - @assert false "fmi3StringToInitial($(s)): Unknown type." - end -end -export fmi3StringToType - -""" - fmi3IntervalQualifierToString(c::fmi3IntervalQualifier) - -Convert [`fmi3IntervalQualifier`](@ref) `c` to the corresponding String ("intervalNotYetKnown", "intervalUnchanged", "intervalChanged"). -""" -function fmi3IntervalQualifierToString(c::fmi3IntervalQualifier) - if c == fmi3IntervalQualifierIntervalNotYetKnown - return "intervalNotYetKnown" - elseif c == fmi3IntervalQualifierIntervalUnchanged - return "intervalUnchanged" - elseif c == fmi3IntervalQualifierIntervalChanged - return "intervalChanged" - else - @assert false "fmi3IntervalQualifierToString(...): Unknown intervalQualifier." - end -end -export fmi3IntervalQualifierToString - -""" - fmi3StringToIntervalQualifier(s::AbstractString) - -Convert `s` ("intervalNotYetKnown", "intervalUnchanged", "intervalChanged") to the corresponding [`fmi3IntervalQualifier`](@ref). -""" -function fmi3StringToIntervalQualifier(s::AbstractString) - if s == "intervalNotYetKnown" - return fmi3IntervalQualifierIntervalNotYetKnown - elseif s == "intervalUnchanged" - return fmi3IntervalQualifierIntervalUnchanged - elseif s == "intervalChanged" - return fmi3IntervalQualifierIntervalChanged - else - @assert false "fmi3StringToIntervalQualifier($(s)): Unknown intervalQualifier." - end -end -export fmi3StringToIntervalQualifier \ No newline at end of file diff --git a/src/FMI3/ctype.jl b/src/FMI3/ctype.jl index 3c86464..87fccf9 100644 --- a/src/FMI3/ctype.jl +++ b/src/FMI3/ctype.jl @@ -49,12 +49,12 @@ mutable struct fmi3VariableFloat32 <: fmi3Variable # Optional description::Union{String, Nothing} - canHandleMultipleSetPerTimeInstant::Union{fmi3Boolean, Nothing} + canHandleMultipleSetPerTimeInstant::Union{Bool, Nothing} annotations::Union{fmi3Annotation, Nothing} clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -64,11 +64,11 @@ mutable struct fmi3VariableFloat32 <: fmi3Variable relativeQuantity::Union{Bool, Nothing} min::Union{fmi3Float32, Nothing} max::Union{fmi3Float32, Nothing} - nominal::Real + nominal::Union{fmi3Float32, Nothing} unbounded::Union{fmi3Boolean, Nothing} start::Union{fmi3Float32, Nothing} derivative::Union{fmi3ValueReference, Nothing} - reinit::Union{fmi3Boolean, Nothing} + reinit::Union{Bool, Nothing} # dependencies dependencies #::Array{fmi3Int32} @@ -122,7 +122,7 @@ mutable struct fmi3VariableFloat64 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -132,11 +132,11 @@ mutable struct fmi3VariableFloat64 <: fmi3Variable relativeQuantity::Union{Bool, Nothing} min::Union{fmi3Float64, Nothing} max::Union{fmi3Float64, Nothing} - nominal::Real + nominal::Union{fmi3Float64, Nothing} unbounded::Union{fmi3Boolean, Nothing} start::Union{fmi3Float64, Nothing} derivative::Union{fmi3ValueReference, Nothing} - reinit::Union{fmi3Boolean, Nothing} + reinit::Union{Bool, Nothing} # dependencies dependencies #::Array{fmi3Int32} @@ -190,7 +190,7 @@ mutable struct fmi3VariableInt8 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -244,7 +244,7 @@ mutable struct fmi3VariableUInt8 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -298,7 +298,7 @@ mutable struct fmi3VariableInt16 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -352,7 +352,7 @@ mutable struct fmi3VariableUInt16 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -406,7 +406,7 @@ mutable struct fmi3VariableInt32 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -460,7 +460,7 @@ mutable struct fmi3VariableUInt32 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -514,7 +514,7 @@ mutable struct fmi3VariableInt64 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -568,7 +568,7 @@ mutable struct fmi3VariableUInt64 <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -622,7 +622,7 @@ mutable struct fmi3VariableBoolean <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} declaredType::Union{String, Nothing} @@ -710,7 +710,7 @@ mutable struct fmi3VariableBinary <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} declaredType::Union{String, Nothing} @@ -820,7 +820,7 @@ mutable struct fmi3VariableEnumeration <: fmi3Variable clocks::Union{Array{fmi3ValueReference}, Nothing} # type specific attributes - intermediateUpdate::fmi3Boolean + intermediateUpdate::Union{Bool, Nothing} previous::Union{fmi3ValueReference, Nothing} initial::Union{fmi3Initial, Nothing} quantity::Union{String, Nothing} @@ -949,8 +949,8 @@ mutable struct fmi3ModelDescriptionModelExchange # optional needsExecutionTool::Union{Bool, Nothing} canBeInstantiatedOnlyOncePerProcess::Union{Bool, Nothing} - canGetAndSetFMUstate::Union{Bool, Nothing} - canSerializeFMUstate::Union{Bool, Nothing} + canGetAndSetFMUState::Union{Bool, Nothing} + canSerializeFMUState::Union{Bool, Nothing} providesDirectionalDerivatives::Union{Bool, Nothing} providesAdjointDerivatives::Union{Bool, Nothing} providesPerElementDependencies::Union{Bool, Nothing} @@ -968,8 +968,8 @@ mutable struct fmi3ModelDescriptionModelExchange inst.modelIdentifier = modelIdentifier inst.needsExecutionTool = nothing inst.canBeInstantiatedOnlyOncePerProcess = nothing - inst.canGetAndSetFMUstate = nothing - inst.canSerializeFMUstate = nothing + inst.canGetAndSetFMUState = nothing + inst.canSerializeFMUState = nothing inst.providesDirectionalDerivatives = nothing inst.providesAdjointDerivatives = nothing inst.providesPerElementDependencies = nothing @@ -987,8 +987,8 @@ mutable struct fmi3ModelDescriptionCoSimulation # optional needsExecutionTool::Union{Bool, Nothing} canBeInstantiatedOnlyOncePerProcess::Union{Bool, Nothing} - canGetAndSetFMUstate::Union{Bool, Nothing} - canSerializeFMUstate::Union{Bool, Nothing} + canGetAndSetFMUState::Union{Bool, Nothing} + canSerializeFMUState::Union{Bool, Nothing} providesDirectionalDerivatives::Union{Bool, Nothing} providesAdjointDerivatives::Union{Bool, Nothing} providesPerElementDependencies::Union{Bool, Nothing} @@ -1015,8 +1015,8 @@ mutable struct fmi3ModelDescriptionCoSimulation inst.modelIdentifier = modelIdentifier inst.needsExecutionTool = nothing inst.canBeInstantiatedOnlyOncePerProcess = nothing - inst.canGetAndSetFMUstate = nothing - inst.canSerializeFMUstate = nothing + inst.canGetAndSetFMUState = nothing + inst.canSerializeFMUState = nothing inst.providesDirectionalDerivatives = nothing inst.providesAdjointDerivatives = nothing inst.providesPerElementDependencies = nothing @@ -1043,8 +1043,8 @@ mutable struct fmi3ModelDescriptionScheduledExecution # optional needsExecutionTool::Union{Bool, Nothing} canBeInstantiatedOnlyOncePerProcess::Union{Bool, Nothing} - canGetAndSetFMUstate::Union{Bool, Nothing} - canSerializeFMUstate::Union{Bool, Nothing} + canGetAndSetFMUState::Union{Bool, Nothing} + canSerializeFMUState::Union{Bool, Nothing} providesDirectionalDerivatives::Union{Bool, Nothing} providesAdjointDerivatives::Union{Bool, Nothing} providesPerElementDependencies::Union{Bool, Nothing} @@ -1060,8 +1060,8 @@ mutable struct fmi3ModelDescriptionScheduledExecution inst.modelIdentifier = modelIdentifier inst.needsExecutionTool = nothing inst.canBeInstantiatedOnlyOncePerProcess = nothing - inst.canGetAndSetFMUstate = nothing - inst.canSerializeFMUstate = nothing + inst.canGetAndSetFMUState = nothing + inst.canSerializeFMUState = nothing inst.providesDirectionalDerivatives = nothing inst.providesAdjointDerivatives = nothing inst.providesPerElementDependencies = nothing @@ -1090,7 +1090,7 @@ Source: FMISpec3.0, Version D5ef1c1: 2.4.1. Definition of an FMU The central FMU data structure defining all variables of the FMU that are visible/accessible via the FMU functions. """ -mutable struct fmi3ModelDescription +mutable struct fmi3ModelDescription <: fmiModelDescription # FMI model description fmiVersion::String modelName::String diff --git a/src/FMI3/struct.jl b/src/FMI3/struct.jl deleted file mode 100644 index 7469f21..0000000 --- a/src/FMI3/struct.jl +++ /dev/null @@ -1,500 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in this file: -# - the `fmi3InstanceState`-enum which mirrors the internal FMU state (state-machine, not the system state) -# - the `FMU3Instance`-struct -# - the `FMU3`-struct -# - string/enum-converters for FMI-attribute-structs (e.g. `fmi3StatusToString`, ...) - -""" -This is a pointer to a data structure in the importer. Using this pointer, data may be transferred between the importer and callback functions the importer provides with the instantiation functions. - -Source: FMISpec 3.0.1 [2.2.3. Platform Dependent Definitions] -""" -mutable struct FMU3InstanceEnvironment - logStatusOK::Bool - logStatusWarning::Bool - logStatusDiscard::Bool - logStatusError::Bool - logStatusFatal::Bool - - function FMU3InstanceEnvironment() - inst = new() - inst.logStatusOK = true - inst.logStatusWarning = true - inst.logStatusDiscard = true - inst.logStatusError = true - inst.logStatusFatal = true - return inst - end -end -export FMU3InstanceEnvironment - -""" -Source: FMISpec3.0, Version D5ef1c1:: 2.2.1. Header Files and Naming of Functions - -The mutable struct represents a pointer to an FMU specific data structure that contains the information needed to process the model equations or to process the co-simulation of the model/subsystem represented by the FMU. -""" -mutable struct FMU3Instance{F} # type is always FMU3, but this would cause a circular dependency - compAddr::fmi3Instance - fmu::F - state::fmi3InstanceState - instanceEnvironment::FMU3InstanceEnvironment - problem - type::Union{fmi3Type, Nothing} - - loggingOn::Bool - instanceName::String - continuousStatesChanged::fmi3Boolean - - t::fmi3Float64 # the system time - t_offset::fmi3Float64 # time offset between simulation environment and FMU - x::Union{Array{fmi3Float64, 1}, Nothing} # the system states (or sometimes u) - ẋ::Union{Array{fmi3Float64, 1}, Nothing} # the system state derivative (or sometimes u̇) - ẍ::Union{Array{fmi3Float64, 1}, Nothing} # the system state second derivative - #u::Array{fmi3Float64, 1} # the system inputs - #y::Array{fmi3Float64, 1} # the system outputs - #p::Array{fmi3Float64, 1} # the system parameters - z::Array{fmi3Float64, 1} # the system event indicators - z_prev::Union{Nothing, Array{fmi3Float64, 1}} # the last system event indicators - - realValues::Dict - - x_vrs::Array{fmi3ValueReference, 1} # the system state value references - ẋ_vrs::Array{fmi3ValueReference, 1} # the system state derivative value references - u_vrs::Array{fmi3ValueReference, 1} # the system input value references - y_vrs::Array{fmi3ValueReference, 1} # the system output value references - p_vrs::Array{fmi3ValueReference, 1} # the system parameter value references - - # deprecated - jac_ẋy_x::Matrix{fmi3Float64} - jac_ẋy_u::Matrix{fmi3Float64} - jac_x::Array{fmi3Float64} - jac_u::Union{Array{fmi3Float64}, Nothing} - jac_t::fmi3Float64 - senseFunc::Symbol # :auto, :full, :sample, :directionalDerivatives, :adjointDerivatives - - # linearization jacobians - A::Union{Matrix{fmi3Float64}, Nothing} - B::Union{Matrix{fmi3Float64}, Nothing} - C::Union{Matrix{fmi3Float64}, Nothing} - D::Union{Matrix{fmi3Float64}, Nothing} - - jacobianUpdate! # function for a custom jacobian constructor (optimization) - skipNextDoStep::Bool # allows skipping the next `fmi3DoStep` like it is not called - - # custom - - rootsFound::Array{fmi3Int32} - stateEvent::fmi3Boolean - timeEvent::fmi3Boolean - stepEvent::fmi3Boolean - - # constructor - - function FMU3Instance{F}() where {F} - inst = new() - inst.state = fmi3InstanceStateInstantiated - inst.t = -Inf - inst.t_offset = 0.0 - inst.problem = nothing - inst.type = nothing - - # deprecated - inst.senseFunc = :auto - - inst.x = nothing - inst.ẋ = nothing - inst.ẍ = nothing - inst.z_prev = nothing - - inst.realValues = Dict() - inst.x_vrs = Array{fmi3ValueReference, 1}() - inst.ẋ_vrs = Array{fmi3ValueReference, 1}() - inst.u_vrs = Array{fmi3ValueReference, 1}() - inst.y_vrs = Array{fmi3ValueReference, 1}() - inst.p_vrs = Array{fmi3ValueReference, 1}() - - # initialize further variables - inst.jac_x = Array{fmi3Float64, 1}() - inst.jac_u = nothing - inst.jac_t = -1.0 - inst.jac_ẋy_x = zeros(fmi3Float64, 0, 0) - inst.jac_ẋy_u = zeros(fmi3Float64, 0, 0) - inst.A = nothing - inst.B = nothing - inst.C = nothing - inst.D = nothing - - # initialize further variables - inst.skipNextDoStep = false - - return inst - end - - function FMU3Instance(compAddr::fmi3Instance, fmu::F) where {F} - inst = FMU3Instance{F}() - inst.compAddr = compAddr - inst.fmu = fmu - return inst - end -end -export FMU3Instance - -""" -Overload the Base.show() function for custom printing of the FMU3Instance. -""" -Base.show(io::IO, c::FMU3Instance) = print(io, -"FMU: $(c.fmu.modelDescription.modelName) -InstanceName: $(isdefined(c, :instanceName) ? c.instanceName : "[not defined]") -Address: $(c.compAddr) -State: $(c.state) -Logging: $(c.loggingOn) -FMU time: $(c.t) -FMU states: $(c.x)" -) - -""" -A mutable struct representing the excution configuration of a FMU. -For FMUs that have issues with calls like `fmi3Reset` or `fmi3FreeInstance`, this is pretty useful. -""" -mutable struct FMU3ExecutionConfiguration <: FMUExecutionConfiguration - terminate::Bool # call fmi3Terminate before every training step / simulation - reset::Bool # call fmi3Reset before every training step / simulation - setup::Bool # call setup functions before every training step / simulation - instantiate::Bool # call fmi3Instantiate before every training step / simulation - freeInstance::Bool # call fmi3FreeInstance after every training step / simulation - - loggingOn::Bool - externalCallbacks::Bool - - handleStateEvents::Bool # handle state events during simulation/training - handleTimeEvents::Bool # handle time events during simulation/training - handleEventIndicators::Union{Array{Integer}, Nothing} # indices of event indicators to be handled, if `nothing` all are handled - - assertOnError::Bool # wheter an exception is thrown if a fmi3XXX-command fails (>= fmi3StatusError) - assertOnWarning::Bool # wheter an exception is thrown if a fmi3XXX-command warns (>= fmi3StatusWarning) - - autoTimeShift::Bool # wheter to shift all time-related functions for simulation intervals not starting at 0.0 - - sensealg # algorithm for sensitivity estimation over solve call - useComponentShadow::Bool # whether FMU outputs/derivatives/jacobians should be cached for frule/rrule (useful for ForwardDiff) - rootSearchInterpolationPoints::UInt # number of root search interpolation points - inPlace::Bool # whether faster in-place-fx should be used - useVectorCallbacks::Bool # whether to vector (faster) or scalar (slower) callbacks - - maxNewDiscreteStateCalls::UInt # max calls for fmi3NewDiscreteStates before throwing an exception - - function FMU3ExecutionConfiguration() - inst = new() - - inst.terminate = true - inst.reset = true - inst.setup = true - inst.instantiate = false - inst.freeInstance = false - - inst.loggingOn = false - inst.externalCallbacks = false - - inst.handleStateEvents = true - inst.handleTimeEvents = true - inst.handleEventIndicators = nothing - - inst.assertOnError = false - inst.assertOnWarning = false - - inst.autoTimeShift = true - - inst.sensealg = nothing # auto - inst.useComponentShadow = false - inst.rootSearchInterpolationPoints = 100 - inst.inPlace = true - inst.useVectorCallbacks = true - - inst.maxNewDiscreteStateCalls = 100 - - return inst - end -end -export FMU3ExecutionConfiguration - -# default for a "healthy" FMU - this is the fastetst -FMU3_EXECUTION_CONFIGURATION_RESET = FMU3ExecutionConfiguration() -FMU3_EXECUTION_CONFIGURATION_RESET.terminate = true -FMU3_EXECUTION_CONFIGURATION_RESET.reset = true -FMU3_EXECUTION_CONFIGURATION_RESET.instantiate = false -FMU3_EXECUTION_CONFIGURATION_RESET.freeInstance = false -export FMU3_EXECUTION_CONFIGURATION_RESET - -# if your FMU has a problem with "fmi3Reset" - this is default -FMU3_EXECUTION_CONFIGURATION_NO_RESET = FMU3ExecutionConfiguration() -FMU3_EXECUTION_CONFIGURATION_NO_RESET.terminate = false -FMU3_EXECUTION_CONFIGURATION_NO_RESET.reset = false -FMU3_EXECUTION_CONFIGURATION_NO_RESET.instantiate = true -FMU3_EXECUTION_CONFIGURATION_NO_RESET.freeInstance = true -export FMU3_EXECUTION_CONFIGURATION_NO_RESET - -# if your FMU has a problem with "fmi3Reset" and "fmi3FreeInstance" - this is for weak FMUs (but slower) -FMU3_EXECUTION_CONFIGURATION_NO_FREEING = FMU3ExecutionConfiguration() -FMU3_EXECUTION_CONFIGURATION_NO_FREEING.terminate = false -FMU3_EXECUTION_CONFIGURATION_NO_FREEING.reset = false -FMU3_EXECUTION_CONFIGURATION_NO_FREEING.instantiate = true -FMU3_EXECUTION_CONFIGURATION_NO_FREEING.freeInstance = false -export FMU3_EXECUTION_CONFIGURATION_NO_FREEING - -FMU3_EXECUTION_CONFIGURATIONS = (FMU3_EXECUTION_CONFIGURATION_NO_FREEING, FMU3_EXECUTION_CONFIGURATION_NO_RESET, FMU3_EXECUTION_CONFIGURATION_RESET) -export FMU3_EXECUTION_CONFIGURATIONS - -""" -Container for event related information. -""" -struct FMU3Event <: FMUEvent - t::fmi3Float64 # event time point - indicator::UInt # index of event indicator ("0" for time events) - - x_left::Union{Array{fmi3Float64, 1}, Nothing} # state before the event - x_right::Union{Array{fmi3Float64, 1}, Nothing} # state after the event (if discontinuous) - - indicatorValue::Union{fmi3Float64, Nothing} # value of the event indicator that triggered the event (should be really close to zero) - - function FMU3Event(t::fmi3Float64, - indicator::UInt = 0, - x_left::Union{Array{fmi3Float64, 1}, Nothing} = nothing, - x_right::Union{Array{fmi3Float64, 1}, Nothing} = nothing, - indicatorValue::Union{fmi3Float64, Nothing} = nothing) - inst = new(t, indicator, x_left, x_right, indicatorValue) - return inst - end -end -export FMU3Event - -""" -Overload the Base.show() function for custom printing of the FMU3. -""" -Base.show(io::IO, e::FMU3Event) = print(io, e.indicator == 0 ? "Time-Event @ $(round(e.t; digits=4))s" : "State-Event #$(e.indicator) @ $(round(e.t; digits=4))s") - - -""" -The mutable struct representing a specific Solution of a FMI2 FMU. -""" -mutable struct FMU3Solution{F} <: FMUSolution where {F} - fmu::F # FMU3 - success::Bool - - states # TODO: ODESolution - - values # TODO: datatype - valueReferences::Union{Array, Nothing} # TODO: Array{fmi3ValueReference} - - events::Array{FMU3Event, 1} - - function FMU3Solution(fmu::F) where {F} - inst = new{F}() - - inst.fmu = fmu - inst.success = false - inst.states = nothing - inst.values = nothing - inst.valueReferences = nothing - - inst.events = [] - - return inst - end -end -export FMU3Solution - -""" -Overload the Base.show() function for custom printing of the FMU3. -""" -function Base.show(io::IO, sol::FMU3Solution) - print(io, "Model name:\n\t$(sol.fmu.modelDescription.modelName)\nSuccess:\n\t$(sol.success)\n") - - if sol.states !== nothing - print(io, "States [$(length(sol.states))]:\n") - if length(sol.states.u) > 10 - for i in 1:9 - print(io, "\t$(sol.states.t[i])\t$(sol.states.u[i])\n") - end - print(io, "\t...\n\t$(sol.states.t[end])\t$(sol.states.u[end])\n") - else - for i in 1:length(sol.states) - print(io, "\t$(sol.states.t[i])\t$(sol.states.u[i])\n") - end - end - end - - if sol.values !== nothing - print(io, "Values [$(length(sol.values.saveval))]:\n") - if length(sol.values.saveval) > 10 - for i in 1:9 - print(io, "\t$(sol.values.t[i])\t$(sol.values.saveval[i])\n") - end - print(io, "\t...\n\t$(sol.values.t[end])\t$(sol.values.saveval[end])\n") - else - for i in 1:length(sol.values.saveval) - print(io, "\t$(sol.values.t[i])\t$(sol.values.saveval[i])\n") - end - end - end - - if sol.events !== nothing - print(io, "Events [$(length(sol.events))]:\n") - if length(sol.events) > 10 - for i in 1:9 - print(io, "\t$(sol.events[i])\n") - end - print(io, "\t...\n\t$(sol.events[end])\n") - else - for i in 1:length(sol.events) - print(io, "\t$(sol.events[i])\n") - end - end - end - -end - -""" -Source: FMISpec3.0, Version D5ef1c1: 2.2.1. Header Files and Naming of Functions - -The mutable struct representing an FMU in the FMI 3.0 Standard. -Also contains the paths to the FMU and ZIP folder as well als all the FMI 3.0 function pointers -""" -mutable struct FMU3 <: FMU - modelName::String - fmuResourceLocation::String - - modelDescription::fmi3ModelDescription - - type::fmi3Type - instances::Array{FMU3Instance,1} - - # c-functions - cInstantiateModelExchange::Ptr{Cvoid} - cInstantiateCoSimulation::Ptr{Cvoid} - cInstantiateScheduledExecution::Ptr{Cvoid} - - cGetVersion::Ptr{Cvoid} - cFreeInstance::Ptr{Cvoid} - cSetDebugLogging::Ptr{Cvoid} - cEnterConfigurationMode::Ptr{Cvoid} - cExitConfigurationMode::Ptr{Cvoid} - cEnterInitializationMode::Ptr{Cvoid} - cExitInitializationMode::Ptr{Cvoid} - cTerminate::Ptr{Cvoid} - cReset::Ptr{Cvoid} - cGetFloat32::Ptr{Cvoid} - cSetFloat32::Ptr{Cvoid} - cGetFloat64::Ptr{Cvoid} - cSetFloat64::Ptr{Cvoid} - cGetInt8::Ptr{Cvoid} - cSetInt8::Ptr{Cvoid} - cGetUInt8::Ptr{Cvoid} - cSetUInt8::Ptr{Cvoid} - cGetInt16::Ptr{Cvoid} - cSetInt16::Ptr{Cvoid} - cGetUInt16::Ptr{Cvoid} - cSetUInt16::Ptr{Cvoid} - cGetInt32::Ptr{Cvoid} - cSetInt32::Ptr{Cvoid} - cGetUInt32::Ptr{Cvoid} - cSetUInt32::Ptr{Cvoid} - cGetInt64::Ptr{Cvoid} - cSetInt64::Ptr{Cvoid} - cGetUInt64::Ptr{Cvoid} - cSetUInt64::Ptr{Cvoid} - cGetBoolean::Ptr{Cvoid} - cSetBoolean::Ptr{Cvoid} - cGetString::Ptr{Cvoid} - cSetString::Ptr{Cvoid} - cGetBinary::Ptr{Cvoid} - cSetBinary::Ptr{Cvoid} - cGetFMUState::Ptr{Cvoid} - cSetFMUState::Ptr{Cvoid} - cFreeFMUState::Ptr{Cvoid} - cSerializedFMUStateSize::Ptr{Cvoid} - cSerializeFMUState::Ptr{Cvoid} - cDeSerializeFMUState::Ptr{Cvoid} - cGetDirectionalDerivative::Ptr{Cvoid} - cGetAdjointDerivative::Ptr{Cvoid} - cEvaluateDiscreteStates::Ptr{Cvoid} - cGetNumberOfVariableDependencies::Ptr{Cvoid} - cGetVariableDependencies::Ptr{Cvoid} - - # Co Simulation function calls - cGetOutputDerivatives::Ptr{Cvoid} - cEnterStepMode::Ptr{Cvoid} - cDoStep::Ptr{Cvoid} - - # Model Exchange function calls - cGetNumberOfContinuousStates::Ptr{Cvoid} - cGetNumberOfEventIndicators::Ptr{Cvoid} - cGetContinuousStates::Ptr{Cvoid} - cGetNominalsOfContinuousStates::Ptr{Cvoid} - cEnterContinuousTimeMode::Ptr{Cvoid} - cSetTime::Ptr{Cvoid} - cSetContinuousStates::Ptr{Cvoid} - cGetContinuousStateDerivatives::Ptr{Cvoid} - cGetEventIndicators::Ptr{Cvoid} - cCompletedIntegratorStep::Ptr{Cvoid} - cEnterEventMode::Ptr{Cvoid} - cUpdateDiscreteStates::Ptr{Cvoid} - - # Scheduled Execution function calls - cSetIntervalDecimal::Ptr{Cvoid} - cSetIntervalFraction::Ptr{Cvoid} - cGetIntervalDecimal::Ptr{Cvoid} - cGetIntervalFraction::Ptr{Cvoid} - cGetShiftDecimal::Ptr{Cvoid} - cGetShiftFraction::Ptr{Cvoid} - cActivateModelPartition::Ptr{Cvoid} - - # paths of ziped and unziped FMU folders - path::String - binaryPath::String - zipPath::String - - # execution configuration - executionConfig::FMU3ExecutionConfiguration - hasStateEvents::Union{Bool, Nothing} - hasTimeEvents::Union{Bool, Nothing} - - # c-libraries - libHandle::Ptr{Nothing} - callbackLibHandle::Ptr{Nothing} - - # START: experimental section (to FMIFlux.jl) - dependencies::Matrix{Union{fmi3DependencyKind, Nothing}} - # linearization jacobians deprecated - # A::Matrix{fmi3Float64} - # B::Matrix{fmi3Float64} - # C::Matrix{fmi3Float64} - # D::Matrix{fmi3Float64} - - # END: experimental section - - # Constructor - function FMU3() - inst = new() - inst.instances = [] - inst.callbackLibHandle = C_NULL - inst.modelName = "" - - inst.hasStateEvents = nothing - inst.hasTimeEvents = nothing - - inst.executionConfig = FMU3_EXECUTION_CONFIGURATION_NO_RESET - return inst - end -end -export FMU3 - -""" Overload the Base.show() function for custom printing of the FMU3""" -Base.show(io::IO, fmu::FMU3) = print(io, -"Model name: $(fmu.modelName) -Type: $(fmu.type)" -) diff --git a/src/FMICore.jl b/src/FMICore.jl index cff37eb..71b2c30 100644 --- a/src/FMICore.jl +++ b/src/FMICore.jl @@ -5,11 +5,7 @@ module FMICore -using Requires -import ChainRulesCore -import Base: show - -# check float size (32 or 64 bits) +# Check float size on system (32 or 64 bits) juliaArch = Sys.WORD_SIZE @assert (juliaArch == 64 || juliaArch == 32) "FMICore: Unknown Julia Architecture with $(juliaArch)-bit, must be 64- or 32-bit." Creal = Cdouble @@ -17,30 +13,11 @@ if juliaArch == 32 Creal = Cfloat end -# checks if integrator has NaNs (that is not good...) -function assert_integrator_valid(integrator) - @assert !isnan(integrator.opts.internalnorm(integrator.u, integrator.t)) "NaN in `integrator.u` @ $(integrator.t)." -end +# abstract types for inheritance +abstract type fmiModelDescription end +export fmiModelDescription -# copy only if field can't be overwritten -function fast_copy!(str, dst::Symbol, src) - @assert false "fast_copy! not implemented for src of type $(typeof(src))" -end -function fast_copy!(str, dst::Symbol, src::Nothing) - setfield!(str, dst, nothing) -end -function fast_copy!(str, dst::Symbol, src::AbstractArray) - tmp = getfield(str, dst) - if isnothing(tmp) || length(tmp) != length(src) - setfield!(str, dst, copy(src)) - else - tmp[:] = src - end -end - -include("error_msg.jl") -include("types.jl") -include("printing.jl") +const SI_UNITS = (:kg, :m, :s, :A, :K, :mol, :cd, :rad) include("FMI2/cconst.jl") include("FMI3/cconst.jl") @@ -54,29 +31,4 @@ include("FMI3/cfunc.jl") include("FMI2/cfunc_unload.jl") # ToDo: include("FMI3/cfunc_unload.jl") -include("FMI2/convert.jl") -include("FMI3/convert.jl") - -include("FMI2/io.jl") -# ToDo: include("FMI3/io.jl") - -include("FMI2/struct.jl") -include("FMI3/struct.jl") - -include("FMI2/eval.jl") -# ToDo: include("FMI3/eval.jl") - -include("jacobian.jl") -include("logging.jl") -include("sense.jl") -include("snapshot.jl") - -# Requires init -function __init__() - @require FMISensitivity="3e748fe5-cd7f-4615-8419-3159287187d2" begin - import .FMISensitivity - include("extensions/FMISensitivity.jl") - end -end - end # module diff --git a/src/error_msg.jl b/src/error_msg.jl deleted file mode 100644 index 3159087..0000000 --- a/src/error_msg.jl +++ /dev/null @@ -1,6 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -const ERR_MSG_CONT_TIME_MODE = "Function must be called in mode continuous time!\nThis is most probably because the FMU errored before. If no messages are printed, check that the FMU message prinintg is enabled (this is tool dependent and must be selected during export) and follow the message printing instructions under https://thummeto.github.io/FMI.jl/dev/features/#Debugging-/-Logging" \ No newline at end of file diff --git a/src/extensions/FMISensitivity.jl b/src/extensions/FMISensitivity.jl deleted file mode 100644 index f9e1f12..0000000 --- a/src/extensions/FMISensitivity.jl +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright (c) 2023 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -import .FMISensitivity.ForwardDiff -import .FMISensitivity.ReverseDiff - -########### - -import .FMISensitivity.SciMLSensitivity.ForwardDiff -import .FMISensitivity.SciMLSensitivity.ReverseDiff - -# check if scalar/vector is ForwardDiff.Dual -function isdual(e::ForwardDiff.Dual{T, V, N}) where {T, V, N} - return true -end -function isdual(e::AbstractVector{<:ForwardDiff.Dual{T, V, N}}) where {T, V, N} - return true -end - -# check if scalar/vector is ForwardDiff.Dual -function istracked(e::ReverseDiff.TrackedReal) - return true -end -function istracked(e::AbstractVector{<:ReverseDiff.TrackedReal}) - return true -end -function istracked(e::ReverseDiff.TrackedArray) - return true -end - -# makes Reals from ForwardDiff.Dual scalar/vector -function undual(e::ForwardDiff.Dual) - return ForwardDiff.value(e) -end - -# makes Reals from ReverseDiff.TrackedXXX scalar/vector -function untrack(e::ReverseDiff.TrackedReal) - return ReverseDiff.value(e) -end -function untrack(e::ReverseDiff.TrackedArray) - return ReverseDiff.value(e) -end - -# makes Reals from ForwardDiff/ReverseDiff.TrackedXXX scalar/vector -function unsense(e::ReverseDiff.TrackedReal) - return ReverseDiff.value(e) -end -function unsense(e::ReverseDiff.TrackedArray) - return ReverseDiff.value(e) -end -function unsense(e::ForwardDiff.Dual) - return ForwardDiff.value(e) -end - -# set sensitive primitives (this is intentionally NO additional dispatch for `setindex!`) -function sense_setindex!(A::Vector{Float64}, x::ForwardDiff.Dual, i::Int64) - return setindex!(A, undual(x), i) -end - -function sense_setindex!(A::Vector{Float64}, x::ReverseDiff.TrackedReal, i::Int64) - return setindex!(A, untrack(x), i) -end - diff --git a/src/jacobian.jl b/src/jacobian.jl deleted file mode 100644 index d5e3dbe..0000000 --- a/src/jacobian.jl +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -function check_invalidate!(vr, jac::Nothing) - return -end - -function invalidate!(jac::Nothing) - return -end - -function uncolor!(jac::Nothing) - return -end - diff --git a/src/logging.jl b/src/logging.jl deleted file mode 100644 index d8bcc0a..0000000 --- a/src/logging.jl +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -function logInfo(component::FMU2Component, message, status::fmi2Status=fmi2StatusOK) - if component.loggingOn == fmi2True - ccall(component.callbackFunctions.logger, - Cvoid, - (fmi2ComponentEnvironment, fmi2String, fmi2Status, fmi2String, fmi2String), - component.callbackFunctions.componentEnvironment, component.instanceName, status, "info", message * "\n") - end -end -function logInfo(::Nothing, message, status::fmi2Status=fmi2StatusOK) - @info "logInfo(nothing, $(message), $(status))" -end - -function logWarning(component::FMU2Component, message, status::fmi2Status=fmi2StatusWarning) - if component.loggingOn == fmi2True - ccall(component.callbackFunctions.logger, - Cvoid, - (fmi2ComponentEnvironment, fmi2String, fmi2Status, fmi2String, fmi2String), - component.callbackFunctions.componentEnvironment, component.instanceName, status, "warning", message * "\n") - end -end -function logWarning(::Nothing, message, status::fmi2Status=fmi2StatusOK) - @warn "logWarning(nothing, $(message), $(status))" -end - -function logError(component::FMU2Component, message, status::fmi2Status=fmi2StatusError) - if component.loggingOn == fmi2True - ccall(component.callbackFunctions.logger, - Cvoid, - (fmi2ComponentEnvironment, fmi2String, fmi2Status, fmi2String, fmi2String), - component.callbackFunctions.componentEnvironment, component.instanceName, status, "error", message * "\n") - end -end -function logError(::Nothing, message, status::fmi2Status=fmi2StatusOK) - @error "logError(nothing, $(message), $(status))" -end \ No newline at end of file diff --git a/src/printing.jl b/src/printing.jl deleted file mode 100644 index 21d6913..0000000 --- a/src/printing.jl +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -""" -Log levels for non-standard printing of infos, warnings and errors. -""" -const FMULogLevel = Cuint -const FMULogLevelNone = Cuint(0) -const FMULogLevelInfo = Cuint(1) -const FMULogLevelWarn = Cuint(2) -const FMULogLevelError = Cuint(3) -export FMULogLevel, FMULogLevelNone, FMULogLevelInfo, FMULogLevelWarn, FMULogLevelError - -""" -Prints a message with level `info` if the log level allows it. -""" -function logInfo(fmu::FMU, message, maxlog=typemax(Int)) - if fmu.logLevel <= FMULogLevelInfo - if maxlog == 1 - message *= "\n(This message is only printed once.)" - @info message maxlog=1 - else - @info message maxlog=maxlog - end - end -end -export logInfo - -""" -Prints a message with level `warn` if the log level allows it. -""" -function logWarning(fmu::FMU, message, maxlog=typemax(Int)) - if fmu.logLevel <= FMULogLevelWarn - if maxlog == 1 - message *= "\n(This message is only printed once.)" - @warn message maxlog=1 - else - @warn message maxlog=maxlog - end - end -end -export logWarning - -""" -Prints a message with level `error` if the log level allows it. -""" -function logError(fmu::FMU, message, maxlog=typemax(Int)) - if fmu.logLevel <= FMULogLevelError - if maxlog == 1 - message *= "\n(This message is only printed once.)" - @error message maxlog=1 - else - @error message maxlog=maxlog - end - end -end -export logError - diff --git a/src/sense.jl b/src/sense.jl deleted file mode 100644 index 285ecb3..0000000 --- a/src/sense.jl +++ /dev/null @@ -1,97 +0,0 @@ -# -# Copyright (c) 2022 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# this file containes placeholders for sensitivity (AD) related functions, -# if FMISensitivity is not loaded, these functions dispatch to neutral statements, -# if FMISensitivity is loaded, these functions are extended. - -# check if scalar/vector is ForwardDiff.Dual -function isdual(e) - return false -end -function isdual(e::Tuple) - return any(isdual.(e)) -end - -# check if scalar/vector is ForwardDiff.Dual -function istracked(e) - return false -end -function istracked(e::Tuple) - return any(istracked.(e)) -end - -# makes Reals from ForwardDiff.Dual scalar/vector -function undual(e::AbstractArray) - return undual.(e) -end -function undual(e::AbstractArray{fmi2Real}) - return e -end -function undual(e::Tuple) - if !isdual(e) - return e - end - return undual.(e) -end -function undual(::Nothing) - return nothing -end -function undual(e) - return e -end - -# makes Reals from ReverseDiff.TrackedXXX scalar/vector -function untrack(e::AbstractArray) - return untrack.(e) -end -function untrack(e::AbstractArray{fmi2Real}) - return e -end -function untrack(e::Tuple) - if !istracked(e) - return e - end - return untrack.(e) -end -function untrack(::Nothing) - return nothing -end -function untrack(e) - return e -end - -# makes Reals from ForwardDiff/ReverseDiff.TrackedXXX scalar/vector -function unsense(e::AbstractArray) - return unsense.(e) -end -function unsense(e::AbstractArray{fmi2Real}) - return e -end -function unsense(e::Tuple) - if !isdual(e) && !istracked(e) - return e - end - return unsense.(e) -end -function unsense(::Nothing) - return nothing -end -function unsense(e) - return e -end - -# makes copied Reals from ForwardDiff/ReverseDiff.TrackedXXX scalar/vector -function unsense_copy(e) - return unsense(e) # inherit, most `unsense` dispatches are allocating anyway -end -function unsense_copy(e::AbstractArray{fmi2Real}) - return copy(e) -end - -# set sensitive primitives (this is intentionally NO additional dispatch for `setindex!`) -function sense_setindex!(A, x, i) - return setindex!(A, x, i) -end diff --git a/src/snapshot.jl b/src/snapshot.jl deleted file mode 100644 index f7a7ae3..0000000 --- a/src/snapshot.jl +++ /dev/null @@ -1,162 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# struct definition is in `src/types.jl` - -function getFMUstate(c::FMU2Component) - state = fmi2FMUstate() - ref = Ref(state) - getFMUstate!(c, ref) - #@info "snap state: $(state)" - return ref[] -end - -function getFMUstate!(c::FMU2Component, state::Ref{fmi2FMUstate}) - if c.fmu.modelDescription.modelExchange.canGetAndSetFMUstate || c.fmu.modelDescription.coSimulation.canGetAndSetFMUstate - return fmi2GetFMUstate!(c.fmu.cGetFMUstate, c.compAddr, state) - end - return nothing -end -function getFMUstate!(c::FMU2Component, s::Ref{Nothing}) - return nothing -end - -function setFMUstate!(c::FMU2Component, state::fmi2FMUstate) - if c.fmu.modelDescription.modelExchange.canGetAndSetFMUstate || c.fmu.modelDescription.coSimulation.canGetAndSetFMUstate - return fmi2SetFMUstate(c.fmu.cSetFMUstate, c.compAddr, state) - end - return nothing -end -function setFMUstate!(c::FMU2Component, state::Nothing) - return nothing -end - -function freeFMUstate!(c::FMU2Component, state::Ref{fmi2FMUstate}) - fmi2FreeFMUstate!(c.fmu.cFreeFMUstate, c.compAddr, state) - return nothing -end -function freeFMUstate!(c::FMU2Component, state::Ref{Nothing}) - return nothing -end - -function snapshot!(c::FMU2Component) - s = FMUSnapshot(c) - return s -end -function snapshot!(sol::FMU2Solution) - s = snapshot!(sol.component) - push!(sol.snapshots, s) - return s -end -export snapshot! - -function snapshot_if_needed!(obj::Union{FMU2Component, FMU2Solution}, t::Real; atol=1e-8) - if !hasSnapshot(obj, t; atol=atol) - snapshot!(obj) - end -end -export snapshot_if_needed! - -function hasSnapshot(c::Union{FMU2Component, FMU2Solution}, t::Float64; atol=0.0) - for snapshot in c.snapshots - if abs(snapshot.t-t) <= atol - return true - end - end - return false -end - -function getSnapshot(c::FMU2Component, t::Float64; kwargs...) - return getSnapshot(c.fmu, t; kwargs...) -end - -function getSnapshot(c::Union{FMU2, FMU2Solution}, t::Float64; exact::Bool=false, atol=0.0) - # [Note] only take exact fit if we are at 0, otherwise take the next left, - # because we are saving snapshots for the right root of events. - - @assert t ∉ (-Inf, Inf) "t = $(t), this is not allowed for snapshot search!" - @assert length(c.snapshots) > 0 "No snapshots available!" - - left = c.snapshots[1] - # right = c.snapshots[1] - - if exact - for snapshot in c.snapshots - if abs(snapshot.t - t) <= atol - return snapshot - end - end - return nothing - else - for snapshot in c.snapshots - if snapshot.t < (t-atol) && snapshot.t > (left.t+atol) - left = snapshot - end - # if snapshot.t > t && snapshot.t < right.t - # right = snapshot - # end - end - end - - return left -end -export getSnapshot - -function update!(c::FMU2Component, s::FMUSnapshot) - s.t = c.t - s.eventInfo = deepcopy(c.eventInfo) - s.state = c.state - s.instance = c - getFMUstate!(c, Ref(s.fmuState)) - # [ToDo] Do a real pull. - s.x_c = isnothing(c.x) ? nothing : copy(c.x) - s.x_d = isnothing(c.x_d) ? nothing : copy(c.x_d) - return nothing -end -export update! - -function apply!(c::FMU2Component, s::FMUSnapshot; - t=s.t, x_c=s.x_c, x_d=s.x_d, fmuState=s.fmuState) - - # FMU state - setFMUstate!(c, fmuState) - c.eventInfo = deepcopy(s.eventInfo) - c.state = s.state - - @debug "Applied snapshot $(s.t)" - - # continuous state - if !isnothing(x_c) - fmi2SetContinuousStates(c.fmu.cSetContinuousStates, c.compAddr, x_c, Csize_t(length(x_c))) - c.x = copy(x_c) - end - - # discrete state - if !isnothing(x_d) - # [ToDo] This works only for real values! - fmi2SetReal(c.fmu.cSetReal, c.compAddr, c.fmu.modelDescription.discreteStateValueReferences, x_d, Csize_t(length(x_d))) - c.x_d = copy(x_d) - end - - # time - fmi2SetTime(c.fmu.cSetTime, c.compAddr, t) - c.t = t - - return nothing -end -export apply! - -function freeSnapshot!(s::FMUSnapshot) - #@async println("cleanup!") - freeFMUstate!(s.instance, Ref(s.fmuState)) - s.fmuState = nothing - - ind = findall(x -> x == s, s.instance.snapshots) - @assert length(ind) == 1 "freeSnapshot!: Freeing $(length(ind)) snapshots with one call, this is not allowed. Target was found $(length(ind)) times at indicies $(ind)." - deleteat!(s.instance.snapshots, ind) - - return nothing -end -export freeSnapshot! \ No newline at end of file diff --git a/src/types.jl b/src/types.jl deleted file mode 100644 index 27b49af..0000000 --- a/src/types.jl +++ /dev/null @@ -1,107 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -""" - - FMU - -The abstract type for FMUs (FMI 2 & 3). -""" -abstract type FMU end -export FMU - -""" - - FMUInstance - -An instance of a FMU. This was called `component` in FMI2, but was corrected to `instance` in FMI3. -""" -abstract type FMUInstance end -export FMUInstance - -""" - - FMUSolution - -The abstract type for a solution generated by simulating an FMU (FMI 2 & 3). -""" -abstract type FMUSolution end -export FMUSolution - -""" - - FMUExecutionConfiguration - -The abstract type for the configuration used to simulate (execute) an FMU (FMI 2 & 3). -""" -abstract type FMUExecutionConfiguration end -export FMUExecutionConfiguration - -""" - - FMUEvent - -The abstract type for an event triggered by a FMU (FMI 2 & 3). -""" -abstract type FMUEvent end -export FMUEvent - -""" - ToDo -""" -mutable struct FMUSnapshot{E, C, D, I, S} - - t::Float64 - eventInfo::E - state::UInt32 - instance::I - fmuState::Union{S, Nothing} - x_c::C - x_d::D - - function FMUSnapshot{E, C, D, I, S}() where {E, C, D, I, S} - inst = new{E, C, D, I, S}() - inst.fmuState = nothing - return inst - end - - function FMUSnapshot(c::FMUInstance) - - t = c.t - eventInfo = deepcopy(c.eventInfo) - state = c.state - instance = c - fmuState = getFMUstate(c) - #x_c = isnothing(c.x ) ? nothing : copy(c.x ) - #x_d = isnothing(c.x_d) ? nothing : copy(c.x_d) - - n_x_c = Csize_t(length(c.fmu.modelDescription.stateValueReferences)) - x_c = zeros(Float64, n_x_c) - fmi2GetContinuousStates!(c.fmu.cGetContinuousStates, c.compAddr, x_c, n_x_c) - x_d = nothing # ToDo - - E = typeof(eventInfo) - C = typeof(x_c) - D = typeof(x_d) - I = typeof(instance) - S = typeof(fmuState) - - inst = new{E, C, D, I, S}(t, eventInfo, state, instance, fmuState, x_c, x_d) - - # if !isnothing(fmuState) - # inst = finalizer((_inst) -> cleanup!(c, _inst), inst) - # end - - push!(c.snapshots, inst) - - return inst - end - -end -export FMUSnapshot - -function Base.show(io::IO, s::FMUSnapshot) - print(io, "FMUSnapshot(t=$(s.t), x_c=$(s.x_c), x_d=$(s.x_d), fmuState=$(s.fmuState))") -end \ No newline at end of file diff --git a/test/eval.jl b/test/eval.jl index 4d6b8b4..2a3b8e4 100644 --- a/test/eval.jl +++ b/test/eval.jl @@ -1,7 +1,12 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + using PkgEval using FMICore -config = Configuration(; julia="1.8"); +config = Configuration(; julia="1.10"); package = Package(; name="FMICore"); diff --git a/test/runtests.jl b/test/runtests.jl index 70c2277..243969a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,10 +6,8 @@ using FMICore using Test -const FMIC = FMICore - @testset "FMICore.jl" begin @testset "FMI2" begin - + # [ToDo] end end \ No newline at end of file