Skip to content

Commit 735d3b5

Browse files
committed
Merge remote-tracking branch 'origin/master' into graph-docs
2 parents d5308cd + 2cd8c75 commit 735d3b5

File tree

9 files changed

+118
-75
lines changed

9 files changed

+118
-75
lines changed

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ BifurcationKit = "0.4.4"
4646
CairoMakie = "0.12"
4747
Combinatorics = "1.0.2"
4848
DataStructures = "0.18"
49-
DiffEqBase = "< 6.159.0"
49+
DiffEqBase = "6.159.0"
5050
DocStringExtensions = "0.8, 0.9"
5151
DynamicPolynomials = "0.5, 0.6"
5252
DynamicQuantities = "0.13.2, 1"
@@ -62,11 +62,11 @@ Parameters = "0.12"
6262
Reexport = "0.2, 1.0"
6363
Requires = "1.0"
6464
RuntimeGeneratedFunctions = "0.5.12"
65-
SciMLBase = "< 2.57.2"
65+
SciMLBase = "2.57.2"
6666
Setfield = "1"
6767
# StructuralIdentifiability = "0.5.8"
6868
SymbolicUtils = "2.1.2, 3.3.0"
69-
Symbolics = "5.30.1, 6"
69+
Symbolics = "6.22"
7070
Unitful = "1.12.4"
7171
julia = "1.10"
7272

docs/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ BifurcationKit = "0.4.4"
5050
CairoMakie = "0.12"
5151
Catalyst = "14.4"
5252
DataFrames = "1.6"
53-
DiffEqBase = "< 6.159.0"
53+
DiffEqBase = "6.159.0"
5454
DiffEqParamEstim = "2.2"
5555
Distributions = "0.25"
5656
Documenter = "1.4.1"
@@ -87,4 +87,4 @@ SpecialFunctions = "2.4"
8787
StaticArrays = "1.9"
8888
SteadyStateDiffEq = "2.2"
8989
StochasticDiffEq = "6.65"
90-
Symbolics = "5.30.1, 6"
90+
Symbolics = "6.22"

docs/src/model_creation/dsl_advanced.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -272,23 +272,24 @@ sol = solve(oprob)
272272
plot(sol)
273273
```
274274

275-
### [Turning off species, parameter, and variable inferring](@id dsl_advanced_options_require_dec)
276-
In some cases it may be desirable for Catalyst to not infer species and parameters from the DSL, as in the case of reaction networks with very many variables, or as a sanity check that variable names are written correctly. To turn off inferring, simply add the `@require_declaration` macro to one of the lines of the `@reaction_network` declaration. Having this macro means that every single variable, species, or parameter will have to be explicitly declared using the `@variable`, `@species`, or `@parameter` macro. In the case that the DSL parser encounters an undeclared symbolic, it will error with an `UndeclaredSymbolicError` and print the reaction or equation that the undeclared symbolic was found in.
275+
### [Turning off species, parameter, and variable inference](@id dsl_advanced_options_require_dec)
276+
In some cases it may be desirable for Catalyst to not infer species and parameters from the DSL, as in the case of reaction networks with very many variables, or as a sanity check that variable names are written correctly. To turn off inference, simply use the `@require_declaration` option when using the `@reaction_network` DSL. This will require every single variable, species, or parameter used within the DSL to be explicitly declared using the `@variable`, `@species`, or `@parameter` options. In the case that the DSL parser encounters an undeclared symbolic, it will error with an `UndeclaredSymbolicError` and print the reaction or equation that the undeclared symbolic was found in.
277277

278-
```@example dsl_advanced_no_infer
278+
```julia
279279
using Catalyst
280-
# The following case will throw an UndeclaredSymbolicError.
281-
try @macroexpand @reaction_network begin
280+
rn = @reaction_network begin
282281
@require_declaration
283282
(k1, k2), A <--> B
284283
end
285-
catch e
286-
println(e.msg)
287-
end
288284
```
289-
In order to avoid an error in this case all the relevant species and parameters will have to be declared.
285+
Running the code above will yield the following error:
290286
```
287+
LoadError: UndeclaredSymbolicError: Unrecognized variables A detected in reaction expression: "((k1, k2), A <--> B)". Since the flag @require_declaration is declared, all species must be explicitly declared with the @species macro.
288+
```
289+
In order to avoid the error in this case all the relevant species and parameters will have to be declared.
290+
```@example dsl_advanced_require_dec
291291
# The following case will not error.
292+
using Catalyst
292293
t = default_t()
293294
rn = @reaction_network begin
294295
@require_declaration
@@ -299,11 +300,11 @@ end
299300
```
300301

301302
The following cases in which the DSL would normally infer variables will all throw errors if `@require_declaration` is set and the variables are not explicitly declared.
302-
- Inferring a species in a reaction, as in the example above
303-
- Inferring a parameter in a reaction rate expression, as in the reaction line `k*n, A --> B`
304-
- Inferring a parameter in the stoichiometry of a species, as in the reaction line `k, n*A --> B`
305-
- Inferring a differential variable on the LHS of a coupled differential equation, as in `A` in `@equations D(A) ~ A^2`
306-
- Inferring an [observable](@ref dsl_advanced_options_observables) that is declared using `@observables`
303+
- Occurrence of an undeclared species in a reaction, as in the example above.
304+
- Occurrence of an undeclared parameter in a reaction rate expression, as in the reaction line `k*n, A --> B`.
305+
- Occurrence of an undeclared parameter in the stoichiometry of a species, as in the reaction line `k, n*A --> B`.
306+
- Occurrence of an undeclared differential variable on the LHS of a coupled differential equation, as in `A` in `@equations D(A) ~ A^2`.
307+
- Occurrence of an undeclared [observable](@ref dsl_advanced_options_observables) in an `@observables` expression, such as `@observables X1 ~ A + B`.
307308

308309
## [Naming reaction networks](@id dsl_advanced_options_naming)
309310
Each reaction network model has a name. It can be accessed using the `nameof` function. By default, some generic name is used:

src/Catalyst.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import ModelingToolkit: check_variables,
4141

4242
import Base: (==), hash, size, getindex, setindex, isless, Sort.defalg, length, show
4343
import MacroTools, Graphs
44+
using MacroTools: striplines
4445
import Graphs: DiGraph, SimpleGraph, SimpleDiGraph, vertices, edges, add_vertices!, nv, ne
4546
import DataStructures: OrderedDict, OrderedSet
4647
import Parameters: @with_kw_noshow

