⚠️ Work in progress: not ready for real use.
fleetis published early so the approach, and its comparison againstmalariasimulation, can be examined and argued with, not so that anyone can rely on its numbers: the API is unstable and nothing here has been peer reviewed. The known discrepancies against the IBM are open rather than resolved, the largest being all-age severe incidence, which runs about 4 to 6% below the IBM, alongside a roughly 9% excess on clinical and severe incidence across the 63-country site files that is not yet explained. The full statement is on the package front page; if you need results you can defend today, use malariasimulation.
The canonical description of the system of ordinary differential
equations fleet integrates: §1 for the one design
constraint everything follows from, §2 for what the state space does and
does not carry, and the appendix for the equations as implemented. Read
it alongside inst/odin/malaria_ode.R and the input builders
in R/build_inputs.R / R/interventions.R.
Everything below describes malariasimulation
v3.0.0.
For a task-oriented introduction with runnable code, see Getting started with fleet; for every
malariasimulation argument one by one,
vignette("parameters"); for what to do differently because
this is an ODE and not the IBM, vignette("using").
1. Scope and design
fleet is a deterministic mean-field (ODE) counterpart to
the malariasimulation individual-based model (IBM) of
Plasmodium falciparum.
Mean field means the model tracks the distribution of the population over states rather than the people themselves: the state must not carry per-individual attributes. Any quantity that depends on two attributes belonging to the same person — owning a net and being vaccinated, say — is therefore unavailable by construction. Almost everything in §2.2 and §2.3 follows from that one fact.
fleet targets the IBM’s code, not the published
equations. malariasimulation’s implementation departs from
the analytic Griffin-style model in four places: it deduplicates bites
within a day, rounds immunity-boosting refractory windows to whole days,
holds people in a state for whole days, and applies extrinsic-incubation
survival at a fixed delay. Wherever the two differ, fleet
reproduces what the IBM does.
The IBM tracks, for each person, their net, their spray status, their
vaccine doses and antibody titres, their drug and the date they took it,
and the date each of their four immunity functions last boosted. A
mean-field model cannot afford a state dimension for each.
fleet therefore keeps only two human structuring dimensions
(age and biting heterogeneity) and represents everything else either as
a time-varying coefficient in the ODE, or as a
discrete state jump between integration segments.
§2.1–2.3 set out exactly which is which.
Abbreviations
| EIR | Entomological inoculation rate: infectious bites per person per
year. fleet reports it per adult per year |
| FOI / FOIM | Force of infection (on humans) / force of infection on mosquitoes |
| EIP | Extrinsic incubation period, the delay in the mosquito between an infectious blood meal and becoming infectious |
| LM / PCR | Light microscopy / polymerase chain reaction (the two prevalence diagnostics reported) |
| ETF / SPC | Early treatment failure / slow parasite clearance, the two
antimalarial-resistance arms malariasimulation
implements |
| PEV / TBV | Pre-erythrocytic vaccine (RTS,S, R21) / transmission-blocking vaccine |
| TRA / TBA | Transmission-reducing activity (an antibody-level quantity) / transmission-blocking activity (the resulting per-state reduction in infectivity) |
| MDA / SMC / PMC | Mass drug administration / seasonal malaria chemoprevention / perennial malaria chemoprevention |
| EPI | The Expanded Programme on Immunization routine schedule. Unrelated
to set_epi_outputs(), where “epi” means
epidemiological
|
| IRS | Indoor residual spraying |
| Erlang chain | A linear chain of sequential exponential stages. Its total has mean and variance , so larger sharpens it toward the IBM’s fixed delay |
| Gauss–Hermite quadrature | A deterministic stand-in for Monte Carlo: it replaces random per-person draws with a small fixed set of representative values and weights that reproduce the distribution’s moments. “Tensor” means the product grid over several such axes |
| knots | The times at which an interpolated series is allowed to change value |
| seed | Throughout this article, the initial state vector — never a
random-number seed. fleet has no random component |
2. State space
2.1 What has a state dimension
Every human compartment is a two-dimensional array over age group
and biting-heterogeneity node
;
every mosquito compartment is indexed by species
.
Human compartments are per-capita densities (fractions
of the total human population), which is why run time is independent of
human_population.
| Dimension | Symbol | Default size | Set by | What it indexes |
|---|---|---|---|---|
| Age group | 53 |
age_lower = / default_age_lower()
|
Graded age grid, fine in infancy and coarse in adulthood. Group edges are pinned at the conventional reporting ages (0, 1, 2, 3, 5, 7, 10, 15, 20, 30, 40, 60 y), so output bands fall on group boundaries; between two anchors the groups are of equal width, with the budget of groups shared out in proportion to log width, because immunity rises with log age rather than with age. An absorbing top group runs from 80 y. Individuals age by a linear-chain (McKendrick) flow between adjacent groups. | |
| Biting heterogeneity | 5 |
parameters$n_heterogeneity_groups,
enable_heterogeneity
|
Gauss–Hermite nodes
and weights
of the log-normal relative-biting-rate distribution with variance
(sigma_squared);
.
Fixed at birth, never mixed: a person stays in their stratum for life,
as in the IBM. |
|
| Vector species | 1 | set_species() |
Independent aquatic + adult mosquito populations, each with its own biting rate, mortality, carrying capacity and vector-control response, coupled only through the shared human population. | |
| EIR lag stage | 10 (n_eir) |
ode_tuning(n_eir =) |
Erlang chain approximating the sporozoite-to-infection delay
(de). |
|
| FOIM lag stage | 10 (n_foim) |
ode_tuning(n_foim =) |
Erlang chain approximating the gametocyte delay
(delay_gam). |
|
| EIP stage | 20 (n_eip) |
ode_tuning(n_eip =) |
Loss-free Erlang chain approximating the fixed extrinsic incubation
period
(dem). |
Human compartments, all . The last column gives the column name in the output table, which is where you will meet these in practice. Eight compartments are reported in six columns.
| Compartment | odin | Output column | Meaning |
|---|---|---|---|
S |
S_count |
Susceptible | |
D |
D_count |
Clinical disease, untreated | |
Tr |
Tr_count (with
) |
Successfully treated, standard clearance | |
Tr_slow |
folded into Tr_count
|
Successfully treated, slow parasite clearance. A separate compartment, so the two clearance speeds form a genuine mixture of exponentials rather than one exponential at the blended mean (§B.4) | |
A |
A_count |
Asymptomatic patent infection | |
U |
U_count |
Sub-patent infection | |
Ph |
Ph_count (with
) |
Post-treatment prophylaxis, an Erlang chain of stages so that the exit-time distribution of the whole sojourn approximates the IBM’s Weibull protection rather than an exponential at its mean (§B.4): = 16 for SP-AQ, 20 for DHA-PQP, 1 for AL (whose 10-day protection is less variable than itself); 1 with no clinical drugs | |
Ph_c |
folded into Ph_count
|
Chemoprevention prophylaxis (MDA/SMC/PMC), its own chain because its drug differs from the clinical first line, and hence so do its mean duration and shape; : 14 for SP-AQ, 15 for DHA-PQP | |
IB |
— | Pre-erythrocytic (anti-infection) immunity | |
ICA |
— | Acquired clinical immunity | |
ID |
— | Anti-parasite (detection) immunity | |
IVA |
— | Acquired severe-disease immunity |
The four immunity arrays hold the mean immunity of the individuals currently in that (age, heterogeneity) cell, not an extensive density; their aging term is correspondingly a difference rather than a flux.
Mosquito compartments, all except the EIP chain:
| Compartment | Meaning |
|---|---|
| , , | Aquatic early larval, late larval, pupal (odin names
ME, ML, MP). Pupae emerge at
,
of which the half that are female enter
;
males are not modelled, so the factor of
on emergence is a sex ratio and not a loss |
| Susceptible adult females | |
EIP delay chain (odin Xi): a pure delay line, carries
no mortality |
|
Incubating (exposed) adults (odin Em_inc) |
|
| Infectious adults |
Total state size. With the defaults (, , , , ) and no drugs, so that :
Every extra prophylaxis stage adds states: an SP-AQ SMC scenario () has 6671.
2.2 What is captured without a dimension
These are the mechanisms the IBM carries as per-individual attributes
and fleet carries as time-varying (and sometimes
age-varying) coefficients. Each row is a dimension that was
not added.
| Mechanism | IBM representation |
fleet representation |
Cost of the collapse |
|---|---|---|---|
| Clinical treatment coverage | Per-person Bernoulli draw at the moment of a clinical episode | Scalar
,
step-interpolated over the union of all drugs’ timesteps;
splits the clinical inflow between
and
|
None at the flow level |
| Which drug a person received | Drug index stored per treated individual, driving their efficacy, infectivity and prophylaxis duration | Three scalar series , , , each a coverage-share-weighted blend across the active clinical drugs, step-interpolated over the coverage change times | A first-line switch is modelled (the blend moves in time); a genuinely mixed first line is represented by its mean, not its mixture |
| Post-treatment prophylaxis clock | Weibull survival multiplying each treated person’s infection probability, running from the dose | An Erlang chain entered after , its mean and its stage count moment-matched to (§B.4) | The chain reproduces the integrated protection exactly and the survival curve to within a few points (§B.4) |
| Early treatment failure | Per-person draw diverting a treated case back to clinical | Folded into the effective treated fraction (§B.4) | None |
| Bed net ownership, net age, retention, repeat rounds | Per-person net-receipt timestep; efficacy decays from that date; nets lost stochastically | Two scalars per species, and , computed from the full mean-field mixture over all past distributions (each weighted by most-recent-receipt probability retention survival, each decaying its own / ) | Protection is population-averaged rather than correlated within individuals across bites, so nets and IRS tend to under-suppress transmission relative to the IBM |
| IRS spray status and spray age | Per-person house-spray timestep | Folded into the same , ; mixture over all past rounds weighted by most-recent-spray probability, with no retention factor (sprayed protection never expires in the IBM) | As above |
| Vaccination status, dose count, booster stratum, antibody titre | Per-person dose history and last-vaccination date. Antibody parameters are not stored: the IBM re-draws all four from their profile distributions every timestep, for every vaccinated person | One
multiplier
on the infection hazard. The vaccinated are partitioned analytically by
the most recent booster each has reached; each stratum’s efficacy is the
average of the Hill efficacy over the IBM’s own 4-D antibody
distribution (create_pev_profile()) |
The antibody average is exact, since the IBM’s draws are
independent. What is lost is the dose history: vaccinated
status is uncorrelated with anything else (nets, treatment),
min_wait re-vaccination exclusion is not applied (set_mass_pev()),
and seasonal boosters become a fixed days-since-primary schedule
(warned) |
| TBV antibody titre | Per-person, mapped to transmission-reducing activity | Four infectivity multipliers, one per infectious state (, , , ), because the IBM’s TRA-to-TBA map is state-specific (§C) | Mean-field only |
| Immunity boosting refractory clock | Per-person last_boosted timestep; a boost fires only if
days have passed |
An analytic renewal rate on the deduplicated per-day event probability, with the wait rounded as the IBM rounds it (§B.5) | Exact for the mean inter-boost interval |
| Age-specific mortality / demographic transition | Per-person death hazard by age band and year | , a constant-interpolated series; its row also sets the seed’s age structure (§F) | Ages above the top deathrate_agegroups take the top
rate (the IBM removes them); a warning fires |
| Maternal immunity | Sampled from a mother drawn at birth | Purely algebraic, from the mean acquired immunity of 20-year-old mothers (§B.3) — no state variable at all | None beyond the mean-field average over mothers |
| Seasonality | Daily rainfall drives larval carrying capacity | , linearly interpolated on a daily grid, from the same truncated Fourier series | None (identical functional form) |
| Repeated bites in one day | Bitten individuals are collected in a set, so a person bitten several times counts once and can be infected at most once per day | Saturating hazard instead of the linear (§B.2) | None at the daily-flow level; it is the linear form that would be wrong |
Mass drug administration is carried without a dimension too, but not
as a coefficient: it cannot be written as a smooth rate. It is a short,
near-instantaneous clearance of a target age band, so fleet
splits the integration at every scheduled MDA/SMC/PMC timestep, applies
a state jump (§E), then resumes, keeping
chemoprevention out of the ODE right-hand side entirely.
2.3 What is not captured at all
| Feature | Why | Behaviour |
|---|---|---|
| P. vivax | A different model (hypnozoites, relapse) | Error at input |
Individual mosquitoes
(individual_mosquitoes = TRUE) |
fleet is always compartmental |
Ignored |
Intervention correlation (get_correlation_parameters(),
run_simulation(correlations =)) |
Purely individual-level; the mean field assumes independence between interventions | Warned and ignored |
| Per-individual stochastic variation | Deterministic model | By construction |
| Partner-drug resistance, late clinical / parasitological failure, reinfection during prophylaxis |
malariasimulation itself rejects non-zero values for
these upstream in set_antimalarial_resistance()
|
Cannot reach the model |
A. Notation
Abbreviations are at the end of §1.
Symbols
| Symbol | odin name | Meaning |
|---|---|---|
r_age |
Aging rate out of age group
,
exponentially fitted:
for band width
in days, computed as mu/expm1(mu*h) to avoid cancellation
when
is small. This makes the stationary ratio between adjacent groups
exactly
,
where the obvious
gives
and so always decays too slowly. Tends to
as
.
Fitted at the baseline mortality
and held constant: it does not follow set_demography() in
time.
(,
absorbing.) |
|
mu_age |
Age- and time-specific death rate | |
re |
Combined exit rate | |
psi |
Relative biting rate by age, | |
| , |
zeta, het_wt
|
Heterogeneity node and quadrature weight |
Npop |
Total population density in cell | |
EPS |
Expected infectious bites per person per day | |
FOI |
Force of infection (hazard per day) | |
| , |
h_c, h_a
|
Clinical and non-clinical components of |
b |
Probability an infectious bite establishes infection | |
phi |
Probability an infection is clinical | |
theta |
Probability an infection is severe | |
q |
Probability an asymptomatic infection is LM-detectable | |
cA, cD, cU,
cT
|
Onward infectivity to mosquitoes, by state | |
ft |
Clinical treatment coverage | |
pev_factor |
PEV hazard multiplier | |
| , |
a_spp, mum
|
Human blood-meal rate and adult mortality, per species |
Kcap |
Larval carrying capacity | |
de, tl, dem
|
EIR lag, gametocyte lag, extrinsic incubation period |
B. The human model
B.1 Demography
Aging is a linear chain over the age grid; deaths are recycled as births into age group 1, distributed across heterogeneity nodes by the quadrature weights, so the total population is conserved:
Every human compartment carries the same structural terms
with the aging inflow replaced by for , , and by zero otherwise.
B.2 Exposure and the infection hazard
The species-summed infectious biting rate, lagged by the Erlang chain , gives the population EIR; individual exposure scales it by the age and heterogeneity biting weights:
The IBM draws the day’s bites from a Poisson and collects the bitten
in a set, so a person bitten several times in one timestep can be
infected at most once. fleet reproduces that cap; the daily
infection probability and the equivalent hazard are
matching the IBM’s prob_to_rate. Setting
parameters$bite_dedup = 0 replaces this with the unbounded
linear form
,
which is the hazard malariaEquilibrium assumes. The two
agree to under 2% at low exposure and diverge at seasonal peaks and in
high-
strata. bite_dedup = 0 does not make the
seed an exact fixed point: it gates only the hazard, while the boosting
terms of §B.5 keep the deduplicated event probability, the integer
refractory window
and the at-risk restriction, and the state exit rates keep the whole-day
form
.
What it does is roughly halve the residual drift. Measured as the
largest excursion from the seeded value over an undisturbed 15-year run
at EIR 20, PfPR(2-10) departs by at most 0.14% with
bite_dedup = 0 against 0.28% at the default. The
endpoint tells the opposite story (the default happens to
return close to its seed, ending -0.05% off it against +0.14% with
0), so the metric has to be stated.
Hazard splitting. In the IBM each person resolves at
most one infection outcome per day, so the daily clinical count is
for susceptibles. (For people already in
or
the infection outcome competes with disease progression inside the
same hazard resolution, which scales their realised infection
probability by
.
fleet’s ODE reproduces that competition automatically,
since
and
/
act simultaneously on the same compartment.) Clinical infections leave
the at-risk pool (to
or
)
while non-clinical ones do not
(;
),
so the pool depletes only through the clinical route. Taking
integrates to exactly clinical episodes over a day. Why not just ? An ODE re-exposes people continuously through the day, so would start a second episode in someone the IBM counts once — over-counting by a factor . By construction , so occupancies and immunity boosting are unaffected.
B.3 Immunity-dependent probabilities
All four are Hill functions of the immunity states.
is acquired_immunity_offset (default 0; set 0.5 to
reproduce the IBM’s literal per-individual +0.5). The IBM
applies that offset only where acquired immunity is strictly
positive, so never-boosted individuals get none — one of the
reasons a flat +0.5 on a stratum mean is the worse match,
and why 0 is the default.
with the age-dependent detection and severity modifiers
takes no offset, matching the IBM.
Maternal immunity is algebraic, not a state. It is inherited from mothers in the model age group containing 20 years (the IBM selects ) and decays with age from birth:
where is the 20-year indicator and the exact mean of over age band ,
and the same with .
Why severe incidence comes out low
Of the three acquired-immunity Hill functions, has the shallowest exponent, not the steepest:
| exponent | scale | |
|---|---|---|
What singles out is the scale, not the exponent. A Hill function is flat well below its scale parameter and only approaches its full log-log slope well above it, so the local slope is a matter of position. Writing for the denominator term,
which is near 0 for , reaches at , and returns toward 0 once has bottomed out on its floor. The same expression with and governs , whose steepest attainable slope, , is the steeper of the two.
Position separates them.
is sixteen times smaller than
while the two acquired immunities take nearly the same values at every
age, so they differ almost entirely in what they are divided by. At
fleet’s own seed at the reference EIR of 20:
| age | ||||
|---|---|---|---|---|
| 1 | 1.80 | 0.12 | ||
| 3 | 6.62 | 0.44 | ||
| 5 | 12.20 | 0.82 | ||
| 10 | 26.31 | 1.79 |
is within 5% of the steepest slope it can have from age 3.4 to age 10.5. at age 3 is less than a fifth as steep, and does not overtake until age 10.
Sitting out on that tail makes
convex in
across essentially the whole population, where
is concave in
through early childhood at this EIR. That fixes the sign of the
mean-field error. fleet evaluates
once per (age group
heterogeneity group) at that stratum’s mean
;
the IBM averages
over individuals whose bite histories differ inside the
stratum. By Jensen’s inequality
, so the mean
field returns the smaller number and severe incidence comes out low.
fleet resolves the log-normal biting strata explicitly
(§2.1), so only the spread within an (age,
)
cell is lost and the realised gap is a few percent rather than tens of
percent, but the direction is the same. vignette("using")
says what to do about it.
B.4 Disease-state equations
Writing
for the at-risk pool,
for the slow-parasite-clearance fraction of the treated (set_antimalarial_resistance()),
and
for the effective treated fraction:
Four implementation points:
Prophylaxis chains. The IBM does not have a prophylaxis state: it multiplies each treated person’s infection probability by the Weibull survival , so a treated cohort’s mean protection at lag is exactly . A single compartment reproduces only the mean of and decays exponentially, keeping just 42% of SP-AQ recipients protected at day 30 against the Weibull’s 70%. The -stage chains above, each stage left at , keep the mean and are moment-matched to . For that is simply (14 for SP-AQ), which puts the chain’s survival within a few points of (0.67 at day 30). is entered only after the exponential sojourn, whereas the IBM’s clock runs from the dose in parallel with : a treated person there is unprotected at lag with probability . Matching the integrated protection gives the chain mean (which reduces to when throughout ), and matching the variance of the whole sojourn gives : 16 for SP-AQ, 20 for DHA-PQP, and 1 for AL, whose 10-day protection is already less variable than itself, so no chain length can sharpen it (its output is the same to five decimals at 1 and 20 stages). While in a chain, people are fully protected from and are not infectious.
Two treated compartments. The IBM assigns each successfully treated individual to standard or slow parasite clearance by a Bernoulli draw, giving a mixture of two exponentials, not one exponential at the blended mean. and reproduce that split structurally (but see the sojourn caveat below for ).
Whole-day sojourns. The IBM advances states once per day with exit probability , so its realised mean dwell is (5.52 d for , not 5).
fleetuses for so the dwells match (slow clearance is resolved through the same per-dayrate_to_probpath as ordinary treatment in the IBM). It is not applied to or , because the IBM models prophylaxis as a hazard multiplier rather than a compartment with a daily census.The chain has no ODE inflow. It is filled, at stage 1, only by the chemoprevention pulses of §E, and carries neither infection risk nor infectivity.
B.5 Immunity equations
The IBM boosts immunity on a per-day event with an integer
refractory window: boost_immunity() fires only if
timestep - last_boosted >= u, and the timestep is an
integer, so the effective wait is
days, after which the person boosts on the first subsequent day carrying
an event (geometric, mean
).
The mean inter-boost gap is therefore
,
i.e. a boosting rate
The event probability is the deduplicated per-day one, and differs between and the rest:
, and are boosted only for individuals eligible to be infected (the IBM restricts its source set to , , ), so their boost is scaled by the at-risk fraction . is boosted for everyone bitten, whatever their state, so it is not scaled:
with (immunity enters at zero at birth).
C. Human → mosquito infectivity
Onward infectivity is the state-weighted, biting-weighted human infectiousness, passed through the gametocyte-delay Erlang chain . TBV enters here as per-state, per-age multipliers :
D. The mosquito model
Per species , with adult total and larval total :
Extrinsic incubation. malariasimulation
uses a fixed
-day
delay and applies the incubation survival
at the exit, with the current
.
fleet substitutes an Erlang chain for the delay, but the
chain must be loss-free: putting death in every stage
would give a through-survival of
instead of
— about 4% too high at baseline mortality, and worsening as vector
control raises
.
So the chain is a pure delay of
,
survival is applied once at the exit, and the incubating stock follows
the IBM’s own
equation:
Vector control enters only through
and
.
For each species and time, fleet reuses
malariasimulation’s own net / IRS decay and combination
algebra, population-averaged over the net-using and sprayed fractions,
to obtain a mean repellency
and a mean survival
,
then
Oviposition is unaffected: the IBM’s
eggs_laid(beta, mu, f) is algebraically identical to
for all
,
so
is constant and vector control acts purely through
and
.
and are linearly interpolated (not step), because the IBM recomputes them every timestep, so IRS logistic decay within a spray round is a ramp rather than a step.
E. Discrete events: chemoprevention
MDA, SMC and PMC are applied as instantaneous state jumps between ODE segments. The integration is split at every scheduled pulse day; at each pulse the target age band is mapped onto the model age grid by fractional overlap
so narrow bands (e.g. PMC dose ages) are captured rather than dropped, and coarse groups are not over-treated. A fraction
of every state in each affected cell —
and the existing
and
stages, because the IBM resets drug_time for everyone it
successfully treats, renewing the protection of those already covered —
is cleared and moved to the first stage of
,
which then runs down its chain to
at
per stage:
is 1 / the coverage-weighted Weibull mean of the chemoprevention drugs
and
their coverage-weighted
,
both distinct from the clinical chain. Pulses take effect the day
after their scheduled timestep. PMC, which the IBM
delivers on an age trigger, is approximated as ~monthly pulses over each
dose-age band.
F. Initial conditions
- The
malariasimulationlist is back-translated tomalariaEquilibriumparameter names (R/translate_params.R), thenparameters$eq_paramsis merged over the top and takes precedence.set_equilibrium()always stores its own back-translation there, even when called witheq_params = NULL, so after anyset_equilibrium()call it is that stored set, notR/translate_params.R, supplying every shared constant. - For each heterogeneity node
,
malariaEquilibrium::human_equilibrium_no_het()is solved at and the effective treated fraction , on the model age grid. Its , ,prop, ,IB,ICA,ID,IVAandcAcolumns are reused directly. The block is re-solved with a corrected prophylaxis aging recursion, — upstream divides only the term by , leaving undivided — and generalised to the -stage chain (stage 1 fed by , stage by , every stage aging at ). The re-solve makes the seed the fixed point of the prophylaxis ODE actually implemented here, so the model holds flat even under treatment. - The equilibrium age structure is recomputed under (which may be the custom-demography baseline row), and the constant-hazard seed is rescaled onto it.
- is split between and by the slow-clearance fraction.
- Mosquito compartments are seeded from
initial_mosquito_counts()at the FOIM implied by the seeded human infectivity, withtotal_Mchosen so that exactly. Under the default demography ; under a custom demographytotal_Mis fixed to the IBM’s (ibm_total_M(),set_equilibrium()) and is the root oftotal_M(EIR) = total_M_IBM, found byuniroot()on (steps 2–4 are re-solved at each trial EIR). Lag chains are seeded at their equilibrium values, and at the corresponding carrying capacity (floored at of the maximum for species with proportion 0, which would otherwise give in the larval term).
Because malariaEquilibrium encodes the
simplified forms — a linear force of infection, refractory
boosting on the raw rate with the un-rounded
,
no at-risk restriction on boosting, and continuous-time state exit rates
— while fleet reproduces the IBM’s per-day semantics, the
seed is a close approximation to fleet’s
true fixed point rather than the fixed point itself: an undisturbed run
relaxes by up to ~0.5% over the first years and then holds.
malariasimulation relaxes off its own
malariaEquilibrium seed for the same reason, though the two
seeds are not identical: the IBM passes the raw treated
fraction
rather than
,
solves on a fixed 0–99.9 y grid with heterogeneity handled inside
human_equilibrium(), and does not correct the prophylaxis
recursion. Set parameters$bite_dedup = 0 to reduce the
drift to well under 1% (no setting makes it exactly zero; see §B.2).
G. Outputs
Per age group (aggregated to output bands in R), all as fractions of
the total human population and multiplied by
human_population on the way out, except
p_detect_lm_*, which is a proportion (the LM-positive count
divided by the band population) and is not scaled:
| Output | Definition |
|---|---|
n_age_* |
|
n_detect_lm_* |
|
p_detect_lm_* |
n_detect_lm_* / n_age_* for the same band
(LM prevalence) |
n_detect_pcr_* |
:
the IBM convention, not
malariaEquilibrium’s sub-patent-weighted
pos_PCR
|
n_inc_clinical_* |
, counted with the clinical hazard, so a day’s integral is exactly the IBM’s |
n_inc_severe_* |
: times the all-infection count below, because the IBM draws severe from the same deduplicated infected set as clinical |
n_inc_* |
(all new infections) |
EIR |
, per adult per year |
FOIM, ft
|
and |
S_count, D_count, A_count,
U_count, Tr_count, Ph_count
|
Population totals by infection state (diagnostic) |
How age groups map onto bands. By exact
overlap: a model age group contributes to a rendering band the
fraction of its own width that lies inside
,
the same weighting the chemoprevention pulses use (§E). A group
straddling a band boundary is split between the two bands rather than
handed whole to one of them, so over any set of bands that partition a
span of the age axis the weights sum to exactly 1 per group inside that
span: no family double-counts, and none loses anyone it renders. The
absorbing top group is the one case the invariant cannot cover, since it
is not a finite interval. It is captured whole by any band reaching
above its lower edge, and fleet reports the population that
no band captured.
Why the two infection counts split the pool. These outputs are rates, which R integrates over a day, so the right rate depends on how fast each compartment drains. and drain at the full , and — the IBM’s deduplicated count, exactly. drains only at , because a sub-clinical re-infection leaves an in ; counting it at would over-count by , so takes directly. Clinical incidence is unaffected: it is counted with , and already.
Six state columns for eight compartments.
Tr_count sums
and Ph_count sums
,
so neither split is observable in the output. That also makes
S_count + D_count + A_count + U_count + Tr_count + Ph_count
a complete population-conservation check.
Why each family gets its own bands. Each output
family is emitted only over its own
*_rendering_ages band list, exactly as
malariasimulation does, with n_age_* over the
union. postie treats every output column as an independent
age stratum, so if a family were emitted over the union of all bands,
the same ages would appear in two columns and any person-day-weighted
aggregate would count them twice. This was a real bug (see
NEWS.md): it inflated all-age clinical incidence by
~1.21×.
H. Numerical solution
The model is compiled from odin2 to C++
(src/malaria_ode.cpp) and integrated by dust2’s adaptive
solver. Defaults atol = rtol = 1e-8 and
step_size_max = 1 preserve the flat equilibrium exactly.
The step cap binds only near equilibrium: there the solution is nearly
flat, so the adaptive stepper proposes a very long step and can jump
clean over an interpolation knot (the day an intervention changes),
missing it entirely. See ?ode_tuning for when to loosen
these settings and what it costs.
The PEV, TBV, carrying-capacity and (constant-demography) mortality
grids are built to extend a year past timesteps so the
stepper never extrapolates them; the vector-control grid ends exactly at
timesteps. Every intervention series starts at its
baseline value at
,
so the equilibrium seed is preserved and interventions act only from
their scheduled timesteps.
That last property is a property of the knots, not of the series’ values. The vector-control, carrying-capacity, PEV and TBV series are interpolated linearly, which is right for the within-round decay each of them carries but means a value that changes on a scheduled day ramps in from whatever knot precedes it. Each of these grids therefore carries a knot at as well as at every scheduled day , pinning the pre-deployment value one day out and confining the ramp to the single step onto the scheduled day. Without it a deployment inherits the spacing of the background grid: off the 10-day vector-control grid, nets scheduled for day 100 reach 66% of their effect on EIR by day 99. With it, a round takes effect within a day of its schedule, the same resolution the chemoprevention pulses (§E) already have.
