Skip to content

Commit

Permalink
include exclusion area
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlosEpia committed Aug 7, 2023
1 parent 7132b01 commit 6e2a0d5
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
2 changes: 2 additions & 0 deletions etrago/appl.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
"method": "kmedoids-dijkstra", # choose clustering method: kmeans or kmedoids-dijkstra
"n_clusters_AC": 30, # total number of resulting AC nodes (DE+foreign)
"cluster_foreign_AC": False, # take foreign AC buses into account, True or False
"exclusion_area": ["Cuxhaven", "Bremerhaven", "Wesermarsch", "Osterholz", "Bremen"], # path to shapefile or list of nust names of not cluster area
"method_gas": "kmedoids-dijkstra", # choose clustering method: kmeans or kmedoids-dijkstra
"n_clusters_gas": 17, # total number of resulting CH4 nodes (DE+foreign)
"cluster_foreign_gas": False, # take foreign CH4 buses into account, True or False
Expand Down Expand Up @@ -464,6 +465,7 @@ def run_etrago(args, json_path):

# spatial clustering
etrago.spatial_clustering()

etrago.spatial_clustering_gas()

# snapshot clustering
Expand Down
89 changes: 72 additions & 17 deletions etrago/cluster/electrical.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
get_clustering_from_busmap,
)
from six import iteritems
import geopandas as gpd
import numpy as np
import pandas as pd
import pypsa.io as io
Expand All @@ -47,6 +48,7 @@
strategies_one_ports,
)
from etrago.tools.utilities import *
from shapely.geometry import Point

logger = logging.getLogger(__name__)

Expand All @@ -69,7 +71,7 @@

