def test_with_non_teaching_staff():
    """
    When with_non_teaching_staff is True, each school should be created with non
    teaching staff. Otherwise when False, there should be no non teaching staff
    in schools.

    """
    sp.logger.info(f'Testing the effect of the parameter with_non_teaching_staff.')

    test_pars = sc.dcp(pars)
    test_pars.with_non_teaching_staff = True
    pop_1 = sp.Pop(**test_pars)
    popdict_1 = pop_1.to_dict()

    test_pars.with_non_teaching_staff = False
    pop_2 = sp.Pop(**test_pars)
    popdict_2 = pop_2.to_dict()

    school_staff_1 = {}
    for i, person in popdict_1.items():
        if person['scid'] is not None:
            school_staff_1.setdefault(person['scid'], 0)
        if person['sc_staff']:
            school_staff_1[person['scid']] += 1

    staff_ids_2 = set()
    for i, person in popdict_2.items():
        if person['sc_staff']:
            staff_ids_2.add(i)

    # with_non_teaching_staff == True so minimum number of staff per school needs to be 1
    assert min(school_staff_1.values()) >= 1, f"with_non_teaching_staff parameter check failed when set to True."

    # with_non_teaching_staff == False so there should be no one who shows up with sc_staff set to 1
    assert len(staff_ids_2) == 0, f"with_non_teaching_staff parameter check failed when set to False."
예제 #2
0
def test_inter_grade_mixing(school_mixing_type='random'):
    """
    When school_mixing_type is 'age_clustered' then inter_grade_mixing should
    rewire a fraction of the edges between students in the same age or grade to
    be edges with any other student in the school.

    When school_mixing_type is 'random' or 'age_and_class_clustered',
    inter_grade_mixing has no effect.

    Args:
        school_mixing_type (str): The mixing type for schools, 'random', 'age_clustered', or 'age_and_class_clustered'.

    """
    sp.logger.info(f'Testing the effect of the parameter inter_grade_mixing for school_mixing_type: {school_mixing_type}')

    test_pars = sc.dcp(pars)
    test_pars['school_mixing_type'] = school_mixing_type

    pop_1 = sp.Pop(**test_pars)
    popdict_1 = pop_1.to_dict()

    test_pars['inter_grade_mixing'] = 0.3
    pop_2 = sp.Pop(**test_pars)
    popdict_2 = pop_2.to_dict()

    # make an adjacency matrix of edges between students
    adjm_1 = np.zeros((101, 101))
    adjm_2 = np.zeros((101, 101))

    student_ids = set()
    for i, person in popdict_1.items():
        if person['sc_student']:
            student_ids.add(i)

    for ni, i in enumerate(student_ids):

        contacts_1 = popdict_1[i]['contacts']['S']
        contacts_2 = popdict_2[i]['contacts']['S']

        student_contacts_1 = list(set(contacts_1).intersection(student_ids))
        student_contacts_2 = list(set(contacts_2).intersection(student_ids))

        age_i = popdict_1[i]['age']

        for nj, j in enumerate(student_contacts_1):
            age_j = popdict_1[j]['age']
            adjm_1[age_i][age_j] += 1

        for nj, j in enumerate(student_contacts_2):
            age_j = popdict_2[j]['age']
            adjm_2[age_i][age_j] += 1

    if school_mixing_type in ['random', 'age_and_class_clustered']:
        assert np.not_equal(adjm_1, adjm_2).sum() == 0, f"inter_grade_mixing parameter check failed. Different values for this parameter produced different results for school_mixing_type: {school_mixing_type}."

    elif school_mixing_type in ['age_clustered']:
        assert np.not_equal(adjm_1, adjm_2).sum() > 0, f"inter_grade_mixing parameter check failed. It produced the same results for different values of this parameter for school_mixing_type: {school_mixing_type}."
