From 24e008a98e03f6cf0def2ed95d1d75fed555a72b Mon Sep 17 00:00:00 2001
From: Philipp Glaum
Date: Fri, 16 Sep 2022 14:25:15 +0200
Subject: [PATCH 1/4] add feature: aggregate carrier exclusion
---
config.default.yaml | 1 +
config.tutorial.yaml | 1 +
scripts/cluster_network.py | 3 +--
scripts/simplify_network.py | 13 ++++++++-----
test/config.test1.yaml | 1 +
5 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/config.default.yaml b/config.default.yaml
index fb1e9603..0c2c8218 100755
--- a/config.default.yaml
+++ b/config.default.yaml
@@ -261,6 +261,7 @@ clustering:
cluster_network:
algorithm: kmeans
feature: solar+onwind-time
+ exclude_carriers: [] # list of carriers which will not be aggregated. If empty, all carriers will be aggregated.
aggregation_strategies:
generators:
p_nom_max: sum # use "min" for more conservative assumptions
diff --git a/config.tutorial.yaml b/config.tutorial.yaml
index fb5fe807..0cfdc5ab 100755
--- a/config.tutorial.yaml
+++ b/config.tutorial.yaml
@@ -191,6 +191,7 @@ clustering:
cluster_network:
algorithm: kmeans
feature: solar+onwind-time
+ exclude_carriers: [] # list of carriers which will not be aggregated. If empty, all carriers will be aggregated.
aggregation_strategies:
generators:
p_nom_max: sum # use "min" for more conservative assumptions
diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py
index 11defccb..a392d024 100644
--- a/scripts/cluster_network.py
+++ b/scripts/cluster_network.py
@@ -393,15 +393,14 @@ if __name__ == "__main__":
for tech in n.generators.carrier.unique()
if tech in snakemake.config['renewable']])
+ aggregate_carriers=set(n.carriers.index)-set(snakemake.config["clustering"]["exclude_carriers"])
if snakemake.wildcards.clusters.endswith('m'):
n_clusters = int(snakemake.wildcards.clusters[:-1])
aggregate_carriers = snakemake.config["electricity"].get("conventional_carriers")
elif snakemake.wildcards.clusters == 'all':
n_clusters = len(n.buses)
- aggregate_carriers = None # All
else:
n_clusters = int(snakemake.wildcards.clusters)
- aggregate_carriers = None # All
if n_clusters == len(n.buses):
# Fast-path if no clustering is necessary
diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py
index 56889fbf..16726156 100644
--- a/scripts/simplify_network.py
+++ b/scripts/simplify_network.py
@@ -197,7 +197,7 @@ def _adjust_capital_costs_using_connection_costs(n, connection_costs_to_bus, out
def _aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
aggregate_one_ports={"Load", "StorageUnit"},
- aggregation_strategies=dict()):
+ aggregation_strategies=dict(), exclude_carriers=None):
def replace_components(n, c, df, pnl):
n.mremove(c, n.df(c).index)
@@ -210,9 +210,10 @@ def _aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
_adjust_capital_costs_using_connection_costs(n, connection_costs_to_bus, output)
_, generator_strategies = get_aggregation_strategies(aggregation_strategies)
-
+
+ carriers=set(n.carriers.index)-set(exclude_carriers)
generators, generators_pnl = aggregategenerators(
- n, busmap, custom_strategies=generator_strategies
+ n, busmap, carriers=carriers, custom_strategies=generator_strategies
)
replace_components(n, "Generator", generators, generators_pnl)
@@ -320,8 +321,9 @@ def simplify_links(n, costs, config, output, aggregation_strategies=dict()):
logger.debug("Collecting all components using the busmap")
+ exclude_carriers=config["clustering"]["exclude_carriers"]
_aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
- aggregation_strategies=aggregation_strategies)
+ aggregation_strategies=aggregation_strategies, exclude_carriers=exclude_carriers)
return n, busmap
def remove_stubs(n, costs, config, output, aggregation_strategies=dict()):
@@ -331,8 +333,9 @@ def remove_stubs(n, costs, config, output, aggregation_strategies=dict()):
connection_costs_to_bus = _compute_connection_costs_to_bus(n, busmap, costs, config)
+ exclude_carriers=config["clustering"]["exclude_carriers"]
_aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
- aggregation_strategies=aggregation_strategies)
+ aggregation_strategies=aggregation_strategies, exclude_carriers=exclude_carriers)
return n, busmap
diff --git a/test/config.test1.yaml b/test/config.test1.yaml
index a9df427b..9cc4015b 100755
--- a/test/config.test1.yaml
+++ b/test/config.test1.yaml
@@ -189,6 +189,7 @@ clustering:
cluster_network:
algorithm: kmeans
feature: solar+onwind-time
+ exclude_carriers: ["OCGT", "offwind-ac", "coal"]
aggregation_strategies:
generators:
p_nom_max: sum # use "min" for more conservative assumptions
From d51ca8695bf2591ba3eb9698b8cfe1c5241194bc Mon Sep 17 00:00:00 2001
From: Philipp Glaum
Date: Mon, 19 Sep 2022 11:46:58 +0200
Subject: [PATCH 2/4] update Fabians comments
---
config.default.yaml | 3 ++-
config.tutorial.yaml | 3 ++-
doc/configtables/clustering.csv | 6 ++++--
scripts/cluster_network.py | 3 ++-
scripts/simplify_network.py | 6 +++---
5 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/config.default.yaml b/config.default.yaml
index 0c2c8218..920e4809 100755
--- a/config.default.yaml
+++ b/config.default.yaml
@@ -258,10 +258,11 @@ clustering:
to_substations: false # network is simplified to nodes with positive or negative power injection (i.e. substations or offwind connections)
algorithm: kmeans # choose from: [hac, kmeans]
feature: solar+onwind-time # only for hac. choose from: [solar+onwind-time, solar+onwind-cap, solar-time, solar-cap, solar+offwind-cap] etc.
+ exclude_carriers: []
cluster_network:
algorithm: kmeans
feature: solar+onwind-time
- exclude_carriers: [] # list of carriers which will not be aggregated. If empty, all carriers will be aggregated.
+ exclude_carriers: []
aggregation_strategies:
generators:
p_nom_max: sum # use "min" for more conservative assumptions
diff --git a/config.tutorial.yaml b/config.tutorial.yaml
index 0cfdc5ab..cf9fd318 100755
--- a/config.tutorial.yaml
+++ b/config.tutorial.yaml
@@ -188,10 +188,11 @@ clustering:
to_substations: false # network is simplified to nodes with positive or negative power injection (i.e. substations or offwind connections)
algorithm: kmeans # choose from: [hac, kmeans]
feature: solar+onwind-time # only for hac. choose from: [solar+onwind-time, solar+onwind-cap, solar-time, solar-cap, solar+offwind-cap] etc.
+ exclude_carriers: []
cluster_network:
algorithm: kmeans
feature: solar+onwind-time
- exclude_carriers: [] # list of carriers which will not be aggregated. If empty, all carriers will be aggregated.
+ exclude_carriers: []
aggregation_strategies:
generators:
p_nom_max: sum # use "min" for more conservative assumptions
diff --git a/doc/configtables/clustering.csv b/doc/configtables/clustering.csv
index 02a7b1fc..1ef6e21b 100644
--- a/doc/configtables/clustering.csv
+++ b/doc/configtables/clustering.csv
@@ -3,11 +3,13 @@ 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’}.",
-cluster_network
+-- 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."
+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."
+-- -- {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."
\ No newline at end of file
diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py
index a392d024..9b0f9377 100644
--- a/scripts/cluster_network.py
+++ b/scripts/cluster_network.py
@@ -393,7 +393,8 @@ if __name__ == "__main__":
for tech in n.generators.carrier.unique()
if tech in snakemake.config['renewable']])
- aggregate_carriers=set(n.carriers.index)-set(snakemake.config["clustering"]["exclude_carriers"])
+ exclude_carriers = snakemake.config["clustering"]["cluster_network"].get("exclude_carriers", [])
+ aggregate_carriers = set(n.generators.carrier) - set(exclude_carriers)
if snakemake.wildcards.clusters.endswith('m'):
n_clusters = int(snakemake.wildcards.clusters[:-1])
aggregate_carriers = snakemake.config["electricity"].get("conventional_carriers")
diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py
index 16726156..b6e0afae 100644
--- a/scripts/simplify_network.py
+++ b/scripts/simplify_network.py
@@ -211,7 +211,7 @@ def _aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
_, generator_strategies = get_aggregation_strategies(aggregation_strategies)
- carriers=set(n.carriers.index)-set(exclude_carriers)
+ carriers = set(n.generators.carrier) - set(exclude_carriers)
generators, generators_pnl = aggregategenerators(
n, busmap, carriers=carriers, custom_strategies=generator_strategies
)
@@ -321,7 +321,7 @@ def simplify_links(n, costs, config, output, aggregation_strategies=dict()):
logger.debug("Collecting all components using the busmap")
- exclude_carriers=config["clustering"]["exclude_carriers"]
+ exclude_carriers = config["clustering"]["simplify_network"].get("exclude_carriers", [])
_aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
aggregation_strategies=aggregation_strategies, exclude_carriers=exclude_carriers)
return n, busmap
@@ -333,7 +333,7 @@ def remove_stubs(n, costs, config, output, aggregation_strategies=dict()):
connection_costs_to_bus = _compute_connection_costs_to_bus(n, busmap, costs, config)
- exclude_carriers=config["clustering"]["exclude_carriers"]
+ exclude_carriers = config["clustering"]["simplify_network"].get("exclude_carriers", [])
_aggregate_and_move_components(n, busmap, connection_costs_to_bus, output,
aggregation_strategies=aggregation_strategies, exclude_carriers=exclude_carriers)
From 85d01bceb0dd87fb0d02648cd70d753450175f62 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 19 Sep 2022 14:34:47 +0000
Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
doc/configtables/clustering.csv | 2 +-
scripts/cluster_network.py | 4 +++-
scripts/simplify_network.py | 10 +++++++---
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/doc/configtables/clustering.csv b/doc/configtables/clustering.csv
index 1ef6e21b..bcab264a 100644
--- a/doc/configtables/clustering.csv
+++ b/doc/configtables/clustering.csv
@@ -12,4 +12,4 @@ 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."
\ No newline at end of file
+-- -- {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."
diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py
index 32e89273..63fec077 100644
--- a/scripts/cluster_network.py
+++ b/scripts/cluster_network.py
@@ -475,7 +475,9 @@ if __name__ == "__main__":
]
)
- exclude_carriers = snakemake.config["clustering"]["cluster_network"].get("exclude_carriers", [])
+ exclude_carriers = snakemake.config["clustering"]["cluster_network"].get(
+ "exclude_carriers", []
+ )
aggregate_carriers = set(n.generators.carrier) - set(exclude_carriers)
if snakemake.wildcards.clusters.endswith("m"):
n_clusters = int(snakemake.wildcards.clusters[:-1])
diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py
index 959c84e8..2c7f8413 100644
--- a/scripts/simplify_network.py
+++ b/scripts/simplify_network.py
@@ -245,7 +245,7 @@ def _aggregate_and_move_components(
_adjust_capital_costs_using_connection_costs(n, connection_costs_to_bus, output)
_, generator_strategies = get_aggregation_strategies(aggregation_strategies)
-
+
carriers = set(n.generators.carrier) - set(exclude_carriers)
generators, generators_pnl = aggregategenerators(
n, busmap, carriers=carriers, custom_strategies=generator_strategies
@@ -377,7 +377,9 @@ def simplify_links(n, costs, config, output, aggregation_strategies=dict()):
logger.debug("Collecting all components using the busmap")
- exclude_carriers = config["clustering"]["simplify_network"].get("exclude_carriers", [])
+ exclude_carriers = config["clustering"]["simplify_network"].get(
+ "exclude_carriers", []
+ )
_aggregate_and_move_components(
n,
@@ -397,7 +399,9 @@ def remove_stubs(n, costs, config, output, aggregation_strategies=dict()):
connection_costs_to_bus = _compute_connection_costs_to_bus(n, busmap, costs, config)
- exclude_carriers = config["clustering"]["simplify_network"].get("exclude_carriers", [])
+ exclude_carriers = config["clustering"]["simplify_network"].get(
+ "exclude_carriers", []
+ )
_aggregate_and_move_components(
n,
From d532424e5db79c8b64760915321457a3471bf4df Mon Sep 17 00:00:00 2001
From: Philipp Glaum
Date: Tue, 20 Sep 2022 08:42:45 +0200
Subject: [PATCH 4/4] update release_notes
---
doc/release_notes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/doc/release_notes.rst b/doc/release_notes.rst
index 0f8e122f..d5016d55 100644
--- a/doc/release_notes.rst
+++ b/doc/release_notes.rst
@@ -14,6 +14,7 @@ Upcoming Release
* Pre-commit CI is now part of the repository's CI.
* The heuristic distribution of today's renewable installations is now enable per default.
* Marginal costs of conventional generators are now taking the plant-specific efficiency into account.
+* Carriers of generators can now be excluded from aggregation in clustering network and simplify network.
PyPSA-Eur 0.6.0 (10th September 2022)
=====================================