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

data.datasets.chp.assign_heat_bus()   B

Complexity

Conditions 4

Size

Total Lines 98
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 53
dl 0
loc 98
rs 8.5381
c 0
b 0
f 0
cc 4
nop 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
"""
2
The central module containing all code dealing with combined heat and power
3
(CHP) plants.
4
"""
5
from pathlib import Path
6
import datetime
7
import json
8
import time
9
10
from geoalchemy2 import Geometry
11
from shapely.ops import nearest_points
12
from sqlalchemy import Boolean, Column, Float, Integer, Sequence, String
13
from sqlalchemy.dialects.postgresql import JSONB
14
from sqlalchemy.ext.declarative import declarative_base
15
from sqlalchemy.orm import sessionmaker
16
import geopandas as gpd
17
import pandas as pd
18
import pypsa
19
20
from egon.data import config, db
21
from egon.data.datasets import Dataset, wrapped_partial
22
from egon.data.datasets.chp.match_nep import insert_large_chp, map_carrier
23
from egon.data.datasets.chp.small_chp import (
24
    assign_use_case,
25
    existing_chp_smaller_10mw,
26
    extension_per_federal_state,
27
    extension_to_areas,
28
    select_target,
29
)
30
from egon.data.datasets.mastr import (
31
    WORKING_DIR_MASTR_OLD,
32
    WORKING_DIR_MASTR_NEW,
33
)
34
from egon.data.datasets.power_plants import (
35
    assign_bus_id,
36
    assign_voltage_level,
37
    filter_mastr_geometry,
38
    scale_prox2now,
39
)
40
from egon.data.metadata import (
41
    context,
42
    generate_resource_fields_from_sqla_model,
43
    license_egon_data_odbl,
44
    meta_metadata,
45
    sources,
46
)
47
48
Base = declarative_base()
49
50
51
class EgonChp(Base):
52
    __tablename__ = "egon_chp_plants"
53
    __table_args__ = {"schema": "supply"}
54
    id = Column(Integer, Sequence("chp_seq"), primary_key=True)
55
    sources = Column(JSONB)
56
    source_id = Column(JSONB)
57
    carrier = Column(String)
58
    district_heating = Column(Boolean)
59
    el_capacity = Column(Float)
60
    th_capacity = Column(Float)
61
    electrical_bus_id = Column(Integer)
62
    district_heating_area_id = Column(Integer)
63
    ch4_bus_id = Column(Integer)
64
    voltage_level = Column(Integer)
65
    scenario = Column(String)
66
    geom = Column(Geometry("POINT", 4326))
67
68
69
class EgonMaStRConventinalWithoutChp(Base):
70
    __tablename__ = "egon_mastr_conventional_without_chp"
71
    __table_args__ = {"schema": "supply"}
72
    id = Column(Integer, Sequence("mastr_conventional_seq"), primary_key=True)
73
    EinheitMastrNummer = Column(String)
74
    carrier = Column(String)
75
    el_capacity = Column(Float)
76
    plz = Column(Integer)
77
    city = Column(String)
78
    federal_state = Column(String)
79
    geometry = Column(Geometry("POINT", 4326))
80
81
82
def metadata():
83
    """Write metadata for heat supply tables
84
85
    Returns
86
    -------
87
    None.
88
89
    """
90
91
    fields = generate_resource_fields_from_sqla_model(EgonChp)
92
93
    fields_df = pd.DataFrame(data=fields).set_index("name")
94
    fields_df.loc["id", "description"] = "Unique identifyer"
95
    fields_df.loc["sources", "description"] = "List of sources"
96
    fields_df.loc[
97
        "source_id", "description"
98
    ] = "Names of sources, e.g. MaStr_id"
99
    fields_df.loc["carrier", "description"] = "Energy carrier"
100
    fields_df.loc[
101
        "district_heating", "description"
102
    ] = "Used in district heating or not"
103
    fields_df.loc[
104
        "el_capacity", "description"
105
    ] = "Installed electrical capacity"
106
    fields_df.loc["th_capacity", "description"] = "Installed thermal capacity"
107
    fields_df.loc[
108
        "electrical_bus_id", "description"
109
    ] = "Index of corresponding electricity bus"
110
    fields_df.loc[
111
        "district_heating_area_id", "description"
112
    ] = "Index of corresponding district heating bus"
