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

data.datasets.power_plants   F

Complexity

Total Complexity 64

Size/Duplication

Total Lines 1412
Duplicated Lines 5.59 %

Importance

Changes 0
Metric Value
wmc 64
eloc 749
dl 79
loc 1412
rs 3.1309
c 0
b 0
f 0

15 Functions

Rating   Name   Duplication   Size   Complexity  
A select_target() 0 34 1
A filter_mastr_geometry() 0 55 3
B insert_biomass_plants() 0 72 5
A scale_prox2now() 0 32 3
A create_tables() 0 34 2
B allocate_other_power_plants() 0 167 4
B assign_bus_id() 66 66 5
A insert_hydro_biomass() 0 27 4
C insert_hydro_plants() 0 102 8
B assign_voltage_level() 0 88 4
B get_conventional_power_plants_non_chp() 0 125 2
A discard_not_available_generators() 0 22 1
B assign_voltage_level_by_capacity() 0 20 7
C allocate_conventional_non_chp_power_plants() 0 163 5
D power_plants_status_quo() 0 221 9

1 Method

Rating   Name   Duplication   Size   Complexity  
A PowerPlants.__init__() 0 6 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.power_plants 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 power plant data.
2
"""
3
4
from pathlib import Path
5
6
from geoalchemy2 import Geometry
7
from shapely.geometry import Point
8
from sqlalchemy import BigInteger, Column, Float, Integer, Sequence, String
9
from sqlalchemy.dialects.postgresql import JSONB
10
from sqlalchemy.ext.declarative import declarative_base
11
from sqlalchemy.orm import sessionmaker
12
import geopandas as gpd
13
import numpy as np
14
import pandas as pd
15
16
from egon.data import db, logger
17
from egon.data.datasets import Dataset, wrapped_partial
18
from egon.data.datasets.mastr import (
19
    WORKING_DIR_MASTR_NEW,
20
    WORKING_DIR_MASTR_OLD,
21
)
22
from egon.data.datasets.power_plants.conventional import (
23
    match_nep_no_chp,
24
    select_nep_power_plants,
25
    select_no_chp_combustion_mastr,
26
)
27
from egon.data.datasets.power_plants.mastr import (
28
    EgonPowerPlantsBiomass,
29
    EgonPowerPlantsHydro,
30
    EgonPowerPlantsPv,
31
    EgonPowerPlantsWind,
32
    import_mastr,
33
)
34
from egon.data.datasets.power_plants.pv_rooftop import pv_rooftop_per_mv_grid
35
from egon.data.datasets.power_plants.pv_rooftop_buildings import (
36
    pv_rooftop_to_buildings,
37
)
38
import egon.data.config
39
import egon.data.datasets.power_plants.assign_weather_data as assign_weather_data  # noqa: E501
40
import egon.data.datasets.power_plants.metadata as pp_metadata
41
import egon.data.datasets.power_plants.pv_ground_mounted as pv_ground_mounted
42
import egon.data.datasets.power_plants.wind_farms as wind_onshore
43
import egon.data.datasets.power_plants.wind_offshore as wind_offshore
44
45
Base = declarative_base()
46
47
48 View Code Duplication
class EgonPowerPlants(Base):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
49
    __tablename__ = "egon_power_plants"
50
    __table_args__ = {"schema": "supply"}
51
    id = Column(BigInteger, Sequence("pp_seq"), primary_key=True)
52
    sources = Column(JSONB)
53
    source_id = Column(JSONB)
54
    carrier = Column(String)
55
    el_capacity = Column(Float)
56
    bus_id = Column(Integer)
57
    voltage_level = Column(Integer)
58
    weather_cell_id = Column(Integer)
59
    scenario = Column(String)
60
    geom = Column(Geometry("POINT", 4326), index=True)
61
62
63
def create_tables():
64
    """Create tables for power plant data
65
    Returns
66
    -------
67
    None.
68
    """
69
70
    # Tables for future scenarios
71
    cfg = egon.data.config.datasets()["power_plants"]
72
    db.execute_sql(f"CREATE SCHEMA IF NOT EXISTS {cfg['target']['schema']};")
73
    engine = db.engine()
74
    db.execute_sql(
75
        f"""DROP TABLE IF EXISTS
76
        {cfg['target']['schema']}.{cfg['target']['table']}"""
77
    )
78
79
    db.execute_sql("""DROP SEQUENCE IF EXISTS pp_seq""")
80
    EgonPowerPlants.__table__.create(bind=engine, checkfirst=True)
81
82
    # Tables for status quo
83
    tables = [
84
        EgonPowerPlantsWind,
85
        EgonPowerPlantsPv,
86
        EgonPowerPlantsBiomass,
87
        EgonPowerPlantsHydro,
88
    ]
89
    for t in tables:
90
        db.execute_sql(
91
            f"""
92
            DROP TABLE IF EXISTS {t.__table_args__['schema']}.
93
            {t.__tablename__} CASCADE;
94
            """
95
        )
96
        t.__table__.create(bind=engine, checkfirst=True)
97
98
99
def scale_prox2now(df, target, level="federal_state"):
100
    """Scale installed capacities linear to status quo power plants
101
102
    Parameters
103
    ----------
104
    df : pandas.DataFrame
105
        Status Quo power plants
106
    target : pandas.Series
107
        Target values for future scenario
108
    level : str, optional
109
        Scale per 'federal_state' or 'country'. The default is 'federal_state'.
110
111
    Returns
112
    -------
113
    df : pandas.DataFrame
114
        Future power plants
115
116
    """
117
    if level == "federal_state":
118
        df.loc[:, "Nettonennleistung"] = (
119
            df.groupby(df.Bundesland)
120
            .Nettonennleistung.apply(lambda grp: grp / grp.sum())
121
            .mul(target[df.Bundesland.values].values)
122
        )
123
    else:
124
        df.loc[:, "Nettonennleistung"] = df.Nettonennleistung * (
125
            target / df.Nettonennleistung.sum()
126
        )
127
128
    df = df[df.Nettonennleistung > 0]
129
130
    return df
131
132
133
def select_target(carrier, scenario):
134
    """Select installed capacity per scenario and carrier
135
136
    Parameters
137
    ----------
138
    carrier : str
139
        Name of energy carrier
140
    scenario : str
141
        Name of scenario
142
143
    Returns
144
    -------
145
    pandas.Series
146
        Target values for carrier and scenario
147
148
    """
149
    cfg = egon.data.config.datasets()["power_plants"]
150
151
    return (
152
        pd.read_sql(
153
            f"""SELECT DISTINCT ON (b.gen)
154
                         REPLACE(REPLACE(b.gen, '-', ''), 'ü', 'ue') as state,
155
                         a.capacity
