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

sanitycheck_emobility_mit()   F

Complexity

Conditions 24

Size

Total Lines 555
Code Lines 358

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 358
dl 0
loc 555
rs 0
c 0
b 0
f 0
cc 24
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like data.datasets.sanity_checks.sanitycheck_emobility_mit() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
This module does sanity checks for both the eGon2035 and the eGon100RE scenario
3
separately where a percentage error is given to showcase difference in output
4
and input values. Please note that there are missing input technologies in the
5
supply tables.
6
Authors: @ALonso, @dana, @nailend, @nesnoj, @khelfen
7
"""
8
from math import isclose
9
from pathlib import Path
10
11
from sqlalchemy import Numeric
12
from sqlalchemy.sql import and_, cast, func, or_
13
import matplotlib.pyplot as plt
14
import numpy as np
15
import pandas as pd
16
import seaborn as sns
17
18
from egon.data import config, db, logger
19
from egon.data.datasets import Dataset
20
from egon.data.datasets.electricity_demand_timeseries.cts_buildings import (
21
    EgonCtsElectricityDemandBuildingShare,
22
    EgonCtsHeatDemandBuildingShare,
23
)
24
from egon.data.datasets.emobility.motorized_individual_travel.db_classes import (
25
    EgonEvCountMunicipality,
26
    EgonEvCountMvGridDistrict,
27
    EgonEvCountRegistrationDistrict,
28
    EgonEvMvGridDistrict,
29
    EgonEvPool,
30
    EgonEvTrip,
31
)
32
from egon.data.datasets.emobility.motorized_individual_travel.helpers import (
33
    DATASET_CFG,
34
    read_simbev_metadata_file,
35
)
36
from egon.data.datasets.etrago_setup import (
37
    EgonPfHvLink,
38
    EgonPfHvLinkTimeseries,
39
    EgonPfHvLoad,
40
    EgonPfHvLoadTimeseries,
41
    EgonPfHvStore,
42
    EgonPfHvStoreTimeseries,
43
)
44
from egon.data.datasets.power_plants.pv_rooftop_buildings import (
45
    PV_CAP_PER_SQ_M,
46
    ROOF_FACTOR,
47
    SCENARIOS,
48
    load_building_data,
49
    scenario_data,
50
)
51
from egon.data.datasets.scenario_parameters import get_sector_parameters
52
import egon.data
53
54
TESTMODE_OFF = (
55
    config.settings()["egon-data"]["--dataset-boundary"] == "Everything"
56
)
57
58
59
class SanityChecks(Dataset):
60
    def __init__(self, dependencies):
61
        super().__init__(
62
            name="SanityChecks",
63
            version="0.0.5",
64
            dependencies=dependencies,
65
            tasks={
66
                etrago_eGon2035_electricity,
67
                etrago_eGon2035_heat,
68
                residential_electricity_annual_sum,
69
                residential_electricity_hh_refinement,
70
                cts_electricity_demand_share,
71
                cts_heat_demand_share,
72
                sanitycheck_emobility_mit,
73
                sanitycheck_pv_rooftop_buildings,
74
            },
75
        )
76
77
78
def etrago_eGon2035_electricity():
79
    """Execute basic sanity checks.
80
81
    Returns print statements as sanity checks for the electricity sector in
82
    the eGon2035 scenario.
83
84
    Parameters
85
    ----------
86
    None
87
88
    Returns
89
    -------
90
    None
91
    """
92
93
    scn = "eGon2035"
94
95
    # Section to check generator capacities
96
    logger.info(f"Sanity checks for scenario {scn}")
97
    logger.info(
98
        "For German electricity generators the following deviations between "
99
        "the inputs and outputs can be observed:"
100
    )
101
102
    carriers_electricity = [
103
        "others",
104
        "reservoir",
105
        "run_of_river",
106
        "oil",
107
        "wind_onshore",
108
        "wind_offshore",
109
        "solar",
110
        "solar_rooftop",
111
        "biomass",
112
    ]
113
114
    for carrier in carriers_electricity:
115
116
        if carrier == "biomass":
117
            sum_output = db.select_dataframe(
118
                """SELECT scn_name, SUM(p_nom::numeric) as output_capacity_mw
119
                    FROM grid.egon_etrago_generator
120
                    WHERE bus IN (
121
                        SELECT bus_id FROM grid.egon_etrago_bus
122
                        WHERE scn_name = 'eGon2035'
123
                        AND country = 'DE')
124
                    AND carrier IN ('biomass', 'industrial_biomass_CHP',
125
                    'central_biomass_CHP')
126
                    GROUP BY (scn_name);
127
                """,
128
                warning=False,
129
            )
130
131
        else:
132
            sum_output = db.select_dataframe(
133
                f"""SELECT scn_name,
134
                 SUM(p_nom::numeric) as output_capacity_mw
135
                         FROM grid.egon_etrago_generator
136
                         WHERE scn_name = '{scn}'
137
                         AND carrier IN ('{carrier}')
138
                         AND bus IN
139
                             (SELECT bus_id
140
                               FROM grid.egon_etrago_bus
141
                               WHERE scn_name = 'eGon2035'
142
                               AND country = 'DE')
143
                         GROUP BY (scn_name);
144
                    """,
145
                warning=False,
146
            )
147
148
        sum_input = db.select_dataframe(
149
            f"""SELECT carrier, SUM(capacity::numeric) as input_capacity_mw
150
                     FROM supply.egon_scenario_capacities
151
                     WHERE carrier= '{carrier}'
152
                     AND scenario_name ='{scn}'
153
                     GROUP BY (carrier);
