Skip to content
Open
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
34 changes: 31 additions & 3 deletions ogcore/TPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,36 @@ def inner_loop(guesses, outer_loop_vars, initial_values, ubi, j, ind, p):
return euler_errors, b_mat, n_mat


def _rc_error_message(RC_error, RC_TPI):
"""
Build the message for a transition resource-constraint failure.

Reports the maximum absolute resource-constraint error, the period it
occurs in, and how to read it: a violation confined to the first or last
periods is usually an initial- or terminal-boundary artifact, while one
spread across the path points to an inconsistent calibration.

Args:
RC_error (array_like): resource constraint error, time on axis 0
RC_TPI (scalar): the tolerance the error is checked against

Returns:
msg (str): the diagnostic error message
"""
abs_rc = np.absolute(RC_error)
rc_by_period = abs_rc.reshape(abs_rc.shape[0], -1).max(axis=1)
t_worst = int(np.argmax(rc_by_period))
return (
"Transition path equilibrium not found (RC_error): max "
f"|resource constraint error| = {rc_by_period[t_worst]:.2e} at "
f"period {t_worst} of {rc_by_period.shape[0]} (tolerance "
f"RC_TPI = {RC_TPI}). A violation confined to the first or last "
"periods is usually an initial- or terminal-boundary artifact; one "
"spread across the path points to an inconsistent calibration "
"(spending, revenue, debt_ratio_ss)."
)


def run_TPI(p, client=None):
"""
Solve for transition path equilibrium of OG-Core.
Expand Down Expand Up @@ -1837,9 +1867,7 @@ def run_TPI(p, client=None):
raise RuntimeError(msg)

if (np.any(np.absolute(RC_error) >= p.RC_TPI)) and ENFORCE_SOLUTION_CHECKS:
raise RuntimeError(
"Transition path equlibrium not found " + "(RC_error)"
)
raise RuntimeError(_rc_error_message(RC_error, p.RC_TPI))

if (
np.any(np.absolute(eul_savings) >= p.mindist_TPI)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_TPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,18 @@ def test_get_initial_SS_values(baseline, param_updates, filename, tmpdir):
)


def test_rc_error_message():
"""The resource-constraint failure message names the largest violation,
the period it occurs in, and the tolerance."""
T, M = 320, 2
RC_error = np.full((T, M), 1e-8)
RC_error[T - 1, 1] = -0.05 # a terminal-boundary spike (signed)
msg = TPI._rc_error_message(RC_error, 1e-4)
assert "5.00e-02" in msg # the max absolute error, reported
assert f"period {T - 1}" in msg # the period it occurs in
assert "1e-04" in msg or "0.0001" in msg # the tolerance


def test_firstdoughnutring():
# Test TPI.firstdoughnutring function. Provide inputs to function and
# ensure that output returned matches what it has been before.
Expand Down