HIV
agents: Set[titan.agent.Agent]
Agents with active hiv
dx_counts: Dict[str, Dict[str, int]]
Counts of diagnosed agents by race and sex_type
name: str
Name of exposure in the params file. Also used to name the attribute in Agent
stats: List[str]
HIV collects the following stats:
- hiv - number of agents with active hiv
- hiv_dx - number of agents with diagnosed hiv
- hiv_aids - number of agents with aids
- hiv_new - number of agents converted to hiv this timestep
- hiv_dx_new - number of agents with diagnosed with hiv this timestep
add_agent(agent)
classmethod
Add an agent to the class (not instance). This can be useful if tracking population level statistics or groups, such as counts or newly active agents.
Add the agent to the agents
set and if the agent is diagnosed, updated the dx_counts
Parameters:
Name | Type | Description | Default |
---|---|---|---|
agent |
agent.Agent |
the agent to add to the class attributes |
required |
Source code in titan/exposures/hiv.py
@classmethod
def add_agent(cls, agent: "agent.Agent"):
"""
Add an agent to the class (not instance). This can be useful if tracking population level statistics or groups, such as counts or newly active agents.
Add the agent to the `agents` set and if the agent is diagnosed, updated the `dx_counts`
args:
agent: the agent to add to the class attributes
"""
cls.agents.add(agent)
if agent.hiv.dx: # type: ignore[attr-defined]
cls.dx_counts[agent.race][agent.sex_type] += 1
convert(self, model)
Agent becomes HIV agent. Update all appropriate attributes, sets and dictionaries.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
The model being run |
required |
Source code in titan/exposures/hiv.py
def convert(self, model: "model.TITAN"):
"""
Agent becomes HIV agent. Update all appropriate attributes, sets and dictionaries.
args:
model: The model being run
"""
if not self.active:
self.active = True
self.time = model.time
self.agent.vaccine.active = False # type: ignore[attr-defined]
self.add_agent(self.agent)
if self.agent.prep.active: # type: ignore[attr-defined]
self.agent.prep.progress(model, force=True) # type: ignore[attr-defined]
diagnose(self, model)
Mark the agent as diagnosed.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
the running model |
required |
Source code in titan/exposures/hiv.py
def diagnose(self, model: "model.TITAN"):
"""
Mark the agent as diagnosed.
args:
model: the running model
"""
self.dx = True
self.dx_time = model.time
self.add_agent(self.agent)
expose(model, interaction, rel, num_acts)
staticmethod
Expose a relationship to the exposure for a number of acts of a specific interaction type. Typically, this is determining if the exposure can cause conversion/change in one of the agents, then if so determining the probability of that and then converting the succeptible agent.
For hiv, one agent must be active and the other not for an exposure to cause conversion.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
The running model |
required |
interaction |
str |
The type of interaction (e.g. sex, injection) |
required |
rel |
agent.Relationship |
The relationship where the interaction is occuring |
required |
num_acts |
int |
The number of acts of that interaction |
required |
Source code in titan/exposures/hiv.py
@staticmethod
def expose(
model: "model.TITAN",
interaction: str,
rel: "agent.Relationship",
num_acts: int,
):
"""
Expose a relationship to the exposure for a number of acts of a specific interaction type. Typically, this is determining if the exposure can cause conversion/change in one of the agents, then if so determining the probability of that and then converting the succeptible agent.
For hiv, one agent must be active and the other not for an exposure to cause conversion.
args:
model: The running model
interaction: The type of interaction (e.g. sex, injection)
rel: The relationship where the interaction is occuring
num_acts: The number of acts of that interaction
"""
# Agent 1 is HIV+, Agent 2 is not, Agent 2 is succept
if rel.agent1.hiv.active and not rel.agent2.hiv.active: # type: ignore[attr-defined]
agent = rel.agent1
partner = rel.agent2
# If Agent 2 is HIV and Agent 1 is not, Agent 1 is succept
elif not rel.agent1.hiv.active and rel.agent2.hiv.active: # type: ignore[attr-defined]
agent = rel.agent2
partner = rel.agent1
else: # neither agent is HIV or both are
return
p = agent.hiv.get_transmission_probability( # type: ignore[attr-defined]
model, interaction, partner, num_acts
)
if model.run_random.random() < p:
# if agent HIV+ partner becomes HIV+
partner.hiv.convert(model) # type: ignore[attr-defined]
get_acute_status(self, time)
Get acute status of agent at time
Parameters:
Name | Type | Description | Default |
---|---|---|---|
time |
int |
The current time step |
required |
Returns:
Type | Description |
---|---|
bool |
whether an agent is acute |
Source code in titan/exposures/hiv.py
def get_acute_status(self, time: int) -> bool:
"""
Get acute status of agent at time
args:
time: The current time step
returns:
whether an agent is acute
"""
if self.active and self.time is not None:
hiv_duration = time - self.time
if self.agent.location.params.hiv.acute.duration >= hiv_duration >= 0:
return True
return False
get_transmission_probability(self, model, interaction, partner, num_acts)
Determines the probability of an hiv transmission event from agent to partner based on interaction type and numer of acts. For sex acts, transmission probability is a function of the acquisition probability of the HIV- agent's sex role and the HIV+ agent's haart adherence, acute status, and dx risk reduction
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
The running model |
required |
interaction |
str |
"injection" or "sex" |
required |
partner |
agent.Agent |
HIV- Agent |
required |
num_acts |
int |
The number of exposure interactions the agents had this time step |
required |
Returns:
Type | Description |
---|---|
float |
probability of transmission from agent to partner |
Source code in titan/exposures/hiv.py
def get_transmission_probability(
self,
model: "model.TITAN",
interaction: str,
partner: "agent.Agent",
num_acts: int,
) -> float:
"""
Determines the probability of an hiv transmission event from agent to partner based on
interaction type and numer of acts. For sex acts, transmission probability is a
function of the acquisition probability of the HIV- agent's sex role
and the HIV+ agent's haart adherence, acute status, and dx risk reduction
args:
model: The running model
interaction : "injection" or "sex"
partner: HIV- Agent
num_acts: The number of exposure interactions the agents had this time step
returns:
probability of transmission from agent to partner
"""
# if this isn't an interaction where hiv can transmit, return 0% prob
if interaction not in ("injection", "sex"):
return 0.0
# Logic for if needle or sex type interaction
p: float
# get baseline probabilities
if interaction == "injection":
p = model.params.partnership.injection.transmission.base
elif interaction == "sex":
agent_sex_role = self.agent.sex_role
partner_sex_role = partner.sex_role
# get partner's sex role during acts
if partner_sex_role == "versatile": # versatile partner takes
# "opposite" position of agent
if agent_sex_role == "insertive":
partner_sex_role = "receptive"
elif agent_sex_role == "receptive":
partner_sex_role = "insertive"
else:
partner_sex_role = "versatile" # if both versatile, can switch
# between receptive and insertive by act
# get probability of sex acquisition given HIV- partner's position
p = partner.location.params.partnership.sex.acquisition[partner.sex_type][
partner_sex_role
]
# feature specific risk adjustment
for feature in model.features:
agent_feature = getattr(self.agent, feature.name)
p *= agent_feature.get_transmission_risk_multiplier(self.time, interaction)
partner_feature = getattr(partner, feature.name)
p *= partner_feature.get_acquisition_risk_multiplier(self.time, interaction)
# Scaling parameter for acute HIV infections
if self.get_acute_status(model.time):
p *= self.agent.location.params.hiv.acute.infectivity
# Scaling parameter for positively identified HIV agents
if self.dx:
p *= 1 - self.agent.location.params.hiv.dx.risk_reduction[interaction]
# Racial calibration parameter to attain proper race incidence disparity
p *= partner.location.params.demographics[partner.race].hiv.transmission
# Scaling parameter for per act transmission.
p *= model.calibration.acquisition
return utils.total_probability(p, num_acts)
init_agent(self, pop, time)
Initialize the agent for this exposure during population initialization (Population.create_agent
). Called on only exposures that are enabled per the params.
Based on demographic params for the agent, stochastically determine if hiv is active, and if active, at what past time point was the agent converted, if the agent is diagnosed, and if the agent has aids.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
pop |
population.Population |
the population this agent is a part of |
required |
time |
int |
the current time step |
required |
Source code in titan/exposures/hiv.py
def init_agent(self, pop: "population.Population", time: int):
"""
Initialize the agent for this exposure during population initialization (`Population.create_agent`). Called on only exposures that are enabled per the params.
Based on demographic params for the agent, stochastically determine if hiv is active, and if active, at what past time point was the agent converted, if the agent is diagnosed, and if the agent has aids.
args:
pop: the population this agent is a part of
time: the current time step
"""
agent_params = (
self.agent.location.params.demographics[self.agent.race]
.sex_type[self.agent.sex_type]
.drug_type[self.agent.drug_type]
)
# HIV
if (
pop.pop_random.random() < agent_params.hiv.init
and time >= pop.params.hiv.start_time
):
self.active = True
# if HIV, when did the agent convert? Random sample
self.time = utils.safe_random_int(
time - self.agent.location.params.hiv.max_init_time,
time,
pop.pop_random,
)
if pop.pop_random.random() < agent_params.hiv.aids.init:
self.aids = True
if pop.pop_random.random() < agent_params.hiv.dx.init:
self.dx = True
# agent was diagnosed at a random time between conversion and now
self.dx_time = utils.safe_random_int(self.time, time, pop.pop_random)
# add agent to class
self.add_agent(self.agent)
init_class(params)
classmethod
Initialize any diagnosis counts and the agents set.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
params |
|
parameters for this population |
required |
Source code in titan/exposures/hiv.py
@classmethod
def init_class(cls, params):
"""
Initialize any diagnosis counts and the agents set.
args:
params: parameters for this population
"""
cls.dx_counts = {
race: {so: 0 for so in params.classes.sex_types}
for race in params.classes.races
}
cls.agents = set()
progress_to_aids(self, model)
Model the progression of HIV agents to AIDS agents
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
the running model |
required |
Source code in titan/exposures/hiv.py
def progress_to_aids(self, model: "model.TITAN"):
"""
Model the progression of HIV agents to AIDS agents
args:
model: the running model
"""
aids_prob = self.agent.location.params.hiv.aids.prob
p = self.agent.haart.aids_scale() # type: ignore[attr-defined]
if model.run_random.random() < p * aids_prob:
self.aids = True
remove_agent(agent)
classmethod
Remove an agent from the class (not instance). This can be useful if tracking population level statistics or groups, such as counts.
Remove the agent from the agents
set and decrement the dx_counts
if the agent was diagnosed.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
agent |
agent.Agent |
the agent to remove from the class attributes |
required |
Source code in titan/exposures/hiv.py
@classmethod
def remove_agent(cls, agent: "agent.Agent"):
"""
Remove an agent from the class (not instance). This can be useful if tracking population level statistics or groups, such as counts.
Remove the agent from the `agents` set and decrement the `dx_counts` if the agent was diagnosed.
args:
agent: the agent to remove from the class attributes
"""
cls.agents.remove(agent)
if agent.hiv.dx: # type: ignore[attr-defined]
cls.dx_counts[agent.race][agent.sex_type] -= 1
set_stats(self, stats, time)
Update the stats
dictionary passed for this agent. Called from output.get_stats
for each enabled exposure in the model.
The stats to be updated must be declared in the class attribute stats
to make sure the dictionary has the expected keys/counter value initialized.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
stats |
Dict[str, int] |
the dictionary to update with this agent's feature statistics |
required |
time |
int |
the time step of the model when the stats are set |
required |
Source code in titan/exposures/hiv.py
def set_stats(self, stats: Dict[str, int], time: int):
if self.active:
stats["hiv"] += 1
if self.time == time:
stats["hiv_new"] += 1
if self.aids:
stats["hiv_aids"] += 1
if self.dx:
stats["hiv_dx"] += 1
if self.dx_time == time:
stats["hiv_dx_new"] += 1
update_agent(self, model)
Update the agent for this exposure for a time step. Called once per time step in TITAN.update_all_agents
. Agent level updates are done after population level updates. Called on only exposures that are enabled per the params.
If the agent is hiv+ and the model time is past the hiv start_time, determine if the agent becomes diagnosed if not yet diagnosed, and if the agent has progressed to aids.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
model.TITAN |
the instance of TITAN currently being run |
required |
Source code in titan/exposures/hiv.py
def update_agent(self, model: "model.TITAN"):
"""
Update the agent for this exposure for a time step. Called once per time step in `TITAN.update_all_agents`. Agent level updates are done after population level updates. Called on only exposures that are enabled per the params.
If the agent is hiv+ and the model time is past the hiv start_time, determine if the agent becomes diagnosed if not yet diagnosed, and if the agent has progressed to aids.
args:
model: the instance of TITAN currently being run
"""
if self.active and model.time >= model.params.hiv.start_time:
if not self.dx:
test_prob = (
self.agent.location.params.demographics[self.agent.race]
.sex_type[self.agent.sex_type]
.drug_type[self.agent.drug_type]
.hiv.dx.prob
)
# Rescale based on calibration param
test_prob *= model.calibration.test_frequency
if model.run_random.random() < test_prob:
self.diagnose(model)
self.progress_to_aids(model)