Skip to content

Commit

Permalink
Merge pull request #651 from PyPSA/validation
Browse files Browse the repository at this point in the history
Validation
  • Loading branch information
fneum authored Aug 6, 2023
2 parents 2d050cc + 8d19043 commit e34cec4
Show file tree
Hide file tree
Showing 46 changed files with 1,625 additions and 189 deletions.
11 changes: 11 additions & 0 deletions .sync-send
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: : 2021-2023 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: CC0-1.0

rules
scripts
config
config/test
envs
matplotlibrc
Snakefile
21 changes: 0 additions & 21 deletions .syncignore-receive

This file was deleted.

23 changes: 0 additions & 23 deletions .syncignore-send

This file was deleted.

14 changes: 13 additions & 1 deletion Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ localrules:

wildcard_constraints:
simpl="[a-zA-Z0-9]*",
clusters="[0-9]+m?|all",
clusters="[0-9]+(m|c)?|all",
ll="(v|c)([0-9\.]+|opt)",
opts="[-+a-zA-Z0-9\.]*",
sector_opts="[-+a-zA-Z0-9\.\s]*",
Expand All @@ -53,6 +53,7 @@ include: "rules/build_electricity.smk"
include: "rules/build_sector.smk"
include: "rules/solve_electricity.smk"
include: "rules/postprocess.smk"
include: "rules/validate.smk"


if config["foresight"] == "overnight":
Expand Down Expand Up @@ -98,3 +99,14 @@ rule doc:
directory("doc/_build"),
shell:
"make -C doc html"


rule sync:
params:
cluster=f"{config['remote']['ssh']}:{config['remote']['path']}",
shell:
"""
rsync -uvarh --ignore-missing-args --files-from=.sync-send . {params.cluster}
rsync -uvarh --no-g {params.cluster}/results . || echo "No results directory, skipping rsync"
rsync -uvarh --no-g {params.cluster}/logs . || echo "No logs directory, skipping rsync"
"""
30 changes: 22 additions & 8 deletions config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ logging:
level: INFO
format: '%(levelname)s:%(name)s:%(message)s'

private:
keys:
entsoe_api:

remote:
ssh: ""
path: ""

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
run:
name: ""
Expand Down Expand Up @@ -209,10 +217,14 @@ renewable:
carriers: [ror, PHS, hydro]
PHS_max_hours: 6
hydro_max_hours: "energy_capacity_totals_by_country" # one of energy_capacity_totals_by_country, estimate_by_large_installations or a float
flatten_dispatch: false
flatten_dispatch_buffer: 0.2
clip_min_inflow: 1.0

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#conventional
conventional:
unit_commitment: false
dynamic_fuel_price: false
nuclear:
p_max_pu: "data/nuclear_p_max_pu.csv" # float of file name

Expand Down Expand Up @@ -574,30 +586,30 @@ clustering:
algorithm: kmeans
feature: solar+onwind-time
exclude_carriers: []
consider_efficiency_classes: false
aggregation_strategies:
generators:
p_nom_max: sum
p_nom_min: sum
p_min_pu: mean
marginal_cost: mean
committable: any
ramp_limit_up: max
ramp_limit_down: max
efficiency: mean

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#solving
solving:
#tmpdir: "path/to/tmp"
options:
clip_p_max_pu: 1.e-2
load_shedding: false
transmission_losses: 0
noisy_costs: true
skip_iterations: true
rolling_horizon: false
seed: 123
# options that go into the optimize function
track_iterations: false
min_iterations: 4
max_iterations: 6
seed: 123
transmission_losses: 0
linearized_unit_commitment: true
horizon: 365

solver:
name: gurobi
Expand Down Expand Up @@ -625,7 +637,6 @@ solving:
AggFill: 0
PreDual: 0
GURO_PAR_BARDENSETHRESH: 200
seed: 10 # Consistent seed for all plattforms
gurobi-numeric-focus:
name: gurobi
NumericFocus: 3 # Favour numeric stability over speed
Expand Down Expand Up @@ -658,6 +669,7 @@ solving:
glpk-default: {} # Used in CI

mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2
walltime: "12:00:00"

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#plotting
plotting:
Expand Down Expand Up @@ -688,6 +700,8 @@ plotting:
H2: "Hydrogen Storage"
lines: "Transmission Lines"
ror: "Run of River"
ac: "AC"
dc: "DC"

tech_colors:
# wind
Expand Down
98 changes: 98 additions & 0 deletions config/config.validation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# SPDX-FileCopyrightText: : 2017-2023 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: CC0-1.0
run:
name: "validation"

scenario:
ll:
- v1.0
clusters:
- 37
opts:
- 'Ept'

snapshots:
start: "2019-01-01"
end: "2020-01-01"
inclusive: 'left'

enable:
retrieve_cutout: false

electricity:
co2limit: 1e9

extendable_carriers:
Generator: []
StorageUnit: []
Store: []
Link: []

powerplants_filter: not (DateOut < 2019)

