Dear all above,
I have taken the above code for the age structured SIR system (thanks for publishing it!) and tried to extend it. I added waning immunity and an age-dependent death rate, which worked well (is set to a constant at the moment). I also added inflow into the system at the a=0 boundary and got some results that I did not understand. I am just starting with Julia, so not sure whether I coded the boundary conditions correctly, but I could not really find any documentation on it. So I thought I could ask here.
I thought I provided a constant inflow at the a=0 boundary and an initial age distribution that is concentrated in the interval [20,30]. The latter seems to work, but then in the heatmap for the total population I get the following:
I don’t understand why there is only inflow during a limited time interval, even though my boundary condition is simply a constant.
Here is the code:
using OrdinaryDiffEq
using ModelingToolkit
using MethodOfLines
using DomainSets
using Plots
using Distributions
tmin = 0.0
tmax = 100.0
amin = 0.0
amax = 100.0
#Model parameters
β = 3.0 #transmission rate
γ = 1.0 # recovery rate
alpha = 0.05 #waning rate
N = 100.0 #population size
k = 10.0
lambda = 90.0
function mu(age) #mortality function
0.01
# pdf(Weibull(k,lambda),age)/(1-cdf(Weibull(k, lambda),age))
end
@register_symbolic mu(age)
# Parameters, variables, and derivatives
@parameters t a
@variables S(..) I(..) R(..)
Dt = Differential(t)
Da = Differential(a)
Ia = Integral(a in DomainSets.ClosedInterval(amin,amax))
#Heaviside function
theta(a) = (a > 0) ? 1 : 0
@register_symbolic theta(a)
# PDE and boundary conditions
eqs = [
Dt(S(t,a)) + Da(S(t,a)) ~ - β * S(t,a) * Ia(I(t,a))/N + alpha * R(t,a) - mu(a)*S(t,a),
Dt(I(t,a)) + Da(I(t,a)) ~ β * S(t,a) * Ia(I(t,a))/N - γ*I(t,a) - mu(a)*I(t,a),
Dt(R(t,a)) + Da(R(t,a)) ~ γ * I(t,a) - alpha * R(t,a) - mu(a)*R(t,a)]
S₀ = N * 0.99 #initial number susceptible
I₀ = N * 0.01 #initial number infected
R₀ = 0.0 #initial number recovered
min_age = 20.0 #minimum age
max_age = 30.0 #maximum age
bcs = [
S(0.0,a) ~ S₀/(max_age - min_age) * theta(max_age - a) * theta(a - min_age),
I(0.0,a) ~ I₀/(max_age - min_age) * theta(max_age - a) * theta(a - min_age),
R(0.0,a) ~ 0.0,
S(t,0.0) ~ N/(max_age - min_age),
I(t,0.0) ~ 0.0,
R(t,0.0) ~ 0.0
]
# Space and age domains
domains = [t ∈ Interval(tmin,tmax), a ∈ Interval(amin,amax)]
# PDE system
@named SIRmodel = PDESystem(eqs, bcs, domains, [t, a], [S(t, a), I(t,a), R(t,a)])
# Method of lines discretization
da = 1.0
discretization = MOLFiniteDifference([a=>da],t)
# Convert the PDE problem into an ODE problem
prob = discretize(SIRmodel, discretization)
# Solve ODE problem
dt = tmax/100.0
sol_pde = solve(prob, Tsit5(), saveat = dt)
discrete_a = sol_pde[a]
discrete_t = sol_pde[t]
sols = sol_pde[S(t, a)]
soli = sol_pde[I(t, a)]
solr = sol_pde[R(t, a)]
soln = sol_pde[S(t, a)]+sol_pde[I(t,a)]+sol_pde[R(t,a)]
#Plotting results
x = range(0, 100, length=100)
y = mu.(x)
pltmort=plot(x,y, xaxis = "Age (a)", yaxis = "Mortality rate")
display(pltmort)
n=10
plt4 = plot()
for i in 1:11
plot!(discrete_a, soln[1+n*(i-1), :],label="t=$(discrete_t[1+n*(i-1)])", title = "Population age distribution",
xaxis = "Age (a)", yaxis = "Number")
end
display(plt4)
savefig(plt4, "AgeDistribution.pdf")
integrate(component) = da .* sum(sol_pde[component], dims=1) |> transpose
cumulativeplot=plot(sol_pde[t], integrate(S(t,a)), label="S", xlabel="Time", ylabel="Number")
plot!(sol_pde[t], integrate(I(t,a)), label="I")
plot!(sol_pde[t], integrate(R(t,a)), label="R")
plot!(sol_pde[t], integrate(S(t,a)) .+ integrate(I(t,a)) .+ integrate(R(t,a)), label="S + I + R",legend=:outerbottom,legendcolumns=4)
display(cumulativeplot)
savefig(cumulativeplot, "cumulativeplot.pdf")
plotall=plot(
heatmap(sol_pde[t], sol_pde[a], sol_pde[S(t,a)], title="S(t,a)"),
heatmap(sol_pde[t], sol_pde[a], sol_pde[I(t,a)], title="I(t,a)"),
heatmap(sol_pde[t], sol_pde[a], sol_pde[R(t,a)], title="R(t,a)"),
xlabel="Time",
ylabel="Age",
layout=(3, 1),
size=(900,1000),
tspan=(0.0,50.0)
)
display(plotall)
savefig(plotall, "heatmaps.pdf")
plotpopdist=plot(
heatmap(sol_pde[t], sol_pde[a], sol_pde[S(t,a)]+sol_pde[I(t,a)]+sol_pde[R(t,a)], title="N(t,a)"),
xlabel="Time",
ylabel="Age",
size=(900,300)
)
display(plotpopdist)
savefig(plotpopdist, "heatmapN.png")