Passed
Pull Request — dev (#936)
by
unknown
01:53
created

insert_biogas_generators_abroad()   A

Complexity

Conditions 1

Size

Total Lines 40
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 40
rs 9.85
c 0
b 0
f 0
cc 1
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 country != 'RU'
183
                        AND carrier = 'CH4'
184
                        AND scn_name = 'eGon2035')
185
                    AND "bus1" IN (SELECT bus_id FROM 
186
                        {sources['buses']['schema']}.{sources['buses']['table']}
187
                        WHERE country = 'DE'
188
                        AND carrier = 'CH4' 
189
                        AND scn_name = 'eGon2035'))
190
                OR ("bus0" IN (
191
                        SELECT bus_id FROM 
192
                        {sources['buses']['schema']}.{sources['buses']['table']}
193
                        WHERE country = 'DE'
194
                        AND carrier = 'CH4'
195
                        AND scn_name = 'eGon2035')
196
                AND "bus1" IN (
197
                        SELECT bus_id FROM 
198
                        {sources['buses']['schema']}.{sources['buses']['table']}
199
                        WHERE country != 'DE'
200
                        AND country != 'RU'
201
                        AND carrier = 'CH4' 
202
                        AND scn_name = 'eGon2035'))
203
        AND scn_name = 'eGon2035'
204
        AND carrier = 'CH4'
205
        """,
206
        epsg=4326,
207
    )
208
209
    # Insert bus0 and bus1
210
    gas_pipelines_list = gas_pipelines_list[
211
        ["bus0", "bus1", "length", "p_min_pu", "geom", "topo"]
212
    ].rename(columns={"bus0": "bus0_2035", "bus1": "bus1_2035"})
213
214
    gas_nodes_list_2035 = db.select_geodataframe(
215
        f"""
216
        SELECT * FROM {sources['buses']['schema']}.{sources['buses']['table']}
217
        WHERE scn_name = 'eGon2035'
218
        AND carrier = 'CH4'
219
        """,
220
        epsg=4326,
221
    )
222
223
    busID_table = gas_nodes_list_2035[["geom", "bus_id", "country"]].rename(
224
        columns={"bus_id": "bus_id_CH4_2035"}
225
    )
226
    gas_pipelines_list_DE = pd.DataFrame(
227
        columns=[
228
            "length",
229
            "geom",
230
            "topo",
231
            "bus0",
232
            "bus1",
233
            "p_min_pu",
234
            "carrier",
235
        ]
236
    )
237
238
    for carrier in ["H2", "CH4"]:
239
        if carrier == "CH4":
240
            carrier_bus_DE = carrier
241
        elif carrier == "H2":
242
            carrier_bus_DE = "H2_grid"
243
244
        busID_table_DE = db.assign_gas_bus_id(
245
            busID_table[busID_table["country"] == "DE"],
246
            scn_name,
247
            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...
248
        ).set_index("bus_id_CH4_2035")
249
250
        gas_nodes_abroad_100RE = db.select_geodataframe(
251
            f"""
252
            SELECT * FROM grid.egon_etrago_bus
253
            WHERE scn_name = 'eGon100RE'
254
            AND carrier = '{carrier_bus_DE}'
255
            AND country != 'DE'
256
            """,
257
            epsg=4326,
258
        )
259
260
        buses = busID_table[busID_table["country"] != "DE"]
261
        buses["bus_id"] = 0
262
263
        # Select bus_id from db
264
        for i, row in buses.iterrows():
265
            distance = gas_nodes_abroad_100RE.set_index(
266
                "bus_id"
267
            ).geom.distance(row.geom)
268
            buses.loc[i, "bus_id"] = distance[
269
                distance == distance.min()
270
            ].index.values[0]
271
272
        buses = buses.set_index("bus_id_CH4_2035")
273
274
        bus0 = []
275
        bus1 = []
276
        country = []
277
278
        for b0 in gas_pipelines_list["bus0_2035"].to_list():
279
            if b0 in busID_table_DE.index.to_list():
280
                bus0.append(int(busID_table_DE.loc[b0, "bus_id"]))
281
            else:
282
                bus0.append(int(buses.loc[b0, "bus_id"]))
283
                country.append(buses.loc[b0, "country"])
284
        for b1 in gas_pipelines_list["bus1_2035"].to_list():
285
            if b1 in busID_table_DE.index.to_list():
286
                bus1.append(int(busID_table_DE.loc[b1, "bus_id"]))
287
            else:
288
                bus1.append(int(buses.loc[b1, "bus_id"]))
289
                country.append(buses.loc[b1, "country"])
290
291
        gas_pipelines_list["bus0"] = bus0
292
        gas_pipelines_list["bus1"] = bus1
293
        gas_pipelines_list["country"] = country
294
295
        # Insert carrier
296
        if carrier == "CH4":
297
            carrier_pipes = carrier
298
        elif carrier == "H2":
299
            carrier_pipes = "H2_retrofit"
300
        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...
301
302
        gas_pipelines_list_DE = gas_pipelines_list_DE.append(
303
            gas_pipelines_list, ignore_index=True
304
        )
305
306
    gas_pipelines_list_DE["scn_name"] = scn_name
307
308
    # Select next id value
309
    new_id = db.next_etrago_id("link")
310
    gas_pipelines_list_DE["link_id"] = range(
311
        new_id, new_id + len(gas_pipelines_list_DE)
312
    )
313
    gas_pipelines_list_DE["link_id"] = gas_pipelines_list_DE["link_id"].astype(
314
        int
315
    )
316
    gas_pipelines_list_DE = gas_pipelines_list_DE.drop(
317
        columns={"bus0_2035", "bus1_2035"}
318
    )
319
320
    return gas_pipelines_list_DE
321
322
323
def read_DE_crossbordering_cap_from_pes():
324
    """Read gas pipelines crossbordering capacities from pes run
