Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into partner-services
Browse files Browse the repository at this point in the history
  • Loading branch information
alrah007 committed Aug 9, 2024
2 parents 8688fc5 + c3ea2b2 commit 9b06539
Show file tree
Hide file tree
Showing 10 changed files with 1,343 additions and 162 deletions.
1,015 changes: 934 additions & 81 deletions poetry.lock

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "titan-model"
version = "3.3.0"
version = "3.3.2"
description = "TITAN Agent Based Model"
license = "GPL-3.0-only"
authors = ["Sam Bessey <[email protected]>", "Mary McGrath <[email protected]>"]
Expand All @@ -12,18 +12,22 @@ classifiers = ["Operating System :: OS Independent"]
packages = [{ include = "titan" }]

[tool.poetry.dependencies]
<<<<<<< HEAD
python = "^3.8"
=======
python = "^3.9"
>>>>>>> origin/main
paraml= "^0.1"
networkx = "^2.4"
nanoid = "^2.0"
numpy = "^1.18"
numpy = "^1.26"
black = {version = "^23.1.0", optional = true}
flake8 = {version = "^3.8", optional = true}
mypy = {version = "^1.0.0", optional = true}
mkdocs = {version = "^1.1", optional = true}
mkdocs-material = {version = "^7.0", optional = true}
mkdocstrings = {version = "^0.15.0", optional = true}
mkdocs = {version = "^1.2.4", optional = true}
oyaml = "^1.0"
mkdocstrings = {version = "^0.25.1", extras = ["python"], optional = true}
mkdocs-material = {version = "^9.5.26", optional = true}

[tool.poetry.dev-dependencies]
pytest = "^6.2"
Expand Down
2 changes: 1 addition & 1 deletion tests/params/basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ features:
timeline_scaling: true

model:
num_pop: 100
num_pop: 1000
network:
enable: true
num_reps: 1
Expand Down
53 changes: 34 additions & 19 deletions titan/exposures/hiv.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class HIV(base_exposure.BaseExposure):
name: str = "hiv"
stats: List[str] = ["hiv", "hiv_dx", "hiv_aids", "hiv_new", "hiv_dx_new"]
stats: List[str] = ["hiv", "hiv_dx", "hiv_aids", "hiv_new", "hiv_dx_new", "hiv_tested_negative_new"]
"""
HIV collects the following stats:
Expand All @@ -34,7 +34,9 @@ def __init__(self, agent: "agent.Agent"):
self.dx = False
self.dx_time: Optional[int] = None
self.aids = False

self.tested_negative = False #has this agent tested negative for hiv?
self.tested_negative_time = None #time agent tested negative

@classmethod
def init_class(cls, params):
"""
Expand Down Expand Up @@ -67,7 +69,7 @@ def init_agent(self, pop: "population.Population", time: int):

# HIV
if (
pop.pop_random.random() < agent_params.hiv.init
pop.pop_random.random() < agent_params.hiv.init #0.13 for white, 0.175 for latino and 0.434 for blacks
and time >= pop.params.hiv.start_time
):
self.active = True
Expand All @@ -82,7 +84,7 @@ def init_agent(self, pop: "population.Population", time: int):
if pop.pop_random.random() < agent_params.hiv.aids.init:
self.aids = True

if pop.pop_random.random() < agent_params.hiv.dx.init:
if pop.pop_random.random() < agent_params.hiv.dx.init: #0.6 - 0.8 depending on race
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)
Expand All @@ -99,23 +101,34 @@ def update_agent(self, model: "model.TITAN"):
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)

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 #freq is 1 so test_prob remains at 0.025

if (
model.run_random.random() < test_prob
and not self.dx # has not yet been diagnosed
):
if self.active and model.time >= model.params.hiv.start_time:
self.diagnose(model)
else:
self.tested_negative = True
self.tested_negative_time = model.time

if self.tested_negative and self.tested_negative_time < model.time:
self.tested_negative = False
self.tested_negative_time = None

@classmethod
def add_agent(cls, agent: "agent.Agent"):
"""
Expand Down Expand Up @@ -157,7 +170,9 @@ def set_stats(self, stats: Dict[str, int], time: int):
stats["hiv_dx"] += 1
if self.dx_time == time:
stats["hiv_dx_new"] += 1

if self.tested_negative and self.tested_negative_time == time:
stats["hiv_tested_negative_new"] += 1

@staticmethod
def expose(
model: "model.TITAN",
Expand Down
55 changes: 47 additions & 8 deletions titan/features/haart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class HAART(base_feature.BaseFeature):
"""

