Completed
Push — dev ( 80489d...aba9f2 )
by Stephan
21s queued 17s
created

data.datasets.gas_grid.GasNodesAndPipes.__init__()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
# -*- coding: utf-8 -*-
2
"""
3
The module containing code aiming to insert the methane grid into the database
4
5
The central module containing all code dealing with the import of data
6
from SciGRID_gas (IGGIELGN dataset) and with the insertion fo the CH4
7
buses and links into the database for the scenarios eGon2035 and eGon100RE.
8
9
The SciGRID_gas data downloaded with :py:func:`download_SciGRID_gas_data`
10
into the folder ./datasets/gas_data/data are also used by other modules.
11
12
In this module, only the IGGIELGN_Nodes and IGGIELGN_PipeSegments cvs files
13
are used in the function :py:func:`insert_gas_data` that inserts the CH4
14
buses and links, which for the case of gas represent pipelines, into the
15
database.
16
17
"""
18
from pathlib import Path
19
from urllib.request import urlretrieve
20
from zipfile import ZipFile
21
import ast
22
import json
23
import os
24
25
from geoalchemy2.types import Geometry
26
from shapely import geometry
27
import geopandas
28
import numpy as np
29
import pandas as pd
30
31
from egon.data import config, db
32
from egon.data.config import settings
33
from egon.data.datasets import Dataset
34
from egon.data.datasets.electrical_neighbours import central_buses_egon100
35
from egon.data.datasets.etrago_helpers import copy_and_modify_buses
36
from egon.data.datasets.scenario_parameters import get_sector_parameters
37
38
39
class GasNodesAndPipes(Dataset):
40
    """
41
    Insert the CH4 buses and links into the database.
42
43
    Insert the CH4 buses and links, which for the case of gas represent
44
    pipelines, into the database for the scenarios eGon2035 and eGon100RE
45
    with the functions :py:func:`insert_gas_data` and :py:func:`insert_gas_data_eGon100RE`.
46
47
    *Dependencies*
48
      * :py:class:`DataBundle <egon.data.datasets.data_bundle.DataBundle>`
49
      * :py:class:`ElectricalNeighbours <egon.data.datasets.electrical_neighbours.ElectricalNeighbours>`
50
      * :py:class:`Osmtgmod <egon.data.datasets.osmtgmod.Osmtgmod>`
51
      * :py:class:`ScenarioParameters <egon.data.datasets.scenario_parameters.ScenarioParameters>`
52
      * :py:class:`EtragoSetup <egon.data.datasets.etrago_setup.EtragoSetup>` (more specifically the :func:`create_tables <egon.data.datasets.etrago_setup.create_tables>` task)
53
54
    *Resulting tables*
55
      * :py:class:`grid.egon_etrago_bus <egon.data.datasets.etrago_setup.EgonPfHvBus>` is extended
56
      * :py:class:`grid.egon_etrago_link <egon.data.datasets.etrago_setup.EgonPfHvLink>` is extended
57
58
    """
59
60
    #:
61
    name: str = "GasNodesAndPipes"
62
    #:
63
    version: str = "0.0.9"
64
65
    def __init__(self, dependencies):
66
        super().__init__(
67
            name=self.name,
68
            version=self.version,
69
            dependencies=dependencies,
70
            tasks=(insert_gas_data, insert_gas_data_eGon100RE),
71
        )
72
73
74
def download_SciGRID_gas_data():
75
    """
76
    Download SciGRID_gas IGGIELGN data from Zenodo
77
78
    The following data for CH4 are downloaded into the folder
79
    ./datasets/gas_data/data:
80
      * Buses (file IGGIELGN_Nodes.csv),
81
      * Pipelines (file IGGIELGN_PipeSegments.csv),
82
      * Productions (file IGGIELGN_Productions.csv),
83
      * Storages (file IGGIELGN_Storages.csv),
84
      * LNG terminals (file IGGIELGN_LNGs.csv).
85
86
    For more information on these data refer, to the
87
    `SciGRID_gas IGGIELGN documentation <https://zenodo.org/record/4767098>`_.
88
89
    Returns
90
    -------
91
    None
92
93
    """
94
    path = Path(".") / "datasets" / "gas_data"
95
    os.makedirs(path, exist_ok=True)
96
97
    basename = "IGGIELGN"
98
    zip_file = Path(".") / "datasets" / "gas_data" / "IGGIELGN.zip"
99
    zenodo_zip_file_url = (
100
        "https://zenodo.org/record/4767098/files/" + basename + ".zip"
101
    )
102
    if not os.path.isfile(zip_file):
103
        urlretrieve(zenodo_zip_file_url, zip_file)
104
105
    components = [
106
        "Nodes",
107
        "PipeSegments",
108
        "Productions",
109
        "Storages",
110
        "LNGs",
111
    ]  #'Compressors'
112
    files = []
113
    for i in components:
114
        files.append("data/" + basename + "_" + i + ".csv")
