def test_genGraphFromContactFile_missing_weight():
    df = pd.DataFrame([{
        "source": "a",
        "target": "b",
        "delta_adjustment": 1.0
    }])

    with pytest.raises(ValueError):
        loaders.genGraphFromContactFile(df)
Пример #2
0
def test_genGraphFromContactFile_negative_delta_adjustment():
    df = pd.DataFrame([{
        "source": "a",
        "target": "b",
        "weight": 0,
        "delta_adjustment": -1.0
    }])
    with pytest.raises(AssertionError):
        loaders.genGraphFromContactFile(df)
Пример #3
0
def test_genGraphFromContactFile(base_data_dir, data_api):
    graph = nx.convert_matrix.from_pandas_edgelist(pd.read_csv(
        str(base_data_dir / "human" / "commutes" / "1" / "data.csv")),
                                                   edge_attr=True,
                                                   create_using=nx.DiGraph)

    assert nx.is_isomorphic(
        loaders.genGraphFromContactFile(data_api.read_table("human/commutes")),
        graph)
def test_genGraphFromContactFile(base_data_dir, data_api):
    with open(str(base_data_dir / "human" / "commutes" / "1" / "data.h5"),
              "rb") as fp:
        df = object_file.read_table(fp, "commutes")
    graph = nx.convert_matrix.from_pandas_edgelist(df,
                                                   edge_attr=True,
                                                   create_using=nx.DiGraph)

    assert nx.is_isomorphic(
        loaders.genGraphFromContactFile(
            data_api.read_table("human/commutes", "commutes")), graph)
Пример #5
0
def test_basicSimulationInternalAgeStructure_invariants(
    age_transitions,
    demographics,
    commute_moves,
    compartment_names,
    age_infection_matrix,
    num_infected,
    generic_infection,
    seed,
):
    age_to_trans = np.setUpParametersAges(
        loaders.readParametersAgeStructured(age_transitions))
    population = loaders.readPopulationAgeStructured(demographics)
    graph = loaders.genGraphFromContactFile(commute_moves)
    states = np.setupInternalPopulations(graph, compartment_names,
                                         list(age_to_trans.keys()), population)
    old_graph = copy.deepcopy(graph)
    old_age_to_trans = copy.deepcopy(age_to_trans)
    initial_population = sum(_count_people_per_region(
        states[0])) + num_infected

    np.basicSimulationInternalAgeStructure(
        rand=random.Random(seed),
        graph=graph,
        numInfected=num_infected,
        timeHorizon=50,
        genericInfection=generic_infection,
        ageInfectionMatrix=age_infection_matrix,
        diseaseProgressionProbs=age_to_trans,
        dictOfStates=states,
    )

    # population remains constant
    assert all([
        sum(_count_people_per_region(state)) == pytest.approx(
            initial_population) for state in states.values()
    ])

    # the graph is unchanged
    assert nx.is_isomorphic(old_graph, graph)

    # infection matrix is unchanged
    assert age_to_trans == old_age_to_trans
Пример #6
0
def test_genGraphFromContactFile(commute_moves):
    graph = nx.read_edgelist(commute_moves, create_using=nx.DiGraph, delimiter=",", data=(("weight", float),))

    assert nx.is_isomorphic(loaders.genGraphFromContactFile(commute_moves), graph)
