Skip to content

Commit

Permalink
Merge pull request #1047 from openego/features/#1001-desaggregate-ind…
Browse files Browse the repository at this point in the history
…ustry-demands

Features/#1001 desaggregate industry demands
  • Loading branch information
nesnoj committed Dec 22, 2022
2 parents ee08003 + c6c164e commit 88fd2da
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 59 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,9 @@ Changed
`#1035 <https://github.com/openego/eGon-data/issues/1035>`_
* Add missing VOM costs for heat sector components
`#942 <https://github.com/openego/eGon-data/issues/942>`_
* Desaggregate industry demands to OSM areas and industrial sites
`#1001 <https://github.com/openego/eGon-data/issues/1001>`_


Bug Fixes
---------
Expand Down
11 changes: 10 additions & 1 deletion src/egon/data/datasets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ distributed_industrial_demand:
demandregio:
schema: 'demand'
table: 'egon_demandregio_cts_ind'
scenarios: ["eGon2035", "eGon100RE"]
scenarios: ["eGon2021", "eGon2035", "eGon100RE"]
wz:
schema: 'demand'
table: 'egon_demandregio_wz'
Expand Down Expand Up @@ -732,13 +732,22 @@ electrical_load_curves_industry:
egon_mv_grid_district:
schema: 'grid'
table: 'egon_mv_grid_district'
egon_ehv_voronoi:
schema: 'grid'
table: 'egon_ehv_substation_voronoi'
targets:
osm_load:
schema: 'demand'
table: 'egon_osm_ind_load_curves'
osm_load_individual:
schema: 'demand'
table: 'egon_osm_ind_load_curves_individual'
sites_load:
schema: 'demand'
table: 'egon_sites_ind_load_curves'
sites_load_individual:
schema: 'demand'
table: 'egon_sites_ind_load_curves_individual'

etrago_electricity:
sources:
Expand Down
2 changes: 1 addition & 1 deletion src/egon/data/datasets/DSM_cts_ind.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def calc_ind_site_timeseries(scenario):
data=curves_bus["bus_id"], index=curves_bus["id"].astype(int)
)
ts["scenario_name"] = scenario
curves_bus.drop({"id", "bus_id"}, axis=1, inplace=True)
curves_bus.drop({"id", "bus_id", "geom"}, axis=1, inplace=True)
ts["p_set"] = curves_bus.values.tolist()

# add subsector to relate to Schmidt's tables afterwards
Expand Down
102 changes: 81 additions & 21 deletions src/egon/data/datasets/industry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@
"""


import egon.data.config
from sqlalchemy import ARRAY, Column, Float, Integer, String
from sqlalchemy.ext.declarative import declarative_base
import geopandas as gpd
import pandas as pd

from egon.data import db
from egon.data.datasets import Dataset
from egon.data.datasets.industry.temporal import (
insert_osm_ind_load,
insert_sites_ind_load,
)
from sqlalchemy import Column, String, Float, Integer, ARRAY
from sqlalchemy.ext.declarative import declarative_base

import egon.data.config

Base = declarative_base()

Expand Down Expand Up @@ -51,6 +50,19 @@ class DemandCurvesOsmIndustry(Base):
p_set = Column(ARRAY(Float))


class DemandCurvesOsmIndustryIndividual(Base):
__tablename__ = "egon_osm_ind_load_curves_individual"
__table_args__ = {"schema": "demand"}

osm_id = Column(Integer, primary_key=True)
bus_id = Column(Integer)
scn_name = Column(String, primary_key=True)
p_set = Column(ARRAY(Float))
peak_load = Column(Float)
demand = Column(Float)
voltage_level = Column(Integer)


class DemandCurvesSitesIndustry(Base):
__tablename__ = "egon_sites_ind_load_curves"
__table_args__ = {"schema": "demand"}
Expand All @@ -61,6 +73,20 @@ class DemandCurvesSitesIndustry(Base):
p_set = Column(ARRAY(Float))


class DemandCurvesSitesIndustryIndividual(Base):
__tablename__ = "egon_sites_ind_load_curves_individual"
__table_args__ = {"schema": "demand"}

site_id = Column(Integer, primary_key=True)
bus_id = Column(Integer)
scn_name = Column(String, primary_key=True)
p_set = Column(ARRAY(Float))
peak_load = Column(Float)
demand = Column(Float)
voltage_level = Column(Integer)
wz = Column(Integer)


def create_tables():
"""Create tables for industrial sites and distributed industrial demands
Returns
Expand Down Expand Up @@ -95,12 +121,26 @@ def create_tables():

db.execute_sql(
f"""DROP TABLE IF EXISTS
{targets_temporal['osm_load']['schema']}.{targets_temporal['osm_load']['table']} CASCADE;"""
{targets_temporal['osm_load']['schema']}.
{targets_temporal['osm_load']['table']} CASCADE;"""
)

db.execute_sql(
f"""DROP TABLE IF EXISTS
{targets_temporal['sites_load']['schema']}.{targets_temporal['sites_load']['table']} CASCADE;"""
{targets_temporal['osm_load_individual']['schema']}.
{targets_temporal['osm_load_individual']['table']} CASCADE;"""
)

db.execute_sql(
f"""DROP TABLE IF EXISTS
{targets_temporal['sites_load']['schema']}.
{targets_temporal['sites_load']['table']} CASCADE;"""
)

