Skip to content

Commit 93ef431

Browse files
Merge pull request #50 from isaacsas/dep-graph
WIP: generate dependency graph for reaction networks
2 parents 0e96aa9 + 7b93562 commit 93ef431

File tree

3 files changed

+139
-16
lines changed

3 files changed

+139
-16
lines changed

src/massaction_jump_utils.jl

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,24 @@ function rate_to_indices(network)
1313
Dict( rates[i] => i for i in eachindex(rates) )
1414
end
1515

16-
# given a ReactionStruct and a species map construct a MassActionJump
17-
function make_majump(rs, specmap, ratemap, params)
16+
# get substrate stoichiometry for a reaction
17+
function get_substrate_stoich(rs, specmap)
1818
reactant_stoich = Vector{Pair{Int,Int}}()
19-
nsdict = Dict{Int,Int}()
2019
for substrate in rs.substrates
2120
specpair = specmap[substrate.reactant] => substrate.stoichiometry
2221
push!(reactant_stoich, specpair)
22+
end
23+
sort!(reactant_stoich)
24+
reactant_stoich
25+
end
26+
27+
# get the net stoichiometry for a reaction
28+
function get_net_stoich(rs, specmap)
29+
nsdict = Dict{Int,Int}()
30+
for substrate in rs.substrates
2331
specpair = specmap[substrate.reactant] => -substrate.stoichiometry
2432
push!(nsdict, specpair)
2533
end
26-
sort!(reactant_stoich)
2734

2835
for product in rs.products
2936
prodidx = specmap[product.reactant]
@@ -36,9 +43,18 @@ function make_majump(rs, specmap, ratemap, params)
3643

3744
net_stoich = Vector{Pair{Int,Int}}()
3845
for stoich_map in sort(collect(nsdict))
39-
push!(net_stoich, stoich_map)
46+
if stoich_map[2] != zero(Int)
47+
push!(net_stoich, stoich_map)
48+
end
4049
end
4150

51+
net_stoich
52+
end
53+
54+
# given a ReactionStruct and a species map construct a MassActionJump
55+
function make_majump(rs, specmap, ratemap, params)
56+
reactant_stoich = get_substrate_stoich(rs, specmap)
57+
net_stoich = get_net_stoich(rs, specmap)
4258
if isempty(net_stoich)
4359
error("Empty net stoichiometry vectors for mass action reactions are not allowed.")
4460
end
@@ -76,4 +92,81 @@ function network_to_jumpset(rn, specmap, ratemap, params)
7692
else
7793
return JumpSet((), cjumpvec, nothing, majumpvec)
7894
end
95+
end
96+
97+
98+
######################### dependency graph utilities #########################
99+
100+
# map from a reaction index to the corresponding jump index
101+
# assumes all mass action jumps are ordered before constant rate jumps
102+
function rxidxs_to_jidxs_map(rn, num_majumps)
103+
majidx = 1
104+
cjidx = num_majumps + 1
105+
numrxs = length(rn.reactions)
106+
rxi_to_ji = zeros(Int, numrxs)
107+
for i = 1:numrxs
108+
if rn.reactions[i].is_pure_mass_action
109+
rxi_to_ji[i] = majidx
110+
majidx += 1
111+
else
112+
rxi_to_ji[i] = cjidx
113+
cjidx += 1
114+
end
115+
end
116+
rxi_to_ji
117+
end
118+
119+
# map from species to Set of jumps depending on that species
120+
function spec_to_dep_jumps_map(rn, specmap, rxidxs_to_jidxs)
121+
122+
numrxs = length(rn.reactions)
123+
numspec = length(specmap)
124+
125+
# map from a species to jumps that depend on it
126+
spec_to_dep_jumps = [Set{Int}() for n = 1:numspec]
127+
for rx in 1:numrxs
128+
for specsym in rn.reactions[rx].dependants
129+
push!(spec_to_dep_jumps[specmap[specsym]], rxidxs_to_jidxs[rx])
130+
end
131+
end
132+
133+
spec_to_dep_jumps
134+
end
135+
136+
# given a reaction network and species map, construct a jump dependency graph
137+
function depgraph_from_network(rn, specmap, jset)
138+
139+
numrxs = length(rn.reactions)
140+
numspec = length(specmap)
141+
num_majumps = get_num_majumps(jset.massaction_jump)
142+
143+
# map reaction indices to jump indices
144+
rxidxs_to_jidxs = rxidxs_to_jidxs_map(rn, num_majumps)
145+
146+
# map from species to jumps that depend on it
147+
spec_to_dep_jumps = spec_to_dep_jumps_map(rn, specmap, rxidxs_to_jidxs)
148+
149+
# create map from a jump to jumps depending on it
150+
dep_sets = [SortedSet{Int}() for n = 1:numrxs]
151+
for rx in 1:numrxs
152+
jidx = rxidxs_to_jidxs[rx]
153+
154+
# get the net reaction stoichiometry
155+
net_stoich = get_net_stoich(rn.reactions[rx], specmap)
156+
157+
# rx changes spec, hence rxs depending on spec depend on rx
158+
for (spec,stoch) in net_stoich
159+
for dependent_jump in spec_to_dep_jumps[spec]
160+
push!(dep_sets[jidx], dependent_jump)
161+
end
162+
end
163+
end
164+
165+
# convert to Vectors of Vectors
166+
dep_graph = Vector{Vector{Int}}(numrxs)
167+
for jidx in 1:numrxs
168+
dep_graph[jidx] = [dep for dep in dep_sets[jidx]]
169+
end
170+
171+
dep_graph
79172
end

