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

data.datasets.storages.create_tables()   A

Complexity

Conditions 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nop 0
dl 0
loc 17
rs 10
c 0
b 0
f 0
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 sqlalchemy import BigInteger, Column, Float, Integer, Sequence, String
8
from sqlalchemy.dialects.postgresql import JSONB
9
from sqlalchemy.ext.declarative import declarative_base
10
from sqlalchemy.orm import sessionmaker
11
import geopandas as gpd
12
import pandas as pd
13
14
from egon.data import config, db
15
from egon.data.datasets import Dataset
16
from egon.data.datasets.scenario_parameters import get_sector_parameters
17
from egon.data.datasets.electrical_neighbours import entsoe_to_bus_etrago
18
from egon.data.datasets.mastr import (
19
    WORKING_DIR_MASTR_NEW,
20
    WORKING_DIR_MASTR_OLD,
21
)
22
from egon.data.datasets.mv_grid_districts import Vg250GemClean
23
from egon.data.datasets.power_plants import assign_bus_id, assign_voltage_level
24
from egon.data.datasets.storages.home_batteries import (
25
    allocate_home_batteries_to_buildings,
26
)
27
from egon.data.datasets.storages.pumped_hydro import (
28
    apply_voltage_level_thresholds,
29
    get_location,
30
    match_storage_units,
31
    select_mastr_pumped_hydro,
32
    select_nep_pumped_hydro,
33
)
34
from egon.data.db import session_scope
35
36
Base = declarative_base()
37
38
39 View Code Duplication
class EgonStorages(Base):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
40
    __tablename__ = "egon_storages"
41
    __table_args__ = {"schema": "supply"}
42
    id = Column(BigInteger, Sequence("storage_seq"), primary_key=True)
43
    sources = Column(JSONB)
44
    source_id = Column(JSONB)
45
    carrier = Column(String)
46
    el_capacity = Column(Float)
47
    bus_id = Column(Integer)
48
    voltage_level = Column(Integer)
49
    scenario = Column(String)
50
    geom = Column(Geometry("POINT", 4326))
51
52
53
class Storages(Dataset):
54
    """
55
    Allocates storage units such as pumped hydro and home batteries
56
57
    This data set creates interim tables to store information on storage units.
58
    In addition the target value for the installed capacity of pumped hydro
59
    storage units are spatially allocated using information of existing plants
60
    from the official registry Markstammdatenregister. After allocating the
61
    plants missing information such as the voltage level and the correct grid
62
    connection point are added.
63
    This data set also allocates the target value of home batteries spatially
64
    on different aggregation levels. In a first step function
65
    :py:func:`allocate_pv_home_batteries_to_grids` spatially distributes the
66
    installed battery capacities to all mv grid districts based on their
67
    installed pv rooftop capacity.
68
    Function :py:func:`allocate_home_batteries_to_buildings` further
69
    distributes the home battery storage systems to buildings with pv
70
    rooftop systems.
71
72
    *Dependencies*
73
      * :py:func:`download_mastr_data <egon.data.datasets.mastr.download_mastr_data>`
74
      * :py:func:`define_mv_grid_districts <egon.data.datasets.mv_grid_districts.define_mv_grid_districts>`
75
      * :py:class: `PowerPlants <egon.data.datasets.power_plants.PowerPlants>`
76
      * :py:class:`ScenarioCapacities <egon.data.datasets.scenario_capacities.ScenarioCapacities>`
77
      * :py:class:`ScenarioParameters <egon.data.datasets.scenario_parameters.ScenarioParameters>`
78
      * :py:class:`Vg250MvGridDistricts <egon.data.datasets.vg250_mv_grid_districts.Vg250MvGridDistricts>`
79
80
    *Resulting tables*
81
      * :py:class:`supply.egon_storages <egon.data.datasets.storages.EgonStorages>`
82
83
    """
84
85
    #:
86
    name: str = "Storages"
87
    #:
88
    version: str = "0.0.8"
89
90
    def __init__(self, dependencies):