325
326
    This function calculates the crossbordering total exchange
327
    capactities for H2 and CH4 between Germany and its neighbouring
328
    countries based on the pypsa-eur-sec results.
329
330
    Returns
331
    -------
332
    DE_pipe_capacities_list : pandas.DataFrame
333
        List of the H2 and CH4 exchange capacity for each neighbouring
334
        country of Germany.
335
336
    """
337
    n = read_network()
338
339
    DE_pipe_capacities_list_H2 = n.links[
340
        (n.links["carrier"] == "H2 pipeline retrofitted")
341
        & ((n.links["bus0"] == "DE0 0 H2") | (n.links["bus1"] == "DE0 0 H2"))
342
    ]
343
344
    DE_pipe_capacities_list_CH4 = n.links[
345
        (n.links["carrier"] == "gas pipeline")
346
        & ((n.links["bus0"] == "DE0 0 gas") | (n.links["bus1"] == "DE0 0 gas"))
347
    ]
348
349
    pipe_capacities_list = pd.DataFrame(
350
        columns=["p_nom", "carrier", "country_code"]
351
    )
352
    for DE_pipe_capacities_list in [
353
        DE_pipe_capacities_list_H2,
354
        DE_pipe_capacities_list_CH4,
355
    ]:
356
357
        DE_pipe_capacities_list = DE_pipe_capacities_list[
358
            ["bus0", "bus1", "p_nom_opt", "carrier"]
359
        ].rename(columns={"p_nom_opt": "p_nom"})
360
361
        DE_pipe_capacities_list[
362
            "country_code"
363
        ] = DE_pipe_capacities_list.apply(
364
            lambda row: str(sorted([row.bus0[:2], row.bus1[:2]])), axis=1
365
        )
366
367
        DE_pipe_capacities_list = DE_pipe_capacities_list.drop(
368
            columns=[
369
                "bus0",
370
                "bus1",
371
            ]
372
        )
373
374
        DE_pipe_capacities_list = DE_pipe_capacities_list.groupby(
375
            ["country_code"], as_index=False
376
        ).agg({"p_nom": "sum", "carrier": "first"})
377
378
        pipe_capacities_list = pipe_capacities_list.append(
379
            DE_pipe_capacities_list, ignore_index=True
380
        )
381
382
    map_countries = {
383
        "['AT', 'DE']": "AT",
384
        "['BE', 'DE']": "BE",
385
        "['CH', 'DE']": "CH",
386
        "['CZ', 'DE']": "CZ",
387
        "['DE', 'DK']": "DK",
388
        "['DE', 'FR']": "FR",
389
        "['DE', 'LU']": "LU",
390
        "['DE', 'NL']": "NL",
391
        "['DE', 'NO']": "NO",
392
        "['DE', 'PL']": "PL",
393
    }
394
395
    pipe_capacities_list["country_code"] = pipe_capacities_list[
396
        "country_code"
397
    ].replace(map_countries)
398
    pipe_capacities_list["carrier"] = pipe_capacities_list["carrier"].replace(
399
        {
400
            "H2 pipeline retrofitted": "H2_retrofit",
401
            "gas pipeline": "CH4",
402
        }
403
    )
404
405
    return pipe_capacities_list
406
407
408
def calculate_crossbordering_gas_grid_capacities_eGon100RE(
409
    cap_DE, DE_pipe_capacities_list
410
):
411
    """Attribute gas crossbordering grid capacities for eGon100RE
412
413
    This function attributes to each crossbordering pipeline (H2 and
414
    CH4) between Germany and its neighbouring countries its capacity.
415
416
    Parameters
417
    ----------
418
    cap_DE : pandas.DataFrame
419
        List of the H2 and CH4 exchange capacity for each neighbouring
420
        country of Germany.
421
    DE_pipe_capacities_list : pandas.DataFrame
422
        List of the crossbordering for H2 and CH4 pipelines between
423
        Germany and its neighbouring countries in eGon100RE, with
424
        geometry (geom and topo) but no capacity.
425
426
    Returns
427
    -------
428
    Crossbordering_pipe_capacities_list : pandas.DataFrame
429
        List of the crossbordering H2 and CH4 pipelines between
430
        Germany and its neighbouring countries in eGon100RE.
431
432
    """
433
434
    Crossbordering_pipe_capacities_list = pd.DataFrame(
435
        columns=[
436
            "length",
437
            "geom",
438
            "topo",
439
            "bus0",
440
            "bus1",
441
            "carrier",
442
            "scn_name",
443
            "link_id",
444
            "p_nom",
445
        ]
446
    )
447
448
    for carrier in ["CH4", "H2_retrofit"]:
449
        p_nom = []
450
        cap = cap_DE[cap_DE["carrier"] == carrier].set_index("country_code")
451
        pipe_capacities_list = DE_pipe_capacities_list[
452
            DE_pipe_capacities_list["carrier"] == carrier
453
        ]
454
455
        for c in pipe_capacities_list["country"].to_list():
456
            n_links = len(
457
                pipe_capacities_list[
458
                    pipe_capacities_list["country"] == c
459
                ].index
460
            )
461
            p_nom.append(cap.at[c, "p_nom"] / n_links)
462
463
        pipe_capacities_list["p_nom"] = p_nom
464
        pipe_capacities_list = pipe_capacities_list.drop(columns={"country"})
465
        Crossbordering_pipe_capacities_list = (
466
            Crossbordering_pipe_capacities_list.append(pipe_capacities_list)
467
        )
468
469
    return Crossbordering_pipe_capacities_list
470