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

data.datasets.heat_demand_timeseries   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 1039
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 37
eloc 380
dl 0
loc 1039
rs 9.44
c 0
b 0
f 0

11 Functions

Rating   Name   Duplication   Size   Complexity  
A store_national_profiles() 0 89 2
A create_individual_heat_per_mv_grid() 0 73 1
A create_district_heating_profile() 0 96 1
B district_heating() 0 67 4
A create_timeseries_for_building() 0 19 1
C create_individual_heating_profile_python_like() 0 146 7
A export_etrago_cts_heat_profiles() 0 31 2
A create_individual_heating_peak_loads() 0 108 3
B individual_heating_per_mv_grid() 0 74 5
C create_district_heating_profile_python_like() 0 165 9
A calulate_peak_load() 0 22 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A HeatTimeSeries.__init__() 0 15 1
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
    selected_profiles = db.select_dataframe(
295
        f"""
296
        SELECT a.zensus_population_id, building_id, c.climate_zone,
297
        selected_idp, ordinality as day, b.area_id
298
        FROM demand.egon_heat_timeseries_selected_profiles a
299
        INNER JOIN boundaries.egon_map_zensus_climate_zones c
300
        ON a.zensus_population_id = c.zensus_population_id
301
        INNER JOIN (
302
            SELECT * FROM demand.egon_map_zensus_district_heating_areas
303
            WHERE scenario = '{scenario}'
304
        ) b ON a.zensus_population_id = b.zensus_population_id        ,
305
306
        UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
307
308
        """
309
    )
310
311
    df = pd.merge(
312
        selected_profiles, daily_demand_shares, on=["day", "climate_zone"]
313
    )
314
315
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
316
        aggregation_level="district"
317
    )
318
319
    # TODO: use session_scope!
320
    from sqlalchemy.orm import sessionmaker
321
322
    session = sessionmaker(bind=db.engine())()
323
    engine = db.engine()
324
    EgonTimeseriesDistrictHeating.__table__.drop(bind=engine, checkfirst=True)
325
    EgonTimeseriesDistrictHeating.__table__.create(
326
        bind=engine, checkfirst=True
327
    )
328
    print(
329
        f"Time to create overhead for time series for district heating scenario {scenario}"
330
    )
331
    print(datetime.now() - start_time)
332
333
    start_time = datetime.now()
334
    for area in district_heating_grids.area_id.unique():
335
336
        if area in df.area_id.values:
337
            slice_df = pd.merge(
338
                df[df.area_id == area],
339
                idp_df,
340
                left_on="selected_idp",
341
                right_on="index",
342
            )
343
344
            for hour in range(24):
345
                slice_df[hour] = (
346
                    slice_df.idp.str[hour]
347
                    .mul(slice_df.daily_demand_share)
348
                    .mul(
349
                        annual_demand.loc[
350
                            slice_df.zensus_population_id.values,
351
                            "per_building",
352
                        ].values
353
                    )
354
                )
355
356
            hh = np.concatenate(
357
                slice_df.groupby("day").sum()[range(24)].values
358
            ).ravel()
359
360
        cts = CTS_demand_dist[
361
            (CTS_demand_dist.scenario == scenario)
362
            & (CTS_demand_dist.index == area)
363
        ].drop("scenario", axis="columns")
364
365
        if (area in df.area_id.values) and not cts.empty:
366
            entry = EgonTimeseriesDistrictHeating(
367
                area_id=int(area),
368
                scenario=scenario,
369
                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...
370
            )
371
        elif (area in df.area_id.values) and cts.empty:
372
            entry = EgonTimeseriesDistrictHeating(
373
                area_id=int(area),
374
                scenario=scenario,
375
                dist_aggregated_mw=(hh).tolist(),
376
            )
377
        elif not cts.empty:
378
            entry = EgonTimeseriesDistrictHeating(
379
                area_id=int(area),
380
                scenario=scenario,
381
                dist_aggregated_mw=(cts.values[0]).tolist(),
382
            )
383
384
        session.add(entry)
0 ignored issues
show
introduced by
The variable entry does not seem to be defined for all execution paths.
Loading history...
385
    session.commit()
386
387
    print(
388
        f"Time to create time series for district heating scenario {scenario}"
389
    )
390
    print(datetime.now() - start_time)
391
392
393
def create_individual_heat_per_mv_grid(scenario="eGon2035", mv_grid_id=1564):
394
    start_time = datetime.now()
