Passed
Pull Request — dev (#1170)
by
unknown
05:05
created

map_id_bus()   B

Complexity

Conditions 4

Size

Total Lines 57
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

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