data.datasets.osmtgmod.osmtgmod()   F
last analyzed

Complexity

Conditions 19

Size

Total Lines 337
Code Lines 167

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 167
dl 0
loc 337
rs 0.4199
c 0
b 0
f 0
cc 19
nop 5

How to fix   Long Method    Complexity   

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:

Complexity

Complex classes like data.datasets.osmtgmod.osmtgmod() 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
from pathlib import Path
2
import codecs
3
import configparser
4
import csv
5
import datetime
6
import logging
7
import os
8
import shutil
9
import subprocess
10
import sys
11
12
import psycopg2
13
14
from egon.data import db, logger
15
from egon.data.config import settings
16
from egon.data.datasets import Dataset
17
from egon.data.datasets.osmtgmod.substation import extract
18
from egon.data.datasets.scenario_parameters import get_sector_parameters
19
import egon.data.config
20
import egon.data.subprocess as subproc
21
22
23
def run():
24
    sys.setrecursionlimit(5000)
25
    # execute osmTGmod
26
27
    data_config = egon.data.config.datasets()
28
    osm_config = data_config["openstreetmap"]["original_data"]
29
30
    if settings()["egon-data"]["--dataset-boundary"] == "Everything":
31
        target_path = osm_config["target"]["file"]
32
    else:
33
        target_path = osm_config["target"]["file_testmode"]
34
35
    filtered_osm_pbf_path_to_file = os.path.join(
36
        egon.data.__path__[0], "datasets", "osm", target_path
37
    )
38
    docker_db_config = db.credentials()
39
40
    osmtgmod(
41
        config_database=docker_db_config["POSTGRES_DB"],
42
        config_basepath="osmTGmod/egon-data",
43
        config_continue_run=False,
44
        filtered_osm_pbf_path_to_file=filtered_osm_pbf_path_to_file,
45
        docker_db_config=docker_db_config,
46
    )
47
48
49
def import_osm_data():
50
51
    osmtgmod_repos = Path(".") / "osmTGmod"
52
53
    # Delete repository if it already exists
54
    if osmtgmod_repos.exists() and osmtgmod_repos.is_dir():
55
        try:
56
            status = subprocess.check_output(
57
                ["git", "status"], cwd=(osmtgmod_repos).absolute()
58
            )
59
            if status.startswith(
60
                b"Auf Branch features/egon"
61
            ) or status.startswith(b"On branch features/egon"):
62
                logger.info("OsmTGmod cloned and right branch checked out.")
63
64
            else:
65
                subproc.run(
66
                    [
67
                        "git",
68
                        "checkout",
69
                        "features/egon",
70
                    ]
71
                )
72
        except subprocess.CalledProcessError:
73
            shutil.rmtree(osmtgmod_repos)
74
            subproc.run(
75
                [
76
                    "git",
77
                    "clone",
78
                    "--single-branch",
79
                    "--branch",
80
                    "features/egon",
81
                    "https://github.com/openego/osmTGmod.git",
82
                ]
83
            )
84
    else:
85
86
        subproc.run(
87
            [
88
                "git",
89
                "clone",
90
                "--single-branch",
91
                "--branch",
92
                "features/egon",
93
                "https://github.com/openego/osmTGmod.git",
94
            ]
95
        )
96
97
    data_config = egon.data.config.datasets()
98
    osm_config = data_config["openstreetmap"]["original_data"]
99
100
    if settings()["egon-data"]["--dataset-boundary"] == "Everything":
101
        target_path = osm_config["target"]["file"]
102
    else:
103
        target_path = osm_config["target"]["file_testmode"]
104
105
    filtered_osm_pbf_path_to_file = Path(".") / "openstreetmap" / target_path
106
107
    docker_db_config = db.credentials()
108
    config_database = docker_db_config["POSTGRES_DB"]
109
    config_basepath = "osmTGmod/egon-data"
110
111
    config = configparser.ConfigParser()
112
    config.read(config_basepath + ".cfg")
113
    config["postgres_server"]["host"] = docker_db_config["HOST"]
114
    config["postgres_server"]["port"] = docker_db_config["PORT"]
115
    config["postgres_server"]["user"] = docker_db_config["POSTGRES_USER"]
116
    config["postgres_server"]["password"] = docker_db_config[
117
        "POSTGRES_PASSWORD"
118
    ]
119
120
    logging.info("Creating status table ...")
