From 1dcc6438250aa18507f09197ce87c95d42062caa Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 22 Nov 2021 09:20:10 +0100 Subject: [PATCH 01/15] remove some unnecessarily explicit Unions --- src/analysis/flux_balance_analysis.jl | 4 ++-- src/analysis/screening.jl | 2 +- src/base/types/FluxVariabilitySummary.jl | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/analysis/flux_balance_analysis.jl b/src/analysis/flux_balance_analysis.jl index 7e60c5e1e..ae096ea3e 100644 --- a/src/analysis/flux_balance_analysis.jl +++ b/src/analysis/flux_balance_analysis.jl @@ -1,5 +1,5 @@ """ - flux_balance_analysis_vec(args...)::Union{Vector{Float64},Nothing} + flux_balance_analysis_vec(args...)::Maybe{Vector{Float64}} A variant of FBA that returns a vector of fluxes in the same order as reactions of the model, if the solution is found. @@ -13,7 +13,7 @@ flux_balance_analysis_vec(args...; kwargs...)::Maybe{Vector{Float64}} = flux_vector(flux_balance_analysis(args...; kwargs...)) """ - flux_balance_analysis_dict(model::MetabolicModel, args...)::Union{Dict{String, Float64},Nothing} + flux_balance_analysis_dict(model::MetabolicModel, args...)::Maybe{Dict{String, Float64}} A variant of FBA that returns a dictionary assigning fluxes to reactions, if the solution is found. Arguments are passed to [`flux_balance_analysis`](@ref). diff --git a/src/analysis/screening.jl b/src/analysis/screening.jl index ba5b035bb..acfd1daa8 100644 --- a/src/analysis/screening.jl +++ b/src/analysis/screening.jl @@ -175,7 +175,7 @@ screen_variants(model, variants, analysis; workers = [myid()]) = screen(model; variants = variants, analysis = analysis, workers = workers) """ - screen_optimize_objective(_, optmodel)::Union{Float64,Nothing} + screen_optimize_objective(_, optmodel)::Maybe{Float64} A variant of [`optimize_objective`](@ref) directly usable in [`screen_optmodel_modifications`](@ref). diff --git a/src/base/types/FluxVariabilitySummary.jl b/src/base/types/FluxVariabilitySummary.jl index ff1c1065f..97a5edc94 100644 --- a/src/base/types/FluxVariabilitySummary.jl +++ b/src/base/types/FluxVariabilitySummary.jl @@ -4,8 +4,8 @@ Stores summary information about the result of a flux variability analysis. """ struct FluxVariabilitySummary - biomass_fluxes::Dict{String,Vector{Union{Float64,Nothing}}} - exchange_fluxes::Dict{String,Vector{Union{Float64,Nothing}}} + biomass_fluxes::Dict{String,Vector{Maybe{Float64}}} + exchange_fluxes::Dict{String,Vector{Maybe{Float64}}} end """ @@ -15,8 +15,8 @@ A default empty constructor for [`FluxVariabilitySummary`](@ref). """ function FluxVariabilitySummary() FluxVariabilitySummary( - Dict{String,Vector{Union{Float64,Nothing}}}(), - Dict{String,Vector{Union{Float64,Nothing}}}(), + Dict{String,Vector{Maybe{Float64}}}(), + Dict{String,Vector{Maybe{Float64}}}(), ) end @@ -84,14 +84,14 @@ function flux_variability_summary( rxn_ids, ) - biomass_fluxes = Dict{String,Vector{Union{Float64,Nothing}}}() + biomass_fluxes = Dict{String,Vector{Maybe{Float64}}}() for rxn_id in bmasses lb = isnothing(flux_result[1][rxn_id]) ? nothing : flux_result[1][rxn_id][rxn_id] ub = isnothing(flux_result[2][rxn_id]) ? nothing : flux_result[2][rxn_id][rxn_id] biomass_fluxes[rxn_id] = [lb, ub] end - ex_rxn_fluxes = Dict{String,Vector{Union{Float64,Nothing}}}() + ex_rxn_fluxes = Dict{String,Vector{Maybe{Float64}}}() for rxn_id in ex_rxns lb = isnothing(flux_result[1][rxn_id]) ? nothing : flux_result[1][rxn_id][rxn_id] ub = isnothing(flux_result[2][rxn_id]) ? nothing : flux_result[2][rxn_id][rxn_id] From a87b3c4604bcea9fc63355ce24d0ae072e77216f Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 27 Dec 2021 21:03:27 +0100 Subject: [PATCH 02/15] use the keyword arguments in new version of SBML ...hopefully ending the series of single-version compatibility fixes once for all. --- Project.toml | 2 +- src/base/types/SBMLModel.jl | 61 +++++++++++++++---------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/Project.toml b/Project.toml index ea8b02ed3..834a1303d 100644 --- a/Project.toml +++ b/Project.toml @@ -28,7 +28,7 @@ MAT = "0.10" MacroTools = "0.5.6" OSQP = "0.6" OrderedCollections = "1.4" -SBML = "0.7, 0.8.2" +SBML = "0.9.1" StableRNGs = "1.0" Tulip = "0.7" julia = "1.5" diff --git a/src/base/types/SBMLModel.jl b/src/base/types/SBMLModel.jl index da9115233..2d183a9a9 100644 --- a/src/base/types/SBMLModel.jl +++ b/src/base/types/SBMLModel.jl @@ -165,65 +165,54 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) rxns = reactions(mm) stoi = stoichiometry(mm) (lbs, ubs) = bounds(mm) - ocs = objective(mm) comps = _default.("", metabolite_compartment.(Ref(mm), mets)) compss = Set(comps) return SBMLModel( SBML.Model( - Dict(), # parameters - Dict("" => 1), # units - Dict( - comp => - SBML.Compartment(nothing, nothing, nothing, nothing, nothing, nothing) - for comp in compss - ), - Dict( + units = Dict("" => []), # units + compartments = Dict(comp => SBML.Compartment() for comp in compss), + species = Dict( mid => SBML.Species( - nothing, # name - _default("", comps[mi]), # compartment - nothing, # no information about boundary conditions - metabolite_formula(mm, mid), - metabolite_charge(mm, mid), - nothing, # initial amount - nothing, # initial concentration - nothing, # only substance unit flags - _sbml_export_notes(metabolite_notes(mm, mid)), - _sbml_export_annotation(metabolite_annotations(mm, mid)), + compartment = _default("", comps[mi]), # compartment + formula = metabolite_formula(mm, mid), + charge = metabolite_charge(mm, mid), + notes = _sbml_export_notes(metabolite_notes(mm, mid)), + annotation = _sbml_export_annotation(metabolite_annotations(mm, mid)), ) for (mi, mid) in enumerate(mets) ), - Dict( + reactions = Dict( rid => SBML.Reaction( - Dict( + reactants = Dict( mets[i] => -stoi[i, ri] for i in SparseArrays.nonzeroinds(stoi[:, ri]) if stoi[i, ri] <= 0 ), - Dict( + products = Dict( mets[i] => stoi[i, ri] for i in SparseArrays.nonzeroinds(stoi[:, ri]) if stoi[i, ri] > 0 ), - (lbs[ri], ""), - (ubs[ri], ""), - ocs[ri], - _maybemap( + kinetic_parameters = Dict( + "LOWER_BOUND" => (lbs[ri], ""), + "UPPER_BOUND" => (ubs[ri], ""), + ), + gene_product_association = _maybemap( x -> _unparse_grr(SBML.GeneProductAssociation, x), reaction_gene_association(mm, rid), ), - nothing, # no kinetic math - true, # reversible by default - _sbml_export_notes(reaction_notes(mm, rid)), - _sbml_export_annotation(reaction_annotations(mm, rid)), + reversible = true, + notes = _sbml_export_notes(reaction_notes(mm, rid)), + annotation = _sbml_export_annotation(reaction_annotations(mm, rid)), ) for (ri, rid) in enumerate(rxns) ), - Dict( + gene_products = Dict( gid => SBML.GeneProduct( - nothing, - nothing, - _sbml_export_notes(gene_notes(mm, gid)), - _sbml_export_annotation(gene_annotations(mm, gid)), + notes = _sbml_export_notes(gene_notes(mm, gid)), + annotation = _sbml_export_annotation(gene_annotations(mm, gid)), ) for gid in genes(mm) ), - Dict(), # function definitions + objective = Dict( + rid => oc for (rid, oc) in zip(rxns, objective(mm)) if oc != 0 + ), ), ) end From 9629381a2710e3c93cff381d195a301406593c69 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Tue, 4 Jan 2022 12:27:56 +0100 Subject: [PATCH 03/15] temporarily allow the failure of mac tests --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eb252b24f..bec11dc77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -133,6 +133,7 @@ windows10:julia1.7: mac:julia1.7: stage: test-compat + allow_failure: true <<: *global_trigger_compat_tests <<: *global_julia17 <<: *global_env_mac @@ -151,6 +152,7 @@ windows10:julia1.6: mac:julia1.6: stage: test-compat + allow_failure: true <<: *global_trigger_compat_tests <<: *global_julia16 <<: *global_env_mac From 462538fc28fbbec09cecc12c70382b5b5a342db9 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Thu, 6 Jan 2022 12:12:29 +0100 Subject: [PATCH 04/15] Revert "Merge pull request #544 from LCSB-BioCore/mk-sbml-091" This reverts commit 553ed70ce59374cb778aa4410b80ceb7ba10467c, reversing changes made to 39f8d880a6552b0d4d9034561d4e10283058bedc. --- .gitlab-ci.yml | 2 -- Project.toml | 2 +- src/base/types/SBMLModel.jl | 61 ++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bec11dc77..eb252b24f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -133,7 +133,6 @@ windows10:julia1.7: mac:julia1.7: stage: test-compat - allow_failure: true <<: *global_trigger_compat_tests <<: *global_julia17 <<: *global_env_mac @@ -152,7 +151,6 @@ windows10:julia1.6: mac:julia1.6: stage: test-compat - allow_failure: true <<: *global_trigger_compat_tests <<: *global_julia16 <<: *global_env_mac diff --git a/Project.toml b/Project.toml index 834a1303d..ea8b02ed3 100644 --- a/Project.toml +++ b/Project.toml @@ -28,7 +28,7 @@ MAT = "0.10" MacroTools = "0.5.6" OSQP = "0.6" OrderedCollections = "1.4" -SBML = "0.9.1" +SBML = "0.7, 0.8.2" StableRNGs = "1.0" Tulip = "0.7" julia = "1.5" diff --git a/src/base/types/SBMLModel.jl b/src/base/types/SBMLModel.jl index 2d183a9a9..da9115233 100644 --- a/src/base/types/SBMLModel.jl +++ b/src/base/types/SBMLModel.jl @@ -165,54 +165,65 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) rxns = reactions(mm) stoi = stoichiometry(mm) (lbs, ubs) = bounds(mm) + ocs = objective(mm) comps = _default.("", metabolite_compartment.(Ref(mm), mets)) compss = Set(comps) return SBMLModel( SBML.Model( - units = Dict("" => []), # units - compartments = Dict(comp => SBML.Compartment() for comp in compss), - species = Dict( + Dict(), # parameters + Dict("" => 1), # units + Dict( + comp => + SBML.Compartment(nothing, nothing, nothing, nothing, nothing, nothing) + for comp in compss + ), + Dict( mid => SBML.Species( - compartment = _default("", comps[mi]), # compartment - formula = metabolite_formula(mm, mid), - charge = metabolite_charge(mm, mid), - notes = _sbml_export_notes(metabolite_notes(mm, mid)), - annotation = _sbml_export_annotation(metabolite_annotations(mm, mid)), + nothing, # name + _default("", comps[mi]), # compartment + nothing, # no information about boundary conditions + metabolite_formula(mm, mid), + metabolite_charge(mm, mid), + nothing, # initial amount + nothing, # initial concentration + nothing, # only substance unit flags + _sbml_export_notes(metabolite_notes(mm, mid)), + _sbml_export_annotation(metabolite_annotations(mm, mid)), ) for (mi, mid) in enumerate(mets) ), - reactions = Dict( + Dict( rid => SBML.Reaction( - reactants = Dict( + Dict( mets[i] => -stoi[i, ri] for i in SparseArrays.nonzeroinds(stoi[:, ri]) if stoi[i, ri] <= 0 ), - products = Dict( + Dict( mets[i] => stoi[i, ri] for i in SparseArrays.nonzeroinds(stoi[:, ri]) if stoi[i, ri] > 0 ), - kinetic_parameters = Dict( - "LOWER_BOUND" => (lbs[ri], ""), - "UPPER_BOUND" => (ubs[ri], ""), - ), - gene_product_association = _maybemap( + (lbs[ri], ""), + (ubs[ri], ""), + ocs[ri], + _maybemap( x -> _unparse_grr(SBML.GeneProductAssociation, x), reaction_gene_association(mm, rid), ), - reversible = true, - notes = _sbml_export_notes(reaction_notes(mm, rid)), - annotation = _sbml_export_annotation(reaction_annotations(mm, rid)), + nothing, # no kinetic math + true, # reversible by default + _sbml_export_notes(reaction_notes(mm, rid)), + _sbml_export_annotation(reaction_annotations(mm, rid)), ) for (ri, rid) in enumerate(rxns) ), - gene_products = Dict( + Dict( gid => SBML.GeneProduct( - notes = _sbml_export_notes(gene_notes(mm, gid)), - annotation = _sbml_export_annotation(gene_annotations(mm, gid)), + nothing, + nothing, + _sbml_export_notes(gene_notes(mm, gid)), + _sbml_export_annotation(gene_annotations(mm, gid)), ) for gid in genes(mm) ), - objective = Dict( - rid => oc for (rid, oc) in zip(rxns, objective(mm)) if oc != 0 - ), + Dict(), # function definitions ), ) end From 871a62d4e7df5ea95e53605fc89653bd6f3e079a Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 2 May 2022 09:38:31 +0200 Subject: [PATCH 05/15] extract metabolite compartments from SBML --- src/base/types/SBMLModel.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/base/types/SBMLModel.jl b/src/base/types/SBMLModel.jl index 33f9a7fd5..ef0e508a6 100644 --- a/src/base/types/SBMLModel.jl +++ b/src/base/types/SBMLModel.jl @@ -114,6 +114,13 @@ Get [`MetaboliteFormula`](@ref) from a chosen metabolite from [`SBMLModel`](@ref metabolite_formula(model::SBMLModel, mid::String)::Maybe{MetaboliteFormula} = _maybemap(_parse_formula, model.sbml.species[mid].formula) +""" + metabolite_compartment(model::SBMLModel, mid::String)::Maybe{String} + +Get the compartment of a chosen metabolite from [`SBMLModel`](@ref). +""" +metabolite_compartment(model::SBMLModel, mid::String) = model.sbml.species[mid].compartment + """ metabolite_charge(model::SBMLModel, mid::String)::Maybe{Int} From 4bccc3be63111240bd05e5786489151166ff77ec Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 2 May 2022 09:50:09 +0200 Subject: [PATCH 06/15] MATModel should return integer metabolite charges --- src/base/types/MATModel.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/base/types/MATModel.jl b/src/base/types/MATModel.jl index 09200476d..aa0fb7ff3 100644 --- a/src/base/types/MATModel.jl +++ b/src/base/types/MATModel.jl @@ -148,16 +148,16 @@ metabolite_formula(m::MATModel, mid::String) = _maybemap( ) """ - metabolite_charge(m::MATModel, mid::String) + metabolite_charge(m::MATModel, mid::String)::Maybe{Int} Extract metabolite charge from `metCharge` or `metCharges`. """ -function metabolite_charge(m::MATModel, mid::String) +function metabolite_charge(m::MATModel, mid::String)::Maybe{Int} met_charge = _maybemap( x -> x[findfirst(==(mid), metabolites(m))], gets(m.mat, nothing, _constants.keynames.metcharges), ) - isnan(met_charge) ? 0 : met_charge + _maybemap(Int, isnan(met_charge) ? nothing : met_charge) end """ From 111073d6a941f2f1c09b9be9cde097a58f5b9f53 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 2 May 2022 10:18:14 +0200 Subject: [PATCH 07/15] MATModel: add a few new names for the compartment ID vector Expectably Yeast-GEM will use these, see: https://github.com/SysBioChalmers/yeast-GEM/pull/301 --- src/base/constants.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/constants.jl b/src/base/constants.jl index 56c8b36f2..3a752c11c 100644 --- a/src/base/constants.jl +++ b/src/base/constants.jl @@ -26,7 +26,7 @@ const _constants = ( ids = ["id", "description"], metformulas = ["metFormula", "metFormulas"], metcharges = ["metCharge", "metCharges"], - metcompartments = ["metCompartment", "metCompartments"], + metcompartments = ["metCompartment", "metCompartments", "metComp", "metComps"], rxnnames = ["rxnNames"], metnames = ["metNames"], ), From 796ade395022ea86a80a0f5c6b70c7cfa1bb1d2f Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Mon, 29 Aug 2022 08:44:19 +0200 Subject: [PATCH 08/15] bump CompatHelper version to work with 1.8 --- .github/workflows/CompatHelper.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 840ac361c..369f4b915 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -12,7 +12,7 @@ jobs: import Pkg name = "CompatHelper" uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" - version = "2" + version = "3" Pkg.add(; name, uuid, version) shell: julia --color=yes {0} - name: "Run CompatHelper" From 21f8636dbd2bca604e2bc54eee9b26b8fbe4a5e3 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Tue, 27 Sep 2022 11:23:38 +0200 Subject: [PATCH 09/15] improve SBML import and export - support CVTerms-based annotations in the usual way (thanks COBRApy for inspiration!) - fix minor issues with notes and formula export - prevent problems when exporting (some) non-SBMLizable metabolite names --- Project.toml | 2 +- src/base/types/SBMLModel.jl | 133 ++++++++++++++++++++++++++++++------ 2 files changed, 115 insertions(+), 20 deletions(-) diff --git a/Project.toml b/Project.toml index b7f0f9612..8d53cca8b 100644 --- a/Project.toml +++ b/Project.toml @@ -32,7 +32,7 @@ JuMP = "1" MAT = "0.10" MacroTools = "0.5.6" OrderedCollections = "1.4" -SBML = "~1.1, ~1.2" +SBML = "~1.3" StableRNGs = "1.0" Tulip = "0.7.0, 0.8.0, 0.9.2" julia = "1.5" diff --git a/src/base/types/SBMLModel.jl b/src/base/types/SBMLModel.jl index 66fda9916..97df62eea 100644 --- a/src/base/types/SBMLModel.jl +++ b/src/base/types/SBMLModel.jl @@ -125,19 +125,54 @@ Get charge of a chosen metabolite from [`SBMLModel`](@ref). metabolite_charge(model::SBMLModel, mid::String)::Maybe{Int} = model.sbml.species[mid].charge -function _sbml_export_annotation(annotation)::Maybe{String} - if isnothing(annotation) || isempty(annotation) - nothing - elseif length(annotation) != 1 || first(annotation).first != "" - @_io_log @warn "Possible data loss: multiple annotations converted to text for SBML" annotation - join(["$k: $v" for (k, v) in annotation], "\n") - else - @_io_log @warn "Possible data loss: trying to represent annotation in SBML is unlikely to work " annotation - first(annotation).second +function _parse_sbml_identifiers_org_uri(uri::String)::Tuple{String,String} + m = match(r"^http://identifiers.org/([^/]+)/(.*)$", uri) + isnothing(m) ? ("RESOURCE_URI", uri) : (m[1], m[2]) +end + +function _sbml_import_cvterms(sbo::Maybe{String}, cvs::Vector{SBML.CVTerm})::Annotations + res = Annotations() + isnothing(sbo) || (res["sbo"] = [sbo]) + for cv in cvs + cv.biological_qualifier == :is || continue + for (id, val) in _parse_sbml_identifiers_org_uri.(cv.resource_uris) + push!(get!(res, id, []), val) + end end + return res +end + +function _sbml_export_cvterms(annotations::Annotations)::Vector{SBML.CVTerm} + isempty(annotations) && return [] + length(annotations) == 1 && haskey(annotations, "sbo") && return [] + [ + SBML.CVTerm( + biological_qualifier = :is, + resource_uris = [ + id == "RESOURCE_URI" ? val : "http://identifiers.org/$id/$val" for + (id, vals) = annotations if id != "sbo" for val in vals + ], + ), + ] end -const _sbml_export_notes = _sbml_export_annotation +function _sbml_export_sbo(annotations::Annotations)::Maybe{String} + haskey(annotations, "sbo") || return nothing + if length(annotations["sbo"]) != 1 + @_io_log @error "Data loss: SBO term is not unique for SBML export" annotations["sbo"] + return + end + return annotations["sbo"][1] +end + +function _sbml_import_notes(notes::Maybe{String})::Notes + isnothing(notes) ? Notes() : Notes("" => [notes]) +end + +function _sbml_export_notes(notes::Notes)::Maybe{String} + isempty(notes) || @_io_log @error "Data loss: notes not exported to SBML" notes + nothing +end """ $(TYPEDSIGNATURES) @@ -180,6 +215,56 @@ gene_name(model::SBMLModel, gid::String) = model.sbml.gene_products[gid].name """ $(TYPEDSIGNATURES) +Return the annotations of reaction with ID `rid`. +""" +reaction_annotations(model::SBMLModel, rid::String) = + _sbml_import_cvterms(model.sbml.reactions[rid].sbo, model.sbml.reactions[rid].cv_terms) + +""" +$(TYPEDSIGNATURES) + +Return the annotations of metabolite with ID `mid`. +""" +metabolite_annotations(model::SBMLModel, mid::String) = + _sbml_import_cvterms(model.sbml.species[mid].sbo, model.sbml.species[mid].cv_terms) + +""" +$(TYPEDSIGNATURES) + +Return the annotations of gene with ID `gid`. +""" +gene_annotations(model::SBMLModel, gid::String) = _sbml_import_cvterms( + model.sbml.gene_products[gid].sbo, + model.sbml.gene_products[gid].cv_terms, +) + +""" +$(TYPEDSIGNATURES) + +Return the notes about reaction with ID `rid`. +""" +reaction_notes(model::SBMLModel, rid::String) = + _sbml_import_notes(model.sbml.reactions[rid].notes) + +""" +$(TYPEDSIGNATURES) + +Return the notes about metabolite with ID `mid`. +""" +metabolite_notes(model::SBMLModel, mid::String) = + _sbml_import_notes(model.sbml.species[mid].notes) + +""" +$(TYPEDSIGNATURES) + +Return the notes about gene with ID `gid`. +""" +gene_notes(model::SBMLModel, gid::String) = + _sbml_import_notes(model.sbml.gene_products[gid].notes) + +""" +$(TYPEDSIGNATURES) + Convert any metabolic model to [`SBMLModel`](@ref). """ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) @@ -194,30 +279,36 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) comps = _default.("compartment", metabolite_compartment.(Ref(mm), mets)) compss = Set(comps) + metid(x) = startswith(x, "M_") ? x : "M_$x" + rxnid(x) = startswith(x, "R_") ? x : "R_$x" + gprid(x) = startswith(x, "G_") ? x : "G_$x" + return SBMLModel( SBML.Model( compartments = Dict( comp => SBML.Compartment(constant = true) for comp in compss ), species = Dict( - mid => SBML.Species( + metid(mid) => SBML.Species( name = metabolite_name(mm, mid), compartment = _default("compartment", comps[mi]), - formula = metabolite_formula(mm, mid), + formula = _unparse_formula(metabolite_formula(mm, mid)), charge = metabolite_charge(mm, mid), constant = false, boundary_condition = false, only_substance_units = false, + sbo = _sbml_export_sbo(metabolite_annotations(mm, mid)), notes = _sbml_export_notes(metabolite_notes(mm, mid)), - annotation = _sbml_export_annotation(metabolite_annotations(mm, mid)), + metaid = metid(mid), + cv_terms = _sbml_export_cvterms(metabolite_annotations(mm, mid)), ) for (mi, mid) in enumerate(mets) ), reactions = Dict( - rid => SBML.Reaction( + rxnid(rid) => SBML.Reaction( name = reaction_name(mm, rid), reactants = [ SBML.SpeciesReference( - species = mets[i], + species = metid(mets[i]), stoichiometry = -stoi[i, ri], constant = true, ) for @@ -225,7 +316,7 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) ], products = [ SBML.SpeciesReference( - species = mets[i], + species = metid(mets[i]), stoichiometry = stoi[i, ri], constant = true, ) for @@ -242,16 +333,20 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) reaction_gene_association(mm, rid), ), reversible = true, + sbo = _sbml_export_sbo(reaction_annotations(mm, rid)), notes = _sbml_export_notes(reaction_notes(mm, rid)), - annotation = _sbml_export_annotation(reaction_annotations(mm, rid)), + metaid = rxnid(rid), + cv_terms = _sbml_export_cvterms(reaction_annotations(mm, rid)), ) for (ri, rid) in enumerate(rxns) ), gene_products = Dict( - gid => SBML.GeneProduct( + gprid(gid) => SBML.GeneProduct( label = gid, name = gene_name(mm, gid), + sbo = _sbml_export_sbo(gene_annotations(mm, gid)), notes = _sbml_export_notes(gene_notes(mm, gid)), - annotation = _sbml_export_annotation(gene_annotations(mm, gid)), + metaid = gprid(gid), + cv_terms = _sbml_export_cvterms(gene_annotations(mm, gid)), ) for gid in genes(mm) ), active_objective = "objective", From 66cebc9cb87e0fe4446db9cb5f0382245fcded98 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Tue, 27 Sep 2022 11:25:41 +0200 Subject: [PATCH 10/15] bump minor version (I need to depend on the fixes here) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 8d53cca8b..ac3b50af2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "COBREXA" uuid = "babc4406-5200-4a30-9033-bf5ae714c842" authors = ["The developers of COBREXA.jl"] -version = "1.4.0" +version = "1.4.1" [deps] Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" From 8ecd4bf5bf6c0ee8a3c183fc09ede0867a6886d1 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Tue, 27 Sep 2022 11:48:50 +0200 Subject: [PATCH 11/15] fix missing formulas --- src/base/types/SBMLModel.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/types/SBMLModel.jl b/src/base/types/SBMLModel.jl index 97df62eea..37ab4bef0 100644 --- a/src/base/types/SBMLModel.jl +++ b/src/base/types/SBMLModel.jl @@ -292,7 +292,7 @@ function Base.convert(::Type{SBMLModel}, mm::MetabolicModel) metid(mid) => SBML.Species( name = metabolite_name(mm, mid), compartment = _default("compartment", comps[mi]), - formula = _unparse_formula(metabolite_formula(mm, mid)), + formula = _maybemap(_unparse_formula, metabolite_formula(mm, mid)), charge = metabolite_charge(mm, mid), constant = false, boundary_condition = false, From c216623e7d7873a35824e5692d1190ae5e65dbbe Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Tue, 27 Sep 2022 17:47:16 +0200 Subject: [PATCH 12/15] docs: reflect the solver change in Project.toml --- docs/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index 6d1d4c31c..1f523ccd8 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,6 +1,7 @@ [deps] COBREXA = "babc4406-5200-4a30-9033-bf5ae714c842" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +Clarabel = "61c947e1-3e6d-4ee4-985a-eec8c727bd6e" Clustering = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5" ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" @@ -10,7 +11,6 @@ InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" -OSQP = "ab2f91bb-94b4-55e3-9ba0-7f65df51de79" Tulip = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa" [compat] From 0a3c94216268ccf4723a32b8c8d19ed14bdbfebd Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Thu, 13 Oct 2022 16:35:49 +0200 Subject: [PATCH 13/15] import JuMP to allow touching MAX/MIN_SENSE --- docs/src/examples/05b_fba_mods.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/examples/05b_fba_mods.jl b/docs/src/examples/05b_fba_mods.jl index a8027a6c1..8beff7a04 100644 --- a/docs/src/examples/05b_fba_mods.jl +++ b/docs/src/examples/05b_fba_mods.jl @@ -10,7 +10,7 @@ !isfile("e_coli_core.xml") && download("http://bigg.ucsd.edu/static/models/e_coli_core.xml", "e_coli_core.xml") -using COBREXA, GLPK, Tulip +using COBREXA, GLPK, Tulip, JuMP model = load_model("e_coli_core.xml") @@ -33,6 +33,6 @@ fluxes = flux_balance_analysis_dict( knockout(["b0978", "b0734"]), # knock out two genes change_optimizer(Tulip.Optimizer), # ignore the above optimizer and switch to Tulip change_optimizer_attribute("IPM_IterationsLimit", 1000), # customize Tulip - change_sense(MAX_SENSE), # explicitly tell Tulip to maximize the objective + change_sense(JuMP.MAX_SENSE), # explicitly tell Tulip to maximize the objective ], ) From d910766a77d34f7d340fb7ac0a19589a7dbfa24a Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Fri, 14 Oct 2022 10:42:56 +0200 Subject: [PATCH 14/15] remove `polish` parameter specific to osqp --- docs/src/examples/08_pfba.jl | 2 -- docs/src/examples/13_moma.jl | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/src/examples/08_pfba.jl b/docs/src/examples/08_pfba.jl index 209b6c82d..c10fbfd02 100644 --- a/docs/src/examples/08_pfba.jl +++ b/docs/src/examples/08_pfba.jl @@ -43,7 +43,6 @@ fluxes = parsimonious_flux_balance_analysis_dict( Clarabel.Optimizer; modifications = [ silence, # optionally silence the optimizer (Clarabel is very verbose by default) - change_optimizer_attribute("polish", true), # tell Clarabel to invest time into improving the precision of the solution change_constraint("R_EX_glc__D_e"; lb = -12, ub = -12), # fix glucose consumption rate ], ) @@ -70,7 +69,6 @@ flux_vector = parsimonious_flux_balance_analysis_vec( ], qp_modifications = [ change_optimizer(Clarabel.Optimizer), # now switch to Clarabel (Tulip wouldn't be able to finish the computation) - change_optimizer_attribute("polish", true), # get an accurate solution, see Clarabel's documentation silence, # and make it quiet. ], ) diff --git a/docs/src/examples/13_moma.jl b/docs/src/examples/13_moma.jl index 82d3439c9..21b9bef00 100644 --- a/docs/src/examples/13_moma.jl +++ b/docs/src/examples/13_moma.jl @@ -28,7 +28,7 @@ using Clarabel reference_flux = flux_balance_analysis_dict( model, Clarabel.Optimizer; - modifications = [silence, change_optimizer_attribute("polish", true)], + modifications = [silence], ) # As the change here, we manually knock out CYTBD reaction: @@ -41,7 +41,7 @@ flux_summary( changed_model, reference_flux, Clarabel.Optimizer; - modifications = [silence, change_optimizer_attribute("polish", true)], + modifications = [silence], ), ) @@ -52,6 +52,6 @@ flux_summary( flux_balance_analysis_dict( changed_model, Clarabel.Optimizer; - modifications = [silence, change_optimizer_attribute("polish", true)], + modifications = [silence], ), ) From f66abed0bee73fad97f70181caa512b04b6cbd51 Mon Sep 17 00:00:00 2001 From: exaexa Date: Fri, 14 Oct 2022 09:32:02 +0000 Subject: [PATCH 15/15] automatic formatting triggered by @exaexa on PR #681 --- docs/src/examples/13_moma.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/src/examples/13_moma.jl b/docs/src/examples/13_moma.jl index 21b9bef00..200ccd07d 100644 --- a/docs/src/examples/13_moma.jl +++ b/docs/src/examples/13_moma.jl @@ -25,11 +25,8 @@ using Clarabel # We will need a reference solution, which represents the original state of the # organism before the change. -reference_flux = flux_balance_analysis_dict( - model, - Clarabel.Optimizer; - modifications = [silence], -) +reference_flux = + flux_balance_analysis_dict(model, Clarabel.Optimizer; modifications = [silence]) # As the change here, we manually knock out CYTBD reaction: changed_model = change_bound(model, "R_CYTBD", lower = 0.0, upper = 0.0);