From b98235c1f1ae4d502a688d3982a72ec711900422 Mon Sep 17 00:00:00 2001 From: martavp Date: Mon, 4 Jan 2021 10:13:30 +0100 Subject: [PATCH] Allow specifying an option to alter the capital cost of carriers by a factor indicated in the config file, eg: solar+c0.5 This is almost a direct copy PyPSA-Eur #167 https://github.com/PyPSA/pypsa-eur/pull/167 A factor altering the maximum capacity (p_nom_max) can also be specified by e.g. solar+p3 One should be careful when using this for solar because the factor is applied to all the generators whose carrier includes the string 'solar' (i.e., it is applied to both utility and rooftop solar) I would suggest implementing 'solar utility' and 'solar rooftop' as carriers, since this can be useful for other selecting processes. Is there is any reason for keeping 'solar' as a carrier for 'solar utility'? The previous way of increasing maximum capacity via the config file (e.g 'solar3') is still present in the code. --- config.default.yaml | 1 + doc/release_notes.rst | 1 + scripts/prepare_sector_network.py | 33 +++++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 08cda6c4..946977f9 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -24,6 +24,7 @@ scenario: # B for biomass supply, I for industry, shipping and aviation # solarx or onwindx changes the available installable potential by factor x # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv + # solar+c0.5 reduces the capital cost of solar to 50\% of reference value # for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative # emissions throughout the transition path in the timeframe determined by the # planning_horizons), be:beta decay; ex:exponential decay diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 66594614..1e43b92c 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -5,6 +5,7 @@ Release Notes 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. +*Added an option to alter the capital cost of carriers by a factor via ``carrier+factor`` in the ``{opts}`` wildcard. This can be useful for exploring uncertain cost parameters. Example: ``solar+0.5`` reduces the capital cost of solar to 50\% of original values. PyPSA-Eur-Sec 0.4.0 (11th December 2020) ========================================= diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 088b124f..a875a635 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1984,8 +1984,8 @@ if __name__ == "__main__": from vresutils.snakemake import MockSnakemake snakemake = MockSnakemake( wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0', - opts='', planning_horizons='2020', - sector_opts='120H-T-H-B-I-solar3-dist1-cb40ex0'), + opts='', planning_horizons='2050', + sector_opts='Co2L0-180H-T-H-B-I-solar3-dist1-solar+c0.5-Sabatier+c0.5'), input=dict( network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc', energy_totals_name='resources/energy_totals.csv', co2_totals_name='resources/co2_totals.csv', @@ -2024,7 +2024,7 @@ if __name__ == "__main__": retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv", floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv" ), - output=['results/version-8/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc'] + output=['results/version-0/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc'] ) import yaml with open('config.yaml', encoding='utf8') as f: @@ -2150,11 +2150,10 @@ if __name__ == "__main__": print("adding CO2 budget limit as per unit of 1990 levels of",limit) add_co2limit(n, Nyears, limit) - - + for o in opts: for tech in ["solar","onwind","offwind"]: - if tech in o: + if tech in o and "+" not in o: limit = o[o.find(tech)+len(tech):] limit = float(limit.replace("p",".").replace("m","-")) print("changing potential for",tech,"by factor",limit) @@ -2170,6 +2169,28 @@ if __name__ == "__main__": if snakemake.config["sector"]['electricity_distribution_grid']: 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] + # handles only p_nom_max as stores and lines have no potentials + attr_lookup = {"p": "p_nom_max", "c": "capital_cost"} + attr = attr_lookup[oo[1][0]] + factor = float(oo[1][1:]) + if carrier == "AC": # lines do not have carrier + n.lines[attr] *= factor + else: + comps = {"Generator", "Link", "StorageUnit", "Store"} + for c in n.iterate_components(comps): + 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']: insert_gas_distribution_costs(n) if snakemake.config["sector"]['electricity_grid_connection']: