diff --git a/config/config.default.yaml b/config/config.default.yaml index 15907133..359b08d2 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -796,6 +796,11 @@ plotting: solar: "#f9d002" solar PV: "#f9d002" solar thermal: '#ffbf2b' + residential rural solar thermal: '#f1c069' + services rural solar thermal: '#eabf61' + residential urban decentral solar thermal: '#e5bc5a' + services urban decentral solar thermal: '#dfb953' + urban central solar thermal: '#d7b24c' solar rooftop: '#ffea80' # gas OCGT: '#e0986c' @@ -804,9 +809,15 @@ plotting: gas boiler: '#db6a25' gas boilers: '#db6a25' gas boiler marginal: '#db6a25' + residential rural gas boiler: '#d4722e' + residential urban decentral gas boiler: '#cb7a36' + services rural gas boiler: '#c4813f' + services urban decentral gas boiler: '#ba8947' + urban central gas boiler: '#b0904f' gas: '#e05b09' fossil gas: '#e05b09' natural gas: '#e05b09' + biogas to gas: '#e36311' CCGT: '#a85522' CCGT marginal: '#a85522' allam: '#B98F76' @@ -819,6 +830,11 @@ plotting: # oil oil: '#c9c9c9' oil boiler: '#adadad' + residential rural oil boiler: '#a9a9a9' + services rural oil boiler: '#a5a5a5' + residential urban decentral oil boiler: '#a1a1a1' + urban central oil boiler: '#9d9d9d' + services urban decentral oil boiler: '#999999' agriculture machinery oil: '#949494' shipping oil: "#808080" land transport oil: '#afafaf' @@ -844,13 +860,20 @@ plotting: solid biomass for industry CC: '#47411c' solid biomass for industry co2 from atmosphere: '#736412' solid biomass for industry co2 to stored: '#47411c' + urban central solid biomass CHP: '#9d9042' + urban central solid biomass CHP CC: '#6c5d28' biomass boiler: '#8A9A5B' + residential rural biomass boiler: '#a1a066' + residential urban decentral biomass boiler: '#b0b87b' + services rural biomass boiler: '#c6cf98' + services urban decentral biomass boiler: '#dde5b5' biomass to liquid: '#32CD32' BioSNG: '#123456' # power transmission lines: '#6c9459' transmission lines: '#6c9459' electricity distribution grid: '#97ad8c' + low voltage: '#97ad8c' # electricity demand Electric load: '#110d63' electric demand: '#110d63' @@ -861,24 +884,48 @@ plotting: # battery + EVs battery: '#ace37f' battery storage: '#ace37f' + battery charger: '#88a75b' + battery discharger: '#5d4e29' home battery: '#80c944' home battery storage: '#80c944' + home battery charger: '#5e8032' + home battery discharger: '#3c5221' BEV charger: '#baf238' V2G: '#e5ffa8' land transport EV: '#baf238' Li ion: '#baf238' # hot water storage water tanks: '#e69487' + residential rural water tanks: '#f7b7a3' + services rural water tanks: '#f3afa3' + residential urban decentral water tanks: '#f2b2a3' + services urban decentral water tanks: '#f1b4a4' + urban central water tanks: '#e9977d' hot water storage: '#e69487' - hot water charging: '#e69487' - hot water discharging: '#e69487' + hot water charging: '#e8998b' + urban central water tanks charger: '#b57a67' + residential rural water tanks charger: '#b4887c' + residential urban decentral water tanks charger: '#b39995' + services rural water tanks charger: '#b3abb0' + services urban decentral water tanks charger: '#b3becc' + hot water discharging: '#e99c8e' + urban central water tanks discharger: '#b9816e' + residential rural water tanks discharger: '#ba9685' + residential urban decentral water tanks discharger: '#baac9e' + services rural water tanks discharger: '#bbc2b8' + services urban decentral water tanks discharger: '#bdd8d3' # heat demand Heat load: '#cc1f1f' heat: '#cc1f1f' heat demand: '#cc1f1f' rural heat: '#ff5c5c' + residential rural heat: '#ff7c7c' + services rural heat: '#ff9c9c' central heat: '#cc1f1f' + urban central heat: '#d15959' decentral heat: '#750606' + residential urban decentral heat: '#a33c3c' + services urban decentral heat: '#cc1f1f' low-temperature heat for industry: '#8f2727' process heat: '#ff0000' agriculture heat: '#d9a5a5' @@ -886,14 +933,26 @@ plotting: heat pumps: '#2fb537' heat pump: '#2fb537' air heat pump: '#36eb41' + residential urban decentral air heat pump: '#48f74f' + services urban decentral air heat pump: '#5af95d' + urban central air heat pump: '#6cfb6b' ground heat pump: '#2fb537' + residential rural ground heat pump: '#48f74f' + services rural ground heat pump: '#5af95d' Ambient: '#98eb9d' CHP: '#8a5751' + urban central gas CHP: '#8d5e56' CHP CC: '#634643' + urban central gas CHP CC: '#6e4e4c' CHP heat: '#8a5751' CHP electric: '#8a5751' district heating: '#e8beac' resistive heater: '#d8f9b8' + residential rural resistive heater: '#bef5b5' + residential urban decentral resistive heater: '#b2f1a9' + services rural resistive heater: '#a5ed9d' + services urban decentral resistive heater: '#98e991' + urban central resistive heater: '#8cdf85' retrofitting: '#8487e8' building retrofitting: '#8487e8' # hydrogen @@ -905,13 +964,16 @@ plotting: SMR CC: '#4f1745' H2 liquefaction: '#d647bd' hydrogen storage: '#bf13a0' + H2 Store: '#bf13a0' H2 storage: '#bf13a0' land transport fuel cell: '#6b3161' H2 pipeline: '#f081dc' H2 pipeline retrofitted: '#ba99b5' H2 Fuel Cell: '#c251ae' + H2 fuel cell: '#c251ae' H2 turbine: '#991f83' H2 Electrolysis: '#ff29d9' + H2 electrolysis: '#ff29d9' # ammonia NH3: '#46caf0' ammonia: '#46caf0' @@ -960,9 +1022,11 @@ plotting: waste: '#e3d37d' other: '#000000' geothermal: '#ba91b1' + AC: "#70af1d" AC-AC: "#70af1d" AC line: "#70af1d" links: "#8a1caf" HVDC links: "#8a1caf" + DC: "#8a1caf" DC-DC: "#8a1caf" DC link: "#8a1caf" diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 8f26ac02..727675c2 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -16,6 +16,8 @@ Upcoming Release * Bugfix: Correct typo in the CPLEX solver configuration in ``config.default.yaml``. +* Bugfix: Error in ``add_electricity`` where carriers were added multiple times to the network, resulting in a non-unique carriers error. + * Renamed script file from PyPSA-EUR ``build_load_data`` to ``build_electricity_demand`` and ``retrieve_load_data`` to ``retrieve_electricity_demand``. * Fix docs readthedocs built @@ -24,12 +26,17 @@ Upcoming Release hydrogen fuel cell. Add switches for both re-electrification options under ``sector: hydrogen_turbine:`` and ``sector: hydrogen_fuel_cell:``. +* A new function named ``sanitize_carrier`` ensures that all unique carrier names are present in the network's carriers attribute, and adds nice names and colors for each carrier according to the provided configuration dictionary. + +* Additional tech_color are added to include previously unlisted carriers. + * Remove ``vresutils`` dependency. * Add option to include a piecewise linear approximation of transmission losses, e.g. by setting ``solving: options: transmission_losses: 2`` for an approximation with two tangents. + PyPSA-Eur 0.8.0 (18th March 2023) ================================= diff --git a/rules/build_electricity.smk b/rules/build_electricity.smk index b06d8ef7..70e01793 100644 --- a/rules/build_electricity.smk +++ b/rules/build_electricity.smk @@ -59,6 +59,9 @@ rule build_powerplants: rule base_network: + params: + countries=config["countries"], + snapshots=config["snapshots"], input: eg_buses="data/entsoegridkit/buses.csv", eg_lines="data/entsoegridkit/lines.csv", diff --git a/rules/retrieve.smk b/rules/retrieve.smk index 4bfbd6c6..0a96406a 100644 --- a/rules/retrieve.smk +++ b/rules/retrieve.smk @@ -19,8 +19,6 @@ if config["enable"].get("retrieve_databundle", True): datafiles.extend(["natura/Natura2000_end2015.shp", "GEBCO_2014_2D.nc"]) rule retrieve_databundle: - params: - tutorial=config["tutorial"], output: expand("data/bundle/{file}", file=datafiles), log: diff --git a/scripts/_helpers.py b/scripts/_helpers.py index 512cb87a..0e1d2327 100644 --- a/scripts/_helpers.py +++ b/scripts/_helpers.py @@ -283,7 +283,7 @@ def get_aggregation_strategies(aggregation_strategies): # when custom values are specified in the config. import numpy as np - from pypsa.networkclustering import _make_consense + from pypsa.clustering.spatial import _make_consense bus_strategies = dict(country=_make_consense("Bus", "country")) bus_strategies.update(aggregation_strategies.get("buses", {})) diff --git a/scripts/add_electricity.py b/scripts/add_electricity.py index b6852bf4..7221021d 100755 --- a/scripts/add_electricity.py +++ b/scripts/add_electricity.py @@ -121,18 +121,68 @@ def calculate_annuity(n, r): return 1 / n -def _add_missing_carriers_from_costs(n, costs, carriers): - missing_carriers = pd.Index(carriers).difference(n.carriers.index) - if missing_carriers.empty: - return +def add_missing_carriers(n, carriers): + """ + Function to add missing carriers to the network without raising errors. + """ + missing_carriers = set(carriers) - set(n.carriers.index) + if len(missing_carriers) > 0: + n.madd("Carrier", missing_carriers) - emissions_cols = ( - costs.columns.to_series().loc[lambda s: s.str.endswith("_emissions")].values + +def sanitize_carriers(n, config): + """ + Sanitize the carrier information in a PyPSA Network object. + + The function ensures that all unique carrier names are present in the network's + carriers attribute, and adds nice names and colors for each carrier according + to the provided configuration dictionary. + + Parameters + ---------- + n : pypsa.Network + A PyPSA Network object that represents an electrical power system. + config : dict + A dictionary containing configuration information, specifically the + "plotting" key with "nice_names" and "tech_colors" keys for carriers. + + Returns + ------- + None + The function modifies the 'n' PyPSA Network object in-place, updating the + carriers attribute with nice names and colors. + + Warnings + -------- + Raises a warning if any carrier's "tech_colors" are not defined in the config dictionary. + """ + + for c in n.iterate_components(): + if "carrier" in c.df: + add_missing_carriers(n, c.df) + + carrier_i = n.carriers.index + nice_names = ( + pd.Series(config["plotting"]["nice_names"]) + .reindex(carrier_i) + .fillna(carrier_i.to_series().str.title()) ) - suptechs = missing_carriers.str.split("-").str[0] - emissions = costs.loc[suptechs, emissions_cols].fillna(0.0) - emissions.index = missing_carriers - n.import_components_from_dataframe(emissions, "Carrier") + n.carriers["nice_name"] = n.carriers.nice_name.where( + n.carriers.nice_name != "", nice_names + ) + colors = pd.Series(config["plotting"]["tech_colors"]).reindex(carrier_i) + if colors.isna().any(): + missing_i = list(colors.index[colors.isna()]) + logger.warning(f"tech_colors for carriers {missing_i} not defined in config.") + n.carriers["color"] = n.carriers.color.where(n.carriers.color != "", colors) + + +def add_co2_emissions(n, costs, carriers): + """ + Add CO2 emissions to the network's carriers attribute. + """ + suptechs = n.carriers.loc[carriers].index.str.split("-").str[0] + n.carriers.loc[carriers, "co2_emissions"] = costs.co2_emissions[suptechs].values def load_costs(tech_costs, config, max_hours, Nyears=1.0): @@ -307,57 +357,56 @@ def update_transmission_costs(n, costs, length_factor=1.0): def attach_wind_and_solar( - n, costs, input_profiles, technologies, extendable_carriers, line_length_factor=1 + n, costs, input_profiles, carriers, extendable_carriers, line_length_factor=1 ): - # TODO: rename tech -> carrier, technologies -> carriers - _add_missing_carriers_from_costs(n, costs, technologies) + add_missing_carriers(n, carriers) - for tech in technologies: - if tech == "hydro": + for car in carriers: + if car == "hydro": continue - with xr.open_dataset(getattr(input_profiles, "profile_" + tech)) as ds: + with xr.open_dataset(getattr(input_profiles, "profile_" + car)) as ds: if ds.indexes["bus"].empty: continue - suptech = tech.split("-", 2)[0] - if suptech == "offwind": + supcar = car.split("-", 2)[0] + if supcar == "offwind": underwater_fraction = ds["underwater_fraction"].to_pandas() connection_cost = ( line_length_factor * ds["average_distance"].to_pandas() * ( underwater_fraction - * costs.at[tech + "-connection-submarine", "capital_cost"] + * costs.at[car + "-connection-submarine", "capital_cost"] + (1.0 - underwater_fraction) - * costs.at[tech + "-connection-underground", "capital_cost"] + * costs.at[car + "-connection-underground", "capital_cost"] ) ) capital_cost = ( costs.at["offwind", "capital_cost"] - + costs.at[tech + "-station", "capital_cost"] + + costs.at[car + "-station", "capital_cost"] + connection_cost ) logger.info( "Added connection cost of {:0.0f}-{:0.0f} Eur/MW/a to {}".format( - connection_cost.min(), connection_cost.max(), tech + connection_cost.min(), connection_cost.max(), car ) ) else: - capital_cost = costs.at[tech, "capital_cost"] + capital_cost = costs.at[car, "capital_cost"] n.madd( "Generator", ds.indexes["bus"], - " " + tech, + " " + car, bus=ds.indexes["bus"], - carrier=tech, - p_nom_extendable=tech in extendable_carriers["Generator"], + carrier=car, + p_nom_extendable=car in extendable_carriers["Generator"], p_nom_max=ds["p_nom_max"].to_pandas(), weight=ds["weight"].to_pandas(), - marginal_cost=costs.at[suptech, "marginal_cost"], + marginal_cost=costs.at[supcar, "marginal_cost"], capital_cost=capital_cost, - efficiency=costs.at[suptech, "efficiency"], + efficiency=costs.at[supcar, "efficiency"], p_max_pu=ds["profile"].transpose("time", "bus").to_pandas(), ) @@ -371,8 +420,9 @@ def attach_conventional_generators( conventional_params, conventional_inputs, ): - carriers = set(conventional_carriers) | set(extendable_carriers["Generator"]) - _add_missing_carriers_from_costs(n, costs, carriers) + carriers = list(set(conventional_carriers) | set(extendable_carriers["Generator"])) + add_missing_carriers(n, carriers) + add_co2_emissions(n, costs, carriers) ppl = ( ppl.query("carrier in @carriers") @@ -428,7 +478,8 @@ def attach_conventional_generators( def attach_hydro(n, costs, ppl, profile_hydro, hydro_capacities, carriers, **params): - _add_missing_carriers_from_costs(n, costs, carriers) + add_missing_carriers(n, carriers) + add_co2_emissions(n, costs, carriers) ppl = ( ppl.query('carrier == "hydro"') @@ -560,7 +611,8 @@ def attach_extendable_generators(n, costs, ppl, carriers): logger.warning( "The function `attach_extendable_generators` is deprecated in v0.5.0." ) - _add_missing_carriers_from_costs(n, costs, carriers) + add_missing_carriers(n, carriers) + add_co2_emissions(n, costs, carriers) for tech in carriers: if tech.startswith("OCGT"): @@ -642,7 +694,7 @@ def attach_OPSD_renewables(n, tech_map): buses = n.buses.loc[gens.bus.unique()] gens_per_bus = gens.groupby("bus").p_nom.count() - caps = map_country_bus(df.query("Fueltype == @fueltype"), buses) + caps = map_country_bus(df.query("Fueltype == @fueltype and lat == lat"), buses) caps = caps.groupby(["bus"]).Capacity.sum() caps = caps / gens_per_bus.reindex(caps.index, fill_value=1) @@ -715,21 +767,6 @@ def attach_line_rating( n.lines_t.s_max_pu *= s_max_pu -def add_nice_carrier_names(n, config): - carrier_i = n.carriers.index - nice_names = ( - pd.Series(config["plotting"]["nice_names"]) - .reindex(carrier_i) - .fillna(carrier_i.to_series().str.title()) - ) - n.carriers["nice_name"] = nice_names - colors = pd.Series(config["plotting"]["tech_colors"]).reindex(carrier_i) - if colors.isna().any(): - missing_i = list(colors.index[colors.isna()]) - logger.warning(f"tech_colors for carriers {missing_i} not defined in config.") - n.carriers["color"] = colors - - if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -829,7 +866,8 @@ if __name__ == "__main__": max_line_rating, ) - add_nice_carrier_names(n, snakemake.config) + sanitize_carriers(n, snakemake.config) + n.meta = snakemake.config n.export_to_netcdf(snakemake.output[0]) diff --git a/scripts/add_existing_baseyear.py b/scripts/add_existing_baseyear.py index 52cb585e..f80bffb8 100644 --- a/scripts/add_existing_baseyear.py +++ b/scripts/add_existing_baseyear.py @@ -22,6 +22,7 @@ import numpy as np import pypsa import xarray as xr from _helpers import override_component_attrs, update_config_with_sector_opts +from add_electricity import sanitize_carriers from prepare_sector_network import cluster_heat_buses, define_spatial, prepare_costs cc = coco.CountryConverter() @@ -665,4 +666,6 @@ if __name__ == "__main__": n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards))) + sanitize_carriers(n, snakemake.config) + n.export_to_netcdf(snakemake.output[0]) diff --git a/scripts/add_extra_components.py b/scripts/add_extra_components.py index f034a7f2..e00e1e5f 100644 --- a/scripts/add_extra_components.py +++ b/scripts/add_extra_components.py @@ -56,11 +56,7 @@ import numpy as np import pandas as pd import pypsa from _helpers import configure_logging -from add_electricity import ( - _add_missing_carriers_from_costs, - add_nice_carrier_names, - load_costs, -) +from add_electricity import load_costs, sanitize_carriers idx = pd.IndexSlice @@ -70,7 +66,7 @@ logger = logging.getLogger(__name__) def attach_storageunits(n, costs, extendable_carriers, max_hours): carriers = extendable_carriers["StorageUnit"] - _add_missing_carriers_from_costs(n, costs, carriers) + n.madd("Carrier", carriers) buses_i = n.buses.index @@ -101,7 +97,7 @@ def attach_storageunits(n, costs, extendable_carriers, max_hours): def attach_stores(n, costs, extendable_carriers): carriers = extendable_carriers["Store"] - _add_missing_carriers_from_costs(n, costs, carriers) + n.madd("Carrier", carriers) buses_i = n.buses.index bus_sub_dict = {k: n.buses[k].values for k in ["x", "y", "country"]} @@ -161,6 +157,8 @@ def attach_stores(n, costs, extendable_carriers): marginal_cost=costs.at["battery", "marginal_cost"], ) + n.madd("Carrier", ["battery charger", "battery discharger"]) + n.madd( "Link", b_buses_i + " charger", @@ -211,6 +209,8 @@ def attach_hydrogen_pipelines(n, costs, extendable_carriers): h2_links.index = h2_links.apply(lambda c: f"H2 pipeline {c.bus0}-{c.bus1}", axis=1) # add pipelines + n.add("Carrier", "H2 pipeline") + n.madd( "Link", h2_links.index, @@ -245,7 +245,7 @@ if __name__ == "__main__": attach_stores(n, costs, extendable_carriers) attach_hydrogen_pipelines(n, costs, extendable_carriers) - add_nice_carrier_names(n, snakemake.config) + sanitize_carriers(n, snakemake.config) n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards))) n.export_to_netcdf(snakemake.output[0]) diff --git a/scripts/base_network.py b/scripts/base_network.py index 53b4dca3..87504ce7 100644 --- a/scripts/base_network.py +++ b/scripts/base_network.py @@ -714,6 +714,7 @@ def base_network( n.name = "PyPSA-Eur" n.set_snapshots(pd.date_range(freq="h", **config["snapshots"])) + n.madd("Carrier", ["AC", "DC"]) n.import_components_from_dataframe(buses, "Bus") n.import_components_from_dataframe(lines, "Line") diff --git a/scripts/build_powerplants.py b/scripts/build_powerplants.py index 7f396e1e..f25f111b 100755 --- a/scripts/build_powerplants.py +++ b/scripts/build_powerplants.py @@ -149,6 +149,7 @@ if __name__ == "__main__": logging.warning(f"No powerplants known in: {', '.join(countries_wo_ppl)}") substations = n.buses.query("substation_lv") + ppl = ppl.dropna(subset=["lat", "lon"]) ppl = map_country_bus(ppl, substations) bus_null_b = ppl["bus"].isnull() diff --git a/scripts/build_renewable_profiles.py b/scripts/build_renewable_profiles.py index 9f1f1a51..88a43f53 100644 --- a/scripts/build_renewable_profiles.py +++ b/scripts/build_renewable_profiles.py @@ -188,7 +188,7 @@ import geopandas as gpd import numpy as np import xarray as xr from _helpers import configure_logging -from dask.distributed import Client, LocalCluster +from dask.distributed import Client from pypsa.geo import haversine from shapely.geometry import LineString @@ -204,6 +204,7 @@ if __name__ == "__main__": nprocesses = int(snakemake.threads) noprogress = snakemake.config["run"].get("disable_progressbar", True) + noprogress = noprogress or not snakemake.config["atlite"]["show_progress"] params = snakemake.params.renewable[snakemake.wildcards.technology] resource = params["resource"] # pv panel params / wind turbine params correction_factor = params.get("correction_factor", 1.0) @@ -216,8 +217,10 @@ if __name__ == "__main__": if correction_factor != 1.0: logger.info(f"correction_factor is set as {correction_factor}") - cluster = LocalCluster(n_workers=nprocesses, threads_per_worker=1) - client = Client(cluster, asynchronous=True) + if nprocesses > 1: + client = Client(n_workers=nprocesses, threads_per_worker=1) + else: + client = None cutout = atlite.Cutout(snakemake.input.cutout) regions = gpd.read_file(snakemake.input.regions) @@ -289,7 +292,8 @@ if __name__ == "__main__": potential = capacity_per_sqkm * availability.sum("bus") * area func = getattr(cutout, resource.pop("method")) - resource["dask_kwargs"] = {"scheduler": client} + if client is not None: + resource["dask_kwargs"] = {"scheduler": client} capacity_factor = correction_factor * func(capacity_factor=True, **resource) layout = capacity_factor * area * capacity_per_sqkm profile, capacities = func( diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index 52685af2..14741f9e 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -89,7 +89,7 @@ Description **Is it possible to run the model without the** ``simplify_network`` **rule?** No, the network clustering methods in the PyPSA module - `pypsa.networkclustering `_ + `pypsa.clustering.spatial `_ do not work reliably with multiple voltage levels and transformers. .. tip:: @@ -134,7 +134,7 @@ import pyomo.environ as po import pypsa import seaborn as sns from _helpers import configure_logging, get_aggregation_strategies, update_p_nom_max -from pypsa.networkclustering import ( +from pypsa.clustering.spatial import ( busmap_by_greedy_modularity, busmap_by_hac, busmap_by_kmeans, @@ -484,7 +484,7 @@ if __name__ == "__main__": # Fast-path if no clustering is necessary busmap = n.buses.index.to_series() linemap = n.lines.index.to_series() - clustering = pypsa.networkclustering.Clustering( + clustering = pypsa.clustering.spatial.Clustering( n, busmap, linemap, linemap, pd.Series(dtype="O") ) else: diff --git a/scripts/prepare_network.py b/scripts/prepare_network.py index adbfa36c..f45e45ed 100755 --- a/scripts/prepare_network.py +++ b/scripts/prepare_network.py @@ -298,6 +298,8 @@ if __name__ == "__main__": break for o in opts: + if "+" not in o: + continue oo = o.split("+") suptechs = map(lambda c: c.split("-", 2)[0], n.carriers.index) if oo[0].startswith(tuple(suptechs)): diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 73adf522..551ea44e 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -22,7 +22,7 @@ from _helpers import ( override_component_attrs, update_config_with_sector_opts, ) -from add_electricity import calculate_annuity +from add_electricity import calculate_annuity, sanitize_carriers from build_energy_totals import build_co2_totals, build_eea_co2, build_eurostat_co2 from networkx.algorithms import complement from networkx.algorithms.connectivity.edge_augmentation import k_edge_augmentation @@ -3425,4 +3425,6 @@ if __name__ == "__main__": n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards))) + sanitize_carriers(n, snakemake.config) + n.export_to_netcdf(snakemake.output[0]) diff --git a/scripts/retrieve_databundle.py b/scripts/retrieve_databundle.py index c7053bed..75d8519e 100644 --- a/scripts/retrieve_databundle.py +++ b/scripts/retrieve_databundle.py @@ -53,7 +53,7 @@ if __name__ == "__main__": snakemake ) # TODO Make logging compatible with progressbar (see PR #102) - if snakemake.params.tutorial: + if snakemake.config["tutorial"]: url = "https://zenodo.org/record/3517921/files/pypsa-eur-tutorial-data-bundle.tar.xz" else: url = "https://zenodo.org/record/3517935/files/pypsa-eur-data-bundle.tar.xz" diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py index 79161760..b4c0829b 100644 --- a/scripts/simplify_network.py +++ b/scripts/simplify_network.py @@ -95,13 +95,13 @@ import scipy as sp from _helpers import configure_logging, get_aggregation_strategies, update_p_nom_max from add_electricity import load_costs from cluster_network import cluster_regions, clustering_for_n_clusters -from pypsa.io import import_components_from_dataframe, import_series_from_dataframe -from pypsa.networkclustering import ( +from pypsa.clustering.spatial import ( aggregategenerators, aggregateoneport, busmap_by_stubs, get_clustering_from_busmap, ) +from pypsa.io import import_components_from_dataframe, import_series_from_dataframe from scipy.sparse.csgraph import connected_components, dijkstra logger = logging.getLogger(__name__) diff --git a/scripts/solve_network.py b/scripts/solve_network.py index d80e38a0..58f4db72 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -235,8 +235,7 @@ def add_CCL_constraints(n, config): p_nom = n.model["Generator-p_nom"] gens = n.generators.query("p_nom_extendable").rename_axis(index="Generator-ext") - grouper = [gens.bus.map(n.buses.country), gens.carrier] - grouper = xr.DataArray(pd.MultiIndex.from_arrays(grouper), dims=["Generator-ext"]) + grouper = pd.concat([gens.bus.map(n.buses.country), gens.carrier]) lhs = p_nom.groupby(grouper).sum().rename(bus="country") minimum = xr.DataArray(agg_p_nom_minmax["min"].dropna()).rename(dim_0="group")