Skip to content

Commit b5a3ebd

Browse files
authored
Merge pull request PSLmodels#1071 from jdebacker/prepop
Merging
2 parents df7b128 + bfb15a7 commit b5a3ebd

5 files changed

Lines changed: 90 additions & 50 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88

9+
## [0.14.12] - 2025-11-07 12:00:00
10+
11+
### Bug Fix
12+
13+
- Use data for pre-time path population distribution (rather than inferring it) ((PR #1071)[https://github.com/PSLmodels/OG-Core/pull/1071])
14+
915
## [0.14.11] - 2025-11-07 12:00:00
1016

1117
### Added
1218

13-
- Adds Ethiopia demographic data mapping ((PR #1054)[https://github.com/PSLmodels/OG-Core/pull/1063])
19+
- Adds Ethiopia demographic data mapping ((PR #1063)[https://github.com/PSLmodels/OG-Core/pull/1063])
1420
-
1521
## [0.14.10] - 2025-09-11 12:00:00
1622

@@ -459,6 +465,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
459465
- 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.
460466

461467

468+
[0.14.12]: https://github.com/PSLmodels/OG-Core/compare/v0.14.11...v0.14.12
462469
[0.14.11]: https://github.com/PSLmodels/OG-Core/compare/v0.14.10...v0.14.11
463470
[0.14.10]: https://github.com/PSLmodels/OG-Core/compare/v0.14.9...v0.14.10
464471
[0.14.9]: https://github.com/PSLmodels/OG-Core/compare/v0.14.8...v0.14.9

ogcore/SS.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def inner_loop(outer_loop_vars, p, client):
307307
futures.append(f)
308308

309309
try:
310-
results = client.gather(futures, timeout=300)
310+
results = client.gather(futures)
311311
except Exception as e:
312312
# Cancel remaining futures and fall back to serial computation
313313
print(

ogcore/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@
2020
from ogcore.txfunc import *
2121
from ogcore.utils import *
2222

23-
__version__ = "0.14.11"
23+
__version__ = "0.14.12"

ogcore/demographics.py

Lines changed: 79 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -990,61 +990,94 @@ def get_pop_objs(
990990
# assert np.allclose(pop_counter_2D, pop_dist)
991991
assert np.allclose(pop_counter_2D, pop_2D)
992992

993-
""""
994-
CHANGE - in OG-Core, we are implicitLy assuming pre-TP rates of mortality,
995-
fertility, and immigration are the same as the period 0 rates.
993+
# """"
994+
# CHANGE - in OG-Core, we are implicitly assuming pre-TP rates of mortality,
995+
# fertility, and immigration are the same as the period 0 rates.
996+
997+
# So let's just infer the pre-pop_dist from those.
998+
# """
999+
# pop1 = pop_2D[0, :]
1000+
# fert0 = fert_rates[0, :]
1001+
# mort0 = mort_rates[0, :]
1002+
# infmort0 = infmort_rates[0]
1003+
# imm0 = imm_rates_orig[0, :]
1004+
# pre_pop_guess = pop1.copy()
1005+
1006+
# # I can't solve this analytically, so set up a system of equation
1007+
# # to solve
1008+
# def pre_pop_solve(pre_pop_guess, pop1, fert0, mort0, infmort0, imm0):
1009+
# pre_pop = pre_pop_guess
1010+
# errors = np.zeros(E + S)
1011+
# errors[0] = pop1[0] - (
1012+
# (1 - infmort0) * (fert0 * pre_pop).sum() + imm0[0] * pre_pop[0]
1013+
# )
1014+
# errors[1:] = pop1[1:] - (
1015+
# pre_pop[:-1] * (1 - mort0[:-1]) + pre_pop[1:] * imm0[1:]
1016+
# )
1017+
# # print("Max error = ", np.abs(errors).max())
1018+
# return errors
1019+
1020+
# opt_res = opt.root(
1021+
# pre_pop_solve,
1022+
# pre_pop_guess,
1023+
# args=(pop1, fert0, mort0, infmort0, imm0),
1024+
# method="lm",
1025+
# )
1026+
# pre_pop = opt_res.x
1027+
# print(
1028+
# "Success? ",
1029+
# opt_res.success,
1030+
# ", Max diff = ",
1031+
# np.abs(opt_res.fun).max(),
1032+
# )
1033+
# pre_pop_EpS = pop_rebin(pre_pop, E + S)
1034+
1035+
# # Check result
1036+
# initial_pop_counter = np.zeros(E + S)
1037+
# newborns = (fert_rates[0, :] * pre_pop[:]).sum()
1038+
# initial_pop_counter[0] = (
1039+
# 1 - infmort_rates[0]
1040+
# ) * newborns + imm_rates_orig[0, 0] * pre_pop[0]
1041+
# initial_pop_counter[1:] = (
1042+
# pre_pop[:-1] * (1 - mort_rates[0, :-1])
1043+
# + pre_pop[1:] * imm_rates_orig[0, 1:]
1044+
# )
1045+
# # Test that using pre pop get to pop in period 1
1046+
# print("Max diff = ", np.abs(pop_2D[0, :] - initial_pop_counter).max())
1047+
# # assert np.allclose(initial_pop_counter, pop_2D[0, :])
9961048

997-
So let's just infer the pre-pop_dist from those.
9981049
"""
999-
pop1 = pop_2D[0, :]
1000-
fert0 = fert_rates[0, :]
1001-
mort0 = mort_rates[0, :]
1002-
infmort0 = infmort_rates[0]
1003-
imm0 = imm_rates_orig[0, :]
1004-
pre_pop_guess = pop1.copy()
1005-
1006-
# I can't solve this analytically, so set up a system of equation
1007-
# to solve
1008-
def pre_pop_solve(pre_pop_guess, pop1, fert0, mort0, infmort0, imm0):
1009-
pre_pop = pre_pop_guess
1010-
errors = np.zeros(E + S)
1011-
errors[0] = pop1[0] - (
1012-
(1 - infmort0) * (fert0 * pre_pop).sum() + imm0[0] * pre_pop[0]
1013-
)
1014-
errors[1:] = pop1[1:] - (
1015-
pre_pop[:-1] * (1 - mort0[:-1]) + pre_pop[1:] * imm0[1:]
1016-
)
1017-
# print("Max error = ", np.abs(errors).max())
1018-
return errors
1019-
1020-
opt_res = opt.root(
1021-
pre_pop_solve,
1022-
pre_pop_guess,
1023-
args=(pop1, fert0, mort0, infmort0, imm0),
1024-
method="lm",
1025-
)
1026-
pre_pop = opt_res.x
1027-
print(
1028-
"Success? ",
1029-
opt_res.success,
1030-
", Max diff = ",
1031-
np.abs(opt_res.fun).max(),
1032-
)
1033-
pre_pop_EpS = pop_rebin(pre_pop, E + S)
1050+
NEW CODE - use the actual UN historical data instead of solving backwards
1051+
"""
1052+
# Get percentage distribution for S periods for pre-TP period
1053+
# Use the actual UN historical data instead of solving backwards
1054+
# pre_pop_EpS = pop_rebin(pre_pop, E + S) -- this assignment is
1055+
# above on line 924, but keep for clarity
10341056

10351057
# Check result
1058+
# Verify that the UN pre-period data is reasonably consistent
1059+
# with the period 0 population using the demographic transition equations
10361060
initial_pop_counter = np.zeros(E + S)
1037-
newborns = (fert_rates[0, :] * pre_pop[:]).sum()
1061+
newborns = (fert_rates[0, :] * pre_pop_EpS[:]).sum()
10381062
initial_pop_counter[0] = (
10391063
1 - infmort_rates[0]
1040-
) * newborns + imm_rates_orig[0, 0] * pre_pop[0]
1064+
) * newborns + imm_rates_orig[0, 0] * pre_pop_EpS[0]
10411065
initial_pop_counter[1:] = (
1042-
pre_pop[:-1] * (1 - mort_rates[0, :-1])
1043-
+ pre_pop[1:] * imm_rates_orig[0, 1:]
1066+
pre_pop_EpS[:-1] * (1 - mort_rates[0, :-1])
1067+
+ pre_pop_EpS[1:] * imm_rates_orig[0, 1:]
10441068
)
1045-
# Test that using pre pop get to pop in period 1
1046-
print("Max diff = ", np.abs(pop_2D[0, :] - initial_pop_counter).max())
1047-
# assert np.allclose(initial_pop_counter, pop_2D[0, :])
1069+
1070+
max_diff = np.abs(pop_2D[0, :] - initial_pop_counter).max()
1071+
print("Pre-period population verification: Max diff = ", max_diff)
1072+
1073+
if max_diff > 100_000:
1074+
print(
1075+
"WARNING: Large difference between UN pre-period population "
1076+
+ "and period 0 population ({:.2f}). ".format(max_diff)
1077+
+ "This may indicate inconsistencies in the data or "
1078+
+ "immigration rate calculations, but using UN historical "
1079+
+ "data as it is more reliable than backward-solved estimates."
1080+
)
10481081

10491082
# Create the transition matrix for the population distribution
10501083
# from T0 going forward (i.e., past when we have data on forecasts)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="ogcore",
8-
version="0.14.11",
8+
version="0.14.12",
99
author="Jason DeBacker and Richard W. Evans",
1010
license="CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
1111
description="A general equilibrium overlapping generations model for fiscal policy analysis",

0 commit comments

Comments
 (0)