JumpProcesses.jl API
Core Types
JumpProcesses.ExtendedJumpArray — Type
struct ExtendedJumpArray{T3<:Number, T1, T<:AbstractArray{T3<:Number, T1}, T2} <: AbstractArray{T3<:Number, 1}Extended state definition used within integrators when there are VariableRateJumps in a system. For detailed examples and usage information, see the
Fields
u: The current state.jump_u: The current rate (i.e. hazard, intensity, or propensity) values for theVariableRateJumps.
Examples
using JumpProcesses, OrdinaryDiffEq
f(du, u, p, t) = du .= 0
rate(u, p, t) = (1+t)*u[1]*u[2]
# suppose we wish to decrease each of the two variables by one
# when a jump occurs
function affect!(integrator)
# Method 1, direct indexing works like normal
integrator.u[1] -= 1
integrator.u[2] -= 1
# Method 2, if we want to broadcast or use array operations we need
# to access integrator.u.u which is the actual state object.
# So equivalently to above we could have said:
# integrator.u.u .-= 1
end
u0 = [10.0, 10.0]
vrj = VariableRateJump(rate, affect!)
oprob = ODEProblem(f, u0, (0.0, 2.0))
jprob = JumpProblem(oprob, Direct(), vrj)
sol = solve(jprob, Tsit5())Notes
If
ueja isa ExtendedJumpArraywithueja.uof sizeNandueja.jump_uof sizenum_variableratejumpsthen# for 1 <= i <= N ueja[i] == ueja.u[i] # for N < i <= (N+num_variableratejumps) ueja[i] == ueja.jump_u[i]In a system with
VariableRateJumps all callback,ConstantRateJump, andVariableRateJumpaffect!functions will receive integrators withintegrator.uanExtendedJumpArray.As such,
affect!functions that wish to modify the state via vector operations should useueja.u.uto obtain the aliased state object.
JumpProcesses.JumpProblem — Type
mutable struct JumpProblem{iip, P, A, C, J<:Union{Nothing, JumpProcesses.AbstractJumpAggregator}, J1, J2, J3, J4, R, K} <: SciMLBase.AbstractJumpProblem{P, J<:Union{Nothing, JumpProcesses.AbstractJumpAggregator}}Defines a collection of jump processes to associate with another problem type.
Constructors
JumpProblems can be constructed by first building another problem type to which the jumps will be associated. For example, to simulate a collection of jump processes for which the transition rates are constant between jumps (called ConstantRateJumps or MassActionJumps), we must first construct a DiscreteProblem
prob = DiscreteProblem(u0, p, tspan)where u0 is the initial condition, p the parameters and tspan the time span. If we wanted to have the jumps coupled with a system of ODEs, or have transition rates with explicit time dependence, we would use an ODEProblem instead that defines the ODE portion of the dynamics.
Given prob we define the jumps via
JumpProblem(prob, aggregator::AbstractAggregatorAlgorithm, jumps::JumpSet ; kwargs...)JumpProblem(prob, aggregator::AbstractAggregatorAlgorithm, jumps...; kwargs...)
Here aggregator specifies the underlying algorithm for calculating next jump times and types, for example Direct. The collection of different AbstractJump types can then be passed within a single JumpSet or as subsequent sequential arguments.
Fields
prob: The type of problem to couple the jumps to. For a pure jump process useDiscreteProblem, to couple to ODEs,ODEProblem, etc.aggregator: The aggregator algorithm that determines the next jump times and types forConstantRateJumps andMassActionJumps. Examples includeDirect.discrete_jump_aggregation: The underlying state data associated with the chosen aggregator.jump_callback:CallBackSetwith the underlyingConstantRateandVariableRatejumps.constant_jumps: TheConstantRateJumps.variable_jumps: TheVariableRateJumps.regular_jump: TheRegularJumps.massaction_jump: TheMassActionJumps.rng: The random number generator to use.kwargs: kwargs to pass on to solve call.
Keyword Arguments
rng, the random number generator to use. Defaults to Julia's built-in generator.save_positions=(true,true)when including variable rates and(false,true)for constant rates, specifies whether to save the system's state (before, after) the jump occurs. NOTE, this only controls saving for non-VariableRateJumps.VariableRateJumpsaving is controlled at the individual jump level via the value of this kwarg passed to the individualVariableRateJumps constructor when it is created.spatial_system, for spatial problems the underlying spatial structure.hopping_constants, for spatial problems the spatial transition rate coefficients.use_vrj_bounds = true, set to false to disable handling boundedVariableRateJumps with a supporting aggregator (such asCoevolve). They will then be handled via the continuous integration interface, and treated like generalVariableRateJumps.vr_aggregator, indicates the aggregator to use for sampling variable rate jumps. Current default isVR_FRM.
Please see the tutorial page in the DifferentialEquations.jl docs for usage examples and commonly asked questions.
JumpProcesses.PureLeaping — Type
PureLeaping()Request that all jumps in a JumpProblem are handled by the leaping algorithm passed to solve, instead of being converted into callback-based SSA aggregators during problem construction.
Returns
- A stateless aggregator marker for
JumpProblem(prob, PureLeaping(), jumps; kwargs...).
Notes
PureLeapingis currently intended for tau-leaping algorithms such asSimpleTauLeapingandSimpleExplicitTauLeaping.- Spatial jump problems are not supported by the
PureLeapingconstruction path.
Examples
using JumpProcesses, DiffEqBase
rate!(out, u, p, t) = (out[1] = 0.2 * u[1])
affect!(du, u, p, t, counts, mark) = (du[1] = -counts[1])
rj = RegularJump(rate!, affect!, 1)
prob = DiscreteProblem([10], (0.0, 1.0))
jprob = JumpProblem(prob, PureLeaping(), rj)
sol = solve(jprob, SimpleTauLeaping(); dt = 0.1)JumpProcesses.SSAStepper — Type
struct SSAStepper <: SciMLBase.AbstractDEAlgorithmHighly efficient integrator for pure jump problems that involve only ConstantRateJumps, MassActionJumps, and/or VariableRateJumps with rate bounds.
Notes
- Only works with
JumpProblems defined fromDiscreteProblems. - Only works with collections of
ConstantRateJumps,MassActionJumps, andVariableRateJumps with rate bounds. - Only supports
DiscreteCallbacks for events, which are checked after every step taken bySSAStepper. - Only supports a limited subset of the output controls from the common solver interface, specifically
save_start,save_end, andsaveat. - As when using jumps with ODEs and SDEs, saving controls for whether to save each time a jump occurs are via the
save_positionskeyword argument toJumpProblem. Note that when choosingSSAStepperas the timestepper,save_positions = (true,true),(true,false), or(false,true)are all equivalent.SSAStepperwill save only the post-jump state in the solution object in each of these cases. This is because solution objects generated viaSSAStepperuse piecewise-constant interpolation, and can therefore exactly reconstruct the sampled jump process path with knowing just the post-jump state. That is,sol(t)for any0 <= t <= tstopwill give the exact value of the sampled solution path attprovided at least one component ofsave_positionsistrue.
Examples
SIR model:
using JumpProcesses
β = 0.1 / 1000.0;
ν = 0.01;
p = (β, ν)
rate1(u, p, t) = p[1]*u[1]*u[2] # β*S*I
function affect1!(integrator)
integrator.u[1] -= 1 # S -> S - 1
integrator.u[2] += 1 # I -> I + 1
end
jump = ConstantRateJump(rate1, affect1!)
rate2(u, p, t) = p[2]*u[2] # ν*I
function affect2!(integrator)
integrator.u[2] -= 1 # I -> I - 1
integrator.u[3] += 1 # R -> R + 1
end
jump2 = ConstantRateJump(rate2, affect2!)
u₀ = [999, 1, 0]
tspan = (0.0, 250.0)
prob = DiscreteProblem(u₀, tspan, p)
jump_prob = JumpProblem(prob, Direct(), jump, jump2)
sol = solve(jump_prob, SSAStepper())see the tutorial for details.
JumpProcesses.SplitCoupledJumpProblem — Function
David F. Anderson, Masanori Koyama; An asymptotic relationship between coupling methods for stochastically modeled population processes. IMA J Numer Anal 2015; 35 (4): 1757-1778. doi: 10.1093/imanum/dru044
JumpProcesses.reset_aggregated_jumps! — Function
reset_aggregated_jumps!(integrator, uprev = nothing; update_jump_params=true)Reset the state of jump processes and associated solvers following a change in parameters or such.
Notes
update_jump_params=truewill recalculate the rates stored within any MassActionJump that was built from the parameter vector. If the parameter vector is unchanged, this can safely be set to false to improve performance.
Jump Types
JumpProcesses.ConstantRateJump — Type
struct ConstantRateJump{F1, F2, B<:Union{Nothing, JumpProcesses.RateBoundFunctions}} <: JumpProcesses.AbstractJumpDefines a jump process with a rate (i.e. hazard, intensity, or propensity) that does not explicitly depend on time. More precisely, one where the rate function is constant between the occurrence of jumps. For detailed examples and usage information, see the
Fields
rate: Functionrate(u,p,t)that returns the jump's current rate.affect!: Functionaffect(integrator)that updates the state for one occurrence of the jump.bounds: OptionalRateBoundFunctionsholding user supplied bracketing functions.
Examples
Suppose u[1] gives the number of particles and p[1] the probability per time each particle can decay away. A corresponding ConstantRateJump for this jump process is
rate(u,p,t) = p[1]*u[1]
affect!(integrator) = integrator.u[1] -= 1
crj = ConstantRateJump(rate, affect!)Notice, here that rate changes in time, but is constant between the occurrence of jumps (when u[1] will decrease).
Rate bounds may be supplied separately, for use with bracketing aggregators such as RSSA:
rate(u, p, t) = p[1] * u[1] / (1 + u[2])
affect!(integrator) = integrator.u[1] -= 1
bounds(ulow, uhigh, u, p, t) = RateBounds(lrate=p[1]*ulow[1] / (1+uhigh[2]),
urate=p[1]*uhigh[1] / (1+ulow[2]))
crj = ConstantRateJump(rate, affect!; bounds)Notes
- When rate bounds are not supplied, they are computed by evaluating the rate at
ulowanduhigh. These bounds are only correct if the rate is monotonic with respect to state, i.e. increasing in all species or decreasing in all species.
JumpProcesses.MassActionJump — Type
struct MassActionJump{T, S, U, V} <: JumpProcesses.AbstractMassActionJumpOptimized representation for ConstantRateJumps that can be represented in mass action form, offering improved performance within jump algorithms compared to ConstantRateJump. For detailed examples and usage information, see the
Constructors
MassActionJump(reactant_stoich, net_stoich; scale_rates = true, param_idxs = nothing)
Here reactant_stoich denotes the reactant stoichiometry for each reaction and net_stoich the net stoichiometry for each reaction.
Fields
scaled_rates: The (scaled) reaction rate constants.reactant_stoch: The reactant stoichiometry vectors.net_stoch: The net stoichiometry vectors.param_mapper: Parameter mapping functor to identify reaction rate constants with parameters inpvectors.rescale_rates_on_update: Whetherupdate_parameters!should apply stoichiometric scaling to rates.
Keyword Arguments
scale_rates = true, whether to rescale the reaction rate constants according to the stoichiometry.nocopy = false, whether theMassActionJumpcan alias thescaled_ratesandreactant_stochfrom the input. Note, ifscale_rates=truethis will potentially modify both of these.param_idxs = nothing, indexes in the parameter vector,JumpProblem.prob.p, that correspond to each reaction's rate.
See the tutorial and main docs for details.
Examples
An SIR model with S + I --> 2I at rate β as the first reaction and I --> R at rate ν as the second reaction can be encoded by
p = (β=1e-4, ν=.01)
u0 = [999, 1, 0] # (S,I,R)
tspan = (0.0, 250.0)
rateidxs = [1, 2] # i.e. [β,ν]
reactant_stoich = [
[1 => 1, 2 => 1], # 1*S and 1*I
[2 => 1] # 1*I
]
net_stoich = [
[1 => -1, 2 => 1], # -1*S and 1*I
[2 => -1, 3 => 1] # -1*I and 1*R
]
maj = MassActionJump(reactant_stoich, net_stoich; param_idxs=rateidxs)
prob = DiscreteProblem(u0, tspan, p)
jprob = JumpProblem(prob, Direct(), maj)Notes
JumpProcesses.VariableRateJump — Type
struct VariableRateJump{R, F, R2, R3, R4, I, T, T2} <: JumpProcesses.AbstractJumpDefines a jump process with a rate (i.e. hazard, intensity, or propensity) that may explicitly depend on time. More precisely, one where the rate function is allowed to change between the occurrence of jumps. For detailed examples and usage information, see the
Note that two types of VariableRateJumps are currently supported, with different performance characteritistics.
A general
VariableRateJumporVariableRateJumpwill refer to one in which onlyrateandaffectfunctions are specified.- These are the most general in what they can represent, but require the use of an
ODEProblemorSDEProblemwhose underlying timestepper handles their evolution in time (via the callback interface). - This is the least performant jump type in simulations.
- These are the most general in what they can represent, but require the use of an
Bounded
VariableRateJumps require passing the keyword argumentsurateandrateinterval, corresponding to functionsurate(u, p, t)andrateinterval(u, p, t), see below. These must calculate a time window over which the rate function is bounded by a constant. Note that it is ok if the rate bound would be violated within the time interval due to a change inuarising from anotherConstantRateJump,MassActionJumpor boundedVariableRateJumpbeing executed, as the chosen aggregator will then handle recalculating the rate bound and interval. However, if the bound could be violated within the time interval due to a change inuarising from continuous dynamics such as a coupled ODE, SDE, or a generalVariableRateJump, bounds should not be given. This ensures the jump is classified as a generalVariableRateJumpand properly handled. One can also optionally provide a lower bound function,lrate(u, p, t), via thelratekeyword argument. This can lead to increased performance. The validity of the lower bound should hold under the same conditions and rate interval asurate.- Bounded
VariableRateJumps can currently be used in theCoevolveaggregator, and can therefore be efficiently simulated in pure-jumpDiscreteProblems using theSSASteppertime-stepper. - These can be substantially more performant than general
VariableRateJumps without the rate bound functions.
- Bounded
Reemphasizing, the additional user provided functions leveraged by bounded VariableRateJumps, urate(u, p, t), rateinterval(u, p, t), and the optional lrate(u, p, t) require that
- For
sin[t, t + rateinterval(u, p, t)], we have thatlrate(u, p, t) <= rate(u, p, s) <= urate(u, p, t). - It is ok if these bounds would be violated during the time window due to another
ConstantRateJump,MassActionJumpor boundedVariableRateJumpoccurring. However, they must remain valid ifuchanges for any other reason (for example, due to continuous dynamics like ODEs, SDEs, or generalVariableRateJumps).
Fields
rate: Functionrate(u,p,t)that returns the jump's current rate given stateu, parameterspand timet.affect!: Functionaffect!(integrator)that updates the state for one occurrence of the jump givenintegrator.lrate: Optional functionlrate(u, p, t)that computes a lower bound on the rate in the intervalttot + rateinterval(u, p, t)at timetgiven stateuand parametersp. This bound must rigorously hold during the time interval as long as anotherConstantRateJump,MassActionJump, or boundedVariableRateJumphas not been sampled. When using aggregators that support boundedVariableRateJumps, currently onlyCoevolve, providing a lower-bound can lead to improved performance.
urate: Optional functionurate(u, p, t)for generalVariableRateJumps, but is required to define a boundedVariableRateJump, which can be used with supporting aggregators, currently onlyCoevolve, and offers improved computational performance. Computes an upper bound for the rate in the intervalttot + rateinterval(u, p, t)at timetgiven stateuand parametersp. This bound must rigorously hold during the time interval as long as anotherConstantRateJump,MassActionJump, or boundedVariableRateJumphas not been sampled.rateinterval: Optional functionrateinterval(u, p, t)for generalVariableRateJumps, but is required to define a boundedVariableRateJump, which can be used with supporting aggregators, currently onlyCoevolve, and offers improved computational performance. Computes the time interval from timetover which theurateandlratebounds will hold,ttot + rateinterval(u, p, t), given stateuand parametersp. This bound must rigorously hold during the time interval as long as anotherConstantRateJump,MassActionJump, or boundedVariableRateJumphas not been sampled.idxsrootfindinterp_pointssave_positionsabstolreltol
Examples
Suppose u[1] gives the number of particles and t*p[1] the probability per time each particle can decay away. A corresponding VariableRateJump for this jump process is
rate(u,p,t) = t*p[1]*u[1]
affect!(integrator) = integrator.u[1] -= 1
vrj = VariableRateJump(rate, affect!)To define a bounded VariableRateJump that can be used with supporting aggregators such as Coevolve, we must define bounds and a rate interval:
rateinterval(u,p,t) = (1 / p[1]) * 2
rate(u,p,t) = t * p[1] * u[1]
lrate(u, p, t) = rate(u, p, t)
urate(u,p,t) = rate(u, p, t + rateinterval(u,p,t))
affect!(integrator) = integrator.u[1] -= 1
vrj = VariableRateJump(rate, affect!; lrate = lrate, urate = urate,
rateinterval = rateinterval)Notes
- When using an aggregator that supports bounded
VariableRateJumps,DiscreteProblemcan be used. Otherwise,ODEProblemorSDEProblemmust be used. - When not using aggregators that support bounded
VariableRateJumps, or when there are generalVariableRateJumps,integrators store an effective state type that wraps the main state vector. SeeExtendedJumpArrayfor details on using this object. In this case allConstantRateJump,VariableRateJumpand callbackaffect!functions receive an integrator withintegrator.uanExtendedJumpArray. - Salis H., Kaznessis Y., Accurate hybrid stochastic simulation of a system of coupled chemical or biochemical reactions, Journal of Chemical Physics, 122 (5), DOI:10.1063/1.1835951 is used for calculating jump times with
VariableRateJumps within ODE/SDE integrators.
JumpProcesses.RegularJump — Type
struct RegularJump{iip, R, C, MD}Representation for encoding rates and multiple simultaneous jumps for use in τ-leaping type methods.
Constructors
RegularJump(rate, c, numjumps; mark_dist = nothing)
Fields
rate: Functionrate!(rate_vals, u, p, t)that returns the current rates, i.e. intensities or propensities, for all possible jumps inrate_vals.
c: Functionc(du, u, p, t, counts, mark)that executes theith jumpcounts[i]times, saving the output indu[i].
numjumps: Number of jumps in the system.mark_dist: A distribution for marks. Not currently used or supported.
Examples
function rate!(out, u, p, t)
out[1] = (0.1 / 1000.0) * u[1] * u[2]
out[2] = 0.01u[2]
nothing
end
const dc = zeros(3,2)
function c(du, u, p, t, counts, mark)
mul!(du, dc, counts)
nothing
end
rj = RegularJump(rate!, c, 2)
## Notes
- `mark_dist` is not currently used or supported in τ-leaping methods.JumpProcesses.JumpSet — Type
struct JumpSet{T1, T2, T3, T4} <: JumpProcesses.AbstractJumpDefines a collection of jumps that should collectively be included in a simulation.
Fields
variable_jumps: Collection ofVariableRateJumpsconstant_jumps: Collection ofConstantRateJumpsregular_jump: Collection ofRegularJumpsmassaction_jump: Collection ofMassActionJumps
Examples
Here we construct two jumps, store them in a JumpSet, and then simulate the resulting process.
using JumpProcesses, OrdinaryDiffEq
rate1(u,p,t) = p[1]
affect1!(integrator) = (integrator.u[1] += 1)
crj = ConstantRateJump(rate1, affect1!)
rate2(u,p,t) = (t/(1+t))*p[2]*u[1]
affect2!(integrator) = (integrator.u[1] -= 1)
vrj = VariableRateJump(rate2, affect2!)
jset = JumpSet(crj, vrj)
f!(du,u,p,t) = (du .= 0)
u0 = [0.0]
p = (20.0, 2.0)
tspan = (0.0, 200.0)
oprob = ODEProblem(f!, u0, tspan, p)
jprob = JumpProblem(oprob, Direct(), jset)
sol = solve(jprob, Tsit5())JumpProcesses.RateBounds — Type
RateBounds(; lrate, urate, rateinterval = Inf)Computed bounds on a jump's rate for a fixed state bracket [ulow, uhigh] at time t.
Fields
lrate: Lower bound of the rate.urate: Upper bound of the rate.rateinterval: Time window over which the bounds hold.
Notes
- The rates must satisfy
lrate <= rate(v, p, s) <= uratefor everyvwithulow .<= v .<= uhighandsin[t, t + rateinterval]. - At least one of
lrateoruratemust be given. An omitted bound defaults to the trivially valid one:zerobelow andtypemaxabove. - For
ConstantRateJumps,rateintervalis alwaysInf, as rates do not explicitly depend ont.
Examples
Increasing rate in one species but decreasing in another:
rate(u, p, t) = p[1] * u[1] / (1 + u[2])
bounds(ulow, uhigh, u, p, t) = RateBounds(lrate = p[1] * ulow[1] / (1 + uhigh[2]),
urate = p[1] * uhigh[1] / (1 + ulow[2]))Extremas lying inside the bracket:
rate(u, p, t) = p[1] * u[1] * (p[2] - u[1])
function bounds(ulow, uhigh, u, p, t)
L = p[1] * max(abs(p[2] - 2*ulow[1]), abs(p[2] - 2*uhigh[1]))
δr = L * max(u[1] - ulow[1], uhigh[1] - u[1])
r = rate(u, p, t)
RateBounds(lrate = max(r - δr, zero(r)), urate = r + δr)
endRate that depends on time:
rate(u, p, t) = p[1] * u[1] * exp(-p[2] * t)
function bounds(ulow, uhigh, u, p, t)
Δ = p[3]
RateBounds(lrate = p[1] * ulow[1] * exp(-p[2] * (t + Δ)),
urate = p[1] * uhigh[1] * exp(-p[2] * t),
rateinterval = Δ)
endAggregator Types
Aggregators are the underlying algorithms used for sampling ConstantRateJumps, MassActionJumps, and VariableRateJumps.
JumpProcesses.BracketData — Type
BracketData(fluctrate, threshold, Δu)
BracketData{T1, T2}()Configure species-population brackets used by RSSA-based aggregators.
For species population u[i], the bracket is [(1 - fluctrate) * u[i], (1 + fluctrate) * u[i]] when u[i] >= threshold. For smaller populations, the bracket is [max(u[i] - Δu, 0), u[i] + Δu]. Each field may be either a scalar shared by all species or a vector indexed by species.
Fields
fluctrate: Relative fluctuation width used for populations at or abovethreshold.threshold: Population threshold below which the absoluteΔubracket is used.Δu: Absolute bracket half-width used for populations belowthreshold.
Notes
BracketData{T1, T2}()constructsBracketData(T1(0.1), T2(25), T2(4)).- The bracketing rules follow the RSSA construction in Thanh et al., J. Chem. Phys. 142, 244106 (2015).
Examples
using JumpProcesses
bd = BracketData(0.1, 25, 4)
bd.fluctrate == 0.1JumpProcesses.CCNRM — Type
A constant-complexity NRM method. Stores next reaction times in a table with a specified bin width.
Kevin R. Sanft and Hans G. Othmer, Constant-complexity stochastic simulation algorithm with optimal binning, Journal of Chemical Physics 143, 074108 (2015). doi: 10.1063/1.4928635.
JumpProcesses.Coevolve — Type
An improvement of the COEVOLVE algorithm for simulating any compound jump process that evolves through time. This method handles variable intensity rates with user-defined bounds and inter-dependent processes. It reduces to NRM when rates are constant. As opposed to COEVOLVE, this method syncs the thinning procedure with the stepper which allows it to handle dependencies on continuous dynamics.
G. A. Zagatti, S. A. Isaacson, C. Rackauckas, V. Ilin, S.-K. Ng and S. Bressan, Extending JumpProcess.jl for fast point process simulation with time-varying intensities, arXiv. doi:10.48550/arXiv.2306.06992.
M. Farajtabar, Y. Wang, M. Gomez-Rodriguez, S. Li, H. Zha, and L. Song, COEVOLVE: a joint point process model for information diffusion and network evolution, Journal of Machine Learning Research 18(1), 1305–1353 (2017). doi: 10.5555/3122009.3122050.
JumpProcesses.Direct — Type
Gillespie's Direct method. ConstantRateJump rates and affects are stored in tuples. Fastest for a small (total) number of ConstantRateJumps or MassActionJumps (~10). For larger numbers of possible jumps, use other methods.
Daniel T. Gillespie, A general method for numerically simulating the stochastic time evolution of coupled chemical reactions, Journal of Computational Physics, 22 (4), 403–434 (1976). doi:10.1016/0021-9991(76)90041-3.
JumpProcesses.DirectCR — Type
The Composition-Rejection Direct method. Performs best relative to other methods for systems with large numbers of jumps with special structure (for example a linear chain of reactions, or jumps corresponding to particles hopping on a grid or graph).
A. Slepoy, A.P. Thompson and S.J. Plimpton, A constant-time kinetic Monte Carlo algorithm for simulation of large biochemical reaction networks, Journal of Chemical Physics, 128 (20), 205101 (2008). doi:10.1063/1.2919546.
S. Mauch and M. Stalzer, Efficient formulations for exact stochastic simulation of chemical systems, ACM Transactions on Computational Biology and Bioinformatics, 8 (1), 27-35 (2010). doi:10.1109/TCBB.2009.47.
JumpProcesses.DirectCRDirect — Type
The Direct Composition-Rejection Direct method. Uses the DirectCR method to determine where on the grid/graph a jump occurs, and the Direct method to determine which jump occurs at the sampled location.
Kevin R. Sanft and Hans G. Othmer, Constant-complexity stochastic simulation algorithm with optimal binning, Journal of Chemical Physics 143, 074108 (2015). doi: 10.1063/1.4928635.
JumpProcesses.DirectFW — Type
Gillespie's Direct method. ConstantRateJump rates and affects are stored via FunctionWrappers, which is more performant than Direct for very large numbers of ConstantRateJumps. However, for such large numbers of jump different classes of aggregators are usually much more performant (i.e. SortingDirect, DirectCR, RSSA or RSSACR).
Daniel T. Gillespie, A general method for numerically simulating the stochastic time evolution of coupled chemical reactions, Journal of Computational Physics, 22 (4), 403–434 (1976). doi:10.1016/0021-9991(76)90041-3.
JumpProcesses.FRM — Type
Gillespie's First Reaction Method. Should not be used for practical applications due to slow performance relative to all other methods.
Daniel T. Gillespie, A general method for numerically simulating the stochastic time evolution of coupled chemical reactions, Journal of Computational Physics, 22 (4), 403–434 (1976). doi:10.1016/0021-9991(76)90041-3.
JumpProcesses.FRMFW — Type
Gillespie's First Reaction Method with FunctionWrappers for handling ConstantRateJumps. Should not be used for practical applications due to slow performance relative to all other methods.
Daniel T. Gillespie, A general method for numerically simulating the stochastic time evolution of coupled chemical reactions, Journal of Computational Physics, 22 (4), 403–434 (1976). doi:10.1016/0021-9991(76)90041-3.
JumpProcesses.NRM — Type
The Next Reaction Method. Can significantly outperform Direct for systems with large numbers of jumps and sparse dependency graphs, but is usually slower than one of DirectCR, RSSA, or RSSACR for such systems.
M. A. Gibson and J. Bruck, Efficient exact stochastic simulation of chemical systems with many species and many channels, Journal of Physical Chemistry A, 104 (9), 1876-1889 (2000). doi:10.1021/jp993732q.
JumpProcesses.NSM — Type
The Next Subvolume Method for spatial jump process simulations. Usually slower than DirectCRDirect. Uses an indexed priority queue tree structure to determine where on the grid/graph the next jump occurs, and then the Direct method to determine which jump at the given location occurs.
Elf, Johan and Ehrenberg, M, Spontaneous separation of bi-stable biochemical systems into spatial domains of opposite phases,Systems Biology, 1(2), 230-236 (2004). doi:10.1049/sb:20045021.
JumpProcesses.RDirect — Type
A rejection-based direct method.
JumpProcesses.RSSA — Type
The Rejection SSA method. One of the best methods for systems with hundreds to many thousands of jumps (along with RSSACR) and sparse dependency graphs.
V. H. Thanh, C. Priami and R. Zunino, Efficient rejection-based simulation of biochemical reactions with stochastic noise and delays, Journal of Chemical Physics, 141 (13), 134116 (2014). doi:10.1063/1.4896985
V. H. Thanh, R. Zunino and C. Priami, On the rejection-based algorithm for simulation and analysis of large-scale reaction networks, Journal of Chemical Physics, 142 (24), 244106 (2015). doi:10.1063/1.4922923.
JumpProcesses.RSSACR — Type
The Rejection SSA Composition-Rejection method. Often the best performer for systems with tens of thousands of jumps and sparse dependency graphs.
V. H. Thanh, R. Zunino, and C. Priami, Efficient constant-time complexity algorithm for stochastic simulation of large reaction networks, IEEE/ACM Transactions on Computational Biology and Bioinformatics, 14 (3), 657-667 (2017). doi:10.1109/TCBB.2016.2530066.
JumpProcesses.SortingDirect — Type
The Sorting Direct method. Often the fastest algorithm for smaller to moderate sized systems (tens of jumps), or systems where a few jumps occur much more frequently than others.
J. M. McCollum, G. D. Peterson, C. D. Cox, M. L. Simpson and N. F. Samatova, The sorting direct method for stochastic simulation of biochemical systems with varying reaction execution behavior, Computational Biology and Chemistry, 30 (1), 39049 (2006). doi:10.1016/j.compbiolchem.2005.10.007.
JumpProcesses.get_num_majumps — Function
get_num_majumps(jumps) -> IntReturn the number of mass-action jumps represented by a jump container.
Arguments
jumps: AMassActionJump,SpatialMassActionJump,JumpSet, ornothing.
Returns
- The number of mass-action reaction channels.
nothingreturns0.
Examples
using JumpProcesses
maj = MassActionJump([1.0], [[1 => 1]], [[1 => -1]])
get_num_majumps(maj) == 1
get_num_majumps(nothing) == 0JumpProcesses.needs_depgraph — Function
needs_depgraph(aggregator) -> BoolReturn whether an aggregator requires a reaction dependency graph when building a JumpProblem.
Arguments
aggregator: AnAbstractAggregatorAlgorithmvalue such asDirectCR,SortingDirect,NRM,CCNRM,RDirect, orCoevolve.
Returns
truewhen the aggregator needs a dependency graph from each reaction to the reactions whose propensities must be updated after it fires.falsefor aggregators that update all rates or otherwise do not use this graph.
Examples
using JumpProcesses
needs_depgraph(Direct()) == false
needs_depgraph(NRM()) == trueJumpProcesses.needs_vartojumps_map — Function
needs_vartojumps_map(aggregator) -> BoolReturn whether an aggregator requires the species-to-reaction dependency map used by RSSA-style bracketing.
Arguments
aggregator: AnAbstractAggregatorAlgorithmvalue.
Returns
Examples
using JumpProcesses
needs_vartojumps_map(RSSA()) == true
needs_vartojumps_map(Direct()) == falseVariable Rate Aggregators
JumpProcesses.VariableRateAggregator — Type
abstract type VariableRateAggregatorAn abstract type for aggregators that manage the simulation of VariableRateJumps in jump processes.
Notes
- In hybrid ODE/SDE systems with general
VariableRateJumps,integrator.umay be anExtendedJumpArrayfor some aggregators.
JumpProcesses.VR_Direct — Type
struct VR_Direct <: VariableRateAggregatorA concrete VariableRateAggregator implementing a direct method-based approach for simulating VariableRateJumps. VR_Direct (Variable Rate Direct Callback) efficiently samples jump times using one continuous callback to integrate the total intensity / propensity for all VariableRateJumps, sample when the next jump occurs, and then sample which jump occurs at this time. VR_DirectFW a separate FunctionWrapper mode, which wraps things in FunctionWrappers in cases with large numbers of jumps
Examples
Simulating a birth-death process with VR_Direct (default) and VR_DirectFW:
using JumpProcesses, OrdinaryDiffEq
u0 = [1.0] # Initial population
p = [10.0, 0.5] # [birth rate, death rate coefficient]
tspan = (0.0, 10.0)
# Birth jump: ∅ → X
birth_rate(u, p, t) = p[1]
birth_affect!(integrator) = (integrator.u[1] += 1; nothing)
birth_jump = VariableRateJump(birth_rate, birth_affect!)
# Death jump: X → ∅
death_rate(u, p, t) = p[2] * u[1]
death_affect!(integrator) = (integrator.u[1] -= 1; nothing)
death_jump = VariableRateJump(death_rate, death_affect!)
# Problem setup
oprob = ODEProblem((du, u, p, t) -> du .= 0, u0, tspan, p)
jprob = JumpProblem(oprob, birth_jump, death_jump; vr_aggregator = VR_Direct())
sol = solve(jprob, Tsit5())
jprob = JumpProblem(oprob, birth_jump, death_jump; vr_aggregator = VR_DirectFW())
sol = solve(jprob, Tsit5())Notes
VR_DirectandVR_DirectFWare expected to generally be more performant thanVR_FRM.
JumpProcesses.VR_DirectFW — Type
struct VR_DirectFW <: VariableRateAggregatorFunction-wrapper variant of VR_Direct for simulations with many VariableRateJumps.
VR_DirectFW uses the same direct-method callback strategy as VR_Direct, but stores the rate and affect functions in FunctionWrappers-based containers.
Returns
- A stateless
VariableRateAggregatorvalue for thevr_aggregatorkeyword ofJumpProblem.
Examples
using JumpProcesses, OrdinaryDiffEq
u0 = [1.0]
p = [10.0, 0.5]
tspan = (0.0, 10.0)
birth_rate(u, p, t) = p[1]
birth_affect!(integrator) = (integrator.u[1] += 1; nothing)
birth_jump = VariableRateJump(birth_rate, birth_affect!)
death_rate(u, p, t) = p[2] * u[1]
death_affect!(integrator) = (integrator.u[1] -= 1; nothing)
death_jump = VariableRateJump(death_rate, death_affect!)
oprob = ODEProblem((du, u, p, t) -> du .= 0, u0, tspan, p)
jprob = JumpProblem(oprob, birth_jump, death_jump; vr_aggregator = VR_DirectFW())
sol = solve(jprob, Tsit5())JumpProcesses.VR_FRM — Type
struct VR_FRM <: VariableRateAggregatorA concrete VariableRateAggregator implementing a first-reaction method variant for simulating VariableRateJumps. VR_FRM (Variable Rate First Reaction Method with Ordinary Differential Equation) uses a user-selected ODE solver to handle integrating each jump's intensity / propensity. A callback is also used for each jump to determine when its integrated intensity reaches a level corresponding to a firing time, and to then execute the affect associated with the jump at that time.
Examples
Simulating a birth-death process with VR_FRM:
using JumpProcesses, OrdinaryDiffEq
u0 = [1.0] # Initial population
p = [10.0, 0.5] # [birth rate, death rate]
tspan = (0.0, 10.0)
# Birth jump: ∅ → X
birth_rate(u, p, t) = p[1]
birth_affect!(integrator) = (integrator.u[1] += 1; nothing)
birth_jump = VariableRateJump(birth_rate, birth_affect!)
# Death jump: X → ∅
death_rate(u, p, t) = p[2] * u[1]
death_affect!(integrator) = (integrator.u[1] -= 1; nothing)
death_jump = VariableRateJump(death_rate, death_affect!)
# Problem setup
oprob = ODEProblem((du, u, p, t) -> du .= 0, u0, tspan, p)
jprob = JumpProblem(oprob, birth_jump, death_jump; vr_aggregator = VR_FRM())
sol = solve(jprob, Tsit5())Notes
- Specify
VR_FRMin aJumpProblemvia thevr_aggregatorkeyword argument to select its use for handlingVariableRateJumps. - While robust, it may be less performant than
VR_Directdue to its integration of each individual jump's intensity, and use of one continuous callback per jump to handle detection of jump times and implementation of state changes from that jump.
Tau-Leaping Algorithms
JumpProcesses.EnsembleGPUKernel — Type
EnsembleGPUKernel()
EnsembleGPUKernel(backend)Ensemble algorithm marker for GPU execution of tau-leaping ensemble simulations.
Arguments
backend: Optional KernelAbstractions-compatible backend.nothingrequests the default backend selected by the extension.
Fields
backend: Backend object used by the GPU extension.cpu_offload: Fraction of trajectories to offload to CPU execution.
Returns
- A
SciMLBase.EnsembleAlgorithmvalue for use as the ensemble algorithm argument tosolve.
Examples
using JumpProcesses
ensemble_alg = EnsembleGPUKernel()JumpProcesses.SimpleAdaptiveTauLeaping — Type
struct SimpleAdaptiveTauLeaping{T<:AbstractFloat, A<:SciMLBase.AbstractDEAlgorithm} <: SciMLBase.AbstractDEAlgorithmA tau-leaping method that switches between an explicit and an implicit step according to whether the system currently looks stiff.
Explicit tau-leaping is efficient on non-stiff systems but is limited by the fastest reaction, while an implicit step lifts that limit at the cost of a nonlinear solve per step. This solver measures stiffness at each step and pays for the implicit step only when it is needed, following Cao et al. (2007).
Stiffness is judged from the spread of the propensities, or, when eigenvalue_check is set, from the eigenvalue ratio of the Jacobian of the drift. When a step is taken implicitly the tau-selection tolerance is relaxed by implicit_epsilon_factor, since the implicit step is not restricted by the fast timescale it damps.
The implicit step itself is whichever algorithm is passed as implicit_alg, either SimpleImplicitTauLeaping or SimpleTrapezoidalLeaping.
Fields
epsilon: Error control parameter used when selectingtau.implicit_alg: The algorithm used for steps that are taken implicitly.eigenvalue_check: Whether to judge stiffness from the eigenvalues of the drift Jacobian.stiffness_ratio_threshold: Eigenvalue ratio above which the system counts as stiff.implicit_epsilon_factor: Factor relaxingepsilonwhen a step is taken implicitly.
Notes
- Only works with
JumpProblems defined fromDiscreteProblems that contain only aMassActionJump, built with thePureLeaping()aggregator. - Supports
saveat,save_startandsave_end.
Examples
using JumpProcesses
maj = MassActionJump([1.0, 1.0], [[1 => 1], [2 => 1]], [[1 => -1, 2 => 1], [1 => 1, 2 => -1]])
prob = DiscreteProblem([100, 100], (0.0, 10.0))
jprob = JumpProblem(prob, PureLeaping(), maj)
sol = solve(jprob, SimpleAdaptiveTauLeaping())
sol = solve(jprob, SimpleAdaptiveTauLeaping(implicit_alg = SimpleTrapezoidalLeaping()))JumpProcesses.SimpleExplicitTauLeaping — Type
SimpleExplicitTauLeaping(; epsilon = 0.05)
SimpleExplicitTauLeaping(epsilon)Adaptive explicit tau-leaping algorithm for pure MassActionJump problems.
Use SimpleExplicitTauLeaping with JumpProblem(prob, PureLeaping(), mass_action_jump). The algorithm computes step sizes from the mass-action propensities and the error-control parameter epsilon.
Arguments
epsilon: Positive floating-point error-control parameter. Smaller values generally produce smaller steps.
Fields
epsilon: Stored error-control parameter used by the adaptive leaping step selector.
Returns
- A
SciMLBase.AbstractDEAlgorithmvalue.
Examples
using JumpProcesses, DiffEqBase
maj = MassActionJump([0.1], [[1 => 1]], [[1 => -1]])
prob = DiscreteProblem([20], (0.0, 2.0))
jprob = JumpProblem(prob, PureLeaping(), maj)
sol = solve(jprob, SimpleExplicitTauLeaping())JumpProcesses.SimpleImplicitTauLeaping — Type
SimpleImplicitTauLeaping(; epsilon = 0.05)An implicit tau-leaping method for stiff pure-jump problems.
Explicit tau-leaping is limited by the fastest reaction in the system, so a stiff model forces a step size far smaller than the timescale of interest. Each step here instead solves a nonlinear equation for the new state, which lifts that restriction; see Rathinam et al. (2003) and Cao et al. (2004).
The deterministic part of the step is taken implicitly and the fluctuations are then sampled with Poisson random variables, after which the step is rejected and tau halved if it would drive a population negative.
\[X(t + \tau) = X(t) + \sum_j \nu_j a_j(X(t + \tau)) \tau\]
as in Rathinam et al. (2003) and Cao et al. (2004).
Fields
epsilon: Error control parameter used when selectingtau.
Notes
- Only works with
JumpProblems defined fromDiscreteProblems that contain only aMassActionJump, built with thePureLeaping()aggregator. - Supports
saveat,save_startandsave_end.
Examples
using JumpProcesses
maj = MassActionJump([1.0, 1.0], [[1 => 1], [2 => 1]], [[1 => -1, 2 => 1], [1 => 1, 2 => -1]])
prob = DiscreteProblem([100, 100], (0.0, 10.0))
jprob = JumpProblem(prob, PureLeaping(), maj)
sol = solve(jprob, SimpleImplicitTauLeaping())JumpProcesses.SimpleTauLeaping — Type
SimpleTauLeaping()Fixed-step tau-leaping algorithm for pure RegularJump problems.
Use SimpleTauLeaping with JumpProblem(prob, PureLeaping(), regular_jump) and pass the timestep through the dt keyword to solve.
Keyword Arguments
The algorithm constructor has no fields or keyword arguments. The solve method accepts:
dt: Required fixed timestep.seed: Optional random seed for the jump problem RNG.saveat: Optional scalar interval or collection of save times.save_start: Whether to save the initial time. Defaults follow SciML save conventions.save_end: Whether to save the final time. Defaults follow SciML save conventions.
Returns
- A stateless
SciMLBase.AbstractDEAlgorithmvalue.
Examples
using JumpProcesses, DiffEqBase
rate!(out, u, p, t) = (out[1] = 0.1 * u[1])
affect!(du, u, p, t, counts, mark) = (du[1] = -counts[1])
rj = RegularJump(rate!, affect!, 1)
prob = DiscreteProblem([20], (0.0, 2.0))
jprob = JumpProblem(prob, PureLeaping(), rj)
sol = solve(jprob, SimpleTauLeaping(); dt = 0.1)JumpProcesses.SimpleTrapezoidalLeaping — Type
SimpleTrapezoidalLeaping(; epsilon = 0.05)An implicit trapezoidal tau-leaping method for stiff pure-jump problems.
The method averages the propensities at the current and new states,
\[X(t + \tau) = X(t) + \sum_j \nu_j \frac{a_j(X(t)) + a_j(X(t + \tau))}{2} \tau.\]
This formulation damps the excessive stiffness of the fully implicit step and keeps the equilibrium distribution closer to the exact one.
Fields
epsilon: Error control parameter used when selectingtau.
Notes
- Only works with
JumpProblems defined fromDiscreteProblems that contain only aMassActionJump, built with thePureLeaping()aggregator. - Supports
saveat,save_startandsave_end.
Examples
using JumpProcesses
maj = MassActionJump([1.0, 1.0], [[1 => 1], [2 => 1]], [[1 => -1, 2 => 1], [1 => 1, 2 => -1]])
prob = DiscreteProblem([100, 100], (0.0, 10.0))
jprob = JumpProblem(prob, PureLeaping(), maj)
sol = solve(jprob, SimpleTrapezoidalLeaping())Spatial Jump APIs
JumpProcesses.CartesianGrid — Function
CartesianGrid(dims)Construct the default Cartesian grid topology for spatial jump simulations.
CartesianGrid currently returns a CartesianGridRej, which samples random neighbors by rejection from the potential coordinate offsets.
Arguments
dims: Tuple or vector of side lengths. One-, two-, and three-dimensional grids are supported by the built-in offset tables.
Returns
- A
CartesianGridRejwith sites indexed by Julia linear indices.
Examples
using JumpProcesses
grid = CartesianGrid((3, 4))
num_sites(grid) == 12
collect(neighbors(grid, 1)) == [2, 4]JumpProcesses.CartesianGridRej — Type
CartesianGridRej(dims)
CartesianGridRej(dimension, linear_size::Int)Cartesian grid topology with rejection-based random neighbor sampling.
Sites are represented by linear indices over dims. Neighbor relations use the nearest Cartesian offsets in one, two, or three dimensions and reject offsets that would leave the domain.
Arguments
dims: Tuple or vector of side lengths.dimension: Number of Cartesian dimensions for a hypercube grid.linear_size: Side length used in every dimension when constructing from(dimension, linear_size).
Fields
dims: Side lengths of the grid.nums_neighbors: Number of valid neighbors for each site.CI: Cartesian indices for the grid domain.LI: Linear indices for the grid domain.offsets: Candidate Cartesian offsets used to enumerate or sample neighbors.
Examples
using JumpProcesses
grid = CartesianGridRej((2, 2))
outdegree(grid, 1) == 2
collect(neighbors(grid, 1)) == [2, 3]JumpProcesses.SpatialMassActionJump — Type
SpatialMassActionJump(uniform_rates, spatial_rates, reactant_stoch, net_stoch,
param_mapper = nothing; scale_rates = true, useiszero = true, nocopy = false)
SpatialMassActionJump(spatial_rates, reactant_stoch, net_stoch, param_mapper = nothing;
kwargs...)
SpatialMassActionJump(uniform_rates, reactant_stoch, net_stoch, param_mapper = nothing;
kwargs...)
SpatialMassActionJump(ma_jumps::MassActionJump; scale_rates = false, kwargs...)Represent mass-action reactions whose rate constants may be uniform across sites, vary by site, or include both uniform and spatially varying reaction channels.
Uniform reactions are ordered before spatially varying reactions. For a spatial rate matrix, rows index reactions and columns index sites.
Arguments
uniform_rates: Vector of rate constants for reactions that use the same rate at every site, ornothing.spatial_rates: Matrix of rate constants for site-dependent reactions, ornothing.reactant_stoch: Reactant stoichiometry for each reaction, using the same pair-vector representation asMassActionJump.net_stoch: Net stoichiometry for each reaction.param_mapper: Optional function mapping problem parameters to rate constants.ma_jumps: ExistingMassActionJumpto reinterpret as spatial mass-action reactions.
Keyword Arguments
scale_rates: Whether to divide rates by factorial stoichiometry factors. Defaults totruefor raw rates andfalsewhen constructing from an existingMassActionJump.useiszero: Whether a single zero reactant entry is treated as an empty reactant list.nocopy: Whether to store input arrays directly instead of copying them.
Fields
uniform_rates: Uniform reaction rates, ornothing.spatial_rates: Site-dependent reaction-rate matrix, ornothing.reactant_stoch: Reactant stoichiometry by reaction.net_stoch: Net stoichiometry by reaction.param_mapper: Optional parameter-to-rate mapping.
Examples
using JumpProcesses
rates = [0.1 0.2 0.3]
reactant_stoch = [[1 => 1]]
net_stoch = [[1 => -1]]
smaj = SpatialMassActionJump(rates, reactant_stoch, net_stoch)
get_num_majumps(smaj) == 1Graphs.neighbors — Function
neighbors(grid, site)return an iterator over neighbors of site in ascending order. Do not use in hot loops
JumpProcesses.num_sites — Function
num_sites(spatial_system) -> IntReturn the number of sites in a spatial system.
Arguments
spatial_system: AGraphs.AbstractGraphorCartesianGridRej-compatible grid.
Returns
- The number of graph vertices or Cartesian grid cells.
Examples
using JumpProcesses
grid = CartesianGrid((2, 3))
num_sites(grid) == 6Graphs.outdegree — Function
outdegree(grid, site) -> IntReturn the number of valid nearest-neighbor sites adjacent to site.
Arguments
grid: ACartesianGridRej-compatible grid.site: Linear site index.
Returns
- The number of in-domain neighbors for
site.
Examples
using JumpProcesses
grid = CartesianGrid((2, 2))
outdegree(grid, 1) == 2Reexported SciML common interface
using JumpProcesses also brings in the parts of the SciML common interface needed to build the problem a JumpProblem wraps, solve it, drive the integrator from a jump's affect!, and inspect the result – so they do not have to be imported separately. These names are owned and documented by SciMLBase; JumpProcesses only re-exports them:
- Problems:
DiscreteProblem,ODEProblem,SDEProblem,EnsembleProblem,remake,NullParameters - Functions:
DiscreteFunction,ODEFunction,SDEFunction - Solutions:
ODESolution,EnsembleSolution,EnsembleSummary, and theEnsembleAnalysismodule - Ensemble algorithms:
EnsembleSerial,EnsembleThreads,EnsembleDistributed,EnsembleSplitThreads - Solving:
solve,solve!,init,step! - Integrator interface:
add_tstop!,add_saveat!,savevalues!,set_proposed_dt!,set_t!,set_u!,reinit!,terminate!,u_modified!,derivative_discontinuity! - Return status:
ReturnCode,successful_retcode - Callbacks:
DiscreteCallback,ContinuousCallback,VectorContinuousCallback,CallbackSet
DiscreteProblem and EnsembleProblem in particular are what most downstream code reaches for through JumpProcesses – see SciML/MomentClosure.jl#111 for what happens when they are not re-exported.
Note that SSAStepper only supports DiscreteCallbacks; ContinuousCallback and VectorContinuousCallback are re-exported for use with the ODE/SDE integrators a JumpProblem can be paired with.
Anything else from SciMLBase – the BVP, DAE, DDE, nonlinear and optimization problem classes, the SciML operators, and the internals – is not re-exported here; import it from SciMLBase directly.