1
|
|
|
"""Central module containing code dealing with gas neighbours for eGon2035
|
2
|
|
|
"""
|
3
|
|
|
|
4
|
|
|
from pathlib import Path
|
5
|
|
|
from urllib.request import urlretrieve
|
6
|
|
|
import ast
|
7
|
|
|
import zipfile
|
8
|
|
|
|
9
|
|
|
from shapely.geometry import LineString, MultiLineString
|
10
|
|
|
import geopandas as gpd
|
11
|
|
|
import pandas as pd
|
12
|
|
|
import pypsa
|
13
|
|
|
|
14
|
|
|
from egon.data import config, db
|
15
|
|
|
from egon.data.datasets.electrical_neighbours import (
|
16
|
|
|
get_foreign_bus_id,
|
17
|
|
|
get_map_buses,
|
18
|
|
|
)
|
19
|
|
|
from egon.data.datasets.gas_neighbours.gas_abroad import (
|
20
|
|
|
insert_gas_grid_capacities,
|
21
|
|
|
)
|
22
|
|
|
from egon.data.datasets.scenario_parameters import get_sector_parameters
|
23
|
|
|
|
24
|
|
|
countries = [
|
25
|
|
|
"AT",
|
26
|
|
|
"BE",
|
27
|
|
|
"CH",
|
28
|
|
|
"CZ",
|
29
|
|
|
"DK",
|
30
|
|
|
"FR",
|
31
|
|
|
"GB",
|
32
|
|
|
"LU",
|
33
|
|
|
"NL",
|
34
|
|
|
"NO",
|
35
|
|
|
"PL",
|
36
|
|
|
"RU",
|
37
|
|
|
"SE",
|
38
|
|
|
"UK",
|
39
|
|
|
]
|
40
|
|
|
|
41
|
|
|
|
42
|
|
View Code Duplication |
def get_foreign_gas_bus_id(carrier="CH4"):
|
|
|
|
|
43
|
|
|
"""Calculate the etrago bus id based on the geometry
|
44
|
|
|
|
45
|
|
|
Map node_ids from TYNDP and etragos bus_id
|
46
|
|
|
|
47
|
|
|
Parameters
|
48
|
|
|
----------
|
49
|
|
|
carrier : str
|
50
|
|
|
Name of the carrier
|
51
|
|
|
|
52
|
|
|
Returns
|
53
|
|
|
-------
|
54
|
|
|
pandas.Series
|
55
|
|
|
List of mapped node_ids from TYNDP and etragos bus_id
|
56
|
|
|
|
57
|
|
|
"""
|
58
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
59
|
|
|
scn_name = "eGon2035"
|
60
|
|
|
|
61
|
|
|
bus_id = db.select_geodataframe(
|
62
|
|
|
f"""
|
63
|
|
|
SELECT bus_id, ST_Buffer(geom, 1) as geom, country
|
64
|
|
|
FROM grid.egon_etrago_bus
|
65
|
|
|
WHERE scn_name = '{scn_name}'
|
66
|
|
|
AND carrier = '{carrier}'
|
67
|
|
|
AND country != 'DE'
|
68
|
|
|
""",
|
69
|
|
|
epsg=3035,
|
70
|
|
|
)
|
71
|
|
|
|
72
|
|
|
# insert installed capacities
|
73
|
|
|
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
|
74
|
|
|
|
75
|
|
|
# Select buses in neighbouring countries as geodataframe
|
76
|
|
|
buses = pd.read_excel(
|
77
|
|
|
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
|
78
|
|
|
sheet_name="Nodes - Dict",
|
79
|
|
|
).query("longitude==longitude")
|
80
|
|
|
buses = gpd.GeoDataFrame(
|
81
|
|
|
buses,
|
82
|
|
|
crs=4326,
|
83
|
|
|
geometry=gpd.points_from_xy(buses.longitude, buses.latitude),
|
84
|
|
|
).to_crs(3035)
|
85
|
|
|
|
86
|
|
|
buses["bus_id"] = 0
|
87
|
|
|
|
88
|
|
|
# Select bus_id from etrago with shortest distance to TYNDP node
|
89
|
|
|
for i, row in buses.iterrows():
|
90
|
|
|
distance = bus_id.set_index("bus_id").geom.distance(row.geometry)
|
91
|
|
|
buses.loc[i, "bus_id"] = distance[
|
92
|
|
|
distance == distance.min()
|
93
|
|
|
].index.values[0]
|
94
|
|
|
|
95
|
|
|
return buses.set_index("node_id").bus_id
|
96
|
|
|
|
97
|
|
|
|
98
|
|
|
def read_LNG_capacities():
|
99
|
|
|
"""Read LNG import capacities from Scigrid gas data
|
100
|
|
|
|
101
|
|
|
Returns
|
102
|
|
|
-------
|
103
|
|
|
IGGIELGN_LNGs: pandas.Series
|
104
|
|
|
LNG terminal capacities per foreign country node (in GWh/d)
|
105
|
|
|
|
106
|
|
|
"""
|
107
|
|
|
lng_file = "datasets/gas_data/data/IGGIELGN_LNGs.csv"
|
108
|
|
|
IGGIELGN_LNGs = gpd.read_file(lng_file)
|
109
|
|
|
|
110
|
|
|
map_countries_scigrid = {
|
111
|
|
|
"BE": "BE00",
|
112
|
|
|
"EE": "EE00",
|
113
|
|
|
"EL": "GR00",
|
114
|
|
|
"ES": "ES00",
|
115
|
|
|
"FI": "FI00",
|
116
|
|
|
"FR": "FR00",
|
117
|
|
|
"GB": "UK00",
|
118
|
|
|
"IT": "ITCN",
|
119
|
|
|
"LT": "LT00",
|
120
|
|
|
"LV": "LV00",
|
121
|
|
|
"MT": "MT00",
|
122
|
|
|
"NL": "NL00",
|
123
|
|
|
"PL": "PL00",
|
124
|
|
|
"PT": "PT00",
|
125
|
|
|
"SE": "SE01",
|
126
|
|
|
}
|
127
|
|
|
|
128
|
|
|
conversion_factor = 437.5 # MCM/day to MWh/h
|
129
|
|
|
c2 = 24 / 1000 # MWh/h to GWh/d
|
130
|
|
|
p_nom = []
|
131
|
|
|
|
132
|
|
|
for index, row in IGGIELGN_LNGs.iterrows():
|
133
|
|
|
param = ast.literal_eval(row["param"])
|
134
|
|
|
p_nom.append(
|
135
|
|
|
param["max_cap_store2pipe_M_m3_per_d"] * conversion_factor * c2
|
136
|
|
|
)
|
137
|
|
|
|
138
|
|
|
IGGIELGN_LNGs["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] = p_nom
|
139
|
|
|
|
140
|
|
|
IGGIELGN_LNGs.drop(
|
141
|
|
|
[
|
142
|
|
|
"uncertainty",
|
143
|
|
|
"method",
|
144
|
|
|
"param",
|
145
|
|
|
"comment",
|
146
|
|
|
"tags",
|
147
|
|
|
"source_id",
|
148
|
|
|
"lat",
|
149
|
|
|
"long",
|
150
|
|
|
"geometry",
|
151
|
|
|
"id",
|
152
|
|
|
"name",
|
153
|
|
|
"node_id",
|
154
|
|
|
],
|
155
|
|
|
axis=1,
|
156
|
|
|
inplace=True,
|
157
|
|
|
)
|
158
|
|
|
|
159
|
|
|
IGGIELGN_LNGs["Country"] = IGGIELGN_LNGs["country_code"].map(
|
160
|
|
|
map_countries_scigrid
|
161
|
|
|
)
|
162
|
|
|
IGGIELGN_LNGs = (
|
163
|
|
|
IGGIELGN_LNGs.groupby(["Country"])[
|
164
|
|
|
"LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"
|
165
|
|
|
]
|
166
|
|
|
.sum()
|
167
|
|
|
.sort_index()
|
168
|
|
|
)
|
169
|
|
|
|
170
|
|
|
return IGGIELGN_LNGs
|
171
|
|
|
|
172
|
|
|
|
173
|
|
|
def calc_capacities():
|
174
|
|
|
"""Calculates gas production capacities of neighbouring countries
|
175
|
|
|
|
176
|
|
|
For each neigbouring country, this function calculates the gas
|
177
|
|
|
generation capacity in 2035 using the function
|
178
|
|
|
:py:func:`calc_capacity_per_year` for 2030 and 2040 and
|
179
|
|
|
interpolating the results. These capacities include LNG import, as
|
180
|
|
|
well as conventional and biogas production.
|
181
|
|
|
Two conventional gas generators for are added for Norway and Russia
|
182
|
|
|
interpolating the supply potential (min) values from the TYNPD 2020
|
183
|
|
|
for 2030 and 2040.
|
184
|
|
|
|
185
|
|
|
Returns
|
186
|
|
|
-------
|
187
|
|
|
grouped_capacities: pandas.DataFrame
|
188
|
|
|
Gas production capacities per foreign node
|
189
|
|
|
|
190
|
|
|
"""
|
191
|
|
|
|
192
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
193
|
|
|
|
194
|
|
|
# insert installed capacities
|
195
|
|
|
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
|
196
|
|
|
df0 = pd.read_excel(
|
197
|
|
|
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
|
198
|
|
|
sheet_name="Gas Data",
|
199
|
|
|
)
|
200
|
|
|
|
201
|
|
|
df = (
|
202
|
|
|
df0.query(
|
203
|
|
|
'Scenario == "Distributed Energy" &'
|
204
|
|
|
' (Case == "Peak" | Case == "Average") &'
|
205
|
|
|
# Case: 2 Week/Average/DF/Peak
|
206
|
|
|
' Category == "Production"'
|
207
|
|
|
)
|
208
|
|
|
.drop(
|
209
|
|
|
columns=[
|
210
|
|
|
"Generator_ID",
|
211
|
|
|
"Climate Year",
|
212
|
|
|
"Simulation_ID",
|
213
|
|
|
"Node 1",
|
214
|
|
|
"Path",
|
215
|
|
|
"Direct/Indirect",
|
216
|
|
|
"Sector",
|
217
|
|
|
"Note",
|
218
|
|
|
"Category",
|
219
|
|
|
"Scenario",
|
220
|
|
|
]
|
221
|
|
|
)
|
222
|
|
|
.set_index("Node/Line")
|
223
|
|
|
.sort_index()
|
224
|
|
|
)
|
225
|
|
|
|
226
|
|
|
lng = read_LNG_capacities()
|
227
|
|
|
df_2030 = calc_capacity_per_year(df, lng, 2030)
|
228
|
|
|
df_2040 = calc_capacity_per_year(df, lng, 2040)
|
229
|
|
|
|
230
|
|
|
# Conversion GWh/d to MWh/h
|
231
|
|
|
conversion_factor = 1000 / 24
|
232
|
|
|
|
233
|
|
|
df_2035 = pd.concat([df_2040, df_2030], axis=1)
|
234
|
|
|
df_2035 = df_2035.drop(
|
235
|
|
|
columns=[
|
236
|
|
|
"Value_conv_2040",
|
237
|
|
|
"Value_conv_2030",
|
238
|
|
|
"Value_bio_2040",
|
239
|
|
|
"Value_bio_2030",
|
240
|
|
|
]
|
241
|
|
|
)
|
242
|
|
|
df_2035["cap_2035"] = (df_2035["CH4_2030"] + df_2035["CH4_2040"]) / 2
|
243
|
|
|
df_2035["e_nom_max"] = (
|
244
|
|
|
((df_2035["e_nom_max_2030"] + df_2035["e_nom_max_2040"]) / 2)
|
245
|
|
|
* conversion_factor
|
246
|
|
|
* 8760
|
247
|
|
|
)
|
248
|
|
|
df_2035["share_LNG_2035"] = (
|
249
|
|
|
df_2035["share_LNG_2030"] + df_2035["share_LNG_2040"]
|
250
|
|
|
) / 2
|
251
|
|
|
df_2035["share_conv_pipe_2035"] = (
|
252
|
|
|
df_2035["share_conv_pipe_2030"] + df_2035["share_conv_pipe_2040"]
|
253
|
|
|
) / 2
|
254
|
|
|
df_2035["share_bio_2035"] = (
|
255
|
|
|
df_2035["share_bio_2030"] + df_2035["share_bio_2040"]
|
256
|
|
|
) / 2
|
257
|
|
|
|
258
|
|
|
grouped_capacities = df_2035.drop(
|
259
|
|
|
columns=[
|
260
|
|
|
"share_LNG_2030",
|
261
|
|
|
"share_LNG_2040",
|
262
|
|
|
"share_conv_pipe_2030",
|
263
|
|
|
"share_conv_pipe_2040",
|
264
|
|
|
"share_bio_2030",
|
265
|
|
|
"share_bio_2040",
|
266
|
|
|
"CH4_2040",
|
267
|
|
|
"CH4_2030",
|
268
|
|
|
"e_nom_max_2030",
|
269
|
|
|
"e_nom_max_2040",
|
270
|
|
|
]
|
271
|
|
|
).reset_index()
|
272
|
|
|
|
273
|
|
|
grouped_capacities["cap_2035"] = (
|
274
|
|
|
grouped_capacities["cap_2035"] * conversion_factor
|
275
|
|
|
)
|
276
|
|
|
|
277
|
|
|
# Add generators in Norway and Russia
|
278
|
|
|
df_conv = (
|
279
|
|
|
df0.query('Case == "Min" & Category == "Supply Potential"')
|
280
|
|
|
.drop(
|
281
|
|
|
columns=[
|
282
|
|
|
"Generator_ID",
|
283
|
|
|
"Climate Year",
|
284
|
|
|
"Simulation_ID",
|
285
|
|
|
"Node 1",
|
286
|
|
|
"Path",
|
287
|
|
|
"Direct/Indirect",
|
288
|
|
|
"Sector",
|
289
|
|
|
"Note",
|
290
|
|
|
"Category",
|
291
|
|
|
"Scenario",
|
292
|
|
|
"Parameter",
|
293
|
|
|
"Case",
|
294
|
|
|
]
|
295
|
|
|
)
|
296
|
|
|
.set_index("Node/Line")
|
297
|
|
|
.sort_index()
|
298
|
|
|
)
|
299
|
|
|
|
300
|
|
|
df_conv_2030 = df_conv[df_conv["Year"] == 2030].rename(
|
301
|
|
|
columns={"Value": "Value_2030"}
|
302
|
|
|
)
|
303
|
|
|
df_conv_2040 = df_conv[df_conv["Year"] == 2040].rename(
|
304
|
|
|
columns={"Value": "Value_2040"}
|
305
|
|
|
)
|
306
|
|
|
df_conv_2035 = pd.concat([df_conv_2040, df_conv_2030], axis=1)
|
307
|
|
|
|
308
|
|
|
df_conv_2035["cap_2035"] = (
|
309
|
|
|
(df_conv_2035["Value_2030"] + df_conv_2035["Value_2040"]) / 2
|
310
|
|
|
) * conversion_factor
|
311
|
|
|
df_conv_2035["e_nom_max"] = df_conv_2035["cap_2035"] * 8760
|
312
|
|
|
df_conv_2035["share_LNG_2035"] = 0
|
313
|
|
|
df_conv_2035["share_conv_pipe_2035"] = 1
|
314
|
|
|
df_conv_2035["share_bio_2035"] = 0
|
315
|
|
|
|
316
|
|
|
df_conv_2035 = df_conv_2035.drop(
|
317
|
|
|
columns=[
|
318
|
|
|
"Year",
|
319
|
|
|
"Value_2030",
|
320
|
|
|
"Value_2040",
|
321
|
|
|
]
|
322
|
|
|
).reset_index()
|
323
|
|
|
df_conv_2035 = df_conv_2035.rename(columns={"Node/Line": "index"})
|
324
|
|
|
grouped_capacities = grouped_capacities.append(df_conv_2035)
|
325
|
|
|
|
326
|
|
|
# choose capacities for considered countries
|
327
|
|
|
grouped_capacities = grouped_capacities[
|
328
|
|
|
grouped_capacities["index"].str[:2].isin(countries)
|
329
|
|
|
]
|
330
|
|
|
return grouped_capacities
|
331
|
|
|
|
332
|
|
|
|
333
|
|
|
def calc_capacity_per_year(df, lng, year):
|
334
|
|
|
"""Calculates gas production capacities for a specified year
|
335
|
|
|
|
336
|
|
|
For a specified year and for the foreign country nodes this function
|
337
|
|
|
calculates the gas production capacity, considering the gas
|
338
|
|
|
(conventional and bio) production capacity from TYNDP data and the
|
339
|
|
|
LGN import capacity from Scigrid gas data.
|
340
|
|
|
|
341
|
|
|
The columns of the returned dataframe are the following:
|
342
|
|
|
* Value_bio_year: biogas capacity prodution (in GWh/d)
|
343
|
|
|
* Value_conv_year: conventional gas capacity prodution including
|
344
|
|
|
LNG imports (in GWh/d)
|
345
|
|
|
* CH4_year: total gas production capacity (in GWh/d). This value
|
346
|
|
|
is calculated using the peak production value from the TYNDP.
|
347
|
|
|
* e_nom_max_year: total gas production capacity representative
|
348
|
|
|
for the whole year (in GWh/d). This value is calculated using
|
349
|
|
|
the average production value from the TYNDP and will then be
|
350
|
|
|
used to limit the energy that can be generated in one year.
|
351
|
|
|
* share_LNG_year: share of LGN import capacity in the total gas
|
352
|
|
|
production capacity
|
353
|
|
|
* share_conv_pipe_year: share of conventional gas extraction
|
354
|
|
|
capacity in the total gas production capacity
|
355
|
|
|
* share_bio_year: share of biogas production capacity in the
|
356
|
|
|
total gas production capacity
|
357
|
|
|
|
358
|
|
|
Parameters
|
359
|
|
|
----------
|
360
|
|
|
df : pandas.DataFrame
|
361
|
|
|
Gas (conventional and bio) production capacities from TYNDP (in GWh/d)
|
362
|
|
|
|
363
|
|
|
lng : pandas.Series
|
364
|
|
|
LNG terminal capacities per foreign country node (in GWh/d)
|
365
|
|
|
|
366
|
|
|
year : int
|
367
|
|
|
Year to calculate gas production capacity for.
|
368
|
|
|
|
369
|
|
|
Returns
|
370
|
|
|
-------
|
371
|
|
|
df_year : pandas.DataFrame
|
372
|
|
|
Gas production capacities (in GWh/d) per foreign country node
|
373
|
|
|
|
374
|
|
|
"""
|
375
|
|
|
df_conv_peak = (
|
376
|
|
|
df[
|
377
|
|
|
(df["Parameter"] == "Conventional")
|
378
|
|
|
& (df["Year"] == year)
|
379
|
|
|
& (df["Case"] == "Peak")
|
380
|
|
|
]
|
381
|
|
|
.rename(columns={"Value": f"Value_conv_{year}_peak"})
|
382
|
|
|
.drop(columns=["Parameter", "Year", "Case"])
|
383
|
|
|
)
|
384
|
|
|
df_conv_average = (
|
385
|
|
|
df[
|
386
|
|
|
(df["Parameter"] == "Conventional")
|
387
|
|
|
& (df["Year"] == year)
|
388
|
|
|
& (df["Case"] == "Average")
|
389
|
|
|
]
|
390
|
|
|
.rename(columns={"Value": f"Value_conv_{year}_average"})
|
391
|
|
|
.drop(columns=["Parameter", "Year", "Case"])
|
392
|
|
|
)
|
393
|
|
|
df_bioch4 = (
|
394
|
|
|
df[
|
395
|
|
|
(df["Parameter"] == "Biomethane")
|
396
|
|
|
& (df["Year"] == year)
|
397
|
|
|
& (df["Case"] == "Peak")
|
398
|
|
|
# Peak and Average have the same values for biogas
|
399
|
|
|
# production in 2030 and 2040
|
400
|
|
|
]
|
401
|
|
|
.rename(columns={"Value": f"Value_bio_{year}"})
|
402
|
|
|
.drop(columns=["Parameter", "Year", "Case"])
|
403
|
|
|
)
|
404
|
|
|
|
405
|
|
|
# Some values are duplicated (DE00 in 2030)
|
406
|
|
|
df_conv_peak = df_conv_peak[~df_conv_peak.index.duplicated(keep="first")]
|
407
|
|
|
df_conv_average = df_conv_average[
|
408
|
|
|
~df_conv_average.index.duplicated(keep="first")
|
409
|
|
|
]
|
410
|
|
|
|
411
|
|
|
df_year = pd.concat(
|
412
|
|
|
[df_conv_peak, df_conv_average, df_bioch4, lng], axis=1
|
413
|
|
|
).fillna(0)
|
414
|
|
|
df_year = df_year[
|
415
|
|
|
~(
|
416
|
|
|
(df_year[f"Value_conv_{year}_peak"] == 0)
|
417
|
|
|
& (df_year[f"Value_bio_{year}"] == 0)
|
418
|
|
|
& (df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] == 0)
|
419
|
|
|
)
|
420
|
|
|
]
|
421
|
|
|
df_year[f"Value_conv_{year}"] = (
|
422
|
|
|
df_year[f"Value_conv_{year}_peak"]
|
423
|
|
|
+ df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
|
424
|
|
|
)
|
425
|
|
|
df_year[f"CH4_{year}"] = (
|
426
|
|
|
df_year[f"Value_conv_{year}"] + df_year[f"Value_bio_{year}"]
|
427
|
|
|
)
|
428
|
|
|
df_year[f"e_nom_max_{year}"] = (
|
429
|
|
|
df_year[f"Value_conv_{year}_average"]
|
430
|
|
|
+ df_year[f"Value_bio_{year}"]
|
431
|
|
|
+ df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
|
432
|
|
|
)
|
433
|
|
|
df_year[f"share_LNG_{year}"] = (
|
434
|
|
|
df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
|
435
|
|
|
/ df_year[f"e_nom_max_{year}"]
|
436
|
|
|
)
|
437
|
|
|
df_year[f"share_conv_pipe_{year}"] = (
|
438
|
|
|
df_year[f"Value_conv_{year}_average"] / df_year[f"e_nom_max_{year}"]
|
439
|
|
|
)
|
440
|
|
|
df_year[f"share_bio_{year}"] = (
|
441
|
|
|
df_year[f"Value_bio_{year}"] / df_year[f"e_nom_max_{year}"]
|
442
|
|
|
)
|
443
|
|
|
|
444
|
|
|
df_year = df_year.drop(
|
445
|
|
|
columns=[
|
446
|
|
|
"LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)",
|
447
|
|
|
f"Value_conv_{year}_average",
|
448
|
|
|
f"Value_conv_{year}_peak",
|
449
|
|
|
]
|
450
|
|
|
)
|
451
|
|
|
|
452
|
|
|
return df_year
|
453
|
|
|
|
454
|
|
|
|
455
|
|
|
def insert_generators(gen):
|
456
|
|
|
"""Insert gas generators for foreign countries in the database
|
457
|
|
|
|
458
|
|
|
Insert gas generators for foreign countries in the data base.
|
459
|
|
|
The marginal cost of the methane is calculated as the sum of the
|
460
|
|
|
imported LNG cost, of the conventional natural gas cost and of the
|
461
|
|
|
biomethane cost, weighted by their share in the total import/
|
462
|
|
|
production capacity.
|
463
|
|
|
LNG is considerate to be 30% more expensive than the natural gas
|
464
|
|
|
transported by pipelines (source: iwd, 2022).
|
465
|
|
|
|
466
|
|
|
Parameters
|
467
|
|
|
----------
|
468
|
|
|
gen : pandas.DataFrame
|
469
|
|
|
Gas production capacities per foreign node and energy carrier
|
470
|
|
|
|
471
|
|
|
Returns
|
472
|
|
|
-------
|
473
|
|
|
None.
|
474
|
|
|
|
475
|
|
|
"""
|
476
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
477
|
|
|
targets = config.datasets()["gas_neighbours"]["targets"]
|
478
|
|
|
map_buses = get_map_buses()
|
479
|
|
|
scn_params = get_sector_parameters("gas", "eGon2035")
|
480
|
|
|
|
481
|
|
|
# Delete existing data
|
482
|
|
|
db.execute_sql(
|
483
|
|
|
f"""
|
484
|
|
|
DELETE FROM
|
485
|
|
|
{targets['generators']['schema']}.{targets['generators']['table']}
|
486
|
|
|
WHERE bus IN (
|
487
|
|
|
SELECT bus_id FROM
|
488
|
|
|
{sources['buses']['schema']}.{sources['buses']['table']}
|
489
|
|
|
WHERE country != 'DE'
|
490
|
|
|
AND scn_name = 'eGon2035')
|
491
|
|
|
AND scn_name = 'eGon2035'
|
492
|
|
|
AND carrier = 'CH4';
|
493
|
|
|
"""
|
494
|
|
|
)
|
495
|
|
|
|
496
|
|
|
# Set bus_id
|
497
|
|
|
gen.loc[gen[gen["index"].isin(map_buses.keys())].index, "index"] = gen.loc[
|
498
|
|
|
gen[gen["index"].isin(map_buses.keys())].index, "index"
|
499
|
|
|
].map(map_buses)
|
500
|
|
|
gen.loc[:, "bus"] = (
|
501
|
|
|
get_foreign_gas_bus_id().loc[gen.loc[:, "index"]].values
|
502
|
|
|
)
|
503
|
|
|
|
504
|
|
|
# Add missing columns
|
505
|
|
|
c = {"scn_name": "eGon2035", "carrier": "CH4"}
|
506
|
|
|
gen = gen.assign(**c)
|
507
|
|
|
|
508
|
|
|
new_id = db.next_etrago_id("generator")
|
509
|
|
|
gen["generator_id"] = range(new_id, new_id + len(gen))
|
510
|
|
|
gen["p_nom"] = gen["cap_2035"]
|
511
|
|
|
gen["marginal_cost"] = (
|
512
|
|
|
gen["share_LNG_2035"] * scn_params["marginal_cost"]["CH4"] * 1.3
|
513
|
|
|
+ gen["share_conv_pipe_2035"] * scn_params["marginal_cost"]["CH4"]
|
514
|
|
|
+ gen["share_bio_2035"] * scn_params["marginal_cost"]["biogas"]
|
515
|
|
|
)
|
516
|
|
|
|
517
|
|
|
# Remove useless columns
|
518
|
|
|
gen = gen.drop(
|
519
|
|
|
columns=[
|
520
|
|
|
"index",
|
521
|
|
|
"share_LNG_2035",
|
522
|
|
|
"share_conv_pipe_2035",
|
523
|
|
|
"share_bio_2035",
|
524
|
|
|
"cap_2035",
|
525
|
|
|
]
|
526
|
|
|
)
|
527
|
|
|
|
528
|
|
|
# Insert data to db
|
529
|
|
|
gen.to_sql(
|
530
|
|
|
targets["generators"]["table"],
|
531
|
|
|
db.engine(),
|
532
|
|
|
schema=targets["generators"]["schema"],
|
533
|
|
|
index=False,
|
534
|
|
|
if_exists="append",
|
535
|
|
|
)
|
536
|
|
|
|
537
|
|
|
|
538
|
|
|
def calc_global_ch4_demand(Norway_global_demand_1y):
|
539
|
|
|
"""Calculates global CH4 demands abroad for eGon2035 scenario
|
540
|
|
|
|
541
|
|
|
The data comes from TYNDP 2020 according to NEP 2021 from the
|
542
|
|
|
scenario 'Distributed Energy', linear interpolate between 2030
|
543
|
|
|
and 2040.
|
544
|
|
|
|
545
|
|
|
Returns
|
546
|
|
|
-------
|
547
|
|
|
pandas.DataFrame
|
548
|
|
|
Global (yearly) CH4 final demand per foreign node
|
549
|
|
|
|
550
|
|
|
"""
|
551
|
|
|
|
552
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
553
|
|
|
|
554
|
|
|
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
|
555
|
|
|
df = pd.read_excel(
|
556
|
|
|
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
|
557
|
|
|
sheet_name="Gas Data",
|
558
|
|
|
)
|
559
|
|
|
|
560
|
|
|
df = (
|
561
|
|
|
df.query(
|
562
|
|
|
'Scenario == "Distributed Energy" & '
|
563
|
|
|
'Case == "Average" &'
|
564
|
|
|
'Category == "Demand"'
|
565
|
|
|
)
|
566
|
|
|
.drop(
|
567
|
|
|
columns=[
|
568
|
|
|
"Generator_ID",
|
569
|
|
|
"Climate Year",
|
570
|
|
|
"Simulation_ID",
|
571
|
|
|
"Node 1",
|
572
|
|
|
"Path",
|
573
|
|
|
"Direct/Indirect",
|
574
|
|
|
"Sector",
|
575
|
|
|
"Note",
|
576
|
|
|
"Category",
|
577
|
|
|
"Case",
|
578
|
|
|
"Scenario",
|
579
|
|
|
]
|
580
|
|
|
)
|
581
|
|
|
.set_index("Node/Line")
|
582
|
|
|
)
|
583
|
|
|
|
584
|
|
|
df_2030 = (
|
585
|
|
|
df[(df["Parameter"] == "Final demand") & (df["Year"] == 2030)]
|
586
|
|
|
.rename(columns={"Value": "Value_2030"})
|
587
|
|
|
.drop(columns=["Parameter", "Year"])
|
588
|
|
|
)
|
589
|
|
|
|
590
|
|
|
df_2040 = (
|
591
|
|
|
df[(df["Parameter"] == "Final demand") & (df["Year"] == 2040)]
|
592
|
|
|
.rename(columns={"Value": "Value_2040"})
|
593
|
|
|
.drop(columns=["Parameter", "Year"])
|
594
|
|
|
)
|
595
|
|
|
|
596
|
|
|
# Conversion GWh/d to MWh/h
|
597
|
|
|
conversion_factor = 1000 / 24
|
598
|
|
|
|
599
|
|
|
df_2035 = pd.concat([df_2040, df_2030], axis=1)
|
600
|
|
|
df_2035["GlobD_2035"] = (
|
601
|
|
|
(df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
|
602
|
|
|
) * conversion_factor
|
603
|
|
|
df_2035.loc["NOS0"] = [
|
604
|
|
|
0,
|
605
|
|
|
0,
|
606
|
|
|
Norway_global_demand_1y / 8760,
|
607
|
|
|
] # Manually add Norway demand
|
608
|
|
|
grouped_demands = df_2035.drop(
|
609
|
|
|
columns=["Value_2030", "Value_2040"]
|
610
|
|
|
).reset_index()
|
611
|
|
|
|
612
|
|
|
# choose demands for considered countries
|
613
|
|
|
return grouped_demands[
|
614
|
|
|
grouped_demands["Node/Line"].str[:2].isin(countries)
|
615
|
|
|
]
|
616
|
|
|
|
617
|
|
|
|
618
|
|
|
def import_ch4_demandTS():
|
619
|
|
|
"""Calculate global CH4 demand in Norway and CH4 demand profile
|
620
|
|
|
|
621
|
|
|
Import from the PyPSA-eur-sec run the timeseries of residential
|
622
|
|
|
rural heat per neighbor country. This timeserie is used to
|
623
|
|
|
calculate:
|
624
|
|
|
* the global (yearly) heat demand of Norway
|
625
|
|
|
(that will be supplied by CH4)
|
626
|
|
|
* the normalized CH4 hourly resolved demand profile
|
627
|
|
|
|
628
|
|
|
Parameters
|
629
|
|
|
----------
|
630
|
|
|
None.
|
631
|
|
|
|
632
|
|
|
Returns
|
633
|
|
|
-------
|
634
|
|
|
Norway_global_demand: Float
|
635
|
|
|
Yearly heat demand of Norway in MWh
|
636
|
|
|
neighbor_loads_t: pandas.DataFrame
|
637
|
|
|
Normalized CH4 hourly resolved demand profiles per neighbor country
|
638
|
|
|
|
639
|
|
|
"""
|
640
|
|
|
|
641
|
|
|
cwd = Path(".")
|
642
|
|
|
target_file = (
|
643
|
|
|
cwd
|
644
|
|
|
/ "data_bundle_egon_data"
|
645
|
|
|
/ "pypsa_eur_sec"
|
646
|
|
|
/ "2022-07-26-egondata-integration"
|
647
|
|
|
/ "postnetworks"
|
648
|
|
|
/ "elec_s_37_lv2.0__Co2L0-1H-T-H-B-I-dist1_2050.nc"
|
649
|
|
|
)
|
650
|
|
|
|
651
|
|
|
network = pypsa.Network(str(target_file))
|
652
|
|
|
|
653
|
|
|
# Set country tag for all buses
|
654
|
|
|
network.buses.country = network.buses.index.str[:2]
|
655
|
|
|
neighbors = network.buses[network.buses.country != "DE"]
|
656
|
|
|
neighbors = neighbors[
|
657
|
|
|
(neighbors["country"].isin(countries))
|
658
|
|
|
& (neighbors["carrier"] == "residential rural heat")
|
659
|
|
|
].drop_duplicates(subset="country")
|
660
|
|
|
|
661
|
|
|
neighbor_loads = network.loads[network.loads.bus.isin(neighbors.index)]
|
662
|
|
|
neighbor_loads_t_index = neighbor_loads.index[
|
663
|
|
|
neighbor_loads.index.isin(network.loads_t.p_set.columns)
|
664
|
|
|
]
|
665
|
|
|
neighbor_loads_t = network.loads_t["p_set"][neighbor_loads_t_index]
|
666
|
|
|
Norway_global_demand = neighbor_loads_t[
|
667
|
|
|
"NO3 0 residential rural heat"
|
668
|
|
|
].sum()
|
669
|
|
|
|
670
|
|
|
for i in neighbor_loads_t.columns:
|
671
|
|
|
neighbor_loads_t[i] = neighbor_loads_t[i] / neighbor_loads_t[i].sum()
|
672
|
|
|
|
673
|
|
|
return Norway_global_demand, neighbor_loads_t
|
674
|
|
|
|
675
|
|
|
|
676
|
|
|
def insert_ch4_demand(global_demand, normalized_ch4_demandTS):
|
677
|
|
|
"""Insert CH4 demands abroad in the database for eGon2035
|
678
|
|
|
|
679
|
|
|
Parameters
|
680
|
|
|
----------
|
681
|
|
|
global_demand : pandas.DataFrame
|
682
|
|
|
Global CH4 demand per foreign node in 1 year
|
683
|
|
|
gas_demandTS : pandas.DataFrame
|
684
|
|
|
Normalized time serie of the demand per foreign country
|
685
|
|
|
|
686
|
|
|
Returns
|
687
|
|
|
-------
|
688
|
|
|
None.
|
689
|
|
|
|
690
|
|
|
"""
|
691
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
692
|
|
|
targets = config.datasets()["gas_neighbours"]["targets"]
|
693
|
|
|
map_buses = get_map_buses()
|
694
|
|
|
|
695
|
|
|
scn_name = "eGon2035"
|
696
|
|
|
carrier = "CH4"
|
697
|
|
|
|
698
|
|
|
# Delete existing data
|
699
|
|
|
db.execute_sql(
|
700
|
|
|
f"""
|
701
|
|
|
DELETE FROM
|
702
|
|
|
{targets['load_timeseries']['schema']}.{targets['load_timeseries']['table']}
|
703
|
|
|
WHERE "load_id" IN (
|
704
|
|
|
SELECT load_id FROM
|
705
|
|
|
{targets['loads']['schema']}.{targets['loads']['table']}
|
706
|
|
|
WHERE bus IN (
|
707
|
|
|
SELECT bus_id FROM
|
708
|
|
|
{sources['buses']['schema']}.{sources['buses']['table']}
|
709
|
|
|
WHERE country != 'DE'
|
710
|
|
|
AND scn_name = '{scn_name}')
|
711
|
|
|
AND scn_name = '{scn_name}'
|
712
|
|
|
AND carrier = '{carrier}'
|
713
|
|
|
);
|
714
|
|
|
"""
|
715
|
|
|
)
|
716
|
|
|
|
717
|
|
|
db.execute_sql(
|
718
|
|
|
f"""
|
719
|
|
|
DELETE FROM
|
720
|
|
|
{targets['loads']['schema']}.{targets['loads']['table']}
|
721
|
|
|
WHERE bus IN (
|
722
|
|
|
SELECT bus_id FROM
|
723
|
|
|
{sources['buses']['schema']}.{sources['buses']['table']}
|
724
|
|
|
WHERE country != 'DE'
|
725
|
|
|
AND scn_name = '{scn_name}')
|
726
|
|
|
AND scn_name = '{scn_name}'
|
727
|
|
|
AND carrier = '{carrier}'
|
728
|
|
|
"""
|
729
|
|
|
)
|
730
|
|
|
|
731
|
|
|
# Set bus_id
|
732
|
|
|
global_demand.loc[
|
733
|
|
|
global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
|
734
|
|
|
"Node/Line",
|
735
|
|
|
] = global_demand.loc[
|
736
|
|
|
global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
|
737
|
|
|
"Node/Line",
|
738
|
|
|
].map(
|
739
|
|
|
map_buses
|
740
|
|
|
)
|
741
|
|
|
global_demand.loc[:, "bus"] = (
|
742
|
|
|
get_foreign_gas_bus_id().loc[global_demand.loc[:, "Node/Line"]].values
|
743
|
|
|
)
|
744
|
|
|
|
745
|
|
|
# Add missing columns
|
746
|
|
|
c = {"scn_name": scn_name, "carrier": carrier}
|
747
|
|
|
global_demand = global_demand.assign(**c)
|
748
|
|
|
|
749
|
|
|
new_id = db.next_etrago_id("load")
|
750
|
|
|
global_demand["load_id"] = range(new_id, new_id + len(global_demand))
|
751
|
|
|
|
752
|
|
|
ch4_demand_TS = global_demand.copy()
|
753
|
|
|
# Remove useless columns
|
754
|
|
|
global_demand = global_demand.drop(columns=["Node/Line", "GlobD_2035"])
|
755
|
|
|
|
756
|
|
|
# Insert data to db
|
757
|
|
|
global_demand.to_sql(
|
758
|
|
|
targets["loads"]["table"],
|
759
|
|
|
db.engine(),
|
760
|
|
|
schema=targets["loads"]["schema"],
|
761
|
|
|
index=False,
|
762
|
|
|
if_exists="append",
|
763
|
|
|
)
|
764
|
|
|
|
765
|
|
|
# Insert time series
|
766
|
|
|
ch4_demand_TS["Node/Line"] = ch4_demand_TS["Node/Line"].replace(
|
767
|
|
|
["UK00"], "GB"
|
768
|
|
|
)
|
769
|
|
|
|
770
|
|
|
p_set = []
|
771
|
|
|
for index, row in ch4_demand_TS.iterrows():
|
772
|
|
|
normalized_TS_df = normalized_ch4_demandTS.loc[
|
773
|
|
|
:,
|
774
|
|
|
normalized_ch4_demandTS.columns.str.contains(row["Node/Line"][:2]),
|
775
|
|
|
]
|
776
|
|
|
p_set.append(
|
777
|
|
|
(
|
778
|
|
|
normalized_TS_df[normalized_TS_df.columns[0]]
|
779
|
|
|
* row["GlobD_2035"]
|
780
|
|
|
).tolist()
|
781
|
|
|
)
|
782
|
|
|
|
783
|
|
|
ch4_demand_TS["p_set"] = p_set
|
784
|
|
|
ch4_demand_TS["temp_id"] = 1
|
785
|
|
|
ch4_demand_TS = ch4_demand_TS.drop(
|
786
|
|
|
columns=["Node/Line", "GlobD_2035", "bus", "carrier"]
|
787
|
|
|
)
|
788
|
|
|
|
789
|
|
|
# Insert data to DB
|
790
|
|
|
ch4_demand_TS.to_sql(
|
791
|
|
|
targets["load_timeseries"]["table"],
|
792
|
|
|
db.engine(),
|
793
|
|
|
schema=targets["load_timeseries"]["schema"],
|
794
|
|
|
index=False,
|
795
|
|
|
if_exists="append",
|
796
|
|
|
)
|
797
|
|
|
|
798
|
|
|
|
799
|
|
|
def calc_ch4_storage_capacities():
|
800
|
|
|
target_file = (
|
801
|
|
|
Path(".") / "datasets" / "gas_data" / "data" / "IGGIELGN_Storages.csv"
|
802
|
|
|
)
|
803
|
|
|
|
804
|
|
|
ch4_storage_capacities = pd.read_csv(
|
805
|
|
|
target_file,
|
806
|
|
|
delimiter=";",
|
807
|
|
|
decimal=".",
|
808
|
|
|
usecols=["country_code", "param"],
|
809
|
|
|
)
|
810
|
|
|
|
811
|
|
|
ch4_storage_capacities = ch4_storage_capacities[
|
812
|
|
|
ch4_storage_capacities["country_code"].isin(countries)
|
813
|
|
|
]
|
814
|
|
|
|
815
|
|
|
map_countries_scigrid = {
|
816
|
|
|
"AT": "AT00",
|
817
|
|
|
"BE": "BE00",
|
818
|
|
|
"CZ": "CZ00",
|
819
|
|
|
"DK": "DKE1",
|
820
|
|
|
"EE": "EE00",
|
821
|
|
|
"EL": "GR00",
|
822
|
|
|
"ES": "ES00",
|
823
|
|
|
"FI": "FI00",
|
824
|
|
|
"FR": "FR00",
|
825
|
|
|
"GB": "UK00",
|
826
|
|
|
"IT": "ITCN",
|
827
|
|
|
"LT": "LT00",
|
828
|
|
|
"LV": "LV00",
|
829
|
|
|
"MT": "MT00",
|
830
|
|
|
"NL": "NL00",
|
831
|
|
|
"PL": "PL00",
|
832
|
|
|
"PT": "PT00",
|
833
|
|
|
"SE": "SE01",
|
834
|
|
|
}
|
835
|
|
|
|
836
|
|
|
# Define new columns
|
837
|
|
|
max_workingGas_M_m3 = []
|
838
|
|
|
end_year = []
|
839
|
|
|
|
840
|
|
|
for index, row in ch4_storage_capacities.iterrows():
|
841
|
|
|
param = ast.literal_eval(row["param"])
|
842
|
|
|
end_year.append(param["end_year"])
|
843
|
|
|
max_workingGas_M_m3.append(param["max_workingGas_M_m3"])
|
844
|
|
|
|
845
|
|
|
end_year = [float("inf") if x is None else x for x in end_year]
|
846
|
|
|
ch4_storage_capacities = ch4_storage_capacities.assign(end_year=end_year)
|
847
|
|
|
ch4_storage_capacities = ch4_storage_capacities[
|
848
|
|
|
ch4_storage_capacities["end_year"] >= 2035
|
849
|
|
|
]
|
850
|
|
|
|
851
|
|
|
# Calculate e_nom
|
852
|
|
|
conv_factor = (
|
853
|
|
|
10830 # M_m3 to MWh - gross calorific value = 39 MJ/m3 (eurogas.org)
|
854
|
|
|
)
|
855
|
|
|
ch4_storage_capacities["e_nom"] = [
|
856
|
|
|
conv_factor * i for i in max_workingGas_M_m3
|
857
|
|
|
]
|
858
|
|
|
|
859
|
|
|
ch4_storage_capacities.drop(
|
860
|
|
|
["param", "end_year"],
|
861
|
|
|
axis=1,
|
862
|
|
|
inplace=True,
|
863
|
|
|
)
|
864
|
|
|
|
865
|
|
|
ch4_storage_capacities["Country"] = ch4_storage_capacities[
|
866
|
|
|
"country_code"
|
867
|
|
|
].map(map_countries_scigrid)
|
868
|
|
|
ch4_storage_capacities = ch4_storage_capacities.groupby(
|
869
|
|
|
["country_code"]
|
870
|
|
|
).agg(
|
871
|
|
|
{
|
872
|
|
|
"e_nom": "sum",
|
873
|
|
|
"Country": "first",
|
874
|
|
|
},
|
875
|
|
|
)
|
876
|
|
|
|
877
|
|
|
ch4_storage_capacities = ch4_storage_capacities.drop(["RU"])
|
878
|
|
|
ch4_storage_capacities.loc[:, "bus"] = (
|
879
|
|
|
get_foreign_gas_bus_id()
|
880
|
|
|
.loc[ch4_storage_capacities.loc[:, "Country"]]
|
881
|
|
|
.values
|
882
|
|
|
)
|
883
|
|
|
|
884
|
|
|
return ch4_storage_capacities
|
885
|
|
|
|
886
|
|
|
|
887
|
|
|
def insert_storage(ch4_storage_capacities):
|
888
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
889
|
|
|
targets = config.datasets()["gas_neighbours"]["targets"]
|
890
|
|
|
|
891
|
|
|
# Clean table
|
892
|
|
|
db.execute_sql(
|
893
|
|
|
f"""
|
894
|
|
|
DELETE FROM {targets['stores']['schema']}.{targets['stores']['table']}
|
895
|
|
|
WHERE "carrier" = 'CH4'
|
896
|
|
|
AND scn_name = 'eGon2035'
|
897
|
|
|
AND bus IN (
|
898
|
|
|
SELECT bus_id
|
899
|
|
|
FROM {sources['buses']['schema']}.{sources['buses']['table']}
|
900
|
|
|
WHERE scn_name = 'eGon2035'
|
901
|
|
|
AND country != 'DE'
|
902
|
|
|
);
|
903
|
|
|
"""
|
904
|
|
|
)
|
905
|
|
|
# Add missing columns
|
906
|
|
|
c = {"scn_name": "eGon2035", "carrier": "CH4"}
|
907
|
|
|
ch4_storage_capacities = ch4_storage_capacities.assign(**c)
|
908
|
|
|
|
909
|
|
|
new_id = db.next_etrago_id("store")
|
910
|
|
|
ch4_storage_capacities["store_id"] = range(
|
911
|
|
|
new_id, new_id + len(ch4_storage_capacities)
|
912
|
|
|
)
|
913
|
|
|
|
914
|
|
|
ch4_storage_capacities.drop(
|
915
|
|
|
["Country"],
|
916
|
|
|
axis=1,
|
917
|
|
|
inplace=True,
|
918
|
|
|
)
|
919
|
|
|
|
920
|
|
|
ch4_storage_capacities = ch4_storage_capacities.reset_index(drop=True)
|
921
|
|
|
# Insert data to db
|
922
|
|
|
ch4_storage_capacities.to_sql(
|
923
|
|
|
targets["stores"]["table"],
|
924
|
|
|
db.engine(),
|
925
|
|
|
schema=targets["stores"]["schema"],
|
926
|
|
|
index=False,
|
927
|
|
|
if_exists="append",
|
928
|
|
|
)
|
929
|
|
|
|
930
|
|
|
|
931
|
|
|
def calc_global_power_to_h2_demand():
|
932
|
|
|
"""Calculates H2 demand abroad for eGon2035 scenario
|
933
|
|
|
|
934
|
|
|
Calculates global power demand abroad linked to H2 production.
|
935
|
|
|
The data comes from TYNDP 2020 according to NEP 2021 from the
|
936
|
|
|
scenario 'Distributed Energy', linear interpolate between 2030
|
937
|
|
|
and 2040.
|
938
|
|
|
|
939
|
|
|
Returns
|
940
|
|
|
-------
|
941
|
|
|
pandas.DataFrame
|
942
|
|
|
Global power-to-h2 demand per foreign node
|
943
|
|
|
|
944
|
|
|
"""
|
945
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
946
|
|
|
|
947
|
|
|
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
|
948
|
|
|
df = pd.read_excel(
|
949
|
|
|
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
|
950
|
|
|
sheet_name="Gas Data",
|
951
|
|
|
)
|
952
|
|
|
|
953
|
|
|
df = (
|
954
|
|
|
df.query(
|
955
|
|
|
'Scenario == "Distributed Energy" & '
|
956
|
|
|
'Case == "Average" &'
|
957
|
|
|
'Parameter == "P2H2"'
|
958
|
|
|
)
|
959
|
|
|
.drop(
|
960
|
|
|
columns=[
|
961
|
|
|
"Generator_ID",
|
962
|
|
|
"Climate Year",
|
963
|
|
|
"Simulation_ID",
|
964
|
|
|
"Node 1",
|
965
|
|
|
"Path",
|
966
|
|
|
"Direct/Indirect",
|
967
|
|
|
"Sector",
|
968
|
|
|
"Note",
|
969
|
|
|
"Category",
|
970
|
|
|
"Case",
|
971
|
|
|
"Scenario",
|
972
|
|
|
"Parameter",
|
973
|
|
|
]
|
974
|
|
|
)
|
975
|
|
|
.set_index("Node/Line")
|
976
|
|
|
)
|
977
|
|
|
|
978
|
|
|
df_2030 = (
|
979
|
|
|
df[df["Year"] == 2030]
|
980
|
|
|
.rename(columns={"Value": "Value_2030"})
|
981
|
|
|
.drop(columns=["Year"])
|
982
|
|
|
)
|
983
|
|
|
df_2040 = (
|
984
|
|
|
df[df["Year"] == 2040]
|
985
|
|
|
.rename(columns={"Value": "Value_2040"})
|
986
|
|
|
.drop(columns=["Year"])
|
987
|
|
|
)
|
988
|
|
|
|
989
|
|
|
# Conversion GWh/d to MWh/h
|
990
|
|
|
conversion_factor = 1000 / 24
|
991
|
|
|
|
992
|
|
|
df_2035 = pd.concat([df_2040, df_2030], axis=1)
|
993
|
|
|
df_2035["GlobD_2035"] = (
|
994
|
|
|
(df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
|
995
|
|
|
) * conversion_factor
|
996
|
|
|
|
997
|
|
|
global_power_to_h2_demand = df_2035.drop(
|
998
|
|
|
columns=["Value_2030", "Value_2040"]
|
999
|
|
|
)
|
1000
|
|
|
|
1001
|
|
|
# choose demands for considered countries
|
1002
|
|
|
global_power_to_h2_demand = global_power_to_h2_demand[
|
1003
|
|
|
(global_power_to_h2_demand.index.str[:2].isin(countries))
|
1004
|
|
|
& (global_power_to_h2_demand["GlobD_2035"] != 0)
|
1005
|
|
|
]
|
1006
|
|
|
|
1007
|
|
|
# Split in two the demands for DK and UK
|
1008
|
|
|
global_power_to_h2_demand.loc["DKW1"] = (
|
1009
|
|
|
global_power_to_h2_demand.loc["DKE1"] / 2
|
1010
|
|
|
)
|
1011
|
|
|
global_power_to_h2_demand.loc["DKE1"] = (
|
1012
|
|
|
global_power_to_h2_demand.loc["DKE1"] / 2
|
1013
|
|
|
)
|
1014
|
|
|
global_power_to_h2_demand.loc["UKNI"] = (
|
1015
|
|
|
global_power_to_h2_demand.loc["UK00"] / 2
|
1016
|
|
|
)
|
1017
|
|
|
global_power_to_h2_demand.loc["UK00"] = (
|
1018
|
|
|
global_power_to_h2_demand.loc["UK00"] / 2
|
1019
|
|
|
)
|
1020
|
|
|
global_power_to_h2_demand = global_power_to_h2_demand.reset_index()
|
1021
|
|
|
|
1022
|
|
|
return global_power_to_h2_demand
|
1023
|
|
|
|
1024
|
|
|
|
1025
|
|
|
def insert_power_to_h2_demand(global_power_to_h2_demand):
|
1026
|
|
|
"""Insert H2 demands into database for eGon2035
|
1027
|
|
|
|
1028
|
|
|
Detailled description
|
1029
|
|
|
This function insert data in the database and has no return.
|
1030
|
|
|
|
1031
|
|
|
Parameters
|
1032
|
|
|
----------
|
1033
|
|
|
global_power_to_h2_demand : pandas.DataFrame
|
1034
|
|
|
Global H2 demand per foreign node in 1 year
|
1035
|
|
|
|
1036
|
|
|
"""
|
1037
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
1038
|
|
|
targets = config.datasets()["gas_neighbours"]["targets"]
|
1039
|
|
|
map_buses = get_map_buses()
|
1040
|
|
|
|
1041
|
|
|
scn_name = "eGon2035"
|
1042
|
|
|
carrier = "H2_for_industry"
|
1043
|
|
|
|
1044
|
|
|
db.execute_sql(
|
1045
|
|
|
f"""
|
1046
|
|
|
DELETE FROM
|
1047
|
|
|
{targets['loads']['schema']}.{targets['loads']['table']}
|
1048
|
|
|
WHERE bus IN (
|
1049
|
|
|
SELECT bus_id FROM
|
1050
|
|
|
{sources['buses']['schema']}.{sources['buses']['table']}
|
1051
|
|
|
WHERE country != 'DE'
|
1052
|
|
|
AND scn_name = '{scn_name}')
|
1053
|
|
|
AND scn_name = '{scn_name}'
|
1054
|
|
|
AND carrier = '{carrier}'
|
1055
|
|
|
"""
|
1056
|
|
|
)
|
1057
|
|
|
|
1058
|
|
|
# Set bus_id
|
1059
|
|
|
global_power_to_h2_demand.loc[
|
1060
|
|
|
global_power_to_h2_demand[
|
1061
|
|
|
global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
|
1062
|
|
|
].index,
|
1063
|
|
|
"Node/Line",
|
1064
|
|
|
] = global_power_to_h2_demand.loc[
|
1065
|
|
|
global_power_to_h2_demand[
|
1066
|
|
|
global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
|
1067
|
|
|
].index,
|
1068
|
|
|
"Node/Line",
|
1069
|
|
|
].map(
|
1070
|
|
|
map_buses
|
1071
|
|
|
)
|
1072
|
|
|
global_power_to_h2_demand.loc[:, "bus"] = (
|
1073
|
|
|
get_foreign_bus_id()
|
1074
|
|
|
.loc[global_power_to_h2_demand.loc[:, "Node/Line"]]
|
1075
|
|
|
.values
|
1076
|
|
|
)
|
1077
|
|
|
|
1078
|
|
|
# Add missing columns
|
1079
|
|
|
c = {"scn_name": scn_name, "carrier": carrier}
|
1080
|
|
|
global_power_to_h2_demand = global_power_to_h2_demand.assign(**c)
|
1081
|
|
|
|
1082
|
|
|
new_id = db.next_etrago_id("load")
|
1083
|
|
|
global_power_to_h2_demand["load_id"] = range(
|
1084
|
|
|
new_id, new_id + len(global_power_to_h2_demand)
|
1085
|
|
|
)
|
1086
|
|
|
|
1087
|
|
|
global_power_to_h2_demand = global_power_to_h2_demand.rename(
|
1088
|
|
|
columns={"GlobD_2035": "p_set"}
|
1089
|
|
|
)
|
1090
|
|
|
|
1091
|
|
|
# Remove useless columns
|
1092
|
|
|
global_power_to_h2_demand = global_power_to_h2_demand.drop(
|
1093
|
|
|
columns=["Node/Line"]
|
1094
|
|
|
)
|
1095
|
|
|
|
1096
|
|
|
# Insert data to db
|
1097
|
|
|
global_power_to_h2_demand.to_sql(
|
1098
|
|
|
targets["loads"]["table"],
|
1099
|
|
|
db.engine(),
|
1100
|
|
|
schema=targets["loads"]["schema"],
|
1101
|
|
|
index=False,
|
1102
|
|
|
if_exists="append",
|
1103
|
|
|
)
|
1104
|
|
|
|
1105
|
|
|
|
1106
|
|
|
def calculate_ch4_grid_capacities():
|
1107
|
|
|
"""Calculates CH4 grid capacities for foreign countries based on TYNDP-data
|
1108
|
|
|
|
1109
|
|
|
Parameters
|
1110
|
|
|
----------
|
1111
|
|
|
None.
|
1112
|
|
|
|
1113
|
|
|
Returns
|
1114
|
|
|
-------
|
1115
|
|
|
Neighbouring_pipe_capacities_list : pandas.DataFrame
|
1116
|
|
|
|
1117
|
|
|
"""
|
1118
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
1119
|
|
|
|
1120
|
|
|
# Download file
|
1121
|
|
|
basename = "ENTSOG_TYNDP_2020_Annex_C2_Capacities_per_country.xlsx"
|
1122
|
|
|
url = "https://www.entsog.eu/sites/default/files/2021-07/" + basename
|
1123
|
|
|
target_file = Path(".") / "datasets" / "gas_data" / basename
|
1124
|
|
|
|
1125
|
|
|
urlretrieve(url, target_file)
|
1126
|
|
|
map_pipelines = {
|
1127
|
|
|
"NORDSTREAM": "RU00",
|
1128
|
|
|
"NORDSTREAM 2": "RU00",
|
1129
|
|
|
"OPAL": "DE",
|
1130
|
|
|
"YAMAL (BY)": "RU00",
|
1131
|
|
|
"Denmark": "DKE1",
|
1132
|
|
|
"Belgium": "BE00",
|
1133
|
|
|
"Netherlands": "NL00",
|
1134
|
|
|
"Norway": "NOM1",
|
1135
|
|
|
"Switzerland": "CH00",
|
1136
|
|
|
"Poland": "PL00",
|
1137
|
|
|
"United Kingdom": "UK00",
|
1138
|
|
|
"Germany": "DE",
|
1139
|
|
|
"Austria": "AT00",
|
1140
|
|
|
"France": "FR00",
|
1141
|
|
|
"Czechia": "CZ00",
|
1142
|
|
|
"Russia": "RU00",
|
1143
|
|
|
"Luxemburg": "LUB1",
|
1144
|
|
|
}
|
1145
|
|
|
|
1146
|
|
|
grid_countries = [
|
1147
|
|
|
"NORDSTREAM",
|
1148
|
|
|
"NORDSTREAM 2",
|
1149
|
|
|
"OPAL",
|
1150
|
|
|
"YAMAL (BY)",
|
1151
|
|
|
"Denmark",
|
1152
|
|
|
"Belgium",
|
1153
|
|
|
"Netherlands",
|
1154
|
|
|
"Norway",
|
1155
|
|
|
"Switzerland",
|
1156
|
|
|
"Poland",
|
1157
|
|
|
"United Kingdom",
|
1158
|
|
|
"Germany",
|
1159
|
|
|
"Austria",
|
1160
|
|
|
"France",
|
1161
|
|
|
"Czechia",
|
1162
|
|
|
"Russia",
|
1163
|
|
|
"Luxemburg",
|
1164
|
|
|
]
|
1165
|
|
|
|
1166
|
|
|
# Read-in data from csv-file
|
1167
|
|
|
pipe_capacities_list = pd.read_excel(
|
1168
|
|
|
target_file,
|
1169
|
|
|
sheet_name="Transmission Peak Capacity",
|
1170
|
|
|
skiprows=range(4),
|
1171
|
|
|
)
|
1172
|
|
|
pipe_capacities_list = pipe_capacities_list[
|
1173
|
|
|
["To Country", "Unnamed: 3", "From Country", 2035]
|
1174
|
|
|
].rename(
|
1175
|
|
|
columns={
|
1176
|
|
|
"Unnamed: 3": "Scenario",
|
1177
|
|
|
"To Country": "To_Country",
|
1178
|
|
|
"From Country": "From_Country",
|
1179
|
|
|
}
|
1180
|
|
|
)
|
1181
|
|
|
pipe_capacities_list["To_Country"] = pd.Series(
|
1182
|
|
|
pipe_capacities_list["To_Country"]
|
1183
|
|
|
).fillna(method="ffill")
|
1184
|
|
|
pipe_capacities_list["From_Country"] = pd.Series(
|
1185
|
|
|
pipe_capacities_list["From_Country"]
|
1186
|
|
|
).fillna(method="ffill")
|
1187
|
|
|
pipe_capacities_list = pipe_capacities_list[
|
1188
|
|
|
pipe_capacities_list["Scenario"] == "Advanced"
|
1189
|
|
|
].drop(columns={"Scenario"})
|
1190
|
|
|
pipe_capacities_list = pipe_capacities_list[
|
1191
|
|
|
(
|
1192
|
|
|
(pipe_capacities_list["To_Country"].isin(grid_countries))
|
1193
|
|
|
& (pipe_capacities_list["From_Country"].isin(grid_countries))
|
1194
|
|
|
)
|
1195
|
|
|
& (pipe_capacities_list[2035] != 0)
|
1196
|
|
|
]
|
1197
|
|
|
pipe_capacities_list["To_Country"] = pipe_capacities_list[
|
1198
|
|
|
"To_Country"
|
1199
|
|
|
].map(map_pipelines)
|
1200
|
|
|
pipe_capacities_list["From_Country"] = pipe_capacities_list[
|
1201
|
|
|
"From_Country"
|
1202
|
|
|
].map(map_pipelines)
|
1203
|
|
|
pipe_capacities_list["countrycombination"] = pipe_capacities_list[
|
1204
|
|
|
["To_Country", "From_Country"]
|
1205
|
|
|
].apply(
|
1206
|
|
|
lambda x: tuple(sorted([str(x.To_Country), str(x.From_Country)])),
|
1207
|
|
|
axis=1,
|
1208
|
|
|
)
|
1209
|
|
|
|
1210
|
|
|
pipeline_strategies = {
|
1211
|
|
|
"To_Country": "first",
|
1212
|
|
|
"From_Country": "first",
|
1213
|
|
|
2035: sum,
|
1214
|
|
|
}
|
1215
|
|
|
|
1216
|
|
|
pipe_capacities_list = pipe_capacities_list.groupby(
|
1217
|
|
|
["countrycombination"]
|
1218
|
|
|
).agg(pipeline_strategies)
|
1219
|
|
|
|
1220
|
|
|
# Add manually DK-SE and AT-CH pipes (Scigrid gas data)
|
1221
|
|
|
pipe_capacities_list.loc["(DKE1, SE02)"] = ["DKE1", "SE02", 651]
|
1222
|
|
|
pipe_capacities_list.loc["(AT00, CH00)"] = ["AT00", "CH00", 651]
|
1223
|
|
|
|
1224
|
|
|
# Conversion GWh/d to MWh/h
|
1225
|
|
|
pipe_capacities_list["p_nom"] = pipe_capacities_list[2035] * (1000 / 24)
|
1226
|
|
|
|
1227
|
|
|
# Border crossing CH4 pipelines between foreign countries
|
1228
|
|
|
|
1229
|
|
|
Neighbouring_pipe_capacities_list = pipe_capacities_list[
|
1230
|
|
|
(pipe_capacities_list["To_Country"] != "DE")
|
1231
|
|
|
& (pipe_capacities_list["From_Country"] != "DE")
|
1232
|
|
|
].reset_index()
|
1233
|
|
|
|
1234
|
|
|
Neighbouring_pipe_capacities_list.loc[:, "bus0"] = (
|
1235
|
|
|
get_foreign_gas_bus_id()
|
1236
|
|
|
.loc[Neighbouring_pipe_capacities_list.loc[:, "To_Country"]]
|
1237
|
|
|
.values
|
1238
|
|
|
)
|
1239
|
|
|
Neighbouring_pipe_capacities_list.loc[:, "bus1"] = (
|
1240
|
|
|
get_foreign_gas_bus_id()
|
1241
|
|
|
.loc[Neighbouring_pipe_capacities_list.loc[:, "From_Country"]]
|
1242
|
|
|
.values
|
1243
|
|
|
)
|
1244
|
|
|
|
1245
|
|
|
# Adjust columns
|
1246
|
|
|
Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
|
1247
|
|
|
columns=[
|
1248
|
|
|
"To_Country",
|
1249
|
|
|
"From_Country",
|
1250
|
|
|
"countrycombination",
|
1251
|
|
|
2035,
|
1252
|
|
|
]
|
1253
|
|
|
)
|
1254
|
|
|
|
1255
|
|
|
new_id = db.next_etrago_id("link")
|
1256
|
|
|
Neighbouring_pipe_capacities_list["link_id"] = range(
|
1257
|
|
|
new_id, new_id + len(Neighbouring_pipe_capacities_list)
|
1258
|
|
|
)
|
1259
|
|
|
|
1260
|
|
|
# Border crossing CH4 pipelines between DE and neighbouring countries
|
1261
|
|
|
DE_pipe_capacities_list = pipe_capacities_list[
|
1262
|
|
|
(pipe_capacities_list["To_Country"] == "DE")
|
1263
|
|
|
| (pipe_capacities_list["From_Country"] == "DE")
|
1264
|
|
|
].reset_index()
|
1265
|
|
|
|
1266
|
|
|
dict_cross_pipes_DE = {
|
1267
|
|
|
("AT00", "DE"): "AT",
|
1268
|
|
|
("BE00", "DE"): "BE",
|
1269
|
|
|
("CH00", "DE"): "CH",
|
1270
|
|
|
("CZ00", "DE"): "CZ",
|
1271
|
|
|
("DE", "DKE1"): "DK",
|
1272
|
|
|
("DE", "FR00"): "FR",
|
1273
|
|
|
("DE", "LUB1"): "LU",
|
1274
|
|
|
("DE", "NL00"): "NL",
|
1275
|
|
|
("DE", "NOM1"): "NO",
|
1276
|
|
|
("DE", "PL00"): "PL",
|
1277
|
|
|
("DE", "RU00"): "RU",
|
1278
|
|
|
}
|
1279
|
|
|
|
1280
|
|
|
DE_pipe_capacities_list["country_code"] = DE_pipe_capacities_list[
|
1281
|
|
|
"countrycombination"
|
1282
|
|
|
].map(dict_cross_pipes_DE)
|
1283
|
|
|
DE_pipe_capacities_list = DE_pipe_capacities_list.set_index("country_code")
|
1284
|
|
|
|
1285
|
|
|
schema = sources["buses"]["schema"]
|
1286
|
|
|
table = sources["buses"]["table"]
|
1287
|
|
|
for country_code in [e for e in countries if e not in ("GB", "SE", "UK")]:
|
1288
|
|
|
|
1289
|
|
|
# Select cross-bording links
|
1290
|
|
|
cap_DE = db.select_dataframe(
|
1291
|
|
|
f"""SELECT link_id, bus0, bus1
|
1292
|
|
|
FROM {sources['links']['schema']}.{sources['links']['table']}
|
1293
|
|
|
WHERE scn_name = 'eGon2035'
|
1294
|
|
|
AND carrier = 'CH4'
|
1295
|
|
|
AND (("bus0" IN (
|
1296
|
|
|
SELECT bus_id FROM {schema}.{table}
|
1297
|
|
|
WHERE country = 'DE'
|
1298
|
|
|
AND carrier = 'CH4'
|
1299
|
|
|
AND scn_name = 'eGon2035')
|
1300
|
|
|
AND "bus1" IN (SELECT bus_id FROM {schema}.{table}
|
1301
|
|
|
WHERE country = '{country_code}'
|
1302
|
|
|
AND carrier = 'CH4'
|
1303
|
|
|
AND scn_name = 'eGon2035')
|
1304
|
|
|
)
|
1305
|
|
|
OR ("bus0" IN (
|
1306
|
|
|
SELECT bus_id FROM {schema}.{table}
|
1307
|
|
|
WHERE country = '{country_code}'
|
1308
|
|
|
AND carrier = 'CH4'
|
1309
|
|
|
AND scn_name = 'eGon2035')
|
1310
|
|
|
AND "bus1" IN (SELECT bus_id FROM {schema}.{table}
|
1311
|
|
|
WHERE country = 'DE'
|
1312
|
|
|
AND carrier = 'CH4'
|
1313
|
|
|
AND scn_name = 'eGon2035'))
|
1314
|
|
|
)
|
1315
|
|
|
;"""
|
1316
|
|
|
)
|
1317
|
|
|
|
1318
|
|
|
cap_DE["p_nom"] = DE_pipe_capacities_list.at[
|
1319
|
|
|
country_code, "p_nom"
|
1320
|
|
|
] / len(cap_DE.index)
|
1321
|
|
|
Neighbouring_pipe_capacities_list = (
|
1322
|
|
|
Neighbouring_pipe_capacities_list.append(cap_DE)
|
1323
|
|
|
)
|
1324
|
|
|
|
1325
|
|
|
# Add topo, geom and length
|
1326
|
|
|
bus_geom = db.select_geodataframe(
|
1327
|
|
|
"""SELECT bus_id, geom
|
1328
|
|
|
FROM grid.egon_etrago_bus
|
1329
|
|
|
WHERE scn_name = 'eGon2035'
|
1330
|
|
|
AND carrier = 'CH4'
|
1331
|
|
|
""",
|
1332
|
|
|
epsg=4326,
|
1333
|
|
|
).set_index("bus_id")
|
1334
|
|
|
|
1335
|
|
|
coordinates_bus0 = []
|
1336
|
|
|
coordinates_bus1 = []
|
1337
|
|
|
|
1338
|
|
|
for index, row in Neighbouring_pipe_capacities_list.iterrows():
|
1339
|
|
|
coordinates_bus0.append(bus_geom["geom"].loc[int(row["bus0"])])
|
1340
|
|
|
coordinates_bus1.append(bus_geom["geom"].loc[int(row["bus1"])])
|
1341
|
|
|
|
1342
|
|
|
Neighbouring_pipe_capacities_list["coordinates_bus0"] = coordinates_bus0
|
1343
|
|
|
Neighbouring_pipe_capacities_list["coordinates_bus1"] = coordinates_bus1
|
1344
|
|
|
|
1345
|
|
|
Neighbouring_pipe_capacities_list[
|
1346
|
|
|
"topo"
|
1347
|
|
|
] = Neighbouring_pipe_capacities_list.apply(
|
1348
|
|
|
lambda row: LineString(
|
1349
|
|
|
[row["coordinates_bus0"], row["coordinates_bus1"]]
|
1350
|
|
|
),
|
1351
|
|
|
axis=1,
|
1352
|
|
|
)
|
1353
|
|
|
Neighbouring_pipe_capacities_list[
|
1354
|
|
|
"geom"
|
1355
|
|
|
] = Neighbouring_pipe_capacities_list.apply(
|
1356
|
|
|
lambda row: MultiLineString([row["topo"]]), axis=1
|
1357
|
|
|
)
|
1358
|
|
|
Neighbouring_pipe_capacities_list[
|
1359
|
|
|
"length"
|
1360
|
|
|
] = Neighbouring_pipe_capacities_list.apply(
|
1361
|
|
|
lambda row: row["topo"].length, axis=1
|
1362
|
|
|
)
|
1363
|
|
|
|
1364
|
|
|
# Remove useless columns
|
1365
|
|
|
Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
|
1366
|
|
|
columns=[
|
1367
|
|
|
"coordinates_bus0",
|
1368
|
|
|
"coordinates_bus1",
|
1369
|
|
|
]
|
1370
|
|
|
)
|
1371
|
|
|
|
1372
|
|
|
# Add missing columns
|
1373
|
|
|
c = {"scn_name": "eGon2035", "carrier": "CH4"}
|
1374
|
|
|
Neighbouring_pipe_capacities_list = (
|
1375
|
|
|
Neighbouring_pipe_capacities_list.assign(**c)
|
1376
|
|
|
)
|
1377
|
|
|
|
1378
|
|
|
Neighbouring_pipe_capacities_list = (
|
1379
|
|
|
Neighbouring_pipe_capacities_list.set_geometry("geom", crs=4326)
|
1380
|
|
|
)
|
1381
|
|
|
|
1382
|
|
|
return Neighbouring_pipe_capacities_list
|
1383
|
|
|
|
1384
|
|
|
|
1385
|
|
|
def tyndp_gas_generation():
|
1386
|
|
|
"""Insert data from TYNDP 2020 accordning to NEP 2021
|
1387
|
|
|
Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
|
1388
|
|
|
|
1389
|
|
|
Returns
|
1390
|
|
|
-------
|
1391
|
|
|
None.
|
1392
|
|
|
"""
|
1393
|
|
|
capacities = calc_capacities()
|
1394
|
|
|
insert_generators(capacities)
|
1395
|
|
|
|
1396
|
|
|
ch4_storage_capacities = calc_ch4_storage_capacities()
|
1397
|
|
|
insert_storage(ch4_storage_capacities)
|
1398
|
|
|
|
1399
|
|
|
|
1400
|
|
|
def tyndp_gas_demand():
|
1401
|
|
|
"""Insert gas demands abroad for eGon2035
|
1402
|
|
|
|
1403
|
|
|
Insert CH4 and H2 demands abroad for eGon2035 by executing the
|
1404
|
|
|
following steps:
|
1405
|
|
|
* CH4
|
1406
|
|
|
* Calculation of the global CH4 demand in Norway and of the
|
1407
|
|
|
CH4 demand profile by executing the function
|
1408
|
|
|
:py:func:`import_ch4_demandTS`
|
1409
|
|
|
* Calculation of the global CH4 demands by executing the
|
1410
|
|
|
function :py:func:`calc_global_ch4_demand`
|
1411
|
|
|
* Insertion the CH4 loads and their associated time series
|
1412
|
|
|
in the database by executing the function
|
1413
|
|
|
:py:func:`insert_ch4_demand`
|
1414
|
|
|
* H2
|
1415
|
|
|
* Calculation of the global power demand abroad linked
|
1416
|
|
|
to H2 production by executing the function
|
1417
|
|
|
:py:func:`calc_global_power_to_h2_demand`
|
1418
|
|
|
* Insertion of these loads in the database by executing the
|
1419
|
|
|
function :py:func:`insert_power_to_h2_demand`
|
1420
|
|
|
This function insert data in the database and has no return.
|
1421
|
|
|
|
1422
|
|
|
"""
|
1423
|
|
|
Norway_global_demand_1y, normalized_ch4_demandTS = import_ch4_demandTS()
|
1424
|
|
|
global_ch4_demand = calc_global_ch4_demand(Norway_global_demand_1y)
|
1425
|
|
|
insert_ch4_demand(global_ch4_demand, normalized_ch4_demandTS)
|
1426
|
|
|
|
1427
|
|
|
global_power_to_h2_demand = calc_global_power_to_h2_demand()
|
1428
|
|
|
insert_power_to_h2_demand(global_power_to_h2_demand)
|
1429
|
|
|
|
1430
|
|
|
|
1431
|
|
|
def grid():
|
1432
|
|
|
"""Insert data from TYNDP 2020 accordning to NEP 2021
|
1433
|
|
|
Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
|
1434
|
|
|
|
1435
|
|
|
Returns
|
1436
|
|
|
-------
|
1437
|
|
|
None.
|
1438
|
|
|
"""
|
1439
|
|
|
Neighbouring_pipe_capacities_list = calculate_ch4_grid_capacities()
|
1440
|
|
|
insert_gas_grid_capacities(
|
1441
|
|
|
Neighbouring_pipe_capacities_list, scn_name="eGon2035"
|
1442
|
|
|
)
|
1443
|
|
|
|
1444
|
|
|
|
1445
|
|
|
def calculate_ocgt_capacities():
|
1446
|
|
|
"""Calculate gas turbine capacities abroad for eGon2035
|
1447
|
|
|
|
1448
|
|
|
Calculate gas turbine capacities abroad for eGon2035 based on TYNDP
|
1449
|
|
|
2020, scenario "Distributed Energy", interpolated between 2030 and 2040
|
1450
|
|
|
|
1451
|
|
|
Returns
|
1452
|
|
|
-------
|
1453
|
|
|
df_ocgt: pandas.DataFrame
|
1454
|
|
|
Gas turbine capacities per foreign node
|
1455
|
|
|
|
1456
|
|
|
"""
|
1457
|
|
|
sources = config.datasets()["gas_neighbours"]["sources"]
|
1458
|
|
|
|
1459
|
|
|
# insert installed capacities
|
1460
|
|
|
file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
|
1461
|
|
|
df = pd.read_excel(
|
1462
|
|
|
file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
|
1463
|
|
|
sheet_name="Capacity",
|
1464
|
|
|
)
|
1465
|
|
|
|
1466
|
|
|
df_ocgt = df[
|
1467
|
|
|
[
|
1468
|
|
|
"Node/Line",
|
1469
|
|
|
"Scenario",
|
1470
|
|
|
"Climate Year",
|
1471
|
|
|
"Generator_ID",
|
1472
|
|
|
"Year",
|
1473
|
|
|
"Value",
|
1474
|
|
|
]
|
1475
|
|
|
]
|
1476
|
|
|
df_ocgt = df_ocgt[
|
1477
|
|
|
(df_ocgt["Scenario"] == "Distributed Energy")
|
1478
|
|
|
& (df_ocgt["Climate Year"] == 1984)
|
1479
|
|
|
]
|
1480
|
|
|
df_ocgt = df_ocgt[df_ocgt["Generator_ID"].str.contains("Gas")]
|
1481
|
|
|
df_ocgt = df_ocgt[df_ocgt["Year"].isin([2030, 2040])]
|
1482
|
|
|
|
1483
|
|
|
df_ocgt = (
|
1484
|
|
|
df_ocgt.groupby(["Node/Line", "Year"])["Value"].sum().reset_index()
|
1485
|
|
|
)
|
1486
|
|
|
df_ocgt = df_ocgt.groupby([df_ocgt["Node/Line"], "Year"]).sum()
|
1487
|
|
|
df_ocgt = df_ocgt.groupby("Node/Line")["Value"].mean()
|
1488
|
|
|
df_ocgt = pd.DataFrame(df_ocgt, columns=["Value"]).rename(
|
1489
|
|
|
columns={"Value": "p_nom"}
|
1490
|
|
|
)
|
1491
|
|
|
|
1492
|
|
|
# Choose capacities for considered countries
|
1493
|
|
|
df_ocgt = df_ocgt[df_ocgt.index.str[:2].isin(countries)]
|
1494
|
|
|
|
1495
|
|
|
# Attribute bus0 and bus1
|
1496
|
|
|
df_ocgt["bus0"] = get_foreign_gas_bus_id()[df_ocgt.index]
|
1497
|
|
|
df_ocgt["bus1"] = get_foreign_bus_id()[df_ocgt.index]
|
1498
|
|
|
df_ocgt = df_ocgt.groupby(by=["bus0", "bus1"], as_index=False).sum()
|
1499
|
|
|
|
1500
|
|
|
return df_ocgt
|
1501
|
|
|
|
1502
|
|
|
|
1503
|
|
|
def insert_ocgt_abroad():
|
1504
|
|
|
"""Insert gas turbine capicities abroad for eGon2035 in the database
|
1505
|
|
|
|
1506
|
|
|
This function inserts data in the database and has no return.
|
1507
|
|
|
|
1508
|
|
|
Parameters
|
1509
|
|
|
----------
|
1510
|
|
|
df_ocgt: pandas.DataFrame
|
1511
|
|
|
Gas turbine capacities per foreign node
|
1512
|
|
|
|
1513
|
|
|
"""
|
1514
|
|
|
scn_name = "eGon2035"
|
1515
|
|
|
carrier = "OCGT"
|
1516
|
|
|
|
1517
|
|
|
# Connect to local database
|
1518
|
|
|
engine = db.engine()
|
1519
|
|
|
|
1520
|
|
|
df_ocgt = calculate_ocgt_capacities()
|
1521
|
|
|
|
1522
|
|
|
df_ocgt["p_nom_extendable"] = False
|
1523
|
|
|
df_ocgt["carrier"] = carrier
|
1524
|
|
|
df_ocgt["scn_name"] = scn_name
|
1525
|
|
|
|
1526
|
|
|
buses = tuple(
|
1527
|
|
|
db.select_dataframe(
|
1528
|
|
|
f"""SELECT bus_id FROM grid.egon_etrago_bus
|
1529
|
|
|
WHERE scn_name = '{scn_name}' AND country != 'DE';
|
1530
|
|
|
"""
|
1531
|
|
|
)["bus_id"]
|
1532
|
|
|
)
|
1533
|
|
|
|
1534
|
|
|
# Delete old entries
|
1535
|
|
|
db.execute_sql(
|
1536
|
|
|
f"""
|
1537
|
|
|
DELETE FROM grid.egon_etrago_link WHERE "carrier" = '{carrier}'
|
1538
|
|
|
AND scn_name = '{scn_name}'
|
1539
|
|
|
AND bus0 IN {buses} AND bus1 IN {buses};
|
1540
|
|
|
"""
|
1541
|
|
|
)
|
1542
|
|
|
|
1543
|
|
|
# read carrier information from scnario parameter data
|
1544
|
|
|
scn_params = get_sector_parameters("gas", scn_name)
|
1545
|
|
|
df_ocgt["efficiency"] = scn_params["efficiency"][carrier]
|
1546
|
|
|
df_ocgt["marginal_cost"] = (
|
1547
|
|
|
scn_params["marginal_cost"][carrier]
|
1548
|
|
|
/ scn_params["efficiency"][carrier]
|
1549
|
|
|
)
|
1550
|
|
|
|
1551
|
|
|
# Adjust p_nom
|
1552
|
|
|
df_ocgt["p_nom"] = df_ocgt["p_nom"] / scn_params["efficiency"][carrier]
|
1553
|
|
|
|
1554
|
|
|
# Select next id value
|
1555
|
|
|
new_id = db.next_etrago_id("link")
|
1556
|
|
|
df_ocgt["link_id"] = range(new_id, new_id + len(df_ocgt))
|
1557
|
|
|
|
1558
|
|
|
# Insert data to db
|
1559
|
|
|
df_ocgt.to_sql(
|
1560
|
|
|
"egon_etrago_link",
|
1561
|
|
|
engine,
|
1562
|
|
|
schema="grid",
|
1563
|
|
|
index=False,
|
1564
|
|
|
if_exists="append",
|
1565
|
|
|
)
|
1566
|
|
|
|