Skip to content

Architecture

Roberto Cruz edited this page May 15, 2026 · 2 revisions

Architecture

This page explains Symthea's internal design — how the simulation engine, world model, module system, and exporters fit together.

High-Level Overview

CLI / Python API
      │
      ▼
 Generator
  ├── reads GeneratorOptions + Config
  ├── loads Demographics data
  ├── spins up N worker threads
  │
  └── per thread:
        Person (seed)
          │
          ▼
       Lifecycle Simulation
        ├── Birth → initialise attributes
        ├── for each time step (default: 1 week):
        │     ├── run all Module state machines
        │     ├── apply growth charts / vital updates
        │     └── check for death condition
        └── Export (FHIR / CSV / JSON)

Project Structure

tietai-symthea/
├── pyproject.toml              # UV project config + dependencies
├── resources/
│   ├── modules/                # 231 disease modules (JSON state machines)
│   │   ├── allergies/
│   │   ├── breast_cancer/
│   │   ├── covid19/
│   │   └── *.json
│   ├── geography/              # Census demographic data
│   ├── providers/              # Healthcare facility CSVs (15 files)
│   ├── payers/                 # Insurance payer data
│   ├── costs/                  # Cost tables (14 files)
│   ├── lookup_tables/          # Transition probability tables
│   ├── cdc_growth_charts.json  # CDC growth data
│   ├── immunization_schedule.json
│   └── synthea.properties      # Default configuration
├── src/synthea/
│   ├── engine/
│   │   ├── generator.py        # Orchestration: threads, lifecycle
│   │   ├── module.py           # Module loader and runner
│   │   ├── state.py            # All state type implementations
│   │   ├── transition.py       # Transition evaluation
│   │   └── logic.py            # Condition / logic evaluation
│   ├── world/
│   │   ├── person.py           # Patient model (attributes + health record)
│   │   ├── health_record.py    # Clinical event log
│   │   ├── demographics.py     # Geographic + census data loader
│   │   ├── location.py         # State / city / zip resolution
│   │   ├── provider.py         # Provider selection
│   │   └── payer.py            # Insurance assignment
│   ├── export/
│   │   ├── fhir.py             # FHIR R4 serialiser
│   │   └── exporter.py         # Base exporter + dispatch
│   ├── helpers/
│   │   └── config.py           # synthea.properties reader/writer
│   └── cli.py                  # Click CLI entry point
├── tests/
│   ├── test_person.py
│   ├── test_state.py
│   ├── test_generator.py
│   └── test_integration.py
└── examples/
    ├── basic_generation.py
    ├── custom_module.py
    └── batch_export.py

Core Components

Generator (engine/generator.py)

The central orchestrator. Responsibilities:

  • Parse GeneratorOptions and load Config
  • Load demographic distributions from resources/geography/
  • Assign each patient a birth date, location, gender, race/ethnicity, and socioeconomic status
  • Run the lifecycle simulation (single-threaded or via ThreadPoolExecutor)
  • Dispatch each completed Person to the configured exporters

Module System (engine/module.py, engine/state.py, engine/transition.py)

Each disease module is a finite state machine loaded from JSON:

  1. module.py reads the JSON file and instantiates State objects
  2. On each time step, the module's current state is evaluated
  3. transition.py picks the next state (direct, probabilistic, conditional)
  4. logic.py evaluates boolean conditions against the Person's current attributes

Modules are composable: any state can call a submodule via CallSubmodule, enabling reuse across conditions (e.g., an encounter template shared by many modules).

Person and Health Record (world/person.py, world/health_record.py)

Person holds:

  • Attributes — a dict of arbitrary key/value pairs set by modules (age, gender, diabetes, custom flags, etc.)
  • Health record — an append-only log of clinical events (conditions, medications, encounters, observations, procedures, immunizations)
  • Vital signs — current height, weight, BMI, blood pressure

HealthRecord maps directly onto FHIR resources at export time.

Exporters (export/)

exporter.py reads the config and dispatches completed Person objects to:

  • FHIRExporter — serialises the health record to a FHIR R4 Bundle
  • CSVExporter — appends rows to per-resource CSV files
  • JSONExporter — dumps the raw Python object as JSON

Exporters are stateless; multiple threads write to separate files or use file locks for CSV append mode.

Threading Model

Main thread
  └─ ThreadPoolExecutor (N workers)
        ├─ Worker 1: Person(seed=0) ... Person(seed=k)
        ├─ Worker 2: Person(seed=k+1) ...
        └─ Worker N: ...

Each worker operates on independent Person objects with no shared mutable state. The RNG is seeded per-patient (seed + patient_index), so results are reproducible when --threads 1 is used (thread-order is deterministic); with multiple threads, generation order is non-deterministic but each individual patient is still reproducible given the same seed.

Data Flow

synthea.properties
      │
      ▼
   Config
      │
      ├── Generator
      │     ├── Demographics → Person attributes
      │     ├── Modules → HealthRecord events
      │     └── Provider / Payer assignment
      │
      └── Exporters
            ├── FHIRExporter → output/fhir/*.json
            ├── CSVExporter  → output/csv/*.csv
            └── JSONExporter → output/json/*.json

Clone this wiki locally