Merge pull request #737 from PyPSA/wildcard-opts-config

Add wildcards option in config (full backward compatibility)
This commit is contained in:
Fabian Neumann 2024-01-05 14:33:05 +01:00 committed by GitHub
commit f6fbd00787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 199 additions and 99 deletions

View File

@ -59,6 +59,9 @@ snapshots:
start: "2013-01-01"
end: "2014-01-01"
inclusive: 'left'
resolution: false
segmentation: false
#representative: false
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#enable
enable:
@ -74,6 +77,7 @@ enable:
retrieve_natura_raster: true
custom_busmap: false
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#co2-budget
co2_budget:
2020: 0.701
@ -87,7 +91,9 @@ co2_budget:
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#electricity
electricity:
voltages: [220., 300., 380., 500., 750.]
gaslimit_enable: false
gaslimit: false
co2limit_enable: false
co2limit: 7.75e+7
co2base: 1.487e+9
agg_p_nom_limits: data/agg_p_nom_minmax.csv
@ -124,6 +130,10 @@ electricity:
Onshore: [onwind]
PV: [solar]
autarky:
enable: false
by_country: false
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#atlite
atlite:
default_cutout: europe-2013-era5
@ -618,7 +628,9 @@ costs:
battery: 0.
battery inverter: 0.
emission_prices:
enable: false
co2: 0.
co2_monthly_prices: false
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#clustering
clustering:
@ -660,6 +672,12 @@ solving:
linearized_unit_commitment: true
horizon: 365
constraints:
CCL: false
EQ: false
BAU: false
SAFE: false
solver:
name: gurobi
options: gurobi-default

View File

