Passed
Pull Request — dev (#870)
by
unknown
01:35
created

create_timeseries_for_building()   A

Complexity

Conditions 1

Size

Total Lines 19
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 19
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
from datetime import datetime
2
from pathlib import Path
3
import os
4
5
from sqlalchemy import ARRAY, Column, Float, Integer, String, Text
6
from sqlalchemy.ext.declarative import declarative_base
7
import geopandas as gpd
8
import numpy as np
9
import pandas as pd
10
11
from egon.data import db
12
import egon.data.datasets.era5 as era
13
14
try:
15
    from disaggregator import temporal
16
except ImportError as e:
17
    pass
18
19
from math import ceil
20
21
from egon.data.datasets import Dataset
22
from egon.data.datasets.heat_demand_timeseries.daily import (
23
    daily_demand_shares_per_climate_zone,
24
    map_climate_zones_to_zensus,
25
)
26
from egon.data.datasets.heat_demand_timeseries.idp_pool import create, select
27
from egon.data.datasets.heat_demand_timeseries.service_sector import (
28
    CTS_demand_scale,
29
)
30
import egon
31
32
Base = declarative_base()
33
34
35
class EgonTimeseriesDistrictHeating(Base):
36
    __tablename__ = "egon_timeseries_district_heating"
37
    __table_args__ = {"schema": "demand"}
38
    area_id = Column(Integer, primary_key=True)
39
    scenario = Column(Text, primary_key=True)
40
    dist_aggregated_mw = Column(ARRAY(Float(53)))
41
42
43
class EgonEtragoTimeseriesIndividualHeating(Base):
44
    __tablename__ = "egon_etrago_timeseries_individual_heating"
45
    __table_args__ = {"schema": "demand"}
46
    bus_id = Column(Integer, primary_key=True)
47
    scenario = Column(Text, primary_key=True)
48
    dist_aggregated_mw = Column(ARRAY(Float(53)))
49
50
51
class EgonIndividualHeatingPeakLoads(Base):
52
    __tablename__ = "egon_individual_heating_peak_loads"
53
    __table_args__ = {"schema": "demand"}
54
    building_id = Column(Integer, primary_key=True)
55
    scenario = Column(Text, primary_key=True)
56
    w_th = Column(Float(53))
57
58
59
class EgonEtragoHeatCts(Base):
60
    __tablename__ = "egon_etrago_heat_cts"
61
    __table_args__ = {"schema": "demand"}
62
63
    bus_id = Column(Integer, primary_key=True)
64
    scn_name = Column(String, primary_key=True)
65
    p_set = Column(ARRAY(Float))
66
67
68
def create_timeseries_for_building(building_id, scenario):
69
    """Generates final heat demand timeseries for a specific building
70
71
    Parameters
72
    ----------
73
    building_id : int
74
        Index of the selected building
75
    scenario : str
76
        Name of the selected scenario.
77
78
    Returns
79
    -------
80
    pandas.DataFrame
81
        Hourly heat demand timeseries in MW for the selected building
82
83
    """
84
85
    return db.select_dataframe(
86
        f"""
87
        SELECT building_demand * UNNEST(idp) as demand
88
        FROM
89
        (
90
        SELECT demand.demand / building.count * daily_demand.daily_demand_share as building_demand, daily_demand.day_of_year
91
        FROM
92
93
        (SELECT demand FROM
94
        demand.egon_peta_heat
95
        WHERE scenario = '{scenario}'
96
        AND sector = 'residential'
97
        AND zensus_population_id IN(
98
        SELECT zensus_population_id FROM
99
        demand.egon_heat_timeseries_selected_profiles
100
        WHERE building_id  = {building_id})) as demand,
101
102
        (SELECT COUNT(building_id)
103
        FROM demand.egon_heat_timeseries_selected_profiles
104
        WHERE zensus_population_id IN(
105
        SELECT zensus_population_id FROM
106
        demand.egon_heat_timeseries_selected_profiles
107
        WHERE building_id  = {building_id})) as building,
108
109
        (SELECT daily_demand_share, day_of_year FROM
110
        demand.egon_daily_heat_demand_per_climate_zone
111
        WHERE climate_zone = (
112
            SELECT climate_zone FROM boundaries.egon_map_zensus_climate_zones
113
            WHERE zensus_population_id =
114
            (SELECT zensus_population_id FROM demand.egon_heat_timeseries_selected_profiles
115
             WHERE building_id = {building_id}))) as daily_demand) as daily_demand
116
117
        JOIN (SELECT b.idp, ordinality as day
118
        FROM demand.egon_heat_timeseries_selected_profiles a,
119
        UNNEST (a.selected_idp_profiles) WITH ORDINALITY as selected_idp
120
        JOIN demand.egon_heat_idp_pool b
121
        ON selected_idp = b.index
122
        WHERE a.building_id = {building_id}) as demand_profile
123
        ON demand_profile.day = daily_demand.day_of_year
124
        """
125
    )
126
127
128
def create_district_heating_profile(scenario, area_id):
129
    """Create heat demand profile for district heating grid including demands of
130
    households and service sector.
131
132
    Parameters
133
    ----------
134
    scenario : str
135
        Name of the selected scenario.
136
    area_id : int
137
        Index of the selected district heating grid
138
139
    Returns
140
    -------
141
    df : pandas,DataFrame
142
        Hourly heat demand timeseries in MW for the selected district heating grid
143
144
    """
145
146
    start_time = datetime.now()
147
148
    df = db.select_dataframe(
149
        f"""
150
151
        SELECT SUM(building_demand_per_hour) as demand_profile, hour_of_year
152
        FROM
153
154
        (
155
        SELECT demand.demand  *
156
        c.daily_demand_share * hourly_demand as building_demand_per_hour,
157
        ordinality + 24* (c.day_of_year-1) as hour_of_year,
158
        demand_profile.building_id,
159
        c.day_of_year,
160
        ordinality
161
162
        FROM
163
164
        (SELECT zensus_population_id, demand FROM
165
        demand.egon_peta_heat
166
        WHERE scenario = '{scenario}'
167
        AND sector = 'residential'
168
        AND zensus_population_id IN(
169
        SELECT zensus_population_id FROM
170
        demand.egon_map_zensus_district_heating_areas
171
        WHERE scenario = '{scenario}'
172
        AND area_id = {area_id}
173
        )) as demand
174
175
        JOIN boundaries.egon_map_zensus_climate_zones b
176
        ON demand.zensus_population_id = b.zensus_population_id
177
178
        JOIN demand.egon_daily_heat_demand_per_climate_zone c
179
        ON c.climate_zone = b.climate_zone
180
181
        JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id
182
        FROM demand.egon_heat_timeseries_selected_profiles d,
183
        UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp
184
        JOIN demand.egon_heat_idp_pool e
185
        ON selected_idp = e.index
186
        WHERE zensus_population_id IN (
187
        SELECT zensus_population_id FROM
188
        demand.egon_map_zensus_district_heating_areas
189
        WHERE scenario = '{scenario}'
190
        AND area_id = {area_id}
191
        ))  demand_profile
192
        ON (demand_profile.day = c.day_of_year AND
193
            demand_profile.zensus_population_id = b.zensus_population_id)
194
195
        JOIN (SELECT COUNT(building_id), zensus_population_id
196
        FROM demand.egon_heat_timeseries_selected_profiles
197
        WHERE zensus_population_id IN(
198
        SELECT zensus_population_id FROM
199
        demand.egon_heat_timeseries_selected_profiles
200
       WHERE zensus_population_id IN (
201
       SELECT zensus_population_id FROM
202
       demand.egon_map_zensus_district_heating_areas
203
       WHERE scenario = '{scenario}'
204
       AND area_id = {area_id}
205
       ))
206
		GROUP BY zensus_population_id) building
207
        ON building.zensus_population_id = b.zensus_population_id,
208
209
        UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand
210
        )   result
211
212
213
        GROUP BY hour_of_year
214
215
        """
216
    )
217
218
    print(
219
        f"Time to create time series for district heating grid {scenario} {area_id}:"
220
    )
221
    print(datetime.now() - start_time)
222
223
    return df
224
225
226
def create_district_heating_profile_python_like(scenario="eGon2035"):
227
    """Creates profiles for all district heating grids in one scenario.
228
    Similar to create_district_heating_profile but faster and needs more RAM.
229
    The results are directly written into the database.
230
231
    Parameters
232
    ----------
233
    scenario : str
234
        Name of the selected scenario.
235
236
    Returns
237
    -------
238
    None.
239
240
    """
241
242
    start_time = datetime.now()
243
244
    idp_df = db.select_dataframe(
245
        """
246
        SELECT index, idp FROM demand.egon_heat_idp_pool
247
        """,
248
        index_col="index",
249
    )
250
251
    district_heating_grids = db.select_dataframe(
252
        f"""
253
        SELECT area_id
254
        FROM demand.egon_district_heating_areas
255
        WHERE scenario = '{scenario}'
256
        """
257
    )
258
259
    annual_demand = db.select_dataframe(
260
        f"""
261
        SELECT a.zensus_population_id, demand/c.count as per_building , area_id FROM
262
        demand.egon_peta_heat a
263
        INNER JOIN (
264
            SELECT * FROM demand.egon_map_zensus_district_heating_areas
265
            WHERE scenario = '{scenario}'
266
        ) b ON a.zensus_population_id = b.zensus_population_id
267
268
        JOIN (SELECT COUNT(building_id), zensus_population_id
269
        FROM demand.egon_heat_timeseries_selected_profiles
270
        WHERE zensus_population_id IN(
271
        SELECT zensus_population_id FROM
272
        demand.egon_heat_timeseries_selected_profiles
273
        WHERE zensus_population_id IN (
274
        SELECT zensus_population_id FROM
275
        boundaries.egon_map_zensus_grid_districts
276
       ))
277
        GROUP BY zensus_population_id)c
278
        ON a.zensus_population_id = c.zensus_population_id
279
280
        WHERE a.scenario = '{scenario}'
281
        AND a.sector = 'residential'
282
283
        """,
284
        index_col="zensus_population_id",
285
    )
286
287
    daily_demand_shares = db.select_dataframe(
288
        """
289
        SELECT climate_zone, day_of_year as day, daily_demand_share FROM
290
        demand.egon_daily_heat_demand_per_climate_zone
291
        """
292
    )
293
294
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
295
        aggregation_level="district"
296
    )
