Skip to content

Commit f94fe04

Browse files
committed
save prorgess
1 parent c9ff227 commit f94fe04

File tree

3 files changed

+71
-43
lines changed

3 files changed

+71
-43
lines changed

src/dsl.jl

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,6 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
315315
parameters_declared = extract_syms(options, :parameters)
316316
variables_declared = extract_syms(options, :variables)
317317

318-
# Reads equations.
319-
vars_extracted, add_default_diff, equations = read_equations_options(
320-
options, variables_declared)
321-
variables = vcat(variables_declared, vars_extracted)
322-
323318
# Handle independent variables
324319
if haskey(options, :ivs)
325320
ivs = Tuple(extract_syms(options, :ivs))
@@ -339,23 +334,29 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
339334
combinatoric_ratelaws = true
340335
end
341336

342-
# Reads observables.
343-
observed_vars, observed_eqs, obs_syms = read_observed_options(
344-
options, [species_declared; variables], all_ivs)
345-
346-
# Collect species and parameters, including ones inferred from the reactions.
337+
# Collect species and parameters.
347338
declared_syms = Set(Iterators.flatten((parameters_declared, species_declared,
348-
variables)))
339+
variables_declared)))
349340
species_extracted, parameters_extracted = extract_species_and_parameters!(
350341
reactions, declared_syms)
351342

352343
species = vcat(species_declared, species_extracted)
353344
parameters = vcat(parameters_declared, parameters_extracted)
354345

346+
# Reads equations.
347+
designated_syms = [species; parameters; variables_declared]
348+
vars_extracted, add_default_diff, equations = read_equations_options(
349+
options, designated_syms)
350+
variables = vcat(variables_declared, vars_extracted)
351+
355352
# Create differential expression.
356353
diffexpr = create_differential_expr(
357354
options, add_default_diff, [species; parameters; variables], tiv)
358355

356+
# Reads observables.
357+
observed_vars, observed_eqs, obs_syms = read_observed_options(
358+
options, [species_declared; variables], all_ivs)
359+
359360
# Checks for input errors.
360361
(sum(length.([reaction_lines, option_lines])) != length(ex.args)) &&
361362
error("@reaction_network input contain $(length(ex.args) - sum(length.([reaction_lines,option_lines]))) malformed lines.")
@@ -384,7 +385,7 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
384385
push!(rxexprs.args, equation)
385386
end
386387

387-
# Output code corresponding to the reaction system.
388+
# Output code corresponding to the reaction system.
388389
quote
389390
$ivexpr
390391
$ps
@@ -682,7 +683,7 @@ end
682683
# `vars_extracted`: A vector with extracted variables (lhs in pure differential equations only).
683684
# `dtexpr`: If a differential equation is defined, the default derivative (D ~ Differential(t)) must be defined.
684685
# `equations`: a vector with the equations provided.
685-
function read_equations_options(options, variables_declared)
686+
function read_equations_options(options, syms_declared)
686687
# Prepares the equations. First, extracts equations from provided option (converting to block form if required).
687688
# Next, uses MTK's `parse_equations!` function to split input into a vector with the equations.
688689
eqs_input = haskey(options, :equations) ? options[:equations].args[3] : :(begin end)
@@ -694,30 +695,35 @@ function read_equations_options(options, variables_declared)
694695
# Loops through all equations, checks for lhs of the form `D(X) ~ ...`.
695696
# When this is the case, the variable X and differential D are extracted (for automatic declaration).
696697
# Also performs simple error checks.
697-
vars_extracted = Vector{Symbol}()
698+
vars_extracted = OrderedSet{Union{Symbol, Expr}}()
699+
excluded_syms = syms_declared
698700
add_default_diff = false
699701
for eq in equations
700702
if (eq.head != :call) || (eq.args[1] != :~)
701703
error("Malformed equation: \"$eq\". Equation's left hand and right hand sides should be separated by a \"~\".")
702704
end
703705

