Completed
Push — dev ( 8582b4...82307e )
by
unknown
30s queued 19s
created

map_id_bus()   B

Complexity

Conditions 6

Size

Total Lines 77
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 57
dl 0
loc 77
rs 7.4739
c 0
b 0
f 0
cc 6
nop 1

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
from pathlib import Path
2
import logging
3
4
from shapely.geometry import Point
5
import geopandas as gpd
6
import pandas as pd
7
8
from egon.data import db
9
import egon.data.config
10
11
12
def map_id_bus(scenario):
13
    # Import manually generated list of wind offshore farms with their
14
    # connection points (OSM_id)
15
    osm_year = egon.data.config.datasets()["openstreetmap"]["original_data"][
16
        "source"
17
    ]["url"]
18
19
    if scenario in ["eGon2035", "eGon100RE"]:
20
        id_bus = {
21
            "Büttel": "136034396",
22
            "Suchraum Gemeinden Ibbenbüren/Mettingen/Westerkappeln": "114319248",
23
            "Suchraum Zensenbusch": "76185022",
24
            "Rommerskirchen": "24839976",
25
            "Oberzier": "26593929",
26
            "Garrel/Ost": "23837631",
27
            "Diele": "177829920",
28
            "Dörpen/West": "142487746",
29
            "Emden/Borßum": "34835258",
30
            "Hagermarsch": "79316833",
31
            "Hanekenfähr": "61918154",
32
            "Inhausen": "29420322",
33
            "Unterweser": "32076853",
34
            "Wehrendorf": "33411203",
35
            "Rastede": "23837631",
36
            "Bentwisch": "32063539",
37
            "Lubmin": "460134233",
38
            "Suchraum Gemeinde Papendorf": "32063539",
39
            "Suchraum Gemeinden Brünzow/Kemnitz": "460134233",
40
            "inhausen": "29420322",
41
            "Cloppenburg": "50643382",
42
        }
43
        if "200101" in osm_year:
44
            id_bus2 = {
45
                "Heide/West": "289836713",
46
                "Emden/Ost": "177829920",
47
                "Wilhelmshaven 2": "23837631",
48
            }
49
        elif ("220101" in osm_year) | ("240101" in osm_year):
50
            id_bus2 = {
51
                "Heide/West": "603661085",
52
                "Emden/Ost": "34835258",
53
                "Wilhelmshaven 2": "23744346",
54
            }
55
        else:
56
            raise Exception(
57
                """The OSM year used is not yet compatible with
58
                            this function"""
59
            )
60
        id_bus = {**id_bus, **id_bus2}
61
62
    elif "status" in scenario:
63
        year = int(scenario[-4:])
64
65
        id_bus = {
66
            "UW Inhausen": "29420322",
67
            "UW Bentwisch": "32063539",
68
            "UW Emden / Borssum": "34835258",
69
            "UW Emden Ost": "34835258",
70
            "UW Cloppenburg": "50643382",
71
            "UW Hagermarsch": "79316833",
72
            "UW Büttel": "136034396",
73
            "UW Dörpen West": "142487746",
74
            "UW Diele": "177829920",
75
            "UW Lubmin": "460134233",
76
        }
77
78
        if year >= 2023:
79
            # No update needed as no new stations used for offshore wind
80
            # between 2019 and 2023
81
            pass
82
83
        # TODO: If necessary add new stations when generating status quo > 2023
84
85
    else:
86
        id_bus = {}
87
88
    return id_bus
89
90
91
def assign_ONEP_areas():
92
    return {
93
        "Büttel": "NOR-4-1",
94
        "Heide/West": "NOR-10-2",
95
        "Suchraum Gemeinden Ibbenbüren/Mettingen/Westerkappeln": "NOR-9-2",
96
        "Suchraum Zensenbusch": "NOR-7-1",
97
        "Rommerskirchen": "NOR-7-1",
98
        "Oberzier": "NOR-7-1",
99
        "Garrel/Ost": "NOR-7-1",
100
        "Diele": "NOR-6-1",
101
        "Dörpen/West": "NOR-2-2",
102
        "Emden/Borßum": "NOR-0-1",
103
        "Emden/Ost": "NOR-3-3",
104
        "Hagermarsch": "NOR-2-1",
105
        "Hanekenfähr": "NOR-6-3",
106
        "Inhausen": "NOR-0-2",
107
        "Unterweser": "NOR-9-1",
108
        "Wehrendorf": "NOR-7-1",
109
        "Wilhelmshaven 2": "NOR-11-1",
110
        "Rastede": "NOR-7-1",
111
        "Bentwisch": "OST-3-1",
112
        "Lubmin": "OST-1-1",
113
        "Suchraum Gemeinde Papendorf": "OST-7-1",
114
        "Suchraum Gemeinden Brünzow/Kemnitz": "OST-1-4",
115
        "inhausen": "NOR-0-2",
116
        "Cloppenburg": "NOR-4-1",
117
    }
