Source code for egon.data.datasets.heat_etrago

"""The central module containing all code dealing with heat sector in etrago
"""
import pandas as pd
import geopandas as gpd
from egon.data import db, config
from egon.data.datasets.heat_etrago.power_to_heat import (
    insert_central_power_to_heat,
    insert_individual_power_to_heat,
)
from egon.data.datasets import Dataset
from egon.data.datasets.etrago_setup import link_geom_from_buses
from egon.data.datasets.scenario_parameters import get_sector_parameters


[docs]def insert_buses(carrier, scenario): """Insert heat buses to etrago table Heat buses are divided into central and individual heating Parameters ---------- carrier : str Name of the carrier, either 'central_heat' or 'rural_heat' scenario : str, optional Name of the scenario. """ sources = config.datasets()["etrago_heat"]["sources"] target = config.datasets()["etrago_heat"]["targets"]["heat_buses"] # Delete existing heat buses (central or rural) db.execute_sql( f""" DELETE FROM {target['schema']}.{target['table']} WHERE scn_name = '{scenario}' AND carrier = '{carrier}' AND country = 'DE' """ ) # Select unused index of buses next_bus_id = db.next_etrago_id("bus") # initalize dataframe for heat buses heat_buses = ( gpd.GeoDataFrame( columns=["scn_name", "bus_id", "carrier", "x", "y", "geom"] ) .set_geometry("geom") .set_crs(epsg=4326) ) # If central heat, create one bus per district heating area if carrier == "central_heat": areas = db.select_geodataframe( f""" SELECT area_id, geom_polygon as geom FROM {sources['district_heating_areas']['schema']}. {sources['district_heating_areas']['table']} WHERE scenario = '{scenario}' """, index_col="area_id", ) heat_buses.geom = areas.centroid.to_crs(epsg=4326) # otherwise create one heat bus per hvmv substation # which represents aggregated individual heating for etrago else: mv_grids = db.select_geodataframe( f""" SELECT ST_Centroid(geom) AS geom FROM {sources['mv_grids']['schema']}. {sources['mv_grids']['table']} WHERE bus_id IN (SELECT DISTINCT bus_id FROM boundaries.egon_map_zensus_grid_districts a JOIN demand.egon_peta_heat b ON a.zensus_population_id = b.zensus_population_id WHERE b.scenario = '{scenario}' AND b.zensus_population_id NOT IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) ) """ ) heat_buses.geom = mv_grids.geom.to_crs(epsg=4326) # Insert values into dataframe heat_buses.scn_name = scenario heat_buses.carrier = carrier heat_buses.x = heat_buses.geom.x heat_buses.y = heat_buses.geom.y heat_buses.bus_id = range(next_bus_id, next_bus_id + len(heat_buses)) # Insert data into database heat_buses.to_postgis( target["table"], schema=target["schema"], if_exists="append", con=db.engine(), )
[docs]def insert_store(scenario, carrier): sources = config.datasets()["etrago_heat"]["sources"] targets = config.datasets()["etrago_heat"]["targets"] db.execute_sql( f""" DELETE FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE carrier = '{carrier}_store' AND scn_name = '{scenario}' AND country = 'DE' """ ) db.execute_sql( f""" DELETE FROM {targets['heat_links']['schema']}. {targets['heat_links']['table']} WHERE carrier LIKE '{carrier}_store%' AND scn_name = '{scenario}' AND bus0 IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') AND bus1 IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') """ ) db.execute_sql( f""" DELETE FROM {targets['heat_stores']['schema']}. {targets['heat_stores']['table']} WHERE carrier = '{carrier}_store' AND scn_name = '{scenario}' AND bus IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') """ ) dh_bus = db.select_geodataframe( f""" SELECT * FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE carrier = '{carrier}' AND scn_name = '{scenario}' AND country = 'DE' """, epsg=4326, ) water_tank_bus = dh_bus.copy() water_tank_bus.carrier = carrier + "_store" water_tank_bus.bus_id = range( db.next_etrago_id("bus"), db.next_etrago_id("bus") + len(water_tank_bus), ) water_tank_bus.to_postgis( targets["heat_buses"]["table"], schema=targets["heat_buses"]["schema"], con=db.engine(), if_exists="append", index=False, ) water_tank_charger = pd.DataFrame( data={ "scn_name": scenario, "bus0": dh_bus.bus_id, "bus1": water_tank_bus.bus_id, "carrier": carrier + "_store_charger", "efficiency": get_sector_parameters("heat", "eGon2035")[ "efficiency" ]["water_tank_charger"], "marginal_cost": get_sector_parameters("heat", "eGon2035")[ "marginal_cost" ]["water_tank_charger"], "p_nom_extendable": True, "link_id": range( db.next_etrago_id("link"), db.next_etrago_id("link") + len(water_tank_bus), ), } ) water_tank_charger.to_sql( targets["heat_links"]["table"], schema=targets["heat_links"]["schema"], con=db.engine(), if_exists="append", index=False, ) water_tank_discharger = pd.DataFrame( data={ "scn_name": scenario, "bus0": water_tank_bus.bus_id, "bus1": dh_bus.bus_id, "carrier": carrier + "_store_discharger", "efficiency": get_sector_parameters("heat", "eGon2035")[ "efficiency" ]["water_tank_discharger"], "marginal_cost": get_sector_parameters("heat", "eGon2035")[ "marginal_cost" ]["water_tank_discharger"], "p_nom_extendable": True, "link_id": range( db.next_etrago_id("link"), db.next_etrago_id("link") + len(water_tank_bus), ), } ) water_tank_discharger.to_sql( targets["heat_links"]["table"], schema=targets["heat_links"]["schema"], con=db.engine(), if_exists="append", index=False, ) water_tank_store = pd.DataFrame( data={ "scn_name": scenario, "bus": water_tank_bus.bus_id, "carrier": carrier + "_store", "capital_cost": get_sector_parameters("heat", "eGon2035")[ "capital_cost" ][f"{carrier.split('_')[0]}_water_tank"], "lifetime": get_sector_parameters("heat", "eGon2035")["lifetime"][ f"{carrier.split('_')[0]}_water_tank" ], "e_nom_extendable": True, "store_id": range( db.next_etrago_id("store"), db.next_etrago_id("store") + len(water_tank_bus), ), } ) water_tank_store.to_sql( targets["heat_stores"]["table"], schema=targets["heat_stores"]["schema"], con=db.engine(), if_exists="append", index=False, )
[docs]def store(): insert_store("eGon2035", "central_heat") insert_store("eGon2035", "rural_heat")
[docs]def insert_central_direct_heat(scenario="eGon2035"): """Insert renewable heating technologies (solar and geo thermal) Parameters ---------- scenario : str, optional Name of the scenario The default is 'eGon2035'. Returns ------- None. """ sources = config.datasets()["etrago_heat"]["sources"] targets = config.datasets()["etrago_heat"]["targets"] db.execute_sql( f""" DELETE FROM {targets['heat_generators']['schema']}. {targets['heat_generators']['table']} WHERE carrier IN ('solar_thermal_collector', 'geo_thermal') AND scn_name = '{scenario}' AND bus IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') """ ) db.execute_sql( f""" DELETE FROM {targets['heat_generator_timeseries']['schema']}. {targets['heat_generator_timeseries']['table']} WHERE scn_name = '{scenario}' AND generator_id NOT IN ( SELECT generator_id FROM {targets['heat_generators']['schema']}. {targets['heat_generators']['table']} WHERE scn_name = '{scenario}') """ ) central_thermal = db.select_geodataframe( f""" SELECT district_heating_id, capacity, geometry, carrier FROM {sources['district_heating_supply']['schema']}. {sources['district_heating_supply']['table']} WHERE scenario = '{scenario}' AND carrier IN ( 'solar_thermal_collector', 'geo_thermal') """, geom_col="geometry", index_col="district_heating_id", ) map_dh_id_bus_id = db.select_dataframe( f""" SELECT bus_id, area_id, id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} JOIN {sources['district_heating_areas']['schema']}. {sources['district_heating_areas']['table']} ON ST_Transform(ST_Centroid(geom_polygon), 4326) = geom WHERE carrier = 'central_heat' AND scenario = '{scenario}' AND scn_name = '{scenario}' """, index_col="id", ) new_id = db.next_etrago_id("generator") generator = pd.DataFrame( data={ "scn_name": scenario, "carrier": central_thermal.carrier, "bus": map_dh_id_bus_id.bus_id[central_thermal.index], "p_nom": central_thermal.capacity, "generator_id": range(new_id, new_id + len(central_thermal)), } ) solar_thermal = central_thermal[ central_thermal.carrier == "solar_thermal_collector" ] weather_cells = db.select_geodataframe( f""" SELECT w_id, geom FROM {sources['weather_cells']['schema']}. {sources['weather_cells']['table']} """, index_col="w_id", ) # Map solar thermal collectors to weather cells join = gpd.sjoin(weather_cells, solar_thermal)[["index_right"]] feedin = db.select_dataframe( f""" SELECT w_id, feedin FROM {sources['feedin_timeseries']['schema']}. {sources['feedin_timeseries']['table']} WHERE carrier = 'solar_thermal' AND weather_year = 2011 """, index_col="w_id", ) timeseries = pd.DataFrame( data={ "scn_name": scenario, "temp_id": 1, "p_max_pu": feedin.feedin[join.index].values, "generator_id": generator.generator_id[ generator.carrier == "solar_thermal_collector" ].values, } ).set_index("generator_id") generator = generator.set_index("generator_id") generator.to_sql( targets["heat_generators"]["table"], schema=targets["heat_generators"]["schema"], if_exists="append", con=db.engine(), ) timeseries.to_sql( targets["heat_generator_timeseries"]["table"], schema=targets["heat_generator_timeseries"]["schema"], if_exists="append", con=db.engine(), )
[docs]def insert_central_gas_boilers(scenario="eGon2035"): """Inserts gas boilers for district heating to eTraGo-table Parameters ---------- scenario : str, optional Name of the scenario. The default is 'eGon2035'. Returns ------- None. """ sources = config.datasets()["etrago_heat"]["sources"] targets = config.datasets()["etrago_heat"]["targets"] db.execute_sql( f""" DELETE FROM {targets['heat_links']['schema']}. {targets['heat_links']['table']} WHERE carrier LIKE '%central_gas_boiler%' AND scn_name = '{scenario}' """ ) central_boilers = db.select_dataframe( f""" SELECT c.bus_id as bus0, b.bus_id as bus1, capacity, a.carrier, scenario as scn_name FROM {sources['district_heating_supply']['schema']}. {sources['district_heating_supply']['table']} a JOIN {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} b ON ST_Transform(ST_Centroid(geometry), 4326) = geom JOIN {sources['ch4_voronoi']['schema']}. {sources['ch4_voronoi']['table']} c ON ST_Intersects(ST_Transform(a.geometry, 4326), c.geom) WHERE scenario = '{scenario}' AND b.scn_name = '{scenario}' AND a.carrier = 'gas_boiler' AND b.carrier='central_heat' AND c.carrier='CH4' AND c.scn_name = '{scenario}' """ ) # Add LineString topology central_boilers = link_geom_from_buses(central_boilers, scenario) # Add efficiency and marginal costs of gas boilers central_boilers["efficiency"] = get_sector_parameters("heat", "eGon2035")[ "efficiency" ]["central_gas_boiler"] central_boilers["marginal_cost"] = get_sector_parameters( "heat", "eGon2035" )["marginal_cost"]["central_gas_boiler"] # Transform thermal capacity to CH4 installed capacity central_boilers["p_nom"] = central_boilers.capacity.div( central_boilers.efficiency ) # Drop unused columns central_boilers.drop(["capacity"], axis=1, inplace=True) # Set index central_boilers.index += db.next_etrago_id("link") central_boilers.index.name = "link_id" # Set carrier name central_boilers.carrier = "central_gas_boiler" central_boilers.reset_index().to_postgis( targets["heat_links"]["table"], schema=targets["heat_links"]["schema"], con=db.engine(), if_exists="append", )
[docs]def insert_rural_gas_boilers(scenario="eGon2035"): """Inserts gas boilers for individual heating to eTraGo-table Parameters ---------- scenario : str, optional Name of the scenario. The default is 'eGon2035'. Returns ------- None. """ sources = config.datasets()["etrago_heat"]["sources"] targets = config.datasets()["etrago_heat"]["targets"] db.execute_sql( f""" DELETE FROM {targets['heat_links']['schema']}. {targets['heat_links']['table']} WHERE carrier = 'rural_gas_boiler' AND scn_name = '{scenario}' AND bus0 IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') AND bus1 IN (SELECT bus_id FROM {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} WHERE scn_name = '{scenario}' AND country = 'DE') """ ) rural_boilers = db.select_dataframe( f""" SELECT c.bus_id as bus0, b.bus_id as bus1, capacity, a.carrier, scenario as scn_name FROM {sources['individual_heating_supply']['schema']}. {sources['individual_heating_supply']['table']} a JOIN {targets['heat_buses']['schema']}. {targets['heat_buses']['table']} b ON ST_Transform(ST_Centroid(a.geometry), 4326) = b.geom JOIN {sources['ch4_voronoi']['schema']}. {sources['ch4_voronoi']['table']} c ON ST_Intersects(ST_Transform(a.geometry, 4326), c.geom) WHERE scenario = '{scenario}' AND b.scn_name = '{scenario}' AND a.carrier = 'gas_boiler' AND b.carrier='rural_heat' AND c.carrier='CH4' AND c.scn_name = '{scenario}' """ ) # Add LineString topology rural_boilers = link_geom_from_buses(rural_boilers, scenario) # Add efficiency of gas boilers rural_boilers["efficiency"] = get_sector_parameters("heat", "eGon2035")[ "efficiency" ]["rural_gas_boiler"] # Transform thermal capacity to CH4 installed capacity rural_boilers["p_nom"] = rural_boilers.capacity.div( rural_boilers.efficiency ) # Drop unused columns rural_boilers.drop(["capacity"], axis=1, inplace=True) # Set index rural_boilers.index += db.next_etrago_id("link") rural_boilers.index.name = "link_id" # Set carrier name rural_boilers.carrier = "rural_gas_boiler" rural_boilers.reset_index().to_postgis( targets["heat_links"]["table"], schema=targets["heat_links"]["schema"], con=db.engine(), if_exists="append", )
[docs]def buses(): """Insert individual and district heat buses into eTraGo-tables Parameters ---------- Returns ------- None. """ insert_buses("central_heat", scenario="eGon2035") insert_buses("rural_heat", scenario="eGon2035") insert_buses("central_heat", scenario="eGon100RE") insert_buses("rural_heat", scenario="eGon100RE")
[docs]def supply(): """Insert individual and district heat supply into eTraGo-tables Parameters ---------- Returns ------- None. """ insert_central_direct_heat(scenario="eGon2035") insert_central_power_to_heat(scenario="eGon2035") insert_individual_power_to_heat(scenario="eGon2035") # insert_rural_gas_boilers(scenario="eGon2035") insert_central_gas_boilers(scenario="eGon2035")
[docs]class HeatEtrago(Dataset): """ Collect data related to the heat sector for the eTraGo tool This dataset collects data from the heat sector and puts it into a format that is needed for the transmission grid optimisation within the tool eTraGo. It includes the creation of individual and central heat nodes, aggregates the heat supply technologies (apart from CHP) per medium voltage grid district and adds extendable heat stores to each bus. This data is then writing into the corresponding tables that are read by eTraGo. *Dependencies* * :py:class:`HeatSupply <egon.data.datasets.heat_supply.HeatSupply>` * :py:class:`MvGridDistricts <egon.data.datasets.mv_grid_districts.mv_grid_districts_setup>` * :py:class:`EtragoSetup <egon.data.datasets.etrago_setup.EtragoSetup>` * :py:class:`RenewableFeedin <egon.data.datasets.renewable_feedin.RenewableFeedin>` * :py:class:`HeatTimeSeries <egon.data.datasets.heat_demand_timeseries.HeatTimeSeries>` *Resulting tables* * :py:class:`grid.egon_etrago_bus <egon.data.datasets.etrago_setup.EgonPfHvBus>` is extended * :py:class:`grid.egon_etrago_link <egon.data.datasets.etrago_setup.EgonPfHvLink>` is extended * :py:class:`grid.egon_etrago_link_timeseries <egon.data.datasets.etrago_setup.EgonPfHvLinkTimeseries>` is extended * :py:class:`grid.egon_etrago_store <egon.data.datasets.etrago_setup.EgonPfHvStore>` is extended * :py:class:`grid.egon_etrago_generator <egon.data.datasets.etrago_setup.EgonPfHvGenerator>` is extended """ #: name: str = "HeatEtrago" #: version: str = "0.0.10" def __init__(self, dependencies): super().__init__( name=self.name, version=self.version, dependencies=dependencies, tasks=(buses, supply, store), )