115
116
    with ZipFile(zip_file, "r") as zipObj:
117
        listOfFileNames = zipObj.namelist()
118
        for fileName in listOfFileNames:
119
            if fileName in files:
120
                zipObj.extract(fileName, path)
121
122
123
def define_gas_nodes_list():
124
    """
125
    Define list of CH4 buses from SciGRID_gas IGGIELGN data
126
127
    The CH4 nodes are modelled as buses. Therefore the SciGRID_gas nodes
128
    are red from the IGGIELGN_Nodes cvs file previously downloaded in the
129
    function :py:func:`download_SciGRID_gas_data`, corrected (erroneous country),
130
    and returned as dataframe.
131
132
    Returns
133
    -------
134
    gas_nodes_list : pandas.DataFrame
135
        Dataframe containing the gas nodes in Europe
136
137
    """
138
    # Select next id value
139
    new_id = db.next_etrago_id("bus")
140
141
    target_file = (
142
        Path(".") / "datasets" / "gas_data" / "data" / "IGGIELGN_Nodes.csv"
143
    )
144
145
    gas_nodes_list = pd.read_csv(
146
        target_file,
147
        delimiter=";",
148
        decimal=".",
149
        usecols=["lat", "long", "id", "country_code", "param"],
150
    )
151
152
    # Correct non valid neighbouring country nodes
153
    gas_nodes_list.loc[
154
        gas_nodes_list["id"] == "INET_N_1182", "country_code"
155
    ] = "AT"
156
    gas_nodes_list.loc[
157
        gas_nodes_list["id"] == "SEQ_10608_p", "country_code"
158
    ] = "NL"
159
    gas_nodes_list.loc[
160
        gas_nodes_list["id"] == "N_88_NS_LMGN", "country_code"
161
    ] = "XX"
162
163
    gas_nodes_list = gas_nodes_list.rename(columns={"lat": "y", "long": "x"})
164
165
    gas_nodes_list["bus_id"] = range(new_id, new_id + len(gas_nodes_list))
166
    gas_nodes_list = gas_nodes_list.set_index("id")
167
168
    return gas_nodes_list
169
170
171
def ch4_nodes_number_G(gas_nodes_list):
172
    """
173
    Return the number of CH4 buses in Germany
174
175
    Parameters
176
    ----------
177
    gas_nodes_list : pandas.DataFrame
178
        Dataframe containing the gas nodes in Europe
179
180
    Returns
181
    -------
182
    N_ch4_nodes_G : int
183
        Number of CH4 buses in Germany
184
185
    """
186
187
    ch4_nodes_list = gas_nodes_list[
188
        gas_nodes_list["country_code"].str.match("DE")
189
    ]
190
    N_ch4_nodes_G = len(ch4_nodes_list)
191
192
    return N_ch4_nodes_G
193
194
195
def insert_CH4_nodes_list(gas_nodes_list):
196
    """
197
    Insert list of German CH4 nodes into the database for eGon2035
198
199
    Insert the list of German CH4 nodes into the database by executing
200
    the following steps:
201
      * Receive the buses as parameter (from SciGRID_gas IGGIELGN data)
202
      * Add the missing information: scn_name and carrier
203
      * Clean the database table grid.egon_etrago_bus of the
204
        CH4 buses of the specific scenario (eGon2035) in Germany
205
      * Insert the buses in the table grid.egon_etrago_bus
206
207
    Parameters
208
    ----------
209
    gas_nodes_list : pandas.DataFrame
210
        Dataframe containing the gas nodes in Europe
211
212
    Returns
213
    -------
214
    None
215
216
    """
217
    # Connect to local database
218
    engine = db.engine()
219
220
    gas_nodes_list = gas_nodes_list[
221
        gas_nodes_list["country_code"].str.match("DE")
222
    ]  # To eventually replace with a test if the nodes are in the german boundaries.
223
224
    # Cut data to federal state if in testmode
225
    NUTS1 = []
226
    for index, row in gas_nodes_list.iterrows():
227
        param = ast.literal_eval(row["param"])
228
        NUTS1.append(param["nuts_id_1"])
229
    gas_nodes_list = gas_nodes_list.assign(NUTS1=NUTS1)
230
231
    boundary = settings()["egon-data"]["--dataset-boundary"]
232
    if boundary != "Everything":
233
        map_states = {
234
            "Baden-Württemberg": "DE1",
235
            "Nordrhein-Westfalen": "DEA",
236
            "Hessen": "DE7",
237
            "Brandenburg": "DE4",
238
            "Bremen": "DE5",
239
            "Rheinland-Pfalz": "DEB",
240
            "Sachsen-Anhalt": "DEE",
241
            "Schleswig-Holstein": "DEF",
242
            "Mecklenburg-Vorpommern": "DE8",
243
            "Thüringen": "DEG",
244
            "Niedersachsen": "DE9",
245
            "Sachsen": "DED",
246
            "Hamburg": "DE6",
247
            "Saarland": "DEC",
248
            "Berlin": "DE3",
249
            "Bayern": "DE2",
250
        }