121
    db.execute_sql(
122
        """
123
        DROP TABLE IF EXISTS _db_status;
124
        CREATE TABLE _db_status (module TEXT, status BOOLEAN);
125
        INSERT INTO _db_status (module, status) VALUES ('grid_model', FALSE);
126
        """
127
    )
128
129
    logging.info("Status table created.")
130
131
    # egon-specific, in order to not fill up the results schema,
132
    # it is dropped before creation
133
    logging.info("Dropping osmtgmod_results schema if exists")
134
    db.execute_sql("DROP SCHEMA IF EXISTS osmtgmod_results CASCADE;")
135
136
    logging.info("Loading functions and result schema ...")
137
    scripts = [
138
        "sql-scripts/extensions.sql",
139
        "sql-scripts/functions.sql",
140
        "sql-scripts/admin_boundaries.sql",
141
        "sql-scripts/electrical_properties.sql",
142
        "sql-scripts/build_up_db.sql",
143
    ]
144
    for script in scripts:
145
        logging.info("Running script {0} ...".format(script))
146
        with codecs.open(
147
            os.path.join("osmTGmod", script), "r", "utf-8-sig"
148
        ) as fd:
149
            sqlfile = fd.read()
150
        db.execute_sql(sqlfile)
151
        logging.info("Done.")
152
153
    db.execute_sql(
154
        """UPDATE _db_status SET status = TRUE
155
            WHERE module = 'grid_model'; """
156
    )
157
158
    logging.info("osmTGmod-database successfully built up!")
159
160
    logging.info("Importing OSM-data to database.")
161
162
    logging.info("Using pdf file: {}".format(filtered_osm_pbf_path_to_file))
163
    logging.info(
164
        f"""Assuming osmosis is avaliable at
165
        {config['osm_data']['osmosis_path_to_binary']}"""
166
    )
167
168
    # create directory to store osmosis' temp files
169
    osmosis_temp_dir = Path("osmTGmod") / "osmosis_temp/"
170
    if not os.path.exists(osmosis_temp_dir):
171
        os.mkdir(osmosis_temp_dir)
172
173
    subproc.run(
174
        "JAVACMD_OPTIONS='%s' %s --read-pbf %s --write-pgsql \
175
                database=%s host=%s user=%s password=%s"
176
        % (
177
            f"-Djava.io.tmpdir={osmosis_temp_dir}",
178
            os.path.join(
179
                "osmTGmod", config["osm_data"]["osmosis_path_to_binary"]
180
            ),
181
            filtered_osm_pbf_path_to_file,
182
            config_database,
183
            config["postgres_server"]["host"]
184
            + ":"
185
            + config["postgres_server"]["port"],
186
            config["postgres_server"]["user"],
187
            config["postgres_server"]["password"],
188
        ),
189
        shell=True,
190
    )
191
    logging.info("Importing OSM-Data...")
192
193
    # After updating OSM-Data, power_tables (for editing)
194
    # have to be updated as well
195
    logging.info("Creating power-tables...")
196
    db.execute_sql("SELECT otg_create_power_tables ();")
197
198
    # Update OSM Metadata
199
    logging.info("Updating OSM metadata")
200
    v_date = datetime.datetime.now().strftime("%Y-%m-%d")
201
    db.execute_sql(f"UPDATE osm_metadata SET imported = '{v_date}'")
202
    logging.info("OSM data imported to database successfully.")
203
204
205
def osmtgmod(
206
    config_database="egon-data",
207
    config_basepath="osmTGmod/egon-data",
208
    config_continue_run=False,
209
    filtered_osm_pbf_path_to_file=None,
210
    docker_db_config=None,
211
):
212
213
    if ("germany-21" in filtered_osm_pbf_path_to_file) | (
214
        "germany-22" in filtered_osm_pbf_path_to_file
215
    ):
216
        """
217
        Manually add under construction substation expansion in Garenfeld
218
        to existing substation. (see:)
219
        """
220
        print("Manually updating geometry of substation in Garenfeld")
221
        db.execute_sql(
222
            """DROP TRIGGER IF EXISTS
223
            power_ways_update ON power_ways CASCADE """
224
        )
