Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Catalyst v14 #163

Merged
merged 14 commits into from
Jul 18, 2024
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
[compat]
Aqua = "0.8"
CSV = "0.10.5"
Catalyst = "13"
Catalyst = "14"
DataFrames = "1"
Downloads = "1"
ModelingToolkit = "8.51"
ModelingToolkit = "9"
OrdinaryDiffEq = "6.42"
Plots = "1.11"
SBML = "1.4.4"
SBMLToolkitTestSuite = "0.0.3"
SBMLToolkitTestSuite = "0.0.4"
SafeTestsets = "0.1"
Sundials = "4.14"
SymbolicUtils = "1, 2"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

SBMLToolkit.jl is a lightweight tool to import models specified in the Systems Biology Markup Language (SBML) into the Julia SciML ecosystem. There are multiple ways to specify the same model in SBML. Please help us improving SBMLToolkit.jl by creating a GitHub issue if you experience errors when converting your SBML model.

SBMLToolkit uses the [SBML.jl](https://github.com/LCSB-BioCore/SBML.jl) wrapper of the [libSBML](https://model.caltech.edu/software/libsbml/) library to lower dynamical SBML models into dynamical systems. If you would like to import BioNetGen models use the `writeSBML()` export function or import the `.net` file with [ReactionNetworkImporters.jl](https://github.com/SciML/ReactionNetworkImporters.jl). For constrained-based modeling, please have a look at [COBREXA.jl](https://github.com/LCSB-BioCore/COBREXA.jl). We also recommend trying [SBMLImporter.jl](https://github.com/sebapersson/SBMLImporter.jl) (Pros: respects directionality of events, outputs concentrations instead of amounts. Cons: imports ODESystems, i.e. does not interface with Catalyst).
SBMLToolkit uses the [SBML.jl](https://github.com/LCSB-BioCore/SBML.jl) wrapper of the [libSBML](https://model.caltech.edu/software/libsbml/) library to lower dynamical SBML models into completed dynamical systems. If you would like to import BioNetGen models use the `writeSBML()` export function or import the `.net` file with [ReactionNetworkImporters.jl](https://github.com/SciML/ReactionNetworkImporters.jl). For constrained-based modeling, please have a look at [COBREXA.jl](https://github.com/LCSB-BioCore/COBREXA.jl). We also recommend trying [SBMLImporter.jl](https://github.com/sebapersson/SBMLImporter.jl). While SBMLToolkit.jl has a slightly cleaner interface, SBMLImporter.jl respects directionality of events, can output concentrations or amounts, and provides better simulation performance for models including time-triggered events and SBML `piecewise` expressions.

## Installation

Expand Down Expand Up @@ -46,7 +46,7 @@ rs = readSBML("my_model.xml", ReactionSystemImporter())

One common case where this is useful is if you want to run stochastic instead of ODE simulations.

In the very unlikely case that you need fine-grained control over the SBML import, you can create an SBML.jl `Model` (we strongly recommend manually running `SBMLToolkit.checksupport_file("my_model.xml")` before)
In the very unlikely case that you need fine-grained control over the SBML import, you can create an SBML.jl `Model` (we strongly recommend manually running `checksupport_file("my_model.xml")` before)

```julia
using SBML
Expand Down
2 changes: 1 addition & 1 deletion src/SBMLToolkit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ include("utils.jl")

export ReactionSystem, ODESystem
export readSBML, readSBMLFromString, set_level_and_version, convert_simplify_math,
convert_promotelocals_expandfuns
convert_promotelocals_expandfuns, checksupport_file
export DefaultImporter, ReactionSystemImporter, ODESystemImporter

end
4 changes: 2 additions & 2 deletions src/reactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Infer forward and reverse components of bidirectional kineticLaw
"""
function get_unidirectional_components(bidirectional_math)
bm = ModelingToolkit.value(bidirectional_math) # Symbolics.tosymbol(bidirectional_math)
bm = simplify(bm; expand = true)
bm = expand(simplify(bm))
if !SymbolicUtils.isadd(bm)
@warn "Cannot separate bidirectional kineticLaw `$bidirectional_math` to forward and reverse part. Setting forward to `$bidirectional_math` and reverse to `0`. Stochastic simulations will be inexact."
return (bidirectional_math, Num(0))
Expand Down Expand Up @@ -168,7 +168,7 @@ function get_massaction(kl::Num, reactants::Union{Vector{Num}, Nothing},

function check_args(::Val{true}, x::SymbolicUtils.BasicSymbolic{Real})
for arg in SymbolicUtils.arguments(x)
if isnan(check_args(arg)) || isequal(arg, Catalyst.DEFAULT_IV)
if isnan(check_args(arg)) || isequal(arg, default_t())
return NaN
end
end
Expand Down
9 changes: 6 additions & 3 deletions src/systems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ See also [`Model`](@ref) and [`ODESystemImporter`](@ref).
"""
function SBML.readSBML(sbmlfile::String, ::ODESystemImporter;
include_zero_odes::Bool = true, kwargs...) # Returns an MTK.ODESystem
convert(ODESystem, readSBML(sbmlfile, ReactionSystemImporter(), kwargs...),
odesys = convert(ODESystem, readSBML(sbmlfile, ReactionSystemImporter(), kwargs...),
include_zero_odes = include_zero_odes)
complete(odesys)
end

"""
Expand Down Expand Up @@ -90,11 +91,12 @@ function Catalyst.ReactionSystem(model::SBML.Model; kwargs...) # Todo: requires
defs = ModelingToolkit._merge(defs, kwargs[:defaults])
kwargs = filter(x -> !isequal(first(x), :defaults), kwargs)
end
ReactionSystem([rxs..., algrules..., raterules_subs..., obsrules_rearranged...],
rs = ReactionSystem([rxs..., algrules..., raterules_subs..., obsrules_rearranged...],
IV, first.(u0map), first.(parammap);
defaults = defs, name = gensym(:SBML),
continuous_events = get_events(model),
combinatoric_ratelaws = false, kwargs...)
return complete(rs) # Todo: maybe add a `complete=True` kwarg
end

"""
Expand All @@ -107,7 +109,8 @@ See also [`ReactionSystem`](@ref).
function ModelingToolkit.ODESystem(model::SBML.Model; include_zero_odes::Bool = true,
kwargs...)
rs = ReactionSystem(model; kwargs...)
convert(ODESystem, rs; include_zero_odes = include_zero_odes)
odesys = convert(ODESystem, rs; include_zero_odes = include_zero_odes)
complete(odesys)
end

function get_mappings(model::SBML.Model)
Expand Down
4 changes: 2 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Conversion to symbolics
const IV = Catalyst.DEFAULT_IV
const D = Differential(IV)
const IV = default_t()
const D = default_time_deriv()
symbolicsRateOf(x) = D(x)
const symbolics_mapping = Dict(SBML.default_function_mapping...,
"rateOf" => symbolicsRateOf)
Expand Down
2 changes: 1 addition & 1 deletion test/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using SBMLToolkit
using Catalyst, SBMLToolkitTestSuite
using Test

const IV = Catalyst.DEFAULT_IV
const IV = default_t()
@parameters compartment
@species S1(IV) S2(IV)

Expand Down
2 changes: 1 addition & 1 deletion test/reactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using Test

cd(@__DIR__)
sbmlfile = joinpath("data", "reactionsystem_01.xml")
const IV = Catalyst.DEFAULT_IV
const IV = default_t()
@parameters k1, c1
@species s1(IV), s2(IV), s1s2(IV)

Expand Down
12 changes: 6 additions & 6 deletions test/rules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using SBML, SBMLToolkitTestSuite
using Catalyst, ModelingToolkit, OrdinaryDiffEq
using Test

const IV = Catalyst.DEFAULT_IV
const IV = default_t()
@parameters k1, compartment
@species S1(IV), S2(IV)

Expand All @@ -24,7 +24,7 @@ o_true = [S1 ~ 7 * compartment]
sbml, _, _ = SBMLToolkitTestSuite.read_case("00031") # rateRule
m = readmodel(sbml)
a, o, r = SBMLToolkit.get_rules(m)
r_true = [Differential(IV)(S1) ~ 7 * compartment]
r_true = [default_time_deriv()(S1) ~ 7 * compartment]
@test isequal(r, r_true)

sbml, _, _ = SBMLToolkitTestSuite.read_case("00039") # algebraicRule
Expand Down Expand Up @@ -59,16 +59,16 @@ m = readmodel(sbml)
vc = SBMLToolkit.get_volume_correction(m, "S1")
@test isnothing(vc)

# tests that non-constant parameters become states
# tests that non-constant parameters become variables
sbml, _, _ = SBMLToolkitTestSuite.read_case("00033")
m = readmodel(sbml)
@named sys = ODESystem(m)
@species k1(IV)
@test isequal(k1, states(sys)[end])
@test isequal(k1, unknowns(sys)[end])

# tests that non-constant compartments become states
# tests that non-constant compartments become variables
sbml, _, _ = SBMLToolkitTestSuite.read_case("00051") # hOSU="true" species
m = readmodel(sbml)
@named sys = ODESystem(m)
@species C(IV)
@test isequal(C, states(sys)[end])
@test isequal(C, unknowns(sys)[end])
20 changes: 10 additions & 10 deletions test/systems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using Test

cd(@__DIR__)
sbmlfile = joinpath("data", "reactionsystem_01.xml")
const IV = Catalyst.DEFAULT_IV
const IV = default_t()
@parameters k1, c1
@species s1(IV), s2(IV), s1s2(IV)

Expand Down Expand Up @@ -49,7 +49,7 @@ rs = ReactionSystem(MODEL1)
@test isequal(Catalyst.get_eqs(rs),
Catalyst.Reaction[Catalyst.Reaction(k1, nothing, [s1], nothing, [1.0])])
@test isequal(Catalyst.get_iv(rs), IV)
@test isequal(Catalyst.get_states(rs), [s1])
@test isequal(Catalyst.get_species(rs), [s1])
@test isequal(Catalyst.get_ps(rs), [k1, c1])
@named rs = ReactionSystem(MODEL1)
isequal(nameof(rs), :rs)
Expand All @@ -59,7 +59,7 @@ rs = ReactionSystem(readSBML(sbmlfile))
Catalyst.Reaction[Catalyst.Reaction(k1 / c1, [s1, s2], [s1s2], [1.0, 1.0],
[1.0])])
@test isequal(Catalyst.get_iv(rs), IV)
@test isequal(Catalyst.get_states(rs), [s1, s1s2, s2])
@test isequal(Catalyst.get_species(rs), [s1, s1s2, s2])
@test isequal(Catalyst.get_ps(rs), [k1, c1])
@named rs = ReactionSystem(MODEL1)
isequal(nameof(rs), :rs)
Expand All @@ -71,18 +71,18 @@ rs = ReactionSystem(MODEL2) # Contains reversible reaction
Catalyst.Reaction(k1, nothing, [s1],
nothing, [1])])
@test isequal(Catalyst.get_iv(rs), IV)
@test isequal(Catalyst.get_states(rs), [s1])
@test isequal(Catalyst.get_species(rs), [s1])
@test isequal(Catalyst.get_ps(rs), [k1, c1])

@test convert(ModelingToolkit.ODESystem, rs) isa ODESystem
@test structural_simplify(convert(ModelingToolkit.ODESystem, rs)) isa ODESystem

# Test ODESystem constructor
odesys = ODESystem(MODEL1)
trueeqs = Equation[Differential(IV)(s1) ~ k1]
trueeqs = Equation[default_time_deriv()(s1) ~ k1]
@test isequal(Catalyst.get_eqs(odesys), trueeqs)
@test isequal(Catalyst.get_iv(odesys), IV)
@test isequal(Catalyst.get_states(odesys), [s1])
@test isequal(Catalyst.get_unknowns(odesys), [s1])
@test isequal(Catalyst.get_ps(odesys), [k1, c1])
u0 = [s1 => 1.0]
par = [k1 => 1.0, c1 => 2.0]
Expand All @@ -93,12 +93,12 @@ isequal(nameof(odesys), :odesys)

odesys = ODESystem(readSBML(sbmlfile))
m = readSBML(sbmlfile)
trueeqs = Equation[Differential(IV)(s1) ~ -(k1 * s1 * s2) / c1,
Differential(IV)(s1s2) ~ (k1 * s1 * s2) / c1,
Differential(IV)(s2) ~ -(k1 * s1 * s2) / c1]
trueeqs = Equation[default_time_deriv()(s1) ~ -((k1 * s1 * s2) / c1),
default_time_deriv()(s1s2) ~ (k1 * s1 * s2) / c1,
default_time_deriv()(s2) ~ -((k1 * s1 * s2) / c1)]
@test isequal(Catalyst.get_eqs(odesys), trueeqs)
@test isequal(Catalyst.get_iv(odesys), IV)
@test isequal(Catalyst.get_states(odesys), [s1, s1s2, s2])
@test isequal(Catalyst.get_unknowns(odesys), [s1, s1s2, s2])
@test isequal(Catalyst.get_ps(odesys), [k1, c1])
u0 = [s1 => 2 * 1.0, s2 => 2 * 1.0, s1s2 => 2 * 1.0]
par = [k1 => 1.0, c1 => 2.0]
Expand Down
2 changes: 1 addition & 1 deletion test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ MODEL1 = SBML.Model(parameters = Dict("D" => PARAM1, "Dv" => PARAM2),
species = Dict("B" => SPECIES1, "Bc" => SPECIES2),
rules = [RULE1])

const IV = Catalyst.DEFAULT_IV
const IV = default_t()
@species s1(IV)
# Test symbolicsRateOf
rate = SBMLToolkit.symbolicsRateOf(s1)
Expand Down
2 changes: 1 addition & 1 deletion test/wuschel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ m = readSBMLFromString(sbml, doc -> begin
end)
sys = ODESystem(m)
@test length(equations(sys)) == 1012
@test length(states(sys)) == 1012
@test length(unknowns(sys)) == 1012
#ssys = structural_simplify(sys) # Todo: Figure out why this complains about ExtraVariablesSystemException
prob = ODEProblem(sys, [], (0, 10.0))
solve(prob, Tsit5(), save_everystep = false)
Loading