297
298
    # TODO: use session_scope!
299
    from sqlalchemy.orm import sessionmaker
300
301
    session = sessionmaker(bind=db.engine())()
302
303
    print(datetime.now() - start_time)
304
305
    start_time = datetime.now()
306
    for area in district_heating_grids.area_id.unique():
307
        selected_profiles = db.select_dataframe(
308
            f"""
309
            SELECT a.zensus_population_id, building_id, c.climate_zone,
310
            selected_idp, ordinality as day, b.area_id
311
            FROM demand.egon_heat_timeseries_selected_profiles a
312
            INNER JOIN boundaries.egon_map_zensus_climate_zones c
313
            ON a.zensus_population_id = c.zensus_population_id
314
            INNER JOIN (
315
                SELECT * FROM demand.egon_map_zensus_district_heating_areas
316
                WHERE scenario = '{scenario}'
317
                AND area_id = '{area}'
318
            ) b ON a.zensus_population_id = b.zensus_population_id        ,
319
    
320
            UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
321
    
322
            """
323
        )
324
325
        if not selected_profiles.empty:
326
327
            df = pd.merge(
328
                selected_profiles,
329
                daily_demand_shares,
330
                on=["day", "climate_zone"],
331
            )
332
333
            slice_df = pd.merge(
334
                df[df.area_id == area],
335
                idp_df,
336
                left_on="selected_idp",
337
                right_on="index",
338
            )
