Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
TorkelE committed Jun 7, 2024
1 parent 5277a2c commit b7b6e8b
Show file tree
Hide file tree
Showing 28 changed files with 891 additions and 768 deletions.
24 changes: 12 additions & 12 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ include("pages.jl")
# pages = pages)

makedocs(sitename = "Catalyst.jl",
authors = "Samuel Isaacson",
format = Documenter.HTML(; analytics = "UA-90474609-3",
prettyurls = (get(ENV, "CI", nothing) == "true"),
assets = ["assets/favicon.ico"],
canonical = "https://docs.sciml.ai/Catalyst/stable/"),
modules = [Catalyst, ModelingToolkit],
doctest = false,
clean = true,
pages = pages,
pagesonly = true,
warnonly = true)
authors = "Samuel Isaacson",
format = Documenter.HTML(; analytics = "UA-90474609-3",
prettyurls = (get(ENV, "CI", nothing) == "true"),
assets = ["assets/favicon.ico"],
canonical = "https://docs.sciml.ai/Catalyst/stable/"),
modules = [Catalyst, ModelingToolkit],
doctest = false,
clean = true,
pages = pages,
pagesonly = true,
warnonly = true)

deploydocs(repo = "github.com/SciML/Catalyst.jl.git";
push_preview = true)
push_preview = true)
20 changes: 8 additions & 12 deletions docs/pages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ pages = Any[
"Home" => "index.md",
"Introduction to Catalyst" => Any[
"introduction_to_catalyst/catalyst_for_new_julia_users.md",
# "introduction_to_catalyst/introduction_to_catalyst.md"
# Advanced introduction.
# "introduction_to_catalyst/introduction_to_catalyst.md"
# Advanced introduction.
],
"Model Creation and Properties" => Any[
"model_creation/dsl_basics.md",
Expand All @@ -21,8 +21,7 @@ pages = Any[
"Model creation examples" => Any[
"model_creation/examples/basic_CRN_library.md",
"model_creation/examples/programmatic_generative_linear_pathway.md",
"model_creation/examples/hodgkin_huxley_equation.md",
#"model_creation/examples/smoluchowski_coagulation_equation.md"
"model_creation/examples/hodgkin_huxley_equation.md" #"model_creation/examples/smoluchowski_coagulation_equation.md"
]
],
"Model simulation" => Any[
Expand All @@ -31,15 +30,12 @@ pages = Any[
"model_simulation/simulation_structure_interfacing.md",
"model_simulation/ensemble_simulations.md",
# Stochastic simulation statistical analysis.
"model_simulation/ode_simulation_performance.md",
# SDE Performance considerations/advice.
# Jump Performance considerations/advice.
# Finite state projection
"model_simulation/ode_simulation_performance.md" # SDE Performance considerations/advice. # Jump Performance considerations/advice. # Finite state projection
],
"Steady state analysis" => Any[
"steady_state_functionality/homotopy_continuation.md",
"steady_state_functionality/nonlinear_solve.md",
"steady_state_functionality/steady_state_stability_computation.md",
"steady_state_functionality/steady_state_stability_computation.md",
"steady_state_functionality/bifurcation_diagrams.md",
"steady_state_functionality/dynamical_systems.md"
],
Expand All @@ -58,9 +54,9 @@ pages = Any[
]
],
"Spatial modelling" => Any[
# Intro.
# Lattice ODEs.
# Lattice Jumps.
# Intro.
# Lattice ODEs.
# Lattice Jumps.
],
# "Developer Documentation" => Any[
# # Contributor's guide.
Expand Down
2 changes: 1 addition & 1 deletion ext/CatalystBifurcationKitExtension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import BifurcationKit as BK
# Creates and exports hc_steady_states function.
include("CatalystBifurcationKitExtension/bifurcation_kit_extension.jl")

end
end
22 changes: 13 additions & 9 deletions ext/CatalystBifurcationKitExtension/bifurcation_kit_extension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@

# 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...)
if !isautonomous(rs)
plot_var = nothing, record_from_solution = BK.record_sol_default, jac = true, u0 = [], kwargs...)
if !isautonomous(rs)
error("Attempting to create a `BifurcationProblem` for a non-autonomous system (e.g. where some rate depend on $(rs.iv)). This is not possible.")
end

# Converts symbols to symbolics.
(bif_par isa Symbol) && (bif_par = ModelingToolkit.get_var_to_name(rs)[bif_par])
(plot_var isa Symbol) && (plot_var = ModelingToolkit.get_var_to_name(rs)[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))
((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 = complete(convert(NonlinearSystem, rs; remove_conserved=true, defaults=Dict(u0)))
nsys = complete(convert(
NonlinearSystem, rs; remove_conserved = true, defaults = Dict(u0)))

# 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
return BK.BifurcationProblem(nsys, u0_bif, ps, bif_par, args...; plot_var = plot_var,
record_from_solution = record_from_solution, jac = jac, kwargs...)
end
2 changes: 1 addition & 1 deletion ext/CatalystHomotopyContinuationExtension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ import Symbolics: unwrap, wrap, Rewriters, symtype, issym, istree
# Creates and exports hc_steady_states function.
include("CatalystHomotopyContinuationExtension/homotopy_continuation_extension.jl")

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ Notes:
- Homotopy-based steady state finding only works when all rates are rational polynomials (e.g. constant, linear, mm, or hill functions).
```
"""
function Catalyst.hc_steady_states(rs::ReactionSystem, ps; filter_negative=true, neg_thres=-1e-20, u0=[], kwargs...)
if !isautonomous(rs)
function Catalyst.hc_steady_states(rs::ReactionSystem, ps; filter_negative = true,
neg_thres = -1e-20, u0 = [], kwargs...)
if !isautonomous(rs)
error("Attempting to compute steady state for a non-autonomous system (e.g. where some rate depend on $(rs.iv)). This is not possible.")
end
ss_poly = steady_state_polynomial(rs, ps, u0)
Expand All @@ -49,10 +50,11 @@ end
function steady_state_polynomial(rs::ReactionSystem, ps, u0)
rs = Catalyst.expand_registered_functions(rs)
ns = complete(convert(NonlinearSystem, rs; remove_conserved = true))
pre_varmap = [symmap_to_varmap(rs,u0)..., symmap_to_varmap(rs,ps)...]
pre_varmap = [symmap_to_varmap(rs, u0)..., symmap_to_varmap(rs, ps)...]
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)
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))
eqs = map(eq -> substitute(eq.rhs - eq.lhs, p_dict), eqs_pars_funcs)
eqs_intexp = make_int_exps.(eqs)
Expand All @@ -61,12 +63,14 @@ function steady_state_polynomial(rs::ReactionSystem, ps, u0)
end

# Parses and expression and return a version where any exponents that are Float64 (but an int, like 2.0) are turned into Int64s.
make_int_exps(expr) = wrap(Rewriters.Postwalk(Rewriters.PassThrough(___make_int_exps))(unwrap(expr))).val
function make_int_exps(expr)
wrap(Rewriters.Postwalk(Rewriters.PassThrough(___make_int_exps))(unwrap(expr))).val
end
function ___make_int_exps(expr)
!istree(expr) && return expr
if (operation(expr) == ^)
if (operation(expr) == ^)
if isinteger(arguments(expr)[2])
return arguments(expr)[1] ^ Int64(arguments(expr)[2])
return arguments(expr)[1]^Int64(arguments(expr)[2])
else
error("An non integer ($(arguments(expr)[2])) was found as a variable exponent. Non-integer exponents are not supported for homotopy continuation based steady state finding.")
end
Expand Down Expand Up @@ -95,7 +99,7 @@ function reorder_sols!(sols, ss_poly, rs::ReactionSystem)
end

# Filters away solutions with negative species concentrations (and for neg_thres < val < 0.0, sets val=0.0).
function filter_negative_f(sols; neg_thres=-1e-20)
function filter_negative_f(sols; neg_thres = -1e-20)
for sol in sols, idx in 1:length(sol)
(neg_thres < sol[idx] < 0) && (sol[idx] = 0)
end
Expand All @@ -104,9 +108,13 @@ end

# Sometimes (when polynomials are created from coupled CRN/DAEs), the steady state polynomial have the wrong type.
# This converts it to the correct type, which homotopy continuation can handle.
const WRONG_POLY_TYPE = Vector{DynamicPolynomials.Polynomial{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, DynamicPolynomials.Graded{DynamicPolynomials.LexOrder}}}
const CORRECT_POLY_TYPE = Vector{DynamicPolynomials.Polynomial{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, DynamicPolynomials.Graded{DynamicPolynomials.LexOrder}, Float64}}
const WRONG_POLY_TYPE = Vector{DynamicPolynomials.Polynomial{
DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder},
DynamicPolynomials.Graded{DynamicPolynomials.LexOrder}}}
const CORRECT_POLY_TYPE = Vector{DynamicPolynomials.Polynomial{
DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder},
DynamicPolynomials.Graded{DynamicPolynomials.LexOrder}, Float64}}
function poly_type_convert(ss_poly)
(typeof(ss_poly) == WRONG_POLY_TYPE) && return convert(CORRECT_POLY_TYPE, ss_poly)
return ss_poly
end
end
2 changes: 1 addition & 1 deletion ext/CatalystStructuralIdentifiabilityExtension.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import StructuralIdentifiability as SI
# Creates and exports hc_steady_states function.
include("CatalystStructuralIdentifiabilityExtension/structural_identifiability_extension.jl")

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ Notes:
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
"""
function Catalyst.make_si_ode(rs::ReactionSystem; measured_quantities = [], known_p = [],
ignore_no_measured_warn = false, remove_conserved = true)
function Catalyst.make_si_ode(rs::ReactionSystem; measured_quantities = [], known_p = [],
ignore_no_measured_warn = false, remove_conserved = true)
# Creates a MTK ODESystem, and a list of measured quantities (there are equations).
# Gives these to SI to create an SI ode model of its preferred form.
osys, conseqs, _ = make_osys(rs; remove_conserved)
measured_quantities = make_measured_quantities(rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
measured_quantities = make_measured_quantities(
rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
return SI.mtk_to_si(osys, measured_quantities)[1]
end

Expand Down Expand Up @@ -62,16 +63,19 @@ Notes:
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
"""
function SI.assess_local_identifiability(rs::ReactionSystem, args...; measured_quantities = [],
known_p = [], funcs_to_check = Vector(), remove_conserved = true,
ignore_no_measured_warn=false, kwargs...)
function SI.assess_local_identifiability(
rs::ReactionSystem, args...; measured_quantities = [],
known_p = [], funcs_to_check = Vector(), remove_conserved = true,
ignore_no_measured_warn = false, kwargs...)
# Creates a ODESystem, list of measured quantities, and functions to check, of SI's preferred form.
osys, conseqs, vars = make_osys(rs; remove_conserved)
measured_quantities = make_measured_quantities(rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
measured_quantities = make_measured_quantities(
rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
funcs_to_check = make_ftc(funcs_to_check, conseqs, vars)

# Computes identifiability and converts it to a easy to read form.
out = SI.assess_local_identifiability(osys, args...; measured_quantities, funcs_to_check, kwargs...)
out = SI.assess_local_identifiability(
osys, args...; measured_quantities, funcs_to_check, kwargs...)
return make_output(out, funcs_to_check, reverse.(conseqs))
end

Expand Down Expand Up @@ -100,16 +104,19 @@ Notes:
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
"""
function SI.assess_identifiability(rs::ReactionSystem, args...; measured_quantities = [], known_p = [],
funcs_to_check = Vector(), remove_conserved = true,
ignore_no_measured_warn=false, kwargs...)
function SI.assess_identifiability(
rs::ReactionSystem, args...; measured_quantities = [], known_p = [],
funcs_to_check = Vector(), remove_conserved = true,
ignore_no_measured_warn = false, kwargs...)
# Creates a ODESystem, list of measured quantities, and functions to check, of SI's preferred form.
osys, conseqs, vars = make_osys(rs; remove_conserved)
measured_quantities = make_measured_quantities(rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
measured_quantities = make_measured_quantities(
rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
funcs_to_check = make_ftc(funcs_to_check, conseqs, vars)

# Computes identifiability and converts it to a easy to read form.
out = SI.assess_identifiability(osys, args...; measured_quantities, funcs_to_check, kwargs...)
out = SI.assess_identifiability(
osys, args...; measured_quantities, funcs_to_check, kwargs...)
return make_output(out, funcs_to_check, reverse.(conseqs))
end

Expand Down Expand Up @@ -138,12 +145,14 @@ Notes:
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
"""
function SI.find_identifiable_functions(rs::ReactionSystem, args...; measured_quantities = [],
known_p = [], remove_conserved = true, ignore_no_measured_warn=false,
kwargs...)
function SI.find_identifiable_functions(
rs::ReactionSystem, args...; measured_quantities = [],
known_p = [], remove_conserved = true, ignore_no_measured_warn = false,
kwargs...)
# Creates a ODESystem, and list of measured quantities, of SI's preferred form.
osys, conseqs = make_osys(rs; remove_conserved)
measured_quantities = make_measured_quantities(rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)
measured_quantities = make_measured_quantities(
rs, measured_quantities, known_p, conseqs; ignore_no_measured_warn)

# Computes identifiable functions and converts it to a easy to read form.
out = SI.find_identifiable_functions(osys, args...; measured_quantities, kwargs...)
Expand All @@ -154,10 +163,11 @@ end

# From a reaction system, creates the corresponding MTK-style ODESystem for SI application
# Also compute the, later needed, conservation law equations and list of system symbols (unknowns and parameters).
function make_osys(rs::ReactionSystem; remove_conserved=true)
function make_osys(rs::ReactionSystem; remove_conserved = true)
# Creates the ODESystem corresponding to the ReactionSystem (expanding functions and flattening it).
# Creates a list of the systems all symbols (unknowns and parameters).
ModelingToolkit.iscomplete(rs) || error("Identifiability should only be computed for complete systems. A ReactionSystem can be marked as complete using the `complete` function.")
ModelingToolkit.iscomplete(rs) ||
error("Identifiability should only be computed for complete systems. A ReactionSystem can be marked as complete using the `complete` function.")
rs = complete(Catalyst.expand_registered_functions(flatten(rs)))
osys = complete(convert(ODESystem, rs; remove_conserved))
vars = [unknowns(rs); parameters(rs)]
Expand All @@ -177,10 +187,11 @@ end
# Creates a list of measured quantities of a form that SI can read.
# Each measured quantity must have a form like:
# `obs_var ~ X` # (Here, `obs_var` is a variable, and X is whatever we can measure).
function make_measured_quantities(rs::ReactionSystem, measured_quantities::Vector{T}, known_p::Vector{S},
conseqs; ignore_no_measured_warn=false) where {T,S}
function make_measured_quantities(
rs::ReactionSystem, measured_quantities::Vector{T}, known_p::Vector{S},
conseqs; ignore_no_measured_warn = false) where {T, S}
# Warning if the user didn't give any measured quantities.
if ignore_no_measured_warn || isempty(measured_quantities)
if ignore_no_measured_warn || isempty(measured_quantities)
@warn "No measured quantity provided to the `measured_quantities` argument, any further identifiability analysis will likely fail. You can disable this warning by setting `ignore_no_measured_warn=true`."
end

Expand All @@ -192,7 +203,8 @@ function make_measured_quantities(rs::ReactionSystem, measured_quantities::Vecto
# Creates one internal observation variable for each measured quantity (`___internal_observables`).
# Creates a vector of equations, setting each measured quantity equal to one observation variable.
@variables t (___internal_observables(Catalyst.get_iv(rs)))[1:length(mqs)]
return Equation[(q isa Equation) ? q : (___internal_observables[i] ~ q) for (i,q) in enumerate(mqs)]
return Equation[(q isa Equation) ? q : (___internal_observables[i] ~ q)
for (i, q) in enumerate(mqs)]
end

# Creates the functions that we wish to check for identifiability.
Expand All @@ -211,9 +223,9 @@ end
function make_output(out, funcs_to_check, conseqs)
funcs_to_check = vector_subs(funcs_to_check, conseqs)
out = Dict(zip(vector_subs(keys(out), conseqs), values(out)))
sortdict = Dict(ftc => i for (i,ftc) in enumerate(funcs_to_check))
return sort(out; by = x -> sortdict[x])
sortdict = Dict(ftc => i for (i, ftc) in enumerate(funcs_to_check))
return sort(out; by = x -> sortdict[x])
end

# For a vector of expressions and a conservation law, substitutes the law into every equation.
vector_subs(eqs, subs) = [substitute(eq, subs) for eq in eqs]
vector_subs(eqs, subs) = [substitute(eq, subs) for eq in eqs]
Loading

0 comments on commit b7b6e8b

Please sign in to comment.