Beispiel #1
0
def test_basic_get_infection_multiplier():
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model._prepare_to_run()
    model._prepare_time_step(0, model.initial_population)
    c_src = model.compartments[0]
    c_dst = model.compartments[1]
    multiplier = model._get_infection_frequency_multiplier(c_src, c_dst)
    assert multiplier == 10 / 1000
    multiplier = model._get_infection_density_multiplier(c_src, c_dst)
    assert multiplier == 10
Beispiel #2
0
def test_apply_universal_death_flow():
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.add_universal_death_flows("universal_death", 0.1)
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    expected_flow_rates = np.array([-99, -1])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #3
0
def test_apply_infect_death_flows(inf_pop, exp_flow):
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"I": inf_pop})
    model.add_death_flow("infection_death", 0.1, "I")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect 0.1 * inf_pop = exp_flow
    expected_flow_rates = np.array([0, -exp_flow])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #4
0
def test_apply_flows__with_infection_density(inf_pop, sus_pop, exp_flow):
    """
    Use infection density, expect infection multiplier to be proportional
    to the infectious pop.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": sus_pop, "I": inf_pop})
    model.add_infection_density_flow("infection", 0.02, "S", "I")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect 0.2 * sus_pop * inf_pop = exp_flow
    expected_flow_rates = np.array([-exp_flow, exp_flow])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #5
0
def test_apply_flows__with_transition_flow__expect_flows_applied(
        inf_pop, sus_pop, exp_flow):
    """
    Expect a flow to occur proportional to the compartment size and parameter.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": sus_pop, "I": inf_pop})
    model.add_transition_flow("deliberately_infected", 0.1, "S", "I")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect sus_pop * 0.1 = exp_flow
    expected_flow_rates = np.array([-exp_flow, exp_flow])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #6
0
def test_apply_flows__with_sojourn_flow__expect_flows_applied(
        inf_pop, exp_flow):
    """
    Expect a flow to occur proportional to the compartment size and parameter.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"I": inf_pop})
    model.add_sojourn_flow("recovery", 10, "I", "R")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect exp_flow = inf_pop * () exp_flow
    expected_flow_rates = np.array([0, -exp_flow, exp_flow])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #7
0
def test_apply_flows__with_infection_frequency(inf_pop, sus_pop, exp_flow):
    """
    Use infection frequency, expect infection multiplier to be proportional
    to the proprotion of infectious to total pop.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": sus_pop, "I": inf_pop})
    model.add_infection_frequency_flow("infection", 20, "S", "I")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect sus_pop * 20 * (inf_pop / 1000) = exp_flow
    expected_flow_rates = np.array([-exp_flow, exp_flow])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #8
