Passed
Pull Request — dev (#1197)
by
unknown
05:18
created

data.datasets.pypsaeur   F

Complexity

Total Complexity 83

Size/Duplication

Total Lines 1654
Duplicated Lines 3.99 %

Importance

Changes 0
Metric Value
wmc 83
eloc 1002
dl 66
loc 1654
rs 1.592
c 0
b 0
f 0

20 Functions

Rating   Name   Duplication   Size   Complexity  
A solve_network() 0 34 2
F download() 0 164 14
A h2_overground_stores() 0 43 1
A update_electrical_timeseries_germany() 0 24 1
A prepare_network() 0 20 2
A overwrite_H2_pipeline_share() 0 43 1
A drop_fossil_gas() 0 7 1
A drop_biomass() 0 6 2
A prepared_network() 33 33 3
A execute() 0 46 3
A rual_heat_technologies() 0 16 1
A read_network() 33 33 3
A drop_urban_decentral_heat() 0 6 2
A clean_database() 0 83 3
F neighbor_reduction() 0 869 34
A electrical_neighbours_egon100() 0 7 2
A drop_new_gas_pipelines() 0 9 1
A district_heating_shares() 0 43 2
A update_heat_timeseries_germany() 0 18 1
A geothermal_district_heating() 0 40 2

2 Methods

Rating   Name   Duplication   Size   Complexity  
A RunPypsaEur.__init__() 0 10 1
A PreparePypsaEur.__init__() 0 8 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like data.datasets.pypsaeur often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""The central module containing all code dealing with importing data from
2
the pysa-eur-sec scenario parameter creation
3
"""
4
5
from pathlib import Path
6
from urllib.request import urlretrieve
7
import json
8
import shutil
9
10
from shapely.geometry import LineString
11
import geopandas as gpd
12
import importlib_resources as resources
13
import numpy as np
14
import pandas as pd
15
import pypsa
16
import requests
17
import yaml
18
19
from egon.data import __path__, config, db, logger
20
from egon.data.datasets import Dataset
21
from egon.data.datasets.scenario_parameters import get_sector_parameters
22
from egon.data.datasets.scenario_parameters.parameters import (
23
    annualize_capital_costs,
24
)
25
import egon.data.config
26
import egon.data.subprocess as subproc
27
28
29
class PreparePypsaEur(Dataset):
30
    def __init__(self, dependencies):
31
        super().__init__(
32
            name="PreparePypsaEur",
33
            version="0.0.9",
34
            dependencies=dependencies,
35
            tasks=(
36
                download,
37
                prepare_network,
38
            ),
39
        )
40
41
42
class RunPypsaEur(Dataset):
43
    def __init__(self, dependencies):
44
        super().__init__(
45
            name="SolvePypsaEur",
46
            version="0.0.8",
47
            dependencies=dependencies,
48
            tasks=(
49
                execute,
50
                solve_network,
51
                clean_database,
52
                electrical_neighbours_egon100,
53
                # Dropped until we decided how we deal with the H2 grid
54
                # overwrite_H2_pipeline_share,
55
            ),
56
        )
57
58
59
def download():
60
    cwd = Path(".")
61
    filepath = cwd / "run-pypsa-eur"
62
    filepath.mkdir(parents=True, exist_ok=True)
63
64
    pypsa_eur_repos = filepath / "pypsa-eur"
65
    if config.settings()["egon-data"]["--run-pypsa-eur"]:
66
        if not pypsa_eur_repos.exists():
67
            subproc.run(
68
                [
69
                    "git",
70
                    "clone",
71
                    "--branch",
72
                    "v0.10.0",
73
                    "https://github.com/PyPSA/pypsa-eur.git",
74
                    pypsa_eur_repos,
75
                ]
76
            )
77
78
            # Add gurobi solver to environment:
79
            # Read YAML file
80
            path_to_env = pypsa_eur_repos / "envs" / "environment.yaml"
81
            with open(path_to_env, "r") as stream:
82
                env = yaml.safe_load(stream)
83
84
            # The version of gurobipy has to fit to the version of gurobi.
85
            # Since we mainly use gurobi 10.0 this is set here.
86
            env["dependencies"][-1]["pip"].append("gurobipy==10.0.0")
87
88
            # Set python version to <3.12
89
            # Python<=3.12 needs gurobipy>=11.0, in case gurobipy is updated,
90
            # this can be removed
91
            env["dependencies"] = [
92
                "python>=3.8,<3.12" if x == "python>=3.8" else x
93
                for x in env["dependencies"]
94
            ]
95
96
            # Limit geopandas version
97
            # our pypsa-eur version is not compatible to geopandas>1
98
            env["dependencies"] = [
99
                "geopandas>=0.11.0,<1" if x == "geopandas>=0.11.0" else x
100
                for x in env["dependencies"]
101
            ]
102
103
            # Write YAML file
104
            with open(path_to_env, "w", encoding="utf8") as outfile:
105
                yaml.dump(
106
                    env, outfile, default_flow_style=False, allow_unicode=True
107
                )
108
109
            # Copy config file for egon-data to pypsa-eur directory
110
            shutil.copy(
111
                Path(__path__[0], "datasets", "pypsaeur", "config.yaml"),
112
                pypsa_eur_repos / "config",
113
            )
114
115
            with open(filepath / "Snakefile", "w") as snakefile:
116
                snakefile.write(
117
                    resources.read_text(
118
                        "egon.data.datasets.pypsaeur", "Snakefile"
119
                    )
120
                )
121
122
        # Copy era5 weather data to folder for pypsaeur
123
        era5_pypsaeur_path = filepath / "pypsa-eur" / "cutouts"
124
125
        if not era5_pypsaeur_path.exists():
126
            era5_pypsaeur_path.mkdir(parents=True, exist_ok=True)
127
            copy_from = config.datasets()["era5_weather_data"]["targets"][
128
                "weather_data"
129
            ]["path"]
130
            filename = "europe-2011-era5.nc"
131
            shutil.copy(
132
                copy_from + "/" + filename, era5_pypsaeur_path / filename
133
            )
134
135
        # Workaround to download natura, shipdensity and globalenergymonitor
136
        # data, which is not working in the regular snakemake workflow.
137
        # The same files are downloaded from the same directory as in pypsa-eur
138
        # version 0.10 here. Is is stored in the folders from pypsa-eur.
139
        if not (filepath / "pypsa-eur" / "resources").exists():
140
            (filepath / "pypsa-eur" / "resources").mkdir(
141
                parents=True, exist_ok=True
142
            )
143
        urlretrieve(
144
            "https://zenodo.org/record/4706686/files/natura.tiff",
145
            filepath / "pypsa-eur" / "resources" / "natura.tiff",
146
        )
147
148
        if not (filepath / "pypsa-eur" / "data").exists():
149
            (filepath / "pypsa-eur" / "data").mkdir(
150
                parents=True, exist_ok=True
151
            )
152
        urlretrieve(
153
            "https://zenodo.org/record/6953563/files/shipdensity_global.zip",
154
            filepath / "pypsa-eur" / "data" / "shipdensity_global.zip",
155
        )
156
157
        if not (
158
            filepath
159
            / "pypsa-eur"
160
            / "zenodo.org"
161
            / "records"
162
            / "10356004"
163
            / "files"
164
        ).exists():
165
            (
166
                filepath
167
                / "pypsa-eur"
168
                / "zenodo.org"
169
                / "records"
170
                / "10356004"
171
                / "files"
172
            ).mkdir(parents=True, exist_ok=True)
173
174
        urlretrieve(
175
            "https://zenodo.org/records/10356004/files/ENSPRESO_BIOMASS.xlsx",
176
            filepath
177
            / "pypsa-eur"
178
            / "zenodo.org"
179
            / "records"
180
            / "10356004"
181
            / "files"
182
            / "ENSPRESO_BIOMASS.xlsx",
183
        )
184
185
        if not (
186
            filepath
187
            / "pypsa-eur"
188
            / "globalenergymonitor.org"
189
            / "wp-content"
190
            / "uploads"
191
            / "2023"
192
            / "07"
193
        ).exists():
194
            (
195
                filepath
196
                / "pypsa-eur"
197
                / "globalenergymonitor.org"
198
                / "wp-content"
199
                / "uploads"
200
                / "2023"
201
                / "07"
202
            ).mkdir(parents=True, exist_ok=True)
203
204
        r = requests.get(
205
            "https://globalenergymonitor.org/wp-content/uploads/2023/07/"
206
            "Europe-Gas-Tracker-2023-03-v3.xlsx"
207
        )
208
        with open(
209
            filepath
210
            / "pypsa-eur"
211
            / "globalenergymonitor.org"
212
            / "wp-content"
213
            / "uploads"
214
            / "2023"
215
            / "07"
216
            / "Europe-Gas-Tracker-2023-03-v3.xlsx",
217
            "wb",
218
        ) as outfile:
219
            outfile.write(r.content)
220
221
    else:
222
        print("Pypsa-eur is not executed due to the settings of egon-data")
223
224
225
def prepare_network():
226
    cwd = Path(".")
227
    filepath = cwd / "run-pypsa-eur"
228
229
    if config.settings()["egon-data"]["--run-pypsa-eur"]:
230
        subproc.run(
231
            [
232
                "snakemake",
233
                "-j1",
234
                "--directory",
235
                filepath,
236
                "--snakefile",
237
                filepath / "Snakefile",
238
                "--use-conda",
239
                "--conda-frontend=conda",
240
                "prepare",
241
            ]
242
        )
243
    else:
244
        print("Pypsa-eur is not executed due to the settings of egon-data")
245
246
247
def solve_network():
248
    cwd = Path(".")
249
    filepath = cwd / "run-pypsa-eur"
250
251
    if config.settings()["egon-data"]["--run-pypsa-eur"]:
252
        subproc.run(
253
            [
254
                "snakemake",
255
                "-j1",
256
                "--directory",
257
                filepath,
258
                "--snakefile",
259
                filepath / "Snakefile",
260
                "--use-conda",
261
                "--conda-frontend=conda",
262
                "solve",
263
            ]
264
        )
265
266
        subproc.run(
267
            [
268
                "snakemake",
269
                "-j1",
270
                "--directory",
271
                filepath,
272
                "--snakefile",
273
                filepath / "Snakefile",
274
                "--use-conda",
275
                "--conda-frontend=conda",
276
                "summary",
277
            ]
278
        )
279
    else:
280
        print("Pypsa-eur is not executed due to the settings of egon-data")
281
282
283 View Code Duplication
def read_network():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
284
    if config.settings()["egon-data"]["--run-pypsa-eur"]:
285
        with open(
286
            __path__[0] + "/datasets/pypsaeur/config.yaml", "r"
287
        ) as stream:
288
            data_config = yaml.safe_load(stream)
289
290
        target_file = (
291
            Path(".")
292
            / "run-pypsa-eur"
293
            / "pypsa-eur"
294
            / "results"
295
            / data_config["run"]["name"]
296
            / "postnetworks"
297
            / f"elec_s_{data_config['scenario']['clusters'][0]}"
298
            f"_l{data_config['scenario']['ll'][0]}"
299
            f"_{data_config['scenario']['opts'][0]}"
300
            f"_{data_config['scenario']['sector_opts'][0]}"
301
            f"_{data_config['scenario']['planning_horizons'][0]}.nc"
302
        )
303
304
    else:
305
        target_file = (
306
            Path(".")
307
            / "data_bundle_powerd_data"
308
            / "pypsa_eur"
309
            / "2024-08-02-egondata-integration"
310
            / "results"
311
            / "postnetworks"
312
            / "elec_s_37_lv1.5__Co2L0-1H-T-H-B-I-A-solar+p3_2050.nc"
313
        )
314
315
    return pypsa.Network(target_file)
316
317
318
def clean_database():
319
    """Remove all components abroad for eGon100RE of the database
320
321
    Remove all components abroad and their associated time series of
322
    the datase for the scenario 'eGon100RE'.
323
324
    Parameters
325
    ----------
326
    None
327
328
    Returns
329
    -------
330
    None
331
332
    """
333
    scn_name = "eGon100RE"
334
335
    comp_one_port = ["load", "generator", "store", "storage"]
336
337
    # delete existing components and associated timeseries
338
    for comp in comp_one_port:
339
        db.execute_sql(
340
            f"""
341
            DELETE FROM {"grid.egon_etrago_" + comp + "_timeseries"}
342
            WHERE {comp + "_id"} IN (
343
                SELECT {comp + "_id"} FROM {"grid.egon_etrago_" + comp}
344
                WHERE bus IN (
345
                    SELECT bus_id FROM grid.egon_etrago_bus
346
                    WHERE country != 'DE'
347
                    AND scn_name = '{scn_name}')
348
                AND scn_name = '{scn_name}'
349
            );
350
351
            DELETE FROM {"grid.egon_etrago_" + comp}
352
            WHERE bus IN (
353
                SELECT bus_id FROM grid.egon_etrago_bus
354
                WHERE country != 'DE'
355
                AND scn_name = '{scn_name}')
356
            AND scn_name = '{scn_name}';"""
357
        )
358
359
    comp_2_ports = [
360
        "line",
361
        "transformer",
362
        "link",
363
    ]
364
365
    for comp, id in zip(comp_2_ports, ["line_id", "trafo_id", "link_id"]):
366
        db.execute_sql(
367
            f"""
368
            DELETE FROM {"grid.egon_etrago_" + comp + "_timeseries"}
369
            WHERE scn_name = '{scn_name}'
370
            AND {id} IN (
371
                SELECT {id} FROM {"grid.egon_etrago_" + comp}
372
            WHERE "bus0" IN (
373
            SELECT bus_id FROM grid.egon_etrago_bus
374
                WHERE country != 'DE'
375
                AND scn_name = '{scn_name}'
376
                AND bus_id NOT IN (SELECT bus_i FROM osmtgmod_results.bus_data))
377
            AND "bus1" IN (
378
            SELECT bus_id FROM grid.egon_etrago_bus
379
                WHERE country != 'DE'
380
                AND scn_name = '{scn_name}'
381
                AND bus_id NOT IN (SELECT bus_i FROM osmtgmod_results.bus_data))
382
            );
383
384
385
            DELETE FROM {"grid.egon_etrago_" + comp}
386
            WHERE scn_name = '{scn_name}'
387
            AND "bus0" IN (
388
            SELECT bus_id FROM grid.egon_etrago_bus
389
                WHERE country != 'DE'
390
                AND scn_name = '{scn_name}'
391
                AND bus_id NOT IN (SELECT bus_i FROM osmtgmod_results.bus_data))
392
            AND "bus1" IN (
393
            SELECT bus_id FROM grid.egon_etrago_bus
394
                WHERE country != 'DE'
395
                AND scn_name = '{scn_name}'
396
                AND bus_id NOT IN (SELECT bus_i FROM osmtgmod_results.bus_data))
397
            ;"""
398
        )
399
400
    db.execute_sql(f"""
401
        DELETE FROM grid.egon_etrago_bus
402
        WHERE scn_name = '{scn_name}'
403
        AND country <> 'DE'
404
        AND carrier <> 'AC'
405
        """
406
    )
407
408
409
def electrical_neighbours_egon100():
410
    if "eGon100RE" in egon.data.config.settings()["egon-data"]["--scenarios"]:
411
        neighbor_reduction()
412
413
    else:
414
        print(
415
            "eGon100RE is not in the list of created scenarios, this task is skipped."
416
        )
417
418
419
def neighbor_reduction():
420
    network = read_network()
421
422
    # network.links.drop("pipe_retrofit", axis="columns", inplace=True)
423
424
    wanted_countries = [
425
        "DE",
426
        "AT",
427
        "CH",
428
        "CZ",
429
        "PL",
430
        "SE",
431
        "NO",
432
        "DK",
433
        "GB",
434
        "NL",
435
        "BE",
436
        "FR",
437
        "LU",
438
    ]
439
    foreign_buses = network.buses[
440
        ~network.buses.index.str.contains("|".join(wanted_countries))
441
    ]
442
    network.buses = network.buses.drop(
443
        network.buses.loc[foreign_buses.index].index
444
    )
445
446
    # drop foreign lines and links from the 2nd row
447
448
    network.lines = network.lines.drop(
449
        network.lines[
450
            (network.lines["bus0"].isin(network.buses.index) == False)
451
            & (network.lines["bus1"].isin(network.buses.index) == False)
452
        ].index
453
    )
454
455
    # select all lines which have at bus1 the bus which is kept
456
    lines_cb_1 = network.lines[
457
        (network.lines["bus0"].isin(network.buses.index) == False)
458
    ]
459
460
    # create a load at bus1 with the line's hourly loading
461
    for i, k in zip(lines_cb_1.bus1.values, lines_cb_1.index):
462
        network.add(
463
            "Load",
464
            "slack_fix " + i + " " + k,
465
            bus=i,
466
            p_set=network.lines_t.p1[k],
467
        )
468
        network.loads.carrier.loc["slack_fix " + i + " " + k] = (
469
            lines_cb_1.carrier[k]
470
        )
471
472
    # select all lines which have at bus0 the bus which is kept
473
    lines_cb_0 = network.lines[
474
        (network.lines["bus1"].isin(network.buses.index) == False)
475
    ]
476
477
    # create a load at bus0 with the line's hourly loading
478
    for i, k in zip(lines_cb_0.bus0.values, lines_cb_0.index):
479
        network.add(
480
            "Load",
481
            "slack_fix " + i + " " + k,
482
            bus=i,
483
            p_set=network.lines_t.p0[k],
484
        )
485
        network.loads.carrier.loc["slack_fix " + i + " " + k] = (
486
            lines_cb_0.carrier[k]
487
        )
488
489
    # do the same for links
490
491
    network.links = network.links.drop(
492
        network.links[
493
            (network.links["bus0"].isin(network.buses.index) == False)
494
            & (network.links["bus1"].isin(network.buses.index) == False)
495
        ].index
496
    )
497
498
    # select all links which have at bus1 the bus which is kept
499
    links_cb_1 = network.links[
500
        (network.links["bus0"].isin(network.buses.index) == False)
501
    ]
502
503
    # create a load at bus1 with the link's hourly loading
504
    for i, k in zip(links_cb_1.bus1.values, links_cb_1.index):
505
        network.add(
506
            "Load",
507
            "slack_fix_links " + i + " " + k,
508
            bus=i,
509
            p_set=network.links_t.p1[k],
510
        )
511
        network.loads.carrier.loc["slack_fix_links " + i + " " + k] = (
512
            links_cb_1.carrier[k]
513
        )
514
515
    # select all links which have at bus0 the bus which is kept
516
    links_cb_0 = network.links[
517
        (network.links["bus1"].isin(network.buses.index) == False)
518
    ]
519
520
    # create a load at bus0 with the link's hourly loading
521
    for i, k in zip(links_cb_0.bus0.values, links_cb_0.index):
522
        network.add(
523
            "Load",
524
            "slack_fix_links " + i + " " + k,
525
            bus=i,
526
            p_set=network.links_t.p0[k],
527
        )
528
        network.loads.carrier.loc["slack_fix_links " + i + " " + k] = (
529
            links_cb_0.carrier[k]
530
        )
531
532
    # drop remaining foreign components
533
534
    network.lines = network.lines.drop(
535
        network.lines[
536
            (network.lines["bus0"].isin(network.buses.index) == False)
537
            | (network.lines["bus1"].isin(network.buses.index) == False)
538
        ].index
539
    )
540
541
    network.links = network.links.drop(
542
        network.links[
543
            (network.links["bus0"].isin(network.buses.index) == False)
544
            | (network.links["bus1"].isin(network.buses.index) == False)
545
        ].index
546
    )
547
548
    network.transformers = network.transformers.drop(
549
        network.transformers[
550
            (network.transformers["bus0"].isin(network.buses.index) == False)
551
            | (network.transformers["bus1"].isin(network.buses.index) == False)
552
        ].index
553
    )
554
    network.generators = network.generators.drop(
555
        network.generators[
556
            (network.generators["bus"].isin(network.buses.index) == False)
557
        ].index
558
    )
559
560
    network.loads = network.loads.drop(
561
        network.loads[
562
            (network.loads["bus"].isin(network.buses.index) == False)
563
        ].index
564
    )
565
566
    network.storage_units = network.storage_units.drop(
567
        network.storage_units[
568
            (network.storage_units["bus"].isin(network.buses.index) == False)
569
        ].index
570
    )
571
572
    components = [
573
        "loads",
574
        "generators",
575
        "lines",
576
        "buses",
577
        "transformers",
578
        "links",
579
    ]
580
    for g in components:  # loads_t
581
        h = g + "_t"
582
        nw = getattr(network, h)  # network.loads_t
583
        for i in nw.keys():  # network.loads_t.p
584
            cols = [
585
                j
586
                for j in getattr(nw, i).columns
587
                if j not in getattr(network, g).index
588
            ]
589
            for k in cols:
590
                del getattr(nw, i)[k]
591
592
    # writing components of neighboring countries to etrago tables
593
594
    # Set country tag for all buses
595
    network.buses.country = network.buses.index.str[:2]
596
    neighbors = network.buses[network.buses.country != "DE"]
597
598
    neighbors["new_index"] = (
599
        db.next_etrago_id("bus") + neighbors.reset_index().index
600
    )
601
602
    # Use index of AC buses created by electrical_neigbors
603
    foreign_ac_buses = db.select_dataframe(
604
        """
605
        SELECT * FROM grid.egon_etrago_bus
606
        WHERE carrier = 'AC' AND v_nom = 380
607
        AND country!= 'DE' AND scn_name ='eGon100RE'
608
        AND bus_id NOT IN (SELECT bus_i FROM osmtgmod_results.bus_data)
609
        """
610
    )
611
    buses_with_defined_id = neighbors[
612
        (neighbors.carrier == "AC")
613
        & (neighbors.country.isin(foreign_ac_buses.country.values))
614
    ].index
615
    neighbors.loc[buses_with_defined_id, "new_index"] = (
616
        foreign_ac_buses.set_index("x")
617
        .loc[neighbors.loc[buses_with_defined_id, "x"]]
618
        .bus_id.values
619
    )
620
621
    # lines, the foreign crossborder lines
622
    # (without crossborder lines to Germany!)
623
624
    neighbor_lines = network.lines[
625
        network.lines.bus0.isin(neighbors.index)
626
        & network.lines.bus1.isin(neighbors.index)
627
    ]
628
    if not network.lines_t["s_max_pu"].empty:
629
        neighbor_lines_t = network.lines_t["s_max_pu"][neighbor_lines.index]
630
631
    neighbor_lines.reset_index(inplace=True)
632
    neighbor_lines.bus0 = (
633
        neighbors.loc[neighbor_lines.bus0, "new_index"].reset_index().new_index
634
    )
635
    neighbor_lines.bus1 = (
636
        neighbors.loc[neighbor_lines.bus1, "new_index"].reset_index().new_index
637
    )
638
    neighbor_lines.index += db.next_etrago_id("line")
639
640
    if not network.lines_t["s_max_pu"].empty:
641
        for i in neighbor_lines_t.columns:
0 ignored issues
show
introduced by
The variable neighbor_lines_t does not seem to be defined in case BooleanNotNode on line 628 is False. Are you sure this can never be the case?
Loading history...
642
            new_index = neighbor_lines[neighbor_lines["name"] == i].index
643
            neighbor_lines_t.rename(columns={i: new_index[0]}, inplace=True)
644
645
    # links
646
    neighbor_links = network.links[
647
        network.links.bus0.isin(neighbors.index)
648
        & network.links.bus1.isin(neighbors.index)
649
    ]
650
651
    neighbor_links.reset_index(inplace=True)
652
    neighbor_links.bus0 = (
653
        neighbors.loc[neighbor_links.bus0, "new_index"].reset_index().new_index
654
    )
655
    neighbor_links.bus1 = (
656
        neighbors.loc[neighbor_links.bus1, "new_index"].reset_index().new_index
657
    )
658
    neighbor_links.index += db.next_etrago_id("link")
659
660
    # generators
661
    neighbor_gens = network.generators[
662
        network.generators.bus.isin(neighbors.index)
663
    ]
664
    neighbor_gens_t = network.generators_t["p_max_pu"][
665
        neighbor_gens[
666
            neighbor_gens.index.isin(network.generators_t["p_max_pu"].columns)
667
        ].index
668
    ]
669
670
    neighbor_gens.reset_index(inplace=True)
671
    neighbor_gens.bus = (
672
        neighbors.loc[neighbor_gens.bus, "new_index"].reset_index().new_index
673
    )
674
    neighbor_gens.index += db.next_etrago_id("generator")
675
676
    for i in neighbor_gens_t.columns:
677
        new_index = neighbor_gens[neighbor_gens["Generator"] == i].index
678
        neighbor_gens_t.rename(columns={i: new_index[0]}, inplace=True)
679
680
    # loads
681
682
    neighbor_loads = network.loads[network.loads.bus.isin(neighbors.index)]
683
    neighbor_loads_t_index = neighbor_loads.index[
684
        neighbor_loads.index.isin(network.loads_t.p_set.columns)
685
    ]
686
    neighbor_loads_t = network.loads_t["p_set"][neighbor_loads_t_index]
687
688
    neighbor_loads.reset_index(inplace=True)
689
    neighbor_loads.bus = (
690
        neighbors.loc[neighbor_loads.bus, "new_index"].reset_index().new_index
691
    )
692
    neighbor_loads.index += db.next_etrago_id("load")
693
694
    for i in neighbor_loads_t.columns:
695
        new_index = neighbor_loads[neighbor_loads["Load"] == i].index
696
        neighbor_loads_t.rename(columns={i: new_index[0]}, inplace=True)
697
698
    # stores
699
    neighbor_stores = network.stores[network.stores.bus.isin(neighbors.index)]
700
    neighbor_stores_t_index = neighbor_stores.index[
701
        neighbor_stores.index.isin(network.stores_t.e_min_pu.columns)
702
    ]
703
    neighbor_stores_t = network.stores_t["e_min_pu"][neighbor_stores_t_index]
704
705
    neighbor_stores.reset_index(inplace=True)
706
    neighbor_stores.bus = (
707
        neighbors.loc[neighbor_stores.bus, "new_index"].reset_index().new_index
708
    )
709
    neighbor_stores.index += db.next_etrago_id("store")
710
711
    for i in neighbor_stores_t.columns:
712
        new_index = neighbor_stores[neighbor_stores["Store"] == i].index
713
        neighbor_stores_t.rename(columns={i: new_index[0]}, inplace=True)
714
715
    # storage_units
716
    neighbor_storage = network.storage_units[
717
        network.storage_units.bus.isin(neighbors.index)
718
    ]
719
    neighbor_storage_t_index = neighbor_storage.index[
720
        neighbor_storage.index.isin(network.storage_units_t.inflow.columns)
721
    ]
722
    neighbor_storage_t = network.storage_units_t["inflow"][
723
        neighbor_storage_t_index
724
    ]
725
726
    neighbor_storage.reset_index(inplace=True)
727
    neighbor_storage.bus = (
728
        neighbors.loc[neighbor_storage.bus, "new_index"]
729
        .reset_index()
730
        .new_index
731
    )
732
    neighbor_storage.index += db.next_etrago_id("storage")
733
734
    for i in neighbor_storage_t.columns:
735
        new_index = neighbor_storage[
736
            neighbor_storage["StorageUnit"] == i
737
        ].index
738
        neighbor_storage_t.rename(columns={i: new_index[0]}, inplace=True)
739
740
    # Connect to local database
741
    engine = db.engine()
742
743
    neighbors["scn_name"] = "eGon100RE"
744
    neighbors.index = neighbors["new_index"]
745
746
    # Correct geometry for non AC buses
747
    carriers = set(neighbors.carrier.to_list())
748
    carriers = [e for e in carriers if e not in ("AC", "biogas")]
749
    non_AC_neighbors = pd.DataFrame()
750
    for c in carriers:
751
        c_neighbors = neighbors[neighbors.carrier == c].set_index(
752
            "location", drop=False
753
        )
754
        for i in ["x", "y"]:
755
            c_neighbors = c_neighbors.drop(i, axis=1)
756
        coordinates = neighbors[neighbors.carrier == "AC"][
757
            ["location", "x", "y"]
758
        ].set_index("location")
759
        c_neighbors = pd.concat([coordinates, c_neighbors], axis=1).set_index(
760
            "new_index", drop=False
761
        )
762
        non_AC_neighbors = pd.concat([non_AC_neighbors, c_neighbors])
763
    neighbors = pd.concat(
764
        [neighbors[neighbors.carrier == "AC"], non_AC_neighbors]
765
    )
766
767
    for i in [
768
        "new_index",
769
        "control",
770
        "generator",
771
        "location",
772
        "sub_network",
773
        "unit",
774
    ]:
775
        neighbors = neighbors.drop(i, axis=1)
776
777
    # Add geometry column
778
    neighbors = (
779
        gpd.GeoDataFrame(
780
            neighbors, geometry=gpd.points_from_xy(neighbors.x, neighbors.y)
781
        )
782
        .rename_geometry("geom")
783
        .set_crs(4326)
784
    )
785
786
    # Unify carrier names
787
    neighbors.carrier = neighbors.carrier.str.replace(" ", "_")
788
    neighbors.carrier.replace(
789
        {
790
            "gas": "CH4",
791
            "gas_for_industry": "CH4_for_industry",
792
        },
793
        inplace=True,
794
    )
795
796
    neighbors[~neighbors.carrier.isin(["AC"])].to_postgis(
797
        "egon_etrago_bus",
798
        engine,
799
        schema="grid",
800
        if_exists="append",
801
        index=True,
802
        index_label="bus_id",
803
    )
804
805
    # prepare and write neighboring crossborder lines to etrago tables
806
    def lines_to_etrago(neighbor_lines=neighbor_lines, scn="eGon100RE"):
807
        neighbor_lines["scn_name"] = scn
808
        neighbor_lines["cables"] = 3 * neighbor_lines["num_parallel"].astype(
809
            int
810
        )
811
        neighbor_lines["s_nom"] = neighbor_lines["s_nom_min"]
812
813
        for i in [
814
            "Line",
815
            "x_pu_eff",
816
            "r_pu_eff",
817
            "sub_network",
818
            "x_pu",
819
            "r_pu",
820
            "g_pu",
821
            "b_pu",
822
            "s_nom_opt",
823
            "i_nom",
824
        ]:
825
            neighbor_lines = neighbor_lines.drop(i, axis=1)
826
827
        # Define geometry and add to lines dataframe as 'topo'
828
        gdf = gpd.GeoDataFrame(index=neighbor_lines.index)
829
        gdf["geom_bus0"] = neighbors.geom[neighbor_lines.bus0].values
830
        gdf["geom_bus1"] = neighbors.geom[neighbor_lines.bus1].values
831
        gdf["geometry"] = gdf.apply(
832
            lambda x: LineString([x["geom_bus0"], x["geom_bus1"]]), axis=1
833
        )
834
835
        neighbor_lines = (
836
            gpd.GeoDataFrame(neighbor_lines, geometry=gdf["geometry"])
837
            .rename_geometry("topo")
838
            .set_crs(4326)
839
        )
840
841
        neighbor_lines["lifetime"] = get_sector_parameters("electricity", scn)[
842
            "lifetime"
843
        ]["ac_ehv_overhead_line"]
844
845
        neighbor_lines.to_postgis(
846
            "egon_etrago_line",
847
            engine,
848
            schema="grid",
849
            if_exists="append",
850
            index=True,
851
            index_label="line_id",
852
        )
853
854
    lines_to_etrago(neighbor_lines=neighbor_lines, scn="eGon100RE")
855
856
    def links_to_etrago(neighbor_links, scn="eGon100RE", extendable=True):
857
        """Prepare and write neighboring crossborder links to eTraGo table
858
859
        This function prepare the neighboring crossborder links
860
        generated the PyPSA-eur-sec (p-e-s) run by:
861
          * Delete the useless columns
862
          * If extendable is false only (non default case):
863
              * Replace p_nom = 0 with the p_nom_op values (arrising
864
                from the p-e-s optimisation)
865
              * Setting p_nom_extendable to false
866
          * Add geomtry to the links: 'geom' and 'topo' columns
867
          * Change the name of the carriers to have the consistent in
868
            eGon-data
869
870
        The function insert then the link to the eTraGo table and has
871
        no return.
872
873
        Parameters
874
        ----------
875
        neighbor_links : pandas.DataFrame
876
            Dataframe containing the neighboring crossborder links
877
        scn_name : str
878
            Name of the scenario
879
        extendable : bool
880
            Boolean expressing if the links should be extendable or not
881
882
        Returns
883
        -------
884
        None
885
886
        """
887
        neighbor_links["scn_name"] = scn
888
889
        dropped_carriers = [
890
            "Link",
891
            "geometry",
892
            "tags",
893
            "under_construction",
894
            "underground",
895
            "underwater_fraction",
896
            "bus2",
897
            "bus3",
898
            "bus4",
899
            "efficiency2",
900
            "efficiency3",
901
            "efficiency4",
902
            "lifetime",
903
            "pipe_retrofit",
904
            "committable",
905
            "start_up_cost",
906
            "shut_down_cost",
907
            "min_up_time",
908
            "min_down_time",
909
            "up_time_before",
910
            "down_time_before",
911
            "ramp_limit_up",
912
            "ramp_limit_down",
913
            "ramp_limit_start_up",
914
            "ramp_limit_shut_down",
915
            "length_original",
916
            "reversed",
917
        ]
918
919
        if extendable:
920
            dropped_carriers.append("p_nom_opt")
921
            neighbor_links = neighbor_links.drop(
922
                columns=dropped_carriers,
923
                errors="ignore",
924
            )
925
926
        else:
927
            dropped_carriers.append("p_nom")
928
            dropped_carriers.append("p_nom_extendable")
929
            neighbor_links = neighbor_links.drop(
930
                columns=dropped_carriers,
931
                errors="ignore",
932
            )
933
            neighbor_links = neighbor_links.rename(
934
                columns={"p_nom_opt": "p_nom"}
935
            )
936
            neighbor_links["p_nom_extendable"] = False
937
938
        if neighbor_links.empty:
939
            print("No links selected")
940
            return
941
942
        # Define geometry and add to lines dataframe as 'topo'
943
        gdf = gpd.GeoDataFrame(
944
            index=neighbor_links.index,
945
            data={
946
                "geom_bus0": neighbors.loc[neighbor_links.bus0, "geom"].values,
947
                "geom_bus1": neighbors.loc[neighbor_links.bus1, "geom"].values,
948
            },
949
        )
950
951
        gdf["geometry"] = gdf.apply(
952
            lambda x: LineString([x["geom_bus0"], x["geom_bus1"]]), axis=1
953
        )
954
955
        neighbor_links = (
956
            gpd.GeoDataFrame(neighbor_links, geometry=gdf["geometry"])
957
            .rename_geometry("topo")
958
            .set_crs(4326)
959
        )
960
961
        # Unify carrier names
962
        neighbor_links.carrier = neighbor_links.carrier.str.replace(" ", "_")
963
964
        neighbor_links.carrier.replace(
965
            {
966
                "H2_Electrolysis": "power_to_H2",
967
                "H2_Fuel_Cell": "H2_to_power",
968
                "H2_pipeline_retrofitted": "H2_retrofit",
969
                "SMR": "CH4_to_H2",
970
                "Sabatier": "H2_to_CH4",
971
                "gas_for_industry": "CH4_for_industry",
972
                "gas_pipeline": "CH4",
973
            },
974
            inplace=True,
975
        )
976
977
        for c in [
978
            "H2_to_CH4",
979
            "H2_to_power",
980
            "power_to_H2",
981
            "CH4_to_H2",
982
        ]:
983
            neighbor_links.loc[
984
                (neighbor_links.carrier == c),
985
                "lifetime",
986
            ] = get_sector_parameters("gas", "eGon100RE")["lifetime"][c]
987
988
        neighbor_links.to_postgis(
989
            "egon_etrago_link",
990
            engine,
991
            schema="grid",
992
            if_exists="append",
993
            index=True,
994
            index_label="link_id",
995
        )
996
997
    non_extendable_links_carriers = [
998
        "H2 pipeline retrofitted",
999
        "H2 pipeline",
1000
        "gas pipeline",
1001
        "biogas to gas",
1002
    ]
1003
1004
    # delete unwanted carriers for eTraGo
1005
    excluded_carriers = [
1006
        "gas for industry CC",
1007
        "SMR CC",
1008
        "biogas to gas",
1009
        "DAC",
1010
        "electricity distribution grid",
1011
    ]
1012
    neighbor_links = neighbor_links[
1013
        ~neighbor_links.carrier.isin(excluded_carriers)
1014
    ]
1015
1016
    links_to_etrago(
1017
        neighbor_links[
1018
            ~neighbor_links.carrier.isin(non_extendable_links_carriers)
1019
        ],
1020
        "eGon100RE",
1021
    )
1022
    links_to_etrago(
1023
        neighbor_links[
1024
            neighbor_links.carrier.isin(non_extendable_links_carriers)
1025
        ],
1026
        "eGon100RE",
1027
        extendable=False,
1028
    )
1029
1030
    # prepare neighboring generators for etrago tables
1031
    neighbor_gens["scn_name"] = "eGon100RE"
1032
    neighbor_gens["p_nom"] = neighbor_gens["p_nom_opt"]
1033
    neighbor_gens["p_nom_extendable"] = False
1034
1035
    # Unify carrier names
1036
    neighbor_gens.carrier = neighbor_gens.carrier.str.replace(" ", "_")
1037
1038
    neighbor_gens.carrier.replace(
1039
        {
1040
            "onwind": "wind_onshore",
1041
            "ror": "run_of_river",
1042
            "offwind-ac": "wind_offshore",
1043
            "offwind-dc": "wind_offshore",
1044
            "urban_central_solar_thermal": "urban_central_solar_thermal_collector",
1045
            "residential_rural_solar_thermal": "residential_rural_solar_thermal_collector",
1046
            "services_rural_solar_thermal": "services_rural_solar_thermal_collector",
1047
        },
1048
        inplace=True,
1049
    )
1050
1051
    for i in [
1052
        "Generator",
1053
        "weight",
1054
        "lifetime",
1055
        "p_set",
1056
        "q_set",
1057
        "p_nom_opt",
1058
    ]:
1059
        neighbor_gens = neighbor_gens.drop(i, axis=1)
1060
1061
    neighbor_gens.to_sql(
1062
        "egon_etrago_generator",
1063
        engine,
1064
        schema="grid",
1065
        if_exists="append",
1066
        index=True,
1067
        index_label="generator_id",
1068
    )
1069
1070
    # prepare neighboring loads for etrago tables
1071
    neighbor_loads["scn_name"] = "eGon100RE"
1072
1073
    # Unify carrier names
1074
    neighbor_loads.carrier = neighbor_loads.carrier.str.replace(" ", "_")
1075
1076
    neighbor_loads.carrier.replace(
1077
        {
1078
            "electricity": "AC",
1079
            "DC": "AC",
1080
            "industry_electricity": "AC",
1081
            "H2_pipeline_retrofitted": "H2_system_boundary",
1082
            "gas_pipeline": "CH4_system_boundary",
1083
            "gas_for_industry": "CH4_for_industry",
1084
        },
1085
        inplace=True,
1086
    )
1087
1088
    neighbor_loads = neighbor_loads.drop(
1089
        columns=["Load"],
1090
        errors="ignore",
1091
    )
1092
1093
    neighbor_loads.to_sql(
1094
        "egon_etrago_load",
1095
        engine,
1096
        schema="grid",
1097
        if_exists="append",
1098
        index=True,
1099
        index_label="load_id",
1100
    )
1101
1102
    # prepare neighboring stores for etrago tables
1103
    neighbor_stores["scn_name"] = "eGon100RE"
1104
1105
    # Unify carrier names
1106
    neighbor_stores.carrier = neighbor_stores.carrier.str.replace(" ", "_")
1107
1108
    neighbor_stores.carrier.replace(
1109
        {
1110
            "Li_ion": "battery",
1111
            "gas": "CH4",
1112
        },
1113
        inplace=True,
1114
    )
1115
    neighbor_stores.loc[
1116
        (
1117
            (neighbor_stores.e_nom_max <= 1e9)
1118
            & (neighbor_stores.carrier == "H2")
1119
        ),
1120
        "carrier",
1121
    ] = "H2_underground"
1122
    neighbor_stores.loc[
1123
        (
1124
            (neighbor_stores.e_nom_max > 1e9)
1125
            & (neighbor_stores.carrier == "H2")
1126
        ),
1127
        "carrier",
1128
    ] = "H2_overground"
1129
1130
    for i in [
1131
        "Store",
1132
        "p_set",
1133
        "q_set",
1134
        "e_nom_opt",
1135
        "lifetime",
1136
        "e_initial_per_period",
1137
        "e_cyclic_per_period",
1138
        "location",
1139
    ]:
1140
        neighbor_stores = neighbor_stores.drop(i, axis=1, errors="ignore")
1141
1142
    for c in ["H2_underground", "H2_overground"]:
1143
        neighbor_stores.loc[
1144
            (neighbor_stores.carrier == c),
1145
            "lifetime",
1146
        ] = get_sector_parameters("gas", "eGon100RE")["lifetime"][c]
1147
1148
    neighbor_stores.to_sql(
1149
        "egon_etrago_store",
1150
        engine,
1151
        schema="grid",
1152
        if_exists="append",
1153
        index=True,
1154
        index_label="store_id",
1155
    )
1156
1157
    # prepare neighboring storage_units for etrago tables
1158
    neighbor_storage["scn_name"] = "eGon100RE"
1159
1160
    # Unify carrier names
1161
    neighbor_storage.carrier = neighbor_storage.carrier.str.replace(" ", "_")
1162
1163
    neighbor_storage.carrier.replace(
1164
        {"PHS": "pumped_hydro", "hydro": "reservoir"}, inplace=True
1165
    )
1166
1167
    for i in [
1168
        "StorageUnit",
1169
        "p_nom_opt",
1170
        "state_of_charge_initial_per_period",
1171
        "cyclic_state_of_charge_per_period",
1172
    ]:
1173
        neighbor_storage = neighbor_storage.drop(i, axis=1, errors="ignore")
1174
1175
    neighbor_storage.to_sql(
1176
        "egon_etrago_storage",
1177
        engine,
1178
        schema="grid",
1179
        if_exists="append",
1180
        index=True,
1181
        index_label="storage_id",
1182
    )
1183
1184
    # writing neighboring loads_t p_sets to etrago tables
1185
1186
    neighbor_loads_t_etrago = pd.DataFrame(
1187
        columns=["scn_name", "temp_id", "p_set"],
1188
        index=neighbor_loads_t.columns,
1189
    )
1190
    neighbor_loads_t_etrago["scn_name"] = "eGon100RE"
1191
    neighbor_loads_t_etrago["temp_id"] = 1
1192
    for i in neighbor_loads_t.columns:
1193
        neighbor_loads_t_etrago["p_set"][i] = neighbor_loads_t[
1194
            i
1195
        ].values.tolist()
1196
1197
    neighbor_loads_t_etrago.to_sql(
1198
        "egon_etrago_load_timeseries",
1199
        engine,
1200
        schema="grid",
1201
        if_exists="append",
1202
        index=True,
1203
        index_label="load_id",
1204
    )
1205
1206
    # writing neighboring generator_t p_max_pu to etrago tables
1207
    neighbor_gens_t_etrago = pd.DataFrame(
1208
        columns=["scn_name", "temp_id", "p_max_pu"],
1209
        index=neighbor_gens_t.columns,
1210
    )
1211
    neighbor_gens_t_etrago["scn_name"] = "eGon100RE"
1212
    neighbor_gens_t_etrago["temp_id"] = 1
1213
    for i in neighbor_gens_t.columns:
1214
        neighbor_gens_t_etrago["p_max_pu"][i] = neighbor_gens_t[
1215
            i
1216
        ].values.tolist()
1217
1218
    neighbor_gens_t_etrago.to_sql(
1219
        "egon_etrago_generator_timeseries",
1220
        engine,
1221
        schema="grid",
1222
        if_exists="append",
1223
        index=True,
1224
        index_label="generator_id",
1225
    )
1226
1227
    # writing neighboring stores_t e_min_pu to etrago tables
1228
    neighbor_stores_t_etrago = pd.DataFrame(
1229
        columns=["scn_name", "temp_id", "e_min_pu"],
1230
        index=neighbor_stores_t.columns,
1231
    )
1232
    neighbor_stores_t_etrago["scn_name"] = "eGon100RE"
1233
    neighbor_stores_t_etrago["temp_id"] = 1
1234
    for i in neighbor_stores_t.columns:
1235
        neighbor_stores_t_etrago["e_min_pu"][i] = neighbor_stores_t[
1236
            i
1237
        ].values.tolist()
1238
1239
    neighbor_stores_t_etrago.to_sql(
1240
        "egon_etrago_store_timeseries",
1241
        engine,
1242
        schema="grid",
1243
        if_exists="append",
1244
        index=True,
1245
        index_label="store_id",
1246
    )
1247
1248
    # writing neighboring storage_units inflow to etrago tables
1249
    neighbor_storage_t_etrago = pd.DataFrame(
1250
        columns=["scn_name", "temp_id", "inflow"],
1251
        index=neighbor_storage_t.columns,
1252
    )
1253
    neighbor_storage_t_etrago["scn_name"] = "eGon100RE"
1254
    neighbor_storage_t_etrago["temp_id"] = 1
1255
    for i in neighbor_storage_t.columns:
1256
        neighbor_storage_t_etrago["inflow"][i] = neighbor_storage_t[
1257
            i
1258
        ].values.tolist()
1259
1260
    neighbor_storage_t_etrago.to_sql(
1261
        "egon_etrago_storage_timeseries",
1262
        engine,
1263
        schema="grid",
1264
        if_exists="append",
1265
        index=True,
1266
        index_label="storage_id",
1267
    )
1268
1269
    # writing neighboring lines_t s_max_pu to etrago tables
1270
    if not network.lines_t["s_max_pu"].empty:
1271
        neighbor_lines_t_etrago = pd.DataFrame(
1272
            columns=["scn_name", "s_max_pu"], index=neighbor_lines_t.columns
1273
        )
1274
        neighbor_lines_t_etrago["scn_name"] = "eGon100RE"
1275
1276
        for i in neighbor_lines_t.columns:
1277
            neighbor_lines_t_etrago["s_max_pu"][i] = neighbor_lines_t[
1278
                i
1279
            ].values.tolist()
1280
1281
        neighbor_lines_t_etrago.to_sql(
1282
            "egon_etrago_line_timeseries",
1283
            engine,
1284
            schema="grid",
1285
            if_exists="append",
1286
            index=True,
1287
            index_label="line_id",
1288
        )
1289
1290
1291 View Code Duplication
def prepared_network():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1292
    if egon.data.config.settings()["egon-data"]["--run-pypsa-eur"]:
1293
        with open(
1294
            __path__[0] + "/datasets/pypsaeur/config.yaml", "r"
1295
        ) as stream:
1296
            data_config = yaml.safe_load(stream)
1297
1298
        target_file = (
1299
            Path(".")
1300
            / "run-pypsa-eur"
1301
            / "pypsa-eur"
1302
            / "results"
1303
            / data_config["run"]["name"]
1304
            / "prenetworks"
1305
            / f"elec_s_{data_config['scenario']['clusters'][0]}"
1306
            f"_l{data_config['scenario']['ll'][0]}"
1307
            f"_{data_config['scenario']['opts'][0]}"
1308
            f"_{data_config['scenario']['sector_opts'][0]}"
1309
            f"_{data_config['scenario']['planning_horizons'][0]}.nc"
1310
        )
1311
1312
    else:
1313
        target_file = (
1314
            Path(".")
1315
            / "data_bundle_powerd_data"
1316
            / "pypsa_eur"
1317
            / "2024-08-02-egondata-integration"
1318
            / "results"
1319
            / "postnetworks"
1320
            / "elec_s_37_lv1.5__Co2L0-1H-T-H-B-I-A-solar+p3_2050.nc"
1321
        )
1322
1323
    return pypsa.Network(target_file.absolute().as_posix())
1324
1325
1326
def overwrite_H2_pipeline_share():
1327
    """Overwrite retrofitted_CH4pipeline-to-H2pipeline_share value
1328
1329
    Overwrite retrofitted_CH4pipeline-to-H2pipeline_share in the
1330
    scenario parameter table if p-e-s is run.
1331
    This function write in the database and has no return.
1332
1333
    """
1334
    scn_name = "eGon100RE"
1335
    # Select source and target from dataset configuration
1336
    target = egon.data.config.datasets()["pypsa-eur-sec"]["target"]
1337
1338
    n = read_network()
1339
1340
    H2_pipelines = n.links[n.links["carrier"] == "H2 pipeline retrofitted"]
1341
    CH4_pipelines = n.links[n.links["carrier"] == "gas pipeline"]
1342
    H2_pipes_share = np.mean(
1343
        [
1344
            (i / j)
1345
            for i, j in zip(
1346
                H2_pipelines.p_nom_opt.to_list(), CH4_pipelines.p_nom.to_list()
1347
            )
1348
        ]
1349
    )
1350
    logger.info(
1351
        "retrofitted_CH4pipeline-to-H2pipeline_share = " + str(H2_pipes_share)
1352
    )
1353
1354
    parameters = db.select_dataframe(
1355
        f"""
1356
        SELECT *
1357
        FROM {target['scenario_parameters']['schema']}.{target['scenario_parameters']['table']}
1358
        WHERE name = '{scn_name}'
1359
        """
1360
    )
1361
1362
    gas_param = parameters.loc[0, "gas_parameters"]
1363
    gas_param["retrofitted_CH4pipeline-to-H2pipeline_share"] = H2_pipes_share
1364
    gas_param = json.dumps(gas_param)
1365
1366
    # Update data in db
1367
    db.execute_sql(
1368
        f"""
1369
    UPDATE {target['scenario_parameters']['schema']}.{target['scenario_parameters']['table']}
1370
    SET gas_parameters = '{gas_param}'
1371
    WHERE name = '{scn_name}';
1372
    """
1373
    )
1374
1375
1376
def update_electrical_timeseries_germany(network):
1377
    """Replace electrical demand time series in Germany with data from egon-data
1378
1379
    Parameters
1380
    ----------
1381
    network : pypsa.Network
1382
        Network including demand time series from pypsa-eur
1383
1384
    Returns
1385
    -------
1386
    network : pypsa.Network
1387
        Network including electrical demand time series in Germany from egon-data
1388
1389
    """
1390
1391
    df = pd.read_csv(
1392
        "input-pypsa-eur-sec/electrical_demand_timeseries_DE_eGon100RE.csv"
1393
    )
1394
1395
    network.loads_t.p_set.loc[:, "DE1 0"] = (
1396
        df["residential_and_service"] + df["industry"]
1397
    ).values
1398
1399
    return network
1400
1401
1402
def geothermal_district_heating(network):
1403
    """Add the option to build geothermal power plants in district heating in Germany
1404
1405
    Parameters
1406
    ----------
1407
    network : pypsa.Network
1408
        Network from pypsa-eur without geothermal generators
1409
1410
    Returns
1411
    -------
1412
    network : pypsa.Network
1413
        Updated network with geothermal generators
1414
1415
    """
1416
1417
    costs_and_potentials = pd.read_csv(
1418
        "input-pypsa-eur-sec/geothermal_potential_germany.csv"
1419
    )
1420
1421
    network.add("Carrier", "urban central geo thermal")
1422
1423
    for i, row in costs_and_potentials.iterrows():
1424
        # Set lifetime of geothermal plant to 30 years based on:
1425
        # Ableitung eines Korridors für den Ausbau der erneuerbaren Wärme im Gebäudebereich,
1426
        # Beuth Hochschule für Technik, Berlin ifeu – Institut für Energie- und Umweltforschung Heidelberg GmbH
1427
        # Februar 2017
1428
        lifetime_geothermal = 30
1429
1430
        network.add(
1431
            "Generator",
1432
            f"DE1 0 urban central geo thermal {i}",
1433
            bus="DE1 0 urban central heat",
1434
            carrier="urban central geo thermal",
1435
            p_nom_extendable=True,
1436
            p_nom_max=row["potential [MW]"],
1437
            capital_cost=annualize_capital_costs(
1438
                row["cost [EUR/kW]"] * 1e6, lifetime_geothermal, 0.07
1439
            ),
1440
        )
1441
    return network
1442
1443
1444
def h2_overground_stores(network):
1445
    """Add hydrogen overground stores to each hydrogen node
1446
1447
    In pypsa-eur, only countries without the potential of underground hydrogen
1448
    stores have to option to build overground hydrogen tanks.
1449
    Overground stores are more expensive, but are not resitcted by the geological
1450
    potential. To allow higher hydrogen store capacities in each country, optional
1451
    hydogen overground tanks are also added to node with a potential for
1452
    underground stores.
1453
1454
    Parameters
1455
    ----------
1456
    network : pypsa.Network
1457
        Network without hydrogen overground stores at each hydrogen node
1458
1459
    Returns
1460
    -------
1461
    network : pypsa.Network
1462
        Network with hydrogen overground stores at each hydrogen node
1463
1464
    """
1465
1466
    underground_h2_stores = network.stores[
1467
        (network.stores.carrier == "H2 Store")
1468
        & (network.stores.e_nom_max != np.inf)
1469
    ]
1470
1471
    overground_h2_stores = network.stores[
1472
        (network.stores.carrier == "H2 Store")
1473
        & (network.stores.e_nom_max == np.inf)
1474
    ]
1475
1476
    network.madd(
1477
        "Store",
1478
        underground_h2_stores.bus + " overground Store",
1479
        bus=underground_h2_stores.bus.values,
1480
        e_nom_extendable=True,
1481
        e_cyclic=True,
1482
        carrier="H2 Store",
1483
        capital_cost=overground_h2_stores.capital_cost.mean(),
1484
    )
1485
1486
    return network
1487
1488
1489
def update_heat_timeseries_germany(network):
1490
    network.loads
1491
    # Import heat demand curves for Germany from eGon-data
1492
    df_egon_heat_demand = pd.read_csv(
1493
        "input-pypsa-eur-sec/heat_demand_timeseries_DE_eGon100RE.csv"
1494
    )
1495
1496
    # Replace heat demand curves in Germany with values from eGon-data
1497
    network.loads_t.p_set.loc[:, "DE1 0 rural heat"] = (
1498
        df_egon_heat_demand.loc[:, "residential rural"].values
1499
        + df_egon_heat_demand.loc[:, "service rural"].values
1500
    )
1501
1502
    network.loads_t.p_set.loc[:, "DE1 0 urban central heat"] = (
1503
        df_egon_heat_demand.loc[:, "urban central"].values
1504
    )
1505
1506
    return network
1507
1508
1509
def drop_biomass(network):
1510
    carrier = "biomass"
1511
1512
    for c in network.iterate_components():
1513
        network.mremove(c.name, c.df[c.df.index.str.contains(carrier)].index)
1514
    return network
1515
1516
1517
def drop_urban_decentral_heat(network):
1518
    carrier = "urban decentral"
1519
1520
    for c in network.iterate_components():
1521
        network.mremove(c.name, c.df[c.df.index.str.contains(carrier)].index)
1522
    return network
1523
1524
1525
def district_heating_shares(network):
1526
    df = pd.read_csv(
1527
        "data_bundle_powerd_data/district_heating_shares_egon.csv"
1528
    ).set_index("country_code")
1529
1530
    heat_demand_per_country = (
1531
        network.loads_t.p_set[
1532
            network.loads[
1533
                (network.loads.carrier.str.contains("heat"))
1534
                & network.loads.index.isin(network.loads_t.p_set.columns)
1535
            ].index
1536
        ]
1537
        .groupby(network.loads.bus.str[:5], axis=1)
1538
        .sum()
1539
    )
1540
1541
    for country in heat_demand_per_country.columns:
1542
        network.loads_t.p_set[f"{country} urban central heat"] = (
1543
            heat_demand_per_country.loc[:, country].mul(
1544
                df.loc[country[:2]].values[0]
1545
            )
1546
        )
1547
        network.loads_t.p_set[f"{country} rural heat"] = (
1548
            heat_demand_per_country.loc[:, country].mul(
1549
                (1 - df.loc[country[:2]].values[0])
1550
            )
1551
        )
1552
1553
    # Drop links with undefined buses or carrier
1554
    network.mremove(
1555
        "Link",
1556
        network.links[
1557
            ~network.links.bus0.isin(network.buses.index.values)
1558
        ].index,
1559
    )
1560
    network.mremove(
1561
        "Link",
1562
        network.links[
1563
            network.links.carrier==""
1564
        ].index,
1565
    )
1566
1567
    return network
1568
1569
1570
def drop_new_gas_pipelines(network):
1571
    network.mremove(
1572
        "Link",
1573
        network.links[
1574
            network.links.index.str.contains("gas pipeline new")
1575
        ].index,
1576
    )
1577
1578
    return network
1579
1580
1581
def drop_fossil_gas(network):
1582
    network.mremove(
1583
        "Generator",
1584
        network.generators[network.generators.carrier == "gas"].index
1585
    )
1586
1587
    return network
1588
1589
1590
def rual_heat_technologies(network):
1591
    network.mremove(
1592
        "Link",
1593
        network.links[
1594
            network.links.index.str.contains("rural gas boiler")
1595
        ].index,
1596
    )
1597
1598
    network.mremove(
1599
        "Generator",
1600
        network.generators[
1601
            network.generators.carrier.str.contains("rural solar thermal")
1602
        ].index,
1603
    )
1604
1605
    return network
1606
1607
1608
def execute():
1609
    if egon.data.config.settings()["egon-data"]["--run-pypsa-eur"]:
1610
        with open(
1611
            __path__[0] + "/datasets/pypsaeur/config.yaml", "r"
1612
        ) as stream:
1613
            data_config = yaml.safe_load(stream)
1614
1615
        network_path = (
1616
            Path(".")
1617
            / "run-pypsa-eur"
1618
            / "pypsa-eur"
1619
            / "results"
1620
            / data_config["run"]["name"]
1621
            / "prenetworks"
1622
            / f"elec_s_{data_config['scenario']['clusters'][0]}"
1623
            f"_l{data_config['scenario']['ll'][0]}"
1624
            f"_{data_config['scenario']['opts'][0]}"
1625
            f"_{data_config['scenario']['sector_opts'][0]}"
1626
            f"_{data_config['scenario']['planning_horizons'][0]}.nc"
1627
        )
1628
1629
        network = pypsa.Network(network_path)
1630
1631
        network = drop_biomass(network)
1632
1633
        network = drop_urban_decentral_heat(network)
1634
1635
        network = district_heating_shares(network)
1636
1637
        network = update_heat_timeseries_germany(network)
1638
1639
        network = update_electrical_timeseries_germany(network)
1640
1641
        network = geothermal_district_heating(network)
1642
1643
        network = h2_overground_stores(network)
1644
1645
        network = drop_new_gas_pipelines(network)
1646
1647
        network = drop_fossil_gas(network)
1648
1649
        network = rual_heat_technologies(network)
1650
1651
        network.export_to_netcdf(network_path)
1652
    else:
1653
        print("Pypsa-eur is not executed due to the settings of egon-data")
1654