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

  1. Agents scheduled to stop ART are removed
  2. Agents whose scheduled ART start has arrived (ti_art == this timestep and not on_art) are filtered by art_initiation probability
  3. If coverage is specified: agents are added/removed to match the target number, prioritized by CD4 count and care-seeking propensity
  4. If no coverage is specified: all who pass art_initiation go on ART (no capacity constraint)
  5. 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]})