154
                """,
155
            warning=False,
156
        )
157
158 View Code Duplication
        if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
159
            sum_output.output_capacity_mw.sum() == 0
160
            and sum_input.input_capacity_mw.sum() == 0
161
        ):
162
            logger.info(
163
                f"No capacity for carrier '{carrier}' needed to be"
164
                f" distributed. Everything is fine"
165
            )
166
167
        elif (
168
            sum_input.input_capacity_mw.sum() > 0
169
            and sum_output.output_capacity_mw.sum() == 0
170
        ):
171
            logger.info(
172
                f"Error: Capacity for carrier '{carrier}' was not distributed "
173
                f"at all!"
174
            )
175
176
        elif (
177
            sum_output.output_capacity_mw.sum() > 0
178
            and sum_input.input_capacity_mw.sum() == 0
179
        ):
180
            logger.info(
181
                f"Error: Eventhough no input capacity was provided for carrier"
182
                f"'{carrier}' a capacity got distributed!"
183
            )
184
185
        else:
186
            sum_input["error"] = (
187
                (sum_output.output_capacity_mw - sum_input.input_capacity_mw)
188
                / sum_input.input_capacity_mw
189
            ) * 100
190
            g = sum_input["error"].values[0]
191
192
            logger.info(f"{carrier}: " + str(round(g, 2)) + " %")
193
194
    # Section to check storage units
195
196
    logger.info(f"Sanity checks for scenario {scn}")
197
    logger.info(
198
        "For German electrical storage units the following deviations between"
199
        "the inputs and outputs can be observed:"
200
    )
201
202
    carriers_electricity = ["pumped_hydro"]
203
204
    for carrier in carriers_electricity:
205
206
        sum_output = db.select_dataframe(
207
            f"""SELECT scn_name, SUM(p_nom::numeric) as output_capacity_mw
208
                         FROM grid.egon_etrago_storage
209
                         WHERE scn_name = '{scn}'
210
                         AND carrier IN ('{carrier}')
211
                         AND bus IN
212
                             (SELECT bus_id
213
                               FROM grid.egon_etrago_bus
214
                               WHERE scn_name = 'eGon2035'
215
                               AND country = 'DE')
216
                         GROUP BY (scn_name);
217
                    """,
218
            warning=False,
219
        )
220
221
        sum_input = db.select_dataframe(
222
            f"""SELECT carrier, SUM(capacity::numeric) as input_capacity_mw
223
                     FROM supply.egon_scenario_capacities
224
                     WHERE carrier= '{carrier}'
225
                     AND scenario_name ='{scn}'
226
                     GROUP BY (carrier);
227
                """,
228
            warning=False,
229
        )
230
231 View Code Duplication
        if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
232
            sum_output.output_capacity_mw.sum() == 0
233
            and sum_input.input_capacity_mw.sum() == 0
234
        ):
235
            print(
236
                f"No capacity for carrier '{carrier}' needed to be "
237
                f"distributed. Everything is fine"
238
            )
239
240
        elif (
241
            sum_input.input_capacity_mw.sum() > 0
242
            and sum_output.output_capacity_mw.sum() == 0
243
        ):
244
            print(
245
                f"Error: Capacity for carrier '{carrier}' was not distributed"
246
                f" at all!"
247
            )
248
249
        elif (
250
            sum_output.output_capacity_mw.sum() > 0
251
            and sum_input.input_capacity_mw.sum() == 0
252
        ):
253
            print(
254
                f"Error: Eventhough no input capacity was provided for carrier"
255
                f" '{carrier}' a capacity got distributed!"
256
            )
257
258
        else:
259
            sum_input["error"] = (
260
                (sum_output.output_capacity_mw - sum_input.input_capacity_mw)
261
                / sum_input.input_capacity_mw
262
            ) * 100
263
            g = sum_input["error"].values[0]
264
265
            print(f"{carrier}: " + str(round(g, 2)) + " %")
266
267
    # Section to check loads
268
269
    print(
270
        "For German electricity loads the following deviations between the"
271
        " input and output can be observed:"
272
    )
273
274
    output_demand = db.select_dataframe(
275
        """SELECT a.scn_name, a.carrier,  SUM((SELECT SUM(p)
276
        FROM UNNEST(b.p_set) p))/1000000::numeric as load_twh
277
            FROM grid.egon_etrago_load a
278
            JOIN grid.egon_etrago_load_timeseries b
279
            ON (a.load_id = b.load_id)
280
            JOIN grid.egon_etrago_bus c
281
            ON (a.bus=c.bus_id)
282
            AND b.scn_name = 'eGon2035'
283
            AND a.scn_name = 'eGon2035'
284
            AND a.carrier = 'AC'
285
            AND c.scn_name= 'eGon2035'
286
            AND c.country='DE'
287
            GROUP BY (a.scn_name, a.carrier);
288
289
    """,
290
        warning=False,
291
    )["load_twh"].values[0]
292
293
    input_cts_ind = db.select_dataframe(
294
        """SELECT scenario,
295
         SUM(demand::numeric/1000000) as demand_mw_regio_cts_ind
296
            FROM demand.egon_demandregio_cts_ind
297
            WHERE scenario= 'eGon2035'
298
            AND year IN ('2035')
299
            GROUP BY (scenario);
300
301
        """,
302
        warning=False,
303
    )["demand_mw_regio_cts_ind"].values[0]
304
305
    input_hh = db.select_dataframe(
306
        """SELECT scenario, SUM(demand::numeric/1000000) as demand_mw_regio_hh
307
            FROM demand.egon_demandregio_hh
308
            WHERE scenario= 'eGon2035'
309
            AND year IN ('2035')
310
            GROUP BY (scenario);
311
        """,
312
        warning=False,
313
    )["demand_mw_regio_hh"].values[0]
314
315
    input_demand = input_hh + input_cts_ind
316
317
    e = round((output_demand - input_demand) / input_demand, 2) * 100
318
319
    print(f"electricity demand: {e} %")
320
321
322
def etrago_eGon2035_heat():
323
    """Execute basic sanity checks.
324
325
    Returns print statements as sanity checks for the heat sector in
326
    the eGon2035 scenario.
327
328
    Parameters
329
    ----------
330
    None
331
332
    Returns
333
    -------
334
    None
335
    """
336
337
    # Check input and output values for the carriers "others",
338
    # "reservoir", "run_of_river" and "oil"
339
340
    scn = "eGon2035"
341
342
    # Section to check generator capacities
343
    print(f"Sanity checks for scenario {scn}")
344
    print(
345
        "For German heat demands the following deviations between the inputs"
346
        " and outputs can be observed:"
347
    )
348
349
    # Sanity checks for heat demand
350
351
    output_heat_demand = db.select_dataframe(
352
        """SELECT a.scn_name,
353
          (SUM(
354
          (SELECT SUM(p) FROM UNNEST(b.p_set) p))/1000000)::numeric as load_twh
355
            FROM grid.egon_etrago_load a
356
            JOIN grid.egon_etrago_load_timeseries b
357
            ON (a.load_id = b.load_id)
358
            JOIN grid.egon_etrago_bus c
359
            ON (a.bus=c.bus_id)
360
            AND b.scn_name = 'eGon2035'
361
            AND a.scn_name = 'eGon2035'
362
            AND c.scn_name= 'eGon2035'
