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