225
226
        db.execute_sql(
227
            """
228
            UPDATE power_ways
229
            SET way =  (SELECT ST_SetSRID(ST_AsText(
230
                '0102000000160000001612D5004A081E4020A8644A35B349407B0ACA'
231
                '7E27071E405F23EE563BB34940287CB60E0E061E4055A4C2D842B34940352FE29'
232
                '6EA051E4017940E7B46B34940C0D02346CF051E4042EBE1CB44B34940D67E219A'
233
                '2F051E40FECF06054AB349407F964A442F031E40C2F441F471B34940A8A544676'
234
                '1021E40AB9412CA8FB349409C4848881E021E40B7BA08C691B34940B22D4E1430'
235
                '001E40CE913856BDB34940E2810B122C001E40898CAEAFDBB349402CDAF043480'
236
                '11E40ED678C32F0B349402FE640E25C041E405A86F21AF1B3494061D525C46F04'
237
                '1E40ABEF60C892B34940DC2F9FAC18061E400D33D9E495B349401FD7868A71061'
238
                'E40D2D8A89894B3494083932353F4061E40077360DE88B34940624ED02687071E'
239
                '404F08782D7CB349405000C5C892091E403EFBDBAF4CB349403DDBFEF04E091E4'
240
                '0658D7A8846B349405AD5928E72081E405BE8EF4A37B349401612D5004A081E40'
241
                '20A8644A35B34940'), 4326))
242
            WHERE name = 'Garenfeld'
243
            AND id = 24667346
244
            """
245
        )
246
247
    # ==============================================================
248
    # Setup logging
249
    # ==============================================================
250
    # log = logging.getLogger()
251
    # log.setLevel(logging.INFO)
252
    # logformat = logging.Formatter(
253
    #     "%(asctime)s %(message)s", "%m/%d/%Y %H:%M:%S"
254
    # )
255
    # sh = logging.StreamHandler()
256
    # sh.setFormatter(logformat)
257
    # log.addHandler(sh)
258
    # logging.info("\n\n======================\nego_otg\n======================")
259
    # logging.info("Logging to standard output...")
260
    # # catch up some log messages from evaluation of command line arguments
261
    # logging.info("Database: {}".format(config_database))
262
    # logging.info(
263
    #     "Path for configuration file and results: {}".format(config_basepath)
264
    # )
265
    # ==============================================================
266
    # read configuration from file and create folder structure
267
    # ==============================================================
268
    logging.info(
269
        (
270
            "Taking db connection credentials from eGon-data "
271
            "with respect to the given docker_db_config variable"
272
        )
273
    )
274
    config = configparser.ConfigParser()
275
    config.read(config_basepath + ".cfg")
276
    config["postgres_server"]["host"] = docker_db_config["HOST"]
277
    config["postgres_server"]["port"] = docker_db_config["PORT"]
278
    config["postgres_server"]["user"] = docker_db_config["POSTGRES_USER"]
279
    config["postgres_server"]["password"] = docker_db_config[
280
        "POSTGRES_PASSWORD"
281
    ]
282
283
    # Setting osmTGmod folder structure:
284
    logging.info("Checking/Creating file directories")
285
    input_data_dir = os.path.join(config_basepath, "input_data")
286
    result_dir = os.path.join(config_basepath, "results")
287
    # Basic folders are created if not existent
288
    if not os.path.exists(input_data_dir):
289
        os.makedirs(input_data_dir)
290
    if not os.path.exists(result_dir):
291
        os.makedirs(result_dir)
292
    # start logging to file
293
    # logfile = os.path.join(config_basepath, config_database + ".log")
294
    # fh = logging.FileHandler(logfile)
295
    # fh.setFormatter(logformat)
296
    # log.addHandler(fh)
297
    # logging.info("Logging to file '{0}' is set up".format(logfile))
298
    # logging.info(
299
    #     "Now logging both to standard output and to file '{0}'...".format(
300
    #         logfile
301
    #     )
302
    # )
303
    logging.info("\n\n======================\nego_otg\n======================")
304
    # copy config file
305
    logging.info(
306
        "Copying configuration file to '{0}'.".format(
307
            os.path.join(config_basepath, config_database + ".cfg")
308
        )
309
    )
310
    os.system(
311
        "cp {0} {1}".format(
312
            config_basepath + ".cfg",
313
            os.path.join(config_basepath, config_database + ".cfg"),
314
        )
315
    )
316
317
    # Connects to new Database
318
    logging.info("Connecting to database {} ...".format(config_database))
