add_electricity: Add heuristic for estimating renewable capacities from country totals
Split per-country capacity totals reported in entsoe SO&AF 2016 in proportion to yearly generation potential at each bus, i.e. p_nom_max * mean(p_max_pu)
This commit is contained in:
parent
b9f1f5a8b5
commit
5c3fcb642c
@ -36,6 +36,11 @@ electricity:
|
|||||||
battery: 6
|
battery: 6
|
||||||
H2: 168
|
H2: 168
|
||||||
|
|
||||||
|
# estimate_renewable_capacities_from_capacity_stats:
|
||||||
|
# # Wind is the Fueltype in ppm.data.Capacity_stats, onwind, offwind-{ac,dc} the carrier in PyPSA-Eur
|
||||||
|
# Wind: [onwind, offwind-ac, offwind-dc]
|
||||||
|
# Solar: [solar]
|
||||||
|
|
||||||
conventional_carriers: [] # nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass]
|
conventional_carriers: [] # nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass]
|
||||||
|
|
||||||
atlite:
|
atlite:
|
||||||
|
@ -18,6 +18,13 @@ from vresutils import transfer as vtransfer
|
|||||||
|
|
||||||
import pypsa
|
import pypsa
|
||||||
|
|
||||||
|
try:
|
||||||
|
import powerplantmatching as ppm
|
||||||
|
from build_powerplants import country_alpha_2
|
||||||
|
|
||||||
|
has_ppm = True
|
||||||
|
except ImportError:
|
||||||
|
has_ppm = False
|
||||||
|
|
||||||
def normed(s): return s/s.sum()
|
def normed(s): return s/s.sum()
|
||||||
|
|
||||||
@ -396,6 +403,29 @@ def attach_storage(n, costs):
|
|||||||
# marginal_cost=options['marginal_cost_storage'],
|
# marginal_cost=options['marginal_cost_storage'],
|
||||||
# p_nom_extendable=True)
|
# p_nom_extendable=True)
|
||||||
|
|
||||||
|
def estimate_renewable_capacities(n, tech_map=None):
|
||||||
|
if tech_map is None:
|
||||||
|
tech_map = snakemake.config['electricity'].get('estimate_renewable_capacities_from_capacity_stats', {})
|
||||||
|
|
||||||
|
if len(tech_map) == 0: return
|
||||||
|
|
||||||
|
assert has_ppm, "The estimation of renewable capacities needs the powerplantmatching package"
|
||||||
|
|
||||||
|
capacities = ppm.data.Capacity_stats()
|
||||||
|
capacities['alpha_2'] = capacities['Country'].map(country_alpha_2)
|
||||||
|
capacities = capacities.loc[capacities.Energy_Source_Level_2].set_index(['Fueltype', 'alpha_2']).sort_index()
|
||||||
|
|
||||||
|
countries = n.buses.country.unique()
|
||||||
|
|
||||||
|
for ppm_fueltype, techs in tech_map.items():
|
||||||
|
tech_capacities = capacities.loc[ppm_fueltype, 'Capacity'].reindex(countries, fill_value=0.)
|
||||||
|
tech_b = n.generators.carrier.isin(techs)
|
||||||
|
n.generators.loc[tech_b, 'p_nom'] = (
|
||||||
|
(n.generators_t.p_max_pu.mean().loc[tech_b] * n.generators.loc[tech_b, 'p_nom_max']) # maximal yearly generation
|
||||||
|
.groupby(n.generators.bus.map(n.buses.country)) # for each country
|
||||||
|
.transform(lambda s: normed(s) * tech_capacities.at[s.name])
|
||||||
|
.where(lambda s: s>0.1, 0.) # only capacities above 100kW
|
||||||
|
)
|
||||||
|
|
||||||
def add_co2limit(n, Nyears=1.):
|
def add_co2limit(n, Nyears=1.):
|
||||||
n.add("GlobalConstraint", "CO2Limit",
|
n.add("GlobalConstraint", "CO2Limit",
|
||||||
@ -418,11 +448,12 @@ if __name__ == "__main__":
|
|||||||
snakemake = MockSnakemake(output=['networks/elec.nc'])
|
snakemake = MockSnakemake(output=['networks/elec.nc'])
|
||||||
snakemake.input = snakemake.expand(
|
snakemake.input = snakemake.expand(
|
||||||
Dict(base_network='networks/base.nc',
|
Dict(base_network='networks/base.nc',
|
||||||
tech_costs='data/costs/costs.csv',
|
tech_costs='data/costs.csv',
|
||||||
regions="resources/regions_onshore.geojson",
|
regions="resources/regions_onshore.geojson",
|
||||||
powerplants="resources/powerplants.csv",
|
powerplants="resources/powerplants.csv",
|
||||||
hydro_capacities='data/hydro_capacities.csv',
|
hydro_capacities='data/bundle/hydro_capacities.csv',
|
||||||
opsd_load='data/time_series_60min_singleindex_filtered.csv',
|
opsd_load='data/bundle/time_series_60min_singleindex_filtered.csv',
|
||||||
|
nuts3_shapes='resources/nuts3_shapes.geojson',
|
||||||
**{'profile_' + t: "resources/profile_" + t + ".nc"
|
**{'profile_' + t: "resources/profile_" + t + ".nc"
|
||||||
for t in snakemake.config['renewable']})
|
for t in snakemake.config['renewable']})
|
||||||
)
|
)
|
||||||
@ -445,4 +476,6 @@ if __name__ == "__main__":
|
|||||||
attach_extendable_generators(n, costs, ppl)
|
attach_extendable_generators(n, costs, ppl)
|
||||||
attach_storage(n, costs)
|
attach_storage(n, costs)
|
||||||
|
|
||||||
|
estimate_renewable_capacities(n)
|
||||||
|
|
||||||
n.export_to_netcdf(snakemake.output[0])
|
n.export_to_netcdf(snakemake.output[0])
|
||||||
|
@ -18,50 +18,51 @@ def country_alpha_2(name):
|
|||||||
cntry = pyc.countries.get(official_name=name)
|
cntry = pyc.countries.get(official_name=name)
|
||||||
return cntry.alpha_2
|
return cntry.alpha_2
|
||||||
|
|
||||||
if 'snakemake' not in globals():
|
if __name__ == "__main__":
|
||||||
from vresutils.snakemake import MockSnakemake, Dict
|
if 'snakemake' not in globals():
|
||||||
|
from vresutils.snakemake import MockSnakemake, Dict
|
||||||
|
|
||||||
snakemake = MockSnakemake(
|
snakemake = MockSnakemake(
|
||||||
input=Dict(base_network='networks/base.nc'),
|
input=Dict(base_network='networks/base.nc'),
|
||||||
output=['resources/powerplants.csv']
|
output=['resources/powerplants.csv']
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.basicConfig(level=snakemake.config['logging_level'])
|
logging.basicConfig(level=snakemake.config['logging_level'])
|
||||||
|
|
||||||
n = pypsa.Network(snakemake.input.base_network)
|
n = pypsa.Network(snakemake.input.base_network)
|
||||||
|
|
||||||
ppl = (ppm.collection.matched_data()
|
ppl = (ppm.collection.matched_data()
|
||||||
[lambda df : ~df.Fueltype.isin(('Solar', 'Wind'))]
|
[lambda df : ~df.Fueltype.isin(('Solar', 'Wind'))]
|
||||||
.pipe(ppm.cleaning.clean_technology)
|
.pipe(ppm.cleaning.clean_technology)
|
||||||
.assign(Fueltype=lambda df: (
|
.assign(Fueltype=lambda df: (
|
||||||
df.Fueltype.where(df.Fueltype != 'Natural Gas',
|
df.Fueltype.where(df.Fueltype != 'Natural Gas',
|
||||||
df.Technology.replace('Steam Turbine', 'OCGT').fillna('OCGT'))))
|
df.Technology.replace('Steam Turbine', 'OCGT').fillna('OCGT'))))
|
||||||
.pipe(ppm.utils.fill_geoposition))
|
.pipe(ppm.utils.fill_geoposition))
|
||||||
|
|
||||||
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('CCGT'), 'Fueltype'] = 'CCGT'
|
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('CCGT'), 'Fueltype'] = 'CCGT'
|
||||||
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('Steam Turbine'), 'Fueltype'] = 'CCGT'
|
# ppl.loc[(ppl.Fueltype == 'Other') & ppl.Technology.str.contains('Steam Turbine'), 'Fueltype'] = 'CCGT'
|
||||||
|
|
||||||
ppl = ppl.loc[ppl.lon.notnull() & ppl.lat.notnull()]
|
ppl = ppl.loc[ppl.lon.notnull() & ppl.lat.notnull()]
|
||||||
|
|
||||||
ppl_country = ppl.Country.map(country_alpha_2)
|
ppl_country = ppl.Country.map(country_alpha_2)
|
||||||
countries = n.buses.country.unique()
|
countries = n.buses.country.unique()
|
||||||
cntries_without_ppl = []
|
cntries_without_ppl = []
|
||||||
|
|
||||||
for cntry in countries:
|
for cntry in countries:
|
||||||
substation_lv_i = n.buses.index[n.buses['substation_lv'] & (n.buses.country == cntry)]
|
substation_lv_i = n.buses.index[n.buses['substation_lv'] & (n.buses.country == cntry)]
|
||||||
ppl_b = ppl_country == cntry
|
ppl_b = ppl_country == cntry
|
||||||
if not ppl_b.any():
|
if not ppl_b.any():
|
||||||
cntries_without_ppl.append(cntry)
|
cntries_without_ppl.append(cntry)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
kdtree = KDTree(n.buses.loc[substation_lv_i, ['x','y']].values)
|
kdtree = KDTree(n.buses.loc[substation_lv_i, ['x','y']].values)
|
||||||
ppl.loc[ppl_b, 'bus'] = substation_lv_i[kdtree.query(ppl.loc[ppl_b, ['lon','lat']].values)[1]]
|
ppl.loc[ppl_b, 'bus'] = substation_lv_i[kdtree.query(ppl.loc[ppl_b, ['lon','lat']].values)[1]]
|
||||||
|
|
||||||
if cntries_without_ppl:
|
if cntries_without_ppl:
|
||||||
logging.warning("No powerplants known in: {}".format(", ".join(cntries_without_ppl)))
|
logging.warning("No powerplants known in: {}".format(", ".join(cntries_without_ppl)))
|
||||||
|
|
||||||
bus_null_b = ppl["bus"].isnull()
|
bus_null_b = ppl["bus"].isnull()
|
||||||
if bus_null_b.any():
|
if bus_null_b.any():
|
||||||
logging.warning("Couldn't find close bus for {} powerplants".format(bus_null_b.sum()))
|
logging.warning("Couldn't find close bus for {} powerplants".format(bus_null_b.sum()))
|
||||||
|
|
||||||
ppl.to_csv(snakemake.output[0])
|
ppl.to_csv(snakemake.output[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user