@ -1,9 +1,11 @@
,Unit,Values,Description
year,--,"YYYY; e.g. '2030'","Year for which to retrieve cost assumptions of ``resources/costs.csv``."
version,--,"vX.X.X; e.g. 'v0.5.0'","Version of ``technology-data`` repository to use."
rooftop_share,--,float,"Share of rooftop PV when calculating capital cost of solar (joint rooftop and utility-scale PV)."
fill_values,--,float,"Default values if not specified for a technology in ``resources/costs.csv``."
capital_cost,EUR/MW,"Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float.","For the given technologies, assumptions about their capital investment costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``."
marginal_cost,EUR/MWh,"Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float.","For the given technologies, assumptions about their marginal operating costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``."
emission_prices,,,"Specify exogenous prices for emission types listed in ``network.carriers`` to marginal costs."
-- co2,EUR/t,float,"Exogenous price of carbon-dioxide added to the marginal costs of fossil-fuelled generators according to their carbon intensity. Added through the keyword ``Ep`` in the ``{opts}`` wildcard only in the rule :mod:`prepare_network``."
,Unit,Values,Description
year,--,YYYY; e.g. '2030',Year for which to retrieve cost assumptions of ``resources/costs.csv``.
version,--,vX.X.X; e.g. 'v0.5.0',Version of ``technology-data`` repository to use.
rooftop_share,--,float,Share of rooftop PV when calculating capital cost of solar (joint rooftop and utility-scale PV).
fill_values,--,float,Default values if not specified for a technology in ``resources/costs.csv``.
capital_cost,EUR/MW,Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float.,"For the given technologies, assumptions about their capital investment costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``."
marginal_cost,EUR/MWh,Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float.,"For the given technologies, assumptions about their marginal operating costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``."
emission_prices,,,Specify exogenous prices for emission types listed in ``network.carriers`` to marginal costs.
-- enable,bool,true or false,Add cost for a carbon-dioxide price configured in ``costs: emission_prices: co2`` to ``marginal_cost`` of generators (other emission types listed in ``network.carriers`` possible as well)
-- co2,EUR/t,float,Exogenous price of carbon-dioxide added to the marginal costs of fossil-fuelled generators according to their carbon intensity. Added through the keyword ``Ep`` in the ``{opts}`` wildcard only in the rule :mod:`prepare_network``.
-- co2_monthly_price,bool,true or false,Add monthly cost for a carbon-dioxide price based on historical values built by the rule ``build_monthly_prices``

1 Unit Values Description
2 year -- YYYY; e.g. '2030' Year for which to retrieve cost assumptions of ``resources/costs.csv``.
3 version -- vX.X.X; e.g. 'v0.5.0' Version of ``technology-data`` repository to use.
4 rooftop_share -- float Share of rooftop PV when calculating capital cost of solar (joint rooftop and utility-scale PV).
5 fill_values -- float Default values if not specified for a technology in ``resources/costs.csv``.
6 capital_cost EUR/MW Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float. For the given technologies, assumptions about their capital investment costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``.
7 marginal_cost EUR/MWh Keys should be in the 'technology' column of ``resources/costs.csv``. Values can be any float. For the given technologies, assumptions about their marginal operating costs are set to the corresponding value. Optional; overwrites cost assumptions from ``resources/costs.csv``.
8 emission_prices Specify exogenous prices for emission types listed in ``network.carriers`` to marginal costs.
9 -- co2 -- enable EUR/t bool float true or false Exogenous price of carbon-dioxide added to the marginal costs of fossil-fuelled generators according to their carbon intensity. Added through the keyword ``Ep`` in the ``{opts}`` wildcard only in the rule :mod:`prepare_network``. Add cost for a carbon-dioxide price configured in ``costs: emission_prices: co2`` to ``marginal_cost`` of generators (other emission types listed in ``network.carriers`` possible as well)
10 -- co2 EUR/t float Exogenous price of carbon-dioxide added to the marginal costs of fossil-fuelled generators according to their carbon intensity. Added through the keyword ``Ep`` in the ``{opts}`` wildcard only in the rule :mod:`prepare_network``.
11 -- co2_monthly_price bool true or false Add monthly cost for a carbon-dioxide price based on historical values built by the rule ``build_monthly_prices``

View File

@ -1,6 +1,8 @@
,Unit,Values,Description
voltages,kV,"Any subset of {220., 300., 380.}",Voltage levels to consider
gaslimit_enable,bool,true or false,Add an overall absolute gas limit configured in ``electricity: gaslimit``.
gaslimit,MWhth,float or false,Global gas usage limit
co2limit_enable,bool,true or false,Add an overall absolute carbon-dioxide emissions limit configured in ``electricity: co2limit``.
co2limit,:math:`t_{CO_2-eq}/a`,float,Cap on total annual system carbon dioxide emissions
co2base,:math:`t_{CO_2-eq}/a`,float,Reference value of total annual system carbon dioxide emissions if relative emission reduction target is specified in ``{opts}`` wildcard.
agg_p_nom_limits,file,path,Reference to ``.csv`` file specifying per carrier generator nominal capacity constraints for individual countries if ``'CCL'`` is in ``{opts}`` wildcard. Defaults to ``data/agg_p_nom_minmax.csv``.
@ -34,3 +36,6 @@ estimate_renewable_capacities,,,
-- -- Offshore,--,"Any subset of {offwind-ac, offwind-dc}","List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) onshore technology."
-- -- Offshore,--,{onwind},"List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) offshore technology."
-- -- PV,--,{solar},"List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) PV technology."
autarky,,,
-- enable,bool,true or false,Require each node to be autarkic by removing all lines and links.
-- by_country,bool,true or false,Require each country to be autarkic by removing all cross-border lines and links. ``electricity: autarky`` must be enabled.

1 Unit Values Description
2 voltages kV Any subset of {220., 300., 380.} Voltage levels to consider
3 gaslimit_enable bool true or false Add an overall absolute gas limit configured in ``electricity: gaslimit``.
4 gaslimit MWhth float or false Global gas usage limit
5 co2limit_enable bool true or false Add an overall absolute carbon-dioxide emissions limit configured in ``electricity: co2limit``.
6 co2limit :math:`t_{CO_2-eq}/a` float Cap on total annual system carbon dioxide emissions
7 co2base :math:`t_{CO_2-eq}/a` float Reference value of total annual system carbon dioxide emissions if relative emission reduction target is specified in ``{opts}`` wildcard.
8 agg_p_nom_limits file path Reference to ``.csv`` file specifying per carrier generator nominal capacity constraints for individual countries if ``'CCL'`` is in ``{opts}`` wildcard. Defaults to ``data/agg_p_nom_minmax.csv``.
36 -- -- Offshore -- Any subset of {offwind-ac, offwind-dc} List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) onshore technology.
37 -- -- Offshore -- {onwind} List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) offshore technology.
38 -- -- PV -- {solar} List of PyPSA-Eur carriers that is considered as (IRENA, OPSD) PV technology.
39 autarky
40 -- enable bool true or false Require each node to be autarkic by removing all lines and links.
41 -- by_country bool true or false Require each country to be autarkic by removing all cross-border lines and links. ``electricity: autarky`` must be enabled.

View File

@ -1,13 +1,13 @@
Trigger, Description, Definition, Status
``nH``; i.e. ``2H``-``6H``, Resample the time-resolution by averaging over every ``n`` snapshots, ``prepare_network``: `average_every_nhours() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L110>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L146>`__), In active use
``nSEG``; e.g. ``4380SEG``, "Apply time series segmentation with `tsam <https://tsam.readthedocs.io/en/latest/index.html>`_ package to ``n`` adjacent snapshots of varying lengths based on capacity factors of varying renewables, hydro inflow and load.", ``prepare_network``: apply_time_segmentation(), In active use
``Co2L``, Add an overall absolute carbon-dioxide emissions limit configured in ``electricity: co2limit``. If a float is appended an overall emission limit relative to the emission level given in ``electricity: co2base`` is added (e.g. ``Co2L0.05`` limits emissisions to 5% of what is given in ``electricity: co2base``), ``prepare_network``: `add_co2limit() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L19>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L154>`__, In active use
``Ep``, Add cost for a carbon-dioxide price configured in ``costs: emission_prices: co2`` to ``marginal_cost`` of generators (other emission types listed in ``network.carriers`` possible as well), ``prepare_network``: `add_emission_prices() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L24>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L158>`__, In active use
``Ept``, Add monthly cost for a carbon-dioxide price based on historical values built by the rule ``build_monthly_prices``, In active use
``CCL``, Add minimum and maximum levels of generator nominal capacity per carrier for individual countries. These can be specified in the file linked at ``electricity: agg_p_nom_limits`` in the configuration. File defaults to ``data/agg_p_nom_minmax.csv``., ``solve_network``, In active use
``EQ``, "Require each country or node to on average produce a minimal share of its total consumption itself. Example: ``EQ0.5c`` demands each country to produce on average at least 50% of its consumption; ``EQ0.5`` demands each node to produce on average at least 50% of its consumption.", ``solve_network``, In active use
``ATK``, "Require each node to be autarkic. Example: ``ATK`` removes all lines and links. ``ATKc`` removes all cross-border lines and links.", ``prepare_network``, In active use
``BAU``, Add a per-``carrier`` minimal overall capacity; i.e. at least ``40GW`` of ``OCGT`` in Europe; configured in ``electricity: BAU_mincapacities``, ``solve_network``: `add_opts_constraints() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/solve_network.py#L66>`__, Untested
``SAFE``, Add a capacity reserve margin of a certain fraction above the peak demand to which renewable generators and storage do *not* contribute. Ignores network., ``solve_network`` `add_opts_constraints() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/solve_network.py#L73>`__, Untested
``carrier+{c|p|m}factor``,"Alter the capital cost (``c``), installable potential (``p``) or marginal costs (``m``) of a carrier by a factor. Example: ``solar+c0.5`` reduces the capital cost of solar to 50\% of original values.", ``prepare_network``, In active use
``CH4L``,"Add an overall absolute gas limit. If configured in ``electricity: gaslimit`` it is given in MWh thermal, if a float is appended, the overall gaslimit is assumed to be given in TWh thermal (e.g. ``CH4L200`` limits gas dispatch to 200 TWh termal)", ``prepare_network``: ``add_gaslimit()``, In active use
Trigger, Description, Definition, Status
``nH``; i.e. ``2H``-``6H``, Resample the time-resolution by averaging over every ``n`` snapshots, ``prepare_network``: `average_every_nhours() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L110>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L146>`__), In active use
``nSEG``; e.g. ``4380SEG``,"Apply time series segmentation with `tsam <https://tsam.readthedocs.io/en/latest/index.html>`_ package to ``n`` adjacent snapshots of varying lengths based on capacity factors of varying renewables, hydro inflow and load.", ``prepare_network``: apply_time_segmentation(), In active use
``Co2L``,Add an overall absolute carbon-dioxide emissions limit configured in ``electricity: co2limit``. If a float is appended an overall emission limit relative to the emission level given in ``electricity: co2base`` is added (e.g. ``Co2L0.05`` limits emissisions to 5% of what is given in ``electricity: co2base``), ``prepare_network``: `add_co2limit() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L19>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L154>`__, In active use
``Ep``,Add cost for a carbon-dioxide price configured in ``costs: emission_prices: co2`` to ``marginal_cost`` of generators (other emission types listed in ``network.carriers`` possible as well), ``prepare_network``: `add_emission_prices() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L24>`_ and its `caller <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/prepare_network.py#L158>`__, In active use
``Ept``,Add monthly cost for a carbon-dioxide price based on historical values built by the rule ``build_monthly_prices``, In active use,
``CCL``,Add minimum and maximum levels of generator nominal capacity per carrier for individual countries. These can be specified in the file linked at ``electricity: agg_p_nom_limits`` in the configuration. File defaults to ``data/agg_p_nom_minmax.csv``., ``solve_network``, In active use
``EQ``,Require each country or node to on average produce a minimal share of its total consumption itself. Example: ``EQ0.5c`` demands each country to produce on average at least 50% of its consumption; ``EQ0.5`` demands each node to produce on average at least 50% of its consumption., ``solve_network``, In active use
``ATK``,Require each node to be autarkic. Example: ``ATK`` removes all lines and links. ``ATKc`` removes all cross-border lines and links., ``prepare_network``, In active use
``BAU``,Add a per-``carrier`` minimal overall capacity; i.e. at least ``40GW`` of ``OCGT`` in Europe; configured in ``electricity: BAU_mincapacities``, ``solve_network``: `add_opts_constraints() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/solve_network.py#L66>`__, Untested
``SAFE``,Add a capacity reserve margin of a certain fraction above the peak demand to which renewable generators and storage do *not* contribute. Ignores network., ``solve_network`` `add_opts_constraints() <https://github.com/PyPSA/pypsa-eur/blob/6b964540ed39d44079cdabddee8333f486d0cd63/scripts/solve_network.py#L73>`__, Untested
``carrier+{c|p|m}factor``,"Alter the capital cost (``c``), installable potential (``p``) or marginal costs (``m``) of a carrier by a factor. Example: ``solar+c0.5`` reduces the capital cost of solar to 50\% of original values.", ``prepare_network``, In active use
``CH4L``,"Add an overall absolute gas limit. If configured in ``electricity: gaslimit`` it is given in MWh thermal, if a float is appended, the overall gaslimit is assumed to be given in TWh thermal (e.g. ``CH4L200`` limits gas dispatch to 200 TWh termal)", ``prepare_network``: ``add_gaslimit()``, In active use

