Skip to content

Commit 8cf609a

Browse files
authored
Merge pull request #1085 from jdebacker/cmin
Merging
2 parents 83227e3 + 5dd3929 commit 8cf609a

27 files changed

Lines changed: 407 additions & 122 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
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

8+
## [0.15.1] - 2026-01-19 12:00:00
9+
10+
### Added
11+
12+
- A new parameter `c_min` to the `Parameters` class that allows the user to specify minium consumption amounts by consumption good. See PR [#1085](https://github.com/PSLmodels/OG-Core/pull/1085)
13+
814
## [0.15.0] - 2025-12-03 12:00:00
915

1016
### Added

docs/book/content/intro/parameters.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ _Valid Range:_ min = 0.0 and max = 1.0
4343
_Out-of-Range Action:_ error
4444

4545

46+
#### `c_min`
47+
_Description:_ Minimum consumption levels for each good in the composite consumption good.
48+
_Notes:_ Enter this value in model units.
49+
_Value Type:_ float
50+
_Valid Range:_ min = 0.0 and max = 100.0
51+
_Out-of-Range Action:_ error
52+
53+
4654
#### `chi_b`
4755
_Description:_ Household utility weight on bequests.
4856
_Value Type:_ float
@@ -114,6 +122,7 @@ _Out-of-Range Action:_ error
114122
#### `use_zeta`
115123
_Description:_ Indicator variable for whether or not to use the zeta matrix to distribute bequests.
116124
_Value Type:_ bool
125+
_Valid Choices:_[True, False]
117126

118127

119128
### Model Dimensions
@@ -395,6 +404,12 @@ _Valid Range:_ min = 0.0 and max = 10.0
395404
_Out-of-Range Action:_ error
396405

397406

407+
#### `baseline_theta`
408+
_Description:_ Flag for use in reform simulations to keep Social Security system replacement rate constant between baseline and reform runs.
409+
_Value Type:_ bool
410+
_Valid Choices:_[True, False]
411+
412+
398413
### Spending
399414

400415
#### `alpha_T`
@@ -586,21 +601,25 @@ _Out-of-Range Action:_ error
586601
#### `constant_rates`
587602
_Description:_ Flag to use linear tax functions.
588603
_Value Type:_ bool
604+
_Valid Choices:_[True, False]
589605

590606

591607
#### `zero_taxes`
592608
_Description:_ Flag to run model without any individual income taxes.
593609
_Value Type:_ bool
610+
_Valid Choices:_[True, False]
594611

595612

596613
#### `analytical_mtrs`
597614
_Description:_ Flag to use analytically derived marginal tax rates in tax functions.
598615
_Value Type:_ bool
616+
_Valid Choices:_[True, False]
599617

600618

601619
#### `age_specific`
602620
_Description:_ Flag to use analytically derived marginal tax rates in tax functions.
603621
_Value Type:_ bool
622+
_Valid Choices:_[True, False]
604623

605624

606625
#### `tax_func_type`
@@ -730,6 +749,7 @@ _Out-of-Range Action:_ error
730749
_Description:_ Use constant demographics.
731750
_Notes:_ This boolean allows one to use empirical mortality rates, but keep the population distribution constant across periods. Note that immigration is shut off when this is true.
732751
_Value Type:_ bool
752+
_Valid Choices:_[True, False]
733753

734754

735755
#### `omega`
@@ -842,6 +862,7 @@ _Out-of-Range Action:_ error
842862
#### `reform_use_baseline_solution`
843863
_Description:_ Whether or not the baseline SS solution is used for starting values when solving the reform.
844864
_Value Type:_ bool
865+
_Valid Choices:_[True, False]
845866

846867

847868
#### `initial_guess_r_SS`

docs/make_params.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import os
66
import sys
77

8-
98
CURDIR_PATH = os.path.abspath(os.path.dirname(__file__))
109
OGCORE_PATH = os.path.join(CURDIR_PATH, "..", "ogcore")
1110
TEMPLATE_PATH = os.path.join(CURDIR_PATH, "templates")

docs/make_vars.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import os
66
import sys
77

8-
98
CURDIR_PATH = os.path.abspath(os.path.dirname(__file__))
109
OGCORE_PATH = os.path.join(CURDIR_PATH, "..", "ogcore")
1110
TEMPLATE_PATH = os.path.join(CURDIR_PATH, "templates")

examples/multi_industry_example.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import matplotlib.pyplot as plt
2020
import ogcore
2121

22-
2322
ogcore.TPI.ENFORCE_SOLUTION_CHECKS = False
2423

2524
# Use a custom matplotlib style file for plots

ogcore/SS.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def euler_equation_solver(guesses, *args):
3939
4040
Args:
4141
guesses (Numpy array): initial guesses for b and n, length 2S
42-
args (tuple): tuple of arguments (r, w, p_tilde, bq, TR, factor, j, p)
42+
args (tuple): tuple of arguments (r, w, p_tilde, p_i, bq, TR, factor, j, p)
4343
r (scalar): real interest rate
4444
w (scalar): real wage rate
4545
p_tilde (scalar): composite good price
@@ -54,7 +54,7 @@ def euler_equation_solver(guesses, *args):
5454
errros (Numpy array): errors from FOCs, length 2S
5555
5656
"""
57-
(r, w, p_tilde, bq, rm, tr, ubi, factor, j, p) = args
57+
r, w, p_tilde, p_i, bq, rm, tr, ubi, factor, j, p = args
5858

5959
b_guess = np.array(guesses[: p.S])
6060
n_guess = np.array(guesses[p.S :])
@@ -67,6 +67,7 @@ def euler_equation_solver(guesses, *args):
6767
r,
6868
w,
6969
p_tilde,
70+
p_i,
7071
b_s,
7172
b_splus1,
7273
n_guess,
@@ -88,6 +89,7 @@ def euler_equation_solver(guesses, *args):
8889
r,
8990
w,
9091
p_tilde,
92+
p_i,
9193
b_s,
9294
b_splus1,
9395
n_guess,
@@ -143,13 +145,15 @@ def euler_equation_solver(guesses, *args):
143145
r,
144146
w,
145147
p_tilde,
148+
p_i,
146149
b_s,
147150
b_splus1,
148151
n_guess,
149152
bq,
150153
rm,
151154
taxes,
152155
p.e[-1, :, j],
156+
p.tau_c[-1, :],
153157
p,
154158
)
155159
mask6 = cons < 0
@@ -164,6 +168,7 @@ def solve_for_j(
164168
r_p,
165169
w,
166170
p_tilde,
171+
p_i,
167172
bq_j,
168173
rm_j,
169174
tr_j,
@@ -180,6 +185,7 @@ def solve_for_j(
180185
r_p (scalar): return on household investment portfolio
181186
w (scalar): real wage rate
182187
p_tilde (scalar): composite good price
188+
p_i (Numpy array): prices for consumption good i
183189
bq_j (Numpy array): bequest amounts by age, length S
184190
rm_j (Numpy array): remittance amounts by age, length S
185191
tr_j (Numpy array): government transfer amount by age, length S
@@ -200,6 +206,7 @@ def solve_for_j(
200206
r_p,
201207
w,
202208
p_tilde,
209+
p_i,
203210
bq_j,
204211
rm_j,
205212
tr_j,
@@ -314,6 +321,7 @@ def inner_loop(outer_loop_vars, p, client):
314321
r_p,
315322
w,
316323
p_tilde,
324+
p_i,
317325
bq[:, j],
318326
rm[:, j],
319327
tr[:, j],
@@ -346,6 +354,7 @@ def inner_loop(outer_loop_vars, p, client):
346354
r_p,
347355
w,
348356
p_tilde,
357+
p_i,
349358
bq[:, j],
350359
rm[:, j],
351360
tr[:, j],
@@ -365,6 +374,7 @@ def inner_loop(outer_loop_vars, p, client):
365374
r_p,
366375
w,
367376
p_tilde,
377+
p_i,
368378
bq[:, j],
369379
rm[:, j],
370380
tr[:, j],
@@ -416,16 +426,20 @@ def inner_loop(outer_loop_vars, p, client):
416426
r_p,
417427
w,
418428
p_tilde,
429+
p_i,
419430
b_s,
420431
b_splus1,
421432
nssmat,
422433
bq,
423434
rm,
424435
net_tax,
425436
np.squeeze(p.e[-1, :, :]),
437+
p.tau_c[-1, :],
426438
p,
427439
)
428-
c_i = household.get_ci(c_s, p_i, p_tilde, p.tau_c[-1, :], p.alpha_c)
440+
c_i = household.get_ci(
441+
c_s, p_i, p_tilde, p.tau_c[-1, :], p.alpha_c, p.c_min
442+
)
429443
L = aggr.get_L(nssmat, p, "SS")
430444
B = aggr.get_B(bssmat, p, "SS", False)
431445

@@ -551,13 +565,15 @@ def inner_loop(outer_loop_vars, p, client):
551565
new_r_p,
552566
new_w,
553567
new_p_tilde,
568+
new_p_i,
554569
b_s,
555570
bssmat,
556571
nssmat,
557572
new_bq,
558573
new_rm,
559574
taxss,
560575
np.squeeze(p.e[-1, :, :]),
576+
p.tau_c[-1, :],
561577
p,
562578
)
563579
(
@@ -990,13 +1006,15 @@ def SS_solver(
9901006
r_p_ss,
9911007
wss,
9921008
p_tilde_ss,
1009+
p_i_ss,
9931010
bssmat_s,
9941011
bssmat_splus1,
9951012
nssmat,
9961013
bqssmat,
9971014
rmssmat,
9981015
taxss,
9991016
np.squeeze(p.e[-1, :, :]),
1017+
p.tau_c[-1, :],
10001018
p,
10011019
)
10021020
c_i = household.get_ci(
@@ -1005,6 +1023,7 @@ def SS_solver(
10051023
p_tilde_ss,
10061024
p.tau_c[-1, :],
10071025
p.alpha_c,
1026+
p.c_min,
10081027
"SS",
10091028
)
10101029
sales_tax_ss = tax.cons_tax_liab(c_i, p_i_ss, p, "SS")
@@ -1013,7 +1032,7 @@ def SS_solver(
10131032
)
10141033
Css = aggr.get_C(cssmat, p, "SS")
10151034
c_i_ss_mat = household.get_ci(
1016-
cssmat, p_i_ss, p_tilde_ss, p.tau_c[-1, :], p.alpha_c
1035+
cssmat, p_i_ss, p_tilde_ss, p.tau_c[-1, :], p.alpha_c, p.c_min
10171036
)
10181037
C_vec_ss = np.zeros(p.I)
10191038
for i_ind in range(
@@ -1235,7 +1254,7 @@ def SS_fsolve(guesses, *args):
12351254
implied outer loop variables
12361255
12371256
"""
1238-
(bssmat, nssmat, TR_ss, Ig_baseline, factor_ss, p, client) = args
1257+
bssmat, nssmat, TR_ss, Ig_baseline, factor_ss, p, client = args
12391258

12401259
# Rename the inputs
12411260
r_p = guesses[0]

0 commit comments

Comments
 (0)