Пример #7
0
def createNetworkOfPopulation(
        compartment_transition_table: pd.DataFrame,
        population_table: pd.DataFrame,
        commutes_table: pd.DataFrame,
        mixing_matrix_table: pd.DataFrame,
        infectious_states: pd.DataFrame,
        infection_prob: pd.DataFrame,
        initial_infections: pd.DataFrame,
        trials: pd.DataFrame,
        movement_multipliers_table: pd.DataFrame = None,
        stochastic_mode: pd.DataFrame = None,
        random_seed: pd.DataFrame = None) -> NetworkOfPopulation:
    """Create the network of the population, loading data from files.

    :param compartment_transition_table: pd.Dataframe specifying the transition rates between infected compartments.
    :param population_table: pd.Dataframe with the population size in each region by gender and age.
    :param commutes_table: pd.Dataframe with the movements between regions.
    :param mixing_matrix_table: pd.Dataframe with the age infection matrix.
    :param movement_multipliers_table: pd.Dataframe with the movement multipliers. This may be None, in
    which case no multipliers are applied to the movements.
    :param infectious_states: States that are considered infectious
    :param infection_prob: Probability that a given contact will result in an infection
    :param initial_infections: Initial infections of the population at time 0
    :param trials: Number of trials for the model
    :param stochastic_mode: Use stochastic mode for the model
    :param random_seed: Random number generator seed used for stochastic mode
    :return: The constructed network
    """
    infection_prob = loaders.readInfectionProbability(infection_prob)

    infectious_states = loaders.readInfectiousStates(infectious_states)
    initial_infections = loaders.readInitialInfections(initial_infections)
    trials = loaders.readTrials(trials)
    stochastic_mode = loaders.readStochasticMode(stochastic_mode)
    random_seed = loaders.readRandomSeed(random_seed)

    # diseases progression matrix
    progression = loaders.readCompartmentRatesByAge(
        compartment_transition_table)

    # population census data
    population = loaders.readPopulationAgeStructured(population_table)

    # Check some requirements for this particular model to work with the progression matrix
    all_states = set()
    for states in progression.values():
        assert SUSCEPTIBLE_STATE not in states, "progression from susceptible state is not allowed"
        for state, nextStates in states.items():
            for nextState in nextStates:
                all_states.add(state)
                all_states.add(nextState)
                assert state == nextState or nextState != EXPOSED_STATE, \
                    "progression into exposed state is not allowed other than in self reference"
    assert (set(infectious_states) - all_states) == set(), \
        f"mismatched infectious states and states {infectious_states} {set(progression.keys())}"

    # people movement's graph
    graph = loaders.genGraphFromContactFile(commutes_table)

    # movement multipliers (dampening or heightening)
    if movement_multipliers_table is not None:
        movementMultipliers = loaders.readMovementMultipliers(
            movement_multipliers_table)
    else:
        movementMultipliers: Dict[int, loaders.Multiplier] = {}

    # age-based infection matrix
    mixingMatrix = loaders.MixingMatrix(mixing_matrix_table)

    agesInInfectionMatrix = set(mixingMatrix)
    for age in mixingMatrix:
        assert agesInInfectionMatrix == set(
            mixingMatrix[age]), "infection matrix columns/rows mismatch"

    # Checks across datasets
    assert agesInInfectionMatrix == set(
        progression.keys()), "infection matrix and progression ages mismatch"
    assert agesInInfectionMatrix == {age for region in population.values() for age in region}, \
        "infection matrix and population ages mismatch"
    assert set(graph.nodes()) == set(
        population.keys()), "regions mismatch between graph and population"

    state0: Dict[str, Dict[Tuple[str, str], float]] = {}
    for node in list(graph.nodes()):
        region = state0.setdefault(node, {})
        for age, compartments in progression.items():
            region[(age, SUSCEPTIBLE_STATE)] = population[node][age]
            for compartment in compartments:
                region[(age, compartment)] = 0

    logger.info("Nodes: %s, Ages: %s, States: %s", len(state0),
                agesInInfectionMatrix, all_states)
    return NetworkOfPopulation(progression=progression,
                               graph=graph,
                               initialState=state0,
                               mixingMatrix=mixingMatrix,
                               movementMultipliers=movementMultipliers,
                               infectiousStates=infectious_states,
                               infectionProb=infection_prob,
                               initialInfections=initial_infections,
                               trials=trials,
                               stochastic=stochastic_mode,
                               randomState=np.random.default_rng(random_seed))
