ogeth 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ogeth-0.1.0/ogeth.egg-info → ogeth-0.2.0}/PKG-INFO +88 -17
- {ogeth-0.1.0 → ogeth-0.2.0}/README.md +85 -13
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/__init__.py +1 -1
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/calibrate.py +4 -2
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/income.py +2 -12
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/macro_params.py +33 -134
- ogeth-0.2.0/ogeth/ogeth_default_parameters.json +874546 -0
- {ogeth-0.1.0 → ogeth-0.2.0/ogeth.egg-info}/PKG-INFO +88 -17
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/requires.txt +1 -1
- {ogeth-0.1.0 → ogeth-0.2.0}/pyproject.toml +17 -5
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_macro_params.py +4 -47
- ogeth-0.1.0/ogeth/ogeth_default_parameters.json +0 -103789
- {ogeth-0.1.0 → ogeth-0.2.0}/LICENSE +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/MANIFEST.in +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/constants.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/data/IFPRI_SAM_ETH_2022_SAM.csv +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/input_output.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/labor.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/ogeth_multi_industry_parameters.json +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/test_est_chi_n.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/update_baseline.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/utils.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/SOURCES.txt +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/dependency_links.txt +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/top_level.txt +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/setup.cfg +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_calibrate.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_import_smoke.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_input_output.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_run_example.py +0 -0
- {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_update_baseline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ogeth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Ethiopia Calibration for OG-Core
|
|
5
5
|
Author: Marcelo LaFleur, Richard W. Evans, and Jason DeBacker
|
|
6
6
|
License: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
@@ -14,12 +14,11 @@ Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
21
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
-
Requires-Python: <3.14,>=3.
|
|
21
|
+
Requires-Python: <3.14,>=3.12
|
|
23
22
|
Description-Content-Type: text/markdown
|
|
24
23
|
License-File: LICENSE
|
|
25
24
|
Requires-Dist: numpy
|
|
@@ -47,7 +46,7 @@ Requires-Dist: ipython; extra == "dev"
|
|
|
47
46
|
Requires-Dist: ipykernel; extra == "dev"
|
|
48
47
|
Requires-Dist: jupyter; extra == "dev"
|
|
49
48
|
Provides-Extra: docs
|
|
50
|
-
Requires-Dist: jupyter-book<2.0.0; extra == "docs"
|
|
49
|
+
Requires-Dist: jupyter-book<2.0,>=1.0; extra == "docs"
|
|
51
50
|
Requires-Dist: sphinx>=3.5.4; extra == "docs"
|
|
52
51
|
Requires-Dist: sphinx-book-theme>=0.1.3; extra == "docs"
|
|
53
52
|
Requires-Dist: sphinx-argparse; extra == "docs"
|
|
@@ -69,28 +68,100 @@ OG-ETH is an overlapping-generations (OG) model that allows for dynamic general
|
|
|
69
68
|
|
|
70
69
|
## Using and contributing to OG-ETH
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
Install and run OG-ETH by cloning this GitHub repository and installing the `ogeth` package with its dependencies using [`uv`](https://docs.astral.sh/uv/), as detailed below. (Installing the `ogeth` package from [PyPI](https://pypi.org/project/ogeth/) with `pip` is no longer the recommended path: on the Python versions many machines ship, `pip` either refuses the current release outright — as on the Python 3.9 built into macOS — or silently pairs it with an older `ogcore` than the model is tested against, and even on a supported Python the PyPI route does not pin the `ogcore` version the repository is tested against. The `uv` workflow installs the exact tested versions of every dependency, including a compatible Python interpreter.)
|
|
73
72
|
|
|
74
|
-
###
|
|
73
|
+
### Installation
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
* Open your terminal and install the [`ogeth`](https://pypi.org/project/ogeth/) package from the Python Package Index by typing `pip install ogeth`.
|
|
78
|
-
* Navigate to a folder `./YourFolderName/` where you want to save scripts to run OG-ETH and output from the simulations in those scripts.
|
|
79
|
-
* Copy the python script [`run_og_eth.py`](https://github.com/EAPD-DRB/OG-ETH/blob/main/examples/run_og_eth.py) from the OG-ETH GitHub repository into your folder as `./YourFolderName/run_og_eth.py`.
|
|
80
|
-
* Run the model with an example reform from terminal/command prompt by typing `python run_og_eth.py`.
|
|
75
|
+
There are two ways to install OG-ETH: the easy way, using the OG model family's universal installer, and a manual install that runs the same steps one command at a time. Both start from a terminal, put the model in a new OG-ETH folder inside your current directory (a freshly opened terminal starts in your home folder), and need git.
|
|
81
76
|
|
|
82
|
-
|
|
77
|
+
#### Before you start: git
|
|
78
|
+
|
|
79
|
+
On a Mac where you have never used git before, run this line first and accept the dialog that appears:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
xcode-select --install
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
On Windows, install Git first (skip this if you already have it):
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
winget install --id Git.Git -e --source winget
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### The easy way: the universal installer
|
|
92
|
+
|
|
93
|
+
The OG model family has a [universal installer](https://github.com/PSLmodels/OG-Core/blob/master/scripts/QUICK_INSTALL.md) that installs the uv tool, downloads the model, builds its environment, and verifies it — for OG-ETH or any of its sibling country models.
|
|
94
|
+
|
|
95
|
+
On macOS and Linux, paste:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
curl -fsSL https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.sh -o og-install.sh
|
|
99
|
+
bash og-install.sh --repo og-eth --yes
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
On Windows (PowerShell), paste:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
$f = "$env:TEMP\og-install.ps1"; irm https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.ps1 -OutFile $f; powershell -ExecutionPolicy Bypass -File $f -Repo og-eth -Yes
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
When the installer finishes, run the example. On macOS and Linux, paste:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
source $HOME/.local/bin/env
|
|
112
|
+
cd OG-ETH
|
|
113
|
+
uv run python examples/run_og_eth.py
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
On Windows, open a new PowerShell window (so the just-installed tools are found) and paste:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
cd OG-ETH
|
|
120
|
+
uv run python examples/run_og_eth.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Manual install
|
|
124
|
+
|
|
125
|
+
The same setup as individual commands. On macOS and Linux, paste:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
129
|
+
source $HOME/.local/bin/env
|
|
130
|
+
git clone https://github.com/EAPD-DRB/OG-ETH.git
|
|
131
|
+
cd OG-ETH
|
|
132
|
+
uv run python examples/run_og_eth.py
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The second line makes the just-installed uv available in the current terminal; from your next terminal session it is available automatically.
|
|
136
|
+
|
|
137
|
+
On Windows (PowerShell), install uv:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Then open a new PowerShell window (so the just-installed tools are found) and paste:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
git clone https://github.com/EAPD-DRB/OG-ETH.git
|
|
147
|
+
cd OG-ETH
|
|
148
|
+
uv run python examples/run_og_eth.py
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### What happens
|
|
152
|
+
|
|
153
|
+
The first `uv run` creates the project environment if it does not exist yet — downloading a compatible Python interpreter if needed and installing the exact locked dependencies — and then runs the example. Early in the run you may be asked for a UN API token; just press return, and the model reads the same population data from a public mirror and continues. A full baseline-plus-reform run takes from 35 minutes to more than two hours; when it finishes, its plots and tables are saved under `./examples/OG-ETH-Example/` (see the list of outputs below).
|
|
154
|
+
|
|
155
|
+
### Installing for development or contributing
|
|
83
156
|
|
|
84
|
-
* On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
|
|
85
|
-
* Install [`uv`](https://docs.astral.sh/uv/) by following the [installation instructions](https://docs.astral.sh/uv/getting-started/installation/) for your platform (or simply run `pip install uv`).
|
|
86
157
|
* Fork this repository and clone your fork to a directory on your computer.
|
|
87
|
-
* From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies
|
|
158
|
+
* From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies (`uv` downloads a compatible Python if you don't already have one).
|
|
88
159
|
* For docs/Jupyter Book work, also run `uv sync --extra dev --extra docs`.
|
|
160
|
+
* Run commands in the environment with `uv run <command>`, or activate it first with `source .venv/bin/activate` (macOS/Linux) or `.\.venv\Scripts\Activate.ps1` (Windows).
|
|
89
161
|
|
|
90
162
|
### Run an example of the model
|
|
91
163
|
|
|
92
|
-
*
|
|
93
|
-
* Run the model with an example reform: `uv run python run_og_eth.py` (or activate the venv first with `source .venv/bin/activate` on macOS/Linux or `.\.venv\Scripts\Activate.ps1` on Windows, then `python run_og_eth.py`).
|
|
164
|
+
* From the repository root, run the model with an example reform: `uv run python examples/run_og_eth.py`.
|
|
94
165
|
* You can adjust the `./examples/run_og_eth.py` by modifying model parameters specified in the dictionary passed to the `p.update_specifications()` calls.
|
|
95
166
|
* Model outputs will be saved in the following files:
|
|
96
167
|
* `./examples/OG-ETH-Example/OG-ETH_example_plots`
|
|
@@ -11,28 +11,100 @@ OG-ETH is an overlapping-generations (OG) model that allows for dynamic general
|
|
|
11
11
|
|
|
12
12
|
## Using and contributing to OG-ETH
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Install and run OG-ETH by cloning this GitHub repository and installing the `ogeth` package with its dependencies using [`uv`](https://docs.astral.sh/uv/), as detailed below. (Installing the `ogeth` package from [PyPI](https://pypi.org/project/ogeth/) with `pip` is no longer the recommended path: on the Python versions many machines ship, `pip` either refuses the current release outright — as on the Python 3.9 built into macOS — or silently pairs it with an older `ogcore` than the model is tested against, and even on a supported Python the PyPI route does not pin the `ogcore` version the repository is tested against. The `uv` workflow installs the exact tested versions of every dependency, including a compatible Python interpreter.)
|
|
15
15
|
|
|
16
|
-
###
|
|
16
|
+
### Installation
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
* Open your terminal and install the [`ogeth`](https://pypi.org/project/ogeth/) package from the Python Package Index by typing `pip install ogeth`.
|
|
20
|
-
* Navigate to a folder `./YourFolderName/` where you want to save scripts to run OG-ETH and output from the simulations in those scripts.
|
|
21
|
-
* Copy the python script [`run_og_eth.py`](https://github.com/EAPD-DRB/OG-ETH/blob/main/examples/run_og_eth.py) from the OG-ETH GitHub repository into your folder as `./YourFolderName/run_og_eth.py`.
|
|
22
|
-
* Run the model with an example reform from terminal/command prompt by typing `python run_og_eth.py`.
|
|
18
|
+
There are two ways to install OG-ETH: the easy way, using the OG model family's universal installer, and a manual install that runs the same steps one command at a time. Both start from a terminal, put the model in a new OG-ETH folder inside your current directory (a freshly opened terminal starts in your home folder), and need git.
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
#### Before you start: git
|
|
21
|
+
|
|
22
|
+
On a Mac where you have never used git before, run this line first and accept the dialog that appears:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
xcode-select --install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
On Windows, install Git first (skip this if you already have it):
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
winget install --id Git.Git -e --source winget
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### The easy way: the universal installer
|
|
35
|
+
|
|
36
|
+
The OG model family has a [universal installer](https://github.com/PSLmodels/OG-Core/blob/master/scripts/QUICK_INSTALL.md) that installs the uv tool, downloads the model, builds its environment, and verifies it — for OG-ETH or any of its sibling country models.
|
|
37
|
+
|
|
38
|
+
On macOS and Linux, paste:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
curl -fsSL https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.sh -o og-install.sh
|
|
42
|
+
bash og-install.sh --repo og-eth --yes
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
On Windows (PowerShell), paste:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
$f = "$env:TEMP\og-install.ps1"; irm https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.ps1 -OutFile $f; powershell -ExecutionPolicy Bypass -File $f -Repo og-eth -Yes
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
When the installer finishes, run the example. On macOS and Linux, paste:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
source $HOME/.local/bin/env
|
|
55
|
+
cd OG-ETH
|
|
56
|
+
uv run python examples/run_og_eth.py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
On Windows, open a new PowerShell window (so the just-installed tools are found) and paste:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
cd OG-ETH
|
|
63
|
+
uv run python examples/run_og_eth.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Manual install
|
|
67
|
+
|
|
68
|
+
The same setup as individual commands. On macOS and Linux, paste:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
72
|
+
source $HOME/.local/bin/env
|
|
73
|
+
git clone https://github.com/EAPD-DRB/OG-ETH.git
|
|
74
|
+
cd OG-ETH
|
|
75
|
+
uv run python examples/run_og_eth.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The second line makes the just-installed uv available in the current terminal; from your next terminal session it is available automatically.
|
|
79
|
+
|
|
80
|
+
On Windows (PowerShell), install uv:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Then open a new PowerShell window (so the just-installed tools are found) and paste:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
git clone https://github.com/EAPD-DRB/OG-ETH.git
|
|
90
|
+
cd OG-ETH
|
|
91
|
+
uv run python examples/run_og_eth.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### What happens
|
|
95
|
+
|
|
96
|
+
The first `uv run` creates the project environment if it does not exist yet — downloading a compatible Python interpreter if needed and installing the exact locked dependencies — and then runs the example. Early in the run you may be asked for a UN API token; just press return, and the model reads the same population data from a public mirror and continues. A full baseline-plus-reform run takes from 35 minutes to more than two hours; when it finishes, its plots and tables are saved under `./examples/OG-ETH-Example/` (see the list of outputs below).
|
|
97
|
+
|
|
98
|
+
### Installing for development or contributing
|
|
25
99
|
|
|
26
|
-
* On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
|
|
27
|
-
* Install [`uv`](https://docs.astral.sh/uv/) by following the [installation instructions](https://docs.astral.sh/uv/getting-started/installation/) for your platform (or simply run `pip install uv`).
|
|
28
100
|
* Fork this repository and clone your fork to a directory on your computer.
|
|
29
|
-
* From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies
|
|
101
|
+
* From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies (`uv` downloads a compatible Python if you don't already have one).
|
|
30
102
|
* For docs/Jupyter Book work, also run `uv sync --extra dev --extra docs`.
|
|
103
|
+
* Run commands in the environment with `uv run <command>`, or activate it first with `source .venv/bin/activate` (macOS/Linux) or `.\.venv\Scripts\Activate.ps1` (Windows).
|
|
31
104
|
|
|
32
105
|
### Run an example of the model
|
|
33
106
|
|
|
34
|
-
*
|
|
35
|
-
* Run the model with an example reform: `uv run python run_og_eth.py` (or activate the venv first with `source .venv/bin/activate` on macOS/Linux or `.\.venv\Scripts\Activate.ps1` on Windows, then `python run_og_eth.py`).
|
|
107
|
+
* From the repository root, run the model with an example reform: `uv run python examples/run_og_eth.py`.
|
|
36
108
|
* You can adjust the `./examples/run_og_eth.py` by modifying model parameters specified in the dictionary passed to the `p.update_specifications()` calls.
|
|
37
109
|
* Model outputs will be saved in the following files:
|
|
38
110
|
* `./examples/OG-ETH-Example/OG-ETH_example_plots`
|
|
@@ -86,9 +86,10 @@ class Calibration:
|
|
|
86
86
|
p.T,
|
|
87
87
|
0,
|
|
88
88
|
99,
|
|
89
|
-
country_id="
|
|
89
|
+
country_id="231",
|
|
90
90
|
initial_data_year=p.start_year - 1,
|
|
91
91
|
final_data_year=p.start_year + 1,
|
|
92
|
+
income_percentiles=p.lambdas.flatten(),
|
|
92
93
|
GraphDiag=False,
|
|
93
94
|
download_path=demographic_data_path,
|
|
94
95
|
)
|
|
@@ -100,9 +101,10 @@ class Calibration:
|
|
|
100
101
|
p.T,
|
|
101
102
|
0,
|
|
102
103
|
99,
|
|
103
|
-
country_id="
|
|
104
|
+
country_id="231",
|
|
104
105
|
initial_data_year=p.start_year - 1,
|
|
105
106
|
final_data_year=p.start_year + 1,
|
|
107
|
+
income_percentiles=p.lambdas.flatten(),
|
|
106
108
|
GraphDiag=False,
|
|
107
109
|
)
|
|
108
110
|
|
|
@@ -116,14 +116,7 @@ def get_e_interp(
|
|
|
116
116
|
)
|
|
117
117
|
a = x.root
|
|
118
118
|
e_new = usa_params.e[0, :, :] * np.exp(a * usa_params.e[0, :, :])
|
|
119
|
-
emat_new_scaled = (
|
|
120
|
-
e_new
|
|
121
|
-
/ (
|
|
122
|
-
e_new
|
|
123
|
-
* usa_params.omega_SS.reshape(usa_params.S, 1)
|
|
124
|
-
* usa_params.lambdas.reshape(1, usa_params.J)
|
|
125
|
-
).sum()
|
|
126
|
-
)
|
|
119
|
+
emat_new_scaled = e_new / (e_new * usa_params.omega_SS).sum()
|
|
127
120
|
# Now interpolate for the cases where S and/or J not the same in the
|
|
128
121
|
# country parameterization as in the default USA parameterization
|
|
129
122
|
if (
|
|
@@ -182,10 +175,7 @@ def get_e_interp(
|
|
|
182
175
|
(new_s_mesh, new_j_mesh),
|
|
183
176
|
method="linear",
|
|
184
177
|
)
|
|
185
|
-
emat_new_scaled = (
|
|
186
|
-
emat_new
|
|
187
|
-
/ (emat_new * age_wgts.reshape(S, 1) * lambdas.reshape(1, J)).sum()
|
|
188
|
-
)
|
|
178
|
+
emat_new_scaled = emat_new / (emat_new * age_wgts).sum()
|
|
189
179
|
|
|
190
180
|
if plot_path is not None:
|
|
191
181
|
kwargs = {"path": plot_path, "filesuffix": "_intrp_scaled"}
|
|
@@ -15,6 +15,11 @@ from pathlib import Path
|
|
|
15
15
|
# Public capital elasticity; see firms.md.
|
|
16
16
|
GAMMA_G_LIC = 0.1
|
|
17
17
|
|
|
18
|
+
# Start year for the g_y_annual average-growth calculation; matches the
|
|
19
|
+
# documented window in macro.md (average annual GDP-per-capita growth
|
|
20
|
+
# 2006-2024 = 6.0%).
|
|
21
|
+
G_Y_START_YEAR = 2006
|
|
22
|
+
|
|
18
23
|
|
|
19
24
|
def _fetch_wb_data(indicators, country_iso, start_year, end_year, source):
|
|
20
25
|
"""
|
|
@@ -236,12 +241,6 @@ def get_macro_params(
|
|
|
236
241
|
"""
|
|
237
242
|
# initialize a dictionary of parameters
|
|
238
243
|
macro_parameters = {}
|
|
239
|
-
# baseline date formatted for World Bank data
|
|
240
|
-
baseline_YYYYQ = (
|
|
241
|
-
str(data_end_date.year)
|
|
242
|
-
+ "Q"
|
|
243
|
-
+ str(pd.Timestamp(data_end_date).quarter)
|
|
244
|
-
)
|
|
245
244
|
|
|
246
245
|
"""
|
|
247
246
|
Retrieve data from the World Bank World Development Indicators.
|
|
@@ -256,12 +255,11 @@ def get_macro_params(
|
|
|
256
255
|
"General government final consumption expenditure (current US$)"
|
|
257
256
|
): "NE.CON.GOVT.CD",
|
|
258
257
|
}
|
|
259
|
-
# Quarterly
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
258
|
+
# Quarterly public-sector-debt (QPSD) indicators are intentionally
|
|
259
|
+
# not fetched for OG-ETH: the World Bank QPSD database has no Ethiopia
|
|
260
|
+
# data. The debt parameters (initial_debt_ratio,
|
|
261
|
+
# initial_foreign_debt_ratio, zeta_D) are hand-calibrated from the
|
|
262
|
+
# Ethiopia MoF Public Sector Debt Bulletin No. 51 (see macro.md).
|
|
265
263
|
if update_from_api:
|
|
266
264
|
try:
|
|
267
265
|
wb_data_a = _fetch_wb_data(
|
|
@@ -271,116 +269,32 @@ def get_macro_params(
|
|
|
271
269
|
data_end_date.year,
|
|
272
270
|
source=2,
|
|
273
271
|
)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
source=20,
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
# Get the latest valid data if baseline_YYYYQ is missing/NaN
|
|
283
|
-
def get_valid_data(series, baseline_YYYYQ):
|
|
284
|
-
value = series.get(baseline_YYYYQ, None)
|
|
285
|
-
|
|
286
|
-
if pd.isna(value):
|
|
287
|
-
latest_non_nan = series.dropna().last_valid_index()
|
|
288
|
-
|
|
289
|
-
if latest_non_nan is not None:
|
|
290
|
-
print(
|
|
291
|
-
f"Warning: No data for {baseline_YYYYQ}. "
|
|
292
|
-
f"Using last available quarter: "
|
|
293
|
-
f"{latest_non_nan}"
|
|
294
|
-
)
|
|
295
|
-
value = series.get(latest_non_nan, None)
|
|
296
|
-
else:
|
|
297
|
-
print(
|
|
298
|
-
"Warning: No historical data available. "
|
|
299
|
-
"Skipping update."
|
|
300
|
-
)
|
|
301
|
-
value = None
|
|
302
|
-
|
|
303
|
-
return value
|
|
304
|
-
|
|
305
|
-
# Compute macro parameters from WB data
|
|
306
|
-
macro_parameters["initial_debt_ratio"] = get_valid_data(
|
|
307
|
-
pd.Series(wb_data_q["Gross PSD Gen Gov - percentage of GDP"])
|
|
308
|
-
/ 100,
|
|
309
|
-
baseline_YYYYQ,
|
|
310
|
-
)
|
|
311
|
-
print(
|
|
312
|
-
"initial_debt_ratio updated from World Bank API: "
|
|
313
|
-
f"{macro_parameters['initial_debt_ratio']}"
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
# Compute initial_foreign_debt_ratio safely
|
|
317
|
-
if (
|
|
318
|
-
"Gross PSD USD - external creditors" in wb_data_q.columns
|
|
319
|
-
and "Gross PSD USD - domestic creditors" in wb_data_q.columns
|
|
320
|
-
):
|
|
321
|
-
total_debt = (
|
|
322
|
-
wb_data_q["Gross PSD USD - domestic creditors"]
|
|
323
|
-
+ wb_data_q["Gross PSD USD - external creditors"]
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
# Avoid division by zero
|
|
327
|
-
wb_data_q["foreign_debt_ratio"] = wb_data_q[
|
|
328
|
-
"Gross PSD USD - external creditors"
|
|
329
|
-
] / total_debt.replace(0, np.nan)
|
|
330
|
-
|
|
331
|
-
macro_parameters["initial_foreign_debt_ratio"] = (
|
|
332
|
-
get_valid_data(
|
|
333
|
-
wb_data_q["foreign_debt_ratio"], baseline_YYYYQ
|
|
334
|
-
)
|
|
335
|
-
)
|
|
336
|
-
else:
|
|
337
|
-
print(
|
|
338
|
-
"Warning: Missing debt variables in World Bank "
|
|
339
|
-
"data. Skipping update for "
|
|
340
|
-
"initial_foreign_debt_ratio."
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
print(
|
|
344
|
-
"initial_foreign_debt_ratio updated from World Bank "
|
|
345
|
-
f"API: {macro_parameters['initial_foreign_debt_ratio']}"
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
# Compute zeta_D safely
|
|
349
|
-
macro_parameters["zeta_D"] = [
|
|
350
|
-
macro_parameters["initial_foreign_debt_ratio"]
|
|
351
|
-
] # Since it's the same formula, we use the same calculated value
|
|
352
|
-
|
|
353
|
-
print(
|
|
354
|
-
"zeta_D updated from World Bank API: "
|
|
355
|
-
f"{macro_parameters['zeta_D']}"
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
# Compute annual GDP growth safely
|
|
272
|
+
# Compute annual GDP-per-capita growth (g_y_annual) from the
|
|
273
|
+
# World Bank WDI series, averaging pct_change from
|
|
274
|
+
# G_Y_START_YEAR onward to match the documented window (see
|
|
275
|
+
# macro.md). Debt parameters are not derived here (see note
|
|
276
|
+
# above).
|
|
359
277
|
if "GDP per capita (constant 2015 US$)" in wb_data_a.columns:
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
278
|
+
gdp_pc = wb_data_a["GDP per capita (constant 2015 US$)"]
|
|
279
|
+
gdp_pc = gdp_pc[gdp_pc.index.astype(int) >= G_Y_START_YEAR]
|
|
280
|
+
g_y_series = gdp_pc.pct_change(-1)
|
|
363
281
|
|
|
364
282
|
# If all values are NaN, return None
|
|
365
283
|
macro_parameters["g_y_annual"] = (
|
|
366
284
|
g_y_series.mean() if not g_y_series.isna().all() else None
|
|
367
285
|
)
|
|
286
|
+
print(
|
|
287
|
+
"g_y_annual updated from World Bank API: "
|
|
288
|
+
f"{macro_parameters['g_y_annual']}"
|
|
289
|
+
)
|
|
368
290
|
else:
|
|
369
291
|
print(
|
|
370
292
|
"Warning: Missing GDP per capita data in World "
|
|
371
293
|
"Bank data. Skipping update for g_y_annual."
|
|
372
294
|
)
|
|
373
|
-
|
|
374
|
-
print(
|
|
375
|
-
"g_y_annual updated from World Bank API: "
|
|
376
|
-
f"{macro_parameters['g_y_annual']}"
|
|
377
|
-
)
|
|
378
295
|
except Exception:
|
|
379
296
|
print("Failed to retrieve data from World Bank")
|
|
380
|
-
print("Will not update
|
|
381
|
-
print(
|
|
382
|
-
"[initial_debt_ratio, initial_foreign_debt_ratio, zeta_D, g_y]"
|
|
383
|
-
)
|
|
297
|
+
print("Will not update g_y_annual")
|
|
384
298
|
else:
|
|
385
299
|
print("Not updating from World Bank API")
|
|
386
300
|
|
|
@@ -443,31 +357,16 @@ def get_macro_params(
|
|
|
443
357
|
print("Not updating from ILOSTAT API")
|
|
444
358
|
|
|
445
359
|
"""
|
|
446
|
-
|
|
360
|
+
Estimate r_gov_shift and r_gov_scale (Li, Magud, Werner 2021 method).
|
|
447
361
|
"""
|
|
448
362
|
|
|
363
|
+
# alpha_T and alpha_G are NOT pulled from the IMF API for OG-ETH: the
|
|
364
|
+
# IMF SDMX endpoint returns only 2002-vintage data for Ethiopia, and
|
|
365
|
+
# the documented sources differ (alpha_G -> World Bank NE.CON.GOVT.ZS;
|
|
366
|
+
# alpha_T -> IMF GFS + IMF Country Report 25/188, hand-combined). Both
|
|
367
|
+
# stay at the committed values in macro.md. _get_imf_macro_params is
|
|
368
|
+
# retained (tested independently) for reuse if wired to the right data.
|
|
449
369
|
if update_from_api:
|
|
450
|
-
try:
|
|
451
|
-
imf_year = (
|
|
452
|
-
data_end_date.year if imf_data_year is None else imf_data_year
|
|
453
|
-
)
|
|
454
|
-
macro_parameters.update(
|
|
455
|
-
_get_imf_macro_params(
|
|
456
|
-
country_iso,
|
|
457
|
-
imf_year,
|
|
458
|
-
data_path=imf_data_path,
|
|
459
|
-
)
|
|
460
|
-
)
|
|
461
|
-
print(
|
|
462
|
-
f"alpha_T updated from IMF data: {macro_parameters['alpha_T']}"
|
|
463
|
-
)
|
|
464
|
-
print(
|
|
465
|
-
f"alpha_G updated from IMF data: {macro_parameters['alpha_G']}"
|
|
466
|
-
)
|
|
467
|
-
except Exception:
|
|
468
|
-
print("Failed to retrieve data from IMF")
|
|
469
|
-
print("Will not update alpha_T, alpha_G")
|
|
470
|
-
|
|
471
370
|
""""
|
|
472
371
|
Estimate the discount on sovereign yields relative to private debt
|
|
473
372
|
Follow the methodology in Li, Magud, Werner, Witte (2021)
|
|
@@ -497,17 +396,17 @@ def get_macro_params(
|
|
|
497
396
|
macro_parameters["r_gov_shift"] = [-res.params[0] / 100]
|
|
498
397
|
macro_parameters["r_gov_scale"] = [res.params[1]]
|
|
499
398
|
print(
|
|
500
|
-
"r_gov_shift
|
|
399
|
+
"r_gov_shift computed (LMW 2021 method): "
|
|
501
400
|
f"{macro_parameters['r_gov_shift']}"
|
|
502
401
|
)
|
|
503
402
|
print(
|
|
504
|
-
"r_gov_scale
|
|
403
|
+
"r_gov_scale computed (LMW 2021 method): "
|
|
505
404
|
f"{macro_parameters['r_gov_scale']}"
|
|
506
405
|
)
|
|
507
406
|
except Exception:
|
|
508
407
|
print("Failed to compute r_gov_shift, r_gov_scale")
|
|
509
408
|
print("Will not update r_gov_shift, r_gov_scale")
|
|
510
409
|
else:
|
|
511
|
-
print("Not
|
|
410
|
+
print("Not computing r_gov_shift, r_gov_scale")
|
|
512
411
|
|
|
513
412
|
return macro_parameters
|