data.datasets.power_plants.pv_ground_mounted   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 1341
Duplicated Lines 0 %

Importance

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

1 Function

Rating   Name   Duplication   Size   Complexity  
F insert() 0 1329 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["index_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["index_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["index_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
        o = overlay["index_right"]
326
        o.drop_duplicates(inplace=True)
327
328
        # define selected potentials areas
329
        pot_sel = potentials_pot.copy()
330
        pot_sel["selected"] = pd.Series()
331
        pot_sel["voltage_level"] = pd.Series(dtype=int)
332
        for i in range(0, len(o)):
333
            index_pot = o.iloc[i]
334
            pot_sel["selected"].loc[index_pot] = True
335
            # get voltage level of existing PVs
336
            index_pv = o.index[i]
337
            pot_sel["voltage_level"] = mastr["voltage_level"].loc[index_pv]
338
        pot_sel = pot_sel[pot_sel["selected"] == True]
339
        pot_sel.drop("selected", axis=1, inplace=True)
340
341
        # drop selected existing pv parks from mastr
342
        mastr.drop(index=o.index, inplace=True)
343
344
        return (pot_sel, mastr)
345
346
    def build_pv(pv_pot, pow_per_area):
347
        """Build new pv parks in selected potential areas.
348
349
        Parameters
350
        ----------
351
        pv_pot: gpd.GeoDataFrame()
352
            Selected potential areas
353
        pow_per_area: int
354
            Assumption for areas of existing pv farms and power of new built
355
            pv farms depending on area in kW/m²
356
357
        """
358
359
        # build pv farms in selected areas
360
361
        # calculation of centroids
362
        pv_pot["centroid"] = pv_pot["geom"].representative_point()
363
364
        # calculation of power in kW
365
        pv_pot["installed capacity in kW"] = pd.Series()
366
        pv_pot["installed capacity in kW"] = pv_pot["area"] * pow_per_area
367
368
        # check for maximal capacity for PV ground mounted
369
        limit_cap = 120000  # in kW
370
        pv_pot["installed capacity in kW"] = pv_pot[
371
            "installed capacity in kW"
372
        ].apply(lambda x: x if x < limit_cap else limit_cap)
373
374
        return pv_pot
375
376
    def adapt_grid_level(pv_pot, max_dist_hv, con):
377
        """Check and if needed adapt grid level of newly built pv parks.
378
379
        Parameters
380
        ----------
381
        pv_pot: gpd.GeoDataFrame()
382
            Newly built pv parks on selected potential areas
383
        max_dist_hv: int
384
            Assumption for maximum distance of park with hv-power to next
385
            substation in m
386
        con:
387
            Connection to database
388
389
        """
390
391
        # divide dataframe in MV and HV
392
        pv_pot_mv = pv_pot[pv_pot["voltage_level"] == 5]
393
        pv_pot_hv = pv_pot[pv_pot["voltage_level"] == 4]
394
395
        # check installed capacity in MV
396
397
        max_cap_mv = 5500  # in kW
398
399
        # find PVs which need to be HV or to have reduced capacity
400
        pv_pot_mv_to_hv = pv_pot_mv[
401
            pv_pot_mv["installed capacity in kW"] > max_cap_mv
402
        ]
403
404
        if len(pv_pot_mv_to_hv) > 0:
405
            # import data for HV substations
406
407
            sql = "SELECT point, voltage FROM grid.egon_hvmv_substation"
408
            hvmv_substation = gpd.GeoDataFrame.from_postgis(
409
                sql, con, geom_col="point"
410
            )
411
            hvmv_substation = hvmv_substation.to_crs(3035)
412
            hvmv_substation["voltage"] = hvmv_substation["voltage"].apply(
413
                lambda x: int(re.split(";|:", x)[0])
414
            )
415
            hv_substations = hvmv_substation[
416
                hvmv_substation["voltage"] >= 110000
417
            ]
418
            hv_substations = (
419
                hv_substations.unary_union
420
            )  # join all the hv_substations
421
422
            # check distance to HV substations of PVs with too high installed
423
            # capacity for MV
424
425
            # calculate distance to substations
426
            pv_pot_mv_to_hv["dist_to_HV"] = (
427
                pv_pot_mv_to_hv["geom"].to_crs(3035).distance(hv_substations)
428
            )
429
430
            # adjust grid level and keep capacity if transmission lines are
431
            # close
432
            pv_pot_mv_to_hv = pv_pot_mv_to_hv[
433
                pv_pot_mv_to_hv["dist_to_HV"] <= max_dist_hv
434
            ]
435
            pv_pot_mv_to_hv = pv_pot_mv_to_hv.drop(columns=["dist_to_HV"])
436
            pv_pot_hv = pd.concat([pv_pot_hv, pv_pot_mv_to_hv])
437
438
            # delete PVs which are now HV from MV dataframe
439
            for index, pot in pv_pot_mv_to_hv.iterrows():
440
                pv_pot_mv = pv_pot_mv.drop([index])
441
            pv_pot_hv["voltage_level"] = 4
442
443
            # keep grid level adjust capacity if transmission lines are too
444
            # far
445
            pv_pot_mv["installed capacity in kW"] = pv_pot_mv[
446
                "installed capacity in kW"
447
            ].apply(lambda x: x if x < max_cap_mv else max_cap_mv)
448
            pv_pot_mv["voltage_level"] = 5
449
450
            pv_pot = pd.concat([pv_pot_mv, pv_pot_hv])
451
452
        return pv_pot
453
454
    def build_additional_pv(potentials, pv, pow_per_area, con):
455
        """Build additional pv parks if pv parks on selected potential areas
456
        do not hit the target value.
457
458
         Parameters
459
         ----------
460
         potenatials: gpd.GeoDataFrame()
461
             All suitable potential areas
462
         pv: gpd.GeoDataFrame()
463
             Newly built pv parks on selected potential areas
464
        pow_per_area: int
465
             Assumption for areas of existing pv farms and power of new built
466
             pv farms depending on area in kW/m²
467
         con:
468
             Connection to database
469
470
        """
471
472
        # get MV grid districts
473
        sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
474
        distr = gpd.GeoDataFrame.from_postgis(sql, con)
475
        distr = distr.set_index("bus_id")
476
477
        # identify potential areas where there are no PV parks yet
478
        for index, pv in pv.iterrows():
479
            potentials = potentials.drop([index])
480
481
        # aggregate potential area per MV grid district
482
        pv_per_distr = gpd.GeoDataFrame()
483
        pv_per_distr["geom"] = distr["geom"].copy()
484
        centroids = potentials.copy()
485
        centroids["geom"] = centroids["geom"].representative_point()
486
487
        overlay = gpd.sjoin(centroids, distr)
488
489
        # ### examine potential area per grid district
490
        anz = len(overlay)
491
        anz_distr = len(overlay["index_right"].unique())
492
        size = 137500  # m2 Fläche für > 5,5 MW: (5500 kW / (0,04 kW/m2))
493
        anz_big = len(overlay[overlay["area"] >= size])
494
        anz_small = len(overlay[overlay["area"] < size])
495
496
        print(" ")
497
        print(
498
            "Examination of remaining potential areas in MV grid districts: "
499
        )
500
        print("Number of potential areas: " + str(anz))
501
        print(" -> distributed to " + str(anz_distr) + " districts")
502
        print("Number of areas with a potential >= 5,5 MW: " + str(anz_big))
503
        print("Number of areas with a potential < 5,5 MW: " + str(anz_small))
504
        print(" ")
505
506
        for index, dist in distr.iterrows():
507
            pots = overlay[overlay["index_right"] == index]["geom"].index
508
            p = gpd.GeoSeries(index=pots)
509
            for i in pots:
510
                p.loc[i] = potentials["geom"].loc[i]
511
            pv_per_distr["geom"].loc[index] = p.unary_union
512
513
        # calculate area per MV grid district and linearly distribute needed
514
        # capacity considering pow_per_area
515
        pv_per_distr["area"] = pv_per_distr["geom"].area
516
        pv_per_distr["installed capacity in kW"] = (
517
            pv_per_distr["area"] * pow_per_area
518
        )
519
520
        # calculate centroid
521
        pv_per_distr["centroid"] = pv_per_distr["geom"].representative_point()
522
523
        return pv_per_distr
524
525
    def check_target(
526
        pv_rora_i,
527
        pv_agri_i,
528
        pv_exist_i,
529
        potentials_rora_i,
530
        potentials_agri_i,
531
        target_power,
532
        pow_per_area,
533
        con,
534
    ):
535
        """Check target value per scenario and per state.
536
537
         Parameters
538
         ----------
539
         pv_rora_i: gpd.GeoDataFrame()
540
             Newly built pv parks on selected potential areas of road and
541
             railways p
542
         pv_agri_i: gpd.GeoDataFrame()
543
             Newly built pv parks on selected potential areas of agriculture
544
         pv_exist_i: gpd.GeoDataFrame()
545
             existing pv parks that don't intercept any potential area
546
         potenatials_rora_i: gpd.GeoDataFrame()
547
             All suitable potential areas of road and railway
548
         potenatials_rora_i: gpd.GeoDataFrame()
549
             All suitable potential areas of agriculture
550
         target_power: int
551
             Target for installed capacity of pv ground mounted in referenced
552
             state
553
        pow_per_area: int
554
             Assumption for areas of existing pv farms and power of new built
555
             pv farms depending on area in kW/m²
556
         con:
557
             Connection to database
558
559
        """
560
561
        # sum overall installed capacity for MV and HV
562
563
        total_pv_power = (
564
            pv_rora_i["installed capacity in kW"].sum()
565
            + pv_agri_i["installed capacity in kW"].sum()
566
            + pv_exist_i["installed capacity in kW"].sum()
567
        )
568
569
        pv_per_distr_i = gpd.GeoDataFrame()
570
571
        # check target value
572
573
        ###
574
        print(" ")
575
        print(
576
            "Installed capacity on areas with existing plants: "
577
            + str(total_pv_power / 1000)
578
            + " MW"
579
        )
580
581
        # linear scale farms to meet target if sum of installed capacity is
582
        # too high
583
        if total_pv_power >= target_power:
584
            scale_factor = target_power / total_pv_power
585
            pv_rora_i["installed capacity in kW"] = (
586
                pv_rora_i["installed capacity in kW"] * scale_factor
587
            )
588
            pv_agri_i["installed capacity in kW"] = (
589
                pv_agri_i["installed capacity in kW"] * scale_factor
590
            )
591
            pv_exist_i["installed capacity in kW"] = (
592
                pv_exist_i["installed capacity in kW"] * scale_factor
593
            )
594
595
            pv_per_distr_i["grid_district"] = pd.Series()
596
            pv_per_distr_i["installed capacity in kW"] = pd.Series(0)
597
598
            ###
599
            print(
600
                "Expansion of existing PV parks on potential areas to "
601
                "achieve target capacity is sufficient."
602
            )
603
            print(
604
                "Installed power is greater than the target value, scaling "
605
                "is applied:"
606
            )
607
            print("Scaling factor: " + str(scale_factor))
608
609
        # build new pv parks if sum of installed capacity is below target
610
        # value
611
        elif total_pv_power < target_power:
612
            rest_cap = target_power - total_pv_power
613
614
            ###
615
            print(
616
                "Expansion of existing PV parks on potential areas to "
617
                "achieve target capacity is unsufficient:"
618
            )
619
            print("Residual capacity: " + str(rest_cap / 1000) + " MW")
620
            print(
621
                "Residual capacity will initially be distributed via "
622
                "remaining potential areas 'Road & Railway'."
623
            )
624
625
            # build pv parks in potential areas road & railway
626
            pv_per_distr_i = build_additional_pv(
627
                potentials_rora_i, pv_rora_i, pow_per_area, con
628
            )
629
            # change index to add different Dataframes in the end
630
            pv_per_distr_i["grid_district"] = pv_per_distr_i.index.copy()
631
            pv_per_distr_i.index = range(0, len(pv_per_distr_i))
632
            # delete empty grid districts
633
            index_names = pv_per_distr_i[
634
                pv_per_distr_i["installed capacity in kW"].isna()
635
            ].index
636
            pv_per_distr_i.drop(index_names, inplace=True)
637
638
            if pv_per_distr_i["installed capacity in kW"].sum() > rest_cap:
639
                scale_factor = (
640
                    rest_cap / pv_per_distr_i["installed capacity in kW"].sum()
641
                )
642
                pv_per_distr_i["installed capacity in kW"] = (
643
                    pv_per_distr_i["installed capacity in kW"] * scale_factor
644
                )
645
646
                ###
647
                print(
648
                    "Residual capacity got distributed via scaling factor "
649
                    + str(scale_factor)
650
                    + " to remaining potential areas 'Road & Railway'."
651
                )
652
653
            # build pv parks on potential areas agriculture if still necessary
654
            elif pv_per_distr_i["installed capacity in kW"].sum() < rest_cap:
655
                rest_cap = (
656
                    target_power
657
                    - total_pv_power
658
                    - pv_per_distr_i["installed capacity in kW"].sum()
659
                )
660
661
                ###
662
                print(
663
                    "Distribution via potential areas Road & Railway "
664
                    "unsufficient to achieve target capacity:"
665
                )
666
                print("Residual capacity: " + str(rest_cap / 1000) + " MW")
667
                print(
668
                    "Residual capacity is distributed to remaining potential "
669
                    "areas 'Agriculture'."
670
                )
671
672
                pv_per_distr_i_2 = build_additional_pv(
673
                    potentials_agri_i, pv_agri_i, pow_per_area, con
674
                )
675
                # change index to add different Dataframes in the end
676
                pv_per_distr_i_2["grid_district"] = pv_per_distr_i_2.index
677
                pv_per_distr_i_2.index = range(len(pv_per_distr_i_2))
678
679
                # delete empty grid districts
680
                index_names = pv_per_distr_i_2[
681
                    pv_per_distr_i_2["installed capacity in kW"].isna()
682
                ].index
683
                pv_per_distr_i_2.drop(index_names, inplace=True)
684
685
                if (
686
                    pv_per_distr_i_2["installed capacity in kW"].sum()
687
                    > rest_cap
688
                ):
689
                    scale_factor = (
690
                        rest_cap
691
                        / pv_per_distr_i_2["installed capacity in kW"].sum()
692
                    )
693
                    pv_per_distr_i_2["installed capacity in kW"] = (
694
                        pv_per_distr_i_2["installed capacity in kW"]
695
                        * scale_factor
696
                    )
697
698
                    ###
699
                    print(
700
                        "Residual capacity got distributed via scaling "
701
                        "factor "
702
                        + str(scale_factor)
703
                        + " to remaining potential areas 'Road & Railway' "
704
                        "and 'Agriculture'."
705
                    )
706
707
                pv_per_distr_i = pd.concat(
708
                    [pv_per_distr_i, pv_per_distr_i_2], ignore_index=True
709
                )
710
711
            # assign grid level to pv_per_distr
712
            v_lvl = pd.Series(dtype=int, index=pv_per_distr_i.index)
713
            for index, distr in pv_per_distr_i.iterrows():
714
                if distr["installed capacity in kW"] > 5500:  # > 5 MW
715
                    v_lvl[index] = 4
716
                else:
717
                    v_lvl[index] = 5
718
            pv_per_distr_i["voltage_level"] = v_lvl
719
720
            # new overall installed capacity
721
            total_pv_power = (
722
                pv_rora_i["installed capacity in kW"].sum()
723
                + pv_agri_i["installed capacity in kW"].sum()
724
                + pv_exist_i["installed capacity in kW"].sum()
725
                + pv_per_distr_i["installed capacity in kW"].sum()
726
            )
727
728
            ###
729
            print(
730
                "Total installed capacity of PV farms: "
731
                + str(total_pv_power / 1000)
732
                + " MW"
733
            )
734
            print(" ")
735
736
        pv_rora_i = pv_rora_i[pv_rora_i["installed capacity in kW"] > 0]
737
        pv_agri_i = pv_agri_i[pv_agri_i["installed capacity in kW"] > 0]
738
        pv_exist_i = pv_exist_i[pv_exist_i["installed capacity in kW"] > 0]
739
        pv_per_distr_i = pv_per_distr_i[
740
            pv_per_distr_i["installed capacity in kW"] > 0
741
        ]
742
743
        return pv_rora_i, pv_agri_i, pv_exist_i, pv_per_distr_i
744
745
    def keep_existing_pv(mastr, con):
746
        pv_exist = mastr[
747
            [
748
                "geometry",
749
                "installed capacity in kW",
750
                "voltage_level",
751
            ]
752
        ]
753
        pv_exist.rename(columns={"geometry": "centroid"}, inplace=True)
754
        pv_exist = gpd.GeoDataFrame(pv_exist, geometry="centroid", crs=3035)
755
756
        # German states
757
        sql = "SELECT geometry as geom, gf FROM boundaries.vg250_lan"
758
        land = gpd.GeoDataFrame.from_postgis(sql, con).to_crs(3035)
759
        land = land[(land["gf"] != 1) & (land["gf"] != 2)]
760
        land = land.unary_union
761
        pv_exist = gpd.clip(pv_exist, land)
762
763
        return pv_exist
764
765
    def run_methodology(
766
        con=db.engine(),
767
        pow_per_area=0.04,
768
        join_buffer=10,
769
        max_dist_hv=20000,
770
        show_map=False,
771
    ):
772
        """Execute methodology to distribute pv ground mounted.
773
774
         Parameters
775
         ----------
776
         con:
777
             Connection to database
778
         pow_per_area: int, default 0.4
779
             Assumption for areas of existing pv farms and power of new built
780
             pv farms depending on area in kW/m²
781
         join_buffer : int, default 10
782
             Maximum distance for joining of potential areas (only small ones
783
             to big ones) in m
784
         max_dist_hv : int, default 20000
785
             Assumption for maximum distance of park with hv-power to next
786
             substation in m
787
        show_map:  boolean
788
            Optional creation of map to show distribution of installed
789
            capacity
790
791
        """
792
        ###
793
        print(" ")
794
        print("MaStR-Data")
795
        print(" ")
796
797
        # MaStR-data: existing PV farms
798
        mastr = mastr_existing_pv(pow_per_area)
799
800
        ###
801
        print(" ")
802
        print("potential area")
803
        print(" ")
804
805
        # database-data: potential areas for new PV farms
806
        potentials_rora, potentials_agri = potential_areas(con, join_buffer)
807
808
        ###
809
        print(" ")
810
        print("select potentials area")
811
        print(" ")
812
813
        # select potential areas with existing PV farms to build new PV farms
814
        pv_rora, mastr = select_pot_areas(mastr, potentials_rora)
815
        pv_agri, mastr = select_pot_areas(mastr, potentials_agri)
816
817
        ###
818
        print(" ")
819
        print(
820
            "build PV parks where there is PV ground mounted already "
821
            "(-> MaStR) on potential area"
822
        )
823
        print(" ")
824
825
        # build new PV farms
826
        pv_rora = build_pv(pv_rora, pow_per_area)
827
        pv_agri = build_pv(pv_agri, pow_per_area)
828
829
        # keep the existing pv_farms that don't intercept potential areas
830
        exist = keep_existing_pv(mastr, con)
831
832
        ###
833
        print(" ")
834
        print("adapt grid level of PV parks")
835
        print(" ")
836
837
        # adapt grid level to new farms
838
        rora = adapt_grid_level(pv_rora, max_dist_hv, con)
839
        agri = adapt_grid_level(pv_agri, max_dist_hv, con)
840
841
        ###
842
        print(" ")
843
        print(
844
            "check target value and build more PV parks on potential area if "
845
            "necessary"
846
        )
847
        print(" ")
848
849
        # initialize final dataframe
850
        pv_rora = gpd.GeoDataFrame()
851
        pv_agri = gpd.GeoDataFrame()
852
        pv_exist = gpd.GeoDataFrame()
853
        pv_per_distr = gpd.GeoDataFrame()
854
855
        pv_rora_100RE = gpd.GeoDataFrame()
856
        pv_agri_100RE = gpd.GeoDataFrame()
857
        pv_exist_100RE = gpd.GeoDataFrame()
858
        pv_per_distr_100RE = gpd.GeoDataFrame()
859
860
        # 1) scenario: eGon2035
861
        if (
862
            "eGon2035"
863
            in egon.data.config.settings()["egon-data"]["--scenarios"]
864
        ):
865
            ###
866
            print(" ")
867
            print("scenario: eGon2035")
868
            print(" ")
869
870
            # German states
871
            sql = "SELECT geometry as geom, nuts FROM boundaries.vg250_lan"
872
            states = gpd.GeoDataFrame.from_postgis(sql, con)
873
874
            # assumption for target value of installed capacity
875
            sql = (
876
                "SELECT capacity,scenario_name,nuts FROM "
877
                "supply.egon_scenario_capacities WHERE carrier='solar'"
878
            )
879
            target = pd.read_sql(sql, con)
880
            target = target[target["scenario_name"] == "eGon2035"]
881
            nuts = np.unique(target["nuts"])
882
883
            # prepare selection per state
884
            rora = rora.set_geometry("centroid")
885
            agri = agri.set_geometry("centroid")
886
            potentials_rora = potentials_rora.set_geometry("geom")
887
            potentials_agri = potentials_agri.set_geometry("geom")
888
889
            # check target value per state
890
            for i in nuts:
891
                target_power = (
892
                    target[target["nuts"] == i]["capacity"].iloc[0] * 1000
893
                )
894
895
                ###
896
                land = target[target["nuts"] == i]["nuts"].iloc[0]
897
                print(" ")
898
                print("Bundesland (NUTS): " + land)
899
                print("target power: " + str(target_power / 1000) + " MW")
900
901
                # select state
902
                state = states[states["nuts"] == i]
903
                state = state.to_crs(3035)
904
905
                # select PVs in state
906
                rora_i = gpd.sjoin(rora, state)
907
                agri_i = gpd.sjoin(agri, state)
908
                exist_i = gpd.sjoin(exist, state)
909
                rora_i.drop("index_right", axis=1, inplace=True)
910
                agri_i.drop("index_right", axis=1, inplace=True)
911
                exist_i.drop("index_right", axis=1, inplace=True)
912
                rora_i.drop_duplicates(inplace=True)
913
                agri_i.drop_duplicates(inplace=True)
914
                exist_i.drop_duplicates(inplace=True)
915
916
                # select potential areas in state
917
                potentials_rora_i = gpd.sjoin(potentials_rora, state)
918
                potentials_agri_i = gpd.sjoin(potentials_agri, state)
919
                potentials_rora_i.drop("index_right", axis=1, inplace=True)
920
                potentials_agri_i.drop("index_right", axis=1, inplace=True)
921
                potentials_rora_i.drop_duplicates(inplace=True)
922
                potentials_agri_i.drop_duplicates(inplace=True)
923
924
                # check target value and adapt installed capacity if necessary
925
                rora_i, agri_i, exist_i, distr_i = check_target(
926
                    rora_i,
927
                    agri_i,
928
                    exist_i,
929
                    potentials_rora_i,
930
                    potentials_agri_i,
931
                    target_power,
932
                    pow_per_area,
933
                    con,
934
                )
935
936
                if len(distr_i) > 0:
937
                    distr_i["nuts"] = target[target["nuts"] == i]["nuts"].iloc[
938
                        0
939
                    ]
940
941
                # ### examination of built PV parks per state
942
                rora_i_mv = rora_i[rora_i["voltage_level"] == 5]
943
                rora_i_hv = rora_i[rora_i["voltage_level"] == 4]
944
                agri_i_mv = agri_i[agri_i["voltage_level"] == 5]
945
                agri_i_hv = agri_i[agri_i["voltage_level"] == 4]
946
                print(
947
                    "eGon2035: Examination of voltage level per federal state:"
948
                )
949
                print("a) PVs on potential areas Road & Railway: ")
950
                print(
951
                    "Total installed capacity: "
952
                    + str(rora_i["installed capacity in kW"].sum() / 1000)
953
                    + " MW"
954
                )
955
                print("Number of PV farms: " + str(len(rora_i)))
956
                print(" - thereof MV: " + str(len(rora_i_mv)))
957
                print(" - thereof HV: " + str(len(rora_i_hv)))
958
                print("b) PVs on potential areas Agriculture: ")
959
                print(
960
                    "Total installed capacity: "
961
                    + str(agri_i["installed capacity in kW"].sum() / 1000)
962
                    + " MW"
963
                )
964
                print("Number of PV farms: " + str(len(agri_i)))
965
                print(" - thereof MV: " + str(len(agri_i_mv)))
966
                print(" - dthereof HV: " + str(len(agri_i_hv)))
967
                print("c) Existing PVs not in potential areas: ")
968
                print("Number of PV farms: " + str(len(exist_i)))
969
                print("d) PVs on additional potential areas per MV-District: ")
970
                if len(distr_i) > 0:
971
                    distr_i_mv = distr_i[distr_i["voltage_level"] == 5]
972
                    distr_i_hv = distr_i[distr_i["voltage_level"] == 4]
973
                    print(
974
                        "Total installed capacity: "
975
                        + str(distr_i["installed capacity in kW"].sum() / 1000)
976
                        + " MW"
977
                    )
978
                    print("Number of PV farms: " + str(len(distr_i)))
979
                    print(" - thereof MV: " + str(len(distr_i_mv)))
980
                    print(" - thereof HV: " + str(len(distr_i_hv)))
981
                else:
982
                    print(" -> No additional expansion necessary")
983
                print(" ")
984
985
                pv_rora = pd.concat([pv_rora, rora_i])
986
                pv_agri = pd.concat([pv_agri, agri_i])
987
                pv_exist = pd.concat([pv_exist, exist_i])
988
                if len(distr_i) > 0:
989
                    pv_per_distr = pd.concat([pv_per_distr, distr_i])
990
991
        if (
992
            "eGon100RE"
993
            in egon.data.config.settings()["egon-data"]["--scenarios"]
994
        ):
995
            # 2) scenario: eGon100RE
996
997
            # assumption for target value of installed capacity in Germany per
998
            # scenario
999
            sql = (
1000
                "SELECT capacity,scenario_name FROM "
1001
                "supply.egon_scenario_capacities WHERE carrier='solar'"
1002
            )
1003
            target_power = pd.read_sql(sql, con)
1004
            target_power = target_power[
1005
                target_power["scenario_name"] == "eGon100RE"
1006
            ]
1007
            target_power = target_power["capacity"].sum() * 1000
1008
1009
            ###
1010
            print(" ")
1011
            print("scenario: eGon100RE")
1012
            print("target power: " + str(target_power) + " kW")
1013
            print(" ")
1014
1015
            # check target value and adapt installed capacity if necessary
1016
            (
1017
                pv_rora_100RE,
1018
                pv_agri_100RE,
1019
                pv_exist_100RE,
1020
                pv_per_distr_100RE,
1021
            ) = check_target(
1022
                rora,
1023
                agri,
1024
                exist,
1025
                potentials_rora,
1026
                potentials_agri,
1027
                target_power,
1028
                pow_per_area,
1029
                con,
1030
            )
1031
1032
            pv_rora_100RE = pv_rora_100RE[
1033
                pv_rora_100RE["installed capacity in kW"] > 0
1034
            ]
1035
            pv_agri_100RE = pv_agri_100RE[
1036
                pv_agri_100RE["installed capacity in kW"] > 0
1037
            ]
1038
            pv_per_distr_100RE = pv_per_distr_100RE[
1039
                pv_per_distr_100RE["installed capacity in kW"] > 0
1040
            ]
1041
1042
        # ### create map to show distribution of installed capacity
1043
        if show_map == True:
1044
            # 1) eGon2035
1045
1046
            # get MV grid districts
1047
            sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
1048
            distr = gpd.GeoDataFrame.from_postgis(sql, con)
1049
            distr = distr.set_index("bus_id")
1050
1051
            # assign pv_per_distr-power to districts
1052
            distr["capacity"] = pd.Series()
1053
            for index, row in distr.iterrows():
1054
                if index in np.unique(pv_per_distr["grid_district"]):
1055
                    pv = pv_per_distr[pv_per_distr["grid_district"] == index]
1056
                    x = pv["installed capacity in kW"].iloc[0]
1057
                    distr["capacity"].loc[index] = x
1058
                else:
1059
                    distr["capacity"].loc[index] = 0
1060
            distr["capacity"] = distr["capacity"] / 1000
1061
1062
            # add pv_rora- and pv_agri-power to district
1063
            pv_rora = pv_rora.set_geometry("centroid")
1064
            pv_agri = pv_agri.set_geometry("centroid")
1065
            overlay_rora = gpd.sjoin(pv_rora, distr)
1066
            overlay_agri = gpd.sjoin(pv_agri, distr)
1067
1068
            for index, row in distr.iterrows():
1069
                o_rora = overlay_rora[overlay_rora["index_right"] == index]
1070
                o_agri = overlay_agri[overlay_agri["index_right"] == index]
1071
                cap_rora = o_rora["installed capacity in kW"].sum() / 1000
1072
                cap_agri = o_agri["installed capacity in kW"].sum() / 1000
1073
            distr["capacity"].loc[index] = (
1074
                distr["capacity"].loc[index] + cap_rora + cap_agri
0 ignored issues
show
introduced by
The variable cap_rora does not seem to be defined in case the for loop on line 1068 is not entered. Are you sure this can never be the case?
Loading history...
introduced by
The variable cap_agri does not seem to be defined in case the for loop on line 1068 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 1053 is not entered. Are you sure this can never be the case?
Loading history...
1075
            )
1076
1077
            from matplotlib import pyplot as plt
1078
1079
            fig, ax = plt.subplots(1, 1)
1080
            distr.boundary.plot(linewidth=0.2, ax=ax, color="black")
1081
            distr.plot(
1082
                ax=ax,
1083
                column="capacity",
1084
                cmap="magma_r",
1085
                legend=True,
1086
                legend_kwds={
1087
                    "label": "Installed capacity in MW",
1088
                    "orientation": "vertical",
1089
                },
1090
            )
1091
            plt.savefig("pv_per_distr_map_eGon2035.png", dpi=300)
1092
1093
            # 2) eGon100RE
1094
1095
            # get MV grid districts
1096
            sql = "SELECT bus_id, geom FROM grid.egon_mv_grid_district"
1097
            distr = gpd.GeoDataFrame.from_postgis(sql, con)
1098
            distr = distr.set_index("bus_id")
1099
1100
            # assign pv_per_distr-power to districts
1101
            distr["capacity"] = pd.Series()
1102
            for index, row in distr.iterrows():
1103
                if index in np.unique(pv_per_distr_100RE["grid_district"]):
1104
                    pv = pv_per_distr_100RE[
1105
                        pv_per_distr_100RE["grid_district"] == index
1106
                    ]
1107
                    x = pv["installed capacity in kW"].iloc[0]
1108
                    distr["capacity"].loc[index] = x
1109
                else:
1110
                    distr["capacity"].loc[index] = 0
1111
            distr["capacity"] = distr["capacity"] / 1000
1112
1113
            # add pv_rora- and pv_agri-power to district
1114
            pv_rora_100RE = pv_rora_100RE.set_geometry("centroid")
1115
            pv_agri_100RE = pv_agri_100RE.set_geometry("centroid")
1116
            overlay_rora = gpd.sjoin(pv_rora_100RE, distr)
1117
            overlay_agri = gpd.sjoin(pv_agri_100RE, distr)
1118
1119
            for index, row in distr.iterrows():
1120
                o_rora = overlay_rora[overlay_rora["index_right"] == index]
1121
                o_agri = overlay_agri[overlay_agri["index_right"] == index]
1122
                cap_rora = o_rora["installed capacity in kW"].sum() / 1000
1123
                cap_agri = o_agri["installed capacity in kW"].sum() / 1000
1124
            distr["capacity"].loc[index] = (
1125
                distr["capacity"].loc[index] + cap_rora + cap_agri
1126
            )
1127
1128
            from matplotlib import pyplot as plt
1129
1130
            fig, ax = plt.subplots(1, 1)
1131
            distr.boundary.plot(linewidth=0.2, ax=ax, color="black")
1132
            distr.plot(
1133
                ax=ax,
1134
                column="capacity",
1135
                cmap="magma_r",
1136
                legend=True,
1137
                legend_kwds={
1138
                    "label": "Installed capacity in MW",
1139
                    "orientation": "vertical",
1140
                },
1141
            )
1142
            plt.savefig("pv_per_distr_map_eGon100RE.png", dpi=300)
1143
1144
        return (
1145
            pv_rora,
1146
            pv_agri,
1147
            pv_exist,
1148
            pv_per_distr,
1149
            pv_rora_100RE,
1150
            pv_agri_100RE,
1151
            pv_exist_100RE,
1152
            pv_per_distr_100RE,
1153
        )
1154
1155
    def insert_pv_parks(
1156
        pv_rora, pv_agri, pv_exist, pv_per_distr, scenario_name
1157
    ):
1158
        """Write to database.
1159
1160
        Parameters
1161
        ----------
1162
        pv_rora : gpd.GeoDataFrame()
1163
            Pv parks on selected potential areas of raod and railway
1164
        pv_agri : gpd.GeoDataFrame()
1165
            Pv parks on selected potential areas of raod and railway
1166
        pv_exist : gpd.GeoDataFrame()
1167
            Existing Pv parks on selected areas
1168
        pv_per_distr: gpd.GeoDataFrame()
1169
            Additionally built pv parks on potential areas per mv grid
1170
            district
1171
        scenario_name:
1172
            Scenario name of calculation
1173
1174
        """
1175
1176
        # prepare dataframe for integration in supply.egon_power_plants
1177
1178
        pv_parks = pd.concat(
1179
            [pv_rora, pv_agri, pv_exist, pv_per_distr], ignore_index=True
1180
        )
1181
        pv_parks["el_capacity"] = pv_parks["installed capacity in kW"] / 1000
1182
        pv_parks.rename(columns={"centroid": "geometry"}, inplace=True)
1183
        pv_parks = gpd.GeoDataFrame(pv_parks, geometry="geometry", crs=3035)
1184
        pv_parks = pv_parks[["el_capacity", "voltage_level", "geometry"]]
1185
1186
        # integration in supply.egon_power_plants
1187
1188
        con = db.engine()
1189
1190
        # maximum ID in egon_power_plants
1191
        sql = "SELECT MAX(id) FROM supply.egon_power_plants"
1192
        max_id = pd.read_sql(sql, con)
1193
        max_id = max_id["max"].iat[0]
1194
        if max_id is None:
1195
            max_id = 1
1196
1197
        pv_park_id = max_id + 1
1198
1199
        # copy relevant columns from pv_parks
1200
        insert_pv_parks = pv_parks[
1201
            ["el_capacity", "voltage_level", "geometry"]
1202
        ]
1203
        insert_pv_parks = insert_pv_parks.set_geometry("geometry")
1204
        insert_pv_parks["voltage_level"] = insert_pv_parks[
1205
            "voltage_level"
1206
        ].apply(int)
1207
1208
        # set static column values
1209
        insert_pv_parks["carrier"] = "solar"
1210
        insert_pv_parks["scenario"] = scenario_name
1211
1212
        # change name and crs of geometry column
1213
        insert_pv_parks.set_crs(epsg=3035, allow_override=True, inplace=True)
1214
        insert_pv_parks = (
1215
            insert_pv_parks.rename({"geometry": "geom"}, axis=1)
1216
            .set_geometry("geom")
1217
            .to_crs(4326)
1218
        )
1219
1220
        # reset index
1221
        insert_pv_parks.index = pd.RangeIndex(
1222
            start=pv_park_id, stop=pv_park_id + len(insert_pv_parks), name="id"
1223
        )
1224
1225
        # insert into database
1226
        insert_pv_parks.reset_index().to_postgis(
1227
            "egon_power_plants",
1228
            schema="supply",
1229
            con=db.engine(),
1230
            if_exists="append",
1231
        )
1232
1233
        return pv_parks
1234
1235
    # ########################################################################
1236
1237
    # execute methodology
1238
1239
    (
1240
        pv_rora,
1241
        pv_agri,
1242
        pv_exist,
1243
        pv_per_distr,
1244
        pv_rora_100RE,
1245
        pv_agri_100RE,
1246
        pv_exist_100RE,
1247
        pv_per_distr_100RE,
1248
    ) = run_methodology(
1249
        con=db.engine(),
1250
        pow_per_area=0.04,
1251
        join_buffer=10,
1252
        max_dist_hv=20000,
1253
        show_map=False,
1254
    )
1255
1256
    # ### examination of results
1257
    if len(pv_per_distr) > 0:
1258
        pv_per_distr_mv = pv_per_distr[pv_per_distr["voltage_level"] == 5]
1259
        pv_per_distr_hv = pv_per_distr[pv_per_distr["voltage_level"] == 4]
1260
    if len(pv_rora) > 0:
1261
        pv_rora_mv = pv_rora[pv_rora["voltage_level"] == 5]
1262
        pv_rora_hv = pv_rora[pv_rora["voltage_level"] == 4]
1263
        pv_agri_mv = pv_agri[pv_agri["voltage_level"] == 5]
1264
        pv_agri_hv = pv_agri[pv_agri["voltage_level"] == 4]
1265
1266
        print(" ")
1267
        print("eGon2035: Examination of overall voltage levels:")
1268
        print("a) PVs on potential areas Road & Railway: ")
1269
        print(
1270
            "Total installed capacity: "
1271
            + str(pv_rora["installed capacity in kW"].sum() / 1000)
1272
            + " MW"
1273
        )
1274
        print("Number of PV farms: " + str(len(pv_rora)))
1275
        print(" - thereof MV: " + str(len(pv_rora_mv)))
1276
        print(" - thereof HV: " + str(len(pv_rora_hv)))
1277
        print("b) PVs on potential areas Agriculture: ")
1278
        print(
1279
            "Total installed capacity: "
1280
            + str(pv_agri["installed capacity in kW"].sum() / 1000)
1281
            + " MW"
1282
        )
1283
        print("Number of PV farms: " + str(len(pv_agri)))
1284
        print(" - thereof MV: " + str(len(pv_agri_mv)))
1285
        print(" - thereof HV: " + str(len(pv_agri_hv)))
1286
        print("c) Existing PVs not in potential areas: ")
1287
        print("Number of PV farms: " + str(len(pv_exist)))
1288
        print("d) PVs on additional potential areas per MV-District: ")
1289
        if len(pv_per_distr) > 0:
1290
            print(
1291
                "Total installed capacity: "
1292
                + str(pv_per_distr["installed capacity in kW"].sum() / 1000)
1293
                + " MW"
1294
            )
1295
            print("Number of PV farms: " + str(len(pv_per_distr)))
1296
            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 1257 is False. Are you sure this can never be the case?
Loading history...
1297
            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 1257 is False. Are you sure this can never be the case?
Loading history...
1298
        else:
1299
            print(" -> No additional expansion needed")
1300
        print(" ")
1301
        ###
1302
1303
    # save to DB
1304
    if "eGon2035" in egon.data.config.settings()["egon-data"]["--scenarios"]:
1305
        if (
1306
            pv_rora["installed capacity in kW"].sum() > 0
1307
            or pv_agri["installed capacity in kW"].sum() > 0
1308
            or pv_per_distr["installed capacity in kW"].sum() > 0
1309
            or pv_exist["installed capacity in kW"].sum() > 0
1310
        ):
1311
            pv_parks = insert_pv_parks(
1312
                pv_rora, pv_agri, pv_exist, pv_per_distr, "eGon2035"
1313
            )
1314
1315
        else:
1316
            pv_parks = gpd.GeoDataFrame()
1317
    else:
1318
        pv_parks = gpd.GeoDataFrame()
1319
1320
    if "eGon100RE" in egon.data.config.settings()["egon-data"]["--scenarios"]:
1321
        if (
1322
            pv_rora_100RE["installed capacity in kW"].sum() > 0
1323
            or pv_agri_100RE["installed capacity in kW"].sum() > 0
1324
            or pv_per_distr_100RE["installed capacity in kW"].sum() > 0
1325
            or pv_exist_100RE["installed capacity in kW"].sum() > 0
1326
        ):
1327
            pv_parks_100RE = insert_pv_parks(
1328
                pv_rora_100RE,
1329
                pv_agri_100RE,
1330
                pv_exist_100RE,
1331
                pv_per_distr_100RE,
1332
                "eGon100RE",
1333
            )
1334
1335
        else:
1336
            pv_parks_100RE = gpd.GeoDataFrame()
1337
    else:
1338
        pv_parks_100RE = gpd.GeoDataFrame()
1339
1340
    return pv_parks, pv_parks_100RE
1341