156
                         FROM {cfg['sources']['capacities']} a,
157
                         {cfg['sources']['geom_federal_states']} b
158
                         WHERE a.nuts = b.nuts
159
                         AND scenario_name = '{scenario}'
160
                         AND carrier = '{carrier}'
161
                         AND b.gen NOT IN ('Baden-Württemberg (Bodensee)',
162
                                           'Bayern (Bodensee)')""",
163
            con=db.engine(),
164
        )
165
        .set_index("state")
166
        .capacity
167
    )
168
169
170
def filter_mastr_geometry(mastr, federal_state=None):
171
    """Filter data from MaStR by geometry
172
173
    Parameters
174
    ----------
175
    mastr : pandas.DataFrame
176
        All power plants listed in MaStR
177
    federal_state : str or None
178
        Name of federal state whoes power plants are returned.
179
        If None, data for Germany is returned
180
181
    Returns
182
    -------
183
    mastr_loc : pandas.DataFrame
184
        Power plants listed in MaStR with geometry inside German boundaries
185
186
    """
187
    cfg = egon.data.config.datasets()["power_plants"]
188
189
    if type(mastr) == pd.core.frame.DataFrame:
190
        # Drop entries without geometry for insert
191
        mastr_loc = mastr[
192
            mastr.Laengengrad.notnull() & mastr.Breitengrad.notnull()
193
        ]
194
195
        # Create geodataframe
196
        mastr_loc = gpd.GeoDataFrame(
197
            mastr_loc,
198
            geometry=gpd.points_from_xy(
199
                mastr_loc.Laengengrad, mastr_loc.Breitengrad, crs=4326
200
            ),
201
        )
202
    else:
203
        mastr_loc = mastr.copy()
204
205
    # Drop entries outside of germany or federal state
206
    if not federal_state:
207
        sql = f"SELECT geometry as geom FROM {cfg['sources']['geom_germany']}"
208
    else:
209
        sql = f"""
210
        SELECT geometry as geom
211
        FROM boundaries.vg250_lan_union
212
        WHERE REPLACE(REPLACE(gen, '-', ''), 'ü', 'ue') = '{federal_state}'"""
213
214
    mastr_loc = (
215
        gpd.sjoin(
216
            gpd.read_postgis(sql, con=db.engine()).to_crs(4326),
217
            mastr_loc,
218
            how="right",
219
        )
220
        .query("index_left==0")
221
        .drop("index_left", axis=1)
222
    )
223
224
    return mastr_loc
225
226
227
def insert_biomass_plants(scenario):
228
    """Insert biomass power plants of future scenario
229
230
    Parameters
231
    ----------
232
    scenario : str
233
        Name of scenario.
234
235
    Returns
236
    -------
237
    None.
238
239
    """
240
    cfg = egon.data.config.datasets()["power_plants"]
241
242
    # import target values
243
    target = select_target("biomass", scenario)
244
245
    # import data for MaStR
246
    mastr = pd.read_csv(
247
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_biomass"]
248
    ).query("EinheitBetriebsstatus=='InBetrieb'")
249
250
    # Drop entries without federal state or 'AusschließlichWirtschaftszone'
251
    mastr = mastr[
252
        mastr.Bundesland.isin(
253
            pd.read_sql(
254
                f"""SELECT DISTINCT ON (gen)
255
        REPLACE(REPLACE(gen, '-', ''), 'ü', 'ue') as states
256
        FROM {cfg['sources']['geom_federal_states']}""",
257
                con=db.engine(),
258
            ).states.values
259
        )
260
    ]
261
262
    # Scaling will be done per federal state in case of eGon2035 scenario.
263
    if scenario == "eGon2035":
264
        level = "federal_state"
265
    else:
266
        level = "country"
267
268
    # Choose only entries with valid geometries inside DE/test mode
269
    mastr_loc = filter_mastr_geometry(mastr).set_geometry("geometry")
270
271
    # Scale capacities to meet target values
272
    mastr_loc = scale_prox2now(mastr_loc, target, level=level)
273
274
    # Assign bus_id
275
    if len(mastr_loc) > 0:
276
        mastr_loc["voltage_level"] = assign_voltage_level(
277
            mastr_loc, cfg, WORKING_DIR_MASTR_OLD
278
        )
279
        mastr_loc = assign_bus_id(mastr_loc, cfg)
280
281
    # Insert entries with location
282
    session = sessionmaker(bind=db.engine())()
283
284
    for i, row in mastr_loc.iterrows():
285
        if not row.ThermischeNutzleistung > 0:
286
            entry = EgonPowerPlants(
287
                sources={"el_capacity": "MaStR scaled with NEP 2021"},
288
                source_id={"MastrNummer": row.EinheitMastrNummer},
289
                carrier="biomass",
290
                el_capacity=row.Nettonennleistung,
291
                scenario=scenario,
292
                bus_id=row.bus_id,
293
                voltage_level=row.voltage_level,
294
                geom=f"SRID=4326;POINT({row.Laengengrad} {row.Breitengrad})",
295
            )
296
            session.add(entry)
297
298
    session.commit()
299
300
301
def insert_hydro_plants(scenario):
302
    """Insert hydro power plants of future scenario.
303
304
    Hydro power plants are diveded into run_of_river and reservoir plants
305
    according to Marktstammdatenregister.
306
    Additional hydro technologies (e.g. turbines inside drinking water
307
    systems) are not considered.
308
309
    Parameters
310
    ----------
311
    scenario : str
312
        Name of scenario.
313
314
    Returns
315
    -------
316
    None.
317
318
    """
319
    cfg = egon.data.config.datasets()["power_plants"]
320
321
    # Map MaStR carriers to eGon carriers
322
    map_carrier = {
323
        "run_of_river": ["Laufwasseranlage"],
324
        "reservoir": ["Speicherwasseranlage"],
325
    }
326
327
    for carrier in map_carrier.keys():
328
        # import target values
329
        if scenario == "eGon100RE":
330
            try:
331
                target = pd.read_sql(
332
                    f"""SELECT capacity FROM supply.egon_scenario_capacities
333
                            WHERE scenario_name = '{scenario}'
334
                            AND carrier = '{carrier}'
335
                            """,
336
                    con=db.engine(),
337
                ).capacity[0]
338
            except:
339
                logger.info(
340
                    f"No assigned capacity for {carrier} in {scenario}"
341
                )
342
                continue
343
344
        elif scenario == "eGon2035":
345
            target = select_target(carrier, scenario)
346
347
        # import data for MaStR
348
        mastr = pd.read_csv(
349
            WORKING_DIR_MASTR_NEW / cfg["sources"]["mastr_hydro"]
350
        ).query("EinheitBetriebsstatus=='InBetrieb'")
351
352
        # Choose only plants with specific carriers
353
        mastr = mastr[mastr.ArtDerWasserkraftanlage.isin(map_carrier[carrier])]
354
355
        # Drop entries without federal state or 'AusschließlichWirtschaftszone'
356
        mastr = mastr[
357
            mastr.Bundesland.isin(
358
                pd.read_sql(
359
                    f"""SELECT DISTINCT ON (gen)
