diff --git a/CHANGELOG.md b/CHANGELOG.md index c5128f071..a93fede26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.14.2] - 2025-04-04 12:00:00 + +### Added + +- `utils.pct_change_unstationarized` replaced with `utils.unstationarize_vars`, which allows for more general use of a utility to find unstationarized values of time series output +- `output_plots.py` and `output_tables.py` are updated to all for plots and tables of unstationarized output for variables of any type, not just percentage changes. +- `ouput_tables.tp_output_dump_table` has been renamed `output_tables.time_series_table` +- `utils.param_dump_json` has been renamed `utils.params_to_json` +- API docs have been updated to include functions left out previously and for new function names + ## [0.14.1] - 2025-03-16 12:00:00 ### Bug Fix @@ -363,6 +373,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Version [0.7.0] on August 30, 2021 was the first time that the OG-USA repository was detached from all of the core model logic, which was named OG-Core. Before this version, OG-USA was part of what is now the [`OG-Core`](https://github.com/PSLmodels/OG-Core) repository. In the next version of OG-USA, we adjusted the version numbering to begin with 0.1.0. This initial version of 0.7.0, was sequential from what OG-USA used to be when the OG-Core project was called OG-USA. - Any earlier versions of OG-USA can be found in the [`OG-Core`](https://github.com/PSLmodels/OG-Core) repository [release history](https://github.com/PSLmodels/OG-Core/releases) from [v.0.6.4](https://github.com/PSLmodels/OG-Core/releases/tag/v0.6.4) (Jul. 20, 2021) or earlier. +[0.14.2]: https://github.com/PSLmodels/OG-Core/compare/v0.14.1...v0.14.2 [0.14.1]: https://github.com/PSLmodels/OG-Core/compare/v0.14.0...v0.14.1 [0.14.0]: https://github.com/PSLmodels/OG-Core/compare/v0.13.2...v0.14.0 [0.13.2]: https://github.com/PSLmodels/OG-Core/compare/v0.13.1...v0.13.2 diff --git a/README.md b/README.md index ae96b2ae1..61950a5ea 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,18 @@ | | | | --- | --- | | Org | [![PSL cataloged](https://img.shields.io/badge/PSL-cataloged-a0a0a0.svg)](https://www.PSLmodels.org) [![OS License: CCO-1.0](https://img.shields.io/badge/OS%20License-CCO%201.0-yellow)](https://github.com/PSLmodels/OG-Core/blob/master/LICENSE) [![Jupyter Book Badge](https://jupyterbook.org/badge.svg)](https://pslmodels.github.io/OG-Core/) | -| Package | [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-3916/) [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3108/) [![Python 3.11](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3118/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | +| Package | [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-31111/) [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3129/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | | Testing | ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/build_and_test.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/deploy_docs.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/check_black.yml/badge.svg?branch=master) [![Codecov](https://codecov.io/gh/PSLmodels/OG-Core/branch/master/graph/badge.svg)](https://codecov.io/gh/PSLmodels/OG-Core) | -OG-Core is an overlapping-generations (OG) model core theory, logic, and solution method algorithms that allow for dynamic general equilibrium analysis of fiscal policy. OG-Core provides a general framework and is a dependency of several country-specific OG models, such as [OG-USA](https://github.com/PSLmodels/OG-USA) and [OG-UK](https://github.com/PSLmodels/OG-UK). The model output includes changes in macroeconomic aggregates (GDP, investment, consumption), wages, interest rates, and the stream of tax revenues over time. Regularly updated documentation of the model theory--its output, and solution method--and the Python API is available [here](https://pslmodels.github.io/OG-Core). +OG-Core is an overlapping-generations (OG) model core theory, logic, and solution method algorithms that allow for dynamic general equilibrium analysis of fiscal policy. OG-Core provides a general framework and is a dependency of several country-specific OG model caliibrations, as listed in the table belowsuch as [OG-USA](https://github.com/PSLmodels/OG-USA) and [OG-UK](https://github.com/PSLmodels/OG-UK). The model output includes changes in macroeconomic aggregates (GDP, investment, consumption), wages, interest rates, and the stream of tax revenues over time. Regularly updated documentation of the model theory--its output, and solution method--and the Python API is available [here](https://pslmodels.github.io/OG-Core). + +**Country calibrations of OG-Core** +| | | | +| :-----------: | :---------: | :---------: | +| United States, [OG-USA](https://github.com/PSLmodels/OG-USA) | United Kingdom, [OG-UK](https://github.com/PSLmodels/OG-USA) | | +| Phillipines, [OG-PHL](https://github.com/EAPD-DRB/OG-PHL) | South Africa, [OG-ZAF](https://github.com/EAPD-DRB/OG-ZAF) | Indonesia, [OG-IDN](https://github.com/EAPD-DRB/OG-IDN) | +| India, [OG-IND](https://github.com/OpenSourceEcon/OG-IND) | Malaysia, [OG-MYS](https://github.com/OpenSourceEcon/OG-MYS) | | ## Disclaimer diff --git a/docs/book/content/api/output_plots.rst b/docs/book/content/api/output_plots.rst index a2e41375a..cb1d8b5ee 100644 --- a/docs/book/content/api/output_plots.rst +++ b/docs/book/content/api/output_plots.rst @@ -9,5 +9,6 @@ ogcore.output_plots ------------------------------------------ .. automodule:: ogcore.output_plots - :members: plot_aggregates, plot_gdp_ratio, ability_bar, ability_bar_ss, - ss_profiles, tpi_profiles, plot_all + :members: plot_aggregates, plot_industry_aggregates, ss_3Dplot, + plot_gdp_ratio, ability_bar, ability_bar_ss, + tpi_profiles, ss_profiles, plot_all, inequality_plot, lambda_labels diff --git a/docs/book/content/api/output_tables.rst b/docs/book/content/api/output_tables.rst index 7d5d9c292..dbb4c4d12 100644 --- a/docs/book/content/api/output_tables.rst +++ b/docs/book/content/api/output_tables.rst @@ -10,4 +10,5 @@ ogcore.output_tables .. automodule:: ogcore.output_tables :members: macro_table, macro_table_SS, ineq_table, gini_table, - wealth_moments_table, tp_output_dump_table, dynamic_revenue_decomposition + wealth_moments_table, time_series_table, + dynamic_revenue_decomposition diff --git a/docs/book/content/api/parameter_plots.rst b/docs/book/content/api/parameter_plots.rst index 16c10f463..cd458e08b 100644 --- a/docs/book/content/api/parameter_plots.rst +++ b/docs/book/content/api/parameter_plots.rst @@ -10,8 +10,9 @@ ogcore.parameter_plots .. automodule:: ogcore.parameter_plots :members: plot_imm_rates, plot_mort_rates, plot_pop_growth, - plot_ability_profiles, plot_elliptical_u, plot_chi_n, - plot_fert_rates, plot_mort_rates_data, plot_g_n, plot_omega_fixed, - plot_imm_fixed, plot_population_path, gen_3Dscatters_hist, - txfunc_graph, txfunc_sse_plot, plot_income_data, plot_2D_taxfunc + plot_population, plot_ability_profiles, plot_elliptical_u, + plot_chi_n, plot_fert_rates, plot_mort_rates_data, plot_g_n, + plot_omega_fixed, plot_imm_fixed, plot_population_path, + gen_3Dscatters_hist, txfunc_graph, txfunc_sse_plot, + plot_income_data, plot_2D_taxfunc diff --git a/docs/book/content/api/utils.rst b/docs/book/content/api/utils.rst index 2507dec81..7292953b5 100644 --- a/docs/book/content/api/utils.rst +++ b/docs/book/content/api/utils.rst @@ -22,4 +22,4 @@ ogcore.utils to_timepath_shape, get_initial_path, safe_read_pickle, rate_conversion, save_return_table, print_progress, fetch_files_from_web, not_connected, avg_by_bin, extrapolate_arrays, get_legacy_session, shift_bio_clock, - pct_change_unstationarized, param_dump_json + unstationarize_vars, params_to_json diff --git a/docs/book/content/intro/intro.md b/docs/book/content/intro/intro.md index 56c27f456..214452b2d 100644 --- a/docs/book/content/intro/intro.md +++ b/docs/book/content/intro/intro.md @@ -4,11 +4,18 @@ | | | | --- | --- | | Org | [![PSL cataloged](https://img.shields.io/badge/PSL-cataloged-a0a0a0.svg)](https://www.PSLmodels.org) [![OS License: CCO-1.0](https://img.shields.io/badge/OS%20License-CCO%201.0-yellow)](https://github.com/PSLmodels/OG-Core/blob/master/LICENSE) [![Jupyter Book Badge](https://jupyterbook.org/badge.svg)](https://pslmodels.github.io/OG-Core/) | -| Package | [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-3916/) [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3108/) [![Python 3.11](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3118/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | +| Package | [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-31111/) [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3129/) [![PyPI Latest Release](https://img.shields.io/pypi/v/ogcore.svg)](https://pypi.org/project/ogcore/) [![PyPI Downloads](https://img.shields.io/pypi/dm/ogcore.svg?label=PyPI%20downloads)](https://pypi.org/project/ogcore/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) | | Testing | ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/build_and_test.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/deploy_docs.yml/badge.svg?branch=master) ![example event parameter](https://github.com/PSLmodels/OG-Core/actions/workflows/check_black.yml/badge.svg?branch=master) [![Codecov](https://codecov.io/gh/PSLmodels/OG-Core/branch/master/graph/badge.svg)](https://codecov.io/gh/PSLmodels/OG-Core) | `OG-Core` is the core logic for a country-agnostic overlapping-generations (OG) model of an economy that allows for dynamic general equilibrium analysis of fiscal policy. The source code is openly available for download or collaboration at the GitHub repository [www.github.com/PSLmodels/OG-Core](https://github.com/PSLmodels/OG-Core), or you can click on the GitHub icon at the top right of this page. +**Country calibrations of OG-Core** +| | | | +| :-----------: | :---------: | :---------: | +| United States, [OG-USA](https://github.com/PSLmodels/OG-USA) | United Kingdom, [OG-UK](https://github.com/PSLmodels/OG-USA) | | +| Phillipines, [OG-PHL](https://github.com/EAPD-DRB/OG-PHL) | South Africa, [OG-ZAF](https://github.com/EAPD-DRB/OG-ZAF) | Indonesia, [OG-IDN](https://github.com/EAPD-DRB/OG-IDN) | +| India, [OG-IND](https://github.com/OpenSourceEcon/OG-IND) | Malaysia, [OG-MYS](https://github.com/OpenSourceEcon/OG-MYS) | | + The model output focuses changes in macroeconomic aggregates (GDP, investment, consumption), wages, interest rates, and the stream of tax revenues over time. Although `OG-Core` can be run independently based on default parameter values (currently representing something similar to the United States), it is meant to be a dependency of a country-specific calibration. This documentation contains the following major sections, which are regularly updated. * Contributing to `OG-Core` diff --git a/ogcore/__init__.py b/ogcore/__init__.py index 523be0821..e733effbf 100644 --- a/ogcore/__init__.py +++ b/ogcore/__init__.py @@ -20,4 +20,4 @@ from ogcore.txfunc import * from ogcore.utils import * -__version__ = "0.14.1" +__version__ = "0.14.2" diff --git a/ogcore/output_plots.py b/ogcore/output_plots.py index ee7851e57..09c8f2adb 100644 --- a/ogcore/output_plots.py +++ b/ogcore/output_plots.py @@ -48,8 +48,7 @@ def plot_aggregates( 'levels': plot variables in model units 'forecast': plots variables in levels relative to baseline economic forecast - stationarized (bool): whether used stationarized variables (False - only affects pct_diff right now) + stationarized (bool): whether used stationarized variables num_years_to_plot (integer): number of years to include in plot start_year (integer): year to start plot forecast_data (array_like): baseline economic forecast series, @@ -76,6 +75,13 @@ def plot_aggregates( if plot_type == "pct_diff" or plot_type == "diff": assert reform_tpi is not None fig1, ax1 = plt.subplots() + if not stationarized: + for v in var_list: + base_tpi[v] = utils.unstationarize_vars(v, base_tpi, base_params) + if reform_tpi: + reform_tpi[v] = utils.unstationarize_vars( + v, reform_tpi, reform_params + ) for i, v in enumerate(var_list): assert ( v in VAR_LABELS.keys() @@ -85,17 +91,7 @@ def plot_aggregates( # Compute just percentage point changes for rates plot_var = reform_tpi[v] - base_tpi[v] else: - if stationarized: - plot_var = (reform_tpi[v] - base_tpi[v]) / base_tpi[v] - else: - pct_changes = utils.pct_change_unstationarized( - base_tpi, - base_params, - reform_tpi, - reform_params, - output_vars=[v], - ) - plot_var = pct_changes[v] + plot_var = (reform_tpi[v] - base_tpi[v]) / base_tpi[v] ylabel = r"Pct. change" plt.plot( year_vec, @@ -182,6 +178,7 @@ def plot_industry_aggregates( var_list=["Y_m"], ind_names_list=None, plot_type="pct_diff", + stationarized=True, num_years_to_plot=50, start_year=DEFAULT_START_YEAR, forecast_data=None, @@ -201,6 +198,7 @@ def plot_industry_aggregates( reform_params (OG-Core Specifications class): reform parameters object var_list (list): names of variable to plot + plot_type (string): type of plot, can be: 'pct_diff': plots percentage difference between baseline and reform ((reform-base)/base) @@ -209,6 +207,7 @@ def plot_industry_aggregates( 'levels': plot variables in model units 'forecast': plots variables in levels relative to baseline economic forecast + stationarized (bool): whether used stationarized variables num_years_to_plot (integer): number of years to include in plot start_year (integer): year to start plot forecast_data (array_like): baseline economic forecast series, @@ -236,6 +235,14 @@ def plot_industry_aggregates( assert base_params.start_year == reform_params.start_year year_vec = np.arange(start_year, start_year + num_years_to_plot) start_index = start_year - base_params.start_year + # Unstationarize variables if needed + if not stationarized: + for v in var_list: + base_tpi[v] = utils.unstationarize_vars(v, base_tpi, base_params) + if reform_tpi: + reform_tpi[v] = utils.unstationarize_vars( + v, reform_tpi, reform_params + ) # Check that reform included if doing pct_diff or diff plot if plot_type == "pct_diff" or plot_type == "diff": assert reform_tpi is not None diff --git a/ogcore/output_tables.py b/ogcore/output_tables.py index fc3311a1e..0e857a4e0 100644 --- a/ogcore/output_tables.py +++ b/ogcore/output_tables.py @@ -4,7 +4,7 @@ from ogcore.constants import VAR_LABELS, DEFAULT_START_YEAR from ogcore import tax from ogcore.utils import save_return_table, Inequality -from ogcore.utils import pct_change_unstationarized +from ogcore.utils import unstationarize_vars cur_path = os.path.split(os.path.abspath(__file__))[0] @@ -64,6 +64,13 @@ def macro_table( assert base_params.start_year == reform_params.start_year year_vec = np.arange(start_year, start_year + num_years) start_index = start_year - base_params.start_year + if not stationarized: + for v in var_list: + base_tpi[v] = unstationarize_vars(v, base_tpi, base_params) + if reform_tpi: + reform_tpi[v] = unstationarize_vars( + v, reform_tpi, reform_params + ) # Check that reform included if doing pct_diff or diff plot if output_type == "pct_diff" or output_type == "diff": assert reform_tpi is not None @@ -76,17 +83,7 @@ def macro_table( for i, v in enumerate(var_list): if output_type == "pct_diff": # multiple by 100 so in percentage points - if stationarized: - results = ((reform_tpi[v] - base_tpi[v]) / base_tpi[v]) * 100 - else: - pct_changes = pct_change_unstationarized( - base_tpi, - base_params, - reform_tpi, - reform_params, - output_vars=[v], - ) - results = pct_changes[v] * 100 + results = ((reform_tpi[v] - base_tpi[v]) / base_tpi[v]) * 100 results_years = results[start_index : start_index + num_years] results_overall = ( ( @@ -452,11 +449,12 @@ def wealth_moments_table( return table -def tp_output_dump_table( +def time_series_table( base_params, base_tpi, reform_params=None, reform_tpi=None, + stationarized=True, table_format=None, path=None, ): @@ -471,6 +469,7 @@ def tp_output_dump_table( reform_params (OG-Core Specifications class): reform parameters object reform_tpi (dictionary): TP output from reform run + stationarized (bool): whether to report stationarized output table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to @@ -501,6 +500,14 @@ def tp_output_dump_table( "total_tax_revenue", "business_tax_revenue", ] + # unstationarize variables if needed + if not stationarized: + for v in vars_to_keep: + base_tpi[v] = unstationarize_vars(v, base_tpi, base_params) + if reform_tpi: + reform_tpi[v] = unstationarize_vars( + v, reform_tpi, reform_params + ) base_dict = {k: base_tpi[k] for k in vars_to_keep} # update key names base_dict_final = dict( diff --git a/ogcore/utils.py b/ogcore/utils.py index 7d8aab50b..a58e2d4f2 100644 --- a/ogcore/utils.py +++ b/ogcore/utils.py @@ -1209,127 +1209,94 @@ def shift_bio_clock( return param_out -def pct_change_unstationarized( - tpi_base, - param_base, - tpi_reform, - param_reform, - output_vars=["K", "Y", "C", "L", "r", "w"], +def unstationarize_vars( + var, + tpi_vars, + params, ): """ - This function takes the time paths of variables from the baseline - and reform and parameters from the baseline and reform runs and - computes percent changes for each variable in the output_vars list. - The function first unstationarizes the time paths of the variables - and then computes the percent changes. + This function takes a model variable and returns the unstationarized + value by adjusting for underlying growth in labor productivity + and population growth (where necessary). Args: - tpi_base (Numpy array): time path of the output variables from + var (string): name of variable to unstationarize + tpi_vars (Numpy array): time path of the output variables from the baseline run - param_base (Specifications object): dictionary of parameters + params (Specifications object): parameters from the baseline run - tpi_reform (Numpy array): time path of the output variables from - the reform run - param_reform (Specifications object): dictionary of parameters - from the reform run - output_vars (list): list of variables for which to compute - percent changes Returns: - pct_changes (dict): dictionary of percent changes for each - variable in output_vars list + pct_changes (array_like): unstationarized values for var """ # compute non-stationary variables - non_stationary_output = {"base": {}, "reform": {}} - pct_changes = {} - T = param_base.T - for var in output_vars: - if var in [ - "Y", - "B", - "K", - "K_f", - "K_d", - "C", - "I", - "K_g", - "I_g", - "Y_vec", - "K_vec", - "C_vec", - "I_total", - "I_d", - "BQ", - "TR", - "total_tax_revenue", - "business_tax_revenue", - "iit_payroll_tax_revenue", - "iit_revenue", - "payroll_tax_revenue", - "agg_pension_outlays", - "bequest_tax_revenue", - "wealth_tax_revenue", - "cons_tax_revenue", - "G", - "D", - "D_f", - "D_d", - "UBI_path", - "new_borrowing_f", - "debt_service_f", - ]: - non_stationary_output["base"][var] = ( - tpi_base[var][:T] - * np.cumprod(1 + param_base.g_n[:T]) - * np.exp(param_base.g_y * np.arange(param_base.T)) - ) - non_stationary_output["reform"][var] = ( - tpi_reform[var][:T] - * np.cumprod(1 + param_reform.g_n[:T]) - * np.exp(param_reform.g_y * np.arange(param_reform.T)) - ) - elif var in [ - "L", - "L_vec", - ]: - non_stationary_output["base"][var] = tpi_base[var][ - :T - ] * np.cumprod(1 + param_base.g_n[:T]) - non_stationary_output["reform"][var] = tpi_reform[var][ - :T - ] * np.cumprod(1 + param_reform.g_n[:T]) - elif var in [ - "w", - "ubi_path", - "tr_path", - "bq_path", - "bmat_splus1", - "bmat_s", - "c_path", - "y_before_tax_path", - "tax_path", - ]: - non_stationary_output["base"][var] = tpi_base[var][:T] * np.exp( - param_base.g_y * np.arange(param_base.T) - ) - non_stationary_output["reform"][var] = tpi_reform[var][ - :T - ] * np.exp(param_reform.g_y * np.arange(param_reform.T)) - else: - non_stationary_output["base"][var] = tpi_base[var][:T] - non_stationary_output["reform"][var] = tpi_reform[var][:T] - - # calculate percent change - pct_changes[var] = ( - non_stationary_output["reform"][var] - / non_stationary_output["base"][var] - - 1 - ) + T = params.T + pop_growth = np.cumprod(1 + params.g_n[:T]) + prod_growth = np.exp(params.g_y * np.arange(params.T)) + if ("_m" in var) or ("_i" in var): + pop_growth = pop_growth.reshape(T, 1) + prod_growth = prod_growth.reshape(T, 1) + if var in [ + "Y", + "B", + "K", + "K_f", + "K_d", + "C", + "I", + "K_g", + "I_g", + "Y_m", + "K_m", + "C_i", + "I_total", + "I_d", + "BQ", + "TR", + "total_tax_revenue", + "business_tax_revenue", + "iit_payroll_tax_revenue", + "iit_revenue", + "payroll_tax_revenue", + "agg_pension_outlays", + "bequest_tax_revenue", + "wealth_tax_revenue", + "cons_tax_revenue", + "G", + "D", + "D_f", + "D_d", + "UBI_path", + "new_borrowing_f", + "debt_service_f", + ]: + non_stationary_output = tpi_vars[var][:T] * pop_growth * prod_growth + elif var in [ + "L", + "L_m", + ]: + non_stationary_output = tpi_vars[var][:T] * pop_growth + + elif var in [ + "w", + "ubi", + "tr", + "bq", + "b_sp1", + "b_s", + "c", + "c_i", + "before_tax_income", + "hh_taxes", + ]: + non_stationary_output = tpi_vars[var][:T] * prod_growth + else: + non_stationary_output = tpi_vars[var][:T] - return pct_changes + return non_stationary_output -def param_dump_json(p, path=None): +def params_to_json(p, path=None): """ This function creates a JSON file with the model parameters of the format used for the default_parameters.json file. @@ -1352,13 +1319,25 @@ def param_dump_json(p, path=None): else: converted_data[key] = val - # Parameters that need to be turned into annual rates for default_parameters.json - # g_y_annual - # beta_annual - # delta_annual - # delta_tau_annual - # delta_g_annual - # world_int_rate_annual + # Parameters that need to be turned into annual rates for + # default_parameters.json + annual_list = [ + "g_y_annual", + "beta_annual", + "delta_annual", + "delta_tau_annual", + "delta_g_annual", + "world_int_rate_annual", + ] + for v in annual_list: + val = getattr(p, v.replace("_annual", "")) + annual_value = (1 + val) ** ( + p.S / ((p.ending_age - p.starting_age)) + ) - 1 + if isinstance(annual_value, np.ndarray): + converted_data[v] = annual_value.tolist() + else: + converted_data[v] = annual_value # Convert to JSON string json_str = json.dumps(converted_data, indent=4) diff --git a/setup.py b/setup.py index 56d7f70ff..4ad5c2b44 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="ogcore", - version="0.14.1", + version="0.14.2", author="Jason DeBacker and Richard W. Evans", license="CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", description="A general equilibrium overlapping generations model for fiscal policy analysis", diff --git a/tests/test_output_tables.py b/tests/test_output_tables.py index 1114c3a43..0de8bf161 100644 --- a/tests/test_output_tables.py +++ b/tests/test_output_tables.py @@ -135,8 +135,8 @@ def test_wealth_moments_table(): assert isinstance(df, pd.DataFrame) -def test_tp_output_dump_table(): - df = output_tables.tp_output_dump_table( +def test_time_series_table(): + df = output_tables.time_series_table( base_params, base_tpi, reform_params=reform_params, diff --git a/tests/test_utils.py b/tests/test_utils.py index b73284ba2..669d8f2fb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -942,7 +942,7 @@ def test_shift_bio_clock(start_period, end_period, total_effect, expected): "Different growth rates", ], ) -def test_pct_change_unstationarized(p1, p2, expected): +def test_unstationarize_vars(p1, p2, expected): """ A test of the percentage change calculation function """ @@ -962,34 +962,34 @@ def test_pct_change_unstationarized(p1, p2, expected): "r": np.ones(p2.T) * 0.06, "w": np.ones(p2.T) * 1.3, } - pct_change = utils.pct_change_unstationarized( - base_tpi, - p1, - reform_tpi, - p2, - output_vars=["K", "Y", "C", "L", "r", "w"], - ) + pct_change = {} + for k in base_tpi.keys(): + base_unstationarized = utils.unstationarize_vars(k, base_tpi, p1) + reform_unstationarized = utils.unstationarize_vars(k, reform_tpi, p2) + pct_change[k] = ( + reform_unstationarized - base_unstationarized + ) / base_unstationarized for key in pct_change.keys(): print("Checking ", key) assert np.allclose(pct_change[key], expected[key]) -def test_param_dump_json(): +def test_params_to_json(): """ - Test of the param_dump_json function + Test of the params_to_json function """ p = Specifications() - j_str = utils.param_dump_json(p) + j_str = utils.params_to_json(p) assert isinstance(j_str, str) -def test_param_dump_json_save(tmpdir): +def test_params_to_json_save(tmpdir): """ - Test of the param_dump_json function + Test of the params_to_json function """ p = Specifications() - utils.param_dump_json(p, path=os.path.join(tmpdir, "test.json")) + utils.params_to_json(p, path=os.path.join(tmpdir, "test.json")) # read in file with open(os.path.join(tmpdir, "test.json"), "r") as f: j_str = f.read()