Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Julia tests

on:
pull_request:
push:
branches: [main]

permissions:
actions: write
contents: read

jobs:
test:
name: Julia ${{ matrix.julia-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
julia-version: ['1.11', '1.12', '1.13']

steps:
- uses: actions/checkout@v7
- uses: julia-actions/setup-julia@v3
with:
version: ${{ matrix.julia-version }}
project: AlgebraicEpiMech
- uses: julia-actions/cache@v3
- uses: julia-actions/julia-buildpkg@v1
with:
project: AlgebraicEpiMech
- uses: julia-actions/julia-runtest@v1
with:
project: AlgebraicEpiMech
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DS_Store

Manifest*
18 changes: 18 additions & 0 deletions AlgebraicEpiMech/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "AlgebraicEpiMech"
uuid = "a6e39d6b-8b2d-49f3-aca0-f4154643f040"
version = "0.1.0"
authors = ["Samuel Brand <usi1@cdc.gov>"]

[workspace]
projects = ["test"]

[deps]
AlgebraicPetri = "4f99eebe-17bf-4e98-b6a1-2c4f205a959b"
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"

[compat]
AlgebraicPetri = "0.10.0"
Catlab = "0.17.2"
DocStringExtensions = "0.9.3"
julia = "1.11, 1.12, 1.13"
60 changes: 60 additions & 0 deletions AlgebraicEpiMech/src/AlgebraicEpiMech.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module AlgebraicEpiMech

using AlgebraicPetri, AlgebraicPetri.TypedPetri
using Catlab
using DocStringExtensions
import Base: *

# Epidemiological typing strategies and their Petri-net type systems
export EpidemiologicalTyping, OnePopulationTyping, UninfectedInfectedTyping, type_system

# Epi mechanism functions
export add_infection!, add_disease_progression!,
add_uninfected_density_progression!, add_reversion_progression!

# Observation chain
# Observation by pushout (attached after composition)
export ObservationTarget, AtEvent, AtCompartment, attach_observation

export ObservationChainLayout, ObservationLayout, observation_layout

# Compartmental models types
export CompartmentalModel, SI, SEI, SIS, SIR, SEIR, SEIRS, SEIS

# Multistrain model types
export MultiStrainModel, NoCrossImmunity, CompleteCrossImmunity

# Immune-history model types
export ImmuneHistory, ImmuneHistoryMode, FullHistory, LatestInfection

# Stratification types
export Stratification, ContactStratification, AgeStratification, GeographicStratification,
compose_stratifications

# Model functions
export EpiMechModel, create_model_uwd, create_model, generate_transition_names

# Vectorfield functions
export flatten_symbols, vectorfield_flat

# Documentation strings
include("docstrings.jl")

# Epidemiological dynamics
include("typing.jl")
include("mechanisms.jl")
include("CompartmentalModel.jl")
include("MultiStrainModel.jl")
include("ImmuneHistory.jl")
include("Stratification.jl")
include("construction_helpers.jl")
include("create_model_uwd.jl")
include("generate_transition_names.jl")
include("create_model.jl")
include("vectorfield_flat.jl")

# Observation attachment.
include("ObservationTarget.jl")
include("ObservationLayout.jl")

end
212 changes: 212 additions & 0 deletions AlgebraicEpiMech/src/CompartmentalModel.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
"""
Abstract base type for all epidemiological-mechanical models in the AlgebraicEpiMech framework.

All concrete epidemiological-mechanical model types should be subtypes of `EpiMechModel`.
This abstract type serves as the root of the type hierarchy for models that combine
epidemiological dynamics with mechanical or algebraic structures.

# Extended help

Subtypes of `EpiMechModel` should implement the necessary interface methods for their
specific model formulation.

# See also
- Related concrete model types (define as needed)
"""
abstract type EpiMechModel end

"""
Abstract base type for compartmental epidemiological models.

Compartmental models define the specific disease dynamics and transitions
between epidemiological states (e.g., S→I→R) as undirected wiring diagrams.
"""
abstract type CompartmentalModel <: EpiMechModel end

function _validate_stage_count(name::Symbol, count::Int)
count >= 1 || throw(ArgumentError("$name must be at least 1"))
return count
end

# Base compartmental models - concrete structs for clean dispatch

"""
Susceptible-Infected (SI) compartmental model.

The SI model includes:
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious

Transitions:
- S + I → I + I (infection/transmission)

The SI model represents endemic diseases with no recovery.
"""
struct SI <: CompartmentalModel
number_I_stages::Int
number_of_states::Int

function SI(; number_I_stages::Int = 1)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_I_stages, 1 + number_I_stages)
end
end

"""
Susceptible-Exposed-Infected (SEI) compartmental model.

The SEI model extends SI with an exposed compartment:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious

Transitions:
- S + I → E + I (exposure/transmission)
- E → I (progression to infectious)

The SEI model represents diseases with an incubation period but no recovery.
"""
struct SEI <: CompartmentalModel
number_E_stages::Int
number_I_stages::Int
number_of_states::Int

function SEI(; number_E_stages::Int = 1, number_I_stages::Int = 1)
_validate_stage_count(:number_E_stages, number_E_stages)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_E_stages, number_I_stages, 1 + number_E_stages + number_I_stages)
end
end

# Extended compartmental models - built by extending base models

"""
Susceptible-Infected-Recovered (SIR) compartmental model.

The SIR model extends SI with recovery:
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered and gained immunity

Transitions:
- S + I → I + I (infection/transmission) [from SI]
- I → R (recovery) [extension]

Built by extending SI model with recovery transition.
"""
struct SIR <: CompartmentalModel
number_I_stages::Int
number_of_states::Int

function SIR(; number_I_stages::Int = 1)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_I_stages, 2 + number_I_stages)
end
end

"""
Susceptible-Exposed-Infected-Recovered (SEIR) compartmental model.

The SEIR model extends SEI with recovery:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered and gained immunity

Transitions:
- S + I → E + I (exposure/transmission) [from SEI]
- E → I (progression to infectious) [from SEI]
- I → R (recovery) [extension]

Built by extending SEI model with recovery transition.
"""
struct SEIR <: CompartmentalModel
number_E_stages::Int
number_I_stages::Int
number_of_states::Int

function SEIR(; number_E_stages::Int = 1, number_I_stages::Int = 1)
_validate_stage_count(:number_E_stages, number_E_stages)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_E_stages, number_I_stages, 2 + number_E_stages + number_I_stages)
end
end

"""
Susceptible-Infected-Susceptible (SIS) compartmental model.

The SIS model extends SI with waning immunity (reversion):
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious

Transitions:
- S + I → I + I (infection/transmission) [from SI]
- I → S (waning immunity/reversion) [extension]

The SIS model represents diseases with no lasting immunity.
"""
struct SIS <: CompartmentalModel
number_I_stages::Int
number_of_states::Int

function SIS(; number_I_stages::Int = 1)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_I_stages, 1 + number_I_stages)
end
end

"""
Susceptible-Exposed-Infected-Susceptible (SEIS) compartmental model.

The SEIS model extends SEI with waning immunity (reversion):
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious

Transitions:
- S + I → E + I (exposure/transmission) [from SEI]
- E → I (progression to infectious) [from SEI]
- I → S (waning immunity/reversion) [extension]

The SEIS model represents diseases with incubation period but no lasting immunity.
"""
struct SEIS <: CompartmentalModel
number_E_stages::Int
number_I_stages::Int
number_of_states::Int

function SEIS(; number_E_stages::Int = 1, number_I_stages::Int = 1)
_validate_stage_count(:number_E_stages, number_E_stages)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_E_stages, number_I_stages, 1 + number_E_stages + number_I_stages)
end
end

"""
Susceptible-Exposed-Infected-Recovered-Susceptible (SEIRS) compartmental model.

The SEIRS model extends SEIR with waning immunity:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered but may lose immunity

Transitions:
- S + I → E + I (exposure/transmission) [from SEIR]
- E → I (progression to infectious) [from SEIR]
- I → R (recovery) [from SEIR]
- R → S (waning immunity) [extension]

Built by extending SEIR model with waning transition.
"""
struct SEIRS <: CompartmentalModel
number_E_stages::Int
number_I_stages::Int
number_of_states::Int

function SEIRS(; number_E_stages::Int = 1, number_I_stages::Int = 1)
_validate_stage_count(:number_E_stages, number_E_stages)
_validate_stage_count(:number_I_stages, number_I_stages)
return new(number_E_stages, number_I_stages, 2 + number_E_stages + number_I_stages)
end
end
Loading
Loading