360
            REPLACE(REPLACE(gen, '-', ''), 'ü', 'ue') as states
361
            FROM {cfg['sources']['geom_federal_states']}""",
362
                    con=db.engine(),
363
                ).states.values
364
            )
365
        ]
366
367
        # Scaling will be done per federal state in case of eGon2035 scenario.
368
        if scenario == "eGon2035":
369
            level = "federal_state"
370
        else:
371
            level = "country"
372
373
        # Scale capacities to meet target values
374
        mastr = scale_prox2now(mastr, target, level=level)
0 ignored issues
show
introduced by
The variable target does not seem to be defined in case the for loop on line 327 is not entered. Are you sure this can never be the case?
Loading history...
375
376
        # Choose only entries with valid geometries inside DE/test mode
377
        mastr_loc = filter_mastr_geometry(mastr).set_geometry("geometry")
378
        # TODO: Deal with power plants without geometry
379
380
        # Assign bus_id and voltage level
381
        if len(mastr_loc) > 0:
382
            mastr_loc["voltage_level"] = assign_voltage_level(
383
                mastr_loc, cfg, WORKING_DIR_MASTR_NEW
384
            )
385
            mastr_loc = assign_bus_id(mastr_loc, cfg)
386
387
        # Insert entries with location
388
        session = sessionmaker(bind=db.engine())()
389
        for i, row in mastr_loc.iterrows():
390
            entry = EgonPowerPlants(
391
                sources={"el_capacity": "MaStR scaled with NEP 2021"},
392
                source_id={"MastrNummer": row.EinheitMastrNummer},
393
                carrier=carrier,
394
                el_capacity=row.Nettonennleistung,
395
                scenario=scenario,
396
                bus_id=row.bus_id,
397
                voltage_level=row.voltage_level,
398
                geom=f"SRID=4326;POINT({row.Laengengrad} {row.Breitengrad})",
399
            )
400
            session.add(entry)
401
402
        session.commit()
403
404
405
def assign_voltage_level(mastr_loc, cfg, mastr_working_dir):
406
    """Assigns voltage level to power plants.
407
408
    If location data inluding voltage level is available from
409
    Marktstammdatenregister, this is used. Otherwise the voltage level is
410
    assigned according to the electrical capacity.
411
412
    Parameters
413
    ----------
414
    mastr_loc : pandas.DataFrame
415
        Power plants listed in MaStR with geometry inside German boundaries
416
417
    Returns
418
    -------
419
    pandas.DataFrame
420
        Power plants including voltage_level
421
422
    """
423
    mastr_loc["Spannungsebene"] = np.nan
424
    mastr_loc["voltage_level"] = np.nan
425
426
    if "LokationMastrNummer" in mastr_loc.columns:
427
        # Adjust column names to format of MaStR location dataset
428
        if mastr_working_dir == WORKING_DIR_MASTR_OLD:
429
            cols = ["LokationMastrNummer", "Spannungsebene"]
430
        elif mastr_working_dir == WORKING_DIR_MASTR_NEW:
431
            cols = ["MaStRNummer", "Spannungsebene"]
432
        else:
433
            raise ValueError("Invalid MaStR working directory!")
434
435
        location = (
436
            pd.read_csv(
437
                mastr_working_dir / cfg["sources"]["mastr_location"],
438
                usecols=cols,
439
            )
440
            .rename(columns={"MaStRNummer": "LokationMastrNummer"})
441
            .set_index("LokationMastrNummer")
442
        )
443
444
        location = location[~location.index.duplicated(keep="first")]
445
446
        mastr_loc.loc[
447
            mastr_loc[
448
                mastr_loc.LokationMastrNummer.isin(location.index)
449
            ].index,
450
            "Spannungsebene",
451
        ] = location.Spannungsebene[
452
            mastr_loc[
453
                mastr_loc.LokationMastrNummer.isin(location.index)
454
            ].LokationMastrNummer
455
        ].values
456
457
        # Transfer voltage_level as integer from Spanungsebene
458
        map_voltage_levels = pd.Series(
459
            data={
460
                "Höchstspannung": 1,
461
                "Hoechstspannung": 1,
462
                "UmspannungZurHochspannung": 2,
463
                "Hochspannung": 3,
464
                "UmspannungZurMittelspannung": 4,
465
                "Mittelspannung": 5,
466
                "UmspannungZurNiederspannung": 6,
467
                "Niederspannung": 7,
468
            }
469
        )
470
471
        mastr_loc.loc[
472
            mastr_loc[mastr_loc["Spannungsebene"].notnull()].index,
473
            "voltage_level",
474
        ] = map_voltage_levels[
475
            mastr_loc.loc[
476
                mastr_loc[mastr_loc["Spannungsebene"].notnull()].index,
477
                "Spannungsebene",
478
            ].values
479
        ].values
480
481
    else:
482
        print(
483
            "No information about MaStR location available. "
484
            "All voltage levels are assigned using threshold values."
485
        )
486
487
    # If no voltage level is available from mastr, choose level according
488
    # to threshold values
489
490
    mastr_loc.voltage_level = assign_voltage_level_by_capacity(mastr_loc)
491
492
    return mastr_loc.voltage_level
493
494
495
def assign_voltage_level_by_capacity(mastr_loc):
496
    for i, row in mastr_loc[mastr_loc.voltage_level.isnull()].iterrows():
497
        if row.Nettonennleistung > 120:
498
            level = 1
499
        elif row.Nettonennleistung > 20:
500
            level = 3
501
        elif row.Nettonennleistung > 5.5:
502
            level = 4
503
        elif row.Nettonennleistung > 0.2:
504
            level = 5
505
        elif row.Nettonennleistung > 0.1:
506
            level = 6
507
        else:
508
            level = 7
509
510
        mastr_loc.loc[i, "voltage_level"] = level
511
512
    mastr_loc.voltage_level = mastr_loc.voltage_level.astype(int)
513
514
    return mastr_loc.voltage_level
515
516
517 View Code Duplication
def assign_bus_id(power_plants, cfg, drop_missing=False):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
518
    """Assigns bus_ids to power plants according to location and voltage level
519
520
    Parameters
521
    ----------
522
    power_plants : pandas.DataFrame
523
        Power plants including voltage level
524
525
    Returns
526
    -------
527
    power_plants : pandas.DataFrame
528
        Power plants including voltage level and bus_id