251
252
        gas_nodes_list = gas_nodes_list[
253
            gas_nodes_list["NUTS1"].isin([map_states[boundary], np.nan])
254
        ]
255
256
        # A completer avec nodes related to pipelines which have an end in the selected area et evt deplacer ds define_gas_nodes_list
257
258
    # Add missing columns
259
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
260
    gas_nodes_list = gas_nodes_list.assign(**c)
261
262
    gas_nodes_list = geopandas.GeoDataFrame(
263
        gas_nodes_list,
264
        geometry=geopandas.points_from_xy(
265
            gas_nodes_list["x"], gas_nodes_list["y"]
266
        ),
267
    )
268
    gas_nodes_list = gas_nodes_list.rename(
269
        columns={"geometry": "geom"}
270
    ).set_geometry("geom", crs=4326)
271
272
    gas_nodes_list = gas_nodes_list.reset_index(drop=True)
273
    gas_nodes_list = gas_nodes_list.drop(
274
        columns=["NUTS1", "param", "country_code"]
275
    )
276
277
    # Insert data to db
278
    db.execute_sql(
279
        f"""
280
    DELETE FROM grid.egon_etrago_bus WHERE "carrier" = 'CH4' AND
281
    scn_name = '{c['scn_name']}' AND country = 'DE';
282
    """
283
    )
284
285
    # Insert CH4 data to db
286
    print(gas_nodes_list)
287
    gas_nodes_list.to_postgis(
288
        "egon_etrago_bus",
289
        engine,
290
        schema="grid",
291
        index=False,
292
        if_exists="append",
293
        dtype={"geom": Geometry()},
294
    )
295
296
297
def insert_gas_buses_abroad(scn_name="eGon2035"):
298
    """
299
    Insert CH4 buses in neighbouring countries to database for eGon2035
300
301
    For the scenario eGon2035, insert central CH4 buses in foreign
302
    countries to the database. The considered foreign countries are the
303
    direct neighbouring countries, with the addition of Russia that is
304
    considered as a source of fossil CH4.
305
    Therefore, the following steps are executed:
306
      * Definition of the foreign buses with the function
307
        :py:func:`import_central_buses_egon100 <egon.data.datasets.electrical_neighbours.central_buses_egon100>` from
308
        the module :py:mod:`electrical_neighbours <egon.data.datasets.electrical_neighbours>`
309
      * Removal of the superfluous buses in order to have only one bus
310
        in each neighbouring country
311
      * Removal of the the irrelevant columns
312
      * Addition of the missing information: scn_name and carrier
313
      * Attribution of an id to each bus
314
      * Cleaning of the database table grid.egon_etrago_bus of the
315
        CH4 buses of the specific scenario (eGon2035) out of Germany
316
      * Insertion of the neighbouring buses in the table grid.egon_etrago_bus.
317
318
    Returns
319
    -------
320
    gdf_abroad_buses : pandas.DataFrame
321
        Dataframe containing the gas buses in the neighbouring countries
322
        and one in the center of Germany in test mode
323
324
    """
325
    # Select sources and targets from dataset configuration
326
    sources = config.datasets()["electrical_neighbours"]["sources"]
327
328
    main_gas_carrier = get_sector_parameters("gas", scenario=scn_name)[
329
        "main_gas_carrier"
330
    ]
331
332
    # Connect to local database
333
    engine = db.engine()
334
    db.execute_sql(
335
        f"""
336
    DELETE FROM grid.egon_etrago_bus WHERE "carrier" = '{main_gas_carrier}' AND
337
    scn_name = '{scn_name}' AND country != 'DE';
338
    """
339
    )
340
341
    # Select the foreign buses
342
    gdf_abroad_buses = central_buses_egon100(sources)
343
    gdf_abroad_buses = gdf_abroad_buses.drop_duplicates(subset=["country"])
344
345
    # Select next id value
346
    new_id = db.next_etrago_id("bus")
347
348
    gdf_abroad_buses = gdf_abroad_buses.drop(
349
        columns=[
350
            "v_nom",
351
            "v_mag_pu_set",
352
            "v_mag_pu_min",
353
            "v_mag_pu_max",
354
            "geom",
355
        ]
356
    )
357
    gdf_abroad_buses["scn_name"] = "eGon2035"
358
    gdf_abroad_buses["carrier"] = main_gas_carrier
359
    gdf_abroad_buses["bus_id"] = range(new_id, new_id + len(gdf_abroad_buses))
360
361
    # Add central bus in Russia
362
    gdf_abroad_buses = gdf_abroad_buses.append(
363
        {
364
            "scn_name": scn_name,
365
            "bus_id": (new_id + len(gdf_abroad_buses) + 1),
366
            "x": 41,
367
            "y": 55,
368
            "country": "RU",
369
            "carrier": main_gas_carrier,
370
        },
371
        ignore_index=True,
372
    )