363
            AND c.country='DE'
364
            AND a.carrier IN ('rural_heat', 'central_heat')
365
            GROUP BY (a.scn_name);
366
        """,
367
        warning=False,
368
    )["load_twh"].values[0]
369
370
    input_heat_demand = db.select_dataframe(
371
        """SELECT scenario, SUM(demand::numeric/1000000) as demand_mw_peta_heat
372
            FROM demand.egon_peta_heat
373
            WHERE scenario= 'eGon2035'
374
            GROUP BY (scenario);
375
        """,
376
        warning=False,
377
    )["demand_mw_peta_heat"].values[0]
378
379
    e_demand = (
380
        round((output_heat_demand - input_heat_demand) / input_heat_demand, 2)
381
        * 100
382
    )
383
384
    logger.info(f"heat demand: {e_demand} %")
385
386
    # Sanity checks for heat supply
387
388
    logger.info(
389
        "For German heat supplies the following deviations between the inputs "
390
        "and outputs can be observed:"
391
    )
392
393
    # Comparison for central heat pumps
394
    heat_pump_input = db.select_dataframe(
395
        """SELECT carrier, SUM(capacity::numeric) as Urban_central_heat_pump_mw
396
            FROM supply.egon_scenario_capacities
397
            WHERE carrier= 'urban_central_heat_pump'
398
            AND scenario_name IN ('eGon2035')
399
            GROUP BY (carrier);
400
        """,
401
        warning=False,
402
    )["urban_central_heat_pump_mw"].values[0]
403
404
    heat_pump_output = db.select_dataframe(
405
        """SELECT carrier, SUM(p_nom::numeric) as Central_heat_pump_mw
406
            FROM grid.egon_etrago_link
407
            WHERE carrier= 'central_heat_pump'
408
            AND scn_name IN ('eGon2035')
409
            GROUP BY (carrier);
410
    """,
411
        warning=False,
412
    )["central_heat_pump_mw"].values[0]
413
414
    e_heat_pump = (
415
        round((heat_pump_output - heat_pump_input) / heat_pump_output, 2) * 100
416
    )
417
418
    logger.info(f"'central_heat_pump': {e_heat_pump} % ")
419
420
    # Comparison for residential heat pumps
421
422
    input_residential_heat_pump = db.select_dataframe(
423
        """SELECT carrier, SUM(capacity::numeric) as residential_heat_pump_mw
424
            FROM supply.egon_scenario_capacities
425
            WHERE carrier= 'residential_rural_heat_pump'
426
            AND scenario_name IN ('eGon2035')
427
            GROUP BY (carrier);
428
        """,
429
        warning=False,
430
    )["residential_heat_pump_mw"].values[0]
431
432
    output_residential_heat_pump = db.select_dataframe(
433
        """SELECT carrier, SUM(p_nom::numeric) as rural_heat_pump_mw
434
            FROM grid.egon_etrago_link
435
            WHERE carrier= 'rural_heat_pump'
436
            AND scn_name IN ('eGon2035')
437
            GROUP BY (carrier);
438
    """,
439
        warning=False,
440
    )["rural_heat_pump_mw"].values[0]
441
442
    e_residential_heat_pump = (
443
        round(
444
            (output_residential_heat_pump - input_residential_heat_pump)
445
            / input_residential_heat_pump,
446
            2,
447
        )
448
        * 100
449
    )
450
    logger.info(f"'residential heat pumps': {e_residential_heat_pump} %")
451
452
    # Comparison for resistive heater
453
    resistive_heater_input = db.select_dataframe(
454
        """SELECT carrier,
455
         SUM(capacity::numeric) as Urban_central_resistive_heater_MW
456
            FROM supply.egon_scenario_capacities
457
            WHERE carrier= 'urban_central_resistive_heater'
458
            AND scenario_name IN ('eGon2035')
459
            GROUP BY (carrier);
460
        """,
461
        warning=False,
462
    )["urban_central_resistive_heater_mw"].values[0]
463
464
    resistive_heater_output = db.select_dataframe(
465
        """SELECT carrier, SUM(p_nom::numeric) as central_resistive_heater_MW
466
            FROM grid.egon_etrago_link
467
            WHERE carrier= 'central_resistive_heater'
468
            AND scn_name IN ('eGon2035')
469
            GROUP BY (carrier);
470
        """,
471
        warning=False,
472
    )["central_resistive_heater_mw"].values[0]
473
474
    e_resistive_heater = (
475
        round(
476
            (resistive_heater_output - resistive_heater_input)
477
            / resistive_heater_input,
478
            2,
479
        )
480
        * 100
481
    )
482
483
    logger.info(f"'resistive heater': {e_resistive_heater} %")
484
485
    # Comparison for solar thermal collectors
486
487
    input_solar_thermal = db.select_dataframe(
488
        """SELECT carrier, SUM(capacity::numeric) as solar_thermal_collector_mw
489
            FROM supply.egon_scenario_capacities
490
            WHERE carrier= 'urban_central_solar_thermal_collector'
491
            AND scenario_name IN ('eGon2035')
492
            GROUP BY (carrier);
493
        """,
494
        warning=False,
495
    )["solar_thermal_collector_mw"].values[0]
496
497
    output_solar_thermal = db.select_dataframe(
498
        """SELECT carrier, SUM(p_nom::numeric) as solar_thermal_collector_mw
499
            FROM grid.egon_etrago_generator
500
            WHERE carrier= 'solar_thermal_collector'
501
            AND scn_name IN ('eGon2035')
502
            GROUP BY (carrier);
503
        """,
504
        warning=False,
505
    )["solar_thermal_collector_mw"].values[0]
506
507
    e_solar_thermal = (
508
        round(
509
            (output_solar_thermal - input_solar_thermal) / input_solar_thermal,
510
            2,
511
        )
512
        * 100
513
    )
514
    logger.info(f"'solar thermal collector': {e_solar_thermal} %")
515
516
    # Comparison for geothermal
517
518
    input_geo_thermal = db.select_dataframe(
519
        """SELECT carrier,
520
         SUM(capacity::numeric) as Urban_central_geo_thermal_MW
521
            FROM supply.egon_scenario_capacities
522
            WHERE carrier= 'urban_central_geo_thermal'
523
            AND scenario_name IN ('eGon2035')
524
            GROUP BY (carrier);
525
        """,
526
        warning=False,
527
    )["urban_central_geo_thermal_mw"].values[0]
528
529
    output_geo_thermal = db.select_dataframe(
530
        """SELECT carrier, SUM(p_nom::numeric) as geo_thermal_MW
