Skip to content

Commit

Permalink
Increase HP awareness over time (#143)
Browse files Browse the repository at this point in the history
* Increase HP awareness over time

- Initial HP awareness at t=0 defined as input using arg `heat-pump-awareness`
- Add intervention which, when applied, increases the number of agents that become HP aware over time
- This is achieved using a sigmoid probability function to determine the probability of a given agent becoming heat pump aware if they are not already

* Update BUS grant cap based on latest data

- Reduce standard BUS grant cap since we are now starting the simulation in 2024 (r.t. 2022)
- Increase the funding cap for the extended BUS based on gov announcement: https://www.gov.uk/government/news/families-business-and-industry-to-get-energy-efficiency-support
  • Loading branch information
charlotte-avery authored Oct 24, 2024
1 parent c6e8843 commit 29147c1
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 5 deletions.
35 changes: 35 additions & 0 deletions k8s/job.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ local job(name, args_excl_output) = {
'--price-gbp-per-kwh-electricity',
'0.182',
]),
job('03g-%s-awareness-intervention-policy' % std.extVar('SHORT_SHA'), [
'--intervention',
'heat_pump_awareness',
'--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',
'--heat-pump-awareness-intervention-factor',
'0.05',
]),
job('04a-%s-max-policy' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
Expand Down Expand Up @@ -158,6 +170,29 @@ local job(name, args_excl_output) = {
'0.182',
'--include-new-builds'
]),
job('04d-%s-max-policy-awareness-intervention' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'--intervention',
'heat_pump_awareness',
'--intervention',
'gas_oil_boiler_ban',
'--gas-oil-boiler-ban-date',
'2035-01-01',
'--gas-oil-boiler-ban-announce-date',
'2025-01-01',
'--heat-pump-awareness',
'0.5',
'--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',
'--heat-pump-awareness-intervention-factor',
'0.05',
'--include-new-builds',
]),
job('05-%s-max-industry' % std.extVar('SHORT_SHA'), [
'--heat-pump-awareness',
'0.5',
Expand Down
8 changes: 8 additions & 0 deletions simulation/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ def format_uuid(str):
help="Include new build projections (from constants.py). Installers will also build heat pumps in new builds from 2025.",
)

parser.add_argument(
"--heat-pump-awareness-intervention-factor",
type=float_between_0_and_1,
default=0.1,
help="A value between 0 and 1 which determines how quickly heat pump awareness increases over time with the heat pump awareness intervention. A value of 0 is equivalent to not applying the heat pump awareness intervention.",
)

def check_string_is_isoformat_datetime(string) -> str:
datetime.datetime.fromisoformat(string)
return string
Expand Down Expand Up @@ -226,6 +233,7 @@ def validate_args(args):
args.heat_pump_installer_count,
args.heat_pump_installer_annual_growth_rate,
ENGLAND_WALES_ANNUAL_NEW_BUILDS if args.include_new_builds else None,
args.heat_pump_awareness_intervention_factor,
)

