Passed
Pull Request — dev (#826)
by
unknown
01:42
created

place_buildings_with_amenities()   A

Complexity

Conditions 3

Size

Total Lines 36
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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