113
    fields_df.loc[
114
        "ch4_bus_id", "description"
115
    ] = "Index of corresponding methane bus"
116
    fields_df.loc["voltage_level", "description"] = "Voltage level"
117
    fields_df.loc["scenario", "description"] = "Name of scenario"
118
    fields_df.loc["geom", "description"] = "Location of CHP plant"
119
120
    fields_df.loc["el_capacity", "unit"] = "MW_el"
121
    fields_df.loc["th_capacity", "unit"] = "MW_th"
122
    fields_df.unit.fillna("none", inplace=True)
123
124
    fields = fields_df.reset_index().to_dict(orient="records")
125
126
    meta_district = {
127
        "name": "supply.egon_chp_plants",
128
        "title": "eGon combined heat and power plants",
129
        "id": "WILL_BE_SET_AT_PUBLICATION",
130
        "description": "Combined heat and power plants",
131
        "language": ["EN"],
132
        "publicationDate": datetime.date.today().isoformat(),
133
        "context": context(),
134
        "spatial": {
135
            "location": None,
136
            "extent": "Germany",
137
            "resolution": None,
138
        },
139
        "sources": [
140
            sources()["vg250"],
141
            sources()["egon-data"],
142
            sources()["egon-data_bundle"],
143
            sources()["openstreetmap"],
144
            sources()["mastr"],
145
        ],
146
        "licenses": [license_egon_data_odbl()],
147
        "contributors": [
148
            {
149
                "title": "Clara Büttner",
150
                "email": "http://github.com/ClaraBuettner",
151
                "date": time.strftime("%Y-%m-%d"),
152
                "object": None,
153
                "comment": "Imported data",
154
            },
155
        ],
156
        "resources": [
157
            {
158
                "profile": "tabular-data-resource",
159
                "name": "supply.egon_chp_plants",
160
                "path": None,
161
                "format": "PostgreSQL",
162
                "encoding": "UTF-8",
163
                "schema": {
164
                    "fields": fields,
165
                    "primaryKey": ["index"],
166
                    "foreignKeys": [],
167
                },
168
                "dialect": {"delimiter": None, "decimalSeparator": "."},
169
            }
170
        ],
171
        "metaMetadata": meta_metadata(),
172
    }
173
174
    # Add metadata as a comment to the table
175
    db.submit_comment(
176
        "'" + json.dumps(meta_district) + "'",
177
        EgonChp.__table__.schema,
178
        EgonChp.__table__.name,
179
    )
180
181
182
def create_tables():
183
    """Create tables for chp data
184
    Returns
185
    -------
186
    None.
187
    """
188
189
    db.execute_sql("CREATE SCHEMA IF NOT EXISTS supply;")
190
    engine = db.engine()
191
    EgonChp.__table__.drop(bind=engine, checkfirst=True)
192
    EgonChp.__table__.create(bind=engine, checkfirst=True)
193
    EgonMaStRConventinalWithoutChp.__table__.drop(bind=engine, checkfirst=True)
194
    EgonMaStRConventinalWithoutChp.__table__.create(
195
        bind=engine, checkfirst=True
196
    )
197
198
199
def nearest(
200
    row,
201
    df,
202
    centroid=False,
203
    row_geom_col="geometry",
204
    df_geom_col="geometry",
205
    src_column=None,
206
):
207
    """
208
    Finds the nearest point and returns the specified column values
209
210
    Parameters
211
    ----------
212
    row : pandas.Series
213
        Data to which the nearest data of df is assigned.
214
    df : pandas.DataFrame
215
        Data which includes all options for the nearest neighbor alogrithm.
216
    centroid : boolean
217
        Use centroid geoemtry. The default is False.
218
    row_geom_col : str, optional
219
        Name of row's geometry column. The default is 'geometry'.
220
    df_geom_col : str, optional
221
        Name of df's geometry column. The default is 'geometry'.
222
    src_column : str, optional
223
        Name of returned df column. The default is None.
224
225
    Returns
226
    -------
227
    value : pandas.Series
228
        Values of specified column of df
229
230
    """
231
232
    if centroid:
233
        unary_union = df.centroid.unary_union
234
    else:
235
        unary_union = df[df_geom_col].unary_union
236
    # Find the geometry that is closest
237
    nearest = (
238
        df[df_geom_col] == nearest_points(row[row_geom_col], unary_union)[1]
239
    )
240
241
    # Get the corresponding value from df (matching is based on the geometry)
