Skip to content

Commit 602d2de

Browse files
Fix state pension (new vs basic SP), add fiscal_year to Simulation, add efrs to Python DATASETS
State pension now matches policyengine-uk approach: new SP recipients (reached SP age after April 2016) get the full parameter rate directly; basic SP recipients get reported amounts scaled by reform ratio. Also adds fiscal_year parameter to Simulation constructor and adds "efrs" to the Python interface's DATASETS tuple for GCS download support. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent cbd4fae commit 602d2de

File tree

7 files changed

+154
-235
lines changed

7 files changed

+154
-235
lines changed

interfaces/python/policyengine_uk_compiled/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def _get_credentials() -> tuple[str, str]:
6060
return token.split(":", 1)
6161

6262

63-
DATASETS = ("frs", "lcfs", "spi", "was")
63+
DATASETS = ("frs", "efrs", "lcfs", "spi", "was")
6464

6565

6666
def ensure_dataset_year(dataset: str, year: int) -> Path:

src/data/lcfs.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,20 @@ pub fn load_lcfs(data_dir: &Path, fiscal_year: u32) -> anyhow::Result<Dataset> {
181181
weight,
182182
region,
183183
rent: rent_annual,
184-
food_and_non_alcoholic_beverages: get_f64(hh_row, "p601").max(0.0) * WEEKS_IN_YEAR,
185-
alcohol_and_tobacco: get_f64(hh_row, "p602").max(0.0) * WEEKS_IN_YEAR,
186-
clothing_and_footwear: get_f64(hh_row, "p603").max(0.0) * WEEKS_IN_YEAR,
187-
housing_water_and_fuel: get_f64(hh_row, "p604").max(0.0) * WEEKS_IN_YEAR,
188-
household_furnishings: get_f64(hh_row, "p605").max(0.0) * WEEKS_IN_YEAR,
189-
health: get_f64(hh_row, "p606").max(0.0) * WEEKS_IN_YEAR,
190-
transport: get_f64(hh_row, "p607").max(0.0) * WEEKS_IN_YEAR,
191-
communication: get_f64(hh_row, "p608").max(0.0) * WEEKS_IN_YEAR,
192-
recreation_and_culture: get_f64(hh_row, "p609").max(0.0) * WEEKS_IN_YEAR,
193-
education: get_f64(hh_row, "p610").max(0.0) * WEEKS_IN_YEAR,
194-
restaurants_and_hotels: get_f64(hh_row, "p611").max(0.0) * WEEKS_IN_YEAR,
195-
miscellaneous_goods_and_services: get_f64(hh_row, "p612").max(0.0) * WEEKS_IN_YEAR,
196-
petrol_spending: get_f64(hh_row, "c72211").max(0.0) * WEEKS_IN_YEAR,
197-
diesel_spending: get_f64(hh_row, "c72212").max(0.0) * WEEKS_IN_YEAR,
184+
food_consumption: get_f64(hh_row, "p601").max(0.0) * WEEKS_IN_YEAR,
185+
alcohol_tobacco_consumption: get_f64(hh_row, "p602").max(0.0) * WEEKS_IN_YEAR,
186+
clothing_consumption: get_f64(hh_row, "p603").max(0.0) * WEEKS_IN_YEAR,
187+
housing_water_electricity_consumption: get_f64(hh_row, "p604").max(0.0) * WEEKS_IN_YEAR,
188+
furnishings_consumption: get_f64(hh_row, "p605").max(0.0) * WEEKS_IN_YEAR,
189+
health_consumption: get_f64(hh_row, "p606").max(0.0) * WEEKS_IN_YEAR,
190+
transport_consumption: get_f64(hh_row, "p607").max(0.0) * WEEKS_IN_YEAR,
191+
communication_consumption: get_f64(hh_row, "p608").max(0.0) * WEEKS_IN_YEAR,
192+
recreation_consumption: get_f64(hh_row, "p609").max(0.0) * WEEKS_IN_YEAR,
193+
education_consumption: get_f64(hh_row, "p610").max(0.0) * WEEKS_IN_YEAR,
194+
restaurants_consumption: get_f64(hh_row, "p611").max(0.0) * WEEKS_IN_YEAR,
195+
miscellaneous_consumption: get_f64(hh_row, "p612").max(0.0) * WEEKS_IN_YEAR,
196+
petrol_spending: get_f64(hh_row, "c72211").max(0.0) * WEEKS_IN_YEAR,
197+
diesel_spending: get_f64(hh_row, "c72212").max(0.0) * WEEKS_IN_YEAR,
198198
..Household::default()
199199
});
200200
}

src/data/was.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ pub fn load_was(data_dir: &Path, fiscal_year: u32) -> anyhow::Result<Dataset> {
106106
// Wealth (zero if column absent in older waves)
107107
let financial_wealth = get_f64(row, &fin_wealth_col);
108108
let property_wealth = get_f64(row, &prop_wealth_col);
109-
let physical_wealth = get_f64(row, &phys_wealth_col);
110-
let total_wealth = get_f64(row, &tot_wealth_col);
109+
let _physical_wealth = get_f64(row, &phys_wealth_col);
110+
let _total_wealth = get_f64(row, &tot_wealth_col);
111111

112112
let hh_id = households.len();
113113
let bu_id = benunits.len();
@@ -177,10 +177,8 @@ pub fn load_was(data_dir: &Path, fiscal_year: u32) -> anyhow::Result<Dataset> {
177177
region,
178178
rent: rent_annual,
179179
council_tax,
180-
financial_wealth,
180+
net_financial_wealth: financial_wealth,
181181
property_wealth,
182-
physical_wealth,
183-
total_wealth,
184182
..Household::default()
185183
});
186184
}

