Source code for egon.data.datasets.ch4_prod

# -*- coding: utf-8 -*-
"""
The central module containing code dealing with importing CH4 production data for eGon2035.

For eGon2035, the gas produced in Germany can be natural gas or biogas.
The source productions are geolocalised potentials described as PyPSA
generators. These generators are not extendable and their overall
production over the year is limited directly in eTraGo by values from
the Netzentwicklungsplan Gas 2020–2030 (36 TWh natural gas and 10 TWh
biogas), also stored in the table
:py:class:`scenario.egon_scenario_parameters <egon.data.datasets.scenario_parameters.EgonScenario>`.

"""
from pathlib import Path
from urllib.request import urlretrieve
import ast

import geopandas as gpd
import numpy as np
import pandas as pd

from egon.data import config, db
from egon.data.config import settings
from egon.data.datasets import Dataset
from egon.data.datasets.scenario_parameters import get_sector_parameters


[docs]class CH4Production(Dataset): """ Insert the CH4 productions into the database for eGon2035 Insert the CH4 productions into the database for eGon2035 by using the function :py:func:`import_gas_generators`. *Dependencies* * :py:class:`GasAreaseGon2035 <egon.data.datasets.gas_areas.GasAreaseGon2035>` * :py:class:`GasNodesAndPipes <egon.data.datasets.gas_grid.GasNodesAndPipes>` *Resulting tables* * :py:class:`grid.egon_etrago_generator <egon.data.datasets.etrago_setup.EgonPfHvGenerator>` is extended """ #: name: str = "CH4Production" #: version: str = "0.0.7" def __init__(self, dependencies): super().__init__( name=self.name, version=self.version, dependencies=dependencies, tasks=(import_gas_generators), )
[docs]def load_NG_generators(scn_name): """ Define the fossil CH4 production units in Germany This function reads from the SciGRID_gas dataset the fossil CH4 production units in Germany, adjusts and returns them. Natural gas production reference: SciGRID_gas dataset (datasets/gas_data/data/IGGIELGN_Production.csv downloaded in :func:`download_SciGRID_gas_data <egon.data.datasets.gas_grid.download_SciGRID_gas_data>`). For more information on this data, refer to the `SciGRID_gas IGGIELGN documentation <https://zenodo.org/record/4767098>`_. Parameters ---------- scn_name : str Name of the scenario. Returns ------- CH4_generators_list : pandas.DataFrame Dataframe containing the natural gas production units in Germany """ # read carrier information from scnario parameter data scn_params = get_sector_parameters("gas", scn_name) target_file = ( Path(".") / "datasets" / "gas_data" / "data" / "IGGIELGN_Productions.csv" ) NG_generators_list = pd.read_csv( target_file, delimiter=";", decimal=".", usecols=["lat", "long", "country_code", "param"], ) NG_generators_list = NG_generators_list[ NG_generators_list["country_code"].str.match("DE") ] # Cut data to federal state if in testmode NUTS1 = [] for index, row in NG_generators_list.iterrows(): param = ast.literal_eval(row["param"]) NUTS1.append(param["nuts_id_1"]) NG_generators_list = NG_generators_list.assign(NUTS1=NUTS1) 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", } NG_generators_list = NG_generators_list[ NG_generators_list["NUTS1"].isin([map_states[boundary], np.nan]) ] NG_generators_list = NG_generators_list.rename( columns={"lat": "y", "long": "x"} ) NG_generators_list = gpd.GeoDataFrame( NG_generators_list, geometry=gpd.points_from_xy( NG_generators_list["x"], NG_generators_list["y"] ), ) NG_generators_list = NG_generators_list.rename( columns={"geometry": "geom"} ).set_geometry("geom", crs=4326) # Insert p_nom p_nom = [] for index, row in NG_generators_list.iterrows(): param = ast.literal_eval(row["param"]) p_nom.append(param["max_supply_M_m3_per_d"]) conversion_factor = 437.5 # MCM/day to MWh/h NG_generators_list["p_nom"] = [i * conversion_factor for i in p_nom] # Add missing columns NG_generators_list["marginal_cost"] = scn_params["marginal_cost"]["CH4"] # Remove useless columns NG_generators_list = NG_generators_list.drop( columns=["x", "y", "param", "country_code", "NUTS1"] ) return NG_generators_list
[docs]def load_biogas_generators(scn_name): """ Define the biogas production units in Germany This function downloads the Biogaspartner Einspeiseatlas into (datasets/gas_data/Biogaspartner_Einspeiseatlas_Deutschland_2021.xlsx), reads the biogas production units in Germany data, adjusts and returns them. For more information on this data refer to the `Einspeiseatlas website <https://www.biogaspartner.de/einspeiseatlas/>`_. Parameters ---------- scn_name : str Name of the scenario Returns ------- CH4_generators_list : pandas.DataFrame Dataframe containing the biogas production units in Germany """ # read carrier information from scnario parameter data scn_params = get_sector_parameters("gas", scn_name) # Download file basename = "Biogaspartner_Einspeiseatlas_Deutschland_2021.xlsx" url = ( "https://www.biogaspartner.de/fileadmin/Biogaspartner/Dokumente/Einspeiseatlas/" + basename ) target_file = Path(".") / "datasets" / "gas_data" / basename urlretrieve(url, target_file) # Read-in data from csv-file biogas_generators_list = pd.read_excel( target_file, usecols=["Koordinaten", "Einspeisung Biomethan [(N*m^3)/h)]"], ) x = [] y = [] for index, row in biogas_generators_list.iterrows(): coordinates = row["Koordinaten"].split(",") y.append(coordinates[0]) x.append(coordinates[1]) biogas_generators_list["x"] = x biogas_generators_list["y"] = y biogas_generators_list = gpd.GeoDataFrame( biogas_generators_list, geometry=gpd.points_from_xy( biogas_generators_list["x"], biogas_generators_list["y"] ), ) biogas_generators_list = biogas_generators_list.rename( columns={"geometry": "geom"} ).set_geometry("geom", crs=4326) # Connect to local database engine = db.engine() # Cut data to federal state if in testmode boundary = settings()["egon-data"]["--dataset-boundary"] if boundary != "Everything": db.execute_sql( """ DROP TABLE IF EXISTS grid.egon_biogas_generator CASCADE; """ ) biogas_generators_list.to_postgis( "egon_biogas_generator", engine, schema="grid", index=False, if_exists="replace", ) sql = """SELECT * FROM grid.egon_biogas_generator, boundaries.vg250_sta_union as vg WHERE ST_Transform(vg.geometry,4326) && egon_biogas_generator.geom AND ST_Contains(ST_Transform(vg.geometry,4326), egon_biogas_generator.geom)""" biogas_generators_list = gpd.GeoDataFrame.from_postgis( sql, con=engine, geom_col="geom", crs=4326 ) biogas_generators_list = biogas_generators_list.drop( columns=["id", "bez", "area_ha", "geometry"] ) db.execute_sql( """ DROP TABLE IF EXISTS grid.egon_biogas_generator CASCADE; """ ) # Insert p_nom conversion_factor = 0.01083 # m^3/h to MWh/h biogas_generators_list["p_nom"] = [ i * conversion_factor for i in biogas_generators_list["Einspeisung Biomethan [(N*m^3)/h)]"] ] # Add missing columns biogas_generators_list["marginal_cost"] = scn_params["marginal_cost"][ "biogas" ] # Remove useless columns biogas_generators_list = biogas_generators_list.drop( columns=["x", "y", "Koordinaten", "Einspeisung Biomethan [(N*m^3)/h)]"] ) return biogas_generators_list
[docs]def import_gas_generators(scn_name="eGon2035"): """ Inserts list of gas production units into the database To insert the gas production units into the database, the following steps are followed: * cleaning of the database table grid.egon_etrago_generator of the CH4 generators of the specific scenario (eGon2035), * call of the functions :py:func:`load_NG_generators` and :py:func:`load_biogas_generators` that respectively return dataframes containing the natural- an bio-gas production units in Germany, * attribution of the bus_id to which each generator is connected (call the function :func:`assign_gas_bus_id <egon.data.db.assign_gas_bus_id>` from :py:mod:`egon.data.db <egon.data.db>`), * aggregation of the CH4 productions with same properties at the same bus. The properties that should be the same in order that different generators are aggregated are: * scenario * carrier * marginal cost: this parameter differentiates the natural gas generators from the biogas generators, * addition of the missing columns: scn_name, carrier and generator_id, * insertion of the generators into the database. Parameters ---------- scn_name : str Name of the scenario. Returns ------- None """ # Connect to local database engine = db.engine() # Select source and target from dataset configuration source = config.datasets()["gas_prod"]["source"] target = config.datasets()["gas_prod"]["target"] # Clean table db.execute_sql( f""" DELETE FROM {target['stores']['schema']}.{target['stores']['table']} WHERE "carrier" = 'CH4' AND scn_name = '{scn_name}' AND bus not IN ( SELECT bus_id FROM {source['buses']['schema']}.{source['buses']['table']} WHERE scn_name = '{scn_name}' AND country != 'DE' ); """ ) CH4_generators_list = pd.concat( [load_NG_generators(scn_name), load_biogas_generators(scn_name)] ) # Add missing columns c = {"scn_name": scn_name, "carrier": "CH4"} CH4_generators_list = CH4_generators_list.assign(**c) # Match to associated CH4 bus CH4_generators_list = db.assign_gas_bus_id( CH4_generators_list, scn_name, "CH4" ) # Remove useless columns CH4_generators_list = CH4_generators_list.drop(columns=["geom", "bus_id"]) # Aggregate ch4 productions with same properties at the same bus CH4_generators_list = ( CH4_generators_list.groupby( ["bus", "carrier", "scn_name", "marginal_cost"] ) .agg({"p_nom": "sum"}) .reset_index(drop=False) ) new_id = db.next_etrago_id("generator") CH4_generators_list["generator_id"] = range( new_id, new_id + len(CH4_generators_list) ) # Insert data to db CH4_generators_list.to_sql( target["stores"]["table"], engine, schema=target["stores"]["schema"], index=False, if_exists="append", )