From 65f79929fcabb04c9b65343b286f84912502d7cd Mon Sep 17 00:00:00 2001 From: JKRT Date: Mon, 11 May 2026 10:14:51 +0200 Subject: [PATCH] Fix matrix read/write update to api --- LICENSE.md | 2 +- Project.toml | 2 +- src/api.jl | 96 ++++++++++++++++++++++++++++++++++++++---------- test/runtests.jl | 37 +++++++++++++++++++ 4 files changed, 116 insertions(+), 21 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 6aa1d87..73c3fa9 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -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. * diff --git a/Project.toml b/Project.toml index 4de8226..b1fae66 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OMRuntimeExternalC" uuid = "ada38df0-e20e-11ed-02f3-2b4b19c1ec8a" authors = ["Adrian Pop ", "John Tinnerholm "] -version = "0.3.0" +version = "0.3.1" [deps] CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" diff --git a/src/api.jl b/src/api.jl index 5028ab0..aa6787d 100644 --- a/src/api.jl +++ b/src/api.jl @@ -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 @@ -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 @@ -665,10 +667,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)]) @@ -997,6 +999,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} @@ -1021,6 +1034,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) @@ -1047,6 +1080,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) ---- =# """ @@ -1084,6 +1127,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 diff --git a/test/runtests.jl b/test/runtests.jl index e8e0d81..4f028ef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -366,6 +366,43 @@ const ORC = OMRuntimeExternalC rm(f, force=true) end + @testset "readMatrixSizes output-by-reference overload" begin + local dim = zeros(Cint, 2) + local ret = ORC.ModelicaIO_readMatrixSizes(testMatFile, "testMatrix", dim) + @test dim == Cint[2, 3] + @test ret === dim + end + + @testset "readRealMatrix output-by-reference overload (Matrix buffer)" begin + local buf = zeros(Cdouble, 2, 3) + local ret = ORC.ModelicaIO_readRealMatrix(testMatFile, "testMatrix", buf, 2, 3) + @test ret === buf + @test isapprox(buf[1, 1], 1.0, atol=1e-10) + @test isapprox(buf[1, 3], 3.0, atol=1e-10) + @test isapprox(buf[2, 2], 5.0, atol=1e-10) + @test isapprox(buf[2, 3], 6.0, atol=1e-10) + end + + @testset "readRealMatrix output-by-reference overload (Vector fallback)" begin + local buf = Cdouble[] + local ret = ORC.ModelicaIO_readRealMatrix(testMatFile, "testMatrix", buf, 2, 3) + @test ret === buf + @test length(buf) == 6 + @test isapprox(buf[1], 1.0, atol=1e-10) + @test isapprox(buf[6], 6.0, atol=1e-10) + end + + @testset "writeRealMatrix Modelica external arg-shape overload" begin + local f = tempname() * ".mat" + local A = [11.0 12.0; 21.0 22.0; 31.0 32.0] + local rc = ORC.ModelicaIO_writeRealMatrix(f, "Matrix_A", A, 3, 2, false, "4") + @test rc == 1 + @test isfile(f) + local dims = ORC.ModelicaIO_readMatrixSizes(f, "Matrix_A") + @test dims == [3, 2] + rm(f, force=true) + end + rm(testMatFile, force=true) end