529
530
    """
531
532
    mv_grid_districts = db.select_geodataframe(
533
        f"""
534
        SELECT * FROM {cfg['sources']['egon_mv_grid_district']}
535
        """,
536
        epsg=4326,
537
    )
538
539
    ehv_grid_districts = db.select_geodataframe(
540
        f"""
541
        SELECT * FROM {cfg['sources']['ehv_voronoi']}
542
        """,
543
        epsg=4326,
544
    )
545
546
    # Assign power plants in hv and below to hvmv bus
547
    power_plants_hv = power_plants[power_plants.voltage_level >= 3].index
548
    if len(power_plants_hv) > 0:
549
        power_plants.loc[power_plants_hv, "bus_id"] = gpd.sjoin(
550
            power_plants[power_plants.index.isin(power_plants_hv)],
551
            mv_grid_districts,
552
        ).bus_id
553
554
    # Assign power plants in ehv to ehv bus
555
    power_plants_ehv = power_plants[power_plants.voltage_level < 3].index
556
557
    if len(power_plants_ehv) > 0:
558
        ehv_join = gpd.sjoin(
559
            power_plants[power_plants.index.isin(power_plants_ehv)],
560
            ehv_grid_districts,
561
        )
562
563
        if "bus_id_right" in ehv_join.columns:
564
            power_plants.loc[power_plants_ehv, "bus_id"] = gpd.sjoin(
565
                power_plants[power_plants.index.isin(power_plants_ehv)],
566
                ehv_grid_districts,
567
            ).bus_id_right
568
569
        else:
570
            power_plants.loc[power_plants_ehv, "bus_id"] = gpd.sjoin(
571
                power_plants[power_plants.index.isin(power_plants_ehv)],
572
                ehv_grid_districts,
573
            ).bus_id
574
575
    if drop_missing:
576
        power_plants = power_plants[~power_plants.bus_id.isnull()]
577
578
    # Assert that all power plants have a bus_id
579
    assert power_plants.bus_id.notnull().all(), f"""Some power plants are
580
    not attached to a bus: {power_plants[power_plants.bus_id.isnull()]}"""
581
582
    return power_plants
583
584
585
def insert_hydro_biomass():
586
    """Insert hydro and biomass power plants in database
587
588
    Returns
589
    -------
590
    None.
591
592
    """
593
    cfg = egon.data.config.datasets()["power_plants"]
594
    db.execute_sql(
595
        f"""
596
        DELETE FROM {cfg['target']['schema']}.{cfg['target']['table']}
597
        WHERE carrier IN ('biomass', 'reservoir', 'run_of_river')
598
        AND scenario IN ('eGon2035', 'eGon100RE')
599
        """
600
    )
601
602
    s = egon.data.config.settings()["egon-data"]["--scenarios"]
603
    scenarios = []
604
    if "eGon2035" in s:
605
        scenarios.append("eGon2035")
606
        insert_biomass_plants("eGon2035")
607
    if "eGon100RE" in s:
608
        scenarios.append("eGon100RE")
609
610
    for scenario in scenarios:
611
        insert_hydro_plants(scenario)
612
613
614
def allocate_conventional_non_chp_power_plants():
615
    # This function is only designed to work for the eGon2035 scenario
616
    if (
617
        "eGon2035"
618
        not in egon.data.config.settings()["egon-data"]["--scenarios"]
619
    ):
620
        return
621
622
    carrier = ["oil", "gas"]
623
624
    cfg = egon.data.config.datasets()["power_plants"]
625
626
    # Delete existing plants in the target table
627
    db.execute_sql(
628
        f"""
629
         DELETE FROM {cfg ['target']['schema']}.{cfg ['target']['table']}
630
         WHERE carrier IN ('gas', 'oil')
631
         AND scenario='eGon2035';
632
         """
633
    )
634
635
    for carrier in carrier:
636
        nep = select_nep_power_plants(carrier)
637
638
        if nep.empty:
639
            print(f"DataFrame from NEP for carrier {carrier} is empty!")
640
641
        else:
642
            mastr = select_no_chp_combustion_mastr(carrier)
643
644
            # Assign voltage level to MaStR
645
            mastr["voltage_level"] = assign_voltage_level(
646
                mastr.rename({"el_capacity": "Nettonennleistung"}, axis=1),
647
                cfg,
648
                WORKING_DIR_MASTR_OLD,
649
            )
650
651
            # Initalize DataFrame for matching power plants
652
            matched = gpd.GeoDataFrame(
653
                columns=[
654
                    "carrier",
655
                    "el_capacity",
656
                    "scenario",
657
                    "geometry",
658
                    "MaStRNummer",
659
                    "source",
660
                    "voltage_level",
661
                ]
662
            )
663
664
            # Match combustion plants of a certain carrier from NEP list
665
            # using PLZ and capacity
666
            matched, mastr, nep = match_nep_no_chp(
667
                nep,
668
                mastr,
669
                matched,
670
                buffer_capacity=0.1,
671
                consider_carrier=False,
672
            )
673
674
            # Match plants from NEP list using city and capacity
675
            matched, mastr, nep = match_nep_no_chp(
676
                nep,
677
                mastr,
678
                matched,
679
                buffer_capacity=0.1,
680
                consider_carrier=False,
681
                consider_location="city",
682
            )
683
684
            # Match plants from NEP list using plz,
685
            # neglecting the capacity
686
            matched, mastr, nep = match_nep_no_chp(
687
                nep,
688
                mastr,
689
                matched,
690
                consider_location="plz",
691
                consider_carrier=False,
692
                consider_capacity=False,
693
            )
694
695
            # Match plants from NEP list using city,
696
            # neglecting the capacity
697
            matched, mastr, nep = match_nep_no_chp(
698
                nep,
699
                mastr,
700
                matched,
701
                consider_location="city",
702
                consider_carrier=False,
703
                consider_capacity=False,
704
            )
705
706
            # Match remaining plants from NEP using the federal state
707
            matched, mastr, nep = match_nep_no_chp(
708
                nep,
709
                mastr,
710
                matched,
711
                buffer_capacity=0.1,
712
                consider_location="federal_state",
713
                consider_carrier=False,
714
            )
715
716
            # Match remaining plants from NEP using the federal state
717
            matched, mastr, nep = match_nep_no_chp(
718
                nep,
719
                mastr,
720
                matched,
721
                buffer_capacity=0.7,
722
                consider_location="federal_state",
723
                consider_carrier=False,
724
            )
725
726
            print(f"{matched.el_capacity.sum()} MW of {carrier} matched")
727
            print(f"{nep.c2035_capacity.sum()} MW of {carrier} not matched")
728
729
            matched.crs = "EPSG:4326"
730
731
            # Assign bus_id
732
            # Load grid district polygons
733
            mv_grid_districts = db.select_geodataframe(
734
                f"""
