diff --git a/docs/book/content/api/aggregates.rst b/docs/book/content/api/aggregates.rst index 788d96423..e83a73d79 100644 --- a/docs/book/content/api/aggregates.rst +++ b/docs/book/content/api/aggregates.rst @@ -9,5 +9,5 @@ ogcore.aggregates ------------------------------------------ .. automodule:: ogcore.aggregates - :members: get_L, get_I, get_B, get_BQ, get_C, revenue, get_r_p, + :members: get_L, get_I, get_B, get_BQ, get_RM, get_C, revenue, get_r_p, resource_constraint, get_K_splits, get_ptilde diff --git a/ogcore/SS.py b/ogcore/SS.py index c1716f3f1..c4faa456d 100644 --- a/ogcore/SS.py +++ b/ogcore/SS.py @@ -55,6 +55,7 @@ def euler_equation_solver(guesses, *args): w (scalar): real wage rate p_tilde (scalar): composite good price bq (Numpy array): bequest amounts by age, length S + rm (scalar): remittance amounts by age, length S tr (scalar): government transfer amount by age, length S ubi (vector): universal basic income (UBI) payment, length S factor (scalar): scaling factor converting model units to dollars @@ -64,7 +65,7 @@ def euler_equation_solver(guesses, *args): errros (Numpy array): errors from FOCs, length 2S """ - (r, w, p_tilde, bq, tr, ubi, factor, j, p) = args + (r, w, p_tilde, bq, rm, tr, ubi, factor, j, p) = args b_guess = np.array(guesses[: p.S]) n_guess = np.array(guesses[p.S :]) @@ -81,6 +82,7 @@ def euler_equation_solver(guesses, *args): b_splus1, n_guess, bq, + rm, factor, tr, ubi, @@ -101,6 +103,7 @@ def euler_equation_solver(guesses, *args): b_splus1, n_guess, bq, + rm, factor, tr, ubi, @@ -155,6 +158,7 @@ def euler_equation_solver(guesses, *args): b_splus1, n_guess, bq, + rm, taxes, p.e[-1, :, j], p, @@ -174,8 +178,8 @@ def inner_loop(outer_loop_vars, p, client): Args: outer_loop_vars (tuple): tuple of outer loop variables, - (bssmat, nssmat, r_p, r, w, p_m, BQ, TR, factor) or - (bssmat, nssmat, r_p, r, w, p_m, BQ, Y, TR, factor) + (bssmat, nssmat, r_p, r, w, p_m, BQ, RM, TR, factor) or + (bssmat, nssmat, r_p, r, w, p_m, BQ, RM, Y, TR, factor) bssmat (Numpy array): initial guess at savings, size = SxJ nssmat (Numpy array): initial guess at labor supply, size = SxJ r_p (scalar): return on household investment portfolio @@ -226,11 +230,13 @@ def inner_loop(outer_loop_vars, p, client): p_m = np.array(p_m) # TODO: why is this a list otherwise? p_i = np.dot(p.io_matrix, p_m) BQ = np.array(BQ) + RM = np.array(aggr.get_RM(Y, p, "SS")) # initialize array for euler errors euler_errors = np.zeros((2 * p.S, p.J)) p_tilde = aggr.get_ptilde(p_i, p.tau_c[-1, :], p.alpha_c) bq = household.get_bq(BQ, None, p, "SS") + rm = household.get_rm(RM, None, p, "SS") tr = household.get_tr(TR, None, p, "SS") ubi = p.ubi_nom_array[-1, :, :] / factor @@ -242,6 +248,7 @@ def inner_loop(outer_loop_vars, p, client): w, p_tilde, bq[:, j], + rm[:, j], tr[:, j], ubi[:, j], factor, @@ -312,6 +319,7 @@ def inner_loop(outer_loop_vars, p, client): b_splus1, nssmat, bq, + rm, net_tax, np.squeeze(p.e[-1, :, :]), p, @@ -400,6 +408,8 @@ def inner_loop(outer_loop_vars, p, client): new_factor = factor new_BQ = aggr.get_BQ(new_r_p, bssmat, None, p, "SS", False) new_bq = household.get_bq(new_BQ, None, p, "SS") + new_RM = aggr.get_RM(Y, p, "SS") + new_rm = household.get_rm(new_RM, None, p, "SS") tr = household.get_tr(TR, None, p, "SS") theta = pensions.replacement_rate_vals(nssmat, new_w, new_factor, None, p) @@ -444,6 +454,7 @@ def inner_loop(outer_loop_vars, p, client): bssmat, nssmat, new_bq, + new_rm, taxss, np.squeeze(p.e[-1, :, :]), p, @@ -532,6 +543,7 @@ def inner_loop(outer_loop_vars, p, client): K_vec, L_vec, Y_vec, + new_RM, new_TR, Y, new_factor, @@ -556,6 +568,7 @@ def SS_solver( p_m (array_like): good prices Y (scalar): real GDP BQ (array_like): aggregate bequest amount(s) + RM (array_like): remittance amount(s) TR (scalar): lump sum transfer amount factor (scalar): scaling factor converting model units to dollars p (OG-Core Specifications object): model parameters @@ -599,6 +612,7 @@ def SS_solver( new_K_vec, new_L_vec, new_Y_vec, + new_RM, new_TR, new_Y, new_factor, @@ -679,6 +693,7 @@ def SS_solver( p_m_ss = new_p_m p_i_ss = np.dot(p.io_matrix, p_m_ss) p_tilde_ss = aggr.get_ptilde(p_i_ss, p.tau_c[-1, :], p.alpha_c) + RM_ss = new_RM TR_ss = new_TR Yss = new_Y I_g_ss = fiscal.get_I_g(Yss, p.alpha_I[-1]) @@ -723,6 +738,7 @@ def SS_solver( factor_ss = factor bqssmat = household.get_bq(BQss, None, p, "SS") trssmat = household.get_tr(TR_ss, None, p, "SS") + rmssmat = household.get_rm(RM_ss, None, p, "SS") ubissmat = p.ubi_nom_array[-1, :, :] / factor_ss theta = pensions.replacement_rate_vals(nssmat, wss, factor_ss, None, p) @@ -823,6 +839,7 @@ def SS_solver( bssmat_splus1, nssmat, bqssmat, + rmssmat, taxss, np.squeeze(p.e[-1, :, :]), p, @@ -979,6 +996,7 @@ def SS_solver( "r_p_ss": r_p_ss, "theta": theta, "BQss": BQss, + "RMss": RM_ss, "factor_ss": factor_ss, "bssmat_s": bssmat_s, "cssmat": cssmat, @@ -987,6 +1005,7 @@ def SS_solver( "bqssmat": bqssmat, "TR_ss": TR_ss, "trssmat": trssmat, + "rmssmat": rmssmat, "Gss": Gss, "total_tax_revenue": total_tax_revenue, "business_tax_revenue": business_tax_revenue, @@ -1072,6 +1091,7 @@ def SS_fsolve(guesses, *args): new_K_vec, new_L_vec, new_Y_vec, + new_RM, new_TR, new_Y, new_factor, diff --git a/ogcore/aggregates.py b/ogcore/aggregates.py index 3b05415e4..70049b7a8 100644 --- a/ogcore/aggregates.py +++ b/ogcore/aggregates.py @@ -231,6 +231,53 @@ def get_BQ(r, b_splus1, j, p, method, preTP): return BQ +def get_RM(Y, p, method): + r""" + Calculation of aggregate remittances. + + .. math:: + \hat{RM}_{t} = \begin{cases} + \alpha_{RM,1}\hat{Y}_t \quad\text{for}\quad t=1 \\ + \frac{(1+g_{RM,t})}{e^{g_y}(1+\tilde{g}_{n,t})}\hat{RM}_{t-1} + \quad\text{for}\quad 2\leq t\leq T_{G1} \\ + \rho_{RM}\alpha_{RM,T}\hat{Y}_t + + (1-\rho_{RM})\frac{(1+g_{RM,t})}{e^{g_y}(1+\tilde{g}_{n,t})} + \hat{RM}_{t-1} \quad\text{for}\quad T_{G1}< t