395
    df = db.select_dataframe(
396
        f"""
397
398
        SELECT SUM(building_demand_per_hour) as demand_profile, hour_of_year
399
        FROM
400
401
        (
402
        SELECT demand.demand  *
403
        c.daily_demand_share * hourly_demand as building_demand_per_hour,
404
        ordinality + 24* (c.day_of_year-1) as hour_of_year,
405
        demand_profile.building_id,
406
        c.day_of_year,
407
        ordinality
408
409
        FROM
410
411
        (SELECT zensus_population_id, demand FROM
412
        demand.egon_peta_heat
413
        WHERE scenario = '{scenario}'
414
        AND sector = 'residential'
415
        AND zensus_population_id IN (
416
        SELECT zensus_population_id FROM
417
        boundaries.egon_map_zensus_grid_districts
418
        WHERE bus_id = {mv_grid_id}
419
        )) as demand
420
421
        JOIN boundaries.egon_map_zensus_climate_zones b
422
        ON demand.zensus_population_id = b.zensus_population_id
423
424
        JOIN demand.egon_daily_heat_demand_per_climate_zone c
425
        ON c.climate_zone = b.climate_zone
426
427
        JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id
428
        FROM demand.egon_heat_timeseries_selected_profiles d,
429
        UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp
430
        JOIN demand.egon_heat_idp_pool e
431
        ON selected_idp = e.index
432
        WHERE zensus_population_id IN (
433
        SELECT zensus_population_id FROM
434
        boundaries.egon_map_zensus_grid_districts
435
        WHERE bus_id = {mv_grid_id}
436
        ))  demand_profile
437
        ON (demand_profile.day = c.day_of_year AND
438
            demand_profile.zensus_population_id = b.zensus_population_id)
439
440
        JOIN (SELECT COUNT(building_id), zensus_population_id
441
        FROM demand.egon_heat_timeseries_selected_profiles
442
        WHERE zensus_population_id IN(
443
        SELECT zensus_population_id FROM
444
        demand.egon_heat_timeseries_selected_profiles
445
        WHERE zensus_population_id IN (
446
        SELECT zensus_population_id FROM
447
        boundaries.egon_map_zensus_grid_districts
448
        WHERE bus_id = {mv_grid_id}
449
       ))
450
		GROUP BY zensus_population_id) building
451
        ON building.zensus_population_id = b.zensus_population_id,
452
453
        UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand
454
        )   result
455
456
457
        GROUP BY hour_of_year
458
459
        """
460
    )
461
462
    print(f"Time to create time series for mv grid {scenario} {mv_grid_id}:")
463
    print(datetime.now() - start_time)
464
465
    return df
466
467
468
def calulate_peak_load(df, scenario):
469
470
    # peat load in W_th
471
    data = (
472
        df.groupby("building_id")
473
        .max()[range(24)]
474
        .max(axis=1)
475
        .mul(1000000)
476
        .astype(int)
477
        .reset_index()
478
    )
479
480
    data["scenario"] = scenario
481
482
    data.rename({0: "w_th"}, axis="columns", inplace=True)
483
484
    data.to_sql(
485
        EgonIndividualHeatingPeakLoads.__table__.name,
486
        schema=EgonIndividualHeatingPeakLoads.__table__.schema,
487
        con=db.engine(),
488
        if_exists="append",
489
        index=False,
490
    )
491
492
493
def create_individual_heating_peak_loads(scenario="eGon2035"):
494
495
    engine = db.engine()
496
497
    EgonIndividualHeatingPeakLoads.__table__.drop(bind=engine, checkfirst=True)
498
499
    EgonIndividualHeatingPeakLoads.__table__.create(
500
        bind=engine, checkfirst=True
501
    )
502
503
    start_time = datetime.now()
504
505
    idp_df = db.select_dataframe(
506
        """
507
        SELECT index, idp FROM demand.egon_heat_idp_pool
508
        """,
509
        index_col="index",
510
    )
