diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b3a4dfc..98c8e569 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: # Sort package imports alphabetically - repo: https://github.com/PyCQA/isort - rev: 5.11.4 + rev: 5.12.0 hooks: - id: isort args: ["--profile", "black", "--filter-files"] @@ -51,7 +51,7 @@ repos: # Formatting with "black" coding style - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.1.0 hooks: # Format Python files - id: black @@ -74,7 +74,7 @@ repos: # Format Snakemake rule / workflow files - repo: https://github.com/snakemake/snakefmt - rev: v0.8.0 + rev: v0.8.1 hooks: - id: snakefmt @@ -87,6 +87,6 @@ repos: # Check for FSFE REUSE compliance (licensing) - repo: https://github.com/fsfe/reuse-tool - rev: v1.1.0 + rev: v1.1.2 hooks: - id: reuse diff --git a/config.default.yaml b/config.default.yaml index 5f2e1c6c..b06c06b7 100755 --- a/config.default.yaml +++ b/config.default.yaml @@ -25,7 +25,7 @@ countries: ['AL', 'AT', 'BA', 'BE', 'BG', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'F snapshots: start: "2013-01-01" end: "2014-01-01" - closed: 'left' # end is not inclusive + inclusive: 'left' # include start, not end enable: prepare_links_p_nom: false diff --git a/config.tutorial.yaml b/config.tutorial.yaml index 4c093a3c..dc5347aa 100755 --- a/config.tutorial.yaml +++ b/config.tutorial.yaml @@ -24,7 +24,7 @@ countries: ['BE'] snapshots: start: "2013-03-01" end: "2013-04-01" - closed: 'left' # end is not inclusive + inclusive: 'left' # include start, not end enable: prepare_links_p_nom: false diff --git a/doc/configtables/snapshots.csv b/doc/configtables/snapshots.csv index 00297498..d60c78dc 100644 --- a/doc/configtables/snapshots.csv +++ b/doc/configtables/snapshots.csv @@ -1,4 +1,4 @@ ,Unit,Values,Description start,--,"str or datetime-like; e.g. YYYY-MM-DD","Left bound of date range" end,--,"str or datetime-like; e.g. YYYY-MM-DD","Right bound of date range" -closed,--,"One of {None, ‘left’, ‘right’}","Make the time interval closed to the ``left``, ``right``, or open on both sides ``None``." +inclusive,--,"One of {'neither', 'both', ‘left’, ‘right’}","Make the time interval closed to the ``left``, ``right``, or both sides ``both`` or neither side ``None``." diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 70927880..adcbfb58 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -10,12 +10,21 @@ Release Notes Upcoming Release ================ -* Carriers of generators can now be excluded from aggregation in clustering network and simplify network. - * Fix EQ constraint for the case no hydro inflow is available * Bugfix in the reserve constraint will increase demand related reserve requirements +**New Features** + +* Carriers of generators can now be excluded from aggregation in clustering network and simplify network. + +**Breaking Changes** + +* The config entry ``snapshots["closed"]`` was renamed to ``snapshots["inclusive"]`` to address the upstream deprecation with ``pandas=1.4``. + The previous setting ``None`` is no longer supported and replaced by ``both``, see the `pandas documentation `_. + Minimum ``pandas`` version now required is `>= 1.4`. + + PyPSA-Eur 0.6.1 (20th September 2022) ===================================== diff --git a/envs/environment.yaml b/envs/environment.yaml index 490268e8..4bdaf48c 100644 --- a/envs/environment.yaml +++ b/envs/environment.yaml @@ -24,15 +24,15 @@ dependencies: - yaml - pytables - lxml -- powerplantmatching>=0.5.5 +- powerplantmatching>=0.5.4 - numpy<1.24 -- pandas +- pandas>=1.4 - geopandas>=0.11.0 - xarray - netcdf4 - networkx - scipy -- shapely<2.0 +- shapely>=2.0 - progressbar2 - pyomo - matplotlib<3.6 diff --git a/scripts/add_electricity.py b/scripts/add_electricity.py index 85391a64..7407dafa 100755 --- a/scripts/add_electricity.py +++ b/scripts/add_electricity.py @@ -394,12 +394,10 @@ def attach_conventional_generators( ) for carrier in conventional_config: - # Generators with technology affected idx = n.generators.query("carrier == @carrier").index for attr in list(set(conventional_config[carrier]) & set(n.generators)): - values = conventional_config[carrier][attr] if f"conventional_{carrier}_{attr}" in conventional_inputs: @@ -498,7 +496,7 @@ def attach_hydro(n, costs, ppl, profile_hydro, hydro_capacities, carriers, **con e_target = hydro_stats["E_store[TWh]"].clip(lower=0.2) * 1e6 e_installed = hydro.eval("p_nom * max_hours").groupby(hydro.country).sum() e_missing = e_target - e_installed - missing_mh_i = hydro.query("max_hours == 0").index + missing_mh_i = hydro.query("max_hours.isnull()").index if hydro_max_hours == "energy_capacity_totals_by_country": # watch out some p_nom values like IE's are totally underrepresented @@ -511,6 +509,8 @@ def attach_hydro(n, costs, ppl, profile_hydro, hydro_capacities, carriers, **con hydro_stats["E_store[TWh]"] * 1e3 / hydro_stats["p_nom_discharge[GW]"] ) + max_hours_country.clip(0, inplace=True) + missing_countries = pd.Index(hydro["country"].unique()).difference( max_hours_country.dropna().index ) diff --git a/scripts/base_network.py b/scripts/base_network.py index f851a521..565d4907 100644 --- a/scripts/base_network.py +++ b/scripts/base_network.py @@ -694,7 +694,6 @@ def base_network( parameter_corrections, config, ): - buses = _load_buses_from_eg(eg_buses, europe_shape, config["electricity"]) links = _load_links_from_eg(buses, eg_links) diff --git a/scripts/build_load_data.py b/scripts/build_load_data.py index 780a651e..986892fc 100755 --- a/scripts/build_load_data.py +++ b/scripts/build_load_data.py @@ -268,7 +268,6 @@ def manual_adjustment(load, fn_load, powerstatistics): if __name__ == "__main__": - if "snakemake" not in globals(): from _helpers import mock_snakemake diff --git a/scripts/build_shapes.py b/scripts/build_shapes.py index ffe6380a..29fa6052 100644 --- a/scripts/build_shapes.py +++ b/scripts/build_shapes.py @@ -80,7 +80,6 @@ import pandas as pd import pycountry as pyc from _helpers import configure_logging from shapely.geometry import MultiPolygon, Polygon -from shapely.ops import unary_union logger = logging.getLogger(__name__) @@ -158,8 +157,7 @@ def country_cover(country_shapes, eez_shapes=None): shapes = country_shapes if eez_shapes is not None: shapes = pd.concat([shapes, eez_shapes]) - - europe_shape = unary_union(shapes) + europe_shape = shapes.unary_union if isinstance(europe_shape, MultiPolygon): europe_shape = max(europe_shape, key=attrgetter("area")) return Polygon(shell=europe_shape.exterior) diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index 80998b20..6a1d58ec 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -238,7 +238,6 @@ def distribute_clusters(n, n_clusters, focus_weights=None, solver_name="cbc"): ), f"Number of clusters must be {len(N)} <= n_clusters <= {N.sum()} for this selection of countries." if focus_weights is not None: - total_focus = sum(list(focus_weights.values())) assert ( @@ -396,7 +395,6 @@ def clustering_for_n_clusters( extended_link_costs=0, focus_weights=None, ): - bus_strategies, generator_strategies = get_aggregation_strategies( aggregation_strategies ) diff --git a/scripts/make_summary.py b/scripts/make_summary.py index 4c3c675a..815f7aec 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -164,7 +164,6 @@ def calculate_curtailment(n, label, curtailment): def calculate_energy(n, label, energy): for c in n.iterate_components(n.one_port_components | n.branch_components): - if c.name in {"Generator", "Load", "ShuntImpedance"}: c_energies = ( c.pnl.p.multiply(n.snapshot_weightings.generators, axis=0) @@ -238,7 +237,6 @@ def calculate_supply(n, label, supply): load_types = n.buses.carrier.unique() for i in load_types: - buses = n.buses.query("carrier == @i").index bus_map = pd.Series(False, index=n.buses.index) @@ -246,7 +244,6 @@ def calculate_supply(n, label, supply): bus_map.loc[buses] = True for c in n.iterate_components(n.one_port_components): - items = c.df.index[c.df.bus.map(bus_map)] if len(items) == 0 or c.pnl.p.empty: @@ -267,9 +264,7 @@ def calculate_supply(n, label, supply): supply.loc[idx[raw_index], label] = s.values for c in n.iterate_components(n.branch_components): - for end in ["0", "1"]: - items = c.df.index[c.df["bus" + end].map(bus_map)] if len(items) == 0 or c.pnl["p" + end].empty: @@ -298,7 +293,6 @@ def calculate_supply_energy(n, label, supply_energy): load_types = n.buses.carrier.unique() for i in load_types: - buses = n.buses.query("carrier == @i").index bus_map = pd.Series(False, index=n.buses.index) @@ -306,7 +300,6 @@ def calculate_supply_energy(n, label, supply_energy): bus_map.loc[buses] = True for c in n.iterate_components(n.one_port_components): - items = c.df.index[c.df.bus.map(bus_map)] if len(items) == 0 or c.pnl.p.empty: @@ -327,9 +320,7 @@ def calculate_supply_energy(n, label, supply_energy): supply_energy.loc[idx[raw_index], label] = s.values for c in n.iterate_components(n.branch_components): - for end in ["0", "1"]: - items = c.df.index[c.df["bus" + end].map(bus_map)] if len(items) == 0 or c.pnl["p" + end].empty: @@ -431,7 +422,6 @@ def calculate_weighted_prices(n, label, weighted_prices): } for carrier in link_loads: - if carrier == "electricity": suffix = "" elif carrier[:5] == "space": @@ -454,7 +444,6 @@ def calculate_weighted_prices(n, label, weighted_prices): load = n.loads_t.p_set[buses] for tech in link_loads[carrier]: - names = n.links.index[n.links.index.to_series().str[-len(tech) :] == tech] if names.empty: diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py index 7aa7a732..a4216450 100644 --- a/scripts/simplify_network.py +++ b/scripts/simplify_network.py @@ -324,7 +324,6 @@ def simplify_links(n, costs, config, output, aggregation_strategies=dict()): ) for lbl in labels.value_counts().loc[lambda s: s > 2].index: - for b, buses, links in split_links(labels.index[labels == lbl]): if len(buses) <= 2: continue diff --git a/test/config.test1.yaml b/test/config.test1.yaml index 7c9b0896..253446ef 100755 --- a/test/config.test1.yaml +++ b/test/config.test1.yaml @@ -22,7 +22,7 @@ countries: ['BE'] snapshots: start: "2013-03-01" end: "2013-03-08" - closed: 'left' # end is not inclusive + inclusive: 'left' # include start, not end enable: prepare_links_p_nom: false