resistance.treatments
resistance.treatments
Strain-aware TB treatment.
TxR (product) holds the regimen’s per-strain efficacy, agent-level adherence, and acquisition-on-failure rules. TxDeliveryR (delivery) initiates treatment from the active-disease states at state-specific rates (or from a custom eligibility callable), freezes the outcome at initiation, and resolves it after a fixed course. It also supports treatment monitoring / regimen switching via interrupt + supersedes (see treatment_monitoring_eligibility).
Per the reference treatment operator (the ODE’s π(m→s)): each carried strain is cured independently (efficacy reduced for strains resistant to regimen drugs), the whole course’s outcomes are correlated through a single agent-level adherence draw, failures return to the state treatment was initiated from with the surviving strains, and each surviving treatment-susceptible strain independently acquires resistance to each regimen drug with probability q_acq[drug] (× a per-state RR) as replacement — so multiple strains may acquire resistance in one course, mirroring de-novo acquisition, with multiplicity transferred source→target. This reproduces the ODE’s π(m → s) outcome table exactly for the single-strain-per-agent two-strain case.
Classes
| Name | Description |
|---|---|
| TxDeliveryR | Rate-based strain-aware treatment delivery. |
| TxR | Strain-aware treatment product. |
TxDeliveryR
resistance.treatments.TxDeliveryR(
product,
rate_asym=ss.peryear(0.0),
rate_sym=ss.peryear(2.0),
dur_treatment=ss.months(6),
eligibility=None,
supersedes=None,
retreat_after=None,
treat_latent=False,
**kwargs,
)Rate-based strain-aware treatment delivery.
Each step, active-TB agents not already on treatment start a course at state-specific rates (rate_asym from ASYMPTOMATIC, rate_sym from SYMPTOMATIC), or from a custom eligibility callable (e.g. a DST-routed regimen). The per-strain outcome is frozen at initiation and resolved after dur_treatment: fully cleared courses go to CLEARED (with post-treatment reinfection protection); otherwise the agent returns to the state it was treated from carrying the surviving (and possibly newly resistant) strains.
Treatment monitoring / regimen switching: a delivery given supersedes=[name, ...] will interrupt any ongoing course on those deliveries for its eligible agents before starting them, so a second-line regimen can take over an in-progress first-line course.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| product | TxR | the strain-aware treatment product. | required |
| rate_asym | ss.rate |
treatment initiation rate from ASYMPTOMATIC. | ss.peryear(0.0) |
| rate_sym | ss.rate |
treatment initiation rate from SYMPTOMATIC. | ss.peryear(2.0) |
| dur_treatment | ss.dur |
course duration (fixed). | ss.months(6) |
| eligibility | callable | optional sim -> uids override; if given, those agents start treatment instead of the rate-based rule. |
None |
| supersedes | str / list | name(s) of other TxDeliveryR whose ongoing course is interrupted for eligible agents before this delivery starts them (regimen switching). |
None |
| retreat_after | ss.dur |
refractory period after a course ends before the same agent may be re-treated by this delivery. Prevents a failing agent from being re-treated on every resolution off a single stale DST result (L1). Default None = no guard. |
None |
| treat_latent | bool | how latent (INFECTION) agents selected for treatment are handled. False (default): strain-aware sterilization — every carried strain susceptible to all regimen drugs is cleared with certainty, any regimen-resistant strain persists (the agent stays latent carrying it), and an agent left carrying no strain moves to CLEARED. No course is run and no resistance is acquired. For a pan-susceptible agent this clears the only strain → CLEARED, matching the single-strain behavior of base tbsim.TxDelivery. True: run through a full course that can fail / select for resistance. See L3 / implementation-decisions.md D-L3. (The default rate-based eligibility never selects latent agents, so this only affects custom / DST-routed eligibilities.) |
False |
Methods
| Name | Description |
|---|---|
| failure_case_eligibility | Classify a later treatment episode as treatment failure/retreatment vs a new case. |
| interrupt | Prematurely stop this delivery’s ongoing courses for uids (treatment monitoring / switch). |
| step | Resolve completed courses, then initiate new ones. |
failure_case_eligibility
resistance.treatments.TxDeliveryR.failure_case_eligibility(
within,
base=None,
new_case=False,
)Classify a later treatment episode as treatment failure/retreatment vs a new case.
Implements the spec’s requirement (§Diagnostics) to “track time since last treatment initiation to inform whether later treatment is managed as treatment failure, with need for DST/second-line treatments, or as a new case.” Reads the durable, cross-regimen tb.ti_last_treatment written by every :class:TxDeliveryR at initiation.
Returns a sim -> uids eligibility callable selecting agents whose most recent treatment initiation was within within (an ss.dur) of the current step — i.e. to be managed as a treatment failure (route to DST / second-line). Pass new_case=True for the complement (agents with no treatment within the window → managed as a new case). base optionally restricts the candidate pool (default: current active TB), e.g. base=dst.matches(RIF=True).
Feed as eligibility= to a DST or TxDeliveryR (optionally via :func:eligibility_all)::
failed = TxDeliveryR.failure_case_eligibility(within=ss.years(2))
second_line = tbsim.TxDeliveryR(eligibility=failed, supersedes=['first'], product=...)
interrupt
resistance.treatments.TxDeliveryR.interrupt(uids)Prematurely stop this delivery’s ongoing courses for uids (treatment monitoring / switch).
Reverts interrupted agents to the state treatment was initiated from, keeping their current strains, so another delivery can re-treat them. Only agents actually on this delivery’s course (on_course) are affected — the flag is delivery-scoped, so a shared TREATMENT state never lets one delivery interrupt another delivery’s patients (#447).
step
resistance.treatments.TxDeliveryR.step()Resolve completed courses, then initiate new ones.
TxR
resistance.treatments.TxR(
strains,
base_efficacy=0.85,
resist_penalty=None,
efficacy_by_strain=None,
adherence=1.0,
q_acq=None,
acq_state_rr=None,
regimen_drugs=None,
**kwargs,
)Strain-aware treatment product.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| strains | Strains | the strain registry (e.g. tb.strains). |
required |
| base_efficacy | float | per-course cure probability for a treatment-susceptible strain. | 0.85 |
| resist_penalty | dict | per-drug multiplicative efficacy penalty applied for each regimen drug a strain is resistant to, e.g. {'TX': 0.333} gives a resistant strain 1/3 the cure probability. Resistance to a drug outside the regimen does not reduce efficacy. |
None |
| efficacy_by_strain | array | optional explicit per-strain cure-probability vector T_l = {t_1,l, ..., t_m,l} (length strains.m, spec §“Treatment efficacy”). When given it is the per-strain efficacy and base_efficacy/resist_penalty are ignored; use it when the constrained base × ∏penalty parameterization cannot express the desired vector. |
None |
| adherence | float or callable | per-course completion probability correlating outcomes across an agent’s strains (non-completers clear no strains this course). A float applies one regimen-level probability to every agent; a callable uids -> per-agent probability makes adherence a regimen-level distribution that varies by agent and is applied across all that agent’s strains (spec §“Treatment efficacy”), e.g. adherence=lambda uids: my_dist.rvs(uids). |
1.0 |
| q_acq | dict | per-drug probability {drug: prob} that a surviving treatment-susceptible strain acquires resistance to that regimen drug on a failed course (always replacement). Default none (off). |
None |
| acq_state_rr | dict | per-TB-state multiplier on q_acq at time of failure (spec’s RR on q). Default 1 for ASYMPTOMATIC/SYMPTOMATIC, 0 for all other states. |
None |
| regimen_drugs | list | drugs the regimen acts on; determines which strains can be cured/acquire resistance. Default: all drugs in strains. |
None |
Methods
| Name | Description |
|---|---|
| acquire_counts | Apply acquisition-on-failure (replacement) to the surviving counts of failed courses. |
| roll_survivors | Pre-roll the surviving strain mask for each treated agent (adherence, then per-strain cure). |
acquire_counts
resistance.treatments.TxR.acquire_counts(tb, uids, counts0, states=None)Apply acquisition-on-failure (replacement) to the surviving counts of failed courses.
Each surviving carried strain independently rolls, once per regimen drug it is susceptible to, whether it acquires that resistance (prob q_acq[drug] × the per-agent state RR acq_state_rr; default 0 outside ASYMPTOMATIC/SYMPTOMATIC). Hits mutate the strain to its resistant counterpart, transferring multiplicity source→target via :meth:TBResistant._apply_acquisition. Multiple strains may acquire resistance in one course.
Returns (counts, mask, n_events) for the treated agents.
roll_survivors
resistance.treatments.TxR.roll_survivors(tb, uids)Pre-roll the surviving strain mask for each treated agent (adherence, then per-strain cure).
Functions
| Name | Description |
|---|---|
| eligibility_all | Combinator (L5): return a sim -> uids selecting agents returned by all of callables |
| eligibility_any | Combinator (L5): return a sim -> uids selecting agents returned by any of callables |
| treatment_monitoring_eligibility | Eligibility callable selecting agents on tx_name’s course for at least after_steps steps. |
| will_fail | Eligibility factory (L5): on-treatment agents on tx_name whose pre-rolled course outcome is a |
eligibility_all
resistance.treatments.eligibility_all(*callables)Combinator (L5): return a sim -> uids selecting agents returned by all of callables (set intersection). E.g. eligibility_all(treatment_monitoring_eligibility('first'), dst.matches(RIF=True)) switches only agents that are both far enough into first-line and observed RIF-resistant.
eligibility_any
resistance.treatments.eligibility_any(*callables)Combinator (L5): return a sim -> uids selecting agents returned by any of callables (set union).
treatment_monitoring_eligibility
resistance.treatments.treatment_monitoring_eligibility(
tx_name,
after_steps=4,
every_steps=None,
require=None,
)Eligibility callable selecting agents on tx_name’s course for at least after_steps steps.
Feed as eligibility= to a monitoring DxDelivery (to flag still-bacteriologically-positive agents by TB state), or — combined with supersedes=[tx_name] on a second-line TxDeliveryR — to switch regimens mid-course (spec §“Treatment monitoring”).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| tx_name | str | the name of the TxDeliveryR to monitor. |
required |
| after_steps | int | minimum sim steps since ti_treatment_start before eligibility. Default 4. |
4 |
| every_steps | int / None | if given, re-test every N steps after the first; else a single test at after_steps. |
None |
| require | callable | optional additional sim -> uids AND-ed in (sugar over :func:eligibility_all), e.g. require=dst.matches(RIF=True, exclude_on_treatment=False) to make monitoring contingent on an observed DST profile (L5). Note monitored agents are on treatment, so pass exclude_on_treatment=False to a matches used here. |
None |
will_fail
resistance.treatments.will_fail(tx_name)Eligibility factory (L5): on-treatment agents on tx_name whose pre-rolled course outcome is a failure (pending_surv != 0). Because the outcome is frozen at initiation, this is an oracle — it selects agents whose course will fail before it completes — useful for constructing failure-contingent regimen-switch scenarios.