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

insert_generators()   A

Complexity

Conditions 1

Size

Total Lines 63
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 63
rs 9.232
c 0
b 0
f 0
cc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 geoalchemy2.types import Geometry
10
from shapely.geometry import LineString, MultiLineString
11
import geopandas as gpd
12
import numpy as np
13
import pandas as pd
14
import pypsa
15
16
from egon.data import config, db
17
from egon.data.datasets import Dataset
18
from egon.data.datasets.electrical_neighbours import (
19
    get_foreign_bus_id,
20
    get_map_buses,
21
)
22
from egon.data.datasets.gas_neighbours.gas_abroad import (
23
    get_foreign_gas_bus_id,
24
    insert_gas_grid_capacities,
25
    insert_generators,
26
)
27
from egon.data.datasets.scenario_parameters import get_sector_parameters
28
29
countries = [
30
    "AT",
31
    "BE",
32
    "CH",
33
    "CZ",
34
    "DK",
35
    "FR",
36
    "GB",
37
    "LU",
38
    "NL",
39
    "NO",
40
    "PL",
41
    "RU",
42
    "SE",
43
    "UK",
44
]
45
46
47
def read_LNG_capacities():
48
    lng_file = "datasets/gas_data/data/IGGIELGN_LNGs.csv"
49
    IGGIELGN_LNGs = gpd.read_file(lng_file)
50
51
    map_countries_scigrid = {
52
        "BE": "BE00",
53
        "EE": "EE00",
54
        "EL": "GR00",
55
        "ES": "ES00",
56
        "FI": "FI00",
57
        "FR": "FR00",
58
        "GB": "UK00",
59
        "IT": "ITCN",
60
        "LT": "LT00",
61
        "LV": "LV00",
62
        "MT": "MT00",
63
        "NL": "NL00",
64
        "PL": "PL00",
65
        "PT": "PT00",
66
        "SE": "SE01",
67
    }
68
69
    conversion_factor = 437.5  # MCM/day to MWh/h
70
    c2 = 24 / 1000  # MWh/h to GWh/d
71
    p_nom = []
72
73
    for index, row in IGGIELGN_LNGs.iterrows():
74
        param = ast.literal_eval(row["param"])
75
        p_nom.append(
76
            param["max_cap_store2pipe_M_m3_per_d"] * conversion_factor * c2
77
        )