511
512
    annual_demand = db.select_dataframe(
513
        f"""
514
        SELECT a.zensus_population_id, demand/c.count as per_building, bus_id
515
        FROM demand.egon_peta_heat a
516
517
518
        JOIN (SELECT COUNT(building_id), zensus_population_id
519
        FROM demand.egon_heat_timeseries_selected_profiles
520
        WHERE zensus_population_id IN(
521
        SELECT zensus_population_id FROM
522
        demand.egon_heat_timeseries_selected_profiles
523
        WHERE zensus_population_id IN (
524
        SELECT zensus_population_id FROM
525
        boundaries.egon_map_zensus_grid_districts
526
       ))
527
        GROUP BY zensus_population_id)c
528
        ON a.zensus_population_id = c.zensus_population_id
529
530
        JOIN boundaries.egon_map_zensus_grid_districts d
531
        ON a.zensus_population_id = d.zensus_population_id
532
533
        WHERE a.scenario = '{scenario}'
534
        AND a.sector = 'residential'
535
        AND a.zensus_population_id NOT IN (
536
            SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
537
            WHERE scenario = '{scenario}'
538
        )
539
540
        """,
541
        index_col="zensus_population_id",
542
    )
543
544
    daily_demand_shares = db.select_dataframe(
545
        """
546
        SELECT climate_zone, day_of_year as day, daily_demand_share FROM
547
        demand.egon_daily_heat_demand_per_climate_zone
548
        """
549
    )
550
551
    start_time = datetime.now()
552
    for grid in annual_demand.bus_id.unique():
553
554
        selected_profiles = db.select_dataframe(
555
            f"""
556
            SELECT a.zensus_population_id, building_id, c.climate_zone,
557
            selected_idp, ordinality as day
558
            FROM demand.egon_heat_timeseries_selected_profiles a
559
            INNER JOIN boundaries.egon_map_zensus_climate_zones c
560
            ON a.zensus_population_id = c.zensus_population_id
561
            ,
562
563
            UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
564
565
            WHERE a.zensus_population_id NOT IN (
566
                SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
567
                WHERE scenario = '{scenario}'
568
            )
569
            AND a.zensus_population_id IN (
570
                SELECT zensus_population_id
571
                FROM boundaries.egon_map_zensus_grid_districts
572
                WHERE bus_id = '{grid}'
573
            )
574
575
            """
576
        )
577
578
        df = pd.merge(
579
            selected_profiles, daily_demand_shares, on=["day", "climate_zone"]
580
        )
581
582
        slice_df = pd.merge(
583
            df, idp_df, left_on="selected_idp", right_on="index"
584
        )
585
586
        for hour in range(24):
587
            slice_df[hour] = (
588
                slice_df.idp.str[hour]
589
                .mul(slice_df.daily_demand_share)
590
                .mul(
591
                    annual_demand.loc[
592
                        slice_df.zensus_population_id.values, "per_building"
593
                    ].values
594
                )
595
            )
596
597
        calulate_peak_load(slice_df, scenario)
598
599
    print(f"Time to create peak loads per building for {scenario}")
600
    print(datetime.now() - start_time)
601
602
603
def create_individual_heating_profile_python_like(scenario="eGon2035"):
604
605
    start_time = datetime.now()
606
607
    idp_df = db.select_dataframe(
608
        f"""
609
        SELECT index, idp FROM demand.egon_heat_idp_pool
610
        """,
611
        index_col="index",
612
    )
613
614
    annual_demand = db.select_dataframe(
615
        f"""
616
        SELECT a.zensus_population_id, demand/c.count as per_building, bus_id
617
        FROM demand.egon_peta_heat a
618
619
620
        JOIN (SELECT COUNT(building_id), zensus_population_id
621
        FROM demand.egon_heat_timeseries_selected_profiles
622
        WHERE zensus_population_id IN(
623
        SELECT zensus_population_id FROM
624
        demand.egon_heat_timeseries_selected_profiles
625
        WHERE zensus_population_id IN (
626
        SELECT zensus_population_id FROM
627
        boundaries.egon_map_zensus_grid_districts
628
       ))
629
        GROUP BY zensus_population_id)c
630
        ON a.zensus_population_id = c.zensus_population_id
631
632
        JOIN boundaries.egon_map_zensus_grid_districts d
633
        ON a.zensus_population_id = d.zensus_population_id
634
635
        WHERE a.scenario = '{scenario}'
636
        AND a.sector = 'residential'
637
        AND a.zensus_population_id NOT IN (
638
            SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
639
            WHERE scenario = '{scenario}'
640
        )
641
642
        """,
643
        index_col="zensus_population_id",
644
    )
