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:
Jonas Hoersch 2019-02-05 23:00:35 +01:00
parent b9f1f5a8b5
commit 5c3fcb642c
3 changed files with 77 additions and 38 deletions

View File

@ -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:

View File

@ -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])

View File

@ -18,6 +18,7 @@ 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 __name__ == "__main__":
if 'snakemake' not in globals(): if 'snakemake' not in globals():
from vresutils.snakemake import MockSnakemake, Dict from vresutils.snakemake import MockSnakemake, Dict