242
    value = df[nearest][src_column].values[0]
243
244
    return value
245
246
247
def assign_heat_bus():
248
    """Selects heat_bus for chps used in district heating.
249
250
    Parameters
251
    ----------
252
    scenario : str, optional
253
        Name of the corresponding scenario. The default is 'eGon2035'.
254
255
    Returns
256
    -------
257
    None.
258
259
    """
260
    sources = config.datasets()["chp_location"]["sources"]
261
    target = config.datasets()["chp_location"]["targets"]["chp_table"]
262
263
    for scenario in config.settings()["egon-data"]["--scenarios"]:
264
        # Select CHP with use_case = 'district_heating'
265
        chp = db.select_geodataframe(
266
            f"""
267
            SELECT * FROM
268
            {target['schema']}.{target['table']}
269
            WHERE scenario = '{scenario}'
270
            AND district_heating = True
271
            """,
272
            index_col="id",
273
            epsg=4326,
274
        )
275
276
        # Select district heating areas and their centroid
277
        district_heating = db.select_geodataframe(
278
            f"""
279
            SELECT area_id, ST_Centroid(geom_polygon) as geom
280
            FROM
281
            {sources['district_heating_areas']['schema']}.
282
            {sources['district_heating_areas']['table']}
283
            WHERE scenario = '{scenario}'
284
            """,
285
            epsg=4326,
286
        )
287
288
        # Assign district heating area_id to district_heating_chp
289
        # According to nearest centroid of district heating area
290
        chp["district_heating_area_id"] = chp.apply(
291
            nearest,
292
            df=district_heating,
293
            row_geom_col="geom",
294
            df_geom_col="geom",
295
            centroid=True,
296
            src_column="area_id",
297
            axis=1,
298
        )
299
300
        # Drop district heating CHP without heat_bus_id
301
        db.execute_sql(
302
            f"""
303
            DELETE FROM {target['schema']}.{target['table']}
304
            WHERE scenario = '{scenario}'
305
            AND district_heating = True
306
            """
307
        )
308
309
        # Insert district heating CHP with heat_bus_id
310
        session = sessionmaker(bind=db.engine())()
311
        for i, row in chp.iterrows():
312
            if row.carrier != "biomass":
313
                entry = EgonChp(
314
                    id=i,
315
                    sources=row.sources,
316
                    source_id=row.source_id,
317
                    carrier=row.carrier,
318
                    el_capacity=row.el_capacity,
319
                    th_capacity=row.th_capacity,
320
                    electrical_bus_id=row.electrical_bus_id,
321
                    ch4_bus_id=row.ch4_bus_id,
322
                    district_heating_area_id=row.district_heating_area_id,
323
                    district_heating=row.district_heating,
324
                    voltage_level=row.voltage_level,
325
                    scenario=scenario,
326
                    geom=f"SRID=4326;POINT({row.geom.x} {row.geom.y})",
327
                )
328
            else:
329
                entry = EgonChp(
330
                    id=i,
331
                    sources=row.sources,
332
                    source_id=row.source_id,
333
                    carrier=row.carrier,
334
                    el_capacity=row.el_capacity,
335
                    th_capacity=row.th_capacity,
336
                    electrical_bus_id=row.electrical_bus_id,
337
                    district_heating_area_id=row.district_heating_area_id,
338
                    district_heating=row.district_heating,
339
                    voltage_level=row.voltage_level,
340
                    scenario=scenario,
341
                    geom=f"SRID=4326;POINT({row.geom.x} {row.geom.y})",
342
                )
343
            session.add(entry)
344
        session.commit()
345
346
347
def insert_biomass_chp(scenario):
348
    """Insert biomass chp plants of future scenario
349
350
    Parameters
351
    ----------
352
    scenario : str
353
        Name of scenario.
354
355
    Returns
356
    -------
357
    None.
358
359
    """
360
    cfg = config.datasets()["chp_location"]
361
362
    # import target values from NEP 2021, scneario C 2035
363
    target = select_target("biomass", scenario)
364
365
    # import data for MaStR
366
    mastr = pd.read_csv(
367
        WORKING_DIR_MASTR_OLD / cfg["sources"]["mastr_biomass"]
368
    ).query("EinheitBetriebsstatus=='InBetrieb'")
369
370
    # Drop entries without federal state or 'AusschließlichWirtschaftszone'