373
    # if in test mode, add bus in center of Germany
374
    boundary = settings()["egon-data"]["--dataset-boundary"]
375
376
    if boundary != "Everything":
377
        gdf_abroad_buses = gdf_abroad_buses.append(
378
            {
379
                "scn_name": scn_name,
380
                "bus_id": (new_id + len(gdf_abroad_buses) + 1),
381
                "x": 10.4234469,
382
                "y": 51.0834196,
383
                "country": "DE",
384
                "carrier": main_gas_carrier,
385
            },
386
            ignore_index=True,
387
        )
388
389
    gdf_abroad_buses = geopandas.GeoDataFrame(
390
        gdf_abroad_buses,
391
        geometry=geopandas.points_from_xy(
392
            gdf_abroad_buses["x"], gdf_abroad_buses["y"]
393
        ),
394
    )
395
    gdf_abroad_buses = gdf_abroad_buses.rename(
396
        columns={"geometry": "geom"}
397
    ).set_geometry("geom", crs=4326)
398
399
    # Insert to db
400
    print(gdf_abroad_buses)
401
    gdf_abroad_buses.to_postgis(
402
        "egon_etrago_bus",
403
        engine,
404
        schema="grid",
405
        index=False,
406
        if_exists="append",
407
        dtype={"geom": Geometry()},
408
    )
409
    return gdf_abroad_buses
410
411
412
def insert_gas_pipeline_list(
413
    gas_nodes_list, abroad_gas_nodes_list, scn_name="eGon2035"
414
):
415
    """
416
    Insert list of gas pipelines into the database
417
418
    The gas pipelines, modelled as Pypsa links are red from the IGGIELGN_PipeSegments
419
    csv file previously downloded in the function :py:func:`download_SciGRID_gas_data`,
420
    adapted and inserted in the database for the eGon2035 scenario.
421
    The manual corrections allows to:
422
      * Delete gas pipelines disconnected of the rest of the gas grid
423
      * Connect one pipeline (also connected to Norway) disconnected of
424
        the rest of the gas grid
425
      * Correct erroneous country of some pipelines
426
427
    The capacities of the pipelines are determined by the correspondance
428
    table given by the Parameters for the classification of gas pipelines
429
    in `Electricity, heat, and gas sector data for modeling the German system
430
    <https://www.econstor.eu/bitstream/10419/173388/1/1011162628.pdf>`_
431
    related to the pipeline diameter given in the SciGRID_gas dataset.
432
433
    The database is cleaned before the insertion of the pipelines.
434
435
    Parameters
436
    ----------
437
    gas_nodes_list : dataframe
438
        Dataframe containing the gas nodes in Europe
439
    abroad_gas_nodes_list: dataframe
440
        Dataframe containing the gas buses in the neighbouring countries
441
        and one in the center of Germany in test mode
442
    scn_name : str
443
        Name of the scenario
444
445
    Returns
446
    -------
447
    None
448
449
    """
450
    abroad_gas_nodes_list = abroad_gas_nodes_list.set_index("country")
451
452
    main_gas_carrier = get_sector_parameters("gas", scenario=scn_name)[
453
        "main_gas_carrier"
454
    ]
455
456
    engine = db.engine()
457
458
    # Select next id value
459
    new_id = db.next_etrago_id("link")
460
461
    classifiaction_file = (
462
        Path(".")
463
        / "data_bundle_egon_data"
464
        / "pipeline_classification_gas"
465
        / "pipeline_classification.csv"
466
    )
467
468
    classification = pd.read_csv(
469
        classifiaction_file,
470
        delimiter=",",
471
        usecols=["classification", "max_transport_capacity_Gwh/d"],
472
    )
473
474
    target_file = (
475
        Path(".")
476
        / "datasets"
477
        / "gas_data"
478
        / "data"
479
        / "IGGIELGN_PipeSegments.csv"
480
    )
481
482
    gas_pipelines_list = pd.read_csv(
483
        target_file,
484
        delimiter=";",
485
        decimal=".",
486
        usecols=["id", "node_id", "lat", "long", "country_code", "param"],
487
    )
488
489
    # Select the links having at least one bus in Germany
490
    gas_pipelines_list = gas_pipelines_list[
491
        gas_pipelines_list["country_code"].str.contains("DE")
492
    ]
493
    # Remove links disconnected of the rest of the grid
494
    # Remove manually for disconnected link EntsoG_Map__ST_195 and EntsoG_Map__ST_108
495
    gas_pipelines_list = gas_pipelines_list[
496
        gas_pipelines_list["node_id"] != "['SEQ_11790_p', 'Stor_EU_107']"
497
    ]
498
    gas_pipelines_list = gas_pipelines_list[
499
        ~gas_pipelines_list["id"].str.match("EntsoG_Map__ST_108")
500
    ]
