Skip to content

Commit

Permalink
Merge pull request #104 from AlgebraicJulia/docs-on-readme
Browse files Browse the repository at this point in the history
Update examples to use Literate
  • Loading branch information
jpfairbanks authored Oct 26, 2023
2 parents c0e3129 + 95453ac commit b76ea7d
Show file tree
Hide file tree
Showing 48 changed files with 52,036 additions and 3,647 deletions.
50 changes: 0 additions & 50 deletions .github/workflows/validate-notebooks.yml

This file was deleted.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# AlgebraicStockFlow

[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://algebraicjulia.github.io/StockFlow.jl/dev/)
[![Tests](https://github.com/AlgebraicJulia/StockFlow.jl/actions/workflows/tests.yml/badge.svg)](https://github.com/AlgebraicJulia/StockFlow.jl/actions/workflows/tests.yml)
<!-- TODO: Set up on codecov.io for repo [![codecov](https://codecov.io/github/AlgebraicJulia/StockFlow.jl/branch/maaster/graph/badge.svg)](https://app.codecov.io/github/AlgebraicJulia/StockFlow.jl) -->


StockFlow.jl is a Julia library for the creation and execution of [stock and flow modeling diagrams](https://en.wikipedia.org/wiki/System_dynamics#Stock_and_flow_diagrams), designed with model composition and stratification in mind through a [categorical approach](https://arxiv.org/abs/2211.01290).

Stock-flow diagrams are used to represent systems where its population can move between different states, such as tracking how many people have been infected or recovered from a disease. By providing initial values, and values for the parameters, we can solve the differential equation which the stock-flow diagram represents, which gives us a graph for how the population varies over time.
Expand Down
5 changes: 5 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
[deps]
AlgebraicRewriting = "725a01d3-f174-5bbd-84e1-b9417bad95d9"
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
GraphViz = "f526b714-d49f-11e8-06ff-31ed36ee7ee0"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
StockFlow = "58c4a0e8-2944-4d18-9fa2-e17726aee9e5"
TikzPictures = "37f6aa50-8035-52d0-81c2-5a1d08754b2d"
111 changes: 111 additions & 0 deletions docs/literate/Covid19_composition_model_in_paper.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# # COVID-19 Composition Model

using StockFlow

using Catlab
using Catlab.CategoricalAlgebra
using LabelledArrays
using OrdinaryDiffEq
using Plots

using Catlab.Graphics
using Catlab.Programs
using Catlab.WiringDiagrams

display_uwd(ex) = to_graphviz(ex, box_labels=:name, junction_labels=:variable, edge_attrs=Dict(:len=>"1"));

# Define functions ϕ of flows in the SEIRH model
fNewIncidence(u,p,t)=p.β*u.S*u.I/p.N
fNewInfectious(u,p,t)=u.E*p.ri
fNewRecovery(u,p,t)=u.I/p.tr * (1.0-p.fH )
fWaningImmunityR(u,p,t)=u.R/p.tw
fHICUAdmission(u,p,t) = u.I/p.tr * p.fH * p.fICU
fHNICUAdmission(u,p,t) = u.I/p.tr * p.fH * (1.0-p.fICU)
fOutICU(u,p,t) = u.HICU/p.tICU
fRecoveryH(u,p,t)= u.HNICU/p.tH

# StockAndFlowp(stocks,
# (flow=>function, upstream=>downstream) => stocks linked)
seirh = StockAndFlowp((:S, :E, :I, :R, :HICU, :HNICU),
((:NewIncidence=>fNewIncidence, :S=>:E) => (:S, :I),
(:NewInfectious=>fNewInfectious, :E=>:I) => :E,
(:NewRecovery=>fNewRecovery, :I=>:R) => :I,
(:WaningImmunityR=>fWaningImmunityR, :R=>:S) => :R,
(:HICUAdmission=>fHICUAdmission, :I=>:HICU) => :I,
(:HNICUAdmission=>fHNICUAdmission, :I=>:HNICU) => :I,
(:OutICU=>fOutICU, :HICU=>:HNICU) => :HICU,
(:RecoveryH=>fRecoveryH, :HNICU=>:R) => :HNICU))

# Graph(primitive stock-flow model, direction of the diagram - the default value is "LR" from left to right;
# users could also use "TB" from top to bottom)
# Graph(seirh)

# Define functions ϕ of flows in the Vaccine model
fFirstdoseVaccine(u,p,t) = u.S * p.rv
fSeconddoseVaccine(u,p,t) = u.VP * p.rv
fWaningImmunityVP(u,p,t) = u.VP / p.tw
fWaningImmunityVF(u,p,t) = u.VF / p.tw
fNewIncidenceVP(u,p,t) = p.β*u.VP*u.I*(1.0-p.eP)/p.N
fNewIncidenceVF(u,p,t) = p.β*u.VF*u.I*(1.0-p.eF)/p.N

# Stock and flow diagram of Vaccine model
v = StockAndFlowp((:S, :E, :I, :VP, :VF),
((:FirstdoseVaccine=>fFirstdoseVaccine, :S=>:VP) => :S,
(:SeconddoseVaccine=>fSeconddoseVaccine, :VP=>:VF) => :VP,
(:WaningImmunityVP=>fWaningImmunityVP, :VP=>:S) => :VP,
(:WaningImmunityVF=>fWaningImmunityVF, :VF=>:VP) => :VF,
(:NewIncidenceVP=>fNewIncidenceVP, :VP=>:E) => (:VP, :I),
(:NewIncidenceVF=>fNewIncidenceVF, :VF=>:E) => (:VF, :I)))

# Graph(v,"TB")

# Define functions ϕ of flows in the Persist Asymptomaticity model
fNewPersistentAsymptomaticity(u,p,t) = u.E * p.ria
fNewRecoveryIA(u,p,t) = u.IA / p.tr

# Stock and flow diagram of Persistent Asymptomaticity Model
ia = StockAndFlowp((:E, :IA, :R),
((:NewPersistentAsymptomaticity=>fNewPersistentAsymptomaticity, :E=>:IA) => :E,
(:NewRecoveryIA=>fNewRecoveryIA, :IA=>:R) => :IA))

# Graph(ia)

covid = @relation (S, E, I, R) begin
modelA(S,E,I,R)
modelB(S,E,I)
modelC(E,R)
end;
display_uwd(covid)

# Open three Stock and Flow Diagrams
openseirh = Open(seirh, [:S], [:E], [:I], [:R])
openv = Open(v, [:S], [:E], [:I])
openia = Open(ia, [:E], [:R])
# Compose those three models according the UWD-algebra
openCOVID19 = oapply(covid, [openseirh, openv, openia])
# Generate the composed model (Stock and Flow Diagram)
COVID19 = apex(openCOVID19)

# Graph(COVID19)

# Define constant parameters
p_COVID19 = LVector(
β=0.8, N=38010001.0, tr=12.22, tw=2*365.0,
fH=0.002, fICU=0.23, tICU=6.0, tH = 12.0,
rv=0.01, eP=0.6, eF=0.85, ri=0.207, ria=0.138
)
# Define initial values for stocks
u0_COVID19 = LVector(
S=38010000.0, E=0.0, I=1.0, IA=0.0, R=0.0, HICU=0.0, HNICU=0.0, VP=0.0, VF=0.0
)

# Check the dependencies of links of all flows' functions
# checkfls(COVID19, u0_COVID19, p_COVID19)

# Solve the ODEs
prob_COVID19 = ODEProblem(vectorfield(COVID19),u0_COVID19,(0.0,300.0),p_COVID19);
sol_COVID19 = solve(prob_COVID19,Tsit5(),abstol=1e-8);
plot(sol_COVID19)

# Flow of ```FirstdoseVaccine```
ϕFirstdoseVaccine = map(x->fFirstdoseVaccine(sol_COVID19.u[x],p_COVID19,sol_COVID19.t[x]),collect(1:length(sol_COVID19.t)))
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# # Convert from SEIR Stock Flow Diagram

using GraphViz

using StockFlow
using StockFlow.Syntax

seir = @stock_and_flow begin
:stocks
S
E
I
R

:parameters
μ
β
tlatent
trecovery
δ

:dynamic_variables
v_birth = μ * N
v_incid₁ = I / N
v_incid₂ = S * v_incid₁
v_incid₃ = β * v_incid₂
v_inf = E / tlatent
v_rec = I / trecovery
v_deathS = S * δ
v_deathE = E * δ
v_deathI = I * δ
v_deathR = R * δ

:flows
CLOUD => f_birth(v_birth) => S
S => f_incid(v_incid₃) => E
S => v_deathS(v_deathS) => CLOUD
E => f_inf(v_inf) => I
E => f_deathE(v_deathE) => CLOUD
I => f_rec(v_rec) => R
I => f_deathI(v_deathI) => CLOUD
R => f_deathR(v_deathR) => CLOUD

:sums
N = [S,E,I,R]

end

GraphF(seir)

seir_causalLoop = convertToCausalLoop(seir)

Graph(seir_causalLoop)


Loading

0 comments on commit b76ea7d

Please sign in to comment.