src/problem.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ function DiffEqJump.JumpProblem(prob,aggregator,rn::AbstractReactionNetwork; kwa
1717
# get a JumpSet of the possible jumps
1818
jset = network_to_jumpset(rn, spec_to_idx, param_to_idx, prob.p)
1919

20-
JumpProblem(prob, aggregator, jset; kwargs...)
20+
# # construct dependency graph if needed by aggregator
21+
if needs_depgraph(aggregator)
22+
dep_graph = depgraph_from_network(rn, spec_to_idx, jset)
23+
else
24+
dep_graph = nothing
25+
end
26+
27+
JumpProblem(prob, aggregator, jset; dep_graph=dep_graph, kwargs...)
2128
end
2229

2330
### SteadyStateProblem ###

test/mass_act_jump_tests.jl

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ using DiffEqBiological, DiffEqJump, DiffEqBase, Base.Test
33
dotestmean = true
44
doprintmeans = false
55
reltol = .01 # required test accuracy
6+
methods = (Direct(), SortingDirect())
67

78
# run the given number of SSAs and return the mean
89
function runSSAs(jump_prob, Nsims, idx)
@@ -16,14 +17,17 @@ end
1617

1718
function execute_test(u0, tf, rates, rs, Nsims, expected_avg, idx, test_name)
1819
prob = DiscreteProblem(u0, (0.0, tf), rates)
19-
jump_prob = JumpProblem(prob, Direct(), rs)
20-
avg_val = runSSAs(jump_prob, Nsims, idx)
21-
22-
if dotestmean
23-
if doprintmeans
24-
println(test_name, ": mean = ", avg_val, ", act_mean = ", expected_avg)
20+
21+
for method in methods
22+
jump_prob = JumpProblem(prob, method, rs)
23+
avg_val = runSSAs(jump_prob, Nsims, idx)
24+
25+
if dotestmean
26+
if doprintmeans
27+
println(test_name, ", method = ", typeof(method), ", mean = ", avg_val, ", act_mean = ", expected_avg)
28+
end
29+
@test abs(avg_val - expected_avg) < reltol * expected_avg
2530
end
26-
@test abs(avg_val - expected_avg) < reltol * expected_avg
2731
end
2832

2933
end
@@ -55,12 +59,29 @@ rs = @reaction_network ptype begin
5559
end k1 k2 k3 k4 k5 k6
5660
Nsims = 8000
5761
tf = 1000.0
58-
u0 = [1,0,0,0]
62+
u0 = [1,0,0,0]
5963
expected_avg = 5.926553750000000e+02
6064
rates = [.5, (20*log(2.)/120.), (log(2.)/120.), (log(2.)/600.), .025, 1.]
6165
execute_test(u0, tf, rates, rs, Nsims, expected_avg, 3, "DNA test")
6266

6367

68+
# DNA repression model, mix of jump types
69+
rs = @reaction_network ptype begin
70+
k1*DNA, 0 --> mRNA
71+
k2*mRNA, 0 --> P
72+
k3, mRNA --> 0
73+
k4, P --> 0
74+
k5, DNA + P --> DNAR
75+
k6, DNAR --> DNA + P
76+
end k1 k2 k3 k4 k5 k6
77+
Nsims = 8000
78+
tf = 1000.0
79+
u0 = [0,0,0,0]
80+
u0[findfirst(rs.syms, :DNA)] = 1
81+
expected_avg = 5.926553750000000e+02
82+
rates = [.5, (20*log(2.)/120.), (log(2.)/120.), (log(2.)/600.), .025, 1.]
83+
execute_test(u0, tf, rates, rs, Nsims, expected_avg, findfirst(rs.syms, :P), "DNA mixed jump test")
84+
6485
# simple constant production with degratation
6586
rs = @reaction_network pdtype begin
6687
1000., 0 --> A
@@ -88,5 +109,7 @@ network = @reaction_network rnType begin
88109
0.05, SP2 --> 0
89110
end;
90111
prob = DiscreteProblem([200.,60.,120.,100.,50.,50.,50.], (0.,4000.))
91-
jump_prob = JumpProblem(prob, Direct(), network)
92-
sol = solve(jump_prob,SSAStepper());
112+
for method in methods
113+
jump_prob = JumpProblem(prob, method, network)
114+
sol = solve(jump_prob,SSAStepper());
115+
end

0 commit comments

Comments
 (0)