def test_readParametersAgeStructured_less_than_100_percent():
    with pytest.raises(AssertionError):
        df = pd.DataFrame([
            {
                "age": "70+",
                "src": "A",
                "dst": "A",
                "rate": 0.5
            },
            {
                "age": "70+",
                "src": "A",
                "dst": "I",
                "rate": 0.2
            },
        ])
        loaders.readCompartmentRatesByAge(df)
def test_readParametersAgeStructured_invalid_float():
    with pytest.raises(AssertionError):
        df = pd.DataFrame([
            {
                "age": "70+",
                "src": "A",
                "dst": "A",
                "rate": 1.5
            },
            {
                "age": "70+",
                "src": "A",
                "dst": "I",
                "rate": -0.5
            },
        ])
        loaders.readCompartmentRatesByAge(df)
def test_readCompartmentRatesByAge_approximately_one():
    result = loaders.readCompartmentRatesByAge(
        pd.DataFrame([{
            "age": "70+",
            "src": "A",
            "dst": "A",
            "rate": 0.999999999
        }]))

    assert result == {"70+": {"A": {"A": 0.999999999}}}
def test_readCompartmentRatesByAge(data_api):
    result = loaders.readCompartmentRatesByAge(
        data_api.read_table("human/compartment-transition"))

    assert result == {
        "70+": {
            "E": {
                "E": pytest.approx(0.573),
                "A": pytest.approx(0.427)
            },
            "A": {
                "A": pytest.approx(0.803),
                "I": pytest.approx(0.0197),
                "R": pytest.approx(0.1773)
            },
            "I": {
                "I": pytest.approx(0.67),
                "D": pytest.approx(0.0165),
                "H": pytest.approx(0.0495),
                "R": pytest.approx(0.264)
            },
            "H": {
                "H": pytest.approx(0.9),
                "D": pytest.approx(0.042),
                "R": pytest.approx(0.058)
            },
            "R": {
                "R": pytest.approx(1.0)
            },
            "D": {
                "D": pytest.approx(1.0)
            },
        },
        "[17,70)": {
            "E": {
                "E": pytest.approx(0.573),
                "A": pytest.approx(0.427)
            },
            "A": {
                "A": pytest.approx(0.803),
                "I": pytest.approx(0.0197),
                "R": pytest.approx(0.1773)
            },
            "I": {
                "I": pytest.approx(0.67),
                "D": pytest.approx(0.0165),
                "H": pytest.approx(0.0495),
                "R": pytest.approx(0.264)
            },
            "H": {
                "H": pytest.approx(0.9),
                "D": pytest.approx(0.042),
                "R": pytest.approx(0.058)
            },
            "R": {
                "R": pytest.approx(1.0)
            },
            "D": {
                "D": pytest.approx(1.0)
            },
        },
        "[0,17)": {
            "E": {
                "E": pytest.approx(0.573),
                "A": pytest.approx(0.427)
            },
            "A": {
                "A": pytest.approx(0.803),
                "I": pytest.approx(0.0197),
                "R": pytest.approx(0.1773)
            },
            "I": {
                "I": pytest.approx(0.67),
                "D": pytest.approx(0.0165),
                "H": pytest.approx(0.0495),
                "R": pytest.approx(0.264)
            },
            "H": {
                "H": pytest.approx(0.9),
                "D": pytest.approx(0.042),
                "R": pytest.approx(0.058)
            },
            "R": {
                "R": pytest.approx(1.0)
            },
            "D": {
                "D": pytest.approx(1.0)
            },
        },
    }
示例#5
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))
示例#6
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)