118
119
120
def map_ONEP_areas():
121
    return {
122
        "NOR-0-1": Point(6.5, 53.6),
123
        "NOR-0-2": Point(8.07, 53.76),
124
        "NOR-1": Point(6.21, 54.06),
125
        "NOR-1-1": Point(6.21, 54.06),
126
        "NOR-2-1": Point(6.54, 53.99),
127
        "NOR-2-2": Point(6.54, 53.99),
128
        "NOR-2-3": Point(6.54, 53.99),
129
        "NOR-3-1": Point(6.95, 54.02),
130
        "NOR-3-3": Point(6.95, 54.02),
131
        "NOR-4-1": Point(7.70, 54.44),
132
        "NOR-4-2": Point(7.70, 54.44),
133
        "NOR-5-1": Point(7.21, 55.14),
134
        "NOR-6-1": Point(5.92, 54.30),
135
        "NOR-6-2": Point(5.92, 54.30),
136
        "NOR-6-3": Point(5.92, 54.30),
137
        "NOR-7": Point(6.22, 54.32),
138
        "NOR-7-1": Point(6.22, 54.32),
139
        "NOR-8-1": Point(6.35, 54.48),
140
        "NOR-9-1": Point(5.75, 54.5),
141
        "NOR-9-2": Point(5.75, 54.5),
142
        "NOR-10-2": Point(6, 54.75),
143
        "NOR-11-1": Point(6.5, 54.75),
144
        "OST-1-1": Point(14.09, 54.82),
145
        "OST-1-2": Point(14.09, 54.82),
146
        "OST-1-3": Point(14.09, 54.82),
147
        "OST-1-4": Point(14.09, 54.82),
148
        "OST-2": Point(13.86, 54.83),
149
        "OST-3-1": Point(13.16, 54.98),
150
        "OST-3-2": Point(13.16, 54.98),
151
        "OST-7-1": Point(12.25, 54.5),
152
    }
153
154
155
def insert():
156
    """
157
    Include the offshore wind parks in egon-data.
158
159
    Parameters
160
    ----------
161
    *No parameters required
162
    """
163
    # Read file with all required input/output tables' names
164
    cfg = egon.data.config.datasets()["power_plants"]
165
166
    scenarios = egon.data.config.settings()["egon-data"]["--scenarios"]
167
168
    for scenario in scenarios:
169
        # Delete previous generators
170
        db.execute_sql(
171
            f"""
172
            DELETE FROM {cfg['target']['schema']}.{cfg['target']['table']}
173
            WHERE carrier = 'wind_offshore'
174
            AND scenario = '{scenario}'
175
            """
176
        )
177
178
        # load file
179
        if scenario == "eGon2035":
180
            offshore_path = (
181
                Path(".")
182
                / "data_bundle_egon_data"
183
                / "nep2035_version2021"
184
                / cfg["sources"]["nep_2035"]
185
            )
186
187
            offshore = pd.read_excel(
188
                offshore_path,
189
                sheet_name="WInd_Offshore_NEP",
190
                usecols=[
191
                    "Netzverknuepfungspunkt",
192
                    "Spannungsebene in kV",
193
                    "C 2035",
194
                ],
195
            )
196
            offshore.dropna(subset=["Netzverknuepfungspunkt"], inplace=True)
197
            offshore.rename(columns={"C 2035": "el_capacity"}, inplace=True)
198
            offshore = offshore[offshore["el_capacity"] > 0]
199
200
        elif scenario == "eGon100RE":
201
            offshore_path = (
202
                Path(".")
203
                / "data_bundle_egon_data"
204
                / "nep2035_version2021"
205
                / cfg["sources"]["nep_2035"]
206
            )
207
208
            offshore = pd.read_excel(
209
                offshore_path,
210
                sheet_name="WInd_Offshore_NEP",
211
                usecols=[
212
                    "Netzverknuepfungspunkt",
213
                    "Spannungsebene in kV",
214
                    "B 2040 ",
215
                ],
216
            )
217
            offshore.dropna(subset=["Netzverknuepfungspunkt"], inplace=True)
218
            offshore.rename(columns={"B 2040 ": "el_capacity"}, inplace=True)
219
            offshore = offshore[offshore["el_capacity"] > 0]
220
221
        elif "status" in scenario:
222
            year = int(scenario[-4:])
223
224
            offshore_path = (
225
                Path(".")
226
                / "data_bundle_egon_data"
227
                / "wind_offshore_status2019"
228
                / cfg["sources"]["wind_offshore_status2019"]
229
            )
230
            offshore = pd.read_excel(
231
                offshore_path,
232
                sheet_name="wind_offshore",
233
                usecols=[
234
                    "Name ONEP/NEP",
235
                    "NVP",
236
                    "Spannung [kV]",
237
                    "Inbetriebnahme",
238
                    "Kapazität Gesamtsystem [MW]",
239
                ],
240
            )
241
            offshore.dropna(subset=["Name ONEP/NEP"], inplace=True)
242
            offshore.rename(
243
                columns={
244
                    "NVP": "Netzverknuepfungspunkt",
245
                    "Spannung [kV]": "Spannungsebene in kV",
246
                    "Kapazität Gesamtsystem [MW]": "el_capacity",
247
                },
248
                inplace=True,
249
            )