Пример #8
0
def createNetworkOfPopulation(
    compartment_transition_table: pd.DataFrame,
    population_table: pd.DataFrame,
    commutes_table: pd.DataFrame,
    mixing_matrix_table: pd.DataFrame,
    infectious_states: pd.DataFrame,
    infection_prob: pd.DataFrame,
    initial_infections: pd.DataFrame,
    trials: pd.DataFrame,
    start_end_date: pd.DataFrame,
    movement_multipliers_table: pd.DataFrame = None,
    stochastic_mode: pd.DataFrame = None,
) -> Tuple[NetworkOfPopulation, List[standard_api.Issue]]:
    """Create the network of the population, loading data from files.

    :param compartment_transition_table: pd.Dataframe specifying the transition rates between infected compartments.
    :param population_table: pd.Dataframe with the population size in each region by gender and age.
    :param commutes_table: pd.Dataframe with the movements between regions.
    :param mixing_matrix_table: pd.Dataframe with the age infection matrix.
    :param infectious_states: States that are considered infectious
    :param infection_prob: Probability that a given contact will result in an infection
    :param initial_infections: Initial infections of the population at time 0
    :param trials: Number of trials for the model
    :param start_end_date: Starting and ending dates of the model
    :param movement_multipliers_table: pd.Dataframe with the movement multipliers. This may be None, in
                                       which case no multipliers are applied to the movements.
    :param stochastic_mode: Use stochastic mode for the model
    :return: A tuple with the constructed network and a list of any issues found. Although it may look convenient,
             storing this list inside of NetworkOfPopulation is not a good idea, as that may give the functions that
             receive it the false impression they can just append new issues there
    """
    issues: List[standard_api.Issue] = []
    infection_prob = loaders.readInfectionProbability(infection_prob)

    infectious_states = loaders.readInfectiousStates(infectious_states)
    initial_infections = loaders.readInitialInfections(initial_infections)
    trials = loaders.readTrials(trials)
    start_date, end_date = loaders.readStartEndDate(start_end_date)
    stochastic_mode = loaders.readStochasticMode(stochastic_mode)

    # diseases progression matrix
    progression = loaders.readCompartmentRatesByAge(
        compartment_transition_table)

    # population census data
    population = loaders.readPopulationAgeStructured(population_table)

    # Check some requirements for this particular model to work with the progression matrix
    all_states = set()
    for states in progression.values():
        assert SUSCEPTIBLE_STATE not in states, "progression from susceptible state is not allowed"
        for state, nextStates in states.items():
            for nextState in nextStates:
                all_states.add(state)
                all_states.add(nextState)
                assert state == nextState or nextState != EXPOSED_STATE, \
                    "progression into exposed state is not allowed other than in self reference"
    assert (set(infectious_states) - all_states) == set(), \
        f"mismatched infectious states and states {infectious_states} {all_states}"

    # people movement's graph
    graph = loaders.genGraphFromContactFile(commutes_table)

    # movement multipliers (dampening or heightening)
    if movement_multipliers_table is not None:
        movementMultipliers = loaders.readMovementMultipliers(
            movement_multipliers_table)
    else:
        movementMultipliers = {}

    # age-based infection matrix
    mixingMatrix = loaders.MixingMatrix(mixing_matrix_table)

    agesInInfectionMatrix = set(mixingMatrix)
    for age in mixingMatrix:
        assert agesInInfectionMatrix == set(
            mixingMatrix[age]), "infection matrix columns/rows mismatch"

    # Checks across datasets
    assert agesInInfectionMatrix == set(
        progression.keys()), "infection matrix and progression ages mismatch"
    assert agesInInfectionMatrix == {age for region in population.values() for age in region}, \
        "infection matrix and population ages mismatch"
    disconnected_nodes = set(population.keys()) - set(graph.nodes())
    if disconnected_nodes:
        log_issue(
            logger,
            f"These nodes have no contacts in the current network: {','.join(disconnected_nodes)}",
            IssueSeverity.MEDIUM,
            issues,
        )

    state0: Dict[str, Dict[Tuple[str, str], float]] = {}
    for node in list(graph.nodes()):
        region = state0.setdefault(node, {})
        for age, compartments in progression.items():
            if node not in population:
                log_issue(
                    logger,
                    f"Node {node} is not in the population table, assuming population of 0 for all ages",
                    IssueSeverity.MEDIUM,
                    issues,
                )
                pop = 0.0
            else:
                pop = population[node][age]
            region[(age, SUSCEPTIBLE_STATE)] = pop
            for compartment in compartments:
                region[(age, compartment)] = 0

    logger.info("Nodes: %s, Ages: %s, States: %s", len(state0),
                agesInInfectionMatrix, all_states)
    nop = NetworkOfPopulation(
        progression=progression,
        graph=graph,
        initialState=state0,
        mixingMatrix=mixingMatrix,
        movementMultipliers=movementMultipliers,
        infectiousStates=infectious_states,
        infectionProb=infection_prob,
        initialInfections=initial_infections,
        trials=trials,
        startDate=start_date,
        endDate=end_date,
        stochastic=stochastic_mode,
    )
    return (nop, issues)
