diff --git a/changelog.d/16-to-19-bursary-fund.added.md b/changelog.d/16-to-19-bursary-fund.added.md new file mode 100644 index 000000000..dd3bf2bb7 --- /dev/null +++ b/changelog.d/16-to-19-bursary-fund.added.md @@ -0,0 +1 @@ +Add a first-pass 16 to 19 Bursary Fund model for vulnerable groups. diff --git a/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/minimum.yaml b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/minimum.yaml new file mode 100644 index 000000000..673e555d9 --- /dev/null +++ b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/minimum.yaml @@ -0,0 +1,11 @@ +description: Minimum age for 16 to 19 Bursary Fund support. +metadata: + unit: year + period: year + label: 16 to 19 Bursary Fund minimum age + reference: + - title: 16 to 19 Bursary Fund guide 2025 to 2026 + href: https://www.gov.uk/government/publications/16-to-19-bursary-fund-guidance/16-to-19-bursary-fund-guide-2025-to-2026 +values: + 2025-01-01: 16 + 2026-01-01: 16 diff --git a/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/standard_upper.yaml b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/standard_upper.yaml new file mode 100644 index 000000000..03203535e --- /dev/null +++ b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/age/standard_upper.yaml @@ -0,0 +1,11 @@ +description: Standard upper age limit for 16 to 19 Bursary Fund support. +metadata: + unit: year + period: year + label: 16 to 19 Bursary Fund standard upper age limit + reference: + - title: 16 to 19 Bursary Fund guide 2025 to 2026 + href: https://www.gov.uk/government/publications/16-to-19-bursary-fund-guidance/16-to-19-bursary-fund-guide-2025-to-2026 +values: + 2025-01-01: 19 + 2026-01-01: 19 diff --git a/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/vulnerable_groups/max_amount.yaml b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/vulnerable_groups/max_amount.yaml new file mode 100644 index 000000000..7a7f106d5 --- /dev/null +++ b/policyengine_uk/parameters/gov/dfe/bursary_fund_16_to_19/vulnerable_groups/max_amount.yaml @@ -0,0 +1,11 @@ +description: Maximum annual 16 to 19 Bursary Fund award for students in defined vulnerable groups. +metadata: + unit: currency-GBP + period: year + label: 16 to 19 Bursary Fund vulnerable group maximum amount + reference: + - title: "16 to 19 Bursary Fund: what you'll get" + href: https://www.gov.uk/1619-bursary-fund/what-youll-get +values: + 2025-01-01: 1200 + 2026-01-01: 1200 diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index 666f8d23a..20427cd8a 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -360,6 +360,18 @@ programs: verified_start_year: 2025 notes: First-pass full-time undergraduate England model using explicit full-time, SEN, and childcare-support inputs plus maintenance-loan proxies; childcare_expenses are treated as out-of-pocket spend net of free hours + - id: bursary_fund_16_to_19 + name: 16 to 19 Bursary Fund + full_name: 16 to 19 Bursary Fund + category: Benefits + agency: DfE + status: partial + coverage: England + variable: bursary_fund_16_to_19 + parameter_prefix: gov.dfe.bursary_fund_16_to_19 + verified_start_year: 2025 + notes: First-pass model of the defined vulnerable-group bursary only, using explicit care, self-supporting, and participation-cost inputs plus person-level reported-benefit proxies + # --- DCMS programs --- - id: tv_licence name: TV Licence diff --git a/policyengine_uk/tests/policy/baseline/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.yaml b/policyengine_uk/tests/policy/baseline/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.yaml new file mode 100644 index 000000000..26726e4ef --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.yaml @@ -0,0 +1,269 @@ +- name: 16 to 19 Bursary Fund pays actual costs for care leavers below the cap + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 600 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [true] + bursary_fund_16_to_19: [600] + +- name: 16 to 19 Bursary Fund caps vulnerable-group support at 1200 + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 2_000 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19: [1_200] + +- name: 16 to 19 Bursary Fund covers self-supporting UC recipients + period: 2025 + input: + people: + student: + age: 18 + current_education: POST_SECONDARY + bursary_fund_16_to_19_self_supporting: true + bursary_fund_16_to_19_participation_costs: 900 + universal_credit_reported: 100 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [true] + bursary_fund_16_to_19: [900] + +- name: 16 to 19 Bursary Fund does not cover UC recipients without self-supporting status + period: 2025 + input: + people: + student: + age: 18 + current_education: POST_SECONDARY + bursary_fund_16_to_19_participation_costs: 900 + universal_credit_reported: 100 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [false] + bursary_fund_16_to_19: [0] + +- name: 16 to 19 Bursary Fund covers self-supporting Income Support recipients + period: 2025 + input: + people: + student: + age: 18 + current_education: POST_SECONDARY + bursary_fund_16_to_19_self_supporting: true + bursary_fund_16_to_19_participation_costs: 850 + income_support_reported: 100 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [true] + bursary_fund_16_to_19: [850] + +- name: 16 to 19 Bursary Fund covers students with disability benefit and UC + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_participation_costs: 700 + pip_dl_category: STANDARD + universal_credit_reported: 100 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [true] + bursary_fund_16_to_19: [700] + +- name: 16 to 19 Bursary Fund does not use a parent UC claim for the disability route + period: 2025 + input: + people: + parent: + age: 40 + universal_credit_reported: 100 + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_participation_costs: 700 + pip_dl_category: STANDARD + sibling: + age: 10 + is_child: true + benunits: + benunit: + members: ["parent", "student", "sibling"] + households: + household: + members: ["parent", "student", "sibling"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [false, false, false] + bursary_fund_16_to_19: [0, 0, 0] + +- name: 16 to 19 Bursary Fund does not cover disability benefit without UC or ESA + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_participation_costs: 700 + pip_dl_category: STANDARD + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [false] + bursary_fund_16_to_19: [0] + +- name: 16 to 19 Bursary Fund excludes apprentices + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + is_apprentice: true + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 600 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_in_qualifying_education: [false] + bursary_fund_16_to_19: [0] + +- name: 16 to 19 Bursary Fund excludes over-19 students without funded extension + period: 2025 + input: + people: + student: + age: 20 + current_education: POST_SECONDARY + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 600 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_age_eligible: [false] + bursary_fund_16_to_19: [0] + +- name: 16 to 19 Bursary Fund does not extend vulnerable-group support beyond age 18 + period: 2025 + input: + people: + student: + age: 20 + bursary_fund_16_to_19_in_qualifying_education: true + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 500 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_age_eligible: [false] + bursary_fund_16_to_19: [0] + +- name: 16 to 19 Bursary Fund covers students with disability benefit and ESA + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_participation_costs: 800 + dla_sc_category: MIDDLE + esa_income_reported: 100 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: ENGLAND + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [true] + bursary_fund_16_to_19: [800] + +- name: 16 to 19 Bursary Fund only applies in England + period: 2025 + input: + people: + student: + age: 17 + current_education: POST_SECONDARY + bursary_fund_16_to_19_in_care_or_care_leaver: true + bursary_fund_16_to_19_participation_costs: 600 + benunits: + benunit: + members: ["student"] + households: + household: + members: ["student"] + country: WALES + output: + bursary_fund_16_to_19_vulnerable_group_eligible: [false] + bursary_fund_16_to_19: [0] diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.py new file mode 100644 index 000000000..80c2eab0f --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19.py @@ -0,0 +1,21 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19(Variable): + value_type = float + entity = Person + label = "16 to 19 Bursary Fund" + documentation = ( + "First-pass vulnerable-group 16 to 19 Bursary Fund support. " + "The model pays actual participation costs up to the vulnerable-group maximum." + ) + definition_period = YEAR + unit = GBP + defined_for = "bursary_fund_16_to_19_vulnerable_group_eligible" + + def formula(person, period, parameters): + p = parameters(period).gov.dfe.bursary_fund_16_to_19.vulnerable_groups + participation_costs = person( + "bursary_fund_16_to_19_participation_costs", period + ) + return min_(participation_costs, p.max_amount) diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_age_eligible.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_age_eligible.py new file mode 100644 index 000000000..75e105ff2 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_age_eligible.py @@ -0,0 +1,14 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_age_eligible(Variable): + value_type = bool + entity = Person + label = "Age eligible for 16 to 19 Bursary Fund" + documentation = "Whether the student is age eligible for the vulnerable-group 16 to 19 Bursary Fund." + definition_period = YEAR + + def formula(person, period, parameters): + p = parameters(period).gov.dfe.bursary_fund_16_to_19.age + age = person("age", period) + return (age >= p.minimum) & (age < p.standard_upper) diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_care_or_care_leaver.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_care_or_care_leaver.py new file mode 100644 index 000000000..27a263cbf --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_care_or_care_leaver.py @@ -0,0 +1,11 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_in_care_or_care_leaver(Variable): + value_type = bool + entity = Person + label = "In care or a care leaver for 16 to 19 Bursary Fund" + documentation = "Whether the student is in care or is a care leaver for 16 to 19 Bursary Fund purposes." + definition_period = YEAR + default_value = False + set_input = set_input_dispatch_by_period diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_qualifying_education.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_qualifying_education.py new file mode 100644 index 000000000..613ccfaa5 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_in_qualifying_education.py @@ -0,0 +1,22 @@ +from policyengine_uk.model_api import * +from policyengine_uk.variables.household.demographic.highest_education import ( + EducationType, +) + + +class bursary_fund_16_to_19_in_qualifying_education(Variable): + value_type = bool + entity = Person + label = "In qualifying education for 16 to 19 Bursary Fund" + documentation = ( + "Whether the student is in a qualifying publicly funded post-16 study programme. " + "This can be set explicitly in simulations; by default it uses post-secondary education " + "and excludes apprenticeships." + ) + definition_period = YEAR + set_input = set_input_dispatch_by_period + + def formula(person, period, parameters): + return ( + person("current_education", period) == EducationType.POST_SECONDARY + ) & ~person("is_apprentice", period) diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_participation_costs.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_participation_costs.py new file mode 100644 index 000000000..1b27e6aec --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_participation_costs.py @@ -0,0 +1,15 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_participation_costs(Variable): + value_type = float + entity = Person + label = "Participation costs for 16 to 19 Bursary Fund support" + documentation = ( + "Annual participation costs that the 16 to 19 Bursary Fund can cover, such as travel, books, " + "equipment, or specialist clothing required for study." + ) + definition_period = YEAR + unit = GBP + default_value = 0 + set_input = set_input_dispatch_by_period diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_esa_in_own_right.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_esa_in_own_right.py new file mode 100644 index 000000000..bd266d6e4 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_esa_in_own_right.py @@ -0,0 +1,21 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_receives_uc_or_esa_in_own_right(Variable): + value_type = bool + entity = Person + label = "Receives UC or ESA in own right for 16 to 19 Bursary Fund" + documentation = ( + "Whether the student receives Universal Credit or Employment and Support Allowance " + "in their own right for 16 to 19 Bursary Fund purposes. This can be set explicitly " + "in simulations; by default it uses person-level reported benefit proxies." + ) + definition_period = YEAR + set_input = set_input_dispatch_by_period + + def formula(person, period, parameters): + return (person("universal_credit_reported", period) > 0) | ( + person("esa_income_reported", period) + + person("esa_contrib_reported", period) + > 0 + ) diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_is_in_own_right.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_is_in_own_right.py new file mode 100644 index 000000000..bce5a69b0 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_receives_uc_or_is_in_own_right.py @@ -0,0 +1,19 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_receives_uc_or_is_in_own_right(Variable): + value_type = bool + entity = Person + label = "Receives UC or IS in own right for 16 to 19 Bursary Fund" + documentation = ( + "Whether the student receives Universal Credit or Income Support in their own right " + "for 16 to 19 Bursary Fund purposes. This can be set explicitly in simulations; by " + "default it uses person-level reported benefit proxies." + ) + definition_period = YEAR + set_input = set_input_dispatch_by_period + + def formula(person, period, parameters): + return (person("universal_credit_reported", period) > 0) | ( + person("income_support_reported", period) > 0 + ) diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_self_supporting.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_self_supporting.py new file mode 100644 index 000000000..011500fe2 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_self_supporting.py @@ -0,0 +1,14 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_self_supporting(Variable): + value_type = bool + entity = Person + label = "Self-supporting for 16 to 19 Bursary Fund" + documentation = ( + "Whether the student is financially supporting themselves, or themselves and a dependent living with them, " + "for 16 to 19 Bursary Fund purposes." + ) + definition_period = YEAR + default_value = False + set_input = set_input_dispatch_by_period diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_vulnerable_group_eligible.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_vulnerable_group_eligible.py new file mode 100644 index 000000000..292adff2e --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/bursary_fund_16_to_19_vulnerable_group_eligible.py @@ -0,0 +1,48 @@ +from policyengine_uk.model_api import * + + +class bursary_fund_16_to_19_vulnerable_group_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for vulnerable-group 16 to 19 Bursary Fund support" + documentation = ( + "Whether the student meets the defined vulnerable-group conditions for the 16 to 19 Bursary Fund. " + "This first-pass model uses explicit care/self-supporting inputs and person-level reported-benefit " + "proxies for own-right UC, IS, and ESA receipt." + ) + definition_period = YEAR + defined_for = "would_claim_bursary_fund_16_to_19" + + def formula(person, period, parameters): + country = person.household("country", period) + countries = country.possible_values + in_england = country == countries.ENGLAND + + age_eligible = person("bursary_fund_16_to_19_age_eligible", period) + in_qualifying_education = person( + "bursary_fund_16_to_19_in_qualifying_education", period + ) + + in_care_or_care_leaver = person( + "bursary_fund_16_to_19_in_care_or_care_leaver", period + ) + self_supporting = person("bursary_fund_16_to_19_self_supporting", period) + + receives_uc_or_is = person( + "bursary_fund_16_to_19_receives_uc_or_is_in_own_right", period + ) + receives_uc_or_esa = person( + "bursary_fund_16_to_19_receives_uc_or_esa_in_own_right", period + ) + + receives_disability_benefit = (person("dla", period) > 0) | ( + person("pip", period) > 0 + ) + + vulnerable_group = ( + in_care_or_care_leaver + | (self_supporting & receives_uc_or_is) + | (receives_disability_benefit & receives_uc_or_esa) + ) + + return in_england & age_eligible & in_qualifying_education & vulnerable_group diff --git a/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/would_claim_bursary_fund_16_to_19.py b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/would_claim_bursary_fund_16_to_19.py new file mode 100644 index 000000000..004c329e8 --- /dev/null +++ b/policyengine_uk/variables/gov/dfe/bursary_fund_16_to_19/would_claim_bursary_fund_16_to_19.py @@ -0,0 +1,12 @@ +from policyengine_uk.model_api import * + + +class would_claim_bursary_fund_16_to_19(Variable): + value_type = bool + entity = Person + label = "Would claim 16 to 19 Bursary Fund support" + documentation = ( + "Whether this person would claim 16 to 19 Bursary Fund support if eligible." + ) + definition_period = YEAR + default_value = True diff --git a/policyengine_uk/variables/gov/gov_spending.py b/policyengine_uk/variables/gov/gov_spending.py index 18c5dbe86..6709d65d3 100644 --- a/policyengine_uk/variables/gov/gov_spending.py +++ b/policyengine_uk/variables/gov/gov_spending.py @@ -47,6 +47,7 @@ class gov_spending(Variable): "targeted_childcare_entitlement", "care_to_learn", "childcare_grant", + "bursary_fund_16_to_19", "dfe_education_spending", "dft_subsidy_spending", "nhs_spending", diff --git a/policyengine_uk/variables/household/income/hbai_benefits.py b/policyengine_uk/variables/household/income/hbai_benefits.py index a1e1baa2f..249a0be43 100644 --- a/policyengine_uk/variables/household/income/hbai_benefits.py +++ b/policyengine_uk/variables/household/income/hbai_benefits.py @@ -37,5 +37,6 @@ class hbai_benefits(Variable): "winter_fuel_allowance", "tax_free_childcare", "childcare_grant", + "bursary_fund_16_to_19", "healthy_start_vouchers", ] diff --git a/policyengine_uk/variables/household/income/household_benefits.py b/policyengine_uk/variables/household/income/household_benefits.py index a9571dc5d..bdcf008ba 100644 --- a/policyengine_uk/variables/household/income/household_benefits.py +++ b/policyengine_uk/variables/household/income/household_benefits.py @@ -46,6 +46,7 @@ class household_benefits(Variable): "targeted_childcare_entitlement", "care_to_learn", "childcare_grant", + "bursary_fund_16_to_19", "nhs_spending", "dfe_education_spending", "dft_subsidy_spending",