Skip to content

Commit dc5e49e

Browse files
Merge pull request #4262 from isaacsas/add_poissonians
Add `@poissonians` macro
2 parents 3164828 + afbe21d commit dc5e49e

File tree

10 files changed

+1312
-7
lines changed

10 files changed

+1312
-7
lines changed

lib/ModelingToolkitBase/src/ModelingToolkitBase.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ export alg_equations, diff_equations, has_alg_equations, has_diff_equations
300300
export get_alg_eqs, get_diff_eqs, has_alg_eqs, has_diff_eqs
301301

302302
export @variables, @parameters, @independent_variables, @constants, @brownians, @brownian,
303-
@discretes
303+
@poissonians, @discretes
304304
export @named, @nonamespace, @namespace, extend, compose, complete, toggle_namespacing
305305
export debug_system
306306

lib/ModelingToolkitBase/src/parameters.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import SymbolicUtils: symtype, term, hasmetadata, issym
66
The type of the declared variable, used for automatic identification of
77
variables/parameters/brownians/etc. by the `System` constructor.
88
"""
9-
@enum VariableType VARIABLE PARAMETER BROWNIAN
9+
@enum VariableType VARIABLE PARAMETER BROWNIAN POISSONIAN
1010

1111
"""
1212
$TYPEDEF
@@ -17,6 +17,24 @@ struct MTKVariableTypeCtx end
1717

1818
getvariabletype(x, def = VARIABLE) = safe_getmetadata(MTKVariableTypeCtx, unwrap(x), def)::Union{typeof(def), VariableType}
1919

20+
"""
21+
$TYPEDEF
22+
23+
The symbolic metadata key for storing the rate expression of a poissonian variable.
24+
"""
25+
struct PoissonianRateCtx end
26+
27+
"""
28+
getpoissonianrate(x)
29+
30+
Get the rate expression associated with poissonian variable `x`. Returns `nothing`
31+
if `x` is not a poissonian or has no rate.
32+
"""
33+
getpoissonianrate(x::Union{Num, Symbolics.Arr}) = getpoissonianrate(Symbolics.unwrap(x))
34+
function getpoissonianrate(x)
35+
return Symbolics.getmetadata(unwrap(x), PoissonianRateCtx, nothing)
36+
end
37+
2038
"""
2139
$TYPEDEF
2240

lib/ModelingToolkitBase/src/problems/compatibility.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,19 @@ function check_has_noise(sys::System, T)
167167
end
168168
end
169169

170+
function check_no_poissonians(sys::System, T)
171+
return if !isempty(poissonians(sys))
172+
throw(
173+
SystemCompatibilityError(
174+
"""
175+
Systems with unprocessed poissonians cannot be used to construct a `$T`. \
176+
Call `mtkcompile` on the system first to convert poissonians to jumps.
177+
"""
178+
)
179+
)
180+
end
181+
end
182+
170183
function check_is_discrete(sys::System, T)
171184
return if !is_discrete_system(sys)
172185
throw(

lib/ModelingToolkitBase/src/problems/jumpproblem.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ function check_compatible_system(T::Union{Type{JumpProblem}}, sys::System)
120120
check_not_dde(sys)
121121
check_no_cost(sys, T)
122122
check_no_constraints(sys, T)
123+
check_no_poissonians(sys, T)
123124
check_has_jumps(sys, T)
124125
return check_is_continuous(sys, T)
125126
end

lib/ModelingToolkitBase/src/systems/abstractsystem.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,7 @@ const SYS_PROPS = [
901901
:ps
902902
:tspan
903903
:brownians
904+
:poissonians
904905
:jumps
905906
:name
906907
:description
@@ -1417,6 +1418,17 @@ function namespace_brownians(sys::AbstractSystem)
14171418
return bs
14181419
end
14191420

1421+
function namespace_poissonians(sys::AbstractSystem)
1422+
ps = poissonians(sys)
1423+
if ps === get_poissonians(sys)
1424+
ps = copy(ps)
1425+
end
1426+
for i in eachindex(ps)
1427+
ps[i] = renamespace(sys, ps[i])
1428+
end
1429+
return ps
1430+
end
1431+
14201432
function namespace_assignment(eq::Assignment, sys)
14211433
_lhs = namespace_expr(eq.lhs, sys)
14221434
_rhs = namespace_expr(eq.rhs, sys)
@@ -1999,6 +2011,25 @@ function brownians(sys::AbstractSystem)
19992011
return bs
20002012
end
20012013

2014+
"""
2015+
$(TYPEDSIGNATURES)
2016+
2017+
Get all of the poissonian variables involved in the system `sys` and all subsystems,
2018+
appropriately namespaced.
2019+
"""
2020+
function poissonians(sys::AbstractSystem)
2021+
ps = get_poissonians(sys)
2022+
systems = get_systems(sys)
2023+
if isempty(systems)
2024+
return ps
2025+
end
2026+
ps = copy(ps)
2027+
for subsys in systems
2028+
append!(ps, namespace_poissonians(subsys))
2029+
end
2030+
return ps
2031+
end
2032+
20022033
"""
20032034
$(TYPEDSIGNATURES)
20042035