def test_basic_simulation(age_transitions, demographics, commute_moves,
                          compartment_names, age_infection_matrix):
    age_to_trans = np.setUpParametersAges(
        loaders.readParametersAgeStructured(age_transitions))
    population = loaders.readPopulationAgeStructured(demographics)
    graph = loaders.genGraphFromContactFile(commute_moves)
    states = np.setupInternalPopulations(graph, compartment_names,
                                         list(age_to_trans.keys()), population)

    result = np.basicSimulationInternalAgeStructure(
        rand=random.Random(1),
        graph=graph,
        numInfected=10,
        timeHorizon=200,
        genericInfection=0.1,
        ageInfectionMatrix=age_infection_matrix,
        diseaseProgressionProbs=age_to_trans,
        dictOfStates=states,
    )

    expected = [
        0,
        4.27,
        5.959639,
        7.495598979703686,
        9.31292448442533,
        11.550960285080539,
        14.32076069530553,
        17.750346856443436,
        21.996595859880493,
        27.253215606191763,
        33.75958029276324,
        41.81147883471944,
        51.77434261313086,
        64.09953959129047,
        79.34443722167374,
        98.19708895391234,
        121.5065842268399,
        150.32032333168627,
        185.92974139403356,
        229.92631464707316,
        284.27004075722795,
        351.3729944719362,
        434.2010173334121,
        536.3970957055917,
        662.4304939975676,
        817.7762023518806,
        1009.1296689642635,
        1244.6620222362512,
        1534.3209088397605,
        1890.1814875375615,
        2326.8507704591293,
        2861.926080186407,
        3516.5045468063877,
        4315.734994514654,
        5289.3961276280115,
        6472.475902589639,
        7905.717433786824,
        9636.08906655341,
        11717.13446074682,
        14209.16871256282,
        17179.315999723975,
        20701.439040274323,
        24856.09052908778,
        29730.707243910434,
        35420.33217223618,
        42029.128554931965,
        49672.773024855385,
        58481.44396269627,
        68602.60309097261,
        80202.27853153124,
        93463.37789059673,
        108579.96624726593,
        125747.53880875603,
        145150.90161910592,
        166952.82966413427,
        191287.47020551964,
        218261.74745540041,
        247965.3261465324,
        280485.2367071461,
        315916.38015373435,
        354356.14564567205,
        395872.69490304653,
        440443.1364258809,
        487868.5388265991,
        537684.1860953799,
        589091.5046792259,
        640938.9095905811,
        691769.9762481726,
        739939.1843065555,
        783772.9904113912,
        821736.8679191938,
        852567.1996643285,
        875343.2246963251,
        889499.9704796937,
        894803.485637448,
        891314.7525319818,
        879359.4394061461,
        859505.977536541,
        832543.5198251844,
        799448.8236543302,
        761336.2708291251,
        719393.6436135583,
        674812.7866198674,
        628726.0228195366,
        582156.5631853839,
        535986.5646189475,
        490942.3244969345,
        447593.5332414354,
        406362.5717409869,
        367540.01510870096,
        331303.2145504978,
        297735.6728639047,
        266845.6949524783,
        238583.40447859198,
        212855.66475276518,
        189538.74944848128,
        168488.80761225612,
        149550.28647197766,
        132562.53827530914,
        117364.86191178164,
        103800.22980549172,
        91717.93520231653,
        80975.37134265121,
        71439.12677319416,
        62985.553271939556,
        55500.93643588842,
        48881.374979513224,
        43032.45371205615,
        37868.777124977256,
        33313.415413891256,
        29297.302334462536,
        25758.61423633403,
        22642.151601387908,
        19898.738109895345,
        17484.64737342592,
        15361.063743396788,
        13493.580801682876,
        11851.739073032668,
        10408.603009095552,
        9140.37625068078,
        8026.053473547509,
        7047.106679898116,
        6187.203546762776,
        5431.955332005772,
        4768.691828813375,
        4186.260919647075,
        3674.8503875840925,
        3225.8297793633656,
        2831.6102674926847,
        2485.5206191429197,
        2181.697540636489,
        1914.9888235502897,
        1680.8678687529227,
        1475.3583061787265,
        1294.9675597411838,
        1136.6283280441162,
        997.6470624276589,
        875.6586246476982,
        768.5863975872606,
        674.6072044116167,
        592.1204651473781,
        519.721085459352,
        456.1756310875024,
        400.40139364220994,
        351.44799986096695,
        308.4812575877343,
        270.76896818966605,
        237.66846737351318,
        208.61568486118352,
        183.11553854396615,
        160.73350093111426,
        141.08819527652577,
        123.8448960080496,
        108.70982326635439,
        95.42513472402354,
        83.76452961376395,
        73.52939023666997,
        64.54539531517312,
        56.65954754922215,
        49.73756475976603,
        43.66159017682611,
        38.328182852791116,
        33.64655394541582,
        29.537018798984292,
        25.929638426375362,
        22.763027221103627,
        19.98330656117008,
        17.54318645356159,
        15.401159551545785,
        13.520793793496033,
        11.870111594347737,
        10.42104499749586,
        9.148957491085977,
        8.032224330272163,
        7.051864205475331,
        6.191215972979529,
        5.435654933281273,
        4.7723438175693484,
        4.1900142350687,
        3.678774853837169,
        3.2299430438278187,
        2.835897111408885,
        2.4899466059017845,
        2.186218487054244,
        1.9195572129748524,
        1.6854370455381997,
        1.4798850786813753,
        1.29941367791204,
        1.1409611798590402,
        1.001839841559402,
        0.8796901527963475,
        0.772440733292397,
        0.6782731317724259,
        0.5955909274692558,
        0.5229926079757407,
        0.45924776170425224,
        0.40327617969564616,
        0.35412951108933594,
        0.3109751600700831,
        0.2730821502880063,
    ]

    assert result == pytest.approx(expected)