Skip to content

Commit

Permalink
Merge pull request #472 from openego/features/#405-insert-ch4-storages
Browse files Browse the repository at this point in the history
Features/#405 insert ch4 storages
  • Loading branch information
AmeliaNadal authored Nov 12, 2021
2 parents 6635b95 + cacbe94 commit d036c18
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ Added
`#330 <https://github.com/openego/eGon-data/issues/330>`_
* Distribute wind offshore capacities
`#329 <https://github.com/openego/eGon-data/issues/329>`_
* Add CH4 storages
`#405 <https://github.com/openego/eGon-data/issues/405>`_
* Include allocation of conventional (non CHP) power plants
`#392 <https://github.com/openego/eGon-data/issues/392>`_

Expand Down
35 changes: 16 additions & 19 deletions src/egon/data/airflow/dags/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
from egon.data.datasets.era5 import WeatherData
from egon.data.datasets.etrago_setup import EtragoSetup
from egon.data.datasets.gas_prod import CH4Production
from egon.data.processing.gas_areas import GasAreas
from egon.data.datasets.ch4_storages import CH4Storages
from egon.data.processing.power_to_h2 import PowertoH2
from egon.data.datasets.gas_grid import GasNodesandPipes
from egon.data.datasets.heat_demand import HeatDemandImport
from egon.data.datasets.heat_demand_timeseries.HTS import HeatTimeSeries
from egon.data.datasets.heat_etrago import HeatEtrago
Expand Down Expand Up @@ -250,34 +254,28 @@
)

