Skip to content

Commit

Permalink
Update household heat pump awareness over time (#149)
Browse files Browse the repository at this point in the history
* Add user inputs for heat pump awareness campaign

* Log heat pump awareness over time in model

* Update HP awareness on campaign date

* Agents become HP aware when ban in place

All agents do not necessarily become HP aware at the ban announcement.
  • Loading branch information
charlotte-avery authored Nov 21, 2024
1 parent cf705ee commit 9ce9d5f
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 134 deletions.
82 changes: 8 additions & 74 deletions k8s/job.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -40,80 +40,15 @@ local job(name, args_excl_output) = {

[
// scenarios
job('03g-%s-extended-bus-policy-very-high-awareness' % std.extVar('SHORT_SHA'), [
job('01a-%s-max-policy-extended-bus' % std.extVar('SHORT_SHA'), [
'--intervention',
'extended_boiler_upgrade_scheme',
'--heat-pump-awareness',
'0.7',
'--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('03h-%s-extended-bus-policy-extremely-awareness' % std.extVar('SHORT_SHA'), [
'--intervention',
'extended_boiler_upgrade_scheme',
'--heat-pump-awareness',
'0.9',
'--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('03i-%s-ext-bus-policy-high-awareness-unlimited-installers' % 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.0682',
'--price-gbp-per-kwh-electricity',
'0.182',
'--heat-pump-installer-count',
'10000000000',
]),
job('03j-%s-ext-bus-high-awareness-unltd-installers-new-builds' % 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.0682',
'--price-gbp-per-kwh-electricity',
'0.182',
'--heat-pump-installer-count',
'10000000000',
'--include-new-builds',
]),
job('04d-%s-max-policy-wo-new-builds' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'--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',
]),
job('04e-%s-max-policy-all-suitable' % std.extVar('SHORT_SHA'), [
'--intervention',
'boiler_upgrade_scheme',
'heat_pump_campaign',
'--campaign-target-heat-pump-awareness',
'0.8',
'--heat-pump-awareness-campaign-date',
'2028-01-01',
'--intervention',
'gas_oil_boiler_ban',
'--gas-oil-boiler-ban-date',
Expand All @@ -122,12 +57,11 @@ local job(name, args_excl_output) = {
'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',
'--all-agents-heat-pump-suitable',
'--heat-pump-installer-count',
'10000000000'
]),
]
19 changes: 19 additions & 0 deletions simulation/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ def check_string_is_isoformat_datetime(string) -> str:
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)

parser.add_argument(
"--heat-pump-awareness-campaign-date",
default=datetime.datetime(2028, 1, 1),
type=convert_to_datetime,
)

parser.add_argument(
"--campaign-target-heat-pump-awareness",
default=0.8,
type=float_between_0_and_1,
)

return parser.parse_args(args)


Expand All @@ -187,6 +199,11 @@ def validate_args(args):
f"Boiler ban announcement date must be on or before ban date, got gas_oil_boiler_ban_date:{args.gas_oil_boiler_ban_date}, gas_oil_boiler_ban_announce_date:{args.gas_oil_boiler_ban_announce_date}"
)

if args.campaign_target_heat_pump_awareness < args.heat_pump_awareness:
raise ValueError(
f"Campaign target awareness must be greater than or equal to the population heat pump awareness, got campaign_target_heat_pump_awareness:{args.campaign_target_heat_pump_awareness}, heat_pump_awareness:{args.heat_pump_awareness}"
)


if __name__ == "__main__":

Expand Down Expand Up @@ -226,6 +243,8 @@ 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.campaign_target_heat_pump_awareness,
args.heat_pump_awareness_campaign_date,
)

with smart_open.open(args.history_file, "w") as file:
Expand Down
44 changes: 42 additions & 2 deletions simulation/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,12 @@ def get_heating_system_options(
[HeatingSystem.BOILER_GAS, HeatingSystem.BOILER_OIL]
)