339
340
            for hour in range(24):
341
                slice_df[hour] = (
342
                    slice_df.idp.str[hour]
343
                    .mul(slice_df.daily_demand_share)
344
                    .mul(
345
                        annual_demand.loc[
346
                            slice_df.zensus_population_id.values,
347
                            "per_building",
348
                        ].values
349
                    )
350
                )
351
352
            hh = np.concatenate(
353
                slice_df.groupby("day").sum()[range(24)].values
354
            ).ravel()
355
356
        cts = CTS_demand_dist[
357
            (CTS_demand_dist.scenario == scenario)
358
            & (CTS_demand_dist.index == area)
359
        ].drop("scenario", axis="columns")
360
361
        if (not selected_profiles.empty) and not cts.empty:
362
            entry = EgonTimeseriesDistrictHeating(
363
                area_id=int(area),
364
                scenario=scenario,
365
                dist_aggregated_mw=(hh + cts.values[0]).tolist(),
0 ignored issues
show
introduced by
The variable hh does not seem to be defined for all execution paths.
Loading history...
366
            )
367
        elif (not selected_profiles.empty) and cts.empty:
368
            entry = EgonTimeseriesDistrictHeating(
369
                area_id=int(area),
370
                scenario=scenario,
371
                dist_aggregated_mw=(hh).tolist(),
372
            )