319
    conn = psycopg2.connect(
320
        host=config["postgres_server"]["host"],
321
        port=config["postgres_server"]["port"],
322
        database=config_database,
323
        user=config["postgres_server"]["user"],
324
        password=config["postgres_server"]["password"],
325
    )
326
327
    cur = conn.cursor()
328
329
    min_voltage = 110000
330
331
    if not config_continue_run:
332
        logging.info("Setting min_voltage...")
333
        cur.execute(
334
            """
335
            UPDATE abstr_values
336
                SET val_int = %s
337
                WHERE val_description = 'min_voltage'""",
338
            (min_voltage,),
339
        )
340
        conn.commit()
341
342
        logging.info("Setting main_station...")
343
        cur.execute(
344
            """
345
            UPDATE abstr_values
346
                SET val_int = %s
347
                WHERE val_description = 'main_station'""",
348
            (config.getint("abstraction", "main_station"),),
349
        )
350
        conn.commit()
351
352
        logging.info("Setting graph_dfs...")
353
        cur.execute(
354
            """
355
            UPDATE abstr_values
356
                SET val_bool = %s
357
                WHERE val_description = 'graph_dfs'""",
358
            (config.getboolean("abstraction", "graph_dfs"),),
359
        )
360
        conn.commit()
361
362
        logging.info("Setting conn_subgraphs...")
363
        cur.execute(
364
            """
365
            UPDATE abstr_values
366
                SET val_bool = %s
367
                WHERE val_description = 'conn_subgraphs'""",
368
            (config.getboolean("abstraction", "conn_subgraphs"),),
369
        )
370
        conn.commit()
371
372
        logging.info("Setting transfer_busses...")
373
        cur.execute(
374
            """
375
            UPDATE abstr_values
376
                SET val_bool = %s
377
                WHERE val_description = 'transfer_busses'""",
378
            (config.getboolean("abstraction", "transfer_busses"),),
379
        )
380
        conn.commit()
381
382
        # setting transfer busses
383
        path_for_transfer_busses = input_data_dir + "/transfer_busses.csv"
384
        logging.info(
385
            "Reading transfer busses from file {} ...".format(
386
                path_for_transfer_busses
387
            )
388
        )
389
        logging.info("Deleting all entries from transfer_busses table ...")
390
        cur.execute(
391
            """
392
        DELETE FROM transfer_busses;
393
        """
394
        )
395
        conn.commit()
396
397
        with open(path_for_transfer_busses, "w") as this_file:
398
            cur.copy_expert(
399
                """COPY transfer_busses_complete to
400
                STDOUT WITH CSV HEADER""",
401
                this_file,
402
            )
403
            conn.commit()
404
405
        reader = csv.reader(open(path_for_transfer_busses, "r"))
406
        next(reader, None)  # Skips header
407
        logging.info("Copying transfer-busses from CSV to database...")
408
        for row in reader:
409
            osm_id = str(row[8])
410
            if osm_id[:1] == "w":
411
                object_type = "way"
412
            elif osm_id[:1] == "n":
413
                object_type = "node"
414
            else:
415
                object_type = None
416
            osm_id_int = int(osm_id[1:])
417
            center_geom = str(row[3])
418
            cur.execute(
419
                """
420
                INSERT INTO transfer_busses (osm_id, object_type,
421
                                             center_geom)
422
                VALUES (%s, %s, %s);
423
                """,
424
                (osm_id_int, object_type, center_geom),
425
            )
426
            conn.commit()
427
        logging.info("All transfer busses imported successfully")
428
429
    # Execute power_script
430
    logging.info(
431
        (
432
            "Preparing execution of abstraction script "
433
            "'sql-scripts/power_script.sql' ..."
434
        )
435
    )
436
    with codecs.open(
437
        "osmTGmod/sql-scripts/power_script.sql", "r", "utf-8-sig"
438
    ) as fd:
439
        sqlfile = fd.read()
440
    # remove lines starting with "--" (comments), tabulators and empty line
441
    # beware: comments in C-like style (such as /* comment */) arn't parsed!
442
    sqlfile_without_comments = "".join(
443
        [
444
            (
445
                line.lstrip().split("--")[0] + "\n"
446
                if not line.lstrip().split("--")[0] == ""
447
                else ""
448
            )
449
            for line in sqlfile.split("\n")
450
        ]
451
    )