# Gas grid import
gas_grid_insert_data = PythonOperator(
task_id="insert-gas-grid", python_callable=gas_grid.insert_gas_data
gas_grid_insert_data = GasNodesandPipes(
dependencies=[etrago_input_data, download_data_bundle, osmtgmod_pypsa]
)

etrago_input_data >> gas_grid_insert_data
download_data_bundle >> gas_grid_insert_data
osmtgmod_pypsa >> gas_grid_insert_data

# Power-to-gas installations creation
insert_power_to_h2_installations = PythonOperator(
task_id="insert-power-to-h2-installations",
python_callable=power_to_h2.insert_power_to_h2,
insert_power_to_h2_installations = PowertoH2(
dependencies=[gas_grid_insert_data]
)

gas_grid_insert_data >> insert_power_to_h2_installations


# Create gas voronoi
create_gas_polygons = PythonOperator(
task_id="create-gas-voronoi", python_callable=gas_areas.create_voronoi
create_gas_polygons = GasAreas(
dependencies=[gas_grid_insert_data, vg250_clean_and_prepare]
)

gas_grid_insert_data >> create_gas_polygons
vg250_clean_and_prepare >> create_gas_polygons

# Gas prod import
gas_production_insert_data = CH4Production(
dependencies=[create_gas_polygons]
)

# CH4 storages import
insert_data_ch4_storages = CH4Storages(
dependencies=[create_gas_polygons])

# Insert industrial gas demand
industrial_gas_demand = IndustrialGasDemand(
Expand Down Expand Up @@ -414,13 +412,12 @@
)

# CHP locations
chp = Chp(dependencies=[mv_grid_districts, mastr_data, industrial_sites])
chp = Chp(dependencies=[mv_grid_districts, mastr_data, industrial_sites, create_gas_polygons])

chp_locations_nep = tasks["chp.insert-chp-egon2035"]
chp_heat_bus = tasks["chp.assign-heat-bus"]

nep_insert_data >> chp_locations_nep
create_gas_polygons >> chp_locations_nep
import_district_heating_areas >> chp_locations_nep

# Power plants
Expand Down
163 changes: 163 additions & 0 deletions src/egon/data/datasets/ch4_storages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
"""
The central module containing all code dealing with importing gas storages data
"""
import ast
import pandas as pd
import numpy as np
import geopandas

from egon.data.datasets.gas_prod import assign_ch4_bus_id
from egon.data.datasets.gas_grid import ch4_nodes_number_G, define_gas_nodes_list
from egon.data import db
from egon.data.config import settings
from egon.data.datasets import Dataset
from pathlib import Path

class CH4Storages(Dataset):
def __init__(self, dependencies):
super().__init__(
name="CH4Storages",
version="0.0.0",
dependencies=dependencies,
tasks=(import_ch4_storages),
)

def import_installed_ch4_storages():
"""Define dataframe containing the ch4 storage units in Germany from the SciGRID_gas data
Returns
-------
Gas_storages_list :
Dataframe containing the gas storages units in Germany
"""
target_file = (
Path(".") /
"datasets" /
"gas_data" /
"data" /
"IGGIELGN_Storages.csv")

Gas_storages_list = pd.read_csv(target_file,
delimiter=';', decimal='.',
usecols = ['lat', 'long', 'country_code','param'])

Gas_storages_list = Gas_storages_list[ Gas_storages_list['country_code'].str.match('DE')]

# Define new columns
e_nom = []
NUTS1 = []
end_year = []
for index, row in Gas_storages_list.iterrows():
param = ast.literal_eval(row['param'])
NUTS1.append(param['nuts_id_1'])
end_year.append(param['end_year'])
e_nom.append(param['max_power_MW'])

Gas_storages_list = Gas_storages_list.assign(e_nom = e_nom)
Gas_storages_list = Gas_storages_list.assign(NUTS1 = NUTS1)

end_year = [float('inf') if x == None else x for x in end_year]
Gas_storages_list = Gas_storages_list.assign(end_year = end_year)

# Cut data to federal state if in testmode
boundary = settings()['egon-data']['--dataset-boundary']
if boundary != 'Everything':
map_states = {'Baden-Württemberg':'DE1', 'Nordrhein-Westfalen': 'DEA',
'Hessen': 'DE7', 'Brandenburg': 'DE4', 'Bremen':'DE5',
'Rheinland-Pfalz': 'DEB', 'Sachsen-Anhalt': 'DEE',
'Schleswig-Holstein':'DEF', 'Mecklenburg-Vorpommern': 'DE8',
'Thüringen': 'DEG', 'Niedersachsen': 'DE9',
'Sachsen': 'DED', 'Hamburg': 'DE6', 'Saarland': 'DEC',
'Berlin': 'DE3', 'Bayern': 'DE2'}

Gas_storages_list = Gas_storages_list[Gas_storages_list['NUTS1'].isin([map_states[boundary], np.nan])]

# Remove unused storage units
Gas_storages_list = Gas_storages_list[Gas_storages_list['end_year'] >= 2035]

Gas_storages_list = Gas_storages_list.rename(columns={'lat': 'y','long': 'x'})
Gas_storages_list = geopandas.GeoDataFrame(Gas_storages_list,
geometry=geopandas.points_from_xy(Gas_storages_list['x'],
Gas_storages_list['y']))
Gas_storages_list = Gas_storages_list.rename(columns={'geometry': 'geom'}).set_geometry('geom', crs=4326)

# Match to associated gas bus
Gas_storages_list = Gas_storages_list.reset_index(drop=True)
Gas_storages_list = assign_ch4_bus_id(Gas_storages_list)

# Add missing columns
c = {'scn_name':'eGon2035', 'carrier':'CH4'}
Gas_storages_list = Gas_storages_list.assign(**c)

# Remove useless columns
Gas_storages_list = Gas_storages_list.drop(columns=['x', 'y',
'param', 'country_code',
'NUTS1', 'end_year',
'geom', 'bus_id'])
return Gas_storages_list


def import_ch4_grid_capacity():
"""Define dataframe containing the modelling of the CH4 grid storage
capacity. The whole storage capacity of the grid (130000 MWh, estimation of
the Bundesnetzagentur) is split uniformly between all the german CH4 nodes
of the grid. The capacities of the pipes are not considerated.
Returns
-------
Gas_storages_list :
Dataframe containing the gas stores in Germany modelling the gas grid storage capacity
"""
Gas_grid_capacity = 130000 # Storage capacity of the CH4 grid - G.Volk "Die Herauforderung an die Bundesnetzagentur die Energiewende zu meistern" Berlin, Dec 2012
N_ch4_nodes_G = ch4_nodes_number_G(define_gas_nodes_list()) # Number of nodes in Germany
Store_capacity = Gas_grid_capacity / N_ch4_nodes_G # Storage capacity associated to each CH4 node of the german grid

sql_gas = """SELECT bus_id, scn_name, carrier, geom
FROM grid.egon_etrago_bus
WHERE carrier = 'CH4';"""
Gas_storages_list = db.select_geodataframe(sql_gas, epsg=4326)

# Add missing column
Gas_storages_list['e_nom'] = Store_capacity
Gas_storages_list['bus'] = Gas_storages_list['bus_id']

# Remove useless columns
Gas_storages_list = Gas_storages_list.drop(columns=['bus_id', 'geom'])

return Gas_storages_list


def import_ch4_storages():
"""Insert list of gas storages units in database
Returns
-------
None.
"""
# Connect to local database
engine = db.engine()

# Clean table
db.execute_sql(
"""
DELETE FROM grid.egon_etrago_store WHERE "carrier" = 'CH4';
"""
)

# Select next id value
new_id = db.next_etrago_id('store')

gas_storages_list = pd.concat([import_installed_ch4_storages(), import_ch4_grid_capacity()])
gas_storages_list['store_id'] = range(new_id, new_id + len(gas_storages_list))

gas_storages_list = gas_storages_list.reset_index(drop=True)

# Insert data to db
gas_storages_list.to_sql('egon_etrago_store',
engine,
schema ='grid',
index = False,
if_exists = 'append')
33 changes: 31 additions & 2 deletions src/egon/data/datasets/gas_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@
from egon.data import db
from egon.data.config import settings
from egon.data.datasets import Dataset
from geoalchemy2.shape import from_shape
from geoalchemy2.types import Geometry
from shapely import geometry

class GasNodesandPipes(Dataset):
def __init__(self, dependencies):
super().__init__(
name="GasNodesandPipes",
version="0.0.0",
dependencies=dependencies,
tasks=(insert_gas_data),
)


def download_SciGRID_gas_data():
"""
Expand Down Expand Up @@ -95,6 +103,26 @@ def define_gas_nodes_list():
return gas_nodes_list


def ch4_nodes_number_G(gas_nodes_list):
"""Insert list of CH4 nodes from SciGRID_gas IGGIELGN data
Parameters
----------
gas_nodes_list : dataframe
Dataframe containing the gas nodes (Europe)
Returns
-------
N_ch4_nodes_G : int
Number of CH4 buses in Germany (independantly from the mode used)
"""

ch4_nodes_list = gas_nodes_list[
gas_nodes_list["country_code"].str.match("DE")
] # A remplacer evtmt par un test sur le NUTS0 ?
N_ch4_nodes_G = len(ch4_nodes_list)

return N_ch4_nodes_G


def insert_CH4_nodes_list(gas_nodes_list):
"""Insert list of CH4 nodes from SciGRID_gas IGGIELGN data
Parameters
Expand All @@ -103,14 +131,15 @@ def insert_CH4_nodes_list(gas_nodes_list):
Dataframe containing the gas nodes (Europe)
Returns
-------
None.
None
"""
# Connect to local database
engine = db.engine()

gas_nodes_list = gas_nodes_list[
gas_nodes_list["country_code"].str.match("DE")
] # A remplacer evtmt par un test sur le NUTS0 ?

# Cut data to federal state if in testmode
NUTS1 = []
for index, row in gas_nodes_list.iterrows():
Expand Down
12 changes: 11 additions & 1 deletion src/egon/data/processing/gas_areas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@
"""
from egon.data import db
from egon.data.datasets import Dataset
from geoalchemy2.types import Geometry
from sqlalchemy import Column, Float, Integer, Sequence, Text
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
class GasAreas(Dataset):
def __init__(self, dependencies):
super().__init__(
name="GasAreas",
version="0.0.0",
dependencies=dependencies,
tasks=(create_voronoi),
)


Base = declarative_base()

class EgonCH4VoronoiTmp(Base):
__tablename__ = "egon_ch4_voronoi_tmp"
Expand Down
10 changes: 10 additions & 0 deletions src/egon/data/processing/power_to_h2.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@

import pandas as pd
from egon.data import db
from egon.data.datasets import Dataset
from geoalchemy2.types import Geometry
from scipy.spatial import cKDTree
from shapely import geometry

class PowertoH2(Dataset):
def __init__(self, dependencies):
super().__init__(
name="PowertoH2",
version="0.0.0",
dependencies=dependencies,
tasks=(insert_power_to_h2),
)


def insert_power_to_h2():
"""Function defining the potential power-to-H2 capacities and inserting them in the etrago_link table.
Expand Down

0 comments on commit d036c18

Please sign in to comment.