Completed
Push — dev ( 8582b4...82307e )
by
unknown
30s queued 19s
created

data.datasets.chp.extension_NW()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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