371
    mastr = mastr[
372
        mastr.Bundesland.isin(
373
            pd.read_sql(
374
                f"""SELECT DISTINCT ON (gen)
375
        REPLACE(REPLACE(gen, '-', ''), 'ü', 'ue') as states
376
        FROM {cfg['sources']['vg250_lan']['schema']}.
377
        {cfg['sources']['vg250_lan']['table']}""",
378
                con=db.engine(),
379
            ).states.values
380
        )
381
    ]
382
383
    # Scaling will be done per federal state in case of eGon2035 scenario.
384
    if scenario == "eGon2035":
385
        level = "federal_state"
386
    else:
387
        level = "country"
388
    # Choose only entries with valid geometries inside DE/test mode
389
    mastr_loc = filter_mastr_geometry(mastr).set_geometry("geometry")
390
391
    # Scale capacities to meet target values
392
    mastr_loc = scale_prox2now(mastr_loc, target, level=level)
393
394
    # Assign bus_id
395
    if len(mastr_loc) > 0:
396
        mastr_loc["voltage_level"] = assign_voltage_level(
397
            mastr_loc, cfg, WORKING_DIR_MASTR_OLD
398
        )
399
        mastr_loc = assign_bus_id(mastr_loc, cfg)
400
    mastr_loc = assign_use_case(mastr_loc, cfg["sources"], scenario)
401
402
    # Insert entries with location
403
    session = sessionmaker(bind=db.engine())()
404
    for i, row in mastr_loc.iterrows():
405
        if row.ThermischeNutzleistung > 0:
406
            entry = EgonChp(
407
                sources={
408
                    "chp": "MaStR",
409
                    "el_capacity": "MaStR scaled with NEP 2021",
410
                    "th_capacity": "MaStR",
411
                },
412
                source_id={"MastrNummer": row.EinheitMastrNummer},
413
                carrier="biomass",
414
                el_capacity=row.Nettonennleistung,
415
                th_capacity=row.ThermischeNutzleistung / 1000,
416
                scenario=scenario,
417
                district_heating=row.district_heating,
418
                electrical_bus_id=row.bus_id,
419
                voltage_level=row.voltage_level,
420
                geom=f"SRID=4326;POINT({row.Laengengrad} {row.Breitengrad})",
421
            )
422
            session.add(entry)
423
    session.commit()
424
425
426
def insert_chp_statusquo(scn="status2019"):
427
    cfg = config.datasets()["chp_location"]
428
429
    # import data for MaStR
430
    mastr = pd.read_csv(
431
        WORKING_DIR_MASTR_NEW / "bnetza_mastr_combustion_cleaned.csv"
432
    )
433
434
    mastr_biomass = pd.read_csv(
435
        WORKING_DIR_MASTR_NEW / "bnetza_mastr_biomass_cleaned.csv"
436
    )
437
438
    mastr = pd.concat([mastr, mastr_biomass]).reset_index(drop=True)
439
440
    mastr = mastr.loc[mastr.ThermischeNutzleistung > 0]
441
442
    mastr = mastr.loc[
443
        mastr.Energietraeger.isin(
444
            [
445
                "Erdgas",
446
                "Mineralölprodukte",
447
                "andere Gase",
448
                "nicht biogener Abfall",
449
                "Braunkohle",
450
                "Steinkohle",
451
                "Biomasse",
452
            ]
453
        )
454
    ]
455
456
    mastr.Inbetriebnahmedatum = pd.to_datetime(mastr.Inbetriebnahmedatum)
457
    mastr.DatumEndgueltigeStilllegung = pd.to_datetime(
458
        mastr.DatumEndgueltigeStilllegung
459
    )
460
    mastr = mastr.loc[
461
        mastr.Inbetriebnahmedatum
462
        <= config.datasets()["mastr_new"][f"{scn}_date_max"]
463
    ]
464
465
    mastr = mastr.loc[
466
        (
467
            mastr.DatumEndgueltigeStilllegung
468
            >= config.datasets()["mastr_new"][f"{scn}_date_max"]
469
        )
470
        | (mastr.DatumEndgueltigeStilllegung.isnull())
471
    ]
472
473
    mastr.groupby("Energietraeger").Nettonennleistung.sum().mul(1e-6)
474
475
    geom_municipalities = db.select_geodataframe(
476
        """
477
        SELECT gen, ST_UNION(geometry) as geom
478
        FROM boundaries.vg250_gem
479
        GROUP BY gen
480
        """
481
    ).set_index("gen")
