data.datasets.power_plants.pv_ground_mounted   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 1342
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 49
eloc 761
dl 0
loc 1342
rs 8.319
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
F insert() 0 1330 49

How to fix   Complexity   

Complexity

Complex classes like data.datasets.power_plants.pv_ground_mounted 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
import re
2
3
import geopandas as gpd
4
import numpy as np
5
import pandas as pd
6
7
from egon.data import db
8
from egon.data.datasets.mastr import WORKING_DIR_MASTR_NEW
9
import egon.data.config
10
11
12
def insert():
13
    def mastr_existing_pv(pow_per_area):
14
        """Import MaStR data from csv-files.
15
16
        Parameters
17
        ----------
18
        pow_per_area: int
19
            Assumption for areas of existing pv farms and power of new built
20
            pv farms depending on area in kW/m²
21
22
        """
23
        # get config
24
        cfg = egon.data.config.datasets()["power_plants"]
25
26
        # import MaStR data: locations, grid levels and installed capacities
27
28
        # get relevant pv plants: ground mounted
29
        df = pd.read_csv(
30
            WORKING_DIR_MASTR_NEW / cfg["sources"]["mastr_pv"],
31
            usecols=[
32
                "Lage",
33
                "Laengengrad",
34
                "Breitengrad",
35
                "Nettonennleistung",
36
                "EinheitMastrNummer",
37
                "LokationMastrNummer",
38
            ],
39
        )
40
        df = df[df["Lage"] == "Freifläche"]
41
42
        # examine data concerning geographical locations and drop NaNs
43
        x1 = df["Laengengrad"].isnull().sum()
44
        x2 = df["Breitengrad"].isnull().sum()
45
        print(" ")
46
        print("Examination of MaStR data set:")
47
        print("original number of rows in the data set: " + str(len(df)))
48
        print("NaNs for longitude and latitude: " + str(x1) + " & " + str(x2))
49
        df.dropna(inplace=True)
50
        print("Number of rows after neglecting NaNs: " + str(len(df)))
51
        print(" ")
52
53
        # derive dataframe for locations
54
        mastr = gpd.GeoDataFrame(
55
            index=df.index,
56
            geometry=gpd.points_from_xy(df["Laengengrad"], df["Breitengrad"]),
57
            crs={"init": "epsg:4326"},
58
        )
59
        mastr = mastr.to_crs(3035)
60
61
        # derive installed capacities
62
        mastr["installed capacity in kW"] = df["Nettonennleistung"]
63
64
        # create buffer around locations
65
66
        # calculate bufferarea and -radius considering installed capacity
67
        df_radius = (
68
            mastr["installed capacity in kW"].div(pow_per_area * np.pi) ** 0.5
69
        )  # in m
70
71
        # create buffer
72
        mastr["buffer"] = mastr["geometry"].buffer(df_radius)
73
        mastr["buffer"].crs = 3035
74
75
        # derive MaStR-Nummer
76
        mastr["LokationMastrNummer"] = df["LokationMastrNummer"]
77
78
        # derive voltage level
79
80
        mastr["voltage_level"] = pd.Series(dtype=int)
81
        lvl = pd.read_csv(
82
            WORKING_DIR_MASTR_NEW / cfg["sources"]["mastr_location"],
83
            usecols=["Spannungsebene", "MaStRNummer"],
84
        )
85
86
        # assign voltage_level to MaStR-unit:
87
88
        vlevel_mapping = {
89
            "Höchstspannung": 1,
90
            "UmspannungZurHochspannung": 2,
91
            "Hochspannung": 3,
92
            "UmspannungZurMittelspannung": 4,
93
            "Mittelspannung": 5,
94
            "UmspannungZurNiederspannung": 6,
95
            "Niederspannung": 7,
96
        }
97
98
        mastr = mastr.merge(
99
            lvl[["MaStRNummer", "Spannungsebene"]],
100
            left_on="LokationMastrNummer",
101
            right_on="MaStRNummer",
102
            how="left",
103
        )
104
105
        mastr["voltage_level"] = mastr.Spannungsebene.replace(vlevel_mapping)
106
107
        mastr.drop(["MaStRNummer", "Spannungsebene"], axis=1, inplace=True)
108
109
        # ### examine data concerning voltage level
110
        x1 = mastr["voltage_level"].isnull().sum()
111
        print(" ")
112
        print("Examination of voltage levels in MaStR data set:")
113
        print("Original number of rows in MaStR: " + str(len(mastr)))
114
        print(
115
            "NaNs in voltage level caused by a) a missing assignment to the "
116
            "number or b) insufficient data: " + str(x1)
117
        )
118
        # drop PVs with missing values due to a) no assignment of
119
        # MaStR-numbers or b) missing data in row
120
        mastr.dropna(inplace=True)
121
        print("Number of rows after neglecting NaNs: " + str(len(mastr)))
122
123
        # drop PVs in low voltage level
124
        index_names = mastr[mastr["voltage_level"] == "Niederspannung"].index
125
        x2 = len(index_names)
126
        mastr.drop(index_names, inplace=True)
127
        index_names = mastr[
128
            mastr["voltage_level"] == "UmspannungZurNiederspannung"
129
        ].index
130
        x3 = len(index_names)
131
        mastr.drop(index_names, inplace=True)
132
133
        # ### further examination
134
        print("Number of PVs in low voltage level: " + str(x2))
135
        print("Number of PVs in LVMV level: " + str(x3))
136
        print(
137
            "Number of rows after dropping entries assigned to these levels: "
138
            + str(len(mastr))
139
        )
140
        print(" ")
141
142
        return mastr
143
144
    def potential_areas(con, join_buffer):
145
        """Import potential areas and choose and prepare areas suitable for PV
146
        ground mounted.
147
148
        Parameters
149
        ----------
150
        con:
151
            Connection to database
152
        join_buffer: int
153
            Maximum distance for joining of potential areas (only small ones
154
            to big ones) in m
155
156
        """
157
158
        # import potential areas: railways and roads & agriculture
159
160
        # roads and railway
161
        sql = (
162
            "SELECT id, geom FROM "
163
            "supply.egon_re_potential_area_pv_road_railway"
164
        )
165
        potentials_rora = gpd.GeoDataFrame.from_postgis(sql, con)
166
        potentials_rora = potentials_rora.set_index("id")
167
168
        # agriculture
169
        sql = (
170
            "SELECT id, geom FROM "
171
            "supply.egon_re_potential_area_pv_agriculture"
172
        )
173
        potentials_agri = gpd.GeoDataFrame.from_postgis(sql, con)
174
        potentials_agri = potentials_agri.set_index("id")
175
176
        # add areas < 1 ha to bigger areas if they are very close, otherwise
177
        # exclude areas < 1 ha
178
179
        # calculate area
180
        potentials_rora["area"] = potentials_rora.area