704706
# Checks if the equation have the format D(X) ~ ... (where X is a symbol). This means that the
705-
# default differential has been used. X is added as a declared variable to the system, and
706-
# we make a note that a differential D = Differential(iv) should be made as well.
707+
# default differential has been used and we make a note that it should be decalred in the DSL output.
707708
lhs = eq.args[2]
708-
# if lhs: is an expression. Is a function call. The function's name is D. Calls a single symbol.
709+
# If lhs: is an expression. Is a function call. The function's name is D. It has a single argument.
709710
if (lhs isa Expr) && (lhs.head == :call) && (lhs.args[1] == :D) &&
710711
(lhs.args[2] isa Symbol)
711712
diff_var = lhs.args[2]
712713
if in(diff_var, forbidden_symbols_error)
713714
error("A forbidden symbol ($(diff_var)) was used as an variable in this differential equation: $eq")
714715
end
715-
add_default_diff = true
716-
in(diff_var, variables_declared) || push!(vars_extracted, diff_var)
716+
if !add_default_diff
717+
add_default_diff = true
718+
excluded_syms = [excluded_syms; :D]
719+
end
717720
end
721+
722+
# Any undecalred symbolic variables encountered should be extracted as variables.
723+
add_syms_from_expr!(vars_extracted, eq, excluded_syms)
718724
end
719725

720-
return vars_extracted, add_default_diff, equations
726+
return collect(vars_extracted), add_default_diff, equations
721727
end
722728

723729
# Creates an expression declaring differentials. Here, `tiv` is the time independent variables,
@@ -917,7 +923,7 @@ end
917923

918924
### Generic Expression Manipulation ###
919925

