Skip to content

Commit

Permalink
Merge pull request #161 from SciML/pl/fix_high_stoichiometries
Browse files Browse the repository at this point in the history
omit conversion to mass action for stoichiometries > 100 to avoid StackOverflow in simplify_fractions
  • Loading branch information
paulflang authored Jul 4, 2024
2 parents 0a74b5d + c909d5a commit 18ebab7
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SBMLToolkit"
uuid = "86080e66-c8ac-44c2-a1a0-9adaadfe4a4e"
authors = ["paulflang", "anandijain"]
version = "0.1.25"
version = "0.1.26"

[deps]
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
Expand Down
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,43 @@ Pkg.add("SBMLToolkit")
SBML models can be simulated with the following steps (note that `sol` is in absolute quantities rather than concentrations):

```julia
using SBMLToolkit, ModelingToolkit, OrdinaryDiffEq
using SBMLToolkit, OrdinaryDiffEq

SBMLToolkit.checksupport_file("my_model.xml")
mdl = readSBML("my_model.xml", doc -> begin
set_level_and_version(3, 2)(doc)
convert_promotelocals_expandfuns(doc)
end)

rs = ReactionSystem(mdl) # If you want to create a reaction system
odesys = convert(ODESystem, rs) # Alternatively: ODESystem(mdl)
odesys = readSBML("my_model.xml", ODESystemImporter())

tspan = (0.0, 1.0)
prob = ODEProblem(odesys, [], tspan, [])
sol = solve(prob, Tsit5())
```

Alternatively, SBMLToolkit also provides more concise methods to import `SBML.Models`, `Catalyst.ReactionSystems`, and `ModelingToolkit.ODESystems`.
While this imports an `ODESystem` directly, you can also import a Catalyst.jl `ReactionSystem`:

```julia
mdl = readSBML("my_model.xml", DefaultImporter())
using SBMLToolkit

rs = readSBML("my_model.xml", ReactionSystemImporter())
odesys = readSBML("my_model.xml", ODESystemImporter())
```

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)

```julia
using SBML

mdl = readSBML("my_model.xml", doc -> begin
set_level_and_version(3, 2)(doc)
convert_promotelocals_expandfuns(doc)
end)
```

The conversion to SBML level 3 version 2 is necessary, because older versions are not well supported in SBMLToolkit. `convert_promotelocals_expandfuns` basically flattens the SBML before the import. Once you have obtained the `Model`, you can convert it to a `ReactionSystem` and `ODESystem`.

```julia
using SBMLToolkit

rs = ReactionSystem(mdl)
odesys = convert(ODESystem, rs)
```

## License
Expand Down
4 changes: 3 additions & 1 deletion src/reactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function get_reagents(reactant_references::Vector{SBML.SpeciesReference},
sn = rr.species
stoich = rr.stoichiometry
if isnothing(stoich)
@warn "Stoichiometries of SpeciesReferences are not defined. Setting to 1." maxlog=1
@warn "SBML SpeciesReferences does not contain stoichiometries. Assuming stoichiometry of 1." maxlog=1
stoich = 1.0
end
iszero(stoich) && @error("Stoichiometry of $sn must be non-zero")
Expand Down Expand Up @@ -183,6 +183,8 @@ function get_massaction(kl::Num, reactants::Union{Vector{Num}, Nothing},
rate_const = kl
elseif isnothing(reactants) | isnothing(stoich)
throw(ErrorException("`reactants` and `stoich` are inconsistent: `reactants` are $(reactants) and `stoich` is $(stoich)."))
elseif max(stoich...) > 100 # simplify_fractions might StackOverflow
rate_const = kl
else
rate_const = SymbolicUtils.simplify_fractions(kl / *((.^(reactants, stoich))...))
end
Expand Down
1 change: 1 addition & 0 deletions test/reactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ m = SBML.Model(species = Dict("s" => s), reactions = Dict("r1" => r))
@test isequal(SBMLToolkit.get_massaction(k1 + c1, nothing, nothing), k1 + c1) # Case zero order kineticLaw
@test isnan(SBMLToolkit.get_massaction(k1 * s1 * s2 / (c1 + s2), [s1], [1])) # Case Michaelis-Menten kinetics
@test isnan(SBMLToolkit.get_massaction(k1 * s1 * IV, [s1], [1])) # Case kineticLaw with time
@test isnan(SBMLToolkit.get_massaction(k1 * s1, [s1], [101])) # Case no simplification performed due to large rstoich

@test isnan(SBMLToolkit.get_massaction(k1 * s1 * s2, [s1], [1]))
@test isnan(SBMLToolkit.get_massaction(k1 + c1, [s1], [1]))
Expand Down

0 comments on commit 18ebab7

Please sign in to comment.