Passed
Pull Request — dev (#826)
by
unknown
02:14
created

data.datasets.electricity_demand_timeseries.cts_buildings   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 777
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 36
eloc 437
dl 0
loc 777
rs 9.52
c 0
b 0
f 0

14 Functions

Rating   Name   Duplication   Size   Complexity  
A place_buildings_with_amenities() 0 36 3
B create_synthetic_buildings() 0 53 6
A delete_synthetic_cts_buildings() 0 9 2
A get_peak_load_cts_buildings() 0 23 2
B calc_building_profiles() 0 34 7
A amenities_without_buildings() 0 59 2
A select_cts_buildings() 0 14 1
B cells_with_cts_demand_only() 0 64 2
A write_synthetic_buildings_to_db() 0 31 2
B cts_to_buildings() 0 115 1
A calc_building_demand_profile_share() 0 34 1
B buildings_with_amenities() 0 72 2
A calc_census_cell_share() 0 43 2
B buildings_without_amenities() 0 90 2

1 Method

Rating   Name   Duplication   Size   Complexity  
A CtsElectricityBuildings.__init__() 0 8 1
1
from geoalchemy2.shape import to_shape
2
from sqlalchemy import REAL, Column, Float, Integer, String, func
3
from sqlalchemy.ext.declarative import declarative_base
4
import geopandas as gpd
5
import pandas as pd
6
import saio
7
8
from egon.data import db
9
from egon.data.datasets import Dataset
10
from egon.data.datasets.electricity_demand import (
11
    EgonDemandRegioZensusElectricity,
12
)
13
from egon.data.datasets.electricity_demand.temporal import calc_load_curves_cts
14
from egon.data.datasets.electricity_demand_timeseries.hh_buildings import (
15
    OsmBuildingsSynthetic,
16
)
17
from egon.data.datasets.electricity_demand_timeseries.tools import (
18
    random_ints_until_sum,
19
    random_point_in_square,
20
    specific_int_until_sum,
21
    write_table_to_postgis,
22
    write_table_to_postgres,
23
)
24
from egon.data.datasets.zensus_mv_grid_districts import MapZensusGridDistricts
25
from egon.data.datasets.zensus_vg250 import DestatisZensusPopulationPerHa
26
import egon.data.config
27
28
engine = db.engine()
29
Base = declarative_base()
30
31
data_config = egon.data.config.datasets()
32
RANDOM_SEED = egon.data.config.settings()["egon-data"]["--random-seed"]
33
34
# import db tables
35
saio.register_schema("openstreetmap", engine=engine)
36
saio.register_schema("society", engine=engine)
37
saio.register_schema("demand", engine=engine)
38
saio.register_schema("boundaries", engine=engine)
39
40
41
class EgonCtsElectricityDemandBuildingShare(Base):
42
    __tablename__ = "egon_cts_electricity_demand_building_share"
43
    __table_args__ = {"schema": "demand"}
44
45
    id = Column(Integer, primary_key=True)
46
    scenario = Column(String, primary_key=True)
47
    bus_id = Column(Integer, index=True)
48
    profile_share = Column(Float)
49
50
51
class CtsPeakLoads(Base):
52
    __tablename__ = "egon_cts_peak_loads"
53
    __table_args__ = {"schema": "demand"}
54
55
    id = Column(String, primary_key=True)
56
    cts_peak_load_in_w_2035 = Column(REAL)
57
    cts_peak_load_in_w_100RE = Column(REAL)
58
59
60
def amenities_without_buildings():
61
    """
62
63
    Returns
64
    -------
65
    pd.DataFrame
66
        Table of amenities without buildings
67
68
    """
69
    from saio.openstreetmap import osm_amenities_not_in_buildings_filtered
70
71
    with db.session_scope() as session:
72
        cells_query = (
73
            session.query(
74
                DestatisZensusPopulationPerHa.id.label("zensus_population_id"),
75
                # TODO can be used for square around amenity
76
                #  (1 geom_amenity: 1 geom_building)
77
                #  not unique amenity_ids yet
78
                osm_amenities_not_in_buildings_filtered.geom_amenity,
79
                osm_amenities_not_in_buildings_filtered.egon_amenity_id,
80
                # EgonDemandRegioZensusElectricity.demand,
81
                # # TODO can be used to generate n random buildings
82
                # # (n amenities : 1 randombuilding)
83
                # func.count(
84
                #     osm_amenities_not_in_buildings_filtered.egon_amenity_id
85
                # ).label("n_amenities_inside"),
86
                # DestatisZensusPopulationPerHa.geom,
87
            )
88
            .filter(
89
                func.st_within(
90
                    osm_amenities_not_in_buildings_filtered.geom_amenity,
91
                    DestatisZensusPopulationPerHa.geom,
92
                )
93
            )
94
            .filter(
95
                DestatisZensusPopulationPerHa.id
96
                == EgonDemandRegioZensusElectricity.zensus_population_id
97
            )
98
            .filter(
99
                EgonDemandRegioZensusElectricity.sector == "service",
100
                EgonDemandRegioZensusElectricity.scenario == "eGon2035"
101
                #         ).group_by(
102
                #             EgonDemandRegioZensusElectricity.zensus_population_id,
103
                #             DestatisZensusPopulationPerHa.geom,
104
            )
105
        )
106
    # # TODO can be used to generate n random buildings
107
    # df_cells_with_amenities_not_in_buildings = gpd.read_postgis(
108
    #     cells_query.statement, cells_query.session.bind, geom_col="geom"
109
    # )
110
    #
111
112
    # # TODO can be used for square around amenity
113
    df_synthetic_buildings_for_amenities = gpd.read_postgis(
114
        cells_query.statement,
115
        cells_query.session.bind,
116
        geom_col="geom_amenity",
117
    )
118
    return df_synthetic_buildings_for_amenities
119
120
121
def place_buildings_with_amenities(df, amenities=None, max_amenities=None):
122
    """
123
    Building centers are placed randomly within census cells.
124
    The Number of buildings is derived from n_amenity_inside, the selected
125
    method and number of amenities per building.
126
    """
127
    if isinstance(max_amenities, int):
128
        # amount of amenities is randomly generated within bounds
129
        # (max_amenities, amenities per cell)
130
        df["n_amenities_inside"] = df["n_amenities_inside"].apply(
131
            random_ints_until_sum, args=[max_amenities]
132
        )
133
    if isinstance(amenities, int):
134
        # Specific amount of amenities per building
135
        df["n_amenities_inside"] = df["n_amenities_inside"].apply(
136
            specific_int_until_sum, args=[amenities]
137
        )
138
139
    # Unnest each building
140
    df = df.explode(column="n_amenities_inside")
141
142
    # building count per cell
143
    df["building_count"] = df.groupby(["zensus_population_id"]).cumcount() + 1
144
145
    # generate random synthetic buildings
146
    edge_length = 5
147
    # create random points within census cells
148
    points = random_point_in_square(geom=df["geom"], tol=edge_length / 2)
149
150
    df.reset_index(drop=True, inplace=True)
151
    # Store center of polygon
152
    df["geom_point"] = points
153
    # Drop geometry of census cell
154
    df = df.drop(columns=["geom"])
155
156
    return df
157
158
159
def create_synthetic_buildings(df, points=None, crs="EPSG:3035"):
160
    """
161
    Synthetic buildings are generated around points.
162
    """
163
164
    if isinstance(points, str) and points in df.columns:
165
        points = df[points]
166
    elif isinstance(points, gpd.GeoSeries):
167
        pass
168
    else:
169
        raise ValueError("Points are of the wrong type")
170
171
    # Create building using a square around point
172
    edge_length = 5
173
    df["geom_building"] = points.buffer(distance=edge_length / 2, cap_style=3)
174
175
    if "geom_point" not in df.columns:
176
        df["geom_point"] = df["geom_building"].centroid
177
178
    # TODO Check CRS
179
    df = gpd.GeoDataFrame(
180
        df,
181
        crs=crs,
182
        geometry="geom_building",
183
    )
184
185
    # TODO remove after implementation of egon_building_id
186
    df.rename(columns={"id": "egon_building_id"}, inplace=True)
187
188
    # get max number of building ids from synthetic residential table
189
    with db.session_scope() as session:
190
        max_synth_residential_id = session.execute(
191
            func.max(OsmBuildingsSynthetic.id)
192
        ).scalar()
193
    max_synth_residential_id = int(max_synth_residential_id)
194
195
    # create sequential ids
196
    df["egon_building_id"] = range(
197
        max_synth_residential_id + 1,
198
        max_synth_residential_id + df.shape[0] + 1,
199
    )
200
201
    df["area"] = df["geom_building"].area
202
    # set building type of synthetic building
203
    df["building"] = "cts"
204
    # TODO remove in #772
205
    df = df.rename(
206
        columns={
207
            # "zensus_population_id": "cell_id",
208
            "egon_building_id": "id",
209
        }
210
    )
211
    return df
212
213
214
def buildings_with_amenities():
215
    """"""
216
217
    from saio.boundaries import egon_map_zensus_buildings_filtered_all
218
    from saio.openstreetmap import osm_buildings_filtered_with_amenities
219
220
    with db.session_scope() as session:
221
        cells_query = (
222
            session.query(
223
                osm_buildings_filtered_with_amenities.id.label(
224
                    "egon_building_id"
225
                ),
226
                osm_buildings_filtered_with_amenities.building,
227
                osm_buildings_filtered_with_amenities.n_amenities_inside,
228
                osm_buildings_filtered_with_amenities.area,
229
                osm_buildings_filtered_with_amenities.geom_building,
230
                osm_buildings_filtered_with_amenities.geom_point,
231
                egon_map_zensus_buildings_filtered_all.zensus_population_id,
232
            )
233
            .filter(
234
                osm_buildings_filtered_with_amenities.id
235
                == egon_map_zensus_buildings_filtered_all.id
236
            )
237
            .filter(
238
                EgonDemandRegioZensusElectricity.zensus_population_id
239
                == egon_map_zensus_buildings_filtered_all.zensus_population_id
240
            )
241
            .filter(
242
                EgonDemandRegioZensusElectricity.sector == "service",
243
                EgonDemandRegioZensusElectricity.scenario == "eGon2035",
244
            )
245
        )
246
    df_amenities_in_buildings = pd.read_sql(
247
        cells_query.statement, cells_query.session.bind, index_col=None
248
    )
249
250
    # TODO necessary?
251
    df_amenities_in_buildings["geom_building"] = df_amenities_in_buildings[
252
        "geom_building"
253
    ].apply(to_shape)
254
    df_amenities_in_buildings["geom_point"] = df_amenities_in_buildings[
255
        "geom_point"
256
    ].apply(to_shape)
257
258
    # # Count amenities per building
259
    # df_amenities_in_buildings["n_amenities_inside"] = 1
260
    # df_amenities_in_buildings[
261
    #     "n_amenities_inside"
262
    # ] = df_amenities_in_buildings.groupby("egon_building_id")[
263
    #     "n_amenities_inside"
264
    # ].transform(
265
    #     "sum"
266
    # )
267
268
    # # Only keep one building for multiple amenities
269
    # df_amenities_in_buildings = df_amenities_in_buildings.drop_duplicates(
270
    #     "egon_building_id"
271
    # )
272
    # df_amenities_in_buildings["building"] = "cts"
273
    # TODO maybe remove later
274
    df_amenities_in_buildings.sort_values("egon_building_id").reset_index(
275
        drop=True, inplace=True
276
    )
277
    df_amenities_in_buildings.rename(
278
        columns={
279
            # "zensus_population_id": "cell_id",
280
            "egon_building_id": "id"
281
        },
282
        inplace=True,
283
    )
284
285
    return df_amenities_in_buildings
286
287
288
# TODO maybe replace with tools.write_table_to_db
289
def write_synthetic_buildings_to_db(df_synthetic_buildings):
290
    """"""
291
    if "geom_point" not in df_synthetic_buildings.columns:
292
        df_synthetic_buildings["geom_point"] = df_synthetic_buildings[
293
            "geom_building"
294
        ].centroid
295
296
    df_synthetic_buildings = df_synthetic_buildings.rename(
297
        columns={
298
            "zensus_population_id": "cell_id",
299
            "egon_building_id": "id",
300
        }
301
    )
302
    # Only take existing columns
303
    columns = [
304
        column.key for column in OsmBuildingsSynthetic.__table__.columns
305
    ]
306
    df_synthetic_buildings = df_synthetic_buildings.loc[:, columns]
307
308
    dtypes = {
309
        i: OsmBuildingsSynthetic.__table__.columns[i].type
310
        for i in OsmBuildingsSynthetic.__table__.columns.keys()
311
    }
312
313
    # Write new buildings incl coord into db
314
    df_synthetic_buildings.to_postgis(
315
        name=OsmBuildingsSynthetic.__tablename__,
316
        con=engine,
317
        if_exists="append",
318
        schema=OsmBuildingsSynthetic.__table_args__["schema"],
319
        dtype=dtypes,
320
    )
321
322
323
def buildings_without_amenities():
324
    """ """
325
    from saio.boundaries import egon_map_zensus_buildings_filtered_all
326
    from saio.openstreetmap import (
327
        osm_amenities_shops_filtered,
328
        osm_buildings_filtered,
329
        osm_buildings_synthetic,
330
    )
331
332
    # buildings_filtered in cts-demand-cells without amenities
333
    with db.session_scope() as session:
334
335
        # Synthetic Buildings
336
        q_synth_buildings = session.query(
337
            osm_buildings_synthetic.cell_id.cast(Integer).label(
338
                "zensus_population_id"
339
            ),
340
            osm_buildings_synthetic.id.cast(Integer).label("id"),
341
            osm_buildings_synthetic.area.label("area"),
342
            osm_buildings_synthetic.geom_building.label("geom_building"),
343
            osm_buildings_synthetic.geom_point.label("geom_point"),
344
        )
345
346
        # Buildings filtered
347
        q_buildings_filtered = session.query(
348
            egon_map_zensus_buildings_filtered_all.zensus_population_id,
349
            osm_buildings_filtered.id,
350
            osm_buildings_filtered.area,
351
            osm_buildings_filtered.geom_building,
352
            osm_buildings_filtered.geom_point,
353
        ).filter(
354
            osm_buildings_filtered.id
355
            == egon_map_zensus_buildings_filtered_all.id
356
        )
357
358
        # Amenities + zensus_population_id
359
        q_amenities = (
360
            session.query(
361
                DestatisZensusPopulationPerHa.id.label("zensus_population_id"),
362
            )
363
            .filter(
364
                func.st_within(
365
                    osm_amenities_shops_filtered.geom_amenity,
366
                    DestatisZensusPopulationPerHa.geom,
367
                )
368
            )
369
            .distinct(DestatisZensusPopulationPerHa.id)
370
        )
371
372
        # Cells with CTS demand but without amenities
373
        q_cts_without_amenities = (
374
            session.query(
375
                EgonDemandRegioZensusElectricity.zensus_population_id,
376
            )
377
            .filter(
378
                EgonDemandRegioZensusElectricity.sector == "service",
379
                EgonDemandRegioZensusElectricity.scenario == "eGon2035",
380
            )
381
            .filter(
382
                EgonDemandRegioZensusElectricity.zensus_population_id.notin_(
383
                    q_amenities
384
                )
385
            )
386
            .distinct()
387
        )
388
389
        # Buildings filtered + synthetic buildings residential in
390
        # cells with CTS demand but without amenities
391
        cells_query = q_synth_buildings.union(q_buildings_filtered).filter(
392
            egon_map_zensus_buildings_filtered_all.zensus_population_id.in_(
393
                q_cts_without_amenities
394
            )
395
        )
396
397
    # df_buildings_without_amenities = pd.read_sql(
398
    #     cells_query.statement, cells_query.session.bind, index_col=None)
399
    df_buildings_without_amenities = gpd.read_postgis(
400
        cells_query.statement,
401
        cells_query.session.bind,
402
        geom_col="geom_building",
403
    )
404
405
    df_buildings_without_amenities = df_buildings_without_amenities.rename(
406
        columns={
407
            # "zensus_population_id": "cell_id",
408
            "egon_building_id": "id",
409
        }
410
    )
411
412
    return df_buildings_without_amenities
413
414
415
def select_cts_buildings(df_buildings_wo_amenities):
416
    """ """
417
    # TODO Adapt method
418
    # Select one building each cell
419
    # take the first
420
    df_buildings_with_cts_demand = df_buildings_wo_amenities.drop_duplicates(
421
        # subset="cell_id", keep="first"
422
        subset="zensus_population_id",
423
        keep="first",
424
    ).reset_index(drop=True)
425
    df_buildings_with_cts_demand["n_amenities_inside"] = 1
426
    df_buildings_with_cts_demand["building"] = "cts"
427
428
    return df_buildings_with_cts_demand
429
430
431
def cells_with_cts_demand_only(df_buildings_without_amenities):
432
    """"""
433
    from saio.openstreetmap import osm_amenities_shops_filtered
434
435
    # cells mit amenities
436
    with db.session_scope() as session:
437
        sub_query = (
438
            session.query(
439
                DestatisZensusPopulationPerHa.id.label("zensus_population_id"),
440
            )
441
            .filter(
442
                func.st_within(
443
                    osm_amenities_shops_filtered.geom_amenity,
444
                    DestatisZensusPopulationPerHa.geom,
445
                )
446
            )
447
            .distinct(DestatisZensusPopulationPerHa.id)
448
        )
449
450
        cells_query = (
451
            session.query(
452
                EgonDemandRegioZensusElectricity.zensus_population_id,
453
                EgonDemandRegioZensusElectricity.scenario,
454
                EgonDemandRegioZensusElectricity.sector,
455
                EgonDemandRegioZensusElectricity.demand,
456
                DestatisZensusPopulationPerHa.geom,
457
            )
458
            .filter(
459
                EgonDemandRegioZensusElectricity.sector == "service",
460
                EgonDemandRegioZensusElectricity.scenario == "eGon2035",
461
            )
462
            .filter(
463
                EgonDemandRegioZensusElectricity.zensus_population_id.notin_(
464
                    sub_query
465
                )
466
            )
467
            .filter(
468
                EgonDemandRegioZensusElectricity.zensus_population_id
469
                == DestatisZensusPopulationPerHa.id
470
            )
471
        )
472
473
    df_cts_cell_without_amenities = gpd.read_postgis(
474
        cells_query.statement,
475
        cells_query.session.bind,
476
        geom_col="geom",
477
        index_col=None,
478
    )
479
480
    # TODO maybe remove
481
    df_buildings_without_amenities = df_buildings_without_amenities.rename(
482
        columns={"cell_id": "zensus_population_id"}
483
    )
484
485
    # Census cells with only cts demand
486
    df_cells_only_cts_demand = df_cts_cell_without_amenities.loc[
487
        ~df_cts_cell_without_amenities["zensus_population_id"].isin(
488
            df_buildings_without_amenities["zensus_population_id"].unique()
489
        )
490
    ]
491
492
    df_cells_only_cts_demand.reset_index(drop=True, inplace=True)
493
494
    return df_cells_only_cts_demand
495
496
497
def calc_census_cell_share(scenario="eGon2035"):
498
    """"""
499
500
    with db.session_scope() as session:
501
        cells_query = (
502
            session.query(
503
                EgonDemandRegioZensusElectricity, MapZensusGridDistricts.bus_id
504
            )
505
            .filter(EgonDemandRegioZensusElectricity.sector == "service")
506
            .filter(EgonDemandRegioZensusElectricity.scenario == scenario)
507
            .filter(
508
                EgonDemandRegioZensusElectricity.zensus_population_id
509
                == MapZensusGridDistricts.zensus_population_id
510
            )
511
        )
512
513
    df_demand_regio_electricity_demand = pd.read_sql(
514
        cells_query.statement,
515
        cells_query.session.bind,
516
        index_col="zensus_population_id",
517
    )
518
519
    # get demand share of cell per bus
520
    # share ist für scenarios identisch
521
    df_census_share = df_demand_regio_electricity_demand[
522
        "demand"
523
    ] / df_demand_regio_electricity_demand.groupby("bus_id")[
524
        "demand"
525
    ].transform(
526
        "sum"
527
    )
528
    df_census_share = df_census_share.rename("cell_share")
529
530
    df_census_share = pd.concat(
531
        [
532
            df_census_share,
533
            df_demand_regio_electricity_demand[["bus_id", "scenario"]],
534
        ],
535
        axis=1,
536
    )
537
538
    df_census_share.reset_index(inplace=True)
539
    return df_census_share
540
541
542
def calc_building_demand_profile_share(df_cts_buildings, scenario="eGon2035"):
543
    """
544
    Share of cts electricity demand profile per bus for every selected building
545
    """
546
547
    def calc_building_amenity_share(df_cts_buildings):
548
        """"""
549
        df_building_amenity_share = 1 / df_cts_buildings.groupby(
550
            "zensus_population_id"
551
        )["n_amenities_inside"].transform("sum")
552
        df_building_amenity_share = pd.concat(
553
            [
554
                df_building_amenity_share.rename("building_amenity_share"),
555
                df_cts_buildings[["zensus_population_id", "id"]],
556
            ],
557
            axis=1,
558
        )
559
        return df_building_amenity_share
560
561
    df_building_amenity_share = calc_building_amenity_share(df_cts_buildings)
562
563
    df_census_cell_share = calc_census_cell_share(scenario)
564
565
    df_demand_share = pd.merge(
566
        left=df_building_amenity_share,
567
        right=df_census_cell_share,
568
        left_on="zensus_population_id",
569
        right_on="zensus_population_id",
570
    )
571
    df_demand_share["profile_share"] = df_demand_share[
572
        "building_amenity_share"
573
    ].multiply(df_demand_share["cell_share"])
574
575
    return df_demand_share[["id", "bus_id", "scenario", "profile_share"]]
576
577
578
def calc_building_profiles(
579
    df_demand_share=None, egon_building_id=None, scenario="eGon2035"
580
):
581
    """"""
582
583
    if not isinstance(df_demand_share, pd.DataFrame):
584
        with db.session_scope() as session:
585
            cells_query = session.query(EgonCtsElectricityDemandBuildingShare)
586
587
        df_demand_share = pd.read_sql(
588
            cells_query.statement, cells_query.session.bind, index_col=None
589
        )
590
591
    df_cts_profiles = calc_load_curves_cts(scenario)
592
593
    # Only calculate selected building profile if egon_building_id is given
594
    if (
595
        isinstance(egon_building_id, int)
596
        and egon_building_id in df_demand_share["id"]
597
    ):
598
        df_demand_share = df_demand_share.loc[
599
            df_demand_share["id"] == egon_building_id
600
        ]
601
602
    df_building_profiles = pd.DataFrame()
603
    for bus_id, df in df_demand_share.groupby("bus_id"):
604
        shares = df.set_index("id", drop=True)["profile_share"]
605
        profile = df_cts_profiles.loc[:, bus_id]
606
        building_profiles = profile.apply(lambda x: x * shares)
0 ignored issues
show
introduced by
The variable shares does not seem to be defined in case the for loop on line 603 is not entered. Are you sure this can never be the case?
Loading history...
607
        df_building_profiles = pd.concat(
608
            [df_building_profiles, building_profiles], axis=1
609
        )
610
611
    return df_building_profiles
612
613
614
def cts_to_buildings():
615
    """"""
616
    # Buildings with amenities
617
    df_buildings_with_amenities = buildings_with_amenities()
618
619
    # Remove synthetic CTS buildings if existing
620
    delete_synthetic_cts_buildings()
621
    # Create synthetic buildings for amenites without buildings
622
    df_amenities_without_buildings = amenities_without_buildings()
623
    df_amenities_without_buildings["n_amenities_inside"] = 1
624
    df_synthetic_buildings_with_amenities = create_synthetic_buildings(
625
        df_amenities_without_buildings, points="geom_amenity"
626
    )
627
628
    # TODO write to DB and remove renaming
629
    # write_synthetic_buildings_to_db(df_synthetic_buildings_with_amenities)
630
    write_table_to_postgis(
631
        df_synthetic_buildings_with_amenities.rename(
632
            columns={
633
                "zensus_population_id": "cell_id",
634
                "egon_building_id": "id",
635
            }
636
        ),
637
        OsmBuildingsSynthetic,
638
        drop=False,
639
    )
640
641
    # Cells without amenities but CTS demand and buildings
642
    df_buildings_without_amenities = buildings_without_amenities()
643
644
    # TODO Fix Adhoc Bugfix duplicated buildings
645
    mask = df_buildings_without_amenities.loc[
646
        df_buildings_without_amenities["id"].isin(
647
            df_buildings_with_amenities["id"]
648
        )
649
    ].index
650
    df_buildings_without_amenities = df_buildings_without_amenities.drop(
651
        index=mask
652
    ).reset_index(drop=True)
653
654
    df_buildings_without_amenities = select_cts_buildings(
655
        df_buildings_without_amenities
656
    )
657
    df_buildings_without_amenities["n_amenities_inside"] = 1
658
659
    # Create synthetic amenities and buildings in cells with only CTS demand
660
    df_cells_with_cts_demand_only = cells_with_cts_demand_only(
661
        df_buildings_without_amenities
662
    )
663
    # Only 1 Amenity per cell
664
    df_cells_with_cts_demand_only["n_amenities_inside"] = 1
665
    # Only 1 Amenity per Building
666
    df_cells_with_cts_demand_only = place_buildings_with_amenities(
667
        df_cells_with_cts_demand_only, amenities=1
668
    )
669
    # Leads to only 1 building per cell
670
    df_synthetic_buildings_without_amenities = create_synthetic_buildings(
671
        df_cells_with_cts_demand_only, points="geom_point"
672
    )
673
674
    # TODO write to DB and remove renaming
675
    # write_synthetic_buildings_to_db(df_synthetic_buildings_without_amenities)
676
    write_table_to_postgis(
677
        df_synthetic_buildings_without_amenities.rename(
678
            columns={
679
                "zensus_population_id": "cell_id",
680
                "egon_building_id": "id",
681
            }
682
        ),
683
        OsmBuildingsSynthetic,
684
        drop=False,
685
    )
686
687
    # Concat all buildings
688
    columns = [
689
        "zensus_population_id",
690
        "id",
691
        "geom_building",
692
        "n_amenities_inside",
693
    ]
694
    df_cts_buildings = pd.concat(
695
        [
696
            df_buildings_with_amenities[columns],
697
            df_synthetic_buildings_with_amenities[columns],
698
            df_buildings_without_amenities[columns],
699
            df_synthetic_buildings_without_amenities[columns],
700
        ],
701
        axis=0,
702
        ignore_index=True,
703
    )
704
    # TODO maybe remove after #772
705
    df_cts_buildings["id"] = df_cts_buildings["id"].astype(int)
706
707
    df_demand_share_2035 = calc_building_demand_profile_share(
708
        df_cts_buildings, scenario="eGon2035"
709
    )
710
    df_demand_share_100RE = calc_building_demand_profile_share(
711
        df_cts_buildings, scenario="eGon100RE"
712
    )
713
714
    df_demand_share = pd.concat(
715
        [df_demand_share_2035, df_demand_share_100RE],
716
        axis=0,
717
        ignore_index=True,
718
    )
719
720
    # TODO Why are there nonunique ids?
721
    #  needs to be removed as soon as 'id' is unique
722
    df_demand_share = df_demand_share.drop_duplicates(subset="id")
723
724
    write_table_to_postgres(
725
        df_demand_share, EgonCtsElectricityDemandBuildingShare, drop=True
726
    )
727
728
    return df_cts_buildings, df_demand_share
729
730
731
def get_peak_load_cts_buildings():
732
733
    # TODO Check units, maybe MwH?
734
    df_building_profiles = calc_building_profiles(scenario="eGon2035")
735
    df_peak_load_2035 = df_building_profiles.max(axis=0).rename(
736
        "cts_peak_load_in_w_2035"
737
    )
738
    df_building_profiles = calc_building_profiles(scenario="eGon2035")
739
    df_peak_load_100RE = df_building_profiles.max(axis=0).rename(
740
        "cts_peak_load_in_w_100RE"
741
    )
742
    df_peak_load = pd.concat(
743
        [df_peak_load_2035, df_peak_load_100RE], axis=1
744
    ).reset_index()
745
746
    CtsPeakLoads.__table__.drop(bind=engine, checkfirst=True)
747
    CtsPeakLoads.__table__.create(bind=engine, checkfirst=True)
748
749
    # Write peak loads into db
750
    with db.session_scope() as session:
751
        session.bulk_insert_mappings(
752
            CtsPeakLoads,
753
            df_peak_load.to_dict(orient="records"),
754
        )
755
756
757
def delete_synthetic_cts_buildings():
758
    # import db tables
759
    from saio.openstreetmap import osm_buildings_synthetic
760
761
    # cells mit amenities
762
    with db.session_scope() as session:
763
        session.query(osm_buildings_synthetic).filter(
764
            osm_buildings_synthetic.building == "cts"
765
        ).delete()
766
767
768
class CtsElectricityBuildings(Dataset):
769
    def __init__(self, dependencies):
770
        super().__init__(
771
            name="CtsElectricityBuildings",
772
            version="0.0.0.",
773
            dependencies=dependencies,
774
            tasks=(
775
                cts_to_buildings,
776
                get_peak_load_cts_buildings,
777
                # get_all_cts_building_profiles,
778
            ),
779
        )
780