def _leading(busmap, df):
"""
Returns a function that computes the leading bus_id for a given mapped
Returns a function that computes the leading bus_id for a given mapped
list of buses.
Parameters
Expand All @@ -95,7 +97,7 @@ def leader(x):

def adjust_no_electric_network(etrago, busmap, cluster_met):
"""
Adjusts the non-electric network based on the electrical network
Adjusts the non-electric network based on the electrical network
(esp. eHV network), adds the gas buses to the busmap, and creates the
new buses for the non-electric network.
Expand All @@ -117,7 +119,7 @@ def adjust_no_electric_network(etrago, busmap, cluster_met):
Maps old bus_ids to new bus_ids including all sectors.
"""
network = etrago.network
# network2 is supposed to contain all the not electrical or gas buses
# network2 is supposed to contain all the not electrical or gas buses
# and links
network2 = network.copy(with_time=False)
network2.buses = network2.buses[
Expand Down Expand Up @@ -386,9 +388,9 @@ def cluster_on_extra_high_voltage(etrago, busmap, with_time=True):

def delete_ehv_buses_no_lines(network):
"""
When there are AC buses totally isolated, this function deletes them in
When there are AC buses totally isolated, this function deletes them in
order to make possible the creation of busmaps based on electrical
connections and other purposes. Additionally, it throws a warning to
connections and other purposes. Additionally, it throws a warning to
inform the user in case that any correction should be done.
Parameters
Expand Down Expand Up @@ -504,6 +506,46 @@ def select_elec_network(etrago):
"""
elec_network = etrago.network.copy()
settings = etrago.args["network_clustering"]

# Exclude buses in the area that should not be clustered
if settings["exclusion_area"]:
con = etrago.engine
query = "SELECT gen, geometry FROM boundaries.vg250_krs"

de_areas = gpd.read_postgis(query, con, geom_col="geometry")
de_areas = de_areas[de_areas["gen"].isin(settings["exclusion_area"])]

try:
buses_area = gpd.GeoDataFrame(
etrago.network.buses, geometry="geom", crs=4326
)
except:
buses_area = etrago.network.buses[
[
"x",
"y",
]
]
buses_area["geom"] = buses_area.apply(
lambda x: Point(x["x"], x["y"]), axis=1
)
buses_area = gpd.GeoDataFrame(
buses_area, geometry="geom", crs=4326
)

buses_area = gpd.clip(buses_area, de_areas)
elec_network.buses = elec_network.buses[
~elec_network.buses.index.isin(buses_area.index)
]

busmap_area = pd.Series(
buses_area.index.rename("bus_area"),
index=buses_area.index.rename("bus"),
)
else:
busmap_area = pd.DataFrame()

# Exclude foreign buses when it is set to don't include them in the clustering
if settings["cluster_foreign_AC"]:
elec_network.buses = elec_network.buses[
elec_network.buses.carrier == "AC"
Expand Down Expand Up @@ -582,7 +624,7 @@ def select_elec_network(etrago):
),
]

return elec_network, n_clusters
return elec_network, n_clusters, busmap_area


def unify_foreign_buses(etrago):
Expand Down Expand Up @@ -764,14 +806,14 @@ def preprocessing(etrago):
else:
busmap_foreign = pd.Series(name="foreign", dtype=str)

network_elec, n_clusters = select_elec_network(etrago)
network_elec, n_clusters, busmap_area = select_elec_network(etrago)

if settings["method"] == "kmedoids-dijkstra":
lines_col = network_elec.lines.columns

# The Dijkstra clustering works using the shortest electrical path
# The Dijkstra clustering works using the shortest electrical path
# between buses. In some cases, a bus has just DC connections, which
# are considered links. Therefore it is necessary to include
# are considered links. Therefore it is necessary to include
# temporarily the DC links into the lines table.
dc = network.links[network.links.carrier == "DC"]
str1 = "DC_"
Expand All @@ -795,10 +837,12 @@ def preprocessing(etrago):
else:
weight = weighting_for_scenario(network=network_elec, save=False)

return network_elec, weight, n_clusters, busmap_foreign
return network_elec, weight, n_clusters, busmap_foreign, busmap_area


def postprocessing(etrago, busmap, busmap_foreign, medoid_idx=None):
def postprocessing(
etrago, busmap, busmap_foreign, medoid_idx=None, busmap_area={}
):
"""
Postprocessing function for network clustering.
Expand Down Expand Up @@ -830,6 +874,7 @@ def postprocessing(etrago, busmap, busmap_foreign, medoid_idx=None):
busmap_elec = pd.DataFrame(busmap.copy(), dtype="string")
busmap_elec.index.name = "bus"
busmap_elec = busmap_elec.join(busmap_foreign, how="outer")
busmap_elec = busmap_elec.join(busmap_area, how="outer")
busmap_elec = busmap_elec.join(
pd.Series(
medoid_idx.index.values.astype(str),
Expand Down Expand Up @@ -866,6 +911,11 @@ def postprocessing(etrago, busmap, busmap_foreign, medoid_idx=None):
medoid_idx.index.values.astype(str), medoid_idx.values.astype(int)
)

# add the not clustered buses to the busmap
if settings["exclusion_area"]:
for bus in busmap_area.index:
busmap[bus] = busmap_area[bus]

network, busmap = adjust_no_electric_network(
etrago, busmap, cluster_met=method
)
Expand Down Expand Up @@ -936,7 +986,6 @@ def weighting_for_scenario(network, save=None):
"""

def calc_availability_factor(gen):

"""
Calculate the availability factor for a given generator.
Expand All @@ -952,10 +1001,10 @@ def calc_availability_factor(gen):
Notes
-----
Availability factor is defined as the ratio of the average power
output of the generator over the maximum power output capacity of
Availability factor is defined as the ratio of the average power
output of the generator over the maximum power output capacity of
the generator. If the generator is time-dependent, its average power
output is calculated using the `network.generators_t` DataFrame.
output is calculated using the `network.generators_t` DataFrame.
Otherwise, its availability factor is obtained from the
`fixed_capacity_fac` dictionary, which contains pre-defined factors
for fixed capacity generators. If the generator's availability factor
Expand Down Expand Up @@ -1055,7 +1104,13 @@ def run_spatial_clustering(self):
if self.args["network_clustering"]["active"]:
self.network.generators.control = "PV"

elec_network, weight, n_clusters, busmap_foreign = preprocessing(self)
(
elec_network,
weight,
n_clusters,
busmap_foreign,
busmap_area,
) = preprocessing(self)

if self.args["network_clustering"]["method"] == "kmeans":
if self.args["network_clustering"]["k_elec_busmap"] == False:
Expand Down Expand Up @@ -1086,7 +1141,7 @@ def run_spatial_clustering(self):
medoid_idx = pd.Series(dtype=str)

self.clustering, busmap = postprocessing(
self, busmap, busmap_foreign, medoid_idx
self, busmap, busmap_foreign, medoid_idx, busmap_area
)
self.update_busmap(busmap)

Expand Down

0 comments on commit 6e2a0d5

Please sign in to comment.