250
            offshore = offshore[offshore["Inbetriebnahme"] <= year]
251
252
        else:
253
            raise ValueError(f"{scenario=} is not valid.")
254
255
        id_bus = map_id_bus(scenario)
256
257
        # Match wind offshore table with the corresponding OSM_id
258
        offshore["osm_id"] = offshore["Netzverknuepfungspunkt"].map(id_bus)
259
260
        buses = db.select_geodataframe(
261
            f"""
262
                SELECT bus_i as bus_id, base_kv, geom as point, CAST(osm_substation_id AS text)
263
                as osm_id FROM {cfg["sources"]["buses_data"]}
264
                """,
265
            epsg=4326,
266
            geom_col="point",
267
        )
268
269
        # Drop NANs in column osm_id
270
        buses.dropna(subset=["osm_id"], inplace=True)
271
272
        # Create columns for bus_id and geometry in the offshore df
273
        offshore["bus_id"] = pd.NA
274
        offshore["geom"] = Point(0, 0)
275
276
        # Match bus_id
277
        for index, wind_park in offshore.iterrows():
278
            if not buses[
279
                (buses["osm_id"] == wind_park["osm_id"])
280
                & (buses["base_kv"] == wind_park["Spannungsebene in kV"])
281
            ].empty:
282
                bus_ind = buses[buses["osm_id"] == wind_park["osm_id"]].index[
283
                    0
284
                ]
285
                offshore.at[index, "bus_id"] = buses.at[bus_ind, "bus_id"]
286
            else:
287
                print(f'Wind offshore farm not found: {wind_park["osm_id"]}')
288
289
        offshore.dropna(subset=["bus_id"], inplace=True)
290
291
        # Overwrite geom for status2019 parks
292
        if scenario in ["eGon2035", "eGon100RE"]:
293
            offshore["Name ONEP/NEP"] = offshore["Netzverknuepfungspunkt"].map(
294
                assign_ONEP_areas()
295
            )
296
297
        offshore["geom"] = offshore["Name ONEP/NEP"].map(map_ONEP_areas())
298
        offshore["weather_cell_id"] = pd.NA
299
300
        offshore.drop(["Name ONEP/NEP"], axis=1, inplace=True)
301
302
        if "status" in scenario:
303
            offshore.drop(["Inbetriebnahme"], axis=1, inplace=True)
304
305
        # Scale capacities for eGon100RE
306
        if scenario == "eGon100RE":
307
            # Import capacity targets for wind_offshore per scenario
308
            cap_100RE = db.select_dataframe(
309
                f"""
310
                    SELECT SUM(capacity)
311
                    FROM {cfg["sources"]["capacities"]}
312
                    WHERE scenario_name = 'eGon100RE' AND
313
                    carrier = 'wind_offshore'
314
                    """
315
            ).iloc[0, 0]
316
317
            # Scale capacities to match  target
318
            scale_factor = cap_100RE / offshore.el_capacity.sum()
319
            offshore["el_capacity"] *= scale_factor
320
321
        # Assign voltage levels to wind offshore parks
322
        offshore["voltage_level"] = 0
323
        offshore.loc[
324
            offshore[offshore["Spannungsebene in kV"] == 110].index,
325
            "voltage_level",
326
        ] = 3
327
        offshore.loc[
328
            offshore[offshore["Spannungsebene in kV"] > 110].index,
329
            "voltage_level",
330
        ] = 1
331
332
        # Delete unnecessary columns
333
        offshore.drop(
334
            [
335
                "Netzverknuepfungspunkt",
336
                "Spannungsebene in kV",
337
                "osm_id",
338
            ],
339
            axis=1,
340
            inplace=True,
341
        )
342
343
        # Set static columns
344
        offshore["carrier"] = "wind_offshore"
345
        offshore["scenario"] = scenario
346
347
        offshore = gpd.GeoDataFrame(offshore, geometry="geom", crs=4326)
348
349
        # Look for the maximum id in the table egon_power_plants
350
        next_id = db.select_dataframe(
351
            "SELECT MAX(id) FROM "
352
            + cfg["target"]["schema"]
353
            + "."
354
            + cfg["target"]["table"]
355
        ).iloc[0, 0]
356
357
        if next_id:
358
            next_id += 1
359
        else:
360
            next_id = 1
361
362
        # Reset index
363
        offshore.index = pd.RangeIndex(
364
            start=next_id, stop=next_id + len(offshore), name="id"
365
        )
366
367
        # Insert into database
368
        offshore.reset_index().to_postgis(
369
            cfg["target"]["table"],
370
            schema=cfg["target"]["schema"],
371
            con=db.engine(),
372
            if_exists="append",
373
        )
374
375
        logging.info(
376
            f"""
377
              {len(offshore)} wind_offshore generators with a total installed capacity of
378
              {offshore['el_capacity'].sum()}MW were inserted into the db
379
              """
380
        )
381