Can't render this file because it has a wrong number of fields in line 6.

View File

@ -1,4 +1,6 @@
,Unit,Values,Description
start,--,"str or datetime-like; e.g. YYYY-MM-DD","Left bound of date range"
end,--,"str or datetime-like; e.g. YYYY-MM-DD","Right bound of date range"
inclusive,--,"One of {'neither', 'both', left, right}","Make the time interval closed to the ``left``, ``right``, or both sides ``both`` or neither side ``None``."
,Unit,Values,Description
start,--,str or datetime-like; e.g. YYYY-MM-DD,Left bound of date range
end,--,str or datetime-like; e.g. YYYY-MM-DD,Right bound of date range
inclusive,--,"One of {'neither', 'both', left, right}","Make the time interval closed to the ``left``, ``right``, or both sides ``both`` or neither side ``None``."
resolution ,--,"{false,``nH``; i.e. ``2H``-``6H``}",Resample the time-resolution by averaging over every ``n`` snapshots
segmentation,--,"{false,``n``; e.g. ``4380``}","Apply time series segmentation with `tsam <https://tsam.readthedocs.io/en/latest/index.html>`_ package to ``n`` adjacent snapshots of varying lengths based on capacity factors of varying renewables, hydro inflow and load."

1 Unit Values Description
2 start -- str or datetime-like; e.g. YYYY-MM-DD Left bound of date range
3 end -- str or datetime-like; e.g. YYYY-MM-DD Right bound of date range
4 inclusive -- One of {'neither', 'both', ‘left’, ‘right’} Make the time interval closed to the ``left``, ``right``, or both sides ``both`` or neither side ``None``.
5 resolution -- {false,``nH``; i.e. ``2H``-``6H``} Resample the time-resolution by averaging over every ``n`` snapshots
6 segmentation -- {false,``n``; e.g. ``4380``} Apply time series segmentation with `tsam <https://tsam.readthedocs.io/en/latest/index.html>`_ package to ``n`` adjacent snapshots of varying lengths based on capacity factors of varying renewables, hydro inflow and load.

