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

Bifurcation kit extension #707

Merged
merged 35 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d5f50b9
init update
TorkelE Oct 24, 2023
131ebf3
save
TorkelE Oct 27, 2023
f4a8cce
allow defaults to be set in `convert` call
TorkelE Oct 28, 2023
d78643c
up
TorkelE Oct 31, 2023
54030de
Finish bifurcation function
TorkelE Oct 31, 2023
1202c04
add tests
TorkelE Nov 1, 2023
419edfc
add documentation
TorkelE Nov 1, 2023
6313833
Conservation law error check.
TorkelE Nov 1, 2023
ceadf0b
finalise
TorkelE Nov 1, 2023
3fd29cc
test updates
TorkelE Nov 6, 2023
0a2957b
require latest MTK version
TorkelE Nov 14, 2023
d52f005
up
TorkelE Nov 14, 2023
7c384d9
up
TorkelE Nov 14, 2023
b102d86
modification
TorkelE Nov 14, 2023
cc83200
history file update
TorkelE Nov 15, 2023
7006bc5
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
9c89d73
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
e95f423
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
dced2f7
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
09eabbf
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
db9a538
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
a2584f3
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
8ad3e54
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
8687770
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
618685e
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
f086b48
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
b335da3
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
e3d487c
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Nov 22, 2023
aa0d28a
up
TorkelE Nov 22, 2023
c23cf66
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Dec 3, 2023
75684d7
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Dec 3, 2023
7be2f68
Update docs/src/catalyst_applications/bifurcation_diagrams.md
TorkelE Dec 3, 2023
c564bac
up
TorkelE Dec 3, 2023
b78882d
better comment
TorkelE Dec 3, 2023
80e94d6
up
TorkelE Dec 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@
```
X's value will be `1.0` in the first vertex, but `0.0` in the remaining one (the system have 25 vertexes in total). SInce th parameters `p` and `d` are part of the non-spatial reaction network, their values are tied to vertexes. However, if the `D` parameter (which governs diffusion between vertexes) is given several values, these will instead correspond to the specific edges (and transportation along those edges.)

- Add a CatalystBifurcationKitExtension, permitting BifurcationKit's `BifurcationProblem`s to be created from Catalyst reaction networks. Example usage:
```julia
using Catalyst
wilhelm_2009_model = @reaction_network begin
k1, Y --> 2X
k2, 2X --> X + Y
k3, X + Y --> Y
k4, X --> 0
k5, 0 --> X
end


using BifurcationKit
bif_par = :k1
u_guess = [:X => 5.0, :Y => 2.0]
p_start = [:k1 => 4.0, :k2 => 1.0, :k3 => 1.0, :k4 => 1.5, :k5 => 1.25]
plot_var = :X
bprob = BifurcationProblem(wilhelm_2009_model, u_guess, p_start, bif_par; plot_var=plot_var)

p_span = (2.0, 20.0)
opts_br = ContinuationPar(p_min = p_span[1], p_max = p_span[2], max_steps=1000)

bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside=true)

using Plots
plot(bif_dia; xguide="k1", yguide="X")
```
- Automatically handles elimination of conservation laws for computing bifurcation diagrams.
- Updated Bifurcation documentation with respect to this new feature.

## Catalyst 13.5
- Added a CatalystHomotopyContinuationExtension extension, which exports the `hc_steady_state` function if HomotopyContinuation is exported. `hc_steady_state` finds the steady states of a reaction system using the homotopy continuation method. This feature is only available for julia versions 1.9+. Example:
Expand Down
9 changes: 7 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,25 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[weakdeps]
BifurcationKit = "0f109fa4-8a5d-4b75-95aa-f515264e7665"
HomotopyContinuation = "f213a82b-91d6-5c5d-acf7-10f1c761b327"

[extensions]
CatalystBifurcationKitExtension = "BifurcationKit"
CatalystHomotopyContinuationExtension = "HomotopyContinuation"

[compat]
TorkelE marked this conversation as resolved.
Show resolved Hide resolved
BifurcationKit = "0.3"
DataStructures = "0.18"
DiffEqBase = "6.83.0"
DocStringExtensions = "0.8, 0.9"
Graphs = "1.4"
JumpProcesses = "9.3.2"
HomotopyContinuation = "2.9"
LaTeXStrings = "1.3.0"
Latexify = "0.14, 0.15, 0.16"
MacroTools = "0.5.5"
ModelingToolkit = "8.66"
ModelingToolkit = "8.73"
Parameters = "0.12"
Reexport = "0.2, 1.0"
Requires = "1.0"
Expand All @@ -50,6 +54,7 @@ Unitful = "1.12.4"
julia = "1.9"

[extras]
BifurcationKit = "0f109fa4-8a5d-4b75-95aa-f515264e7665"
DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
Graphviz_jll = "3c863552-8265-54e4-a6dc-903eb78fde85"
HomotopyContinuation = "f213a82b-91d6-5c5d-acf7-10f1c761b327"
Expand All @@ -68,4 +73,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["DomainSets", "Graphviz_jll", "HomotopyContinuation", "NonlinearSolve", "OrdinaryDiffEq", "Random", "SafeTestsets", "SciMLBase", "SciMLNLSolve", "StableRNGs", "Statistics", "SteadyStateDiffEq", "StochasticDiffEq", "Test", "Unitful"]
test = ["BifurcationKit", "DomainSets", "Graphviz_jll", "HomotopyContinuation", "NonlinearSolve", "OrdinaryDiffEq", "Random", "SafeTestsets", "SciMLBase", "SciMLNLSolve", "StableRNGs", "Statistics", "SteadyStateDiffEq", "StochasticDiffEq", "Test", "Unitful"]
2 changes: 1 addition & 1 deletion docs/src/api/catalyst_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ netstoichmat
reactionrates
```

## Functions to extend or modify a network
## (Functions to extend or modify a network)(@id api_network_extension_and_modification)
`ReactionSystem`s can be programmatically extended using
[`@add_reactions`](@ref), [`addspecies!`](@ref), [`addparam!`](@ref) and
[`addreaction!`](@ref), or using [`ModelingToolkit.extend`](@ref) and
Expand Down
177 changes: 90 additions & 87 deletions docs/src/catalyst_applications/bifurcation_diagrams.md

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion docs/src/catalyst_applications/homotopy_continuation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ The order of the species in the output vectors are the same as in `species(wilhe

It should be noted that the steady state multivariate polynomials produced by reaction systems may have both imaginary and negative roots, which are filtered away by `hc_steady_states`. If you want the negative roots, you can use the `hc_steady_states(wilhelm_2009_model, ps; filter_negative=false)` argument.


## [Systems with conservation laws](@id homotopy_continuation_conservation_laws)
Some systems are under-determined, and have an infinite number of possible steady states. These are typically systems containing a conservation
law, e.g.
Expand Down
10 changes: 10 additions & 0 deletions ext/CatalystBifurcationKitExtension.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module CatalystBifurcationKitExtension

# Fetch packages.
using Catalyst
import BifurcationKit as BK

# Creates and exports hc_steady_states function.
include("CatalystBifurcationKitExtension/bifurcation_kit_extension.jl")

end
21 changes: 21 additions & 0 deletions ext/CatalystBifurcationKitExtension/bifurcation_kit_extension.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Dispatch for BifurcationKit BifurcationProblems ###

# Creates a BifurcationProblem, using a ReactionSystem as an input.
function BK.BifurcationProblem(rs::ReactionSystem, u0_bif, ps, bif_par, args...;
plot_var=nothing, record_from_solution=BK.record_sol_default, jac=true, u0=[], kwargs...)

# Converts symbols to symbolics.
(bif_par isa Symbol) && (bif_par = rs.var_to_name[bif_par])
(plot_var isa Symbol) && (plot_var = rs.var_to_name[plot_var])
((u0_bif isa Vector{<:Pair{Symbol,<:Any}}) || (u0_bif isa Dict{Symbol, <:Any})) && (u0_bif = symmap_to_varmap(rs, u0_bif))
((ps isa Vector{<:Pair{Symbol,<:Any}}) || (ps isa Dict{Symbol, <:Any})) && (ps = symmap_to_varmap(rs, ps))
((u0 isa Vector{<:Pair{Symbol,<:Any}}) || (u0 isa Dict{Symbol, <:Any})) && (u0 = symmap_to_varmap(rs, u0))

# Creates NonlinearSystem.
Catalyst.conservationlaw_errorcheck(rs, vcat(ps, u0))
nsys = convert(NonlinearSystem, rs; remove_conserved=true, defaults=Dict(u0))
TorkelE marked this conversation as resolved.
Show resolved Hide resolved

# Makes BifurcationProblem (this call goes through the ModelingToolkit-based BifurcationKit extension).
return BK.BifurcationProblem(nsys, u0_bif, ps, bif_par, args...; plot_var=plot_var,
record_from_solution=record_from_solution, jac=jac, kwargs...)
end
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function steady_state_polynomial(rs::ReactionSystem, ps, u0)
rs = Catalyst.expand_registered_functions(rs)
ns = convert(NonlinearSystem, rs; remove_conserved = true)
pre_varmap = [symmap_to_varmap(rs,u0)..., symmap_to_varmap(rs,ps)...]
conservationlaw_errorcheck(rs, pre_varmap)
Catalyst.conservationlaw_errorcheck(rs, pre_varmap)
p_vals = ModelingToolkit.varmap_to_vars(pre_varmap, parameters(ns); defaults = ModelingToolkit.defaults(ns))
p_dict = Dict(parameters(ns) .=> p_vals)
eqs_pars_funcs = vcat(equations(ns), conservedequations(rs))
Expand Down
12 changes: 12 additions & 0 deletions src/networkapi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,18 @@ Compute conserved quantities for a system with the given conservation laws.
"""
conservedquantities(state, cons_laws) = cons_laws * state


# If u0s are not given while conservation laws are present, throws an error.
# Used in HomotopyContinuation and BifurcationKit extensions.
# Currently only checks if any u0s are given
# (not whether these are enough for computing conserved quantitites, this will yield a less informative error).
function conservationlaw_errorcheck(rs, pre_varmap)
vars_with_vals = Set(p[1] for p in pre_varmap)
any(s -> s in vars_with_vals, species(rs)) && return
isempty(conservedequations(Catalyst.flatten(rs))) ||
error("The system has conservation laws but initial conditions were not provided for some species.")
end

######################## reaction network operators #######################

"""
Expand Down
13 changes: 9 additions & 4 deletions src/reactionsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,7 @@ Keyword args and default values:
function Base.convert(::Type{<:ODESystem}, rs::ReactionSystem; name = nameof(rs),
combinatoric_ratelaws = get_combinatoric_ratelaws(rs),
include_zero_odes = true, remove_conserved = false, checks = false,
default_u0 = Dict(), default_p = Dict(), defaults = _merge(Dict(default_u0), Dict(default_p)),
kwargs...)
spatial_convert_err(rs::ReactionSystem, ODESystem)
fullrs = Catalyst.flatten(rs)
Expand All @@ -1299,7 +1300,7 @@ function Base.convert(::Type{<:ODESystem}, rs::ReactionSystem; name = nameof(rs)
ODESystem(eqs, get_iv(fullrs), sts, ps;
observed = obs,
name,
defaults = defs,
defaults = _merge(defaults,defs),
checks,
continuous_events = MT.get_continuous_events(fullrs),
discrete_events = MT.get_discrete_events(fullrs),
Expand All @@ -1326,6 +1327,7 @@ Keyword args and default values:
function Base.convert(::Type{<:NonlinearSystem}, rs::ReactionSystem; name = nameof(rs),
combinatoric_ratelaws = get_combinatoric_ratelaws(rs),
include_zero_odes = true, remove_conserved = false, checks = false,
default_u0 = Dict(), default_p = Dict(), defaults = _merge(Dict(default_u0), Dict(default_p)),
kwargs...)
spatial_convert_err(rs::ReactionSystem, NonlinearSystem)
fullrs = Catalyst.flatten(rs)
Expand All @@ -1339,7 +1341,7 @@ function Base.convert(::Type{<:NonlinearSystem}, rs::ReactionSystem; name = name
NonlinearSystem(eqs, sts, ps;
name,
observed = obs,
defaults = defs,
defaults = _merge(defaults,defs),
checks,
kwargs...)
end
Expand Down Expand Up @@ -1375,6 +1377,7 @@ function Base.convert(::Type{<:SDESystem}, rs::ReactionSystem;
noise_scaling = nothing, name = nameof(rs),
combinatoric_ratelaws = get_combinatoric_ratelaws(rs),
include_zero_odes = true, checks = false, remove_conserved = false,
default_u0 = Dict(), default_p = Dict(), defaults = _merge(Dict(default_u0), Dict(default_p)),
kwargs...)
spatial_convert_err(rs::ReactionSystem, SDESystem)

Expand Down Expand Up @@ -1435,7 +1438,9 @@ Notes:
"""
function Base.convert(::Type{<:JumpSystem}, rs::ReactionSystem; name = nameof(rs),
combinatoric_ratelaws = get_combinatoric_ratelaws(rs),
remove_conserved = nothing, checks = false, kwargs...)
remove_conserved = nothing, checks = false,
default_u0 = Dict(), default_p = Dict(), defaults = _merge(Dict(default_u0), Dict(default_p)),
kwargs...)
spatial_convert_err(rs::ReactionSystem, JumpSystem)

(remove_conserved !== nothing) &&
Expand All @@ -1457,7 +1462,7 @@ function Base.convert(::Type{<:JumpSystem}, rs::ReactionSystem; name = nameof(rs
JumpSystem(eqs, get_iv(flatrs), sts, ps;
observed = MT.observed(flatrs),
name,
defaults = MT.defaults(flatrs),
defaults = _merge(defaults,MT.defaults(flatrs)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does merging after flattening give the correct namespacing of parameters and variables? This seems like it is going to cause problems. Merging probably needs to happen before flattening.

Copy link
Member Author

@TorkelE TorkelE Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not, that is a good point. I just used the current order of things, but if you suggest changing than that is be better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test to check this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean providing defaults to a convert for a system with sub-systems, which got defaults?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

checks,
discrete_events = MT.discrete_events(flatrs),
kwargs...)
Expand Down
173 changes: 173 additions & 0 deletions test/extensions/bifurcation_kit.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
### Fetch Packages ###
using BifurcationKit, Catalyst, Test

# Sets rnd number.
using StableRNGs
rng = StableRNG(12345)

### Run Tests ###

# Brusselator extended with conserved species.
# Runs full computation, checks values corresponds to known values.
# Checks that teh correct bifurcation point is found at the correct position.
# Checks that bifurcation diagrams can be computed for systems with conservation laws.
# Checks that bifurcation diagrams can be computed for systems with default values.
# Checks that bifurcation diagrams can be computed for systems with non-constant rate.
# Checks that not providing conserved species throws and appropriate error.
let
# Create model.
extended_brusselator = @reaction_network begin
@species W(t) = 2.0
@parameters k2 = 0.5
A, ∅ → X
1, 2X + Y → 3X
B, X → Y
1, X → ∅
(k1*Y, k2), V <--> W
end
@unpack A, B, k1 = extended_brusselator
u0_guess = [:X => 1.0, :Y => 1.0, :V => 0.0, :W => 0.0]
p_start = [A => 1.0, B => 4.0, k1 => 0.1]

# Computes bifurcation diagram.
bprob = BifurcationProblem(extended_brusselator, u0_guess, p_start, :B; plot_var = :V, u0 = [:V => 1.0])
p_span = (0.1, 6.0)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)

# Checks computed V values are correct (Formula: V = k2*(V0+W0)/(k1*Y+k2), where Y=2*B.)
B_vals = getfield.(bif_dia.γ.branch, :param)
V_vals = getfield.(bif_dia.γ.branch, :x)
@test all(V_vals .≈ 0.5*(1.0+2.0) ./ (0.1 .* 2*B_vals .+ 0.5))

# Checks that the bifurcation point is correct.
@test length(bif_dia.γ.specialpoint) == 3 # Includes start and end point.
hopf_bif_point = filter(sp -> sp.type == :hopf, bif_dia.γ.specialpoint)[1]
@test isapprox(hopf_bif_point.param, 1.5, atol=1e-5)

# Tests that an error is thrown if information of conserved species is not fully provided.
@test_throws Exception BifurcationProblem(extended_brusselator, u0_guess, p_start, :B; plot_var=:V, u0 = [:X => 1.0])
end

# Bistable switch.
# Checks that the same bifurcation problem is created as for BifurcationKit.
# Checks with Symbolics as bifurcation and plot vars.
# Tries setting `jac=false`.
let
# Creates BifurcationProblem via Catalyst.
bistable_switch = @reaction_network begin
0.1 + hill(X,v,K,n), 0 --> X
d, X --> 0
end
@unpack X, v, K, n, d = bistable_switch
u0_guess = [X => 1.0]
p_start = [v => 5.0, K => 2.5, n => 3, d => 1.0]
bprob = BifurcationProblem(bistable_switch, u0_guess, p_start, K; jac=false, plot_var=X)

# Creates BifurcationProblem via BifurcationKit.
function bistable_switch_BK(u, p)
X, = u
v, K, n, d = p
return [0.1 + v*(X^n)/(X^n + K^n) - d*X]
end
bprob_BK = BifurcationProblem(bistable_switch_BK, [1.0], [5.0, 2.5, 3, 1.0], (@lens _[1]); record_from_solution = (x, p) -> x[1])

# Check the same function have been generated.
bprob.u0 == bprob_BK.u0
bprob.params == bprob_BK.params
for repeat = 1:20
u0 = rand(rng, 1)
p = rand(rng, 4)
@test bprob_BK.VF.F(u0, p) == bprob.VF.F(u0, p)
end
end

# Creates a system where rn is composed of 4, somewhat nested, networks.
# Tests with defaults within nested networks.
let
rn1 = @reaction_network rn1 begin
@parameters p=1.0
(p, d), 0 <--> X
end
rn2 = @reaction_network rn2 begin
@parameters p=2.0
(p, d), 0 <--> X
end
rn3 = @reaction_network rn3 begin
@parameters p=3.0
(p, d), 0 <--> X
end
rn4 = @reaction_network rn4 begin
@parameters p=4.0
(p, d), 0 <--> X
end
@named rn3 =compose(rn3, [rn4])
@named rn = compose(rn1, [rn2, rn3])

# Declares parameter values and initial u guess.
@unpack X, d = rn
u0_guess = [X => 1.0, rn2.X => 1.0, rn3.X => 1.0, rn3.rn4.X => 1.0]
p_start = [d => 1.0, rn2.d => 1.0, rn3.d => 1.0, rn3.rn4.d => 1.0]


# Computes bifurcation diagrams and check them (the final point at [p_value = 6] should be =[p/d]).
p_span = (0.1, 6.0)

let
# Checks top layer.
bprob = BifurcationProblem(rn, u0_guess, p_start, d; plot_var = X)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)
@test bif_dia.γ.branch[end].x ≈ 1.0/6

# Checks second layer (1).
bprob = BifurcationProblem(rn, u0_guess, p_start, rn2.d; plot_var = rn2.X)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)
@test bif_dia.γ.branch[end].x ≈ 2.0/6

# Checks second layer (2).
bprob = BifurcationProblem(rn, u0_guess, p_start, rn3.d; plot_var = rn3.X)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)
@test bif_dia.γ.branch[end].x ≈ 3.0/6

# Checks third layer.
bprob = BifurcationProblem(rn, u0_guess, p_start, rn3.rn4.d; plot_var = rn3.rn4.X)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)
@test bif_dia.γ.branch[end].x ≈ 4.0/6
end
end

# Tests for nested model with conservation laws.
let
# Creates model.
rn1 = @reaction_network rn1 begin
(k1, k2), X1 <--> X2
end
rn2 = @reaction_network rn2 begin
(l1, l2), Y1 <--> Y2
end
@named rn = compose(rn1, [rn2])

# Creates input parameter and species vectors.
@unpack X1, X2, k1, k2 = rn1
u_guess = [X1 => 1.0, X2 => 1.0, rn2.Y1 => 1.0, rn2.Y2 => 1.0]
p_start = [k1 => 1.0, k2 => 1.0, rn2.l1 => 1.0, rn2.l2 => 1.0]
u0 = [X1 => 1.0, X2 => 0.0, rn2.Y1 => 1.0, rn2.Y2 => 0.0]

# Computes bifurcation diagram.
p_span = (0.2, 5.0)
bprob = BifurcationProblem(rn, u_guess, p_start, k1; plot_var = X1, u0=u0)
opts_br = ContinuationPar(dsmin = 0.0001, dsmax = 0.001, ds = 0.0001, max_steps = 10000, p_min = p_span[1], p_max = p_span[2], n_inversion = 4)
bif_dia = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside = true)

# Checks that the bifurcation diagram is correct.
xs = getfield.(bif_dia.γ.branch, :x)
k1s = getfield.(bif_dia.γ.branch, :param)
@test all(1 ./ k1s .* (1 .- xs) .≈ xs)

# Checks that there is an error if information for conserved quantities computation is not provided.
@test_throws Exception bprob = BifurcationProblem(rn, u_guess, p_start, k1; plot_var = X1)
end
Loading
Loading