452
453
    logging.info("Stating execution of  power script...")
454
    config_continue_run_at = -1
455
456
    if not config_continue_run:  # debugging - to be removed
457
        cur.execute(
458
            """drop table if exists debug;create table debug
459
            (step_before int,max_bus_id int, num_bus int,max_branch_id int,
460
            num_branch int, num_110_bus int, num_220_bus int,
461
            num_380_bus int)"""
462
        )
463
        conn.commit()
464
465
    # split sqlfile in commands seperated by ";", while not considering
466
    # symbols for splitting if "escaped" by single quoted strings.
467
    # Drop everything after last semicolon.
468
    for i, command in enumerate(
469
        "'".join(
470
            [
471
                segment.replace(";", "§") if i % 2 == 0 else segment
472
                for i, segment in enumerate(
473
                    sqlfile_without_comments.split("'")
474
                )
475
            ]
476
        ).split("§")[:-1]
477
    ):
478
479
        if i >= config_continue_run_at:
480
            logging.info(
481
                "Executing SQL statement {0}:{1}\n".format(i, command)
482
            )
483
            try:
484
                cur.execute(command)
485
                conn.commit()
486
            except:
487
                logging.exception(
488
                    (
489
                        "Exception raised with command {0}. "
490
                        "Check data and code "
491
                        "and restart with 'python ego_otg.py {1} {0}'."
492
                    ).format(i, config_database)
493
                )
494
                sys.exit()
495
            if i > 16:  # debugging - to be removed
496
                cur.execute(
497
                    """insert into debug values ({0},
498
                    (select max(id) from bus_data),(select count(*)
499
                    from bus_data),(select max(branch_id)
500
                    from branch_data),(select count(*)
501
                    from branch_data),(select count(*)
502
                    from bus_data where voltage = 110000),
503
                    (select count (*) from bus_data where voltage = 220000),
504
                    (select count (*)
505
                    from bus_data where voltage = 380000))""".format(
506
                        i
507
                    )
508
                )
509
                conn.commit()
510
511
    logging.info("Power-script executed successfully.")
512
513
    logging.info("Saving Results...")
514
    cur.execute("SELECT otg_save_results ();")
515
    conn.commit()
516
517
    logging.info("Abstraction process complete!")
518
519
    # ==============================================================
520
    # Write results
521
    # ==============================================================
522
    logging.info("Writing results")
523
524
    tables = ["bus_data", "branch_data", "dcline_data", "results_metadata"]
525
    for table in tables:
526
        logging.info("writing %s..." % table)
527
        filename = os.path.join(result_dir, table + ".csv")
528
        logging.info(
529
            "Writing contents of table {0} to {1}...".format(table, filename)
530
        )
531
        query = "SELECT * FROM osmtgmod_results.%s " % (table,)
532
        outputquery = "COPY ({0}) TO STDOUT WITH DELIMITER \
533
            ',' CSV HEADER".format(
534
            query
535
        )
536
        with open(filename, encoding="utf-8", mode="w") as fh:
537
            cur.copy_expert(outputquery, fh)
538
539
    logging.info("All tables written!")
540
541
    logging.info("EXECUTION FINISHED SUCCESSFULLY!")
542
543
544
def to_pypsa():
545
    db.execute_sql(
546
        """
547
            -- CLEAN UP OF TABLES
548
            DELETE FROM grid.egon_etrago_bus
549
            WHERE carrier = 'AC';
550
            DELETE FROM grid.egon_etrago_line;
551
            DELETE FROM grid.egon_etrago_transformer;
552
            """
553
    )
554
555
    # for scenario_name in ["'eGon2035'", "'eGon100RE'", "'status2019'"]:
556
    scenario_list = egon.data.config.settings()["egon-data"]["--scenarios"]
557
    scenario_list = [
558
        f"'{scn}'" if not scn[1] == "'" else scn for scn in scenario_list
559
    ]
560
    for scenario_name in scenario_list:
561
562
        # TODO maybe not needed anymore?
563
        capital_cost = get_sector_parameters(
564
            "electricity", scenario_name.replace("'", "")
565
        )["capital_cost"]
566
        lifetime = get_sector_parameters(
567
            "electricity", scenario_name.replace("'", "")
568
        )["lifetime"]
