From 2aa59a39051edb600dbc0c4087ea4f22a36423fe Mon Sep 17 00:00:00 2001 From: huckebrink <68848357+huckebrink@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:19:23 +0200 Subject: [PATCH 1/7] exporting additional costs, and compatibility adjustments (#261) * added export for connection_cost adjustment * removed lambda function from multiprocessing changed true/false_values to lists * removed double import of functools * moved added costs to df column * Update scripts/simplify_network.py Co-authored-by: Leonie Plaga Co-authored-by: Fabian Neumann --- Snakefile | 3 ++- scripts/base_network.py | 10 +++++----- scripts/simplify_network.py | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Snakefile b/Snakefile index 2702fd3d..7f5be34d 100644 --- a/Snakefile +++ b/Snakefile @@ -239,7 +239,8 @@ rule simplify_network: network='networks/elec_s{simpl}.nc', regions_onshore="resources/regions_onshore_elec_s{simpl}.geojson", regions_offshore="resources/regions_offshore_elec_s{simpl}.geojson", - busmap='resources/busmap_elec_s{simpl}.csv' + busmap='resources/busmap_elec_s{simpl}.csv', + connection_costs='resources/connection_costs_s{simpl}.csv' log: "logs/simplify_network/elec_s{simpl}.log" benchmark: "benchmarks/simplify_network/elec_s{simpl}" threads: 1 diff --git a/scripts/base_network.py b/scripts/base_network.py index 778f8dc4..4c2ed2c5 100644 --- a/scripts/base_network.py +++ b/scripts/base_network.py @@ -114,7 +114,7 @@ def _find_closest_links(links, new_links, distance_upper_bound=1.5): def _load_buses_from_eg(): buses = (pd.read_csv(snakemake.input.eg_buses, quotechar="'", - true_values='t', false_values='f', + true_values=['t'], false_values=['f'], dtype=dict(bus_id="str")) .set_index("bus_id") .drop(['station_id'], axis=1) @@ -136,7 +136,7 @@ def _load_buses_from_eg(): def _load_transformers_from_eg(buses): transformers = (pd.read_csv(snakemake.input.eg_transformers, quotechar="'", - true_values='t', false_values='f', + true_values=['t'], false_values=['f'], dtype=dict(transformer_id='str', bus0='str', bus1='str')) .set_index('transformer_id')) @@ -147,7 +147,7 @@ def _load_transformers_from_eg(buses): def _load_converters_from_eg(buses): converters = (pd.read_csv(snakemake.input.eg_converters, quotechar="'", - true_values='t', false_values='f', + true_values=['t'], false_values=['f'], dtype=dict(converter_id='str', bus0='str', bus1='str')) .set_index('converter_id')) @@ -159,7 +159,7 @@ def _load_converters_from_eg(buses): def _load_links_from_eg(buses): - links = (pd.read_csv(snakemake.input.eg_links, quotechar="'", true_values='t', false_values='f', + links = (pd.read_csv(snakemake.input.eg_links, quotechar="'", true_values=['t'], false_values=['f'], dtype=dict(link_id='str', bus0='str', bus1='str', under_construction="bool")) .set_index('link_id')) @@ -249,7 +249,7 @@ def _add_links_from_tyndp(buses, links): def _load_lines_from_eg(buses): - lines = (pd.read_csv(snakemake.input.eg_lines, quotechar="'", true_values='t', false_values='f', + lines = (pd.read_csv(snakemake.input.eg_lines, quotechar="'", true_values=['t'], false_values=['f'], dtype=dict(line_id='str', bus0='str', bus1='str', underground="bool", under_construction="bool")) .set_index('line_id') diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py index 4678f796..c1840760 100644 --- a/scripts/simplify_network.py +++ b/scripts/simplify_network.py @@ -178,6 +178,7 @@ def _compute_connection_costs_to_bus(n, busmap, connection_costs_per_link=None, def _adjust_capital_costs_using_connection_costs(n, connection_costs_to_bus): + connection_costs = {} for tech in connection_costs_to_bus: tech_b = n.generators.carrier == tech costs = n.generators.loc[tech_b, "bus"].map(connection_costs_to_bus[tech]).loc[lambda s: s>0] @@ -185,6 +186,9 @@ def _adjust_capital_costs_using_connection_costs(n, connection_costs_to_bus): n.generators.loc[costs.index, "capital_cost"] += costs logger.info("Displacing {} generator(s) and adding connection costs to capital_costs: {} " .format(tech, ", ".join("{:.0f} Eur/MW/a for `{}`".format(d, b) for b, d in costs.iteritems()))) + connection_costs[tech] = costs + pd.DataFrame(connection_costs).to_csv(snakemake.output.connection_costs) + def _aggregate_and_move_components(n, busmap, connection_costs_to_bus, aggregate_one_ports={"Load", "StorageUnit"}): From 4cc5e49ca85dbef1fcc6e7b7916bf5bed60e2c6d Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 6 Aug 2021 15:43:12 +0200 Subject: [PATCH 2/7] Adapt to new snapshot weightings (#259) * for now use n.snapshot_weightings.generators * require pypsa master; use .objective for Nyears * implement suggestions from code review * add release note --- doc/release_notes.rst | 1 + envs/environment.docs.yaml | 3 ++- envs/environment.yaml | 3 ++- scripts/_helpers.py | 2 +- scripts/add_electricity.py | 2 +- scripts/add_extra_components.py | 2 +- scripts/cluster_network.py | 3 ++- scripts/make_summary.py | 16 +++++++++------- scripts/plot_network.py | 2 +- scripts/prepare_network.py | 3 ++- scripts/simplify_network.py | 3 ++- scripts/solve_network.py | 10 +++++----- 12 files changed, 29 insertions(+), 21 deletions(-) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index b8aaeba2..e35d3cf6 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -24,6 +24,7 @@ Upcoming Release * The ``focus_weights`` are now also considered when pre-clustering in the :mod:`simplify_network` rule [`#241 `_]. * Continuous integration testing switches to Github Actions from Travis CI [`#252 `_]. * Bugfix in :mod:`build_renewable_profile` where offshore wind profiles could no longer be created [`#249 `_]. +* Implements changes to ``n.snapshot_weightings`` in upcoming PyPSA version (cf. `PyPSA/PyPSA/#227 `_) [`#259 `_]. * Bugfix: Lower expansion limit of extendable carriers is now set to the existing capacity, i.e. ``p_nom_min = p_nom`` (0 before). Simultaneously, the upper limit (``p_nom_max``) is now the maximum of the installed capacity (``p_nom``) and the previous estimate based on land availability (``p_nom_max``) [`#260 `_]. PyPSA-Eur 0.3.0 (7th December 2020) diff --git a/envs/environment.docs.yaml b/envs/environment.docs.yaml index 772583d4..9edf0118 100755 --- a/envs/environment.docs.yaml +++ b/envs/environment.docs.yaml @@ -8,7 +8,7 @@ channels: dependencies: - python<=3.7 - pip - - pypsa>=0.17.1 + #- pypsa>=0.17.1 - atlite>=0.2.2 - dask<=2021.3.1 # until https://github.com/dask/dask/issues/7583 is solved - pre-commit @@ -27,6 +27,7 @@ dependencies: - descartes - pip: + - git+https://github.com/pypsa/pypsa.git#egg=pypsa - vresutils==0.3.1 - sphinx - sphinx_rtd_theme diff --git a/envs/environment.yaml b/envs/environment.yaml index 979c83df..039bfd63 100644 --- a/envs/environment.yaml +++ b/envs/environment.yaml @@ -12,7 +12,7 @@ dependencies: - pip - mamba # esp for windows build - - pypsa>=0.17.1 + #- pypsa>=0.17.1 - atlite>=0.2.4 - dask<=2021.3.1 # until https://github.com/dask/dask/issues/7583 is solved @@ -54,5 +54,6 @@ dependencies: - country_converter - pip: + - git+https://github.com/pypsa/pypsa.git#egg=pypsa - vresutils==0.3.1 - tsam>=1.1.0 diff --git a/scripts/_helpers.py b/scripts/_helpers.py index 0c6a4658..ae28f808 100644 --- a/scripts/_helpers.py +++ b/scripts/_helpers.py @@ -119,7 +119,7 @@ def load_network_for_plots(fn, tech_costs, config, combine_hydro_ps=True): # bus_carrier = n.storage_units.bus.map(n.buses.carrier) # n.storage_units.loc[bus_carrier == "heat","carrier"] = "water tanks" - Nyears = n.snapshot_weightings.sum() / 8760. + Nyears = n.snapshot_weightings.objective.sum() / 8760. costs = load_costs(Nyears, tech_costs, config['costs'], config['electricity']) update_transmission_costs(n, costs) diff --git a/scripts/add_electricity.py b/scripts/add_electricity.py index bf80e8aa..8f721652 100755 --- a/scripts/add_electricity.py +++ b/scripts/add_electricity.py @@ -561,7 +561,7 @@ if __name__ == "__main__": configure_logging(snakemake) n = pypsa.Network(snakemake.input.base_network) - Nyears = n.snapshot_weightings.sum() / 8760. + Nyears = n.snapshot_weightings.objective.sum() / 8760. costs = load_costs(Nyears) ppl = load_powerplants() diff --git a/scripts/add_extra_components.py b/scripts/add_extra_components.py index 946c4433..ae581382 100644 --- a/scripts/add_extra_components.py +++ b/scripts/add_extra_components.py @@ -197,7 +197,7 @@ if __name__ == "__main__": configure_logging(snakemake) n = pypsa.Network(snakemake.input.network) - Nyears = n.snapshot_weightings.sum() / 8760. + Nyears = n.snapshot_weightings.objective.sum() / 8760. costs = load_costs(Nyears, tech_costs=snakemake.input.tech_costs, config=snakemake.config['costs'], elec_config=snakemake.config['electricity']) diff --git a/scripts/cluster_network.py b/scripts/cluster_network.py index 3503bd9b..d74745d0 100644 --- a/scripts/cluster_network.py +++ b/scripts/cluster_network.py @@ -357,7 +357,8 @@ if __name__ == "__main__": clustering = pypsa.networkclustering.Clustering(n, busmap, linemap, linemap, pd.Series(dtype='O')) else: line_length_factor = snakemake.config['lines']['length_factor'] - hvac_overhead_cost = (load_costs(n.snapshot_weightings.sum()/8760, + Nyears = n.snapshot_weightings.objective.sum()/8760 + hvac_overhead_cost = (load_costs(Nyears, tech_costs=snakemake.input.tech_costs, config=snakemake.config['costs'], elec_config=snakemake.config['electricity']) diff --git a/scripts/make_summary.py b/scripts/make_summary.py index f815d5f0..e26db34c 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -111,15 +111,15 @@ def calculate_costs(n, label, costs): costs.loc[idx[raw_index],label] = capital_costs_grouped.values if c.name == "Link": - p = c.pnl.p0.multiply(n.snapshot_weightings,axis=0).sum() + p = c.pnl.p0.multiply(n.snapshot_weightings.generators,axis=0).sum() elif c.name == "Line": continue elif c.name == "StorageUnit": - p_all = c.pnl.p.multiply(n.snapshot_weightings,axis=0) + p_all = c.pnl.p.multiply(n.snapshot_weightings.generators,axis=0) p_all[p_all < 0.] = 0. p = p_all.sum() else: - p = c.pnl.p.multiply(n.snapshot_weightings,axis=0).sum() + p = c.pnl.p.multiply(n.snapshot_weightings.generators,axis=0).sum() marginal_costs = p*c.df.marginal_cost @@ -144,10 +144,12 @@ def calculate_energy(n, label, energy): for c in n.iterate_components(n.one_port_components|n.branch_components): - if c.name in n.one_port_components: - c_energies = c.pnl.p.multiply(n.snapshot_weightings,axis=0).sum().multiply(c.df.sign).groupby(c.df.carrier).sum() + if c.name in {'Generator', 'Load', 'ShuntImpedance'}: + c_energies = c.pnl.p.multiply(n.snapshot_weightings.generators,axis=0).sum().multiply(c.df.sign).groupby(c.df.carrier).sum() + elif c.name in {'StorageUnit', 'Store'}: + c_energies = c.pnl.p.multiply(n.snapshot_weightings.stores,axis=0).sum().multiply(c.df.sign).groupby(c.df.carrier).sum() else: - c_energies = (-c.pnl.p1.multiply(n.snapshot_weightings,axis=0).sum() - c.pnl.p0.multiply(n.snapshot_weightings,axis=0).sum()).groupby(c.df.carrier).sum() + c_energies = (-c.pnl.p1.multiply(n.snapshot_weightings.generators,axis=0).sum() - c.pnl.p0.multiply(n.snapshot_weightings.generators,axis=0).sum()).groupby(c.df.carrier).sum() energy = include_in_summary(energy, [c.list_name], label, c_energies) @@ -400,7 +402,7 @@ def make_summaries(networks_dict, country='all'): if country != 'all': n = n[n.buses.country == country] - Nyears = n.snapshot_weightings.sum() / 8760. + Nyears = n.snapshot_weightings.objective.sum() / 8760. costs = load_costs(Nyears, snakemake.input[0], snakemake.config['costs'], snakemake.config['electricity']) update_transmission_costs(n, costs, simple_hvdc_costs=False) diff --git a/scripts/plot_network.py b/scripts/plot_network.py index 810f6284..61a2ac9b 100755 --- a/scripts/plot_network.py +++ b/scripts/plot_network.py @@ -196,7 +196,7 @@ def plot_total_energy_pie(n, ax=None): def plot_total_cost_bar(n, ax=None): if ax is None: ax = plt.gca() - total_load = (n.snapshot_weightings * n.loads_t.p.sum(axis=1)).sum() + total_load = (n.snapshot_weightings.generators * n.loads_t.p.sum(axis=1)).sum() tech_colors = opts['tech_colors'] def split_costs(n): diff --git a/scripts/prepare_network.py b/scripts/prepare_network.py index 4caa5703..86afef2f 100755 --- a/scripts/prepare_network.py +++ b/scripts/prepare_network.py @@ -150,6 +150,7 @@ def average_every_nhours(n, offset): return m + def apply_time_segmentation(n, segments): logger.info(f"Aggregating time series to {segments} segments.") try: @@ -223,7 +224,7 @@ if __name__ == "__main__": opts = snakemake.wildcards.opts.split('-') n = pypsa.Network(snakemake.input[0]) - Nyears = n.snapshot_weightings.sum() / 8760. + Nyears = n.snapshot_weightings.objective.sum() / 8760. set_line_s_max_pu(n) diff --git a/scripts/simplify_network.py b/scripts/simplify_network.py index c1840760..f37899b9 100644 --- a/scripts/simplify_network.py +++ b/scripts/simplify_network.py @@ -141,7 +141,8 @@ def simplify_network_to_380(n): def _prepare_connection_costs_per_link(n): if n.links.empty: return {} - costs = load_costs(n.snapshot_weightings.sum() / 8760, snakemake.input.tech_costs, + Nyears = n.snapshot_weightings.objective.sum() / 8760 + costs = load_costs(Nyears, snakemake.input.tech_costs, snakemake.config['costs'], snakemake.config['electricity']) connection_costs_per_link = {} diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 24cd0464..f8146b43 100755 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -127,7 +127,7 @@ def prepare_network(n, solve_opts): if solve_opts.get('nhours'): nhours = solve_opts['nhours'] n.set_snapshots(n.snapshots[:nhours]) - n.snapshot_weightings[:] = 8760./nhours + n.snapshot_weightings[:] = 8760. / nhours return n @@ -174,16 +174,16 @@ def add_EQ_constraints(n, o, scaling=1e-1): ggrouper = n.generators.bus lgrouper = n.loads.bus sgrouper = n.storage_units.bus - load = n.snapshot_weightings @ \ + load = n.snapshot_weightings.generators @ \ n.loads_t.p_set.groupby(lgrouper, axis=1).sum() - inflow = n.snapshot_weightings @ \ + inflow = n.snapshot_weightings.stores @ \ n.storage_units_t.inflow.groupby(sgrouper, axis=1).sum() inflow = inflow.reindex(load.index).fillna(0.) rhs = scaling * ( level * load - inflow ) - lhs_gen = linexpr((n.snapshot_weightings * scaling, + lhs_gen = linexpr((n.snapshot_weightings.generators * scaling, get_var(n, "Generator", "p").T) ).T.groupby(ggrouper, axis=1).apply(join_exprs) - lhs_spill = linexpr((-n.snapshot_weightings * scaling, + lhs_spill = linexpr((-n.snapshot_weightings.stores * scaling, get_var(n, "StorageUnit", "spill").T) ).T.groupby(sgrouper, axis=1).apply(join_exprs) lhs_spill = lhs_spill.reindex(lhs_gen.index).fillna("") From 7a8ef1a2d44a77de240bb7144438dd35f51bff6f Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 9 Aug 2021 14:37:51 +0200 Subject: [PATCH 3/7] Add tabula-py to dependencies (for PyPSA-Eur-Sec) --- envs/environment.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/envs/environment.yaml b/envs/environment.yaml index 039bfd63..3dcbeea0 100644 --- a/envs/environment.yaml +++ b/envs/environment.yaml @@ -52,6 +52,7 @@ dependencies: - tqdm - pytz - country_converter + - tabula-py - pip: - git+https://github.com/pypsa/pypsa.git#egg=pypsa From b82c55543bc345581a5205e95e8da6499c8ce70e Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 13 Aug 2021 10:11:35 +0200 Subject: [PATCH 4/7] Readthedocs documentation with pip (#267) * Use pip with requirements.txt file for setting up doc environment * Try w/o cartopy * Try w/o cartopy take 2 * Try w/o cartopy take 3 * try pip * try pip ii * python 3.8 * fix links * remove conda docs and fix line references * remove conda on .readthedocs.yml * correct ambiguous line reference Co-authored-by: Jonas Hoersch --- .readthedocs.yml | 7 ++++-- doc/configuration.rst | 47 +++++++++++++++++++++++++------------- doc/requirements.txt | 17 ++++++++++++++ envs/environment.docs.yaml | 33 -------------------------- 4 files changed, 53 insertions(+), 51 deletions(-) create mode 100644 doc/requirements.txt delete mode 100755 envs/environment.docs.yaml diff --git a/.readthedocs.yml b/.readthedocs.yml index 173d21d7..d6b81a40 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,5 +4,8 @@ version: 2 -conda: - environment: envs/environment.docs.yaml +python: + version: 3.8 + install: + - requirements: doc/requirements.txt + system_packages: true diff --git a/doc/configuration.rst b/doc/configuration.rst index a75669cd..a6683046 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -50,7 +50,8 @@ An exemplary dependency graph (starting from the simplification rules) then look .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 14-18 + :start-at: scenario: + :end-before: countries: .. csv-table:: :header-rows: 1 @@ -66,7 +67,8 @@ Specifies the temporal range to build an energy system model for as arguments to .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 22-25 + :start-at: snapshots: + :end-before: enable: .. csv-table:: :header-rows: 1 @@ -80,7 +82,8 @@ Specifies the temporal range to build an energy system model for as arguments to .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 36-60 + :start-at: electricity: + :end-before: atlite: .. csv-table:: :header-rows: 1 @@ -117,7 +120,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 77-94 + :start-at: renewable: + :end-before: offwind-ac: .. csv-table:: :header-rows: 1 @@ -129,7 +133,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 77,95-107 + :start-at: offwind-ac: + :end-before: offwind-dc: .. csv-table:: :header-rows: 1 @@ -141,7 +146,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 77,108-121 + :start-at: offwind-dc: + :end-before: solar: .. csv-table:: :header-rows: 1 @@ -153,7 +159,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 77,122-141 + :start-at: solar: + :end-before: hydro: .. csv-table:: :header-rows: 1 @@ -165,7 +172,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 77,142-147 + :start-at: hydro: + :end-before: lines: .. csv-table:: :header-rows: 1 @@ -179,7 +187,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 149-157 + :start-at: lines: + :end-before: links: .. csv-table:: :header-rows: 1 @@ -193,7 +202,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 159-163 + :start-at: links: + :end-before: transformers: .. csv-table:: :header-rows: 1 @@ -207,7 +217,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 165-168 + :start-at: transformers: + :end-before: load: .. csv-table:: :header-rows: 1 @@ -221,7 +232,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 170-176 + :start-at: load: + :end-before: costs: .. csv-table:: :header-rows: 1 @@ -235,7 +247,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 178-190 + :start-after: scaling_factor: + :end-before: solving: .. csv-table:: :header-rows: 1 @@ -256,7 +269,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 192-202 + :start-at: solving: + :end-before: solver: .. csv-table:: :header-rows: 1 @@ -268,7 +282,8 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 192,203-219 + :start-at: solver: + :end-before: plotting: .. csv-table:: :header-rows: 1 @@ -282,7 +297,7 @@ Define and specify the ``atlite.Cutout`` used for calculating renewable potentia .. literalinclude:: ../config.default.yaml :language: yaml - :lines: 221-299 + :start-at: plotting: .. csv-table:: :header-rows: 1 diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 00000000..890eda95 --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,17 @@ +sphinx +sphinx_rtd_theme + +pypsa +vresutils>=0.3.1 +powerplantmatching>=0.4.8 +atlite>=0.2.2 +dask<=2021.3.1 + +# cartopy +scikit-learn +pycountry +pyyaml +seaborn +memory_profiler +tables +descartes \ No newline at end of file diff --git a/envs/environment.docs.yaml b/envs/environment.docs.yaml deleted file mode 100755 index 9edf0118..00000000 --- a/envs/environment.docs.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-FileCopyrightText: : 2017-2020 The PyPSA-Eur Authors -# -# SPDX-License-Identifier: GPL-3.0-or-later - -name: pypsa-eur-docs -channels: - - conda-forge -dependencies: - - python<=3.7 - - pip - #- pypsa>=0.17.1 - - atlite>=0.2.2 - - dask<=2021.3.1 # until https://github.com/dask/dask/issues/7583 is solved - - pre-commit - - # Dependencies of the workflow itself - - scikit-learn - - pycountry - - seaborn - - memory_profiler - - yaml - - pytables - - powerplantmatching>=0.4.8 - - # GIS dependencies have to come all from conda-forge - - cartopy - - descartes - - - pip: - - git+https://github.com/pypsa/pypsa.git#egg=pypsa - - vresutils==0.3.1 - - sphinx - - sphinx_rtd_theme From 0fa3888b0ebdf393208483ce8c4e62b69898b599 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 13 Aug 2021 10:15:06 +0200 Subject: [PATCH 5/7] restore REUSE compliance [skip ci] --- doc/requirements.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/requirements.txt b/doc/requirements.txt index 890eda95..2b461718 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: : 2019-2021 The PyPSA-Eur Authors +# +# SPDX-License-Identifier: CC0-1.0 + sphinx sphinx_rtd_theme From 400317d0622ca67e4ff02d00af96d739ccd3b354 Mon Sep 17 00:00:00 2001 From: martacki Date: Mon, 16 Aug 2021 17:53:56 +0200 Subject: [PATCH 6/7] update plot_network and make_summary scripts to latest pypsa/-eur versions --- Snakefile | 1 - scripts/make_summary.py | 2 +- scripts/plot_network.py | 33 ++++++++++++++++++++------------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Snakefile b/Snakefile index 7f5be34d..2f8eea3b 100644 --- a/Snakefile +++ b/Snakefile @@ -361,7 +361,6 @@ def input_make_summary(w): ll = w.ll return ([COSTS] + expand("results/networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc", - network=w.network, ll=ll, **{k: config["scenario"][k] if getattr(w, k) == "all" else getattr(w, k) for k in ["simpl", "clusters", "opts"]})) diff --git a/scripts/make_summary.py b/scripts/make_summary.py index e26db34c..53482c48 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -444,7 +444,7 @@ if __name__ == "__main__": ll = [snakemake.wildcards.ll] networks_dict = {(simpl,clusters,l,opts) : - os.path.join(network_dir, f'{snakemake.wildcards.network}_s{simpl}_' + os.path.join(network_dir, f'elec_s{simpl}_' f'{clusters}_ec_l{l}_{opts}.nc') for simpl in expand_from_wildcard("simpl") for clusters in expand_from_wildcard("clusters") diff --git a/scripts/plot_network.py b/scripts/plot_network.py index 61a2ac9b..571f5bad 100755 --- a/scripts/plot_network.py +++ b/scripts/plot_network.py @@ -88,36 +88,43 @@ def plot_map(n, ax=None, attribute='p_nom', opts={}): # bus_sizes = n.generators_t.p.sum().loc[n.generators.carrier == "load"].groupby(n.generators.bus).sum() bus_sizes = pd.concat((n.generators.query('carrier != "load"').groupby(['bus', 'carrier']).p_nom_opt.sum(), n.storage_units.groupby(['bus', 'carrier']).p_nom_opt.sum())) - line_widths_exp = dict(Line=n.lines.s_nom_opt, Link=n.links.p_nom_opt) - line_widths_cur = dict(Line=n.lines.s_nom_min, Link=n.links.p_nom_min) + line_widths_exp = n.lines.s_nom_opt + line_widths_cur = n.lines.s_nom_min + link_widths_exp = n.links.p_nom_opt + link_widths_cur = n.links.p_nom_min else: raise 'plotting of {} has not been implemented yet'.format(attribute) line_colors_with_alpha = \ - dict(Line=(line_widths_cur['Line'] / n.lines.s_nom > 1e-3) - .map({True: line_colors['cur'], False: to_rgba(line_colors['cur'], 0.)}), - Link=(line_widths_cur['Link'] / n.links.p_nom > 1e-3) + ((line_widths_cur / n.lines.s_nom > 1e-3) + .map({True: line_colors['cur'], False: to_rgba(line_colors['cur'], 0.)})) + link_colors_with_alpha = \ + ((link_widths_cur / n.links.p_nom > 1e-3) .map({True: line_colors['cur'], False: to_rgba(line_colors['cur'], 0.)})) + ## FORMAT linewidth_factor = opts['map'][attribute]['linewidth_factor'] bus_size_factor = opts['map'][attribute]['bus_size_factor'] ## PLOT - n.plot(line_widths=pd.concat(line_widths_exp)/linewidth_factor, - line_colors=dict(Line=line_colors['exp'], Link=line_colors['exp']), + n.plot(line_widths=line_widths_exp/linewidth_factor, + link_widths=link_widths_exp/linewidth_factor, + line_colors=line_colors['exp'], + link_colors=line_colors['exp'], bus_sizes=bus_sizes/bus_size_factor, bus_colors=tech_colors, boundaries=map_boundaries, - geomap=True, + color_geomap=True, geomap=True, ax=ax) - n.plot(line_widths=pd.concat(line_widths_cur)/linewidth_factor, - line_colors=pd.concat(line_colors_with_alpha), + n.plot(line_widths=line_widths_cur/linewidth_factor, + link_widths=link_widths_cur/linewidth_factor, + line_colors=line_colors_with_alpha, + link_colors=link_colors_with_alpha, bus_sizes=0, - bus_colors=tech_colors, boundaries=map_boundaries, - geomap=False, + color_geomap=True, geomap=False, ax=ax) ax.set_aspect('equal') ax.axis('off') @@ -138,7 +145,7 @@ def plot_map(n, ax=None, attribute='p_nom', opts={}): loc="upper left", bbox_to_anchor=(0.24, 1.01), frameon=False, labelspacing=0.8, handletextpad=1.5, - title='Transmission Exist./Exp. ') + title='Transmission Exp./Exist. ') ax.add_artist(l1_1) handles = [] From 1c173567b5fdb6c4ebdc2ff1ccb802fc95439879 Mon Sep 17 00:00:00 2001 From: Martha Frysztacki Date: Wed, 18 Aug 2021 10:38:51 +0200 Subject: [PATCH 7/7] solve_operations_network: include optimized stores to operation (#269) * remove stores-buses from load generators * include optimized stores to operation network * add release notes * Update doc/release_notes.rst Co-authored-by: Fabian Neumann * Update doc/release_notes.rst Co-authored-by: Fabian Neumann * Update release_notes.rst * Update scripts/solve_network.py Co-authored-by: Fabian Neumann --- doc/release_notes.rst | 2 ++ scripts/solve_network.py | 5 +++-- scripts/solve_operations_network.py | 13 +++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index e35d3cf6..af9a58f6 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -26,6 +26,8 @@ Upcoming Release * Bugfix in :mod:`build_renewable_profile` where offshore wind profiles could no longer be created [`#249 `_]. * Implements changes to ``n.snapshot_weightings`` in upcoming PyPSA version (cf. `PyPSA/PyPSA/#227 `_) [`#259 `_]. * Bugfix: Lower expansion limit of extendable carriers is now set to the existing capacity, i.e. ``p_nom_min = p_nom`` (0 before). Simultaneously, the upper limit (``p_nom_max``) is now the maximum of the installed capacity (``p_nom``) and the previous estimate based on land availability (``p_nom_max``) [`#260 `_]. +* Bugfix: Solving an operations network now includes optimized store capacities as well. Before only lines, links, generators and storage units were considered. +* Bugfix: With ``load_shedding: true`` in the solving options of ``config.yaml`` load shedding generators are only added at the AC buses, excluding buses for H2 and battery stores. PyPSA-Eur 0.3.0 (7th December 2020) ================================== diff --git a/scripts/solve_network.py b/scripts/solve_network.py index f8146b43..d874d335 100755 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -101,8 +101,9 @@ def prepare_network(n, solve_opts): if solve_opts.get('load_shedding'): n.add("Carrier", "Load") - n.madd("Generator", n.buses.index, " load", - bus=n.buses.index, + buses_i = n.buses.query("carrier == 'AC'").index + n.madd("Generator", buses_i, " load", + bus=buses_i, carrier='load', sign=1e-3, # Adjust sign to measure p and p_nom in kW instead of MW marginal_cost=1e2, # Eur/kWh diff --git a/scripts/solve_operations_network.py b/scripts/solve_operations_network.py index b698c2f1..9f97754a 100644 --- a/scripts/solve_operations_network.py +++ b/scripts/solve_operations_network.py @@ -81,10 +81,15 @@ def set_parameters_from_optimized(n, n_optim): n_optim.generators['p_nom_opt'].reindex(gen_extend_i, fill_value=0.) n.generators.loc[gen_extend_i, 'p_nom_extendable'] = False - stor_extend_i = n.storage_units.index[n.storage_units.p_nom_extendable] - n.storage_units.loc[stor_extend_i, 'p_nom'] = \ - n_optim.storage_units['p_nom_opt'].reindex(stor_extend_i, fill_value=0.) - n.storage_units.loc[stor_extend_i, 'p_nom_extendable'] = False + stor_units_extend_i = n.storage_units.index[n.storage_units.p_nom_extendable] + n.storage_units.loc[stor_units_extend_i, 'p_nom'] = \ + n_optim.storage_units['p_nom_opt'].reindex(stor_units_extend_i, fill_value=0.) + n.storage_units.loc[stor_units_extend_i, 'p_nom_extendable'] = False + + stor_extend_i = n.stores.index[n.stores.e_nom_extendable] + n.stores.loc[stor_extend_i, 'e_nom'] = \ + n_optim.stores['e_nom_opt'].reindex(stor_extend_i, fill_value=0.) + n.stores.loc[stor_extend_i, 'e_nom_extendable'] = False return n