def test_agent_pop_stable_setting(tmpdir): """ Agent population count stable across time """ param_file = os.path.join( os.path.dirname(os.path.abspath(__file__)), "params", "integration_base.yml" ) for item in os.listdir( os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "titan", "settings" ) ): if "__" not in item and item != "base": path = tmpdir.mkdir(item) os.mkdir(os.path.join(path, "network")) print(f"-----------Starting run for {item}-----------") params = create_params(item, param_file, tmpdir) model = TITAN(params) orig_pop = model.pop.all_agents.num_members() assert orig_pop == params.model.num_pop model.run(path) assert model.pop.all_agents.num_members() == orig_pop
def test_prep_coverage(make_model_integration, tmpdir): """ If we increase the target of prep coverage, does the incidence of hiv decrease? """ path_a = tmpdir.mkdir("a") path_a.mkdir("network") path_b = tmpdir.mkdir("b") path_b.mkdir("network") model_a = make_model_integration() model_a.run(path_a) # change the coverage upward for creating model b, use same seeds model_a.params.prep.cap = 0.9 model_a.params.prep.init = 0.9 model_a.params.model.seed.run = model_a.run_seed model_a.params.model.seed.ppl = model_a.pop.pop_seed model_b = TITAN(model_a.params) model_b.run(path_b) print( f"model b prep world cap: {model_b.pop.geography.locations['world'].params.prep.cap}" ) result_file_a = os.path.join(path_a, "basicReport.txt") result_file_b = os.path.join(path_b, "basicReport.txt") assert os.path.isfile(result_file_a) with open(result_file_a, newline="") as fa, open(result_file_b, newline="") as fb: reader_a = csv.DictReader(fa, delimiter="\t") res_a = {} for row in reader_a: if row["t"] not in res_a: res_a[row["t"]] = {"hiv": 0, "prep": 0} res_a[row["t"]]["hiv"] += float(row["hiv"]) res_a[row["t"]]["prep"] += float(row["hiv"]) reader_b = csv.DictReader(fb, delimiter="\t") res_b = {} for row in reader_b: if row["t"] not in res_b: res_b[row["t"]] = {"hiv": 0, "prep": 0} res_b[row["t"]]["hiv"] += float(row["hiv"]) res_b[row["t"]]["prep"] += float(row["prep"]) # at start, should be similar t0_hiv_a = res_a["0"]["hiv"] t0_hiv_b = res_b["0"]["hiv"] t0_diff = t0_hiv_a - t0_hiv_b assert math.isclose(t0_hiv_a, t0_hiv_b, abs_tol=15) # within 15 agents assert res_a["0"]["prep"] < res_b["0"]["prep"] # at end, should be different t10_hiv_a = res_a["10"]["hiv"] t10_hiv_b = res_b["10"]["hiv"] t10_diff = t10_hiv_a - t10_hiv_b # a should be higher assert res_a["10"]["prep"] < res_b["10"]["prep"] assert t10_hiv_a > t0_hiv_a assert t10_diff > t0_diff
def test_target_partners(make_model_integration, tmpdir): """ If we increase the number of target partners, does the number of actual partners increase? """ model_a = make_model_integration() model_a.params.outputs.network.edge_list = True path_a = tmpdir.mkdir("a") path_a.mkdir("network") path_b = tmpdir.mkdir("b") path_b.mkdir("network") # run with default bins (0-9) run_id_a = model_a.id model_a.run(path_a) # change the partner distribution mean upward for creating model b for bond in model_a.params.classes.bond_types: model_a.params.demographics.black.sex_type.MSM.drug_type["None"].num_partners[ bond ].vars[1].value *= 10 model_a.params.demographics.black.sex_type.MSM.drug_type["Inj"].num_partners[ bond ].vars[1].value *= 10 model_a.params.model.seed.run = model_a.run_seed model_a.params.model.seed.ppl = model_a.pop.pop_seed model_b = TITAN(model_a.params) run_id_b = model_b.id model_b.run(path_b) g_a_0 = nx.read_edgelist( os.path.join(path_a, "network", f"{run_id_a}_Edgelist_t0.txt"), delimiter="|", data=False, ) g_a_10 = nx.read_edgelist( os.path.join(path_a, "network", f"{run_id_a}_Edgelist_t10.txt"), delimiter="|", data=False, ) g_b_0 = nx.read_edgelist( os.path.join(path_b, "network", f"{run_id_b}_Edgelist_t0.txt"), delimiter="|", data=False, ) g_b_10 = nx.read_edgelist( os.path.join(path_b, "network", f"{run_id_b}_Edgelist_t10.txt"), delimiter="|", data=False, ) # should be at least 2x bigger assert (g_a_0.number_of_edges() * 1.5) < g_b_0.number_of_edges() assert (g_a_10.number_of_edges() * 1.5) < g_b_10.number_of_edges()
def single_run(sweep, outfile_dir, params, save_pop, pop_path): """ A single run of titan. Dispatched from main using parallel processes. """ pid = str(os.getpid()) pid_outfile_dir = os.path.join(outfile_dir, pid) save_pop_dir = (os.path.join(pid_outfile_dir, "pop") if save_pop is not None else None) if not os.path.isdir(pid_outfile_dir): os.mkdir(pid_outfile_dir) os.mkdir(os.path.join(pid_outfile_dir, "network")) if save_pop: os.mkdir(save_pop_dir) else: save_pop_dir = None # apply params from sweep for this run for param, val in sweep.items(): utils.override_param(params, param, val, delimiter=".") tic = time_mod.time() # runs simulations if pop_path is None: pop = Population(params) else: pop = pop_io.read(params, pop_path) if save_pop_dir is not None: pop_io.write(pop, save_pop_dir) print(f"Population saved to: {save_pop_dir}") try: model = TITAN(params, pop=pop) except Exception as e: raise Exception(f"Model creation failed: {e}") try: model.run(pid_outfile_dir) except Exception as e: raise Exception(f"Model run failed for run {model.id}: {e}") update_sweep_file(model.id, model.pop.id, sweep, pid_outfile_dir) return time_mod.time() - tic
def _make_model(p=params): return TITAN(p)
import os import sys param_file = "viz_basic.yml" setting = "scott" outdir = "results" try: os.mkdir(outdir) except: print("results directory already exists, exiting") exit() params = create_params(setting, param_file, outdir) model = TITAN(params) def run(self, outdir: str): """ Runs the model for the number of time steps defined in params, at each time step does: 1. Increments time 2. Takes one step 3. Resets trackers 4. Saves population for visualization args: outdir: path to directory where results should be saved """ # make sure initial state of things get printed
def test_incar(params_integration, tmpdir): # turn on incar - initi is set to 0, so for these purposes, just run time params_integration.features.incar = True model = TITAN(params_integration) tmpdir.mkdir("network") # make sure we're starting from a clean slate init_incar = sum([1 for agent in model.pop.all_agents if agent.incar.active]) assert init_incar == 0 model.time = 1 model.step(tmpdir) model.reset_trackers() time_1_incars = [agent for agent in model.pop.all_agents if agent.incar.active] time_1_incar_hiv_neg = [agent for agent in time_1_incars if not agent.hiv.active] should_release_t2 = [ agent for agent in time_1_incars if agent.incar.release_time == 2 ] assert len(time_1_incars) > 0 assert len(time_1_incar_hiv_neg) > 0 assert len(should_release_t2) > 0 for agent in time_1_incars: assert agent.incar.time == 1 assert agent.incar.release_time > 1 model.time += 1 model.step(tmpdir) model.reset_trackers() for agent in should_release_t2: assert not agent.incar.active # agents should not hiv convert during incar for agent in time_1_incar_hiv_neg: assert not agent.hiv.active
def test_syringe_services(params_integration, tmpdir): """ If we use syringe services, does the incidence of hiv decrease? """ params_integration.demographics.black.sex_type.MSM.drug_type.Inj.ppl = 1.0 params_integration.demographics.black.sex_type.MSM.drug_type["None"].ppl = 0.0 params_integration.model.num_pop = 500 model_a = TITAN(params_integration) model_a.params.partnership.sex.frequency.Sex = ( ObjMap( # turn off sex to show only injection effects {"type": "bins", "bins": {1: {"prob": 1.0, "min": 0, "max": 1}}} ) ) path_a = tmpdir.mkdir("a") path_a.mkdir("network") path_b = tmpdir.mkdir("b") path_b.mkdir("network") # run with default bins (0-9) model_a.run(path_a) num_bonds = 0 num_ag = 0 for ag in model_a.pop.all_agents: if ag.hiv.active: num_ag += 1 for ptnr in ag.get_partners(["Inj", "SexInj"]): if not ptnr.hiv.active: num_bonds += 1 assert num_bonds # make sure there are serodiscordant partnerships # change the coverage upward for creating model b, use same seeds model_a.params.features.syringe_services = True model_a.params.model.seed.run = model_a.run_seed model_a.params.model.seed.ppl = model_a.pop.pop_seed model_b = TITAN(model_a.params) model_b.run(path_b) result_file_a = os.path.join(path_a, "basicReport.txt") result_file_b = os.path.join(path_b, "basicReport.txt") assert os.path.isfile(result_file_a) with open(result_file_a, newline="") as fa, open(result_file_b, newline="") as fb: reader_a = csv.DictReader(fa, delimiter="\t") res_a = {} for row in reader_a: if row["drug_type"] == "Inj": res_a[row["t"]] = res_a.get(row["t"], 0) + float(row["hiv"]) reader_b = csv.DictReader(fb, delimiter="\t") res_b = {} for row in reader_b: if row["drug_type"] == "Inj": res_b[row["t"]] = res_b.get(row["t"], 0) + float(row["hiv"]) # at start, should be similar t0_hiv_a = res_a["0"] t0_hiv_b = res_b["0"] t0_diff = t0_hiv_a - t0_hiv_b assert math.isclose(t0_hiv_a, t0_hiv_b, abs_tol=15) # within 15 agents # at end, should be different t10_hiv_a = res_a["10"] t10_hiv_b = res_b["10"] t10_diff = t10_hiv_a - t10_hiv_b # a should be higher assert t10_hiv_a > t0_hiv_a assert t10_hiv_b > t0_hiv_b assert t10_diff > t0_diff
def _make_model_integration(): return TITAN(params_integration)