482
483
    # Assing Laengengrad and Breitengrad to chps without location data
484
    # based on the centroid of the municipaltiy
485
    idx_no_location = mastr[
486
        (mastr.Laengengrad.isnull())
487
        & (mastr.Gemeinde.isin(geom_municipalities.index))
488
    ].index
489
490
    mastr.loc[idx_no_location, "Laengengrad"] = (
491
        geom_municipalities.to_crs(epsg="4326").centroid.x.loc[
492
            mastr.Gemeinde[idx_no_location]
493
        ]
494
    ).values
495
496
    mastr.loc[idx_no_location, "Breitengrad"] = (
497
        geom_municipalities.to_crs(epsg="4326").centroid.y.loc[
498
            mastr.Gemeinde[idx_no_location]
499
        ]
500
    ).values
501
502
    if (
503
        config.settings()["egon-data"]["--dataset-boundary"]
504
        == "Schleswig-Holstein"
505
    ):
506
        dropped_capacity = mastr[
507
            (mastr.Laengengrad.isnull())
508
            & (mastr.Bundesland == "SchleswigHolstein")
509
        ].Nettonennleistung.sum()
510
511
    else:
512
        dropped_capacity = mastr[
513
            (mastr.Laengengrad.isnull())
514
        ].Nettonennleistung.sum()
515
516
    print(
517
        f"""
518
          CHPs with a total installed electrical capacity of {dropped_capacity} kW are dropped
519
          because of missing or wrong location data
520
          """
521
    )
522
523
    mastr = mastr[~mastr.Laengengrad.isnull()]
524
    mastr = filter_mastr_geometry(mastr).set_geometry("geometry")
525
526
    # Assign bus_id
527
    if len(mastr) > 0:
528
        mastr["voltage_level"] = assign_voltage_level(
529
            mastr, cfg, WORKING_DIR_MASTR_NEW
530
        )
531
532
        gas_bus_id = db.assign_gas_bus_id(mastr, scn, "CH4").bus
533
534
        mastr = assign_bus_id(mastr, cfg, drop_missing=True)
535
536
        mastr["gas_bus_id"] = gas_bus_id
537
538
    mastr = assign_use_case(mastr, cfg["sources"], scn)
539
540
    # Insert entries with location
541
    session = sessionmaker(bind=db.engine())()
542
    for i, row in mastr.iterrows():
543
        if row.ThermischeNutzleistung > 0:
544
            entry = EgonChp(
545
                sources={
546
                    "chp": "MaStR",
547
                    "el_capacity": "MaStR",
548
                    "th_capacity": "MaStR",
549
                },
550
                source_id={"MastrNummer": row.EinheitMastrNummer},
551
                carrier=map_carrier().loc[row.Energietraeger],
552
                el_capacity=row.Nettonennleistung / 1000,
553
                th_capacity=row.ThermischeNutzleistung / 1000,
554
                scenario=scn,
555
                district_heating=row.district_heating,
556
                electrical_bus_id=row.bus_id,
557
                ch4_bus_id=row.gas_bus_id,
558
                voltage_level=row.voltage_level,
559
                geom=f"SRID=4326;POINT({row.Laengengrad} {row.Breitengrad})",
560
            )
561
            session.add(entry)
562
    session.commit()
563
564
565
def insert_chp_egon2035():
566
    """Insert CHP plants for eGon2035 considering NEP and MaStR data
567
568
    Returns
569
    -------
570
    None.
571
572
    """
573
574
    sources = config.datasets()["chp_location"]["sources"]
575
576
    targets = config.datasets()["chp_location"]["targets"]
577
578
    insert_biomass_chp("eGon2035")
579
580
    # Insert large CHPs based on NEP's list of conventional power plants
581
    MaStR_konv = insert_large_chp(sources, targets["chp_table"], EgonChp)
582
583
    # Insert smaller CHPs (< 10MW) based on existing locations from MaStR
584
    existing_chp_smaller_10mw(sources, MaStR_konv, EgonChp)