78
79
    IGGIELGN_LNGs["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] = p_nom
80
81
    IGGIELGN_LNGs.drop(
82
        [
83
            "uncertainty",
84
            "method",
85
            "param",
86
            "comment",
87
            "tags",
88
            "source_id",
89
            "lat",
90
            "long",
91
            "geometry",
92
            "id",
93
            "name",
94
            "node_id",
95
        ],
96
        axis=1,
97
        inplace=True,
98
    )
99
100
    IGGIELGN_LNGs["Country"] = IGGIELGN_LNGs["country_code"].map(
101
        map_countries_scigrid
102
    )
103
    IGGIELGN_LNGs = (
104
        IGGIELGN_LNGs.groupby(["Country"])[
105
            "LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"
106
        ]
107
        .sum()
108
        .sort_index()
109
    )
110
111
    return IGGIELGN_LNGs
112
113
114
def calc_capacities():
115
    """Calculates gas production capacities from TYNDP data
116
117
    Returns
118
    -------
119
    grouped_capacities : pandas.DataFrame
120
        Gas production capacities per foreign node
121
122
    """
123
124
    sources = config.datasets()["gas_neighbours"]["sources"]
125
126
    # insert installed capacities
127
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
128
    df = pd.read_excel(
129
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
130
        sheet_name="Gas Data",
131
    )
132
133
    df = (
134
        df.query(
135
            'Scenario == "Distributed Energy" & '
136
            '(Case == "Peak" | Case == "Average") &'  # Case: 2 Week/Average/DF/Peak
137
            'Category == "Production"'
138
        )
139
        .drop(
140
            columns=[
141
                "Generator_ID",
142
                "Climate Year",
143
                "Simulation_ID",
144
                "Node 1",
145
                "Path",
146
                "Direct/Indirect",
147
                "Sector",
148
                "Note",
149
                "Category",
150
                "Scenario",
151
            ]
152
        )
153
        .set_index("Node/Line")
154
        .sort_index()
155
    )
156
157
    lng = read_LNG_capacities()
158
    df_2030 = calc_capacity_per_year(df, lng, 2030)
159
    df_2040 = calc_capacity_per_year(df, lng, 2040)
160
161
    # Conversion GWh/d to MWh/h
162
    conversion_factor = 1000 / 24
163
164
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
165
    df_2035 = df_2035.drop(
166
        columns=[
167
            "Value_conv_2040",
168
            "Value_conv_2030",
169
            "Value_bio_2040",
170
            "Value_bio_2030",
171
        ]
172
    )
173
    df_2035["cap_2035"] = (df_2035["CH4_2030"] + df_2035["CH4_2040"]) / 2
174
    df_2035["e_nom_max"] = (
175
        ((df_2035["e_nom_max_2030"] + df_2035["e_nom_max_2040"]) / 2)
176
        * conversion_factor
177
        * 8760
178
    )
179
    df_2035["ratioConv_2035"] = (
180
        df_2035["ratioConv_2030"] + df_2035["ratioConv_2040"]
181
    ) / 2
182
    grouped_capacities = df_2035.drop(
183
        columns=[
184
            "ratioConv_2030",
185
            "ratioConv_2040",
186
            "CH4_2040",
187
            "CH4_2030",
188
            "e_nom_max_2030",
189
            "e_nom_max_2040",
190
        ]
191
    ).reset_index()
192
193
    grouped_capacities["cap_2035"] = (
194
        grouped_capacities["cap_2035"] * conversion_factor
195
    )
196
197
    # Add generator in Russia of infinite capacity
198
    grouped_capacities = grouped_capacities.append(
199
        {
200
            "cap_2035": 1e9,
201
            "e_nom_max": np.inf,
202
            "ratioConv_2035": 1,
203
            "index": "RU",
204
        },
205
        ignore_index=True,
206
    )
207
208
    # choose capacities for considered countries
209
    grouped_capacities = grouped_capacities[
210
        grouped_capacities["index"].str[:2].isin(countries)
211
    ]
212
    return grouped_capacities
213
214
215
def calc_capacity_per_year(df, lng, year):
216
    """Calculates gas production capacities from TYNDP data for a specified year
217
218
    Parameters
219
    ----------
220
    df : pandas.DataFrame
221
        DataFrame containing all TYNDP data.
222
223
    lng : geopandas.GeoDataFrame
224
        Georeferenced LNG terminal capacities.
225
226
    year : int
227
        Year to calculate gas production capacity for.
228
229
    Returns
230
    -------
231
    pandas.DataFrame
232
        Gas production capacities per foreign node and energy carrier
233
    """
234
    df_conv_peak = (
235
        df[
236
            (df["Parameter"] == "Conventional")
237
            & (df["Year"] == year)
238
            & (df["Case"] == "Peak")
239
        ]
240
        .rename(columns={"Value": f"Value_conv_{year}_peak"})
241
        .drop(columns=["Parameter", "Year", "Case"])
242
    )
243
    df_conv_average = (
244
        df[
245
            (df["Parameter"] == "Conventional")
246
            & (df["Year"] == year)
247
            & (df["Case"] == "Average")
248
        ]
249
        .rename(columns={"Value": f"Value_conv_{year}_average"})
250
        .drop(columns=["Parameter", "Year", "Case"])
251
    )
252
    df_bioch4 = (
253
        df[
254
            (df["Parameter"] == "Biomethane")
255
            & (df["Year"] == year)
256
            & (
257
                df["Case"] == "Peak"
258
            )  # Peak and Average have the same valus for biogas production in 2030 and 2040
259
        ]
260
        .rename(columns={"Value": f"Value_bio_{year}"})
261
        .drop(columns=["Parameter", "Year", "Case"])
262
    )
263
264
    # Some values are duplicated (DE00 in 2030)
265
    df_conv_peak = df_conv_peak[~df_conv_peak.index.duplicated(keep="first")]
266
    df_conv_average = df_conv_average[
267
        ~df_conv_average.index.duplicated(keep="first")
268
    ]
269
270
    df_year = pd.concat(
271
        [df_conv_peak, df_conv_average, df_bioch4, lng], axis=1
272
    ).fillna(0)
273
    df_year = df_year[
274
        ~(
275
            (df_year[f"Value_conv_{year}_peak"] == 0)
276
            & (df_year[f"Value_bio_{year}"] == 0)
277
            & (df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] == 0)
278
        )
279
    ]
280
    df_year[f"Value_conv_{year}"] = (
281
        df_year[f"Value_conv_{year}_peak"]
282
        + df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
283
    )
284
    df_year[f"CH4_{year}"] = (
285
        df_year[f"Value_conv_{year}"] + df_year[f"Value_bio_{year}"]
286
    )
287
    df_year[f"ratioConv_{year}"] = (
288
        df_year[f"Value_conv_{year}_peak"] / df_year[f"CH4_{year}"]
289
    )
290
    df_year[f"e_nom_max_{year}"] = (
291
        df_year[f"Value_conv_{year}_average"] + df_year[f"Value_bio_{year}"]
292
    )
293
    df_year = df_year.drop(
294
        columns=[
295
            "LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)",
296
            f"Value_conv_{year}_average",
297
            f"Value_conv_{year}_peak",
298
        ]
299
    )
300
301
    return df_year
302
303
304
def calc_global_ch4_demand(Norway_global_demand_1y):
305
    """Calculates global CH4 demands abroad for eGon2035 scenario
306
307
    The data comes from TYNDP 2020 according to NEP 2021 from the
308
    scenario 'Distributed Energy', linear interpolate between 2030
309
    and 2040.
310
311
    Returns
312
    -------
313
    pandas.DataFrame
314
        Global (yearly) CH4 final demand per foreign node
315
316
    """
317
318
    sources = config.datasets()["gas_neighbours"]["sources"]
319
320
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
321
    df = pd.read_excel(
322
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
323
        sheet_name="Gas Data",
324
    )
325
326
    df = (
327
        df.query(
328
            'Scenario == "Distributed Energy" & '
329
            'Case == "Average" &'
330
            'Category == "Demand"'
331
        )
332
        .drop(
333
            columns=[
334
                "Generator_ID",
335
                "Climate Year",
336
                "Simulation_ID",
337
                "Node 1",
338
                "Path",
339
                "Direct/Indirect",
340
                "Sector",
341
                "Note",
342
                "Category",
343
                "Case",
344
                "Scenario",
345
            ]
346
        )
347
        .set_index("Node/Line")
348
    )
