Passed
Pull Request — dev (#1006)
by
unknown
01:37
created

insert_gas_neigbours_eGon100RE_pipes()   A

Complexity

Conditions 3

Size

Total Lines 50
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 50
rs 9.7
c 0
b 0
f 0
cc 3
nop 0
1
"""Module containing code dealing with gas components abroad for eGon100RE
2
3
In this module the missing gas components abroad for eGon100RE are
4
defined and inserted in the database:
5
  * missing crossbording pipelines: the missing crossbordering
6
    pipelines for H2 and CH4,are exclusively between Germany and
7
    its neighbouring countries
8
  * biogas generators
9
10
Dependecies (pipeline)
11
======================
12
  * :dataset: PypsaEurSec, GasNodesandPipes, HydrogenBusEtrago,
13
    ElectricalNeighbours
14
15
Resulting tables
16
================
17
  * grid.egon_etrago_link is completed
18
  * grid.egon_etrago_store is completed
19
  * grid.egon_etrago_generator is modified
20
21
"""
22
23
import pandas as pd
24
25
from egon.data import config, db
26
from egon.data.datasets.gas_neighbours.gas_abroad import (
27
    insert_gas_grid_capacities,
28
    insert_generators,
29
)
30
from egon.data.datasets.pypsaeursec import read_network
31
32
countries = [
33
    "AT",
34
    "BE",
35
    "CH",
36
    "CZ",
37
    "DK",
38
    "FR",
39
    "LU",
40
    "NL",
41
    "NO",
42
    "PL",
43
]
44
45
46
def insert_gas_neigbours_eGon100RE():
47
    """Insert gas components abroad for eGon100RE
48
49
    Insert the missing gas crossbordering grid capacities and the
50
    biogas generators for eGon100RE
51
52
    """
53
    insert_gas_neigbours_eGon100RE_pipes()
54
    insert_generators(insert_biogas_generators_abroad(), scn_name="eGon100RE")
55
56
57
def insert_biogas_generators_abroad():
58
    """Insert biogas generators abroad for eGon100RE
59
60
    This function defines the biogas generators in the neighbouring
61
    countries for the scenario eGon100RE. The capacities arrise from
62
    the pypsa-eur-sec run where the biogas available is modelled as
63
    stores. Therefore, the corresponding stores are deleted and the
64
    capacities inserted as biogas generation potentials.
65
66
    Returns
67
    -------
68
    gen : pandas.DataFrame
69
        Gas production capacities per foreign node
70
71
    """
72
    sources = config.datasets()["gas_neighbours"]["sources"]
73
    scn_name = "eGon100RE"
74
    carrier = "biogas"
75
76
    gen = db.select_dataframe(
77
        f"""
78
        SELECT scn_name, bus, e_initial, marginal_cost
79
        FROM {sources['stores']['schema']}.{sources['stores']['table']}
80
        WHERE scn_name = '{scn_name}'
81
        AND carrier = '{carrier}'
82
        """
83
    )
84
    gen = gen.rename(columns={"e_initial": "p_nom"})
85
    gen["e_nom_max"] = gen["p_nom"]
86
87
    db.execute_sql(
88
        f"""
89
        DELETE FROM
90
        {sources['stores']['schema']}.{sources['stores']['table']}
91
        WHERE scn_name = '{scn_name}'
92
        AND carrier = '{carrier}';
93
        """
94
    )
95
96
    return gen
97
98
99
def insert_gas_neigbours_eGon100RE_pipes():
100
    """Insert missing gas crossbordering grid capacities for eGon100RE
101
102
    This function insert the crossbordering pipelines for H2 and CH4,
103
    exclusively between Germany and its neighbouring countries,
104
    for eGon100RE in the database by executing the following steps:
105
      * call of the the function
106
        :py:func:`define_DE_crossbording_pipes_geom_eGon100RE`, that
107
        defines the crossbordering pipelines (H2 and CH4) between
108
        Germany and its neighbouring countries
109
      * call of the the function
110
        :py:func:`read_DE_crossbordering_cap_from_pes`, that calculates
111
        the crossbordering total exchange capactities for H2 and CH4
112
        between Germany and its neighbouring countries based on the
113
        pypsa-eur-sec results
114
      * call of the the function
115
        :py:func:`calculate_crossbordering_gas_grid_capacities_eGon100RE`,
116
        that attributes to each crossbordering pipeline (H2 and CH4)
117
        between Germany and its neighbouring countries its capacity
118
      * insertion of the H2 and CH4 pipelines between Germany and its
119
        neighbouring countries in the database with function
120
        :py:func:`insert_gas_grid_capacities`
121
122
    Returns
123
    -------
124
    None
125
126
    """
127
128
    DE_pipe_capacities_list = define_DE_crossbording_pipes_geom_eGon100RE()
129
    cap_DE = read_DE_crossbordering_cap_from_pes()
130
131
    Crossbordering_pipe_capacities_list = (
132
        calculate_crossbordering_gas_grid_capacities_eGon100RE(
133
            cap_DE, DE_pipe_capacities_list
134
        )
135
    )
136
137
    for i in ["link_id", "bus0", "bus1"]:
138
        Crossbordering_pipe_capacities_list[i] = (
139
            Crossbordering_pipe_capacities_list[i].astype(str).astype(int)
140
        )
141
142
    for i in ["p_nom", "length"]:
143
        Crossbordering_pipe_capacities_list[i] = (
144
            Crossbordering_pipe_capacities_list[i].astype(str).astype(float)
145
        )
146
147
    insert_gas_grid_capacities(
148
        Crossbordering_pipe_capacities_list, "eGon100RE"
149
    )
150
151
152
def define_DE_crossbording_pipes_geom_eGon100RE(scn_name="eGon100RE"):
153
    """Define the missing crossbordering gas pipelines in eGon100RE
154
155
    This function defines the crossbordering pipelines (for H2 and CH4)
156
    between Germany and its neighbouring countries. These pipelines
157
    are defined as links and there are copied from the corresponding
158
    CH4 crossbering pipelines from eGon2035.
159
160
    Parameters
161
    ----------
162
    scn_name : str
163
        Name of the scenario
164
165
    Returns
166
    -------
167
    gas_pipelines_list_DE : pandas.DataFrame
168
        List of the crossbordering H2 and CH4 pipelines between
169
        Germany and its neighbouring countries in eGon100RE, with
170
        geometry (geom and topo) but no capacity.
171
172
    """
173
    sources = config.datasets()["gas_neighbours"]["sources"]
174
175
    gas_pipelines_list = db.select_geodataframe(
176
        f"""
177
        SELECT * FROM grid.egon_etrago_link
178
        WHERE ("bus0" IN (
179
                        SELECT bus_id FROM 
180
                        {sources['buses']['schema']}.{sources['buses']['table']}
181
                        WHERE country != 'DE'
182
                        AND carrier = 'CH4'
183
                        AND scn_name = 'eGon2035')
184
                    AND "bus1" IN (SELECT bus_id FROM 
185
                        {sources['buses']['schema']}.{sources['buses']['table']}
186
                        WHERE country = 'DE'
187
                        AND carrier = 'CH4' 
188
                        AND scn_name = 'eGon2035'))
189
                OR ("bus0" IN (
190
                        SELECT bus_id FROM 
191
                        {sources['buses']['schema']}.{sources['buses']['table']}
192
                        WHERE country = 'DE'
193
                        AND carrier = 'CH4'
194
                        AND scn_name = 'eGon2035')
195
                AND "bus1" IN (
196
                        SELECT bus_id FROM 
197
                        {sources['buses']['schema']}.{sources['buses']['table']}
198
                        WHERE country != 'DE'
199
                        AND carrier = 'CH4' 
200
                        AND scn_name = 'eGon2035'))
201
        AND scn_name = 'eGon2035'
202
        AND carrier = 'CH4'
203
        """,
204
        epsg=4326,
205
    )
206
207
    # Insert bus0 and bus1
208
    gas_pipelines_list = gas_pipelines_list[
209
        ["bus0", "bus1", "length", "geom", "topo"]
210
    ].rename(columns={"bus0": "bus0_2035", "bus1": "bus1_2035"})
211
212
    gas_nodes_list_2035 = db.select_geodataframe(
213
        f"""
214
        SELECT * FROM {sources['buses']['schema']}.{sources['buses']['table']}
215
        WHERE scn_name = 'eGon2035'
216
        AND carrier = 'CH4'
217
        """,
218
        epsg=4326,
219
    )
220
221
    busID_table = gas_nodes_list_2035[["geom", "bus_id", "country"]].rename(
222
        columns={"bus_id": "bus_id_CH4_2035"}
223
    )
224
    gas_pipelines_list_DE = pd.DataFrame(
225
        columns=["length", "geom", "topo", "bus0", "bus1", "carrier"]
226
    )
227
228
    for carrier in ["H2", "CH4"]:
229
        if carrier == "CH4":
230
            carrier_bus_DE = carrier
231
        elif carrier == "H2":
232
            carrier_bus_DE = "H2_grid"
233
234
        busID_table_DE = db.assign_gas_bus_id(
235
            busID_table[busID_table["country"] == "DE"],
236
            scn_name,
237
            carrier_bus_DE,
0 ignored issues
show
introduced by
The variable carrier_bus_DE does not seem to be defined for all execution paths.
Loading history...
238
        ).set_index("bus_id_CH4_2035")
239
240
        gas_nodes_abroad_100RE = db.select_geodataframe(
241
            f"""
242
            SELECT * FROM grid.egon_etrago_bus
243
            WHERE scn_name = 'eGon100RE'
244
            AND carrier = '{carrier}'
245
            AND country != 'DE'
246
            """,
247
            epsg=4326,
248
        )
249
250
        buses = busID_table[busID_table["country"] != "DE"]
251
        buses["bus_id"] = 0
252
253
        # Select bus_id from db
254
        for i, row in buses.iterrows():
255
            distance = gas_nodes_abroad_100RE.set_index(
256
                "bus_id"
257
            ).geom.distance(row.geom)
258
            buses.loc[i, "bus_id"] = distance[
259
                distance == distance.min()
260
            ].index.values[0]
261
262
        buses = buses.set_index("bus_id_CH4_2035")
263
264
        bus0 = []
265
        bus1 = []
266
        country = []
267
268
        for b0 in gas_pipelines_list["bus0_2035"].to_list():
269
            if b0 in busID_table_DE.index.to_list():
270
                bus0.append(int(busID_table_DE.loc[b0, "bus_id"]))
271
            else:
272
                bus0.append(int(buses.loc[b0, "bus_id"]))
273
                country.append(buses.loc[b0, "country"])
274
        for b1 in gas_pipelines_list["bus1_2035"].to_list():
275
            if b1 in busID_table_DE.index.to_list():
276
                bus1.append(int(busID_table_DE.loc[b1, "bus_id"]))
277
            else:
278
                bus1.append(int(buses.loc[b1, "bus_id"]))
279
                country.append(buses.loc[b1, "country"])
280
281
        gas_pipelines_list["bus0"] = bus0
282
        gas_pipelines_list["bus1"] = bus1
283
        gas_pipelines_list["country"] = country
284
285
        # Insert carrier
286
        if carrier == "CH4":
287
            carrier_pipes = carrier
288
        elif carrier == "H2":
289
            carrier_pipes = "H2_retrofit"
290
        gas_pipelines_list["carrier"] = carrier_pipes
0 ignored issues
show
introduced by
The variable carrier_pipes does not seem to be defined for all execution paths.
Loading history...
291
292
        gas_pipelines_list_DE = gas_pipelines_list_DE.append(
293
            gas_pipelines_list, ignore_index=True
294
        )
295
296
    gas_pipelines_list_DE["scn_name"] = scn_name
297
298
    # Select next id value
299
    new_id = db.next_etrago_id("link")
300
    gas_pipelines_list_DE["link_id"] = range(
301
        new_id, new_id + len(gas_pipelines_list_DE)
302
    )
303
    gas_pipelines_list_DE["link_id"] = gas_pipelines_list_DE["link_id"].astype(
304
        int
305
    )
306
    gas_pipelines_list_DE = gas_pipelines_list_DE.drop(
307
        columns={"bus0_2035", "bus1_2035"}
308
    )
309
310
    return gas_pipelines_list_DE
311
312
313
def read_DE_crossbordering_cap_from_pes():
314
    """Read gas pipelines crossbordering capacities from pes run
315
316
    This function calculates the crossbordering total exchange
317
    capactities for H2 and CH4 between Germany and its neighbouring
318
    countries based on the pypsa-eur-sec results.
319
320
    Returns
321
    -------
322
    DE_pipe_capacities_list : pandas.DataFrame
323
        List of the H2 and CH4 exchange capacity for each neighbouring
324
        country of Germany.
325
326
    """
327
    n = read_network()
328
329
    DE_pipe_capacities_list_H2 = n.links[
330
        (n.links["carrier"] == "H2 pipeline retrofitted")
331
        & ((n.links["bus0"] == "DE0 0 H2") | (n.links["bus1"] == "DE0 0 H2"))
332
    ]
333
334
    DE_pipe_capacities_list_CH4 = n.links[
335
        (n.links["carrier"] == "gas pipeline")
336
        & ((n.links["bus0"] == "DE0 0 gas") | (n.links["bus1"] == "DE0 0 gas"))
337
    ]
338
339
    pipe_capacities_list = pd.DataFrame(
340
        columns=["p_nom", "carrier", "country_code"]
341
    )
342
    for DE_pipe_capacities_list in [
343
        DE_pipe_capacities_list_H2,
344
        DE_pipe_capacities_list_CH4,
345
    ]:
346
347
        DE_pipe_capacities_list = DE_pipe_capacities_list[
348
            ["bus0", "bus1", "p_nom_opt", "carrier"]
349
        ].rename(columns={"p_nom_opt": "p_nom"})
350
351
        DE_pipe_capacities_list[
352
            "country_code"
353
        ] = DE_pipe_capacities_list.apply(
354
            lambda row: str(sorted([row.bus0[:2], row.bus1[:2]])), axis=1
355
        )
356
357
        DE_pipe_capacities_list = DE_pipe_capacities_list.drop(
358
            columns=[
359
                "bus0",
360
                "bus1",
361
            ]
362
        )
363
364
        DE_pipe_capacities_list = DE_pipe_capacities_list.groupby(
365
            ["country_code"], as_index=False
366
        ).agg({"p_nom": "sum", "carrier": "first"})
367
368
        pipe_capacities_list = pipe_capacities_list.append(
369
            DE_pipe_capacities_list, ignore_index=True
370
        )
371
372
    map_countries = {
373
        "['AT', 'DE']": "AT",
374
        "['BE', 'DE']": "BE",
375
        "['CH', 'DE']": "CH",
376
        "['CZ', 'DE']": "CZ",
377
        "['DE', 'DK']": "DK",
378
        "['DE', 'FR']": "FR",
379
        "['DE', 'LU']": "LU",
380
        "['DE', 'NL']": "NL",
381
        "['DE', 'NO']": "NO",
382
        "['DE', 'PL']": "PL",
383
    }
384
385
    pipe_capacities_list["country_code"] = pipe_capacities_list[
386
        "country_code"
387
    ].replace(map_countries)
388
    pipe_capacities_list["carrier"] = pipe_capacities_list["carrier"].replace(
389
        {
390
            "H2 pipeline retrofitted": "H2_retrofit",
391
            "gas pipeline": "CH4",
392
        }
393
    )
394
395
    return pipe_capacities_list
396
397
398
def calculate_crossbordering_gas_grid_capacities_eGon100RE(
399
    cap_DE, DE_pipe_capacities_list
400
):
401
    """Attribute gas crossbordering grid capacities for eGon100RE
402
403
    This function attributes to each crossbordering pipeline (H2 and
404
    CH4) between Germany and its neighbouring countries its capacity.
405
406
    Parameters
407
    ----------
408
    cap_DE : pandas.DataFrame
409
        List of the H2 and CH4 exchange capacity for each neighbouring
410
        country of Germany.
411
    DE_pipe_capacities_list : pandas.DataFrame
412
        List of the crossbordering for H2 and CH4 pipelines between
413
        Germany and its neighbouring countries in eGon100RE, with
414
        geometry (geom and topo) but no capacity.
415
416
    Returns
417
    -------
418
    Crossbordering_pipe_capacities_list : pandas.DataFrame
419
        List of the crossbordering H2 and CH4 pipelines between
420
        Germany and its neighbouring countries in eGon100RE.
421
422
    """
423
424
    Crossbordering_pipe_capacities_list = pd.DataFrame(
425
        columns=[
426
            "length",
427
            "geom",
428
            "topo",
429
            "bus0",
430
            "bus1",
431
            "carrier",
432
            "scn_name",
433
            "link_id",
434
            "p_nom",
435
        ]
436
    )
437
438
    for carrier in ["CH4", "H2_retrofit"]:
439
        p_nom = []
440
        cap = cap_DE[cap_DE["carrier"] == carrier].set_index("country_code")
441
        pipe_capacities_list = DE_pipe_capacities_list[
442
            DE_pipe_capacities_list["carrier"] == carrier
443
        ]
444
445
        for c in pipe_capacities_list["country"].to_list():
446
            n_links = len(
447
                pipe_capacities_list[
448
                    pipe_capacities_list["country"] == c
449
                ].index
450
            )
451
            p_nom.append(cap.at[c, "p_nom"] / n_links)
452
453
        pipe_capacities_list["p_nom"] = p_nom
454
        pipe_capacities_list = pipe_capacities_list.drop(columns={"country"})
455
        Crossbordering_pipe_capacities_list = (
456
            Crossbordering_pipe_capacities_list.append(pipe_capacities_list)
457
        )
458
459
    return Crossbordering_pipe_capacities_list
460