Unverified Commit 744310aa authored by Laurent Heirendt's avatar Laurent Heirendt Committed by GitHub
Browse files

Merge pull request #24 from LCSB-BioCore/mk-metadata

load more useful metadata
parents 54a9390e e662b218
name = "SBML" name = "SBML"
uuid = "e5567a89-2604-4b09-9718-f5f78e97c3bb" uuid = "e5567a89-2604-4b09-9718-f5f78e97c3bb"
authors = ["Mirek Kratochvil <miroslav.kratochvil@uni.lu>", "LCSB R3 team <lcsb-r3@uni.lu>"] authors = ["Mirek Kratochvil <miroslav.kratochvil@uni.lu>", "LCSB R3 team <lcsb-r3@uni.lu>"]
version = "0.2.0" version = "0.3.0"
[deps] [deps]
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
......
...@@ -11,6 +11,6 @@ include("utils.jl") ...@@ -11,6 +11,6 @@ include("utils.jl")
sbml = (sym::Symbol) -> dlsym(SBML_jll.libsbml_handle, sym) sbml = (sym::Symbol) -> dlsym(SBML_jll.libsbml_handle, sym)
export SBMLVersion, export SBMLVersion,
readSBML, Model, UnitPart, Species, Reaction, getS, getLBs, getUBs, getOCs readSBML, Model, Maybe, UnitPart, Species, Reaction, getS, getLBs, getUBs, getOCs
end # module end # module
...@@ -31,9 +31,36 @@ function readSBML(fn::String)::Model ...@@ -31,9 +31,36 @@ function readSBML(fn::String)::Model
end end
end end
"""
function getOptionalString(x::VPtr, fn_sym)::Maybe{String}
C-call the SBML function `fn_sym` with a single parameter `x`, interpret the result as a nullable string pointer and return appropriately.
This is used to get notes and annotations and several other things (see `getNotes`, `getAnnotations`)
"""
function getOptionalString(x::VPtr, fn_sym)::Maybe{String}
str = ccall(sbml(fn_sym), Cstring, (VPtr,), x)
if str != C_NULL
return unsafe_string(str)
else
return nothing
end
end
getNotes(x::VPtr)::Maybe{String} = getOptionalString(x, :SBase_getNotesString)
getAnnotation(x::VPtr)::Maybe{String} = getOptionalString(x, :SBase_getAnnotationString)
"""
function extractModel(mdl::VPtr)::Model
Take the `SBMLModel_t` pointer and extract all information required to make a
valid [`Model`](@ref) structure.
"""
function extractModel(mdl::VPtr)::Model function extractModel(mdl::VPtr)::Model
# get the FBC plugin pointer (FbcModelPlugin_t)
mdl_fbc = ccall(sbml(:SBase_getPlugin), VPtr, (VPtr, Cstring), mdl, "fbc") mdl_fbc = ccall(sbml(:SBase_getPlugin), VPtr, (VPtr, Cstring), mdl, "fbc")
# get the parameters
parameters = Dict{String,Float64}() parameters = Dict{String,Float64}()
for i = 1:ccall(sbml(:Model_getNumParameters), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumParameters), Cuint, (VPtr,), mdl)
p = ccall(sbml(:Model_getParameter), VPtr, (VPtr, Cuint), mdl, i - 1) p = ccall(sbml(:Model_getParameter), VPtr, (VPtr, Cuint), mdl, i - 1)
...@@ -42,6 +69,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -42,6 +69,7 @@ function extractModel(mdl::VPtr)::Model
parameters[id] = v parameters[id] = v
end end
# parse out the unit definitions
units = Dict{String,Vector{UnitPart}}() units = Dict{String,Vector{UnitPart}}()
for i = 1:ccall(sbml(:Model_getNumUnitDefinitions), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumUnitDefinitions), Cuint, (VPtr,), mdl)
ud = ccall(sbml(:Model_getUnitDefinition), VPtr, (VPtr, Cuint), mdl, i - 1) ud = ccall(sbml(:Model_getUnitDefinition), VPtr, (VPtr, Cuint), mdl, i - 1)
...@@ -66,6 +94,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -66,6 +94,7 @@ function extractModel(mdl::VPtr)::Model
] ]
end end
# parse out compartment names
compartments = [ compartments = [
unsafe_string( unsafe_string(
ccall( ccall(
...@@ -77,15 +106,42 @@ function extractModel(mdl::VPtr)::Model ...@@ -77,15 +106,42 @@ function extractModel(mdl::VPtr)::Model
) for i = 1:ccall(sbml(:Model_getNumCompartments), Cuint, (VPtr,), mdl) ) for i = 1:ccall(sbml(:Model_getNumCompartments), Cuint, (VPtr,), mdl)
] ]
# parse out species
species = Dict{String,Species}() species = Dict{String,Species}()
for i = 1:ccall(sbml(:Model_getNumSpecies), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumSpecies), Cuint, (VPtr,), mdl)
sp = ccall(sbml(:Model_getSpecies), VPtr, (VPtr, Cuint), mdl, i - 1) sp = ccall(sbml(:Model_getSpecies), VPtr, (VPtr, Cuint), mdl, i - 1)
sp_fbc = ccall(sbml(:SBase_getPlugin), VPtr, (VPtr, Cstring), sp, "fbc") # FbcSpeciesPlugin_t
formula = nothing
charge = nothing
if sp_fbc != C_NULL
# if the FBC plugin is present, try to get the chemical formula and charge
if 0 !=
ccall(sbml(:FbcSpeciesPlugin_isSetChemicalFormula), Cint, (VPtr,), sp_fbc)
formula = unsafe_string(
ccall(
sbml(:FbcSpeciesPlugin_getChemicalFormula),
Cstring,
(VPtr,),
sp_fbc,
),
)
end
if 0 != ccall(sbml(:FbcSpeciesPlugin_isSetCharge), Cint, (VPtr,), sp_fbc)
charge = ccall(sbml(:FbcSpeciesPlugin_getCharge), Cint, (VPtr,), sp_fbc)
end
end
species[unsafe_string(ccall(sbml(:Species_getId), Cstring, (VPtr,), sp))] = Species( 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_getName), Cstring, (VPtr,), sp)),
unsafe_string(ccall(sbml(:Species_getCompartment), Cstring, (VPtr,), sp)), unsafe_string(ccall(sbml(:Species_getCompartment), Cstring, (VPtr,), sp)),
formula,
charge,
getNotes(sp),
getAnnotation(sp),
) )
end end
# parse out the flux objectives (these are complementary to the objectives
# that appear in the reactions, see comments lower)
objectives_fbc = Dict{String,Float64}() objectives_fbc = Dict{String,Float64}()
if mdl_fbc != C_NULL if mdl_fbc != C_NULL
for i = 1:ccall(sbml(:FbcModelPlugin_getNumObjectives), Cuint, (VPtr,), mdl_fbc) for i = 1:ccall(sbml(:FbcModelPlugin_getNumObjectives), Cuint, (VPtr,), mdl_fbc)
...@@ -96,7 +152,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -96,7 +152,7 @@ function extractModel(mdl::VPtr)::Model
mdl_fbc, mdl_fbc,
i - 1, i - 1,
) )
# this part seems missing in C API docs...
for j = 1:ccall(sbml(:Objective_getNumFluxObjectives), Cuint, (VPtr,), o) for j = 1:ccall(sbml(:Objective_getNumFluxObjectives), Cuint, (VPtr,), o)
fo = ccall(sbml(:Objective_getFluxObjective), VPtr, (VPtr, Cuint), o, j - 1) fo = ccall(sbml(:Objective_getFluxObjective), VPtr, (VPtr, Cuint), o, j - 1)
objectives_fbc[unsafe_string( objectives_fbc[unsafe_string(
...@@ -106,13 +162,15 @@ function extractModel(mdl::VPtr)::Model ...@@ -106,13 +162,15 @@ function extractModel(mdl::VPtr)::Model
end end
end end
# reactions!
reactions = Dict{String,Reaction}() reactions = Dict{String,Reaction}()
for i = 1:ccall(sbml(:Model_getNumReactions), Cuint, (VPtr,), mdl) for i = 1:ccall(sbml(:Model_getNumReactions), Cuint, (VPtr,), mdl)
re = ccall(sbml(:Model_getReaction), VPtr, (VPtr, Cuint), mdl, i - 1) re = ccall(sbml(:Model_getReaction), VPtr, (VPtr, Cuint), mdl, i - 1)
lb = (-Inf, "") lb = (-Inf, "") # (bound value, unit id)
ub = (Inf, "") ub = (Inf, "")
oc = 0.0 oc = 0.0
# kinetic laws store a second version of the bounds and objectives
kl = ccall(sbml(:Reaction_getKineticLaw), VPtr, (VPtr,), re) kl = ccall(sbml(:Reaction_getKineticLaw), VPtr, (VPtr,), re)
if kl != C_NULL if kl != C_NULL
for j = 1:ccall(sbml(:KineticLaw_getNumParameters), Cuint, (VPtr,), kl) for j = 1:ccall(sbml(:KineticLaw_getNumParameters), Cuint, (VPtr,), kl)
...@@ -152,6 +210,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -152,6 +210,7 @@ function extractModel(mdl::VPtr)::Model
end end
end end
# extract stoichiometry
stoi = Dict{String,Float64}() stoi = Dict{String,Float64}()
add_stoi = add_stoi =
(sr, factor) -> (sr, factor) ->
...@@ -161,6 +220,7 @@ function extractModel(mdl::VPtr)::Model ...@@ -161,6 +220,7 @@ function extractModel(mdl::VPtr)::Model
ccall(sbml(:SpeciesReference_getStoichiometry), Cdouble, (VPtr,), sr) * ccall(sbml(:SpeciesReference_getStoichiometry), Cdouble, (VPtr,), sr) *
factor factor
# reactants and products
for j = 1:ccall(sbml(:Reaction_getNumReactants), Cuint, (VPtr,), re) for j = 1:ccall(sbml(:Reaction_getNumReactants), Cuint, (VPtr,), re)
sr = ccall(sbml(:Reaction_getReactant), VPtr, (VPtr, Cuint), re, j - 1) sr = ccall(sbml(:Reaction_getReactant), VPtr, (VPtr, Cuint), re, j - 1)
add_stoi(sr, -1) add_stoi(sr, -1)
...@@ -172,9 +232,49 @@ function extractModel(mdl::VPtr)::Model ...@@ -172,9 +232,49 @@ function extractModel(mdl::VPtr)::Model
end end
reid = unsafe_string(ccall(sbml(:Reaction_getId), Cstring, (VPtr,), re)) reid = unsafe_string(ccall(sbml(:Reaction_getId), Cstring, (VPtr,), re))
reactions[reid] = reactions[reid] = Reaction(
Reaction(stoi, lb, ub, haskey(objectives_fbc, reid) ? objectives_fbc[reid] : oc) stoi,
lb,
ub,
haskey(objectives_fbc, reid) ? objectives_fbc[reid] : oc,
getNotes(re),
getAnnotation(re),
)
end
# extract gene products
gene_products = Dict{String,GeneProduct}()
if mdl_fbc != C_NULL
for i = 1:ccall(sbml(:FbcModelPlugin_getNumGeneProducts), Cuint, (VPtr,), mdl_fbc)
gp = ccall(
sbml(:FbcModelPlugin_getGeneProduct),
VPtr,
(VPtr, Cuint),
mdl_fbc,
i - 1,
)
id = getOptionalString(gp, :GeneProduct_getId) # IDs don't need to be set
if id != nothing
gene_products[id] = GeneProduct(
getOptionalString(gp, :GeneProduct_getName),
getOptionalString(gp, :GeneProduct_getLabel),
getNotes(gp),
getAnnotation(gp),
)
end
end
end end
return Model(parameters, units, compartments, species, reactions) return Model(
parameters,
units,
compartments,
species,
reactions,
gene_products,
getNotes(mdl),
getAnnotation(mdl),
)
end end
"""
Maybe{X}
Type shortcut for "`X` or nothing" or "nullable `X`" in javaspeak. Name
got inspired by our functional friends.
"""
const Maybe{X} = Union{Nothing,X}
""" """
Part of a measurement unit definition that corresponds to the SBML definition Part of a measurement unit definition that corresponds to the SBML definition
of `Unit`. For example, the unit "per square megahour", Mh^(-2), is written as: of `Unit`. For example, the unit "per square megahour", Mh^(-2), is written as:
...@@ -24,36 +32,58 @@ end ...@@ -24,36 +32,58 @@ end
Reaction with stoichiometry that assigns reactants and products their relative Reaction with stoichiometry that assigns reactants and products their relative
consumption/production rates (accessible in field `stoichiometry`), lower/upper consumption/production rates (accessible in field `stoichiometry`), lower/upper
bounds (in tuples `lb` and `ub`, with unit names), and objective coefficient bounds (in tuples `lb` and `ub`, with unit names), and objective coefficient
(`oc`). (`oc`). Also may contains `notes` and `annotation`.
""" """
struct Reaction struct Reaction
stoichiometry::Dict{String,Float64} stoichiometry::Dict{String,Float64}
lb::Tuple{Float64,String} lb::Tuple{Float64,String}
ub::Tuple{Float64,String} ub::Tuple{Float64,String}
oc::Float64 oc::Float64
Reaction(s, l, u, o) = new(s, l, u, o) notes::Maybe{String}
annotation::Maybe{String}
Reaction(s, l, u, o, n = nothing, a = nothing) = new(s, l, u, o, n, a)
end end
""" """
Species metadata -- contains a human-readable `name`, and a `compartment` Species metadata -- contains a human-readable `name`, a `compartment`
identifier identifier, `formula`, `charge`, and additional `notes` and `annotation`.
""" """
struct Species struct Species
name::String name::String
compartment::String compartment::String
Species(n, c) = new(n, c) formula::Maybe{String}
charge::Maybe{Int}
notes::Maybe{String}
annotation::Maybe{String}
Species(na, co, f, ch, no = nothing, a = nothing) = new(na, co, f, ch, no, a)
end
"""
Gene product metadata.
"""
struct GeneProduct
name::Maybe{String}
label::Maybe{String}
notes::Maybe{String}
annotation::Maybe{String}
GeneProduct(na, l, no = nothing, a = nothing) = new(na, l, no, a)
end end
""" """
Structure that collects the model-related data. Contains `units`, Structure that collects the model-related data. Contains `parameters`, `units`,
`compartments`, `species` and `reactions`. The contained dictionaries are `compartments`, `species` and `reactions` and `gene_products`, and additional
indexed by identifiers of the corresponding objects. `notes` and `annotation` (also present internally in some of the data fields).
The contained dictionaries are indexed by identifiers of the corresponding
objects.
""" """
struct Model struct Model
params::Dict{String,Float64} parameters::Dict{String,Float64}
units::Dict{String,Vector{UnitPart}} units::Dict{String,Vector{UnitPart}}
compartments::Vector{String} compartments::Vector{String}
species::Dict{String,Species} species::Dict{String,Species}
reactions::Dict{String,Reaction} reactions::Dict{String,Reaction}
Model(p, u, c, s, r) = new(p, u, c, s, r) gene_products::Dict{String,GeneProduct}
notes::Maybe{String}
annotation::Maybe{String}
Model(p, u, c, s, r, g, n = nothing, a = nothing) = new(p, u, c, s, r, g, n, a)
end 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