View File

@ -13,6 +13,11 @@ options,,,
-- transmission_losses,int,[0-9],"Add piecewise linear approximation of transmission losses based on n tangents. Defaults to 0, which means losses are ignored."
-- linearized_unit_commitment,bool,"{'true','false'}",Whether to optimise using the linearized unit commitment formulation.
-- horizon,--,int,Number of snapshots to consider in each iteration. Defaults to 100.
constraints ,,,
-- CCL,bool,"{'true','false'}",Add minimum and maximum levels of generator nominal capacity per carrier for individual countries. These can be specified in the file linked at ``electricity: agg_p_nom_limits`` in the configuration. File defaults to ``data/agg_p_nom_minmax.csv``.
-- EQ,bool/string,"{'false',`n(c| )``; i.e. ``0.5``-``0.7c``}",Require each country or node to on average produce a minimal share of its total consumption itself. Example: ``EQ0.5c`` demands each country to produce on average at least 50% of its consumption; ``EQ0.5`` demands each node to produce on average at least 50% of its consumption.
-- BAU,bool,"{'true','false'}",Add a per-``carrier`` minimal overall capacity; i.e. at least ``40GW`` of ``OCGT`` in Europe; configured in ``electricity: BAU_mincapacities``
-- SAFE,bool,"{'true','false'}",Add a capacity reserve margin of a certain fraction above the peak demand to which renewable generators and storage do *not* contribute. Ignores network.
solver,,,
-- name,--,"One of {'gurobi', 'cplex', 'cbc', 'glpk', 'ipopt'}; potentially more possible",Solver to use for optimisation problems in the workflow; e.g. clustering and linear optimal power flow.
-- options,--,Key listed under ``solver_options``.,Link to specific parameter settings.

