From Prompt to Biennial Endemic (This One Trick Could Save Your Calibration) - laser-base/laser-measles GitHub Wiki

From Prompt to Biennial Endemic: The Case Against Premature Calibration

The Goal

Produce classic biennial endemic measles waves in a large metropolitan node using laser-measles, calibrated from scratch. Constraints: CBR ~30-33/1000/yr, no importation to reseed, no spelunking the source code -- MCP tools only.


Chapter 1 -- The Landscape Before Calibration

The first instinct in any calibration problem is to reach for an optimizer. Here we did the opposite: we mapped the territory first.

A 6x10 grid sweep across R0 in {6, 8, 10, 12, 14, 16} and seasonality in {0.05, ..., 0.50} revealed a stark picture. Most of the parameter space falls into one of two failure modes:

  • Extinction zone (upper-right): seasonality too strong for the given R0. The epidemic fires intensely, depletes susceptibles, and the integer-count compartmental model drives I to exactly zero -- permanently. No importation means no recovery.
  • Annual / irregular zone (lower-left): R0 too low. Susceptibles replenish fast enough to sustain near-annual cycles, but there is no subharmonic resonance with the seasonal forcing.

Sandwiched between them is a narrow biennial corridor: R0 ~12-16, seasonality ~0.10-0.25. This is where the 2-year subharmonic locks in -- births at CBR=32 replenish susceptibles on a timescale that resonates with twice the annual forcing period.

The lesson: without this map, an optimizer handed a mostly-flat, mostly-zero objective landscape would waste the majority of its trials on dead zones. It might converge on something mediocre, or not converge at all. The sweep costs nothing -- 60 runs x 2.5 s = 2.5 minutes -- and makes the problem legible.

Phase 1: Parameter identifiability sweep


Chapter 2 -- The Ratio Landscape and What It Reveals

The right panel of the sweep goes further: it plots log(1 + epidemic/off-year peak ratio) for every surviving cell. The brighter the cell, the more dramatically the model alternates between epidemic and off-years.

The standout result: R0=16, seasonality=0.15 produces a 33x ratio -- a near-complete biennial saw-tooth. The R0=14-16, seasonality=0.10-0.15 band is unambiguously the sweet spot.


Chapter 2b -- Calibration as Finishing Touch

With the corridor identified, Optuna was given a narrow search box (R0 in [10, 18], seasonality in [0.01, 0.25]) and warm-started from the sweep's best grid point (R0=14, seas=0.10, score=0.621).

The optimizer converged in roughly 15 trials to R0=13.845, seasonality=0.112, score=0.628 -- a marginal improvement over the grid point. The optimizer did not discover the corridor; the sweep did. Optuna merely sharpened the pencil.

This is the correct role for calibration: precision work inside a region that science has already identified as viable.

Phase 2: Optuna calibration convergence


Chapter 3 -- The Self-Sustaining Biennial Endemic

The final 30-year run with the calibrated parameters tells the story plainly.

After a 5-year burn-in, the model settles into a stable, self-perpetuating biennial rhythm:

Metric Value
Dominant period (annual-peak FFT) 2.08 years
Biennial peak ratio 12.3x
Epidemic year peak I ~33,000 - 59,000
Off-year peak I ~2,000 - 5,000
Off-year minimum I never zero
Importation used none

The mechanism is purely endogenous: CBR=32 births replenish the susceptible pool on a ~2-year cycle, seasonal forcing synchronises the epidemic timing, and high R0 creates deep enough troughs to prevent annual re-ignition -- but not so deep that the infection extinguishes.

Phase 3: 30-year endemic biennial showcase


Chapter 3b -- The Annual Peak Fingerprint

The bar chart says it in one glance: perfectly alternating red (epidemic) and blue (off-year) bars, spanning 25 post-burnin years without deviation, growing slowly as the population accumulates net births. This is the canonical biennial fingerprint.


Chapter 3c -- Spectral Confirmation

The FFT of the annual-peak series places the dominant spectral peak at 2.08 years -- squarely in the biennial window (2.0 +/- 0.3 yr), with no competing annual or triennial peak. The spectrum is the mathematician's way of saying what the eye already sees in the time series.


The Full Story in One Figure

Full narrative: from prompt to biennial endemic


The Moral

Step Role Time
Identifiability sweep Map the viable region; expose extinction and annual zones ~2.5 min
Optuna calibration Sharpen within the known-good corridor ~2.5 min
30-year validation Confirm stability and measure the result ~4 s

Premature calibration is not a speed shortcut -- it is a way to optimise the wrong thing efficiently. The sweep is not a preliminary step; it is the step that makes calibration meaningful.


Model & Parameters

Property Value
Model laser-measles CompartmentalModel (SEIR, daily ticks)
Population 10,000,000 (large metropolitan node)
CBR 32 /1000/yr
CDR 10 /1000/yr
MCV1 coverage 0%
Importation None
R0 (calibrated) 13.845
Seasonality (calibrated) 0.112
Infectious period 8 days
Latent period 6 days

Prompt & Skills

Prompt (cleaned up)

OK, big cool project. I want you to create a scenario in which a large metropolitan node (patch) exhibits the classic biennial measles endemic waves. CBR should be about 30-33. Do not make CBR massive to get this to work. Use calibration to find parameters which work. Use clever objective functions as necessary. Remember to use parameter identifiabilty sweeps against objective functions before trying calibrations that might never work. Do not rely on importation to reseed. Pick the best base model for this. You might have to work hard.

Skills

Using just the jenner-measles-mcp-beta server to learn about laser-measles and using just the jenner-mcp server to learn about laser-core (INCLUDING CALIBRATION WITH LASER, see Chapter 17). Use Python3.11 (global). You do not need to go inspecting the laser-measles codebase. Use the MCP services. Do not go spellunking on my disk for help.

Note

The "use parameter identifiability first" was a key part of this whole experiment and arguably should be moved into the skills, but in this case it was not.

Code (Coming Soon)

Here: biennial_metro.py