if not is_gas_oil_boiler_ban_announced:
# if a gas/boiler ban is announced, we assume all households are aware of heat pumps
is_gas_oil_boiler_ban_in_place = (
InterventionType.GAS_OIL_BOILER_BAN in model.interventions
and model.current_datetime >= model.gas_oil_boiler_ban_datetime
)
if not is_gas_oil_boiler_ban_in_place:
# if a gas/boiler ban is in place, we assume all households are aware of heat pumps
if not self.is_heat_pump_aware:
heating_system_options -= HEAT_PUMPS

Expand Down Expand Up @@ -611,8 +615,44 @@ def compute_heat_pump_capacity_kw(self, heat_pump_type: HeatingSystem) -> int:
)
)

def proba_of_becoming_heat_pump_aware_required_to_reach_campaign_target(
self, model
) -> float:
heat_pump_awareness_at_previous_timestep = (
model.heat_pump_awareness_at_timestep
- (
model.num_households_switching_to_heat_pump_aware_at_current_timestep
/ model.household_count
)
)
return (
model.campaign_target_heat_pump_awareness
- heat_pump_awareness_at_previous_timestep
) / (1 - heat_pump_awareness_at_previous_timestep)

def update_heat_pump_awareness(self, model) -> None:
if (
InterventionType.HEAT_PUMP_CAMPAIGN in model.interventions
and model.current_datetime >= model.heat_pump_awareness_campaign_date
and model.heat_pump_awareness_at_timestep
< model.campaign_target_heat_pump_awareness
and not self.is_heat_pump_aware
):
proba_to_become_heat_pump_aware = self.proba_of_becoming_heat_pump_aware_required_to_reach_campaign_target(
model
)
self.is_heat_pump_aware = true_with_probability(
proba_to_become_heat_pump_aware
)
if self.is_heat_pump_aware:
model.num_households_switching_to_heat_pump_aware += 1
model.num_households_switching_to_heat_pump_aware_at_current_timestep += (
1
)

def make_decisions(self, model):

self.update_heat_pump_awareness(model)
self.update_heating_status(model)
self.evaluate_renovation(model)

Expand Down
7 changes: 6 additions & 1 deletion simulation/collectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ def model_heat_pump_installations_at_current_step(model) -> int:
return model.heat_pump_installations_at_current_step


def model_heat_pump_awareness_at_timestep(model) -> float:
return model.heat_pump_awareness_at_timestep


def is_first_timestep(model: "DomesticHeatingABM") -> bool:
return model.current_datetime == model.start_datetime + model.step_interval

Expand All @@ -303,7 +307,6 @@ def get_agent_collectors(
collect_when(model, is_first_timestep)(household_discount_rate),
collect_when(model, is_first_timestep)(household_renovation_budget),
collect_when(model, is_first_timestep)(household_is_heat_pump_suitable),
collect_when(model, is_first_timestep)(household_is_heat_pump_aware),
household_heating_system,
household_heating_system_previous,
household_heating_functioning,
Expand Down Expand Up @@ -340,6 +343,7 @@ def get_agent_collectors(
household_heating_system_costs_insulation_heat_pump_air_source,
household_heating_system_costs_insulation_heat_pump_ground_source,
household_boiler_upgrade_grant_used,
household_is_heat_pump_aware,
]


Expand All @@ -355,4 +359,5 @@ def get_model_collectors(
collect_when(model, is_first_timestep)(model_price_gbp_per_kwh_gas),
collect_when(model, is_first_timestep)(model_price_gbp_per_kwh_electricity),
collect_when(model, is_first_timestep)(model_price_gbp_per_kwh_oil),
model_heat_pump_awareness_at_timestep,
]
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_CAMPAIGN = 4


# Source: https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/householdsbytypeofhouseholdandfamilyregionsofenglandandukconstituentcountries
Expand Down
37 changes: 33 additions & 4 deletions simulation/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ def __init__(
heat_pump_installer_count: int,
heat_pump_installer_annual_growth_rate: float,
annual_new_builds: Optional[Dict[int, int]],
heat_pump_awareness: float,
campaign_target_heat_pump_awareness: float,
heat_pump_awareness_campaign_date: datetime.datetime,
population_heat_pump_awareness: List[bool],
):
self.start_datetime = start_datetime
self.step_interval = step_interval
Expand Down Expand Up @@ -74,6 +78,13 @@ def __init__(
)
self.heat_pump_installations_at_current_step = 0
self.annual_new_builds = annual_new_builds
self.heat_pump_awareness = heat_pump_awareness
self.campaign_target_heat_pump_awareness = campaign_target_heat_pump_awareness
self.heat_pump_awareness_campaign_date = heat_pump_awareness_campaign_date

self.population_heat_pump_awareness = population_heat_pump_awareness
self.num_households_heat_pump_aware = sum(population_heat_pump_awareness)
self.num_households_switching_to_heat_pump_aware = 0

super().__init__(UnorderedSpace())

Expand Down Expand Up @@ -193,21 +204,29 @@ def boiler_upgrade_scheme_spend_gbp(self) -> int:
]
)

