Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
* Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
* c/o Linköpings universitet, Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "OMRuntimeExternalC"
uuid = "ada38df0-e20e-11ed-02f3-2b4b19c1ec8a"
authors = ["Adrian Pop <adrian.pop@liu.se>", "John Tinnerholm <john.tinnerholm@liu.se>"]
version = "0.3.0"
version = "0.3.1"

[deps]
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
Expand Down
239 changes: 220 additions & 19 deletions src/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,19 @@ function ModelicaStandardTables_CombiTable1D_init2(
fileName::String,
tableName::String,
table::Matrix{Float64},
nRow::Int64,
nColumn::Int64,
columns::Vector{Int64},
nCols::Int64,
smoothness::Int64,
extrapolation::Int64,
nRow::Integer,
nColumn::Integer,
columns::AbstractVector{<:Integer},
nCols::Integer,
smoothness::Integer,
extrapolation::Integer,
verbose::Integer)
#= Converts the table into the C format, that is double* =#
local tableCShape = reduce(vcat, [table[j,i] for i in 1:size(table,2), j in 1:size(table,1)])
local columnsCInt = convert(Vector{Cint}, columns)
local res = ccall((:ModelicaStandardTables_CombiTable1D_init2, installedLibPath), Ptr{Cvoid},
(Cstring, Cstring, Ptr{Cdouble}, Csize_t, Csize_t, Ptr{Cint}, Csize_t, Cint, Cint, Cint),
fileName, tableName, tableCShape, nRow, nColumn, columns, nCols, smoothness, extrapolation, verbose)
fileName, tableName, tableCShape, nRow, nColumn, columnsCInt, nCols, smoothness, extrapolation, verbose)
res
end

Expand Down Expand Up @@ -431,21 +432,22 @@ function ModelicaStandardTables_CombiTimeTable_init2(
fileName::String,
tableName::String,
table::Matrix{Float64},
nRow::Int64,
nColumn::Int64,
nRow::Integer,
nColumn::Integer,
startTime::Float64,
columns::Vector{Int64},
nCols::Int64,
smoothness::Int64,
extrapolation::Int64,
columns::AbstractVector{<:Integer},
nCols::Integer,
smoothness::Integer,
extrapolation::Integer,
shiftTime::Float64,
timeEvents::Int64,
timeEvents::Integer,
verbose::Integer)
#= Converts the table into the C format, that is double* =#
local tableCShape = reduce(vcat, [table[j,i] for i in 1:size(table,2), j in 1:size(table,1)])
local columnsCInt = convert(Vector{Cint}, columns)
local res = ccall((:ModelicaStandardTables_CombiTimeTable_init2, installedLibPath), Ptr{Cvoid},
(Cstring, Cstring, Ptr{Cdouble}, Csize_t, Csize_t, Cdouble, Ptr{Cint}, Csize_t, Cint, Cint, Cdouble, Cint, Cint),
fileName, tableName, tableCShape, nRow, nColumn, startTime, columns, nCols, smoothness, extrapolation, shiftTime, timeEvents, verbose)
fileName, tableName, tableCShape, nRow, nColumn, startTime, columnsCInt, nCols, smoothness, extrapolation, shiftTime, timeEvents, verbose)
res
end

Expand Down Expand Up @@ -489,6 +491,30 @@ function ModelicaStandardTables_CombiTimeTable_getValue(
tableID, icol, t, nextTimeEvent, preNextTimeEvent)
end

#= Strip a possibly-AD (ForwardDiff.Dual) Real to its primal Cdouble WITHOUT a
ForwardDiff dependency: a Dual stores its primal in the `value` field, so peel
it recursively until an AbstractFloat (handles nested/higher-order Duals). =#
@inline _orcPrimal(x::AbstractFloat)::Float64 = Float64(x)
@inline _orcPrimal(x::Integer)::Float64 = Float64(x)
@inline _orcPrimal(x::Real)::Float64 = _orcPrimal(getfield(x, :value))

