interventions.hiv_interventions
interventions.hiv_interventions
Define HIV interventions for STIsim By default, these all have units of a year and timesteps of 1/12
Classes
| Name | Description |
|---|---|
| ART | Antiretroviral therapy intervention. |
| HIVDx | HIV diagnostic product used by :class:HIVTest. |
| HIVTest | HIV-specific testing intervention. |
| InfantHIVTest | HIV test for infants born to mothers diagnosed during pregnancy. |
| Prep | Pre-exposure prophylaxis (PrEP). |
| VMMC | Voluntary medical male circumcision. |
ART
interventions.hiv_interventions.ART(
pars=None,
coverage=None,
smoothness=0,
format_priority='n',
**kwargs,
)Antiretroviral therapy intervention.
Requires HIVTest (or equivalent) to diagnose agents first — ART only initiates agents who have hiv.diagnosed=True. A warning is raised if no HIVTest is found in the sim.
Processing flow each timestep
- Agents scheduled to stop ART are removed
- Agents whose scheduled ART start has arrived (ti_art == this timestep and not on_art) are filtered by art_initiation probability
- If coverage is specified: agents are added/removed to match the target number, prioritized by CD4 count and care-seeking propensity
- If no coverage is specified: all who pass art_initiation go on ART (no capacity constraint)
- Mothers on ART reduce infant susceptibility (prenatal via MaternalNet, postnatal via BreastfeedingNet) by pmtct_efficacy
The scheduling (setting ti_art) is owned by the testing intervention that diagnoses the agent (HIVTest, ANCTest). ART here is passive: it picks up whoever is ready to start.
Coverage is parsed by :func:parse_coverage and accepts: - None: no coverage target; treat all who initiate (default) - Scalar (e.g. 0.8): constant proportion of infected on ART - Dict: {'year': [...], 'value': [...]} — interpolated to yearvec - Dict with mixed format: {'year': [...], 'value': [...], 'format': ['n','n','p','p']} - Single-column DataFrame: index=years, column n_art or p_art - Dual-column DataFrame: both n_art and p_art columns — uses format_priority to resolve (default: n_art when non-NaN) - Stratified DataFrame: columns Year, AgeBin (e.g. [15,25)), and optionally Gender/Sex, plus a numeric value column
Intervention ordering: HIVTest must appear before ART in the interventions list so that agents diagnosed this timestep can initiate ART in the same step.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coverage | coverage target in any format above (default None) | None |
|
| art_initiation | probability a newly diagnosed person initiates ART (default: ss.bernoulli(p=0.9)). Set to 1 to treat all diagnosed. | required | |
| pmtct_efficacy | efficacy of maternal ART in reducing infant susceptibility to HIV (default 0.96). Applied to both prenatal (MaternalNet) and postnatal (BreastfeedingNet) transmission. Set to 1.0 for complete protection (previous default behavior). | required | |
| smoothness | interpolation smoothness (0=linear, default) | 0 |
|
| format_priority | when both n_art and p_art are non-NaN, prefer this format (‘n’ or ‘p’, default ‘n’) | 'n' |
Examples::
# Simple: 80% of infected on ART
art = sti.ART(coverage=0.8)
# Time-varying coverage
art = sti.ART(coverage={'year': [2000, 2010, 2025], 'value': [0, 0.5, 0.9]})
# No coverage target — 90% of newly diagnosed initiate (default art_initiation)
art = sti.ART()
# From a CSV file
art = sti.ART(coverage=pd.read_csv('art_coverage.csv').set_index('year'))
# Historical n_art then projected p_art
df = pd.read_csv('n_art.csv').set_index('year')
df['p_art'] = np.nan
df.loc[2023:, 'p_art'] = 0.90
art = sti.ART(coverage=df)
Methods
| Name | Description |
|---|---|
| art_coverage_correction | Adjust ART coverage to match data. |
| prioritize_art | Prioritize ART to n agents among those awaiting treatment |
| step | Apply ART at each timestep: stop ART for those scheduled, initiate for newly diagnosed, |
art_coverage_correction
interventions.hiv_interventions.ART.art_coverage_correction(
sim,
target_coverage=None,
stratum_targets=None,
)Adjust ART coverage to match data.
If stratum_targets is supplied, correction is done independently within each (age_bin, sex) stratum so that age/sex differentials in the input data are preserved. Otherwise, correction is done globally against target_coverage.
prioritize_art
interventions.hiv_interventions.ART.prioritize_art(
sim,
n=None,
awaiting_art_uids=None,
)Prioritize ART to n agents among those awaiting treatment
step
interventions.hiv_interventions.ART.step()Apply ART at each timestep: stop ART for those scheduled, initiate for newly diagnosed, and correct coverage to match targets (per-stratum when stratified data is supplied, otherwise against the aggregate total).
HIVDx
interventions.hiv_interventions.HIVDx(*args, **kwargs)HIV diagnostic product used by :class:HIVTest.
A simple perfect-sensitivity test that classifies agents as positive (infected) or negative (susceptible) based on their current HIV state.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| *args | Positional arguments forwarded to ss.Product. |
() |
|
| **kwargs | Keyword arguments forwarded to ss.Product. |
{} |
HIVTest
interventions.hiv_interventions.HIVTest(
product=None,
pars=None,
test_prob_data=None,
years=None,
start=None,
eligibility=None,
name=None,
label=None,
newborn_test=None,
**kwargs,
)HIV-specific testing intervention.
Tests eligible agents for HIV; positive results set hiv.diagnosed=True, which is a prerequisite for ART initiation. By default, only undiagnosed agents are eligible.
The testing → diagnosis → ART pipeline works as follows:
1. HIVTest tests eligible agents each timestep (annual probability, converted via ss.probperyear)
2. Positive results set hiv.diagnosed=True and hiv.ti_diagnosed
3. HIVTest samples dur_dx2tx and sets hiv.ti_art = ti + delay (scheduled start)
4. ART picks up agents whose ti_art == current ti (and not yet on_art),
filters by art_initiation, and puts them on ART
5. If coverage data is provided, ART corrects to match targets
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| product | diagnostic product (default: :class:HIVDx). |
None |
|
| pars | dict | override default pars (rel_test, dt_scale, dur_dx2tx). |
None |
| test_prob_data | annual testing probability (if dt_scale=True, the default). A value of 0.1 means ~10% of eligible agents tested per year. To specify a per-timestep probability instead, set dt_scale=False. |
None |
|
| years | array | years over which testing is active (mutually exclusive with start). |
None |
| start | float | calendar year when testing begins. | None |
| eligibility | func |
who can be tested. Default: undiagnosed agents. | None |
| name, label | standard module identifiers. | required | |
| newborn_test ( | class:InfantHIVTest): if supplied, schedules an infant HIV test at delivery for unborn children of mothers who test positive (requires ss.MaternalNet and ss.Pregnancy in the sim). |
required | |
| dur_dx2tx | ss.Dist |
delay from diagnosis to scheduled ART start (default: ss.constant(0), no delay). May be passed directly or via the pars dict. Example: ss.constant(ss.years(0.5)) for a 6-month delay. |
required |
| dt_scale | bool | if True (default), test_prob_data is an annual probability. Set to False for per-timestep probability. |
required |
Example::
# Test 20% of undiagnosed agents per year starting in 2000
test = sti.HIVTest(test_prob_data=0.2, start=2000, name='hiv_test')
# Test everyone every timestep (per-timestep probability)
test = sti.HIVTest(test_prob_data=1.0, dt_scale=False, name='hiv_test')
# FSW-targeted testing at higher rate
fsw_test = sti.HIVTest(
test_prob_data=0.5,
name='fsw_test',
eligibility=lambda sim: sim.networks.structuredsexual.fsw & ~sim.diseases.hiv.diagnosed,
)
# ANC testing: test undiagnosed pregnant women in first trimester
anc_test = sti.HIVTest(
test_prob_data=0.9,
dt_scale=False,
name='anc_test',
eligibility=lambda sim: sim.demographics.pregnancy.tri1_uids[
~sim.diseases.hiv.diagnosed[sim.demographics.pregnancy.tri1_uids]
],
)
InfantHIVTest
interventions.hiv_interventions.InfantHIVTest(
test_prob=1.0,
name=None,
label=None,
**kwargs,
)HIV test for infants born to mothers diagnosed during pregnancy.
Scheduled by :class:HIVTest (via newborn_test=) or :class:ANCTest when the mother tests positive. Fires only at the scheduled timestep. A positive result sets hiv.diagnosed on the infant, enabling ART linkage.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| test_prob | float | probability of the infant receiving the test once scheduled (default 1.0 — if scheduled, it happens) | 1.0 |
| name, label | standard | required |
Prep
interventions.hiv_interventions.Prep(
pars=None,
coverage=None,
eligibility=None,
smoothness=0,
**kwargs,
)Pre-exposure prophylaxis (PrEP).
Reduces HIV susceptibility by eff_prep (default 80%) among eligible agents. Coverage ramps up over time via parse_coverage (same flexible inputs as ART/VMMC). Uses a per-agent probability model (coverage = probability of being on PrEP each step) rather than a target-count model like ART/VMMC.
The eligibility callable defines the target population. It receives the Sim object and should return a boolean array over all agents. HIV-negative and not-already-on-PrEP filters are always applied on top, so eligibility only needs to express who to target, not the clinical preconditions.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coverage | coverage level(s); any format accepted by parse_coverage, or legacy (years, coverage) list pairs via pars | None |
|
| eff_prep | efficacy (default 0.8 = 80% reduction in acquisition) | required | |
| smoothness | interpolation smoothness (0=linear, default) | 0 |
|
| eligibility | callable (sim) -> BoolArr defining the target population; defaults to FSW (sim.networks.structuredsexual.fsw) |
None |
Examples::
# Default: FSW at time-varying coverage
prep = sti.Prep(coverage={'year': [2020, 2025], 'value': [0, 0.5]})
# AGYW targeting
prep = sti.Prep(
coverage=0.4,
eligibility=lambda sim: sim.people.female & (sim.people.age < 25),
)
VMMC
interventions.hiv_interventions.VMMC(
pars=None,
coverage=None,
eligibility=None,
smoothness=0,
format_priority='n',
**kwargs,
)Voluntary medical male circumcision.
Reduces male susceptibility to HIV acquisition by eff_circ (default 60%). Unlike ART, VMMC does not require diagnosis — it circumcises males up to a coverage target, prioritized by willingness (a random per-agent score).
If no coverage is specified, VMMC does nothing. Coverage must be provided explicitly via the coverage parameter.
Coverage is parsed by :func:parse_coverage (same formats as ART, using n_vmmc/p_vmmc column names). Age-only stratification is supported (no Gender column required, since VMMC is males-only).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coverage | coverage target (default None; VMMC does nothing without data). See :func:parse_coverage for supported formats. |
None |
|
| eff_circ | efficacy (default 0.6 = 60% reduction in HIV acquisition) | required | |
| eligibility | optional function to restrict who is eligible (default: all males) | None |
|
| smoothness | interpolation smoothness (0=linear, default) | 0 |
|
| format_priority | when both n_vmmc and p_vmmc are non-NaN, prefer this format | 'n' |
Examples::
vmmc = sti.VMMC(coverage=0.3)
vmmc = sti.VMMC(coverage={'year': [2010, 2025], 'value': [0, 0.4]})