Passed
Pull Request — dev (#1375)
by
unknown
02:18
created

MotorizedIndividualTravel.__init__()   C

Complexity

Conditions 7

Size

Total Lines 274
Code Lines 199

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 199
dl 0
loc 274
rs 5.6
c 0
b 0
f 0
cc 7
nop 2

How to fix   Long Method   

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:

1
"""
2
Main module for preparation of model data (static and timeseries) for
3
motorized individual travel (MIT).
4
5
**Contents of this module**
6
  * Creation of DB tables
7
  * Download and preprocessing of vehicle registration data from KBA and BMVI
8
  * Calculate number of electric vehicles and allocate on different spatial
9
    levels.
10
  * Extract and write pre-generated trips to DB
11
12
"""
13
14
from pathlib import Path
15
from urllib.request import urlretrieve
16
import os
17
import tarfile
18
19
from airflow.operators.python import PythonOperator
20
from psycopg2.extensions import AsIs, register_adapter
21
import numpy as np
22
import pandas as pd
23
24
from egon.data import config, db, subprocess
25
from egon.data.datasets import Dataset
26
from egon.data.datasets.emobility.motorized_individual_travel.db_classes import (  # noqa: E501
27
    EgonEvCountMunicipality,
28
    EgonEvCountMvGridDistrict,
29
    EgonEvCountRegistrationDistrict,
30
    EgonEvMetadata,
31
    EgonEvMvGridDistrict,
32
    EgonEvPool,
33
    EgonEvTrip,
34
    add_metadata,
35
)
36
from egon.data.datasets.emobility.motorized_individual_travel.ev_allocation import (  # noqa: E501
37
    allocate_evs_numbers,
38
    allocate_evs_to_grid_districts,
39
)
40
from egon.data.datasets.emobility.motorized_individual_travel.helpers import (
41
    COLUMNS_KBA,
42
    DATA_BUNDLE_DIR,
43
    DATASET_CFG,
44
    MVGD_MIN_COUNT,
45
    TESTMODE_OFF,
46
    TRIP_COLUMN_MAPPING,
47
    WORKING_DIR,
48
)
49
from egon.data.datasets.emobility.motorized_individual_travel.model_timeseries import (  # noqa: E501
50
    delete_model_data_from_db,
51
    generate_model_data_bunch,
52
    generate_model_data_eGon100RE_remaining,
53
    generate_model_data_eGon2035_remaining,
54
    generate_model_data_status2019_remaining,
55
    generate_model_data_status2023_remaining,
56
    read_simbev_metadata_file,
57
)
58
59
from egon_validation import (
60
    RowCountValidation,
61
    DataTypeValidation,
62
    WholeTableNotNullAndNotNaNValidation,
63
    ValueSetValidation
64
)
65
66
67
# ========== Register np datatypes with SQLA ==========
68
def adapt_numpy_float64(numpy_float64):
69
    return AsIs(numpy_float64)
70
71
72
def adapt_numpy_int64(numpy_int64):
73
    return AsIs(numpy_int64)
74
75
76
register_adapter(np.float64, adapt_numpy_float64)
77
register_adapter(np.int64, adapt_numpy_int64)
78
# =====================================================
79
80
81
def create_tables():
82
    """Create tables for electric vehicles
83
84
    Returns
85
    -------
86
    None
87
    """
88
89
    engine = db.engine()
90
    EgonEvCountRegistrationDistrict.__table__.drop(
91
        bind=engine, checkfirst=True
92
    )
93
    EgonEvCountRegistrationDistrict.__table__.create(
94
        bind=engine, checkfirst=True
95
    )
96
    EgonEvCountMunicipality.__table__.drop(bind=engine, checkfirst=True)
97
    EgonEvCountMunicipality.__table__.create(bind=engine, checkfirst=True)
98
    EgonEvCountMvGridDistrict.__table__.drop(bind=engine, checkfirst=True)
99
    EgonEvCountMvGridDistrict.__table__.create(bind=engine, checkfirst=True)
100
    EgonEvPool.__table__.drop(bind=engine, checkfirst=True)
101
    EgonEvPool.__table__.create(bind=engine, checkfirst=True)
102
    EgonEvTrip.__table__.drop(bind=engine, checkfirst=True)
103
    EgonEvTrip.__table__.create(bind=engine, checkfirst=True)
104
    EgonEvMvGridDistrict.__table__.drop(bind=engine, checkfirst=True)
105
    EgonEvMvGridDistrict.__table__.create(bind=engine, checkfirst=True)
106
    EgonEvMetadata.__table__.drop(bind=engine, checkfirst=True)
107
    EgonEvMetadata.__table__.create(bind=engine, checkfirst=True)
108
109
    # Create dir for results, if it does not exist
110
    result_dir = WORKING_DIR / Path("results")
111
    result_dir.mkdir(exist_ok=True, parents=True)
112
113
114
def download_and_preprocess():
115
    """Downloads and preprocesses data from KBA and BMVI
116
117
    Returns
118
    -------
119
    pandas.DataFrame
120
        Vehicle registration data for registration district
121
    pandas.DataFrame
122
        RegioStaR7 data
123
    """
124
125
    mit_sources = DATASET_CFG["original_data"]["sources"]
126
127
    # Create the folder, if it does not exist
128
    if not os.path.exists(WORKING_DIR):
129
        os.mkdir(WORKING_DIR)
130
131
    ################################
132
    # Download and import KBA data #
133
    ################################
134
    url = mit_sources["KBA"]["url"]
135
    file = WORKING_DIR / mit_sources["KBA"]["file"]
136
    if not os.path.isfile(file):
137
        urlretrieve(url, file)
138
139
    kba_data = pd.read_excel(
140
        file,
141
        sheet_name=mit_sources["KBA"]["sheet"],
142
        usecols=mit_sources["KBA"]["columns"],
143
        skiprows=mit_sources["KBA"]["skiprows"],
144
    )
145
    kba_data.columns = COLUMNS_KBA
146
    kba_data.replace(
147
        " ",
148
        np.nan,
149
        inplace=True,
150
    )
151
    kba_data = kba_data.dropna()
152
    kba_data[["ags_reg_district", "reg_district"]] = (
153
        kba_data.reg_district.str.split(
154
            pat=" ",
155
            n=1,
156
            expand=True,
157
        )
158
    )
159
    kba_data.ags_reg_district = kba_data.ags_reg_district.astype("int")
160
161
    kba_data.to_csv(
162
        WORKING_DIR / mit_sources["KBA"]["file_processed"], index=None
163
    )
164
165
    #######################################
166
    # Download and import RegioStaR7 data #
167
    #######################################
168
169
    url = mit_sources["RS7"]["url"]
170
    file = WORKING_DIR / mit_sources["RS7"]["file"]
171
    if not os.path.isfile(file):
172
        urlretrieve(url, file)
173
174
    rs7_data = pd.read_excel(file, sheet_name=mit_sources["RS7"]["sheet"])
175
176
    rs7_data["ags_district"] = (
177
        rs7_data.gem_20.multiply(1 / 1000).apply(np.floor).astype("int")
178
    )
179
    rs7_data = rs7_data.rename(
180
        columns={"gem_20": "ags", "RegioStaR7": "rs7_id"}
181
    )
182
    rs7_data.rs7_id = rs7_data.rs7_id.astype("int")
183
184
    rs7_data.to_csv(
185
        WORKING_DIR / mit_sources["RS7"]["file_processed"], index=None
186
    )
187
188
189
def extract_trip_file():
190
    """Extract trip file from data bundle"""
191
    trip_dir = DATA_BUNDLE_DIR / Path("mit_trip_data")
192
193
    for scenario_name in config.settings()["egon-data"]["--scenarios"]:
194
        print(f"SCENARIO: {scenario_name}")
195
        trip_file = trip_dir / Path(
196
            DATASET_CFG["original_data"]["sources"]["trips"][scenario_name][
197
                "file"
198
            ]
199
        )
200
201
        tar = tarfile.open(trip_file)
202
        if os.path.isfile(trip_file):
203
            tar.extractall(trip_dir)
204
        else:
205
            raise FileNotFoundError(
206
                f"Trip file {trip_file} not found in data bundle."
207
            )
208
209
210
def write_evs_trips_to_db():
211
    """Write EVs and trips generated by simBEV from data bundle to database
212
    table
213
    """
214
215
    def import_csv(f):
216
        df = pd.read_csv(f, usecols=TRIP_COLUMN_MAPPING.keys())
217
        df["rs7_id"] = int(f.parent.name)
218
        df["simbev_ev_id"] = "_".join(f.name.split("_")[0:3])
219
        return df
220
221
    for scenario_name in config.settings()["egon-data"]["--scenarios"]:
222
        print(f"SCENARIO: {scenario_name}")
223
        trip_dir_name = Path(
224
            DATASET_CFG["original_data"]["sources"]["trips"][scenario_name][
225
                "file"
226
            ].split(".")[0]
227
        )
228
229
        trip_dir_root = DATA_BUNDLE_DIR / Path("mit_trip_data", trip_dir_name)
230
231
        if TESTMODE_OFF:
232
            trip_files = list(trip_dir_root.glob("*/*.csv"))
233
        else:
234
            # Load only 1000 EVs per region if in test mode
235
            trip_files = [
236
                list(rdir.glob("*.csv"))[:1000]
237
                for rdir in [_ for _ in trip_dir_root.iterdir() if _.is_dir()]
238
            ]
239
            # Flatten
240
            trip_files = [i for sub in trip_files for i in sub]
241
242
        # Read, concat and reorder cols
243
        print(f"Importing {len(trip_files)} EV trip CSV files...")
244
        trip_data = pd.concat(map(import_csv, trip_files))
245
        trip_data.rename(columns=TRIP_COLUMN_MAPPING, inplace=True)
246
        trip_data = trip_data.reset_index().rename(
247
            columns={"index": "simbev_event_id"}
248
        )
249
        cols = ["rs7_id", "simbev_ev_id", "simbev_event_id"] + list(
250
            TRIP_COLUMN_MAPPING.values()
251
        )
252
        trip_data.index.name = "event_id"
253
        trip_data = trip_data[cols]
254
255
        # Extract EVs from trips
256
        evs_unique = trip_data[["rs7_id", "simbev_ev_id"]].drop_duplicates()
257
        evs_unique = evs_unique.reset_index().drop(columns=["event_id"])
258
        evs_unique.index.name = "ev_id"
259
260
        # Add EV id to trip DF
261
        trip_data["egon_ev_pool_ev_id"] = pd.merge(
262
            trip_data, evs_unique.reset_index(), on=["rs7_id", "simbev_ev_id"]
263
        )["ev_id"]
264
265
        # Split simBEV id into type and id
266
        evs_unique[["type", "simbev_ev_id"]] = evs_unique[
267
            "simbev_ev_id"
268
        ].str.rsplit(pat="_", n=1, expand=True)
269
        evs_unique.simbev_ev_id = evs_unique.simbev_ev_id.astype(int)
270
        evs_unique["scenario"] = scenario_name
271
272
        trip_data.drop(columns=["rs7_id", "simbev_ev_id"], inplace=True)
273
        trip_data["scenario"] = scenario_name
274
        trip_data.sort_index(inplace=True)
275
276
        # Write EVs to DB
277
        print("Writing EVs to DB pool...")
278
        evs_unique.to_sql(
279
            name=EgonEvPool.__table__.name,
280
            schema=EgonEvPool.__table__.schema,
281
            con=db.engine(),
282
            if_exists="append",
283
            index=True,
284
        )
285
286
        # Write trips to CSV and import to DB
287
        print("Writing EV trips to CSV file...")
288
        trip_file = WORKING_DIR / f"trip_data_{scenario_name}.csv"
289
        trip_data.to_csv(trip_file)
290
291
        # Get DB config
292
        docker_db_config = db.credentials()
293
        host = ["-h", f"{docker_db_config['HOST']}"]
294
        port = ["-p", f"{docker_db_config['PORT']}"]
295
        pgdb = ["-d", f"{docker_db_config['POSTGRES_DB']}"]
296
        user = ["-U", f"{docker_db_config['POSTGRES_USER']}"]
297
        command = [
298
            "-c",
299
            rf"\copy {EgonEvTrip.__table__.schema}.{EgonEvTrip.__table__.name}"
300
            rf"({','.join(trip_data.reset_index().columns)})"
301
            rf" FROM '{str(trip_file)}' DELIMITER ',' CSV HEADER;",
302
        ]
303
304
        print("Importing EV trips from CSV file to DB...")
305
        subprocess.run(
306
            ["psql"] + host + port + pgdb + user + command,
307
            env={"PGPASSWORD": docker_db_config["POSTGRES_PASSWORD"]},
308
        )
309
310
        os.remove(trip_file)
311
312
313
def write_metadata_to_db():
314
    """
315
    Write used SimBEV metadata per scenario to database.
316
    """
317
    dtypes = {
318
        "scenario": str,
319
        "eta_cp": float,
320
        "stepsize": int,
321
        "start_date": "datetime64[ns]",
322
        "end_date": "datetime64[ns]",
323
        "soc_min": float,
324
        "grid_timeseries": bool,
325
        "grid_timeseries_by_usecase": bool,
326
    }
327
328
    for scenario_name in config.settings()["egon-data"]["--scenarios"]:
329
        meta_run_config = read_simbev_metadata_file(
330
            scenario_name, "config"
331
        ).loc["basic"]
332
333
        meta_run_config = (
334
            meta_run_config.to_frame()
335
            .T.assign(scenario=scenario_name)[dtypes.keys()]
336
            .astype(dtypes)
337
        )
338
339
        meta_run_config.to_sql(
340
            name=EgonEvMetadata.__table__.name,
341
            schema=EgonEvMetadata.__table__.schema,
342
            con=db.engine(),
343
            if_exists="append",
344
            index=False,
345
        )
346
347
348
class MotorizedIndividualTravel(Dataset):
349
    """
350
    Class to set up static and timeseries data for motorized individual travel (MIT).
351
352
    For more information see data documentation on :ref:`mobility-demand-mit-ref`.
353
354
    *Dependencies*
355
      * :py:class:`DataBundle <egon.data.datasets.data_bundle.DataBundle>`
356
      * :py:class:`MvGridDistricts
357
        <egon.data.datasets.mv_grid_districts.mv_grid_districts_setup>`
358
      * :py:class:`ScenarioParameters
359
        <egon.data.datasets.scenario_parameters.ScenarioParameters>`
360
      * :py:class:`EtragoSetup <egon.data.datasets.etrago_setup.EtragoSetup>`
361
      * :py:class:`ZensusMvGridDistricts
362
        <egon.data.datasets.zensus_mv_grid_districts.ZensusMvGridDistricts>`
363
      * :py:class:`ZensusVg250 <egon.data.datasets.zensus_vg250.ZensusVg250>`
364
      * :py:class:`StorageEtrago <egon.data.datasets.storages_etrago.StorageEtrago>`
365
      * :py:class:`HtsEtragoTable
366
        <egon.data.datasets.heat_etrago.hts_etrago.HtsEtragoTable>`
367
      * :py:class:`ChpEtrago <egon.data.datasets.chp_etrago.ChpEtrago>`
368
      * :py:class:`DsmPotential <egon.data.datasets.DSM_cts_ind.DsmPotential>`
369
      * :py:class:`HeatEtrago <egon.data.datasets.heat_etrago.HeatEtrago>`
370
      * :py:class:`Egon_etrago_gen <egon.data.datasets.fill_etrago_gen.Egon_etrago_gen>`
371
      * :py:class:`OpenCycleGasTurbineEtrago
372
        <egon.data.datasets.power_etrago.OpenCycleGasTurbineEtrago>`
373
      * :py:class:`HydrogenStoreEtrago
374
        <egon.data.datasets.hydrogen_etrago.HydrogenStoreEtrago>`
375
      * :py:class:`HydrogenPowerLinkEtrago
376
        <egon.data.datasets.hydrogen_etrago.HydrogenPowerLinkEtrago>`
377
      * :py:class:`HydrogenMethaneLinkEtrago
378
        <egon.data.datasets.hydrogen_etrago.HydrogenMethaneLinkEtrago>`
379
      * :py:class:`GasAreaseGon100RE <egon.data.datasets.gas_areas.GasAreaseGon100RE>`
380
      * :py:class:`CH4Production <egon.data.datasets.ch4_prod.CH4Production>`
381
      * :py:class:`CH4Storages <egon.data.datasets.ch4_storages.CH4Storages>`
382
383
    *Resulting Tables*
384
      * :py:class:`EgonEvPool <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvPool>`
385
        is created and filled
386
      * :py:class:`EgonEvTrip <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvTrip>`
387
        is created and filled
388
      * :py:class:`EgonEvCountRegistrationDistrict <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvCountRegistrationDistrict>`
389
        is created and filled
390
      * :py:class:`EgonEvCountMunicipality <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvCountMunicipality>`
391
        is created and filled
392
      * :py:class:`EgonEvCountMvGridDistrict <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvCountMvGridDistrict>`
393
        is created and filled
394
      * :py:class:`EgonEvMvGridDistrict <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvMvGridDistrict>`
395
        is created and filled
396
      * :py:class:`EgonEvMetadata <egon.data.datasets.emobility.motorized_individual_travel.db_classes.EgonEvMetadata>`
397
        is created and filled
398
399
    *Configuration*
400
401
    The config of this dataset can be found in *datasets.yml* in section
402
    *emobility_mit*.
403
404
    """
405
406
    #:
407
    name: str = "MotorizedIndividualTravel"
408
    #:
409
    version: str = "0.0.7"
410
411
    def __init__(self, dependencies):
412
        def generate_model_data_tasks(scenario_name):
413
            """Dynamically generate tasks for model data creation.
414
415
            The goal is to speed up the creation of model timeseries. However,
416
            the exact number of parallel task cannot be determined during the
417
            DAG building as the number of grid districts (MVGD) is calculated
418
            within another pipeline task.
419
            Approach: assuming an approx. count of `mvgd_min_count` of 3700,
420
            the majority of the MVGDs can be parallelized. The remainder is
421
            handled subsequently in XXX.
422
            The number of parallel tasks is defined via parameter
423
            `parallel_tasks` in the dataset config `datasets.yml`.
424
425
            Parameters
426
            ----------
427
            scenario_name : str
428
                Scenario name
429
430
            Returns
431
            -------
432
            set of functools.partial
433
                The tasks. Each element is of
434
                :func:`egon.data.datasets.emobility.motorized_individual_travel.model_timeseries.generate_model_data`
435
            """
436
            parallel_tasks = DATASET_CFG["model_timeseries"].get(
437
                "parallel_tasks", 1
438
            )
439
            mvgd_bunch_size = divmod(MVGD_MIN_COUNT, parallel_tasks)[0]
440
441
            tasks = set()
442
            for _ in range(parallel_tasks):
443
                bunch = range(_ * mvgd_bunch_size, (_ + 1) * mvgd_bunch_size)
444
                tasks.add(
445
                    PythonOperator(
446
                        task_id=(
447
                            f"generate_model_data_"
448
                            f"{scenario_name}_"
449
                            f"bunch{bunch[0]}-{bunch[-1]}"
450
                        ),
451
                        python_callable=generate_model_data_bunch,
452
                        op_kwargs={
453
                            "scenario_name": scenario_name,
454
                            "bunch": bunch,
455
                        },
456
                    )
457
                )
458
459
            if scenario_name == "status2019":
460
                tasks.add(generate_model_data_status2019_remaining)
461
            if scenario_name == "status2023":
462
                tasks.add(generate_model_data_status2023_remaining)
463
            elif scenario_name == "eGon2035":
464
                tasks.add(generate_model_data_eGon2035_remaining)
465
            elif scenario_name == "eGon100RE":
466
                tasks.add(generate_model_data_eGon100RE_remaining)
467
            return tasks
468
469
        tasks = (
470
            create_tables,
471
            {
472
                (
473
                    download_and_preprocess,
474
                    allocate_evs_numbers,
475
                ),
476
                (
477
                    extract_trip_file,
478
                    write_metadata_to_db,
479
                    write_evs_trips_to_db,
480
                ),
481
            },
482
            allocate_evs_to_grid_districts,
483
            delete_model_data_from_db,
484
        )
485
486
        tasks_per_scenario = set()
487
488
        for scenario_name in config.settings()["egon-data"]["--scenarios"]:
489
            tasks_per_scenario.update(
490
                generate_model_data_tasks(scenario_name=scenario_name)
491
            )
492
493
        tasks = tasks + (tasks_per_scenario,)
494
495
        super().__init__(
496
            name=self.name,
497
            version=self.version,
498
            dependencies=dependencies,
499
            tasks=tasks,
500
            validation={
501
                "data_quality": [
502
                    RowCountValidation(
503
                        table=" demand.egon_ev_count_municipality",
504
                        rule_id="ROW_COUNT.egon_ev_count_municipality",
505
                        expected_count={"Schleswig-Holstein": 1108, "Everything": 44012}
506
                    ),
507
                    DataTypeValidation(
508
                        table="demand.egon_ev_count_municipality",
509
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_count_municipality",
510
                        column_types={"scenario": "character varying", "scenario_variation": "character varying",
511
                                      "ags": "integer", "bev_mini": "integer", "bev_medium": "integer",
512
                                      "bev_luxury": "integer", "phev_mini": "integer", "phev_medium": "integer",
513
                                      "phev_luxury": "integer", "rs7_id": "smallint"}
514
                    ),
515
                    WholeTableNotNullAndNotNaNValidation(
516
                        table="demand.egon_ev_count_municipality",
517
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_count_municipality"
518
                    ),
519
                    ValueSetValidation(
520
                        table="demand.egon_ev_count_municipality",
521
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_count_municipality",
522
                        column="scenario",
523
                        expected_values=["eGon2035", "eGon100RE"]
524
                    ),
525
                    ValueSetValidation(
526
                        table="demand.egon_ev_count_municipality",
527
                        rule_id="VALUE_SET_VALIDATION_SCENARIO_VARIATION.egon_ev_count_municipality",
528
                        column="scenario_variation",
529
                        expected_values=["Mobility Transition 2050", "NEP C 2035", "Electrification 2050", "Reference 2050"]
530
                    ),
531
                    RowCountValidation(
532
                        table=" demand.egon_ev_count_mv_grid_district",
533
                        rule_id="ROW_COUNT.egon_ev_count_mv_grid_district",
534
                        expected_count={"Schleswig-Holstein": 199, "Everything": 15348}
535
                    ),
536
                    DataTypeValidation(
537
                        table="demand.egon_ev_count_mv_grid_district",
538
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_count_mv_grid_district",
539
                        column_types={"scenario": "character varying", "scenario_variation": "character varying",
540
                                      "bus_id": "integer", "bev_mini": "integer", "bev_medium": "integer",
541
                                      "bev_luxury": "integer", "phev_mini": "integer", "phev_medium": "integer",
542
                                      "phev_luxury": "integer", "rs7_id": "smallint"}
543
                    ),
544
                    WholeTableNotNullAndNotNaNValidation(
545
                        table="demand.egon_ev_count_mv_grid_district",
546
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_count_mv_grid_district"
547
                    ),
548
                    ValueSetValidation(
549
                        table="demand.egon_ev_count_mv_grid_district",
550
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_count_mv_grid_district",
551
                        column="scenario",
552
                        expected_values=["eGon2035", "eGon100RE"]
553
                    ),
554
                    ValueSetValidation(
555
                        table="demand.egon_ev_count_mv_grid_district",
556
                        rule_id="VALUE_SET_VALIDATION_SCENARIO_VARIATION.egon_ev_count_mv_grid_district",
557
                        column="scenario_variation",
558
                        expected_values=["Mobility Transition 2050", "NEP C 2035", "Electrification 2050",
559
                                         "Reference 2050"]
560
                    ),
561
                    RowCountValidation(
562
                        table=" demand.egon_ev_count_registration_district",
563
                        rule_id="ROW_COUNT.egon_ev_count_registration_district",
564
                        expected_count={"Schleswig-Holstein": 400, "Everything": 1600}
565
                    ),
566
                    DataTypeValidation(
567
                        table="demand.egon_ev_count_registration_district",
568
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_count_registration_district",
569
                        column_types={"scenario": "character varying", "scenario_variation": "character varying",
570
                                      "ags_reg_district": "integer", "reg_district": "character varying",
571
                                      "bev_mini": "integer", "bev_medium": "integer", "bev_luxury": "integer",
572
                                      "phev_mini": "integer", "phev_medium": "integer", "phev_luxury": "integer"}
573
                    ),
574
                    WholeTableNotNullAndNotNaNValidation(
575
                        table="demand.egon_ev_count_registration_district",
576
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_count_registration_district"
577
                    ),
578
                    ValueSetValidation(
579
                        table="demand.egon_ev_count_registration_district",
580
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_count_registration_district",
581
                        column="scenario",
582
                        expected_values=["eGon2035", "eGon100RE"]
583
                    ),
584
                    ValueSetValidation(
585
                        table="demand.egon_ev_count_registration_district",
586
                        rule_id="VALUE_SET_VALIDATION_SCENARIO_VARIATION.egon_ev_count_registration_district",
587
                        column="scenario_variation",
588
                        expected_values=["Mobility Transition 2050", "NEP C 2035", "Electrification 2050",
589
                                         "Reference 2050"]
590
                    ),
591
                    RowCountValidation(
592
                        table=" demand.egon_ev_mv_grid_district",
593
                        rule_id="ROW_COUNT.egon_ev_mv_grid_district",
594
                        expected_count={"Schleswig-Holstein": 534899, "Everything": 125609556}
595
                    ),
596
                    DataTypeValidation(
597
                        table="demand.egon_ev_mv_grid_district",
598
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_mv_grid_district",
599
                        column_types={"scenario": "character varying", "scenario_variation": "character varying",
600
                                      "bus_id": "integer", "reg_district": "character varying",
601
                                      "bev_mini": "integer", "bev_medium": "integer", "bev_luxury": "integer",
602
                                      "phev_mini": "integer", "phev_medium": "integer", "phev_luxury": "integer",
603
                                      "rs7_id": "smallint"}
604
                    ),
605
                    WholeTableNotNullAndNotNaNValidation(
606
                        table="demand.egon_ev_mv_grid_district",
607
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_mv_grid_district"
608
                    ),
609
                    ValueSetValidation(
610
                        table="demand.egon_ev_mv_grid_district",
611
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_mv_grid_district",
612
                        column="scenario",
613
                        expected_values=["eGon2035", "eGon100RE"]
614
                    ),
615
                    ValueSetValidation(
616
                        table="demand.egon_ev_mv_grid_district",
617
                        rule_id="VALUE_SET_VALIDATION_SCENARIO_VARIATION.egon_ev_mv_grid_district",
618
                        column="scenario_variation",
619
                        expected_values=["Mobility Transition 2050", "NEP C 2035", "Electrification 2050",
620
                                         "Reference 2050"]
621
                    ),
622
                    RowCountValidation(
623
                        table=" demand.egon_ev_pool",
624
                        rule_id="ROW_COUNT.egon_ev_pool",
625
                        expected_count={"Schleswig-Holstein": 7000, "Everything": 65376}
626
                    ),
627
                    DataTypeValidation(
628
                        table="demand.egon_ev_pool",
629
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_pool",
630
                        column_types={"scenario": "character varying", "ev_id": "integer", "rs7_id": "smallint",
631
                                      "type": "character varying", "simbev_ev_id": "integer"}
632
                    ),
633
                    WholeTableNotNullAndNotNaNValidation(
634
                        table="demand.egon_ev_pool",
635
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_pool"
636
                    ),
637
                    ValueSetValidation(
638
                        table="demand.egon_ev_pool",
639
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_pool",
640
                        column="scenario",
641
                        expected_values=["eGon2035", "eGon100RE"]
642
                    ),
643
                    ValueSetValidation(
644
                        table="demand.egon_ev_pool",
645
                        rule_id="VALUE_SET_VALIDATION_TYPE.egon_ev_pool",
646
                        column="type",
647
                        expected_values=["bev_mini", "bev_medium", "bev_luxury", "phev_mini", "phev_medium",
648
                                         "phev_luxury"]
649
                    ),
650
                    RowCountValidation(
651
                        table=" demand.egon_ev_trip",
652
                        rule_id="ROW_COUNT.egon_ev_trip",
653
                        expected_count={"Schleswig-Holstein":11642066, "Everything": 108342188}
654
                    ),
655
                    DataTypeValidation(
656
                        table="demand.egon_ev_trip",
657
                        rule_id="DATA_MULTIPLE_TYPES.egon_ev_trip",
658
                        column_types={"scenario": "character varying", "event_id": "integer", "egon_ev_pool_ev_id": "integer",
659
                                      "simbev_event_id": "integer", "location": "character varying", "use_case": "character varying",
660
                                      "charging_capacity_nominal": "real", "charging_capacity_grid": "real",
661
                                      "charging_capacity_battery": "real", "soc_start": "real", "soc_end": "real",
662
                                      "charging_demand": "real", "park_start": "integer", "park_end": "integer",
663
                                      "drive_start": "integer", "drive_end": "integer", "consumption": "real"}
664
                    ),
665
                    WholeTableNotNullAndNotNaNValidation(
666
                        table="demand.egon_ev_trip",
667
                        rule_id="WHOLE_TABLE_NOT_NAN.egon_ev_trip"
668
                    ),
669
                    ValueSetValidation(
670
                        table="demand.egon_ev_trip",
671
                        rule_id="VALUE_SET_VALIDATION_SCENARIO.egon_ev_trip",
672
                        column="scenario",
673
                        expected_values=["eGon2035", "eGon100RE"]
674
                    ),
675
                    ValueSetValidation(
676
                        table="demand.egon_ev_trip",
677
                        rule_id="VALUE_SET_LOCATION.egon_ev_trip",
678
                        column="type",
679
                        expected_values=["0_work", "1_business", "2_school", "3_shopping", "4_private/ridesharing",
680
                                         "5_leisure", "6_home", "7_charging_hub", "driving"]
681
                    )
682
                ]
683
            },
684
            on_validation_failure="continue"
685
        )
686