645
646
    daily_demand_shares = db.select_dataframe(
647
        f"""
648
        SELECT climate_zone, day_of_year as day, daily_demand_share FROM
649
        demand.egon_daily_heat_demand_per_climate_zone
650
        """
651
    )
652
653
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
654
        aggregation_level="district"
655
    )
656
657
    # TODO: use session_scope!
658
    from sqlalchemy.orm import sessionmaker
659
660
    session = sessionmaker(bind=db.engine())()
661
662
    print(
663
        f"Time to create overhead for time series for district heating scenario {scenario}"
664
    )
665
    print(datetime.now() - start_time)
666
667
    start_time = datetime.now()
668
    for grid in annual_demand.bus_id.unique():
669
670
        selected_profiles = db.select_dataframe(
671
            f"""
672
            SELECT a.zensus_population_id, building_id, c.climate_zone,
673
            selected_idp, ordinality as day
674
            FROM demand.egon_heat_timeseries_selected_profiles a
675
            INNER JOIN boundaries.egon_map_zensus_climate_zones c
676
            ON a.zensus_population_id = c.zensus_population_id
677
            ,
678
679
            UNNEST (selected_idp_profiles) WITH ORDINALITY as selected_idp
680
681
            WHERE a.zensus_population_id NOT IN (
682
                SELECT zensus_population_id FROM demand.egon_map_zensus_district_heating_areas
683
                WHERE scenario = '{scenario}'
684
            )
685
            AND a.zensus_population_id IN (
686
                SELECT zensus_population_id
687
                FROM boundaries.egon_map_zensus_grid_districts
688
                WHERE bus_id = '{grid}'
689
            )
690
691
            """
692
        )
693
694
        df = pd.merge(
695
            selected_profiles, daily_demand_shares, on=["day", "climate_zone"]
696
        )
697
698
        slice_df = pd.merge(
699
            df, idp_df, left_on="selected_idp", right_on="index"
700
        )
701
702
        for hour in range(24):
703
            slice_df[hour] = (
704
                slice_df.idp.str[hour]
705
                .mul(slice_df.daily_demand_share)
706
                .mul(
707
                    annual_demand.loc[
708
                        slice_df.zensus_population_id.values, "per_building"
709
                    ].values
710
                )
711
            )
712
713
        cts = CTS_demand_grid[
714
            (CTS_demand_grid.scenario == scenario)
715
            & (CTS_demand_grid.index == grid)
716
        ].drop("scenario", axis="columns")
717
718
        hh = np.concatenate(
719
            slice_df.groupby("day").sum()[range(24)].values
720
        ).ravel()
721
722
        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...
723
            entry = EgonEtragoTimeseriesIndividualHeating(
724
                bus_id=int(grid),
725
                scenario=scenario,
726
                dist_aggregated_mw=(hh + cts.values[0]).tolist(),
727
            )
728
        elif not slice_df[hour].empty:
729
            entry = EgonEtragoTimeseriesIndividualHeating(
730
                bus_id=int(grid),
731
                scenario=scenario,
732
                dist_aggregated_mw=(hh).tolist(),
733
            )
734
        elif not cts.empty:
735
            entry = EgonEtragoTimeseriesIndividualHeating(
736
                bus_id=int(grid),
737
                scenario=scenario,
738
                dist_aggregated_mw=(cts).tolist(),
739
            )
740
741
        session.add(entry)
0 ignored issues
show
introduced by
The variable entry does not seem to be defined for all execution paths.
Loading history...
742
743
    session.commit()
744
745
    print(
746
        f"Time to create time series for district heating scenario {scenario}"
747
    )
748
    print(datetime.now() - start_time)
749
750
751
def district_heating(method="python"):
752
753
    engine = db.engine()
754
    EgonTimeseriesDistrictHeating.__table__.drop(bind=engine, checkfirst=True)
755
    EgonTimeseriesDistrictHeating.__table__.create(
756
        bind=engine, checkfirst=True
757
    )
758
759
    if method == "python":
760
        create_district_heating_profile_python_like("eGon2035")
761
        create_district_heating_profile_python_like("eGon100RE")
762
763
    else:
764
765
        CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
766
            aggregation_level="district"
767
        )
768
769
        ids = db.select_dataframe(
770
            """
771
            SELECT area_id, scenario
772
            FROM demand.egon_district_heating_areas
773
            """
774
        )
775
776
        df = pd.DataFrame(
777
            columns=["area_id", "scenario", "dist_aggregated_mw"]
778
        )
