diff --git a/scripts/build_powerplants.py b/scripts/build_powerplants.py index 764028d1..c1ee4127 100755 --- a/scripts/build_powerplants.py +++ b/scripts/build_powerplants.py @@ -79,6 +79,7 @@ import powerplantmatching as pm import pandas as pd import numpy as np +from powerplantmatching.export import map_country_bus from scipy.spatial import cKDTree as KDTree logger = logging.getLogger(__name__) @@ -87,13 +88,16 @@ logger = logging.getLogger(__name__) def add_custom_powerplants(ppl, custom_powerplants, custom_ppl_query=False): if not custom_ppl_query: return ppl - add_ppls = pd.read_csv(custom_powerplants, index_col=0, - dtype={'bus': 'str'}) + add_ppls = pd.read_csv(custom_powerplants, index_col=0, dtype={'bus': 'str'}) if isinstance(custom_ppl_query, str): add_ppls.query(custom_ppl_query, inplace=True) return pd.concat([ppl, add_ppls], sort=False, ignore_index=True, verify_integrity=True) +def replace_natural_gas_by_technology(df): + return df.Fueltype.where(df.Fueltype != 'Natural Gas', df.Technology) + + if __name__ == "__main__": if 'snakemake' not in globals(): from _helpers import mock_snakemake @@ -103,17 +107,22 @@ if __name__ == "__main__": n = pypsa.Network(snakemake.input.base_network) countries = n.buses.country.unique() + ppl = (pm.powerplants(from_url=True) - .powerplant.fill_missing_decommyears() + .powerplant.fill_missing_decommissioning_years() .powerplant.convert_country_to_alpha2() .query('Fueltype not in ["Solar", "Wind"] and Country in @countries') - .replace({'Technology': {'Steam Turbine': 'OCGT'}}) - .assign(Fueltype=lambda df: ( - df.Fueltype - .where(df.Fueltype != 'Natural Gas', - df.Technology.replace('Steam Turbine', - 'OCGT').fillna('OCGT'))))) + .replace({'Technology': {'Steam Turbine': 'OCGT', "Combustion Engine": "OCGT"}}) + .assign(Fueltype=replace_natural_gas_by_technology)) + # Correct bioenergy for countries where possible + opsd = pm.data.OPSD_VRE().powerplant.convert_country_to_alpha2() + opsd = opsd.query('Country in @countries and Fueltype == "Bioenergy"') + opsd['Name'] = "Biomass" + available_countries = opsd.Country.unique() + ppl = ppl.query('not (Country in @available_countries and Fueltype == "Bioenergy")') + ppl = pd.concat([ppl, opsd]) + ppl_query = snakemake.config['electricity']['powerplants_filter'] if isinstance(ppl_query, str): ppl.query(ppl_query, inplace=True) @@ -122,21 +131,21 @@ if __name__ == "__main__": custom_ppl_query = snakemake.config['electricity']['custom_powerplants'] ppl = add_custom_powerplants(ppl, snakemake.input.custom_powerplants, custom_ppl_query) - cntries_without_ppl = [c for c in countries if c not in ppl.Country.unique()] + countries_wo_ppl = [c for c in countries if c not in ppl.Country.unique()] + if countries_wo_ppl: + logging.warning(f"No powerplants known in: {', '.join(countries_wo_ppl)}") - for c in countries: - substation_i = n.buses.query('substation_lv and country == @c').index - kdtree = KDTree(n.buses.loc[substation_i, ['x','y']].values) - ppl_i = ppl.query('Country == @c').index - - tree_i = kdtree.query(ppl.loc[ppl_i, ['lon','lat']].values)[1] - ppl.loc[ppl_i, 'bus'] = substation_i.append(pd.Index([np.nan]))[tree_i] - - if cntries_without_ppl: - logging.warning(f"No powerplants known in: {', '.join(cntries_without_ppl)}") + substations = n.buses.query('substation_lv') + ppl = map_country_bus(ppl, substations) bus_null_b = ppl["bus"].isnull() if bus_null_b.any(): - logging.warning(f"Couldn't find close bus for {bus_null_b.sum()} powerplants") + logging.warning(f"Couldn't find close bus for {bus_null_b.sum()} powerplants. " + "Removing them from the powerplants list.") + ppl = ppl[~bus_null_b] - ppl.to_csv(snakemake.output[0]) + # TODO: This has to fixed in PPM, some powerplants are still duplicated + cumcount = ppl.groupby(['bus', 'Fueltype']).cumcount() + 1 + ppl.Name = ppl.Name.where(cumcount == 1, ppl.Name + " " + cumcount.astype(str)) + + ppl.reset_index(drop=True).to_csv(snakemake.output[0])