181
        potentials_agri["area"] = potentials_agri.area
182
183
        # roads and railways
184
185
        # ### counting variable for examination
186
        before = len(potentials_rora)
187
188
        # get small areas and create buffer for joining around them
189
        small_areas = potentials_rora[potentials_rora["area"] < 10000]
190
        small_buffers = small_areas.copy()
191
        small_buffers["geom"] = small_areas["geom"].buffer(join_buffer)
192
193
        # drop small areas in potential areas
194
        index_names = potentials_rora[potentials_rora["area"] < 10000].index
195
        potentials_rora.drop(index_names, inplace=True)
196
197
        # check intersection of small areas with other potential areas
198
        overlay = gpd.sjoin(potentials_rora, small_buffers)
199
        o = overlay["id_right"]
200
        o.drop_duplicates(inplace=True)
201
202
        # add small areas to big ones if buffer intersects
203
        for i in range(0, len(o)):
204
            index_potentials = o.index[i]
205
            index_small = o.iloc[i]
206
            x = potentials_rora["geom"].loc[index_potentials]
207
            y = small_areas["geom"].loc[index_small]
208
            join = gpd.GeoSeries(data=[x, y])
209
            potentials_rora["geom"].loc[index_potentials] = join.unary_union
210
211
        # ### examination of joining of areas
212
        count_small = len(small_buffers)
213
        count_join = len(o)
214
        count_delete = count_small - count_join
215
        print(" ")
216
        print(
217
            "Examination of potential areas in category 'Roads and Railways'"
218
        )
219
        print("Length of original data frame: " + str(before))
220
        print("Number of small areas: " + str(count_small))
221
        print("Number of joins: " + str(count_join))
222
        print("Deleted areas (not joined): " + str(count_delete))
223
        print("Length of resulting data frame: " + str(len(potentials_rora)))
224
        print(" ")
225
226
        # agriculture
227
228
        # ### counting variable for examination
229
        before = len(potentials_agri)
230
231
        # get small areas and create buffer for joining around them
232
        small_areas = potentials_agri[potentials_agri["area"] < 10000]
233
        small_buffers = small_areas.copy()
234
        small_buffers["geom"] = small_areas["geom"].buffer(join_buffer)
235
236
        # drop small areas in potential areas
237
        index_names = potentials_agri[potentials_agri["area"] < 10000].index
238
        potentials_agri.drop(index_names, inplace=True)
239
240
        # check intersection of small areas with other potential areas
241
        overlay = gpd.sjoin(potentials_agri, small_buffers)
242
        o = overlay["id_right"]
243
        o.drop_duplicates(inplace=True)
244
245
        # add small areas to big ones if buffer intersects
246
        for i in range(0, len(o)):
247
            index_potentials = o.index[i]
248
            index_small = o.iloc[i]
249
            x = potentials_agri["geom"].loc[index_potentials]
250
            y = small_areas["geom"].loc[index_small]
251
            join = gpd.GeoSeries(data=[x, y])
252
            potentials_agri["geom"].loc[index_potentials] = join.unary_union
253
254
        # ### examination of joining of areas
255
        count_small = len(small_buffers)
256
        count_join = len(o)
257
        count_delete = count_small - count_join
258
        print(" ")
259
        print("Examination of potential areas in category 'Agriculture'")
260
        print("Length of original data frame: " + str(before))
261
        print("Number of small areas: " + str(count_small))
262
        print("Number of joins: " + str(count_join))
263
        print("Deleted areas (not joined): " + str(count_delete))
264
        print("Length of resulting data frame: " + str(len(potentials_agri)))
265
        print(" ")
266
267
        # calculate new areas
268
        potentials_rora["area"] = potentials_rora.area
269
        potentials_agri["area"] = potentials_agri.area
270
271
        # check intersection of potential areas
272
273
        # ### counting variable
274
        agri_vorher = len(potentials_agri)
275
276
        # if areas intersect, keep road & railway potential areas and drop
277
        # agricultural ones
278
        overlay = gpd.sjoin(potentials_rora, potentials_agri)
279
        o = overlay["id_right"]
280
        o.drop_duplicates(inplace=True)
281
        for i in range(0, len(o)):
282
            index = o.iloc[i]
283
            potentials_agri.drop([index], inplace=True)
284
285
        # ### examination of intersection of areas
286
        print(" ")
287
        print("Review function to avoid intersection of potential areas:")
288
        print("Initial length potentials_agri: " + str(agri_vorher))
289
        print("Number of occurred cases: " + str(len(o)))
290
        print("Resulting length potentials_agri: " + str(len(potentials_agri)))
291
        print(" ")
292
293
        return potentials_rora, potentials_agri
294
295
    def select_pot_areas(mastr, potentials_pot):
296
        """Select potential areas where there are existing pv parks
297
        (MaStR-data).
298
299
        Parameters
300
        ----------
301
        mastr: gpd.GeoDataFrame()
302
            MaStR-DataFrame with existing pv parks
303
        potentials_pot: gpd.GeoDataFrame()
304
            Suitable potential areas
305
306
        """
307
308
        # select potential areas with existing pv parks
309
        # (potential areas intersect buffer around existing plants)
310
311
        # prepare dataframes to check intersection
312
        pvs = gpd.GeoDataFrame()
313
        pvs["geom"] = mastr["buffer"].copy()
314
        pvs.set_geometry("geom", inplace=True)
315
        pvs.crs = 3035
316
        pvs = pvs.set_geometry("geom")
317
        potentials = gpd.GeoDataFrame()
318
        potentials["geom"] = potentials_pot["geom"].copy()
319
        potentials.set_geometry("geom", inplace=True)
320
        potentials.crs = 3035
321
        potentials = potentials.set_geometry("geom")
322
323
        # check intersection of potential areas with exisiting PVs (MaStR)
324
        overlay = gpd.sjoin(pvs, potentials)
325
326
        o = overlay["id"]
327
        o.drop_duplicates(inplace=True)
328
329
        # define selected potentials areas
330
        pot_sel = potentials_pot.copy()
331
        pot_sel["selected"] = pd.Series()
332
        pot_sel["voltage_level"] = pd.Series(dtype=int)
333
        for i in range(0, len(o)):
334
            index_pot = o.iloc[i]
335
            pot_sel["selected"].loc[index_pot] = True
336
            # get voltage level of existing PVs
337
            index_pv = o.index[i]
338
            pot_sel["voltage_level"] = mastr["voltage_level"].loc[index_pv]
339
        pot_sel = pot_sel[pot_sel["selected"] == True]
340
        pot_sel.drop("selected", axis=1, inplace=True)
341
342
        # drop selected existing pv parks from mastr
343
        mastr.drop(index=o.index, inplace=True)
344
345
        return (pot_sel, mastr)
346
347
    def build_pv(pv_pot, pow_per_area):