91
        super().__init__(
92
            name=self.name,
93
            version=self.version,
94
            dependencies=dependencies,
95
            tasks=(
96
                create_tables,
97
                allocate_pumped_hydro_scn,
98
                allocate_other_storage_units,
99
                allocate_pv_home_batteries_to_grids,
100
                allocate_home_batteries_to_buildings,
101
            ),
102
        )
103
104
105
def create_tables():
106
    """Create tables for power plant data
107
    Returns
108
    -------
109
    None.
110
    """
111
112
    cfg = config.datasets()["storages"]
113
    db.execute_sql(f"CREATE SCHEMA IF NOT EXISTS {cfg['target']['schema']};")
114
    engine = db.engine()
115
    db.execute_sql(
116
        f"""DROP TABLE IF EXISTS
117
        {cfg['target']['schema']}.{cfg['target']['table']}"""
118
    )
119
120
    db.execute_sql("""DROP SEQUENCE IF EXISTS pp_seq""")
121
    EgonStorages.__table__.create(bind=engine, checkfirst=True)
122
123
124
def allocate_pumped_hydro(scn, export=True):
125
    """Allocates pumped_hydro plants for eGon2035 and scenario2019 scenarios
126
    and either exports results to data base or returns as a dataframe
127
128
    Parameters
129
    ----------
130
    export : bool
131
        Choose if allocated pumped hydro plants should be exported to the data
132
        base. The default is True.
133
        If export=False a data frame will be returned
134
135
    Returns
136
    -------
137
    power_plants : pandas.DataFrame
138
        List of pumped hydro plants in 'eGon2035' and 'scenario2019' scenarios
139
    """
140
141
    carrier = "pumped_hydro"
142
143
    cfg = config.datasets()["power_plants"]
144
145
    nep = select_nep_pumped_hydro(scn=scn)
146
    mastr = select_mastr_pumped_hydro()
147
148
    # Assign voltage level to MaStR
149
    mastr["voltage_level"] = assign_voltage_level(
150
        mastr.rename({"el_capacity": "Nettonennleistung"}, axis=1),
151
        cfg,
152
        WORKING_DIR_MASTR_OLD,
153
    )
154
155
    # Initalize DataFrame for matching power plants
156
    matched = gpd.GeoDataFrame(
157
        columns=[
158
            "carrier",
159
            "el_capacity",
160
            "scenario",
161
            "geometry",
162
            "MaStRNummer",
163
            "source",
164
            "voltage_level",
165
        ]
166
    )
167
168
    # Match pumped_hydro units from NEP list
169
    # using PLZ and capacity
170
    matched, mastr, nep = match_storage_units(
171
        nep,
172
        mastr,
173
        matched,
174
        buffer_capacity=0.1,
175
        consider_carrier=False,
176
        scn=scn,
177
    )
178
179
    # Match plants from NEP list using plz,
180
    # neglecting the capacity
181
    matched, mastr, nep = match_storage_units(
182
        nep,
183
        mastr,
184
        matched,
185
        consider_location="plz",
186
        consider_carrier=False,
187
        consider_capacity=False,
188
        scn=scn,
189
    )
190
191
    # Match plants from NEP list using city,
192
    # neglecting the capacity
193
    matched, mastr, nep = match_storage_units(
194
        nep,
195
        mastr,
196
        matched,
197
        consider_location="city",
198
        consider_carrier=False,
199
        consider_capacity=False,
200
        scn=scn,
201
    )
202
203
    # Match remaining plants from NEP using the federal state
204
    matched, mastr, nep = match_storage_units(
205
        nep,
206
        mastr,
207
        matched,
208
        buffer_capacity=0.1,
209
        consider_location="federal_state",
210
        consider_carrier=False,
211
        scn=scn,
212
    )
213
214
    # Match remaining plants from NEP using the federal state
215
    matched, mastr, nep = match_storage_units(
216
        nep,
217
        mastr,
218
        matched,
219
        buffer_capacity=0.7,
220
        consider_location="federal_state",
221
        consider_carrier=False,
222
        scn=scn,
223
    )
