Source code for egon.data.datasets.heat_demand_timeseries

from datetime import datetime
from pathlib import Path
import os

from sqlalchemy import ARRAY, Column, Float, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
import geopandas as gpd
import numpy as np
import pandas as pd

from egon.data import db
import egon.data.datasets.era5 as era

try:
    from disaggregator import temporal
except ImportError as e:
    pass

from math import ceil

from egon.data.datasets import Dataset
from egon.data.datasets.heat_demand_timeseries.daily import (
    daily_demand_shares_per_climate_zone,
    map_climate_zones_to_zensus,
)
from egon.data.datasets.heat_demand_timeseries.idp_pool import create, select
from egon.data.datasets.heat_demand_timeseries.service_sector import (
    CTS_demand_scale,
)
import egon

Base = declarative_base()


[docs]class EgonTimeseriesDistrictHeating(Base): __tablename__ = "egon_timeseries_district_heating" __table_args__ = {"schema": "demand"} area_id = Column(Integer, primary_key=True) scenario = Column(Text, primary_key=True) dist_aggregated_mw = Column(ARRAY(Float(53)))
[docs]class EgonEtragoTimeseriesIndividualHeating(Base): __tablename__ = "egon_etrago_timeseries_individual_heating" __table_args__ = {"schema": "demand"} bus_id = Column(Integer, primary_key=True) scenario = Column(Text, primary_key=True) dist_aggregated_mw = Column(ARRAY(Float(53)))
[docs]class EgonIndividualHeatingPeakLoads(Base): __tablename__ = "egon_individual_heating_peak_loads" __table_args__ = {"schema": "demand"} building_id = Column(Integer, primary_key=True) scenario = Column(Text, primary_key=True) w_th = Column(Float(53))
[docs]class EgonEtragoHeatCts(Base): __tablename__ = "egon_etrago_heat_cts" __table_args__ = {"schema": "demand"} bus_id = Column(Integer, primary_key=True) scn_name = Column(String, primary_key=True) p_set = Column(ARRAY(Float))
[docs]def create_timeseries_for_building(building_id, scenario): """Generates final heat demand timeseries for a specific building Parameters ---------- building_id : int Index of the selected building scenario : str Name of the selected scenario. Returns ------- pandas.DataFrame Hourly heat demand timeseries in MW for the selected building """ return db.select_dataframe( f""" SELECT building_demand * UNNEST(idp) as demand FROM ( SELECT demand.demand / building.count * daily_demand.daily_demand_share as building_demand, daily_demand.day_of_year FROM (SELECT demand FROM demand.egon_peta_heat WHERE scenario = '{scenario}' AND sector = 'residential' AND zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE building_id = {building_id})) as demand, (SELECT COUNT(building_id) FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE building_id = {building_id})) as building, (SELECT daily_demand_share, day_of_year FROM demand.egon_daily_heat_demand_per_climate_zone WHERE climate_zone = ( SELECT climate_zone FROM boundaries.egon_map_zensus_climate_zones WHERE zensus_population_id = (SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE building_id = {building_id}))) as daily_demand) as daily_demand JOIN (SELECT b.idp, ordinality as day FROM demand.egon_heat_timeseries_selected_profiles a, UNNEST (a.selected_idp_profiles) WITH ORDINALITY as selected_idp JOIN demand.egon_heat_idp_pool b ON selected_idp = b.index WHERE a.building_id = {building_id}) as demand_profile ON demand_profile.day = daily_demand.day_of_year """ )
[docs]def create_district_heating_profile(scenario, area_id): """Create heat demand profile for district heating grid including demands of households and service sector. Parameters ---------- scenario : str Name of the selected scenario. area_id : int Index of the selected district heating grid Returns ------- df : pandas,DataFrame Hourly heat demand timeseries in MW for the selected district heating grid """ start_time = datetime.now() df = db.select_dataframe( f""" SELECT SUM(building_demand_per_hour) as demand_profile, hour_of_year FROM ( SELECT demand.demand * c.daily_demand_share * hourly_demand as building_demand_per_hour, ordinality + 24* (c.day_of_year-1) as hour_of_year, demand_profile.building_id, c.day_of_year, ordinality FROM (SELECT zensus_population_id, demand FROM demand.egon_peta_heat WHERE scenario = '{scenario}' AND sector = 'residential' AND zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' AND area_id = {area_id} )) as demand JOIN boundaries.egon_map_zensus_climate_zones b ON demand.zensus_population_id = b.zensus_population_id JOIN demand.egon_daily_heat_demand_per_climate_zone c ON c.climate_zone = b.climate_zone JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id FROM demand.egon_heat_timeseries_selected_profiles d, UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp JOIN demand.egon_heat_idp_pool e ON selected_idp = e.index WHERE zensus_population_id IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' AND area_id = {area_id} )) demand_profile ON (demand_profile.day = c.day_of_year AND demand_profile.zensus_population_id = b.zensus_population_id) JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' AND area_id = {area_id} )) GROUP BY zensus_population_id) building ON building.zensus_population_id = b.zensus_population_id, UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand ) result GROUP BY hour_of_year """ ) print( f"Time to create time series for district heating grid {scenario} {area_id}:" ) print(datetime.now() - start_time) return df
[docs]def create_district_heating_profile_python_like(scenario="eGon2035"): """Creates profiles for all district heating grids in one scenario. Similar to create_district_heating_profile but faster and needs more RAM. The results are directly written into the database. Parameters ---------- scenario : str Name of the selected scenario. Returns ------- None. """ start_time = datetime.now() idp_df = db.select_dataframe( """ SELECT index, idp FROM demand.egon_heat_idp_pool """, index_col="index", ) district_heating_grids = db.select_dataframe( f""" SELECT area_id FROM demand.egon_district_heating_areas WHERE scenario = '{scenario}' """ ) annual_demand = db.select_dataframe( f""" SELECT a.zensus_population_id, demand/c.count as per_building , area_id, demand as demand_total FROM demand.egon_peta_heat a INNER JOIN ( SELECT * FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) b ON a.zensus_population_id = b.zensus_population_id JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts )) GROUP BY zensus_population_id)c ON a.zensus_population_id = c.zensus_population_id WHERE a.scenario = '{scenario}' AND a.sector = 'residential' """, index_col="zensus_population_id", ) annual_demand = annual_demand[ ~annual_demand.index.duplicated(keep="first") ] daily_demand_shares = db.select_dataframe( """ SELECT climate_zone, day_of_year as day, daily_demand_share FROM demand.egon_daily_heat_demand_per_climate_zone """ ) CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale( aggregation_level="district" ) # TODO: use session_scope! from sqlalchemy.orm import sessionmaker session = sessionmaker(bind=db.engine())() print(datetime.now() - start_time) start_time = datetime.now() for area in district_heating_grids.area_id.unique(): selected_profiles = db.select_dataframe( f""" SELECT a.zensus_population_id, building_id, c.climate_zone, selected_idp, ordinality as day, b.area_id FROM demand.egon_heat_timeseries_selected_profiles a INNER JOIN boundaries.egon_map_zensus_climate_zones c ON a.zensus_population_id = c.zensus_population_id INNER JOIN ( SELECT * FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' AND area_id = '{area}' ) b ON a.zensus_population_id = b.zensus_population_id , UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp """ ) if not selected_profiles.empty: df = pd.merge( selected_profiles, daily_demand_shares, on=["day", "climate_zone"], ) slice_df = pd.merge( df[df.area_id == area], idp_df, left_on="selected_idp", right_on="index", ) for hour in range(24): slice_df[hour] = ( slice_df.idp.str[hour] .mul(slice_df.daily_demand_share) .mul( annual_demand.loc[ slice_df.zensus_population_id.values, "per_building", ].values ) ) diff = ( slice_df.groupby("day").sum()[range(24)].sum().sum() - annual_demand[ annual_demand.area_id == area ].demand_total.sum() ) / ( annual_demand[annual_demand.area_id == area].demand_total.sum() ) assert ( abs(diff) < 0.03 ), f"""Deviation of residential heat demand time series for district heating grid {str(area)} is {diff}""" hh = np.concatenate( slice_df.groupby("day").sum()[range(24)].values ).ravel() cts = CTS_demand_dist[ (CTS_demand_dist.scenario == scenario) & (CTS_demand_dist.index == area) ].drop("scenario", axis="columns") if (not selected_profiles.empty) and not cts.empty: entry = EgonTimeseriesDistrictHeating( area_id=int(area), scenario=scenario, dist_aggregated_mw=(hh + cts.values[0]).tolist(), ) elif (not selected_profiles.empty) and cts.empty: entry = EgonTimeseriesDistrictHeating( area_id=int(area), scenario=scenario, dist_aggregated_mw=(hh).tolist(), ) elif not cts.empty: entry = EgonTimeseriesDistrictHeating( area_id=int(area), scenario=scenario, dist_aggregated_mw=(cts.values[0]).tolist(), ) session.add(entry) session.commit() print( f"Time to create time series for district heating scenario {scenario}" ) print(datetime.now() - start_time)
[docs]def create_individual_heat_per_mv_grid(scenario="eGon2035", mv_grid_id=1564): start_time = datetime.now() df = db.select_dataframe( f""" SELECT SUM(building_demand_per_hour) as demand_profile, hour_of_year FROM ( SELECT demand.demand * c.daily_demand_share * hourly_demand as building_demand_per_hour, ordinality + 24* (c.day_of_year-1) as hour_of_year, demand_profile.building_id, c.day_of_year, ordinality FROM (SELECT zensus_population_id, demand FROM demand.egon_peta_heat WHERE scenario = '{scenario}' AND sector = 'residential' AND zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts WHERE bus_id = {mv_grid_id} )) as demand JOIN boundaries.egon_map_zensus_climate_zones b ON demand.zensus_population_id = b.zensus_population_id JOIN demand.egon_daily_heat_demand_per_climate_zone c ON c.climate_zone = b.climate_zone JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id FROM demand.egon_heat_timeseries_selected_profiles d, UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp JOIN demand.egon_heat_idp_pool e ON selected_idp = e.index WHERE zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts WHERE bus_id = {mv_grid_id} )) demand_profile ON (demand_profile.day = c.day_of_year AND demand_profile.zensus_population_id = b.zensus_population_id) JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts WHERE bus_id = {mv_grid_id} )) GROUP BY zensus_population_id) building ON building.zensus_population_id = b.zensus_population_id, UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand ) result GROUP BY hour_of_year """ ) print(f"Time to create time series for mv grid {scenario} {mv_grid_id}:") print(datetime.now() - start_time) return df
[docs]def calulate_peak_load(df, scenario): # peat load in W_th data = ( df.groupby("building_id") .max()[range(24)] .max(axis=1) .mul(1000000) .astype(int) .reset_index() ) data["scenario"] = scenario data.rename({0: "w_th"}, axis="columns", inplace=True) data.to_sql( EgonIndividualHeatingPeakLoads.__table__.name, schema=EgonIndividualHeatingPeakLoads.__table__.schema, con=db.engine(), if_exists="append", index=False, )
[docs]def create_individual_heating_peak_loads(scenario="eGon2035"): engine = db.engine() EgonIndividualHeatingPeakLoads.__table__.drop(bind=engine, checkfirst=True) EgonIndividualHeatingPeakLoads.__table__.create( bind=engine, checkfirst=True ) start_time = datetime.now() idp_df = db.select_dataframe( """ SELECT index, idp FROM demand.egon_heat_idp_pool """, index_col="index", ) annual_demand = db.select_dataframe( f""" SELECT a.zensus_population_id, demand/c.count as per_building, bus_id FROM demand.egon_peta_heat a JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts )) GROUP BY zensus_population_id)c ON a.zensus_population_id = c.zensus_population_id JOIN boundaries.egon_map_zensus_grid_districts d ON a.zensus_population_id = d.zensus_population_id WHERE a.scenario = '{scenario}' AND a.sector = 'residential' AND a.zensus_population_id NOT IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) """, index_col="zensus_population_id", ) daily_demand_shares = db.select_dataframe( """ SELECT climate_zone, day_of_year as day, daily_demand_share FROM demand.egon_daily_heat_demand_per_climate_zone """ ) start_time = datetime.now() for grid in annual_demand.bus_id.unique(): selected_profiles = db.select_dataframe( f""" SELECT a.zensus_population_id, building_id, c.climate_zone, selected_idp, ordinality as day FROM demand.egon_heat_timeseries_selected_profiles a INNER JOIN boundaries.egon_map_zensus_climate_zones c ON a.zensus_population_id = c.zensus_population_id , UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp WHERE a.zensus_population_id NOT IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) AND a.zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts WHERE bus_id = '{grid}' ) """ ) df = pd.merge( selected_profiles, daily_demand_shares, on=["day", "climate_zone"] ) slice_df = pd.merge( df, idp_df, left_on="selected_idp", right_on="index" ) for hour in range(24): slice_df[hour] = ( slice_df.idp.str[hour] .mul(slice_df.daily_demand_share) .mul( annual_demand.loc[ slice_df.zensus_population_id.values, "per_building" ].values ) ) calulate_peak_load(slice_df, scenario) print(f"Time to create peak loads per building for {scenario}") print(datetime.now() - start_time)
[docs]def create_individual_heating_profile_python_like(scenario="eGon2035"): start_time = datetime.now() idp_df = db.select_dataframe( f""" SELECT index, idp FROM demand.egon_heat_idp_pool """, index_col="index", ) annual_demand = db.select_dataframe( f""" SELECT a.zensus_population_id, demand/c.count as per_building, demand as demand_total, bus_id FROM demand.egon_peta_heat a JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts )) GROUP BY zensus_population_id)c ON a.zensus_population_id = c.zensus_population_id JOIN boundaries.egon_map_zensus_grid_districts d ON a.zensus_population_id = d.zensus_population_id WHERE a.scenario = '{scenario}' AND a.sector = 'residential' AND a.zensus_population_id NOT IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) """, index_col="zensus_population_id", ) daily_demand_shares = db.select_dataframe( f""" SELECT climate_zone, day_of_year as day, daily_demand_share FROM demand.egon_daily_heat_demand_per_climate_zone """ ) CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale( aggregation_level="district" ) # TODO: use session_scope! from sqlalchemy.orm import sessionmaker session = sessionmaker(bind=db.engine())() print( f"Time to create overhead for time series for district heating scenario {scenario}" ) print(datetime.now() - start_time) start_time = datetime.now() for grid in annual_demand.bus_id.unique(): selected_profiles = db.select_dataframe( f""" SELECT a.zensus_population_id, building_id, c.climate_zone, selected_idp, ordinality as day FROM demand.egon_heat_timeseries_selected_profiles a INNER JOIN boundaries.egon_map_zensus_climate_zones c ON a.zensus_population_id = c.zensus_population_id , UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp WHERE a.zensus_population_id NOT IN ( SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas WHERE scenario = '{scenario}' ) AND a.zensus_population_id IN ( SELECT zensus_population_id FROM boundaries.egon_map_zensus_grid_districts WHERE bus_id = '{grid}' ) """ ) df = pd.merge( selected_profiles, daily_demand_shares, on=["day", "climate_zone"] ) slice_df = pd.merge( df, idp_df, left_on="selected_idp", right_on="index" ) for hour in range(24): slice_df[hour] = ( slice_df.idp.str[hour] .mul(slice_df.daily_demand_share) .mul( annual_demand.loc[ slice_df.zensus_population_id.values, "per_building" ].values ) ) cts = CTS_demand_grid[ (CTS_demand_grid.scenario == scenario) & (CTS_demand_grid.index == grid) ].drop("scenario", axis="columns") hh = np.concatenate( slice_df.groupby("day").sum()[range(24)].values ).ravel() diff = ( slice_df.groupby("day").sum()[range(24)].sum().sum() - annual_demand[annual_demand.bus_id == grid].demand_total.sum() ) / (annual_demand[annual_demand.bus_id == grid].demand_total.sum()) assert ( abs(diff) < 0.03 ), f"""Deviation of residential heat demand time series for mv grid {str(grid)} is {diff}""" if not (slice_df[hour].empty or cts.empty): entry = EgonEtragoTimeseriesIndividualHeating( bus_id=int(grid), scenario=scenario, dist_aggregated_mw=(hh + cts.values[0]).tolist(), ) elif not slice_df[hour].empty: entry = EgonEtragoTimeseriesIndividualHeating( bus_id=int(grid), scenario=scenario, dist_aggregated_mw=(hh).tolist(), ) elif not cts.empty: entry = EgonEtragoTimeseriesIndividualHeating( bus_id=int(grid), scenario=scenario, dist_aggregated_mw=(cts).tolist(), ) session.add(entry) session.commit() print( f"Time to create time series for district heating scenario {scenario}" ) print(datetime.now() - start_time)
[docs]def district_heating(method="python"): engine = db.engine() EgonTimeseriesDistrictHeating.__table__.drop(bind=engine, checkfirst=True) EgonTimeseriesDistrictHeating.__table__.create( bind=engine, checkfirst=True ) if method == "python": create_district_heating_profile_python_like("eGon2035") create_district_heating_profile_python_like("eGon100RE") else: CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale( aggregation_level="district" ) ids = db.select_dataframe( """ SELECT area_id, scenario FROM demand.egon_district_heating_areas """ ) df = pd.DataFrame( columns=["area_id", "scenario", "dist_aggregated_mw"] ) for index, row in ids.iterrows(): series = create_district_heating_profile( scenario=row.scenario, area_id=row.area_id ) cts = ( CTS_demand_dist[ (CTS_demand_dist.scenario == row.scenario) & (CTS_demand_dist.index == row.area_id) ] .drop("scenario", axis="columns") .transpose() ) if not cts.empty: data = ( cts[row.area_id] + series.demand_profile ).values.tolist() else: data = series.demand_profile.values.tolist() df = df.append( pd.Series( data={ "area_id": row.area_id, "scenario": row.scenario, "dist_aggregated_mw": data, }, ), ignore_index=True, ) df.to_sql( "egon_timeseries_district_heating", schema="demand", con=db.engine(), if_exists="append", index=False, )
[docs]def individual_heating_per_mv_grid_tables(method="python"): engine = db.engine() EgonEtragoTimeseriesIndividualHeating.__table__.drop( bind=engine, checkfirst=True ) EgonEtragoTimeseriesIndividualHeating.__table__.create( bind=engine, checkfirst=True )
[docs]def individual_heating_per_mv_grid_2035(method="python"): create_individual_heating_profile_python_like("eGon2035")
[docs]def individual_heating_per_mv_grid_100(method="python"): create_individual_heating_profile_python_like("eGon100RE")
[docs]def individual_heating_per_mv_grid(method="python"): if method == "python": engine = db.engine() EgonEtragoTimeseriesIndividualHeating.__table__.drop( bind=engine, checkfirst=True ) EgonEtragoTimeseriesIndividualHeating.__table__.create( bind=engine, checkfirst=True ) create_individual_heating_profile_python_like("eGon2035") create_individual_heating_profile_python_like("eGon100RE") else: engine = db.engine() EgonEtragoTimeseriesIndividualHeating.__table__.drop( bind=engine, checkfirst=True ) EgonEtragoTimeseriesIndividualHeating.__table__.create( bind=engine, checkfirst=True ) CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale( aggregation_level="district" ) df = pd.DataFrame(columns=["bus_id", "scenario", "dist_aggregated_mw"]) ids = db.select_dataframe( """ SELECT bus_id FROM grid.egon_mv_grid_district """ ) for index, row in ids.iterrows(): for scenario in ["eGon2035", "eGon100RE"]: series = create_individual_heat_per_mv_grid( scenario, row.bus_id ) cts = ( CTS_demand_grid[ (CTS_demand_grid.scenario == scenario) & (CTS_demand_grid.index == row.bus_id) ] .drop("scenario", axis="columns") .transpose() ) if not cts.empty: data = ( cts[row.bus_id] + series.demand_profile ).values.tolist() else: data = series.demand_profile.values.tolist() df = df.append( pd.Series( data={ "bus_id": row.bus_id, "scenario": scenario, "dist_aggregated_mw": data, }, ), ignore_index=True, ) df.to_sql( "egon_etrago_timeseries_individual_heating", schema="demand", con=db.engine(), if_exists="append", index=False, )
[docs]def store_national_profiles(): scenario = "eGon100RE" df = db.select_dataframe( f""" SELECT SUM(building_demand_per_hour) as "residential rural" FROM ( SELECT demand.demand * c.daily_demand_share * hourly_demand as building_demand_per_hour, ordinality + 24* (c.day_of_year-1) as hour_of_year, demand_profile.building_id, c.day_of_year, ordinality FROM (SELECT zensus_population_id, demand FROM demand.egon_peta_heat WHERE scenario = '{scenario}' AND sector = 'residential' ) as demand JOIN boundaries.egon_map_zensus_climate_zones b ON demand.zensus_population_id = b.zensus_population_id JOIN demand.egon_daily_heat_demand_per_climate_zone c ON c.climate_zone = b.climate_zone JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id FROM demand.egon_heat_timeseries_selected_profiles d, UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp JOIN demand.egon_heat_idp_pool e ON selected_idp = e.index ) demand_profile ON (demand_profile.day = c.day_of_year AND demand_profile.zensus_population_id = b.zensus_population_id) JOIN (SELECT COUNT(building_id), zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles WHERE zensus_population_id IN( SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles ) GROUP BY zensus_population_id) building ON building.zensus_population_id = b.zensus_population_id, UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand ) result GROUP BY hour_of_year """ ) CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale( aggregation_level="district" ) df["service rural"] = ( CTS_demand_dist.loc[CTS_demand_dist.scenario == scenario] .drop("scenario", axis=1) .sum() ) df["urban central"] = db.select_dataframe( f""" SELECT sum(demand) as "urban central" FROM demand.egon_timeseries_district_heating, UNNEST (dist_aggregated_mw) WITH ORDINALITY as demand WHERE scenario = '{scenario}' GROUP BY ordinality """ ) folder = Path(".") / "input-pypsa-eur-sec" # Create the folder, if it does not exists already if not os.path.exists(folder): os.mkdir(folder) df.to_csv(folder / f"heat_demand_timeseries_DE_{scenario}.csv")
[docs]def export_etrago_cts_heat_profiles(): """Export heat cts load profiles at mv substation level to etrago-table in the database Returns ------- None. """ # Calculate cts heat profiles at substation _, CTS_grid, _ = CTS_demand_scale("district") # Change format data = CTS_grid.drop(columns="scenario") df_etrago_cts_heat_profiles = pd.DataFrame( index=data.index, columns=["scn_name", "p_set"] ) df_etrago_cts_heat_profiles.p_set = data.values.tolist() df_etrago_cts_heat_profiles.scn_name = CTS_grid["scenario"] df_etrago_cts_heat_profiles.reset_index(inplace=True) # Drop and recreate Table if exists EgonEtragoHeatCts.__table__.drop(bind=db.engine(), checkfirst=True) EgonEtragoHeatCts.__table__.create(bind=db.engine(), checkfirst=True) # Write heat ts into db with db.session_scope() as session: session.bulk_insert_mappings( EgonEtragoHeatCts, df_etrago_cts_heat_profiles.to_dict(orient="records"), )
[docs]class HeatTimeSeries(Dataset): """ Chooses heat demand profiles for each residential and CTS building This dataset creates heat demand profiles in an hourly resoultion. Time series for CTS buildings are created using the SLP-gas method implemented in the demandregio disagregator with the function :py:func:`export_etrago_cts_heat_profiles` and stored in the database. Time series for residential buildings are created based on a variety of synthetical created individual demand profiles that are part of :py:class:`DataBundle <egon.data.datasets.data_bundle.DataBundle>`. This method is desribed within the functions and in this publication: C. Büttner, J. Amme, J. Endres, A. Malla, B. Schachler, I. Cußmann, Open modeling of electricity and heat demand curves for all residential buildings in Germany, Energy Informatics 5 (1) (2022) 21. doi:10.1186/s42162-022-00201-y. *Dependencies* * :py:class:`DataBundle <egon.data.datasets.data_bundle.DataBundle>` * :py:class:`DemandRegio <egon.data.datasets.demandregio.DemandRegio>` * :py:class:`HeatDemandImport <egon.data.datasets.heat_demand.HeatDemandImport>` * :py:class:`DistrictHeatingAreas <egon.data.datasets.district_heating_areas.DistrictHeatingAreas>` * :py:class:`Vg250 <egon.data.datasets.vg250.Vg250>` * :py:class:`ZensusMvGridDistricts <egon.data.datasets.zensus_mv_grid_districts.ZensusMvGridDistricts>` * :py:func:`hh_demand_buildings_setup <egon.data.datasets.electricity_demand_timeseries.hh_buildings.map_houseprofiles_to_buildings>` * :py:class:`WeatherData <egon.data.datasets.era5.WeatherData>` *Resulting tables* * :py:class:`demand.egon_timeseries_district_heating <egon.data.datasets.heat_demand_timeseries.EgonTimeseriesDistrictHeating>` is created and filled * :py:class:`demand.egon_etrago_heat_cts <egon.data.datasets.heat_demand_timeseries.EgonEtragoHeatCts>` is created and filled * :py:class:`demand.egon_heat_timeseries_selected_profiles <egon.data.datasets.heat_demand_timeseries.idp_pool.EgonHeatTimeseries>` is created and filled * :py:class:`demand.egon_daily_heat_demand_per_climate_zone <egon.data.datasets.heat_demand_timeseries.daily.EgonDailyHeatDemandPerClimateZone>` is created and filled * :py:class:`boundaries.egon_map_zensus_climate_zones <egon.data.datasets.heat_demand_timeseries.daily.EgonMapZensusClimateZones>` is created and filled """ #: name: str = "HeatTimeSeries" #: version: str = "0.0.7" def __init__(self, dependencies): super().__init__( name=self.name, version=self.version, dependencies=dependencies, tasks=( { export_etrago_cts_heat_profiles, map_climate_zones_to_zensus, daily_demand_shares_per_climate_zone, create, }, select, district_heating, # store_national_profiles, ), )