373
        elif not cts.empty:
374
            entry = EgonTimeseriesDistrictHeating(
375
                area_id=int(area),
376
                scenario=scenario,
377
                dist_aggregated_mw=(cts.values[0]).tolist(),
378
            )
379
380
        session.add(entry)
0 ignored issues
show
introduced by
The variable entry does not seem to be defined for all execution paths.
Loading history...
381
    session.commit()
382
383
    print(
384
        f"Time to create time series for district heating scenario {scenario}"
385
    )
386
    print(datetime.now() - start_time)
387
388
389
def create_individual_heat_per_mv_grid(scenario="eGon2035", mv_grid_id=1564):
390
    start_time = datetime.now()
391
    df = db.select_dataframe(
392
        f"""
393
394
        SELECT SUM(building_demand_per_hour) as demand_profile, hour_of_year
395
        FROM
396
397
        (
398
        SELECT demand.demand  *
399
        c.daily_demand_share * hourly_demand as building_demand_per_hour,
400
        ordinality + 24* (c.day_of_year-1) as hour_of_year,
401
        demand_profile.building_id,
402
        c.day_of_year,
403
        ordinality
404
405
        FROM
406
407
        (SELECT zensus_population_id, demand FROM
408
        demand.egon_peta_heat
409
        WHERE scenario = '{scenario}'
410
        AND sector = 'residential'
411
        AND zensus_population_id IN (
412
        SELECT zensus_population_id FROM
413
        boundaries.egon_map_zensus_grid_districts
414
        WHERE bus_id = {mv_grid_id}
415
        )) as demand
416
417
        JOIN boundaries.egon_map_zensus_climate_zones b
418
        ON demand.zensus_population_id = b.zensus_population_id
419
420
        JOIN demand.egon_daily_heat_demand_per_climate_zone c
421
        ON c.climate_zone = b.climate_zone
422
423
        JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id
424
        FROM demand.egon_heat_timeseries_selected_profiles d,
425
        UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp
426
        JOIN demand.egon_heat_idp_pool e
427
        ON selected_idp = e.index
428
        WHERE zensus_population_id IN (
429
        SELECT zensus_population_id FROM
430
        boundaries.egon_map_zensus_grid_districts
431
        WHERE bus_id = {mv_grid_id}
432
        ))  demand_profile
433
        ON (demand_profile.day = c.day_of_year AND
434
            demand_profile.zensus_population_id = b.zensus_population_id)
435
436
        JOIN (SELECT COUNT(building_id), zensus_population_id
437
        FROM demand.egon_heat_timeseries_selected_profiles
438
        WHERE zensus_population_id IN(
439
        SELECT zensus_population_id FROM
440
        demand.egon_heat_timeseries_selected_profiles
441
        WHERE zensus_population_id IN (
442
        SELECT zensus_population_id FROM
443
        boundaries.egon_map_zensus_grid_districts
444
        WHERE bus_id = {mv_grid_id}
445
       ))
446
		GROUP BY zensus_population_id) building
447
        ON building.zensus_population_id = b.zensus_population_id,
448
449
        UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand
450
        )   result
451
452
453
        GROUP BY hour_of_year
454
455
        """
456
    )
457
458
    print(f"Time to create time series for mv grid {scenario} {mv_grid_id}:")
459
    print(datetime.now() - start_time)
460
461
    return df
462
463
464
def calulate_peak_load(df, scenario):
465
466
    # peat load in W_th
467
    data = (
468
        df.groupby("building_id")
469
        .max()[range(24)]
470
        .max(axis=1)
471
        .mul(1000000)
472
        .astype(int)
473
        .reset_index()
474
    )
475
476
    data["scenario"] = scenario
477
478
    data.rename({0: "w_th"}, axis="columns", inplace=True)
479
480
    data.to_sql(
481
        EgonIndividualHeatingPeakLoads.__table__.name,
482
        schema=EgonIndividualHeatingPeakLoads.__table__.schema,
483
        con=db.engine(),
484
        if_exists="append",
485
        index=False,
486
    )
487
488
489
def create_individual_heating_peak_loads(scenario="eGon2035"):
490
491
    engine = db.engine()
492
493
    EgonIndividualHeatingPeakLoads.__table__.drop(bind=engine, checkfirst=True)
494
495
    EgonIndividualHeatingPeakLoads.__table__.create(
496
        bind=engine, checkfirst=True
497
    )
498
499
    start_time = datetime.now()