224
225
    print(f"{matched.el_capacity.sum()} MW of {carrier} matched")
226
    print(f"{nep.elec_capacity.sum()} MW of {carrier} not matched")
227
228
    if nep.elec_capacity.sum() > 0:
229
        # Get location using geolocator and city information
230
        located, unmatched = get_location(nep)
231
232
        # Bring both dataframes together
233
        matched = pd.concat(
234
            [
235
                matched,
236
                located[
237
                    [
238
                        "carrier",
239
                        "el_capacity",
240
                        "scenario",
241
                        "geometry",
242
                        "source",
243
                        "MaStRNummer",
244
                    ]
245
                ],
246
            ],
247
            ignore_index=True,
248
        )
249
250
    # Set CRS
251
    matched.crs = "EPSG:4326"
252
253
    # Assign voltage level
254
    matched = apply_voltage_level_thresholds(matched)
255
256
    # Assign bus_id
257
    # Load grid district polygons
258
    mv_grid_districts = db.select_geodataframe(
259
        f"""
260
    SELECT * FROM {cfg['sources']['egon_mv_grid_district']}
261
    """,
262
        epsg=4326,
263
    )
264
265
    ehv_grid_districts = db.select_geodataframe(
266
        f"""
267
    SELECT * FROM {cfg['sources']['ehv_voronoi']}
268
    """,
269
        epsg=4326,
270
    )
271
272
    # Perform spatial joins for plants in ehv and hv level seperately
273
    power_plants_hv = gpd.sjoin(
274
        matched[matched.voltage_level >= 3],
275
        mv_grid_districts[["bus_id", "geom"]],
276
        how="left",
277
    ).drop(columns=["index_right"])
278
    power_plants_ehv = gpd.sjoin(
279
        matched[matched.voltage_level < 3],
280
        ehv_grid_districts[["bus_id", "geom"]],
281
        how="left",
282
    ).drop(columns=["index_right"])
283
284
    # Combine both dataframes
285
    power_plants = pd.concat([power_plants_hv, power_plants_ehv])
286
287
    # Delete existing units in the target table
288
    db.execute_sql(
289
        f""" DELETE FROM {cfg ['sources']['storages']}
290
        WHERE carrier IN ('pumped_hydro')
291
        AND scenario='{scn}';"""
292
    )
293
294
    # If export = True export pumped_hydro plants to data base
295
296
    if export:
297
        # Insert into target table
298
        with session_scope() as session:
299
            for i, row in power_plants.iterrows():
300
                entry = EgonStorages(
301
                    sources={"el_capacity": row.source},
302
                    source_id={"MastrNummer": row.MaStRNummer},
303
                    carrier=row.carrier,
304
                    el_capacity=row.el_capacity,
305
                    voltage_level=row.voltage_level,
306
                    bus_id=row.bus_id,
307
                    scenario=row.scenario,
308
                    geom=f"SRID=4326;POINT({row.geometry.x} {row.geometry.y})",
309
                )
310
                session.add(entry)
311
            session.commit()
312
313
    else:
314
        return power_plants
315
316
317
def allocate_storage_units_sq(scn_name, storage_types):
318
    """
319
    Allocate storage units by mastr data only. Capacities outside
320
    germany are assigned to foreign buses.
321
322
    Parameters
323
    ----------
324
    scn_name: str
325
        Scenario name
326
    storage_types: list
327
        contains all the required storage units carriers to be imported
328
329
    Returns
330
    -------
331
332
    """
333
    sources = config.datasets()["power_plants"]["sources"]
334
    scn_parameters = get_sector_parameters("global", scn_name)
335
    scenario_date_max = str(scn_parameters["weather_year"]) + "-12-31 23:59:00"
336
337
    map_storage = {
338
        "battery": "Batterie",
339
        "pumped_hydro": "Pumpspeicher",
340
        "compressed_air": "Druckluft",
341
        "flywheel": "Schwungrad",
342
        "other": "Sonstige",
343
    }