348
        """Build new pv parks in selected potential areas.
349
350
        Parameters
351
        ----------
352
        pv_pot: gpd.GeoDataFrame()
353
            Selected potential areas
354
        pow_per_area: int
355
            Assumption for areas of existing pv farms and power of new built
356
            pv farms depending on area in kW/m²
357
358
        """
359
360
        # build pv farms in selected areas
361
362
        # calculation of centroids
363
        pv_pot["centroid"] = pv_pot["geom"].representative_point()
364
365
        # calculation of power in kW
366
        pv_pot["installed capacity in kW"] = pd.Series()
367
        pv_pot["installed capacity in kW"] = pv_pot["area"] * pow_per_area
368
369
        # check for maximal capacity for PV ground mounted
370
        limit_cap = 120000  # in kW
371
        pv_pot["installed capacity in kW"] = pv_pot[
372
            "installed capacity in kW"
373
        ].apply(lambda x: x if x < limit_cap else limit_cap)
374
375
        return pv_pot
376
377
    def adapt_grid_level(pv_pot, max_dist_hv, con):
378
        """Check and if needed adapt grid level of newly built pv parks.
379
380
        Parameters
381
        ----------
382
        pv_pot: gpd.GeoDataFrame()
383
            Newly built pv parks on selected potential areas
384
        max_dist_hv: int
385
            Assumption for maximum distance of park with hv-power to next
386
            substation in m
387
        con:
388
            Connection to database
389
390
        """
391
392
        # divide dataframe in MV and HV
393
        pv_pot_mv = pv_pot[pv_pot["voltage_level"] == 5]
394
        pv_pot_hv = pv_pot[pv_pot["voltage_level"] == 4]
395
396
        # check installed capacity in MV
397
398
        max_cap_mv = 5500  # in kW
399
400
        # find PVs which need to be HV or to have reduced capacity
401
        pv_pot_mv_to_hv = pv_pot_mv[
402
            pv_pot_mv["installed capacity in kW"] > max_cap_mv
403
        ]
404
405
        if len(pv_pot_mv_to_hv) > 0:
406
            # import data for HV substations
407
408
            sql = "SELECT point, voltage FROM grid.egon_hvmv_substation"
409
            hvmv_substation = gpd.GeoDataFrame.from_postgis(
410
                sql, con, geom_col="point"
411
            )
412
            hvmv_substation = hvmv_substation.to_crs(3035)
413
            hvmv_substation["voltage"] = hvmv_substation["voltage"].apply(
414
                lambda x: int(re.split(";|:", x)[0])
415
            )
416
            hv_substations = hvmv_substation[
417
                hvmv_substation["voltage"] >= 110000
418
            ]
419
            hv_substations = (
420
                hv_substations.unary_union
421
            )  # join all the hv_substations
422
423
            # check distance to HV substations of PVs with too high installed
424
            # capacity for MV
425
426
            # calculate distance to substations
427
            pv_pot_mv_to_hv["dist_to_HV"] = (
428
                pv_pot_mv_to_hv["geom"].to_crs(3035).distance(hv_substations)
429
            )
430
431
            # adjust grid level and keep capacity if transmission lines are
432
            # close
433
            pv_pot_mv_to_hv = pv_pot_mv_to_hv[
434
                pv_pot_mv_to_hv["dist_to_HV"] <= max_dist_hv
435
            ]
436
            pv_pot_mv_to_hv = pv_pot_mv_to_hv.drop(columns=["dist_to_HV"])
437
            pv_pot_hv = pd.concat([pv_pot_hv, pv_pot_mv_to_hv])
438
439
            # delete PVs which are now HV from MV dataframe
440
            for index, pot in pv_pot_mv_to_hv.iterrows():
441
                pv_pot_mv = pv_pot_mv.drop([index])
442
            pv_pot_hv["voltage_level"] = 4
443
444
            # keep grid level adjust capacity if transmission lines are too
445
            # far
446
            pv_pot_mv["installed capacity in kW"] = pv_pot_mv[
447
                "installed capacity in kW"
448
            ].apply(lambda x: x if x < max_cap_mv else max_cap_mv)
449
            pv_pot_mv["voltage_level"] = 5
450
451
            pv_pot = pd.concat([pv_pot_mv, pv_pot_hv])
452
453
        return pv_pot
454
455
    def build_additional_pv(potentials, pv, pow_per_area, con):
456
        """Build additional pv parks if pv parks on selected potential areas
457
        do not hit the target value.
458
459
         Parameters
460
         ----------
461
         potenatials: gpd.GeoDataFrame()
462
             All suitable potential areas
463
         pv: gpd.GeoDataFrame()
464
             Newly built pv parks on selected potential areas
465
        pow_per_area: int
466
             Assumption for areas of existing pv farms and power of new built
467
             pv farms depending on area in kW/m²
468
         con:
469
             Connection to database
470
471
        """
472
473
        # get MV grid districts
474
        sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
475
        distr = gpd.GeoDataFrame.from_postgis(sql, con)
476
        distr = distr.set_index("bus_id")
477
478
        # identify potential areas where there are no PV parks yet
479
        for index, pv in pv.iterrows():
480
            potentials = potentials.drop([index])
481
482
        # aggregate potential area per MV grid district
483
        pv_per_distr = gpd.GeoDataFrame()
484
        pv_per_distr["geom"] = distr["geom"].copy()
485
        centroids = potentials.copy()
486
        centroids["geom"] = centroids["geom"].representative_point()
487
488
        overlay = gpd.sjoin(centroids, distr)
489
490
        # ### examine potential area per grid district
491
        anz = len(overlay)
492
        anz_distr = len(overlay["bus_id"].unique())
493
        size = 137500  # m2 Fläche für > 5,5 MW: (5500 kW / (0,04 kW/m2))
494
        anz_big = len(overlay[overlay["area"] >= size])
495
        anz_small = len(overlay[overlay["area"] < size])
496
497
        print(" ")
498
        print(
499
            "Examination of remaining potential areas in MV grid districts: "
500
        )
501
        print("Number of potential areas: " + str(anz))
502
        print(" -> distributed to " + str(anz_distr) + " districts")
503
        print("Number of areas with a potential >= 5,5 MW: " + str(anz_big))
504
        print("Number of areas with a potential < 5,5 MW: " + str(anz_small))
505
        print(" ")
506
507
        for index, dist in distr.iterrows():
508
            pots = overlay[overlay["bus_id"] == index]["geom"].index
509
            p = gpd.GeoSeries(index=pots)
510
            for i in pots:
511
                p.loc[i] = potentials["geom"].loc[i]
512
            pv_per_distr["geom"].loc[index] = p.unary_union
513
514
        # calculate area per MV grid district and linearly distribute needed
515
        # capacity considering pow_per_area
516
        pv_per_distr["area"] = pv_per_distr["geom"].area