349
350
    df_2030 = (
351
        df[(df["Parameter"] == "Final demand") & (df["Year"] == 2030)]
352
        .rename(columns={"Value": "Value_2030"})
353
        .drop(columns=["Parameter", "Year"])
354
    )
355
356
    df_2040 = (
357
        df[(df["Parameter"] == "Final demand") & (df["Year"] == 2040)]
358
        .rename(columns={"Value": "Value_2040"})
359
        .drop(columns=["Parameter", "Year"])
360
    )
361
362
    # Conversion GWh/d to MWh/h
363
    conversion_factor = 1000 / 24
364
365
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
366
    df_2035["GlobD_2035"] = (
367
        (df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
368
    ) * conversion_factor
369
    df_2035.loc["NOS0"] = [
370
        0,
371
        0,
372
        Norway_global_demand_1y / 8760,
373
    ]  # Manually add Norway demand
374
    grouped_demands = df_2035.drop(
375
        columns=["Value_2030", "Value_2040"]
376
    ).reset_index()
377
378
    # choose demands for considered countries
379
    return grouped_demands[
380
        grouped_demands["Node/Line"].str[:2].isin(countries)
381
    ]
382
383
384
def import_ch4_demandTS():
385
    """Calculate global CH4 demand in Norway and CH4 demand profile
386
387
    Import from the PyPSA-eur-sec run the timeseries of residential
388
    rural heat per neighbor country. This timeserie is used to
389
    calculate:
390
      * the global (yearly) heat demand of Norway
391
        (that will be supplied by CH4)
392
      * the normalized CH4 hourly resolved demand profile
393
394
    Parameters
395
    ----------
396
    None.
397
398
    Returns
399
    -------
400
    Norway_global_demand: Float
401
        Yearly heat demand of Norway in MWh
402
    neighbor_loads_t: pandas.DataFrame
403
        Normalized CH4 hourly resolved demand profiles per neighbor country
404
405
    """
406
407
    cwd = Path(".")
408
    target_file = (
409
        cwd
410
        / "data_bundle_egon_data"
411
        / "pypsa_eur_sec"
412
        / "2022-07-26-egondata-integration"
413
        / "postnetworks"
414
        / "elec_s_37_lv2.0__Co2L0-1H-T-H-B-I-dist1_2050.nc"
415
    )
416
417
    network = pypsa.Network(str(target_file))
418
419
    # Set country tag for all buses
420
    network.buses.country = network.buses.index.str[:2]
421
    neighbors = network.buses[network.buses.country != "DE"]
422
    neighbors = neighbors[
423
        (neighbors["country"].isin(countries))
424
        & (neighbors["carrier"] == "residential rural heat")
425
    ].drop_duplicates(subset="country")
426
427
    neighbor_loads = network.loads[network.loads.bus.isin(neighbors.index)]
428
    neighbor_loads_t_index = neighbor_loads.index[
429
        neighbor_loads.index.isin(network.loads_t.p_set.columns)
430
    ]
431
    neighbor_loads_t = network.loads_t["p_set"][neighbor_loads_t_index]
432
    Norway_global_demand = neighbor_loads_t[
433
        "NO3 0 residential rural heat"
434
    ].sum()
435
436
    for i in neighbor_loads_t.columns:
437
        neighbor_loads_t[i] = neighbor_loads_t[i] / neighbor_loads_t[i].sum()
438
439
    return Norway_global_demand, neighbor_loads_t
440
441
442
def insert_ch4_demand(global_demand, normalized_ch4_demandTS):
443
    """Insert CH4 demands abroad in the database for eGon2035
444
445
    Parameters
446
    ----------
447
    global_demand : pandas.DataFrame
448
        Global CH4 demand per foreign node in 1 year
449
    gas_demandTS : pandas.DataFrame
450
        Normalized time serie of the demand per foreign country
451
452
    Returns
453
    -------
454
    None.
455
456
    """
457
    sources = config.datasets()["gas_neighbours"]["sources"]
458
    targets = config.datasets()["gas_neighbours"]["targets"]
459
    map_buses = get_map_buses()
460
461
    scn_name = "eGon2035"
462
    carrier = "CH4"
463
464
    # Delete existing data
465
    db.execute_sql(
466
        f"""
467
        DELETE FROM 
468
        {targets['load_timeseries']['schema']}.{targets['load_timeseries']['table']}
469
        WHERE "load_id" IN (
470
            SELECT load_id FROM 
471
            {targets['loads']['schema']}.{targets['loads']['table']}
472
            WHERE bus IN (
473
                SELECT bus_id FROM
474
                {sources['buses']['schema']}.{sources['buses']['table']}
475
                WHERE country != 'DE'
476
                AND scn_name = '{scn_name}')
477
            AND scn_name = '{scn_name}'
478
            AND carrier = '{carrier}'
479
        );
480
        """
481
    )
482
483
    db.execute_sql(
484
        f"""
485
        DELETE FROM
486
        {targets['loads']['schema']}.{targets['loads']['table']}
487
        WHERE bus IN (
488
            SELECT bus_id FROM
489
            {sources['buses']['schema']}.{sources['buses']['table']}
490
            WHERE country != 'DE'
491
            AND scn_name = '{scn_name}')
492
        AND scn_name = '{scn_name}'
493
        AND carrier = '{carrier}'
494
        """
495
    )
496
497
    # Set bus_id
498
    global_demand.loc[
499
        global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
500
        "Node/Line",
501
    ] = global_demand.loc[
502
        global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
503
        "Node/Line",
504
    ].map(
505
        map_buses
506
    )
507
    global_demand.loc[:, "bus"] = (
508
        get_foreign_gas_bus_id().loc[global_demand.loc[:, "Node/Line"]].values
509
    )
510
511
    # Add missing columns
512
    c = {"scn_name": scn_name, "carrier": carrier}
513
    global_demand = global_demand.assign(**c)
514
515
    new_id = db.next_etrago_id("load")
516
    global_demand["load_id"] = range(new_id, new_id + len(global_demand))
517
518
    ch4_demand_TS = global_demand.copy()
519
    # Remove useless columns
520
    global_demand = global_demand.drop(columns=["Node/Line", "GlobD_2035"])
521
522
    # Insert data to db
523
    global_demand.to_sql(
524
        targets["loads"]["table"],
525
        db.engine(),
526
        schema=targets["loads"]["schema"],
527
        index=False,
528
        if_exists="append",
529
    )
530
531
    # Insert time series
532
    ch4_demand_TS["Node/Line"] = ch4_demand_TS["Node/Line"].replace(
533
        ["UK00"], "GB"
534
    )
535
536
    p_set = []
537
    for index, row in ch4_demand_TS.iterrows():
538
        normalized_TS_df = normalized_ch4_demandTS.loc[
539
            :,
540
            normalized_ch4_demandTS.columns.str.contains(row["Node/Line"][:2]),
541
        ]
542
        p_set.append(
543
            (
544
                normalized_TS_df[normalized_TS_df.columns[0]]
545
                * row["GlobD_2035"]
546
            ).tolist()
547
        )
548
549
    ch4_demand_TS["p_set"] = p_set
550
    ch4_demand_TS["temp_id"] = 1
551
    ch4_demand_TS = ch4_demand_TS.drop(
552
        columns=["Node/Line", "GlobD_2035", "bus", "carrier"]
553
    )
554
555
    # Insert data to DB
556
    ch4_demand_TS.to_sql(
557
        targets["load_timeseries"]["table"],
558
        db.engine(),
559
        schema=targets["load_timeseries"]["schema"],
560
        index=False,
561
        if_exists="append",
562
    )
563
564
565
def calc_ch4_storage_capacities():
566
    target_file = (
567
        Path(".") / "datasets" / "gas_data" / "data" / "IGGIELGN_Storages.csv"
568
    )
569
570
    ch4_storage_capacities = pd.read_csv(
571
        target_file,
572
        delimiter=";",
573
        decimal=".",
574
        usecols=["country_code", "param"],
575
    )
576
577
    ch4_storage_capacities = ch4_storage_capacities[
578
        ch4_storage_capacities["country_code"].isin(countries)
579
    ]
580
581
    map_countries_scigrid = {
582
        "AT": "AT00",
583
        "BE": "BE00",
584
        "CZ": "CZ00",
585
        "DK": "DKE1",
586
        "EE": "EE00",
587
        "EL": "GR00",
588
        "ES": "ES00",
589
        "FI": "FI00",
590
        "FR": "FR00",
591
        "GB": "UK00",
592
        "IT": "ITCN",
593
        "LT": "LT00",
594
        "LV": "LV00",
595
        "MT": "MT00",
596
        "NL": "NL00",
597
        "PL": "PL00",
598
        "PT": "PT00",
599
        "SE": "SE01",
600
    }
601
602
    # Define new columns
603
    max_workingGas_M_m3 = []
604
    end_year = []
605
606
    for index, row in ch4_storage_capacities.iterrows():
607
        param = ast.literal_eval(row["param"])
608
        end_year.append(param["end_year"])
609
        max_workingGas_M_m3.append(param["max_workingGas_M_m3"])
610
611
    end_year = [float("inf") if x == None else x for x in end_year]
612
    ch4_storage_capacities = ch4_storage_capacities.assign(end_year=end_year)
613
    ch4_storage_capacities = ch4_storage_capacities[
614
        ch4_storage_capacities["end_year"] >= 2035
615
    ]
616
617
    # Calculate e_nom
618
    conv_factor = (
619
        10830  # M_m3 to MWh - gross calorific value = 39 MJ/m3 (eurogas.org)
620
    )
621
    ch4_storage_capacities["e_nom"] = [
622
        conv_factor * i for i in max_workingGas_M_m3
623
    ]
624
625
    ch4_storage_capacities.drop(
626
        ["param", "end_year"],
627
        axis=1,
628
        inplace=True,
629
    )
630
631
    ch4_storage_capacities["Country"] = ch4_storage_capacities[
632
        "country_code"
633
    ].map(map_countries_scigrid)
634
    ch4_storage_capacities = ch4_storage_capacities.groupby(
635
        ["country_code"]
636
    ).agg(
637
        {
638
            "e_nom": "sum",
639
            "Country": "first",
640
        },
641
    )
642
643
    ch4_storage_capacities = ch4_storage_capacities.drop(["RU"])
644
    ch4_storage_capacities.loc[:, "bus"] = (
645
        get_foreign_gas_bus_id()
646
        .loc[ch4_storage_capacities.loc[:, "Country"]]
647
        .values
648
    )
649
650
    return ch4_storage_capacities
651
652
653
def insert_storage(ch4_storage_capacities):
654
    sources = config.datasets()["gas_neighbours"]["sources"]
655
    targets = config.datasets()["gas_neighbours"]["targets"]
656
657
    # Clean table
658
    db.execute_sql(
659
        f"""
660
        DELETE FROM {targets['stores']['schema']}.{targets['stores']['table']}  
661
        WHERE "carrier" = 'CH4'
662
        AND scn_name = 'eGon2035'
663
        AND bus IN (
664
            SELECT bus_id FROM {sources['buses']['schema']}.{sources['buses']['table']}
665
            WHERE scn_name = 'eGon2035' 
666
            AND country != 'DE'
667
            );
668
        """
669
    )
670
    # Add missing columns
671
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
672
    ch4_storage_capacities = ch4_storage_capacities.assign(**c)
673
674
    new_id = db.next_etrago_id("store")
675
    ch4_storage_capacities["store_id"] = range(
676
        new_id, new_id + len(ch4_storage_capacities)
677
    )
678
679
    ch4_storage_capacities.drop(
680
        ["Country"],
681
        axis=1,
682
        inplace=True,
683
    )
684
685
    ch4_storage_capacities = ch4_storage_capacities.reset_index(drop=True)
686
    # Insert data to db
687
    ch4_storage_capacities.to_sql(
688
        targets["stores"]["table"],
689
        db.engine(),
690
        schema=targets["stores"]["schema"],
691
        index=False,
692
        if_exists="append",
693
    )
694
695
696
def calc_global_power_to_h2_demand():
697
    """Calculates H2 demand abroad for eGon2035 scenario
698
699
    Calculates global power demand abroad linked to H2 production.
700
    The data comes from TYNDP 2020 according to NEP 2021 from the
701
    scenario 'Distributed Energy', linear interpolate between 2030
702
    and 2040.
703
704
    Returns
705
    -------
706
    pandas.DataFrame
707
        Global power-to-h2 demand per foreign node
708
709
    """
710
    sources = config.datasets()["gas_neighbours"]["sources"]
711
712
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
713
    df = pd.read_excel(
714
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
715
        sheet_name="Gas Data",
716
    )
717
718
    df = (
719
        df.query(
720
            'Scenario == "Distributed Energy" & '
721
            'Case == "Average" &'
722
            'Parameter == "P2H2"'
723
        )
724
        .drop(
725
            columns=[
726
                "Generator_ID",
727
                "Climate Year",
728
                "Simulation_ID",
729
                "Node 1",
730
                "Path",
731
                "Direct/Indirect",
732
                "Sector",
733
                "Note",
734
                "Category",
735
                "Case",
736
                "Scenario",
737
                "Parameter",
738
            ]
739
        )
740
        .set_index("Node/Line")
741
    )
742
743
    df_2030 = (
744
        df[df["Year"] == 2030]
745
        .rename(columns={"Value": "Value_2030"})
746
        .drop(columns=["Year"])
747
    )
748
    df_2040 = (
749
        df[df["Year"] == 2040]
750
        .rename(columns={"Value": "Value_2040"})
751
        .drop(columns=["Year"])
752
    )
753
754
    # Conversion GWh/d to MWh/h
755
    conversion_factor = 1000 / 24
756
757
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
758
    df_2035["GlobD_2035"] = (
759
        (df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
760
    ) * conversion_factor
761
762
    global_power_to_h2_demand = df_2035.drop(
763
        columns=["Value_2030", "Value_2040"]
764
    )
765
766
    # choose demands for considered countries
767
    global_power_to_h2_demand = global_power_to_h2_demand[
768
        (global_power_to_h2_demand.index.str[:2].isin(countries))
769
        & (global_power_to_h2_demand["GlobD_2035"] != 0)
770
    ]
771
772
    # Split in two the demands for DK and UK
773
    global_power_to_h2_demand.loc["DKW1"] = (
774
        global_power_to_h2_demand.loc["DKE1"] / 2
775
    )
776
    global_power_to_h2_demand.loc["DKE1"] = (
777
        global_power_to_h2_demand.loc["DKE1"] / 2
778
    )
779
    global_power_to_h2_demand.loc["UKNI"] = (
780
        global_power_to_h2_demand.loc["UK00"] / 2
781
    )
782
    global_power_to_h2_demand.loc["UK00"] = (
783
        global_power_to_h2_demand.loc["UK00"] / 2
784
    )
785
    global_power_to_h2_demand = global_power_to_h2_demand.reset_index()
786
787
    return global_power_to_h2_demand
788
789
790
def insert_power_to_h2_demand(global_power_to_h2_demand):
791
    """Insert H2 demands into database for eGon2035
792
793
    Detailled description
794
    This function insert data in the database and has no return.
795
796
    Parameters
797
    ----------
798
    global_power_to_h2_demand : pandas.DataFrame
799
        Global H2 demand per foreign node in 1 year
800
801
    """
802
    sources = config.datasets()["gas_neighbours"]["sources"]
803
    targets = config.datasets()["gas_neighbours"]["targets"]
804
    map_buses = get_map_buses()
805
806
    scn_name = "eGon2035"
807
    carrier = "H2_for_industry"
808
809
    db.execute_sql(
810
        f"""
811
        DELETE FROM
812
        {targets['loads']['schema']}.{targets['loads']['table']}
813
        WHERE bus IN (
814
            SELECT bus_id FROM
815
            {sources['buses']['schema']}.{sources['buses']['table']}
816
            WHERE country != 'DE'
817
            AND scn_name = '{scn_name}')
818
        AND scn_name = '{scn_name}'
819
        AND carrier = '{carrier}'
820
        """
821
    )
822
823
    # Set bus_id
824
    global_power_to_h2_demand.loc[
825
        global_power_to_h2_demand[
826
            global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
827
        ].index,
828
        "Node/Line",
829
    ] = global_power_to_h2_demand.loc[
830
        global_power_to_h2_demand[
831
            global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
832
        ].index,
833
        "Node/Line",
834
    ].map(
835
        map_buses
836
    )
837
    global_power_to_h2_demand.loc[:, "bus"] = (
838
        get_foreign_bus_id()
839
        .loc[global_power_to_h2_demand.loc[:, "Node/Line"]]
840
        .values
841
    )
842
843
    # Add missing columns
844
    c = {"scn_name": scn_name, "carrier": carrier}
845
    global_power_to_h2_demand = global_power_to_h2_demand.assign(**c)
846
847
    new_id = db.next_etrago_id("load")
848
    global_power_to_h2_demand["load_id"] = range(
849
        new_id, new_id + len(global_power_to_h2_demand)
850
    )
851
852
    global_power_to_h2_demand = global_power_to_h2_demand.rename(
853
        columns={"GlobD_2035": "p_set"}
854
    )
855
856
    power_to_h2_demand_TS = global_power_to_h2_demand.copy()
857
    # Remove useless columns
858
    global_power_to_h2_demand = global_power_to_h2_demand.drop(
859
        columns=["Node/Line"]
860
    )
861
862
    # Insert data to db
863
    global_power_to_h2_demand.to_sql(
864
        targets["loads"]["table"],
865
        db.engine(),
866
        schema=targets["loads"]["schema"],
867
        index=False,
868
        if_exists="append",
869
    )
870
871
872
def calculate_ch4_grid_capacities():
873
    """Calculates CH4 grid capacities for foreign countries based on TYNDP-data
874
875
    Parameters
876
    ----------
877
    None.
878
879
    Returns
880
    -------
881
    Neighbouring_pipe_capacities_list : pandas.DataFrame
882
883
    """
884
    sources = config.datasets()["gas_neighbours"]["sources"]
885
886
    # Download file
887
    basename = "ENTSOG_TYNDP_2020_Annex_C2_Capacities_per_country.xlsx"
888
    url = "https://www.entsog.eu/sites/default/files/2021-07/" + basename
889
    target_file = Path(".") / "datasets" / "gas_data" / basename
890
891
    urlretrieve(url, target_file)
892
    map_pipelines = {
893
        "NORDSTREAM": "RU00",
894
        "NORDSTREAM 2": "RU00",
895
        "OPAL": "DE",
896
        "YAMAL (BY)": "RU00",
897
        "Denmark": "DKE1",
898
        "Belgium": "BE00",
899
        "Netherlands": "NL00",
900
        "Norway": "NOM1",
901
        "Switzerland": "CH00",
902
        "Poland": "PL00",
903
        "United Kingdom": "UK00",
904
        "Germany": "DE",
905
        "Austria": "AT00",
906
        "France": "FR00",
907
        "Czechia": "CZ00",
908
        "Russia": "RU00",
909
        "Luxemburg": "LUB1",
910
    }
911
912
    grid_countries = [
913
        "NORDSTREAM",
914
        "NORDSTREAM 2",
915
        "OPAL",
916
        "YAMAL (BY)",
917
        "Denmark",
918
        "Belgium",
919
        "Netherlands",
920
        "Norway",
921
        "Switzerland",
922
        "Poland",
923
        "United Kingdom",
924
        "Germany",
925
        "Austria",
926
        "France",
927
        "Czechia",
928
        "Russia",
929
        "Luxemburg",
930
    ]
931
932
    # Read-in data from csv-file
933
    pipe_capacities_list = pd.read_excel(
934
        target_file,
935
        sheet_name="Transmission Peak Capacity",
936
        skiprows=range(4),
937
    )
938
    pipe_capacities_list = pipe_capacities_list[
939
        ["To Country", "Unnamed: 3", "From Country", 2035]
940
    ].rename(
941
        columns={
942
            "Unnamed: 3": "Scenario",
943
            "To Country": "To_Country",
944
            "From Country": "From_Country",
945
        }
946
    )
947
    pipe_capacities_list["To_Country"] = pd.Series(
948
        pipe_capacities_list["To_Country"]
949
    ).fillna(method="ffill")
950
    pipe_capacities_list["From_Country"] = pd.Series(
951
        pipe_capacities_list["From_Country"]
952
    ).fillna(method="ffill")
953
    pipe_capacities_list = pipe_capacities_list[
954
        pipe_capacities_list["Scenario"] == "Advanced"
955
    ].drop(columns={"Scenario"})
956
    pipe_capacities_list = pipe_capacities_list[
957
        (
958
            (pipe_capacities_list["To_Country"].isin(grid_countries))
959
            & (pipe_capacities_list["From_Country"].isin(grid_countries))
960
        )
961
        & (pipe_capacities_list[2035] != 0)
962
    ]
963
    pipe_capacities_list["To_Country"] = pipe_capacities_list[
964
        "To_Country"
965
    ].map(map_pipelines)
966
    pipe_capacities_list["From_Country"] = pipe_capacities_list[
967
        "From_Country"
968
    ].map(map_pipelines)
969
    pipe_capacities_list["countrycombination"] = pipe_capacities_list[
970
        ["To_Country", "From_Country"]
971
    ].apply(
972
        lambda x: tuple(sorted([str(x.To_Country), str(x.From_Country)])),
973
        axis=1,
974
    )
975
976
    pipeline_strategies = {
977
        "To_Country": "first",
978
        "From_Country": "first",
979
        2035: sum,
980
    }
981
982
    pipe_capacities_list = pipe_capacities_list.groupby(
983
        ["countrycombination"]
984
    ).agg(pipeline_strategies)
985
986
    # Add manually DK-SE and AT-CH pipes (Scigrid gas data)
987
    pipe_capacities_list.loc["(DKE1, SE02)"] = ["DKE1", "SE02", 651]
988
    pipe_capacities_list.loc["(AT00, CH00)"] = ["AT00", "CH00", 651]
989
990
    # Conversion GWh/d to MWh/h
991
    pipe_capacities_list["p_nom"] = pipe_capacities_list[2035] * (1000 / 24)
992
993
    # Border crossing CH4 pipelines between foreign countries
994
995
    Neighbouring_pipe_capacities_list = pipe_capacities_list[
996
        (pipe_capacities_list["To_Country"] != "DE")
997
        & (pipe_capacities_list["From_Country"] != "DE")
998
    ].reset_index()
999
1000
    Neighbouring_pipe_capacities_list.loc[:, "bus0"] = (
1001
        get_foreign_gas_bus_id()
1002
        .loc[Neighbouring_pipe_capacities_list.loc[:, "To_Country"]]
1003
        .values
1004
    )
1005
    Neighbouring_pipe_capacities_list.loc[:, "bus1"] = (
1006
        get_foreign_gas_bus_id()
1007
        .loc[Neighbouring_pipe_capacities_list.loc[:, "From_Country"]]
1008
        .values
1009
    )
1010
1011
    # Adjust columns
1012
    Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
1013
        columns=[
1014
            "To_Country",
1015
            "From_Country",
1016
            "countrycombination",
1017
            2035,
1018
        ]
1019
    )
1020
1021
    new_id = db.next_etrago_id("link")
1022
    Neighbouring_pipe_capacities_list["link_id"] = range(
1023
        new_id, new_id + len(Neighbouring_pipe_capacities_list)
1024
    )
1025
1026
    # Border crossing CH4 pipelines between DE and neighbouring countries
1027
    DE_pipe_capacities_list = pipe_capacities_list[
1028
        (pipe_capacities_list["To_Country"] == "DE")
1029
        | (pipe_capacities_list["From_Country"] == "DE")
1030
    ].reset_index()
1031
1032
    dict_cross_pipes_DE = {
1033
        ("AT00", "DE"): "AT",
1034
        ("BE00", "DE"): "BE",
1035
        ("CH00", "DE"): "CH",
1036
        ("CZ00", "DE"): "CZ",
1037
        ("DE", "DKE1"): "DK",
1038
        ("DE", "FR00"): "FR",
1039
        ("DE", "LUB1"): "LU",
1040
        ("DE", "NL00"): "NL",
1041
        ("DE", "NOM1"): "NO",
1042
        ("DE", "PL00"): "PL",
1043
        ("DE", "RU00"): "RU",
1044
    }
1045
1046
    DE_pipe_capacities_list["country_code"] = DE_pipe_capacities_list[
1047
        "countrycombination"
1048
    ].map(dict_cross_pipes_DE)
1049
    DE_pipe_capacities_list = DE_pipe_capacities_list.set_index("country_code")
1050
1051
    for country_code in [e for e in countries if e not in ("GB", "SE", "UK")]:
1052
1053
        # Select cross-bording links
1054
        cap_DE = db.select_dataframe(
1055
            f"""SELECT link_id, bus0, bus1
1056
                FROM {sources['links']['schema']}.{sources['links']['table']}
1057
                    WHERE scn_name = 'eGon2035' 
1058
                    AND carrier = 'CH4'
1059
                    AND (("bus0" IN (
1060
                        SELECT bus_id FROM {sources['buses']['schema']}.{sources['buses']['table']}
1061
                            WHERE country = 'DE'
1062
                            AND carrier = 'CH4'
1063
                            AND scn_name = 'eGon2035')
1064
                        AND "bus1" IN (SELECT bus_id FROM {sources['buses']['schema']}.{sources['buses']['table']}
1065
                            WHERE country = '{country_code}'
1066
                            AND carrier = 'CH4'
1067
                            AND scn_name = 'eGon2035')
1068
                    )
1069
                    OR ("bus0" IN (
1070
                        SELECT bus_id FROM {sources['buses']['schema']}.{sources['buses']['table']}
1071
                            WHERE country = '{country_code}'
1072
                            AND carrier = 'CH4'
1073
                            AND scn_name = 'eGon2035')
1074
                        AND "bus1" IN (SELECT bus_id FROM {sources['buses']['schema']}.{sources['buses']['table']}
1075
                            WHERE country = 'DE'
1076
                            AND carrier = 'CH4'
1077
                            AND scn_name = 'eGon2035'))
1078
                    )
1079
            ;"""
1080
        )
1081
1082
        cap_DE["p_nom"] = DE_pipe_capacities_list.at[
1083
            country_code, "p_nom"
1084
        ] / len(cap_DE.index)
1085
        Neighbouring_pipe_capacities_list = (
1086
            Neighbouring_pipe_capacities_list.append(cap_DE)
1087
        )
1088
1089
    # Add topo, geom and length
1090
    bus_geom = db.select_geodataframe(
1091
        """SELECT bus_id, geom
1092
        FROM grid.egon_etrago_bus
1093
        WHERE scn_name = 'eGon2035'
1094
        AND carrier = 'CH4'
1095
        """,
1096
        epsg=4326,
1097
    ).set_index("bus_id")
1098
1099
    coordinates_bus0 = []
1100
    coordinates_bus1 = []
1101
1102
    for index, row in Neighbouring_pipe_capacities_list.iterrows():
1103
        coordinates_bus0.append(bus_geom["geom"].loc[int(row["bus0"])])
1104
        coordinates_bus1.append(bus_geom["geom"].loc[int(row["bus1"])])
1105
1106
    Neighbouring_pipe_capacities_list["coordinates_bus0"] = coordinates_bus0
1107
    Neighbouring_pipe_capacities_list["coordinates_bus1"] = coordinates_bus1
1108
1109
    Neighbouring_pipe_capacities_list[
1110
        "topo"
1111
    ] = Neighbouring_pipe_capacities_list.apply(
1112
        lambda row: LineString(
1113
            [row["coordinates_bus0"], row["coordinates_bus1"]]
1114
        ),
1115
        axis=1,
1116
    )
1117
    Neighbouring_pipe_capacities_list[
1118
        "geom"
1119
    ] = Neighbouring_pipe_capacities_list.apply(
1120
        lambda row: MultiLineString([row["topo"]]), axis=1
1121
    )
1122
    Neighbouring_pipe_capacities_list[
1123
        "length"
1124
    ] = Neighbouring_pipe_capacities_list.apply(
1125
        lambda row: row["topo"].length, axis=1
1126
    )
1127
1128
    # Remove useless columns
1129
    Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
1130
        columns=[
1131
            "coordinates_bus0",
1132
            "coordinates_bus1",
1133
        ]
1134
    )
