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

data.datasets.power_plants.pv_ground_mounted   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 1339
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 44
eloc 745
dl 0
loc 1339
rs 8.735
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
F insert() 0 1329 44

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