585
586
    gpd.GeoDataFrame(
587
        MaStR_konv[
588
            [
589
                "EinheitMastrNummer",
590
                "el_capacity",
591
                "geometry",
592
                "carrier",
593
                "plz",
594
                "city",
595
                "federal_state",
596
            ]
597
        ]
598
    ).to_postgis(
599
        targets["mastr_conventional_without_chp"]["table"],
600
        schema=targets["mastr_conventional_without_chp"]["schema"],
601
        con=db.engine(),
602
        if_exists="replace",
603
    )
604
605
606
def extension_BW():
607
    extension_per_federal_state("BadenWuerttemberg", EgonChp)
608
609
610
def extension_BY():
611
    extension_per_federal_state("Bayern", EgonChp)
612
613
614
def extension_HB():
615
    extension_per_federal_state("Bremen", EgonChp)
616
617
618
def extension_BB():
619
    extension_per_federal_state("Brandenburg", EgonChp)
620
621
622
def extension_HH():
623
    extension_per_federal_state("Hamburg", EgonChp)
624
625
626
def extension_HE():
627
    extension_per_federal_state("Hessen", EgonChp)
628
629
630
def extension_MV():
631
    extension_per_federal_state("MecklenburgVorpommern", EgonChp)
632
633
634
def extension_NS():
635
    extension_per_federal_state("Niedersachsen", EgonChp)
636
637
638
def extension_NW():
639
    extension_per_federal_state("NordrheinWestfalen", EgonChp)
640
641
642
def extension_SN():
643
    extension_per_federal_state("Sachsen", EgonChp)
644
645
646
def extension_TH():
647
    extension_per_federal_state("Thueringen", EgonChp)
648
649
650
def extension_SL():
651
    extension_per_federal_state("Saarland", EgonChp)
652
653
654
def extension_ST():
655
    extension_per_federal_state("SachsenAnhalt", EgonChp)
656
657
658
def extension_RP():
659
    extension_per_federal_state("RheinlandPfalz", EgonChp)
660
661
662
def extension_BE():
663
    extension_per_federal_state("Berlin", EgonChp)
664
665
666
def extension_SH():
667
    extension_per_federal_state("SchleswigHolstein", EgonChp)
668
669
670
def insert_chp_egon100re():
671
    """Insert CHP plants for eGon100RE considering results from pypsa-eur-sec
672
673
    Returns
674
    -------
675
    None.
676
677
    """
678
679
    sources = config.datasets()["chp_location"]["sources"]
680
681
    db.execute_sql(
682
        f"""
683
        DELETE FROM {EgonChp.__table__.schema}.{EgonChp.__table__.name}
684
        WHERE scenario = 'eGon100RE'
685
        """
686
    )
687
688
    # select target values from pypsa-eur-sec
689
    additional_capacity = db.select_dataframe(
690
        """
691
        SELECT capacity
692
        FROM supply.egon_scenario_capacities
693
        WHERE scenario_name = 'eGon100RE'
694
        AND carrier = 'urban_central_gas_CHP'
695
        """
696
    ).capacity[0]
697
698
    if config.settings()["egon-data"]["--dataset-boundary"] != "Everything":
699
        additional_capacity /= 16
700
    target_file = (
701
        Path(".")
702
        / "data_bundle_egon_data"
703
        / "pypsa_eur_sec"
704
        / "2022-07-26-egondata-integration"
705
        / "postnetworks"
706
        / "elec_s_37_lv2.0__Co2L0-1H-T-H-B-I-dist1_2050.nc"
707
    )
708
709
    network = pypsa.Network(str(target_file))
710
    chp_index = "DE0 0 urban central gas CHP"
711
712
    standard_chp_th = 10
713
    standard_chp_el = (
714
        standard_chp_th
715
        * network.links.loc[chp_index, "efficiency"]
716
        / network.links.loc[chp_index, "efficiency2"]
717
    )
718
719
    areas = db.select_geodataframe(
720
        f"""
721
            SELECT
722
            residential_and_service_demand as demand, area_id,
723
            ST_Transform(ST_PointOnSurface(geom_polygon), 4326)  as geom
724
            FROM
725
            {sources['district_heating_areas']['schema']}.
726
            {sources['district_heating_areas']['table']}
727
            WHERE scenario = 'eGon100RE'
728
            """
729
    )
730
731
    existing_chp = pd.DataFrame(
732
        data={
733
            "el_capacity": standard_chp_el,
734
            "th_capacity": standard_chp_th,
735
            "voltage_level": 5,
736
        },
737
        index=range(1),
738
    )
