"""The central module containing all code dealing with electrical neighbours
"""
import zipfile
import geopandas as gpd
import pandas as pd
from shapely.geometry import LineString
from sqlalchemy.orm import sessionmaker
import egon.data.datasets.etrago_setup as etrago
import egon.data.datasets.scenario_parameters.parameters as scenario_parameters
from egon.data import config, db
from egon.data.datasets import Dataset
from egon.data.datasets.fill_etrago_gen import add_marginal_costs
from egon.data.datasets.scenario_parameters import get_sector_parameters
[docs]class ElectricalNeighbours(Dataset):
"""
Add lines, loads, generation and storage for electrical neighbours
This dataset creates data for modelling the considered foreign countries and writes
that data into the database tables that can be read by the eTraGo tool.
Neighbouring countries are modelled in a lower spatial resolution, in general one node per
country is considered.
Defined load timeseries as well as generatrion and storage capacities are connected to these nodes.
The nodes are connected by AC and DC transmission lines with the German grid and other neighbouring countries
considering the grid topology from ENTSO-E.
*Dependencies*
* :py:class:`Tyndp <egon.data.datasets.tyndp.Tyndp>`
* :py:class:`PypsaEurSec <egon.data.datasets.pypsaeursec.PypsaEurSec>`
*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_line <egon.data.datasets.etrago_setup.EgonPfHvLine>` is extended
* :py:class:`grid.egon_etrago_load <egon.data.datasets.etrago_setup.EgonPfHvLoad>` is extended
* :py:class:`grid.egon_etrago_load_timeseries <egon.data.datasets.etrago_setup.EgonPfHvLoadTimeseries>` is extended
* :py:class:`grid.egon_etrago_storage <egon.data.datasets.etrago_setup.EgonPfHvStorageUnit>` is extended
* :py:class:`grid.egon_etrago_generator <egon.data.datasets.etrago_setup.EgonPfHvGenerator>` is extended
* :py:class:`grid.egon_etrago_generator_timeseries <egon.data.datasets.etrago_setup.EgonPfHvGeneratorTimeseries>` is extended
* :py:class:`grid.egon_etrago_transformer <egon.data.datasets.etrago_setup.EgonPfHvTransformer>` is extended
"""
#:
name: str = "ElectricalNeighbours"
#:
version: str = "0.0.7"
def __init__(self, dependencies):
super().__init__(
name=self.name,
version=self.version,
dependencies=dependencies,
tasks=(grid, {tyndp_generation, tyndp_demand}),
)
[docs]def get_cross_border_buses(scenario, sources):
"""Returns buses from osmTGmod which are outside of Germany.
Parameters
----------
sources : dict
List of sources
Returns
-------
geopandas.GeoDataFrame
Electricity buses outside of Germany
"""
return db.select_geodataframe(
f"""
SELECT *
FROM {sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE
NOT ST_INTERSECTS (
geom,
(SELECT ST_Transform(ST_Buffer(geometry, 5), 4326) FROM
{sources['german_borders']['schema']}.
{sources['german_borders']['table']}))
AND (bus_id IN (
SELECT bus0 FROM
{sources['lines']['schema']}.{sources['lines']['table']})
OR bus_id IN (
SELECT bus1 FROM
{sources['lines']['schema']}.{sources['lines']['table']}))
AND scn_name = '{scenario}';
""",
epsg=4326,
)
[docs]def get_cross_border_lines(scenario, sources):
"""Returns lines from osmTGmod which end or start outside of Germany.
Parameters
----------
sources : dict
List of sources
Returns
-------
geopandas.GeoDataFrame
AC-lines outside of Germany
"""
return db.select_geodataframe(
f"""
SELECT *
FROM {sources['lines']['schema']}.{sources['lines']['table']} a
WHERE
ST_INTERSECTS (
a.topo,
(SELECT ST_Transform(ST_boundary(geometry), 4326)
FROM {sources['german_borders']['schema']}.
{sources['german_borders']['table']}))
AND scn_name = '{scenario}';
""",
epsg=4326,
)
[docs]def central_buses_egon100(sources):
"""Returns buses in the middle of foreign countries based on eGon100RE
Parameters
----------
sources : dict
List of sources
Returns
-------
pandas.DataFrame
Buses in the center of foreign countries
"""
return db.select_dataframe(
f"""
SELECT *
FROM {sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE country != 'DE'
AND scn_name = 'eGon100RE'
AND bus_id NOT IN (
SELECT bus_i
FROM {sources['osmtgmod_bus']['schema']}.
{sources['osmtgmod_bus']['table']})
AND carrier = 'AC'
"""
)
[docs]def buses(scenario, sources, targets):
"""Insert central buses in foreign countries per scenario
Parameters
----------
sources : dict
List of dataset sources
targets : dict
List of dataset targets
Returns
-------
central_buses : geoapndas.GeoDataFrame
Buses in the center of foreign countries
"""
sql_delete = f"""
DELETE FROM {sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE country != 'DE' AND scn_name = '{scenario}'
AND carrier = 'AC'
AND bus_id NOT IN (
SELECT bus_i
FROM {sources['osmtgmod_bus']['schema']}.
{sources['osmtgmod_bus']['table']})
"""
# Drop only buses with v_nom != 380 for eGon100RE
# to keep buses from pypsa-eur-sec
if scenario == "eGon100RE":
sql_delete += "AND v_nom < 380"
# Delete existing buses
db.execute_sql(sql_delete)
central_buses = central_buses_egon100(sources)
next_bus_id = db.next_etrago_id("bus") + 1
# if in test mode, add bus in center of Germany
if config.settings()["egon-data"]["--dataset-boundary"] != "Everything":
central_buses = central_buses.append(
{
"scn_name": scenario,
"bus_id": next_bus_id,
"x": 10.4234469,
"y": 51.0834196,
"country": "DE",
"carrier": "AC",
"v_nom": 380.0,
},
ignore_index=True,
)
next_bus_id += 1
# Add buses for other voltage levels
foreign_buses = get_cross_border_buses(scenario, sources)
if config.settings()["egon-data"]["--dataset-boundary"] == "Everything":
foreign_buses = foreign_buses[foreign_buses.country != "DE"]
vnom_per_country = foreign_buses.groupby("country").v_nom.unique().copy()
for cntr in vnom_per_country.index:
print(cntr)
if 110.0 in vnom_per_country[cntr]:
central_buses = central_buses.append(
{
"scn_name": scenario,
"bus_id": next_bus_id,
"x": central_buses[
central_buses.country == cntr
].x.unique()[0],
"y": central_buses[
central_buses.country == cntr
].y.unique()[0],
"country": cntr,
"carrier": "AC",
"v_nom": 110.0,
},
ignore_index=True,
)
next_bus_id += 1
if 220.0 in vnom_per_country[cntr]:
central_buses = central_buses.append(
{
"scn_name": scenario,
"bus_id": next_bus_id,
"x": central_buses[
central_buses.country == cntr
].x.unique()[0],
"y": central_buses[
central_buses.country == cntr
].y.unique()[0],
"country": cntr,
"carrier": "AC",
"v_nom": 220.0,
},
ignore_index=True,
)
next_bus_id += 1
# Add geometry column
central_buses = gpd.GeoDataFrame(
central_buses,
geometry=gpd.points_from_xy(central_buses.x, central_buses.y),
crs="EPSG:4326",
)
central_buses["geom"] = central_buses.geometry.copy()
central_buses = central_buses.set_geometry("geom").drop(
"geometry", axis="columns"
)
central_buses.scn_name = scenario
# Insert all central buses for eGon2035
if scenario == "eGon2035":
central_buses.to_postgis(
targets["buses"]["table"],
schema=targets["buses"]["schema"],
if_exists="append",
con=db.engine(),
index=False,
)
# Insert only buses for eGon100RE that are not coming from pypsa-eur-sec
# (buses with another voltage_level or inside Germany in test mode)
else:
central_buses[
(central_buses.v_nom != 380) | (central_buses.country == "DE")
].to_postgis(
targets["buses"]["table"],
schema=targets["buses"]["schema"],
if_exists="append",
con=db.engine(),
index=False,
)
return central_buses
[docs]def cross_border_lines(scenario, sources, targets, central_buses):
"""Adds lines which connect border-crossing lines from osmtgmod
to the central buses in the corresponding neigbouring country
Parameters
----------
sources : dict
List of dataset sources
targets : dict
List of dataset targets
central_buses : geopandas.GeoDataFrame
Buses in the center of foreign countries
Returns
-------
new_lines : geopandas.GeoDataFrame
Lines that connect cross-border lines to central bus per country
"""
# Delete existing data
db.execute_sql(
f"""
DELETE FROM {targets['lines']['schema']}.
{targets['lines']['table']}
WHERE scn_name = '{scenario}'
AND line_id NOT IN (
SELECT branch_id
FROM {sources['osmtgmod_branch']['schema']}.
{sources['osmtgmod_branch']['table']}
WHERE result_id = 1 and (link_type = 'line' or
link_type = 'cable'))
AND bus0 IN (
SELECT bus_i
FROM {sources['osmtgmod_bus']['schema']}.
{sources['osmtgmod_bus']['table']})
AND bus1 NOT IN (
SELECT bus_i
FROM {sources['osmtgmod_bus']['schema']}.
{sources['osmtgmod_bus']['table']})
"""
)
# Calculate cross-border busses and lines from osmtgmod
foreign_buses = get_cross_border_buses(scenario, sources)
if config.settings()["egon-data"]["--dataset-boundary"] == "Everything":
foreign_buses = foreign_buses[foreign_buses.country != "DE"]
lines = get_cross_border_lines(scenario, sources)
# Select bus outside of Germany from border-crossing lines
lines.loc[
lines[lines.bus0.isin(foreign_buses.bus_id)].index, "foreign_bus"
] = lines.loc[lines[lines.bus0.isin(foreign_buses.bus_id)].index, "bus0"]
lines.loc[
lines[lines.bus1.isin(foreign_buses.bus_id)].index, "foreign_bus"
] = lines.loc[lines[lines.bus1.isin(foreign_buses.bus_id)].index, "bus1"]
# Drop lines with start and endpoint in Germany
lines = lines[lines.foreign_bus.notnull()]
lines.loc[:, "foreign_bus"] = lines.loc[:, "foreign_bus"].astype(int)
# Copy all parameters from border-crossing lines
new_lines = lines.copy()
# Set bus0 as foreign_bus from osmtgmod
new_lines.bus0 = new_lines.foreign_bus.copy()
# Add country tag and set index
new_lines["country"] = (
foreign_buses.set_index("bus_id")
.loc[lines.foreign_bus, "country"]
.values
)
if config.settings()["egon-data"]["--dataset-boundary"] == "Everything":
new_lines = new_lines[~new_lines.country.isnull()]
new_lines.line_id = range(
db.next_etrago_id("line"), db.next_etrago_id("line") + len(new_lines)
)
# Set bus in center of foreogn countries as bus1
for i, row in new_lines.iterrows():
print(row)
new_lines.loc[i, "bus1"] = central_buses.bus_id[
(central_buses.country == row.country)
& (central_buses.v_nom == row.v_nom)
].values[0]
# Create geometry for new lines
new_lines["geom_bus0"] = (
foreign_buses.set_index("bus_id").geom[new_lines.bus0].values
)
new_lines["geom_bus1"] = (
central_buses.set_index("bus_id").geom[new_lines.bus1].values
)
new_lines["topo"] = new_lines.apply(
lambda x: LineString([x["geom_bus0"], x["geom_bus1"]]), axis=1
)
# Set topo as geometry column
new_lines = new_lines.set_geometry("topo")
# Calcultae length of lines based on topology
old_length = new_lines["length"].copy()
new_lines["length"] = new_lines.to_crs(3035).length / 1000
# Set electrical parameters based on lines from osmtgmod
for parameter in ["x", "r"]:
new_lines[parameter] = (
new_lines[parameter] / old_length * new_lines["length"]
)
for parameter in ["b", "g"]:
new_lines[parameter] = (
new_lines[parameter] * old_length / new_lines["length"]
)
# Drop intermediate columns
new_lines.drop(
["foreign_bus", "country", "geom_bus0", "geom_bus1", "geom"],
axis="columns",
inplace=True,
)
new_lines = new_lines[new_lines.bus0 != new_lines.bus1]
# Set scn_name
# Insert lines to the database
new_lines.to_postgis(
targets["lines"]["table"],
schema=targets["lines"]["schema"],
if_exists="append",
con=db.engine(),
index=False,
)
return new_lines
[docs]def foreign_dc_lines(scenario, sources, targets, central_buses):
"""Insert DC lines to foreign countries manually
Parameters
----------
sources : dict
List of dataset sources
targets : dict
List of dataset targets
central_buses : geopandas.GeoDataFrame
Buses in the center of foreign countries
Returns
-------
None.
"""
# Delete existing dc lines to foreign countries
db.execute_sql(
f"""
DELETE FROM {targets['links']['schema']}.
{targets['links']['table']}
WHERE scn_name = '{scenario}'
AND carrier = 'DC'
AND bus0 IN (
SELECT bus_id
FROM {sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE scn_name = '{scenario}'
AND carrier = 'AC'
AND country = 'DE')
AND bus1 IN (
SELECT bus_id
FROM {sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE scn_name = '{scenario}'
AND carrier = 'AC'
AND country != 'DE')
"""
)
capital_cost = get_sector_parameters("electricity", "eGon2035")[
"capital_cost"
]
# Add DC line from Lübeck to Sweden
converter_luebeck = db.select_dataframe(
f"""
SELECT bus_id FROM
{sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE x = 10.802358024202768
AND y = 53.897547401787
AND v_nom = 380
AND scn_name = '{scenario}'
AND carrier = 'AC'
"""
).squeeze()
foreign_links = pd.DataFrame(
index=[0],
data={
"link_id": db.next_etrago_id("link"),
"bus0": converter_luebeck,
"bus1": central_buses[
(central_buses.country == "SE") & (central_buses.v_nom == 380)
]
.squeeze()
.bus_id,
"p_nom": 600,
"length": 262,
},
)
# When not in test-mode, add DC line from Bentwisch to Denmark
if config.settings()["egon-data"]["--dataset-boundary"] == "Everything":
converter_bentwisch = db.select_dataframe(
f"""
SELECT bus_id FROM
{sources['electricity_buses']['schema']}.
{sources['electricity_buses']['table']}
WHERE x = 12.213671694775988
AND y = 54.09974494662279
AND v_nom = 380
AND scn_name = '{scenario}'
AND carrier = 'AC'
"""
).squeeze()
foreign_links = foreign_links.append(
pd.DataFrame(
index=[1],
data={
"link_id": db.next_etrago_id("link") + 1,
"bus0": converter_bentwisch,
"bus1": central_buses[
(central_buses.country == "DK")
& (central_buses.v_nom == 380)
& (central_buses.x > 10)
]
.squeeze()
.bus_id,
"p_nom": 600,
"length": 170,
},
)
)
# Set parameters for all DC lines
foreign_links["capital_cost"] = (
capital_cost["dc_cable"] * foreign_links.length
+ 2 * capital_cost["dc_inverter"]
)
foreign_links["p_min_pu"] = -1
foreign_links["p_nom_extendable"] = True
foreign_links["p_nom_min"] = foreign_links["p_nom"]
foreign_links["scn_name"] = scenario
foreign_links["carrier"] = "DC"
foreign_links["efficiency"] = 1
# Add topology
foreign_links = etrago.link_geom_from_buses(foreign_links, scenario)
# Insert DC lines to the database
foreign_links.to_postgis(
targets["links"]["table"],
schema=targets["links"]["schema"],
if_exists="append",
con=db.engine(),
index=False,
)
[docs]def grid():
"""Insert electrical grid compoenents for neighbouring countries
Returns
-------
None.
"""
# Select sources and targets from dataset configuration
sources = config.datasets()["electrical_neighbours"]["sources"]
targets = config.datasets()["electrical_neighbours"]["targets"]
for scenario in ["eGon2035"]:
central_buses = buses(scenario, sources, targets)
foreign_lines = cross_border_lines(
scenario, sources, targets, central_buses
)
central_transformer(
scenario, sources, targets, central_buses, foreign_lines
)
foreign_dc_lines(scenario, sources, targets, central_buses)
[docs]def map_carriers_tyndp():
"""Map carriers from TYNDP-data to carriers used in eGon
Returns
-------
dict
Carrier from TYNDP and eGon
"""
return {
"Battery": "battery",
"DSR": "demand_side_response",
"Gas CCGT new": "gas",
"Gas CCGT old 2": "gas",
"Gas CCGT present 1": "gas",
"Gas CCGT present 2": "gas",
"Gas conventional old 1": "gas",
"Gas conventional old 2": "gas",
"Gas OCGT new": "gas",
"Gas OCGT old": "gas",
"Gas CCGT old 1": "gas",
"Gas CCGT old 2 Bio": "biogas",
"Gas conventional old 2 Bio": "biogas",
"Hard coal new": "coal",
"Hard coal old 1": "coal",
"Hard coal old 2": "coal",
"Hard coal old 2 Bio": "coal",
"Heavy oil old 1": "oil",
"Heavy oil old 1 Bio": "oil",
"Heavy oil old 2": "oil",
"Light oil": "oil",
"Lignite new": "lignite",
"Lignite old 1": "lignite",
"Lignite old 2": "lignite",
"Lignite old 1 Bio": "lignite",
"Lignite old 2 Bio": "lignite",
"Nuclear": "nuclear",
"Offshore Wind": "wind_offshore",
"Onshore Wind": "wind_onshore",
"Other non-RES": "others",
"Other RES": "others",
"P2G": "power_to_gas",
"PS Closed": "pumped_hydro",
"PS Open": "reservoir",
"Reservoir": "reservoir",
"Run-of-River": "run_of_river",
"Solar PV": "solar",
"Solar Thermal": "others",
"Waste": "Other RES",
}
[docs]def get_foreign_bus_id():
"""Calculte the etrago bus id from Nodes of TYNDP based on the geometry
Returns
-------
pandas.Series
List of mapped node_ids from TYNDP and etragos bus_id
"""
sources = config.datasets()["electrical_neighbours"]["sources"]
bus_id = db.select_geodataframe(
"""SELECT bus_id, ST_Buffer(geom, 1) as geom, country
FROM grid.egon_etrago_bus
WHERE scn_name = 'eGon2035'
AND carrier = 'AC'
AND v_nom = 380.
AND country != 'DE'
AND bus_id NOT IN (
SELECT bus_i
FROM osmtgmod_results.bus_data)
""",
epsg=3035,
)
# insert installed capacities
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
# Select buses in neighbouring countries as geodataframe
buses = pd.read_excel(
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
sheet_name="Nodes - Dict",
).query("longitude==longitude")
buses = gpd.GeoDataFrame(
buses,
crs=4326,
geometry=gpd.points_from_xy(buses.longitude, buses.latitude),
).to_crs(3035)
buses["bus_id"] = 0
# Select bus_id from etrago with shortest distance to TYNDP node
for i, row in buses.iterrows():
distance = bus_id.set_index("bus_id").geom.distance(row.geometry)
buses.loc[i, "bus_id"] = distance[
distance == distance.min()
].index.values[0]
return buses.set_index("node_id").bus_id
[docs]def calc_capacities():
"""Calculates installed capacities from TYNDP data
Returns
-------
pandas.DataFrame
Installed capacities per foreign node and energy carrier
"""
sources = config.datasets()["electrical_neighbours"]["sources"]
countries = [
"AT",
"BE",
"CH",
"CZ",
"DK",
"FR",
"NL",
"NO",
"SE",
"PL",
"UK",
]
# insert installed capacities
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
df = pd.read_excel(
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
sheet_name="Capacity",
)
# differneces between different climate years are very small (<1MW)
# choose 1984 because it is the mean value
df_2030 = (
df.rename({"Climate Year": "Climate_Year"}, axis="columns")
.query(
'Scenario == "Distributed Energy" & Year == 2030 & '
"Climate_Year == 1984"
)
.set_index(["Node/Line", "Generator_ID"])
)
df_2040 = (
df.rename({"Climate Year": "Climate_Year"}, axis="columns")
.query(
'Scenario == "Distributed Energy" & Year == 2040 & '
"Climate_Year == 1984"
)
.set_index(["Node/Line", "Generator_ID"])
)
# interpolate linear between 2030 and 2040 for 2035 accordning to
# scenario report of TSO's and the approval by BNetzA
df_2035 = pd.DataFrame(index=df_2030.index)
df_2035["cap_2030"] = df_2030.Value
df_2035["cap_2040"] = df_2040.Value
df_2035.fillna(0.0, inplace=True)
df_2035["cap_2035"] = (
df_2035["cap_2030"] + (df_2035["cap_2040"] - df_2035["cap_2030"]) / 2
)
df_2035 = df_2035.reset_index()
df_2035["carrier"] = df_2035.Generator_ID.map(map_carriers_tyndp())
# group capacities by new carriers
grouped_capacities = (
df_2035.groupby(["carrier", "Node/Line"]).cap_2035.sum().reset_index()
)
# choose capacities for considered countries
return grouped_capacities[
grouped_capacities["Node/Line"].str[:2].isin(countries)
]
[docs]def insert_generators(capacities):
"""Insert generators for foreign countries based on TYNDP-data
Parameters
----------
capacities : pandas.DataFrame
Installed capacities per foreign node and energy carrier
Returns
-------
None.
"""
targets = config.datasets()["electrical_neighbours"]["targets"]
map_buses = get_map_buses()
# Delete existing data
db.execute_sql(
f"""
DELETE FROM
{targets['generators']['schema']}.{targets['generators']['table']}
WHERE bus IN (
SELECT bus_id FROM
{targets['buses']['schema']}.{targets['buses']['table']}
WHERE country != 'DE'
AND scn_name = 'eGon2035')
AND scn_name = 'eGon2035'
AND carrier != 'CH4'
"""
)
db.execute_sql(
f"""
DELETE FROM
{targets['generators_timeseries']['schema']}.
{targets['generators_timeseries']['table']}
WHERE generator_id NOT IN (
SELECT generator_id FROM
{targets['generators']['schema']}.{targets['generators']['table']}
)
AND scn_name = 'eGon2035'
"""
)
# Select generators from TYNDP capacities
gen = capacities[
capacities.carrier.isin(
[
"others",
"wind_offshore",
"wind_onshore",
"solar",
"reservoir",
"run_of_river",
"lignite",
"coal",
"oil",
"nuclear",
]
)
]
# Set bus_id
gen.loc[
gen[gen["Node/Line"].isin(map_buses.keys())].index, "Node/Line"
] = gen.loc[
gen[gen["Node/Line"].isin(map_buses.keys())].index, "Node/Line"
].map(
map_buses
)
gen.loc[:, "bus"] = (
get_foreign_bus_id().loc[gen.loc[:, "Node/Line"]].values
)
# Add scenario column
gen["scenario"] = "eGon2035"
# Add marginal costs
gen = add_marginal_costs(gen)
# insert generators data
session = sessionmaker(bind=db.engine())()
for i, row in gen.iterrows():
entry = etrago.EgonPfHvGenerator(
scn_name=row.scenario,
generator_id=int(db.next_etrago_id("generator")),
bus=row.bus,
carrier=row.carrier,
p_nom=row.cap_2035,
marginal_cost=row.marginal_cost,
)
session.add(entry)
session.commit()
# assign generators time-series data
renew_carriers_2035 = ["wind_onshore", "wind_offshore", "solar"]
sql = f"""SELECT * FROM
{targets['generators_timeseries']['schema']}.
{targets['generators_timeseries']['table']}
WHERE scn_name = 'eGon100RE'
"""
series_egon100 = pd.read_sql_query(sql, db.engine())
sql = f""" SELECT * FROM
{targets['generators']['schema']}.{targets['generators']['table']}
WHERE bus IN (
SELECT bus_id FROM
{targets['buses']['schema']}.{targets['buses']['table']}
WHERE country != 'DE'
AND scn_name = 'eGon2035')
AND scn_name = 'eGon2035'
"""
gen_2035 = pd.read_sql_query(sql, db.engine())
gen_2035 = gen_2035[gen_2035.carrier.isin(renew_carriers_2035)]
sql = f""" SELECT * FROM
{targets['generators']['schema']}.{targets['generators']['table']}
WHERE bus IN (
SELECT bus_id FROM
{targets['buses']['schema']}.{targets['buses']['table']}
WHERE country != 'DE'
AND scn_name = 'eGon100RE')
AND scn_name = 'eGon100RE'
"""
gen_100 = pd.read_sql_query(sql, db.engine())
gen_100 = gen_100[gen_100["carrier"].isin(renew_carriers_2035)]
# egon_2035_to_100 map the timeseries used in the scenario eGon100RE
# to the same bus and carrier for the scenario egon2035
egon_2035_to_100 = {}
for i, gen in gen_2035.iterrows():
gen_id_100 = gen_100[
(gen_100["bus"] == gen["bus"])
& (gen_100["carrier"] == gen["carrier"])
]["generator_id"].values[0]
egon_2035_to_100[gen["generator_id"]] = gen_id_100
# insert generators_timeseries data
session = sessionmaker(bind=db.engine())()
for gen_id in gen_2035.generator_id:
serie = series_egon100[
series_egon100.generator_id == egon_2035_to_100[gen_id]
]["p_max_pu"].values[0]
entry = etrago.EgonPfHvGeneratorTimeseries(
scn_name="eGon2035", generator_id=gen_id, temp_id=1, p_max_pu=serie
)
session.add(entry)
session.commit()
[docs]def insert_storage(capacities):
"""Insert storage units for foreign countries based on TYNDP-data
Parameters
----------
capacities : pandas.DataFrame
Installed capacities per foreign node and energy carrier
Returns
-------
None.
"""
targets = config.datasets()["electrical_neighbours"]["targets"]
map_buses = get_map_buses()
# Delete existing data
db.execute_sql(
f"""
DELETE FROM {targets['storage']['schema']}.{targets['storage']['table']}
WHERE bus IN (
SELECT bus_id FROM
{targets['buses']['schema']}.{targets['buses']['table']}
WHERE country != 'DE'
AND scn_name = 'eGon2035')
AND scn_name = 'eGon2035'
"""
)
# Add missing information suitable for eTraGo selected from scenario_parameter table
parameters_pumped_hydro = scenario_parameters.electricity("eGon2035")[
"efficiency"
]["pumped_hydro"]
parameters_battery = scenario_parameters.electricity("eGon2035")[
"efficiency"
]["battery"]
# Select storage capacities from TYNDP-data
store = capacities[capacities.carrier.isin(["battery", "pumped_hydro"])]
# Set bus_id
store.loc[
store[store["Node/Line"].isin(map_buses.keys())].index, "Node/Line"
] = store.loc[
store[store["Node/Line"].isin(map_buses.keys())].index, "Node/Line"
].map(
map_buses
)
store.loc[:, "bus"] = (
get_foreign_bus_id().loc[store.loc[:, "Node/Line"]].values
)
# Add columns for additional parameters to df
(
store["dispatch"],
store["store"],
store["standing_loss"],
store["max_hours"],
) = (None, None, None, None)
# Insert carrier specific parameters
parameters = ["dispatch", "store", "standing_loss", "max_hours"]
for x in parameters:
store.loc[store["carrier"] == "battery", x] = parameters_battery[x]
store.loc[
store["carrier"] == "pumped_hydro", x
] = parameters_pumped_hydro[x]
# insert data
session = sessionmaker(bind=db.engine())()
for i, row in store.iterrows():
entry = etrago.EgonPfHvStorage(
scn_name="eGon2035",
storage_id=int(db.next_etrago_id("storage")),
bus=row.bus,
max_hours=row.max_hours,
efficiency_store=row.store,
efficiency_dispatch=row.dispatch,
standing_loss=row.standing_loss,
carrier=row.carrier,
p_nom=row.cap_2035,
)
session.add(entry)
session.commit()
[docs]def get_map_buses():
"""Returns a dictonary of foreign regions which are aggregated to another
Returns
-------
Combination of aggregated regions
"""
return {
"DK00": "DKW1",
"DKKF": "DKE1",
"FR15": "FR00",
"NON1": "NOM1",
"NOS0": "NOM1",
"NOS1": "NOM1",
"PLE0": "PL00",
"PLI0": "PL00",
"SE00": "SE02",
"SE01": "SE02",
"SE03": "SE02",
"SE04": "SE02",
"RU": "RU00",
}
[docs]def tyndp_generation():
"""Insert data from TYNDP 2020 accordning to NEP 2021
Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
Returns
-------
None.
"""
capacities = calc_capacities()
insert_generators(capacities)
insert_storage(capacities)
[docs]def tyndp_demand():
"""Copy load timeseries data from TYNDP 2020.
According to NEP 2021, the data for 2030 and 2040 is interpolated linearly.
Returns
-------
None.
"""
map_buses = get_map_buses()
sources = config.datasets()["electrical_neighbours"]["sources"]
targets = config.datasets()["electrical_neighbours"]["targets"]
# Delete existing data
db.execute_sql(
f"""
DELETE FROM {targets['loads']['schema']}.
{targets['loads']['table']}
WHERE
scn_name = 'eGon2035'
AND carrier = 'AC'
AND bus NOT IN (
SELECT bus_i
FROM {sources['osmtgmod_bus']['schema']}.
{sources['osmtgmod_bus']['table']})
"""
)
# Connect to database
engine = db.engine()
session = sessionmaker(bind=engine)()
nodes = [
"AT00",
"BE00",
"CH00",
"CZ00",
"DKE1",
"DKW1",
"FR00",
"NL00",
"LUB1",
"LUF1",
"LUG1",
"NOM1",
"NON1",
"NOS0",
"SE01",
"SE02",
"SE03",
"SE04",
"PL00",
"UK00",
"UKNI",
]
# Assign etrago bus_id to TYNDP nodes
buses = pd.DataFrame({"nodes": nodes})
buses.loc[
buses[buses.nodes.isin(map_buses.keys())].index, "nodes"
] = buses[buses.nodes.isin(map_buses.keys())].nodes.map(map_buses)
buses.loc[:, "bus"] = (
get_foreign_bus_id().loc[buses.loc[:, "nodes"]].values
)
buses.set_index("nodes", inplace=True)
buses = buses[~buses.index.duplicated(keep="first")]
# Read in data from TYNDP for 2030 and 2040
dataset_2030 = pd.read_excel(
f"tyndp/{sources['tyndp_demand_2030']}", sheet_name=nodes, skiprows=10
)
dataset_2040 = pd.read_excel(
f"tyndp/{sources['tyndp_demand_2040']}", sheet_name=None, skiprows=10
)
# Transform map_buses to pandas.Series and select only used values
map_series = pd.Series(map_buses)
map_series = map_series[map_series.index.isin(nodes)]
# Calculate and insert demand timeseries per etrago bus_id
for bus in buses.index:
nodes = [bus]
if bus in map_series.values:
nodes.extend(list(map_series[map_series == bus].index.values))
load_id = db.next_etrago_id("load")
# Some etrago bus_ids represent multiple TYNDP nodes,
# in this cases the loads are summed
data_2030 = pd.Series(index=range(8760), data=0.0)
for node in nodes:
data_2030 = dataset_2030[node][2011] + data_2030
try:
data_2040 = pd.Series(index=range(8760), data=0.0)
for node in nodes:
data_2040 = dataset_2040[node][2011] + data_2040
except:
data_2040 = data_2030
# According to the NEP, data for 2030 and 2040 is linear interpolated
data_2035 = ((data_2030 + data_2040) / 2)[:8760]
entry = etrago.EgonPfHvLoad(
scn_name="eGon2035",
load_id=int(load_id),
carrier="AC",
bus=int(buses.bus[bus]),
)
entry_ts = etrago.EgonPfHvLoadTimeseries(
scn_name="eGon2035",
load_id=int(load_id),
temp_id=1,
p_set=list(data_2035.values),
)
session.add(entry)
session.add(entry_ts)
session.commit()