Skip to content

Commit

Permalink
Update model assumptions (#141)
Browse files Browse the repository at this point in the history
* Update BUS grant

Now using same grant of £7.5k for both GSHP and ASHP.

* Set default ban announcement to 2025

* Update BUS tests

* Lower EPC threshold to D

Threshold for household to be suitable for a heat pump reduced from EPC C to D.

* Exclude agents in social rentals

* Add extended BUS intervention

* Add hassle factor for rented as input argument

Set default value for rented of 0.4, and default value for owner occupied as 0.1.

* Increase extended BUS funding cap to 1.65B

£150m of total funding per year from 2024 to 2035

* Update fuel costs

Update using 2024 fuel prices and adjust associated policy costs

* Start simulation 1 Jan 2024

* Delay HP discount date to 2026

HP prices are set based on 2020 data, however prices have remained approximately unchanged (looking at 2024 data), so it no longer makes sense to discount the HP price in 2023. Delay discount to 2026.
  • Loading branch information
charlotte-avery authored Oct 22, 2024
1 parent 1fa7a09 commit 0c18289
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 80 deletions.
109 changes: 68 additions & 41 deletions k8s/job.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ local job(name, args_excl_output) = {
command: ['python', '-m', 'simulation'],
args: args_excl_output + [
'--bigquery',
'select * from %s.prod_domestic_heating.household_agents where abs(mod(farm_fingerprint(id), 307)) = 1' % std.extVar('PROJECT_ID'),
"select * from %s.prod_domestic_heating.household_agents where abs(mod(farm_fingerprint(id), 307)) = 1 and occupant_type != 'rented_social'" % std.extVar('PROJECT_ID'),
'gs://%s/%s/{uuid}/output.jsonl.gz' % [std.extVar('BUCKET_NAME'), name],
],
env: [
Expand All @@ -40,48 +40,65 @@ local job(name, args_excl_output) = {

[
// scenarios

job('01-%s-rhi' % std.extVar('SHORT_SHA'), [
'--intervention',
'rhi',
'--start-date',
'2012-01-01',
'--steps',
'120',
'--heat-pump-installer-annual-growth-rate',
'0',
]),
job('02-%s-baseline' % std.extVar('SHORT_SHA'), [
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
]),
job('03a-%s-bus' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
]),
job('03b-%s-bus-policy' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
]),
job('03c-%s-bus-policy-high-awareness' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'--heat-pump-awareness',
'0.5',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.182',
]),
job('03d-%s-extended-bus' % std.extVar('SHORT_SHA'), [
'--intervention',
'extended_boiler_upgrade_scheme',
'--air-source-heat-pump-price-discount-date',
'2026-01-01:0.3',
]),
job('03e-%s-extended-bus-policy' % std.extVar('SHORT_SHA'), [
'--intervention',
'extended_boiler_upgrade_scheme',
'--air-source-heat-pump-price-discount-date',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.182',
]),
job('03f-%s-extended-bus-policy-high-awareness' % std.extVar('SHORT_SHA'), [
'--intervention',
'extended_boiler_upgrade_scheme',
'--heat-pump-awareness',
'0.5',
'--air-source-heat-pump-price-discount-date',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
]),
job('04a-%s-max-policy' % std.extVar('SHORT_SHA'), [
'--intervention',
Expand All @@ -95,11 +112,11 @@ local job(name, args_excl_output) = {
'--heat-pump-awareness',
'0.5',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
'--include-new-builds',
]),
job('04b-%s-max-policy-unlimited-installers' % std.extVar('SHORT_SHA'), [
Expand All @@ -114,11 +131,11 @@ local job(name, args_excl_output) = {
'--heat-pump-awareness',
'0.5',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
'--heat-pump-installer-count',
'10000000000'
]),
Expand All @@ -134,23 +151,25 @@ local job(name, args_excl_output) = {
'--heat-pump-awareness',
'0.5',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
'--include-new-builds'
]),
job('05-%s-max-industry' % std.extVar('SHORT_SHA'), [
'--heat-pump-awareness',
'0.5',
'--heating-system-hassle-factor',
'0',
'--rented-heating-system-hassle-factor',
'0',
'--all-agents-heat-pump-suitable',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--air-source-heat-pump-price-discount-date',
'2025-01-01:0.6',
'2028-01-01:0.6',
]),
job('06a-%s-max-policy-max-industry' % std.extVar('SHORT_SHA'), [
'--intervention',
Expand All @@ -165,15 +184,17 @@ local job(name, args_excl_output) = {
'0.5',
'--heating-system-hassle-factor',
'0',
'--rented-heating-system-hassle-factor',
'0',
'--all-agents-heat-pump-suitable',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--air-source-heat-pump-price-discount-date',
'2025-01-01:0.6',
'2028-01-01:0.6',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
'--include-new-builds'
]),
job('06b-%s-max-policy-max-industry-unlimited-installers' % std.extVar('SHORT_SHA'), [
Expand All @@ -189,15 +210,17 @@ local job(name, args_excl_output) = {
'0.5',
'--heating-system-hassle-factor',
'0',
'--rented-heating-system-hassle-factor',
'0',
'--all-agents-heat-pump-suitable',
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.3',
'2026-01-01:0.3',
'--air-source-heat-pump-price-discount-date',
'2025-01-01:0.6',
'2028-01-01:0.6',
'--price-gbp-per-kwh-gas',
'0.0589',
'0.0682',
'--price-gbp-per-kwh-electricity',
'0.1494',
'0.182',
'--heat-pump-installer-count',
'10000000000'
]),
Expand Down Expand Up @@ -234,10 +257,14 @@ local job(name, args_excl_output) = {
job('56-%s-heating-system-hassle-low' % std.extVar('SHORT_SHA'), [
'--heating-system-hassle-factor',
'0',
'--rented-heating-system-hassle-factor',
'0.2',
]),
job('57-%s-heating-system-hassle-high' % std.extVar('SHORT_SHA'), [
'--heating-system-hassle-factor',
'0.2',
'--rented-heating-system-hassle-factor',
'0.6',
]),

job('58-%s-heat-pump-suitable-low' % std.extVar('SHORT_SHA'), []),
Expand All @@ -264,11 +291,11 @@ local job(name, args_excl_output) = {

job('61-%s-ashp-discount-low' % std.extVar('SHORT_SHA'), [
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0',
'2026-01-01:0',
]),
job('62-%s-ashp-discount-high' % std.extVar('SHORT_SHA'), [
'--air-source-heat-pump-price-discount-date',
'2023-01-01:0.6',
'2026-01-01:0.6',
]),

job('63-%s-hp-installer-growth-low' % std.extVar('SHORT_SHA'), [
Expand Down
18 changes: 13 additions & 5 deletions simulation/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def format_uuid(str):
"--start-date",
dest="start_datetime",
type=convert_to_datetime,
default=datetime.datetime(2022, 1, 1),
default=datetime.datetime(2024, 1, 1),
)

parser.add_argument(
Expand All @@ -97,6 +97,13 @@ def format_uuid(str):
help="A value between 0 and 1 which suppresses the likelihood of a household choosing a given heating system (the higher the value, the lower the likelihood)",
)

parser.add_argument(
"--rented-heating-system-hassle-factor",
type=float_between_0_and_1,
default=0.4,
help="A value between 0 and 1 which suppresses the likelihood of a household choosing a given heating system (the higher the value, the lower the likelihood)",
)

parser.add_argument(
"--intervention",
action="append",
Expand Down Expand Up @@ -161,15 +168,15 @@ def check_string_is_isoformat_datetime(string) -> str:

parser.add_argument(
"--gas-oil-boiler-ban-announce-date",
default=datetime.datetime(2035, 1, 1),
default=datetime.datetime(2025, 1, 1),
type=convert_to_datetime,
)

# SOURCE: Default values from https://energysavingtrust.org.uk/about-us/our-data/ (England, Scotland and Wales)
# These fuel prices were last updated in November 2021, based on predicted fuel prices for 2022
parser.add_argument("--price-gbp-per-kwh-gas", type=float, default=0.0465)
parser.add_argument("--price-gbp-per-kwh-electricity", type=float, default=0.2006)
parser.add_argument("--price-gbp-per-kwh-oil", type=float, default=0.0482)
parser.add_argument("--price-gbp-per-kwh-gas", type=float, default=0.062)
parser.add_argument("--price-gbp-per-kwh-electricity", type=float, default=0.245)
parser.add_argument("--price-gbp-per-kwh-oil", type=float, default=0.068)

return parser.parse_args(args)

Expand Down Expand Up @@ -207,6 +214,7 @@ def validate_args(args):
args.annual_renovation_rate,
args.household_num_lookahead_years,
args.heating_system_hassle_factor,
args.rented_heating_system_hassle_factor,
args.intervention,
args.all_agents_heat_pump_suitable,
args.gas_oil_boiler_ban_date,
Expand Down
39 changes: 34 additions & 5 deletions simulation/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
LOFT_INSULATION_JOISTS_COST,
discount_annual_cash_flow,
estimate_boiler_upgrade_scheme_grant,
estimate_extended_boiler_upgrade_scheme_grant,
estimate_rhi_annual_payment,
get_heating_fuel_costs_net_present_value,
get_unit_and_install_costs,
Expand Down Expand Up @@ -250,7 +251,7 @@ def is_heat_pump_suitable(self) -> bool:
if not all(
[
self.is_heat_pump_suitable_archetype,
self.potential_epc_rating.value >= EPCRating.C.value,
self.potential_epc_rating.value >= EPCRating.D.value,
]
)
else True
Expand Down Expand Up @@ -493,6 +494,12 @@ def get_total_heating_system_costs(
subsidies = estimate_boiler_upgrade_scheme_grant(heating_system, model)
if subsidies > 0:
self.boiler_upgrade_grant_available = True
elif InterventionType.EXTENDED_BOILER_UPGRADE_SCHEME in model.interventions:
subsidies = estimate_extended_boiler_upgrade_scheme_grant(
heating_system, model
)
if subsidies > 0:
self.boiler_upgrade_grant_available = True

elif InterventionType.RHI in model.interventions:
rhi_annual_payment = estimate_rhi_annual_payment(self, heating_system)
Expand All @@ -506,8 +513,24 @@ def get_total_heating_system_costs(

return unit_and_install_costs, fuel_costs_net_present_value, -subsidies

def reset_heating_system_hassle(
self,
heating_system_hassle_factor: float,
rented_heating_system_hassle_factor: float,
):
if (
self.occupant_type == OccupantType.RENTED_PRIVATE
or self.occupant_type == OccupantType.RENTED_SOCIAL
):
return rented_heating_system_hassle_factor
else:
return heating_system_hassle_factor

def choose_heating_system(
self, costs: Dict[HeatingSystem, float], heating_system_hassle_factor: float
self,
costs: Dict[HeatingSystem, float],
heating_system_hassle_factor: float,
rented_heating_system_hassle_factor: float,
):

weights = []
Expand All @@ -519,6 +542,10 @@ def choose_heating_system(
)
weight = 1 / math.exp(cost_as_proportion_of_budget)
if self.is_heating_system_hassle(heating_system):
heating_system_hassle_factor = self.reset_heating_system_hassle(
heating_system_hassle_factor,
rented_heating_system_hassle_factor,
)
weight *= 1 - heating_system_hassle_factor
weights.append(weight)

Expand All @@ -539,9 +566,9 @@ def install_heating_system(

if self.boiler_upgrade_grant_available:
if heating_system == HeatingSystem.HEAT_PUMP_AIR_SOURCE:
self.boiler_upgrade_grant_used = 5_000
self.boiler_upgrade_grant_used = 7_500
if heating_system == HeatingSystem.HEAT_PUMP_GROUND_SOURCE:
self.boiler_upgrade_grant_used = 6_000
self.boiler_upgrade_grant_used = 7_500

def reset_previous_heating_decision_log(self) -> None:

Expand Down Expand Up @@ -641,7 +668,9 @@ def make_decisions(self, model):
}

chosen_heating_system = self.choose_heating_system(
heating_system_replacement_costs, model.heating_system_hassle_factor
heating_system_replacement_costs,
model.heating_system_hassle_factor,
model.rented_heating_system_hassle_factor,
)

self.install_heating_system(chosen_heating_system, model)
Expand Down
1 change: 1 addition & 0 deletions simulation/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ class InterventionType(enum.Enum):
RHI = 0
BOILER_UPGRADE_SCHEME = 1
GAS_OIL_BOILER_BAN = 2
EXTENDED_BOILER_UPGRADE_SCHEME = 3


# Source: https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/householdsbytypeofhouseholdandfamilyregionsofenglandandukconstituentcountries
Expand Down
Loading

0 comments on commit 0c18289

Please sign in to comment.