517
        pv_per_distr["installed capacity in kW"] = (
518
            pv_per_distr["area"] * pow_per_area
519
        )
520
521
        # calculate centroid
522
        pv_per_distr["centroid"] = pv_per_distr["geom"].representative_point()
523
524
        return pv_per_distr
525
526
    def check_target(
527
        pv_rora_i,
528
        pv_agri_i,
529
        pv_exist_i,
530
        potentials_rora_i,
531
        potentials_agri_i,
532
        target_power,
533
        pow_per_area,
534
        con,
535
    ):
536
        """Check target value per scenario and per state.
537
538
         Parameters
539
         ----------
540
         pv_rora_i: gpd.GeoDataFrame()
541
             Newly built pv parks on selected potential areas of road and
542
             railways p
543
         pv_agri_i: gpd.GeoDataFrame()
544
             Newly built pv parks on selected potential areas of agriculture
545
         pv_exist_i: gpd.GeoDataFrame()
546
             existing pv parks that don't intercept any potential area
547
         potenatials_rora_i: gpd.GeoDataFrame()
548
             All suitable potential areas of road and railway
549
         potenatials_rora_i: gpd.GeoDataFrame()
550
             All suitable potential areas of agriculture
551
         target_power: int
552
             Target for installed capacity of pv ground mounted in referenced
553
             state
554
        pow_per_area: int
555
             Assumption for areas of existing pv farms and power of new built
556
             pv farms depending on area in kW/m²
557
         con:
558
             Connection to database
559
560
        """
561
562
        # sum overall installed capacity for MV and HV
563
564
        total_pv_power = (
565
            pv_rora_i["installed capacity in kW"].sum()
566
            + pv_agri_i["installed capacity in kW"].sum()
567
            + pv_exist_i["installed capacity in kW"].sum()
568
        )
569
570
        pv_per_distr_i = gpd.GeoDataFrame()
571
572
        # check target value
573
574
        ###
575
        print(" ")
576
        print(
577
            "Installed capacity on areas with existing plants: "
578
            + str(total_pv_power / 1000)
579
            + " MW"
580
        )
581
582
        # linear scale farms to meet target if sum of installed capacity is
583
        # too high
584
        if total_pv_power >= target_power:
585
            scale_factor = target_power / total_pv_power
586
            pv_rora_i["installed capacity in kW"] = (
587
                pv_rora_i["installed capacity in kW"] * scale_factor
588
            )
589
            pv_agri_i["installed capacity in kW"] = (
590
                pv_agri_i["installed capacity in kW"] * scale_factor
591
            )
592
            pv_exist_i["installed capacity in kW"] = (
593
                pv_exist_i["installed capacity in kW"] * scale_factor
594
            )
595
596
            pv_per_distr_i["grid_district"] = pd.Series()
597
            pv_per_distr_i["installed capacity in kW"] = pd.Series(0)
598
599
            ###
600
            print(
601
                "Expansion of existing PV parks on potential areas to "
602
                "achieve target capacity is sufficient."
603
            )
604
            print(
605
                "Installed power is greater than the target value, scaling "
606
                "is applied:"
607
            )
608
            print("Scaling factor: " + str(scale_factor))
609
610
        # build new pv parks if sum of installed capacity is below target
611
        # value
612
        elif total_pv_power < target_power:
613
            rest_cap = target_power - total_pv_power
614
615
            ###
616
            print(
617
                "Expansion of existing PV parks on potential areas to "
618
                "achieve target capacity is unsufficient:"
619
            )
620
            print("Residual capacity: " + str(rest_cap / 1000) + " MW")
621
            print(
622
                "Residual capacity will initially be distributed via "
623
                "remaining potential areas 'Road & Railway'."
624
            )
625
626
            # build pv parks in potential areas road & railway
627
            pv_per_distr_i = build_additional_pv(
628
                potentials_rora_i, pv_rora_i, pow_per_area, con
629
            )
630
            # change index to add different Dataframes in the end
631
            pv_per_distr_i["grid_district"] = pv_per_distr_i.index.copy()
632
            pv_per_distr_i.index = range(0, len(pv_per_distr_i))
633
            # delete empty grid districts
634
            index_names = pv_per_distr_i[
635
                pv_per_distr_i["installed capacity in kW"].isna()
636
            ].index
637
            pv_per_distr_i.drop(index_names, inplace=True)
638
639
            if pv_per_distr_i["installed capacity in kW"].sum() > rest_cap:
640
                scale_factor = (
641
                    rest_cap / pv_per_distr_i["installed capacity in kW"].sum()
642
                )
643
                pv_per_distr_i["installed capacity in kW"] = (
644
                    pv_per_distr_i["installed capacity in kW"] * scale_factor
645
                )
646
647
                ###
648
                print(
649
                    "Residual capacity got distributed via scaling factor "
650
                    + str(scale_factor)
651
                    + " to remaining potential areas 'Road & Railway'."
652
                )
653
654
            # build pv parks on potential areas agriculture if still necessary
655
            elif pv_per_distr_i["installed capacity in kW"].sum() < rest_cap:
656
                rest_cap = (
657
                    target_power
658
                    - total_pv_power
659
                    - pv_per_distr_i["installed capacity in kW"].sum()
660
                )
661
662
                ###
663
                print(
664
                    "Distribution via potential areas Road & Railway "
665
                    "unsufficient to achieve target capacity:"
666
                )
667
                print("Residual capacity: " + str(rest_cap / 1000) + " MW")
668
                print(
669
                    "Residual capacity is distributed to remaining potential "
670
                    "areas 'Agriculture'."
671
                )
672
673
                pv_per_distr_i_2 = build_additional_pv(
674
                    potentials_agri_i, pv_agri_i, pow_per_area, con
675
                )
676
                # change index to add different Dataframes in the end
677
                pv_per_distr_i_2["grid_district"] = pv_per_distr_i_2.index
678
                pv_per_distr_i_2.index = range(len(pv_per_distr_i_2))
679
680
                # delete empty grid districts
681
                index_names = pv_per_distr_i_2[
682
                    pv_per_distr_i_2["installed capacity in kW"].isna()
683
                ].index
684
                pv_per_distr_i_2.drop(index_names, inplace=True)
685
686
                if (
687
                    pv_per_distr_i_2["installed capacity in kW"].sum()
688
                    > rest_cap
689
                ):
690
                    scale_factor = (
691
                        rest_cap
692
                        / pv_per_distr_i_2["installed capacity in kW"].sum()
693
                    )
694
                    pv_per_distr_i_2["installed capacity in kW"] = (
695
                        pv_per_distr_i_2["installed capacity in kW"]
696
                        * scale_factor
697
                    )
698
699
                    ###
