# Find project root and include ensure_packages.jl
project_root = let
current = pwd()
while !isfile(joinpath(current, "Project.toml")) && !isfile(joinpath(current, "_quarto.yml"))
parent = dirname(current)
parent == current && break
current = parent
end
current
end
include(joinpath(project_root, "scripts", "ensure_packages.jl"))
@auto_using DifferentialEquations Random Statistics CairoMakie
Random.seed!(42)
# Stochastic compartment model parameters
Ξ² = 0.3 # Transmission rate
Ξ³ = 0.1 # Recovery rate
Ξ± = 0.05 # Treatment rate (when intervention is active)
Ο_S = 0.02 # Noise in S
Ο_I = 0.02 # Noise in I
Ο_R = 0.02 # Noise in R
# Original SDE (no intervention)
function f_original!(du, u, p, t)
"""SIR SDE drift: Susceptible β Infected β Recovered."""
S, I, R = u
du[1] = -Ξ² * S * I # dS/dt
du[2] = Ξ² * S * I - Ξ³ * I # dI/dt
du[3] = Ξ³ * I # dR/dt
end
function g_original!(du, u, p, t)
"""SIR SDE diffusion: additive noise in each compartment."""
du[1] = Ο_S # Noise in S
du[2] = Ο_I # Noise in I
du[3] = Ο_R # Noise in R
end
# SDE under intervention do(A = 1) (treatment active)
function f_intervened!(du, u, p, t)
"""SIR SDE drift with treatment intervention: do(A = 1)."""
S, I, R = u
# Intervention: do(A = 1) means treatment is active
du[1] = -Ξ² * S * I - Ξ± # dS/dt: treatment moves S β R
du[2] = Ξ² * S * I - Ξ³ * I # dI/dt: unchanged
du[3] = Ξ³ * I + Ξ± # dR/dt: treatment adds to recovered
end
function g_intervened!(du, u, p, t)
"""SIR SDE diffusion: noise structure unchanged under intervention."""
# Noise structure unchanged
du[1] = Ο_S
du[2] = Ο_I
du[3] = Ο_R
end
# Initial conditions
u0 = [0.99, 0.01, 0.0]
tspan = (0.0, 50.0)
# Solve original SDE (single trajectory)
prob_original = SDEProblem(f_original!, g_original!, u0, tspan)
sol_original = solve(prob_original, EM(), dt=0.1)
# Solve intervened SDE (single trajectory)
prob_intervened = SDEProblem(f_intervened!, g_intervened!, u0, tspan)
sol_intervened = solve(prob_intervened, EM(), dt=0.1)
# Monte Carlo simulation for uncertainty quantification
n_sims = 100
trajectories_original = []
trajectories_intervened = []
for i in 1:n_sims
sol_o = solve(prob_original, EM(), dt=0.1)
sol_i = solve(prob_intervened, EM(), dt=0.1)
push!(trajectories_original, sol_o)
push!(trajectories_intervened, sol_i)
end
# Visualise with uncertainty bands
let
fig = Figure(size = (1000, 600))
ax1 = Axis(fig[1, 1], title = "Infected (I) - Original", xlabel = "Time", ylabel = "Proportion")
ax2 = Axis(fig[1, 2], title = "Infected (I) - Intervened (do(A=1))", xlabel = "Time", ylabel = "Proportion")
# Plot trajectories and compute mean Β± std
function plot_with_uncertainty(ax, trajectories::Vector, color, label::String)
"""
Plot mean trajectory with uncertainty bands (mean Β± 1 std).
Args:
ax: Makie axis
trajectories: Vector of solution objects from SDE solves
color: Color for plotting
label: Label for legend
"""
# Trajectories may have slightly different lengths; use the minimum length
n_points = minimum(length(traj.t) for traj in trajectories)
t_points = trajectories[1].t[1:n_points]
# Pre-allocate for performance
means = Vector{Float64}(undef, n_points)
stds = Vector{Float64}(undef, n_points)
for i in 1:n_points
values = [traj.u[i][2] for traj in trajectories]
means[i] = mean(values)
stds[i] = std(values)
end
# Plot mean
lines!(ax, t_points, means, label = label, color = color, linewidth = 2)
# Plot uncertainty bands
band!(ax, t_points, means .- stds, means .+ stds, color = (color, 0.3))
end
plot_with_uncertainty(ax1, trajectories_original, :blue, "Original (mean Β± 1 std)")
plot_with_uncertainty(ax2, trajectories_intervened, :red, "Intervened (mean Β± 1 std)")
axislegend(ax1)
axislegend(ax2)
fig # Only this gets displayed
end
# Compare expected outcomes
final_I_original = mean([traj.u[end][2] for traj in trajectories_original])
final_I_intervened = mean([traj.u[end][2] for traj in trajectories_intervened])
std_I_original = std([traj.u[end][2] for traj in trajectories_original])
std_I_intervened = std([traj.u[end][2] for traj in trajectories_intervened])
println("Expected final infection rate (mean Β± std):")
println(" Original: ", round(final_I_original, digits=3), " Β± ", round(std_I_original, digits=3))
println(" Intervened (do(A=1)): ", round(final_I_intervened, digits=3), " Β± ", round(std_I_intervened, digits=3))
println(" Reduction: ", round((1 - final_I_intervened/final_I_original) * 100, digits=1), "%")β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 β Warning: Instability detected. Aborting β @ SciMLBase ~/.julia/packages/SciMLBase/J3OUh/src/integrator_interface.jl:743 Expected final infection rate (mean Β± std): Original: -Inf Β± NaN Intervened (do(A=1)): -Inf Β± NaN Reduction: NaN%