1135
1136
    # Add missing columns
1137
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
1138
    Neighbouring_pipe_capacities_list = (
1139
        Neighbouring_pipe_capacities_list.assign(**c)
1140
    )
1141
1142
    Neighbouring_pipe_capacities_list = (
1143
        Neighbouring_pipe_capacities_list.set_geometry("geom", crs=4326)
1144
    )
1145
1146
    return Neighbouring_pipe_capacities_list
1147
1148
1149
def tyndp_gas_generation():
1150
    """Insert data from TYNDP 2020 accordning to NEP 2021
1151
    Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
1152
1153
    Returns
1154
    -------
1155
    None.
1156
    """
1157
    capacities = calc_capacities()
1158
    insert_generators(capacities, "eGon2035")
1159
1160
    ch4_storage_capacities = calc_ch4_storage_capacities()
1161
    insert_storage(ch4_storage_capacities)
1162
1163
1164
def tyndp_gas_demand():
1165
    """Insert gas demands abroad for eGon2035
1166
1167
    Insert CH4 and H2 demands abroad for eGon2035 by executing the
1168
    following steps:
1169
      * CH4
1170
          * Calculation of the global CH4 demand in Norway and of the
1171
            CH4 demand profile by executing the function
1172
            :py:func:`import_ch4_demandTS`
1173
          * Calculation of the global CH4 demands by executing the
1174
            function :py:func:`calc_global_ch4_demand`
1175
          * Insertion the CH4 loads and their associated time series
1176
            in the database by executing the function
1177
            :py:func:`insert_ch4_demand`
1178
      * H2
1179
          * Calculation of the global power demand abroad linked
1180
            to H2 production by executing the function
1181
            :py:func:`calc_global_power_to_h2_demand`
1182
          * Insertion of these loads in the database by executing the
1183
            function :py:func:`insert_power_to_h2_demand`
1184
    This function insert data in the database and has no return.
1185
1186
    """
1187
    Norway_global_demand_1y, normalized_ch4_demandTS = import_ch4_demandTS()
1188
    global_ch4_demand = calc_global_ch4_demand(Norway_global_demand_1y)
1189
    insert_ch4_demand(global_ch4_demand, normalized_ch4_demandTS)
1190
1191
    global_power_to_h2_demand = calc_global_power_to_h2_demand()
1192
    insert_power_to_h2_demand(global_power_to_h2_demand)
1193
1194
1195
def grid():
1196
    """Insert data from TYNDP 2020 accordning to NEP 2021
1197
    Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
1198
1199
    Returns
1200
    -------
1201
    None.
1202
    """
1203
    Neighbouring_pipe_capacities_list = calculate_ch4_grid_capacities()
1204
    insert_gas_grid_capacities(
1205
        Neighbouring_pipe_capacities_list, scn_name="eGon2035"
1206
    )
1207