Merge pull request #90 from martavp/alter-cost-potential

Add a factor to alter cost or capacity potential via the config file
This commit is contained in:
Tom Brown 2021-01-18 18:19:24 +01:00 committed by GitHub
commit 0dc9196b76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 19 deletions

View File

@ -8,7 +8,7 @@ wildcard_constraints:
clusters="[0-9]+m?", clusters="[0-9]+m?",
sectors="[+a-zA-Z0-9]+", sectors="[+a-zA-Z0-9]+",
opts="[-+a-zA-Z0-9]*", opts="[-+a-zA-Z0-9]*",
sector_opts="[-+a-zA-Z0-9\.]*" sector_opts="[-+a-zA-Z0-9\.\s]*"

View File

@ -15,14 +15,15 @@ scenario:
lv: [1.0,1.5] # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt" lv: [1.0,1.5] # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt"
clusters: [45,50] # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred clusters: [45,50] # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred
opts: [''] # only relevant for PyPSA-Eur opts: [''] # only relevant for PyPSA-Eur
sector_opts: [Co2L0-3H-T-H-B-I-solar3-dist1] # this is where the main scenario settings are sector_opts: [Co2L0-3H-T-H-B-I-solar+p3-dist1] # this is where the main scenario settings are
# to really understand the options here, look in scripts/prepare_sector_network.py # to really understand the options here, look in scripts/prepare_sector_network.py
# Co2Lx specifies the CO2 target in x% of the 1990 values; default will give default (5%); # Co2Lx specifies the CO2 target in x% of the 1990 values; default will give default (5%);
# Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions # Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions
# xH is the temporal resolution; 3H is 3-hourly, i.e. one snapshot every 3 hours # xH is the temporal resolution; 3H is 3-hourly, i.e. one snapshot every 3 hours
# single letters are sectors: T for land transport, H for building heating, # single letters are sectors: T for land transport, H for building heating,
# B for biomass supply, I for industry, shipping and aviation # B for biomass supply, I for industry, shipping and aviation
# solarx or onwindx changes the available installable potential by factor x # solar+c0.5 reduces the capital cost of solar to 50\% of reference value
# solar+p3 multiplies the available installable potential by factor 3
# dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv
# for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative # for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative
# emissions throughout the transition path in the timeframe determined by the # emissions throughout the transition path in the timeframe determined by the

View File

@ -5,6 +5,7 @@ Release Notes
Future release Future release
=================== ===================
*For the myopic option, a carbon budget and a type of decay (exponential or beta) can be selected in the config file to distribute the budget across the planning_horizons. *For the myopic option, a carbon budget and a type of decay (exponential or beta) can be selected in the config file to distribute the budget across the planning_horizons.
*Added an option to alter the capital cost or maximum capacity of carriers by a factor via ``carrier+factor`` in the ``{opts}`` wildcard. This can be useful for exploring uncertain cost parameters. Example: ``solar+c0.5`` reduces the capital cost of solar to 50\% of original values. Similarly ``solar+p3`` multiplies the p_nom_max by 3.
PyPSA-Eur-Sec 0.4.0 (11th December 2020) PyPSA-Eur-Sec 0.4.0 (11th December 2020)
========================================= =========================================

View File

