Passed
Pull Request — dev (#1053)
by
unknown
01:34
created

insert()   F

Complexity

Conditions 44

Size

Total Lines 1283
Code Lines 734

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 734
dl 0
loc 1283
rs 0
c 0
b 0
f 0
cc 44
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

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