920-
# Recursively traverses an expression and escapes all the user-defined functions. Special function calls like "hill(...)" are not expanded.
926+
# Recursively traverses an expression and escapes all the user-defined functions. Special function calls like "hill(...)" are not expanded.
921927
function recursive_escape_functions!(expr::ExprValues)
922928
(typeof(expr) != Expr) && (return expr)
923929
foreach(i -> expr.args[i] = recursive_escape_functions!(expr.args[i]),

src/reactionsystem.jl

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ Base.@kwdef mutable struct NetworkProperties{I <: Integer, V <: BasicSymbolic{Re
9797
stronglinkageclasses::Vector{Vector{Int}} = Vector{Vector{Int}}(undef, 0)
9898
terminallinkageclasses::Vector{Vector{Int}} = Vector{Vector{Int}}(undef, 0)
9999

100-
checkedrobust::Bool = false
100+
checkedrobust::Bool = false
101101
robustspecies::Vector{Int} = Vector{Int}(undef, 0)
102-
deficiency::Int = -1
102+
deficiency::Int = -1
103103
end
104104
#! format: on
105105

@@ -215,11 +215,11 @@ end
215215

216216
### ReactionSystem Structure ###
217217

218-
"""
218+
"""
219219
WARNING!!!
220220
221-
The following variable is used to check that code that should be updated when the `ReactionSystem`
222-
fields are updated has in fact been updated. Do not just blindly update this without first checking
221+
The following variable is used to check that code that should be updated when the `ReactionSystem`
222+
fields are updated has in fact been updated. Do not just blindly update this without first checking
223223
all such code and updating it appropriately (e.g. serialization). Please use a search for
224224
`reactionsystem_fields` throughout the package to ensure all places which should be updated, are updated.
225225
"""
@@ -318,7 +318,7 @@ struct ReactionSystem{V <: NetworkProperties} <:
318318
"""
319319
discrete_events::Vector{MT.SymbolicDiscreteCallback}
320320
"""
321-
Metadata for the system, to be used by downstream packages.
321+
Metadata for the system, to be used by downstream packages.
322322
"""
323323
metadata::Any
324324
"""
@@ -480,10 +480,10 @@ function ReactionSystem(iv; kwargs...)
480480
ReactionSystem(Reaction[], iv, [], []; kwargs...)
481481
end
482482

483-
# Called internally (whether DSL-based or programmatic model creation is used).
483+
# Called internally (whether DSL-based or programmatic model creation is used).
484484
# Creates a sorted reactions + equations vector, also ensuring reaction is first in this vector.
485-
# Extracts potential species, variables, and parameters from the input (if not provided as part of
486-
# the model creation) and creates the corresponding vectors.
485+
# Extracts potential species, variables, and parameters from the input (if not provided as part of
486+
# the model creation) and creates the corresponding vectors.
487487
# While species are ordered before variables in the unknowns vector, this ordering is not imposed here,
488488
# but carried out at a later stage.
489489
function make_ReactionSystem_internal(rxs_and_eqs::Vector, iv, us_in, ps_in;
@@ -495,7 +495,7 @@ function make_ReactionSystem_internal(rxs_and_eqs::Vector, iv, us_in, ps_in;
495495
any(in(obs_vars), us_in) &&
496496
error("Found an observable in the list of unknowns. This is not allowed.")
497497

498-
# Creates a combined iv vector (iv and sivs). This is used later in the function (so that
498+
# Creates a combined iv vector (iv and sivs). This is used later in the function (so that
499499
# independent variables can be excluded when encountered quantities are added to `us` and `ps`).
500500
t = value(iv)
501501
ivs = Set([t])
@@ -524,6 +524,8 @@ function make_ReactionSystem_internal(rxs_and_eqs::Vector, iv, us_in, ps_in;
524524
# Extracts any species, variables, and parameters that occur in (non-reaction) equations.
525525
# Creates the new reactions + equations vector, `fulleqs` (sorted reactions first, equations next).
526526
if !isempty(eqs)
527+
println(eqs)
528+
println(iv)
527529
osys = ODESystem(eqs, iv; name = gensym())
528530
fulleqs = CatalystEqType[rxs; equations(osys)]
529531
union!(us, unknowns(osys))
@@ -560,7 +562,7 @@ function make_ReactionSystem_internal(rxs_and_eqs::Vector, iv, us_in, ps_in;
560562
end
561563
psv = collect(new_ps)
562564

563-
# Passes the processed input into the next `ReactionSystem` call.
565+
# Passes the processed input into the next `ReactionSystem` call.
564566
ReactionSystem(fulleqs, t, usv, psv; spatial_ivs, continuous_events,
565567
discrete_events, observed, kwargs...)
566568
end
@@ -1062,8 +1064,8 @@ end
10621064

10631065
### General `ReactionSystem`-specific Functions ###
10641066

1065-
# Checks if the `ReactionSystem` structure have been updated without also updating the
1066-
# `reactionsystem_fields` constant. If this is the case, returns `false`. This is used in
1067+
# Checks if the `ReactionSystem` structure have been updated without also updating the
1068+
# `reactionsystem_fields` constant. If this is the case, returns `false`. This is used in
10671069
# certain functionalities which would break if the `ReactionSystem` structure is updated without
10681070
# also updating these functionalities.
10691071
function reactionsystem_uptodate_check()
@@ -1241,7 +1243,7 @@ end
12411243
### `ReactionSystem` Remaking ###
12421244

12431245
"""
1244-
remake_ReactionSystem_internal(rs::ReactionSystem;
1246+
remake_ReactionSystem_internal(rs::ReactionSystem;
12451247
default_reaction_metadata::Vector{Pair{Symbol, T}} = Vector{Pair{Symbol, Any}}()) where {T}
12461248
12471249
Takes a `ReactionSystem` and remakes it, returning a modified `ReactionSystem`. Modifications depend
@@ -1274,7 +1276,7 @@ function set_default_metadata(rs::ReactionSystem; default_reaction_metadata = []
12741276
# Currently, `noise_scaling` is the only relevant metadata supported this way.
12751277
drm_dict = Dict(default_reaction_metadata)
12761278
if haskey(drm_dict, :noise_scaling)
1277-
# Finds parameters, species, and variables in the noise scaling term.
1279+
# Finds parameters, species, and variables in the noise scaling term.
12781280
ns_expr = drm_dict[:noise_scaling]
12791281
ns_syms = [Symbolics.unwrap(sym) for sym in get_variables(ns_expr)]
12801282
ns_ps = Iterators.filter(ModelingToolkit.isparameter, ns_syms)
@@ -1414,7 +1416,7 @@ function ModelingToolkit.compose(sys::ReactionSystem, systems::AbstractArray; na
14141416
MT.collect_scoped_vars!(newunknowns, newparams, ssys, iv)
14151417
end
14161418

1417-
if !isempty(newunknowns)
1419+
if !isempty(newunknowns)
14181420
@set! sys.unknowns = union(get_unknowns(sys), newunknowns)
14191421
sort!(get_unknowns(sys), by = !isspecies)
14201422
@set! sys.species = filter(isspecies, get_unknowns(sys))

test/dsl/dsl_options.jl

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,26 @@ let
901901
@test 5*sol[:Y][end] sol[:S][end] + sol[:X][end]
902902
end
903903

904+
# Tests that the correct symbolic variables are infered as species, variables, and paraemters.
905+
let
906+
rn = @reaction_network begin
907+
@parameters p1 p2
908+
@species X1(t) X2(t)
909+
@variables W(t)
910+
@equations begin
911+
D(V1) ~ p1 * X1 - k1 * V1 + W
912+
k2 * V2 ~ D(V2) + p2 * X2
913+
V3 + X3 ~ V1^2 + X2^2
914+
end
915+
(k1, k2), X1 <--> X2
916+
(k3, k4), X2 <--> X3
917+
end
918+
919+
@test issetequal(species(rn), @species X1(t) X2(t) X3(t))
920+
@test issetequal(parameters(rn), @parameters p1 p2 k1 k2 k3 k4)
921+
@test issetequal(nonspecies(rn), @variables V1(t) V2(t) V3(t) W(t))
922+
end
923+
904924
# Tests that various erroneous declarations throw errors.
905925
let
906926
# Using = instead of ~ (for equation).
@@ -951,7 +971,7 @@ let
951971
@test isequal(rl, k1*A^2)
952972
end
953973

954-
# Test whether user-defined functions are properly expanded in equations.
974+
# Test whether user-defined functions are properly expanded in equations.
955975
let
956976
f(A, t) = 2*A*t
957977

@@ -965,7 +985,7 @@ let
965985
@test isequal(equations(rn)[1], D(A) ~ 2*A*t)
966986

967987

968-
# Test whether expansion happens properly for unregistered/registered functions.
988+
# Test whether expansion happens properly for unregistered/registered functions.
969989
hill_unregistered(A, v, K, n) = v*(A^n) / (A^n + K^n)
970990
rn2 = @reaction_network begin
971991
@parameters v K n
@@ -978,7 +998,7 @@ let
978998

979999
hill2(A, v, K, n) = v*(A^n) / (A^n + K^n)
9801000
@register_symbolic hill2(A, v, K, n)
981-
# Registered symbolic function should not expand.
1001+
# Registered symbolic function should not expand.
9821002
rn2r = @reaction_network begin
9831003
@parameters v K n
9841004
@equations D(A) ~ hill2(A, v, K, n)
@@ -1009,9 +1029,9 @@ let
10091029
@named rn3_sym = ReactionSystem(eq, t)
10101030
rn3_sym = complete(rn3_sym)
10111031
@test isequivalent(rn3, rn3_sym)
1012-
1013-
1014-
# Test more complicated expression involving both registered function and a user-defined function.
1032+
1033+
1034+
# Test more complicated expression involving both registered function and a user-defined function.
10151035
g(A, K, n) = A^n + K^n
10161036
rn4 = @reaction_network begin
10171037
@parameters v K n

0 commit comments

Comments
 (0)