0
def test_apply_crude_birth_rate_flow(birth_rate, exp_flow):
    """
    Expect births proportional to the total population and birth rate when
    the birth approach is "crude birth rate".
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.add_crude_birth_flow("births", birth_rate, "S")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect birth_rate * total_population = exp_flow
    expected_flow_rates = np.array([exp_flow, 0])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
def test_no_derived_outputs():

    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.run()
    # 6 timesteps, 3 compartments.
    assert model.outputs.shape == (6, 3)
    assert model.derived_outputs == {}
def test_aggregate_derived_outputs():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.run()
    model.outputs = np.array(
        [
            [990, 10, 0],
            [980, 15, 5],
            [970, 20, 10],
            [960, 25, 15],
            [950, 30, 20],
            [940, 35, 25],
        ]
    )
    model.request_output_for_compartments("recovered", ["R"])
    model.request_output_for_compartments("not_infected", ["S", "R"])
    model.request_output_for_compartments("total_population", ["S", "I", "R"])
    model.request_aggregate_output(name="my_aggregate", sources=["recovered", "total_population"])
    dos = model._calculate_derived_outputs()
    assert_array_equal(dos["my_aggregate"], np.array([1000, 1005, 1010, 1015, 1020, 1025]))
Beispiel #11
0
def test_strat_get_infection_multiplier__with_age_split_and_simple_mixing():
    """
    Check FoI when a simple 2-strata stratification applied AND heteregeneous mixing.
    Unequally split the children and adults.
    Expect same density as before, different frequency.
    Note that the mixing matrix has different meanings for density / vs frequency.
    """
    # Create a model
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    mixing_matrix = np.array([[0.5, 0.5], [0.5, 0.5]])
    strat.set_mixing_matrix(mixing_matrix)
    strat.set_population_split({"child": 0.2, "adult": 0.8})
    model.stratify_with(strat)

    assert model._mixing_categories == [{"age": "child"}, {"age": "adult"}]
    assert model.compartments == [
        C("S", {"age": "child"}),
        C("S", {"age": "adult"}),
        C("I", {"age": "child"}),
        C("I", {"age": "adult"}),
        C("R", {"age": "child"}),
        C("R", {"age": "adult"}),
    ]
    assert_array_equal(model.initial_population,
                       np.array([198.0, 792.0, 2.0, 8.0, 0.0, 0.0]))

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    assert_array_equal(model._compartment_infectiousness["default"],
                       np.array([0.0, 0.0, 1.0, 1.0, 0.0, 0.0]))
    assert_array_equal(
        model._category_matrix,
        np.array([[1.0, 0.0, 1.0, 0.0, 1.0, 0.0],
                  [0.0, 1.0, 0.0, 1.0, 0.0, 1.0]]),
    )
    assert model._category_lookup == {0: 0, 1: 1, 2: 0, 3: 1, 4: 0, 5: 1}

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    child_density = 5
    adult_density = 5
    assert child_density == 0.5 * 5 + 0.5 * 5
    assert adult_density == 0.5 * 5 + 0.5 * 5
    assert_array_equal(model._infection_density["default"],
                       np.array([child_density, adult_density]))
    child_freq = 0.01
    adult_freq = 0.01
    assert child_freq == 0.5 * 2 / 200 + 0.5 * 8 / 800
    assert adult_freq == 0.5 * 2 / 200 + 0.5 * 8 / 800
    assert_array_equal(model._infection_frequency["default"],
                       np.array([child_freq, adult_freq]))

    # Get multipliers
    s_child = model.compartments[0]
    s_adult = model.compartments[1]
    i_child = model.compartments[2]
    i_adult = model.compartments[3]

    assert model._get_infection_density_multiplier(s_child,
                                                   i_child) == child_density
    assert model._get_infection_density_multiplier(s_adult,
                                                   i_adult) == adult_density
    assert model._get_infection_frequency_multiplier(s_child,
                                                     i_child) == child_freq
    assert model._get_infection_frequency_multiplier(s_adult,
                                                     i_adult) == adult_freq
    # Santiy check frequency-dependent force of infection
    assert 200.0 * child_freq + 800.0 * adult_freq == 10
def test_derived_outputs_with_no_save_results():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.add_importation_flow("imports", num_imported=2, dest="S")

    # Expect np.array([0, 2, 2, 2, 2, 2]))
    model.request_output_for_flow(name="importation", flow_name="imports", save_results=False)
    # Expect np.array([0, 5, 10, 15, 20, 25]))
    model.request_output_for_compartments("recovered", ["R"], save_results=False)
    # Expect np.array([0, 5, 15, 30, 50, 75]))
    model.request_cumulative_output(
        name="recovered_cumulative", source="recovered", save_results=False
    )
    # Expect np.array([0, 7, 12, 17, 22, 227]))
    model.request_aggregate_output(
        name="some_aggregate", sources=["recovered", "importation"], save_results=False
    )
    # Expect np.array([  0,  12,  27,  47,  72, 102])
    model.request_aggregate_output(
        name="final_aggregate", sources=["some_aggregate", "recovered_cumulative"]
    )

    model.run()
    # Override outputs so the test is easier to write
    model.outputs = np.array(
        [
            [990, 10, 0],
            [980, 15, 5],
            [970, 20, 10],
            [960, 25, 15],
            [950, 30, 20],
            [940, 35, 25],
        ]
    )
    dos = model._calculate_derived_outputs()
    assert_array_equal(dos["final_aggregate"][1:], np.array([12, 27, 47, 72, 102]))
    assert "importation" not in dos
    assert "recovered" not in dos
    assert "recovered_cumulative" not in dos
    assert "some_aggregate" not in dos
def test_derived_outputs_whitelist():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.run()
    model.outputs = np.array(
        [
            [990, 10, 0],
            [980, 15, 5],
            [970, 20, 10],
            [960, 25, 15],
            [950, 30, 20],
            [940, 35, 25],
        ]
    )

    model.request_output_for_compartments("recovered", ["R"])
    model.request_output_for_compartments("not_infected", ["S", "R"])
    model.request_output_for_compartments("infected", ["I"])
    model.request_output_for_compartments("total_population", ["S", "I", "R"])
    model.request_cumulative_output(name="accum_infected", source="infected")

    model.set_derived_outputs_whitelist(["recovered", "accum_infected"])

    dos = model._calculate_derived_outputs()
    assert "recovered" in dos  # Included coz in whitelist (or dependency of)
    assert "infected" in dos  # Included coz in whitelist (or dependency of)
    assert "accum_infected" in dos  # Included coz in whitelist (or dependency of)
    assert "not_infected" not in dos  # Excluded coz not in whitelist
    assert "total_population" not in dos  # Excluded coz not in whitelist

    assert_array_equal(dos["recovered"], np.array([0, 5, 10, 15, 20, 25]))
    assert_array_equal(dos["infected"], np.array([10, 15, 20, 25, 30, 35]))
    assert_array_equal(dos["accum_infected"], np.array([10, 25, 45, 70, 100, 135]))
Beispiel #14
0
def test_strat_get_infection_multiplier__with_double_strat_and_no_mixing():
    """
    Check FoI when a two 2-strata stratificationz applied and no mixing matrix.
    Expect the same results as with the basic case.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    model.stratify_with(strat)
    strat = Stratification("location", ["work", "home"], ["S", "I", "R"])
    model.stratify_with(strat)

    assert model._mixing_categories == [{}]
    assert model.compartments == [
        C("S", {
            "age": "child",
            "location": "work"
        }),
        C("S", {
            "age": "child",
            "location": "home"
        }),
        C("S", {
            "age": "adult",
            "location": "work"
        }),
        C("S", {
            "age": "adult",
            "location": "home"
        }),
        C("I", {
            "age": "child",
            "location": "work"
        }),
        C("I", {
            "age": "child",
            "location": "home"
        }),
        C("I", {
            "age": "adult",
            "location": "work"
        }),
        C("I", {
            "age": "adult",
            "location": "home"
        }),
        C("R", {
            "age": "child",
            "location": "work"
        }),
        C("R", {
            "age": "child",
            "location": "home"
        }),
        C("R", {
            "age": "adult",
            "location": "work"
        }),
        C("R", {
            "age": "adult",
            "location": "home"
        }),
    ]
    expected_comp_vals = np.array(
        [247.5, 247.5, 247.5, 247.5, 2.5, 2.5, 2.5, 2.5, 0, 0, 0, 0])
    assert_array_equal(model.initial_population, expected_comp_vals)

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    expected_compartment_infectiousness = np.array(
        [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0])
    expected_category_matrix = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
    expected_lookup = {n: 0 for n in range(12)}
    assert_array_equal(model._compartment_infectiousness["default"],
                       expected_compartment_infectiousness)
    assert_array_equal(model._category_matrix, expected_category_matrix)
    assert model._category_lookup == expected_lookup

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    assert_array_equal(model._category_populations, np.array([1000]))
    assert_array_equal(model._infection_density["default"], np.array([10.0]))
    assert_array_equal(model._infection_frequency["default"], np.array([0.01]))
    s_child_work = model.compartments[0]
    s_child_home = model.compartments[1]
    s_adult_work = model.compartments[2]
    s_adult_home = model.compartments[3]
    i_child_work = model.compartments[4]
    i_child_home = model.compartments[5]
    i_adult_work = model.compartments[6]
    i_adult_home = model.compartments[7]

    assert model._get_infection_density_multiplier(s_child_work,
                                                   i_child_work) == 10.0
    assert model._get_infection_density_multiplier(s_child_home,
                                                   i_child_home) == 10.0
    assert model._get_infection_density_multiplier(s_adult_work,
                                                   i_adult_work) == 10.0
    assert model._get_infection_density_multiplier(s_adult_home,
                                                   i_adult_home) == 10.0
    assert model._get_infection_frequency_multiplier(s_child_work,
                                                     i_child_work) == 0.01
    assert model._get_infection_frequency_multiplier(s_child_home,
                                                     i_child_home) == 0.01
    assert model._get_infection_frequency_multiplier(s_adult_work,
                                                     i_adult_work) == 0.01
    assert model._get_infection_frequency_multiplier(s_adult_home,
                                                     i_adult_home) == 0.01