344
345
    for storage_type in storage_types:
346
        # Read-in data from MaStR
347
        mastr_ph = pd.read_csv(
348
            WORKING_DIR_MASTR_NEW / sources["mastr_storage"],
349
            delimiter=",",
350
            usecols=[
351
                "Nettonennleistung",
352
                "EinheitMastrNummer",
353
                "Kraftwerksnummer",
354
                "Technologie",
355
                "Postleitzahl",
356
                "Laengengrad",
357
                "Breitengrad",
358
                "EinheitBetriebsstatus",
359
                "LokationMastrNummer",
360
                "Ort",
361
                "Bundesland",
362
                "DatumEndgueltigeStilllegung",
363
                "Inbetriebnahmedatum",
364
            ],
365
            dtype={"Postleitzahl": str},
366
        )
367
368
        # Rename columns
369
        mastr_ph = mastr_ph.rename(
370
            columns={
371
                "Kraftwerksnummer": "bnetza_id",
372
                "Technologie": "carrier",
373
                "Postleitzahl": "plz",
374
                "Ort": "city",
375
                "Bundesland": "federal_state",
376
                "Nettonennleistung": "el_capacity",
377
                "DatumEndgueltigeStilllegung": "decommissioning_date",
378
            }
379
        )
380
381
        # Select only the required type of storage
382
        mastr_ph = mastr_ph.loc[mastr_ph.carrier == map_storage[storage_type]]
383
384
        # Select only storage units in operation
385
        mastr_ph.loc[
386
            mastr_ph["decommissioning_date"] > scenario_date_max,
387
            "EinheitBetriebsstatus",
388
        ] = "InBetrieb"
389
        mastr_ph = mastr_ph.loc[
390
            mastr_ph.EinheitBetriebsstatus.isin(
391
                ["InBetrieb", "VoruebergehendStillgelegt"]
392
            )
393
        ]
394
395
        # Select only storage units installed before scenario_date_max
396
        mastr_ph = mastr_ph[
397
            pd.to_datetime(mastr_ph["Inbetriebnahmedatum"]) < scenario_date_max
398
        ]
399
400
        # Calculate power in MW
401
        mastr_ph.loc[:, "el_capacity"] *= 1e-3
402
403
        # Create geodataframe from long, lat
404
        mastr_ph = gpd.GeoDataFrame(
405
            mastr_ph,
406
            geometry=gpd.points_from_xy(
407
                mastr_ph["Laengengrad"], mastr_ph["Breitengrad"]
408
            ),
409
            crs="4326",
410
        )
411
412
        # Identify pp without geocord
413
        mastr_ph_nogeo = mastr_ph.loc[mastr_ph["Laengengrad"].isna()]
414
415
        # Remove all PP without geocord
416
        mastr_ph = mastr_ph.dropna(subset="Laengengrad")
417
418
        # Get geometry of villages/cities with same name of pp with missing geocord
419
        with session_scope() as session:
420
            query = session.query(Vg250GemClean.gen, Vg250GemClean.geometry)
421
            df_cities = gpd.read_postgis(
422
                query.statement,
423
                query.session.bind,
424
                geom_col="geometry",
425
                crs="3035",
426
            )
427
428
        # Keep only useful cities
429
        df_cities = df_cities[df_cities["gen"].isin(mastr_ph_nogeo["city"])]
430
431
        # Just take the first entry, inaccuracy is negligible as centroid is taken afterwards
432
        df_cities = df_cities.drop_duplicates("gen", keep="first")
433
434
        # Use the centroid instead of polygon of region
435
        df_cities.loc[:, "geometry"] = df_cities["geometry"].centroid
436
437
        # Change coordinate system
438
        df_cities.to_crs("4326", inplace=True)
439
440
        # Add centroid geometry to pp without geometry