779
780
        for index, row in ids.iterrows():
781
            series = create_district_heating_profile(
782
                scenario=row.scenario, area_id=row.area_id
783
            )
784
785
            cts = (
786
                CTS_demand_dist[
787
                    (CTS_demand_dist.scenario == row.scenario)
788
                    & (CTS_demand_dist.index == row.area_id)
789
                ]
790
                .drop("scenario", axis="columns")
791
                .transpose()
792
            )
793
794
            if not cts.empty:
795
                data = (
796
                    cts[row.area_id] + series.demand_profile
797
                ).values.tolist()
798
            else:
799
                data = series.demand_profile.values.tolist()
800
801
            df = df.append(
802
                pd.Series(
803
                    data={
804
                        "area_id": row.area_id,
805
                        "scenario": row.scenario,
806
                        "dist_aggregated_mw": data,
807
                    },
808
                ),
809
                ignore_index=True,
810
            )
811
812
        df.to_sql(
813
            "egon_timeseries_district_heating",
814
            schema="demand",
815
            con=db.engine(),
816
            if_exists="append",
817
            index=False,
818
        )
819
820
821
def individual_heating_per_mv_grid(method="python"):
822
823
    if method == "python":
824
        engine = db.engine()
825
        EgonEtragoTimeseriesIndividualHeating.__table__.drop(
826
            bind=engine, checkfirst=True
827
        )
828
        EgonEtragoTimeseriesIndividualHeating.__table__.create(
829
            bind=engine, checkfirst=True
830
        )
831
832
        create_individual_heating_profile_python_like("eGon2035")
833
        create_individual_heating_profile_python_like("eGon100RE")
834
835
    else:
836
837
        engine = db.engine()
838
        EgonEtragoTimeseriesIndividualHeating.__table__.drop(
839
            bind=engine, checkfirst=True
840
        )
841
        EgonEtragoTimeseriesIndividualHeating.__table__.create(
842
            bind=engine, checkfirst=True
843
        )
844
845
        CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
846
            aggregation_level="district"
847
        )
848
        df = pd.DataFrame(columns=["bus_id", "scenario", "dist_aggregated_mw"])
849
850
        ids = db.select_dataframe(
851
            """
852
            SELECT bus_id
853
            FROM grid.egon_mv_grid_district
854
            """
855
        )
856
857
        for index, row in ids.iterrows():
858
859
            for scenario in ["eGon2035", "eGon100RE"]:
860
                series = create_individual_heat_per_mv_grid(
861
                    scenario, row.bus_id
862
                )
863
                cts = (
864
                    CTS_demand_grid[
865
                        (CTS_demand_grid.scenario == scenario)
866
                        & (CTS_demand_grid.index == row.bus_id)
867
                    ]
868
                    .drop("scenario", axis="columns")
869
                    .transpose()
870
                )
871
                if not cts.empty:
872
                    data = (
873
                        cts[row.bus_id] + series.demand_profile
874
                    ).values.tolist()
875
                else:
876
                    data = series.demand_profile.values.tolist()
877
878
                df = df.append(
879
                    pd.Series(
880
                        data={
881
                            "bus_id": row.bus_id,
882
                            "scenario": scenario,
883
                            "dist_aggregated_mw": data,
884
                        },
885
                    ),
886
                    ignore_index=True,
887
                )
888
889
        df.to_sql(
890
            "egon_etrago_timeseries_individual_heating",
891
            schema="demand",
892
            con=db.engine(),
893
            if_exists="append",
894
            index=False,
895
        )
896
897
898
def store_national_profiles():
899
900
    scenario = "eGon100RE"