501
502
    # Manually add pipeline to artificially connect isolated pipeline
503
    gas_pipelines_list.at["new_pipe", "param"] = gas_pipelines_list[
504
        gas_pipelines_list["id"] == "NO_PS_8_Seg_0_Seg_23"
505
    ]["param"].values[0]
506
    gas_pipelines_list.at[
507
        "new_pipe", "node_id"
508
    ] = "['SEQ_12442_p', 'LKD_N_200']"
509
    gas_pipelines_list.at["new_pipe", "lat"] = "[53.358536, 53.412719]"
510
    gas_pipelines_list.at["new_pipe", "long"] = "[7.041677, 7.093251]"
511
    gas_pipelines_list.at["new_pipe", "country_code"] = "['DE', 'DE']"
512
513
    gas_pipelines_list["link_id"] = range(
514
        new_id, new_id + len(gas_pipelines_list)
515
    )
516
    gas_pipelines_list["link_id"] = gas_pipelines_list["link_id"].astype(int)
517
518
    # Cut data to federal state if in testmode
519
    NUTS1 = []
520
    for index, row in gas_pipelines_list.iterrows():
521
        param = ast.literal_eval(row["param"])
522
        NUTS1.append(param["nuts_id_1"])
523
    gas_pipelines_list["NUTS1"] = NUTS1
524
525
    map_states = {
526
        "Baden-Württemberg": "DE1",
527
        "Nordrhein-Westfalen": "DEA",
528
        "Hessen": "DE7",
529
        "Brandenburg": "DE4",
530
        "Bremen": "DE5",
531
        "Rheinland-Pfalz": "DEB",
532
        "Sachsen-Anhalt": "DEE",
533
        "Schleswig-Holstein": "DEF",
534
        "Mecklenburg-Vorpommern": "DE8",
535
        "Thüringen": "DEG",
536
        "Niedersachsen": "DE9",
537
        "Sachsen": "DED",
538
        "Hamburg": "DE6",
539
        "Saarland": "DEC",
540
        "Berlin": "DE3",
541
        "Bayern": "DE2",
542
        "Everything": "Nan",
543
    }
544
    gas_pipelines_list["NUTS1_0"] = [x[0] for x in gas_pipelines_list["NUTS1"]]
545
    gas_pipelines_list["NUTS1_1"] = [x[1] for x in gas_pipelines_list["NUTS1"]]
546
547
    boundary = settings()["egon-data"]["--dataset-boundary"]
548
549
    if boundary != "Everything":
550
551
        gas_pipelines_list = gas_pipelines_list[
552
            gas_pipelines_list["NUTS1_0"].str.contains(map_states[boundary])
553
            | gas_pipelines_list["NUTS1_1"].str.contains(map_states[boundary])
554
        ]
555
556
    # Add missing columns
557
    gas_pipelines_list["scn_name"] = scn_name
558
    gas_pipelines_list["carrier"] = main_gas_carrier
559
    gas_pipelines_list["p_nom_extendable"] = False
560
    gas_pipelines_list["p_min_pu"] = -1.0
561
562
    diameter = []
563
    geom = []
564
    topo = []
565
    length_km = []
566
567
    for index, row in gas_pipelines_list.iterrows():
568
569
        param = ast.literal_eval(row["param"])
570
        diameter.append(param["diameter_mm"])
571
        length_km.append(param["length_km"])
572
573
        long_e = json.loads(row["long"])
574
        lat_e = json.loads(row["lat"])
575
        crd_e = list(zip(long_e, lat_e))
576
        topo.append(geometry.LineString(crd_e))
577
578
        long_path = param["path_long"]
579
        lat_path = param["path_lat"]
580
        crd = list(zip(long_path, lat_path))
581
        crd.insert(0, crd_e[0])
582
        crd.append(crd_e[1])
583
        lines = []
584
        for i in range(len(crd) - 1):
585
            lines.append(geometry.LineString([crd[i], crd[i + 1]]))
586
        geom.append(geometry.MultiLineString(lines))
587
588
    gas_pipelines_list["diameter"] = diameter
589
    gas_pipelines_list["geom"] = geom
590
    gas_pipelines_list["topo"] = topo
591
    gas_pipelines_list["length_km"] = length_km
592
    gas_pipelines_list = gas_pipelines_list.set_geometry("geom", crs=4326)
593
594
    country_0 = []
595
    country_1 = []
596
    for index, row in gas_pipelines_list.iterrows():
597
        c = ast.literal_eval(row["country_code"])
598
        country_0.append(c[0])
599
        country_1.append(c[1])
600
601
    gas_pipelines_list["country_0"] = country_0
602
    gas_pipelines_list["country_1"] = country_1
603
604
    # Correct non valid neighbouring country nodes
605
    gas_pipelines_list.loc[
606
        gas_pipelines_list["country_0"] == "XX", "country_0"
607
    ] = "NO"