def test_plot_ages(do_show=False, do_save=False):
    """
    Test that the age comparison plotting method in sp.Pop class works.

    Note:
        With any popdict, you will need to supply more information to
        tell the method where to look for expected data.
    """
    sp.logger.info(
        "Test that the age comparison plotting method with sp.Pop object.")
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_pop_ages_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    fig, ax = pop.plot_ages(**kwargs)
    # fig, ax = pop.plot_ages()  # to plot without extra information

    assert isinstance(fig, mplt.figure.Figure), 'Check 1 failed.'
    print('Check passed. Figure 1 made.')

    popdict = pop.to_dict()
    kwargs.datadir = sp.datadir  # extra information required
    kwargs.figname = f"test_popdict_ages_{kwargs.location}_popdict"
    kwargs.do_show = False
    fig2, ax2 = sp.plot_ages(popdict, **kwargs)
    # fig2, ax2 = sp.plot_ages(popdict)  # to plot without extra information
    if not kwargs.do_show:
        plt.close()
    assert isinstance(fig, mplt.figure.Figure), 'Check 2 failed.'
    print('Check passed. Figure 2 made.')
    return fig, ax, pop
예제 #4
0
def test_ltcf_resident_ages(do_show=False):
    """
    Compare the ltcf resident ages generated with those expected for the location.
    """
    sp.logger.info(f"Testing that ltcf resident ages align with the expected resident ages for the location.")
    test_pars = sc.dcp(pars)

    # to actually match decently, you need to model a higher population size, but for regular
    # test purposes, large sizes will be quite a lot to test on every merge
    test_pars['n'] = settings.pop_sizes.large
    pop = sp.Pop(**test_pars)
    pop_dict = pop.to_dict()

    ltcf_resident_rates_by_age = sp.get_long_term_care_facility_use_rates(sp.settings.datadir,
                                                                          country_location=pop.country_location,
                                                                          state_location=pop.state_location,
                                                                          )
    expected_ltcf_rates = ltcf_resident_rates_by_age.values()
    ltcf_resident_ages = dict.fromkeys(ltcf_resident_rates_by_age.keys(), 0)
    age_count = pop.count_pop_ages()

    for i, person in pop_dict.items():
        if person['ltcf_res']:
            ltcf_resident_ages[person['age']] += 1

    gen_ltcf_rates = {a: ltcf_resident_ages[a] / age_count[a] for a in ltcf_resident_ages}

    fig, ax = sppl.plot_array(expected_ltcf_rates, generated=gen_ltcf_rates.values(), do_show=False, binned=True)
    ax.set_xlabel('LTCF Resident Ages')
    ax.set_title('LTCF Resident Use Rates by Age')
    ax.set_ylim(0., 1.)
    ax.set_xlim(0., 100)

    if do_show:
        plt.show()
예제 #5
0
def test_separate_school_types_for_seattle_metro(do_show=False, do_save=False):
    """
    Notes:
        By default, when no location is given and use_default is set to True,
        data pulled in will be for seattle metro and school type data will
        default to previous seattle metro data with pre-k and elementary kept
        separate.
    """
    sp.logger.info(
        "Creating schools where pre-k and elementary schools are separate and school sizes are the same for all school types. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations."
    )
    test_pars = sc.dcp(pars)
    test_pars.location = None  # seattle_metro results with school size distribution the same for all types
    test_pars.state_location = None  # no state information; will call default data for seattle metro but create figure without location information in title
    test_pars.country_location = None  # no country information; will call default data for seattle metro but create figure without location information in title
    pop = sp.Pop(**test_pars)
    kwargs = sc.objdict(sc.dcp(test_pars))
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    fig, ax = pop.plot_school_sizes(**kwargs)

    enrollment_by_school_type = pop.count_enrollment_by_school_type(
        **test_pars)
    school_types = enrollment_by_school_type.keys()

    assert ('pk' in school_types) and (
        'es' in school_types
    ), 'Check failed. pk and es school type are not separately created.'
    print('Check passed.')

    return fig, ax, pop, school_types
예제 #6
0
def test_plot_schools_sizes_without_types(do_show=False, do_save=False):
    """Test that without school types, all schools are put together in one group."""
    sp.logger.info(
        "Creating schools where school types are not specified. Test school size distribution plotting method without school types. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations."
    )
    pars.with_school_types = False  # need to rerun the population
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.datadir = sp.settings.datadir
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    kwargs.screen_width_factor = 0.30
    kwargs.screen_height_factor = 0.20
    kwargs.width = 5
    kwargs.height = 3.2
    kwargs.figname = f"test_all_school_size_distributions_{kwargs.location}_pop"
    fig, ax = pop.plot_school_sizes(**kwargs)

    enrollment_by_school_type = pop.count_enrollment_by_school_type()
    school_types = list(enrollment_by_school_type.keys())

    assert school_types[0] is None and len(
        school_types
    ) == 1, f"Check 3 failed. School types created: {school_types}."

    return fig, ax, pop