@property
def heat_pump_awareness_at_timestep(self) -> float:
return (
self.num_households_heat_pump_aware
+ self.num_households_switching_to_heat_pump_aware
) / self.household_count

def increment_timestep(self):
self.current_datetime += self.step_interval
self.boiler_upgrade_scheme_cumulative_spend_gbp += (
self.boiler_upgrade_scheme_spend_gbp
)
self.heat_pump_installations_at_current_step = 0
self.num_households_switching_to_heat_pump_aware_at_current_timestep = 0


def create_household_agents(
household_population: pd.DataFrame,
heat_pump_awareness: float,
population_heat_pump_awareness: List[bool],
simulation_start_datetime: datetime.datetime,
all_agents_heat_pump_suitable: bool,
) -> Iterator[Household]:
for household in household_population.itertuples():
for i, household in enumerate(household_population.itertuples()):
yield Household(
id=household.id,
location=household.location,
Expand Down Expand Up @@ -236,7 +255,7 @@ def create_household_agents(
is_heat_pump_suitable_archetype=True
if all_agents_heat_pump_suitable
else household.is_heat_pump_suitable_archetype,
is_heat_pump_aware=random.random() < heat_pump_awareness,
is_heat_pump_aware=population_heat_pump_awareness[i],
)


Expand All @@ -263,8 +282,14 @@ def create_and_run_simulation(
heat_pump_installer_count: int,
heat_pump_installer_annual_growth_rate: float,
annual_new_builds: Dict[int, int],
campaign_target_heat_pump_awareness: float,
heat_pump_awareness_campaign_date: datetime.datetime,
):

population_heat_pump_awareness = [
random.random() < heat_pump_awareness for _ in range(len(household_population))
]

model = DomesticHeatingABM(
start_datetime=start_datetime,
step_interval=step_interval,
Expand All @@ -282,11 +307,15 @@ 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=heat_pump_awareness,
campaign_target_heat_pump_awareness=campaign_target_heat_pump_awareness,
heat_pump_awareness_campaign_date=heat_pump_awareness_campaign_date,
population_heat_pump_awareness=population_heat_pump_awareness,
)

households = create_household_agents(
household_population,
heat_pump_awareness,
population_heat_pump_awareness,
model.start_datetime,
all_agents_heat_pump_suitable,
)
Expand Down
4 changes: 4 additions & 0 deletions simulation/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ 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": 0.5,
"campaign_target_heat_pump_awareness": 0.8,
"heat_pump_awareness_campaign_date": datetime.datetime(2028, 1, 1),
"population_heat_pump_awareness": [],
}

return DomesticHeatingABM(**{**default_values, **model_attributes})
Loading

0 comments on commit 9ce9d5f

Please sign in to comment.