Passed
Push — dev ( 7a7ea3...eb04d6 )
by
unknown
02:01 queued 15s
created

insert_ocgt_abroad()   A

Complexity

Conditions 1

Size

Total Lines 62
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 28
dl 0
loc 62
rs 9.208
c 0
b 0
f 0
cc 1
nop 0

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 shapely.geometry import LineString, MultiLineString
10
import geopandas as gpd
11
import pandas as pd
12
import pypsa
13
14
from egon.data import config, db
15
from egon.data.datasets.electrical_neighbours import (
16
    get_foreign_bus_id,
17
    get_map_buses,
18
)
19
from egon.data.datasets.gas_neighbours.gas_abroad import (
20
    insert_gas_grid_capacities,
21
)
22
from egon.data.datasets.scenario_parameters import get_sector_parameters
23
24
countries = [
25
    "AT",
26
    "BE",
27
    "CH",
28
    "CZ",
29
    "DK",
30
    "FR",
31
    "GB",
32
    "LU",
33
    "NL",
34
    "NO",
35
    "PL",
36
    "RU",
37
    "SE",
38
    "UK",
39
]
40
41
42 View Code Duplication
def get_foreign_gas_bus_id(carrier="CH4"):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
43
    """Calculate the etrago bus id based on the geometry
44
45
    Map node_ids from TYNDP and etragos bus_id
46
47
    Parameters
48
    ----------
49
    carrier : str
50
        Name of the carrier
51
52
    Returns
53
    -------
54
    pandas.Series
55
        List of mapped node_ids from TYNDP and etragos bus_id
56
57
    """
58
    sources = config.datasets()["gas_neighbours"]["sources"]
59
    scn_name = "eGon2035"
60
61
    bus_id = db.select_geodataframe(
62
        f"""
63
        SELECT bus_id, ST_Buffer(geom, 1) as geom, country
64
        FROM grid.egon_etrago_bus
65
        WHERE scn_name = '{scn_name}'
66
        AND carrier = '{carrier}'
67
        AND country != 'DE'
68
        """,
69
        epsg=3035,
70
    )
71
72
    # insert installed capacities
73
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
74
75
    # Select buses in neighbouring countries as geodataframe
76
    buses = pd.read_excel(
77
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
78
        sheet_name="Nodes - Dict",
79
    ).query("longitude==longitude")
80
    buses = gpd.GeoDataFrame(
81
        buses,
82
        crs=4326,
83
        geometry=gpd.points_from_xy(buses.longitude, buses.latitude),
84
    ).to_crs(3035)
85
86
    buses["bus_id"] = 0
87
88
    # Select bus_id from etrago with shortest distance to TYNDP node
89
    for i, row in buses.iterrows():
90
        distance = bus_id.set_index("bus_id").geom.distance(row.geometry)
91
        buses.loc[i, "bus_id"] = distance[
92
            distance == distance.min()
93
        ].index.values[0]
94
95
    return buses.set_index("node_id").bus_id
96
97
98
def read_LNG_capacities():
99
    """Read LNG import capacities from Scigrid gas data
100
101
    Returns
102
    -------
103
    IGGIELGN_LNGs: pandas.Series
104
        LNG terminal capacities per foreign country node (in GWh/d)
105
106
    """
107
    lng_file = "datasets/gas_data/data/IGGIELGN_LNGs.csv"
108
    IGGIELGN_LNGs = gpd.read_file(lng_file)
109
110
    map_countries_scigrid = {
111
        "BE": "BE00",
112
        "EE": "EE00",
113
        "EL": "GR00",
114
        "ES": "ES00",
115
        "FI": "FI00",
116
        "FR": "FR00",
117
        "GB": "UK00",
118
        "IT": "ITCN",
119
        "LT": "LT00",
120
        "LV": "LV00",
121
        "MT": "MT00",
122
        "NL": "NL00",
123
        "PL": "PL00",
124
        "PT": "PT00",
125
        "SE": "SE01",
126
    }
127
128
    conversion_factor = 437.5  # MCM/day to MWh/h
129
    c2 = 24 / 1000  # MWh/h to GWh/d
130
    p_nom = []
131
132
    for index, row in IGGIELGN_LNGs.iterrows():
133
        param = ast.literal_eval(row["param"])
134
        p_nom.append(
135
            param["max_cap_store2pipe_M_m3_per_d"] * conversion_factor * c2
136
        )