예제 #7
0
def test_ltcf_resident_to_staff_ratios(do_show=False):
    """
    Compare the ltcf resident to staff ratios generated to the data available for the location.
    """
    sp.logger.info(f'Testing the ratios of ltcf residents to staff.')

    # to actually match decently, you need to model a higher population size, but for regular
    # test purposes, large sizes will be quite a lot to test on every merge
    pop = sp.Pop(**pars)
    popdict = pop.to_dict()
    loc_pars = pop.loc_pars

    expected_ltcf_ratio_distr = sp.get_long_term_care_facility_resident_to_staff_ratios_distr(
        **loc_pars)
    resident_to_staff_ratio_brackets = sp.get_long_term_care_facility_resident_to_staff_ratios_brackets(
        **loc_pars)

    bins = [
        resident_to_staff_ratio_brackets[i][0] - 1
        for i in range(len(resident_to_staff_ratio_brackets))
    ] + [
        resident_to_staff_ratio_brackets[max(
            resident_to_staff_ratio_brackets.keys())][0]
    ]

    ltcfs = {}
    for i, person in popdict.items():
        if person['ltcfid'] is not None:
            ltcfs.setdefault(person['ltcfid'], {'residents': [], 'staff': []})
            if person['ltcf_res'] is not None:
                ltcfs[person['ltcfid']]['residents'].append(i)
            elif person['ltcf_staff']:
                ltcfs[person['ltcfid']]['staff'].append(i)

    gen_ratios = []
    for l in ltcfs:

        ratio = len(ltcfs[l]['residents']) / len(ltcfs[l]['staff'])
        gen_ratios.append(ratio)

    hist, bins = np.histogram(gen_ratios, bins=bins)
    gen_ltcf_ratio_distr = {i: hist[i] / sum(hist) for i in range(len(hist))}

    xlabels = [
        f'{resident_to_staff_ratio_brackets[b][0]:.0f}'
        for b in resident_to_staff_ratio_brackets
    ]

    fig, ax = sppl.plot_array(list(expected_ltcf_ratio_distr.values()),
                              generated=list(gen_ltcf_ratio_distr.values()),
                              names=xlabels,
                              do_show=False,
                              binned=True)

    ax.set_xlabel('LTCF Resident to Staff Ratio')
    ax.set_title('Comparison of LTCF Resident to Staff Ratios')
    ax.set_ylim(0., 1.)

    if do_show:
        plt.show()
예제 #8
0
def test_age_brackets_used_with_contact_matrix():
    """
    Test that the age brackets used in sp.Pop.generate() matches the contact matrices used.

    Note:
        This is a test to ensure that within sp.Pop.generate() uses the right age brackets. By default, without specifying nbrackets in sp.get_census_age_brackets(), the number of age brackets will not match the granularity of the contact matrix.

    """

    sp.logger.info(
        "Test that the age brackets used in sp.Pop.generate() with the contact matrices have the same number of bins as the contact matrices."
    )

    pop = sp.Pop(**pars)
    sheet_name = pop.sheet_name

    loc_pars = pop.loc_pars

    contact_matrices = sp.get_contact_matrices(sp.settings.datadir,
                                               sheet_name=sheet_name)
    contact_matrix_nbrackets = contact_matrices[list(
        contact_matrices.keys())[0]].shape[0]
    cm_age_brackets = sp.get_census_age_brackets(
        **sc.mergedicts(loc_pars, {'nbrackets': contact_matrix_nbrackets}))
    assert contact_matrix_nbrackets == len(
        cm_age_brackets
    ), f'Check failed, len(contact_matrix_nbrackets): {contact_matrix_nbrackets} does not match len(cm_age_brackets): {len(cm_age_brackets)}.'
    print(
        f'Check passed. The age brackets loaded match the number of age brackets for the contact matrices used for the location.'
    )