700
                    print(
701
                        "Residual capacity got distributed via scaling "
702
                        "factor "
703
                        + str(scale_factor)
704
                        + " to remaining potential areas 'Road & Railway' "
705
                        "and 'Agriculture'."
706
                    )
707
708
                pv_per_distr_i = pd.concat(
709
                    [pv_per_distr_i, pv_per_distr_i_2], ignore_index=True
710
                )
711
712
            # assign grid level to pv_per_distr
713
            v_lvl = pd.Series(dtype=int, index=pv_per_distr_i.index)
714
            for index, distr in pv_per_distr_i.iterrows():
715
                if distr["installed capacity in kW"] > 5500:  # > 5 MW
716
                    v_lvl[index] = 4
717
                else:
718
                    v_lvl[index] = 5
719
            pv_per_distr_i["voltage_level"] = v_lvl
720
721
            # new overall installed capacity
722
            total_pv_power = (
723
                pv_rora_i["installed capacity in kW"].sum()
724
                + pv_agri_i["installed capacity in kW"].sum()
725
                + pv_exist_i["installed capacity in kW"].sum()
726
                + pv_per_distr_i["installed capacity in kW"].sum()
727
            )
728
729
            ###
730
            print(
731
                "Total installed capacity of PV farms: "
732
                + str(total_pv_power / 1000)
733
                + " MW"
734
            )
735
            print(" ")
736
737
        pv_rora_i = pv_rora_i[pv_rora_i["installed capacity in kW"] > 0]
738
        pv_agri_i = pv_agri_i[pv_agri_i["installed capacity in kW"] > 0]
739
        pv_exist_i = pv_exist_i[pv_exist_i["installed capacity in kW"] > 0]
740
        pv_per_distr_i = pv_per_distr_i[
741
            pv_per_distr_i["installed capacity in kW"] > 0
742
        ]
743
744
        return pv_rora_i, pv_agri_i, pv_exist_i, pv_per_distr_i
745
746
    def keep_existing_pv(mastr, con):
747
        pv_exist = mastr[
748
            [
749
                "geometry",
750
                "installed capacity in kW",
751
                "voltage_level",
752
            ]
753
        ]
754
        pv_exist.rename(columns={"geometry": "centroid"}, inplace=True)
755
        pv_exist = gpd.GeoDataFrame(pv_exist, geometry="centroid", crs=3035)
756
757
        # German states
758
        sql = "SELECT geometry as geom, gf FROM boundaries.vg250_lan"
759
        land = gpd.GeoDataFrame.from_postgis(sql, con).to_crs(3035)
760
        land = land[(land["gf"] != 1) & (land["gf"] != 2)]
761
        land = land.unary_union
762
        pv_exist = gpd.clip(pv_exist, land)
763
764
        return pv_exist
765
766
    def run_methodology(
767
        con=db.engine(),
768
        pow_per_area=0.04,
769
        join_buffer=10,
770
        max_dist_hv=20000,
771
        show_map=False,
772
    ):
773
        """Execute methodology to distribute pv ground mounted.
774
775
         Parameters
776
         ----------
777
         con:
778
             Connection to database
779
         pow_per_area: int, default 0.4
780
             Assumption for areas of existing pv farms and power of new built
781
             pv farms depending on area in kW/m²
782
         join_buffer : int, default 10
783
             Maximum distance for joining of potential areas (only small ones
784
             to big ones) in m
785
         max_dist_hv : int, default 20000
786
             Assumption for maximum distance of park with hv-power to next
787
             substation in m
788
        show_map:  boolean
789
            Optional creation of map to show distribution of installed
790
            capacity
791
792
        """
793
        ###
794
        print(" ")
795
        print("MaStR-Data")
796
        print(" ")
797
798
        # MaStR-data: existing PV farms
799
        mastr = mastr_existing_pv(pow_per_area)
800
801
        ###
802
        print(" ")
803
        print("potential area")
804
        print(" ")
805
806
        # database-data: potential areas for new PV farms
807
        potentials_rora, potentials_agri = potential_areas(con, join_buffer)
808
809
        ###
810
        print(" ")
811
        print("select potentials area")
812
        print(" ")
813
814
        # select potential areas with existing PV farms to build new PV farms
815
        pv_rora, mastr = select_pot_areas(mastr, potentials_rora)
816
        pv_agri, mastr = select_pot_areas(mastr, potentials_agri)
817
818
        ###
819
        print(" ")
820
        print(
821
            "build PV parks where there is PV ground mounted already "
822
            "(-> MaStR) on potential area"
823
        )
824
        print(" ")
825
826
        # build new PV farms
827
        pv_rora = build_pv(pv_rora, pow_per_area)
828
        pv_agri = build_pv(pv_agri, pow_per_area)
829
830
        # keep the existing pv_farms that don't intercept potential areas
831
        exist = keep_existing_pv(mastr, con)
832
833
        ###
834
        print(" ")
835
        print("adapt grid level of PV parks")
836
        print(" ")
837
838
        # adapt grid level to new farms
839
        rora = adapt_grid_level(pv_rora, max_dist_hv, con)
840
        agri = adapt_grid_level(pv_agri, max_dist_hv, con)
841
842
        ###
843
        print(" ")
844
        print(
845
            "check target value and build more PV parks on potential area if "
846
            "necessary"
847
        )
848
        print(" ")
849
850
        # initialize final dataframe
851
        pv_rora = gpd.GeoDataFrame()
852
        pv_agri = gpd.GeoDataFrame()
853
        pv_exist = gpd.GeoDataFrame()
854
        pv_per_distr = gpd.GeoDataFrame()
855
856
        pv_rora_100RE = gpd.GeoDataFrame()
857
        pv_agri_100RE = gpd.GeoDataFrame()
858
        pv_exist_100RE = gpd.GeoDataFrame()
859
        pv_per_distr_100RE = gpd.GeoDataFrame()
860
861
        # 1) scenario: eGon2035
862
        if (
863
            "eGon2035"
864
            in egon.data.config.settings()["egon-data"]["--scenarios"]
865
        ):
866
            ###
867
            print(" ")
868
            print("scenario: eGon2035")
869
            print(" ")
870
871
            # German states
872
            sql = "SELECT geometry as geom, nuts FROM boundaries.vg250_lan"
873
            states = gpd.GeoDataFrame.from_postgis(sql, con)
874
875
            # assumption for target value of installed capacity
876
            sql = (
877
                "SELECT capacity,scenario_name,nuts FROM "
878
                "supply.egon_scenario_capacities WHERE carrier='solar'"
879
            )
880
            target = pd.read_sql(sql, con)
881
            target = target[target["scenario_name"] == "eGon2035"]
882
            nuts = np.unique(target["nuts"])
883
884
            # prepare selection per state
885
            rora = rora.set_geometry("centroid")
886
            agri = agri.set_geometry("centroid")
887
            potentials_rora = potentials_rora.set_geometry("geom")