441
        mastr_ph_nogeo = pd.merge(
442
            left=df_cities,
443
            right=mastr_ph_nogeo,
444
            right_on="city",
445
            left_on="gen",
446
            suffixes=("", "_no-geo"),
447
            how="inner",
448
        ).drop("gen", axis=1)
449
450
        mastr_ph = pd.concat([mastr_ph, mastr_ph_nogeo], axis=0)
451
452
        # aggregate capacity per location
453
        agg_cap = mastr_ph.groupby("geometry")["el_capacity"].sum()
454
455
        # list mastr number by location
456
        agg_mastr = mastr_ph.groupby("geometry")["EinheitMastrNummer"].apply(
457
            list
458
        )
459
460
        # remove duplicates by location
461
        mastr_ph = mastr_ph.drop_duplicates(
462
            subset="geometry", keep="first"
463
        ).drop(["el_capacity", "EinheitMastrNummer"], axis=1)
464
465
        # Adjust capacity
466
        mastr_ph = pd.merge(
467
            left=mastr_ph,
468
            right=agg_cap,
469
            left_on="geometry",
470
            right_on="geometry",
471
        )
472
473
        # Adjust capacity
474
        mastr_ph = pd.merge(
475
            left=mastr_ph,
476
            right=agg_mastr,
477
            left_on="geometry",
478
            right_on="geometry",
479
        )
480
481
        # Drop small pp <= 30 kW
482
        mastr_ph = mastr_ph.loc[mastr_ph["el_capacity"] > 0.03]
483
484
        # Apply voltage level by capacity
485
        mastr_ph = apply_voltage_level_thresholds(mastr_ph)
486
        mastr_ph["voltage_level"] = mastr_ph["voltage_level"].astype(int)
487
488
        # Capacity located outside germany -> will be assigned to foreign buses
489
        mastr_ph_foreign = mastr_ph.loc[mastr_ph["federal_state"].isna()]
490
491
        # Keep only capacities within germany
492
        mastr_ph = mastr_ph.dropna(subset="federal_state")
493
494
        # Asign buses within germany
495
        mastr_ph = assign_bus_id(
496
            mastr_ph, cfg=config.datasets()["power_plants"], drop_missing=True
497
        )
498
        mastr_ph["bus_id"] = mastr_ph["bus_id"].astype(int)
499
500
        # Get foreign central buses
501
        sql = f"""
502
        SELECT * FROM grid.egon_etrago_bus
503
        WHERE scn_name = '{scn_name}'
504
        and country != 'DE'
505
        """
506
        df_foreign_buses = db.select_geodataframe(
507
            sql, geom_col="geom", epsg="4326"
508
        )
509
        central_bus = entsoe_to_bus_etrago(scn_name).to_frame()
510
        central_bus["geom"] = (
511
            df_foreign_buses.set_index("bus_id")
512
            .loc[central_bus[0], "geom"]
513
            .values
514
        )
515
        df_foreign_buses = df_foreign_buses[
516
            df_foreign_buses["geom"].isin(central_bus["geom"])
517
        ]
518
519
        if len(mastr_ph_foreign) > 0:
520
            # Assign closest bus at voltage level to foreign pp
521
            nearest_neighbors = []
522
            for vl, v_nom in {1: 380, 2: 220, 3: 110}.items():
523
                ph = mastr_ph_foreign.loc[
524
                    mastr_ph_foreign["voltage_level"] == vl
525
                ]
526
                if ph.empty:
527
                    continue
528
                bus = df_foreign_buses.loc[
529
                    df_foreign_buses["v_nom"] == v_nom,
530
                    ["v_nom", "country", "bus_id", "geom"],
531
                ]
532
                results = gpd.sjoin_nearest(
533
                    left_df=ph,
534
                    right_df=bus,
535
                    how="left",
536
                    distance_col="distance",
537
                )
538
                nearest_neighbors.append(results)
539
            mastr_ph_foreign = pd.concat(nearest_neighbors)
540
541
            # Merge foreign pp
542
            mastr_ph = pd.concat([mastr_ph, mastr_ph_foreign])
543
544
        # Reduce to necessary columns