500
501
    idp_df = db.select_dataframe(
502
        """
503
        SELECT index, idp FROM demand.egon_heat_idp_pool
504
        """,
505
        index_col="index",
506
    )
507
508
    annual_demand = db.select_dataframe(
509
        f"""
510
        SELECT a.zensus_population_id, demand/c.count as per_building, bus_id
511
        FROM demand.egon_peta_heat a
512
513
514
        JOIN (SELECT COUNT(building_id), zensus_population_id
515
        FROM demand.egon_heat_timeseries_selected_profiles
516
        WHERE zensus_population_id IN(
517
        SELECT zensus_population_id FROM
518
        demand.egon_heat_timeseries_selected_profiles
519
        WHERE zensus_population_id IN (
520
        SELECT zensus_population_id FROM
521
        boundaries.egon_map_zensus_grid_districts
522
       ))
523
        GROUP BY zensus_population_id)c
524
        ON a.zensus_population_id = c.zensus_population_id
525
526
        JOIN boundaries.egon_map_zensus_grid_districts d
527
        ON a.zensus_population_id = d.zensus_population_id
528
529
        WHERE a.scenario = '{scenario}'
530
        AND a.sector = 'residential'
531
        AND a.zensus_population_id NOT IN (
532
            SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
533
            WHERE scenario = '{scenario}'
534
        )
535
536
        """,
537
        index_col="zensus_population_id",
538
    )
539
540
    daily_demand_shares = db.select_dataframe(
541
        """
542
        SELECT climate_zone, day_of_year as day, daily_demand_share FROM
543
        demand.egon_daily_heat_demand_per_climate_zone
544
        """
545
    )
546
547
    start_time = datetime.now()
548
    for grid in annual_demand.bus_id.unique():
549
550
        selected_profiles = db.select_dataframe(
551
            f"""
552
            SELECT a.zensus_population_id, building_id, c.climate_zone,
553
            selected_idp, ordinality as day
554
            FROM demand.egon_heat_timeseries_selected_profiles a
555
            INNER JOIN boundaries.egon_map_zensus_climate_zones c
556
            ON a.zensus_population_id = c.zensus_population_id
557
            ,
558
559
            UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
560
561
            WHERE a.zensus_population_id NOT IN (
562
                SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
563
                WHERE scenario = '{scenario}'
564
            )
565
            AND a.zensus_population_id IN (
566
                SELECT zensus_population_id
567
                FROM boundaries.egon_map_zensus_grid_districts
568
                WHERE bus_id = '{grid}'
569
            )
570
571
            """
572
        )
573
574
        df = pd.merge(
575
            selected_profiles, daily_demand_shares, on=["day", "climate_zone"]
576
        )
577
578
        slice_df = pd.merge(
579
            df, idp_df, left_on="selected_idp", right_on="index"
580
        )
581
582
        for hour in range(24):
583
            slice_df[hour] = (
584
                slice_df.idp.str[hour]
585
                .mul(slice_df.daily_demand_share)
586
                .mul(
587
                    annual_demand.loc[
588
                        slice_df.zensus_population_id.values, "per_building"
589
                    ].values
590
                )
591
            )
592
593
        calulate_peak_load(slice_df, scenario)
594
595
    print(f"Time to create peak loads per building for {scenario}")
596
    print(datetime.now() - start_time)
597
598
599
def create_individual_heating_profile_python_like(scenario="eGon2035"):
600
601
    start_time = datetime.now()
602
603
    idp_df = db.select_dataframe(
604
        f"""
605
        SELECT index, idp FROM demand.egon_heat_idp_pool
606
        """,
607
        index_col="index",
608
    )
609
610
    annual_demand = db.select_dataframe(
611
        f"""
612
        SELECT a.zensus_population_id, demand/c.count as per_building, bus_id
613
        FROM demand.egon_peta_heat a
614
615
616
        JOIN (SELECT COUNT(building_id), zensus_population_id
617
        FROM demand.egon_heat_timeseries_selected_profiles
618
        WHERE zensus_population_id IN(
619
        SELECT zensus_population_id FROM
620
        demand.egon_heat_timeseries_selected_profiles
621
        WHERE zensus_population_id IN (
622
        SELECT zensus_population_id FROM
623
        boundaries.egon_map_zensus_grid_districts
624
       ))
625
        GROUP BY zensus_population_id)c
626
        ON a.zensus_population_id = c.zensus_population_id
627
628
        JOIN boundaries.egon_map_zensus_grid_districts d
629
        ON a.zensus_population_id = d.zensus_population_id
630
631
        WHERE a.scenario = '{scenario}'
632
        AND a.sector = 'residential'
633
        AND a.zensus_population_id NOT IN (
634
            SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
635
            WHERE scenario = '{scenario}'
636
        )
637
638
        """,
639
        index_col="zensus_population_id",
640
    )