888
            potentials_agri = potentials_agri.set_geometry("geom")
889
890
            # check target value per state
891
            for i in nuts:
892
                target_power = (
893
                    target[target["nuts"] == i]["capacity"].iloc[0] * 1000
894
                )
895
896
                ###
897
                land = target[target["nuts"] == i]["nuts"].iloc[0]
898
                print(" ")
899
                print("Bundesland (NUTS): " + land)
900
                print("target power: " + str(target_power / 1000) + " MW")
901
902
                # select state
903
                state = states[states["nuts"] == i]
904
                state = state.to_crs(3035)
905
906
                # select PVs in state
907
                rora_i = gpd.sjoin(rora, state)
908
                agri_i = gpd.sjoin(agri, state)
909
                exist_i = gpd.sjoin(exist, state)
910
                rora_i.drop("index_right", axis=1, inplace=True)
911
                agri_i.drop("index_right", axis=1, inplace=True)
912
                exist_i.drop("index_right", axis=1, inplace=True)
913
                rora_i.drop_duplicates(inplace=True)
914
                agri_i.drop_duplicates(inplace=True)
915
                exist_i.drop_duplicates(inplace=True)
916
917
                # select potential areas in state
918
                potentials_rora_i = gpd.sjoin(potentials_rora, state)
919
                potentials_agri_i = gpd.sjoin(potentials_agri, state)
920
                potentials_rora_i.drop("index_right", axis=1, inplace=True)
921
                potentials_agri_i.drop("index_right", axis=1, inplace=True)
922
                potentials_rora_i.drop_duplicates(inplace=True)
923
                potentials_agri_i.drop_duplicates(inplace=True)
924
925
                # check target value and adapt installed capacity if necessary
926
                rora_i, agri_i, exist_i, distr_i = check_target(
927
                    rora_i,
928
                    agri_i,
929
                    exist_i,
930
                    potentials_rora_i,
931
                    potentials_agri_i,
932
                    target_power,
933
                    pow_per_area,
934
                    con,
935
                )
936
937
                if len(distr_i) > 0:
938
                    distr_i["nuts"] = target[target["nuts"] == i]["nuts"].iloc[
939
                        0
940
                    ]
941
942
                # ### examination of built PV parks per state
943
                rora_i_mv = rora_i[rora_i["voltage_level"] == 5]
944
                rora_i_hv = rora_i[rora_i["voltage_level"] == 4]
945
                agri_i_mv = agri_i[agri_i["voltage_level"] == 5]
946
                agri_i_hv = agri_i[agri_i["voltage_level"] == 4]
947
                print(
948
                    "eGon2035: Examination of voltage level per federal state:"
949
                )
950
                print("a) PVs on potential areas Road & Railway: ")
951
                print(
952
                    "Total installed capacity: "
953
                    + str(rora_i["installed capacity in kW"].sum() / 1000)
954
                    + " MW"
955
                )
956
                print("Number of PV farms: " + str(len(rora_i)))
957
                print(" - thereof MV: " + str(len(rora_i_mv)))
958
                print(" - thereof HV: " + str(len(rora_i_hv)))
959
                print("b) PVs on potential areas Agriculture: ")
960
                print(
961
                    "Total installed capacity: "
962
                    + str(agri_i["installed capacity in kW"].sum() / 1000)
963
                    + " MW"
964
                )
965
                print("Number of PV farms: " + str(len(agri_i)))
966
                print(" - thereof MV: " + str(len(agri_i_mv)))
967
                print(" - dthereof HV: " + str(len(agri_i_hv)))
968
                print("c) Existing PVs not in potential areas: ")
969
                print("Number of PV farms: " + str(len(exist_i)))
970
                print("d) PVs on additional potential areas per MV-District: ")
971
                if len(distr_i) > 0:
972
                    distr_i_mv = distr_i[distr_i["voltage_level"] == 5]
973
                    distr_i_hv = distr_i[distr_i["voltage_level"] == 4]
974
                    print(
975
                        "Total installed capacity: "
976
                        + str(distr_i["installed capacity in kW"].sum() / 1000)
977
                        + " MW"
978
                    )
979
                    print("Number of PV farms: " + str(len(distr_i)))
980
                    print(" - thereof MV: " + str(len(distr_i_mv)))
981
                    print(" - thereof HV: " + str(len(distr_i_hv)))
982
                else:
983
                    print(" -> No additional expansion necessary")
984
                print(" ")
985
986
                pv_rora = pd.concat([pv_rora, rora_i])
987
                pv_agri = pd.concat([pv_agri, agri_i])
988
                pv_exist = pd.concat([pv_exist, exist_i])
989
                if len(distr_i) > 0:
990
                    pv_per_distr = pd.concat([pv_per_distr, distr_i])
991
992
        if (
993
            "eGon100RE"
994
            in egon.data.config.settings()["egon-data"]["--scenarios"]
995
        ):
996
            # 2) scenario: eGon100RE
997
998
            # assumption for target value of installed capacity in Germany per
999
            # scenario
1000
            sql = (
1001
                "SELECT capacity,scenario_name FROM "
1002
                "supply.egon_scenario_capacities WHERE carrier='solar'"
1003
            )
1004
            target_power = pd.read_sql(sql, con)
1005
            target_power = target_power[
1006
                target_power["scenario_name"] == "eGon100RE"
1007
            ]
1008
            target_power = target_power["capacity"].sum() * 1000
1009
1010
            ###
1011
            print(" ")
1012
            print("scenario: eGon100RE")
1013
            print("target power: " + str(target_power) + " kW")
1014
            print(" ")
1015
1016
            # check target value and adapt installed capacity if necessary
1017
            (
1018
                pv_rora_100RE,
1019
                pv_agri_100RE,
1020
                pv_exist_100RE,
1021
                pv_per_distr_100RE,
1022
            ) = check_target(
1023
                rora,
1024
                agri,
1025
                exist,
1026
                potentials_rora,
1027
                potentials_agri,
1028
                target_power,
1029
                pow_per_area,
1030
                con,
1031
            )
1032
1033
            pv_rora_100RE = pv_rora_100RE[
1034
                pv_rora_100RE["installed capacity in kW"] > 0
1035
            ]
1036
            pv_agri_100RE = pv_agri_100RE[
1037
                pv_agri_100RE["installed capacity in kW"] > 0
1038
            ]
1039
            pv_per_distr_100RE = pv_per_distr_100RE[
1040
                pv_per_distr_100RE["installed capacity in kW"] > 0
1041
            ]
1042
1043
        # ### create map to show distribution of installed capacity
1044
        if show_map == True:
1045
            # 1) eGon2035
1046
1047
            # get MV grid districts
1048
            sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
1049
            distr = gpd.GeoDataFrame.from_postgis(sql, con)
1050
            distr = distr.set_index("bus_id")