531
            FROM grid.egon_etrago_generator
532
            WHERE carrier= 'geo_thermal'
533
            AND scn_name IN ('eGon2035')
534
            GROUP BY (carrier);
535
    """,
536
        warning=False,
537
    )["geo_thermal_mw"].values[0]
538
539
    e_geo_thermal = (
540
        round((output_geo_thermal - input_geo_thermal) / input_geo_thermal, 2)
541
        * 100
542
    )
543
    logger.info(f"'geothermal': {e_geo_thermal} %")
544
545
546
def residential_electricity_annual_sum(rtol=1e-5):
547
    """Sanity check for dataset electricity_demand_timeseries :
548
    Demand_Building_Assignment
549
550
    Aggregate the annual demand of all census cells at NUTS3 to compare
551
    with initial scaling parameters from DemandRegio.
552
    """
553
554
    df_nuts3_annual_sum = db.select_dataframe(
555
        sql="""
556
        SELECT dr.nuts3, dr.scenario, dr.demand_regio_sum, profiles.profile_sum
557
        FROM (
558
            SELECT scenario, SUM(demand) AS profile_sum, vg250_nuts3
559
            FROM demand.egon_demandregio_zensus_electricity AS egon,
560
             boundaries.egon_map_zensus_vg250 AS boundaries
561
            Where egon.zensus_population_id = boundaries.zensus_population_id
562
            AND sector = 'residential'
563
            GROUP BY vg250_nuts3, scenario
564
            ) AS profiles
565
        JOIN (
566
            SELECT nuts3, scenario, sum(demand) AS demand_regio_sum
567
            FROM demand.egon_demandregio_hh
568
            GROUP BY year, scenario, nuts3
569
              ) AS dr
570
        ON profiles.vg250_nuts3 = dr.nuts3 and profiles.scenario  = dr.scenario
571
        """
572
    )
573
574
    np.testing.assert_allclose(
575
        actual=df_nuts3_annual_sum["profile_sum"],
576
        desired=df_nuts3_annual_sum["demand_regio_sum"],
577
        rtol=rtol,
578
        verbose=False,
579
    )
580
581
    logger.info(
582
        "Aggregated annual residential electricity demand"
583
        " matches with DemandRegio at NUTS-3."
584
    )
585
586
587
def residential_electricity_hh_refinement(rtol=1e-5):
588
    """Sanity check for dataset electricity_demand_timeseries :
589
    Household Demands
590
591
    Check sum of aggregated household types after refinement method
592
    was applied and compare it to the original census values."""
593
594
    df_refinement = db.select_dataframe(
595
        sql="""
596
        SELECT refined.nuts3, refined.characteristics_code,
597
                refined.sum_refined::int, census.sum_census::int
598
        FROM(
599
            SELECT nuts3, characteristics_code, SUM(hh_10types) as sum_refined
600
            FROM society.egon_destatis_zensus_household_per_ha_refined
601
            GROUP BY nuts3, characteristics_code)
602
            AS refined
603
        JOIN(
604
            SELECT t.nuts3, t.characteristics_code, sum(orig) as sum_census
605
            FROM(
606
                SELECT nuts3, cell_id, characteristics_code,
607
                        sum(DISTINCT(hh_5types))as orig
608
                FROM society.egon_destatis_zensus_household_per_ha_refined
609
                GROUP BY cell_id, characteristics_code, nuts3) AS t
610
            GROUP BY t.nuts3, t.characteristics_code    ) AS census
611
        ON refined.nuts3 = census.nuts3
612
        AND refined.characteristics_code = census.characteristics_code
613
    """
614
    )
615
616
    np.testing.assert_allclose(
617
        actual=df_refinement["sum_refined"],
618
        desired=df_refinement["sum_census"],
619
        rtol=rtol,
620
        verbose=False,
621
    )
622
623
    logger.info("All Aggregated household types match at NUTS-3.")
624
625
626
def cts_electricity_demand_share(rtol=1e-5):
627
    """Sanity check for dataset electricity_demand_timeseries :
628
    CtsBuildings
629
630
    Check sum of aggregated cts electricity demand share which equals to one
631
    for every substation as the substation profile is linearly disaggregated
632
    to all buildings."""
633
634
    with db.session_scope() as session:
635
        cells_query = session.query(EgonCtsElectricityDemandBuildingShare)
636
637
    df_demand_share = pd.read_sql(
638
        cells_query.statement, cells_query.session.bind, index_col=None
639
    )
640
641
    np.testing.assert_allclose(
642
        actual=df_demand_share.groupby(["bus_id", "scenario"])[
643
            "profile_share"
644
        ].sum(),
645
        desired=1,
646
        rtol=rtol,
647
        verbose=False,
648
    )
649
650
    logger.info("The aggregated demand shares equal to one!.")
651
652
653
def cts_heat_demand_share(rtol=1e-5):
654
    """Sanity check for dataset electricity_demand_timeseries
655
    : CtsBuildings
656
657
    Check sum of aggregated cts heat demand share which equals to one
658
    for every substation as the substation profile is linearly disaggregated
659
    to all buildings."""
660
661
    with db.session_scope() as session:
662
        cells_query = session.query(EgonCtsHeatDemandBuildingShare)
663
664
    df_demand_share = pd.read_sql(
665
        cells_query.statement, cells_query.session.bind, index_col=None
666
    )
667
668
    np.testing.assert_allclose(
669
        actual=df_demand_share.groupby(["bus_id", "scenario"])[
670
            "profile_share"
671
        ].sum(),
672
        desired=1,
673
        rtol=rtol,
674
        verbose=False,
675
    )
676
677
    logger.info("The aggregated demand shares equal to one!.")
678
679
680
def sanitycheck_pv_rooftop_buildings():
681
    def egon_power_plants_pv_roof_building():
682
        sql = """
683
        SELECT *
684
        FROM supply.egon_power_plants_pv_roof_building