735
            SELECT * FROM {cfg['sources']['egon_mv_grid_district']}
736
            """,
737
                epsg=4326,
738
            )
739
740
            ehv_grid_districts = db.select_geodataframe(
741
                f"""
742
            SELECT * FROM {cfg['sources']['ehv_voronoi']}
743
            """,
744
                epsg=4326,
745
            )
746
747
            # Perform spatial joins for plants in ehv and hv level seperately
748
            power_plants_hv = gpd.sjoin(
749
                matched[matched.voltage_level >= 3],
750
                mv_grid_districts[["bus_id", "geom"]],
751
                how="left",
752
            ).drop(columns=["index_right"])
753
            power_plants_ehv = gpd.sjoin(
754
                matched[matched.voltage_level < 3],
755
                ehv_grid_districts[["bus_id", "geom"]],
756
                how="left",
757
            ).drop(columns=["index_right"])
758
759
            # Combine both dataframes
760
            power_plants = pd.concat([power_plants_hv, power_plants_ehv])
761
762
            # Insert into target table
763
            session = sessionmaker(bind=db.engine())()
764
            for i, row in power_plants.iterrows():
765
                entry = EgonPowerPlants(
766
                    sources={"el_capacity": row.source},
767
                    source_id={"MastrNummer": row.MaStRNummer},
768
                    carrier=row.carrier,
769
                    el_capacity=row.el_capacity,
770
                    voltage_level=row.voltage_level,
771
                    bus_id=row.bus_id,
772
                    scenario=row.scenario,
773
                    geom=f"SRID=4326;POINT({row.geometry.x} {row.geometry.y})",
774
                )
775
                session.add(entry)
776
            session.commit()
777
778
779
def allocate_other_power_plants():
780
    # This function is only designed to work for the eGon2035 scenario
781
    if (
782
        "eGon2035"
783
        not in egon.data.config.settings()["egon-data"]["--scenarios"]
784
    ):
785
        return
786
787
    # Get configuration
788
    cfg = egon.data.config.datasets()["power_plants"]
789
    boundary = egon.data.config.settings()["egon-data"]["--dataset-boundary"]
790
791
    db.execute_sql(
792
        f"""
793
        DELETE FROM {cfg['target']['schema']}.{cfg['target']['table']}
794
        WHERE carrier ='others'
795
        """
796
    )
797
798
    # Define scenario, carrier 'others' is only present in 'eGon2035'
799
    scenario = "eGon2035"
800
801
    # Select target values for carrier 'others'
802
    target = db.select_dataframe(
803
        f"""
804
        SELECT sum(capacity) as capacity, carrier, scenario_name, nuts
805
            FROM {cfg['sources']['capacities']}
806
            WHERE scenario_name = '{scenario}'
807
            AND carrier = 'others'
808
            GROUP BY carrier, nuts, scenario_name;