name = "haart"
stats = ["haart"]
stats = ["haart", "ps_haart_count"]
"""
HAART collects the following stats:
Expand All @@ -28,7 +28,7 @@ def __init__(self, agent: "agent.Agent"):
self.active = False
self.ever = False
self.adherent = False

@classmethod
def init_class(cls, params: "ObjMap"):
"""
Expand All @@ -41,6 +41,8 @@ def init_class(cls, params: "ObjMap"):
race: {sex_type: 0 for sex_type in params.classes.sex_types}
for race in params.classes.races
}

cls.ps_haart_count = 0

def init_agent(self, pop: "population.Population", time: int):
"""
Expand Down Expand Up @@ -132,10 +134,25 @@ def remove_agent(cls, agent: "agent.Agent"):
"""
cls.counts[agent.race][agent.sex_type] -= 1

@classmethod
def ps_add_stat(cls):
cls.ps_haart_count += 1

@classmethod
def ps_remove_stat(cls): # do we subtract agents who stop using haart?
pass
#cls.ps_haart_count -= 1

@classmethod
def ps_get_stat(cls):
return cls.ps_haart_count

def set_stats(self, stats: Dict[str, int], time: int):
if self.active:
stats["haart"] += 1


stats["ps_haart_count"] = self.ps_get_stat()

def get_transmission_risk_multiplier(self, time: int, interaction_type: str):
"""
Get a multiplier for how haart reduces hiv transmission risk based on interaction type and params.
Expand Down Expand Up @@ -182,6 +199,7 @@ def enroll(self, model: "model.TITAN", haart_params: ObjMap):
model: the instance of TITAN currently being run
haart_params: the HAART demographic params for this agent
"""

if self.agent.location.params.haart.use_cap:
self.enroll_cap(model, haart_params)
else:
Expand All @@ -201,11 +219,22 @@ def enroll_cap(self, model: "model.TITAN", haart_params: ObjMap):
# HAART agents based on % of diagnosed agents
num_dx_agents = self.agent.hiv.dx_counts[race][sex_type] # type: ignore[attr-defined]
num_haart_agents = self.counts[race][sex_type]

# take value from dictionary for cap
if num_haart_agents < (haart_params.cap * num_dx_agents):
self.initiate(model.run_random, haart_params, "prob")


# if agent is diagnosed through PS, use PS parameter
if self.agent.partner_tracing.ps_dx:
cap = self.agent.partner_tracing.get_positive_count() * self.agent.location.params.partner_tracing.treatment_prob
# initiate agent only if required capacity is not yet met
if self.ps_get_stat() < cap:
self.initiate(model.run_random, haart_params, "prob")
self.ps_add_stat()

# else, use base parameter
else:
cap = haart_params.cap
# initiate agent only if required capacity is not yet met
if num_haart_agents < (cap * num_dx_agents):
self.initiate(model.run_random, haart_params, "prob")

def enroll_prob(self, model: "model.TITAN", haart_params: ObjMap):
"""
Determine whether to enroll an agent in HAART using probability method.
Expand All @@ -214,9 +243,19 @@ def enroll_prob(self, model: "model.TITAN", haart_params: ObjMap):
model: the instance of TITAN currently being run
haart_params: the HAART demographic params for this agent
"""
# if agent has ever been on haart and use_reinit is true, use reinit probability
if self.ever and self.agent.location.params.haart.use_reinit:
if model.run_random.random() < haart_params.reinit.prob:
self.initiate(model.run_random, haart_params, "prob")

# if agent has been diagnosed through PS, use PS treatment (haart) probability
elif self.agent.partner_tracing.ps_dx:
enroll_prob = self.agent.location.params.partner_tracing.treatment_prob
if model.run_random.random() < enroll_prob:
self.initiate(model.run_random, haart_params, "prob")
self.ps_add_stat()

# else, use normal base probability scaled by time since diagnoses
else:
# Find enroll probability based on time since diagnosis
enroll_prob = 0.0
Expand Down
Loading

0 comments on commit 9b06539

Please sign in to comment.