예제 #9
0
def test_age_brackets_used_with_contact_matrix():
    """
    Test that the age brackets used in sp.Pop.generate() matches the contact matrices used.

    Note:
        This is a test to ensure that within sp.Pop.generate() uses the right age brackets. By default, without specifying nbrackets in sp.get_census_age_brackets(), the number of age brackets will not match the granularity of the contact matrix.

    """

    sp.logger.info(
        "Test that the age brackets used in sp.Pop.generate() with the contact matrices have the same number of bins as the contact matrices."
    )

    pop_obj = sp.Pop(**pars)
    sheet_name = pop_obj.sheet_name
    pop = pop_obj.to_dict(
    )  # this is basically what sp.make_population does...

    contact_matrix_dic = sp.get_contact_matrix_dic(sp.datadir,
                                                   sheet_name=sheet_name)
    contact_matrix_nbrackets = contact_matrix_dic[list(
        contact_matrix_dic.keys())[0]].shape[0]
    cm_age_brackets = sp.get_census_age_brackets(
        sp.datadir,
        country_location=pop_obj.country_location,
        state_location=pop_obj.state_location,
        location=pop_obj.location,
        nbrackets=contact_matrix_nbrackets)
    assert contact_matrix_nbrackets == len(
        cm_age_brackets
    ), f'Check failed, len(contact_matrix_nbrackets): {contact_matrix_nbrackets} does not match len(cm_age_brackets): {len(cm_age_brackets)}.'
    print(
        f'Check passed. The age brackets loaded match the number of age brackets for the contact matrices used for the location.'
    )
예제 #10
0
def test_plot_school_sizes(do_show, do_save, artifact_dir):
    """
    Test that the school size distribution by type plotting method in sp.Pop
    class works for a large population. This will be a longer test that is
    run as part of our end-to-end testing suite.

    Visually show how the school size distribution generated compares to the
    data for the location being simulated.

    Notes:
        The larger the population size, the better the generated school size
        distributions by school type can match the expected data. If generated
        populations are too small, larger schools will be missed and in
        general there won't be enough schools generated to apply statistical
        tests.
    """
    sp.logger.info("Test that the school size distribution by type plotting method in sp.Pop class works. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations.")
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    if artifact_dir:
        kwargs.figdir = artifact_dir
    kwargs.screen_height_factor = 0.20
    kwargs.hspace = 0.8
    kwargs.bottom = 0.09
    kwargs.keys_to_exclude = ['uv']
    kwargs.cmap = cmr.get_sub_cmap('cmo.curl', 0.08, 1)

    fig, ax = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig, mplt.figure.Figure), 'End-to-end school sizes check failed.'
    print('Check passed. Figure made.')

    return fig, ax, pop
예제 #11
0
def test_pop_n():
    sp.logger.info("Testing when n is None.")
    test_pars = sc.dcp(pars)
    test_pars['n'] = None
    pop = sp.Pop(**test_pars)
    assert pop.n == sp.defaults.default_pop_size, 'Check failed.'
    print('Check passed')
예제 #12
0
def test_people():
    sc.heading('Basic People tests with plotting')
    pop = sp.Pop(n=50)
    ppl = pop.to_people()
    ppl.plot()
    ppl.plot_graph()
    return ppl
예제 #13
0
def test_Dakar():
    """Test Dakar population constructed."""
    sp.logger.info("Not a real test yet. To be filled out.")
    pop = sp.Pop(**pars)
    assert pop.location == 'Dakar', 'population location information is not set to Dakar'

    sp.reset_default_settings()  # reset defaults
예제 #14
0
def test_student_all_staff_ratio(average_student_all_staff_ratio,
                                 do_show,
                                 do_save,
                                 get_fig_dir,
                                 threshold=2):
    """
    Test case to check average_student_all_staff_ratio by taking average of students contacts from teachers and staff

    Args:
        average_student_all_staff_ratio: The average number of students per staff members at school
        (including both teachers and non teachers)

    Returns:
        None
    """
    testpars = dict(
        average_student_all_staff_ratio=average_student_all_staff_ratio, )
    pop = sp.Pop(**pars, **testpars)
    ratios = get_teacher_staff_ratio(pop.popdict,
                                     "average_student_all_staff_ratio",
                                     average_student_all_staff_ratio, do_show,
                                     do_save, get_fig_dir)
    sp.check_normal(actual=ratios,
                    expected=average_student_all_staff_ratio,
                    label='average_student_all_staff_ratio',
                    check='mean')
    return