641
642
    daily_demand_shares = db.select_dataframe(
643
        f"""
644
        SELECT climate_zone, day_of_year as day, daily_demand_share FROM
645
        demand.egon_daily_heat_demand_per_climate_zone
646
        """
647
    )
648
649
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
650
        aggregation_level="district"
651
    )
652
653
    # TODO: use session_scope!
654
    from sqlalchemy.orm import sessionmaker
655
656
    session = sessionmaker(bind=db.engine())()
657
658
    print(
659
        f"Time to create overhead for time series for district heating scenario {scenario}"
660
    )
661
    print(datetime.now() - start_time)
662
663
    start_time = datetime.now()
664
    for grid in annual_demand.bus_id.unique():
665
666
        selected_profiles = db.select_dataframe(
667
            f"""
668
            SELECT a.zensus_population_id, building_id, c.climate_zone,
669
            selected_idp, ordinality as day
670
            FROM demand.egon_heat_timeseries_selected_profiles a
671
            INNER JOIN boundaries.egon_map_zensus_climate_zones c
672
            ON a.zensus_population_id = c.zensus_population_id
673
            ,
674
675
            UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
676
677
            WHERE a.zensus_population_id NOT IN (
678
                SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
679
                WHERE scenario = '{scenario}'
680
            )
681
            AND a.zensus_population_id IN (
682
                SELECT zensus_population_id
683
                FROM boundaries.egon_map_zensus_grid_districts
684
                WHERE bus_id = '{grid}'
685
            )
686
687
            """
688
        )
689
690
        df = pd.merge(
691
            selected_profiles, daily_demand_shares, on=["day", "climate_zone"]
692
        )
693
694
        slice_df = pd.merge(
695
            df, idp_df, left_on="selected_idp", right_on="index"
696
        )
697
698
        for hour in range(24):
699
            slice_df[hour] = (
700
                slice_df.idp.str[hour]
701
                .mul(slice_df.daily_demand_share)
702
                .mul(
703
                    annual_demand.loc[
704
                        slice_df.zensus_population_id.values, "per_building"
705
                    ].values
706
                )
707
            )
708
709
        cts = CTS_demand_grid[
710
            (CTS_demand_grid.scenario == scenario)
711
            & (CTS_demand_grid.index == grid)
712
        ].drop("scenario", axis="columns")
713
714
        hh = np.concatenate(
715
            slice_df.groupby("day").sum()[range(24)].values
716
        ).ravel()
717
718
        if not (slice_df[hour].empty or cts.empty):
0 ignored issues
show
introduced by
The variable hour does not seem to be defined for all execution paths.
Loading history...
719
            entry = EgonEtragoTimeseriesIndividualHeating(
720
                bus_id=int(grid),
721
                scenario=scenario,
722
                dist_aggregated_mw=(hh + cts.values[0]).tolist(),
723
            )
724
        elif not slice_df[hour].empty:
725
            entry = EgonEtragoTimeseriesIndividualHeating(
726
                bus_id=int(grid),
727
                scenario=scenario,
728
                dist_aggregated_mw=(hh).tolist(),
729
            )
730
        elif not cts.empty:
731
            entry = EgonEtragoTimeseriesIndividualHeating(
732
                bus_id=int(grid),
733
                scenario=scenario,
734
                dist_aggregated_mw=(cts).tolist(),
735
            )
736
737
        session.add(entry)
0 ignored issues
show
introduced by
The variable entry does not seem to be defined for all execution paths.
Loading history...
738
739
    session.commit()
740
741
    print(
742
        f"Time to create time series for district heating scenario {scenario}"
743
    )
744
    print(datetime.now() - start_time)
745
746
747
def district_heating(method="python"):
748
749
    engine = db.engine()
750
    EgonTimeseriesDistrictHeating.__table__.drop(bind=engine, checkfirst=True)
751
    EgonTimeseriesDistrictHeating.__table__.create(
752
        bind=engine, checkfirst=True
753
    )
754
755
    if method == "python":
756
        create_district_heating_profile_python_like("eGon2035")