545
        mastr_ph = mastr_ph[
546
            [
547
                "el_capacity",
548
                "voltage_level",
549
                "bus_id",
550
                "geometry",
551
                "EinheitMastrNummer",
552
            ]
553
        ]
554
555
        # Rename and format columns
556
        mastr_ph["carrier"] = storage_type
557
        mastr_ph = mastr_ph.rename(
558
            columns={"EinheitMastrNummer": "source_id", "geometry": "geom"}
559
        )
560
        mastr_ph["source_id"] = mastr_ph["source_id"].apply(
561
            lambda x: {"MastrNummer": ", ".join(x)}
562
        )
563
        mastr_ph = mastr_ph.set_geometry("geom")
564
        mastr_ph["geom"] = mastr_ph["geom"].apply(lambda x: x.wkb_hex)
565
        mastr_ph["scenario"] = scn_name
566
        mastr_ph["sources"] = [
567
            {"el_capacity": "MaStR aggregated by location"}
568
        ] * mastr_ph.shape[0]
569
570
        # Delete existing units in the target table
571
        db.execute_sql(
572
            f""" DELETE FROM supply.egon_storages
573
            WHERE carrier = '{storage_type}'
574
            AND scenario = '{scn_name}'
575
            AND sources ->> 'el_capacity' = 'MaStR aggregated by location';"""
576
        )
577
578
        with db.session_scope() as session:
579
            session.bulk_insert_mappings(
580
                EgonStorages,
581
                mastr_ph.to_dict(orient="records"),
582
            )
583
584
585
def allocate_pumped_hydro_eGon100RE():
586
    """Allocates pumped_hydro plants for eGon100RE scenario based on a
587
    prox-to-now method applied on allocated pumped-hydro plants in the eGon2035
588
    scenario.
589
590
    Parameters
591
    ----------
592
    None
593
594
    Returns
595
    -------
596
    None
597
    """
598
599
    carrier = "pumped_hydro"
600
    cfg = config.datasets()["power_plants"]
601
    boundary = config.settings()["egon-data"]["--dataset-boundary"]
602
603
    # Select installed capacity for pumped_hydro in eGon100RE scenario from
604
    # scenario capacities table
605
    capacity = db.select_dataframe(
606
        f"""
607
        SELECT capacity
608
        FROM {cfg['sources']['capacities']}
609
        WHERE carrier = '{carrier}'
610
        AND scenario_name = 'eGon100RE';
611
        """
612
    )
613
614
    if boundary == "Schleswig-Holstein":
615
        # Break capacity of pumped hydron plants down SH share in eGon2035
616
        capacity_phes = capacity.iat[0, 0] * 0.0176
617
618
    elif boundary == "Everything":
619
        # Select national capacity for pumped hydro
620
        capacity_phes = capacity.iat[0, 0]
621
622
    else:
623
        raise ValueError(f"'{boundary}' is not a valid dataset boundary.")
624
625
    # Get allocation of pumped_hydro plants in eGon2035 scenario as the
626
    # reference for the distribution in eGon100RE scenario
627
    allocation = allocate_pumped_hydro(scn="status2019", export=False)
628
629
    scaling_factor = capacity_phes / allocation.el_capacity.sum()
630
631
    power_plants = allocation.copy()
632
    power_plants["scenario"] = "eGon100RE"
633
    power_plants["el_capacity"] = allocation.el_capacity * scaling_factor
634
635
    # Insert into target table
636
    session = sessionmaker(bind=db.engine())()
637
    for i, row in power_plants.iterrows():
638
        entry = EgonStorages(
639
            sources={"el_capacity": row.source},
640
            source_id={"MastrNummer": row.MaStRNummer},
641
            carrier=row.carrier,
642
            el_capacity=row.el_capacity,
643
            voltage_level=row.voltage_level,
644
            bus_id=row.bus_id,
645
            scenario=row.scenario,
646
            geom=f"SRID=4326;POINT({row.geometry.x} {row.geometry.y})",
647
        )
