|
28 | 28 | function JumpProcesses.JumpProblem(lrs::LatticeReactionSystem, dprob, aggregator, args...; name = nameof(lrs.rs),
|
29 | 29 | combinatoric_ratelaws = get_combinatoric_ratelaws(lrs.rs), kwargs...)
|
30 | 30 | # Error checks.
|
31 |
| - (dprob.p isa Vector{Vector{Vector{Float64}}}) || dprob.p isa Vector{Vector} || error("Parameters in input DiscreteProblem is of an unexpected type: $(typeof(dprob.p)). Was a LatticeReactionProblem passed into the DiscreteProblem when it was created?") # The second check (Vector{Vector} is needed becaus on the CI server somehow the Tuple{..., ...} is covnerted into a Vector[..., ...]). It does not happen when I run tests locally, so no ideal how to fix. |
32 |
| - any(length.(dprob.p[1]) .> 1) && error("Spatial reaction rates are currently not supported in lattice jump simulations.") |
| 31 | + # The second check (Vector{Vector} is needed because on the CI server somehow the Tuple{..., ...} is converted into a Vector[..., ...]). |
| 32 | + # It does not happen when I run tests locally, so no ideal how to fix. |
| 33 | + (dprob.p isa Vector{Vector{Vector{Float64}}}) || dprob.p isa Vector{Vector} || error("Parameters in input DiscreteProblem is of an unexpected type: $(typeof(dprob.p)). Was a LatticeReactionProblem passed into the DiscreteProblem when it was created?") |
33 | 34 |
|
34 | 35 | # Computes hopping constants and mass action jumps (requires some internal juggling).
|
35 |
| - # The non-spatial DiscreteProblem have a u0 matrix with entries for all combinations of species and vertexes. |
36 | 36 | # Currently, JumpProcesses requires uniform vertex parameters (hence `p=first.(dprob.p[1])`).
|
| 37 | + # Currently, the resulting JumpProblem does not depend on parameters (no way to incorporate these). |
| 38 | + # Hence the parameters of this one does nto actually matter. If at some point JumpProcess can |
| 39 | + # handle parameters this can be updated and improved. |
| 40 | + # The non-spatial DiscreteProblem have a u0 matrix with entries for all combinations of species and vertexes. |
37 | 41 | hopping_constants = make_hopping_constants(dprob, lrs)
|
| 42 | + sma_jumps = make_spatial_majumps(dprob, lrs) |
38 | 43 | non_spat_dprob = DiscreteProblem(reshape(dprob.u0, lrs.num_species, lrs.num_verts), dprob.tspan, first.(dprob.p[1]))
|
39 |
| - sma_jumps = make_spatial_majumps(non_spat_dprob, dprob, lrs) |
40 | 44 |
|
41 | 45 | return JumpProblem(non_spat_dprob, aggregator, sma_jumps;
|
42 | 46 | hopping_constants, spatial_system = lrs.lattice, name, kwargs...)
|
@@ -66,22 +70,65 @@ function make_hopping_constants(dprob::DiscreteProblem, lrs::LatticeReactionSyst
|
66 | 70 | return hopping_constants
|
67 | 71 | end
|
68 | 72 |
|
69 |
| -# Creates the (spatial) mass action jumps from a (spatial) DiscreteProblem its non-spatial version, and a LatticeReactionSystem. |
70 |
| -function make_spatial_majumps(non_spat_dprob, dprob, rs::LatticeReactionSystem) |
71 |
| - ma_jumps = make_majumps(non_spat_dprob, lrs.rs) |
72 |
| - |
| 73 | +# Creates a SpatialMassActionJump struct from a (spatial) DiscreteProblem and a LatticeReactionSystem. |
| 74 | +# Could implementation a version which, if all reaction's rates are uniform, returns a MassActionJump. |
| 75 | +# Not sure if there is any form of performance improvement from that though. Possibly is not the case. |
| 76 | +function make_spatial_majumps(dprob, lrs::LatticeReactionSystem) |
| 77 | + # Creates a vector, storing which reactions have spatial components. |
| 78 | + is_spatials = [Catalyst.has_spatial_vertex_component(rx.rate, lrs; vert_ps = dprob.p[1]) for rx in reactions(lrs.rs)] |
| 79 | + |
| 80 | + # Creates templates for the rates (uniform and spatial) and the stoichiometries. |
| 81 | + # We cannot fetch reactant_stoich and net_stoich from a (non-spatial) MassActionJump. |
| 82 | + # The reason is that we need to re-order the reactions so that uniform appears first, and spatial next. |
| 83 | + u_rates = Vector{Float64}(undef, length(reactions(lrs.rs)) - count(is_spatials)) |
| 84 | + s_rates = Matrix{Float64}(undef, count(is_spatials), lrs.num_verts) |
| 85 | + reactant_stoich = Vector{Vector{Pair{Int64, Int64}}}(undef, length(reactions(lrs.rs))) |
| 86 | + net_stoich = Vector{Vector{Pair{Int64, Int64}}}(undef, length(reactions(lrs.rs))) |
| 87 | + |
| 88 | + # Loops through reactions with non-spatial rates, computes their rates and stoichiometries. |
| 89 | + cur_rx = 1; |
| 90 | + for (is_spat, rx) in zip(is_spatials, reactions(lrs.rs)) |
| 91 | + is_spat && continue |
| 92 | + u_rates[cur_rx] = compute_vertex_value(rx.rate, lrs; vert_ps = dprob.p[1])[1] |
| 93 | + substoich_map = Pair.(rx.substrates, rx.substoich) |
| 94 | + reactant_stoich[cur_rx] = int_map(substoich_map, lrs.rs) |
| 95 | + net_stoich[cur_rx] = int_map(rx.netstoich, lrs.rs) |
| 96 | + cur_rx += 1 |
| 97 | + end |
| 98 | + # Loops through reactions with spatial rates, computes their rates and stoichiometries. |
| 99 | + for (is_spat, rx) in zip(is_spatials, reactions(lrs.rs)) |
| 100 | + is_spat || continue |
| 101 | + s_rates[cur_rx-length(u_rates),:] = compute_vertex_value(rx.rate, lrs; vert_ps = dprob.p[1]) |
| 102 | + substoich_map = Pair.(rx.substrates, rx.substoich) |
| 103 | + reactant_stoich[cur_rx] = int_map(substoich_map, lrs.rs) |
| 104 | + net_stoich[cur_rx] = int_map(rx.netstoich, lrs.rs) |
| 105 | + cur_rx += 1 |
| 106 | + end |
| 107 | + # SpatialMassActionJump expects empty rate containers to be nothing. |
| 108 | + isempty(u_rates) && (u_rates = nothing) |
| 109 | + (count(is_spatials)==0) && (s_rates = nothing) |
| 110 | + |
| 111 | + return SpatialMassActionJump(u_rates, s_rates, reactant_stoich, net_stoich) |
73 | 112 | end
|
74 | 113 |
|
75 |
| -# Creates the (non-spatial) mass action jumps from a (non-spatial) DiscreteProblem (and its Reaction System of origin). |
76 |
| -function make_majumps(non_spat_dprob, rs::ReactionSystem) |
77 |
| - # Computes various required inputs for assembling the mass action jumps. |
78 |
| - js = convert(JumpSystem, rs) |
79 |
| - statetoid = Dict(ModelingToolkit.value(state) => i for (i, state) in enumerate(states(rs))) |
80 |
| - eqs = equations(js) |
81 |
| - invttype = non_spat_dprob.tspan[1] === nothing ? Float64 : typeof(1 / non_spat_dprob.tspan[2]) |
82 |
| - |
83 |
| - # Assembles the non-spatial mass action jumps. |
84 |
| - p = (non_spat_dprob.p isa DiffEqBase.NullParameters || non_spat_dprob.p === nothing) ? Num[] : non_spat_dprob.p |
85 |
| - majpmapper = ModelingToolkit.JumpSysMajParamMapper(js, p; jseqs = eqs, rateconsttype = invttype) |
86 |
| - return ModelingToolkit.assemble_maj(eqs.x[1], statetoid, majpmapper) |
| 114 | +### Extra ### |
| 115 | + |
| 116 | +# Temporary. Awaiting implementation in SII, or proper implementation withinCatalyst (with more general functionality). |
| 117 | +function int_map(map_in, sys) where {T,S} |
| 118 | + return [ModelingToolkit.variable_index(sys, pair[1]) => pair[2] for pair in map_in] |
87 | 119 | end
|
| 120 | + |
| 121 | +# Currently unused. If we want to create certain types of MassActionJumps (instead of SpatialMassActionJumps) we can take this one back. |
| 122 | +# Creates the (non-spatial) mass action jumps from a (non-spatial) DiscreteProblem (and its Reaction System of origin). |
| 123 | +# function make_majumps(non_spat_dprob, rs::ReactionSystem) |
| 124 | +# # Computes various required inputs for assembling the mass action jumps. |
| 125 | +# js = convert(JumpSystem, rs) |
| 126 | +# statetoid = Dict(ModelingToolkit.value(state) => i for (i, state) in enumerate(states(rs))) |
| 127 | +# eqs = equations(js) |
| 128 | +# invttype = non_spat_dprob.tspan[1] === nothing ? Float64 : typeof(1 / non_spat_dprob.tspan[2]) |
| 129 | +# |
| 130 | +# # Assembles the non-spatial mass action jumps. |
| 131 | +# p = (non_spat_dprob.p isa DiffEqBase.NullParameters || non_spat_dprob.p === nothing) ? Num[] : non_spat_dprob.p |
| 132 | +# majpmapper = ModelingToolkit.JumpSysMajParamMapper(js, p; jseqs = eqs, rateconsttype = invttype) |
| 133 | +# return ModelingToolkit.assemble_maj(eqs.x[1], statetoid, majpmapper) |
| 134 | +# end |
0 commit comments