@ -1812,13 +1812,6 @@ def add_waste_heat(network):
network.links.loc[urban_central + " H2 Fuel Cell","bus2"] = urban_central + " urban central heat" network.links.loc[urban_central + " H2 Fuel Cell","bus2"] = urban_central + " urban central heat"
network.links.loc[urban_central + " H2 Fuel Cell","efficiency2"] = 0.95 - network.links.loc[urban_central + " H2 Fuel Cell","efficiency"] network.links.loc[urban_central + " H2 Fuel Cell","efficiency2"] = 0.95 - network.links.loc[urban_central + " H2 Fuel Cell","efficiency"]
def restrict_technology_potential(n,tech,limit):
print("restricting potentials (p_nom_max) for {} to {} of technical potential".format(tech,limit))
gens = n.generators.index[n.generators.carrier.str.contains(tech)]
#beware if limit is 0 and p_nom_max is np.inf, 0*np.inf is nan
n.generators.loc[gens,"p_nom_max"] *=limit
def decentral(n): def decentral(n):
n.lines.drop(n.lines.index,inplace=True) n.lines.drop(n.lines.index,inplace=True)
n.links.drop(n.links.index[n.links.carrier.isin(["DC","B2B"])],inplace=True) n.links.drop(n.links.index[n.links.carrier.isin(["DC","B2B"])],inplace=True)
@ -1862,7 +1855,7 @@ if __name__ == "__main__":
snakemake = MockSnakemake( snakemake = MockSnakemake(
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0', wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
opts='', planning_horizons='2020', opts='', planning_horizons='2020',
sector_opts='120H-T-H-B-I-solar3-dist1-cb48be3'), sector_opts='120H-T-H-B-I-onwind+p3-dist1-cb48be3'),
input=dict( network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc', input=dict( network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc',
energy_totals_name='resources/energy_totals.csv', energy_totals_name='resources/energy_totals.csv',
co2_totals_name='resources/co2_totals.csv', co2_totals_name='resources/co2_totals.csv',
@ -2028,15 +2021,7 @@ if __name__ == "__main__":
print("adding CO2 budget limit as per unit of 1990 levels of",limit) print("adding CO2 budget limit as per unit of 1990 levels of",limit)
add_co2limit(n, Nyears, limit) add_co2limit(n, Nyears, limit)
for o in opts: for o in opts:
for tech in ["solar","onwind","offwind"]:
if tech in o:
limit = o[o.find(tech)+len(tech):]
limit = float(limit.replace("p",".").replace("m","-"))
print("changing potential for",tech,"by factor",limit)
restrict_technology_potential(n,tech,limit)
if o[:10] == 'linemaxext': if o[:10] == 'linemaxext':
maxext = float(o[10:])*1e3 maxext = float(o[10:])*1e3
print("limiting new HVAC and HVDC extensions to",maxext,"MW") print("limiting new HVAC and HVDC extensions to",maxext,"MW")
@ -2047,6 +2032,31 @@ if __name__ == "__main__":
if snakemake.config["sector"]['electricity_distribution_grid']: if snakemake.config["sector"]['electricity_distribution_grid']:
insert_electricity_distribution_grid(n) insert_electricity_distribution_grid(n)
for o in opts:
if "+" in o:
oo = o.split("+")
carrier_list=np.hstack((n.generators.carrier.unique(), n.links.carrier.unique(),
n.stores.carrier.unique(), n.storage_units.carrier.unique()))
suptechs = map(lambda c: c.split("-", 2)[0], carrier_list)
if oo[0].startswith(tuple(suptechs)):
carrier = oo[0]
attr_lookup = {"p": "p_nom_max", "c": "capital_cost"}
attr = attr_lookup[oo[1][0]]
factor = float(oo[1][1:])
#beware if factor is 0 and p_nom_max is np.inf, 0*np.inf is nan
if carrier == "AC": # lines do not have carrier
n.lines[attr] *= factor
else:
comps = {"Generator", "Link", "StorageUnit"} if attr=='p_nom_max' else {"Generator", "Link", "StorageUnit", "Store"}
for c in n.iterate_components(comps):
if carrier=='solar':
sel = c.df.carrier.str.contains(carrier) & ~c.df.carrier.str.contains("solar rooftop")
else:
sel = c.df.carrier.str.contains(carrier)
c.df.loc[sel,attr] *= factor
print("changing", attr ,"for",carrier,"by factor",factor)
if snakemake.config["sector"]['gas_distribution_grid']: if snakemake.config["sector"]['gas_distribution_grid']:
insert_gas_distribution_costs(n) insert_gas_distribution_costs(n)
if snakemake.config["sector"]['electricity_grid_connection']: if snakemake.config["sector"]['electricity_grid_connection']: