Skip to contents
fleet is a work in progress and is not validated for research, policy or operational use.Work in progress: not validated for real use. Details

fleet is not yet validated for real use; see the status note.

fleet carries the same mechanisms as the individual-based model (IBM) and, for most outcomes, lands inside its replicate spread. A stratum mean is not a population of individuals, however, and some effects do not survive the averaging. This article covers what to do because of that, which settings to leave alone, which results to treat with caution, and what a run costs.

Section references such as §B.4 are to vignette("model"), and function links go to vignette("parameters"). The measurements behind the claims here are in fleetcheck, which is kept current as the model changes; the figures quoted here are not.

Call set_equilibrium() last

set_equilibrium() stores the equilibrium parameters on the list as eq_params, and fleet uses that stored set in place of the live values, except iv0. An edit made afterwards, by another set_*() function or by hand (parameters$du <- 10), therefore has no effect, and the run is bit-identical to one without it. The IBM reads those fields directly and would apply the edit, so this is a real difference between the two models. fleet warns when a live value disagrees with the stored one. If a calibration loop varies any of these parameters, call set_equilibrium() again on each iteration. ?run_simulation_ode has the details.

Burn in

The seed is a close approximation to the model’s fixed point, not the fixed point itself (§F). Falciparum prevalence relaxes by under 0.5%, and incidence by a few per cent over the first years, more at high transmission (+6% for under-5 clinical incidence at EIR 120).

A P. vivax run moves further, as the IBM’s does, because both build up a within-cell spread of immunity that the seed does not have. Clinical incidence settles about 20% above the seed and the realised EIR 4 to 17% above init_EIR (more at lower EIR), within about eight years at EIR 3 but over two decades at EIR 0.3. init_EIR is therefore not the EIR a P. vivax run realises.

A run whose treatment starts at timestep 1 starts untreated, as the IBM’s does, and settles onto its treated state over the first months. A seasonal run takes about 10 years to settle onto its limit cycle, and its annual-mean EIR is about 7% below the aseasonal init_EIR target through nonlinear averaging. Discard the transient.

Match the age grid to the demography

Under set_demography(), if the oldest model age group runs past the top of deathrate_agegroups, fleet applies the top death rate to those ages, where the IBM removes them. A warning is given. Do not ignore it: it changes the equilibrium age structure the whole run is seeded on (set_demography()). Make the two match, either by extending the death rates or by lowering the grid’s top age group below the top death-rate edge. For death rates that stop at 60 years:

run_simulation_ode(t, p, tuning = list(age_lower = default_age_lower(max_age = 59)))

Output

postie treats every column as an independent age stratum, so overlapping bands are double-counted by any person-day-weighted aggregate (§G). Make each family’s bands a partition. A band [lower, upper] includes both end days, as in the IBM, so in a partition each band ends the day before the next one starts:

p$prevalence_rendering_min_ages <- c(0, 2, 10) * 365
p$prevalence_rendering_max_ages <- c(2, 10, 100) * 365 - 1

A family whose list is empty renders nothing, in fleet as in the IBM: the defaults give the 2-10 prevalence band and no incidence.

Row tt of the output is day tt, the state at its start and the incidence during it, exactly as malariasimulation renders timestep tt, so the two tables line up row for row.

Prevalence is n_detect_lm_* / n_age_*, as postie computes it. p_detect_lm_* is the IBM’s expected number LM-detected, a count like n_detect_lm_*, not a prevalence.

EIR is per adult per year, the value biting humans today. The IBM reports the same lagged quantity as a per-species daily total, so the like-for-like comparison is EIR_<species> / human_population * 365.

S_count + D_count + A_count + U_count + Tr_count should equal human_population to numerical tolerance. Ph_count is the drug-protected part of S_count, so it is not added again.

Settings to leave alone

  • acquired_immunity_offset: leave it unset. It defaults to 0 for falciparum, whose curves are read at a stratum mean, where the IBM’s per-individual 0.5 is a worse match to the IBM ensemble mean (§B.3); to 0.5 for P. vivax, whose curves are read at quadrature nodes that stand for people (§V.3); and to 0 for P. vivax with immunity_spread = FALSE, back at the cell mean.
  • bite_dedup: leave it at 1 for any scientific falciparum run. Setting 0 lets every bite infect independently, which the IBM does not do for falciparum (§B.2). P. vivax counts every bite, as the IBM does, and ignores it.
  • n_sub: the default of 32 mosquito sub-steps per day integrates each day about as accurately as the IBM’s own mosquito solver, and the model’s lags are the IBM’s own delay lines, so there is nothing to sharpen.
  • n_ph, n_phc: the prophylaxis chains are sized from the drug’s Weibull by default (§B.4) and capped at 20 stages. Each stage adds nanzn_a n_z states, and no chain can have more stages than its mean has days.
  • parameterise_total_M(), parameterise_mosquito_equilibrium(): these have no effect. fleet re-derives total_M itself, from init_EIR under the default demography and as the IBM’s own value under a custom one (set_equilibrium()).

Limitations

Severe incidence and the age grid

Severe incidence is the output most sensitive to the age grid. θ\theta sits on the convex tail of its Hill function from early childhood (§B.3 has the numbers), and a group’s severe incidence is evaluated at its mean immunity. So wherever immunity changes across a group, as it does fastest in the young groups where severe disease concentrates, the group returns too small a value. The error is first order in the group width. On the default 118 groups, severe incidence at EIR 120 is 2% below the IBM median; on 53 groups, at under half the cost, it is 7% below, and clinical incidence in young children a few per cent low. A result that rests on the level of severe incidence, or of clinical incidence in under-5s at high transmission, needs the default grid or a finer one; a coarser grid is adequate otherwise:

run_simulation_ode(t, p, tuning = list(age_lower = default_age_lower(n_group = 53)))

The same convexity within an (age, ζ\zeta) stratum, where the IBM holds a spread of infection histories and the mean field one value, is a much smaller effect for falciparum. The measurements are the severe-allage-eir and age-profile-clinical claims in fleetcheck.

θ\theta is also a post-hoc multiplier: severe counts are θ\theta times an infection count the state equations have already determined (§G), so nothing downstream absorbs an error in it. ϕ\phi, by contrast, splits the infection inflow and feeds back through infectivity, treatment and immunity.

P. vivax where days without a bite are common

malariasimulation 3.0.0 evaluates vivax relapses only on days when at least one person is bitten, so wherever days without a bite are common the IBM loses relapses that fleet keeps, and runs below it, sometimes to elimination. This is a defect in the IBM, which fleet does not copy; comparing the two there compares fleet with the defect. The probability of a day without a bite in the IBM is about e−EIRdayψ‾Ne^{-\text{EIR}_{\text{day}}\, \bar\psi\, N} for a daily EIR per adult, mean relative biting rate ψ‾\bar\psi and population NN. In a 10,000-person run it exceeds 5% only below an EIR of about 0.14, and in a 50,000-person run below about 0.03. It therefore matters in small populations, at the lowest transmission, and where vector control drives the day’s bites down. It does not explain fleet’s excess over the IBM on the vivax site files, whose 50,000-person runs almost never go a day without a bite; that excess is not yet explained.

P. vivax at school age

The vivax immunity curves are steep, and the IBM’s immunity-dependent transitions sort people within an age, heterogeneity and batch cell: those with more anti-parasite immunity clear sub-patent infections sooner, so the uninfected hold more of the immune, and the clinical draw takes the least immune. A mean field with one immunity distribution per cell does not carry that sorting (§V.7), and at EIR 10 its LM prevalence and clinical incidence in school-age children are 1–3% above the IBM’s.

Vector control

Population-averaged coverage loses the correlation of protection within individuals across bites, so fleet tends to sit above the IBM while nets or IRS are active (§2.2).

Repeated mass campaigns

A campaign’s protection ages with the cohort it vaccinated, and repeated rounds combine as the most recent dose, as in the IBM. What the mean field cannot carry is who was reached before: each round reaches a person independently of the last, and min_wait re-vaccination exclusion is not applied (set_mass_pev(), set_tbv()). A single campaign is unaffected.

Stochastic variation

fleet returns the ensemble mean, so it has no replicate spread of its own, and a single IBM replicate is not a fair comparison. Compare against the IBM’s replicate median, and read the replicate band (median ± 1.28 SD, fleetcheck’s definition) as the noise fleet does not carry.

Run times

Seconds for one complete run_simulation_ode() call: building the inputs, seeding the equilibrium, stepping the days and rendering the outputs. Single core, ode_tuning() defaults, default 118-group age grid. Falciparum at EIR 20, the SMC scenarios at EIR 15:

Scenario 5 years 10 years 30 years
No interventions 0.30 s 0.59 s 1.65 s
Seasonal 0.31 s 0.60 s 1.67 s
Seasonal + treatment (AL) 0.33 s 0.62 s 1.75 s
Seasonal + nets + IRS 0.31 s 0.61 s 1.79 s
Seasonal + SMC (4 rounds/yr) 0.42 s 0.75 s 2.15 s
All of the above + RTS,S 0.43 s 0.81 s 2.34 s

Cost is proportional to the horizon, because every day costs the same: the no-intervention row is 0.05 s per simulated year on an intercept of a few hundredths of a second, so building the inputs and solving the seed are a small fixed charge. Seasonality adds 1% at 30 years: the update does the same work each day however fast the solution is moving, and rainfall only changes the day’s carrying capacity. Chemoprevention is the most expensive intervention, SMC adding 29% to a seasonal run and everything together, vaccination included, 40%. SMC adds state, the two chemoprevention protection chains and the treated phase, about 600 states per stage on the default grid, and each round pauses the run for its pulse.

A P. vivax run costs about 13 times a falciparum one: every compartment carries the hypnozoite-batch dimension, eight levels for eleven batch counts (§V.1), and each cell carries the spread of its immunity. At EIR 3, with 40% of clinical cases treated where a drug is named:

Scenario 5 years 10 years 30 years
No interventions 3.7 s 6.9 s 21.8 s
Treatment (chloroquine) 4.6 s 8.3 s 22.2 s
Radical cure (CQ + primaquine) 5.6 s 10.3 s 28.5 s
Radical cure (CQ + tafenoquine) 16.6 s 30.5 s 88.2 s

Radical cure adds the day’s radical-cure transfers: with primaquine, 1.3 times the cost of treatment alone at 30 years. Tafenoquine costs 4.0 times as much: its liver-stage protection outlasts the blood-stage drug’s, so it adds eleven liver-stage-protected levels to the batch dimension, whereas primaquine’s ends inside chloroquine’s and adds none (§V.5).

Population size does not affect run time: the compartments are per-capita densities, and human_population only rescales the count columns on output.

Population 1,000 10,000 100,000 1,000,000 10,000,000
30-year seasonal run 1.74 s 1.73 s 1.70 s 1.72 s 1.70 s

Of the discretisation settings, the mosquito sub-steps barely affect cost, since the mosquito model is a small part of the day: a 30-year seasonal run takes 1.70 s at n_sub = 8, 1.72 s at the default 32 and 1.75 s at 64. The age grid is the setting that costs, a little more than in proportion to its number of groups: on the 53 groups of default_age_lower(n_group = 53) the same run takes 0.70 s.

Times are the minimum of five repeats (two for P. vivax), since contention can only add time, on R 4.5.2, aarch64-w64-mingw32. They are indicative: one machine, one core, and a laptop under load will be slower. The 30-year seasonal run appears three times above, at 1.67 to 1.75 s; that spread is the machine’s, not the model’s. For a comparison with the IBM’s cost, see the speed claims in fleetcheck.

Index of approximations

Every mechanism labelled Approximate in vignette("parameters"), and when it matters. The Where column links to the argument-by-argument account; § refers to vignette("model").

Mechanism Where Matters when
Ages above the top deathrate_agegroups take the top death rate set_demography() A custom demography whose age grid stops short of the model’s oldest group; the IBM removes those people instead. Warned
Weibull prophylaxis → stage chain (moment-matched), protecting fully while it lasts set_drugs(), §B.4 SMC and MDA at high transmission, where the chain’s all-or-nothing protection shields dosed children a little more than the IBM’s partial, fading protection does; the far tail of chemoprevention protection; for post-treatment protection the TT stage in front of the chain spreads AL’s sharp 10-day protection, reproducing its integral rather than its shape
Multi-drug blend rather than parallel sub-populations, weighted by coverage where the IBM’s treated are weighted by success set_clinical_treatment() A genuinely mixed first line, especially with resistance on one drug (a switch is modelled fine)
Single scalar slow-clearance rate blended across drugs set_antimalarial_resistance(), §B.4 High artemisinin resistance with several treatment drugs
Population-averaged nets set_bednets() Any nets era, the largest routine gap
Population-averaged IRS set_spraying() Any IRS era
Carrying-capacity floor at K0×10−4K_0\times10^{-4} set_carrying_capacity() Modelling complete vector elimination
Chemoprevention as pulses; target bands half-open, where the IBM’s hold both end days set_mda(), set_smc(), §E Very narrow target bands
PMC age trigger → monthly pulses set_pmc() PMC dose timing specifically
Seasonal PEV boosters → fixed delay set_pev_epi() Seasonally-timed booster campaigns (warned)
Repeated campaigns: no min_wait, each round reaching people independently set_mass_pev(), set_tbv() Repeated mass PEV or TBV rounds
The absorbing top age group taken whole, or not at all, by a rendering band set_epi_outputs(), §G A band ending inside the top group (above 80 years on the default grid), which is given all of it
Refractory boosting of ICAI_{CA}, IDI_D, IVAI_{VA} as a quasi-steady closure §B.5 Exposure changing sharply within a week
One immunity value per age group default_age_lower(), §B.3 Severe incidence, and clinical incidence in young children at high transmission, on a grid coarser than the default
Vivax: one immunity distribution per age, heterogeneity and batch cell, shared by every disease state §V.7 School-age LM prevalence and clinical incidence, 1–3% high at EIR 10
Vivax: IAA’s 44-day refractory window as four 11-day stages §V.3 Infants’ IAA, 2.7% of itself; nothing else by more than 0.7%
Vivax: hypnozoite batch counts 4 to 9 sharing levels in pairs, a Poisson inside each; ode_tuning(batch_bins = FALSE) gives every count its own ode_tuning(), §V.1 No output of the fleetcheck vivax suite by more than 0.4%
Vivax: no liver-stage protection after primaquine, whose protection ends inside chloroquine’s blood-stage protection §V.5 Primaquine radical cure, below 0.2%
Vivax: prophylaxis chains protecting fully while they last, Tr included set_drugs(), §V.4–V.5 The shape of liver-stage protection after radical cure; under a switch from primaquine to tafenoquine, tafenoquine’s protection keeps its mean and widens its spread
Vivax: the day’s bites averaged before the competing draw §V.2, §V.7 D’s infection probability 0.1–0.5% low, and the bite share of infections 0.2–1% low
Vivax: refractory people infected at their cell’s average rate, Tr included §V.3, §V.7 IAA boosts in young children under treatment, up to an estimated 1.6% too few
Vivax: IAA’s within-cell spread from a renewal closure §V.3, §V.7 Clinical incidence and LM prevalence where daily infection probabilities pass about 0.05, at high EIR