Skip to content

Commit

Permalink
Merge pull request #1119 from danielelerede-oet/split_hydro_inflow
Browse files Browse the repository at this point in the history
Split inflow in ppl units + same hydro profile in alt. clustering
  • Loading branch information
davide-f authored Oct 29, 2024
2 parents b6499af + 8073162 commit 8d93ddb
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 49 deletions.
2 changes: 2 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ E.g. if a new rule becomes available describe how to use it `make test` and in o

* Drop duplicate entries in `AL_production.csv` data used in `build_industry_demand` rule `PR #1143 <https://github.com/pypsa-meets-earth/pypsa-earth/pull/1143>`_

* The computation of `hydro_profile.nc` in `build_renewable_profiles.py` is not differentiated whether alternative clustering is applied or not; the indexing of the different power plants in `add_electricity.py` is performed according to the bus either in case alternative clustering is applied or not and a `hydro_inflow_factor` is computed prior to the computation of `inflow_t` to split the inflow according to the capacity of each different unit of each power plant (if more units are present). `PR #1119 <https://github.com/pypsa-meets-earth/pypsa-earth/pull/1119>`_


PyPSA-Earth 0.4.1
=================
Expand Down
11 changes: 7 additions & 4 deletions scripts/add_electricity.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,7 @@ def attach_hydro(n, costs, ppl):
ror = ppl.query('technology == "Run-Of-River"')
phs = ppl.query('technology == "Pumped Storage"')
hydro = ppl.query('technology == "Reservoir"')
if snakemake.params.alternative_clustering:
bus_id = ppl["region_id"]
else:
bus_id = ppl["bus"]
bus_id = ppl["bus"]

inflow_idx = ror.index.union(hydro.index)
if not inflow_idx.empty:
Expand Down Expand Up @@ -530,12 +527,18 @@ def attach_hydro(n, costs, ppl):
network_buses_to_keep = plants_with_data.index
plants_to_keep = plants_with_data.to_numpy()

# hydro_inflow_factor is used to divide the inflow between the various units of each power plant
hydro_inflow_factor = hydro["p_nom"] / hydro.groupby("bus")[
"p_nom"
].transform("sum")

inflow_t = (
inflow.sel(plant=plants_to_keep)
.rename({"plant": "name"})
.assign_coords(name=network_buses_to_keep)
.transpose("time", "name")
.to_pandas()
* hydro_inflow_factor
)

if "ror" in carriers and not ror.empty:
Expand Down
53 changes: 8 additions & 45 deletions scripts/build_renewable_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,6 @@ def rescale_hydro(plants, runoff, normalize_using_yearly, normalization_year):
logger.info("No bus has installed hydro plants, ignoring normalization.")
return runoff

if snakemake.params.alternative_clustering:
plants = plants.set_index("shape_id")

years_statistics = normalize_using_yearly.index
if isinstance(years_statistics, pd.DatetimeIndex):
years_statistics = years_statistics.year
Expand Down Expand Up @@ -533,24 +530,6 @@ def create_scaling_factor(
# the region should be restricted for non-hydro technologies, as the hydro potential is calculated across hydrobasins which may span beyond the region of the country
cutout = filter_cutout_region(cutout, regions)

if snakemake.params.alternative_clustering:
regions = gpd.GeoDataFrame(
regions.reset_index()
.groupby("shape_id")
.agg(
{
"x": "mean",
"y": "mean",
"country": "first",
"geometry": "first",
"bus": "first",
}
)
.reset_index()
.set_index("bus"),
crs=regions.crs,
)

buses = regions.index

func = getattr(cutout, resource.pop("method"))
Expand All @@ -575,17 +554,10 @@ def create_scaling_factor(
# select busbar whose location (p) belongs to at least one hydrobasin geometry
# if extendable option is true, all buses are included
# otherwise only where hydro powerplants are available are considered
if snakemake.params.alternative_clustering:
filter_bus_to_consider = regions.index.map(
lambda bus_id: config.get("extendable", False)
| (bus_id in hydro_ppls.region_id.values)
)
### TODO: quickfix. above case and the below case should by unified
if snakemake.params.alternative_clustering == False:
filter_bus_to_consider = regions.index.map(
lambda bus_id: config.get("extendable", False)
| (bus_id in hydro_ppls.bus.values)
)
filter_bus_to_consider = regions.index.map(
lambda bus_id: config.get("extendable", False)
| (bus_id in hydro_ppls.bus.values)
)
bus_to_consider = regions.index[filter_bus_to_consider]

# identify subset of buses within the hydrobasins
Expand All @@ -603,17 +575,10 @@ def create_scaling_factor(
columns={"x": "lon", "y": "lat", "country": "countries"}
).loc[bus_in_hydrobasins, ["lon", "lat", "countries", "shape_id"]]

# TODO: these cases shall be fixed by restructuring the alternative clustering procedure
if snakemake.params.alternative_clustering == False:
resource["plants"]["installed_hydro"] = [
True if (bus_id in hydro_ppls.bus.values) else False
for bus_id in resource["plants"].index
]
else:
resource["plants"]["installed_hydro"] = [
True if (bus_id in hydro_ppls.region_id.values) else False
for bus_id in resource["plants"].shape_id.values
]
resource["plants"]["installed_hydro"] = [
True if (bus_id in hydro_ppls.bus.values) else False
for bus_id in resource["plants"].index
]

# get normalization before executing runoff
normalization = None
Expand All @@ -629,8 +594,6 @@ def create_scaling_factor(
else:
# otherwise perform the calculations
inflow = correction_factor * func(capacity_factor=True, **resource)
if snakemake.params.alternative_clustering:
inflow["plant"] = regions.shape_id.loc[inflow["plant"]].values

if "clip_min_inflow" in config:
inflow = inflow.where(inflow >= config["clip_min_inflow"], 0)
Expand Down

0 comments on commit 8d93ddb

Please sign in to comment.