137
138
    IGGIELGN_LNGs["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] = p_nom
139
140
    IGGIELGN_LNGs.drop(
141
        [
142
            "uncertainty",
143
            "method",
144
            "param",
145
            "comment",
146
            "tags",
147
            "source_id",
148
            "lat",
149
            "long",
150
            "geometry",
151
            "id",
152
            "name",
153
            "node_id",
154
        ],
155
        axis=1,
156
        inplace=True,
157
    )
158
159
    IGGIELGN_LNGs["Country"] = IGGIELGN_LNGs["country_code"].map(
160
        map_countries_scigrid
161
    )
162
    IGGIELGN_LNGs = (
163
        IGGIELGN_LNGs.groupby(["Country"])[
164
            "LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"
165
        ]
166
        .sum()
167
        .sort_index()
168
    )
169
170
    return IGGIELGN_LNGs
171
172
173
def calc_capacities():
174
    """Calculates gas production capacities of neighbouring countries
175
176
    For each neigbouring country, this function calculates the gas
177
    generation capacity in 2035 using the function
178
    :py:func:`calc_capacity_per_year` for 2030 and 2040 and
179
    interpolating the results. These capacities include LNG import, as
180
    well as conventional and biogas production.
181
    Two conventional gas generators for are added for Norway and Russia
182
    interpolating the supply potential (min) values from the TYNPD 2020
183
    for 2030 and 2040.
184
185
    Returns
186
    -------
187
    grouped_capacities: pandas.DataFrame
188
        Gas production capacities per foreign node
189
190
    """
191
192
    sources = config.datasets()["gas_neighbours"]["sources"]
193
194
    # insert installed capacities
195
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
196
    df0 = pd.read_excel(
197
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
198
        sheet_name="Gas Data",
199
    )
200
201
    df = (
202
        df0.query(
203
            'Scenario == "Distributed Energy" &'
204
            ' (Case == "Peak" | Case == "Average") &'
205
            # Case: 2 Week/Average/DF/Peak
206
            ' Category == "Production"'
207
        )
208
        .drop(
209
            columns=[
210
                "Generator_ID",
211
                "Climate Year",
212
                "Simulation_ID",
213
                "Node 1",
214
                "Path",
215
                "Direct/Indirect",
216
                "Sector",
217
                "Note",
218
                "Category",
219
                "Scenario",
220
            ]
221
        )
222
        .set_index("Node/Line")
223
        .sort_index()
224
    )
225
226
    lng = read_LNG_capacities()
227
    df_2030 = calc_capacity_per_year(df, lng, 2030)
228
    df_2040 = calc_capacity_per_year(df, lng, 2040)
229
230
    # Conversion GWh/d to MWh/h
231
    conversion_factor = 1000 / 24
232
233
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
234
    df_2035 = df_2035.drop(
235
        columns=[
236
            "Value_conv_2040",
237
            "Value_conv_2030",
238
            "Value_bio_2040",
239
            "Value_bio_2030",
240
        ]
241
    )
242
    df_2035["cap_2035"] = (df_2035["CH4_2030"] + df_2035["CH4_2040"]) / 2
243
    df_2035["e_nom_max"] = (
244
        ((df_2035["e_nom_max_2030"] + df_2035["e_nom_max_2040"]) / 2)
245
        * conversion_factor
246
        * 8760
247
    )
248
    df_2035["share_LNG_2035"] = (
249
        df_2035["share_LNG_2030"] + df_2035["share_LNG_2040"]
250
    ) / 2
251
    df_2035["share_conv_pipe_2035"] = (
252
        df_2035["share_conv_pipe_2030"] + df_2035["share_conv_pipe_2040"]
253
    ) / 2
254
    df_2035["share_bio_2035"] = (
255
        df_2035["share_bio_2030"] + df_2035["share_bio_2040"]
256
    ) / 2
257
258
    grouped_capacities = df_2035.drop(
259
        columns=[
260
            "share_LNG_2030",
261
            "share_LNG_2040",
262
            "share_conv_pipe_2030",
263
            "share_conv_pipe_2040",
264
            "share_bio_2030",
265
            "share_bio_2040",
266
            "CH4_2040",
267
            "CH4_2030",
268
            "e_nom_max_2030",
269
            "e_nom_max_2040",
270
        ]
271
    ).reset_index()
272
273
    grouped_capacities["cap_2035"] = (
274
        grouped_capacities["cap_2035"] * conversion_factor
275
    )
276
277
    # Add generators in Norway and Russia
278
    df_conv = (
279
        df0.query('Case == "Min" & Category == "Supply Potential"')
280
        .drop(
281
            columns=[
282
                "Generator_ID",
283
                "Climate Year",
284
                "Simulation_ID",
285
                "Node 1",
286
                "Path",
287
                "Direct/Indirect",
288
                "Sector",
289
                "Note",
290
                "Category",
291
                "Scenario",
292
                "Parameter",
293
                "Case",
294
            ]
295
        )
296
        .set_index("Node/Line")
297
        .sort_index()
298
    )
299
300
    df_conv_2030 = df_conv[df_conv["Year"] == 2030].rename(
301
        columns={"Value": "Value_2030"}
302
    )
303
    df_conv_2040 = df_conv[df_conv["Year"] == 2040].rename(
304
        columns={"Value": "Value_2040"}
305
    )
306
    df_conv_2035 = pd.concat([df_conv_2040, df_conv_2030], axis=1)
307
308
    df_conv_2035["cap_2035"] = (
309
        (df_conv_2035["Value_2030"] + df_conv_2035["Value_2040"]) / 2
310
    ) * conversion_factor
311
    df_conv_2035["e_nom_max"] = df_conv_2035["cap_2035"] * 8760
312
    df_conv_2035["share_LNG_2035"] = 0
313
    df_conv_2035["share_conv_pipe_2035"] = 1
314
    df_conv_2035["share_bio_2035"] = 0
315
316
    df_conv_2035 = df_conv_2035.drop(
317
        columns=[
318
            "Year",
319
            "Value_2030",
320
            "Value_2040",
321
        ]
322
    ).reset_index()
323
    df_conv_2035 = df_conv_2035.rename(columns={"Node/Line": "index"})
324
    grouped_capacities = grouped_capacities.append(df_conv_2035)
325
326
    # choose capacities for considered countries
327
    grouped_capacities = grouped_capacities[
328
        grouped_capacities["index"].str[:2].isin(countries)
329
    ]
330
    return grouped_capacities
331
332
333
def calc_capacity_per_year(df, lng, year):
334
    """Calculates gas production capacities for a specified year
335
336
    For a specified year and for the foreign country nodes this function
337
    calculates the gas production capacity, considering the gas
338
    (conventional and bio) production capacity from TYNDP data and the
339
    LGN import capacity from Scigrid gas data.
340
341
    The columns of the returned dataframe are the following:
342
      * Value_bio_year: biogas capacity prodution (in GWh/d)
343
      * Value_conv_year: conventional gas capacity prodution including
344
        LNG imports (in GWh/d)
345
      * CH4_year: total gas production capacity (in GWh/d). This value
346
        is calculated using the peak production value from the TYNDP.
347
      * e_nom_max_year: total gas production capacity representative
348
        for the whole year (in GWh/d). This value is calculated using
349
        the average production value from the TYNDP and will then be
350
        used to limit the energy that can be generated in one year.
351
      * share_LNG_year: share of LGN import capacity in the total gas
352
        production capacity
353
      * share_conv_pipe_year: share of conventional gas extraction
354
        capacity in the total gas production capacity
355
      * share_bio_year: share of biogas production capacity in the
356
        total gas production capacity
357
358
    Parameters
359
    ----------
360
    df : pandas.DataFrame
361
        Gas (conventional and bio) production capacities from TYNDP (in GWh/d)
362
363
    lng : pandas.Series
364
        LNG terminal capacities per foreign country node (in GWh/d)
365
366
    year : int
367
        Year to calculate gas production capacity for.
368
369
    Returns
370
    -------
371
    df_year : pandas.DataFrame
372
        Gas production capacities (in GWh/d) per foreign country node
373
374
    """
375
    df_conv_peak = (
376
        df[
377
            (df["Parameter"] == "Conventional")
378
            & (df["Year"] == year)
379
            & (df["Case"] == "Peak")
380
        ]
381
        .rename(columns={"Value": f"Value_conv_{year}_peak"})
382
        .drop(columns=["Parameter", "Year", "Case"])
383
    )
384
    df_conv_average = (
385
        df[
386
            (df["Parameter"] == "Conventional")
387
            & (df["Year"] == year)
388
            & (df["Case"] == "Average")
389
        ]
390
        .rename(columns={"Value": f"Value_conv_{year}_average"})
391
        .drop(columns=["Parameter", "Year", "Case"])
392
    )
393
    df_bioch4 = (
394
        df[
395
            (df["Parameter"] == "Biomethane")
396
            & (df["Year"] == year)
397
            & (df["Case"] == "Peak")
398
            # Peak and Average have the same values for biogas
399
            # production in 2030 and 2040
400
        ]
401
        .rename(columns={"Value": f"Value_bio_{year}"})
402
        .drop(columns=["Parameter", "Year", "Case"])
403
    )
404
405
    # Some values are duplicated (DE00 in 2030)
406
    df_conv_peak = df_conv_peak[~df_conv_peak.index.duplicated(keep="first")]
407
    df_conv_average = df_conv_average[
408
        ~df_conv_average.index.duplicated(keep="first")
409
    ]
410
411
    df_year = pd.concat(
412
        [df_conv_peak, df_conv_average, df_bioch4, lng], axis=1
413
    ).fillna(0)
414
    df_year = df_year[
415
        ~(
416
            (df_year[f"Value_conv_{year}_peak"] == 0)
417
            & (df_year[f"Value_bio_{year}"] == 0)
418
            & (df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"] == 0)
419
        )
420
    ]
421
    df_year[f"Value_conv_{year}"] = (
422
        df_year[f"Value_conv_{year}_peak"]
423
        + df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
424
    )
425
    df_year[f"CH4_{year}"] = (
426
        df_year[f"Value_conv_{year}"] + df_year[f"Value_bio_{year}"]
427
    )
428
    df_year[f"e_nom_max_{year}"] = (
429
        df_year[f"Value_conv_{year}_average"]
430
        + df_year[f"Value_bio_{year}"]
431
        + df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
432
    )
433
    df_year[f"share_LNG_{year}"] = (
434
        df_year["LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)"]
435
        / df_year[f"e_nom_max_{year}"]
436
    )
437
    df_year[f"share_conv_pipe_{year}"] = (
438
        df_year[f"Value_conv_{year}_average"] / df_year[f"e_nom_max_{year}"]
439
    )
440
    df_year[f"share_bio_{year}"] = (
441
        df_year[f"Value_bio_{year}"] / df_year[f"e_nom_max_{year}"]
442
    )
443
444
    df_year = df_year.drop(
445
        columns=[
446
            "LNG max_cap_store2pipe_M_m3_per_d (in GWh/d)",
447
            f"Value_conv_{year}_average",
448
            f"Value_conv_{year}_peak",
449
        ]
450
    )
451
452
    return df_year
453
454
455
def insert_generators(gen):
456
    """Insert gas generators for foreign countries in the database
457
458
    Insert gas generators for foreign countries in the data base.
459
    The marginal cost of the methane is calculated as the sum of the
460
    imported LNG cost, of the conventional natural gas cost and of the
461
    biomethane cost, weighted by their share in the total import/
462
    production capacity.
463
    LNG is considerate to be 30% more expensive than the natural gas
464
    transported by pipelines (source: iwd, 2022).
465
466
    Parameters
467
    ----------
468
    gen : pandas.DataFrame
469
        Gas production capacities per foreign node and energy carrier
470
471
    Returns
472
    -------
473
    None.
474
475
    """
476
    sources = config.datasets()["gas_neighbours"]["sources"]
477
    targets = config.datasets()["gas_neighbours"]["targets"]
478
    map_buses = get_map_buses()
479
    scn_params = get_sector_parameters("gas", "eGon2035")
480
481
    # Delete existing data
482
    db.execute_sql(
483
        f"""
484
        DELETE FROM
485
        {targets['generators']['schema']}.{targets['generators']['table']}
486
        WHERE bus IN (
487
            SELECT bus_id FROM
488
            {sources['buses']['schema']}.{sources['buses']['table']}
489
            WHERE country != 'DE'
490
            AND scn_name = 'eGon2035')
491
        AND scn_name = 'eGon2035'
492
        AND carrier = 'CH4';
493
        """
494
    )
495
496
    # Set bus_id
497
    gen.loc[gen[gen["index"].isin(map_buses.keys())].index, "index"] = gen.loc[
498
        gen[gen["index"].isin(map_buses.keys())].index, "index"
499
    ].map(map_buses)
500
    gen.loc[:, "bus"] = (
501
        get_foreign_gas_bus_id().loc[gen.loc[:, "index"]].values
502
    )
503
504
    # Add missing columns
505
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
506
    gen = gen.assign(**c)
507
508
    new_id = db.next_etrago_id("generator")
509
    gen["generator_id"] = range(new_id, new_id + len(gen))
510
    gen["p_nom"] = gen["cap_2035"]
511
    gen["marginal_cost"] = (
512
        gen["share_LNG_2035"] * scn_params["marginal_cost"]["CH4"] * 1.3
513
        + gen["share_conv_pipe_2035"] * scn_params["marginal_cost"]["CH4"]
514
        + gen["share_bio_2035"] * scn_params["marginal_cost"]["biogas"]
515
    )
516
517
    # Remove useless columns
518
    gen = gen.drop(
519
        columns=[
520
            "index",
521
            "share_LNG_2035",
522
            "share_conv_pipe_2035",
523
            "share_bio_2035",
524
            "cap_2035",
525
        ]
526
    )
527
528
    # Insert data to db
529
    gen.to_sql(
530
        targets["generators"]["table"],
531
        db.engine(),
532
        schema=targets["generators"]["schema"],
533
        index=False,
534
        if_exists="append",
535
    )
536
537
538
def calc_global_ch4_demand(Norway_global_demand_1y):
539
    """Calculates global CH4 demands abroad for eGon2035 scenario
540
541
    The data comes from TYNDP 2020 according to NEP 2021 from the
542
    scenario 'Distributed Energy', linear interpolate between 2030
543
    and 2040.
544
545
    Returns
546
    -------
547
    pandas.DataFrame
548
        Global (yearly) CH4 final demand per foreign node
549
550
    """
551
552
    sources = config.datasets()["gas_neighbours"]["sources"]
553
554
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
555
    df = pd.read_excel(
556
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
557
        sheet_name="Gas Data",
558
    )
559
560
    df = (
561
        df.query(
562
            'Scenario == "Distributed Energy" & '
563
            'Case == "Average" &'
564
            'Category == "Demand"'
565
        )
566
        .drop(
567
            columns=[
568
                "Generator_ID",
569
                "Climate Year",
570
                "Simulation_ID",
571
                "Node 1",
572
                "Path",
573
                "Direct/Indirect",
574
                "Sector",
575
                "Note",
576
                "Category",
577
                "Case",
578
                "Scenario",
579
            ]
580
        )
581
        .set_index("Node/Line")
582
    )
583
584
    df_2030 = (
585
        df[(df["Parameter"] == "Final demand") & (df["Year"] == 2030)]
586
        .rename(columns={"Value": "Value_2030"})
587
        .drop(columns=["Parameter", "Year"])
588
    )
589
590
    df_2040 = (
591
        df[(df["Parameter"] == "Final demand") & (df["Year"] == 2040)]
592
        .rename(columns={"Value": "Value_2040"})
593
        .drop(columns=["Parameter", "Year"])
594
    )
595
596
    # Conversion GWh/d to MWh/h
597
    conversion_factor = 1000 / 24
598
599
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
600
    df_2035["GlobD_2035"] = (
601
        (df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
602
    ) * conversion_factor
603
    df_2035.loc["NOS0"] = [
604
        0,
605
        0,
606
        Norway_global_demand_1y / 8760,
607
    ]  # Manually add Norway demand
608
    grouped_demands = df_2035.drop(
609
        columns=["Value_2030", "Value_2040"]
610
    ).reset_index()
611
612
    # choose demands for considered countries
613
    return grouped_demands[
614
        grouped_demands["Node/Line"].str[:2].isin(countries)
615
    ]
616
617
618
def import_ch4_demandTS():
619
    """Calculate global CH4 demand in Norway and CH4 demand profile
620
621
    Import from the PyPSA-eur-sec run the timeseries of residential
622
    rural heat per neighbor country. This timeserie is used to
623
    calculate:
624
      * the global (yearly) heat demand of Norway
625
        (that will be supplied by CH4)
626
      * the normalized CH4 hourly resolved demand profile
627
628
    Parameters
629
    ----------
630
    None.
631
632
    Returns
633
    -------
634
    Norway_global_demand: Float
635
        Yearly heat demand of Norway in MWh
636
    neighbor_loads_t: pandas.DataFrame
637
        Normalized CH4 hourly resolved demand profiles per neighbor country
638
639
    """
640
641
    cwd = Path(".")
642
    target_file = (
643
        cwd
644
        / "data_bundle_egon_data"
645
        / "pypsa_eur_sec"
646
        / "2022-07-26-egondata-integration"
647
        / "postnetworks"
648
        / "elec_s_37_lv2.0__Co2L0-1H-T-H-B-I-dist1_2050.nc"
649
    )
650
651
    network = pypsa.Network(str(target_file))
652
653
    # Set country tag for all buses
654
    network.buses.country = network.buses.index.str[:2]
655
    neighbors = network.buses[network.buses.country != "DE"]
656
    neighbors = neighbors[
657
        (neighbors["country"].isin(countries))
658
        & (neighbors["carrier"] == "residential rural heat")
659
    ].drop_duplicates(subset="country")
660
661
    neighbor_loads = network.loads[network.loads.bus.isin(neighbors.index)]
662
    neighbor_loads_t_index = neighbor_loads.index[
663
        neighbor_loads.index.isin(network.loads_t.p_set.columns)
664
    ]
665
    neighbor_loads_t = network.loads_t["p_set"][neighbor_loads_t_index]
666
    Norway_global_demand = neighbor_loads_t[
667
        "NO3 0 residential rural heat"
668
    ].sum()
669
670
    for i in neighbor_loads_t.columns:
671
        neighbor_loads_t[i] = neighbor_loads_t[i] / neighbor_loads_t[i].sum()
672
673
    return Norway_global_demand, neighbor_loads_t
674
675
676
def insert_ch4_demand(global_demand, normalized_ch4_demandTS):
677
    """Insert CH4 demands abroad in the database for eGon2035
678
679
    Parameters
680
    ----------
681
    global_demand : pandas.DataFrame
682
        Global CH4 demand per foreign node in 1 year
683
    gas_demandTS : pandas.DataFrame
684
        Normalized time serie of the demand per foreign country
685
686
    Returns
687
    -------
688
    None.
689
690
    """
691
    sources = config.datasets()["gas_neighbours"]["sources"]
692
    targets = config.datasets()["gas_neighbours"]["targets"]
693
    map_buses = get_map_buses()
694
695
    scn_name = "eGon2035"
696
    carrier = "CH4"
697
698
    # Delete existing data
699
    db.execute_sql(
700
        f"""
701
        DELETE FROM
702
        {targets['load_timeseries']['schema']}.{targets['load_timeseries']['table']}
703
        WHERE "load_id" IN (
704
            SELECT load_id FROM
705
            {targets['loads']['schema']}.{targets['loads']['table']}
706
            WHERE bus IN (
707
                SELECT bus_id FROM
708
                {sources['buses']['schema']}.{sources['buses']['table']}
709
                WHERE country != 'DE'
710
                AND scn_name = '{scn_name}')
711
            AND scn_name = '{scn_name}'
712
            AND carrier = '{carrier}'
713
        );
714
        """
715
    )
716
717
    db.execute_sql(
718
        f"""
719
        DELETE FROM
720
        {targets['loads']['schema']}.{targets['loads']['table']}
721
        WHERE bus IN (
722
            SELECT bus_id FROM
723
            {sources['buses']['schema']}.{sources['buses']['table']}
724
            WHERE country != 'DE'
725
            AND scn_name = '{scn_name}')
726
        AND scn_name = '{scn_name}'
727
        AND carrier = '{carrier}'
728
        """
729
    )
730
731
    # Set bus_id
732
    global_demand.loc[
733
        global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
734
        "Node/Line",
735
    ] = global_demand.loc[
736
        global_demand[global_demand["Node/Line"].isin(map_buses.keys())].index,
737
        "Node/Line",
738
    ].map(
739
        map_buses
740
    )
741
    global_demand.loc[:, "bus"] = (
742
        get_foreign_gas_bus_id().loc[global_demand.loc[:, "Node/Line"]].values
743
    )
744
745
    # Add missing columns
746
    c = {"scn_name": scn_name, "carrier": carrier}
747
    global_demand = global_demand.assign(**c)
748
749
    new_id = db.next_etrago_id("load")
750
    global_demand["load_id"] = range(new_id, new_id + len(global_demand))
751
752
    ch4_demand_TS = global_demand.copy()
753
    # Remove useless columns
754
    global_demand = global_demand.drop(columns=["Node/Line", "GlobD_2035"])
755
756
    # Insert data to db
757
    global_demand.to_sql(
758
        targets["loads"]["table"],
759
        db.engine(),
760
        schema=targets["loads"]["schema"],
761
        index=False,
762
        if_exists="append",
763
    )
764
765
    # Insert time series
766
    ch4_demand_TS["Node/Line"] = ch4_demand_TS["Node/Line"].replace(
767
        ["UK00"], "GB"
768
    )
769
770
    p_set = []
771
    for index, row in ch4_demand_TS.iterrows():
772
        normalized_TS_df = normalized_ch4_demandTS.loc[
773
            :,
774
            normalized_ch4_demandTS.columns.str.contains(row["Node/Line"][:2]),
775
        ]
776
        p_set.append(
777
            (
778
                normalized_TS_df[normalized_TS_df.columns[0]]
779
                * row["GlobD_2035"]
780
            ).tolist()
781
        )
782
783
    ch4_demand_TS["p_set"] = p_set
784
    ch4_demand_TS["temp_id"] = 1
785
    ch4_demand_TS = ch4_demand_TS.drop(
786
        columns=["Node/Line", "GlobD_2035", "bus", "carrier"]
787
    )
788
789
    # Insert data to DB
790
    ch4_demand_TS.to_sql(
791
        targets["load_timeseries"]["table"],
792
        db.engine(),
793
        schema=targets["load_timeseries"]["schema"],
794
        index=False,
795
        if_exists="append",
796
    )
797
798
799
def calc_ch4_storage_capacities():
800
    target_file = (
801
        Path(".") / "datasets" / "gas_data" / "data" / "IGGIELGN_Storages.csv"
802
    )
803
804
    ch4_storage_capacities = pd.read_csv(
805
        target_file,
806
        delimiter=";",
807
        decimal=".",
808
        usecols=["country_code", "param"],
809
    )
810
811
    ch4_storage_capacities = ch4_storage_capacities[
812
        ch4_storage_capacities["country_code"].isin(countries)
813
    ]
814
815
    map_countries_scigrid = {
816
        "AT": "AT00",
817
        "BE": "BE00",
818
        "CZ": "CZ00",
819
        "DK": "DKE1",
820
        "EE": "EE00",
821
        "EL": "GR00",
822
        "ES": "ES00",
823
        "FI": "FI00",
824
        "FR": "FR00",
825
        "GB": "UK00",
826
        "IT": "ITCN",
827
        "LT": "LT00",
828
        "LV": "LV00",
829
        "MT": "MT00",
830
        "NL": "NL00",
831
        "PL": "PL00",
832
        "PT": "PT00",
833
        "SE": "SE01",
834
    }
835
836
    # Define new columns
837
    max_workingGas_M_m3 = []
838
    end_year = []
839
840
    for index, row in ch4_storage_capacities.iterrows():
841
        param = ast.literal_eval(row["param"])
842
        end_year.append(param["end_year"])
843
        max_workingGas_M_m3.append(param["max_workingGas_M_m3"])
844
845
    end_year = [float("inf") if x is None else x for x in end_year]
846
    ch4_storage_capacities = ch4_storage_capacities.assign(end_year=end_year)
847
    ch4_storage_capacities = ch4_storage_capacities[
848
        ch4_storage_capacities["end_year"] >= 2035
849
    ]
850
851
    # Calculate e_nom
852
    conv_factor = (
853
        10830  # M_m3 to MWh - gross calorific value = 39 MJ/m3 (eurogas.org)
854
    )
855
    ch4_storage_capacities["e_nom"] = [
856
        conv_factor * i for i in max_workingGas_M_m3
857
    ]
858
859
    ch4_storage_capacities.drop(
860
        ["param", "end_year"],
861
        axis=1,
862
        inplace=True,
863
    )
864
865
    ch4_storage_capacities["Country"] = ch4_storage_capacities[
866
        "country_code"
867
    ].map(map_countries_scigrid)
868
    ch4_storage_capacities = ch4_storage_capacities.groupby(
869
        ["country_code"]
870
    ).agg(
871
        {
872
            "e_nom": "sum",
873
            "Country": "first",
874
        },
875
    )
876
877
    ch4_storage_capacities = ch4_storage_capacities.drop(["RU"])
878
    ch4_storage_capacities.loc[:, "bus"] = (
879
        get_foreign_gas_bus_id()
880
        .loc[ch4_storage_capacities.loc[:, "Country"]]
881
        .values
882
    )
883
884
    return ch4_storage_capacities
885
886
887
def insert_storage(ch4_storage_capacities):
888
    sources = config.datasets()["gas_neighbours"]["sources"]
889
    targets = config.datasets()["gas_neighbours"]["targets"]
890
891
    # Clean table
892
    db.execute_sql(
893
        f"""
894
        DELETE FROM {targets['stores']['schema']}.{targets['stores']['table']}
895
        WHERE "carrier" = 'CH4'
896
        AND scn_name = 'eGon2035'
897
        AND bus IN (
898
            SELECT bus_id
899
            FROM {sources['buses']['schema']}.{sources['buses']['table']}
900
            WHERE scn_name = 'eGon2035'
901
            AND country != 'DE'
902
            );
903
        """
904
    )
905
    # Add missing columns
906
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
907
    ch4_storage_capacities = ch4_storage_capacities.assign(**c)
908
909
    new_id = db.next_etrago_id("store")
910
    ch4_storage_capacities["store_id"] = range(
911
        new_id, new_id + len(ch4_storage_capacities)
912
    )
913
914
    ch4_storage_capacities.drop(
915
        ["Country"],
916
        axis=1,
917
        inplace=True,
918
    )
919
920
    ch4_storage_capacities = ch4_storage_capacities.reset_index(drop=True)
921
    # Insert data to db
922
    ch4_storage_capacities.to_sql(
923
        targets["stores"]["table"],
924
        db.engine(),
925
        schema=targets["stores"]["schema"],
926
        index=False,
927
        if_exists="append",
928
    )
929
930
931
def calc_global_power_to_h2_demand():
932
    """Calculates H2 demand abroad for eGon2035 scenario
933
934
    Calculates global power demand abroad linked to H2 production.
935
    The data comes from TYNDP 2020 according to NEP 2021 from the
936
    scenario 'Distributed Energy', linear interpolate between 2030
937
    and 2040.
938
939
    Returns
940
    -------
941
    pandas.DataFrame
942
        Global power-to-h2 demand per foreign node
943
944
    """
945
    sources = config.datasets()["gas_neighbours"]["sources"]
946
947
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
948
    df = pd.read_excel(
949
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
950
        sheet_name="Gas Data",
951
    )
952
953
    df = (
954
        df.query(
955
            'Scenario == "Distributed Energy" & '
956
            'Case == "Average" &'
957
            'Parameter == "P2H2"'
958
        )
959
        .drop(
960
            columns=[
961
                "Generator_ID",
962
                "Climate Year",
963
                "Simulation_ID",
964
                "Node 1",
965
                "Path",
966
                "Direct/Indirect",
967
                "Sector",
968
                "Note",
969
                "Category",
970
                "Case",
971
                "Scenario",
972
                "Parameter",
973
            ]
974
        )
975
        .set_index("Node/Line")
976
    )
977
978
    df_2030 = (
979
        df[df["Year"] == 2030]
980
        .rename(columns={"Value": "Value_2030"})
981
        .drop(columns=["Year"])
982
    )
983
    df_2040 = (
984
        df[df["Year"] == 2040]
985
        .rename(columns={"Value": "Value_2040"})
986
        .drop(columns=["Year"])
987
    )
988
989
    # Conversion GWh/d to MWh/h
990
    conversion_factor = 1000 / 24
991
992
    df_2035 = pd.concat([df_2040, df_2030], axis=1)
993
    df_2035["GlobD_2035"] = (
994
        (df_2035["Value_2030"] + df_2035["Value_2040"]) / 2
995
    ) * conversion_factor
996
997
    global_power_to_h2_demand = df_2035.drop(
998
        columns=["Value_2030", "Value_2040"]
999
    )
1000
1001
    # choose demands for considered countries
1002
    global_power_to_h2_demand = global_power_to_h2_demand[
1003
        (global_power_to_h2_demand.index.str[:2].isin(countries))
1004
        & (global_power_to_h2_demand["GlobD_2035"] != 0)
1005
    ]
1006
1007
    # Split in two the demands for DK and UK
1008
    global_power_to_h2_demand.loc["DKW1"] = (
1009
        global_power_to_h2_demand.loc["DKE1"] / 2
1010
    )
1011
    global_power_to_h2_demand.loc["DKE1"] = (
1012
        global_power_to_h2_demand.loc["DKE1"] / 2
1013
    )
1014
    global_power_to_h2_demand.loc["UKNI"] = (
1015
        global_power_to_h2_demand.loc["UK00"] / 2
1016
    )
1017
    global_power_to_h2_demand.loc["UK00"] = (
1018
        global_power_to_h2_demand.loc["UK00"] / 2
1019
    )
1020
    global_power_to_h2_demand = global_power_to_h2_demand.reset_index()
1021
1022
    return global_power_to_h2_demand
1023
1024
1025
def insert_power_to_h2_demand(global_power_to_h2_demand):
1026
    """Insert H2 demands into database for eGon2035
1027
1028
    Detailled description
1029
    This function insert data in the database and has no return.
1030
1031
    Parameters
1032
    ----------
1033
    global_power_to_h2_demand : pandas.DataFrame
1034
        Global H2 demand per foreign node in 1 year
1035
1036
    """
1037
    sources = config.datasets()["gas_neighbours"]["sources"]
1038
    targets = config.datasets()["gas_neighbours"]["targets"]
1039
    map_buses = get_map_buses()
1040
1041
    scn_name = "eGon2035"
1042
    carrier = "H2_for_industry"
1043
1044
    db.execute_sql(
1045
        f"""
1046
        DELETE FROM
1047
        {targets['loads']['schema']}.{targets['loads']['table']}
1048
        WHERE bus IN (
1049
            SELECT bus_id FROM
1050
            {sources['buses']['schema']}.{sources['buses']['table']}
1051
            WHERE country != 'DE'
1052
            AND scn_name = '{scn_name}')
1053
        AND scn_name = '{scn_name}'
1054
        AND carrier = '{carrier}'
1055
        """
1056
    )
1057
1058
    # Set bus_id
1059
    global_power_to_h2_demand.loc[
1060
        global_power_to_h2_demand[
1061
            global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
1062
        ].index,
1063
        "Node/Line",
1064
    ] = global_power_to_h2_demand.loc[
1065
        global_power_to_h2_demand[
1066
            global_power_to_h2_demand["Node/Line"].isin(map_buses.keys())
1067
        ].index,
1068
        "Node/Line",
1069
    ].map(
1070
        map_buses
1071
    )
1072
    global_power_to_h2_demand.loc[:, "bus"] = (
1073
        get_foreign_bus_id()
1074
        .loc[global_power_to_h2_demand.loc[:, "Node/Line"]]
1075
        .values
1076
    )
1077
1078
    # Add missing columns
1079
    c = {"scn_name": scn_name, "carrier": carrier}
1080
    global_power_to_h2_demand = global_power_to_h2_demand.assign(**c)
1081
1082
    new_id = db.next_etrago_id("load")
1083
    global_power_to_h2_demand["load_id"] = range(
1084
        new_id, new_id + len(global_power_to_h2_demand)
1085
    )
1086
1087
    global_power_to_h2_demand = global_power_to_h2_demand.rename(
1088
        columns={"GlobD_2035": "p_set"}
1089
    )
1090
1091
    # Remove useless columns
1092
    global_power_to_h2_demand = global_power_to_h2_demand.drop(
1093
        columns=["Node/Line"]
1094
    )
1095
1096
    # Insert data to db
1097
    global_power_to_h2_demand.to_sql(
1098
        targets["loads"]["table"],
1099
        db.engine(),
1100
        schema=targets["loads"]["schema"],
1101
        index=False,
1102
        if_exists="append",
1103
    )
1104
1105
1106
def calculate_ch4_grid_capacities():
1107
    """Calculates CH4 grid capacities for foreign countries based on TYNDP-data
1108
1109
    Parameters
1110
    ----------
1111
    None.
1112
1113
    Returns
1114
    -------
1115
    Neighbouring_pipe_capacities_list : pandas.DataFrame
1116
1117
    """
1118
    sources = config.datasets()["gas_neighbours"]["sources"]
1119
1120
    # Download file
1121
    basename = "ENTSOG_TYNDP_2020_Annex_C2_Capacities_per_country.xlsx"
1122
    url = "https://www.entsog.eu/sites/default/files/2021-07/" + basename
1123
    target_file = Path(".") / "datasets" / "gas_data" / basename
1124
1125
    urlretrieve(url, target_file)
1126
    map_pipelines = {
1127
        "NORDSTREAM": "RU00",
1128
        "NORDSTREAM 2": "RU00",
1129
        "OPAL": "DE",
1130
        "YAMAL (BY)": "RU00",
1131
        "Denmark": "DKE1",
1132
        "Belgium": "BE00",
1133
        "Netherlands": "NL00",
1134
        "Norway": "NOM1",
1135
        "Switzerland": "CH00",
1136
        "Poland": "PL00",
1137
        "United Kingdom": "UK00",
1138
        "Germany": "DE",
1139
        "Austria": "AT00",
1140
        "France": "FR00",
1141
        "Czechia": "CZ00",
1142
        "Russia": "RU00",
1143
        "Luxemburg": "LUB1",
1144
    }
1145
1146
    grid_countries = [
1147
        "NORDSTREAM",
1148
        "NORDSTREAM 2",
1149
        "OPAL",
1150
        "YAMAL (BY)",
1151
        "Denmark",
1152
        "Belgium",
1153
        "Netherlands",
1154
        "Norway",
1155
        "Switzerland",
1156
        "Poland",
1157
        "United Kingdom",
1158
        "Germany",
1159
        "Austria",
1160
        "France",
1161
        "Czechia",
1162
        "Russia",
1163
        "Luxemburg",
1164
    ]
1165
1166
    # Read-in data from csv-file
1167
    pipe_capacities_list = pd.read_excel(
1168
        target_file,
1169
        sheet_name="Transmission Peak Capacity",
1170
        skiprows=range(4),
1171
    )
1172
    pipe_capacities_list = pipe_capacities_list[
1173
        ["To Country", "Unnamed: 3", "From Country", 2035]
1174
    ].rename(
1175
        columns={
1176
            "Unnamed: 3": "Scenario",
1177
            "To Country": "To_Country",
1178
            "From Country": "From_Country",
1179
        }
1180
    )
1181
    pipe_capacities_list["To_Country"] = pd.Series(
1182
        pipe_capacities_list["To_Country"]
1183
    ).fillna(method="ffill")
1184
    pipe_capacities_list["From_Country"] = pd.Series(
1185
        pipe_capacities_list["From_Country"]
1186
    ).fillna(method="ffill")
1187
    pipe_capacities_list = pipe_capacities_list[
1188
        pipe_capacities_list["Scenario"] == "Advanced"
1189
    ].drop(columns={"Scenario"})
1190
    pipe_capacities_list = pipe_capacities_list[
1191
        (
1192
            (pipe_capacities_list["To_Country"].isin(grid_countries))
1193
            & (pipe_capacities_list["From_Country"].isin(grid_countries))
1194
        )
1195
        & (pipe_capacities_list[2035] != 0)
1196
    ]
1197
    pipe_capacities_list["To_Country"] = pipe_capacities_list[
1198
        "To_Country"
1199
    ].map(map_pipelines)
1200
    pipe_capacities_list["From_Country"] = pipe_capacities_list[
1201
        "From_Country"
1202
    ].map(map_pipelines)
1203
    pipe_capacities_list["countrycombination"] = pipe_capacities_list[
1204
        ["To_Country", "From_Country"]
1205
    ].apply(
1206
        lambda x: tuple(sorted([str(x.To_Country), str(x.From_Country)])),
1207
        axis=1,
1208
    )
1209
1210
    pipeline_strategies = {
1211
        "To_Country": "first",
1212
        "From_Country": "first",
1213
        2035: sum,
1214
    }
1215
1216
    pipe_capacities_list = pipe_capacities_list.groupby(
1217
        ["countrycombination"]
1218
    ).agg(pipeline_strategies)
1219
1220
    # Add manually DK-SE and AT-CH pipes (Scigrid gas data)
1221
    pipe_capacities_list.loc["(DKE1, SE02)"] = ["DKE1", "SE02", 651]
1222
    pipe_capacities_list.loc["(AT00, CH00)"] = ["AT00", "CH00", 651]
1223
1224
    # Conversion GWh/d to MWh/h
1225
    pipe_capacities_list["p_nom"] = pipe_capacities_list[2035] * (1000 / 24)
1226
1227
    # Border crossing CH4 pipelines between foreign countries
1228
1229
    Neighbouring_pipe_capacities_list = pipe_capacities_list[
1230
        (pipe_capacities_list["To_Country"] != "DE")
1231
        & (pipe_capacities_list["From_Country"] != "DE")
1232
    ].reset_index()
1233
1234
    Neighbouring_pipe_capacities_list.loc[:, "bus0"] = (
1235
        get_foreign_gas_bus_id()
1236
        .loc[Neighbouring_pipe_capacities_list.loc[:, "To_Country"]]
1237
        .values
1238
    )
1239
    Neighbouring_pipe_capacities_list.loc[:, "bus1"] = (
1240
        get_foreign_gas_bus_id()
1241
        .loc[Neighbouring_pipe_capacities_list.loc[:, "From_Country"]]
1242
        .values
1243
    )
1244
1245
    # Adjust columns
1246
    Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
1247
        columns=[
1248
            "To_Country",
1249
            "From_Country",
1250
            "countrycombination",
1251
            2035,
1252
        ]
1253
    )
1254
1255
    new_id = db.next_etrago_id("link")
1256
    Neighbouring_pipe_capacities_list["link_id"] = range(
1257
        new_id, new_id + len(Neighbouring_pipe_capacities_list)
1258
    )
1259
1260
    # Border crossing CH4 pipelines between DE and neighbouring countries
1261
    DE_pipe_capacities_list = pipe_capacities_list[
1262
        (pipe_capacities_list["To_Country"] == "DE")
1263
        | (pipe_capacities_list["From_Country"] == "DE")
1264
    ].reset_index()
1265
1266
    dict_cross_pipes_DE = {
1267
        ("AT00", "DE"): "AT",
1268
        ("BE00", "DE"): "BE",
1269
        ("CH00", "DE"): "CH",
1270
        ("CZ00", "DE"): "CZ",
1271
        ("DE", "DKE1"): "DK",
1272
        ("DE", "FR00"): "FR",
1273
        ("DE", "LUB1"): "LU",
1274
        ("DE", "NL00"): "NL",
1275
        ("DE", "NOM1"): "NO",
1276
        ("DE", "PL00"): "PL",
1277
        ("DE", "RU00"): "RU",
1278
    }
1279
1280
    DE_pipe_capacities_list["country_code"] = DE_pipe_capacities_list[
1281
        "countrycombination"
1282
    ].map(dict_cross_pipes_DE)
1283
    DE_pipe_capacities_list = DE_pipe_capacities_list.set_index("country_code")
1284
1285
    schema = sources["buses"]["schema"]
1286
    table = sources["buses"]["table"]
1287
    for country_code in [e for e in countries if e not in ("GB", "SE", "UK")]:
1288
1289
        # Select cross-bording links
1290
        cap_DE = db.select_dataframe(
1291
            f"""SELECT link_id, bus0, bus1
1292
                FROM {sources['links']['schema']}.{sources['links']['table']}
1293
                    WHERE scn_name = 'eGon2035'
1294
                    AND carrier = 'CH4'
1295
                    AND (("bus0" IN (
1296
                        SELECT bus_id FROM {schema}.{table}
1297
                            WHERE country = 'DE'
1298
                            AND carrier = 'CH4'
1299
                            AND scn_name = 'eGon2035')
1300
                        AND "bus1" IN (SELECT bus_id FROM {schema}.{table}
1301
                            WHERE country = '{country_code}'
1302
                            AND carrier = 'CH4'
1303
                            AND scn_name = 'eGon2035')
1304
                    )
1305
                    OR ("bus0" IN (
1306
                        SELECT bus_id FROM {schema}.{table}
1307
                            WHERE country = '{country_code}'
1308
                            AND carrier = 'CH4'
1309
                            AND scn_name = 'eGon2035')
1310
                        AND "bus1" IN (SELECT bus_id FROM {schema}.{table}
1311
                            WHERE country = 'DE'
1312
                            AND carrier = 'CH4'
1313
                            AND scn_name = 'eGon2035'))
1314
                    )
1315
            ;"""
1316
        )
1317
1318
        cap_DE["p_nom"] = DE_pipe_capacities_list.at[
1319
            country_code, "p_nom"
1320
        ] / len(cap_DE.index)
1321
        Neighbouring_pipe_capacities_list = (
1322
            Neighbouring_pipe_capacities_list.append(cap_DE)
1323
        )
1324
1325
    # Add topo, geom and length
1326
    bus_geom = db.select_geodataframe(
1327
        """SELECT bus_id, geom
1328
        FROM grid.egon_etrago_bus
1329
        WHERE scn_name = 'eGon2035'
1330
        AND carrier = 'CH4'
1331
        """,
1332
        epsg=4326,
1333
    ).set_index("bus_id")
1334
1335
    coordinates_bus0 = []
1336
    coordinates_bus1 = []
1337
1338
    for index, row in Neighbouring_pipe_capacities_list.iterrows():
1339
        coordinates_bus0.append(bus_geom["geom"].loc[int(row["bus0"])])
1340
        coordinates_bus1.append(bus_geom["geom"].loc[int(row["bus1"])])
1341
1342
    Neighbouring_pipe_capacities_list["coordinates_bus0"] = coordinates_bus0
1343
    Neighbouring_pipe_capacities_list["coordinates_bus1"] = coordinates_bus1
1344
1345
    Neighbouring_pipe_capacities_list[
1346
        "topo"
1347
    ] = Neighbouring_pipe_capacities_list.apply(
1348
        lambda row: LineString(
1349
            [row["coordinates_bus0"], row["coordinates_bus1"]]
1350
        ),
1351
        axis=1,
1352
    )
1353
    Neighbouring_pipe_capacities_list[
1354
        "geom"
1355
    ] = Neighbouring_pipe_capacities_list.apply(
1356
        lambda row: MultiLineString([row["topo"]]), axis=1
1357
    )
1358
    Neighbouring_pipe_capacities_list[
1359
        "length"
1360
    ] = Neighbouring_pipe_capacities_list.apply(
1361
        lambda row: row["topo"].length, axis=1
1362
    )
1363
1364
    # Remove useless columns
1365
    Neighbouring_pipe_capacities_list = Neighbouring_pipe_capacities_list.drop(
1366
        columns=[
1367
            "coordinates_bus0",
1368
            "coordinates_bus1",
1369
        ]
1370
    )
1371
1372
    # Add missing columns
1373
    c = {"scn_name": "eGon2035", "carrier": "CH4"}
1374
    Neighbouring_pipe_capacities_list = (
1375
        Neighbouring_pipe_capacities_list.assign(**c)
1376
    )
1377
1378
    Neighbouring_pipe_capacities_list = (
1379
        Neighbouring_pipe_capacities_list.set_geometry("geom", crs=4326)
1380
    )
1381
1382
    return Neighbouring_pipe_capacities_list
1383
1384
1385
def tyndp_gas_generation():
1386
    """Insert data from TYNDP 2020 accordning to NEP 2021
1387
    Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
1388
1389
    Returns
1390
    -------
1391
    None.
1392
    """
1393
    capacities = calc_capacities()
1394
    insert_generators(capacities)
1395
1396
    ch4_storage_capacities = calc_ch4_storage_capacities()
1397
    insert_storage(ch4_storage_capacities)
1398
1399
1400
def tyndp_gas_demand():
1401
    """Insert gas demands abroad for eGon2035
1402
1403
    Insert CH4 and H2 demands abroad for eGon2035 by executing the
1404
    following steps:
1405
      * CH4
1406
          * Calculation of the global CH4 demand in Norway and of the
1407
            CH4 demand profile by executing the function
1408
            :py:func:`import_ch4_demandTS`
1409
          * Calculation of the global CH4 demands by executing the
1410
            function :py:func:`calc_global_ch4_demand`
1411
          * Insertion the CH4 loads and their associated time series
1412
            in the database by executing the function
1413
            :py:func:`insert_ch4_demand`
1414
      * H2
1415
          * Calculation of the global power demand abroad linked
1416
            to H2 production by executing the function
1417
            :py:func:`calc_global_power_to_h2_demand`
1418
          * Insertion of these loads in the database by executing the
1419
            function :py:func:`insert_power_to_h2_demand`
1420
    This function insert data in the database and has no return.
1421
1422
    """
1423
    Norway_global_demand_1y, normalized_ch4_demandTS = import_ch4_demandTS()
1424
    global_ch4_demand = calc_global_ch4_demand(Norway_global_demand_1y)
1425
    insert_ch4_demand(global_ch4_demand, normalized_ch4_demandTS)
1426
1427
    global_power_to_h2_demand = calc_global_power_to_h2_demand()
1428
    insert_power_to_h2_demand(global_power_to_h2_demand)
1429
1430
1431
def grid():
1432
    """Insert data from TYNDP 2020 accordning to NEP 2021
1433
    Scenario 'Distributed Energy', linear interpolate between 2030 and 2040
1434
1435
    Returns
1436
    -------
1437
    None.
1438
    """
1439
    Neighbouring_pipe_capacities_list = calculate_ch4_grid_capacities()
1440
    insert_gas_grid_capacities(
1441
        Neighbouring_pipe_capacities_list, scn_name="eGon2035"
1442
    )
1443
1444
1445
def calculate_ocgt_capacities():
1446
    """Calculate gas turbine capacities abroad for eGon2035
1447
1448
    Calculate gas turbine capacities abroad for eGon2035 based on TYNDP
1449
    2020, scenario "Distributed Energy", interpolated between 2030 and 2040
1450
1451
    Returns
1452
    -------
1453
    df_ocgt: pandas.DataFrame
1454
        Gas turbine capacities per foreign node
1455
1456
    """
1457
    sources = config.datasets()["gas_neighbours"]["sources"]
1458
1459
    # insert installed capacities
1460
    file = zipfile.ZipFile(f"tyndp/{sources['tyndp_capacities']}")
1461
    df = pd.read_excel(
1462
        file.open("TYNDP-2020-Scenario-Datafile.xlsx").read(),
1463
        sheet_name="Capacity",
1464
    )
1465
1466
    df_ocgt = df[
1467
        [
1468
            "Node/Line",
1469
            "Scenario",
1470
            "Climate Year",
1471
            "Generator_ID",
1472
            "Year",
1473
            "Value",
1474
        ]
1475
    ]
1476
    df_ocgt = df_ocgt[
1477
        (df_ocgt["Scenario"] == "Distributed Energy")
1478
        & (df_ocgt["Climate Year"] == 1984)
1479
    ]
1480
    df_ocgt = df_ocgt[df_ocgt["Generator_ID"].str.contains("Gas")]
1481
    df_ocgt = df_ocgt[df_ocgt["Year"].isin([2030, 2040])]
1482
1483
    df_ocgt = (
1484
        df_ocgt.groupby(["Node/Line", "Year"])["Value"].sum().reset_index()
1485
    )
1486
    df_ocgt = df_ocgt.groupby([df_ocgt["Node/Line"], "Year"]).sum()
1487
    df_ocgt = df_ocgt.groupby("Node/Line")["Value"].mean()
1488
    df_ocgt = pd.DataFrame(df_ocgt, columns=["Value"]).rename(
1489
        columns={"Value": "p_nom"}
1490
    )
1491
1492
    # Choose capacities for considered countries
1493
    df_ocgt = df_ocgt[df_ocgt.index.str[:2].isin(countries)]
1494
1495
    # Attribute bus0 and bus1
1496
    df_ocgt["bus0"] = get_foreign_gas_bus_id()[df_ocgt.index]
1497
    df_ocgt["bus1"] = get_foreign_bus_id()[df_ocgt.index]
1498
    df_ocgt = df_ocgt.groupby(by=["bus0", "bus1"], as_index=False).sum()
1499
1500
    return df_ocgt
1501
1502
1503
def insert_ocgt_abroad():
1504
    """Insert gas turbine capicities abroad for eGon2035 in the database
1505
1506
    This function inserts data in the database and has no return.
1507
1508
    Parameters
1509
    ----------
1510
    df_ocgt: pandas.DataFrame
1511
        Gas turbine capacities per foreign node
1512
1513
    """
1514
    scn_name = "eGon2035"
1515
    carrier = "OCGT"
1516
1517
    # Connect to local database
1518
    engine = db.engine()
1519
1520
    df_ocgt = calculate_ocgt_capacities()
1521
1522
    df_ocgt["p_nom_extendable"] = False
1523
    df_ocgt["carrier"] = carrier
1524
    df_ocgt["scn_name"] = scn_name
1525
1526
    buses = tuple(
1527
        db.select_dataframe(
1528
            f"""SELECT bus_id FROM grid.egon_etrago_bus
1529
            WHERE scn_name = '{scn_name}' AND country != 'DE';
1530
        """
1531
        )["bus_id"]
1532
    )
1533
1534
    # Delete old entries
1535
    db.execute_sql(
1536
        f"""
1537
        DELETE FROM grid.egon_etrago_link WHERE "carrier" = '{carrier}'
1538
        AND scn_name = '{scn_name}'
1539
        AND bus0 IN {buses} AND bus1 IN {buses};
1540
        """
1541
    )
1542
1543
    # read carrier information from scnario parameter data
1544
    scn_params = get_sector_parameters("gas", scn_name)
1545
    df_ocgt["efficiency"] = scn_params["efficiency"][carrier]
1546
    df_ocgt["marginal_cost"] = (
1547
        scn_params["marginal_cost"][carrier]
1548
        / scn_params["efficiency"][carrier]
1549
    )
1550
1551
    # Adjust p_nom
1552
    df_ocgt["p_nom"] = df_ocgt["p_nom"] / scn_params["efficiency"][carrier]
1553
1554
    # Select next id value
1555
    new_id = db.next_etrago_id("link")
1556
    df_ocgt["link_id"] = range(new_id, new_id + len(df_ocgt))
1557
1558
    # Insert data to db
1559
    df_ocgt.to_sql(
1560
        "egon_etrago_link",
1561
        engine,
1562
        schema="grid",
1563
        index=False,
1564
        if_exists="append",
1565
    )
1566