def test_functional_derived_outputs():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.run()
    model.outputs = np.array(
        [
            [990, 10, 0],
            [980, 15, 5],
            [970, 20, 10],
            [960, 25, 15],
            [950, 30, 20],
            [940, 35, 25],
        ]
    )

    def get_non_infected(rec, pop):
        return rec / pop

    model.request_output_for_compartments("recovered", ["R"])
    model.request_output_for_compartments("population", ["S", "I", "R"])
    model.request_function_output("recovered_prop", get_non_infected, ["recovered", "population"])

    dos = model._calculate_derived_outputs()
    assert_array_equal(dos["recovered_prop"], np.array([0, 0.005, 0.01, 0.015, 0.020, 0.025]))
Beispiel #16
0
def test_apply_many_flows():
    """
    Expect multiple flows to operate independently and produce the correct final flow rate.
    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 900, "I": 100})
    model.add_death_flow("infection_death", 0.1, "I")
    model.add_universal_death_flows("universal_death", 0.1)
    model.add_infection_frequency_flow("infection", 0.2, "S", "I")
    model.add_sojourn_flow("recovery", 10, "I", "R")
    model.add_transition_flow("vaccination", 0.1, "S", "R")
    model.add_crude_birth_flow("births", 0.1, "S")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)

    # Expect the effects of all these flows to be linearly superimposed.
    infect_death_flows = np.array([0, -10, 0])
    universal_death_flows = np.array([-90, -10, 0])
    infected = 900 * 0.2 * (100 / 1000)
    infection_flows = np.array([-infected, infected, 0])
    recovery_flows = np.array([0, -10, 10])
    vaccination_flows = np.array([-90, 0, 90])
    birth_flows = np.array([100, 0, 0])
    expected_flow_rates = (infect_death_flows + universal_death_flows +
                           infection_flows + recovery_flows +
                           vaccination_flows + birth_flows)
    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #17
0
def test_strat_get_infection_multiplier__with_double_strat_and_second_strat_mixing(
):
    """
    Check FoI when a two 2-strata stratification applied and the second stratification has a mixing matrix.
    """
    # Create the model
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    strat.set_population_split({"child": 0.3, "adult": 0.7})
    model.stratify_with(strat)
    strat = Stratification("location", ["work", "home"], ["S", "I", "R"])
    location_mixing = np.array([[2, 3], [5, 7]])
    strat.set_mixing_matrix(location_mixing)
    model.stratify_with(strat)

    assert model._mixing_categories == [{
        "location": "work"
    }, {
        "location": "home"
    }]
    assert model.compartments == [
        C("S", {
            "age": "child",
            "location": "work"
        }),
        C("S", {
            "age": "child",
            "location": "home"
        }),
        C("S", {
            "age": "adult",
            "location": "work"
        }),
        C("S", {
            "age": "adult",
            "location": "home"
        }),
        C("I", {
            "age": "child",
            "location": "work"
        }),
        C("I", {
            "age": "child",
            "location": "home"
        }),
        C("I", {
            "age": "adult",
            "location": "work"
        }),
        C("I", {
            "age": "adult",
            "location": "home"
        }),
        C("R", {
            "age": "child",
            "location": "work"
        }),
        C("R", {
            "age": "child",
            "location": "home"
        }),
        C("R", {
            "age": "adult",
            "location": "work"
        }),
        C("R", {
            "age": "adult",
            "location": "home"
        }),
    ]
    expected_comp_vals = np.array(
        [148.5, 148.5, 346.5, 346.5, 1.5, 1.5, 3.5, 3.5, 0, 0, 0, 0])
    assert_array_equal(model.initial_population, expected_comp_vals)

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    exp_lookup = {
        0: 0,
        1: 1,
        2: 0,
        3: 1,
        4: 0,
        5: 1,
        6: 0,
        7: 1,
        8: 0,
        9: 1,
        10: 0,
        11: 1
    }
    exp_matrix = np.array([
        [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
        [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
    ])
    exp_mults = np.array([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0])
    assert_array_equal(model._compartment_infectiousness["default"], exp_mults)
    assert_array_equal(model._category_matrix, exp_matrix)
    assert model._category_lookup == exp_lookup

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    assert_array_equal(model._category_populations, np.array([500.0, 500.0]))
    work_density = 25
    home_density = 60
    assert work_density == 2 * 5 + 3 * 5
    assert home_density == 5 * 5 + 7 * 5
    assert_array_equal(model._infection_density["default"],
                       np.array([work_density, home_density]))
    work_freq = 2 * 5 / 500 + 3 * 5 / 500
    home_freq = 5 * 5 / 500 + 7 * 5 / 500
    assert_array_equal(model._infection_frequency["default"],
                       np.array([work_freq, home_freq]))

    # Get multipliers
    s_child_work = model.compartments[0]
    s_child_home = model.compartments[1]
    s_adult_work = model.compartments[2]
    s_adult_home = model.compartments[3]
    i_child_work = model.compartments[4]
    i_child_home = model.compartments[5]
    i_adult_work = model.compartments[6]
    i_adult_home = model.compartments[7]

    assert model._get_infection_density_multiplier(
        s_child_work, i_child_work) == work_density
    assert model._get_infection_density_multiplier(
        s_child_home, i_child_home) == home_density
    assert model._get_infection_density_multiplier(
        s_adult_work, i_adult_work) == work_density
    assert model._get_infection_density_multiplier(
        s_adult_home, i_adult_home) == home_density
    assert model._get_infection_frequency_multiplier(s_child_work,
                                                     i_child_work) == work_freq
    assert model._get_infection_frequency_multiplier(s_child_home,
                                                     i_child_home) == home_freq
    assert model._get_infection_frequency_multiplier(s_adult_work,
                                                     i_adult_work) == work_freq
    assert model._get_infection_frequency_multiplier(s_adult_home,
                                                     i_adult_home) == home_freq
Beispiel #18
0
def test_strat_get_infection_multiplier__with_age_strat_and_no_mixing():
    """
    Check FoI when a simple 2-strata stratification applied and no mixing matrix.
    Expect the same results as with the basic case.
    """
    # Create a model
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    model.stratify_with(strat)
    assert model._mixing_categories == [{}]

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    assert_array_equal(model._compartment_infectiousness["default"],
                       np.array([0.0, 0.0, 1.0, 1.0, 0.0, 0.0]))
    assert_array_equal(model._category_matrix,
                       np.array([[1.0, 1.0, 1.0, 1.0, 1.0, 1.0]]))
    assert model._category_lookup == {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    assert_array_equal(model._category_populations, np.array([1000]))
    assert_array_equal(model._infection_density["default"], np.array([10.0]))
    assert_array_equal(model._infection_frequency["default"], np.array([0.01]))

    # Get multipliers
    s_child = model.compartments[0]
    s_adult = model.compartments[1]
    i_child = model.compartments[2]
    i_adult = model.compartments[3]

    assert model._get_infection_density_multiplier(s_child, i_child) == 10.0
    assert model._get_infection_density_multiplier(s_adult, i_adult) == 10.0
    assert model._get_infection_frequency_multiplier(s_child, i_child) == 0.01
    assert model._get_infection_frequency_multiplier(s_adult, i_adult) == 0.01
    # Santiy check frequency-dependent force of infection
    assert 1000.0 * 0.01 == 10
Beispiel #19
0
def test_apply_replace_death_birth_flow():
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 900, "I": 100})
    model.add_death_flow("infection_death", 0.1, "I")
    model.add_universal_death_flows("universal_death", 0.05)
    model.add_replacement_birth_flow("births", "S")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    # Expect 10 people to die and 10 to be born
    exp_i_flow_rate = -0.1 * 100 - 0.05 * 100
    exp_s_flow_rate = -exp_i_flow_rate  # N.B births + deaths in the S compartment should balance.
    expected_flow_rates = np.array([exp_s_flow_rate, exp_i_flow_rate])
    assert_array_equal(actual_flow_rates, expected_flow_rates)
def test_cumulative_derived_outputs():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 990, "I": 10})
    model.run()
    model.outputs = np.array(
        [
            [990, 10, 0],
            [980, 15, 5],
            [970, 20, 10],
            [960, 25, 15],
            [950, 30, 20],
            [940, 35, 25],
        ]
    )
    model.request_output_for_compartments("recovered", ["R"])
    model.request_cumulative_output(name="recoved_cumulative", source="recovered")
    model.request_cumulative_output(name="recoved_cumulative_2", source="recovered", start_time=2)
    dos = model._calculate_derived_outputs()
    assert_array_equal(dos["recoved_cumulative"], np.array([0, 5, 15, 30, 50, 75]))
    assert_array_equal(dos["recoved_cumulative_2"], np.array([0, 0, 10, 25, 45, 70]))
Beispiel #21
0
def test_strat_get_infection_multiplier__with_age_strat_and_simple_mixing():
    """
    Check FoI when a simple 2-strata stratification applied AND heteregeneous mixing.
    Expect same frequency as before, different density.
    Note that the mixing matrix has different meanings for density / vs frequency.

    N.B Mixing matrix format.
    Columns are  the people who are infectors
    Rows are the people who are infected
    So matrix has following values

                  child               adult

      child       child -> child      adult -> child
      adult       child -> adult      adult -> adult

    """
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    mixing_matrix = np.array([[0.5, 0.5], [0.5, 0.5]])
    strat.set_mixing_matrix(mixing_matrix)
    model.stratify_with(strat)

    assert model._mixing_categories == [{"age": "child"}, {"age": "adult"}]
    assert model.compartments == [
        C("S", {"age": "child"}),
        C("S", {"age": "adult"}),
        C("I", {"age": "child"}),
        C("I", {"age": "adult"}),
        C("R", {"age": "child"}),
        C("R", {"age": "adult"}),
    ]
    assert_array_equal(model.initial_population,
                       np.array([495, 495, 5, 5, 0.0, 0.0]))

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    assert_array_equal(model._compartment_infectiousness["default"],
                       np.array([0.0, 0.0, 1.0, 1.0, 0.0, 0.0]))
    assert_array_equal(
        model._category_matrix,
        np.array([[1.0, 0.0, 1.0, 0.0, 1.0, 0.0],
                  [0.0, 1.0, 0.0, 1.0, 0.0, 1.0]]),
    )
    assert model._category_lookup == {0: 0, 1: 1, 2: 0, 3: 1, 4: 0, 5: 1}

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    child_density = 5
    adult_density = 5
    assert child_density == 0.5 * 5 + 0.5 * 5
    assert adult_density == 0.5 * 5 + 0.5 * 5
    assert_array_equal(model._infection_density["default"],
                       np.array([child_density, adult_density]))
    child_freq = 0.01
    adult_freq = 0.01
    assert child_freq == child_density / 500
    assert adult_freq == adult_density / 500
    assert_array_equal(model._infection_frequency["default"],
                       np.array([child_freq, adult_freq]))

    # Get multipliers
    s_child = model.compartments[0]
    s_adult = model.compartments[1]
    i_child = model.compartments[2]
    i_adult = model.compartments[3]
    assert model._get_infection_density_multiplier(s_child,
                                                   i_child) == child_density
    assert model._get_infection_density_multiplier(s_adult,
                                                   i_adult) == adult_density
    assert model._get_infection_frequency_multiplier(s_child,
                                                     i_child) == child_freq
    assert model._get_infection_frequency_multiplier(s_adult,
                                                     i_adult) == adult_freq
    # Santiy check frequency-dependent force of infection
    assert 500.0 * child_freq + 500.0 * adult_freq == 10
Beispiel #22
0
def test_strat_get_infection_multiplier__with_double_strat_and_both_strats_mixing(
):
    """
    Check FoI when a two 2-strata stratification applied and both stratifications have a mixing matrix.
    """
    # Create the model
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    strat.set_population_split({"child": 0.3, "adult": 0.7})
    am = np.array([[2, 3], [5, 7]])
    strat.set_mixing_matrix(am)
    model.stratify_with(strat)
    strat = Stratification("location", ["work", "home"], ["S", "I", "R"])
    lm = np.array([[11, 13], [17, 19]])
    strat.set_mixing_matrix(lm)
    model.stratify_with(strat)

    expected_mixing = np.array([
        [2 * 11, 2 * 13, 3 * 11, 3 * 13],
        [2 * 17, 2 * 19, 3 * 17, 3 * 19],
        [5 * 11, 5 * 13, 7 * 11, 7 * 13],
        [5 * 17, 5 * 19, 7 * 17, 7 * 19],
    ])
    assert_array_equal(model._get_mixing_matrix(0), expected_mixing)
    assert model._mixing_categories == [
        {
            "age": "child",
            "location": "work"
        },
        {
            "age": "child",
            "location": "home"
        },
        {
            "age": "adult",
            "location": "work"
        },
        {
            "age": "adult",
            "location": "home"
        },
    ]
    assert model.compartments == [
        C("S", {
            "age": "child",
            "location": "work"
        }),
        C("S", {
            "age": "child",
            "location": "home"
        }),
        C("S", {
            "age": "adult",
            "location": "work"
        }),
        C("S", {
            "age": "adult",
            "location": "home"
        }),
        C("I", {
            "age": "child",
            "location": "work"
        }),
        C("I", {
            "age": "child",
            "location": "home"
        }),
        C("I", {
            "age": "adult",
            "location": "work"
        }),
        C("I", {
            "age": "adult",
            "location": "home"
        }),
        C("R", {
            "age": "child",
            "location": "work"
        }),
        C("R", {
            "age": "child",
            "location": "home"
        }),
        C("R", {
            "age": "adult",
            "location": "work"
        }),
        C("R", {
            "age": "adult",
            "location": "home"
        }),
    ]
    expected_comp_vals = np.array(
        [148.5, 148.5, 346.5, 346.5, 1.5, 1.5, 3.5, 3.5, 0, 0, 0, 0])
    assert_array_equal(model.initial_population, expected_comp_vals)

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    exp_lookup = {
        0: 0,  # S age: child location: work -> children at work
        1: 1,  # S age: child location: home -> children at home
        2: 2,  # S age: adult location: work -> adults at work
        3: 3,  # S age: adult location: home -> adults at home
        4: 0,  # I age: child location: work -> children at work
        5: 1,  # I age: child location: home -> children at home
        6: 2,  # I age: adult location: work -> adults at work
        7: 3,  # I age: adult location: home -> adults at home
        8: 0,  # R age: child location: work -> children at work
        9: 1,  # R age: child location: home -> children at home
        10: 2,  # R age: adult location: work -> adults at work
        11: 3,  # R age: adult location: home -> adults at home
    }
    exp_matrix = np.array([
        [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # children at work
        [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],  # children at home
        [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],  # adults at work
        [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],  # adults at home
    ])
    exp_mults = np.array([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0])
    assert_array_equal(model._compartment_infectiousness["default"], exp_mults)
    assert_array_equal(model._category_matrix, exp_matrix)
    assert model._category_lookup == exp_lookup

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    exp_pops = np.array([
        150,  # children at work
        150,  # children at home
        350,  # adults at work
        350,  # adults at home
    ])
    assert_array_equal(model._category_populations, exp_pops)
    child_work_density = 2 * 11 * 1.5 + 2 * 13 * 1.5 + 3 * 11 * 3.5 + 3 * 13 * 3.5
    child_home_density = 2 * 17 * 1.5 + 2 * 19 * 1.5 + 3 * 17 * 3.5 + 3 * 19 * 3.5
    adult_work_density = 5 * 11 * 1.5 + 5 * 13 * 1.5 + 7 * 11 * 3.5 + 7 * 13 * 3.5
    adult_home_density = 5 * 17 * 1.5 + 5 * 19 * 1.5 + 7 * 17 * 3.5 + 7 * 19 * 3.5
    child_work_freq = (2 * 11 * 1.5 / 150 + 2 * 13 * 1.5 / 150 +
                       3 * 11 * 3.5 / 350 + 3 * 13 * 3.5 / 350)
    child_home_freq = (2 * 17 * 1.5 / 150 + 2 * 19 * 1.5 / 150 +
                       3 * 17 * 3.5 / 350 + 3 * 19 * 3.5 / 350)
    adult_work_freq = (5 * 11 * 1.5 / 150 + 5 * 13 * 1.5 / 150 +
                       7 * 11 * 3.5 / 350 + 7 * 13 * 3.5 / 350)
    adult_home_freq = (5 * 17 * 1.5 / 150 + 5 * 19 * 1.5 / 150 +
                       7 * 17 * 3.5 / 350 + 7 * 19 * 3.5 / 350)
    exp_density = np.array([
        child_work_density,  # children at work
        child_home_density,  # children at home
        adult_work_density,  # adults at work
        adult_home_density,  # adults at home
    ])
    exp_frequency = np.array([
        child_work_freq,  # children at work
        child_home_freq,  # children at home
        adult_work_freq,  # adults at work
        adult_home_freq,  # adults at home
    ])
    assert_array_equal(model._infection_density["default"], exp_density)
    assert_allclose(model._infection_frequency["default"],
                    exp_frequency,
                    rtol=0,
                    atol=1e-9)

    # Get multipliers
    s_child_work = model.compartments[0]
    s_child_home = model.compartments[1]
    s_adult_work = model.compartments[2]
    s_adult_home = model.compartments[3]
    i_child_work = model.compartments[4]
    i_child_home = model.compartments[5]
    i_adult_work = model.compartments[6]
    i_adult_home = model.compartments[7]

    assert (abs(
        model._get_infection_density_multiplier(s_child_work, i_child_work) -
        child_work_density) <= 1e-9)
    assert (abs(
        model._get_infection_density_multiplier(s_child_home, i_child_home) -
        child_home_density) <= 1e-9)
    assert (abs(
        model._get_infection_density_multiplier(s_adult_work, i_adult_work) -
        adult_work_density) <= 1e-9)
    assert (abs(
        model._get_infection_density_multiplier(s_adult_home, i_adult_home) -
        adult_home_density) <= 1e-9)
    assert (abs(
        model._get_infection_frequency_multiplier(s_child_work, i_child_work) -
        child_work_freq) <= 1e-9)
    assert (abs(
        model._get_infection_frequency_multiplier(s_child_home, i_child_home) -
        child_home_freq) <= 1e-9)
    assert (abs(
        model._get_infection_frequency_multiplier(s_adult_work, i_adult_work) -
        adult_work_freq) <= 1e-9)
    assert (abs(
        model._get_infection_frequency_multiplier(s_adult_home, i_adult_home) -
        adult_home_freq) <= 1e-9)
Beispiel #23
0
def test_apply_flows__with_function_flow__expect_flows_applied(
        inf_pop, sus_pop, exp_flow):
    """
    Expect a flow to occur proportional to the result of `get_flow_rate`.
    """
    def get_flow_rate(flow, comps, comp_vals, flows, flow_rates, time):
        _, i_pop, _ = comp_vals
        i_flow, _ = flow_rates
        return i_pop + i_flow

    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": sus_pop, "I": inf_pop})
    model.add_transition_flow("infection", 0.1, "S", "I")
    model.add_function_flow("treatment", get_flow_rate, "I", "S")
    model._prepare_to_run()
    actual_flow_rates = model._get_compartment_rates(model.initial_population,
                                                     0)
    expected_infected = sus_pop * 0.1
    expected_flow_rates = np.array([
        exp_flow - expected_infected,
        expected_infected - exp_flow,
        0,
    ])

    assert_array_equal(actual_flow_rates, expected_flow_rates)
Beispiel #24
0
def create_simple_model():
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    return model
def test_flow_derived_outputs():
    model = CompartmentalModel(
        times=[0, 5], compartments=["S", "I", "R"], infectious_compartments=["I"]
    )
    model.set_initial_population(distribution={"S": 900, "I": 100})

    # Constant entry.
    model.add_importation_flow("imports", num_imported=2, dest="S")
    model.request_output_for_flow(name="importation", flow_name="imports")
    model.request_output_for_flow(name="importation_raw", flow_name="imports", raw_results=True)

    # Linear entry.
    model.add_importation_flow("imports_land", num_imported=lambda t: 3 * t, dest="S")
    model.request_output_for_flow(name="importation_land", flow_name="imports_land")

    # Quadratic entry.
    model.add_importation_flow("imports_air", num_imported=lambda t: t ** 2, dest="S")
    model.request_output_for_flow(name="importation_air", flow_name="imports_air")

    # Fractional transition flow
    model.add_transition_flow("recovery", 0.1, "I", "R")
    model.request_output_for_flow(name="recovery_raw", flow_name="recovery", raw_results=True)
    model.request_output_for_flow(name="recovery_delta", flow_name="recovery", raw_results=False)

    model.run()
    dos = model.derived_outputs

    # Raw outputs are the instantaneous flow rate at a given time.
    assert_allclose(dos["recovery_raw"], model.outputs[:, 1] * 0.1, rtol=0.01)

    # Post-processed outputs reflect changes in compartment size.
    recovered_count = np.zeros_like(model.outputs[:, 2])
    recovered_count[1:] = np.diff(model.outputs[:, 2])
    assert_allclose(dos["recovery_delta"][1:], recovered_count[1:], rtol=0.01)

    # Good match for constant
    assert_array_equal(dos["importation"][1:], np.array([2, 2, 2, 2, 2]))
    assert_array_equal(dos["importation_raw"], np.array([2, 2, 2, 2, 2, 2]))

    # Good match for linear
    assert_allclose(dos["importation_land"][1:], np.array([1.5, 4.5, 7.5, 10.5, 13.5]))
    # So-so match for quadratic
    assert_allclose(dos["importation_air"][1:], np.array([0.5, 2.5, 6.5, 12.5, 20.5]), rtol=0.1)
Beispiel #26
0
def test_strat_get_infection_multiplier__with_age_strat_and_mixing():
    """
    Check FoI when a simple 2-strata stratification applied AND heteregeneous mixing.
    Use a non-uniform mixing matrix
    """
    # Create a model
    model = CompartmentalModel(times=[0, 5],
                               compartments=["S", "I", "R"],
                               infectious_compartments=["I"])
    model.set_initial_population(distribution={"S": 990, "I": 10})
    strat = Stratification("age", ["child", "adult"], ["S", "I", "R"])
    mixing_matrix = np.array([[2, 3], [5, 7]])
    strat.set_mixing_matrix(mixing_matrix)
    strat.set_population_split({"child": 0.2, "adult": 0.8})
    model.stratify_with(strat)

    assert model._mixing_categories == [{"age": "child"}, {"age": "adult"}]
    assert model.compartments == [
        C("S", {"age": "child"}),
        C("S", {"age": "adult"}),
        C("I", {"age": "child"}),
        C("I", {"age": "adult"}),
        C("R", {"age": "child"}),
        C("R", {"age": "adult"}),
    ]
    assert_array_equal(model.initial_population,
                       np.array([198.0, 792.0, 2.0, 8.0, 0.0, 0.0]))

    # Do pre-run force of infection calcs.
    model._prepare_to_run()
    assert_array_equal(model._compartment_infectiousness["default"],
                       np.array([0.0, 0.0, 1.0, 1.0, 0.0, 0.0]))
    assert_array_equal(
        model._category_matrix,
        np.array([[1.0, 0.0, 1.0, 0.0, 1.0, 0.0],
                  [0.0, 1.0, 0.0, 1.0, 0.0, 1.0]]),
    )
    assert model._category_lookup == {0: 0, 1: 1, 2: 0, 3: 1, 4: 0, 5: 1}

    # Do pre-iteration force of infection calcs
    model._prepare_time_step(0, model.initial_population)
    assert_array_equal(model._category_populations, np.array([200.0, 800.0]))
    child_density = 28
    adult_density = 66
    assert child_density == 2 * 2.0 + 3 * 8.0
    assert adult_density == 5 * 2.0 + 7 * 8.0
    assert_array_equal(model._infection_density["default"],
                       np.array([child_density, adult_density]))
    child_freq = 0.05
    adult_freq = 0.12000000000000001
    assert child_freq == 2 * 2.0 / 200 + 3 * 8.0 / 800
    assert adult_freq == 5 * 2.0 / 200 + 7 * 8.0 / 800

    assert_array_equal(model._infection_frequency["default"],
                       np.array([child_freq, adult_freq]))

    # Get multipliers
    s_child = model.compartments[0]
    s_adult = model.compartments[1]
    i_child = model.compartments[2]
    i_adult = model.compartments[3]
    assert model._get_infection_density_multiplier(s_child,
                                                   i_child) == child_density
    assert model._get_infection_density_multiplier(s_adult,
                                                   i_adult) == adult_density
    assert model._get_infection_frequency_multiplier(s_child,
                                                     i_child) == child_freq
    assert model._get_infection_frequency_multiplier(s_adult,
                                                     i_adult) == adult_freq