Commit b2f9bb7a authored by Miroslav Kratochvil's avatar Miroslav Kratochvil
Browse files

reimplement the CxxWrapped glue library in Julia ccalls

parent 44888233
......@@ -4,5 +4,6 @@ authors = ["Mirek Kratochvil <exa.exa@gmail.com>"]
version = "0.1.0"
[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
SBML_jll = "bb12108a-f4ef-5f88-8ef3-0b33ff7017f1"
module SBML
using CxxWrap
using ReadSBML_jll
function __init__()
@initcxx
end
@wrapmodule(libreadsbml)
using SBML_jll, Libdl, Pkg
include("structs.jl")
include("version.jl")
include("readsbml.jl")
include("utils.jl")
sbml = (sym::Symbol) -> dlsym(SBML_jll.libsbml_handle, sym)
export getLibSBMLDottedVersion,
readSBML,
Model,
UnitPart,
Species,
Reaction,
getS,
getLBs,
getUBs,
getOCs
export SBMLVersion,
readSBML, Model, UnitPart, Species, Reaction, getS, getLBs, getUBs, getOCs
end # module
struct UnitPart
kind :: String
exponent :: Int
scale :: Int
multiplier :: Float64
UnitPart(k,e,s,m) = new(k,e,s,m)
end
const VPtr = Ptr{Cvoid}
struct Reaction
stoichiometry :: Dict{String, Float64}
lb :: Tuple{Float64, String}
ub :: Tuple{Float64, String}
oc :: Float64
Reaction(s,l,u,o) = new(s,l,u,o)
end
function readSBML(fn::String)::Model
doc = ccall(sbml(:readSBML), VPtr, (Cstring,), fn)
try
n_errs = ccall(sbml(:SBMLDocument_getNumErrors), Cuint, (VPtr,), doc)
if n_errs > 0
@error "SBML loading failed"
throw(:IOError)
end
struct Species
name :: String
compartment :: String
Species(n,c) = new(n,c)
end
if 0 == ccall(sbml(:SBMLDocument_isSetModel), Cint, (VPtr,), doc)
@error "SBML document does not contain a model"
throw(:ValueError)
end
struct Model
units :: Dict{String,Vector{UnitPart}}
compartments :: Vector{String}
species :: Dict{String,Species}
reactions :: Dict{String, Reaction}
Model(u,c,s,r) = new(u,c,s,r)
end
model = ccall(sbml(:SBMLDocument_getModel), VPtr, (VPtr,), doc)
function readSBML(fn::String)::Model
mi = readSBML_internal(fn)
if length(errors(mi))>0
@error "Loading failed!" errors(mi)
return extractModel(model)
finally
ccall(sbml(:SBMLDocument_free), Nothing, (VPtr,), doc)
end
end
us = Dict{String, Vector{UnitPart}}()
for u in units(mi)
us[unit(u)]=Vector{UnitPart}()
end
for u in units(mi)
push!(us[unit(u)], UnitPart(kind(u), exponent(u), scale(u), multiplier(u)))
function extractModel(mdl::VPtr)::Model
units = Dict{String,Vector{UnitPart}}()
for i = 0:ccall(sbml(:Model_getNumUnitDefinitions), Cuint, (VPtr,), mdl)-1
ud = ccall(sbml(:Model_getUnitDefinition), VPtr, (VPtr, Cuint), mdl, i)
id = unsafe_string(ccall(sbml(:UnitDefinition_getId), Cstring, (VPtr,), ud))
units[id] = [
begin
u = ccall(sbml(:UnitDefinition_getUnit), VPtr, (VPtr, Cuint), ud, j)
UnitPart(
unsafe_string(
ccall(
sbml(:UnitKind_toString),
Cstring,
(Cint,),
ccall(sbml(:Unit_getKind), Cint, (VPtr,), u),
),
),
ccall(sbml(:Unit_getExponent), Cint, (VPtr,), u),
ccall(sbml(:Unit_getScale), Cint, (VPtr,), u),
ccall(sbml(:Unit_getMultiplier), Cdouble, (VPtr,), u),
)
end for j = 0:ccall(sbml(:UnitDefinition_getNumUnits), Cuint, (VPtr,), ud)-1
]
end
ss = Dict{String, Species}()
for s in species(mi)
ss[id(s)] = Species(name(s), compartment(s))
compartments = [
unsafe_string(
ccall(
sbml(:Compartment_getId),
Cstring,
(VPtr,),
ccall(sbml(:Model_getCompartment), VPtr, (VPtr, Cuint), mdl, i),
),
) for i = 0:ccall(sbml(:Model_getNumCompartments), Cuint, (VPtr,), mdl)-1
]
species = Dict{String,Species}()
for i = 0:ccall(sbml(:Model_getNumSpecies), Cuint, (VPtr,), mdl)-1
sp = ccall(sbml(:Model_getSpecies), VPtr, (VPtr, Cuint), mdl, i)
species[unsafe_string(ccall(sbml(:Species_getId), Cstring, (VPtr,), sp))] = Species(
unsafe_string(ccall(sbml(:Species_getName), Cstring, (VPtr,), sp)),
unsafe_string(ccall(sbml(:Species_getCompartment), Cstring, (VPtr,), sp)),
)
end
rs = Dict{String, Reaction}()
for r in reactions(mi)
sts = Dict{String, Float64}()
for s in species(r)
sts[id(s)] = stoichiometry(s)
reactions = Dict{String,Reaction}()
for i = 0:ccall(sbml(:Model_getNumReactions), Cuint, (VPtr,), mdl)-1
re = ccall(sbml(:Model_getReaction), VPtr, (VPtr, Cuint), mdl, i)
kl = ccall(sbml(:Reaction_getKineticLaw), VPtr, (VPtr,), re)
lb = (-Inf, "")
ub = (Inf, "")
oc = 0.0
for j = 0:ccall(sbml(:KineticLaw_getNumParameters), Cuint, (VPtr,), kl)-1
p = ccall(sbml(:KineticLaw_getParameter), VPtr, (VPtr, Cuint), kl, j)
id = unsafe_string(ccall(sbml(:Parameter_getId), Cstring, (VPtr,), p))
pval = () -> ccall(sbml(:Parameter_getValue), Cdouble, (VPtr,), p)
punit =
() -> unsafe_string(ccall(sbml(:Parameter_getUnits), Cstring, (VPtr,), p))
if id == "LOWER_BOUND"
lb = (pval(), punit())
elseif id == "UPPER_BOUND"
ub = (pval(), punit())
elseif id == "OBJECTIVE_COEFFICIENT"
oc = pval()
end
end
rs[id(r)] = Reaction(sts, lb(r), ub(r), oc(r))
end
return Model(us, compartments(mi), ss, rs)
end
stoi = Dict{String,Float64}()
add_stoi =
(sr, factor) ->
stoi[unsafe_string(
ccall(sbml(:SpeciesReference_getSpecies), Cstring, (VPtr,), sr),
)] =
ccall(sbml(:SpeciesReference_getStoichiometry), Cdouble, (VPtr,), sr) *
factor
#TODO this needs a sparse version and faster row ID lookup
function getS(m::Model)::Tuple{Vector{String}, Vector{String}, Matrix{Float64}}
rows = [k for k in keys(m.species)] #TODO this too
cols = [k for k in keys(m.reactions)]
S = zeros(Float64, length(rows), length(cols))
for ri in 1:length(cols)
stoi = m.reactions[cols[ri]].stoichiometry
S[indexin(keys(stoi), rows), ri] .= values(stoi)
end
return rows, cols, S
end
for j = 0:ccall(sbml(:Reaction_getNumReactants), Cuint, (VPtr,), re)-1
sr = ccall(sbml(:Reaction_getReactant), VPtr, (VPtr, Cuint), re, j)
add_stoi(sr, -1)
end
function getLBs(m::Model)::Vector{Tuple{Float64,String}}
return broadcast(x -> x.lb, values(m.reactions))
end
for j = 0:ccall(sbml(:Reaction_getNumProducts), Cuint, (VPtr,), re)-1
sr = ccall(sbml(:Reaction_getProduct), VPtr, (VPtr, Cuint), re, j)
add_stoi(sr, 1)
end
function getUBs(m::Model)::Vector{Tuple{Float64,String}}
return broadcast(x -> x.ub, values(m.reactions))
end
reactions[unsafe_string(ccall(sbml(:Reaction_getId), Cstring, (VPtr,), re))] =
Reaction(stoi, lb, ub, oc)
end
function getOCs(m::Model)::Vector{Float64}
return broadcast(x -> x.oc, values(m.reactions))
return Model(units, compartments, species, reactions)
end
struct UnitPart
kind::String
exponent::Int
scale::Int
multiplier::Float64
UnitPart(k, e, s, m) = new(k, e, s, m)
end
struct Reaction
stoichiometry::Dict{String,Float64}
lb::Tuple{Float64,String}
ub::Tuple{Float64,String}
oc::Float64
Reaction(s, l, u, o) = new(s, l, u, o)
end
struct Species
name::String
compartment::String
Species(n, c) = new(n, c)
end
struct Model
units::Dict{String,Vector{UnitPart}}
compartments::Vector{String}
species::Dict{String,Species}
reactions::Dict{String,Reaction}
Model(u, c, s, r) = new(u, c, s, r)
end
#TODO this will need a sparse version and faster row ID lookup
function getS(m::Model)::Tuple{Vector{String},Vector{String},Matrix{Float64}}
rows = [k for k in keys(m.species)] #TODO this too
cols = [k for k in keys(m.reactions)]
S = zeros(Float64, length(rows), length(cols))
for ri = 1:length(cols)
stoi = m.reactions[cols[ri]].stoichiometry
S[indexin(keys(stoi), rows), ri] .= values(stoi)
end
return rows, cols, S
end
function getLBs(m::Model)::Vector{Tuple{Float64,String}}
return broadcast(x -> x.lb, values(m.reactions))
end
function getUBs(m::Model)::Vector{Tuple{Float64,String}}
return broadcast(x -> x.ub, values(m.reactions))
end
function getOCs(m::Model)::Vector{Float64}
return broadcast(x -> x.oc, values(m.reactions))
end
function SBMLVersion()
VersionNumber(unsafe_string(ccall(sbml(:getLibSBMLDottedVersion), Cstring, ())))
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment