Skip to content

Commit f31cc23

Browse files
add @per_step deterministic "rate"
1 parent a64d86f commit f31cc23

File tree

6 files changed

+86
-9
lines changed

6 files changed

+86
-9
lines changed

docs/src/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ We list common species attributes:
2626
| `specInitUncertainty` | uncertainty about variable's initial state (modelled as Gaussian standard deviation) |
2727
| `specInitVal` | initial value of a variable |
2828

29+
Moreover, it is possible to specify the semantics of the "rate" term. By default, at each time step `n ~ Poisson(rate * dt)` instances of a given transition will be spawned. If you want to specify the rate in terms of a cycle time, you may want to use `@ct(cycle_time)`, e.g., `@ct(ex), A --> B, ...`. This is a shorthand for `1/ex, A --> B, ...`.
30+
31+
For deterministic "rates", use `@per_step(ex)`. Here, `ex` evaluates to a deterministic number (ceiled to the nearest integer) of a transition's instances to spawn per a single integrator's step. However, note that in this case, the number doesn't scale with the step length! Moreover
32+
2933
```@docs
3034
@add_species
3135
@aka

src/interface/create.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,22 @@ function recursively_expand_actions!(evs, condex, event)
115115
else push!(evs, Event(condex, event)) end
116116
end
117117

118-
function prune_rate(rate)
119-
if (isexpr(rate, :macrocall) && (macroname(rate) prettynames[:transCycleTime]))
120-
:(1/$(rate.args[3]))
121-
else rate end
118+
function expand_rate(rate)
119+
rate = if !(isexpr(rate, :macrocall) && (macroname(rate) == :per_step))
120+
:(rand(Poisson(max($rate, 0))))
121+
else rate.args[3] end
122+
123+
postwalk(rate) do ex
124+
if (isexpr(ex, :macrocall) && (macroname(ex) prettynames[:transCycleTime]))
125+
:(1/$(ex.args[3]))
126+
else ex end
127+
end
122128
end
123129

124130
function get_transitions!(trans, reactants, pcs, exs)
125131
args = empty(defargs[:T])
126132
(rate, r_line) = exs[1:2]
127-
rxs = prune_reaction_line!(pcs, reactants, r_line); rate = prune_rate(rate)
133+
rxs = prune_reaction_line!(pcs, reactants, r_line); rate = expand_rate(rate)
128134
rxs = rxs isa Tuple ? tuple.(rate.args, rxs) : ((rate, rxs),)
129135

130136
exs = exs[3:end]; empty!(args)

src/solvers.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ function evolve!(u, state)
9999
reqs = zeros(nparts(state, :S), nparts(state, :T)); qs = zeros(nparts(state, :T))
100100

101101
foreach(i -> qs[i] = state[i, :transRate] * state[i, :transMultiplier], 1:nparts(state, :T))
102+
qs .= ceil.(Ref(Int), qs)
102103
for i in 1:nparts(state, :T)
103-
new_instances = rand(Poisson(max(state.solverargs[:tstep] * qs[i], 0))) + state[i, :transToSpawn]
104+
new_instances = state.solverargs[:tstep]*qs[i] + state[i, :transToSpawn]
104105
capacity = state[i, :transCapacity] - count(t -> t[:transHash] == state[i, :transHash], state.ongoing_transitions)
105106
(capacity < new_instances) && add_to_spawn!(state, state[i, :transHash], new_instances - capacity)
106107
qs[i] = min(capacity, new_instances)

test/tutorial_tests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ using ReactiveDynamics
44
@safeinclude "joins" "../tutorial/joins/joins.jl"
55
@safeinclude "loadsave" "../tutorial/loadsave/loadsave.jl"
66
@safeinclude "optimize" "../tutorial/optimize/optimize.jl"
7-
@safeinclude "solution wrap" "../tutorial/optimize/optimize_custom.jl"
7+
@safeinclude "solution wrap" "../tutorial/optimize/optimize_custom.jl"
8+
@safeinclude "toy pharma model" "../tutorial/toy_pharma_model.jl"

tutorial/example.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ end
2121
@valuation sir_acs I=.1 # for testing purpose only
2222

2323
# atomic data: initial values, parameter values
24-
@prob_init sir_acs S=999 I=10 R=0
24+
@prob_init sir_acs S=999 I=100 R=100
2525
u0 = [999, 10, 0] # alternative specification
2626
@prob_init sir_acs u0
2727
@prob_params sir_acs β=0.0001 ν=0.01 γ=5
2828
@prob_meta sir_acs tspan=100
2929

30-
prob = @problematize sir_acs
30+
#prob = @problematize sir_acs
3131
prob = @problematize sir_acs tspan=200
3232

3333
sol = @solve prob trajectories=20

tutorial/toy_pharma_model.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using ReactiveDynamics
2+
3+
# model dynamics
4+
toy_pharma_model = @ReactionNetwork begin
5+
α(candidate_compound, marketed_drug, κ), 3*@conserved(scientist) + @rate(budget) --> candidate_compound, name=>discovery, probability=>.3, cycletime=>10., priority=>.5
6+
β(candidate_compound, marketed_drug), candidate_compound + 5*@conserved(scientist) + 2*@rate(budget) --> marketed_drug + 5*budget, name=>dx2market, probability=>.5+.001*@t(), cycletime=>4
7+
γ*marketed_drug, marketed_drug --> ∅, name=>drug_killed
8+
end
9+
10+
@periodic toy_pharma_model 1. budget += 11*marketed_drug
11+
12+
@register α(number_candidate_compounds, number_marketed_drugs, κ) = κ + exp(-number_candidate_compounds) + exp(-number_marketed_drugs)
13+
@register β(number_candidate_compounds, number_marketed_drugs) = number_candidate_compounds + exp(-number_marketed_drugs)
14+
15+
# simulation parameters
16+
## initial values
17+
@prob_init toy_pharma_model candidate_compound=5 marketed_drug=6 scientist=20 budget=100
18+
## parameters
19+
@prob_params toy_pharma_model κ=4 γ=.1
20+
## other arguments passed to the solver
21+
@prob_meta toy_pharma_model tspan=250 dt=.1
22+
23+
24+
prob = @problematize toy_pharma_model
25+
26+
sol = @solve prob trajectories=20
27+
28+
using Plots; plotly()
29+
30+
@plot sol plot_type=summary
31+
32+
@plot sol plot_type=summary show=:marketed_drug
33+
34+
## for deterministic rates
35+
36+
# model dynamics
37+
toy_pharma_model = @ReactionNetwork begin
38+
@per_step(α(candidate_compound, marketed_drug, κ)), 3*@conserved(scientist) + @rate(budget) --> candidate_compound, name=>discovery, probability=>.3, cycletime=>10., priority=>.5
39+
@per_step(β(candidate_compound, marketed_drug)), candidate_compound + 5*@conserved(scientist) + 2*@rate(budget) --> marketed_drug + 5*budget, name=>dx2market, probability=>.5+.001*@t(), cycletime=>4
40+
@per_step*marketed_drug), marketed_drug --> ∅, name=>drug_killed
41+
end
42+
43+
@periodic toy_pharma_model 0. budget += 11*marketed_drug
44+
45+
@register α(number_candidate_compounds, number_marketed_drugs, κ) = κ + exp(-number_candidate_compounds) + exp(-number_marketed_drugs)
46+
@register β(number_candidate_compounds, number_marketed_drugs) = number_candidate_compounds + exp(-number_marketed_drugs)
47+
48+
# simulation parameters
49+
## initial values
50+
@prob_init toy_pharma_model candidate_compound=5 marketed_drug=6 scientist=20 budget=100
51+
## parameters
52+
@prob_params toy_pharma_model κ=4 γ=.1
53+
## other arguments passed to the solver
54+
@prob_meta toy_pharma_model tspan=250
55+
56+
57+
prob = @problematize toy_pharma_model
58+
59+
sol = @solve prob trajectories=20
60+
61+
using Plots; plotly()
62+
63+
@plot sol plot_type=summary
64+
65+
@plot sol plot_type=summary show=:marketed_drug

0 commit comments

Comments
 (0)