Skip to content

Commit 21e944e

Browse files
committed
up
1 parent 9ee6b7e commit 21e944e

File tree

4 files changed

+36
-22
lines changed

4 files changed

+36
-22
lines changed

docs/src/model_creation/dsl_basics.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ Catalyst comes with the following predefined functions:
264264
- The repressive Hill function: $hillr(X,v,K,n) = v * (K^n)/(X^n + K^n)$.
265265
- The activating/repressive Hill function: $hillar(X,Y,v,K,n) = v * (X^n)/(X^n + Y^n + K^n)$.
266266

267+
### [Registration of non-algebraic functions](@id dsl_description_nonconstant_rates_function_registration)
268+
Previously we showed how user-defined functions [can be used in rates directly](@ref dsl_description_nonconstant_rates_available_functions). For functions containing more complicated syntax (e.g. `for` loops or `if` statements), we must add an additional step: registering it using the `@register_symbolic` macro. Below we define a function which output depends on whether `X` is smaller or larger than a threshold value. Next, we register it using `@register_symbolic`, after which we can use it within the DSL.
269+
```@example dsl_basics
270+
threshold_func(X) = (X < 10) ? X : 10.0
271+
@register_symbolic threshold_func(X)
272+
rn = @reaction_network begin
273+
threshold_func(X), 0 --> X
274+
d, X --> 0
275+
end
276+
```
277+
267278
### [Time-dependant rates](@id dsl_description_nonconstant_rates_time)
268279
Previously we have assumed that the rates are independent of the time variable, $t$. However, time-dependent reactions are also possible. Here, simply use `t` to represent the time variable. E.g., to create a production/degradation model where the production rate decays as time progresses, we can use:
269280
```@example dsl_basics

docs/src/model_creation/functional_parameters.md

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
# [Inputs and time-dependent (or functional) parameters](@id time_dependent_parameters)
2-
Catalyst supports the usage of "functional parameters". In practice these are parameters that are given by time-dependent functions, representing a way to inject custom functions into models. They can be used when rates depend on real data, or to represent complicated functions (which use e.g. `for` loops or random number generation). Here, the function's values are declared as a data interpolation, which is then used as the functional parameter's value in the simulation. On this page, we first show how to create time-dependent functional parameters, and then give an example where the functional parameter depends on a species value.
2+
Catalyst supports the usage of "functional parameters". In practice, these are parameters that are given by (typically) time-dependent functions (they can also depend on e.g. species values, as discussed [here](@ref functional_parameters_sir)). They are a way to inject custom functions into models. Functional parameters can be used when rates depend on real data, or to represent complicated functions (which use e.g. `for` loops or random number generation). Here, the function's values are declared as a data interpolation (which interpolates discrete samples to a continuous function). This is then used as the functional parameter's value in the simulation. This tutorial first shows how to create time-dependent functional parameters, and then gives an example where the functional parameter depends on a species value.
3+
4+
An alternative approach for representing complicated functions is by [using `@register_symbolic`](@ref dsl_description_nonconstant_rates_function_registration).
35

46
## [Basic example](@id functional_parameters_basic_example)
5-
Let us first consider an easy, quick-start example. We will consider a simple [birth-death model](@ref basic_CRN_library_bd), but where the birth rate is determined by an input parameter (for which the value depends on time). First, we [define the input parameter programmatically](@ref programmatic_CRN_construction), and its values across all time points using the [DataInterpolations.jl](https://github.com/SciML/DataInterpolations.jl) package. In this example we will use the input function $pIn(t) = (2 + t)/(1 + t)$.
7+
Let us first consider an easy, quick-start example (the next section will discuss what is going on in more detail). We will consider a simple [birth-death model](@ref basic_CRN_library_bd), but where the birth rate is determined by an input parameter (for which the value depends on time). First, we [define the input parameter programmatically](@ref programmatic_CRN_construction), and its values across all time points using the [DataInterpolations.jl](https://github.com/SciML/DataInterpolations.jl) package. In this example we will use the input function $pIn(t) = (2 + t)/(1 + t)$. Finally, we plot the input function, demonstrating how while it is defined at discrete points, DataInterpolations.jl generalises this to a continuous function.
68
```@example functional_parameters_basic_example
7-
using Catalyst, DataInterpolations
9+
using Catalyst, DataInterpolations, Plots
810
t = default_t()
911
tend = 10.0
1012
ts = collect(0.0:0.01:tend)
1113
spline = LinearInterpolation((2 .+ ts) ./ (1 .+ ts), ts)
1214
@parameters (pIn::typeof(spline))(..)
13-
nothing # hide
15+
plot(spline)
1416
```
1517
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`).
1618
```@example functional_parameters_basic_example
@@ -20,9 +22,9 @@ bd_model = @reaction_network begin
2022
d, X --> 0
2123
end
2224
```
23-
Finally, we can simulate our model as normal, but setting the value of the `pIn` parameter to our interpolated data.
25+
Finally, we can simulate our model as normal (but where we set the value of the `pIn` parameter to our interpolated data).
2426
```@example functional_parameters_basic_example
25-
using OrdinaryDiffEqDefault, Plots
27+
using OrdinaryDiffEqDefault
2628
u0 = [:X => 0.5]
2729
ps = [:d => 2.0, :pIn => spline]
2830
oprob = ODEProblem(bd_model, u0, tend, ps)
@@ -48,7 +50,7 @@ using DataInterpolations
4850
interpolated_light = LinearInterpolation(light, ts)
4951
plot(interpolated_light)
5052
```
51-
We are now ready to declare our model. We will consider a protein with an active and an inactive form ($Pₐ$ and $Pᵢ$) where the activation is driven by the presence of sunlight. In this example we we create our model using the [programmatic approach](@ref programmatic_CRN_construction). Do note the special syntax we use to declare our input parameter, where we both designate it as a generic function and its type as the type of our interpolated input. Also note that, within the model, we mark the input parameter (`light_in`) a function of `t`.
53+
We are now ready to declare our model. We will consider a protein with an active and an inactive form ($Pₐ$ and $Pᵢ$) where the activation is driven by the presence of sunlight. In this example we we create our model using the [programmatic approach](@ref programmatic_CRN_construction). Do note the special syntax we use to declare our input parameter, where we both designate it as a generic function and its type as the type of our interpolated input. Also note that, within the model, we mark the input parameter (`light_in`) as a function of `t`.
5254
```@example functional_parameters_circ_rhythm
5355
using Catalyst
5456
t = default_t()
@@ -73,24 +75,24 @@ plot(sol)
7375
```
7476

7577
### [Interpolating the input into the DSL](@id functional_parameters_circ_rhythm_dsl)
76-
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 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. 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:
7779
```@example functional_parameters_circ_rhythm
7880
input = light_in(t)
7981
rs_dsl = @reaction_network rs begin
8082
(kA*$input, kD), Pᵢ <--> Pₐ
8183
end
8284
```
83-
We can confirm that this model is identical to our programmatic one (and should we wish to, we can simulate it using identical syntax syntax).
85+
We can confirm that this model is identical to our programmatic one (and should we wish to, we can simulate it using identical syntax).
8486
```@example functional_parameters_circ_rhythm
8587
rs == rs_dsl
8688
```
8789

8890
## [Non-time functional parameters](@id functional_parameters_sir)
89-
Previously we have demonstrated functional parameters that are a function of time. However, functional parameters can be functions of any variable (however, currently, more than one argument is not supported). Here we will demonstrate this using a [SIR model](@ref basic_CRN_library_sir), but instead of having the infection rate scale linearly with the number of infected individuals, we instead assume we have measured data of the infection rate (as dependent on the number of infected individuals) and wish to use this instead. Normally we use the following infection reaction in the SIR model:
91+
Previously we have demonstrated functional parameters that are functions of time. However, functional parameters can be functions of any variable (however, currently, more than one argument is not supported). Here we will demonstrate this using a [SIR model](@ref basic_CRN_library_sir), but instead of having the infection rate scale linearly with the number of infected individuals, we instead assume we have measured data of the infection rate (as dependent on the number of infected individuals) and wish to use this instead. Normally we use the following infection reaction in the SIR model:
9092
```julia
9193
@reaction k1, S + I --> 2I
9294
```
93-
In practise, this is identical to
95+
For ODE models, this would give the same equations as
9496
```julia
9597
@reaction k1*I, S --> I
9698
```
@@ -104,27 +106,28 @@ We start by declaring the functional parameter that describes how the infection
104106
```@example functional_parameters_sir
105107
using DataInterpolations, Plots
106108
I_grid = collect(0.0:5.0:100.0)
107-
I_meassured = 300.0 *(0.8*rand(length(I_grid)) .+ 0.6) .* I_grid ./ (300 .+ I_grid)
108-
I_rate = LinearInterpolation(I_meassured, I_grid)
109-
plot(I_rate; label = "Meassured infection rate")
109+
I_measured = 300.0 *(0.8*rand(length(I_grid)) .+ 0.6) .* I_grid ./ (300 .+ I_grid)
110+
I_rate = LinearInterpolation(I_measured, I_grid)
111+
plot(I_rate; label = "Measured infection rate")
110112
plot!(I_grid, I_grid; label = "Normal SIR infection rate")
111113
```
112-
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.
114+
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.
113115
```@example functional_parameters_sir
114116
using Catalyst
117+
@parameters (inf_rate::typeof(I_rate))(..)
115118
@species I(default_t())
116-
inf_rate = I_rate(I)
119+
inf_rate_in = inf_rate(I)
117120
sir = @reaction_network rs begin
118-
k1*$inf_rate, S --> I
121+
k1*$inf_rate_in, S --> I
119122
k2, I --> R
120123
end
121124
nothing # hide
122125
```
123-
Finally, we can simualte our model.
126+
Finally, we can simulate our model.
124127
```@example functional_parameters_sir
125128
using OrdinaryDiffEqDefault
126129
u0 = [:S => 99.0, :I => 1.0, :R => 0.0]
127-
ps = [:k1 => 0.002, :k2 => 0.01, inf_rate => I_rate]
130+
ps = [:k1 => 0.002, :k2 => 0.01, :inf_rate => I_rate]
128131
oprob = ODEProblem(sir, u0, 250.0, ps)
129132
sol = solve(oprob)
130133
plot(sol)
@@ -145,4 +148,4 @@ plot(spline_linear)
145148
plot!(spline_cubuc)
146149
plot!(spline_const)
147150
```
148-
Finally, DataInterpolation.jl also allows various [extrapolation methods](https://docs.sciml.ai/DataInterpolations/stable/extrapolation_methods/).
151+
Finally, DataInterpolations.jl also allows various [extrapolation methods](https://docs.sciml.ai/DataInterpolations/stable/extrapolation_methods/).

test/reactionsystem_core/custom_crn_functions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ let
4949
ps = rnd_ps(custom_function_network_1, rng; factor)
5050
t = rand(rng)
5151
@test f_eval(custom_function_network_1, u0, ps, t) f_eval(custom_function_network_2, u0, ps, t)
52-
@test_broken jac_eval(custom_function_network_1, u0, ps, t) jac_eval(custom_function_network_2, u0, ps, t) # Weird error dur to some SciML update. Reported in https://github.com/SciML/ModelingToolkit.jl/issues/3447.
52+
@test jac_eval(custom_function_network_1, u0, ps, t) jac_eval(custom_function_network_2, u0, ps, t)
5353
@test g_eval(custom_function_network_1, u0, ps, t) g_eval(custom_function_network_2, u0, ps, t)
5454
end
5555
end

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ end
2121
@time @safetestset "Higher Order Reactions" begin include("reactionsystem_core/higher_order_reactions.jl") end
2222
@time @safetestset "Symbolic Stoichiometry" begin include("reactionsystem_core/symbolic_stoichiometry.jl") end
2323
@time @safetestset "Parameter Type Designation" begin include("reactionsystem_core/parameter_type_designation.jl") end
24-
@time @safetestset "Functional Parameters" begin include("reactionsystem_core/functional_parameters.jl") end
2524
@time @safetestset "Custom CRN Functions" begin include("reactionsystem_core/custom_crn_functions.jl") end
2625
@time @safetestset "Coupled CRN/Equation Systems" begin include("reactionsystem_core/coupled_equation_crn_systems.jl") end
2726
@time @safetestset "Events" begin include("reactionsystem_core/events.jl") end
27+
@time @safetestset "Functional Parameters" begin include("reactionsystem_core/functional_parameters.jl") end
2828

2929
# Tests model creation via the @reaction_network DSL.
3030
@time @safetestset "DSL Basic Model Construction" begin include("dsl/dsl_basic_model_construction.jl") end

0 commit comments

Comments
 (0)