src/chemistry_functionality.jl

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ t = default_t()
6363
@compound CO2(t) ~ C + 2O
6464
```
6565
66-
Notes:
66+
Notes:
6767
- The component species must be defined before using the `@compound` macro.
6868
"""
6969
macro compound(expr)
70-
make_compound(MacroTools.striplines(expr))
70+
make_compound(striplines(expr))
7171
end
7272

7373
# Declares compound error messages:
@@ -83,12 +83,12 @@ function make_compound(expr)
8383
error(COMPOUND_CREATION_ERROR_BAD_SEPARATOR)
8484

8585
# Loops through all components, add the component and the coefficients to the corresponding vectors
86-
# Cannot extract directly using e.g. "getfield.(composition, :reactant)" because then
86+
# Cannot extract directly using e.g. "getfield.(composition, :reactant)" because then
8787
# we get something like :([:C, :O]), rather than :([C, O]).
8888
composition = Catalyst.recursive_find_reactants!(expr.args[3], 1,
8989
Vector{ReactantStruct}(undef, 0))
90-
components = :([]) # Becomes something like :([C, O]).
91-
coefficients = :([]) # Becomes something like :([1, 2]).
90+
components = :([]) # Becomes something like :([C, O]).
91+
coefficients = :([]) # Becomes something like :([1, 2]).
9292
for comp in composition
9393
push!(components.args, comp.reactant)
9494
push!(coefficients.args, comp.stoichiometry)
@@ -110,13 +110,13 @@ function make_compound(expr)
110110
for comp in $components])))
111111

112112
# Creates the found expressions that will create the compound species.
113-
# The `Expr(:escape, :(...))` is required so that the expressions are evaluated in
114-
# the scope the users use the macro in (to e.g. detect already exiting species).
113+
# The `Expr(:escape, :(...))` is required so that the expressions are evaluated in
114+
# the scope the users use the macro in (to e.g. detect already exiting species).
115115
# Creates something like (where `compound_ivs` and `component_ivs` evaluates to all the compound's and components' ivs):
116116
# `@species CO2(..)`
117117
# `isempty([])` && length(component_ivs) && error("When ...)
118-
# `CO2 = CO2(component_ivs..)`
119-
# `issetequal(compound_ivs, component_ivs) || error("The ...)`
118+
# `CO2 = CO2(component_ivs..)`
119+
# `issetequal(compound_ivs, component_ivs) || error("The ...)`
120120
# `CO2 = ModelingToolkit.setmetadata(CO2, Catalyst.CompoundSpecies, true)`
121121
# `CO2 = ModelingToolkit.setmetadata(CO2, Catalyst.CompoundSpecies, [C, O])`
122122
# `CO2 = ModelingToolkit.setmetadata(CO2, Catalyst.CompoundSpecies, [1, 2])`
@@ -159,7 +159,7 @@ Macro that creates several compound species, which each is composed of smaller c
159159
Example:
160160
```julia
161161
t = default_t()
162-
@species C(t) H(t) O(t)
162+
@species C(t) H(t) O(t)
163163
@compounds
164164
CH4(t) = C + 4H
165165
O2(t) = 2O
@@ -168,11 +168,11 @@ t = default_t()
168168
end
169169
```
170170
171-
Notes:
171+
Notes:
172172
- The component species must be defined before using the `@compound` macro.
173173
"""
174174
macro compounds(expr)
175-
make_compounds(MacroTools.striplines(expr))
175+
make_compounds(striplines(expr))
176176
end
177177

178178
# Function managing the @compound macro.
@@ -183,7 +183,7 @@ function make_compounds(expr)
183183
# For each compound in `expr`, creates the set of 7 compound creation lines (using `make_compound`).
184184
# Next, loops through all 7*[Number of compounds] lines and add them to compound_declarations.
185185
compound_calls = [Catalyst.make_compound(line) for line in expr.args]
186-
for compound_call in compound_calls, line in MacroTools.striplines(compound_call).args
186+
for compound_call in compound_calls, line in striplines(compound_call).args
187187
push!(compound_declarations.args, line)
188188
end
189189

@@ -249,7 +249,7 @@ brxs = balance_reaction(rx) # No solution.
249249
250250
Notes:
251251
- Balancing reactions that contain compounds of compounds is currently not supported.
252-
- A reaction may not always yield a single solution; it could have an infinite number of solutions or none at all. When there are multiple solutions, a vector of all possible `Reaction` objects is returned. However, substrates and products may be interchanged as we currently do not solve for a linear combination that maintains the set of substrates and products.
252+
- A reaction may not always yield a single solution; it could have an infinite number of solutions or none at all. When there are multiple solutions, a vector of all possible `Reaction` objects is returned. However, substrates and products may be interchanged as we currently do not solve for a linear combination that maintains the set of substrates and products.
253253
- If the reaction cannot be balanced, an empty `Reaction` vector is returned.
254254
"""
255255
function balance_reaction(reaction::Reaction)
@@ -369,16 +369,16 @@ From a system, creates a new system where each reaction is a balanced version of
369369
reaction of the original system. For more information, consider the `balance_reaction` function
370370
(which is internally applied to each system reaction).
371371
372-
Arguments
372+
Arguments
373373
- `rs`: The reaction system that should be balanced.
374374
375375
Notes:
376376
- If any reaction in the system cannot be balanced, throws an error.
377-
- If any reaction in the system have an infinite number of potential reactions, throws an error.
377+
- If any reaction in the system have an infinite number of potential reactions, throws an error.
378378
Here, it would be possible to generate a valid reaction, however, no such routine is currently
379379
implemented in `balance_system`.
380380
- `balance_system` will not modify reactions of subsystems to the input system. It is recommended
381-
not to apply `balance_system` to non-flattened systems.
381+
not to apply `balance_system` to non-flattened systems.
382382
"""
383383
function balance_system(rs::ReactionSystem)
384384
@set! rs.eqs = CatalystEqType[get_balanced_reaction(eq) for eq in get_eqs(rs)]
@@ -391,7 +391,7 @@ end
391391
function get_balanced_reaction(rx::Reaction)
392392
brxs = balance_reaction(rx)
393393

394-
# In case there are no, or multiple, solutions to the balancing problem.
394+
# In case there are no, or multiple, solutions to the balancing problem.
395395
if isempty(brxs)
396396
error("Could not balance reaction `$rx`, unable to create a balanced `ReactionSystem`.")
397397
end

src/dsl.jl

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,17 @@ ReactionSystems generated through `@reaction_network` are complete.
141141
"""
142142
macro reaction_network(name::Symbol, ex::Expr)
143143
:(complete($(make_reaction_system(
144-
MacroTools.striplines(ex); name = :($(QuoteNode(name)))))))
144+
striplines(ex); name = :($(QuoteNode(name)))))))
145145
end
146146