648
        session.add(entry)
649
    session.commit()
650
651
652
def home_batteries_per_scenario(scenario):
653
    """Allocates home batteries which define a lower boundary for extendable
654
    battery storage units. The overall installed capacity is taken from NEP
655
    for eGon2035 scenario. The spatial distribution of installed battery
656
    capacities is based on the installed pv rooftop capacity.
657
658
    Parameters
659
    ----------
660
    None
661
662
    Returns
663
    -------
664
    None
665
    """
666
667
    cfg = config.datasets()["storages"]
668
    dataset = config.settings()["egon-data"]["--dataset-boundary"]
669
670
    if scenario == "eGon2035":
671
        target_file = (
672
            Path(".")
673
            / "data_bundle_egon_data"
674
            / "nep2035_version2021"
675
            / cfg["sources"]["nep_capacities"]
676
        )
677
678
        capacities_nep = pd.read_excel(
679
            target_file,
680
            sheet_name="1.Entwurf_NEP2035_V2021",
681
            index_col="Unnamed: 0",
682
        )
683
684
        # Select target value in MW
685
        target = capacities_nep.Summe["PV-Batteriespeicher"] * 1000
686
687
    else:
688
        target = db.select_dataframe(
689
            f"""
690
            SELECT capacity
691
            FROM {cfg['sources']['capacities']}
692
            WHERE scenario_name = '{scenario}'
693
            AND carrier = 'battery';
694
            """
695
        ).capacity[0]
696
697
    pv_rooftop = db.select_dataframe(
698
        f"""
699
        SELECT bus, p_nom, generator_id
700
        FROM {cfg['sources']['generators']}
701
        WHERE scn_name = '{scenario}'
702
        AND carrier = 'solar_rooftop'
703
        AND bus IN
704
            (SELECT bus_id FROM {cfg['sources']['bus']}
705
               WHERE scn_name = '{scenario}' AND country = 'DE' );
706
        """
707
    )
708
709
    if dataset == "Schleswig-Holstein":
710
        target = target / 16
711
712
    battery = pv_rooftop
713
    battery["p_nom_min"] = target * battery["p_nom"] / battery["p_nom"].sum()
714
    battery = battery.drop(columns=["p_nom"])
715
716
    battery["carrier"] = "home_battery"
717
    battery["scenario"] = scenario
718
719
    if (scenario == "eGon2035") | ("status" in scenario):
720
        source = "NEP"
721
722
    else:
723
        source = "p-e-s"
724
725
    battery["source"] = (
726
        f"{source} capacity allocated based in installed PV rooftop capacity"
727
    )
728
729
    # Insert into target table
730
    session = sessionmaker(bind=db.engine())()
731
    for i, row in battery.iterrows():
732
        entry = EgonStorages(
733
            sources={"el_capacity": row.source},
734
            source_id={"generator_id": row.generator_id},
735
            carrier=row.carrier,
736
            el_capacity=row.p_nom_min,
737
            bus_id=row.bus,
738
            scenario=row.scenario,
739
        )
740
        session.add(entry)
741
    session.commit()
742
743
744
def allocate_pv_home_batteries_to_grids():
745
    for scn in config.settings()["egon-data"]["--scenarios"]:
746
        home_batteries_per_scenario(scn)
747
748
749
def allocate_pumped_hydro_scn():
750
    for scn in config.settings()["egon-data"]["--scenarios"]:
751
        if scn == "eGon2035":
752
            allocate_pumped_hydro(scn="eGon2035")
753
        elif scn == "eGon100RE":
754
            allocate_pumped_hydro_eGon100RE()
755
        elif "status" in scn:
756
            allocate_storage_units_sq(scn_name=scn, storage_types=["pumped_hydro"])
757
758
759
def allocate_other_storage_units():
760
    for scn in config.settings()["egon-data"]["--scenarios"]:
761
        if "status" in scn:
762
            allocate_storage_units_sq(
763
                scn_name=scn, storage_types=["battery"]
764
            )
765