What’s new
All notable changes to the codebase are documented in this file.
Version 0.10.3 (2026-08-29)
- Updated for Starsim 3.6.0, which makes
float()on anss.TimeParraise aTypeError(it silently discarded the unit) and recordsnew_infectionsinsidess.Infection.set_prognoses()rather than inferring them fromti_infectedafterwards. - Fixed
DxDelivery(result_validity=...):step_expire_resultsconverted the validity window withfloat(self.result_validity), which now raises. It divides by the module’s owndtinstead (self.result_validity / self.t.dt), matchingDSTDelivery._expire_stale. - Fixed the LSHTM reference ODE (
tbsim.compartmental.TB_SS): its Euler step tookfloat(self.dt)for a timestep in years, which now raises; it usesself.dt.yearsexplicitly. - Fixed silently-zero incidence results for
TBResistant:TBResistant.set_prognosesoverrode the base method without callingsuper(), so under Starsim 3.6.0 itsnew_infectionsandcum_infectionsresults stayed zero for the whole run (under 3.5.x the base class recomputed them afterwards, hiding the omission). Added a regression test. - Raised minimum Starsim dependency to
>=3.6.0.
Version 0.10.2 (2026-07-20)
- Reworked several multi-strain / drug-resistance behaviors (
tbsim.resistance) and lifted latent reinfection into baseTB. - Latent reinfection in base
TB:rr_reinfection_inf(σ_L) andrr_reinfection_non(σ_N) are now base-TBparameters, so latent (INFECTION) and non-infectious (NON_INFECTIOUS) agents are reinfection-eligible in single-strain models too. A re-exposure resets theti_infectedclock without otherwise changing the agent’s state (clock reset only). σ_L defaults torr_reinfection_recand σ_N to σ_L; set them to0to disable. - Per-strain count preserved through acquisition: when a strain acquires resistance (de-novo, on treatment, or under TPT), the emergent resistant strain now inherits the source strain’s per-strain multiplicity count and accumulates onto any copies already present, instead of resetting to
1. Replacement moves the source count to the target; de-novo'mixed'keeps the source and copies the count to the target. - Multi-strain treatment/TPT acquisition: treatment- and TPT-acquired resistance now let each carried drug-susceptible strain acquire resistance independently in one round (mirroring de-novo), rather than a single picked strain; the
acq_selectparameter was removed fromTxR/TPTRx. - Independent per-drug DST errors:
DSTdraws sensitivity/specificity errors independently per (strain, drug), so a multi-drug DST behaves like independent per-drug tests. - Latent-treatment mode:
TxDeliveryR(treat_latent=False)(default) now clears a latent agent’s regimen-susceptible strains with certainty while keeping any regimen-resistant strain (no course, no acquisition, not counted inn_treated), instead of unconditionally clearing the agent toCLEARED; pan-susceptible / single-strain behavior is unchanged. - Added a
skills/folder (symlink to.claude/skills/) holding repo-specific Claude Code skills, starting withtbsim.address-issuefor fixing a specified GitHub issue end to end. - Fixed cross-delivery treatment resolution (#447): with two or more
TxDeliveryRdeliveries treating overlapping agents, one delivery could re-resolve an agent another delivery was actively treating — using its own stalepending_surv— zeroing an infectious agent’sstrain_maskand crashing the next transmission draw (IndexErrorin the strain PPF).TxDeliveryRnow tracks a delivery-scopedon_courseownership flag, so_resolve,interrupt,treatment_monitoring_eligibility, andwill_failonly ever act on the courses that delivery itself started.ti_treatment_endstill persists after a course (so theretreat_afterrefractory guard is unchanged).
Version 0.10.1 (2026-07-15)
- Added optional time-varying (front-loaded) TB progression: the latent
INFECTION-exit hazards can now decline exponentially with time since infection,inf_asy(τ) = inf_asy · exp(−k_asy · τ)(andinf_nonviak_non), whereτis years since the agent was infected (reinfection restarts the clock). Controlled by two newTBparameters,k_asyandk_non, both defaulting to0(constant hazard), so the default behaviour and existing calibrations are bit-for-bit unchanged. Setk_asy > 0for the recommended one-parameter front-loaded progression to active TB, matching the front-loaded shape seen in historical household-contact data. The per-agent effective rates are exposed viaTB.progression_rates().
Version 0.10.0 (2026-07-10)
- Added the multi-strain / drug-resistance extension
tbsim.resistance. TBResistant(drop-inTBsubclass) encoding2ⁿstrains overndrugs as a per-agent bitmask with per-strain fitness costs, superinfection, de-novo resistance, and a per-strain multiplicity counter (identical-strain re-exposure now increments the count and feeds the transmission multinomial and progression bottleneck).- Strain-aware product/delivery interventions
TxR/TxDeliveryR(per-strain efficacy incl. explicitefficacy_by_strainvectors, float or per-agent-distributionadherence, acquisition-on-failure, regimen switching, andfailure_case_eligibilityretreatment-vs-new-case classification),DST/DSTDeliverydiagnostics with observed-profile routing, and strain-awareTPTRx. ResistanceStatsandStrainResultsanalyzers, plus a two-strain reference ODE (tbsim.compartmental.TwoStrainODE) for ABM↔︎ODE validation.
Version 0.9.0 (2026-07-09)
- Added read-only boolean views of TB
state(latent,non_infectious,asymptomatic,symptomatic,active_tb,terminal), giving the Starsim boolean idiom at call sites while keeping the categoricalstateas the single source of truth. - Replaced the
TBSstatic-method state groups with tuple constants (TBS.ACTIVE,TBS.TERMINAL,TBS.CARE_SEEKING) used viastate.isin(...); addedHIVState.INFECTEDsimilarly. - Made
TBSenum values contiguous (0–8) so per-state result counts use a single-passnp.bincount, replacing per-state==/np.isinscans and the every-step re-derivation ofinfected/susceptible/on_treatment. - Updated for Starsim 3.5.1:
ss.library.HouseholdNet(replacingss.HouseholdNet). - Raised minimum Starsim dependency to
>=3.5.1.
Version 0.8.1 (2026-06-10)
- Fixed a UID/position confusion bug (#425) where several interventions identified agents by running
np.where/np.flatnonzeroover a starsimArr’s compact, alive-only.valuesview and then treating the resulting positions as UIDs. Once any agents had died (so UIDs no longer matched compact positions), this silently selected the wrong agents. AffectedHouseholdContactTracing.step,TPTHousehold.check_eligibility,TxDelivery._get_eligible,Migration._members_by_household_id, andHealthSeekingBehavior.step. All now use native starsim filtering (arr.auids[mask]) so positions map back to real UIDs. - Added regression tests covering household contact tracing, treatment eligibility, care-seeking, and diagnostic administration after agent deaths.
Version 0.8.0 (2026-06-02)
- Added
migration.pywith a singleMigrationdemographics class providing bidirectional, household-aware population turnover:- Immigration (new agents enter) and emigration (existing agents leave), each driven by an annual
ss.freqrate; settingemigration_rate=0gives immigration-only behavior - Optional
maintain_populationmode that tops up arrivals each step to hold the active (non-terminal) population near its starting size - Configurable immigrant age profiles via
immigration_age_distributionbins or anage_datahistogram, plus optional age-weighted emigrant selection viaemigration_age_distribution - TB-state-aware imports: immigrants enter with a TB-state mix from
tb_state_distribution, or a default derived from the TB module’sinit_prevand progression parameters - Household integration with
ss.HouseholdNet: immigrants are assigned to existing households (size-weighted) and wired into household edges, and emigrants are removed from their households - Per-step
n_immigrants,n_emigrants, andnet_migrationresults
- Immigration (new agents enter) and emigration (existing agents leave), each driven by an annual
- Removed the separate
Immigrationclass in favor of the unifiedMigrationclass - Removed the
TBAcutemodel variant and its ACUTE state; onlyTBis supported now
Version 0.7.0 (2026-03-16)
- Added
tbsim.Sim, a convenience wrapper aroundss.Simthat auto-routes flat parameters between the sim and the TB module, provides TB-specific defaults (demographics, networks, disease), and supports atb_modelargument for selecting among TB model variants. Includes ademo()function for quick setup. - Refactored all diagnostic and treatment interventions into a product/delivery architecture:
- Added
Dxdiagnostic product class with DataFrame-based test definitions supporting state, age, and HIV stratification - Added built-in diagnostic products:
Xpert,OralSwab,FujiLAM,CAD - Added
DxDeliveryintervention for delivering diagnostics with eligibility filtering, coverage, and false-negative retry logic - Added
Txtreatment product class with drug-type-based efficacy - Added built-in treatment products:
DOTS,DOTSImproved,FirstLine,SecondLine - Added
TxDeliveryintervention for delivering treatments with success/failure tracking and retry logic - Simplified
drug_types.pyto a single dictionary of drug parameters (previously ~600 lines of class hierarchy) - Removed old monolithic
tb_diagnostic.py,tb_drug_types.py, andtb_treatment.py
- Added
- Removed
TB_EMODand renamedTB_LSHTMto TB; onlyTBandTBAcuteare supported now - Added
HouseholdStatsanalyzer for tracking household size distributions, age-mixing matrices, and contact patterns over time when usingss.HouseholdNet. Includes visualization methods for household statistics, age-mixing heatmaps, and normalized contact matrices. - Renamed
tb_health_seeking.pytohealth_seeking.pyand simplified theHealthSeekingBehaviorclass - Moved
immigration.pyto an archive folder - Added admin files (
code_of_conduct.md,contributing.md,CHANGELOG.md) - Updated
starsimdependency to v3.2.1 forHouseholdNetsupport