Skip to content
Closed
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
1 change: 1 addition & 0 deletions changelog.d/fix-carry-over-definition-period.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Auto-carry-over now prefers, for a variable with a `set_input` helper, periods at the variable's definition unit, and uses other units only when it has nothing there. Since 3.24.0 it took the latest-starting period of any unit, so it could pick the twelfth of a yearly flow that `calculate_divide` caches at a month: a yearly input known only for one year came out at a twelfth of its value in later years once any month after January had been requested. In policyengine-us this set every person's age to a twelfth of its value in the second year of a multi-year simulation. Variables without a helper (DAY variables, `set_input = None`) are unchanged.
29 changes: 28 additions & 1 deletion policyengine_core/simulations/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,34 @@ def _calculate(self, variable_name: str, period: Period = None) -> ArrayLike:
# tuples lexicographically puts "year" before "month"
# alphabetically, so a known "2023" annual value would
# win over a later "2024-06" monthly value (bug H1).
last_known_period = max(known_periods, key=lambda p: p.start)
#
# A variable with a ``set_input`` helper prefers periods at
# its definition unit. The helper stores inputs at the
# definition period, so a value at another unit beside them
# is ordinarily a cache derived from them: a YEAR flow
# requested for a month caches a twelfth of the year's value
# there (``calculate_divide``), and a sum over several
# sub-periods is cached at the larger period
# (``calculate_add``). Carrying either forward rescales the
# variable. A value at another unit can still be a genuine
# input (stored before a reform changed the variable's
# definition period or helper, restored from a simulation
# with other definitions, or written by a custom helper), so
# other units are used when there is nothing at the
# definition unit. Variables without a helper (DAY
# variables, ``set_input = None``) keep every period.
own_unit_periods = (
[
known_period
for known_period in known_periods
if known_period.unit == variable.definition_period
]
if variable.set_input
else []
)
last_known_period = max(
own_unit_periods or known_periods, key=lambda p: p.start
)
if last_known_period.start > period.start:
return holder.default_array()
# Pass branch_name through so auto-carry-over respects the
Expand Down
Loading
Loading