db.execute_sql(
f"""DROP TABLE IF EXISTS
{targets_temporal['sites_load_individual']['schema']}.
{targets_temporal['sites_load_individual']['table']} CASCADE;"""
)

engine = db.engine()
Expand All @@ -115,11 +155,19 @@ def create_tables():

DemandCurvesOsmIndustry.__table__.create(bind=engine, checkfirst=True)

DemandCurvesOsmIndustryIndividual.__table__.create(
bind=engine, checkfirst=True
)

DemandCurvesSitesIndustry.__table__.create(bind=engine, checkfirst=True)

DemandCurvesSitesIndustryIndividual.__table__.create(
bind=engine, checkfirst=True
)


def industrial_demand_distr():
""" Distribute electrical demands for industry to osm landuse polygons
"""Distribute electrical demands for industry to osm landuse polygons
and/or industrial sites, identified earlier in the process.
The demands per subsector on nuts3-level from demandregio are distributed
linearly to the area of the corresponding landuse polygons or evenly to
Expand Down Expand Up @@ -172,7 +220,9 @@ def industrial_demand_distr():
WHERE sector = 3
AND NOT ST_Intersects(
geom,
(SELECT ST_UNION(ST_Transform(geom,3035)) FROM {sources['industrial_sites']['schema']}.{sources['industrial_sites']['table']}))
(SELECT ST_UNION(ST_Transform(geom,3035)) FROM
{sources['industrial_sites']['schema']}.
{sources['industrial_sites']['table']}))
AND name NOT LIKE '%%kraftwerk%%'
AND name NOT LIKE '%%Stadtwerke%%'
AND name NOT LIKE '%%Müllverbrennung%%'
Expand Down Expand Up @@ -210,7 +260,8 @@ def industrial_demand_distr():
{sources['industrial_sites']['table']}""",
index_col=None,
)
# Count number of industrial sites per subsector (wz) and nuts3 district
# Count number of industrial sites per subsector (wz) and nuts3
# district
sites_grouped = (
sites.groupby(["nuts3", "wz"]).size().reset_index(name="counts")
)
Expand All @@ -227,38 +278,45 @@ def industrial_demand_distr():
WHERE sector = 'industry')"""
)

# Replace wz=17 and wz=18 by wz=1718 as a differentiation of these two subsectors can't be performed
# Replace wz=17 and wz=18 by wz=1718 as a differentiation of these two
# subsectors can't be performed
demand_nuts3_import["wz"] = demand_nuts3_import["wz"].replace(
[17, 18], 1718
)

# Group results by nuts3 and wz to aggregate demands from subsectors 17 and 18
# Group results by nuts3 and wz to aggregate demands from subsectors
# 17 and 18
demand_nuts3 = (
demand_nuts3_import.groupby(["nuts3", "wz"]).sum().reset_index()
)

# A differentiation between those industrial subsectors (wz) which aren't represented
# and subsectors with a representation in the data set on industrial sites is needed
# A differentiation between those industrial subsectors (wz) which
# aren't represented and subsectors with a representation in the
# dataset on industrial sites is needed

# Select industrial demand for sectors which aren't found in industrial sites as category a
# Select industrial demand for sectors which aren't found in
# industrial sites as category a
demand_nuts3_a = demand_nuts3[
~demand_nuts3["wz"].isin([1718, 19, 20, 23, 24])
]

# Select industrial demand for sectors which are found in industrial sites as category b
# Select industrial demand for sectors which are found in industrial
# sites as category b
demand_nuts3_b = demand_nuts3[
demand_nuts3["wz"].isin([1718, 19, 20, 23, 24])
]

# Bring demands on nuts3 level and information on industrial sites per nuts3 district together
# Bring demands on nuts3 level and information on industrial sites per
# nuts3 district together
demand_nuts3_b = demand_nuts3_b.merge(
sites_grouped,
how="left",
left_on=["nuts3", "wz"],
right_on=["nuts3", "wz"],
)

# Define share of industrial demand per nuts3 region and subsector allocated to industrial sites
# Define share of industrial demand per nuts3 region and subsector
# allocated to industrial sites
share_to_sites = 0.5

# Define demand per site for every nuts3 region and subsector
Expand All @@ -270,7 +328,8 @@ def industrial_demand_distr():
# Replace NaN by 0
demand_nuts3_b = demand_nuts3_b.fillna(0)

# Calculate demand which needs to be distributed to osm landuse areas from category b
# Calculate demand which needs to be distributed to osm landuse areas
# from category b
demand_nuts3_b["demand_b_osm"] = demand_nuts3_b["demand"] - (
demand_nuts3_b["demand_per_site"] * demand_nuts3_b["counts"]
)
Expand All @@ -290,7 +349,8 @@ def industrial_demand_distr():
{"demand_b_osm": "demand"}, axis=1
)

# Create df containing all demand per wz which will be allocated to osm areas
# Create df containing all demand per wz which will be allocated to
# osm areas
demand_nuts3_osm_wz = demand_nuts3_a.append(
demand_nuts3_b_osm, ignore_index=True
)
Expand Down Expand Up @@ -350,7 +410,7 @@ class IndustrialDemandCurves(Dataset):
def __init__(self, dependencies):
super().__init__(
name="Industrial_demand_curves",
version="0.0.4",
version="0.0.5",
dependencies=dependencies,
tasks=(
create_tables,
Expand Down

0 comments on commit 88fd2da

Please sign in to comment.