757
        create_district_heating_profile_python_like("eGon100RE")
758
759
    else:
760
761
        CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
762
            aggregation_level="district"
763
        )
764
765
        ids = db.select_dataframe(
766
            """
767
            SELECT area_id, scenario
768
            FROM demand.egon_district_heating_areas
769
            """
770
        )
771
772
        df = pd.DataFrame(
773
            columns=["area_id", "scenario", "dist_aggregated_mw"]
774
        )
775
776
        for index, row in ids.iterrows():
777
            series = create_district_heating_profile(
778
                scenario=row.scenario, area_id=row.area_id
779
            )
780
781
            cts = (
782
                CTS_demand_dist[
783
                    (CTS_demand_dist.scenario == row.scenario)
784
                    & (CTS_demand_dist.index == row.area_id)
785
                ]
786
                .drop("scenario", axis="columns")
787
                .transpose()
788
            )
789
790
            if not cts.empty:
791
                data = (
792
                    cts[row.area_id] + series.demand_profile
793
                ).values.tolist()
794
            else:
795
                data = series.demand_profile.values.tolist()
796
797
            df = df.append(
798
                pd.Series(
799
                    data={
800
                        "area_id": row.area_id,
801
                        "scenario": row.scenario,
802
                        "dist_aggregated_mw": data,
803
                    },
804
                ),
805
                ignore_index=True,
806
            )
807
808
        df.to_sql(
809
            "egon_timeseries_district_heating",
810
            schema="demand",
811
            con=db.engine(),
812
            if_exists="append",
813
            index=False,
814
        )
815
816
817
def individual_heating_per_mv_grid(method="python"):
818
819
    if method == "python":
820
        engine = db.engine()
821
        EgonEtragoTimeseriesIndividualHeating.__table__.drop(
822
            bind=engine, checkfirst=True
823
        )
824
        EgonEtragoTimeseriesIndividualHeating.__table__.create(
825
            bind=engine, checkfirst=True
826
        )
827
828
        create_individual_heating_profile_python_like("eGon2035")
829
        create_individual_heating_profile_python_like("eGon100RE")
830
831
    else:
832
833
        engine = db.engine()
834
        EgonEtragoTimeseriesIndividualHeating.__table__.drop(
835
            bind=engine, checkfirst=True
836
        )
837
        EgonEtragoTimeseriesIndividualHeating.__table__.create(
838
            bind=engine, checkfirst=True
839
        )
840
841
        CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
842
            aggregation_level="district"
843
        )
844
        df = pd.DataFrame(columns=["bus_id", "scenario", "dist_aggregated_mw"])
845
846
        ids = db.select_dataframe(
847
            """
848
            SELECT bus_id
849
            FROM grid.egon_mv_grid_district
850
            """
851
        )
852
853
        for index, row in ids.iterrows():
854
855
            for scenario in ["eGon2035", "eGon100RE"]:
856
                series = create_individual_heat_per_mv_grid(
857
                    scenario, row.bus_id
858
                )
859
                cts = (
860
                    CTS_demand_grid[
861
                        (CTS_demand_grid.scenario == scenario)
862
                        & (CTS_demand_grid.index == row.bus_id)
863
                    ]
864
                    .drop("scenario", axis="columns")
865
                    .transpose()
866
                )
867
                if not cts.empty:
868
                    data = (
869
                        cts[row.bus_id] + series.demand_profile
870
                    ).values.tolist()
871
                else:
872
                    data = series.demand_profile.values.tolist()
873
874
                df = df.append(
875
                    pd.Series(
876
                        data={
877
                            "bus_id": row.bus_id,
878
                            "scenario": scenario,
879
                            "dist_aggregated_mw": data,
880
                        },
881
                    ),
882
                    ignore_index=True,
883
                )
884
885
        df.to_sql(
886
            "egon_etrago_timeseries_individual_heating",
887
            schema="demand",
888
            con=db.engine(),
889
            if_exists="append",
890
            index=False,
891
        )
892
893
894
def store_national_profiles():
895
896
    scenario = "eGon100RE"
