diff --git a/Project.toml b/Project.toml index 37fbf09..ff375d7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MATFBCModels" uuid = "bd2e13bf-42c0-49e1-9a9c-885d36daf88b" authors = ["The authors of MATFBCModels.jl"] -version = "0.2.0" +version = "1.0.0" [deps] AbstractFBCModels = "5a4f3dfa-1789-40f8-8221-69268c29937c" diff --git a/src/constants.jl b/src/constants.jl index b8d53df..f431289 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -33,6 +33,10 @@ metabolite_formulas = ["metFormula", "metFormulas"] metabolite_charges = ["metCharge", "metCharges"] +metabolite_compartments = ["metCompartment", "metCompartments", "metComp", "metComps"] + +metabolite_compartment_tables = ["comps", "compNames"] + reaction_names = ["rxnNames"] metabolite_names = ["metNames"] diff --git a/src/interface.jl b/src/interface.jl index 9e2c5d7..f319879 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -108,7 +108,17 @@ function A.metabolite_charge(m::MATFBCModel, mid::String) parse_charge(m.mat[guesskeys(:metabolite_charges, m)][idx]) end -A.metabolite_compartment(m::MATFBCModel, mid::String) = nothing +function A.metabolite_compartment(m::MATFBCModel, mid::String)::Union{Nothing,String} + comp_key = guesskeys_maybe(:metabolite_compartments, m) + isnothing(comp_key) && return nothing + res = m.mat[comp_key][findfirst(==(mid), A.metabolites(m))] + # now, if the metabolite is an integer or a (very integerish) float, it is an + # index to a table of metabolite names (such as in the yeast GEM) + typeof(res) <: Real || return parse_compartment(res) + ct_key = guesskeys_maybe(:metabolite_compartment_tables, m) + isnothing(ct_key) && return nothing + return parse_compartment(m.mat[ct_key][Int(res)]) +end function A.reaction_stoichiometry(m::MATFBCModel, rid::String) ridx = first(indexin([rid], m.mat[guesskeys(:reactions, m)]))[1] # get the index out of the cartesian index @@ -178,7 +188,12 @@ function Base.convert(::Type{MATFBCModel}, m::A.AbstractFBCModel) ], "metFormulas" => [unparse_formula(A.metabolite_formula(m, mid)) for mid in A.metabolites(m)], - "metCharges" => [A.metabolite_charge(m, mid) for mid in A.metabolites(m)], + "metCharges" => + [unparse_charge(A.metabolite_charge(m, mid)) for mid in A.metabolites(m)], + "metCompartments" => [ + unparse_compartment(A.metabolite_compartment(m, mid)) for + mid in A.metabolites(m) + ], ), ) end diff --git a/src/utils.jl b/src/utils.jl index 1b3a005..a6e093e 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,5 +1,18 @@ -guesskeys(id, model) = first(intersect(keys(model.mat), getfield(key_names, id))) +guesskeys_maybe(id, model) = + let keys = [k for k in getfield(key_names, id) if k in keys(model.mat)] + isempty(keys) ? nothing : first(keys) + end + +guesskeys(id, model) = + let key = guesskeys_maybe(id, model) + isnothing(key) ? throw(KeyError, "no applicable model key found for $id") : key + end + +function parse_compartment(x::String) + isempty(x) && return nothing + return x +end function parse_formula(x::Maybe{String}) isnothing(x) && return nothing @@ -15,20 +28,26 @@ end function parse_charge(x)::Maybe{Int} if isa(x, Int) - x + return x elseif isa(x, Float64) - Int(x) + return isnan(x) ? nothing : Int(x) elseif isa(x, String) - Int(parse(Float64, x)) + return Int(parse(Float64, x)) elseif isnothing(x) - nothing + return nothing else throw(DomainError(x, "cannot parse charge")) end end +unparse_compartment(::Nothing) = "" +unparse_compartment(x::String) = x + function unparse_formula(x::Maybe{A.MetaboliteFormula}) isnothing(x) && return nothing ks = sort(collect(keys(x))) join(k * string(x[k]) for k in ks) end + +unparse_charge(::Nothing) = NaN +unparse_charge(x::Int) = float(x) diff --git a/test/runtests.jl b/test/runtests.jl index 8c837f3..b781a58 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -29,6 +29,12 @@ import SparseArrays "223db0b1ed69a7cc782f2a3093c1f48911a3c8bbd5bdf4bcdb13185cab5fdaa0", true, ), + ( + "yeast-GEM", + "https://github.com/SysBioChalmers/yeast-GEM/raw/v8.6.2/model/yeast-GEM.mat", + "c2587e258501737e0141cd47e0f854a60a47faee2d4c6ad582a00e437676b181", + true, + ), ] path = joinpath(modeldir, "$name.mat") A.download_data_file(url, path, hash)