use JRC-IDEES thermal energy service instead of FE for buildings
This change consists of: - reading the final energy (FE) to thermal energy service (TES) efficiency for each each country, seperately for gas and oil (this efficiency represents e.g. the losses in older non-condensing boilers) - using TES instead of FE for the n.loads, so that it is pure energy service instead of including losses in legacy equipment - using the stored efficiencies for baseyear equipment in add_existing_baseyear In the baseyear (e.g. 2020) this should have no effect on FE, since the reduction to TES is conpensated by the lower efficiencies of existing equipment. In the future (e.g. 2050) this leads to a reduction in heating demand, since new equipment is more efficient than existing.
This commit is contained in:
parent
e815c36b5c
commit
0bcb215597
@ -305,6 +305,7 @@ rule build_energy_totals:
|
||||
co2_name=resources("co2_totals.csv"),
|
||||
transport_name=resources("transport_data.csv"),
|
||||
district_heat_share=resources("district_heat_share.csv"),
|
||||
heating_efficiencies=resources("heating_efficiencies.csv"),
|
||||
threads: 16
|
||||
resources:
|
||||
mem_mb=10000,
|
||||
@ -1037,6 +1038,7 @@ rule prepare_sector_network:
|
||||
district_heat_share=resources(
|
||||
"district_heat_share_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
||||
),
|
||||
heating_efficiencies=resources("heating_efficiencies.csv"),
|
||||
temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"),
|
||||
temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"),
|
||||
cop_profiles=resources("cop_profiles_elec_s{simpl}_{clusters}.nc"),
|
||||
|
@ -26,6 +26,7 @@ rule add_existing_baseyear:
|
||||
existing_heating_distribution=resources(
|
||||
"existing_heating_distribution_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
||||
),
|
||||
heating_efficiencies=resources("heating_efficiencies.csv"),
|
||||
output:
|
||||
RESULTS
|
||||
+ "prenetworks-brownfield/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc",
|
||||
|
@ -546,6 +546,14 @@ def add_heating_capacities_installed_before_baseyear(
|
||||
lifetime=costs.at[heat_system.resistive_heater_costs_name, "lifetime"],
|
||||
)
|
||||
|
||||
if "residential" in heat_system.value:
|
||||
efficiency = nodes.str[:2].map(heating_efficiencies["gas residential space efficiency"])
|
||||
elif "services" in heat_system.value:
|
||||
efficiency = nodes.str[:2].map(heating_efficiencies["gas services space efficiency"])
|
||||
else:
|
||||
#default used for urban central, since no info on district heating boilers
|
||||
efficiency = costs.at[heat_system.gas_boiler_costs_name, "efficiency"]
|
||||
|
||||
n.madd(
|
||||
"Link",
|
||||
nodes,
|
||||
@ -554,7 +562,7 @@ def add_heating_capacities_installed_before_baseyear(
|
||||
bus1=nodes + " " + heat_system.value + " heat",
|
||||
bus2="co2 atmosphere",
|
||||
carrier=heat_system.value + " gas boiler",
|
||||
efficiency=costs.at[heat_system.gas_boiler_costs_name, "efficiency"],
|
||||
efficiency=efficiency,
|
||||
efficiency2=costs.at["gas", "CO2 intensity"],
|
||||
capital_cost=(
|
||||
costs.at[heat_system.gas_boiler_costs_name, "efficiency"]
|
||||
@ -569,6 +577,14 @@ def add_heating_capacities_installed_before_baseyear(
|
||||
lifetime=costs.at[heat_system.gas_boiler_costs_name, "lifetime"],
|
||||
)
|
||||
|
||||
if "residential" in heat_system.value:
|
||||
efficiency = nodes.str[:2].map(heating_efficiencies["oil residential space efficiency"])
|
||||
elif "services" in heat_system.value:
|
||||
efficiency = nodes.str[:2].map(heating_efficiencies["oil services space efficiency"])
|
||||
else:
|
||||
#default used for urban central, since no info on district heating boilers
|
||||
efficiency = costs.at[heat_system.oil_boiler_costs_name, "efficiency"]
|
||||
|
||||
n.madd(
|
||||
"Link",
|
||||
nodes,
|
||||
@ -577,7 +593,7 @@ def add_heating_capacities_installed_before_baseyear(
|
||||
bus1=nodes + " " + heat_system.value + " heat",
|
||||
bus2="co2 atmosphere",
|
||||
carrier=heat_system.value + " oil boiler",
|
||||
efficiency=costs.at[heat_system.oil_boiler_costs_name, "efficiency"],
|
||||
efficiency=efficiency,
|
||||
efficiency2=costs.at["oil", "CO2 intensity"],
|
||||
capital_cost=costs.at[heat_system.oil_boiler_costs_name, "efficiency"]
|
||||
* costs.at[heat_system.oil_boiler_costs_name, "fixed"],
|
||||
@ -660,6 +676,11 @@ if __name__ == "__main__":
|
||||
|
||||
if options["heating"]:
|
||||
|
||||
#one could use baseyear here instead (but dangerous if no data)
|
||||
heating_efficiencies = (
|
||||
pd.read_csv(snakemake.input.heating_efficiencies, index_col=[0,1])
|
||||
).swaplevel().loc[int(snakemake.config["energy"]["energy_totals_year"])]
|
||||
|
||||
add_heating_capacities_installed_before_baseyear(
|
||||
n=n,
|
||||
baseyear=baseyear,
|
||||
|
@ -367,6 +367,24 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
|
||||
assert df.index[43] == "Thermal uses"
|
||||
ct_totals["thermal uses residential"] = df.iloc[43]
|
||||
|
||||
df = pd.read_excel(fn_residential, "RES_hh_eff", index_col=0)
|
||||
|
||||
ct_totals["total residential space efficiency"] = df.loc["Space heating"]
|
||||
|
||||
assert df.index[5] == "Diesel oil"
|
||||
ct_totals["oil residential space efficiency"] = df.iloc[5]
|
||||
|
||||
assert df.index[6] == "Natural gas"
|
||||
ct_totals["gas residential space efficiency"] = df.iloc[6]
|
||||
|
||||
ct_totals["total residential water efficiency"] = df.loc["Water heating"]
|
||||
|
||||
assert df.index[18] == "Diesel oil"
|
||||
ct_totals["oil residential water efficiency"] = df.iloc[18]
|
||||
|
||||
assert df.index[19] == "Natural gas"
|
||||
ct_totals["gas residential water efficiency"] = df.iloc[19]
|
||||
|
||||
# services
|
||||
|
||||
df = pd.read_excel(fn_tertiary, "SER_hh_fec", index_col=0)
|
||||
@ -400,6 +418,24 @@ def idees_per_country(ct: str, base_dir: str) -> pd.DataFrame:
|
||||
assert df.index[46] == "Thermal uses"
|
||||
ct_totals["thermal uses services"] = df.iloc[46]
|
||||
|
||||
df = pd.read_excel(fn_tertiary, "SER_hh_eff", index_col=0)
|
||||
|
||||
ct_totals["total services space efficiency"] = df.loc["Space heating"]
|
||||
|
||||
assert df.index[5] == "Diesel oil"
|
||||
ct_totals["oil services space efficiency"] = df.iloc[5]
|
||||
|
||||
assert df.index[7] == "Conventional gas heaters"
|
||||
ct_totals["gas services space efficiency"] = df.iloc[7]
|
||||
|
||||
ct_totals["total services water efficiency"] = df.loc["Hot water"]
|
||||
|
||||
assert df.index[20] == "Diesel oil"
|
||||
ct_totals["oil services water efficiency"] = df.iloc[20]
|
||||
|
||||
assert df.index[21] == "Natural gas"
|
||||
ct_totals["gas services water efficiency"] = df.iloc[21]
|
||||
|
||||
# agriculture, forestry and fishing
|
||||
|
||||
start = "Detailed split of energy consumption (ktoe)"
|
||||
@ -576,7 +612,9 @@ def build_idees(countries: List[str]) -> pd.DataFrame:
|
||||
# efficiency kgoe/100km -> ktoe/100km so that after conversion TWh/100km
|
||||
totals.loc[:, "passenger car efficiency"] /= 1e6
|
||||
# convert ktoe to TWh
|
||||
exclude = totals.columns.str.fullmatch("passenger cars")
|
||||
exclude = totals.columns.str.fullmatch("passenger cars") \
|
||||
^ totals.columns.str.fullmatch(".*space efficiency") \
|
||||
^ totals.columns.str.fullmatch(".*water efficiency")
|
||||
totals = totals.copy()
|
||||
totals.loc[:, ~exclude] *= 11.63 / 1e3
|
||||
|
||||
@ -654,11 +692,16 @@ def build_energy_totals(
|
||||
eurostat_countries = eurostat.index.unique(0)
|
||||
eurostat_years = eurostat.index.unique(1)
|
||||
|
||||
to_drop = ["passenger cars", "passenger car efficiency"]
|
||||
new_index = pd.MultiIndex.from_product(
|
||||
[countries, eurostat_years], names=["country", "year"]
|
||||
)
|
||||
|
||||
to_drop = idees.columns[idees.columns.str.contains("space efficiency")
|
||||
^ idees.columns.str.contains("water efficiency")]
|
||||
to_drop = to_drop.append(pd.Index(
|
||||
["passenger cars", "passenger car efficiency"]
|
||||
))
|
||||
|
||||
df = idees.reindex(new_index).drop(to_drop, axis=1)
|
||||
|
||||
in_eurostat = df.index.levels[0].intersection(eurostat_countries)
|
||||
@ -1500,6 +1543,57 @@ def build_transformation_output_coke(eurostat, fn):
|
||||
df = eurostat.loc[slicer, :].droplevel(level=[2, 3, 4, 5])
|
||||
df.to_csv(fn)
|
||||
|
||||
def build_heating_efficiencies(
|
||||
countries: List[str], idees: pd.DataFrame
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Build heating efficiencies for a set of countries based on IDEES data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
countries : List[str]
|
||||
List of country codes.
|
||||
idees : pd.DataFrame
|
||||
DataFrame with IDEES data.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
DataFrame with heating efficiencies.
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
- It fills missing data with average data.
|
||||
"""
|
||||
|
||||
years = np.arange(2000, 2022)
|
||||
|
||||
cols = idees.columns[idees.columns.str.contains("space efficiency")
|
||||
^ idees.columns.str.contains("water efficiency")]
|
||||
|
||||
logger.info(cols)
|
||||
|
||||
heating_efficiencies = pd.DataFrame(idees[cols])
|
||||
|
||||
new_index = pd.MultiIndex.from_product(
|
||||
[countries, heating_efficiencies.index.unique(1)],
|
||||
names=["country", "year"],
|
||||
)
|
||||
|
||||
heating_efficiencies = heating_efficiencies.reindex(index=new_index)
|
||||
|
||||
for col in cols:
|
||||
unstacked = heating_efficiencies[col].unstack()
|
||||
|
||||
fillvalue = unstacked.mean()
|
||||
|
||||
for ct in unstacked.index:
|
||||
mask = unstacked.loc[ct].isna()
|
||||
unstacked.loc[ct, mask] = fillvalue[mask]
|
||||
heating_efficiencies[col] = unstacked.stack()
|
||||
|
||||
return heating_efficiencies
|
||||
|
||||
# %%
|
||||
if __name__ == "__main__":
|
||||
@ -1556,3 +1650,6 @@ if __name__ == "__main__":
|
||||
|
||||
transport = build_transport_data(countries, population, idees)
|
||||
transport.to_csv(snakemake.output.transport_name)
|
||||
|
||||
heating_efficiencies = build_heating_efficiencies(countries, idees)
|
||||
heating_efficiencies.to_csv(snakemake.output.heating_efficiencies)
|
||||
|
@ -1806,9 +1806,14 @@ def build_heat_demand(n):
|
||||
for sector, use in product(sectors, uses):
|
||||
name = f"{sector} {use}"
|
||||
|
||||
#efficiency for final energy to thermal energy service
|
||||
eff = pop_weighted_energy_totals.index.str[:2].map(
|
||||
heating_efficiencies[f"total {sector} {use} efficiency"]
|
||||
)
|
||||
|
||||
heat_demand[name] = (
|
||||
heat_demand_shape[name] / heat_demand_shape[name].sum()
|
||||
).multiply(pop_weighted_energy_totals[f"total {sector} {use}"]) * 1e6
|
||||
).multiply(pop_weighted_energy_totals[f"total {sector} {use}"]*eff) * 1e6
|
||||
electric_heat_supply[name] = (
|
||||
heat_demand_shape[name] / heat_demand_shape[name].sum()
|
||||
).multiply(pop_weighted_energy_totals[f"electricity {sector} {use}"]) * 1e6
|
||||
@ -4282,6 +4287,10 @@ if __name__ == "__main__":
|
||||
)
|
||||
pop_weighted_energy_totals.update(pop_weighted_heat_totals)
|
||||
|
||||
heating_efficiencies = (
|
||||
pd.read_csv(snakemake.input.heating_efficiencies, index_col=[0,1])
|
||||
).swaplevel().loc[int(snakemake.config["energy"]["energy_totals_year"])]
|
||||
|
||||
patch_electricity_network(n)
|
||||
|
||||
spatial = define_spatial(pop_layout.index, options)
|
||||
|
Loading…
Reference in New Issue
Block a user