Public Health Observer

The PublicHealthObserver is a convenience base class for building observers in public health simulations. It extends vivarium’s Observer with two capabilities that most public health observers share:

  1. A simplified method for registering adding observations.

  2. A standardized results-formatting pipeline that produces a consistent column layout across all public health outputs.

All of the concrete observers shipped with this package inherit from PublicHealthObserver.

Registering Adding Observations

The most common observation type in public health models is the adding observation: one that sums new results into a running total each time step (e.g. counting deaths or accumulating person-time). Rather than calling the results interface directly (via the builder), PublicHealthObserver exposes register_adding_observation(), which wraps that call with sensible defaults and automatically applies the standardized formatter.

The method accepts the same core arguments as register_adding_observation() (pop_filter, when, aggregator, etc.) plus two convenience parameters:

  • additional_stratifications — extra stratification names to add on top of the defaults registered by the ResultsStratifier.

  • excluded_stratifications — default stratification names to remove from this particular observation.

Results Formatting

Public health result files follow a standardized column layout. Every row contains four metadata columns in addition to any stratification and value columns:

Column

Purpose

measure

The name of the quantity being measured (e.g. "person_time", "transition_count").

entity_type

A classifier for the entity (e.g. "cause", "rei").

entity

The specific entity being observed (e.g. "measles", "high_systolic_blood_pressure").

sub_entity

A finer-grained descriptor within the entity (e.g. a specific disease state or risk category).

PublicHealthObserver produces these columns through a chain of overridable methods that subclasses customize:

The top-level format_results() method calls each of these in sequence and reorders the final columns so that metadata columns appear first, stratification columns in the middle, and the value column last.

Writing a Custom Observer

To create a new public health observer:

  1. Subclass PublicHealthObserver.

  2. Implement register_observations() and call self.register_adding_observation(...) within it.

  3. Override the formatting sub-methods as needed to populate the metadata columns.

Concrete Observers

The vivarium_public_health results package ships several concrete observers that cover the most common public health measures. Each inherits from PublicHealthObserver and registers one or more adding observations during setup.

All concrete observers support per-observer stratification overrides via the stratification configuration block. Under configuration.stratification.<observer_config_name>, each observer accepts an include list of additional stratification names and an exclude list of default stratification names to remove.

Disability Observer

DisabilityObserver counts years lived with disability (YLDs).

It discovers all components that contribute disability weights — by default DiseaseState and RiskAttributableDisease instances — and adds an all_causes aggregate on top.

Observation registered: ylds

On each time_step__prepare event, the observer reads each cause’s {cause}.disability_weight pipeline for every living simulant, multiplies by the step size (converted to years), and sums the result. Because a simulant can carry disability from multiple causes simultaneously, YLDs are not stratified by cause through the normal stratification mechanism. Instead, the observer produces wide results (one column per cause) and then reshapes them into long format during formatting, with each cause appearing as a separate sub_entity.

Categories listed under excluded_categories.disability in the model specification are dropped before observation.

The observer’s configuration key is disability.

Disease Observer

DiseaseObserver tracks disease-state person time and transition counts for a single disease model.

Each instance is constructed with the name of the disease to observe (e.g. DiseaseObserver("measles")).

Observations registered:

Observation

Description

person_time_{disease}

Person-time (in years) spent in each disease state during each time step, observed at time_step__prepare.

transition_count_{disease}

Count of simulants that transitioned between disease states during each time step, observed at collect_metrics.

In addition to registering observations, the observer registers two stratifications specific to its disease:

  1. Disease state — categories correspond to the state IDs of the disease model’s states (e.g. susceptible_to_measles, measles).

  2. Transition — categories correspond to the transition names (e.g. susceptible_to_measles_to_measles), plus a no_transition category that is automatically excluded from results.

To track transitions, the observer maintains a previous_{disease} column on the state table that is updated at the start of each time step.

The observer’s configuration key matches the disease name (e.g. configuration.stratification.measles).

Mortality Observer

MortalityObserver counts cause-specific deaths and years of life lost (YLLs).

It discovers all components that use the ExcessMortalityState mixin and have active excess mortality, then adds other_causes (for non-modeled causes) and not_dead (automatically excluded) as additional categories.

Observations registered:

Observation

Description

deaths

Count of simulants who died during the current time step (exit_time > clock()).

ylls

Sum of years_of_life_lost for simulants who died during the current time step.

Both observations filter on is_alive == False and are observed at collect_metrics.

By default the observer registers a cause_of_death stratification so that deaths and YLLs are broken down by cause. Setting aggregate: true in the configuration collapses all causes into a single all_causes row, which can improve runtime when cause-level detail is not needed. Set configuration.stratification.mortality.aggregate to true to enable this mode.

The observer’s configuration key is mortality.

Categorical Risk Observer

CategoricalRiskObserver tracks person-time spent in each exposure category of a categorical risk factor. It is a convenience subclass of CategoricalCausalFactorObserver, which provides the core logic.

Each instance is constructed with the name of the risk factor (e.g. CategoricalRiskObserver("child_wasting")).

Observation registered: person_time_{risk_factor}

At time_step__prepare the observer counts the number of living simulants in each exposure category and multiplies by the step size (converted to years) to produce person-time.

The observer registers a stratification for the risk factor whose categories are loaded from the artifact at risk_factor.{name}.categories, and the exposure values come from the {name}.exposure pipeline.

The observer’s configuration key matches the risk factor name (e.g. configuration.stratification.child_wasting).

See Also