685
        """
686
687
        return db.select_dataframe(sql, index_col="index")
688
689
    pv_roof_df = egon_power_plants_pv_roof_building()
690
691
    valid_buildings_gdf = load_building_data()
692
693
    valid_buildings_gdf = valid_buildings_gdf.assign(
694
        bus_id=valid_buildings_gdf.bus_id.astype(int),
695
        overlay_id=valid_buildings_gdf.overlay_id.astype(int),
696
        max_cap=valid_buildings_gdf.building_area.multiply(
697
            ROOF_FACTOR * PV_CAP_PER_SQ_M
698
        ),
699
    )
700
701
    merge_df = pv_roof_df.merge(
702
        valid_buildings_gdf[["building_area"]],
703
        how="left",
704
        left_on="building_id",
705
        right_index=True,
706
    )
707
708
    assert (
709
        len(merge_df.loc[merge_df.building_area.isna()]) == 0
710
    ), f"{len(merge_df.loc[merge_df.building_area.isna()])} != 0"
711
712
    scenarios = ["status_quo", "eGon2035"]
713
714
    base_path = Path(egon.data.__path__[0]).resolve()
715
716
    res_dir = base_path / "sanity_checks"
717
718
    res_dir.mkdir(parents=True, exist_ok=True)
719
720
    for scenario in scenarios:
721
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 8))
722
723
        scenario_df = merge_df.loc[merge_df.scenario == scenario]
724
725
        logger.info(
726
            scenario + " Capacity:\n" + str(scenario_df.capacity.describe())
727
        )
728
729
        small_gens_df = scenario_df.loc[scenario_df.capacity < 100]
730
731
        sns.histplot(data=small_gens_df, x="capacity", ax=ax1).set_title(
732
            scenario
733
        )
734
735
        sns.scatterplot(
736
            data=small_gens_df, x="capacity", y="building_area", ax=ax2
737
        ).set_title(scenario)
738
739
        plt.tight_layout()
740
741
        plt.savefig(
742
            res_dir / f"{scenario}_pv_rooftop_distribution.png",
743
            bbox_inches="tight",
744
        )
745
746
    for scenario in SCENARIOS:
747
        if scenario == "eGon2035":
748
            assert isclose(
749
                scenario_data(scenario=scenario).capacity.sum(),
750
                merge_df.loc[merge_df.scenario == scenario].capacity.sum(),
751
                rel_tol=1e-02,
752
            ), (
753
                f"{scenario_data(scenario=scenario).capacity.sum()} != "
754
                f"{merge_df.loc[merge_df.scenario == scenario].capacity.sum()}"
755
            )
756
        elif scenario == "eGon100RE":
757
            sources = config.datasets()["solar_rooftop"]["sources"]
758
759
            target = db.select_dataframe(
760
                f"""
761
                SELECT capacity
762
                FROM {sources['scenario_capacities']['schema']}.
763
                {sources['scenario_capacities']['table']} a
764
                WHERE carrier = 'solar_rooftop'
765
                AND scenario_name = '{scenario}'
766
                """
767
            ).capacity[0]
768
769
            dataset = config.settings()["egon-data"]["--dataset-boundary"]
770
771
            if dataset == "Schleswig-Holstein":
772
                # since the required data is missing for a SH run, it is implemented
773
                # manually here
774
                total_2035 = 84070
775
                sh_2035 = 2700
776
777
                share = sh_2035 / total_2035
778
779
                target *= share
780
781
            assert isclose(
782
                target,
783
                merge_df.loc[merge_df.scenario == scenario].capacity.sum(),
784
                rel_tol=1e-02,
785
            ), (
786
                f"{target} != "
787
                f"{merge_df.loc[merge_df.scenario == scenario].capacity.sum()}"
788
            )
789
        else:
790
            raise ValueError(f"Scenario {scenario} is not valid.")
791
792
793
def sanitycheck_emobility_mit():
794
    """Execute sanity checks for eMobility: motorized individual travel
795
796
    Checks data integrity for eGon2035, eGon2035_lowflex and eGon100RE scenario
797
    using assertions:
798
      1. Allocated EV numbers and EVs allocated to grid districts
799
      2. Trip data (original inout data from simBEV)
800
      3. Model data in eTraGo PF tables (grid.egon_etrago_*)
801
802
    Parameters
803
    ----------
804
    None
805
806
    Returns
807
    -------
808
    None