예제 #15
0
def test_average_student_teacher_ratio(average_student_teacher_ratio,
                                       do_show,
                                       do_save,
                                       get_fig_dir,
                                       threshold=2):
    """
    Test case for average_student_teacher_ratio by taking average of student contacts per teacher

    Args:
        average_student_teacher_ratio: The average number of students per teacher

    Returns:
        None
    """
    testpars = dict(
        average_student_teacher_ratio=average_student_teacher_ratio, )
    pop = sp.Pop(**pars, **testpars)
    ratios = get_teacher_staff_ratio(pop.popdict,
                                     "average_student_teacher_ratio",
                                     average_student_teacher_ratio, do_show,
                                     do_save, get_fig_dir)
    sp.check_normal(actual=ratios,
                    expected=average_student_teacher_ratio,
                    label='average_student_teacher_ratio',
                    check='mean')
    return
예제 #16
0
def test_log_level():
    """Test resetting the log level"""
    sp.logger.setLevel('DEBUG')
    pars = sc.objdict(n=100)
    pop = sp.Pop(**pars)
    sp.logger.setLevel(
        'INFO'
    )  # need to reset logger level - this changes a synthpops setting
예제 #17
0
def test_plots(do_plot=False):
    ''' Basic plots '''
    if not do_plot:
        pl.switch_backend('agg')  # Plot but don't show
    pop = sp.Pop(n=5000)  # default parameters, 5k people
    fig1 = pop.plot_people()  # equivalent to cv.Sim.people.plot()
    fig2 = pop.plot_contacts()  # equivalent to sp.plot_contact_matrix(popdict)
    return [fig1, fig2]
예제 #18
0
def test_plot_school_sizes(do_show=False, do_save=False):
    """
    Test that the school size distribution by type plotting method in sp.Pop
    class works.

    Visually show how the school size distribution generated compares to the
    data for the location being simulated.

    Notes:
        The larger the population size, the better the generated school size
        distributions by school type can match the expected data. If generated
        populations are too small, larger schools will be missed and in
        general there won't be enough schools generated to apply statistical
        tests.

    """
    sp.logger.info(
        "Test that the school size distribution by type plotting method in sp.Pop class works. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations."
    )
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    kwargs.screen_height_factor = 0.20
    kwargs.hspace = 0.8
    kwargs.bottom = 0.09
    kwargs.keys_to_exclude = ['uv']
    kwargs.cmap = cmr.get_sub_cmap('cmo.curl', 0.08, 1)

    fig, ax = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig, mplt.figure.Figure), 'Check 1 failed.'
    print('Check passed. Figure 1 made.')

    # works on popdict
    sp.logger.info("Test school size distribution plotting method on popdict.")
    popdict = pop.popdict
    kwargs.datadir = sp.settings.datadir
    kwargs.do_show = False
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_popdict"
    fig2, ax2 = sp.plot_school_sizes(popdict, **kwargs)
    if not kwargs.do_show:
        plt.close()
    assert isinstance(fig2, mplt.figure.Figure), 'Check 2 failed.'
    print('Check passed. Figure 2 made.')

    sp.logger.info(
        "Test school size distribution plotting method with keys_to_exclude as a string and without comparison."
    )
    kwargs.keys_to_exclude = 'uv'
    kwargs.comparison = False
    fig3, ax3 = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig3, mplt.figure.Figure), 'Check 3 failed.'
    print(
        'Check passed. Figure 3 made with keys_to_exclude as a string and without comparison.'
    )

    return fig, ax, pop
def test_filter_age(create_pop):
    pop = sp.Pop(**pars)
    ages = [15, 16, 17, 18, 19]
    pids = sp.filter_people(pop, ages=ages)
    expected_pids = []
    for p in pop.popdict.items():
        if p[1]['age'] in ages:
            expected_pids.append(p[0])
    assert set(expected_pids) == set(pids)
예제 #20
0
def test_small_pop_n(caplog):
    sp.logger.info("Testing when n is small.")
    test_pars = sc.dcp(pars)
    test_pars['n'] = sp.defaults.default_pop_size - 1
    with caplog.at_level(logging.WARNING):
        pop2 = sp.Pop(**test_pars)
        assert pop2.n == sp.defaults.default_pop_size - 1, 'Check failed.'
        assert len(
            caplog.text
        ) != 0, 'Check failed. No warning message about small pop size n.'
    print('Check passed')