147147
# Allows @reaction_network $name begin ... to interpolate variables storing a name.
148148
macro reaction_network(name::Expr, ex::Expr)
149149
:(complete($(make_reaction_system(
150-
MacroTools.striplines(ex); name = :($(esc(name.args[1])))))))
150+
striplines(ex); name = :($(esc(name.args[1])))))))
151151
end
152152

153153
macro reaction_network(ex::Expr)
154-
ex = MacroTools.striplines(ex)
154+
ex = striplines(ex)
155155

156156
# no name but equations: @reaction_network begin ... end ...
157157
if ex.head == :block
@@ -179,16 +179,16 @@ Equivalent to `@reaction_network` except the generated `ReactionSystem` is not m
179179
complete.
180180
"""
181181
macro network_component(name::Symbol, ex::Expr)
182-
make_reaction_system(MacroTools.striplines(ex); name = :($(QuoteNode(name))))
182+
make_reaction_system(striplines(ex); name = :($(QuoteNode(name))))
183183
end
184184

185185
# Allows @network_component $name begin ... to interpolate variables storing a name.
186186
macro network_component(name::Expr, ex::Expr)
187-
make_reaction_system(MacroTools.striplines(ex); name = :($(esc(name.args[1]))))
187+
make_reaction_system(striplines(ex); name = :($(esc(name.args[1]))))
188188
end
189189

190190
macro network_component(ex::Expr)
191-
ex = MacroTools.striplines(ex)
191+
ex = striplines(ex)
192192

193193
# no name but equations: @network_component begin ... end ...
194194
if ex.head == :block
@@ -328,7 +328,7 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
328328
parameters_declared = extract_syms(options, :parameters)
329329
variables_declared = extract_syms(options, :variables)
330330

331-
# Reads equations.
331+
# Reads equations.
332332
vars_extracted, add_default_diff, equations = read_equations_options(
333333
options, variables_declared; requiredec)
334334
variables = vcat(variables_declared, vars_extracted)
@@ -356,7 +356,7 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
356356
observed_vars, observed_eqs, obs_syms = read_observed_options(
357357
options, [species_declared; variables], all_ivs; requiredec)
358358

359-
# Collect species and parameters, including ones inferred from the reactions.
359+
# Collect species and parameters, including ones inferred from the reactions.
360360
declared_syms = Set(Iterators.flatten((parameters_declared, species_declared,
361361
variables)))
362362
species_extracted, parameters_extracted = extract_species_and_parameters!(
@@ -397,7 +397,7 @@ function make_reaction_system(ex::Expr; name = :(gensym(:ReactionSystem)))
397397
push!(rxexprs.args, equation)
398398
end
399399

400-
# Output code corresponding to the reaction system.
400+
# Output code corresponding to the reaction system.
401401
quote
402402
$ivexpr
403403
$ps
@@ -448,7 +448,7 @@ function get_reactions(exprs::Vector{Expr}, reactions = Vector{ReactionStruct}(u
448448
push_reactions!(reactions, reaction.args[3], reaction.args[2],
449449
rate, metadata, arrow, line)
450450
else
451-
throw("Malformed reaction, invalid arrow type used in: $(MacroTools.striplines(line))")
451+
throw("Malformed reaction, invalid arrow type used in: $(striplines(line))")
452452
end
453453
end
454454
return reactions
@@ -670,7 +670,7 @@ function read_events_option(options, event_type::Symbol)
670670
error("Trying to read an unsupported event type.")
671671
end
672672
events_input = haskey(options, event_type) ? options[event_type].args[3] :
673-
MacroTools.striplines(:(begin end))
673+
striplines(:(begin end))
674674
events_input = option_block_form(events_input)
675675

676676
# Goes through the events, checks for errors, and adds them to the output vector.
@@ -750,7 +750,7 @@ function create_differential_expr(options, add_default_diff, used_syms, tiv)
750750
# If differentials was provided as options, this is used as the initial expression.
751751
# If the default differential (D(...)) was used in equations, this is added to the expression.
752752
diffexpr = (haskey(options, :differentials) ? options[:differentials].args[3] :
753-
MacroTools.striplines(:(begin end)))
753+
striplines(:(begin end)))
754754
diffexpr = option_block_form(diffexpr)
755755

756756
# Goes through all differentials, checking that they are correctly formatted and their symbol is not used elsewhere.
@@ -810,23 +810,18 @@ function read_observed_options(options, species_n_vars_declared, ivs_sorted; req
810810
# For Observables that have already been declared using @species/@variables,
811811
# or are interpolated, this parts should not be carried out.
812812
if !((obs_name in species_n_vars_declared) || is_escaped_expr(obs_eq.args[2]))
813-
# Appends (..) to the observable (which is later replaced with the extracted ivs).
814-
# Adds the observable to the first line of the output expression (starting with `@variables`).
815-
obs_expr = insert_independent_variable(obs_eq.args[2], :(..))
816-
push!(observed_vars.args[1].args, obs_expr)
817-
818-
# Adds a line to the `observed_vars` expression, setting the ivs for this observable.
819-
# Cannot extract directly using e.g. "getfield.(dependants_structs, :reactant)" because
820-
# then we get something like :([:X1, :X2]), rather than :([X1, X2]).
813+
# Creates an expression which extracts the ivs of the species & variables the
814+
# observable depends on, and splats them out in the correct order.
821815
dep_var_expr = :(filter(!MT.isparameter,
822816
Symbolics.get_variables($(obs_eq.args[3]))))
823817
ivs_get_expr = :(unique(reduce(
824818
vcat, [sorted_arguments(MT.unwrap(dep))
825819
for dep in $dep_var_expr])))
826820
ivs_get_expr_sorted = :(sort($(ivs_get_expr);
827821
by = iv -> findfirst(MT.getname(iv) == ivs for ivs in $ivs_sorted)))
828-
push!(observed_vars.args,
829-
:($obs_name = $(obs_name)($(ivs_get_expr_sorted)...)))
822+
823+
obs_expr = insert_independent_variable(obs_eq.args[2], :($ivs_get_expr_sorted...))
824+
push!(observed_vars.args[1].args, obs_expr)
830825
end
831826

832827
# In case metadata was given, this must be cleared from `observed_eqs`.
@@ -840,7 +835,8 @@ function read_observed_options(options, species_n_vars_declared, ivs_sorted; req
840835
end
841836

842837
# If nothing was added to `observed_vars`, it has to be modified not to throw an error.
843-
(length(observed_vars.args) == 1) && (observed_vars = :())
838+
(striplines(observed_vars) == striplines(Expr(:block, :(@variables)))) &&
839+
(observed_vars = :())
844840
else
845841
# If option is not used, return empty expression and vector.
846842
observed_vars = :()
@@ -944,7 +940,7 @@ end
944940

945941
### Generic Expression Manipulation ###
946942

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

src/spatial_reaction_systems/spatial_reactions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ end
4343

4444
# Macro for creating a `TransportReaction`.
4545
macro transport_reaction(rateex::ExprValues, species::ExprValues)
46-
make_transport_reaction(MacroTools.striplines(rateex), species)
46+
make_transport_reaction(striplines(rateex), species)
4747
end
4848
function make_transport_reaction(rateex, species)
4949
# Handle interpolation of variables

0 commit comments

Comments
 (0)