1 Unit Values Description
13 -- transmission_losses int [0-9] Add piecewise linear approximation of transmission losses based on n tangents. Defaults to 0, which means losses are ignored.
14 -- linearized_unit_commitment bool {'true','false'} Whether to optimise using the linearized unit commitment formulation.
15 -- horizon -- int Number of snapshots to consider in each iteration. Defaults to 100.
16 constraints
17 -- CCL bool {'true','false'} Add minimum and maximum levels of generator nominal capacity per carrier for individual countries. These can be specified in the file linked at ``electricity: agg_p_nom_limits`` in the configuration. File defaults to ``data/agg_p_nom_minmax.csv``.
18 -- EQ bool/string {'false',`n(c| )``; i.e. ``0.5``-``0.7c``} Require each country or node to on average produce a minimal share of its total consumption itself. Example: ``EQ0.5c`` demands each country to produce on average at least 50% of its consumption; ``EQ0.5`` demands each node to produce on average at least 50% of its consumption.
19 -- BAU bool {'true','false'} Add a per-``carrier`` minimal overall capacity; i.e. at least ``40GW`` of ``OCGT`` in Europe; configured in ``electricity: BAU_mincapacities``
20 -- SAFE bool {'true','false'} Add a capacity reserve margin of a certain fraction above the peak demand to which renewable generators and storage do *not* contribute. Ignores network.
21 solver
22 -- name -- One of {'gurobi', 'cplex', 'cbc', 'glpk', 'ipopt'}; potentially more possible Solver to use for optimisation problems in the workflow; e.g. clustering and linear optimal power flow.
23 -- options -- Key listed under ``solver_options``. Link to specific parameter settings.

View File

@ -10,6 +10,11 @@ Release Notes
Upcoming Release
================
* More wildcard options now have a corresponding config entry. If the wildcard
is given, then its value is used. If the wildcard is not given but the options
in config are enabled, then the value from config is used. If neither is
given, the options are skipped.
* Distinguish between stored and sequestered CO2. Stored CO2 is stored
overground in tanks and can be used for CCU (e.g. methanolisation).
Sequestered CO2 is stored underground and can no longer be used for CCU. This

View File

@ -20,7 +20,7 @@ if config["enable"].get("prepare_links_p_nom", False):
rule build_electricity_demand:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
countries=config["countries"],
load=config["load"],
input:
@ -61,7 +61,7 @@ rule build_powerplants:
rule base_network:
params:
countries=config["countries"],
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
lines=config["lines"],
links=config["links"],
transformers=config["transformers"],
@ -144,7 +144,7 @@ if config["enable"].get("build_cutout", False):
rule build_cutout:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
cutouts=config["atlite"]["cutouts"],
input:
regions_onshore=RESOURCES + "regions_onshore.geojson",
@ -258,6 +258,7 @@ else:
rule build_renewable_profiles:
params:
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
renewable=config["renewable"],
input:
**opt,
@ -354,6 +355,8 @@ rule build_hydro_profile:
if config["lines"]["dynamic_line_rating"]["activate"]:
rule build_line_rating:
params:
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
input:
base_network=RESOURCES + "networks/base.nc",
cutout="cutouts/"
@ -531,13 +534,20 @@ rule add_extra_components:
rule prepare_network:
params:
snapshots={
"resolution": config["snapshots"].get("resolution", False),
"segmentation": config["snapshots"].get("segmentation", False),
},
links=config["links"],
lines=config["lines"],
co2base=config["electricity"]["co2base"],
co2limit_enable=config["electricity"].get("co2limit_enable", False),
co2limit=config["electricity"]["co2limit"],
gaslimit_enable=config["electricity"].get("gaslimit_enable", False),
gaslimit=config["electricity"].get("gaslimit"),
max_hours=config["electricity"]["max_hours"],
costs=config["costs"],
autarky=config["electricity"].get("autarky", {}),
input:
RESOURCES + "networks/elec_s{simpl}_{clusters}_ec.nc",
tech_costs=COSTS,

View File

@ -125,7 +125,7 @@ rule cluster_gas_network:
rule build_heat_demands:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
input:
pop_layout=RESOURCES + "pop_layout_{scope}.nc",
regions_onshore=RESOURCES + "regions_onshore_elec_s{simpl}_{clusters}.geojson",
@ -147,7 +147,7 @@ rule build_heat_demands:
rule build_temperature_profiles:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
input:
pop_layout=RESOURCES + "pop_layout_{scope}.nc",
regions_onshore=RESOURCES + "regions_onshore_elec_s{simpl}_{clusters}.geojson",
@ -199,7 +199,7 @@ rule build_cop_profiles:
rule build_solar_thermal_profiles:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
solar_thermal=config["solar_thermal"],
input:
pop_layout=RESOURCES + "pop_layout_{scope}.nc",
@ -662,7 +662,7 @@ rule build_shipping_demand:
rule build_transport_demand:
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
sector=config["sector"],
input:
clustered_pop_layout=RESOURCES + "pop_layout_elec_s{simpl}_{clusters}.csv",

View File

@ -85,7 +85,7 @@ rule make_summary:
params:
foresight=config["foresight"],
costs=config["costs"],
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
scenario=config["scenario"],
RDIR=RDIR,
input:

View File

@ -17,7 +17,7 @@ rule build_electricity_production:
The data is used for validation of the optimization results.
"""
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
countries=config["countries"],
output:
RESOURCES + "historical_electricity_production.csv",
@ -35,7 +35,7 @@ rule build_cross_border_flows:
The data is used for validation of the optimization results.
"""
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
countries=config["countries"],
input:
network=RESOURCES + "networks/base.nc",
@ -55,7 +55,7 @@ rule build_electricity_prices:
The data is used for validation of the optimization results.
"""
params:
snapshots=config["snapshots"],
snapshots={k: config["snapshots"][k] for k in ["start", "end", "inclusive"]},
countries=config["countries"],
output:
RESOURCES + "historical_electricity_prices.csv",

View File

@ -7,6 +7,7 @@ import contextlib
import hashlib
import logging
import os
import re
import urllib
from pathlib import Path
@ -23,6 +24,35 @@ logger = logging.getLogger(__name__)
REGION_COLS = ["geometry", "name", "x", "y", "country"]
def get_opt(opts, expr, flags=None):
"""
Return the first option matching the regular expression.
The regular expression is case-insensitive by default.
"""
if flags is None:
flags = re.IGNORECASE
for o in opts:
match = re.match(expr, o, flags=flags)
if match:
return match.group(0)
return None
def find_opt(opts, expr):
"""
Return if available the float after the expression.
"""
for o in opts:
if expr in o:
m = re.findall("[0-9]*\.?[0-9]+$", o)
if len(m) > 0:
return True, float(m[0])
else:
return True, None
return False, None
# Define a context manager to temporarily mute print statements
@contextlib.contextmanager
def mute_print():

View File

@ -725,11 +725,12 @@ def base_network(
transformers = _set_electrical_parameters_transformers(transformers, config)
links = _set_electrical_parameters_links(links, config, links_p_nom)
converters = _set_electrical_parameters_converters(converters, config)
snapshots = snakemake.params.snapshots
n = pypsa.Network()
n.name = "PyPSA-Eur"
n.set_snapshots(pd.date_range(freq="h", **config["snapshots"]))
n.set_snapshots(pd.date_range(freq="h", **snapshots))
n.madd("Carrier", ["AC", "DC"])
n.import_components_from_dataframe(buses, "Bus")

View File

@ -146,8 +146,10 @@ if __name__ == "__main__":
)
configure_logging(snakemake)
snapshots = snakemake.params.snapshots
n = pypsa.Network(snakemake.input.base_network)
time = pd.date_range(freq="h", **snakemake.config["snapshots"])
time = pd.date_range(freq="h", **snapshots)
cutout = atlite.Cutout(snakemake.input.cutout).sel(time=time)
da = calculate_line_rating(n, cutout)

View File

@ -210,6 +210,7 @@ if __name__ == "__main__":
resource = params["resource"] # pv panel params / wind turbine params
correction_factor = params.get("correction_factor", 1.0)
capacity_per_sqkm = params["capacity_per_sqkm"]
snapshots = snakemake.params.snapshots
if correction_factor != 1.0:
logger.info(f"correction_factor is set as {correction_factor}")
@ -219,7 +220,7 @@ if __name__ == "__main__":
else:
client = None
sns = pd.date_range(freq="h", **snakemake.config["snapshots"])
sns = pd.date_range(freq="h", **snapshots)
cutout = atlite.Cutout(snakemake.input.cutout).sel(time=sns)
regions = gpd.read_file(snakemake.input.regions)
assert not regions.empty, (

View File

@ -63,7 +63,7 @@ import re
import numpy as np
import pandas as pd
import pypsa
from _helpers import configure_logging
from _helpers import configure_logging, find_opt, get_opt
from add_electricity import load_costs, update_transmission_costs
from pypsa.descriptors import expand_series
@ -296,42 +296,42 @@ if __name__ == "__main__":
set_line_s_max_pu(n, snakemake.params.lines["s_max_pu"])
for o in opts:
m = re.match(r"^\d+h$", o, re.IGNORECASE)
if m is not None:
n = average_every_nhours(n, m.group(0))
break
# temporal averaging
nhours_config = snakemake.params.snapshots.get("resolution", False)
nhours_wildcard = get_opt(opts, r"^\d+h$")
nhours = nhours_wildcard or nhours_config
if nhours:
n = average_every_nhours(n, nhours)
for o in opts:
m = re.match(r"^\d+seg$", o, re.IGNORECASE)
if m is not None:
solver_name = snakemake.config["solving"]["solver"]["name"]
n = apply_time_segmentation(n, m.group(0)[:-3], solver_name)
break
# segments with package tsam
time_seg_config = snakemake.params.snapshots.get("segmentation", False)
time_seg_wildcard = get_opt(opts, r"^\d+seg$")
time_seg = time_seg_wildcard or time_seg_config
if time_seg:
solver_name = snakemake.config["solving"]["solver"]["name"]
n = apply_time_segmentation(n, time_seg.replace("seg", ""), solver_name)
for o in opts:
if "Co2L" in o:
m = re.findall("[0-9]*\.?[0-9]+$", o)
if len(m) > 0:
co2limit = float(m[0]) * snakemake.params.co2base
add_co2limit(n, co2limit, Nyears)
logger.info("Setting CO2 limit according to wildcard value.")
else:
add_co2limit(n, snakemake.params.co2limit, Nyears)
logger.info("Setting CO2 limit according to config value.")
break
Co2L_config = snakemake.params.co2limit_enable
Co2L_wildcard, co2limit_wildcard = find_opt(opts, "Co2L")
if Co2L_wildcard or Co2L_config:
if co2limit_wildcard is not None:
co2limit = co2limit_wildcard * snakemake.params.co2base
add_co2limit(n, co2limit, Nyears)
logger.info("Setting CO2 limit according to wildcard value.")
else:
add_co2limit(n, snakemake.params.co2limit, Nyears)
logger.info("Setting CO2 limit according to config value.")
for o in opts:
if "CH4L" in o:
m = re.findall("[0-9]*\.?[0-9]+$", o)
if len(m) > 0:
limit = float(m[0]) * 1e6
add_gaslimit(n, limit, Nyears)
logger.info("Setting gas usage limit according to wildcard value.")
else:
add_gaslimit(n, snakemake.params.gaslimit, Nyears)
logger.info("Setting gas usage limit according to config value.")
break
CH4L_config = snakemake.params.gaslimit_enable
CH4L_wildcard, gaslimit_wildcard = find_opt(opts, "CH4L")
if CH4L_wildcard or CH4L_config:
if gaslimit_wildcard is not None:
gaslimit = gaslimit_wildcard * 1e6
add_gaslimit(n, gaslimit, Nyears)
logger.info("Setting gas usage limit according to wildcard value.")
else:
add_gaslimit(n, snakemake.params.gaslimit, Nyears)
logger.info("Setting gas usage limit according to config value.")
for o in opts:
if "+" not in o:
@ -352,21 +352,26 @@ if __name__ == "__main__":
sel = c.df.carrier.str.contains(carrier)
c.df.loc[sel, attr] *= factor
for o in opts:
if "Ept" in o:
logger.info(
"Setting time dependent emission prices according spot market price"
emission_prices = snakemake.params.costs["emission_prices"]
Ept_config = emission_prices.get("co2_monthly_prices", False)
Ept_wildcard = "Ept" in opts
Ep_config = emission_prices.get("enable", False)
Ep_wildcard, co2_wildcard = find_opt(opts, "Ep")
if Ept_wildcard or Ept_config:
logger.info(
"Setting time dependent emission prices according spot market price"
)
add_dynamic_emission_prices(n)
elif Ep_wildcard or Ep_config:
if co2_wildcard is not None:
logger.info("Setting CO2 prices according to wildcard value.")
add_emission_prices(n, dict(co2=co2_wildcard))
else:
logger.info("Setting CO2 prices according to config value.")
add_emission_prices(
n, dict(co2=snakemake.params.costs["emission_prices"]["co2"])
)
add_dynamic_emission_prices(n)
elif "Ep" in o:
m = re.findall("[0-9]*\.?[0-9]+$", o)
if len(m) > 0:
logger.info("Setting emission prices according to wildcard value.")
add_emission_prices(n, dict(co2=float(m[0])))
else:
logger.info("Setting emission prices according to config value.")
add_emission_prices(n, snakemake.params.costs["emission_prices"])
break
ll_type, factor = snakemake.wildcards.ll[0], snakemake.wildcards.ll[1:]
set_transmission_limit(n, ll_type, factor, costs, Nyears)
@ -379,10 +384,12 @@ if __name__ == "__main__":
p_nom_max_ext=snakemake.params.links.get("max_extension", np.inf),
)
if "ATK" in opts:
enforce_autarky(n)
elif "ATKc" in opts:
enforce_autarky(n, only_crossborder=True)
autarky_config = snakemake.params.autarky
if "ATK" in opts or autarky_config.get("enable", False):
only_crossborder = False
if "ATKc" in opts or autarky_config.get("by_country", False):
only_crossborder = True
enforce_autarky(n, only_crossborder=only_crossborder)
n.meta = dict(snakemake.config, **dict(wildcards=dict(snakemake.wildcards)))
n.export_to_netcdf(snakemake.output[0])

View File

@ -37,7 +37,7 @@ import pandas as pd
import pypsa
import xarray as xr
from _benchmark import memory_logger
from _helpers import configure_logging, update_config_with_sector_opts
from _helpers import configure_logging, get_opt, update_config_with_sector_opts
from pypsa.descriptors import get_activity_mask
logger = logging.getLogger(__name__)
@ -806,18 +806,30 @@ def extra_functionality(n, snapshots):
"""
opts = n.opts
config = n.config
if "BAU" in opts and n.generators.p_nom_extendable.any():
constraints = config["solving"].get("constraints", {})
if (
"BAU" in opts or constraints.get("BAU", False)
) and n.generators.p_nom_extendable.any():
add_BAU_constraints(n, config)
if "SAFE" in opts and n.generators.p_nom_extendable.any():
if (
"SAFE" in opts or constraints.get("SAFE", False)
) and n.generators.p_nom_extendable.any():
add_SAFE_constraints(n, config)
if "CCL" in opts and n.generators.p_nom_extendable.any():
if (
"CCL" in opts or constraints.get("CCL", False)
) and n.generators.p_nom_extendable.any():
add_CCL_constraints(n, config)
reserve = config["electricity"].get("operational_reserve", {})
if reserve.get("activate"):
add_operational_reserve_margin(n, snapshots, config)
for o in opts:
if "EQ" in o:
add_EQ_constraints(n, o)
EQ_config = constraints.get("EQ", False)
EQ_wildcard = get_opt(opts, r"^EQ+[0-9]*\.?[0-9]+(c|)")
EQ_o = EQ_wildcard or EQ_config
if EQ_o:
add_EQ_constraints(n, EQ_o.replace("EQ", ""))
add_battery_constraints(n)
add_lossy_bidirectional_link_constraints(n)
add_pipe_retrofit_constraint(n)