Passed
Pull Request — dev (#934)
by
unknown
01:34
created

data.datasets.heat_demand_timeseries   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 1037
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 37
eloc 377
dl 0
loc 1037
rs 9.44
c 0
b 0
f 0

11 Functions

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