lib/ModelingToolkitBase/src/systems/system.jl

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ struct System <: IntermediateDeprecationSystem
102102
"""
103103
brownians::Vector{SymbolicT}
104104
"""
105+
The poissonian variables of the system, created via `@poissonians`. Each poissonian
106+
variable represents an independent Poisson counting process with an associated rate.
107+
A system with poissonians cannot be simulated directly. It needs to be compiled using
108+
`mtkcompile` which converts poissonians into jump equations.
109+
"""
110+
poissonians::Vector{SymbolicT}
111+
"""
105112
The independent variable for a time-dependent system, or `nothing` for a time-independent
106113
system.
107114
"""
@@ -286,7 +293,7 @@ struct System <: IntermediateDeprecationSystem
286293

287294
function System(
288295
tag, eqs, noise_eqs, jumps, constraints, costs, consolidate, unknowns, ps,
289-
brownians, iv, observed, var_to_name, name, description, bindings,
296+
brownians, poissonians, iv, observed, var_to_name, name, description, bindings,
290297
initial_conditions, guesses, systems, initialization_eqs, continuous_events,
291298
discrete_events, connector_type, assertions = Dict{SymbolicT, String}(),
292299
metadata = MetadataT(), gui_metadata = nothing, is_dde = false, tstops = [],
@@ -350,7 +357,7 @@ struct System <: IntermediateDeprecationSystem
350357
end
351358
return new(
352359
tag, eqs, noise_eqs, jumps, constraints, costs,
353-
consolidate, unknowns, ps, brownians, iv,
360+
consolidate, unknowns, ps, brownians, poissonians, iv,
354361
observed, var_to_name, name, description, bindings, initial_conditions,
355362
guesses, systems, initialization_eqs, continuous_events, discrete_events,
356363
connector_type, assertions, metadata, gui_metadata, is_dde,
@@ -433,6 +440,7 @@ All other keyword arguments are named identically to the corresponding fields in
433440
"""
434441
function System(
435442
eqs::Vector{Equation}, iv, dvs, ps, brownians = SymbolicT[];
443+
poissonians = SymbolicT[],
436444
constraints = Union{Equation, Inequality}[], noise_eqs = nothing, jumps = JumpType[],
437445
costs = SymbolicT[], consolidate = default_consolidate,
438446
# `@nospecialize` is only supported on the first 32 arguments. Keep this early.
@@ -477,6 +485,7 @@ function System(
477485
filter!(!Base.Fix2(_is_unknown_delay_or_evalat, iv), dvs)
478486
end
479487
brownians = unwrap_vars(brownians)
488+
poissonians = unwrap_vars(poissonians)
480489

481490
if noise_eqs !== nothing
482491
noise_eqs = unwrap_vars(noise_eqs)
@@ -613,7 +622,7 @@ function System(
613622
jumps = Vector{JumpType}(jumps)
614623
return System(
615624
__get_new_tag(), eqs, noise_eqs, jumps, constraints,
616-
costs, consolidate, dvs, ps, brownians, iv, observed,
625+
costs, consolidate, dvs, ps, brownians, poissonians, iv, observed,
617626
var_to_name, name, description, bindings, initial_conditions, guesses, systems, initialization_eqs,
618627
continuous_events, discrete_events, connector_type, assertions, metadata, gui_metadata, is_dde,
619628
tstops, inputs, outputs, tearing_state, true, false,
@@ -704,13 +713,25 @@ function System(eqs::Vector{Equation}, iv; kwargs...)
704713
eqs = [diffeqs; othereqs]
705714

706715
brownians = Set{SymbolicT}()
716+
poissonians = Set{SymbolicT}()
707717
for x in allunknowns
708718
x = unwrap(x)
709719
if getvariabletype(x) == BROWNIAN
710720
push!(brownians, x)
721+
elseif getvariabletype(x) == POISSONIAN
722+
push!(poissonians, x)
711723
end
712724
end
713725
setdiff!(allunknowns, brownians)
726+
setdiff!(allunknowns, poissonians)
727+
728+
# Extract variables and parameters from poissonian rate expressions
729+
for p in poissonians
730+
rate = getpoissonianrate(p)
731+
if rate !== nothing
732+
collect_vars!(allunknowns, ps, rate, iv)
733+
end
734+
end
714735

715736
cstrs = Vector{Union{Equation, Inequality}}(get(kwargs, :constraints, []))
716737
_cstrunknowns, cstrps = process_constraint_system(cstrs, allunknowns, ps, iv)
@@ -764,7 +785,8 @@ function System(eqs::Vector{Equation}, iv; kwargs...)
764785
end
765786

766787
return System(
767-
eqs, iv, collect(allunknowns), collect(new_ps), collect(brownians); kwargs...
788+
eqs, iv, collect(allunknowns), collect(new_ps), collect(brownians);
789+
poissonians = collect(poissonians), kwargs...
768790
)
769791
end
770792

@@ -995,6 +1017,7 @@ function flatten(sys::System, noeqs = false)
9951017
return System(
9961018
noeqs ? Equation[] : equations(sys), get_iv(sys), unknowns(sys),
9971019
parameters(sys; initial_parameters = true), brownians(sys);
1020+
poissonians = poissonians(sys),
9981021
jumps = jumps(sys), constraints = constraints(sys), costs = costs,
9991022
consolidate = default_consolidate, observed = observed(sys),
10001023
bindings = bindings(sys), initial_conditions = initial_conditions(sys),
@@ -1424,6 +1447,7 @@ function Base.isapprox(sysa::System, sysb::System)
14241447
issetequal(get_unknowns(sysa), get_unknowns(sysb)) &&
14251448
issetequal(get_ps(sysa), get_ps(sysb)) &&
14261449
issetequal(get_brownians(sysa), get_brownians(sysb)) &&
1450+
issetequal(get_poissonians(sysa), get_poissonians(sysb)) &&
14271451
issetequal(get_observed(sysa), get_observed(sysb)) &&
14281452
isequal(get_description(sysa), get_description(sysb)) &&
14291453
isequal(get_bindings(sysa), get_bindings(sysb)) &&
@@ -1452,7 +1476,8 @@ function Base.copy(sys::System)
14521476
return System(
14531477
__get_new_tag(), copy(get_eqs(sys)), _maybe_copy(get_noise_eqs(sys)), copy(get_jumps(sys)),
14541478
copy(get_constraints(sys)), copy(get_costs(sys)), get_consolidate(sys),
1455-
copy(get_unknowns(sys)), copy(get_ps(sys)), copy(get_brownians(sys)), get_iv(sys),
1479+
copy(get_unknowns(sys)), copy(get_ps(sys)), copy(get_brownians(sys)),
1480+
copy(get_poissonians(sys)), get_iv(sys),
14561481
copy(get_observed(sys)), copy(get_var_to_name(sys)), nameof(sys), get_description(sys),
14571482
copy(get_bindings(sys)), copy(get_initial_conditions(sys)), copy(get_guesses(sys)),
14581483
map(copy, get_systems(sys)), copy(get_initialization_eqs(sys)),

0 commit comments

Comments
 (0)