From 4ab5bc05fdc202e427aae7d128650c6214e57b85 Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 10:34:29 -0500 Subject: [PATCH 1/6] feat: allow ssp to influence hiv dx prob --- settings/scott/model.yml | 2 ++ tests/params/basic.yml | 1 + tests/params/simple_integration.yml | 1 + titan/model.py | 5 +++++ titan/params/syringe_services.yml | 5 +++++ 5 files changed, 14 insertions(+) diff --git a/settings/scott/model.yml b/settings/scott/model.yml index 2a578bf9..6243501f 100644 --- a/settings/scott/model.yml +++ b/settings/scott/model.yml @@ -27,12 +27,14 @@ syringe_services: num_slots_start: 0 num_slots_stop: 237 risk: 0.02 + dx_scalar: 1.195 ssp_on: start_time: 4 stop_time: 121 num_slots_start: 237 num_slots_stop: 237 risk: 0.02 + dx_scalar: 1.195 agent_zero: num_partners: 4 diff --git a/tests/params/basic.yml b/tests/params/basic.yml index b0957de7..a16d806b 100644 --- a/tests/params/basic.yml +++ b/tests/params/basic.yml @@ -862,6 +862,7 @@ syringe_services: num_slots_start: 100 num_slots_stop: 100 risk: 0.02 + dx_scalar: 1.0 agent_zero: bond_type: Inj diff --git a/tests/params/simple_integration.yml b/tests/params/simple_integration.yml index 865f237e..51041a65 100644 --- a/tests/params/simple_integration.yml +++ b/tests/params/simple_integration.yml @@ -191,6 +191,7 @@ syringe_services: num_slots_start: 500 num_slots_stop: 500 risk: 0.00 + dx_scalar: 1.0 partner_tracing: prob: 1 diff --git a/titan/model.py b/titan/model.py index e7fa3544..bff6427c 100644 --- a/titan/model.py +++ b/titan/model.py @@ -70,6 +70,7 @@ def __init__( self.new_prep = AgentSet("new_prep") self.ssp_enrolled_risk = 0.0 + self.ssp_dx = 1.0 self.time = -1 * self.params.model.time.burn_steps # burn is negative time self.id = nanoid.generate(size=8) @@ -899,6 +900,7 @@ def update_syringe_services(self): for item in self.params.syringe_services.timeline.values(): if item.start_time <= self.time < item.stop_time: self.ssp_enrolled_risk = item.risk + self.ssp_dx = item.dx_scalar ssp_num_slots = (item.num_slots_stop - item.num_slots_start) / ( item.stop_time - item.start_time @@ -1102,6 +1104,9 @@ def diagnose( sex_type ].hiv.dx.prob + if agent.ssp: + test_prob *= self.ssp_dx + # Rescale based on calibration param test_prob *= self.calibration.test_frequency diff --git a/titan/params/syringe_services.yml b/titan/params/syringe_services.yml index 8f258ff5..96609398 100644 --- a/titan/params/syringe_services.yml +++ b/titan/params/syringe_services.yml @@ -23,6 +23,10 @@ syringe_services: description: "Risk of unsafe sharing for agents enrolled in the SSP" min: 0.0 max: 1.0 + dx_scalar: + type: float + description: "Diagnosis scalar for HIV+ agents enrolled in ssp" + min: 0.0 default: ssp_default: start_time: 1 @@ -30,3 +34,4 @@ syringe_services: num_slots_start: 0 num_slots_stop: 0 risk: 0.02 + dx_scalar: 1.0 From 66ccad26926909dd4c8c3889cb46d300caf638bc Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 10:38:09 -0500 Subject: [PATCH 2/6] style: style with black --- titan/agent.py | 4 +--- titan/model.py | 19 ++++++++----------- titan/network.py | 8 ++------ 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/titan/agent.py b/titan/agent.py index 5f234945..d1206d1a 100644 --- a/titan/agent.py +++ b/titan/agent.py @@ -505,9 +505,7 @@ class AgentSet: """ def __init__( - self, - id: str, - parent: Optional["AgentSet"] = None, + self, id: str, parent: Optional["AgentSet"] = None, ): """ Constructor of an AgentSet diff --git a/titan/model.py b/titan/model.py index bff6427c..987c6b6b 100644 --- a/titan/model.py +++ b/titan/model.py @@ -28,9 +28,7 @@ def __repr__(self): return res def __init__( - self, - params: ObjMap, - population: Optional[Population] = None, + self, params: ObjMap, population: Optional[Population] = None, ): """ This is the core class used to simulate @@ -1078,9 +1076,7 @@ def diagnose_hiv(self, agent: Agent): diagnosed = agent.hiv_dx partner_tracing = agent.location.params.partner_tracing - def diagnose( - agent, - ): + def diagnose(agent,): # agent's location's params used throughout as that is the agent who # would be interacting with the service agent.hiv_dx = True @@ -1106,7 +1102,7 @@ def diagnose( if agent.ssp: test_prob *= self.ssp_dx - + # Rescale based on calibration param test_prob *= self.calibration.test_frequency @@ -1284,10 +1280,11 @@ def enroll_prep(self, agent: Agent): hiv_agents = len(all_hiv_agents & all_race) target_prep = ( - len(all_race) - hiv_agents - ) * agent.location.params.demographics[agent.race][ - agent.sex_type - ].prep.coverage + (len(all_race) - hiv_agents) + * agent.location.params.demographics[agent.race][ + agent.sex_type + ].prep.coverage + ) else: num_prep_agents = sum(self.pop.prep_counts.values()) diff --git a/titan/network.py b/titan/network.py index 653fbc0f..6169ba18 100644 --- a/titan/network.py +++ b/titan/network.py @@ -250,12 +250,8 @@ def visualize_network( textstr = "\n".join( ( - r"N infection={:.2f}".format( - infection_label, - ), - r"Time={:.2f}".format( - curtime, - ), + r"N infection={:.2f}".format(infection_label,), + r"Time={:.2f}".format(curtime,), ) ) From 26cb060fe7e317d4bb34e59773edf8d149f8cc49 Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 10:52:42 -0500 Subject: [PATCH 3/6] style: fix weird black-introduced format errors --- titan/agent.py | 4 +++- titan/model.py | 13 +++++++------ titan/network.py | 8 ++++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/titan/agent.py b/titan/agent.py index d1206d1a..5f234945 100644 --- a/titan/agent.py +++ b/titan/agent.py @@ -505,7 +505,9 @@ class AgentSet: """ def __init__( - self, id: str, parent: Optional["AgentSet"] = None, + self, + id: str, + parent: Optional["AgentSet"] = None, ): """ Constructor of an AgentSet diff --git a/titan/model.py b/titan/model.py index 987c6b6b..ff76432f 100644 --- a/titan/model.py +++ b/titan/model.py @@ -28,7 +28,9 @@ def __repr__(self): return res def __init__( - self, params: ObjMap, population: Optional[Population] = None, + self, + params: ObjMap, + population: Optional[Population] = None, ): """ This is the core class used to simulate @@ -1280,11 +1282,10 @@ def enroll_prep(self, agent: Agent): hiv_agents = len(all_hiv_agents & all_race) target_prep = ( - (len(all_race) - hiv_agents) - * agent.location.params.demographics[agent.race][ - agent.sex_type - ].prep.coverage - ) + len(all_race) - hiv_agents + ) * agent.location.params.demographics[agent.race][ + agent.sex_type + ].prep.coverage else: num_prep_agents = sum(self.pop.prep_counts.values()) diff --git a/titan/network.py b/titan/network.py index 6169ba18..653fbc0f 100644 --- a/titan/network.py +++ b/titan/network.py @@ -250,8 +250,12 @@ def visualize_network( textstr = "\n".join( ( - r"N infection={:.2f}".format(infection_label,), - r"Time={:.2f}".format(curtime,), + r"N infection={:.2f}".format( + infection_label, + ), + r"Time={:.2f}".format( + curtime, + ), ) ) From e5cb1db9014f002e6920299949c1d86f744b69cf Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 10:58:58 -0500 Subject: [PATCH 4/6] style: more weird black differences between local and remote --- titan/model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/titan/model.py b/titan/model.py index ff76432f..2d8e00b2 100644 --- a/titan/model.py +++ b/titan/model.py @@ -1078,7 +1078,9 @@ def diagnose_hiv(self, agent: Agent): diagnosed = agent.hiv_dx partner_tracing = agent.location.params.partner_tracing - def diagnose(agent,): + def diagnose( + agent, + ): # agent's location's params used throughout as that is the agent who # would be interacting with the service agent.hiv_dx = True From a95109041c63ce33027a2be424d17093361bd0f5 Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 12:16:13 -0500 Subject: [PATCH 5/6] refactor: remove unused matplotlib --- titan/model.py | 4 -- titan/network.py | 119 ----------------------------------------------- 2 files changed, 123 deletions(-) diff --git a/titan/model.py b/titan/model.py index 2d8e00b2..197d7cb1 100644 --- a/titan/model.py +++ b/titan/model.py @@ -114,10 +114,6 @@ def print_stats(self, stat: Dict[str, Dict[str, int]], outdir: str): ), "Graph must be enabled to print network reports" network_outdir = os.path.join(outdir, "network") - if self.params.outputs.network.draw_figures: - self.network_utils.visualize_network( - network_outdir, curtime=self.time, label=f"{self.id}" - ) if self.params.outputs.network.calc_component_stats: ao.print_components( diff --git a/titan/network.py b/titan/network.py index 653fbc0f..987ca220 100644 --- a/titan/network.py +++ b/titan/network.py @@ -6,8 +6,6 @@ import networkx as nx # type: ignore from networkx.drawing.nx_agraph import graphviz_layout # type: ignore -import matplotlib.pyplot as plt # type: ignore -import matplotlib.patches as patches # type: ignore class NetworkGraphUtils: @@ -164,120 +162,3 @@ def get_network_color(self, coloring) -> List[str]: return node_color - def visualize_network( - self, - outdir: str, - coloring: str = "sex_type", - pos=None, - return_layout: bool = False, - node_size: Optional[float] = None, - curtime: int = 0, - infection_label: int = 0, - label: str = "Network", - ): - """ - Visualize the network using the spring layout (default). - - args: - outdir: directory the figure should be saved to - coloring: what attribute to color the nodes by - pos: a graphviz_layout - return_layout: whether to return the layout (if `False`, nothing is returned) - node_size: size of the nodes in the graph - curtime: the current timestep of the model - infection_label: number of infections to list in figure's label - label: identifier for this network - """ - if node_size is None: - node_size = 5000.0 / self.G.number_of_nodes() - - print(("\tPlotting {} colored by {}...").format(label, coloring)) - fig = plt.figure() - ax = fig.add_axes([0, 0, 1, 1]) - fig.clf() - - # build a rectangle in axes coords - left, width = 0.0, 1.0 - bottom, height = 0.0, 1.0 - right = left + width - top = bottom + height - - fig = plt.figure() - ax = fig.add_axes([0, 0, 1, 1]) - - # axes coordinates are 0,0 is bottom left and 1,1 is upper right - p = patches.Rectangle( - (left, bottom), - width, - height, - fill=False, - transform=ax.transAxes, - clip_on=False, - ) - - ax.add_patch(p) - - if not pos: - pos = graphviz_layout(self.G, prog="neato", args="") - - edge_color = "k" - node_shape = "o" - - # node color to by type - node_color = self.get_network_color(coloring) - - # node size indicating node degree - NodeSize = [] - if node_size: - for v in self.G: - NodeSize.append(node_size) - else: - for v in self.G: - NodeSize.append((10 * self.G.degree(v)) ** (1.0)) - - # draw: - nx.draw( - self.G, - pos, - node_size=NodeSize, - node_color=node_color, - node_shape=node_shape, - edge_color=edge_color, - with_labels=False, - linewidths=0.5, - width=0.5, - ) - - textstr = "\n".join( - ( - r"N infection={:.2f}".format( - infection_label, - ), - r"Time={:.2f}".format( - curtime, - ), - ) - ) - - # these are matplotlib.patch.Patch properties - props = dict(boxstyle="round", facecolor="wheat", alpha=0.9) - - # place a text box in upper right in axes coords - ax.text( - right - 0.025, - top - 0.025, - textstr, - horizontalalignment="right", - verticalalignment="top", - transform=ax.transAxes, - bbox=props, - ) - - filename = os.path.join( - outdir, f"{label}_{self.G.number_of_nodes()}_{coloring}_{curtime}.png" - ) - - fig.savefig(filename) - - if return_layout: - return pos From 58773f78cba1aea247ffc206d754a9906076e6a3 Mon Sep 17 00:00:00 2001 From: s-bessey Date: Mon, 20 Dec 2021 12:22:42 -0500 Subject: [PATCH 6/6] style --- titan/network.py | 1 - 1 file changed, 1 deletion(-) diff --git a/titan/network.py b/titan/network.py index 987ca220..2aed2f10 100644 --- a/titan/network.py +++ b/titan/network.py @@ -161,4 +161,3 @@ def get_network_color(self, coloring) -> List[str]: ) return node_color -