* Cluster first: build renewable profiles and add all assets after clustering * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * correction: pass landfall_lengths through functions * assign landfall_lenghts correctly * remove parameter add_land_use_constraint * fix network_dict * calculate distance to shoreline, remove underwater_fraction * adjust simplification parameter to exclude Crete from offshore wind connections * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * remove unused geth2015 hydro capacities * removing remaining traces of {simpl} wildcard * add release notes and update workflow graphics * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: lisazeyen <lisa.zeyen@web.de>
128 lines
3.9 KiB
Python
128 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
# SPDX-FileCopyrightText: : 2017-2024 The PyPSA-Eur Authors
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
"""
|
|
Builds the electricity demand for base regions based on population and GDP.
|
|
"""
|
|
|
|
import logging
|
|
from itertools import product
|
|
|
|
import geopandas as gpd
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pypsa
|
|
import scipy.sparse as sparse
|
|
import xarray as xr
|
|
from _helpers import configure_logging, set_scenario_config
|
|
from shapely.prepared import prep
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def normed(s: pd.Series) -> pd.Series:
|
|
return s / s.sum()
|
|
|
|
|
|
def shapes_to_shapes(orig: gpd.GeoSeries, dest: gpd.GeoSeries) -> sparse.lil_matrix:
|
|
"""
|
|
Adopted from vresutils.transfer.Shapes2Shapes()
|
|
"""
|
|
orig_prepped = list(map(prep, orig))
|
|
transfer = sparse.lil_matrix((len(dest), len(orig)), dtype=float)
|
|
|
|
for i, j in product(range(len(dest)), range(len(orig))):
|
|
if orig_prepped[j].intersects(dest.iloc[i]):
|
|
area = orig.iloc[j].intersection(dest.iloc[i]).area
|
|
transfer[i, j] = area / dest.iloc[i].area
|
|
|
|
return transfer
|
|
|
|
|
|
def upsample_load(
|
|
n: pypsa.Network,
|
|
regions_fn: str,
|
|
load_fn: str,
|
|
nuts3_fn: str,
|
|
gdp_pop_non_nuts3_fn: str,
|
|
distribution_key: dict[str, float],
|
|
) -> pd.DataFrame:
|
|
substation_lv_i = n.buses.index[n.buses["substation_lv"]]
|
|
gdf_regions = gpd.read_file(regions_fn).set_index("name").reindex(substation_lv_i)
|
|
load = pd.read_csv(load_fn, index_col=0, parse_dates=True)
|
|
|
|
nuts3 = gpd.read_file(nuts3_fn).set_index("index")
|
|
|
|
gdp_weight = distribution_key.get("gdp", 0.6)
|
|
pop_weight = distribution_key.get("pop", 0.4)
|
|
|
|
data_arrays = []
|
|
|
|
for cntry, group in gdf_regions.geometry.groupby(gdf_regions.country):
|
|
|
|
load_ct = load[cntry]
|
|
|
|
if cntry in ["UA", "MD"]:
|
|
# separate handling because nuts3 provides no data for UA+MD
|
|
gdp_pop_non_nuts3 = gpd.read_file(gdp_pop_non_nuts3_fn).set_index("Bus")
|
|
gdp_pop_non_nuts3 = gdp_pop_non_nuts3.loc[
|
|
(gdp_pop_non_nuts3.country == cntry)
|
|
& (gdp_pop_non_nuts3.index.isin(substation_lv_i))
|
|
]
|
|
factors = normed(
|
|
gdp_weight * normed(gdp_pop_non_nuts3["gdp"])
|
|
+ pop_weight * normed(gdp_pop_non_nuts3["pop"])
|
|
)
|
|
|
|
elif len(group) == 1:
|
|
factors = pd.Series(1.0, index=group.index)
|
|
|
|
else:
|
|
nuts3_cntry = nuts3.loc[nuts3.country == cntry]
|
|
transfer = shapes_to_shapes(group, nuts3_cntry.geometry).T.tocsr()
|
|
gdp_n = pd.Series(
|
|
transfer.dot(nuts3_cntry["gdp"].fillna(1.0).values), index=group.index
|
|
)
|
|
pop_n = pd.Series(
|
|
transfer.dot(nuts3_cntry["pop"].fillna(1.0).values), index=group.index
|
|
)
|
|
|
|
factors = normed(gdp_weight * normed(gdp_n) + pop_weight * normed(pop_n))
|
|
|
|
data_arrays.append(
|
|
xr.DataArray(
|
|
factors.values * load_ct.values[:, np.newaxis],
|
|
dims=["time", "bus"],
|
|
coords={"time": load_ct.index.values, "bus": factors.index.values},
|
|
)
|
|
)
|
|
|
|
return xr.concat(data_arrays, dim="bus")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if "snakemake" not in globals():
|
|
from _helpers import mock_snakemake
|
|
|
|
snakemake = mock_snakemake("build_electricity_demand_base")
|
|
configure_logging(snakemake)
|
|
set_scenario_config(snakemake)
|
|
|
|
params = snakemake.params
|
|
|
|
n = pypsa.Network(snakemake.input.base_network)
|
|
|
|
load = upsample_load(
|
|
n,
|
|
regions_fn=snakemake.input.regions,
|
|
load_fn=snakemake.input.load,
|
|
nuts3_fn=snakemake.input.nuts3,
|
|
gdp_pop_non_nuts3_fn=snakemake.input.get("gdp_pop_non_nuts3"),
|
|
distribution_key=params.distribution_key,
|
|
)
|
|
|
|
load.name = "electricity demand (MW)"
|
|
comp = dict(zlib=True, complevel=9, least_significant_digit=5)
|
|
load.to_netcdf(snakemake.output[0], encoding={load.name: comp})
|