#= AD-safe overload: the DAE consistent-IC nonlinear solve autodiffs the RHS, so
the table getter can be called with Dual args on the event-timing parameters.
The table value depends only on `t` (constant during that solve), so it is
constant w.r.t. the differentiated unknowns (zero derivative). Strip to primals
and return the numeric value; the Float64 return is treated as a constant by
ForwardDiff, which is the correct zero-derivative through the table. =#
function ModelicaStandardTables_CombiTimeTable_getValue(
tableID::ExternalCombiTimeTable,
icol::Integer,
t::Real,
nextTimeEvent::Real,
preNextTimeEvent::Real,
)::Float64
ModelicaStandardTables_CombiTimeTable_getValue(tableID, Int64(icol),
_orcPrimal(t), _orcPrimal(nextTimeEvent), _orcPrimal(preNextTimeEvent))
end

"""
MODELICA_EXPORT double ModelicaStandardTables_CombiTimeTable_getDerValue(void* tableID, int icol,
double t, double nextTimeEvent, double preNextTimeEvent, double der_t);
Expand Down Expand Up @@ -523,6 +549,20 @@ function ModelicaStandardTables_CombiTimeTable_getDerValue(
return res
end

#= AD-safe overload (see CombiTimeTable_getValue): a time-function, constant
w.r.t. the differentiated unknowns; strip any Dual args to primals. =#
function ModelicaStandardTables_CombiTimeTable_getDerValue(
tableID::ExternalCombiTimeTable,
icol::Integer,
t::Real,
nextTimeEvent::Real,
preNextTimeEvent::Real,
der_t::Real,
)
ModelicaStandardTables_CombiTimeTable_getDerValue(tableID, Int64(icol),
_orcPrimal(t), _orcPrimal(nextTimeEvent), _orcPrimal(preNextTimeEvent), _orcPrimal(der_t))
end

"""
MODELICA_EXPORT double ModelicaStandardTables_CombiTimeTable_getDer2Value(void* tableID, int icol,
double t, double nextTimeEvent, double preNextTimeEvent,
Expand Down Expand Up @@ -560,6 +600,21 @@ function ModelicaStandardTables_CombiTimeTable_getDer2Value(
return res
end

#= AD-safe overload (see CombiTimeTable_getValue): a time-function, constant
w.r.t. the differentiated unknowns; strip any Dual args to primals. =#
function ModelicaStandardTables_CombiTimeTable_getDer2Value(
tableID::ExternalCombiTimeTable,
icol::Integer,
t::Real,
nextTimeEvent::Real,
preNextTimeEvent::Real,
der_t::Real,
der2_t::Real,
)
ModelicaStandardTables_CombiTimeTable_getDer2Value(tableID, Int64(icol),
_orcPrimal(t), _orcPrimal(nextTimeEvent), _orcPrimal(preNextTimeEvent), _orcPrimal(der_t), _orcPrimal(der2_t))
end

"""
MODELICA_EXPORT double ModelicaStandardTables_CombiTimeTable_minimumTime(void* tableID);
"""
Expand Down Expand Up @@ -665,10 +720,10 @@ function ModelicaStandardTables_CombiTable2D_init2(
fileName::String,
tableName::String,
table::Matrix{Float64},
nRow::Int64,
nColumn::Int64,
smoothness::Int64,
extrapolation::Int64,
nRow::Integer,
nColumn::Integer,
smoothness::Integer,
extrapolation::Integer,
verbose::Integer)
#= Converts the table into the C format, that is double* =#
local tableCShape = reduce(vcat, [table[j,i] for i in 1:size(table,2), j in 1:size(table,1)])
Expand Down Expand Up @@ -914,6 +969,14 @@ function ModelicaStrings_scanInteger(string::String, startIndex::Int64, unsigned
return (Int64(nextIndex[]), Int64(integerNumber[]))
end

function ModelicaStrings_scanInteger(string::String, startIndex::Integer, unsignedNumber::Integer,
nextIndex::Ref{Cint}, integerNumber::Ref{Cint})
ccall((:ModelicaStrings_scanInteger, installedLibPathlibModelicaExternalC),
Cvoid,
(Cstring, Cint, Cint, Ref{Cint}, Ref{Cint}),
string, Cint(startIndex), Cint(unsignedNumber), nextIndex, integerNumber)
end

"""
MODELICA_EXPORT void ModelicaStrings_scanReal(_In_z_ const char* string, int startIndex,
int unsignedNumber, int* nextIndex, double* number);
Expand Down Expand Up @@ -997,6 +1060,17 @@ function ModelicaIO_readMatrixSizes(fileName::String, matrixName::String)::Vecto
return Int64[dim[1], dim[2]]
end

#= Output-by-reference overload matching the Modelica `external "C"` decl
`ModelicaIO_readMatrixSizes(fileName, matrixName, dim)`. =#
function ModelicaIO_readMatrixSizes(fileName::AbstractString,
matrixName::AbstractString,
dim::AbstractVector)
local res = ModelicaIO_readMatrixSizes(String(fileName), String(matrixName))
dim[1] = res[1]
dim[2] = res[2]
return dim
end

"""
ModelicaIO_readRealMatrix(fileName, matrixName, nrow, ncol, verbose) -> Matrix{Float64}

Expand All @@ -1021,6 +1095,26 @@ function ModelicaIO_readRealMatrix(
return Matrix{Float64}(reshape(buffer, ncol, nrow)')
end

#= Output-by-reference overload matching the Modelica `external "C"` decl
`ModelicaIO_readRealMatrix(fileName, matrixName, matrix, size(matrix,1), size(matrix,2), verbose)`.
`matrix` may arrive as a `Matrix{Cdouble}(nrow,ncol)` (constant dims folded) or as a
degenerate `Cdouble[]` (runtime-sized) — both shapes accept linear `copyto!`. =#
function ModelicaIO_readRealMatrix(fileName::AbstractString,
matrixName::AbstractString,
matrix::AbstractArray,
nrow::Integer,
ncol::Integer,
verbose::Bool = true)
local res = ModelicaIO_readRealMatrix(String(fileName), String(matrixName),
Int64(nrow), Int64(ncol), verbose)
local need = Int(nrow) * Int(ncol)
if matrix isa Vector && length(matrix) != need
resize!(matrix, need)
end
copyto!(matrix, res)
return matrix
end

"""
ModelicaIO_writeRealMatrix(fileName, matrixName, matrix; append, version)

Expand All @@ -1047,6 +1141,16 @@ function ModelicaIO_writeRealMatrix(
return Int64(rc)
end

#= Output-by-reference style overload matching the Modelica `external "C"` decl
`success = ModelicaIO_writeRealMatrix(fileName, matrixName, matrix, size(matrix,1), size(matrix,2), append, format)`.
The redundant nrow/ncol args are derived from `matrix` itself; we accept and ignore them. =#
function ModelicaIO_writeRealMatrix(fileName::AbstractString, matrixName::AbstractString,
matrix::AbstractMatrix, nrow::Integer, ncol::Integer,
append::Bool, version::AbstractString)::Int64
return ModelicaIO_writeRealMatrix(String(fileName), String(matrixName),
Matrix{Float64}(matrix), Bool(append), String(version))
end

#= ---- ModelicaInternal functions (via safe_* wrappers in libModelicaCallbacks) ---- =#

"""
Expand Down Expand Up @@ -1084,6 +1188,21 @@ function ModelicaInternal_readLine(fileName::String, lineNumber::Int64)
return (str, endOfFile[] != 0)
end

#= Output-by-reference overload matching the Modelica `external "C"` decl
`line = ModelicaInternal_readLine(fileName, lineNumber, endOfFile)`. The
third arg is a Ref/Vector slot the C function writes the EOF flag into; we
delegate to the 2-arg form and store the result. =#
function ModelicaInternal_readLine(fileName::AbstractString, lineNumber::Integer,
endOfFile)::String
local (line, isEnd) = ModelicaInternal_readLine(String(fileName), Int64(lineNumber))
if endOfFile isa Ref
endOfFile[] = isEnd ? Cint(1) : Cint(0)
elseif endOfFile isa AbstractArray && !isempty(endOfFile)
endOfFile[1] = isEnd ? Cint(1) : Cint(0)
end
return line
end

"""
ModelicaInternal_countLines(fileName) -> Int64

Expand Down Expand Up @@ -1272,6 +1391,88 @@ function ModelicaRandom_impureRandom_xorshift1024star(id::Integer)::Float64
)
end

#= ---- Modelica.Math.Random.Utilities impure-RNG functions ----
The codegen does not translate these MSL algorithm bodies, so provide them
here (routed via MODELICA_UTILITIES_TO_RUNTIME_C). Faithful to the MSL 3.2.3
sources, built on the ModelicaRandom_* C primitives above. =#

#= Generators.Xorshift64star.initialState(localSeed, globalSeed): seed a length-2
state (a fixed prime replaces an all-zero seed) and iterate 10 times. =#
function _xorshift64starInitialState(localSeed::Integer, globalSeed::Integer)
local state = (localSeed == 0 && globalSeed == 0) ?
Cint[126247697, Cint(globalSeed)] : Cint[Cint(localSeed), Cint(globalSeed)]
local out = Cint[0, 0]
local r = Ref{Cdouble}(0.0)
for _ in 1:10
ModelicaRandom_xorshift64star(state, out, r)
state[1] = out[1]; state[2] = out[2]
end
return state
end

#= Utilities.initialStateWithXorshift64star(localSeed, globalSeed, nState): fill an
nState-length Integer state vector with xorshift64* draws (pairwise). =#
function _initialStateWithXorshift64star(localSeed::Integer, globalSeed::Integer, nState::Integer)
local state = zeros(Cint, nState)
local aux = _xorshift64starInitialState(localSeed, globalSeed)
if nState >= 2
state[1] = aux[1]; state[2] = aux[2]
else
state[1] = aux[1]
end
local nStateEven = 2 * div(nState, 2)
local out = Cint[0, 0]
local r = Ref{Cdouble}(0.0)
local i = 3
while i <= nStateEven
ModelicaRandom_xorshift64star(Cint[state[i-2], state[i-1]], out, r)
state[i] = out[1]; state[i+1] = out[2]
i += 2
end
if nState >= 3 && nState != nStateEven
ModelicaRandom_xorshift64star(Cint[state[nState-2], state[nState-1]], out, r)
state[nState] = out[1]
end
return state
end

"""
Modelica_Math_Random_Utilities_initializeImpureRandom(seed) -> Int

Modelica.Math.Random.Utilities.initializeImpureRandom: seed the impure
xorshift1024* generator's hidden C state from `seed` and return the id
(the constant localSeed) to be passed to impureRandom.
"""
function Modelica_Math_Random_Utilities_initializeImpureRandom(seed::Integer)::Int
local localSeed = 715827883
#= MSL passes localSeed as the local seed and `seed` as the global seed. =#
local rngState = _initialStateWithXorshift64star(localSeed, seed, 33)
local id = localSeed
ModelicaRandom_setInternalState_xorshift1024star(rngState, length(rngState), id)
return id
end

"""
Modelica_Math_Random_Utilities_impureRandom(id) -> Float64

Modelica.Math.Random.Utilities.impureRandom: draw the next impure sample.
"""
Modelica_Math_Random_Utilities_impureRandom(id::Integer)::Float64 =
ModelicaRandom_impureRandom_xorshift1024star(id)

"""
Modelica_Math_Random_Utilities_impureRandomInteger(id, imin, imax) -> Int

Modelica.Math.Random.Utilities.impureRandomInteger: map an impure sample to the
integer range [imin, imax].
"""
function Modelica_Math_Random_Utilities_impureRandomInteger(id::Integer,
imin::Integer = 1,
imax::Integer = 268435456)::Int
local r = ModelicaRandom_impureRandom_xorshift1024star(id)
return min(imax, floor(Int, r * (imax - imin + 1)) + imin)
end

"""
ModelicaRandom_automaticGlobalSeed(dummy) -> Int

Expand Down
Loading
Loading