809
    """
810
811
    def check_ev_allocation():
812
        # Get target number for scenario
813
        ev_count_target = scenario_variation_parameters["ev_count"]
814
        print(f"  Target count: {str(ev_count_target)}")
815
816
        # Get allocated numbers
817
        ev_counts_dict = {}
818
        with db.session_scope() as session:
819
            for table, level in zip(
820
                [
821
                    EgonEvCountMvGridDistrict,
822
                    EgonEvCountMunicipality,
823
                    EgonEvCountRegistrationDistrict,
824
                ],
825
                ["Grid District", "Municipality", "Registration District"],
826
            ):
827
                query = session.query(
828
                    func.sum(
829
                        table.bev_mini
830
                        + table.bev_medium
831
                        + table.bev_luxury
832
                        + table.phev_mini
833
                        + table.phev_medium
834
                        + table.phev_luxury
835
                    ).label("ev_count")
836
                ).filter(
837
                    table.scenario == scenario_name,
838
                    table.scenario_variation == scenario_var_name,
839
                )
840
841
                ev_counts = pd.read_sql(
842
                    query.statement, query.session.bind, index_col=None
843
                )
844
                ev_counts_dict[level] = ev_counts.iloc[0].ev_count
845
                print(
846
                    f"    Count table: Total count for level {level} "
847
                    f"(table: {table.__table__}): "
848
                    f"{str(ev_counts_dict[level])}"
849
                )
850
851
        # Compare with scenario target (only if not in testmode)
852
        if TESTMODE_OFF:
853
            for level, count in ev_counts_dict.items():
854
                np.testing.assert_allclose(
855
                    count,
856
                    ev_count_target,
857
                    rtol=0.0001,
858
                    err_msg=f"EV numbers in {level} seems to be flawed.",
859
                )
860
        else:
861
            print("    Testmode is on, skipping sanity check...")
862
863
        # Get allocated EVs in grid districts
864
        with db.session_scope() as session:
865
            query = session.query(
866
                func.count(EgonEvMvGridDistrict.egon_ev_pool_ev_id).label(
867
                    "ev_count"
868
                ),
869
            ).filter(
870
                EgonEvMvGridDistrict.scenario == scenario_name,
871
                EgonEvMvGridDistrict.scenario_variation == scenario_var_name,
872
            )
873
        ev_count_alloc = (
874
            pd.read_sql(query.statement, query.session.bind, index_col=None)
875
            .iloc[0]
876
            .ev_count
877
        )
878
        print(
879
            f"    EVs allocated to Grid Districts "
880
            f"(table: {EgonEvMvGridDistrict.__table__}) total count: "
881
            f"{str(ev_count_alloc)}"
882
        )
883
884
        # Compare with scenario target (only if not in testmode)
885
        if TESTMODE_OFF:
886
            np.testing.assert_allclose(
887
                ev_count_alloc,
888
                ev_count_target,
889
                rtol=0.0001,
890
                err_msg=(
891
                    "EV numbers allocated to Grid Districts seems to be "
892
                    "flawed."
893
                ),
894
            )
895
        else:
896
            print("    Testmode is on, skipping sanity check...")
897
898
        return ev_count_alloc
899
900
    def check_trip_data():
901
        # Check if trips start at timestep 0 and have a max. of 35040 steps
902
        # (8760h in 15min steps)
903
        print("  Checking timeranges...")
904
        with db.session_scope() as session:
905
            query = session.query(
906
                func.count(EgonEvTrip.event_id).label("cnt")
907
            ).filter(
908
                or_(
909
                    and_(
910
                        EgonEvTrip.park_start > 0,
911
                        EgonEvTrip.simbev_event_id == 0,
912
                    ),
913
                    EgonEvTrip.park_end
914
                    > (60 / int(meta_run_config.stepsize)) * 8760,
915
                ),
916
                EgonEvTrip.scenario == scenario_name,
917
            )
918
        invalid_trips = pd.read_sql(
919
            query.statement, query.session.bind, index_col=None
920
        )
921
        np.testing.assert_equal(
922
            invalid_trips.iloc[0].cnt,
923
            0,
924
            err_msg=(
925
                f"{str(invalid_trips.iloc[0].cnt)} trips in table "
926
                f"{EgonEvTrip.__table__} have invalid timesteps."
927
            ),
928
        )
929
930
        # Check if charging demand can be covered by available charging energy
931
        # while parking
932
        print("  Compare charging demand with available power...")
933
        with db.session_scope() as session:
934
            query = session.query(
935
                func.count(EgonEvTrip.event_id).label("cnt")
936
            ).filter(
937
                func.round(
938
                    cast(
939
                        (EgonEvTrip.park_end - EgonEvTrip.park_start + 1)
940
                        * EgonEvTrip.charging_capacity_nominal
941
                        * (int(meta_run_config.stepsize) / 60),
942
                        Numeric,
943
                    ),
944
                    3,
945
                )
946
                < cast(EgonEvTrip.charging_demand, Numeric),
947
                EgonEvTrip.scenario == scenario_name,
948
            )
949
        invalid_trips = pd.read_sql(
950
            query.statement, query.session.bind, index_col=None
951
        )
952
        np.testing.assert_equal(
953
            invalid_trips.iloc[0].cnt,
954
            0,
955
            err_msg=(
956
                f"In {str(invalid_trips.iloc[0].cnt)} trips (table: "
957
                f"{EgonEvTrip.__table__}) the charging demand cannot be "
958
                f"covered by available charging power."
959
            ),
960
        )
961
962
    def check_model_data():
963
        # Check if model components were fully created
964
        print("  Check if all model components were created...")
965
        # Get MVGDs which got EV allocated
966
        with db.session_scope() as session:
967
            query = (
968
                session.query(
969
                    EgonEvMvGridDistrict.bus_id,
970
                )
971
                .filter(
972
                    EgonEvMvGridDistrict.scenario == scenario_name,
973
                    EgonEvMvGridDistrict.scenario_variation
974
                    == scenario_var_name,
975
                )
976
                .group_by(EgonEvMvGridDistrict.bus_id)
977
            )
978
        mvgds_with_ev = (
979
            pd.read_sql(query.statement, query.session.bind, index_col=None)
980
            .bus_id.sort_values()
981
            .to_list()
982
        )
983
984
        # Load model components
985
        with db.session_scope() as session:
986
            query = (
987
                session.query(
988
                    EgonPfHvLink.bus0.label("mvgd_bus_id"),
989
                    EgonPfHvLoad.bus.label("emob_bus_id"),
990
                    EgonPfHvLoad.load_id.label("load_id"),
991
                    EgonPfHvStore.store_id.label("store_id"),
992
                )
993
                .select_from(EgonPfHvLoad, EgonPfHvStore)
994
                .join(
995
                    EgonPfHvLoadTimeseries,
996
                    EgonPfHvLoadTimeseries.load_id == EgonPfHvLoad.load_id,
997
                )
998
                .join(
999
                    EgonPfHvStoreTimeseries,
1000
                    EgonPfHvStoreTimeseries.store_id == EgonPfHvStore.store_id,
1001
                )
1002
                .filter(
1003
                    EgonPfHvLoad.carrier == "land transport EV",
1004
                    EgonPfHvLoad.scn_name == scenario_name,
1005
                    EgonPfHvLoadTimeseries.scn_name == scenario_name,
1006
                    EgonPfHvStore.carrier == "battery storage",
1007
                    EgonPfHvStore.scn_name == scenario_name,
1008
                    EgonPfHvStoreTimeseries.scn_name == scenario_name,
1009
                    EgonPfHvLink.scn_name == scenario_name,
1010
                    EgonPfHvLink.bus1 == EgonPfHvLoad.bus,
1011
                    EgonPfHvLink.bus1 == EgonPfHvStore.bus,
1012
                )
1013
            )
1014
        model_components = pd.read_sql(
1015
            query.statement, query.session.bind, index_col=None
1016
        )
1017
1018
        # Check number of buses with model components connected
1019
        mvgd_buses_with_ev = model_components.loc[
1020
            model_components.mvgd_bus_id.isin(mvgds_with_ev)
1021
        ]
1022
        np.testing.assert_equal(
1023
            len(mvgds_with_ev),
1024
            len(mvgd_buses_with_ev),
1025
            err_msg=(
1026
                f"Number of Grid Districts with connected model components "
1027
                f"({str(len(mvgd_buses_with_ev))} in tables egon_etrago_*) "
1028
                f"differ from number of Grid Districts that got EVs "
1029
                f"allocated ({len(mvgds_with_ev)} in table "
1030
                f"{EgonEvMvGridDistrict.__table__})."
1031
            ),
1032
        )
1033
1034
        # Check if all required components exist (if no id is NaN)
1035
        np.testing.assert_equal(
1036
            model_components.drop_duplicates().isna().any().any(),
1037
            False,
1038
            err_msg=(
1039
                f"Some components are missing (see True values): "
1040
                f"{model_components.drop_duplicates().isna().any()}"
1041
            ),
1042
        )
1043
1044
        # Get all model timeseries
1045
        print("  Loading model timeseries...")
1046
        # Get all model timeseries
1047
        model_ts_dict = {
1048
            "Load": {
1049
                "carrier": "land transport EV",
1050
                "table": EgonPfHvLoad,
1051
                "table_ts": EgonPfHvLoadTimeseries,
1052
                "column_id": "load_id",
1053
                "columns_ts": ["p_set"],
1054
                "ts": None,
1055
            },
1056
            "Link": {
1057
                "carrier": "BEV charger",
1058
                "table": EgonPfHvLink,
1059
                "table_ts": EgonPfHvLinkTimeseries,
1060
                "column_id": "link_id",
1061
                "columns_ts": ["p_max_pu"],
1062
                "ts": None,
1063
            },
1064
            "Store": {
1065
                "carrier": "battery storage",
1066
                "table": EgonPfHvStore,
1067
                "table_ts": EgonPfHvStoreTimeseries,
1068
                "column_id": "store_id",
1069
                "columns_ts": ["e_min_pu", "e_max_pu"],
1070
                "ts": None,
1071
            },
1072
        }
1073
1074
        with db.session_scope() as session:
1075
            for node, attrs in model_ts_dict.items():
1076
                print(f"    Loading {node} timeseries...")
1077
                subquery = (
1078
                    session.query(getattr(attrs["table"], attrs["column_id"]))
1079
                    .filter(attrs["table"].carrier == attrs["carrier"])
1080
                    .filter(attrs["table"].scn_name == scenario_name)
1081
                    .subquery()
1082
                )
1083
1084
                cols = [
1085
                    getattr(attrs["table_ts"], c) for c in attrs["columns_ts"]
1086
                ]
1087
                query = session.query(
1088
                    getattr(attrs["table_ts"], attrs["column_id"]), *cols
1089
                ).filter(
1090
                    getattr(attrs["table_ts"], attrs["column_id"]).in_(
1091
                        subquery
1092
                    ),
1093
                    attrs["table_ts"].scn_name == scenario_name,
1094
                )
1095
                attrs["ts"] = pd.read_sql(
1096
                    query.statement,
1097
                    query.session.bind,
1098
                    index_col=attrs["column_id"],
1099
                )
1100
1101
        # Check if all timeseries have 8760 steps
1102
        print("    Checking timeranges...")
1103
        for node, attrs in model_ts_dict.items():
1104
            for col in attrs["columns_ts"]:
1105
                ts = attrs["ts"]
1106
                invalid_ts = ts.loc[ts[col].apply(lambda _: len(_)) != 8760][
1107
                    col
1108
                ].apply(len)
1109
                np.testing.assert_equal(
1110
                    len(invalid_ts),
1111
                    0,
1112
                    err_msg=(
1113
                        f"{str(len(invalid_ts))} rows in timeseries do not "
1114
                        f"have 8760 timesteps. Table: "
1115
                        f"{attrs['table_ts'].__table__}, Column: {col}, IDs: "
1116
                        f"{str(list(invalid_ts.index))}"
1117
                    ),
1118
                )
1119
1120
        # Compare total energy demand in model with some approximate values
1121
        # (per EV: 14,000 km/a, 0.17 kWh/km)
1122
        print("  Checking energy demand in model...")
1123
        total_energy_model = (
1124
            model_ts_dict["Load"]["ts"].p_set.apply(lambda _: sum(_)).sum()
1125
            / 1e6
1126
        )
1127
        print(f"    Total energy amount in model: {total_energy_model} TWh")
1128
        total_energy_scenario_approx = ev_count_alloc * 14000 * 0.17 / 1e9
1129
        print(
1130
            f"    Total approximated energy amount in scenario: "
1131
            f"{total_energy_scenario_approx} TWh"
1132
        )
1133
        np.testing.assert_allclose(
1134
            total_energy_model,
1135
            total_energy_scenario_approx,
1136
            rtol=0.1,
1137
            err_msg=(
1138
                "The total energy amount in the model deviates heavily "
1139
                "from the approximated value for current scenario."
1140
            ),
1141
        )
1142
1143
        # Compare total storage capacity
1144
        print("  Checking storage capacity...")
1145
        # Load storage capacities from model
1146
        with db.session_scope() as session:
1147
            query = session.query(
1148
                func.sum(EgonPfHvStore.e_nom).label("e_nom")
1149
            ).filter(
1150
                EgonPfHvStore.scn_name == scenario_name,
1151
                EgonPfHvStore.carrier == "battery storage",
1152
            )
1153
        storage_capacity_model = (
1154
            pd.read_sql(
1155
                query.statement, query.session.bind, index_col=None
1156
            ).e_nom.sum()
1157
            / 1e3
1158
        )
1159
        print(
1160
            f"    Total storage capacity ({EgonPfHvStore.__table__}): "
1161
            f"{round(storage_capacity_model, 1)} GWh"
1162
        )
1163
1164
        # Load occurences of each EV
1165
        with db.session_scope() as session:
1166
            query = (
1167
                session.query(
1168
                    EgonEvMvGridDistrict.bus_id,
1169
                    EgonEvPool.type,
1170
                    func.count(EgonEvMvGridDistrict.egon_ev_pool_ev_id).label(
1171
                        "count"
1172
                    ),
1173
                )
1174
                .join(
1175
                    EgonEvPool,
1176
                    EgonEvPool.ev_id
1177
                    == EgonEvMvGridDistrict.egon_ev_pool_ev_id,
1178
                )
1179
                .filter(
1180
                    EgonEvMvGridDistrict.scenario == scenario_name,
1181
                    EgonEvMvGridDistrict.scenario_variation
1182
                    == scenario_var_name,
1183
                    EgonEvPool.scenario == scenario_name,
1184
                )
1185
                .group_by(EgonEvMvGridDistrict.bus_id, EgonEvPool.type)
1186
            )
1187
        count_per_ev_all = pd.read_sql(
1188
            query.statement, query.session.bind, index_col="bus_id"
1189
        )
1190
        count_per_ev_all["bat_cap"] = count_per_ev_all.type.map(
1191
            meta_tech_data.battery_capacity
1192
        )
1193
        count_per_ev_all["bat_cap_total_MWh"] = (
1194
            count_per_ev_all["count"] * count_per_ev_all.bat_cap / 1e3
1195
        )
1196
        storage_capacity_simbev = count_per_ev_all.bat_cap_total_MWh.div(
1197
            1e3
1198
        ).sum()
1199
        print(
1200
            f"    Total storage capacity (simBEV): "
1201
            f"{round(storage_capacity_simbev, 1)} GWh"
1202
        )
1203
1204
        np.testing.assert_allclose(
1205
            storage_capacity_model,
1206
            storage_capacity_simbev,
1207
            rtol=0.01,
1208
            err_msg=(
1209
                "The total storage capacity in the model deviates heavily "
1210
                "from the input data provided by simBEV for current scenario."
1211
            ),
1212
        )
1213
1214
        # Check SoC storage constraint: e_min_pu < e_max_pu for all timesteps
1215
        print("  Validating SoC constraints...")
1216
        stores_with_invalid_soc = []
1217
        for idx, row in model_ts_dict["Store"]["ts"].iterrows():
1218
            ts = row[["e_min_pu", "e_max_pu"]]
1219
            x = np.array(ts.e_min_pu) > np.array(ts.e_max_pu)
1220
            if x.any():
1221
                stores_with_invalid_soc.append(idx)
1222
1223
        np.testing.assert_equal(
1224
            len(stores_with_invalid_soc),
1225
            0,
1226
            err_msg=(
1227
                f"The store constraint e_min_pu < e_max_pu does not apply "
1228
                f"for some storages in {EgonPfHvStoreTimeseries.__table__}. "
1229
                f"Invalid store_ids: {stores_with_invalid_soc}"
1230
            ),
1231
        )
1232
1233
    def check_model_data_lowflex_eGon2035():
1234
        # TODO: Add eGon100RE_lowflex
1235
        print("")
1236
        print("SCENARIO: eGon2035_lowflex")
1237
1238
        # Compare driving load and charging load
1239
        print("  Loading eGon2035 model timeseries: driving load...")
1240
        with db.session_scope() as session:
1241
            query = (
1242
                session.query(
1243
                    EgonPfHvLoad.load_id,
1244
                    EgonPfHvLoadTimeseries.p_set,
1245
                )
1246
                .join(
1247
                    EgonPfHvLoadTimeseries,
1248
                    EgonPfHvLoadTimeseries.load_id == EgonPfHvLoad.load_id,
1249
                )
1250
                .filter(
1251
                    EgonPfHvLoad.carrier == "land transport EV",
1252
                    EgonPfHvLoad.scn_name == "eGon2035",
1253
                    EgonPfHvLoadTimeseries.scn_name == "eGon2035",
1254
                )
1255
            )
1256
        model_driving_load = pd.read_sql(
1257
            query.statement, query.session.bind, index_col=None
1258
        )
1259
        driving_load = np.array(model_driving_load.p_set.to_list()).sum(axis=0)
1260
1261
        print(
1262
            "  Loading eGon2035_lowflex model timeseries: dumb charging "
1263
            "load..."
1264
        )
1265
        with db.session_scope() as session:
1266
            query = (
1267
                session.query(
1268
                    EgonPfHvLoad.load_id,
1269
                    EgonPfHvLoadTimeseries.p_set,
1270
                )
1271
                .join(
1272
                    EgonPfHvLoadTimeseries,
1273
                    EgonPfHvLoadTimeseries.load_id == EgonPfHvLoad.load_id,
1274
                )
1275
                .filter(
1276
                    EgonPfHvLoad.carrier == "land transport EV",
1277
                    EgonPfHvLoad.scn_name == "eGon2035_lowflex",
1278
                    EgonPfHvLoadTimeseries.scn_name == "eGon2035_lowflex",
1279
                )
1280
            )
1281
        model_charging_load_lowflex = pd.read_sql(
1282
            query.statement, query.session.bind, index_col=None
1283
        )
1284
        charging_load = np.array(
1285
            model_charging_load_lowflex.p_set.to_list()
1286
        ).sum(axis=0)
1287
1288
        # Ratio of driving and charging load should be 0.9 due to charging
1289
        # efficiency
1290
        print("  Compare cumulative loads...")
1291
        print(f"    Driving load (eGon2035): {driving_load.sum() / 1e6} TWh")
1292
        print(
1293
            f"    Dumb charging load (eGon2035_lowflex): "
1294
            f"{charging_load.sum() / 1e6} TWh"
1295
        )
1296
        driving_load_theoretical = (
1297
            float(meta_run_config.eta_cp) * charging_load.sum()
0 ignored issues
show
introduced by
The variable meta_run_config does not seem to be defined in case the for loop on line 1315 is not entered. Are you sure this can never be the case?
Loading history...
1298
        )
1299
        np.testing.assert_allclose(
1300
            driving_load.sum(),
1301
            driving_load_theoretical,
1302
            rtol=0.01,
1303
            err_msg=(
1304
                f"The driving load (eGon2035) deviates by more than 1% "
1305
                f"from the theoretical driving load calculated from charging "
1306
                f"load (eGon2035_lowflex) with an efficiency of "
1307
                f"{float(meta_run_config.eta_cp)}."
1308
            ),
1309
        )
1310
1311
    print("=====================================================")
1312
    print("=== SANITY CHECKS FOR MOTORIZED INDIVIDUAL TRAVEL ===")
1313
    print("=====================================================")
1314
1315
    for scenario_name in ["eGon2035", "eGon100RE"]:
1316
        scenario_var_name = DATASET_CFG["scenario"]["variation"][scenario_name]
1317
1318
        print("")
1319
        print(f"SCENARIO: {scenario_name}, VARIATION: {scenario_var_name}")
1320
1321
        # Load scenario params for scenario and scenario variation
1322
        scenario_variation_parameters = get_sector_parameters(
1323
            "mobility", scenario=scenario_name
1324
        )["motorized_individual_travel"][scenario_var_name]
1325
1326
        # Load simBEV run config and tech data
1327
        meta_run_config = read_simbev_metadata_file(
1328
            scenario_name, "config"
1329
        ).loc["basic"]
1330
        meta_tech_data = read_simbev_metadata_file(scenario_name, "tech_data")
1331
1332
        print("")
1333
        print("Checking EV counts...")
1334
        ev_count_alloc = check_ev_allocation()
1335
1336
        print("")
1337
        print("Checking trip data...")
1338
        check_trip_data()
1339
1340
        print("")
1341
        print("Checking model data...")
1342
        check_model_data()
1343
1344
    print("")
1345
    check_model_data_lowflex_eGon2035()
1346
1347
    print("=====================================================")
1348