809
        """
810
    )
811
812
    # Assign name of federal state
813
814
    map_states = {
815
        "DE1": "BadenWuerttemberg",
816
        "DEA": "NordrheinWestfalen",
817
        "DE7": "Hessen",
818
        "DE4": "Brandenburg",
819
        "DE5": "Bremen",
820
        "DEB": "RheinlandPfalz",
821
        "DEE": "SachsenAnhalt",
822
        "DEF": "SchleswigHolstein",
823
        "DE8": "MecklenburgVorpommern",
824
        "DEG": "Thueringen",
825
        "DE9": "Niedersachsen",
826
        "DED": "Sachsen",
827
        "DE6": "Hamburg",
828
        "DEC": "Saarland",
829
        "DE3": "Berlin",
830
        "DE2": "Bayern",
831
    }
832
833
    target = (
834
        target.replace({"nuts": map_states})
835
        .rename(columns={"nuts": "Bundesland"})
836
        .set_index("Bundesland")
837
    )
838
    target = target.capacity
839
840
    # Select 'non chp' power plants from mastr table
841
    mastr_combustion = select_no_chp_combustion_mastr("others")
842
843
    # Rename columns
844
    mastr_combustion = mastr_combustion.rename(
845
        columns={
846
            "carrier": "Energietraeger",
847
            "plz": "Postleitzahl",
848
            "city": "Ort",
849
            "federal_state": "Bundesland",
850
            "el_capacity": "Nettonennleistung",
851
        }
852
    )
853
854
    # Select power plants representing carrier 'others' from MaStR files
855
    mastr_sludge = pd.read_csv(
856
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_gsgk"]
857
    ).query(
858
        """EinheitBetriebsstatus=='InBetrieb'and Energietraeger=='Klärschlamm'"""  # noqa: E501
859
    )
860
    mastr_geothermal = pd.read_csv(
861
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_gsgk"]
862
    ).query(
863
        "EinheitBetriebsstatus=='InBetrieb' and Energietraeger=='Geothermie' "
864
        "and Technologie == 'ORCOrganicRankineCycleAnlage'"
865
    )
866
867
    mastr_sg = pd.concat([mastr_sludge, mastr_geothermal])
868
869
    # Insert geometry column
870
    mastr_sg = mastr_sg[~(mastr_sg["Laengengrad"].isnull())]
871
    mastr_sg = gpd.GeoDataFrame(
872
        mastr_sg,
873
        geometry=gpd.points_from_xy(
874
            mastr_sg["Laengengrad"], mastr_sg["Breitengrad"], crs=4326
875
        ),
876
    )
877
878
    # Exclude columns which are not essential
879
    mastr_sg = mastr_sg.filter(
880
        [
881
            "EinheitMastrNummer",
882
            "Nettonennleistung",
883
            "geometry",
884
            "Energietraeger",
885
            "Postleitzahl",
886
            "Ort",
887
            "Bundesland",
888
        ],
889
        axis=1,
890
    )
891
    # Rename carrier
892
    mastr_sg.Energietraeger = "others"
893
894
    # Change data type
895
    mastr_sg["Postleitzahl"] = mastr_sg["Postleitzahl"].astype(int)
896
897
    # Capacity in MW
898
    mastr_sg.loc[:, "Nettonennleistung"] *= 1e-3
899
900
    # Merge different sources to one df
901
    mastr_others = pd.concat([mastr_sg, mastr_combustion]).reset_index()
902
903
    # Delete entries outside Schleswig-Holstein for test mode
904
    if boundary == "Schleswig-Holstein":
905
        mastr_others = mastr_others[
906
            mastr_others["Bundesland"] == "SchleswigHolstein"
907
        ]
908
909
    # Scale capacities prox to now to meet target values
910
    mastr_prox = scale_prox2now(mastr_others, target, level="federal_state")
911
912
    # Assign voltage_level based on scaled capacity
913
    mastr_prox["voltage_level"] = np.nan
914
    mastr_prox["voltage_level"] = assign_voltage_level_by_capacity(mastr_prox)
915
916
    # Rename columns
917
    mastr_prox = mastr_prox.rename(
918
        columns={
919
            "Energietraeger": "carrier",
920
            "Postleitzahl": "plz",
921
            "Ort": "city",
922
            "Bundesland": "federal_state",
923
            "Nettonennleistung": "el_capacity",
924
        }
925
    )
926
927
    # Assign bus_id
928
    mastr_prox = assign_bus_id(mastr_prox, cfg)
929
    mastr_prox = mastr_prox.set_crs(4326, allow_override=True)
930
931
    # Insert into target table
932
    session = sessionmaker(bind=db.engine())()
933
    for i, row in mastr_prox.iterrows():
934
        entry = EgonPowerPlants(
935
            sources=row.el_capacity,
936
            source_id={"MastrNummer": row.EinheitMastrNummer},
937
            carrier=row.carrier,
938
            el_capacity=row.el_capacity,
939
            voltage_level=row.voltage_level,
940
            bus_id=row.bus_id,
941
            scenario=scenario,
942
            geom=f"SRID=4326; {row.geometry}",
943
        )
944
        session.add(entry)
945
    session.commit()
946
947
948
def discard_not_available_generators(gen, max_date):
949
    gen["decommissioning_date"] = pd.to_datetime(
950
        gen["decommissioning_date"]
951
    )
952
    gen["commissioning_date"] = pd.to_datetime(gen["commissioning_date"])
953
    # drop plants that are commissioned after the max date
954
    gen = gen[gen["commissioning_date"] < max_date]
955
956
    # drop decommissioned plants while keeping the ones decommissioned
957
    # after the max date
958
    gen.loc[(gen["decommissioning_date"] > max_date), "status"] = (
959
        "InBetrieb"
960
    )
961
962
    gen = gen.loc[
963
        gen["status"].isin(["InBetrieb", "VoruebergehendStillgelegt"])
964
    ]
965
966
    # drop unnecessary columns
967
    gen = gen.drop(columns=["commissioning_date", "decommissioning_date"])
968
969
    return gen
970
971
972
def get_conventional_power_plants_non_chp(scn_name):
973
974
    cfg = egon.data.config.datasets()["power_plants"]
975
    # Write conventional power plants in supply.egon_power_plants
976
    common_columns = [
977
        "EinheitMastrNummer",
978
        "Energietraeger",
979
        "Nettonennleistung",
980
        "Laengengrad",
981
        "Breitengrad",
982
        "Gemeinde",
983
        "Inbetriebnahmedatum",
984
        "EinheitBetriebsstatus",
985
        "DatumEndgueltigeStilllegung",
986
    ]
987
    # import nuclear power plants
988
    nuclear = pd.read_csv(
989
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_nuclear"],
990
        usecols=common_columns,
991
    )
992
    # import combustion power plants
993
    comb = pd.read_csv(
994
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_combustion"],
995
        usecols=common_columns + ["ThermischeNutzleistung"],
996
    )
997
998
    conv = pd.concat([comb, nuclear])
999
1000
    conv = conv[
1001
        conv.Energietraeger.isin(
1002
            [
1003
                "Braunkohle",
1004
                "Mineralölprodukte",
1005
                "Steinkohle",
1006
                "Kernenergie",
1007
                "Erdgas",
1008
            ]
1009
        )
1010
    ]
1011
1012
    # drop plants that are decommissioned
1013
    conv["DatumEndgueltigeStilllegung"] = pd.to_datetime(
1014
        conv["DatumEndgueltigeStilllegung"]
1015
    )
1016
1017
    # keep plants that were decommissioned after the max date
1018
    conv.loc[
1019
        (
1020
            conv.DatumEndgueltigeStilllegung
1021
            > egon.data.config.datasets()["mastr_new"][f"{scn_name}_date_max"]
1022
        ),
1023
        "EinheitBetriebsstatus",
1024
    ] = "InBetrieb"
1025
1026
    conv = conv.loc[conv.EinheitBetriebsstatus == "InBetrieb"]
1027
1028
    conv = conv.drop(
1029
        columns=["EinheitBetriebsstatus", "DatumEndgueltigeStilllegung"]
1030
    )
1031
1032
    # convert from KW to MW
1033
    conv["Nettonennleistung"] = conv["Nettonennleistung"] / 1000
1034
1035
    # drop generators installed after 2019
1036
    conv["Inbetriebnahmedatum"] = pd.to_datetime(conv["Inbetriebnahmedatum"])
1037
    conv = conv[
1038
        conv["Inbetriebnahmedatum"]
1039
        < egon.data.config.datasets()["mastr_new"][f"{scn_name}_date_max"]
1040
    ]
1041
1042
    conv_cap_chp = (
1043
        conv.groupby("Energietraeger")["Nettonennleistung"].sum() / 1e3
1044
    )
1045
    # drop chp generators
1046
    conv["ThermischeNutzleistung"] = conv["ThermischeNutzleistung"].fillna(0)
1047
    conv = conv[conv.ThermischeNutzleistung == 0]
1048
    conv_cap_no_chp = (
1049
        conv.groupby("Energietraeger")["Nettonennleistung"].sum() / 1e3
1050
    )
1051
1052
    logger.info("Dropped CHP generators in GW")
1053
    logger.info(conv_cap_chp - conv_cap_no_chp)
1054
1055
    # rename carriers
1056
    # rename carriers
1057
    conv["Energietraeger"] = conv["Energietraeger"].replace(
1058
        to_replace={
1059
            "Braunkohle": "lignite",
1060
            "Steinkohle": "coal",
1061
            "Erdgas": "gas",
1062
            "Mineralölprodukte": "oil",
1063
            "Kernenergie": "nuclear",
1064
        }
1065
    )
1066
1067
    # rename columns
1068
    conv.rename(
1069
        columns={
1070
            "EinheitMastrNummer": "gens_id",
1071
            "Energietraeger": "carrier",
1072
            "Nettonennleistung": "capacity",
1073
            "Gemeinde": "location",
1074
        },
1075
        inplace=True,
1076
    )
1077
    conv["bus_id"] = np.nan
1078
    conv["geom"] = gpd.points_from_xy(
1079
        conv.Laengengrad, conv.Breitengrad, crs=4326
1080
    )
1081
    conv.loc[(conv.Laengengrad.isna() | conv.Breitengrad.isna()), "geom"] = (
1082
        Point()
1083
    )
1084
    conv = gpd.GeoDataFrame(conv, geometry="geom")
1085
1086
    # assign voltage level by capacity
1087
    conv["voltage_level"] = np.nan
1088
    conv["voltage_level"] = assign_voltage_level_by_capacity(
1089
        conv.rename(columns={"capacity": "Nettonennleistung"})
1090
    )
1091
    # Add further information
1092
    conv["sources"] = [{"el_capacity": "MaStR"}] * conv.shape[0]
1093
    conv["source_id"] = conv["gens_id"].apply(lambda x: {"MastrNummer": x})
1094
    conv["scenario"] = scn_name
1095
1096
    return conv
1097
1098
1099
def power_plants_status_quo(scn_name="status2019"):
1100
    def fill_missing_bus_and_geom(gens, carrier):
1101
        # drop generators without data to get geometry.
1102
        drop_id = gens[
1103
            (gens.geom.is_empty)
1104
            & ~(gens.location.isin(geom_municipalities.index))
1105
        ].index
1106
        new_geom = gens["capacity"][
1107
            (gens.geom.is_empty)
1108
            & (gens.location.isin(geom_municipalities.index))
1109
        ]
1110
        logger.info(
1111
            f"""{len(drop_id)} {carrier} generator(s) ({int(gens.loc[drop_id, 'capacity']
1112
            .sum())}MW) were drop"""
1113
        )
1114
1115
        logger.info(
1116
            f"""{len(new_geom)} {carrier} generator(s) ({int(new_geom
1117
            .sum())}MW) received a geom based on location