예제 #21
0
def test_api(do_plot=False):
    ''' More examples of basic API usage '''
    pop = sp.Pop(n=20000) # default parameters, 5k people
    pop.save('test_api.pop') # save as pickle
    pop.to_json('test_api.json') # save as JSON
    popdict = pop.to_dict() # export from class to standard python object; current default synthpops output
    if do_plot:
        # pop.plot() # do the most obvious plotting thing, whatever that may be...
        pop.plot_people() # equivalent to cv.Sim.people.plot()
        pop.plot_contacts() # equivalent to sp.plot_contact_matrix(popdict)
    return popdict
def test_Spokane():
    """Test that a Dakar population can be created with the basic SynthPops API."""
    sp.logger.info("Test that a Spokane population can be created with the basic SynthPops API.")

    pop = sp.Pop(**pars)
    loc_pars = pop.loc_pars
    age_dist = sp.read_age_bracket_distr(**loc_pars)
    assert len(age_dist) == 20, f'Check failed, len(age_dist): {len(age_dist)}'  # will remove if this passes in github actions test

    sp.set_location_defaults('defaults')  # Reset default values after this test is complete.
    return pop
예제 #23
0
def test_Nepal():
    """Test Nepal population constructed."""
    sp.logger.info(
        "Test that Nepal contact networks can be made. Not a guarantee that the population made matches age mixing patterns well yet."
    )

    # make a basic population
    pop = sp.Pop(**pars)
    assert pop.country_location == 'Nepal', "population location information is not set to Malawi"
    sp.reset_default_settings(
    )  # reset defaults so that other tests in parallel are not impacted
예제 #24
0
def test_ltcf_two_group_reduction_off():
    """
    Test that populations can be created with ltcfs that don't split people
    into two groups (residents and staff) to create edges based on role.
    """
    sp.logger.info("Testing population generation with ltcf connections created randomly instead of based on role. This means there is no guarantee that every resident is connected with a staff member. ")
    test_pars = sc.dcp(pars)
    test_pars.use_two_group_reduction = False
    pop = sp.Pop(**test_pars)

    assert len(pop.popdict) == test_pars.n, 'Check failed. Did not generate the right number of people.'
    print('Check passed.')
예제 #25
0
def test_random_schools(average_class_size):
    """
    There is a lower bound to the average_class_size and how well clustering
    and density will match when group sizes are small and any change in discrete
    numbers changes these values significantly. It does not mean that the networks
    created are wrong, but rather that at such low sizes, it becomes difficult
    to test their validity with the same thresholds as graphs with higher average
    degrees.
    """
    sp.logger.info("Test random school networks.")
    test_pars = sc.dcp(pars)
    test_pars['average_class_size'] = average_class_size
    pop = sp.Pop(**test_pars)

    G = nx.Graph()

    for i, person in pop.popdict.items():
        if person['scid'] is not None:

            # only for students and teachers
            if (person['sc_student'] == 1) | (person['sc_teacher'] == 1):
                contacts = person['contacts']['S']

                # we only expect this to pass for edges among students and teachers, non teaching staff are added after
                contacts = [
                    c for c in contacts if (pop.popdict[c]['sc_student'] == 1)
                    | (pop.popdict[c]['sc_teacher'] == 1)
                ]
                edges = [(i, c) for c in contacts]
                G.add_edges_from(edges)

    g = [G.subgraph(c) for c in nx.connected_components(G)
         ]  # split into each disconnected school

    for c in range(len(g)):

        expected_density = sp.get_expected_density(average_class_size,
                                                   len(g[c].nodes()))
        # for Erdos-Renyi random graphs, expected clustering is approximated by the average degree / number of nodes. Expected clustering is the average of the clustering coefficients over all nodes in the graph, where node i has clustering coefficient: 2 * ei / ki * (ki - 1).
        expected_clustering = average_class_size / len(g[c].nodes())
        expected_clustering = min(expected_clustering, 1)
        density = nx.density(g[c])
        clustering = nx.transitivity(g[c])

        lowerbound = 0.8
        upperbound = 1.2
        # check overall density of edges is as expected
        assert expected_density * lowerbound < density < expected_density * upperbound, f'Check failed on random graph densities. {len(g[c].nodes())} {len(g[c].edges())}'
        # check that the distribution of edges is random and clustered as expected for a random graph
        assert expected_clustering * lowerbound < clustering < expected_clustering * upperbound, f'Check failed on random graph clustering. {clustering} {density} {expected_density}, {expected_clustering} {np.mean([g[c].degree(n) for n in g[c].nodes()])}'
        print(
            f"Check passed. School {c}, size {len(g[c].nodes())} with random mixing has clustering {clustering:.3f} and density {density:.3f} close to expected values {expected_density:.3f}, {expected_clustering:.3f}."
        )