608
    gas_pipelines_list.loc[
609
        gas_pipelines_list["country_1"] == "FI", "country_1"
610
    ] = "RU"
611
    gas_pipelines_list.loc[
612
        gas_pipelines_list["id"] == "ST_2612_Seg_0_Seg_0", "country_0"
613
    ] = "AT"  # bus "INET_N_1182" DE -> AT
614
    gas_pipelines_list.loc[
615
        gas_pipelines_list["id"] == "INET_PL_385_EE_3_Seg_0_Seg_1", "country_1"
616
    ] = "AT"  # "INET_N_1182" DE -> AT
617
    gas_pipelines_list.loc[
618
        gas_pipelines_list["id"] == "LKD_PS_0_Seg_0_Seg_3", "country_0"
619
    ] = "NL"  # bus "SEQ_10608_p" DE -> NL
620
621
    # Remove uncorrect pipelines
622
    gas_pipelines_list = gas_pipelines_list[
623
        (gas_pipelines_list["id"] != "PLNG_2637_Seg_0_Seg_0_Seg_0")
624
        & (gas_pipelines_list["id"] != "NSG_6650_Seg_2_Seg_0")
625
        & (gas_pipelines_list["id"] != "NSG_6734_Seg_2_Seg_0")
626
    ]
627
628
    # Remove link test if length = 0
629
    gas_pipelines_list = gas_pipelines_list[
630
        gas_pipelines_list["length_km"] != 0
631
    ]
632
633
    # Adjust columns
634
    bus0 = []
635
    bus1 = []
636
    geom_adjusted = []
637
    topo_adjusted = []
638
    length_adjusted = []
639
    pipe_class = []
640
641
    for index, row in gas_pipelines_list.iterrows():
642
        buses = row["node_id"].strip("][").split(", ")
643
644
        if (
645
            (boundary != "Everything")
646
            & (row["NUTS1_0"] != map_states[boundary])
647
            & (row["country_0"] == "DE")
648
        ):
649
            bus0.append(abroad_gas_nodes_list.loc["DE", "bus_id"])
650
            bus1.append(gas_nodes_list.loc[buses[1][1:-1], "bus_id"])
651
            long_e = [
652
                abroad_gas_nodes_list.loc["DE", "x"],
653
                json.loads(row["long"])[1],
654
            ]
655
            lat_e = [
656
                abroad_gas_nodes_list.loc["DE", "y"],
657
                json.loads(row["lat"])[1],
658
            ]
659
            geom_pipe = geometry.MultiLineString(
660
                [geometry.LineString(list(zip(long_e, lat_e)))]
661
            )
662
            topo_adjusted.append(geometry.LineString(list(zip(long_e, lat_e))))
663
664
        elif row["country_0"] != "DE":
665
            country = str(row["country_0"])
666
            bus0.append(abroad_gas_nodes_list.loc[country, "bus_id"])
667
            bus1.append(gas_nodes_list.loc[buses[1][1:-1], "bus_id"])
668
            long_e = [
669
                abroad_gas_nodes_list.loc[country, "x"],
670
                json.loads(row["long"])[1],
671
            ]
672
            lat_e = [
673
                abroad_gas_nodes_list.loc[country, "y"],
674
                json.loads(row["lat"])[1],
675
            ]
676
            geom_pipe = geometry.MultiLineString(
677
                [geometry.LineString(list(zip(long_e, lat_e)))]
678
            )
679
            topo_adjusted.append(geometry.LineString(list(zip(long_e, lat_e))))
680
681
        elif (
682
            (boundary != "Everything")
683
            & (row["NUTS1_1"] != map_states[boundary])
684
            & (row["country_1"] == "DE")
685
        ):
686
            bus0.append(gas_nodes_list.loc[buses[0][1:-1], "bus_id"])
687
            bus1.append(abroad_gas_nodes_list.loc["DE", "bus_id"])
688
            long_e = [
689
                json.loads(row["long"])[0],
690
                abroad_gas_nodes_list.loc["DE", "x"],
691
            ]
692
            lat_e = [
693
                json.loads(row["lat"])[0],
694
                abroad_gas_nodes_list.loc["DE", "y"],
695
            ]
696
            geom_pipe = geometry.MultiLineString(
697
                [geometry.LineString(list(zip(long_e, lat_e)))]
698
            )
699
            topo_adjusted.append(geometry.LineString(list(zip(long_e, lat_e))))
700
701
        elif row["country_1"] != "DE":
702
            country = str(row["country_1"])
703
            bus0.append(gas_nodes_list.loc[buses[0][1:-1], "bus_id"])
704
            bus1.append(abroad_gas_nodes_list.loc[country, "bus_id"])
705
            long_e = [
706
                json.loads(row["long"])[0],
707
                abroad_gas_nodes_list.loc[country, "x"],
708
            ]
709
            lat_e = [
710
                json.loads(row["lat"])[0],
711
                abroad_gas_nodes_list.loc[country, "y"],
712
            ]