src/engine/simulation.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ pub struct Simulation {
8080
pub benunits: Vec<BenUnit>,
8181
pub households: Vec<Household>,
8282
pub parameters: Parameters,
83-
/// Baseline SP weekly rates for scaling reported amounts under reforms.
84-
pub baseline_new_sp_weekly: f64,
83+
/// Baseline old basic SP weekly rate for scaling reported amounts under reforms.
8584
pub baseline_old_sp_weekly: f64,
85+
/// Fiscal year (e.g. 2025 for 2025/26) — used for new/basic SP cutoff.
86+
pub fiscal_year: u32,
8687
}
8788

8889
impl Simulation {
@@ -91,28 +92,28 @@ impl Simulation {
9192
benunits: Vec<BenUnit>,
9293
households: Vec<Household>,
9394
parameters: Parameters,
95+
fiscal_year: u32,
9496
) -> Self {
95-
let baseline_new_sp_weekly = parameters.state_pension.new_state_pension_weekly;
9697
let baseline_old_sp_weekly = parameters.state_pension.old_basic_pension_weekly;
9798
Simulation {
9899
people, benunits, households, parameters,
99-
baseline_new_sp_weekly, baseline_old_sp_weekly,
100+
baseline_old_sp_weekly, fiscal_year,
100101
}
101102
}
102103

103-
/// Create a simulation with explicit baseline SP rates (for reform simulations
104-
/// where the baseline rates differ from the reform parameters).
104+
/// Create a simulation with explicit baseline old SP rate (for reform simulations
105+
/// where the baseline rate differs from the reform parameters).
105106
pub fn new_with_baseline_sp(
106107
people: Vec<Person>,
107108
benunits: Vec<BenUnit>,
108109
households: Vec<Household>,
109110
parameters: Parameters,
110-
baseline_new_sp_weekly: f64,
111111
baseline_old_sp_weekly: f64,
112+
fiscal_year: u32,
112113
) -> Self {
113114
Simulation {
114115
people, benunits, households, parameters,
115-
baseline_new_sp_weekly, baseline_old_sp_weekly,
116+
baseline_old_sp_weekly, fiscal_year,
116117
}
117118
}
118119

@@ -138,13 +139,13 @@ impl Simulation {
138139
}
139140

140141
// Phase 2: BenUnit-level calculations (parallelised)
141-
let baseline_new_sp = self.baseline_new_sp_weekly;
142142
let baseline_old_sp = self.baseline_old_sp_weekly;
143+
let fiscal_year = self.fiscal_year;
143144
let br: Vec<BenUnitResult> = self.benunits.par_iter().map(|bu| {
144145
let hh = &self.households[bu.household_id];
145146
variables::benefits::calculate_benunit(
146147
bu, &self.people, &person_results, hh, &self.parameters,
147-
baseline_new_sp, baseline_old_sp,
148+
baseline_old_sp, fiscal_year,
148149
)
149150
}).collect();
150151
benunit_results = br;
@@ -299,16 +300,16 @@ mod tests {
299300

300301
let bu = BenUnit {
301302
id: 0, household_id: 0, person_ids: vec![0, 1],
302-
take_up_seed: 0.0, reported_cb: true,
303+
migration_seed: 0.0, would_claim_cb: true,
303304
..BenUnit::default()
304305
};
305306
let hh = Household {
306307
id: 0, person_ids: vec![0, 1], benunit_ids: vec![0],
307308
weight: 1.0, region: Region::London, council_tax: 1500.0,
308-
..Default::default()
309+
..Household::default()
309310
};
310311

311-
Simulation::new(vec![adult, child], vec![bu], vec![hh], params)
312+
Simulation::new(vec![adult, child], vec![bu], vec![hh], params, 2025)
312313
}
313314

314315
#[test]

src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,17 +445,18 @@ fn main() -> anyhow::Result<()> {
445445
dataset.benunits.clone(),
446446
dataset.households.clone(),
447447
baseline_params.clone(),
448+
cli.year,
448449
);
449450
let baseline = baseline_sim.run();
450451

451-
// Run policy simulation (pass baseline SP rates so reported amounts scale correctly)
452+
// Run policy simulation (pass baseline old SP rate so reported amounts scale correctly)
452453
let policy_sim = Simulation::new_with_baseline_sp(
453454
dataset.people.clone(),
454455
dataset.benunits.clone(),
455456
dataset.households.clone(),
456457
policy_params.clone(),
457-
baseline_params.state_pension.new_state_pension_weekly,
458458
baseline_params.state_pension.old_basic_pension_weekly,
459+
cli.year,
459460
);
460461
let reformed = policy_sim.run();
461462

@@ -1021,7 +1022,7 @@ mod obr_validation {
10211022
let params = Parameters::for_year(2025).unwrap();
10221023
let sim = Simulation::new(
10231024
dataset.people.clone(), dataset.benunits.clone(),
1024-
dataset.households.clone(), params,
1025+
dataset.households.clone(), params, 2025,
10251026
);
10261027
let results = sim.run();
10271028

@@ -1163,7 +1164,7 @@ mod historical_frs_tests {
11631164

11641165
let sim = Simulation::new(
11651166
dataset.people.clone(), dataset.benunits.clone(),
1166-
dataset.households.clone(), params,
1167+
dataset.households.clone(), params, year,
11671168
);
11681169
let results = sim.run();
11691170

0 commit comments

Comments
 (0)