def pop_exploration():
    sp.logger.info(
        "Exploration of the Malawi population generation with default methods and missing data filled in with Senegal data"
    )
    sp.set_location_defaults(country_location="Senegal")
    pop = sp.Pop(**pars)
    print(pop.summarize())
    pop.plot_ages()
    pop.plot_enrollment_rates_by_age()
    sp.set_location_defaults()
    plt.show()
    sp.reset_default_settings()  # reset defaults
def test_Malawi():
    """Test Malawi population constructed."""
    sp.logger.info(
        "Test that Malawi contact networks can be made. Not a guarantee that the population made matches age mixing patterns well yet."
    )

    # reset the default location to pull other data
    sp.set_location_defaults(country_location="Senegal")
    # make a basic population
    pop = sp.Pop(**pars)
    assert pop.country_location == 'Malawi', "population location information is not set to Malawi"
    sp.reset_default_settings()  # reset defaults
예제 #28
0
def test_average_class_size(average_class_size,
                            do_show,
                            do_save,
                            get_fig_dir,
                            quantiles=None):
    """
    Test case to check average_class_size by taking average of student-student contacts

    Args:
        average_class_size: The average classroom size.

    Returns:
        None
    """
    testpars = dict(
        average_class_size=average_class_size,
        # average_student_teacher_ratio = average_class_size,  # DM: note that this parameter will overide the average class size parameter when school mixing types are something other than random or undefined (which defaults to random) --- method refactor work for schools will clarify these relationships
    )
    pop = sp.Pop(**pars, **testpars)
    plotting_kwargs = sc.objdict(do_show=do_show,
                                 do_save=do_save,
                                 figdir=get_fig_dir)
    contacts = sp.get_contact_counts_by_layer(pop.popdict, with_layer_ids=1)[0]
    plotting_kwargs.append("title_prefix",
                           f"Average Class Size = {average_class_size}")
    plotting_kwargs.append("figname",
                           f"contact_average_class_size_{average_class_size}")
    sp.plot_contact_counts(contacts, **plotting_kwargs)
    counts = []
    if not pop.school_pars.with_school_types:
        counts.extend(contacts['sc_student']['all'])
        counts.extend(contacts['sc_teacher']['all'])
        counts.extend(contacts['sc_staff']['all'])

    elif pop.school_pars.with_school_types and pop.school_pars.school_mixing_type == 'age_and_class_clustered':

        counts.extend(contacts['sc_student']['sc_student'])

    sp.check_poisson(actual=counts,
                     expected=average_class_size,
                     label='average_class_size',
                     check='dist')
    # visual check with scipy.stats.probplot -- temporary, just to show that the null hypothesis should pass here for the distribution
    fig, ax = plt.subplots(1, 1)
    res = stats.probplot(counts,
                         dist=stats.poisson,
                         sparams=(average_class_size, ),
                         plot=ax)
    if do_show:
        plt.show()
    plt.close()
    return
예제 #29
0
def create_sample_pop_e2e():
    """
        fixture to create and return a sample population for the session

    Returns:
        a sample population based on sample_pars
    """
    sp.logger.info("Use sample_pars to create sample_pop population")
    sample_pop = sp.Pop(**sample_pars)
    sp.logger.info(
        "If you define a fixture with the same name, this fixture may be overridden!"
    )
    return sample_pop
def test_age_distribution_used():
    """
    Test that the age distribution used in sp.Pop.generate() is the expected one for the location specified.
    """
    sp.logger.info("Test that the age distribution used in sp.Pop.generate() are the expected age distributions. \nThis should be binned to the default number of age brackets (cfg.nbrackets).")

    pop = sp.Pop(**pars)
    loc_pars = pop.loc_pars
    age_dist = sp.read_age_bracket_distr(**loc_pars)
    assert len(age_dist) == sp.settings.nbrackets, f'Check failed, len(age_dist): {len(age_dist)} does not match sp.config.nbrackets: {sp.config.nbrackets}.'
    print(f'Check passed, len(age_dist): {len(age_dist)} == sp.config.nbrackets: {sp.settings.nbrackets}.')

    return pop