diff --git a/config/config.default.yaml b/config/config.default.yaml index cca5018f..5a32e61c 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -579,6 +579,7 @@ clustering: algorithm: kmeans feature: solar+onwind-time exclude_carriers: [] + consider_efficiency_classes: false aggregation_strategies: generators: committable: any diff --git a/config/config.validation.yaml b/config/config.validation.yaml index ff1f87ce..bc0b0048 100644 --- a/config/config.validation.yaml +++ b/config/config.validation.yaml @@ -9,11 +9,9 @@ scenario: ll: # allowed transmission line volume expansion, can be any float >= 1.0 with a prefix v|c (today) or "copt" - v1.0 clusters: # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred - - 37c + - 37 opts: # only relevant for PyPSA-Eur - 'Ept' - sector_opts: # this is where the main scenario settings are - - Co2L0-1H-T-H-B-I-A-solar+p3-dist1 snapshots: start: "2019-01-01" @@ -96,12 +94,17 @@ costs: emission_prices: # in currency per tonne emission, only used with the option Ep co2: 25 +clustering: + simplify_network: + exclude_carriers: [oil, coal, lignite, OCGT, CCGT] + cluster_network: + consider_efficiency_classes: true solving: #tmpdir: "path/to/tmp" options: load_shedding: true - rolling_horizon: true - horizon: 365 + rolling_horizon: false + horizon: 389 overlap: 24 diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index f0fd80eb..65a3c36c 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -461,7 +461,7 @@ if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake - snakemake = mock_snakemake("cluster_network", simpl="", clusters="37c") + snakemake = mock_snakemake("cluster_network", simpl="", clusters="37") configure_logging(snakemake) params = snakemake.params @@ -483,6 +483,23 @@ if __name__ == "__main__": else: n_clusters = int(snakemake.wildcards.clusters) + if params.cluster_network["consider_efficiency_classes"]: + carriers = [] + for c in aggregate_carriers: + gens = n.generators.query("carrier == @c") + low = gens.efficiency.quantile(0.10) + high = gens.efficiency.quantile(0.90) + if low >= high: + carriers += [c] + else: + labels = ["low", "medium", "high"] + suffix = pd.cut( + gens.efficiency, bins=[0, low, high, 1], labels=labels + ).astype(str) + carriers += [f"{c} {label} efficiency" for label in labels] + n.generators.carrier.update(gens.carrier + " " + suffix + " efficiency") + aggregate_carriers = carriers + if n_clusters == len(n.buses): # Fast-path if no clustering is necessary busmap = n.buses.index.to_series() @@ -524,6 +541,11 @@ if __name__ == "__main__": update_p_nom_max(clustering.network) + if params.cluster_network.get("consider_efficiency_classes"): + labels = [f" {label} efficiency" for label in ["low", "medium", "high"]] + nc = clustering.network + nc.generators["carrier"] = nc.generators.carrier.replace(labels, "", regex=True) + clustering.network.meta = dict( snakemake.config, **dict(wildcards=dict(snakemake.wildcards)) )