with smart_open.open(args.history_file, "w") as file:
Expand Down
20 changes: 20 additions & 0 deletions simulation/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ def reverse_sigmoid(x: float, k: float = SIGMOID_K, offset: float = SIGMOID_OFFS
return 1 / (1 + math.exp(k * (x + offset)))


def heat_pump_awareness_intervention(x: float, m: float):

return min(m * x, 1)


class Household(Agent):
def __init__(
self,
Expand Down Expand Up @@ -416,6 +421,14 @@ def get_proba_rule_out_banned_heating_systems(self, model):

return reverse_sigmoid(years_to_ban)

def get_proba_becomes_heat_pump_aware(self, model):

years_since_start = (model.current_datetime - model.start_datetime).days / 365

return heat_pump_awareness_intervention(
years_since_start, model.heat_pump_awareness_intervention_factor
)

def get_heating_system_options(
self, model: "DomesticHeatingABM", event_trigger: EventTrigger
) -> Set[HeatingSystem]:
Expand All @@ -440,6 +453,13 @@ def get_heating_system_options(
[HeatingSystem.BOILER_GAS, HeatingSystem.BOILER_OIL]
)

if InterventionType.HEAT_PUMP_AWARENESS in model.interventions:
# if awareness intervention used, allow for more agents to become aware of heat pumps
if not self.is_heat_pump_aware:
self.is_heat_pump_aware = true_with_probability(
self.get_proba_becomes_heat_pump_aware(model)
)

if not is_gas_oil_boiler_ban_announced:
# if a gas/boiler ban is announced, we assume all households are aware of heat pumps
if not self.is_heat_pump_aware:
Expand Down
1 change: 1 addition & 0 deletions simulation/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class InterventionType(enum.Enum):
BOILER_UPGRADE_SCHEME = 1
GAS_OIL_BOILER_BAN = 2
EXTENDED_BOILER_UPGRADE_SCHEME = 3
HEAT_PUMP_AWARENESS = 4


# Source: https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/householdsbytypeofhouseholdandfamilyregionsofenglandandukconstituentcountries
Expand Down
4 changes: 2 additions & 2 deletions simulation/costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def estimate_boiler_upgrade_scheme_grant(
return 0

model_population_scale = ENGLAND_WALES_HOUSEHOLD_COUNT_2020 / model.household_count
boiler_upgrade_funding_cap_gbp = 450_000_000 / model_population_scale
boiler_upgrade_funding_cap_gbp = 237_500_000 / model_population_scale
if (
model.boiler_upgrade_scheme_cumulative_spend_gbp
>= boiler_upgrade_funding_cap_gbp
Expand Down Expand Up @@ -345,7 +345,7 @@ def estimate_extended_boiler_upgrade_scheme_grant(
return 0

model_population_scale = ENGLAND_WALES_HOUSEHOLD_COUNT_2020 / model.household_count
boiler_upgrade_funding_cap_gbp = 1_650_000_000 / model_population_scale
boiler_upgrade_funding_cap_gbp = 5_400_000_000 / model_population_scale
if (
model.boiler_upgrade_scheme_cumulative_spend_gbp
>= boiler_upgrade_funding_cap_gbp
Expand Down
6 changes: 6 additions & 0 deletions simulation/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(
heat_pump_installer_count: int,
heat_pump_installer_annual_growth_rate: float,
annual_new_builds: Optional[Dict[int, int]],
heat_pump_awareness_intervention_factor: float,
):
self.start_datetime = start_datetime
self.step_interval = step_interval
Expand Down Expand Up @@ -74,6 +75,9 @@ def __init__(
)
self.heat_pump_installations_at_current_step = 0
self.annual_new_builds = annual_new_builds
self.heat_pump_awareness_intervention_factor = (
heat_pump_awareness_intervention_factor
)

super().__init__(UnorderedSpace())

Expand Down Expand Up @@ -263,6 +267,7 @@ def create_and_run_simulation(
heat_pump_installer_count: int,
heat_pump_installer_annual_growth_rate: float,
annual_new_builds: Dict[int, int],
heat_pump_awareness_intervention_factor: float,
):

model = DomesticHeatingABM(
Expand All @@ -282,6 +287,7 @@ def create_and_run_simulation(
heat_pump_installer_count=heat_pump_installer_count,
heat_pump_installer_annual_growth_rate=heat_pump_installer_annual_growth_rate,
annual_new_builds=annual_new_builds,
heat_pump_awareness_intervention_factor=heat_pump_awareness_intervention_factor,
)

households = create_household_agents(
Expand Down
1 change: 1 addition & 0 deletions simulation/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def model_factory(**model_attributes):
"heat_pump_installer_count": 2_800,
"heat_pump_installer_annual_growth_rate": 0,
"annual_new_builds": None,
"heat_pump_awareness_intervention_factor": 0.0,
}

return DomesticHeatingABM(**{**default_values, **model_attributes})
2 changes: 1 addition & 1 deletion simulation/tests/household_population.csv
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ id,location,property_value_gbp,total_floor_area_m2,is_off_gas_grid,construction_
5,BIRMINGHAM,500000,100,True,BUILT_PRE_1900,BUNGALOW,MID_TERRACE,BOILER_OIL,F,B,RENTED_SOCIAL,False,3,4,4,False
6,BIRMINGHAM,400000,190,False,BUILT_1900_1929,FLAT,END_TERRACE,BOILER_ELECTRIC,E,C,RENTED_PRIVATE,False,1,4,4,False
7,LONDON,300000,50,True,BUILT_1900_1929,FLAT,SEMI_DETACHED,BOILER_GAS,F,E,OWNER_OCCUPIED,True,2,1,3,True
8,MANCHESTER,600000,80,False,BUILT_PRE_1900,BUNGALOW,MID_TERRACE,BOILER_OIL,B,B,RENTED_PRIVATE,True,2,3,2,False
8,MANCHESTER,600000,80,False,BUILT_PRE_1900,BUNGALOW,MID_TERRACE,BOILER_OIL,B,B,RENTED_PRIVATE,True,2,3,2,False
37 changes: 37 additions & 0 deletions simulation/tests/test_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,43 @@ def test_household_ability_to_choose_heat_pump_as_option_depends_on_model_heat_p

assert all(heat_pump in heating_system_options for heat_pump in HEAT_PUMPS)

def test_households_increasingly_likely_to_become_heat_pump_aware(
self,
):
household = household_factory()
model = model_factory(
start_datetime=datetime.datetime(2025, 1, 1),
interventions=[InterventionType.HEAT_PUMP_AWARENESS],
heat_pump_awareness_intervention_factor=0.1,
)

proba_becomes_heat_pump_aware = household.get_proba_becomes_heat_pump_aware(
model
)

model.increment_timestep()
proba_becomes_heat_pump_aware_updated = (
household.get_proba_becomes_heat_pump_aware(model)
)

assert proba_becomes_heat_pump_aware < proba_becomes_heat_pump_aware_updated

def test_heat_pump_awareness_increase_is_zero_in_first_year(
self,
):
household = household_factory()
model = model_factory(
start_datetime=datetime.datetime(2024, 1, 1),
interventions=[InterventionType.HEAT_PUMP_AWARENESS],
heat_pump_awareness_intervention_factor=0.1,
)

proba_becomes_heat_pump_aware = household.get_proba_becomes_heat_pump_aware(
model
)

assert proba_becomes_heat_pump_aware == 0


class TestAgentsWithBoilerBan:
def test_households_increasingly_likely_to_rule_out_heating_systems_that_will_be_banned_as_time_to_ban_decreases(
Expand Down
4 changes: 2 additions & 2 deletions simulation/tests/test_costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def test_boiler_upgrade_scheme_grant_is_zero_when_grant_cap_exceeded(
model_population_scale = (
ENGLAND_WALES_HOUSEHOLD_COUNT_2020 / model.household_count
)
boiler_upgrade_scheme_budget_scaled = 450_000_000 / model_population_scale
boiler_upgrade_scheme_budget_scaled = 237_500_000 / model_population_scale

model.boiler_upgrade_scheme_cumulative_spend_gbp = (
boiler_upgrade_scheme_budget_scaled * 0.8
Expand Down Expand Up @@ -338,7 +338,7 @@ def test_extended_boiler_upgrade_scheme_grant_is_zero_when_grant_cap_exceeded(
model_population_scale = (
ENGLAND_WALES_HOUSEHOLD_COUNT_2020 / model.household_count
)
boiler_upgrade_scheme_budget_scaled = 1_650_000_000 / model_population_scale
boiler_upgrade_scheme_budget_scaled = 5_400_000_000 / model_population_scale

model.boiler_upgrade_scheme_cumulative_spend_gbp = (
boiler_upgrade_scheme_budget_scaled * 0.8
Expand Down
21 changes: 21 additions & 0 deletions simulation/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ def test_rented_heating_system_hassle_factor_must_be_between_0_and_1(
[*mandatory_local_args, "--rented-heating-system-hassle-factor", "10"]
)

def test_heat_pump_awareness_intervention_factor(self, mandatory_local_args):
args = parse_args(
[*mandatory_local_args, "--rented-heating-system-hassle-factor", "0.05"]
)
assert args.rented_heating_system_hassle_factor == 0.05

def test_heat_pump_awareness_intervention_factor_must_be_between_0_and_1(
self, mandatory_local_args
):
with pytest.raises(SystemExit):
parse_args(
[
*mandatory_local_args,
"--heat-pump-awareness-intervention-factor",
"10.0",
]
)

def test_help_flag(self):
with pytest.raises(SystemExit):
parse_args(["-h"])
Expand Down Expand Up @@ -158,13 +176,16 @@ def test_intervention_argument(self, mandatory_local_args):
"boiler_upgrade_scheme",
"--intervention",
"extended_boiler_upgrade_scheme",
"--intervention",
"heat_pump_awareness",
]
)

assert args.intervention == [
InterventionType.RHI,
InterventionType.BOILER_UPGRADE_SCHEME,
InterventionType.EXTENDED_BOILER_UPGRADE_SCHEME,
InterventionType.HEAT_PUMP_AWARENESS,
]

def test_gas_oil_boiler_ban_date_returns_datetime(self, mandatory_local_args):
Expand Down

0 comments on commit 29147c1

Please sign in to comment.