1051
1052
            # assign pv_per_distr-power to districts
1053
            distr["capacity"] = pd.Series()
1054
            for index, row in distr.iterrows():
1055
                if index in np.unique(pv_per_distr["grid_district"]):
1056
                    pv = pv_per_distr[pv_per_distr["grid_district"] == index]
1057
                    x = pv["installed capacity in kW"].iloc[0]
1058
                    distr["capacity"].loc[index] = x
1059
                else:
1060
                    distr["capacity"].loc[index] = 0
1061
            distr["capacity"] = distr["capacity"] / 1000
1062
1063
            # add pv_rora- and pv_agri-power to district
1064
            pv_rora = pv_rora.set_geometry("centroid")
1065
            pv_agri = pv_agri.set_geometry("centroid")
1066
            overlay_rora = gpd.sjoin(pv_rora, distr)
1067
            overlay_agri = gpd.sjoin(pv_agri, distr)
1068
1069
            for index, row in distr.iterrows():
1070
                o_rora = overlay_rora[overlay_rora["bus_id"] == index]
1071
                o_agri = overlay_agri[overlay_agri["bus_id"] == index]
1072
                cap_rora = o_rora["installed capacity in kW"].sum() / 1000
1073
                cap_agri = o_agri["installed capacity in kW"].sum() / 1000
1074
            distr["capacity"].loc[index] = (
1075
                distr["capacity"].loc[index] + cap_rora + cap_agri
0 ignored issues
show
introduced by
The variable cap_agri does not seem to be defined in case the for loop on line 1069 is not entered. Are you sure this can never be the case?
Loading history...
introduced by
The variable index does not seem to be defined in case the for loop on line 1054 is not entered. Are you sure this can never be the case?
Loading history...
introduced by
The variable cap_rora does not seem to be defined in case the for loop on line 1069 is not entered. Are you sure this can never be the case?
Loading history...
1076
            )
1077
1078
            from matplotlib import pyplot as plt
1079
1080
            fig, ax = plt.subplots(1, 1)
1081
            distr.boundary.plot(linewidth=0.2, ax=ax, color="black")
1082
            distr.plot(
1083
                ax=ax,
1084
                column="capacity",
1085
                cmap="magma_r",
1086
                legend=True,
1087
                legend_kwds={
1088
                    "label": "Installed capacity in MW",
1089
                    "orientation": "vertical",
1090
                },
1091
            )
1092
            plt.savefig("pv_per_distr_map_eGon2035.png", dpi=300)
1093
1094
            # 2) eGon100RE
1095
1096
            # get MV grid districts
1097
            sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
1098
            distr = gpd.GeoDataFrame.from_postgis(sql, con)
1099
            distr = distr.set_index("bus_id")
1100
1101
            # assign pv_per_distr-power to districts
1102
            distr["capacity"] = pd.Series()
1103
            for index, row in distr.iterrows():
1104
                if index in np.unique(pv_per_distr_100RE["grid_district"]):
1105
                    pv = pv_per_distr_100RE[
1106
                        pv_per_distr_100RE["grid_district"] == index
1107
                    ]
1108
                    x = pv["installed capacity in kW"].iloc[0]
1109
                    distr["capacity"].loc[index] = x
1110
                else:
1111
                    distr["capacity"].loc[index] = 0
1112
            distr["capacity"] = distr["capacity"] / 1000
1113
1114
            # add pv_rora- and pv_agri-power to district
1115
            pv_rora_100RE = pv_rora_100RE.set_geometry("centroid")
1116
            pv_agri_100RE = pv_agri_100RE.set_geometry("centroid")
1117
            overlay_rora = gpd.sjoin(pv_rora_100RE, distr)
1118
            overlay_agri = gpd.sjoin(pv_agri_100RE, distr)
1119
1120
            for index, row in distr.iterrows():
1121
                o_rora = overlay_rora[overlay_rora["bus_id"] == index]
1122
                o_agri = overlay_agri[overlay_agri["bus_id"] == index]
1123
                cap_rora = o_rora["installed capacity in kW"].sum() / 1000
1124
                cap_agri = o_agri["installed capacity in kW"].sum() / 1000
1125
            distr["capacity"].loc[index] = (
1126
                distr["capacity"].loc[index] + cap_rora + cap_agri
1127
            )
1128
1129
            from matplotlib import pyplot as plt
1130
1131
            fig, ax = plt.subplots(1, 1)
1132
            distr.boundary.plot(linewidth=0.2, ax=ax, color="black")
1133
            distr.plot(
1134
                ax=ax,
1135
                column="capacity",
1136
                cmap="magma_r",
1137
                legend=True,
1138
                legend_kwds={
1139
                    "label": "Installed capacity in MW",
1140
                    "orientation": "vertical",
1141
                },
1142
            )
1143
            plt.savefig("pv_per_distr_map_eGon100RE.png", dpi=300)
1144
1145
        return (
1146
            pv_rora,
1147
            pv_agri,
1148
            pv_exist,
1149
            pv_per_distr,
1150
            pv_rora_100RE,
1151
            pv_agri_100RE,
1152
            pv_exist_100RE,
1153
            pv_per_distr_100RE,
1154
        )
1155
1156
    def insert_pv_parks(
1157
        pv_rora, pv_agri, pv_exist, pv_per_distr, scenario_name
1158
    ):
1159
        """Write to database.
1160
1161
        Parameters
1162
        ----------
1163
        pv_rora : gpd.GeoDataFrame()
1164
            Pv parks on selected potential areas of raod and railway
1165
        pv_agri : gpd.GeoDataFrame()
1166
            Pv parks on selected potential areas of raod and railway
1167
        pv_exist : gpd.GeoDataFrame()
1168
            Existing Pv parks on selected areas
1169
        pv_per_distr: gpd.GeoDataFrame()
1170
            Additionally built pv parks on potential areas per mv grid
1171
            district
1172
        scenario_name:
1173
            Scenario name of calculation
1174
1175
        """
1176
1177
        # prepare dataframe for integration in supply.egon_power_plants
1178
1179
        pv_parks = pd.concat(
1180
            [pv_rora, pv_agri, pv_exist, pv_per_distr], ignore_index=True
1181
        )
1182
        pv_parks["el_capacity"] = pv_parks["installed capacity in kW"] / 1000
1183
        pv_parks.rename(columns={"centroid": "geometry"}, inplace=True)
1184
        pv_parks = gpd.GeoDataFrame(pv_parks, geometry="geometry", crs=3035)
1185
        pv_parks = pv_parks[["el_capacity", "voltage_level", "geometry"]]
1186
1187
        # integration in supply.egon_power_plants
1188
1189
        con = db.engine()
1190
1191
        # maximum ID in egon_power_plants
1192
        sql = "SELECT MAX(id) FROM supply.egon_power_plants"
1193
        max_id = pd.read_sql(sql, con)
