Unverified Commit b22577e1 authored by Miroslav Kratochvil's avatar Miroslav Kratochvil
Browse files

rework the filename extension routing and reduce polymorphism in model loading/saving

parent d9dab2a1
...@@ -137,7 +137,7 @@ Returns a solved JuMP model from [`optimize_model`](@ref). ...@@ -137,7 +137,7 @@ Returns a solved JuMP model from [`optimize_model`](@ref).
# Example # Example
``` ```
optimizer = GLPK.Optimizer optimizer = GLPK.Optimizer
model = CobraTools.read_model("e_coli_core.json") model = load_model(StandardModel, "e_coli_core.json")
biomass = findfirst(model.reactions, "BIOMASS_Ecoli_core_w_GAM") biomass = findfirst(model.reactions, "BIOMASS_Ecoli_core_w_GAM")
solved_model = fba(model, optimizer; modifications=[modify_objective(biomass)]) solved_model = fba(model, optimizer; modifications=[modify_objective(biomass)])
``` ```
......
...@@ -133,7 +133,7 @@ See also: [`CoreModel`](@ref) ...@@ -133,7 +133,7 @@ See also: [`CoreModel`](@ref)
# Example # Example
``` ```
optimizer = Gurobi.Optimizer optimizer = Gurobi.Optimizer
model = Cobraread_model("iJO1366.json") model = load_model(StandardModel, "iJO1366.json")
biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M") biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M")
fva_max, fva_min = fva(model, biomass, optimizer; solver_attributes=atts) fva_max, fva_min = fva(model, biomass, optimizer; solver_attributes=atts)
``` ```
......
...@@ -15,7 +15,7 @@ Return a solved pFBA model. ...@@ -15,7 +15,7 @@ Return a solved pFBA model.
``` ```
optimizer = Gurobi.Optimizer optimizer = Gurobi.Optimizer
atts = Dict("OutputFlag" => 0) atts = Dict("OutputFlag" => 0)
model = CobraTools.read_model("iJO1366.json") model = load_model(StandardModel, "iJO1366.json")
biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M") biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M")
sol = pfba(model, biomass, optimizer; solver_attributes=atts) sol = pfba(model, biomass, optimizer; solver_attributes=atts)
``` ```
......
struct JSONFile end
struct SBMLFile end
struct MFile end
struct YAMLFile end
struct UNKNOWNFile end
""" """
_infer_file_type(file_name::String) load_model(file_name::String)::MetabolicModel
Infer the file type. Generic function for loading models that chooses a specific loader function
from the `file_name` extension, or throws an error.
Currently, these model types are supported:
- SBML models (`*.xml`, loaded with [`load_sbml_model`](@ref))
- JSON models (`*.json`, loaded with [`load_json_model`](@ref))
- MATLAB models (`*.mat`, loaded with [`load_mat_model`](@ref))
""" """
function _infer_file_type(file_name::String) function load_model(file_name::String)::MetabolicModel
if endswith(file_name, ".json") if endswith(file_name, ".json")
return JSONFile return load_json_model(file_name)
elseif endswith(file_name, ".xml") elseif endswith(file_name, ".xml")
return SBMLFile return load_sbml_model(file_name)
elseif endswith(file_name, ".mat") elseif endswith(file_name, ".mat")
return MFile return load_mat_model(file_name)
elseif endswith(file_name, ".yml") else
return YAMLFile throw(DomainError(file_name, "Unknown file extension"))
end end
return UNKNOWNFile
end end
"""
read_model(file_location::String, ::Type{StandardModel})
Reads a model at `file_location` and returns a constraint based `model::StandardModel`. """
Currently supported formats include SBML (.xml), Matlab (.mat) and JSON (.json) models. load_model(type::Type{T}, file_name::String)::T where T
The model format is inferred from the `file_location` extension.
Note, some meta-information may be lost when importing a model. Importantly, only information regarding the Helper function tht loads the model using [`load_model`](@ref) and return it
reactions, metabolites and genes are imported. Currently reading JSON models captures the most meta-information converted to `type`.
regarding reactions, metabolites and genes (e.g. the notes and annotation fields).
When importing Matlab models some annotation and notes may not be imported because of non-standard field names used by some models. # Example:
Gene reaction rules are successfully imported only if they adhere to this format: `"(YIL010W and YLR043C) or (YIL010W and YGR209C)"`,
where `or` can be interchanged with `OR, |, ||` and `and` can be interchanged with `AND, &, &&`.
Other gene reaction rules formats are not supported yet, but file an issue if your format is standard and needs to be included.
However, in all cases the basic information needed to perform constraint based analysis should be imported successfully, load_model(CoreModel, "mySBMLModel.xml")
e.g. stoichiometrix matrix, constraints etc..
Advanced tools that require, e.g. metabolite formulas, gene reaction rules, and KEGG or BIGG IDs, will not function if these are improperly imported.
Always inspect the imported model before running analysis (garbage in -> garbage out).
""" """
function read_model(file_location::String, modelType) function load_model(type::Type{T}, file_name::String)::T where {T<:MetabolicModel}
inferred_type = _infer_file_type(file_location) convert(type, load_model(file_name))
if inferred_type == UNKNOWNFile
@warn "File type not supported."
return nothing
else
return _read_model(file_location, inferred_type, modelType)
end
end end
""" """
write_model(model::StandardModel, file_location::String) save_model(model::MetabolicModel, file_name::String)
Generic function for saving models that chooses a specific writer function
from the `file_name` extension, or throws an error.
Save model at `file_location`. Infers format from `file_location` extension. Currently, these model types are supported:
Supported formats include SBML (.xml), Matlab COBRA models (.mat) and JSON COBRA models (.json).
Note, only the fields contained in model are saved. Make sure that information isn't - JSON models (`*.json`, loaded with [`save_json_model`](@ref))
lost between reading a model and writing a model (e.g. check gene reaction rules, notes and annotations). - MATLAB models (`*.mat`, loaded with [`save_mat_model`](@ref))
""" """
function write_model(model::MetabolicModel, file_location::String) function save_model(model::MetabolicModel, file_name::String)
inferred_type = _infer_file_type(file_location) if endswith(file_name, ".json")
if inferred_type == UNKNOWNFile return save_json_model(model, file_name)
@warn "File type not supported." elseif endswith(file_name, ".mat")
return nothing return save_mat_model(model, file_name)
else else
_write_model(model, inferred_type, file_location) throw(DomainError(file_name, "Unknown file extension"))
return nothing
end end
end end
function _read_model(filename::String, ::Type{JSONFile}, ::Type{JSONModel})
"""
load_json_model(filename::String)::JSONModel
Load and return a JSON-formatted model that is stored in `file_name`.
"""
function load_json_model(filename::String)::JSONModel
return JSONModel(JSON.parsefile(filename)) return JSONModel(JSON.parsefile(filename))
end end
......
"""
save_json_model(model::MetabolicModel, file_name::String)
Save a [`JSONModel`](@ref) in `model` to a JSON file `file_name`.
In case the `model` is not `JSONModel`, it will be converted automatically.
"""
function save_json_model(model::MetabolicModel, file_name::String)
m = (typeof(model) == JSONModel ? model : convert(JSONModel, model)).m
JSON.print(open(file_name, "w"), modeldict)
end
#TODO this needs to be subsumed by the above function with auto-conversion
function _write_model(model::StandardModel, ::Type{JSONFile}, file_location::String) function _write_model(model::StandardModel, ::Type{JSONFile}, file_location::String)
modeldict = Dict{String,Any}() modeldict = Dict{String,Any}()
modeldict["id"] = model.id modeldict["id"] = model.id
......
"""
save_mat_model(model::MetabolicModel, file_name::String; model_name::String="model")
Save a [`MATModel`](@ref) in `model` to a MATLAB file `file_name` in a format
compatible with other MATLAB-based COBRA software.
In case the `model` is not `MATModel`, it will be converted automatically.
`model_name` is the identifier name for the whole model written to the MATLAB
file; defaults to just "model".
"""
function save_mat_model(model::MetabolicModel, file_path::String; model_name = "model")
m = (typeof(model) == MATModel ? model : convert(MATModel, model)).mat
matwrite(file_path, Dict(model_name => m))
end
#TODO this needs to get merged into convert function StdModel->MATModel
function _write_model(model::StandardModel, ::Type{MFile}, file_location::String) function _write_model(model::StandardModel, ::Type{MFile}, file_location::String)
# Some information is lost here, e.g. notes and some annotations. # Some information is lost here, e.g. notes and some annotations.
S = stoichiometry(model) S = stoichiometry(model)
......
function _read_model(file_location::String, ::Type{SBMLFile}, ::Type{SBMLModel})
return SBMLModel(SBML.readSBML(file_location)) # direct import
end
function _read_model(file_location::String, ::Type{SBMLFile}, ::Type{CoreModel})
sbmlmodel = _read_model(file_location, SBMLFile, SBMLModel) # use other import
return convert(CoreModel, sbmlmodel)
end
function _read_model(file_location::String, ::Type{SBMLFile}, ::Type{StandardModel}) """
m = _read_model(file_location, SBMLFile, SBMLModel) # use other import load_sbml_model(file_name::String)::SBMLModel
# do more processing
return StandardModel() Load and return a SBML XML model in `file_name`.
"""
function load_sbml_model(file_name::String)::SBMLModel
return SBMLModel(SBML.readSBML(file_name))
end end
...@@ -18,7 +18,7 @@ using COBREXA ...@@ -18,7 +18,7 @@ using COBREXA
using JuMP using JuMP
using Tulip using Tulip
model = read_model("e_coli_core.json") model = load_model(StandardModel, "e_coli_core.json")
biomass = findfirst(model.reactions, "BIOMASS_Ecoli_core_w_GAM") biomass = findfirst(model.reactions, "BIOMASS_Ecoli_core_w_GAM")
glucose = findfirst(model.reactions, "EX_glc__D_e") glucose = findfirst(model.reactions, "EX_glc__D_e")
......
...@@ -14,8 +14,8 @@ See also: [`CoreModel`](@ref), [`CoreModelCoupled`](@ref), [`StandardModel`](@re ...@@ -14,8 +14,8 @@ See also: [`CoreModel`](@ref), [`CoreModelCoupled`](@ref), [`StandardModel`](@re
# Example # Example
```` ````
model = read_model("some_model.json") model = load_json_model("some_model.json")
model.m # the actual underlying model model.m # the actual underlying JSON
```` ````
""" """
struct JSONModel <: MetabolicModel struct JSONModel <: MetabolicModel
......
Supports Markdown
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