Unverified Commit 10481422 authored by St. Elmo's avatar St. Elmo
Browse files

added generic interface

parent 3980cbbf
......@@ -21,6 +21,7 @@ MAT = "23992714-dd62-5051-b70f-ba57cb901cac"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
OSQP = "ab2f91bb-94b4-55e3-9ba0-7f65df51de79"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
......@@ -34,6 +35,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Tulip = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa"
[compat]
julia = "1"
DistributedData = ">=0.1.3"
SBML = ">=0.4"
julia = "1"
......@@ -16,6 +16,7 @@ using Measurements
using Statistics
using Random
using MacroTools # for DSL :)
using OrderedCollections
import Base: findfirst, getindex, show
import Pkg
......
"""
StandardModel struct of a constraint based metabolic model.
`StandardModel` is used to store a constraint based metabolic model with meta-information.
Meta-information is defined as annotation details, which include gene-reaction-rules, formulas, etc.
This model type seeks to keep as much meta-information as possible.
When merging models and keeping meta-information is important, use this as the output type.
If meta-information is not important, use the more efficient core model types.
See [`CoreModel`](@ref) and [`CoreModelCoupled`](@ref) for comparison.
In this model, reactions, metabolites, and genes are stored in dictionaries indexed by each structs `id` field.
For example, `model.reactions["rxn1_id"]` returns a `Reaction` with index `rxn1_id`.
This makes adding and removing reactions efficient.
However, note that the stoichiometric matrix (or any other core data, e.g. flux bounds) is not stored directly.
When this model type is used in analysis functions, these core data structures are built from scratch.
This can cause performance issues if you run many small analysis functions sequentially.
Consider using the core model types if performance is critical.
See also: [`Reaction`](@ref), [`Metabolite`](@ref), [`Gene`](@ref)
# Fields
````
id :: String
reactions :: Vector{Reaction}
metabolites :: Vector{Metabolite}
genes :: Vector{Gene}
reactions :: OrderedDict{String, Reaction}
metabolites :: OrderedDict{String, Metabolite}
genes :: OrderedDict{String, Gene}
````
"""
mutable struct StandardModel <: MetabolicModel
id::String
reactions::Vector{Reaction}
metabolites::Vector{Metabolite}
genes::Vector{Gene}
reactions::OrderedDict{String,Reaction}
metabolites::OrderedDict{String,Metabolite}
genes::OrderedDict{String,Gene}
StandardModel(
id = "",
reactions::Vector{Reaction} = Reaction[],
metabolites::Vector{Metabolite} = Metabolite[],
genes::Vector{Gene} = Gene[],
reactions = OrderedDict{String,Reaction}(),
metabolites = OrderedDict{String,Metabolite}(),
genes = OrderedDict{String,Gene}(),
) = new(id, reactions, metabolites, genes)
end
# MetabolicModel interface follows
reactions(model::StandardModel)::Vector{String} = [r.id for r in model.reactions]
reactions(model::StandardModel)::Vector{String} = [r_id for r_id in keys(model.reactions)]
n_reactions(model::StandardModel)::Int = length(model.reactions)
metabolites(model::StandardModel)::Vector{String} = [m.id for m in model.metabolites]
metabolites(model::StandardModel)::Vector{String} = [m_id for m_id in keys(model.metabolites)]
n_metabolites(model::StandardModel)::Int = length(model.metabolites)
function stoichiometry(model::StandardModel)::SparseMat
genes(model::StandardModel)::Vector{String} = [g_id for g_id in keys(model.genes)]
n_genes(model::StandardModel)::Int = length(model.genes)
function stoichiometry(model::StandardModel)
S = SparseArrays.spzeros(length(model.metabolites), length(model.reactions))
metids = metabolites(model)
for (i, rxn) in enumerate(model.reactions) # column
for (met, coeff) in rxn.metabolites
j = findfirst(x -> x == met.id, metids) # row
met_ids = metabolites(model) # vector of metabolite ids
for (i, rxn_id) in enumerate(reactions(model)) # column, in order
for (met_id, coeff) in model.reactions[rxn_id].metabolites
j = findfirst(x -> x == met_id, met_ids) # row
isnothing(j) ?
(@error "S matrix construction error: $(met.id) not defined."; continue) :
(@error "S matrix construction error: $(met_id) not defined."; return nothing) :
nothing
S[j, i] = coeff
end
......@@ -45,9 +65,17 @@ function stoichiometry(model::StandardModel)::SparseMat
return S
end
function bounds(model::StandardModel)::Tuple{SparseVec,SparseVec}
ubs = [rxn.ub for rxn in model.reactions]
lbs = [rxn.lb for rxn in model.reactions]
function lower_bounds(model::StandardModel)
[model.reactions[rxn].lb for rxn in reactions(model)]
end
function upper_bounds(model::StandardModel)
[model.reactions[rxn].ub for rxn in reactions(model)]
end
function bounds(model::StandardModel)
ubs = upper_bounds(model)
lbs = lower_bounds(model)
return lbs, ubs
end
......@@ -56,14 +84,65 @@ balance(model::StandardModel)::SparseVec = spzeros(length(model.metabolites))
function objective(model::StandardModel)::SparseVec
obj_arr = SparseArrays.spzeros(length(model.reactions))
j = -1
for (i, r) in enumerate(model.reactions)
if r.objective_coefficient != 0.0
for (i, r) in enumerate(reactions(model))
if model[rxn].objective_coefficient != 0.0
j = i
obj_arr[j] = 1.0 # could have multiple objective coefficients
break
end
end
if j != -1 # objective assigned, otherwise return array of 0s
obj_arr[j] = 1.0
else
nnz(c) == 0 && (@warn "No objective found.")
end
return obj_arr
end
function gene_associations(model::StandardModel)
grrs = [_unparse_grr(r.grr) for r in values(model.reactions)]
end
function formulas(model::StandardModel)
[_formula_to_atoms(m.formula) for m in model.metabolites]
end
function charges(model::StandardModel)
[m.charge for m in model.metabolites]
end
function metabolite_chemistry(model::StandardModel)
(formulas(model), charges(model))
end
function metabolite_compartments(model::StandardModel)
[m.compartment for m in model.metabolites]
end
function reaction_subsystems(model::StandardModel)
[r.subsystem for r in model.reactions]
end
function metabolite_notes(model::JSONModel)
[m.notes for m in model.metabolites]
end
function metabolite_annotations(model::JSONModel)
[m.annotation for m in model.metabolites]
end
function gene_notes(model::JSONModel)
[g.notes for g in model.genes]
end
function gene_annotations(model::JSONModel)
[g.annotation for g in model.genes]
end
function reaction_notes(model::JSONModel)
[r.notes for r in model.reactions]
end
function reaction_annotations(model::JSONModel)
[r.annotation for r in model.reactions]
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