Skip to content

Commit d69f4d7

Browse files
authored
Merge pull request #1240 from SciML/permit_function_name_interpolation
Enables DSL interpolation of a function name only
2 parents b8cff13 + 2f78a31 commit d69f4d7

File tree

3 files changed

+37
-16
lines changed

3 files changed

+37
-16
lines changed

docs/src/model_creation/functional_parameters.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ spline = LinearInterpolation((2 .+ ts) ./ (1 .+ ts), ts)
1414
@parameters (pIn::typeof(spline))(..)
1515
plot(spline)
1616
```
17-
Next, we create our model, [interpolating](@ref dsl_advanced_options_symbolics_and_DSL_interpolation) the input parameter into it (making it a function of `t`).
17+
Next, we create our model, [interpolating](@ref dsl_advanced_options_symbolics_and_DSL_interpolation) the input parameter into the `@reaction_network` declaration.
1818
```@example functional_parameters_basic_example
19-
input = pIn(default_t())
2019
bd_model = @reaction_network begin
21-
$input, 0 --> X
20+
$pIn(t), 0 --> X
2221
d, X --> 0
2322
end
2423
```
@@ -76,11 +75,10 @@ plot(sol)
7675
```
7776

7877
### [Interpolating the input into the DSL](@id functional_parameters_circ_rhythm_dsl)
79-
It is possible to use time-dependent inputs when creating models [through the DSL](@ref dsl_description) as well. However, it can still be convenient to declare the input parameter programmatically as above. Using it, we form an expression of it as a function of time, and then [interpolate](@ref dsl_advanced_options_symbolics_and_DSL_interpolation) it into our DSL-declaration:
78+
It is possible to use time-dependent inputs when creating models [through the DSL](@ref dsl_description) as well. However, it can still be convenient to declare the input parameter programmatically as above. Next, we can [interpolate](@ref dsl_advanced_options_symbolics_and_DSL_interpolation) it into our DSL-declaration (ensuring to also make it a function of `t`):
8079
```@example functional_parameters_circ_rhythm
81-
input = light_in(t)
8280
rs_dsl = @reaction_network rs begin
83-
(kA*$input, kD), Pᵢ <--> Pₐ
81+
(kA*$light_in(t), kD), Pᵢ <--> Pₐ
8482
end
8583
```
8684
We can confirm that this model is identical to our programmatic one (and should we wish to, we can simulate it using identical syntax).
@@ -112,14 +110,12 @@ I_rate = LinearInterpolation(I_measured, I_grid)
112110
plot(I_rate; label = "Measured infection rate")
113111
plot!(I_grid, I_grid; label = "Normal SIR infection rate")
114112
```
115-
Next, we create our model (using the DSL approach). As `I_rate` will be a function of $I$ we will need to declare this species first as well.
113+
Next, we create our model (using the DSL approach).
116114
```@example functional_parameters_sir
117115
using Catalyst
118116
@parameters (inf_rate::typeof(I_rate))(..)
119-
@species I(default_t())
120-
inf_rate_in = inf_rate(I)
121117
sir = @reaction_network rs begin
122-
k1*$inf_rate_in, S --> I
118+
k1*$inf_rate(I), S --> I
123119
k2, I --> R
124120
end
125121
nothing # hide

src/dsl.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,8 @@ function recursive_escape_functions!(expr::ExprValues, syms_skip = [])
984984
(typeof(expr) != Expr) && (return expr)
985985
foreach(i -> expr.args[i] = recursive_escape_functions!(expr.args[i], syms_skip),
986986
1:length(expr.args))
987-
if (expr.head == :call) && !isdefined(Catalyst, expr.args[1]) && expr.args[1] syms_skip
987+
if (expr.head == :call) && (expr.args[1] isa Symbol) &&!isdefined(Catalyst, expr.args[1]) &&
988+
expr.args[1] syms_skip
988989
expr.args[1] = esc(expr.args[1])
989990
end
990991
expr

test/reactionsystem_core/functional_parameters.jl

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ let
4141
rs_pIn = complete(rs_pIn)
4242

4343
# Defines a `ReactionSystem` with the input parameter (DSL).
44-
input = pIn(t)
4544
rs_pIn_dsl = @reaction_network rs_pIn begin
46-
($input,d), 0 <--> X
45+
($pIn(t),d), 0 <--> X
4746
(k1*X,k2), Y1 <--> Y2
4847
end
4948

@@ -123,14 +122,13 @@ let
123122
spline1d = LinearInterpolation(100.0*Is ./ (100.0 .+ Is), Is)
124123
@parameters (i_rate::typeof(spline1d))(..)
125124

126-
# Decalres the models.
125+
# Declares the models.
127126
sir = @reaction_network begin
128127
k1*100*I/(100 + I), S --> I
129128
k2, I --> R
130129
end
131-
input = i_rate(sir.I)
132130
sir_funcp = @reaction_network rs begin
133-
k1*$(input), S --> I
131+
k1*$i_rate(I), S --> I
134132
k2, I --> R
135133
end
136134

@@ -169,3 +167,29 @@ let
169167
@named rs = ReactionSystem(rxs, t)
170168
@test issetequal([Catalyst.get_unit(rx.rate) for rx in reactions(rs)], [u"mol/(s*m^3)", u"1/s"])
171169
end
170+
171+
# Tests that a functional parameter can be interpolated as the function only, as a function of a
172+
# symbolic variable, or interpolated with the functional parameter and argument separately.
173+
let
174+
# Prepares the functional parameter.
175+
ts = collect(0.0:0.1:1.0)
176+
spline = LinearInterpolation(log.(ts), ts)
177+
t_var = default_t()
178+
@parameters (pIn::typeof(spline))(..)
179+
pIn_func = pIn(t_var)
180+
181+
# Creates models using different approaches, check that all yield the same model.
182+
rn1 = @reaction_network rn begin
183+
p, 0 --> X
184+
$pIn_func, 0 --> X
185+
end
186+
rn2 = @reaction_network rn begin
187+
p, 0 --> X
188+
$pIn(t), 0 --> X
189+
end
190+
rn3 = @reaction_network rn begin
191+
p, 0 --> X
192+
$pIn($t_var), 0 --> X
193+
end
194+
@test rn1 == rn2 == rn3
195+
end

0 commit comments

Comments
 (0)