diff --git a/ogcore/default_parameters.json b/ogcore/default_parameters.json index a7d1bcce2..91aa1a18c 100644 --- a/ogcore/default_parameters.json +++ b/ogcore/default_parameters.json @@ -772,6 +772,25 @@ } } }, + "infra_investment_leakage_rate": { + "title": "Government infrastructure investment leakage rate", + "description": "Fraction of government infrastructure investment lost to leakage (e.g., corruption or other frictions) and treated as deadweight loss. Only (1 - infra_investment_leakage_rate) * I_g enters the public capital stock.", + "section_1": "Fiscal Policy Parameters", + "section_2": "Spending", + "notes": "A value of 0.0 (default) implies no leakage. A value of 0.2 implies 20% of infrastructure spending is lost before entering the public capital stock.", + "type": "float", + "value": [ + { + "value": 0.0 + } + ], + "validators": { + "range": { + "min": 0.0, + "max": 1.0 + } + } + }, "alpha_bs_T": { "title": "Proportional adjustment to government transfers relative to baseline amount when budget balance is true", "description": "Proportional adjustment to government transfers relative to baseline amount when budget balance is true. Set value for base year, click '+' to add value for next year. All future years not specified are set to last value entered.", diff --git a/ogcore/fiscal.py b/ogcore/fiscal.py index 30bc2bdce..57ef29135 100644 --- a/ogcore/fiscal.py +++ b/ogcore/fiscal.py @@ -432,9 +432,13 @@ def get_K_g(K_g0, I_g, p, method): Law of motion for the government capital stock .. math:: - K_{g,t+1} = \frac{(1 - \delta_g)K_{g,t} + I_{g,t}} + K_{g,t+1} = \frac{(1 - \delta_g)K_{g,t} + (1 - \phi_g)I_{g,t}} {(1 + \tilde{g}_{n,t+1})e^{g_y}} + where :math:`\phi_g` (``infra_investment_leakage_rate``) is the fraction + of infrastructure investment lost to leakage. When :math:`\phi_g = 0`, + there is no leakage and the formula reduces to the baseline. + Args: K_g0 (scalar): initial stock of public capital I_g (array_like): government infrastructure investment @@ -445,14 +449,17 @@ def get_K_g(K_g0, I_g, p, method): K_g (array_like): stock of public capital """ + phi_g = p.infra_investment_leakage_rate if method == "TPI": K_g = np.zeros(p.T) K_g[0] = K_g0 for t in range(p.T - 1): # TODO: numba jit this growth = (1 + p.g_n[t + 1]) * np.exp(p.g_y) - K_g[t + 1] = ((1 - p.delta_g) * K_g[t] + I_g[t]) / growth + K_g[t + 1] = ( + (1 - p.delta_g) * K_g[t] + (1 - phi_g) * I_g[t] + ) / growth else: # SS growth = (1 + p.g_n_ss) * np.exp(p.g_y) - K_g = I_g / (growth - (1 - p.delta_g)) + K_g = (1 - phi_g) * I_g / (growth - (1 - p.delta_g)) return K_g diff --git a/tests/test_fiscal.py b/tests/test_fiscal.py index 5155bd857..07f8571f5 100644 --- a/tests/test_fiscal.py +++ b/tests/test_fiscal.py @@ -381,24 +381,26 @@ def test_get_I_g(baseline_spending, Ig_baseline, method): # need to parameterize to test for TPI and SS @pytest.mark.parametrize( - "K_g0,I_g,method,expected", + "K_g0,I_g,method,leakage,expected", [ - (None, 0.2, "SS", 3.291689115882805), + (None, 0.2, "SS", 0.0, 3.291689115882805), ( 0.0, np.array([0.2, 0.3, 0.01]), "TPI", + 0.0, np.array([0, 0.19028344, 0.46284331]), ), + (None, 0.2, "SS", 0.2, 2.6333513127062443), ], - ids=["SS", "TPI"], + ids=["SS", "TPI", "SS with leakage"], ) -def test_get_K_g(K_g0, I_g, method, expected): +def test_get_K_g(K_g0, I_g, method, leakage, expected): """ Test of the law of motion for the government capital stock """ p = Specifications() - p.update_specifications({"T": 3}) + p.update_specifications({"T": 3, "infra_investment_leakage_rate": leakage}) p.g_n = np.array([0.02, 0.02, 0.02]) p.g_n_ss = 0.01