From d5b6b4e87d8779f911c9aed757d1a4aacb14e078 Mon Sep 17 00:00:00 2001 From: Nikhil Woodruff Date: Tue, 13 Jan 2026 00:24:35 +0000 Subject: [PATCH] fix: clear caches after parameter updates in simulation modifier The simulation modifier now clears both parameter caches and variable holder caches after updating parameter values. This ensures that subsequent calculations use the updated parameter values instead of stale cached values. Previously, when a simulation was created and then modified with parameter updates, the cached calculations would still use the old parameter values, causing reforms to have no effect. --- src/policyengine/utils/parametric_reforms.py | 12 ++++ tests/test_parametric_reforms.py | 68 ++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/test_parametric_reforms.py diff --git a/src/policyengine/utils/parametric_reforms.py b/src/policyengine/utils/parametric_reforms.py index 7d7a869a..7548ea7e 100644 --- a/src/policyengine/utils/parametric_reforms.py +++ b/src/policyengine/utils/parametric_reforms.py @@ -34,6 +34,18 @@ def modifier(simulation): start=start_period, stop=stop_period, ) + + # Clear caches so calculations use updated parameter values + simulation.tax_benefit_system.reset_parameter_caches() + + # Clear computed variable caches (but preserve input variables) + # Variables with formulas are computed; those without are inputs + for population in simulation.populations.values(): + for var_name, holder in population._holders.items(): + variable = simulation.tax_benefit_system.get_variable(var_name) + if variable.formulas: # Only clear computed variables + holder.delete_arrays() + return simulation return modifier diff --git a/tests/test_parametric_reforms.py b/tests/test_parametric_reforms.py new file mode 100644 index 00000000..bc8f9d70 --- /dev/null +++ b/tests/test_parametric_reforms.py @@ -0,0 +1,68 @@ +"""Test that parameter reforms are applied correctly.""" + +from datetime import datetime + +from policyengine.core.policy import ParameterValue as PEParameterValue +from policyengine.core.policy import Policy as PEPolicy +from policyengine.tax_benefit_models.uk import uk_latest +from policyengine.tax_benefit_models.uk.analysis import ( + UKHouseholdInput, + calculate_household_impact, +) + + +def test_parameter_reform_affects_calculation(): + """Test that modifying a parameter actually changes the calculation result.""" + param_lookup = {p.name: p for p in uk_latest.parameters} + pe_param = param_lookup["gov.dwp.universal_credit.standard_allowance.amount.SINGLE_OLD"] + + pe_input = UKHouseholdInput( + people=[{"age": 30, "employment_income": 0}], + benunit={}, + household={}, + year=2026, + ) + + # Baseline + baseline = calculate_household_impact(pe_input, policy=None) + baseline_uc = baseline.benunit[0]["universal_credit"] + + # Reform - increase standard allowance + pv = PEParameterValue( + parameter=pe_param, + value=533.0, + start_date=datetime(2026, 1, 1), + end_date=None, + ) + policy = PEPolicy(name="Test", description="Test", parameter_values=[pv]) + reform = calculate_household_impact(pe_input, policy=policy) + reform_uc = reform.benunit[0]["universal_credit"] + + # UC should increase + assert reform_uc > baseline_uc + assert abs(reform_uc - 533 * 12) < 1 + + +def test_parameter_reform_preserves_inputs(): + """Test that input variables are preserved when applying a reform.""" + param_lookup = {p.name: p for p in uk_latest.parameters} + pe_param = param_lookup["gov.dwp.universal_credit.standard_allowance.amount.SINGLE_OLD"] + + pe_input = UKHouseholdInput( + people=[{"age": 30, "employment_income": 5000}], + benunit={}, + household={}, + year=2026, + ) + + pv = PEParameterValue( + parameter=pe_param, + value=533.0, + start_date=datetime(2026, 1, 1), + end_date=None, + ) + policy = PEPolicy(name="Test", description="Test", parameter_values=[pv]) + reform = calculate_household_impact(pe_input, policy=policy) + + assert reform.person[0]["employment_income"] == 5000 + assert reform.person[0]["age"] == 30