Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions ogcore/SS.py
Original file line number Diff line number Diff line change
Expand Up @@ -1424,15 +1424,20 @@ def SS_fsolve(guesses, *args):
return errors


def SS_initial_guesses(p, b_val=0.0055, n_val=0.4, r_tr_scalars=[1.0, 1.0]):
def SS_initial_guesses(p, b_val=None, n_val=None, r_tr_scalars=[1.0, 1.0]):
"""
Finds the initial guesses for b, n and for the steady state outer
loop variables.

Args:
p (OG-Core Specifications object): model parameters
b_val (float): initial guess value for savings
n_val (float): initial guess value for labor supply
b_val (float): initial guess value for savings; if None, the value
is taken from the model parameters (``initial_guess_b_SS`` when
``use_zeta`` is True, ``initial_guess_b_SS_no_zeta`` otherwise)
n_val (float): initial guess value for labor supply; if None, the
value is taken from the model parameters (``initial_guess_n_SS``
when ``use_zeta`` is True, ``initial_guess_n_SS_no_zeta``
otherwise)
r_tr_scalars (list): scalars to adjust initial guesses for r and TR

Returns:
Expand All @@ -1450,14 +1455,16 @@ def SS_initial_guesses(p, b_val=0.0055, n_val=0.4, r_tr_scalars=[1.0, 1.0]):
# create guesses list
# Note that BQ is an vector of lenght J if use_zeta=False
if p.use_zeta:
b_guess = np.ones((p.S, p.J)) * b_val
n_guess = np.ones((p.S, p.J)) * n_val * p.ltilde
b0 = p.initial_guess_b_SS if b_val is None else b_val
n0 = p.initial_guess_n_SS if n_val is None else n_val
b_guess = np.ones((p.S, p.J)) * b0
n_guess = np.ones((p.S, p.J)) * n0 * p.ltilde
BQguess = 0.12231465279007188
else:
b_guess = (
np.ones((p.S, p.J)) * 0.07
) # TODO: remove hardcode here and next line
n_guess = np.ones((p.S, p.J)) * 0.35 * p.ltilde
b0 = p.initial_guess_b_SS_no_zeta if b_val is None else b_val
n0 = p.initial_guess_n_SS_no_zeta if n_val is None else n_val
b_guess = np.ones((p.S, p.J)) * b0
n_guess = np.ones((p.S, p.J)) * n0 * p.ltilde
BQguess = aggr.get_BQ(rguess, b_guess, None, p, "SS", False)
# append factor guess if baseline
BQ_items = [BQguess] if p.use_zeta else list(BQguess)
Expand Down
80 changes: 80 additions & 0 deletions ogcore/default_parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -5016,6 +5016,86 @@
}
}
},
"initial_guess_b_SS": {
"title": "Initial guess for household savings in the SS solution when use_zeta is True",
"description": "Constant used as the initial guess for the household savings distribution in the steady-state solution when use_zeta is True.",
"short_description": "Initial guess for SS savings (use_zeta True)",
"param_notation": "\\texttt{initial\\_guess\\_b\\_SS}",
"section_1": "Model Solution Parameters",
"notes": "",
"type": "float",
"value": [
{
"value": 0.0055
}
],
"validators": {
"range": {
"min": 1e-13,
"max": 100.0
}
}
},
"initial_guess_n_SS": {
"title": "Initial guess for household labor supply in the SS solution when use_zeta is True",
"description": "Constant (as a fraction of the labor endowment ltilde) used as the initial guess for the household labor-supply distribution in the steady-state solution when use_zeta is True.",
"short_description": "Initial guess for SS labor supply (use_zeta True)",
"param_notation": "\\texttt{initial\\_guess\\_n\\_SS}",
"section_1": "Model Solution Parameters",
"notes": "",
"type": "float",
"value": [
{
"value": 0.4
}
],
"validators": {
"range": {
"min": 1e-13,
"max": 1.0
}
}
},
"initial_guess_b_SS_no_zeta": {
"title": "Initial guess for household savings in the SS solution when use_zeta is False",
"description": "Constant used as the initial guess for the household savings distribution in the steady-state solution when use_zeta is False.",
"short_description": "Initial guess for SS savings (use_zeta False)",
"param_notation": "\\texttt{initial\\_guess\\_b\\_SS\\_no\\_zeta}",
"section_1": "Model Solution Parameters",
"notes": "",
"type": "float",
"value": [
{
"value": 0.07
}
],
"validators": {
"range": {
"min": 1e-13,
"max": 100.0
}
}
},
"initial_guess_n_SS_no_zeta": {
"title": "Initial guess for household labor supply in the SS solution when use_zeta is False",
"description": "Constant (as a fraction of the labor endowment ltilde) used as the initial guess for the household labor-supply distribution in the steady-state solution when use_zeta is False.",
"short_description": "Initial guess for SS labor supply (use_zeta False)",
"param_notation": "\\texttt{initial\\_guess\\_n\\_SS\\_no\\_zeta}",
"section_1": "Model Solution Parameters",
"notes": "",
"type": "float",
"value": [
{
"value": 0.35
}
],
"validators": {
"range": {
"min": 1e-13,
"max": 1.0
}
}
},
"omega": {
"title": "Population distribution (fraction at each age) over the time path.",
"description": "Population distribution (fraction at each age) over the time path.",
Expand Down
33 changes: 33 additions & 0 deletions tests/test_SS.py
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,39 @@ def test_initial_guesses(tmpdir, use_zeta):
assert b_guess.shape == (p.S, p.J)


@pytest.mark.parametrize(
"use_zeta", [True, False], ids=["use_zeta=True", "use_zeta=False"]
)
def test_initial_guesses_from_params(tmpdir, use_zeta):
"""The b and n initial guesses come from the model parameters and can be
changed without touching the solver code (OG-Core issue #1007)."""
baseline_dir = os.path.join(tmpdir, "OUTPUT_BASELINE")
p = Specifications(
output_base=baseline_dir,
baseline_dir=baseline_dir,
baseline=True,
num_workers=NUM_WORKERS,
)
p.use_zeta = use_zeta
# SS_initial_guesses returns (guesses, b_guess, n_guess).
_, b_guess, n_guess = SS.SS_initial_guesses(p)
if use_zeta:
b_param, n_param = p.initial_guess_b_SS, p.initial_guess_n_SS
else:
b_param = p.initial_guess_b_SS_no_zeta
n_param = p.initial_guess_n_SS_no_zeta
assert np.allclose(b_guess, b_param)
assert np.allclose(n_guess, n_param * p.ltilde)

# Changing the parameter changes the guess.
if use_zeta:
p.initial_guess_b_SS = 0.02
else:
p.initial_guess_b_SS_no_zeta = 0.02
_, b_guess2, _ = SS.SS_initial_guesses(p)
assert np.allclose(b_guess2, 0.02)


class ScatterCountingClient:
"""
Minimal fake Dask client that counts calls to `scatter` and runs
Expand Down
Loading