1118
              """
1119
        )
1120
        gens.drop(index=drop_id, inplace=True)
1121
1122
        # assign missing geometries based on location and buses based on geom
1123
1124
        gens["geom"] = gens.apply(
1125
            lambda x: (
1126
                geom_municipalities.at[x["location"], "geom"]
1127
                if x["geom"].is_empty
1128
                else x["geom"]
1129
            ),
1130
            axis=1,
1131
        )
1132
        gens["bus_id"] = gens.sjoin(
1133
            mv_grid_districts[["bus_id", "geom"]], how="left"
1134
        ).bus_id_right.values
1135
1136
        gens = gens.dropna(subset=["bus_id"])
1137
        # convert geom to WKB
1138
        gens["geom"] = gens["geom"].to_wkt()
1139
1140
        return gens
1141
1142
    def convert_master_info(df):
1143
        # Add further information
1144
        df["sources"] = [{"el_capacity": "MaStR"}] * df.shape[0]
1145
        df["source_id"] = df["gens_id"].apply(lambda x: {"MastrNummer": x})
1146
        return df
1147
1148
    def log_insert_capacity(df, tech):
1149
        logger.info(
1150
            f"""
1151
            {len(df)} {tech} generators with a total installed capacity of
1152
            {int(df["el_capacity"].sum())} MW were inserted into the db
1153
              """
1154
        )
1155
1156
    con = db.engine()
1157
    cfg = egon.data.config.datasets()["power_plants"]
1158
1159
    db.execute_sql(
1160
        f"""
1161
        DELETE FROM {cfg['target']['schema']}.{cfg['target']['table']}
1162
        WHERE carrier IN ('wind_onshore', 'solar', 'biomass',
1163
                          'run_of_river', 'reservoir', 'solar_rooftop',
1164
                          'wind_offshore', 'nuclear', 'coal', 'lignite', 'oil',
1165
                          'gas')
1166
        AND scenario = '{scn_name}'
1167
        """
1168
    )
1169
1170
    # import municipalities to assign missing geom and bus_id
1171
    geom_municipalities = gpd.GeoDataFrame.from_postgis(
1172
        """
1173
        SELECT gen, ST_UNION(geometry) as geom
1174
        FROM boundaries.vg250_gem
1175
        GROUP BY gen
1176
        """,
1177
        con,
1178
        geom_col="geom",
1179
    ).set_index("gen")
1180
    geom_municipalities["geom"] = geom_municipalities["geom"].centroid
1181
1182
    mv_grid_districts = gpd.GeoDataFrame.from_postgis(
1183
        f"""
1184
        SELECT * FROM {cfg['sources']['egon_mv_grid_district']}
1185
        """,
1186
        con,
1187
    )
1188
    mv_grid_districts.geom = mv_grid_districts.geom.to_crs(4326)
1189
1190
    # Conventional non CHP
1191
    #  ###################
1192
    conv = get_conventional_power_plants_non_chp(scn_name)
1193
    conv = fill_missing_bus_and_geom(conv, carrier="conventional")
1194
    conv=  conv.rename(columns={"capacity": "el_capacity"})
1195
1196
    # Write into DB
1197
    with db.session_scope() as session:
1198
        session.bulk_insert_mappings(
1199
            EgonPowerPlants,
1200
            conv.to_dict(orient="records"),
1201
        )
1202
1203
    log_insert_capacity(conv, tech="conventional non chp")
1204
1205
    # Hydro Power Plants
1206
    #  ###################
1207
    hydro = gpd.GeoDataFrame.from_postgis(
1208
        f"""SELECT *, city AS location FROM {cfg['sources']['hydro']}
1209
        WHERE plant_type IN ('Laufwasseranlage', 'Speicherwasseranlage')""",
1210
        con,
1211
        geom_col="geom",
1212
    )
1213
1214
    hydro = fill_missing_bus_and_geom(hydro, carrier="hydro")
1215
1216
    hydro = convert_master_info(hydro)
1217
    hydro["carrier"] = hydro["plant_type"].replace(
1218
        to_replace={
1219
            "Laufwasseranlage": "run_of_river",
1220
            "Speicherwasseranlage": "reservoir",
1221
        }
1222
    )
1223
    hydro["scenario"] = scn_name
1224
    hydro = hydro.rename(columns={"capacity": "el_capacity"})
1225
    hydro = hydro.drop(columns="id")
1226
1227
    # Write into DB
1228
    with db.session_scope() as session:
1229
        session.bulk_insert_mappings(
1230
            EgonPowerPlants,
1231
            hydro.to_dict(orient="records"),
1232
        )
1233
1234
    log_insert_capacity(hydro, tech="hydro")
1235
1236
    # Biomass
1237
    #  ###################
1238
    biomass = gpd.GeoDataFrame.from_postgis(
1239
        f"""SELECT *, city AS location FROM {cfg['sources']['biomass']}""",
1240
        con,
1241
        geom_col="geom",
1242
    )
1243
1244
    # drop chp generators
1245
    biomass["th_capacity"] = biomass["th_capacity"].fillna(0)
1246
    biomass = biomass[biomass.th_capacity == 0]
1247
1248
    biomass = fill_missing_bus_and_geom(biomass, carrier="biomass")
1249
1250
    biomass = convert_master_info(biomass)
1251
    biomass["scenario"] = scn_name
1252
    biomass["carrier"] = "biomass"
1253
    biomass = biomass.rename(columns={"capacity": "el_capacity"})
1254
    biomass = biomass.drop(columns="id")
1255
1256
    # Write into DB
1257
    with db.session_scope() as session:
1258
        session.bulk_insert_mappings(
1259
            EgonPowerPlants,
1260
            biomass.to_dict(orient="records"),
1261
        )
1262
1263
    log_insert_capacity(biomass, tech="biomass")
1264
1265
    # Solar
1266
    #  ###################
1267
    solar = gpd.GeoDataFrame.from_postgis(
1268
        f"""SELECT *, city AS location FROM {cfg['sources']['pv']}
