Pathogens & Immunity

Overview Structs

Overview Functions

Pathogen Struct

GEMS.PathogenType
Pathogen

A type that holds all relevant information about a pathogen.

Fields

  • id::Int8: Unique identifier for the pathogen.
  • name::String: Name of the pathogen.
  • progressions::Tuple: A typed tuple containing instances of ProgressionCategory that define the possible disease progressions.
  • progression_assignment::ProgressionAssignmentFunction: A function that assigns a progression category to an individual. Must be a subtype of ProgressionAssignmentFunction.
  • transmission_function::TransmissionFunction: A function that calculates the transmission probability of the pathogen. Must be a subtype of TransmissionFunction.
  • infectiousness_profile::InfectiousnessProfile: The profile defining the infectiousness dynamics over time.
  • immunity_profile::ImmunityProfile: The profile defining the immunity dynamics (e.g., acquisition and waning).

Example

```julia

Define disease progressions

dpa = Asymptomatic( exposuretoinfectiousnessonset = Poisson(2), symptomonsettorecovery = Poisson(5) ) dps = Mild( exposuretoinfectiousnessonset = Poisson(3), infectiousnessonsettosymptomonset = Poisson(1), symptomonsettorecovery = Poisson(7) )

Define progression assignment function

pa = RandomProgressionAssignment([Asymptomatic, Mild])

Define transmission function

tf = ConstantTransmissionRate(transmission_rate = 0.3)

Create pathogen

pathogen = Pathogen( id = 1, name = "Covid19", progressions = [dpa, dps], progressionassignment = pa, transmissionfunction = tf # infectiousnessprofile and immunityprofile will use their defaults )

Progression Categories

Structs

GEMS.AsymptomaticType
Asymptomatic <: ProgressionCategory

A disease progression category where individuals do not show symptoms but can spread the disease.

IMPORTANT: The infectiousness onset must be at least 1 tick after exposure to avoid issues with immediate transmission. Therefore, the calculation for infectiousness_onset includes a +1 offset. The provided distributions should account for this offset to ensure realistic timing. Providing, for example a Poisson(2) distribution would result in an average of 3 ticks from exposure to infectiousness onset (Poisson(2) + 1).

Disease events

exposure -> infectiousness_onset -> recovery.

Parameters

  • exposure_to_infectiousness_onset::Union{Distribution, Real}: Time from exposure to becoming infectious.
  • infectiousness_onset_to_recovery::Union{Distribution, Real}: Time from becoming infectious to recovery.

Example

The code below instantiates an Asymptomatic progression category with specific distributions for the time intervals.

dp = Asymptomatic(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_recovery = Poisson(7)
)
GEMS.MildType
Mild <: ProgressionCategory

A disease progression category for individuals who develop mild symptoms. They do not require hospitalization and continue their daily activities but are aware of their illness.

IMPORTANT: The infectiousness onset must be at least 1 tick after exposure to avoid issues with immediate transmission. Therefore, the calculation for infectiousness_onset includes a +1 offset. The provided distributions should account for this offset to ensure realistic timing. Providing, for example a Poisson(2) distribution would result in an average of 3 ticks from exposure to infectiousness onset (Poisson(2) + 1).

Disease events

exposure -> infectiousness_onset -> symptom_onset -> recovery.

Parameters

  • exposure_to_infectiousness_onset::Union{Distribution, Real}: Time from exposure to becoming infectious.
  • infectiousness_onset_to_symptom_onset::Union{Distribution, Real}: Time from becoming infectious to symptom onset.
  • symptom_onset_to_recovery::Union{Distribution, Real}: Time from symptom onset to recovery.

Example

The code below instantiates a Mild progression category with specific distributions for the time intervals.

dp = Mild(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_symptom_onset = Poisson(1),
    symptom_onset_to_recovery = Poisson(7)
)
GEMS.SevereType
Severe <: ProgressionCategory

A disease progression category for individuals who develop severe symptoms. They will stay home during the severe stage of their illness but do not require hospitalization.

IMPORTANT: The infectiousness onset must be at least 1 tick after exposure to avoid issues with immediate transmission. Therefore, the calculation for infectiousness_onset includes a +1 offset. The provided distributions should account for this offset to ensure realistic timing. Providing, for example a Poisson(2) distribution would result in an average of 3 ticks from exposure to infectiousness onset (Poisson(2) + 1).

Disease events

exposure -> infectiousness_onset -> symptom_onset -> severeness_onset -> severeness_offset -> recovery.

Parameters

  • exposure_to_infectiousness_onset::Union{Distribution, Real}: Time from exposure to becoming infectious.
  • infectiousness_onset_to_symptom_onset::Union{Distribution, Real}: Time from becoming infectious to symptom onset.
  • symptom_onset_to_severeness_onset::Union{Distribution, Real}: Time from symptom onset to severeness onset.
  • severeness_onset_to_severeness_offset::Union{Distribution, Real}: Time from severeness onset to severeness offset.
  • severeness_offset_to_recovery::Union{Distribution, Real}: Time from severeness offset to recovery.

Example

The code below instantiates a Severe progression category with specific distributions for the time intervals.

dp = Severe(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_symptom_onset = Poisson(1),
    symptom_onset_to_severeness_onset = Poisson(2),
    severeness_onset_to_severeness_offset = Poisson(3),
    severeness_offset_to_recovery = Poisson(7)
)

Host care for this tier may be embedded directly, either as a SevereHealthProfile object or as flat SevereHealthProfile parameters (the latter is a convenience only; see SevereHealthProfile for its defaults):

dp = Severe(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_symptom_onset = Poisson(1),
    symptom_onset_to_severeness_onset = Poisson(2),
    severeness_onset_to_severeness_offset = Poisson(3),
    severeness_offset_to_recovery = Poisson(7),
    hospital_probability = 0.1
)
GEMS.CriticalType
Critical <: ProgressionCategory

A disease progression category for individuals who develop critical symptoms. Critical is the most severe disease tier: it nests a critical interval inside the severe interval. Host-level care and outcomes (hospitalization, ICU, ventilation, death) are not part of the disease progression; they are decided by the simulation's HealthProgression from this tier's severe/critical demand.

IMPORTANT: The infectiousness onset must be at least 1 tick after exposure to avoid issues with immediate transmission. Therefore, the calculation for infectiousness_onset includes a +1 offset. The provided distributions should account for this offset to ensure realistic timing. Providing, for example a Poisson(2) distribution would result in an average of 3 ticks from exposure to infectiousness onset (Poisson(2) + 1).

Disease events

exposure -> infectiousness_onset -> symptom_onset -> severeness_onset -> critical_onset -> critical_offset -> severeness_offset -> recovery.

Parameters

  • exposure_to_infectiousness_onset::Union{Distribution, Real}: Time from exposure to becoming infectious.
  • infectiousness_onset_to_symptom_onset::Union{Distribution, Real}: Time from becoming infectious to symptom onset.
  • symptom_onset_to_severeness_onset::Union{Distribution, Real}: Time from symptom onset to severeness onset.
  • severeness_onset_to_critical_onset::Union{Distribution, Real}: Time from severeness onset to critical onset.
  • critical_onset_to_critical_offset::Union{Distribution, Real}: Time from critical onset to critical offset.
  • critical_offset_to_severeness_offset::Union{Distribution, Real}: Time from critical offset to severeness offset.
  • severeness_offset_to_recovery::Union{Distribution, Real}: Time from severeness offset to recovery.

Example

dp = Critical(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_symptom_onset = Poisson(1),
    symptom_onset_to_severeness_onset = Poisson(2),
    severeness_onset_to_critical_onset = Poisson(1),
    critical_onset_to_critical_offset = Poisson(5),
    critical_offset_to_severeness_offset = Poisson(2),
    severeness_offset_to_recovery = Poisson(7)
)

Host care for this tier may be embedded directly, either as a CriticalHealthProfile object or as flat CriticalHealthProfile parameters (the latter is a convenience only; see CriticalHealthProfile for its defaults and the cascading-off caveat):

dp = Critical(
    exposure_to_infectiousness_onset = Poisson(3),
    infectiousness_onset_to_symptom_onset = Poisson(1),
    symptom_onset_to_severeness_onset = Poisson(2),
    severeness_onset_to_critical_onset = Poisson(1),
    critical_onset_to_critical_offset = Poisson(5),
    critical_offset_to_severeness_offset = Poisson(2),
    severeness_offset_to_recovery = Poisson(7),
    hospital_probability = 0.9,
    hospital_to_icu_probability = 0.5
)

Functions

Health Progression

GEMS.HealthProgressionType
HealthProgression

Abstract supertype for host-level health policies. A HealthProgression turns the severe/critical intervals of an individual's active infections into CareContributions, which superpose into the host's hospital/ICU/ventilation occupancy, and into a HealthOutcome.

Subtype it and implement calculate_health_progression! for a custom combination policy, e.g. coinfection synergy. A policy is invoked whenever a new infection is added to a host.

A policy cannot read the host's scheduled future care; joint reasoning is done over each_infection, whose courses are already drawn.

GEMS.HealthProfileType
HealthProfile

Abstract supertype for a single disease tier's health profile (e.g. SevereHealthProfile, CriticalHealthProfile). Implement calculate_health_profile to define how one infection of that tier demands host care and/or mortality risk.

GEMS.DefaultHealthProgressionType
DefaultHealthProgression <: HealthProgression

Default host health policy. Holds a SevereHealthProfile and a CriticalHealthProfile; each infection contributes care and mortality risk from the profile for its peak tier once, when it arrives. Care contributions superpose into the host's occupancy and mortality folds by earliest death; the two are independent. Ventilation is disabled by default (CriticalHealthProfile has zero ventilation probability and length).

Contributions are independent, not synergistic: a host's occupancy is the union of what each infection demanded on its own, so two infections that each demand a ward bed never escalate to ICU. Override calculate_health_progression! to model interaction between co-active infections.

Example

hp = DefaultHealthProgression(
    severe = SevereHealthProfile(hospital_probability = 0.1),
    critical = CriticalHealthProfile(hospital_to_icu_probability = 0.6, death_probability = 0.25))
GEMS.SevereHealthProfileType
SevereHealthProfile

Health profile for an infection whose peak tier is severe: a possible hospital (ward) admission, anchored at the infection's severeness_onset.

Parameters

  • hospital_probability::Real: Hospital admission probability (0.0 by default).
  • severeness_onset_to_hospital_admission::Union{Distribution, Real}: Admission delay after severeness onset.
  • hospital_admission_to_hospital_discharge::Union{Distribution, Real}: Ward stay length.
GEMS.CriticalHealthProfileType
CriticalHealthProfile

Health profile for an infection whose peak tier is critical: a hospital admission that can escalate to ICU and ventilation, plus mortality risk. Each step's probability is conditional on the step below (hospital_to_icu_probability = P(ICU | hospitalized), icu_to_ventilation_probability = P(ventilation | ICU)); discharges chain inward-out so the stays nest by construction. Timings are anchored at the infection's critical_onset. Care and mortality are computed independently here and reconciled once, downstream, by compute_health!.

Parameters

  • hospital_probability::Real: Hospital admission probability (0.0 by default).
  • critical_onset_to_hospital_admission::Union{Distribution, Real}: Admission delay after critical onset.
  • hospital_admission_to_hospital_discharge::Union{Distribution, Real}: Ward stay length when the patient does not enter the ICU.
  • hospital_to_icu_probability::Real: ICU probability for a hospitalized patient (0.0 by default).
  • hospital_admission_to_icu_admission::Union{Distribution, Real}: Delay from hospital to ICU admission.
  • icu_admission_to_icu_discharge::Union{Distribution, Real}: ICU stay length when the patient is not ventilated.
  • icu_to_ventilation_probability::Real: Ventilation probability for an ICU patient (0.0 by default).
  • icu_admission_to_ventilation_admission::Union{Distribution, Real}: Delay from ICU to ventilation admission.
  • ventilation_admission_to_ventilation_discharge::Union{Distribution, Real}: Ventilation length.
  • ventilation_discharge_to_icu_discharge::Union{Distribution, Real}: ICU stay after ventilation ends.
  • icu_discharge_to_hospital_discharge::Union{Distribution, Real}: Hospital stay after ICU discharge.
  • death_probability::Real: Death probability (0.0 by default).
  • critical_onset_to_death::Union{Distribution, Real}: Delay from critical onset to death.
GEMS.calculate_health_progression!Function
calculate_health_progression!(contributions::Vector{CareContribution}, individual::Individual, infections::InfectionRegistry, hp::HealthProgression, new_infection::InfectionState, tick::Int16, rng::Xoshiro)::HealthOutcome

Combination policy: push!es this call's care demand onto contributions and returns the death it proposes. Invoked once per arriving infection. Care unions and death minimizes, hence the asymmetry.

Contribute only the increment. Contributions superpose and are never retracted, so contributing the whole active set again on each call leaves the host admitted for the rest of the run, silently. A policy must therefore be deterministic (never re-draw what it already contributed), monotone (demand only ever rises as infections are added), and incremental.

The returned HealthOutcome is likewise this call's own, not the host's total, so HealthOutcome() means "no mortality from this infection", not "cancel the scheduled death".

Every tick contributed must be > tick. contributions is a reused buffer: only push! to it.

When reasoning across infections:

  • each_infection already includes new_infection.
  • A co-active infection's window may start at or before tick, so clamp overlaps to tick + 1.
  • From the seeding path, each_infection can include an infection that recovers this tick.

An override must annotate every argument, differing from the generic method only in hp. Annotating hp alone is ambiguous with the generic method.

See DefaultHealthProgression for the generic method, which contributes for new_infection only.

GEMS.calculate_health_profileFunction
calculate_health_profile(profile::HealthProfile, individual::Individual, infection::InfectionState, rng::Xoshiro)::Tuple{CareContribution, HealthOutcome}

Overridable per-tier policy. Maps a single infection's severe/critical schedule onto a (CareContribution, HealthOutcome) pair. individual is available so a custom HealthProfile can condition on host traits (e.g. comorbidities); the built-in profiles ignore it.

GEMS.select_health_profileFunction
select_health_profile(hp::HealthProgression, infection::InfectionState)::Union{HealthProfile, Nothing}

Overridable per-infection routing. Returns the HealthProfile to apply to infection, or nothing if it demands no host care. The generic calculate_health_progression! calls this for the arriving infection; override it to route infections (e.g. by their progression_id) to custom profiles while reusing the default combination.

GEMS.compute_health!Function
compute_health!(individual::Individual, infections::InfectionRegistry, hp::HealthProgression, new_infection::InfectionState, tick::Int16, rng::Xoshiro, sched::AbstractHealthSchedule)

Framework entry point, not overridable. Hands calculate_health_progression! the shard's buffer to contribute care into, folds the death it proposes with the host's committed one, validates the whole result, and only then files the transitions and writes the death. Invoked whenever a new infection is added to a host.

GEMS.CareLevelType
CareLevel

The host care ladder. Declaration order is the ladder; the drain depends on it.

GEMS.CareContributionType
CareContribution

Isbits value type holding a host's precomputed care timeline: hospital/ICU/ventilation admission and discharge ticks. Unset ticks are -1.

Constraints

  • Each admission requires its discharge and cannot happen after it.
  • The care ladder must hold: ICU is gated behind hospital, ventilation behind ICU.
GEMS.HealthOutcomeType
HealthOutcome

Isbits value type holding a host's precomputed terminal outcome: the death tick and the pathogen credited for it. Unset death is -1.

GEMS.combine_outcomeFunction
combine_outcome(a::HealthOutcome, b::HealthOutcome)

The earlier of two deaths, with its attributed pathogen.

Applied by compute_health!, so a policy returning HealthOutcome() cannot cancel a committed death.

Progression Assignment

GEMS.AgeBasedProgressionAssignmentType
AgeBasedProgressionAssignment <: ProgressionAssignmentFunction

An assignment function that assigns disease progression categories based on age groups and a stratification matrix.

Fields

  • age_groups::Vector{AgeGroup}: A vector of age groups.
  • progression_categories::Vector{DataType}: A vector of progression categories.
  • stratification_matrix::Matrix{Float64}: A matrix where each column corresponds to an age group and each row corresponds to a progression category.

Parameters for constructor

  • age_groups::Vector{String}: A vector of age group strings in the format "-X", "X-Y", or "Y-".
  • progression_categories::Vector{String}: A vector of progression category type names as strings.
  • stratification_matrix::Vector{Vector{T}} where T <: Real: A matrix (as a vector of vectors) where each column corresponds to an age group and each row corresponds to a progression category. Each column must sum to 1 and contain no negative values.

Example

The code below instantiates an AgeBasedProgressionAssignment with specific age groups, progression categories, and a stratification matrix.

aba = AgeBasedProgressionAssignment(
    age_groups = ["-14", "15-65", "66-"],
    progression_categories = ["Asymptomatic", "Mild", "Severe", "Critical"],
    stratification_matrix = [[0.4, 0.45, 0.1, 0.05],
                             [0.2, 0.6, 0.15, 0.05],
                             [0.1, 0.4, 0.3, 0.2]]
)

Tramission Function

GEMS.AgeDependentTransmissionRateType
AgeDependentTransmissionRate <: TransmissionFunction

A TransmissionFunction type that allows to define transmission probabilities for specific age groups. The age group corresponds to the infectee, i.e., the individual who may become infected, not the infecter.

Fields

  • age_groups::Vector{AgeGroup}: A vector of age groups.
  • age_transmission_rates::Vector{Float64}: A vector of transmission rates corresponding to each age group.

Example

The code below instantiates an AgeDependentTransmissionRate with specific age groups and transmission rates.

adtr = AgeDependentTransmissionRate(
    age_groups = ["0-9", "10-19", "20-64", "65-"],
    transmission_rates = [0.1, 0.2, 0.3, 0.4]
)
GEMS.ConstantTransmissionRateType
ConstantTransmissionRate <: TransmissionFunction

A TransmissionFunction type that uses a constant transmission rate.

Functions