conventional_carriers: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass]
renewable_carriers: [solar, onwind, offwind-ac, offwind-dc, hydro]

estimate_renewable_capacities:
year: 2019

atlite:
default_cutout: europe-2019-era5
cutouts:
europe-2019-era5:
module: era5
x: [-12., 35.]
y: [33., 72]
dx: 0.3
dy: 0.3
time: ['2019', '2019']

renewable:
onwind:
cutout: europe-2019-era5
offwind-ac:
cutout: europe-2019-era5
offwind-dc:
cutout: europe-2019-era5
solar:
cutout: europe-2019-era5
hydro:
cutout: europe-2019-era5
flatten_dispatch: 0.01

conventional:
unit_commitment: false
dynamic_fuel_price: true
nuclear:
p_max_pu: "data/nuclear_p_max_pu.csv"
biomass:
p_max_pu: 0.65

load:
power_statistics: false

lines:
s_max_pu: 0.23
under_construction: 'remove'

links:
include_tyndp: false

costs:
year: 2020
emission_prices:
co2: 25

clustering:
simplify_network:
exclude_carriers: [oil, coal, lignite, OCGT, CCGT]
cluster_network:
consider_efficiency_classes: true

solving:
options:
load_shedding: true
rolling_horizon: false
horizon: 1000
overlap: 48
30 changes: 15 additions & 15 deletions data/nuclear_p_max_pu.csv
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
country,factor
BE,0.65
BG,0.89
CZ,0.82
FI,0.92
FR,0.70
DE,0.88
HU,0.90
NL,0.86
RO,0.92
SK,0.89
SI,0.94
ES,0.89
SE,0.82
CH,0.86
GB,0.67
BE,0.796
BG,0.894
CZ,0.827
FI,0.936
FR,0.71
DE,0.871
HU,0.913
NL,0.868
RO,0.909
SK,0.9
SI,0.913
ES,0.897
SE,0.851
CH,0.87
GB,0.656
8 changes: 8 additions & 0 deletions data/unit_commitment.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
attribute,OCGT,CCGT,coal,lignite,nuclear
ramp_limit_up,1,1,1,1,0.3
ramp_limit_start_up,0.2,0.45,0.38,0.4,0.5
ramp_limit_shut_down,0.2,0.45,0.38,0.4,0.5
p_min_pu,0.2,0.45,0.325,0.4,0.5
min_up_time,,3,5,7,6
min_down_time,,2,6,6,10
start_up_cost,9.6,34.2,35.64,19.14,16.5
35 changes: 18 additions & 17 deletions doc/configtables/clustering.csv
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
,Unit,Values,Description
simplify_network,,,
-- to_substations,bool,"{'true','false'}","Aggregates all nodes without power injection (positive or negative, i.e. demand or generation) to electrically closest ones"
-- algorithm,str,"One of {‘kmeans’, ‘hac’, ‘modularity‘}",
-- feature,str,"Str in the format ‘carrier1+carrier2+...+carrierN-X’, where CarrierI can be from {‘solar’, ‘onwind’, ‘offwind’, ‘ror’} and X is one of {‘cap’, ‘time’}.",
-- exclude_carriers,list,"List of Str like [ 'solar', 'onwind'] or empy list []","List of carriers which will not be aggregated. If empty, all carriers will be aggregated."
-- remove stubs,bool,"true/false","Controls whether radial parts of the network should be recursively aggregated. Defaults to true."
-- remove_stubs_across_borders,bool,"true/false","Controls whether radial parts of the network should be recursively aggregated across borders. Defaults to true."
cluster_network,,,
-- algorithm,str,"One of {‘kmeans’, ‘hac’}",
-- feature,str,"Str in the format ‘carrier1+carrier2+...+carrierN-X’, where CarrierI can be from {‘solar’, ‘onwind’, ‘offwind’, ‘ror’} and X is one of {‘cap’, ‘time’}.",
-- exclude_carriers,list,"List of Str like [ 'solar', 'onwind'] or empy list []","List of carriers which will not be aggregated. If empty, all carriers will be aggregated."
aggregation_strategies,,,
-- generators,,,
-- -- {key},str,"{key} can be any of the component of the generator (str). It’s value can be any that can be converted to pandas.Series using getattr(). For example one of {min, max, sum}.","Aggregates the component according to the given strategy. For example, if sum, then all values within each cluster are summed to represent the new generator."
-- buses,,,
-- -- {key},str,"{key} can be any of the component of the bus (str). It’s value can be any that can be converted to pandas.Series using getattr(). For example one of {min, max, sum}.","Aggregates the component according to the given strategy. For example, if sum, then all values within each cluster are summed to represent the new bus."
,Unit,Values,Description
simplify_network,,,
-- to_substations,bool,"{'true','false'}","Aggregates all nodes without power injection (positive or negative, i.e. demand or generation) to electrically closest ones"
-- algorithm,str,"One of {‘kmeans’, ‘hac’, ‘modularity‘}",
-- feature,str,"Str in the format ‘carrier1+carrier2+...+carrierN-X’, where CarrierI can be from {‘solar’, ‘onwind’, ‘offwind’, ‘ror’} and X is one of {‘cap’, ‘time’}.",
-- exclude_carriers,list,"List of Str like [ 'solar', 'onwind'] or empy list []","List of carriers which will not be aggregated. If empty, all carriers will be aggregated."
-- remove stubs,bool,"{'true','false'}",Controls whether radial parts of the network should be recursively aggregated. Defaults to true.
-- remove_stubs_across_borders,bool,"{'true','false'}",Controls whether radial parts of the network should be recursively aggregated across borders. Defaults to true.
cluster_network,,,
-- algorithm,str,"One of {‘kmeans’, ‘hac’}",
-- feature,str,"Str in the format ‘carrier1+carrier2+...+carrierN-X’, where CarrierI can be from {‘solar’, ‘onwind’, ‘offwind’, ‘ror’} and X is one of {‘cap’, ‘time’}.",
-- exclude_carriers,list,"List of Str like [ 'solar', 'onwind'] or empy list []","List of carriers which will not be aggregated. If empty, all carriers will be aggregated."
-- consider_efficiency_classes,bool,"{'true','false'}","Aggregated each carriers into the top 10-quantile (high), the bottom 90-quantile (low), and everything in between (medium)."
aggregation_strategies,,,
-- generators,,,
-- -- {key},str,"{key} can be any of the component of the generator (str). It’s value can be any that can be converted to pandas.Series using getattr(). For example one of {min, max, sum}.","Aggregates the component according to the given strategy. For example, if sum, then all values within each cluster are summed to represent the new generator."
-- buses,,,
-- -- {key},str,"{key} can be any of the component of the bus (str). It’s value can be any that can be converted to pandas.Series using getattr(). For example one of {min, max, sum}.","Aggregates the component according to the given strategy. For example, if sum, then all values within each cluster are summed to represent the new bus."
8 changes: 5 additions & 3 deletions doc/configtables/conventional.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
,Unit,Values,Description
{name},--,"string","For any carrier/technology overwrite attributes as listed below."
-- {attribute},--,"string or float","For any attribute, can specify a float or reference to a file path to a CSV file giving floats for each country (2-letter code)."
,Unit,Values,Description
unit_commitment ,bool,"{true, false}","Allow the overwrite of ramp_limit_up, ramp_limit_start_up, ramp_limit_shut_down, p_min_pu, min_up_time, min_down_time, and start_up_cost of conventional generators. Refer to the CSV file „unit_commitment.csv“."
dynamic_fuel_price ,bool,"{true, false}","Consider the monthly fluctuating fuel prices for each conventional generator. Refer to the CSV file ""data/validation/monthly_fuel_price.csv""."
{name},--,string,For any carrier/technology overwrite attributes as listed below.
-- {attribute},--,string or float,"For any attribute, can specify a float or reference to a file path to a CSV file giving floats for each country (2-letter code)."
14 changes: 8 additions & 6 deletions doc/configtables/hydro.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
,Unit,Values,Description
cutout,--,"Must be 'europe-2013-era5'","Specifies the directory where the relevant weather data ist stored."
carriers,--,"Any subset of {'ror', 'PHS', 'hydro'}","Specifies the types of hydro power plants to build per-unit availability time series for. 'ror' stands for run-of-river plants, 'PHS' represents pumped-hydro storage, and 'hydro' stands for hydroelectric dams."
PHS_max_hours,h,float,"Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom``. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_."
hydro_max_hours,h,"Any of {float, 'energy_capacity_totals_by_country', 'estimate_by_large_installations'}","Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom`` or heuristically determined. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_."
clip_min_inflow,MW,float,"To avoid too small values in the inflow time series, values below this threshold are set to zero."
,Unit,Values,Description
cutout,--,Must be 'europe-2013-era5',Specifies the directory where the relevant weather data ist stored.
carriers,--,"Any subset of {'ror', 'PHS', 'hydro'}","Specifies the types of hydro power plants to build per-unit availability time series for. 'ror' stands for run-of-river plants, 'PHS' represents pumped-hydro storage, and 'hydro' stands for hydroelectric dams."
PHS_max_hours,h,float,Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom``. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_.
hydro_max_hours,h,"Any of {float, 'energy_capacity_totals_by_country', 'estimate_by_large_installations'}",Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom`` or heuristically determined. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_.
flatten_dispatch,bool,"{true, false}",Consider an upper limit for the hydro dispatch. The limit is given by the average capacity factor plus the buffer given in ``flatten_dispatch_buffer``
flatten_dispatch_buffer,--,float,"If ``flatten_dispatch`` is true, specify the value added above the average capacity factor."
clip_min_inflow,MW,float,"To avoid too small values in the inflow time series, values below this threshold are set to zero."
1 change: 1 addition & 0 deletions doc/configtables/opts.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Trigger, Description, Definition, Status
``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
Expand Down
Loading

0 comments on commit e34cec4

Please sign in to comment.