713
            geom_pipe = geometry.MultiLineString(
714
                [geometry.LineString(list(zip(long_e, lat_e)))]
715
            )
716
            topo_adjusted.append(geometry.LineString(list(zip(long_e, lat_e))))
717
718
        else:
719
            bus0.append(gas_nodes_list.loc[buses[0][1:-1], "bus_id"])
720
            bus1.append(gas_nodes_list.loc[buses[1][1:-1], "bus_id"])
721
            geom_pipe = row["geom"]
722
            topo_adjusted.append(row["topo"])
723
724
        geom_adjusted.append(geom_pipe)
725
        length_adjusted.append(geom_pipe.length)
726
727
        if row["diameter"] >= 1000:
728
            pipe_class = "A"
729
        elif 700 <= row["diameter"] <= 1000:
730
            pipe_class = "B"
731
        elif 500 <= row["diameter"] <= 700:
732
            pipe_class = "C"
733
        elif 350 <= row["diameter"] <= 500:
734
            pipe_class = "D"
735
        elif 200 <= row["diameter"] <= 350:
736
            pipe_class = "E"
737
        elif 100 <= row["diameter"] <= 200:
738
            pipe_class = "F"
739
        elif row["diameter"] <= 100:
740
            pipe_class = "G"
741
742
    gas_pipelines_list["bus0"] = bus0
743
    gas_pipelines_list["bus1"] = bus1
744
    gas_pipelines_list["geom"] = geom_adjusted
745
    gas_pipelines_list["topo"] = topo_adjusted
746
    gas_pipelines_list["length"] = length_adjusted
747
    gas_pipelines_list["pipe_class"] = pipe_class
748
749
    # Remove pipes having the same node for start and end
750
    gas_pipelines_list = gas_pipelines_list[
751
        gas_pipelines_list["bus0"] != gas_pipelines_list["bus1"]
752
    ]
753
754
    gas_pipelines_list = gas_pipelines_list.merge(
755
        classification,
756
        how="left",
757
        left_on="pipe_class",
758
        right_on="classification",
759
    )
760
    gas_pipelines_list["p_nom"] = gas_pipelines_list[
761
        "max_transport_capacity_Gwh/d"
762
    ] * (1000 / 24)
763
764
    # Remove useless columns
765
    gas_pipelines_list = gas_pipelines_list.drop(
766
        columns=[
767
            "id",
768
            "node_id",
769
            "param",
770
            "NUTS1",
771
            "NUTS1_0",
772
            "NUTS1_1",
773
            "country_code",
774
            "country_0",
775
            "country_1",
776
            "diameter",
777
            "pipe_class",
778
            "classification",
779
            "max_transport_capacity_Gwh/d",
780
            "lat",
781
            "long",
782
            "length_km",
783
        ]
784
    )
785
786
    # Clean db
787
    db.execute_sql(
788
        f"""DELETE FROM grid.egon_etrago_link
789
        WHERE "carrier" = '{main_gas_carrier}'
790
        AND scn_name = '{scn_name}';
791
        """
792
    )
793
794
    print(gas_pipelines_list)
795
    # Insert data to db
796
    gas_pipelines_list.to_postgis(
797
        "egon_etrago_gas_link",
798
        engine,
799
        schema="grid",
800
        index=False,
801
        if_exists="replace",
802
        dtype={"geom": Geometry(), "topo": Geometry()},
803
    )
804
805
    db.execute_sql(
806
        """
807
    select UpdateGeometrySRID('grid', 'egon_etrago_gas_link', 'topo', 4326) ;
808
809
    INSERT INTO grid.egon_etrago_link (scn_name,
810
                                              link_id, carrier,
811
                                              bus0, bus1, p_min_pu,
812
                                              p_nom, p_nom_extendable, length,
813
                                              geom, topo)
814
    SELECT scn_name,
815
                link_id, carrier,
816
                bus0, bus1, p_min_pu,
817
                p_nom, p_nom_extendable, length,
818
                geom, topo
819
820
    FROM grid.egon_etrago_gas_link;
821
822
    DROP TABLE grid.egon_etrago_gas_link;
823
        """
824
    )
825
826
827
def remove_isolated_gas_buses():
828
    """
829
    Delete CH4 buses which are disconnected of the CH4 grid for the eGon2035 scenario
830
831
    This function deletes directly in the database and has no return.
832
833
    """
834
    targets = config.datasets()["gas_grid"]["targets"]
835
836
    db.execute_sql(
837
        f"""
838
        DELETE FROM {targets['buses']['schema']}.{targets['buses']['table']}
839
        WHERE "carrier" = 'CH4'
840
        AND scn_name = 'eGon2035'
841
        AND country = 'DE'
842
        AND "bus_id" NOT IN
843
            (SELECT bus0 FROM {targets['links']['schema']}.{targets['links']['table']}
844
            WHERE scn_name = 'eGon2035'
845
            AND carrier = 'CH4')
846
        AND "bus_id" NOT IN
847
            (SELECT bus1 FROM {targets['links']['schema']}.{targets['links']['table']}
848
            WHERE scn_name = 'eGon2035'
849
            AND carrier = 'CH4');
850
    """
851
    )
