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).
# Example
```
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")
solved_model = fba(model, optimizer; modifications=[modify_objective(biomass)])
```
......
......@@ -133,7 +133,7 @@ See also: [`CoreModel`](@ref)
# Example
```
optimizer = Gurobi.Optimizer
model = Cobraread_model("iJO1366.json")
model = load_model(StandardModel, "iJO1366.json")
biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M")
fva_max, fva_min = fva(model, biomass, optimizer; solver_attributes=atts)
```
......
......@@ -15,7 +15,7 @@ Return a solved pFBA model.
```
optimizer = Gurobi.Optimizer
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")
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")
return JSONFile
return load_json_model(file_name)
elseif endswith(file_name, ".xml")
return SBMLFile
return load_sbml_model(file_name)
elseif endswith(file_name, ".mat")
return MFile
elseif endswith(file_name, ".yml")
return YAMLFile
return load_mat_model(file_name)
else
throw(DomainError(file_name, "Unknown file extension"))
end
return UNKNOWNFile
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.
The model format is inferred from the `file_location` extension.
"""
load_model(type::Type{T}, file_name::String)::T where T
Note, some meta-information may be lost when importing a model. Importantly, only information regarding the
reactions, metabolites and genes are imported. Currently reading JSON models captures the most meta-information
regarding reactions, metabolites and genes (e.g. the notes and annotation fields).
Helper function tht loads the model using [`load_model`](@ref) and return it
converted to `type`.
When importing Matlab models some annotation and notes may not be imported because of non-standard field names used by some models.
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.
# Example:
However, in all cases the basic information needed to perform constraint based analysis should be imported successfully,
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).
load_model(CoreModel, "mySBMLModel.xml")
"""
function read_model(file_location::String, modelType)
inferred_type = _infer_file_type(file_location)
if inferred_type == UNKNOWNFile
@warn "File type not supported."
return nothing
else
return _read_model(file_location, inferred_type, modelType)
end
function load_model(type::Type{T}, file_name::String)::T where {T<:MetabolicModel}
convert(type, load_model(file_name))
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.
Supported formats include SBML (.xml), Matlab COBRA models (.mat) and JSON COBRA models (.json).
Currently, these model types are supported:
Note, only the fields contained in model are saved. Make sure that information isn't
lost between reading a model and writing a model (e.g. check gene reaction rules, notes and annotations).
- JSON models (`*.json`, loaded with [`save_json_model`](@ref))
- MATLAB models (`*.mat`, loaded with [`save_mat_model`](@ref))
"""
function write_model(model::MetabolicModel, file_location::String)
inferred_type = _infer_file_type(file_location)
if inferred_type == UNKNOWNFile
@warn "File type not supported."
return nothing
function save_model(model::MetabolicModel, file_name::String)
if endswith(file_name, ".json")
return save_json_model(model, file_name)
elseif endswith(file_name, ".mat")
return save_mat_model(model, file_name)
else
_write_model(model, inferred_type, file_location)
return nothing
throw(DomainError(file_name, "Unknown file extension"))
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))
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)
modeldict = Dict{String,Any}()
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)
# Some information is lost here, e.g. notes and some annotations.
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
# do more processing
"""
load_sbml_model(file_name::String)::SBMLModel
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
......@@ -18,7 +18,7 @@ using COBREXA
using JuMP
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")
glucose = findfirst(model.reactions, "EX_glc__D_e")
......
......@@ -14,8 +14,8 @@ See also: [`CoreModel`](@ref), [`CoreModelCoupled`](@ref), [`StandardModel`](@re
# Example
````
model = read_model("some_model.json")
model.m # the actual underlying model
model = load_json_model("some_model.json")
model.m # the actual underlying JSON
````
"""
struct JSONModel <: MetabolicModel
......
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