569
        db.execute_sql(
570
            f"""
571
            -- BUS DATA
572
            INSERT INTO grid.egon_etrago_bus (scn_name, bus_id, v_nom,
573
                                             geom, x, y, carrier, country)
574
            SELECT
575
              {scenario_name},
576
              bus_i AS bus_id,
577
              base_kv AS v_nom,
578
              geom,
579
              ST_X(geom) as x,
580
              ST_Y(geom) as y,
581
              'AC' as carrier,
582
              cntr_id
583
              FROM osmtgmod_results.bus_data
584
              WHERE result_id = 1;
585
586
587
            -- BRANCH DATA
588
            INSERT INTO grid.egon_etrago_line (scn_name, line_id, bus0,
589
                                              bus1, x, r, b, s_nom, s_nom_min, s_nom_extendable,
590
                                              cables, v_nom,
591
                                              geom, topo, carrier)
592
            SELECT
593
              {scenario_name},
594
              branch_id AS line_id,
595
              f_bus AS bus0,
596
              t_bus AS bus1,
597
              br_x AS x,
598
              br_r AS r,
599
              br_b as b,
600
              rate_a as s_nom,
601
              rate_a as s_nom_min,
602
              TRUE,
603
              cables,
604
              branch_voltage/1000 as v_nom,
605
              geom,
606
              topo,
607
              'AC' as carrier
608
              FROM osmtgmod_results.branch_data
609
              WHERE result_id = 1 and (link_type = 'line' or
610
                                       link_type = 'cable');
611
612
613
            -- TRANSFORMER DATA
614
            INSERT INTO grid.egon_etrago_transformer (scn_name,
615
                                                     trafo_id, bus0, bus1, x,
616
                                                     s_nom, s_nom_min, s_nom_extendable, tap_ratio,
617
                                                     phase_shift, geom, topo)
618
            SELECT
619
              {scenario_name},
620
              branch_id AS trafo_id,
621
              f_bus AS bus0,
622
              t_bus AS bus1,
623
              br_x/(100 * rate_a) AS x, --- change base from 100MVA (osmtgmod) to the its individual s_nom (pypsa)
624
              rate_a as s_nom,
625
              rate_a as s_nom_min,
626
              TRUE,
627
              tap AS tap_ratio,
628
              shift AS phase_shift,
629
              geom,
630
              topo
631
              FROM osmtgmod_results.branch_data
632
              WHERE result_id = 1 and link_type = 'transformer';
633
634
635
            -- per unit to absolute values
636
637
            UPDATE grid.egon_etrago_line a
638
            SET
639
                 r = r * (((SELECT v_nom
640
                            FROM grid.egon_etrago_bus b
641
                            WHERE bus_id=bus1
642
                            AND a.scn_name = b.scn_name
643
                            )*1000)^2 / (100 * 10^6)),
644
                 x = x * (((SELECT v_nom
645
                            FROM grid.egon_etrago_bus b
646
                            WHERE bus_id=bus1
647
                            AND a.scn_name = b.scn_name
648
                            )*1000)^2 / (100 * 10^6)),
649
                 b = b * (((SELECT v_nom
650
                            FROM grid.egon_etrago_bus b
651
                            WHERE bus_id=bus1
652
                            AND a.scn_name = b.scn_name
653
                            )*1000)^2 / (100 * 10^6))
654
            WHERE scn_name = {scenario_name};
655
656
            -- calculate line length (in km) from geoms
657
658
            UPDATE grid.egon_etrago_line a
659
            SET
660
                 length = result.length
661
                 FROM
662
                 (SELECT b.line_id, st_length(b.geom,false)/1000 as length
663
                  from grid.egon_etrago_line b)
664
                 as result
665
            WHERE a.line_id = result.line_id
666
            AND scn_name = {scenario_name};
667
668
            -- set capital costs for eHV-lines
669
            UPDATE grid.egon_etrago_line
670
            SET capital_cost = {capital_cost['ac_ehv_overhead_line']} * length
671
            WHERE v_nom > 110
672
            AND scn_name = {scenario_name};
673
674
            -- set capital costs for HV-lines
675
            UPDATE grid.egon_etrago_line
676
            SET capital_cost = {capital_cost['ac_hv_overhead_line']} * length
677
            WHERE v_nom = 110
678
            AND scn_name = {scenario_name};
679
680
            -- set capital costs for transformers
681
            UPDATE grid.egon_etrago_transformer a
682
            SET capital_cost = {capital_cost['transformer_380_220']}
683
            WHERE (a.bus0 IN (
684
                SELECT bus_id FROM grid.egon_etrago_bus
685
                WHERE v_nom = 380)
686
            AND a.bus1 IN (
687
                SELECT bus_id FROM grid.egon_etrago_bus
688
                WHERE v_nom = 220))
689
            OR (a.bus0 IN (
690
                SELECT bus_id FROM grid.egon_etrago_bus
691
                WHERE v_nom = 220)
692
            AND a.bus1 IN (
693
                SELECT bus_id FROM grid.egon_etrago_bus
694
                WHERE v_nom = 380))
695
            AND scn_name = {scenario_name};
696
697
            UPDATE grid.egon_etrago_transformer a
698
            SET capital_cost = {capital_cost['transformer_380_110']}
699
            WHERE (a.bus0 IN (
700
                SELECT bus_id FROM grid.egon_etrago_bus
701
                WHERE v_nom = 380)
702
            AND a.bus1 IN (
703
                SELECT bus_id FROM grid.egon_etrago_bus
704
                WHERE v_nom = 110))
705
            OR (a.bus0 IN (
706
                SELECT bus_id FROM grid.egon_etrago_bus
707
                WHERE v_nom = 110)
708
            AND a.bus1 IN (
709
                SELECT bus_id FROM grid.egon_etrago_bus
710
                WHERE v_nom = 380))
711
            AND scn_name = {scenario_name};
712
713
            UPDATE grid.egon_etrago_transformer a
714
            SET capital_cost = {capital_cost['transformer_220_110']}
715
            WHERE (a.bus0 IN (
716
                SELECT bus_id FROM grid.egon_etrago_bus
717
                WHERE v_nom = 220)
718
            AND a.bus1 IN (
719
                SELECT bus_id FROM grid.egon_etrago_bus
720
                WHERE v_nom = 110))
721
            OR (a.bus0 IN (
722
                SELECT bus_id FROM grid.egon_etrago_bus
723
                WHERE v_nom = 110)
724
            AND a.bus1 IN (
725
                SELECT bus_id FROM grid.egon_etrago_bus
726
                WHERE v_nom = 220))
727
            AND scn_name = {scenario_name};
728
729
            -- set lifetime for eHV-lines
730
            UPDATE grid.egon_etrago_line
731
            SET lifetime = {lifetime['ac_ehv_overhead_line']}
732
            WHERE v_nom > 110
733
            AND scn_name = {scenario_name};
734
735
            -- set capital costs for HV-lines
736
            UPDATE grid.egon_etrago_line
737
            SET lifetime = {lifetime['ac_hv_overhead_line']}
738
            WHERE v_nom = 110
739
            AND scn_name = {scenario_name};
740
741
            -- set capital costs for transformers
742
            UPDATE grid.egon_etrago_transformer a
743
            SET lifetime = {lifetime['transformer_380_220']}
744
            WHERE (a.bus0 IN (
745
                SELECT bus_id FROM grid.egon_etrago_bus
746
                WHERE v_nom = 380)
747
            AND a.bus1 IN (
748
                SELECT bus_id FROM grid.egon_etrago_bus
749
                WHERE v_nom = 220))
750
            OR (a.bus0 IN (
751
                SELECT bus_id FROM grid.egon_etrago_bus
752
                WHERE v_nom = 220)
753
            AND a.bus1 IN (
754
                SELECT bus_id FROM grid.egon_etrago_bus
755
                WHERE v_nom = 380))
756
            AND scn_name = {scenario_name};
757
758
            UPDATE grid.egon_etrago_transformer a
759
            SET lifetime = {lifetime['transformer_380_110']}
760
            WHERE (a.bus0 IN (
761
                SELECT bus_id FROM grid.egon_etrago_bus
762
                WHERE v_nom = 380)
763
            AND a.bus1 IN (
764
                SELECT bus_id FROM grid.egon_etrago_bus
765
                WHERE v_nom = 110))
766
            OR (a.bus0 IN (
767
                SELECT bus_id FROM grid.egon_etrago_bus
768
                WHERE v_nom = 110)
769
            AND a.bus1 IN (
770
                SELECT bus_id FROM grid.egon_etrago_bus
771
                WHERE v_nom = 380))
772
            AND scn_name = {scenario_name};
773
774
            UPDATE grid.egon_etrago_transformer a
775
            SET lifetime = {lifetime['transformer_220_110']}
776
            WHERE (a.bus0 IN (
777
                SELECT bus_id FROM grid.egon_etrago_bus
778
                WHERE v_nom = 220)
779
            AND a.bus1 IN (
780
                SELECT bus_id FROM grid.egon_etrago_bus
781
                WHERE v_nom = 110))
782
            OR (a.bus0 IN (
783
                SELECT bus_id FROM grid.egon_etrago_bus
784
                WHERE v_nom = 110)
785
            AND a.bus1 IN (
786
                SELECT bus_id FROM grid.egon_etrago_bus
787
                WHERE v_nom = 220))
788
            AND scn_name = {scenario_name};
789
790
            -- delete buses without connection to AC grid and generation or
791
            -- load assigned
792
793
            DELETE FROM grid.egon_etrago_bus
794
            WHERE scn_name={scenario_name}
795
            AND carrier = 'AC'
796
            AND bus_id NOT IN
797
            (SELECT bus0 FROM grid.egon_etrago_line WHERE
798
             scn_name={scenario_name})
799
            AND bus_id NOT IN
800
            (SELECT bus1 FROM grid.egon_etrago_line WHERE
801
             scn_name={scenario_name})
802
            AND bus_id NOT IN
803
            (SELECT bus0 FROM grid.egon_etrago_transformer
804
             WHERE scn_name={scenario_name})
805
            AND bus_id NOT IN
806
            (SELECT bus1 FROM grid.egon_etrago_transformer
807
             WHERE scn_name={scenario_name});
808
                """
809
        )