852
853
854
def insert_gas_data():
855
    """
856
    Overall function for importing methane data for eGon2035
857
858
    This function import the methane data (buses and pipelines) for
859
    eGon2035, by executing the following steps:
860
      * Download the SciGRID_gas datasets with the function :py:func:`download_SciGRID_gas_data`
861
      * Define CH4 buses with the function :py:func:`define_gas_nodes_list`
862
      * Insert the CH4 buses in Germany into the database with the
863
        function :py:func:`insert_CH4_nodes_list`
864
      * Insert the CH4 buses abroad into the database with the function
865
        :py:func:`insert_gas_buses_abroad`
866
      * Insert the CH4 links representing the CH4 pipeline into the
867
        database with the function :py:func:`insert_gas_pipeline_list`
868
      * Remove the isolated CH4 buses directly from the database using
869
        the function :py:func:`remove_isolated_gas_buses`
870
871
    This function inserts data into the database and has no return.
872
873
    """
874
    download_SciGRID_gas_data()
875
876
    gas_nodes_list = define_gas_nodes_list()
877
878
    insert_CH4_nodes_list(gas_nodes_list)
879
    abroad_gas_nodes_list = insert_gas_buses_abroad()
880
881
    insert_gas_pipeline_list(gas_nodes_list, abroad_gas_nodes_list)
882
    remove_isolated_gas_buses()
883
884
885
def insert_gas_data_eGon100RE():
886
    """
887
    Overall function for importing methane data for eGon100RE
888
889
    This function import the methane data (buses and pipelines) for
890
    eGon100RE, by copying the CH4 buses from the eGon2035 scenario using
891
    the function :py:func:`copy_and_modify_buses <egon.data.datasets.etrago_helpers.copy_and_modify_buses>`
892
    from the module :py:mod:`etrago_helpers <egon.data.datasets.etrago_helpers>`. The methane
893
    pipelines are also copied and their capacities are adapted: one
894
    share of the methane grid is retroffited into an hydrogen grid, so
895
    the methane pieplines nominal capacities are reduced from this share
896
    (calculated in the pyspa-eur-sec run).
897
898
    This function inserts data into the database and has no return.
899
900
    """
901
    # copy buses
902
    copy_and_modify_buses("eGon2035", "eGon100RE", {"carrier": ["CH4"]})
903
904
    # get CH4 pipelines and modify their nominal capacity with the
905
    # retrofitting factor
906
    gdf = db.select_geodataframe(
907
        f"""
908
        SELECT * FROM grid.egon_etrago_link
909
        WHERE carrier = 'CH4' AND scn_name = 'eGon2035' AND
910
        bus0 IN (
911
            SELECT bus_id FROM grid.egon_etrago_bus
912
            WHERE scn_name = 'eGon2035' AND country = 'DE'
913
        ) AND bus1 IN (
914
            SELECT bus_id FROM grid.egon_etrago_bus
915
            WHERE scn_name = 'eGon2035' AND country = 'DE'
916
        );
917
        """,
918
        epsg=4326,
919
        geom_col="topo",
920
    )
921
922
    # Update scenario specific information
923
    scn_name = "eGon100RE"
924
    gdf["scn_name"] = scn_name
925
    scn_params = get_sector_parameters("gas", scn_name)
926
927
    for param in ["capital_cost", "marginal_cost", "efficiency"]:
928
        try:
929
            gdf.loc[:, param] = scn_params[param]["CH4"]
930
        except KeyError:
931
            pass
932
933
    # remaining CH4 share is 1 - retroffited pipeline share
934
    gdf["p_nom"] *= (
935
        1 - scn_params["retrofitted_CH4pipeline-to-H2pipeline_share"]
936
    )
937
938
    # delete old entries
939
    db.execute_sql(
940
        f"""
941
        DELETE FROM grid.egon_etrago_link
942
        WHERE carrier = 'CH4' AND scn_name = '{scn_name}' AND
943
        bus0 NOT IN (
944
            SELECT bus_id FROM grid.egon_etrago_bus
945
            WHERE scn_name = '{scn_name}' AND country != 'DE'
946
        ) AND bus1 NOT IN (
947
            SELECT bus_id FROM grid.egon_etrago_bus
948
            WHERE scn_name = '{scn_name}' AND country != 'DE'
949
        );
950
        """
951
    )
952
953
    gdf.to_postgis(
954
        "egon_etrago_link",
955
        schema="grid",
956
        if_exists="append",
957
        con=db.engine(),
958
        index=False,
959
        dtype={"geom": Geometry(), "topo": Geometry()},
960
    )
961