diff --git a/config.default.yaml b/config.default.yaml index fddd7531..ca2b2a39 100755 --- a/config.default.yaml +++ b/config.default.yaml @@ -256,9 +256,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: [] aggregation_strategies: generators: p_nom_max: sum # use "min" for more conservative assumptions diff --git a/config.tutorial.yaml b/config.tutorial.yaml index 9d802d81..a3ffc2a9 100755 --- a/config.tutorial.yaml +++ b/config.tutorial.yaml @@ -187,9 +187,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: [] 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..bcab264a 100644 --- a/doc/configtables/clustering.csv +++ b/doc/configtables/clustering.csv @@ -3,9 +3,11 @@ 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." diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 935c1e9a..812712bc 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -10,7 +10,7 @@ Release Notes Upcoming Release ================ -* new feature +* Carriers of generators can now be excluded from aggregation in clustering network and simplify network. PyPSA-Eur 0.6.1 (20th September 2022) ===================================== @@ -35,7 +35,6 @@ PyPSA-Eur 0.6.1 (20th September 2022) * The marginal costs of conventional generators are now taking the plant-specific efficiency into account where available. - PyPSA-Eur 0.6.0 (10th September 2022) ===================================== diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index 956bfd97..63fec077 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -475,6 +475,10 @@ if __name__ == "__main__": ] ) + 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( @@ -482,10 +486,8 @@ if __name__ == "__main__": ) 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 3d03567c..2c7f8413 100644 --- a/scripts/simplify_network.py +++ b/scripts/simplify_network.py @@ -232,6 +232,7 @@ def _aggregate_and_move_components( output, aggregate_one_ports={"Load", "StorageUnit"}, aggregation_strategies=dict(), + exclude_carriers=None, ): def replace_components(n, c, df, pnl): n.mremove(c, n.df(c).index) @@ -245,8 +246,9 @@ def _aggregate_and_move_components( _, generator_strategies = get_aggregation_strategies(aggregation_strategies) + carriers = set(n.generators.carrier) - 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) @@ -375,12 +377,17 @@ 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", [] + ) + _aggregate_and_move_components( n, busmap, connection_costs_to_bus, output, aggregation_strategies=aggregation_strategies, + exclude_carriers=exclude_carriers, ) return n, busmap @@ -392,12 +399,17 @@ 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", [] + ) + _aggregate_and_move_components( n, busmap, connection_costs_to_bus, output, aggregation_strategies=aggregation_strategies, + exclude_carriers=exclude_carriers, ) return n, busmap @@ -489,7 +501,7 @@ if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake - snakemake = mock_snakemake("simplify_network", simpl="f") + snakemake = mock_snakemake("simplify_network", simpl="") configure_logging(snakemake) n = pypsa.Network(snakemake.input.network) diff --git a/test/config.test1.yaml b/test/config.test1.yaml index 3684c7fe..15dc8e6e 100755 --- a/test/config.test1.yaml +++ b/test/config.test1.yaml @@ -187,6 +187,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