897
898
    df = db.select_dataframe(
899
        f"""
900
901
        SELECT SUM(building_demand_per_hour) as "residential rural"
902
        FROM
903
904
        (
905
        SELECT demand.demand  *
906
        c.daily_demand_share * hourly_demand as building_demand_per_hour,
907
        ordinality + 24* (c.day_of_year-1) as hour_of_year,
908
        demand_profile.building_id,
909
        c.day_of_year,
910
        ordinality
911
912
        FROM
913
914
        (SELECT zensus_population_id, demand FROM
915
        demand.egon_peta_heat
916
        WHERE scenario = '{scenario}'
917
        AND sector = 'residential'
918
       ) as demand
919
920
        JOIN boundaries.egon_map_zensus_climate_zones b
921
        ON demand.zensus_population_id = b.zensus_population_id
922
923
        JOIN demand.egon_daily_heat_demand_per_climate_zone c
924
        ON c.climate_zone = b.climate_zone
925
926
        JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id
927
        FROM demand.egon_heat_timeseries_selected_profiles d,
928
        UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp
929
        JOIN demand.egon_heat_idp_pool e
930
        ON selected_idp = e.index
931
        )  demand_profile
932
        ON (demand_profile.day = c.day_of_year AND
933
            demand_profile.zensus_population_id = b.zensus_population_id)
934
935
        JOIN (SELECT COUNT(building_id), zensus_population_id
936
        FROM demand.egon_heat_timeseries_selected_profiles
937
        WHERE zensus_population_id IN(
938
        SELECT zensus_population_id FROM
939
        demand.egon_heat_timeseries_selected_profiles
940
        )
941
		GROUP BY zensus_population_id) building
942
        ON building.zensus_population_id = b.zensus_population_id,
943
944
        UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand
945
        )   result
946
947
948
        GROUP BY hour_of_year
949
950
        """
951
    )
952
953
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
954
        aggregation_level="district"
955
    )
956
957
    df["service rural"] = (
958
        CTS_demand_dist.loc[CTS_demand_dist.scenario == scenario]
959
        .drop("scenario", axis=1)
960
        .sum()
961
    )
962
963
    df["urban central"] = db.select_dataframe(
964
        f"""
965
        SELECT sum(demand) as "urban central"
966
967
        FROM demand.egon_timeseries_district_heating,
968
        UNNEST (dist_aggregated_mw) WITH ORDINALITY as demand
969
970
        WHERE scenario = '{scenario}'
971
972
        GROUP BY ordinality
973
974
        """
975
    )
976
977
    folder = Path(".") / "input-pypsa-eur-sec"
978
    # Create the folder, if it does not exists already
979
    if not os.path.exists(folder):
980
        os.mkdir(folder)
981
982
    df.to_csv(folder / f"heat_demand_timeseries_DE_{scenario}.csv")
983
984
985
def export_etrago_cts_heat_profiles():
986
    """Export heat cts load profiles at mv substation level
987
    to etrago-table in the database
988
989
    Returns
990
    -------
991
    None.
992
993
    """
994
995
    # Calculate cts heat profiles at substation
996
    _, CTS_grid, _ = CTS_demand_scale("district")
997
998
    # Change format
999
    data = CTS_grid.drop(columns="scenario")
1000
    df_etrago_cts_heat_profiles = pd.DataFrame(
1001
        index=data.index, columns=["scn_name", "p_set"]
1002
    )
1003
    df_etrago_cts_heat_profiles.p_set = data.values.tolist()
1004
    df_etrago_cts_heat_profiles.scn_name = CTS_grid["scenario"]
1005
    df_etrago_cts_heat_profiles.reset_index(inplace=True)
1006
1007
    # Drop and recreate Table if exists
1008
    EgonEtragoHeatCts.__table__.drop(bind=db.engine(), checkfirst=True)
1009
    EgonEtragoHeatCts.__table__.create(bind=db.engine(), checkfirst=True)
1010
1011
    # Write heat ts into db
1012
    with db.session_scope() as session:
1013
        session.bulk_insert_mappings(
1014
            EgonEtragoHeatCts,
1015
            df_etrago_cts_heat_profiles.to_dict(orient="records"),
1016
        )
1017
1018
1019
class HeatTimeSeries(Dataset):
1020
    def __init__(self, dependencies):
1021
        super().__init__(
1022
            name="HeatTimeSeries",
1023
            version="0.0.7.dev",
1024
            dependencies=dependencies,
1025
            tasks=(
1026
                {
1027
                    export_etrago_cts_heat_profiles,
1028
                    map_climate_zones_to_zensus,
1029
                    daily_demand_shares_per_climate_zone,
1030
                    create,
1031
                },
1032
                select,
1033
                district_heating,
1034
                store_national_profiles,
1035
            ),
1036
        )
1037