1194
        max_id = max_id["max"].iat[0]
1195
        if max_id is None:
1196
            max_id = 1
1197
1198
        pv_park_id = max_id + 1
1199
1200
        # copy relevant columns from pv_parks
1201
        insert_pv_parks = pv_parks[
1202
            ["el_capacity", "voltage_level", "geometry"]
1203
        ]
1204
        insert_pv_parks = insert_pv_parks.set_geometry("geometry")
1205
        insert_pv_parks["voltage_level"] = insert_pv_parks[
1206
            "voltage_level"
1207
        ].apply(int)
1208
1209
        # set static column values
1210
        insert_pv_parks["carrier"] = "solar"
1211
        insert_pv_parks["scenario"] = scenario_name
1212
1213
        # change name and crs of geometry column
1214
        insert_pv_parks.set_crs(epsg=3035, allow_override=True, inplace=True)
1215
        insert_pv_parks = (
1216
            insert_pv_parks.rename({"geometry": "geom"}, axis=1)
1217
            .set_geometry("geom")
1218
            .to_crs(4326)
1219
        )
1220
1221
        # reset index
1222
        insert_pv_parks.index = pd.RangeIndex(
1223
            start=pv_park_id, stop=pv_park_id + len(insert_pv_parks), name="id"
1224
        )
1225
1226
        # insert into database
1227
        insert_pv_parks.reset_index().to_postgis(
1228
            "egon_power_plants",
1229
            schema="supply",
1230
            con=db.engine(),
1231
            if_exists="append",
1232
        )
1233
1234
        return pv_parks
1235
1236
    # ########################################################################
1237
1238
    # execute methodology
1239
1240
    (
1241
        pv_rora,
1242
        pv_agri,
1243
        pv_exist,
1244
        pv_per_distr,
1245
        pv_rora_100RE,
1246
        pv_agri_100RE,
1247
        pv_exist_100RE,
1248
        pv_per_distr_100RE,
1249
    ) = run_methodology(
1250
        con=db.engine(),
1251
        pow_per_area=0.04,
1252
        join_buffer=10,
1253
        max_dist_hv=20000,
1254
        show_map=False,
1255
    )
1256
1257
    # ### examination of results
1258
    if len(pv_per_distr) > 0:
1259
        pv_per_distr_mv = pv_per_distr[pv_per_distr["voltage_level"] == 5]
1260
        pv_per_distr_hv = pv_per_distr[pv_per_distr["voltage_level"] == 4]
1261
    if len(pv_rora) > 0:
1262
        pv_rora_mv = pv_rora[pv_rora["voltage_level"] == 5]
1263
        pv_rora_hv = pv_rora[pv_rora["voltage_level"] == 4]
1264
        pv_agri_mv = pv_agri[pv_agri["voltage_level"] == 5]
1265
        pv_agri_hv = pv_agri[pv_agri["voltage_level"] == 4]
1266
1267
        print(" ")
1268
        print("eGon2035: Examination of overall voltage levels:")
1269
        print("a) PVs on potential areas Road & Railway: ")
1270
        print(
1271
            "Total installed capacity: "
1272
            + str(pv_rora["installed capacity in kW"].sum() / 1000)
1273
            + " MW"
1274
        )
1275
        print("Number of PV farms: " + str(len(pv_rora)))
1276
        print(" - thereof MV: " + str(len(pv_rora_mv)))
1277
        print(" - thereof HV: " + str(len(pv_rora_hv)))
1278
        print("b) PVs on potential areas Agriculture: ")
1279
        print(
1280
            "Total installed capacity: "
1281
            + str(pv_agri["installed capacity in kW"].sum() / 1000)
1282
            + " MW"
1283
        )
1284
        print("Number of PV farms: " + str(len(pv_agri)))
1285
        print(" - thereof MV: " + str(len(pv_agri_mv)))
1286
        print(" - thereof HV: " + str(len(pv_agri_hv)))
1287
        print("c) Existing PVs not in potential areas: ")
1288
        print("Number of PV farms: " + str(len(pv_exist)))
1289
        print("d) PVs on additional potential areas per MV-District: ")
1290
        if len(pv_per_distr) > 0:
1291
            print(
1292
                "Total installed capacity: "
1293
                + str(pv_per_distr["installed capacity in kW"].sum() / 1000)
1294
                + " MW"
1295
            )
1296
            print("Number of PV farms: " + str(len(pv_per_distr)))
1297
            print(" - thereof MV: " + str(len(pv_per_distr_mv)))
0 ignored issues
show
introduced by
The variable pv_per_distr_mv does not seem to be defined in case len(pv_per_distr) > 0 on line 1258 is False. Are you sure this can never be the case?
Loading history...
1298
            print(" - thereof HV: " + str(len(pv_per_distr_hv)))
0 ignored issues
show
introduced by
The variable pv_per_distr_hv does not seem to be defined in case len(pv_per_distr) > 0 on line 1258 is False. Are you sure this can never be the case?
Loading history...
1299
        else:
1300
            print(" -> No additional expansion needed")
1301
        print(" ")
1302
        ###
1303
1304
    # save to DB
1305
    if "eGon2035" in egon.data.config.settings()["egon-data"]["--scenarios"]:
1306
        if (
1307
            pv_rora["installed capacity in kW"].sum() > 0
1308
            or pv_agri["installed capacity in kW"].sum() > 0
1309
            or pv_per_distr["installed capacity in kW"].sum() > 0
1310
            or pv_exist["installed capacity in kW"].sum() > 0
1311
        ):
1312
            pv_parks = insert_pv_parks(
1313
                pv_rora, pv_agri, pv_exist, pv_per_distr, "eGon2035"
1314
            )
1315
1316
        else:
1317
            pv_parks = gpd.GeoDataFrame()
1318
    else:
1319
        pv_parks = gpd.GeoDataFrame()
1320
1321
    if "eGon100RE" in egon.data.config.settings()["egon-data"]["--scenarios"]:
1322
        if (
1323
            pv_rora_100RE["installed capacity in kW"].sum() > 0
1324
            or pv_agri_100RE["installed capacity in kW"].sum() > 0
1325
            or pv_per_distr_100RE["installed capacity in kW"].sum() > 0
1326
            or pv_exist_100RE["installed capacity in kW"].sum() > 0
1327
        ):
1328
            pv_parks_100RE = insert_pv_parks(
1329
                pv_rora_100RE,
1330
                pv_agri_100RE,
1331
                pv_exist_100RE,
1332
                pv_per_distr_100RE,
1333
                "eGon100RE",
1334
            )
1335
1336
        else:
1337
            pv_parks_100RE = gpd.GeoDataFrame()
1338
    else:
1339
        pv_parks_100RE = gpd.GeoDataFrame()
1340
1341
    return pv_parks, pv_parks_100RE
1342