739
740
    flh = (
741
        network.links_t.p0[chp_index].sum()
742
        / network.links.p_nom_opt[chp_index]
743
    )
744
745
    extension_to_areas(
746
        areas,
747
        additional_capacity,
748
        existing_chp,
749
        flh,
750
        EgonChp,
751
        district_heating=True,
752
        scenario="eGon100RE",
753
    )
754
755
756
tasks = (create_tables,)
757
758
insert_per_scenario = set()
759
760
if "status2019" in config.settings()["egon-data"]["--scenarios"]:
761
    insert_per_scenario.add(
762
        wrapped_partial(insert_chp_statusquo, scn="status2019", postfix="_2019")
763
    )
764
765
if "status2023" in config.settings()["egon-data"]["--scenarios"]:
766
    insert_per_scenario.add(
767
        wrapped_partial(insert_chp_statusquo, scn="status2023", postfix="_2023")
768
    )
769
770
if "eGon2035" in config.settings()["egon-data"]["--scenarios"]:
771
    insert_per_scenario.add(insert_chp_egon2035)
772
773
if "eGon100RE" in config.settings()["egon-data"]["--scenarios"]:
774
    insert_per_scenario.add(insert_chp_egon100re)
775
776
tasks = tasks + (insert_per_scenario, assign_heat_bus)
777
778
extension = set()
779
780
if "eGon2035" in config.settings()["egon-data"]["--scenarios"]:
781
    # Add one task per federal state for small CHP extension
782
    if (
783
        config.settings()["egon-data"]["--dataset-boundary"]
784
        == "Schleswig-Holstein"
785
    ):
786
        extension = extension_SH
787
    else:
788
        extension = {
789
            extension_BW,
790
            extension_BY,
791
            extension_HB,
792
            extension_BB,
793
            extension_HE,
794
            extension_MV,
795
            extension_NS,
796
            extension_NW,
797
            extension_SH,
798
            extension_HH,
799
            extension_RP,
800
            extension_SL,
801
            extension_SN,
802
            extension_ST,
803
            extension_TH,
804
            extension_BE,
805
        }
806
807
if extension != set():
808
    tasks = tasks + (extension,)
809
810
tasks += (metadata,)
811
812
813
class Chp(Dataset):
814
    """
815
    Extract combined heat and power plants for each scenario
816
817
    This dataset creates combined heat and power (CHP) plants for each scenario and defines their use case.
818
    The method bases on existing CHP plants from Marktstammdatenregister. For the eGon2035 scenario,
819
    a list of CHP plans from the grid operator is used for new largescale CHP plants. CHP < 10MW are
820
    randomly distributed.
821
    Depending on the distance to a district heating grid, it is decided if the CHP is used to
822
    supply a district heating grid or used by an industrial site.
823
824
825
    *Dependencies*
826
      * :py:class:`GasAreaseGon100RE <egon.data.datasets.gas_areas.GasAreaseGon100RE>`
827
      * :py:class:`GasAreaseGon2035 <egon.data.datasets.gas_areas.GasAreaseGon2035>`
828
      * :py:class:`DistrictHeatingAreas <egon.data.datasets.district_heating_areas.DistrictHeatingAreas>`
829
      * :py:class:`IndustrialDemandCurves <egon.data.datasets.industry.IndustrialDemandCurves>`
830
      * :py:class:`OsmLanduse <egon.data.datasets.loadarea.OsmLanduse>`
831
      * :py:func:`download_mastr_data <egon.data.datasets.mastr.download_mastr_data>`
832
      * :py:func:`define_mv_grid_districts <egon.data.datasets.mv_grid_districts.define_mv_grid_districts>`
833
      * :py:class:`ScenarioCapacities <egon.data.datasets.scenario_capacities.ScenarioCapacities>`
834
835
836
    *Resulting tables*
837
      * :py:class:`supply.egon_chp_plants <egon.data.datasets.chp.EgonChp>` is created and filled
838
      * :py:class:`supply.egon_mastr_conventional_without_chp <egon.data.datasets.chp.EgonMaStRConventinalWithoutChp>` is created and filled
839
840
    """
841
842
    #:
843
    name: str = "Chp"
844
    #:
845
    version: str = "0.0.7"
846
847
    def __init__(self, dependencies):
848
        super().__init__(
849
            name=self.name,
850
            version=self.version,
851
            dependencies=dependencies,
852
            tasks=tasks,
853
        )
854