901
902
    df = db.select_dataframe(
903
        f"""
904
905
        SELECT SUM(building_demand_per_hour) as "residential rural"
906
        FROM
907
908
        (
909
        SELECT demand.demand  *
910
        c.daily_demand_share * hourly_demand as building_demand_per_hour,
911
        ordinality + 24* (c.day_of_year-1) as hour_of_year,
912
        demand_profile.building_id,
913
        c.day_of_year,
914
        ordinality
915
916
        FROM
917
918
        (SELECT zensus_population_id, demand FROM
919
        demand.egon_peta_heat
920
        WHERE scenario = '{scenario}'
921
        AND sector = 'residential'
922
       ) as demand
923
924
        JOIN boundaries.egon_map_zensus_climate_zones b
925
        ON demand.zensus_population_id = b.zensus_population_id
926
927
        JOIN demand.egon_daily_heat_demand_per_climate_zone c
928
        ON c.climate_zone = b.climate_zone
929
930
        JOIN (SELECT e.idp, ordinality as day, zensus_population_id, building_id
931
        FROM demand.egon_heat_timeseries_selected_profiles d,
932
        UNNEST (d.selected_idp_profiles) WITH ORDINALITY as selected_idp
933
        JOIN demand.egon_heat_idp_pool e
934
        ON selected_idp = e.index
935
        )  demand_profile
936
        ON (demand_profile.day = c.day_of_year AND
937
            demand_profile.zensus_population_id = b.zensus_population_id)
938
939
        JOIN (SELECT COUNT(building_id), zensus_population_id
940
        FROM demand.egon_heat_timeseries_selected_profiles
941
        WHERE zensus_population_id IN(
942
        SELECT zensus_population_id FROM
943
        demand.egon_heat_timeseries_selected_profiles
944
        )
945
		GROUP BY zensus_population_id) building
946
        ON building.zensus_population_id = b.zensus_population_id,
947
948
        UNNEST(demand_profile.idp) WITH ORDINALITY as hourly_demand
949
        )   result
950
951
952
        GROUP BY hour_of_year
953
954
        """
955
    )
956
957
    CTS_demand_dist, CTS_demand_grid, CTS_demand_zensus = CTS_demand_scale(
958
        aggregation_level="district"
959
    )
960
961
    df["service rural"] = (
962
        CTS_demand_dist.loc[CTS_demand_dist.scenario == scenario]
963
        .drop("scenario", axis=1)
964
        .sum()
965
    )
966
967
    df["urban central"] = db.select_dataframe(
968
        f"""
969
        SELECT sum(demand) as "urban central"
970
971
        FROM demand.egon_timeseries_district_heating,
972
        UNNEST (dist_aggregated_mw) WITH ORDINALITY as demand
973
974
        WHERE scenario = '{scenario}'
975
976
        GROUP BY ordinality
977
978
        """
979
    )
980
981
    folder = Path(".") / "input-pypsa-eur-sec"
982
    # Create the folder, if it does not exists already
983
    if not os.path.exists(folder):
984
        os.mkdir(folder)
985
986
    df.to_csv(folder / f"heat_demand_timeseries_DE_{scenario}.csv")
987
988
989
def export_etrago_cts_heat_profiles():
990
    """Export heat cts load profiles at mv substation level
991
    to etrago-table in the database
992
993
    Returns
994
    -------
995
    None.
996
997
    """
998
999
    # Calculate cts heat profiles at substation
1000
    _, CTS_grid, _ = CTS_demand_scale("district")
1001
1002
    # Change format
1003
    data = CTS_grid.drop(columns="scenario")
1004
    df_etrago_cts_heat_profiles = pd.DataFrame(
1005
        index=data.index, columns=["scn_name", "p_set"]
1006
    )
1007
    df_etrago_cts_heat_profiles.p_set = data.values.tolist()
1008
    df_etrago_cts_heat_profiles.scn_name = CTS_grid["scenario"]
1009
    df_etrago_cts_heat_profiles.reset_index(inplace=True)
1010
1011
    # Drop and recreate Table if exists
1012
    EgonEtragoHeatCts.__table__.drop(bind=db.engine(), checkfirst=True)
1013
    EgonEtragoHeatCts.__table__.create(bind=db.engine(), checkfirst=True)
1014
1015
    # Write heat ts into db
1016
    with db.session_scope() as session:
1017
        session.bulk_insert_mappings(
1018
            EgonEtragoHeatCts,
1019
            df_etrago_cts_heat_profiles.to_dict(orient="records"),
1020
        )
1021
1022
1023
class HeatTimeSeries(Dataset):
1024
    def __init__(self, dependencies):
1025
        super().__init__(
1026
            name="HeatTimeSeries",
1027
            version="0.0.7.dev",
1028
            dependencies=dependencies,
1029
            tasks=(
1030
                {
1031
                    export_etrago_cts_heat_profiles,
1032
                    map_climate_zones_to_zensus,
1033
                    daily_demand_shares_per_climate_zone,
1034
                    create,
1035
                },
1036
                select,
1037
                district_heating,
1038
                store_national_profiles,
1039
            ),
1040
        )
1041