810
811
812
def fix_transformer_snom():
813
    db.execute_sql(
814
        """
815
        UPDATE grid.egon_etrago_transformer AS t
816
        SET s_nom = CAST(
817
            LEAST(
818
                (SELECT SUM(COALESCE(l.s_nom,0))
819
                 FROM grid.egon_etrago_line AS l
820
                 WHERE (l.bus0 = t.bus0 OR l.bus1 = t.bus0)
821
                 AND l.scn_name = t.scn_name),
822
                (SELECT SUM(COALESCE(l.s_nom,0))
823
                 FROM grid.egon_etrago_line AS l
824
                 WHERE (l.bus0 = t.bus1 OR l.bus1 = t.bus1)
825
                 AND l.scn_name = t.scn_name)
826
            ) AS smallint
827
        );
828
        """)
829
830
831
class Osmtgmod(Dataset):
832
    """
833
    Run the tool osmtgmod to generate transmission grid topology
834
835
    Executes the tool osmtgmod which create a electricity grid topology based
836
    on OSM data for the voltage levels 110 - 380 kV. For further information
837
    on osmtgmod please refer our `osmtgmod fork. <https://github.com/openego/osmTGmod>`_
838
    Standard electrical line parameters are added to the grid topology and
839
    resulting data on buses, lines and transformers are exported to the data
840
    base.
841
842
    *Dependencies*
843
      * :py:class:`ScenarioParameters <egon.data.datasets.scenario_parameters.ScenarioParameters>`
844
      * :py:class:`EtragoSetup <egon.data.datasets.etrago_setup.EtragoSetup>`
845
      * :py:class:`SubstationExtraction <egon.data.datasets.substation.SubstationExtraction>`
846
      * :py:class:`OpenStreetMap <egon.data.datasets.osm.OpenStreetMap>`
847
848
    *Resulting tables*
849
      * :py:class:`grid.egon_etrago_bus <egon.data.datasets.etrago_setup.EgonPfHvBus>` is extended
850
      * :py:class:`grid.egon_etrago_line <egon.data.datasets.etrago_setup.EgonPfHvLine>` is extended
851
      * :py:class:`grid.egon_etrago_transformer <egon.data.datasets.etrago_setup.EgonPfHvTransformer>` is extended
852
853
    """
854
855
    #:
856
    name: str = "Osmtgmod"
857
    #:
858
    version: str = "0.0.7"
859
860
    def __init__(self, dependencies):
861
        super().__init__(
862
            name=self.name,
863
            version=self.version,
864
            dependencies=dependencies,
865
            tasks=(
866
                import_osm_data,
867
                run,
868
                {
869
                    extract,
870
                    to_pypsa,
871
                },
872
                fix_transformer_snom,
873
            ),
874
        )
875