1269
        WHERE site_type IN ('Freifläche',
1270
        'Bauliche Anlagen (Hausdach, Gebäude und Fassade)') """,
1271
        con,
1272
        geom_col="geom",
1273
    )
1274
    map_solar = {
1275
        "Freifläche": "solar",
1276
        "Bauliche Anlagen (Hausdach, Gebäude und Fassade)": "solar_rooftop",
1277
    }
1278
    solar["carrier"] = solar["site_type"].replace(to_replace=map_solar)
1279
1280
    solar = fill_missing_bus_and_geom(solar, carrier="solar")
1281
    solar = convert_master_info(solar)
1282
    solar["scenario"] = scn_name
1283
    solar = solar.rename(columns={"capacity": "el_capacity"})
1284
    solar = solar.drop(columns="id")
1285
1286
    # Write into DB
1287
    with db.session_scope() as session:
1288
        session.bulk_insert_mappings(
1289
            EgonPowerPlants,
1290
            solar.to_dict(orient="records"),
1291
        )
1292
1293
    log_insert_capacity(solar, tech="solar")
1294
1295
    # Wind
1296
    #  ###################
1297
    wind_onshore = gpd.GeoDataFrame.from_postgis(
1298
        f"""SELECT *, city AS location FROM {cfg['sources']['wind']}""",
1299
        con,
1300
        geom_col="geom",
1301
    )
1302
1303
    wind_onshore = fill_missing_bus_and_geom(
1304
        wind_onshore, carrier="wind_onshore"
1305
    )
1306
    wind_onshore = convert_master_info(wind_onshore)
1307
    wind_onshore["scenario"] = scn_name
1308
    wind_onshore = wind_onshore.rename(columns={"capacity": "el_capacity"})
1309
    wind_onshore["carrier"] = "wind_onshore"
1310
    wind_onshore = wind_onshore.drop(columns="id")
1311
1312
    # Write into DB
1313
    with db.session_scope() as session:
1314
        session.bulk_insert_mappings(
1315
            EgonPowerPlants,
1316
            wind_onshore.to_dict(orient="records"),
1317
        )
1318
1319
    log_insert_capacity(wind_onshore, tech="wind_onshore")
1320
1321
1322
tasks = (
1323
    create_tables,
1324
    import_mastr,
1325
)
1326
1327
for scn_name in egon.data.config.settings()["egon-data"]["--scenarios"]:
1328
    if "status" in scn_name:
1329
        tasks += (
1330
            wrapped_partial(
1331
                power_plants_status_quo,
1332
                scn_name=scn_name,
1333
                postfix=f"_{scn_name[-4:]}",
1334
            ),
1335
        )
1336
1337
if (
1338
    "eGon2035" in egon.data.config.settings()["egon-data"]["--scenarios"]
1339
    or "eGon100RE" in egon.data.config.settings()["egon-data"]["--scenarios"]
1340
):
1341
    tasks = tasks + (
1342
        insert_hydro_biomass,
1343
        allocate_conventional_non_chp_power_plants,
1344
        allocate_other_power_plants,
1345
        {
1346
            wind_onshore.insert,
1347
            pv_ground_mounted.insert,
1348
            pv_rooftop_per_mv_grid,
1349
        },
1350
    )
1351
1352
tasks = tasks + (
1353
    pv_rooftop_to_buildings,
1354
    wind_offshore.insert,
1355
)
1356
1357
for scn_name in egon.data.config.settings()["egon-data"]["--scenarios"]:
1358
    tasks += (wrapped_partial(assign_weather_data.weatherId_and_busId,
1359
                              scn_name=scn_name,
1360
                              postfix=f"_{scn_name}"
1361
                              ),)
1362
1363
tasks += (pp_metadata.metadata,)
1364
1365
class PowerPlants(Dataset):
1366
    """
1367
    This module creates all electrical generators for different scenarios. It
1368
    also calculates the weather area for each weather dependent generator.
1369
1370
    *Dependencies*
1371
      * :py:class:`Chp <egon.data.datasets.chp.Chp>`
1372
      * :py:class:`CtsElectricityDemand
1373
      <egon.data.datasets.electricity_demand.CtsElectricityDemand>`
1374
      * :py:class:`HouseholdElectricityDemand
1375
      <egon.data.datasets.electricity_demand.HouseholdElectricityDemand>`
1376
      * :py:class:`mastr_data <egon.data.datasets.mastr.mastr_data>`
1377
      * :py:func:`define_mv_grid_districts
1378
      <egon.data.datasets.mv_grid_districts.define_mv_grid_districts>`
1379
      * :py:class:`RePotentialAreas
1380
      <egon.data.datasets.re_potential_areas.RePotentialAreas>`
1381
      * :py:class:`ZensusVg250
1382
      <egon.data.datasets.RenewableFeedin>`
1383
      * :py:class:`ScenarioCapacities
1384
      <egon.data.datasets.scenario_capacities.ScenarioCapacities>`
1385
      * :py:class:`ScenarioParameters
1386
      <egon.data.datasets.scenario_parameters.ScenarioParameters>`
1387
      * :py:func:`Setup <egon.data.datasets.database.setup>`
1388
      * :py:class:`substation_extraction
1389
      <egon.data.datasets.substation.substation_extraction>`
1390
      * :py:class:`Vg250MvGridDistricts
1391
      <egon.data.datasets.Vg250MvGridDistricts>`
1392
      * :py:class:`ZensusMvGridDistricts
1393
      <egon.data.datasets.zensus_mv_grid_districts.ZensusMvGridDistricts>`
1394
1395
    *Resulting tables*
1396
      * :py:class:`supply.egon_power_plants
1397
      <egon.data.datasets.power_plants.EgonPowerPlants>` is filled
1398
1399
    """
1400
1401
    #:
1402
    name: str = "PowerPlants"
1403
    #:
1404
    version: str = "0.0.27"
1405
1406
    def __init__(self, dependencies):
1407
        super().__init__(
1408
            name=self.name,
1409
            version=self.version,
1410
            dependencies=dependencies,
1411
            tasks=tasks,
1412
        )
1413
1414