Пример #1
0
def test_plot_imm_fixed_save_fig(tmpdir):
    E = 0
    S = base_params.S
    age_per_EpS = np.arange(21, S + 21)
    imm_rates_orig = base_params.imm_rates[0, :]
    imm_rates_adj = base_params.imm_rates[-1, :]
    parameter_plots.plot_imm_fixed(
        age_per_EpS, imm_rates_orig, imm_rates_adj, E, S,
        output_dir=tmpdir)
    img = mpimg.imread(os.path.join(tmpdir, 'OrigVsAdjImm.png'))

    assert isinstance(img, np.ndarray)
Пример #2
0
def test_plot_imm_fixed():
    E = 0
    S = base_params.S
    age_per_EpS = np.arange(21, S + 21)
    imm_rates_orig = base_params.imm_rates[0, :]
    imm_rates_adj = base_params.imm_rates[-1, :]
    fig = parameter_plots.plot_imm_fixed(
        age_per_EpS, imm_rates_orig, imm_rates_adj, E, S)
    assert fig
Пример #3
0
def get_pop_objs(E, S, T, min_yr, max_yr, curr_year, GraphDiag=False):
    '''
    This function produces the demographics objects to be used in the
    OG-USA model package.

    Args:
        E (int): number of model periods in which agent is not
            economically active, >= 1
        S (int): number of model periods in which agent is economically
            active, >= 3
        T (int): number of periods to be simulated in TPI, > 2*S
        min_yr (int): age in years at which agents are born, >= 0
        max_yr (int): age in years at which agents die with certainty,
            >= 4
        curr_year (int): current year for which analysis will begin,
            >= 2016
        GraphDiag (bool): =True if want graphical output and printed
                diagnostics

    Returns:
        pop_dict (dict): includes:
            omega_path_S (Numpy array), time path of the population
                distribution from the current state to the steady-state,
                size T+S x S
            g_n_SS (scalar): steady-state population growth rate
            omega_SS (Numpy array): normalized steady-state population
                distribution, length S
            surv_rates (Numpy array): survival rates that correspond to
                each model period of life, length S
            mort_rates (Numpy array): mortality rates that correspond to
                each model period of life, length S
            g_n_path (Numpy array): population growth rates over the time
                path, length T + S

    '''
    assert curr_year >= 2019
    # age_per = np.linspace(min_yr, max_yr, E+S)
    fert_rates = get_fert(E + S, min_yr, max_yr, graph=False)
    mort_rates, infmort_rate = get_mort(E + S, min_yr, max_yr, graph=False)
    mort_rates_S = mort_rates[-S:]
    imm_rates_orig = get_imm_resid(E + S, min_yr, max_yr)
    OMEGA_orig = np.zeros((E + S, E + S))
    OMEGA_orig[0, :] = ((1 - infmort_rate) * fert_rates + np.hstack(
        (imm_rates_orig[0], np.zeros(E + S - 1))))
    OMEGA_orig[1:, :-1] += np.diag(1 - mort_rates[:-1])
    OMEGA_orig[1:, 1:] += np.diag(imm_rates_orig[1:])

    # Solve for steady-state population growth rate and steady-state
    # population distribution by age using eigenvalue and eigenvector
    # decomposition
    eigvalues, eigvectors = np.linalg.eig(OMEGA_orig)
    g_n_SS = (eigvalues[np.isreal(eigvalues)].real).max() - 1
    eigvec_raw =\
        eigvectors[:,
                   (eigvalues[np.isreal(eigvalues)].real).argmax()].real
    omega_SS_orig = eigvec_raw / eigvec_raw.sum()

    # Generate time path of the nonstationary population distribution
    omega_path_lev = np.zeros((E + S, T + S))
    pop_data = pd.read_csv(
        'https://www2.census.gov/programs-surveys/popest/technical-documentation/file-layouts/2010-2019/nc-est2019-agesex-res.csv'
    )
    pop_data = (pop_data[pop_data['SEX'] == 0][[
        'AGE', 'POPESTIMATE2016', 'POPESTIMATE2017', 'POPESTIMATE2018',
        'POPESTIMATE2019'
    ]])
    pop_data.rename(columns={
        'AGE': 'Age',
        'POPESTIMATE2016': '2016',
        'POPESTIMATE2017': '2017',
        'POPESTIMATE2018': '2018',
        'POPESTIMATE2019': '2019'
    },
                    inplace=True)
    pop_data_samp = pop_data[(pop_data['Age'] >= min_yr - 1)
                             & (pop_data['Age'] <= max_yr - 1)]
    pop_2019 = np.array(pop_data_samp['2019'], dtype='f')
    # Generate the current population distribution given that E+S might
    # be less than max_yr-min_yr+1
    age_per_EpS = np.arange(1, E + S + 1)
    pop_2019_EpS = pop_rebin(pop_2019, E + S)
    pop_2019_pct = pop_2019_EpS / pop_2019_EpS.sum()
    # Age most recent population data to the current year of analysis
    pop_curr = pop_2019_EpS.copy()
    data_year = 2019
    pop_next = np.dot(OMEGA_orig, pop_curr)
    g_n_curr = (
        (pop_next[-S:].sum() - pop_curr[-S:].sum()) / pop_curr[-S:].sum()
    )  # g_n in 2019
    pop_past = pop_curr  # assume 2018-2019 pop
    # Age the data to the current year
    for per in range(curr_year - data_year):
        pop_next = np.dot(OMEGA_orig, pop_curr)
        g_n_curr = ((pop_next[-S:].sum() - pop_curr[-S:].sum()) /
                    pop_curr[-S:].sum())
        pop_past = pop_curr
        pop_curr = pop_next

    # Generate time path of the population distribution
    omega_path_lev[:, 0] = pop_curr.copy()
    for per in range(1, T + S):
        pop_next = np.dot(OMEGA_orig, pop_curr)
        omega_path_lev[:, per] = pop_next.copy()
        pop_curr = pop_next.copy()

    # Force the population distribution after 1.5*S periods to be the
    # steady-state distribution by adjusting immigration rates, holding
    # constant mortality, fertility, and SS growth rates
    imm_tol = 1e-14
    fixper = int(1.5 * S)
    omega_SSfx = (omega_path_lev[:, fixper] / omega_path_lev[:, fixper].sum())
    imm_objs = (fert_rates, mort_rates, infmort_rate,
                omega_path_lev[:, fixper], g_n_SS)
    imm_fulloutput = opt.fsolve(immsolve,
                                imm_rates_orig,
                                args=(imm_objs),
                                full_output=True,
                                xtol=imm_tol)
    imm_rates_adj = imm_fulloutput[0]
    imm_diagdict = imm_fulloutput[1]
    omega_path_S = (omega_path_lev[-S:, :] /
                    np.tile(omega_path_lev[-S:, :].sum(axis=0), (S, 1)))
    omega_path_S[:, fixper:] = \
        np.tile(omega_path_S[:, fixper].reshape((S, 1)),
                (1, T + S - fixper))
    g_n_path = np.zeros(T + S)
    g_n_path[0] = g_n_curr.copy()
    g_n_path[1:] = ((omega_path_lev[-S:, 1:].sum(axis=0) -
                     omega_path_lev[-S:, :-1].sum(axis=0)) /
                    omega_path_lev[-S:, :-1].sum(axis=0))
    g_n_path[fixper + 1:] = g_n_SS
    omega_S_preTP = (pop_past.copy()[-S:]) / (pop_past.copy()[-S:].sum())
    imm_rates_mat = np.hstack(
        (np.tile(np.reshape(imm_rates_orig[E:], (S, 1)), (1, fixper)),
         np.tile(np.reshape(imm_rates_adj[E:], (S, 1)), (1, T + S - fixper))))

    if GraphDiag:
        # Check whether original SS population distribution is close to
        # the period-T population distribution
        omegaSSmaxdif = np.absolute(omega_SS_orig -
                                    (omega_path_lev[:, T] /
                                     omega_path_lev[:, T].sum())).max()
        if omegaSSmaxdif > 0.0003:
            print('POP. WARNING: Max. abs. dist. between original SS ' +
                  "pop. dist'n and period-T pop. dist'n is greater than" +
                  ' 0.0003. It is ' + str(omegaSSmaxdif) + '.')
        else:
            print('POP. SUCCESS: orig. SS pop. dist is very close to ' +
                  "period-T pop. dist'n. The maximum absolute " +
                  'difference is ' + str(omegaSSmaxdif) + '.')

        # Plot the adjusted steady-state population distribution versus
        # the original population distribution. The difference should be
        # small
        omegaSSvTmaxdiff = np.absolute(omega_SS_orig - omega_SSfx).max()
        if omegaSSvTmaxdiff > 0.0003:
            print('POP. WARNING: The maximimum absolute difference ' +
                  'between any two corresponding points in the original' +
                  ' and adjusted steady-state population ' +
                  'distributions is' + str(omegaSSvTmaxdiff) + ', ' +
                  'which is greater than 0.0003.')
        else:
            print('POP. SUCCESS: The maximum absolute difference ' +
                  'between any two corresponding points in the original' +
                  ' and adjusted steady-state population ' +
                  'distributions is ' + str(omegaSSvTmaxdiff))

        # Print whether or not the adjusted immigration rates solved the
        # zero condition
        immtol_solved = \
            np.absolute(imm_diagdict['fvec'].max()) < imm_tol
        if immtol_solved:
            print('POP. SUCCESS: Adjusted immigration rates solved ' +
                  'with maximum absolute error of ' +
                  str(np.absolute(imm_diagdict['fvec'].max())) +
                  ', which is less than the tolerance of ' + str(imm_tol))
        else:
            print('POP. WARNING: Adjusted immigration rates did not ' +
                  'solve. Maximum absolute error of ' +
                  str(np.absolute(imm_diagdict['fvec'].max())) +
                  ' is greater than the tolerance of ' + str(imm_tol))

        # Test whether the steady-state growth rates implied by the
        # adjusted OMEGA matrix equals the steady-state growth rate of
        # the original OMEGA matrix
        OMEGA2 = np.zeros((E + S, E + S))
        OMEGA2[0, :] = ((1 - infmort_rate) * fert_rates + np.hstack(
            (imm_rates_adj[0], np.zeros(E + S - 1))))
        OMEGA2[1:, :-1] += np.diag(1 - mort_rates[:-1])
        OMEGA2[1:, 1:] += np.diag(imm_rates_adj[1:])
        eigvalues2, eigvectors2 = np.linalg.eig(OMEGA2)
        g_n_SS_adj = (eigvalues[np.isreal(eigvalues2)].real).max() - 1
        if np.max(np.absolute(g_n_SS_adj - g_n_SS)) > 10**(-8):
            print('FAILURE: The steady-state population growth rate' +
                  ' from adjusted OMEGA is different (diff is ' +
                  str(g_n_SS_adj - g_n_SS) + ') than the steady-' +
                  'state population growth rate from the original' + ' OMEGA.')
        elif np.max(np.absolute(g_n_SS_adj - g_n_SS)) <= 10**(-8):
            print('SUCCESS: The steady-state population growth rate' +
                  ' from adjusted OMEGA is close to (diff is ' +
                  str(g_n_SS_adj - g_n_SS) + ') the steady-' +
                  'state population growth rate from the original' + ' OMEGA.')

        # Do another test of the adjusted immigration rates. Create the
        # new OMEGA matrix implied by the new immigration rates. Plug in
        # the adjusted steady-state population distribution. Hit is with
        # the new OMEGA transition matrix and it should return the new
        # steady-state population distribution
        omega_new = np.dot(OMEGA2, omega_SSfx)
        omega_errs = np.absolute(omega_new - omega_SSfx)
        print('The maximum absolute difference between the adjusted ' +
              'steady-state population distribution and the ' +
              'distribution generated by hitting the adjusted OMEGA ' +
              'transition matrix is ' + str(omega_errs.max()))

        # Plot the original immigration rates versus the adjusted
        # immigration rates
        immratesmaxdiff = \
            np.absolute(imm_rates_orig - imm_rates_adj).max()
        print('The maximum absolute distance between any two points ' +
              'of the original immigration rates and adjusted ' +
              'immigration rates is ' + str(immratesmaxdiff))

        # plots
        pp.plot_omega_fixed(age_per_EpS,
                            omega_SS_orig,
                            omega_SSfx,
                            E,
                            S,
                            output_dir=OUTPUT_DIR)
        pp.plot_imm_fixed(age_per_EpS,
                          imm_rates_orig,
                          imm_rates_adj,
                          E,
                          S,
                          output_dir=OUTPUT_DIR)
        pp.plot_population_path(age_per_EpS,
                                pop_2019_pct,
                                omega_path_lev,
                                omega_SSfx,
                                curr_year,
                                E,
                                S,
                                output_dir=OUTPUT_DIR)

    # return omega_path_S, g_n_SS, omega_SSfx, survival rates,
    # mort_rates_S, and g_n_path
    pop_dict = {
        'omega': omega_path_S.T,
        'g_n_SS': g_n_SS,
        'omega_SS': omega_SSfx[-S:] / omega_SSfx[-S:].sum(),
        'surv_rate': 1 - mort_rates_S,
        'rho': mort_rates_S,
        'g_n': g_n_path,
        'imm_rates': imm_rates_mat.T,
        'omega_S_preTP': omega_S_preTP
    }

    return pop_dict