From 910d0c26d26e427417a273822da5d4357a9069a2 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Fri, 3 Mar 2023 14:59:13 +0100 Subject: [PATCH 01/20] Add function to calculate system costs in Germany --- etrago/tools/calc_results.py | 157 +++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index b12dd79bf..17fe163a5 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -204,6 +204,163 @@ def calc_marginal_cost(self): marginal_cost = gen + link + stor return marginal_cost +def german_network(self): + """Cut out all network components in Germany + + Returns + ------- + new_network : pypsa.Network + Network with all components in Germany + + """ + keep_cntr = ["DE"] + new_idx = self.network.buses[self.network.buses.country.isin(keep_cntr)].index + + new_network = self.network.copy() + + # drop components of other countries + new_network.mremove( + "Bus", + new_network.buses[~new_network.buses.index.isin(new_idx)].index) + + new_network.mremove( + "Line", + new_network.lines[~new_network.lines.index.isin( + new_network.lines[ + ( + new_network.lines.bus0.isin(new_idx) + & new_network.lines.bus1.isin(new_idx) + ) + ].index)].index) + new_network.mremove( + "Link", + new_network.links[~new_network.links.index.isin( + new_network.links[ + ( + new_network.links.bus0.isin(new_idx) + & new_network.links.bus1.isin(new_idx) + ) + ].index)].index) + + new_network.mremove( + "Transformer", + new_network.transformers[~new_network.transformers.index.isin( + new_network.transformers[ + ( + new_network.transformers.bus0.isin(new_idx) + & new_network.transformers.bus1.isin(new_idx) + ) + ].index)].index) + + new_network.mremove( + "Generator", + new_network.generators[~new_network.generators.index.isin( + new_network.generators[ + new_network.generators.bus.isin(new_idx) + ].index)].index) + + new_network.mremove( + "Load", + new_network.loads[~new_network.loads.index.isin( + new_network.loads[ + new_network.loads.bus.isin(new_idx) + ].index)].index) + + new_network.mremove( + "Store", + new_network.stores[~new_network.stores.index.isin( + new_network.stores[ + new_network.stores.bus.isin(new_idx) + ].index)].index) + + new_network.mremove( + "StorageUnit", + new_network.storage_units[~new_network.storage_units.index.isin( + new_network.storage_units[ + new_network.storage_units.bus.isin(new_idx) + ].index)].index) + + return new_network + + +def system_costs_germany(self): + """Calculte system costs for Germany + + Returns + ------- + marginal_cost : float + Marginal costs for dispatch in Germany + invest_cost : float + Annualized investment costs for components in Germany + import_costs : float + Costs for energy imported to Germany minus costs for exports + + """ + + network_de = self.german_network + + marginal_cost = 0 + invest_cost = 0 + + for c in network_de.iterate_components(): + if c.name in ["Store"]: + value = "e" + elif c.name in ["Line", "Transformer"]: + value = "s" + else: + value = "p" + if c.name in network_de.one_port_components: + if "marginal_cost" in c.df.columns: + marginal_cost += c.pnl.p.mul(c.df.marginal_cost).mul( + network_de.snapshot_weightings.generators, axis=0).sum().sum() + + else: + if "marginal_cost" in c.df.columns: + marginal_cost += c.pnl.p0.mul(c.df.marginal_cost).mul( + network_de.snapshot_weightings.generators, axis=0).sum().sum() + if not c.name in ["Bus", "Load", "LineType", "TransformerType", "Carrier"]: + invest_cost += (( + c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_opt"] - + c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_min"] + )*c.df[c.df[f"{value}_nom_extendable"]]["capital_cost"]).sum() + + # import and its costs + links_export = self.network.links[( + self.network.links.bus0.isin(network_de.buses.index.values) & ~( + self.network.links.bus1.isin(network_de.buses.index.values)) + )] + + export_positive = self.network.links_t.p0[links_export.index].clip(lower=0).mul( + self.network.snapshot_weightings.generators, axis=0).mul( + self.network.buses_t.marginal_price[links_export.bus1].values, + ).sum().sum() + + export_negative = self.network.links_t.p0[links_export.index].clip(upper=0).mul( + self.network.snapshot_weightings.generators, axis=0).mul( + self.network.buses_t.marginal_price[links_export.bus1].values, + ).mul(-1).sum().sum() + + links_import = self.network.links[( + self.network.links.bus1.isin(network_de.buses.index.values) & ~( + self.network.links.bus0.isin(network_de.buses.index.values)) + ) + ] + + import_positive = self.network.links_t.p0[links_import.index].clip(lower=0).mul( + self.network.snapshot_weightings.generators, axis=0).mul( + self.network.buses_t.marginal_price[links_import.bus1].values, + ).sum().sum() + + import_negative = self.network.links_t.p0[links_import.index].clip(upper=0).mul( + self.network.snapshot_weightings.generators, axis=0).mul( + self.network.buses_t.marginal_price[links_import.bus1].values, + ).mul(-1).sum().sum() + + import_costs = export_negative + import_positive - export_positive - import_negative + + return marginal_cost, invest_cost, import_costs + + def calc_etrago_results(self): """ Function that calculates main results of grid optimization and adds them to Etrago object. From 34b9cb39ec3305bfb4d57d000e0e0a29742b4724 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Fri, 3 Mar 2023 15:00:05 +0100 Subject: [PATCH 02/20] Apply black and isort --- etrago/tools/calc_results.py | 793 +++++++++++++++++++++-------------- 1 file changed, 471 insertions(+), 322 deletions(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index 17fe163a5..c25289705 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -22,187 +22,221 @@ calc_results.py defines methods to calculate results of eTraGo """ import os -if 'READTHEDOCS' not in os.environ: - import time + +if "READTHEDOCS" not in os.environ: import logging + import time - import pandas as pd import numpy as np + import pandas as pd logger = logging.getLogger(__name__) -__copyright__ = ("Flensburg University of Applied Sciences, " - "Europa-Universität Flensburg, " - "Centre for Sustainable Energy Systems, " - "DLR-Institute for Networked Energy Systems") +__copyright__ = ( + "Flensburg University of Applied Sciences, " + "Europa-Universität Flensburg, " + "Centre for Sustainable Energy Systems, " + "DLR-Institute for Networked Energy Systems" +) __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" __author__ = "ulfmueller, s3pp, wolfbunke, mariusves, lukasol" def _calc_storage_expansion(self): - """ Function that calulates storage expansion in MW + """Function that calulates storage expansion in MW - Returns - ------- - float - storage expansion in MW + Returns + ------- + float + storage expansion in MW + + """ + return ( + ( + self.network.storage_units.p_nom_opt + - self.network.storage_units.p_nom_min + )[self.network.storage_units.p_nom_extendable] + .groupby(self.network.storage_units.carrier) + .sum() + ) - """ - return (self.network.storage_units.p_nom_opt - - self.network.storage_units.p_nom_min - )[self.network.storage_units.p_nom_extendable]\ - .groupby(self.network.storage_units.carrier).sum() def _calc_store_expansion(self): - """ Function that calulates store expansion in MW + """Function that calulates store expansion in MW - Returns - ------- - float - store expansion in MW + Returns + ------- + float + store expansion in MW + + """ + return (self.network.stores.e_nom_opt - self.network.stores.e_nom_min)[ + self.network.stores.e_nom_extendable + ] - """ - return (self.network.stores.e_nom_opt - - self.network.stores.e_nom_min - )[self.network.stores.e_nom_extendable] def _calc_sectorcoupling_link_expansion(self): - """ Function that calulates expansion of sectorcoupling links in MW + """Function that calulates expansion of sectorcoupling links in MW - Returns - ------- - float - link expansion in MW (differentiating between technologies) + Returns + ------- + float + link expansion in MW (differentiating between technologies) - """ - ext_links = self.network.links[self.network.links.p_nom_extendable] + """ + ext_links = self.network.links[self.network.links.p_nom_extendable] + + links = [0, 0, 0, 0] - links = [0, 0, 0, 0] + l1 = ext_links[ext_links.carrier == "H2_to_power"] + l2 = ext_links[ext_links.carrier == "power_to_H2"] + l3 = ext_links[ext_links.carrier == "H2_to_CH4"] + l4 = ext_links[ext_links.carrier == "CH4_to_H2"] - l1 = ext_links[ext_links.carrier=='H2_to_power'] - l2 = ext_links[ext_links.carrier=='power_to_H2'] - l3 = ext_links[ext_links.carrier=='H2_to_CH4'] - l4 = ext_links[ext_links.carrier=='CH4_to_H2'] + links[0] = (l1.p_nom_opt - l1.p_nom_min).sum() + links[1] = (l2.p_nom_opt - l2.p_nom_min).sum() + links[2] = (l3.p_nom_opt - l3.p_nom_min).sum() + links[3] = (l4.p_nom_opt - l4.p_nom_min).sum() - links[0] = (l1.p_nom_opt-l1.p_nom_min).sum() - links[1] = (l2.p_nom_opt-l2.p_nom_min).sum() - links[2] = (l3.p_nom_opt-l3.p_nom_min).sum() - links[3] = (l4.p_nom_opt-l4.p_nom_min).sum() + return links - return links def _calc_network_expansion(self): - """ Function that calulates electrical network expansion in MW + """Function that calulates electrical network expansion in MW - Returns - ------- - float - network expansion (AC lines and DC links) in MW + Returns + ------- + float + network expansion (AC lines and DC links) in MW - """ + """ - network = self.network + network = self.network - lines = (network.lines.s_nom_opt - - network.lines.s_nom_min - )[network.lines.s_nom_extendable] + lines = (network.lines.s_nom_opt - network.lines.s_nom_min)[ + network.lines.s_nom_extendable + ] - ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] + ext_links = network.links[network.links.p_nom_extendable] + ext_dc_lines = ext_links[ext_links.carrier == "DC"] + + dc_links = ext_dc_lines.p_nom_opt - ext_dc_lines.p_nom_min - dc_links = (ext_dc_lines.p_nom_opt - - ext_dc_lines.p_nom_min) + return lines, dc_links - return lines, dc_links def calc_investment_cost(self): - """ Function that calulates overall annualized investment costs. + """Function that calulates overall annualized investment costs. - Returns - ------- - network_costs : float - Investments in line expansion (AC+DC) - link_costs : float - Investments in sectorcoupling link expansion - stor_costs : float - Investments in storage and store expansion + Returns + ------- + network_costs : float + Investments in line expansion (AC+DC) + link_costs : float + Investments in sectorcoupling link expansion + stor_costs : float + Investments in storage and store expansion - """ - network = self.network + """ + network = self.network - # electrical grid: AC lines, DC lines + # electrical grid: AC lines, DC lines - network_costs = [0, 0] + network_costs = [0, 0] - ext_lines = network.lines[network.lines.s_nom_extendable] - ext_trafos = network.transformers[network.transformers.s_nom_extendable] - ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] + ext_lines = network.lines[network.lines.s_nom_extendable] + ext_trafos = network.transformers[network.transformers.s_nom_extendable] + ext_links = network.links[network.links.p_nom_extendable] + ext_dc_lines = ext_links[ext_links.carrier == "DC"] + + if not ext_lines.empty: + network_costs[0] = ( + (ext_lines.s_nom_opt - ext_lines.s_nom_min) + * ext_lines.capital_cost + ).sum() - if not ext_lines.empty: - network_costs[0] = ((ext_lines.s_nom_opt-ext_lines.s_nom_min - )*ext_lines.capital_cost).sum() + if not ext_trafos.empty: + network_costs[0] = ( + network_costs[0] + + ( + (ext_trafos.s_nom_opt - ext_trafos.s_nom) + * ext_trafos.capital_cost + ).sum() + ) - if not ext_trafos.empty: - network_costs[0] = network_costs[0]+(( - ext_trafos.s_nom_opt-ext_trafos.s_nom - )*ext_trafos.capital_cost).sum() + if not ext_dc_lines.empty: + network_costs[1] = ( + (ext_dc_lines.p_nom_opt - ext_dc_lines.p_nom_min) + * ext_dc_lines.capital_cost + ).sum() - if not ext_dc_lines.empty: - network_costs[1] = ((ext_dc_lines.p_nom_opt-ext_dc_lines.p_nom_min - )*ext_dc_lines.capital_cost).sum() + # links in other sectors / coupling different sectors - # links in other sectors / coupling different sectors + link_costs = 0 - link_costs = 0 + ext_links = ext_links[ext_links.carrier != "DC"] - ext_links = ext_links[ext_links.carrier!='DC'] + if not ext_links.empty: + link_costs = ( + (ext_links.p_nom_opt - ext_links.p_nom_min) + * ext_links.capital_cost + ).sum() - if not ext_links.empty: - link_costs = ((ext_links.p_nom_opt-ext_links.p_nom_min - )*ext_links.capital_cost).sum() + # storage and store costs - # storage and store costs + sto_costs = [0, 0] - sto_costs = [0, 0] + ext_storage = network.storage_units[network.storage_units.p_nom_extendable] + ext_store = network.stores[network.stores.e_nom_extendable] - ext_storage = network.storage_units[network.storage_units.p_nom_extendable] - ext_store = network.stores[network.stores.e_nom_extendable] + if not ext_storage.empty: + sto_costs[0] = (ext_storage.p_nom_opt * ext_storage.capital_cost).sum() - if not ext_storage.empty: - sto_costs[0] = (ext_storage.p_nom_opt* - ext_storage.capital_cost).sum() + if not ext_store.empty: + sto_costs[1] = (ext_store.e_nom_opt * ext_store.capital_cost).sum() - if not ext_store.empty: - sto_costs[1] = (ext_store.e_nom_opt* - ext_store.capital_cost).sum() + return network_costs, link_costs, sto_costs - return network_costs, link_costs, sto_costs def calc_marginal_cost(self): - """ - Function that caluclates and returns marginal costs, considering - generation and link and storage dispatch costs - - Returns - ------- - marginal_cost : float - Annual marginal cost in EUR - - """ - network = self.network - gen = network.generators_t.p.mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.generators.marginal_cost).sum() - link = abs(network.links_t.p0).mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.links.marginal_cost).sum() - stor = network.storage_units_t.p.mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.storage_units.marginal_cost).sum() - marginal_cost = gen + link + stor - return marginal_cost + """ + Function that caluclates and returns marginal costs, considering + generation and link and storage dispatch costs + + Returns + ------- + marginal_cost : float + Annual marginal cost in EUR + + """ + network = self.network + gen = ( + network.generators_t.p.mul( + network.snapshot_weightings.objective, axis=0 + ) + .sum(axis=0) + .mul(network.generators.marginal_cost) + .sum() + ) + link = ( + abs(network.links_t.p0) + .mul(network.snapshot_weightings.objective, axis=0) + .sum(axis=0) + .mul(network.links.marginal_cost) + .sum() + ) + stor = ( + network.storage_units_t.p.mul( + network.snapshot_weightings.objective, axis=0 + ) + .sum(axis=0) + .mul(network.storage_units.marginal_cost) + .sum() + ) + marginal_cost = gen + link + stor + return marginal_cost + def german_network(self): """Cut out all network components in Germany @@ -214,72 +248,98 @@ def german_network(self): """ keep_cntr = ["DE"] - new_idx = self.network.buses[self.network.buses.country.isin(keep_cntr)].index + new_idx = self.network.buses[ + self.network.buses.country.isin(keep_cntr) + ].index new_network = self.network.copy() # drop components of other countries new_network.mremove( - "Bus", - new_network.buses[~new_network.buses.index.isin(new_idx)].index) - + "Bus", new_network.buses[~new_network.buses.index.isin(new_idx)].index + ) + new_network.mremove( "Line", - new_network.lines[~new_network.lines.index.isin( - new_network.lines[ - ( - new_network.lines.bus0.isin(new_idx) - & new_network.lines.bus1.isin(new_idx) - ) - ].index)].index) + new_network.lines[ + ~new_network.lines.index.isin( + new_network.lines[ + ( + new_network.lines.bus0.isin(new_idx) + & new_network.lines.bus1.isin(new_idx) + ) + ].index + ) + ].index, + ) new_network.mremove( "Link", - new_network.links[~new_network.links.index.isin( - new_network.links[ - ( - new_network.links.bus0.isin(new_idx) - & new_network.links.bus1.isin(new_idx) - ) - ].index)].index) - + new_network.links[ + ~new_network.links.index.isin( + new_network.links[ + ( + new_network.links.bus0.isin(new_idx) + & new_network.links.bus1.isin(new_idx) + ) + ].index + ) + ].index, + ) + new_network.mremove( "Transformer", - new_network.transformers[~new_network.transformers.index.isin( - new_network.transformers[ - ( - new_network.transformers.bus0.isin(new_idx) - & new_network.transformers.bus1.isin(new_idx) - ) - ].index)].index) - + new_network.transformers[ + ~new_network.transformers.index.isin( + new_network.transformers[ + ( + new_network.transformers.bus0.isin(new_idx) + & new_network.transformers.bus1.isin(new_idx) + ) + ].index + ) + ].index, + ) + new_network.mremove( "Generator", - new_network.generators[~new_network.generators.index.isin( - new_network.generators[ - new_network.generators.bus.isin(new_idx) - ].index)].index) - + new_network.generators[ + ~new_network.generators.index.isin( + new_network.generators[ + new_network.generators.bus.isin(new_idx) + ].index + ) + ].index, + ) + new_network.mremove( "Load", - new_network.loads[~new_network.loads.index.isin( - new_network.loads[ - new_network.loads.bus.isin(new_idx) - ].index)].index) - + new_network.loads[ + ~new_network.loads.index.isin( + new_network.loads[new_network.loads.bus.isin(new_idx)].index + ) + ].index, + ) + new_network.mremove( "Store", - new_network.stores[~new_network.stores.index.isin( - new_network.stores[ - new_network.stores.bus.isin(new_idx) - ].index)].index) - + new_network.stores[ + ~new_network.stores.index.isin( + new_network.stores[new_network.stores.bus.isin(new_idx)].index + ) + ].index, + ) + new_network.mremove( "StorageUnit", - new_network.storage_units[~new_network.storage_units.index.isin( - new_network.storage_units[ - new_network.storage_units.bus.isin(new_idx) - ].index)].index) - + new_network.storage_units[ + ~new_network.storage_units.index.isin( + new_network.storage_units[ + new_network.storage_units.bus.isin(new_idx) + ].index + ) + ].index, + ) + return new_network @@ -296,12 +356,12 @@ def system_costs_germany(self): Costs for energy imported to Germany minus costs for exports """ - + network_de = self.german_network - + marginal_cost = 0 invest_cost = 0 - + for c in network_de.iterate_components(): if c.name in ["Store"]: value = "e" @@ -311,158 +371,247 @@ def system_costs_germany(self): value = "p" if c.name in network_de.one_port_components: if "marginal_cost" in c.df.columns: - marginal_cost += c.pnl.p.mul(c.df.marginal_cost).mul( - network_de.snapshot_weightings.generators, axis=0).sum().sum() + marginal_cost += ( + c.pnl.p.mul(c.df.marginal_cost) + .mul(network_de.snapshot_weightings.generators, axis=0) + .sum() + .sum() + ) else: if "marginal_cost" in c.df.columns: - marginal_cost += c.pnl.p0.mul(c.df.marginal_cost).mul( - network_de.snapshot_weightings.generators, axis=0).sum().sum() - if not c.name in ["Bus", "Load", "LineType", "TransformerType", "Carrier"]: - invest_cost += (( - c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_opt"] - - c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_min"] - )*c.df[c.df[f"{value}_nom_extendable"]]["capital_cost"]).sum() - - # import and its costs - links_export = self.network.links[( - self.network.links.bus0.isin(network_de.buses.index.values) & ~( - self.network.links.bus1.isin(network_de.buses.index.values)) - )] - - export_positive = self.network.links_t.p0[links_export.index].clip(lower=0).mul( - self.network.snapshot_weightings.generators, axis=0).mul( - self.network.buses_t.marginal_price[links_export.bus1].values, - ).sum().sum() - - export_negative = self.network.links_t.p0[links_export.index].clip(upper=0).mul( - self.network.snapshot_weightings.generators, axis=0).mul( - self.network.buses_t.marginal_price[links_export.bus1].values, - ).mul(-1).sum().sum() - - links_import = self.network.links[( - self.network.links.bus1.isin(network_de.buses.index.values) & ~( - self.network.links.bus0.isin(network_de.buses.index.values)) - ) - ] - - import_positive = self.network.links_t.p0[links_import.index].clip(lower=0).mul( - self.network.snapshot_weightings.generators, axis=0).mul( - self.network.buses_t.marginal_price[links_import.bus1].values, - ).sum().sum() - - import_negative = self.network.links_t.p0[links_import.index].clip(upper=0).mul( - self.network.snapshot_weightings.generators, axis=0).mul( - self.network.buses_t.marginal_price[links_import.bus1].values, - ).mul(-1).sum().sum() - - import_costs = export_negative + import_positive - export_positive - import_negative - + marginal_cost += ( + c.pnl.p0.mul(c.df.marginal_cost) + .mul(network_de.snapshot_weightings.generators, axis=0) + .sum() + .sum() + ) + if not c.name in [ + "Bus", + "Load", + "LineType", + "TransformerType", + "Carrier", + ]: + invest_cost += ( + ( + c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_opt"] + - c.df[c.df[f"{value}_nom_extendable"]][f"{value}_nom_min"] + ) + * c.df[c.df[f"{value}_nom_extendable"]]["capital_cost"] + ).sum() + + # import and its costs + links_export = self.network.links[ + ( + self.network.links.bus0.isin(network_de.buses.index.values) + & ~(self.network.links.bus1.isin(network_de.buses.index.values)) + ) + ] + + export_positive = ( + self.network.links_t.p0[links_export.index] + .clip(lower=0) + .mul(self.network.snapshot_weightings.generators, axis=0) + .mul( + self.network.buses_t.marginal_price[links_export.bus1].values, + ) + .sum() + .sum() + ) + + export_negative = ( + self.network.links_t.p0[links_export.index] + .clip(upper=0) + .mul(self.network.snapshot_weightings.generators, axis=0) + .mul( + self.network.buses_t.marginal_price[links_export.bus1].values, + ) + .mul(-1) + .sum() + .sum() + ) + + links_import = self.network.links[ + ( + self.network.links.bus1.isin(network_de.buses.index.values) + & ~(self.network.links.bus0.isin(network_de.buses.index.values)) + ) + ] + + import_positive = ( + self.network.links_t.p0[links_import.index] + .clip(lower=0) + .mul(self.network.snapshot_weightings.generators, axis=0) + .mul( + self.network.buses_t.marginal_price[links_import.bus1].values, + ) + .sum() + .sum() + ) + + import_negative = ( + self.network.links_t.p0[links_import.index] + .clip(upper=0) + .mul(self.network.snapshot_weightings.generators, axis=0) + .mul( + self.network.buses_t.marginal_price[links_import.bus1].values, + ) + .mul(-1) + .sum() + .sum() + ) + + import_costs = ( + export_negative + import_positive - export_positive - import_negative + ) + return marginal_cost, invest_cost, import_costs def calc_etrago_results(self): - """ Function that calculates main results of grid optimization - and adds them to Etrago object. - - Returns - ------- - None. - - """ - self.results = pd.DataFrame(columns=['unit', 'value'], - index=['annual system costs', - 'annual investment costs', - 'annual marginal costs', - 'annual electrical grid investment costs', - 'annual ac grid investment costs', - 'annual dc grid investment costs', - 'annual links investment costs', - 'annual storage+store investment costs', - 'annual electrical storage investment costs', - 'annual store investment costs', - 'battery storage expansion', - 'store expansion', - 'H2 store expansion', - 'CH4 store expansion', - 'heat store expansion', - 'storage+store expansion', - 'fuel cell links expansion', - 'electrolyzer links expansion', - 'methanisation links expansion', - 'Steam Methane Reformation links expansion', - 'abs. electrical grid expansion', - 'abs. electrical ac grid expansion', - 'abs. electrical dc grid expansion', - 'rel. electrical ac grid expansion', - 'rel. electrical dc grid expansion']) - - self.results.unit[self.results.index.str.contains('cost')] = 'EUR/a' - self.results.unit[self.results.index.str.contains('expansion')] = 'MW' - self.results.unit[self.results.index.str.contains('rel.')] = 'p.u.' - - # system costs - - self.results.value['annual ac grid investment costs'] = calc_investment_cost(self)[0][0] - self.results.value['annual dc grid investment costs'] = calc_investment_cost(self)[0][1] - self.results.value['annual electrical grid investment costs'] = sum(calc_investment_cost(self)[0]) - - self.results.value['annual links investment costs'] = calc_investment_cost(self)[1] - - self.results.value['annual electrical storage investment costs'] = calc_investment_cost(self)[2][0] - self.results.value['annual store investment costs'] = calc_investment_cost(self)[2][1] - self.results.value['annual storage+store investment costs'] = sum(calc_investment_cost(self)[2]) - - - self.results.value['annual investment costs'] = \ - sum(calc_investment_cost(self)[0]) + calc_investment_cost(self)[1] + sum(calc_investment_cost(self)[2]) - self.results.value['annual marginal costs'] = calc_marginal_cost(self) - - self.results.value['annual system costs'] = \ - self.results.value['annual investment costs'] + self.results.value['annual marginal costs'] - - # storage and store expansion - - network = self.network - - if not network.storage_units[network.storage_units.p_nom_extendable].empty: - - self.results.value['battery storage expansion'] = \ - _calc_storage_expansion(self).sum() - - store = _calc_store_expansion(self) - self.results.value['store expansion'] = store.sum() - self.results.value['H2 store expansion'] = \ - store[store.index.str.contains('H2')].sum() - self.results.value['CH4 store expansion'] = \ - store[store.index.str.contains('CH4')].sum() - self.results.value['heat store expansion'] = \ - store[store.index.str.contains('heat')].sum() - - self.results.value['storage+store expansion'] = \ - self.results.value['battery storage expansion'] + self.results.value['store expansion'] - - # links expansion - - if not network.links[network.links.p_nom_extendable].empty: - - links = _calc_sectorcoupling_link_expansion(self) - self.results.value['fuel cell links expansion'] = links[0] - self.results.value['electrolyzer links expansion'] = links[1] - self.results.value['methanisation links expansion'] = links[2] - self.results.value['Steam Methane Reformation links expansion'] = links[3] - - # grid expansion - - if not network.lines[network.lines.s_nom_extendable].empty: - - self.results.value['abs. electrical ac grid expansion'] = _calc_network_expansion(self)[0].sum() - self.results.value['abs. electrical dc grid expansion'] = _calc_network_expansion(self)[1].sum() - self.results.value['abs. electrical grid expansion'] = self.results.value['abs. electrical ac grid expansion'] + self.results.value['abs. electrical dc grid expansion'] - - ext_lines = network.lines[network.lines.s_nom_extendable] - ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] - - self.results.value['rel. electrical ac grid expansion'] = (_calc_network_expansion(self)[0].sum() / ext_lines.s_nom.sum()) - self.results.value['rel. electrical dc grid expansion'] = (_calc_network_expansion(self)[1].sum() / ext_dc_lines.p_nom.sum()) \ No newline at end of file + """Function that calculates main results of grid optimization + and adds them to Etrago object. + + Returns + ------- + None. + + """ + self.results = pd.DataFrame( + columns=["unit", "value"], + index=[ + "annual system costs", + "annual investment costs", + "annual marginal costs", + "annual electrical grid investment costs", + "annual ac grid investment costs", + "annual dc grid investment costs", + "annual links investment costs", + "annual storage+store investment costs", + "annual electrical storage investment costs", + "annual store investment costs", + "battery storage expansion", + "store expansion", + "H2 store expansion", + "CH4 store expansion", + "heat store expansion", + "storage+store expansion", + "fuel cell links expansion", + "electrolyzer links expansion", + "methanisation links expansion", + "Steam Methane Reformation links expansion", + "abs. electrical grid expansion", + "abs. electrical ac grid expansion", + "abs. electrical dc grid expansion", + "rel. electrical ac grid expansion", + "rel. electrical dc grid expansion", + ], + ) + + self.results.unit[self.results.index.str.contains("cost")] = "EUR/a" + self.results.unit[self.results.index.str.contains("expansion")] = "MW" + self.results.unit[self.results.index.str.contains("rel.")] = "p.u." + + # system costs + + self.results.value[ + "annual ac grid investment costs" + ] = calc_investment_cost(self)[0][0] + self.results.value[ + "annual dc grid investment costs" + ] = calc_investment_cost(self)[0][1] + self.results.value["annual electrical grid investment costs"] = sum( + calc_investment_cost(self)[0] + ) + + self.results.value["annual links investment costs"] = calc_investment_cost( + self + )[1] + + self.results.value[ + "annual electrical storage investment costs" + ] = calc_investment_cost(self)[2][0] + self.results.value["annual store investment costs"] = calc_investment_cost( + self + )[2][1] + self.results.value["annual storage+store investment costs"] = sum( + calc_investment_cost(self)[2] + ) + + self.results.value["annual investment costs"] = ( + sum(calc_investment_cost(self)[0]) + + calc_investment_cost(self)[1] + + sum(calc_investment_cost(self)[2]) + ) + self.results.value["annual marginal costs"] = calc_marginal_cost(self) + + self.results.value["annual system costs"] = ( + self.results.value["annual investment costs"] + + self.results.value["annual marginal costs"] + ) + + # storage and store expansion + + network = self.network + + if not network.storage_units[network.storage_units.p_nom_extendable].empty: + + self.results.value[ + "battery storage expansion" + ] = _calc_storage_expansion(self).sum() + + store = _calc_store_expansion(self) + self.results.value["store expansion"] = store.sum() + self.results.value["H2 store expansion"] = store[ + store.index.str.contains("H2") + ].sum() + self.results.value["CH4 store expansion"] = store[ + store.index.str.contains("CH4") + ].sum() + self.results.value["heat store expansion"] = store[ + store.index.str.contains("heat") + ].sum() + + self.results.value["storage+store expansion"] = ( + self.results.value["battery storage expansion"] + + self.results.value["store expansion"] + ) + + # links expansion + + if not network.links[network.links.p_nom_extendable].empty: + + links = _calc_sectorcoupling_link_expansion(self) + self.results.value["fuel cell links expansion"] = links[0] + self.results.value["electrolyzer links expansion"] = links[1] + self.results.value["methanisation links expansion"] = links[2] + self.results.value[ + "Steam Methane Reformation links expansion" + ] = links[3] + + # grid expansion + + if not network.lines[network.lines.s_nom_extendable].empty: + + self.results.value[ + "abs. electrical ac grid expansion" + ] = _calc_network_expansion(self)[0].sum() + self.results.value[ + "abs. electrical dc grid expansion" + ] = _calc_network_expansion(self)[1].sum() + self.results.value["abs. electrical grid expansion"] = ( + self.results.value["abs. electrical ac grid expansion"] + + self.results.value["abs. electrical dc grid expansion"] + ) + + ext_lines = network.lines[network.lines.s_nom_extendable] + ext_links = network.links[network.links.p_nom_extendable] + ext_dc_lines = ext_links[ext_links.carrier == "DC"] + + self.results.value["rel. electrical ac grid expansion"] = ( + _calc_network_expansion(self)[0].sum() / ext_lines.s_nom.sum() + ) + self.results.value["rel. electrical dc grid expansion"] = ( + _calc_network_expansion(self)[1].sum() / ext_dc_lines.p_nom.sum() + ) From 26bf6ccb2a1d25f4ce34db9e6ade55f985c054aa Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Fri, 3 Mar 2023 15:08:13 +0100 Subject: [PATCH 03/20] Add plots for duration curves of flexibility options --- etrago/tools/network.py | 3 + etrago/tools/plot.py | 123 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/etrago/tools/network.py b/etrago/tools/network.py index d0d2a1330..936a6a228 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -50,6 +50,7 @@ from etrago.tools.plot import ( bev_flexibility_potential, demand_side_management, + flexibility_duration_curve, flexibility_usage, heat_stores, hydrogen_stores, @@ -269,6 +270,8 @@ def __init__( plot_heat_summary = plot_heat_summary + plot_flexibility_duration_curve = flexibility_duration_curve + plot_flexibility_usage = flexibility_usage demand_side_management = demand_side_management diff --git a/etrago/tools/plot.py b/etrago/tools/plot.py index 270366e03..953c3841e 100644 --- a/etrago/tools/plot.py +++ b/etrago/tools/plot.py @@ -3276,3 +3276,126 @@ def plot_heat_summary(self, t_resolution="20H", stacked=True, save_path=False): if save_path: plt.savefig(save_path, dpi=300) + +def shifted_energy(self, carrier, buses): + """Calulate shifted energy for a specific carrier + + Parameters + ---------- + carrier : str + Name of energy carrier + buses : list + List of considered bus indices + + Returns + ------- + shifted : pandas.Series + Shifted energy per time step + + """ + + buses = self.network.links[ + self.network.links.bus0.isin( + self.network.buses[ + (self.network.buses.carrier == "AC") + & (self.network.buses.index.isin(buses)) + ].index + ) + & self.network.links.bus1.isin( + self.network.buses[ + self.network.buses.carrier.str.contains(carrier) + ].index + ) + ].bus1.unique() + + supply = self.network.links_t.p1[ + self.network.links[ + (self.network.links.bus1.isin(buses)) + & ~(self.network.links.carrier.str.contains("charger")) + ].index + ].mul(-1).sum(axis=1) + ( + self.network.generators_t.p[ + self.network.generators[ + self.network.generators.bus.isin(buses) + ].index + ].sum(axis=1) + ) + + demand = self.network.loads_t.p[ + self.network.loads[self.network.loads.bus.isin(buses)].index + ].sum(axis=1) + ( + self.network.links_t.p0[ + self.network.links[ + (self.network.links.bus0.isin(buses)) + & ~(self.network.links.carrier.str.contains("charger")) + ].index + ].sum(axis=1) + ) + + shifted = supply - demand + return shifted + + +def flexibility_duration_curve(self, buses, filename=None): + """Plot duration curves of flexibility options + + Parameters + ---------- + buses : list + List of considered bus indices + filename : str, optional + Name of file to save plot. The default is None. + + Returns + ------- + None. + + """ + fig, ax = plt.subplots(figsize=(15, 8)) + df = pd.DataFrame(index=range(len(self.network.snapshots))) + + df["dsm"] = ( + self.demand_side_management( + buses=buses, + snapshots=range(len(self.network.snapshots)), + used=True, + ) + .e.sort_values() + .reset_index() + .e + ) + + df["mobility"] = ( + ( + self.bev_flexibility_potential( + buses=buses, + snapshots=range(len(self.network.snapshots)), + used=True, + ).e + - self.bev_flexibility_potential( + buses=buses, + snapshots=range(len(self.network.snapshots)), + used=True, + )[["e_max", "e_min"]].mean(axis=1) + ) + .sort_values() + .reset_index()[0] + ) + df["mobility"] + df["heat"] = ( + shifted_energy(self, "heat", buses).sort_values().reset_index()[0] + ) + + df["hydrogen_stores"] = ( + shifted_energy(self, "H2", buses).sort_values().reset_index()[0] + ) + + df.mul(1e-3).plot(ax=ax) + ax.set_ylabel("Usage in GWh") + plt.axhline(y=0.0, color="grey", linestyle="dotted") + + if filename is None: + plt.show() + else: + matplotlib.pylab.savefig(filename, dpi=400, bbox_inches="tight") + plt.close() From ad0ba1c34f123bcce09e8713f237d24c380f4eeb Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Fri, 3 Mar 2023 15:13:56 +0100 Subject: [PATCH 04/20] Add functions to calculate exports --- etrago/tools/calc_results.py | 160 +++++++++++++++++++++++++++++++++++ etrago/tools/network.py | 16 +++- 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index c25289705..2ef643c7a 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -469,6 +469,166 @@ def system_costs_germany(self): return marginal_cost, invest_cost, import_costs +def ac_export(self): + """Calculate electricity exports and imports over AC lines + + Returns + ------- + float + Electricity export (if negative: import) from Germany + + """ + de_buses = self.network.buses[self.network.buses.country == "DE"] + for_buses = self.network.buses[self.network.buses.country != "DE"] + exp = self.network.lines[ + (self.network.lines.bus0.isin(de_buses.index)) + & (self.network.lines.bus1.isin(for_buses.index)) + ] + imp = self.network.lines[ + (self.network.lines.bus1.isin(de_buses.index)) + & (self.network.lines.bus0.isin(for_buses.index)) + ] + + return ( + self.network.lines_t.p0[exp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + + self.network.lines_t.p1[imp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + ) + + +def ac_export_per_country(self): + """Calculate electricity exports and imports over AC lines per country + + Returns + ------- + float + Electricity export (if negative: import) from Germany + + """ + de_buses = self.network.buses[self.network.buses.country == "DE"] + + for_buses = self.network.buses[self.network.buses.country != "DE"] + + result = pd.Series(index=for_buses.country.unique()) + + for c in for_buses.country.unique(): + exp = self.network.lines[ + (self.network.lines.bus0.isin(de_buses.index)) + & ( + self.network.lines.bus1.isin( + for_buses[for_buses.country == c].index + ) + ) + ] + imp = self.network.lines[ + (self.network.lines.bus1.isin(de_buses.index)) + & ( + self.network.lines.bus0.isin( + for_buses[for_buses.country == c].index + ) + ) + ] + + result[c] = ( + self.network.lines_t.p0[exp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + + self.network.lines_t.p1[imp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + ) * 1e-6 + + return result + + +def dc_export(self): + """Calculate electricity exports and imports over DC lines + + Returns + ------- + float + Electricity export (if negative: import) from Germany + + """ + de_buses = self.network.buses[self.network.buses.country == "DE"] + for_buses = self.network.buses[self.network.buses.country != "DE"] + exp = self.network.links[ + (self.network.links.carrier == "DC") + & (self.network.links.bus0.isin(de_buses.index)) + & (self.network.links.bus1.isin(for_buses.index)) + ] + imp = self.network.links[ + (self.network.links.carrier == "DC") + & (self.network.links.bus1.isin(de_buses.index)) + & (self.network.links.bus0.isin(for_buses.index)) + ] + return ( + self.network.links_t.p0[exp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + + self.network.links_t.p1[imp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + ) + + +def dc_export_per_country(self): + """Calculate electricity exports and imports over DC lines per country + + Returns + ------- + float + Electricity export (if negative: import) from Germany + + """ + de_buses = self.network.buses[self.network.buses.country == "DE"] + + for_buses = self.network.buses[self.network.buses.country != "DE"] + + result = pd.Series(index=for_buses.country.unique()) + + for c in for_buses.country.unique(): + exp = self.network.links[ + (self.network.links.carrier == "DC") + & (self.network.links.bus0.isin(de_buses.index)) + & ( + self.network.links.bus1.isin( + for_buses[for_buses.country == c].index + ) + ) + ] + imp = self.network.links[ + (self.network.links.carrier == "DC") + & (self.network.links.bus1.isin(de_buses.index)) + & ( + self.network.links.bus0.isin( + for_buses[for_buses.country == c].index + ) + ) + ] + + result[c] = ( + self.network.links_t.p0[exp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + + self.network.links_t.p1[imp.index] + .sum(axis=1) + .mul(self.network.snapshot_weightings.generators) + .sum() + ) * 1e-6 + + return result + def calc_etrago_results(self): """Function that calculates main results of grid optimization and adds them to Etrago object. diff --git a/etrago/tools/network.py b/etrago/tools/network.py index 936a6a228..a80b4830f 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -34,7 +34,13 @@ from etrago.cluster.electrical import ehv_clustering, run_spatial_clustering from etrago.cluster.gas import run_spatial_clustering_gas from etrago.cluster.snapshot import skip_snapshots, snapshot_clustering -from etrago.tools.calc_results import calc_etrago_results +from etrago.tools.calc_results import ( + ac_export, + ac_export_per_country, + calc_etrago_results, + dc_export, + dc_export_per_country +) from etrago.tools.execute import ( dispatch_disaggregation, lopf, @@ -240,6 +246,14 @@ def __init__( calc_results = calc_etrago_results + calc_ac_export = ac_export() + + calc_ac_export_per_country = ac_export_per_country() + + calc_dc_export = dc_export() + + calc_dc_export_per_country = dc_export_per_country() + export_to_csv = export_to_csv filter_links_by_carrier = filter_links_by_carrier From 37849b3b8d53c0c6bbfb1ed885488552398343a8 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Fri, 3 Mar 2023 15:22:07 +0100 Subject: [PATCH 05/20] Apply black and isort --- etrago/tools/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etrago/tools/network.py b/etrago/tools/network.py index a80b4830f..2ed5aa5e9 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -39,7 +39,7 @@ ac_export_per_country, calc_etrago_results, dc_export, - dc_export_per_country + dc_export_per_country, ) from etrago.tools.execute import ( dispatch_disaggregation, From c7288fb7c3c96a1c7080f3d8b85fbeb5db823142 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Thu, 23 Mar 2023 09:46:41 +0100 Subject: [PATCH 06/20] Move egio functions to etrago --- etrago/tools/constraints.py | 2 +- etrago/tools/db.py | 200 ++++++++++++++++++++++++++++++++++++ etrago/tools/network.py | 2 +- etrago/tools/utilities.py | 2 +- 4 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 etrago/tools/db.py diff --git a/etrago/tools/constraints.py b/etrago/tools/constraints.py index ab3650bca..b53ff3b10 100755 --- a/etrago/tools/constraints.py +++ b/etrago/tools/constraints.py @@ -23,7 +23,7 @@ """ import logging -from egoio.tools import db +from etrago.tools import db from pyomo.environ import Constraint from pypsa.descriptors import expand_series from pypsa.linopt import define_constraints, define_variables, get_var, linexpr diff --git a/etrago/tools/db.py b/etrago/tools/db.py new file mode 100644 index 000000000..d5de25ee8 --- /dev/null +++ b/etrago/tools/db.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# Copyright 2016-2018 Flensburg University of Applied Sciences, +# Europa-Universität Flensburg, +# Centre for Sustainable Energy Systems, +# DLR-Institute for Networked Energy Systems + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import configparser as cp +import keyring +import getpass +from sqlalchemy import create_engine +import oedialect + +def readcfg(filepath, section): + """ + Reads the configuration file. If section is not available, calls + create_oedb_config_file to add the new section to an existing config.ini. + + Parameters + ---------- + filepath : str + Absolute path of config file including the filename itself + section : str + Section in config file which contains connection details + Returns + ------- + cfg : configparser.ConfigParser + Used for configuration file parser language. + """ + + cfg = cp.ConfigParser() + cfg.read(filepath) + + if not cfg.has_section(section): + print('The section "{sec}" is not in the config file {file}.' + .format(sec=section, + file=filepath)) + cfg = create_oedb_config_file(filepath, section) + + return cfg + +def get_connection_details(section): + """ + Asks the user for the database connection details and returns them as a + ConfigParser-object. + + Parameters + ---------- + None + + Returns + ------- + cfg : configparser.ConfigParser + Used for configuration file parser language. + """ + print('Please enter your connection details:') + dialect = input('Enter input value for `dialect` (default: psycopg2): ') or 'psycopg2' + username = input('Enter value for `username`: ') + database = input('Enter value for `database`: ') + host = input('Enter value for `host`: ') + port = input('Enter value for `port` (default: 5432): ') or '5432' + + cfg = cp.ConfigParser() + cfg.add_section(section) + cfg.set(section, 'dialect', dialect) + cfg.set(section, 'username', username) + cfg.set(section, 'host', host) + cfg.set(section, 'port', port) + cfg.set(section, 'database', database) + pw = getpass.getpass(prompt="Enter your password/token to " \ + "store it in " + "keyring: ".format(database=section)) + keyring.set_password(section, cfg.get(section, "username"), pw) + + return cfg + +def create_oedb_config_file(filepath, section='oep'): + """ + + Parameters + ---------- + filepath : str + Absolute path of config file including the filename itself + section : str + Section in config file which contains connection details + + Returns + ------- + cfg : configparser.ConfigParser + Used for configuration file parser language. + """ + + cfg = get_connection_details(section) + + print('Do you want to store the connection details in the config file {file} ?' + .format(file=filepath)) + choice = '' + while choice not in ['y', 'n']: + choice = input('(y/n): ') + + if choice == 'y': + # create egoio dir if not existent + base_path = os.path.split(filepath)[0] + if not os.path.isdir(base_path): + os.mkdir(base_path) + print('The directory {path} was created.'.format(path=base_path)) + + with open(filepath, 'a') as configfile: + cfg.write(configfile) + pass + + + print('Template {0} with section "{1}" created.\nYou can manually edit' + ' the config file.' + .format(filepath, + section)) + else: + pass + + return cfg + +def connection(filepath=None, section='oep', readonly=False): + """ + Instantiate a database connection (for the use with SQLAlchemy). + + The keyword argument `filepath` specifies the location of the config file + that contains database connection information. If not given, the default + of `~/.etrago_database/config.ini` applies. + + Parameters + ---------- + filepath : str + Absolute path of config file including the filename itself + section : str + Section in config file containing database connection parameters. + Default: 'oep'. + readonly : bool + Set this option to True for creating a read-only and passwordless + engine for accessing the open energy platform. + Default: False. + + Returns + ------- + conn : sqlalchemy.engine + SQLalchemy engine object containing the connection details + """ + + if readonly: + conn = create_engine( + "postgresql+oedialect://openenergy-platform.org") + else: + # define default filepath if not provided + if filepath is None: + filepath = os.path.join(os.path.expanduser("~"), '.etrago_database', 'config.ini') + + # does the file exist? + if not os.path.isfile(filepath): + print('DB config file {file} not found. ' + 'This might be the first run of the tool. ' + .format(file=filepath)) + cfg = create_oedb_config_file(filepath, section=section) + else: + cfg = readcfg(filepath, section) + + try: + pw = cfg.get(section, "password") + except: + pw = keyring.get_password(section, + cfg.get(section, "username")) + if pw is None: + pw = getpass.getpass(prompt='No password found for database "{db}". ' + 'Enter your password to ' + 'store it in keyring: ' + .format(db=cfg.get(section, 'database'))) + keyring.set_password(section, cfg.get(section, "username"), pw) + + # establish connection and return it + conn = create_engine( + "postgresql+{dialect}://{user}:{password}@{host}:{port}/{db}".format( + dialect=cfg.get(section, 'dialect', fallback='psycopg2'), + user=cfg.get(section, 'username'), + password=pw, + host=cfg.get(section, 'host'), + port=cfg.get(section, 'port'), + db=cfg.get(section, 'database'))) + + return conn \ No newline at end of file diff --git a/etrago/tools/network.py b/etrago/tools/network.py index fa215352e..07c0b4666 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -24,7 +24,7 @@ import logging -from egoio.tools import db +from etrago.tools import db from pypsa.components import Network from sqlalchemy.orm import sessionmaker import pandas as pd diff --git a/etrago/tools/utilities.py b/etrago/tools/utilities.py index e1c266e13..bc2be0441 100755 --- a/etrago/tools/utilities.py +++ b/etrago/tools/utilities.py @@ -29,7 +29,7 @@ import math import os -from egoio.tools import db +from etrago.tools import db from pyomo.environ import Constraint, PositiveReals, Var from shapely.geometry import LineString, Point import geopandas as gpd From fc74e3ab2f01888f2803f971a04c82192fa57caf Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Thu, 23 Mar 2023 09:47:05 +0100 Subject: [PATCH 07/20] Remove egio from installation --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4ea9b7ab6..dac4c1eb5 100755 --- a/setup.py +++ b/setup.py @@ -43,9 +43,9 @@ def read(*names, **kwargs): packages=find_packages(), include_package_data=True, install_requires=[ - "egoio == 0.4.7", "geoalchemy2 >= 0.3.0", "geopandas", + "keyring", "matplotlib >= 3.0.3", "oedialect", # PyPSA uses a deprecated import that errors with Pyomo 6.4.3. From 71c9bc27882de810c0e0864b9263aa4241f3f53d Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Thu, 23 Mar 2023 09:49:13 +0100 Subject: [PATCH 08/20] Apply black and isort --- etrago/tools/constraints.py | 3 +- etrago/tools/db.py | 152 +++++++++++++++++++++--------------- etrago/tools/network.py | 2 +- etrago/tools/utilities.py | 3 +- 4 files changed, 92 insertions(+), 68 deletions(-) diff --git a/etrago/tools/constraints.py b/etrago/tools/constraints.py index b53ff3b10..b77197e17 100755 --- a/etrago/tools/constraints.py +++ b/etrago/tools/constraints.py @@ -23,7 +23,6 @@ """ import logging -from etrago.tools import db from pyomo.environ import Constraint from pypsa.descriptors import expand_series from pypsa.linopt import define_constraints, define_variables, get_var, linexpr @@ -32,6 +31,8 @@ import pandas as pd import pyomo.environ as po +from etrago.tools import db + logger = logging.getLogger(__name__) __copyright__ = ( diff --git a/etrago/tools/db.py b/etrago/tools/db.py index d5de25ee8..3f9ca2a5a 100644 --- a/etrago/tools/db.py +++ b/etrago/tools/db.py @@ -17,18 +17,20 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import os import configparser as cp -import keyring import getpass +import os + from sqlalchemy import create_engine +import keyring import oedialect + def readcfg(filepath, section): - """ + """ Reads the configuration file. If section is not available, calls create_oedb_config_file to add the new section to an existing config.ini. - + Parameters ---------- filepath : str @@ -43,51 +45,60 @@ def readcfg(filepath, section): cfg = cp.ConfigParser() cfg.read(filepath) - + if not cfg.has_section(section): - print('The section "{sec}" is not in the config file {file}.' - .format(sec=section, - file=filepath)) - cfg = create_oedb_config_file(filepath, section) + print( + 'The section "{sec}" is not in the config file {file}.'.format( + sec=section, file=filepath + ) + ) + cfg = create_oedb_config_file(filepath, section) return cfg + def get_connection_details(section): """ Asks the user for the database connection details and returns them as a ConfigParser-object. - + Parameters ---------- None - + Returns ------- cfg : configparser.ConfigParser Used for configuration file parser language. """ - print('Please enter your connection details:') - dialect = input('Enter input value for `dialect` (default: psycopg2): ') or 'psycopg2' - username = input('Enter value for `username`: ') - database = input('Enter value for `database`: ') - host = input('Enter value for `host`: ') - port = input('Enter value for `port` (default: 5432): ') or '5432' + print("Please enter your connection details:") + dialect = ( + input("Enter input value for `dialect` (default: psycopg2): ") + or "psycopg2" + ) + username = input("Enter value for `username`: ") + database = input("Enter value for `database`: ") + host = input("Enter value for `host`: ") + port = input("Enter value for `port` (default: 5432): ") or "5432" cfg = cp.ConfigParser() cfg.add_section(section) - cfg.set(section, 'dialect', dialect) - cfg.set(section, 'username', username) - cfg.set(section, 'host', host) - cfg.set(section, 'port', port) - cfg.set(section, 'database', database) - pw = getpass.getpass(prompt="Enter your password/token to " \ - "store it in " - "keyring: ".format(database=section)) + cfg.set(section, "dialect", dialect) + cfg.set(section, "username", username) + cfg.set(section, "host", host) + cfg.set(section, "port", port) + cfg.set(section, "database", database) + pw = getpass.getpass( + prompt="Enter your password/token to " + "store it in " + "keyring: ".format(database=section) + ) keyring.set_password(section, cfg.get(section, "username"), pw) - + return cfg -def create_oedb_config_file(filepath, section='oep'): + +def create_oedb_config_file(filepath, section="oep"): """ Parameters @@ -96,43 +107,46 @@ def create_oedb_config_file(filepath, section='oep'): Absolute path of config file including the filename itself section : str Section in config file which contains connection details - + Returns ------- cfg : configparser.ConfigParser Used for configuration file parser language. """ - + cfg = get_connection_details(section) - print('Do you want to store the connection details in the config file {file} ?' - .format(file=filepath)) - choice = '' - while choice not in ['y', 'n']: - choice = input('(y/n): ') + print( + "Do you want to store the connection details in the config file {file} ?".format( + file=filepath + ) + ) + choice = "" + while choice not in ["y", "n"]: + choice = input("(y/n): ") - if choice == 'y': + if choice == "y": # create egoio dir if not existent base_path = os.path.split(filepath)[0] if not os.path.isdir(base_path): os.mkdir(base_path) - print('The directory {path} was created.'.format(path=base_path)) - - with open(filepath, 'a') as configfile: + print("The directory {path} was created.".format(path=base_path)) + + with open(filepath, "a") as configfile: cfg.write(configfile) pass - - - print('Template {0} with section "{1}" created.\nYou can manually edit' - ' the config file.' - .format(filepath, - section)) + + print( + 'Template {0} with section "{1}" created.\nYou can manually edit' + " the config file.".format(filepath, section) + ) else: pass - + return cfg -def connection(filepath=None, section='oep', readonly=False): + +def connection(filepath=None, section="oep", readonly=False): """ Instantiate a database connection (for the use with SQLAlchemy). @@ -151,7 +165,7 @@ def connection(filepath=None, section='oep', readonly=False): Set this option to True for creating a read-only and passwordless engine for accessing the open energy platform. Default: False. - + Returns ------- conn : sqlalchemy.engine @@ -159,18 +173,22 @@ def connection(filepath=None, section='oep', readonly=False): """ if readonly: - conn = create_engine( - "postgresql+oedialect://openenergy-platform.org") + conn = create_engine("postgresql+oedialect://openenergy-platform.org") else: # define default filepath if not provided if filepath is None: - filepath = os.path.join(os.path.expanduser("~"), '.etrago_database', 'config.ini') + filepath = os.path.join( + os.path.expanduser("~"), ".etrago_database", "config.ini" + ) # does the file exist? if not os.path.isfile(filepath): - print('DB config file {file} not found. ' - 'This might be the first run of the tool. ' - .format(file=filepath)) + print( + "DB config file {file} not found. " + "This might be the first run of the tool. ".format( + file=filepath + ) + ) cfg = create_oedb_config_file(filepath, section=section) else: cfg = readcfg(filepath, section) @@ -178,23 +196,27 @@ def connection(filepath=None, section='oep', readonly=False): try: pw = cfg.get(section, "password") except: - pw = keyring.get_password(section, - cfg.get(section, "username")) + pw = keyring.get_password(section, cfg.get(section, "username")) if pw is None: - pw = getpass.getpass(prompt='No password found for database "{db}". ' - 'Enter your password to ' - 'store it in keyring: ' - .format(db=cfg.get(section, 'database'))) + pw = getpass.getpass( + prompt='No password found for database "{db}". ' + "Enter your password to " + "store it in keyring: ".format( + db=cfg.get(section, "database") + ) + ) keyring.set_password(section, cfg.get(section, "username"), pw) # establish connection and return it conn = create_engine( "postgresql+{dialect}://{user}:{password}@{host}:{port}/{db}".format( - dialect=cfg.get(section, 'dialect', fallback='psycopg2'), - user=cfg.get(section, 'username'), + dialect=cfg.get(section, "dialect", fallback="psycopg2"), + user=cfg.get(section, "username"), password=pw, - host=cfg.get(section, 'host'), - port=cfg.get(section, 'port'), - db=cfg.get(section, 'database'))) + host=cfg.get(section, "host"), + port=cfg.get(section, "port"), + db=cfg.get(section, "database"), + ) + ) - return conn \ No newline at end of file + return conn diff --git a/etrago/tools/network.py b/etrago/tools/network.py index 07c0b4666..38251cf06 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -24,7 +24,6 @@ import logging -from etrago.tools import db from pypsa.components import Network from sqlalchemy.orm import sessionmaker import pandas as pd @@ -34,6 +33,7 @@ from etrago.cluster.electrical import ehv_clustering, run_spatial_clustering from etrago.cluster.gas import run_spatial_clustering_gas from etrago.cluster.snapshot import skip_snapshots, snapshot_clustering +from etrago.tools import db from etrago.tools.calc_results import calc_etrago_results from etrago.tools.execute import ( dispatch_disaggregation, diff --git a/etrago/tools/utilities.py b/etrago/tools/utilities.py index bc2be0441..e758d2af4 100755 --- a/etrago/tools/utilities.py +++ b/etrago/tools/utilities.py @@ -29,7 +29,6 @@ import math import os -from etrago.tools import db from pyomo.environ import Constraint, PositiveReals, Var from shapely.geometry import LineString, Point import geopandas as gpd @@ -38,6 +37,8 @@ import pypsa import sqlalchemy.exc +from etrago.tools import db + logger = logging.getLogger(__name__) From 36f2735d88f27751d5255e0b5258d6daf0ebec24 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 27 Mar 2023 12:02:00 +0200 Subject: [PATCH 09/20] Reformat etrago/tools/calc_results --- etrago/tools/calc_results.py | 8 ++------ noxfile.py | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index 2ef643c7a..5c3f3f4c8 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -25,9 +25,7 @@ if "READTHEDOCS" not in os.environ: import logging - import time - import numpy as np import pandas as pd logger = logging.getLogger(__name__) @@ -386,7 +384,7 @@ def system_costs_germany(self): .sum() .sum() ) - if not c.name in [ + if c.name not in [ "Bus", "Load", "LineType", @@ -629,6 +627,7 @@ def dc_export_per_country(self): return result + def calc_etrago_results(self): """Function that calculates main results of grid optimization and adds them to Etrago object. @@ -716,7 +715,6 @@ def calc_etrago_results(self): network = self.network if not network.storage_units[network.storage_units.p_nom_extendable].empty: - self.results.value[ "battery storage expansion" ] = _calc_storage_expansion(self).sum() @@ -741,7 +739,6 @@ def calc_etrago_results(self): # links expansion if not network.links[network.links.p_nom_extendable].empty: - links = _calc_sectorcoupling_link_expansion(self) self.results.value["fuel cell links expansion"] = links[0] self.results.value["electrolyzer links expansion"] = links[1] @@ -753,7 +750,6 @@ def calc_etrago_results(self): # grid expansion if not network.lines[network.lines.s_nom_extendable].empty: - self.results.value[ "abs. electrical ac grid expansion" ] = _calc_network_expansion(self)[0].sum() diff --git a/noxfile.py b/noxfile.py index 98f0c9eb6..69cf698e1 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,6 +4,7 @@ cleaned = [ "etrago/cluster/disaggregation.py", + "etrago/tools/calc_results.py", "etrago/tools/network.py", "etrago/tools/utilities.py", "noxfile.py", From 5becb5e8c96007ff502fea92375918ff65fb32b1 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Wed, 29 Mar 2023 10:46:38 +0200 Subject: [PATCH 10/20] Fix calc results functions --- etrago/tools/calc_results.py | 2 +- etrago/tools/network.py | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index 5c3f3f4c8..1605f9915 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -355,7 +355,7 @@ def system_costs_germany(self): """ - network_de = self.german_network + network_de = self.german_network() marginal_cost = 0 invest_cost = 0 diff --git a/etrago/tools/network.py b/etrago/tools/network.py index 2ed5aa5e9..8e4b57b7f 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -40,6 +40,8 @@ calc_etrago_results, dc_export, dc_export_per_country, + german_network, + system_costs_germany, ) from etrago.tools.execute import ( dispatch_disaggregation, @@ -246,22 +248,26 @@ def __init__( calc_results = calc_etrago_results - calc_ac_export = ac_export() + calc_ac_export = ac_export - calc_ac_export_per_country = ac_export_per_country() + calc_ac_export_per_country = ac_export_per_country - calc_dc_export = dc_export() + calc_dc_export = dc_export - calc_dc_export_per_country = dc_export_per_country() + calc_dc_export_per_country = dc_export_per_country export_to_csv = export_to_csv filter_links_by_carrier = filter_links_by_carrier + german_network = german_network + set_line_costs = set_line_costs set_trafo_costs = set_trafo_costs + system_costs_germany = system_costs_germany + drop_sectors = drop_sectors buses_by_country = buses_by_country From 355cf3c11bd3dd51f2180a71b44cacdacd13c507 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Thu, 14 Sep 2023 10:05:53 +0200 Subject: [PATCH 11/20] Set upper version limits for pandas and pyomo to avoid conflicts with pypsa --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 8b6dde20d..89c9b4584 100755 --- a/setup.py +++ b/setup.py @@ -54,9 +54,10 @@ def read(*names, **kwargs): "loguru", "matplotlib >= 3.0.3", "oedialect", - # PyPSA uses a deprecated import that errors with Pyomo 6.4.3. - # Upstream has a fix but it's not yet released. - "pyomo != 6.4.3", + # Fix upper version limits for pyomo and pandas + # Related to problems with old pypsa version + "pandas < 2", + "pyomo == 6.4.1", "pypsa == 0.20.1", "rtree", "saio", From cb29280c20b0c1d4807de37665fa54e9316b0793 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 18 Sep 2023 11:48:21 +0200 Subject: [PATCH 12/20] Allow pyomo version 6.5.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 89c9b4584..0853fbbf1 100755 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def read(*names, **kwargs): # Fix upper version limits for pyomo and pandas # Related to problems with old pypsa version "pandas < 2", - "pyomo == 6.4.1", + "pyomo>6.4, <6.6", "pypsa == 0.20.1", "rtree", "saio", From b21a59a2e15960374b747edf90284198a647b799 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 18 Sep 2023 13:39:30 +0200 Subject: [PATCH 13/20] Exclude not-working pyomo-version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0853fbbf1..10846360f 100755 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def read(*names, **kwargs): # Fix upper version limits for pyomo and pandas # Related to problems with old pypsa version "pandas < 2", - "pyomo>6.4, <6.6", + "pyomo>6.4, <6.6, !=6.4.3", "pypsa == 0.20.1", "rtree", "saio", From 96eb11a7757bd05cf071c78b5de9d820fcc21099 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Tue, 19 Sep 2023 11:42:40 +0200 Subject: [PATCH 14/20] Add unit to docstring --- etrago/tools/calc_results.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index 1605f9915..bf1edac83 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -505,7 +505,7 @@ def ac_export_per_country(self): Returns ------- float - Electricity export (if negative: import) from Germany + Electricity export (if negative: import) from Germany in TWh """ de_buses = self.network.buses[self.network.buses.country == "DE"] @@ -585,7 +585,7 @@ def dc_export_per_country(self): Returns ------- float - Electricity export (if negative: import) from Germany + Electricity export (if negative: import) from Germany in TWh """ de_buses = self.network.buses[self.network.buses.country == "DE"] From 0256a3f254fbad6843f18f3cb0a9e4b4a71db5e3 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Tue, 19 Sep 2023 13:42:30 +0200 Subject: [PATCH 15/20] Replace flexibility duration curve plot --- etrago/tools/network.py | 3 -- etrago/tools/plot.py | 117 +++++++++++++++++++++++----------------- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/etrago/tools/network.py b/etrago/tools/network.py index 8e4b57b7f..ebefc8db7 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -58,7 +58,6 @@ from etrago.tools.plot import ( bev_flexibility_potential, demand_side_management, - flexibility_duration_curve, flexibility_usage, heat_stores, hydrogen_stores, @@ -290,8 +289,6 @@ def __init__( plot_heat_summary = plot_heat_summary - plot_flexibility_duration_curve = flexibility_duration_curve - plot_flexibility_usage = flexibility_usage demand_side_management = demand_side_management diff --git a/etrago/tools/plot.py b/etrago/tools/plot.py index 953c3841e..feff65558 100644 --- a/etrago/tools/plot.py +++ b/etrago/tools/plot.py @@ -124,6 +124,7 @@ def coloring(): "power_to_H2": "cyan", "H2_overground": "cyan", "H2_underground": "cyan", + "H2": "cyan", "dsm-cts": "dodgerblue", "dsm-ind-osm": "dodgerblue", "dsm-ind-sites": "dodgerblue", @@ -144,6 +145,7 @@ def coloring(): "H2_to_CH4": "seagreen", "central_heat_store_charger": "firebrick", "central_heat_store": "firebrick", + "heat": "firebrick", "rural_heat_store_charger": "salmon", "rural_heat_store": "salmon", "central_heat_store_discharger": "firebrick", @@ -3335,14 +3337,15 @@ def shifted_energy(self, carrier, buses): shifted = supply - demand return shifted - -def flexibility_duration_curve(self, buses, filename=None): +def flexibility_duration_curve(etrago, etrago_lowflex, filename=None): """Plot duration curves of flexibility options Parameters ---------- - buses : list - List of considered bus indices + etrago : Etrago + Object including network with flexibility options + etrago_lowflex : Etrago + Object including network with less flexibility options filename : str, optional Name of file to save plot. The default is None. @@ -3351,51 +3354,67 @@ def flexibility_duration_curve(self, buses, filename=None): None. """ - fig, ax = plt.subplots(figsize=(15, 8)) - df = pd.DataFrame(index=range(len(self.network.snapshots))) - - df["dsm"] = ( - self.demand_side_management( - buses=buses, - snapshots=range(len(self.network.snapshots)), - used=True, - ) - .e.sort_values() - .reset_index() - .e - ) - - df["mobility"] = ( - ( - self.bev_flexibility_potential( - buses=buses, - snapshots=range(len(self.network.snapshots)), - used=True, - ).e - - self.bev_flexibility_potential( - buses=buses, - snapshots=range(len(self.network.snapshots)), - used=True, - )[["e_max", "e_min"]].mean(axis=1) - ) - .sort_values() - .reset_index()[0] - ) - df["mobility"] - df["heat"] = ( - shifted_energy(self, "heat", buses).sort_values().reset_index()[0] - ) - - df["hydrogen_stores"] = ( - shifted_energy(self, "H2", buses).sort_values().reset_index()[0] - ) + colors = coloring() - df.mul(1e-3).plot(ax=ax) - ax.set_ylabel("Usage in GWh") - plt.axhline(y=0.0, color="grey", linestyle="dotted") + value = 'p' + + df = pd.DataFrame() + + dsm_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('dsm')] + df['dsm_positive'] = etrago.network.stores_t[value][dsm_stores.index].clip(lower=0).sum(axis=1) + df['dsm_negative'] = etrago.network.stores_t[value][dsm_stores.index].clip(upper=0).sum(axis=1) + + emob_static = etrago_lowflex.network.loads[ + etrago_lowflex.network.loads.carrier=='land transport EV'] + + emob_static_t = etrago_lowflex.network.loads_t.p_set[emob_static.index] + + emob_static_t = emob_static_t.loc[:, emob_static.index] + + emob_static_t.columns = emob_static.bus.values + + emob_flex = etrago.network.links[etrago.network.links.carrier.str.contains('BEV')] + + emob_flex_t = etrago.network.links_t.p0[emob_flex.index] + + emob_flex_t = emob_flex_t.loc[:, emob_flex.index] + + emob_flex_t.columns = emob_flex.bus0.values + + emob_flex_t - emob_static_t + df['BEV charger_positive'] = (emob_flex_t - emob_static_t).clip(lower=0).sum(axis=1) + df['BEV charger_negative'] = (emob_flex_t - emob_static_t).clip(upper=0).sum(axis=1) + + heat_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('heat')] + df['heat_positive'] = etrago.network.stores_t[value][heat_stores.index].clip(lower=0).sum(axis=1) + df['heat_negative'] = etrago.network.stores_t[value][heat_stores.index].clip(upper=0).sum(axis=1) + + h2_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('H2')] + df['H2_positive'] = etrago.network.stores_t[value][h2_stores.index].clip(lower=0).sum(axis=1) + df['H2_negative'] = etrago.network.stores_t[value][h2_stores.index].clip(upper=0).sum(axis=1) - if filename is None: - plt.show() - else: - matplotlib.pylab.savefig(filename, dpi=400, bbox_inches="tight") + fig, ax = plt.subplots(figsize=(15, 8)) + for c in df.columns: + result = pd.Series(dtype=float) + color = colors[c.split('_')[0]] + for p in range(0,100): + result[ + p*df[c].abs().max() + *np.sign(df[c].sum())/100] = ( + df[c][df[c].abs()>p*0.01*df[c].abs().max()].size / df[c].size) *100 + + data_to_plot = pd.DataFrame(index = result.values, data = result.index*1e-3) + data_to_plot.columns = [c.split('_')[0]] + data_to_plot.plot(ax=ax, color = color, linewidth=3.0) + plt.axhline(y = 0.0, color = 'grey', linestyle = 'dotted') + ax.set_xlim(0, 80) + ax.set_xlabel("time in %") + ax.set_ylabel("flexibility usage in GW") + + handles, labels = plt.gca().get_legend_handles_labels() + by_label = dict(zip(labels, handles)) + plt.legend(by_label.values(), by_label.keys()) + + if filename: + fig.savefig(filename, dpi=600) plt.close() From ad5f9cc079f192b366f1af3e7c52079da69e92d5 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Tue, 19 Sep 2023 13:42:57 +0200 Subject: [PATCH 16/20] Apply black --- etrago/tools/plot.py | 125 ++++++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 44 deletions(-) diff --git a/etrago/tools/plot.py b/etrago/tools/plot.py index feff65558..6a227ab54 100644 --- a/etrago/tools/plot.py +++ b/etrago/tools/plot.py @@ -117,7 +117,6 @@ def plot_osm(x, y, zoom, alpha=0.4): def coloring(): - colors = { "load": "red", "DC": "blue", @@ -219,6 +218,7 @@ def plot_line_loading_diff(networkA, networkB, timestep=0, osm=False): set_epsg_network(networkA) set_epsg_network(networkB) plot_osm(osm["x"], osm["y"], osm["zoom"]) + # new colormap to make sure 0% difference has the same color in every plot def shiftedColorMap( cmap, start=0, midpoint=0.5, stop=1.0, name="shiftedcmap" @@ -1224,7 +1224,6 @@ def storage_p_soc(network, mean="1H", filename=None): network.storage_units.p_nom_opt[sbatt].sum() > 1 and network.storage_units.p_nom_opt[shydr].sum() < 1 ): - ( network.storage_units_t.p[sbatt].resample(mean).mean().sum(axis=1) / network.storage_units.p_nom_opt[sbatt].sum() @@ -1449,7 +1448,6 @@ def calc_ac_loading(network, timesteps): ) if not network.lines_t.q0.empty: - loading_lines = ( loading_lines**2 + mul_weighting(network, network.lines_t.q0) @@ -1490,7 +1488,6 @@ def calc_dc_loading(network, timesteps): & (network.links.length == row["length"]) ] ).empty: - l = network.links.index[ (network.links.bus0 == row["bus1"]) & (network.links.bus1 == row["bus0"]) @@ -1608,7 +1605,6 @@ def calc_network_expansion(network, method="abs", ext_min=0.1): network.links.p_nom_opt[i] = linked.p_nom_opt.values[0] if method == "rel": - extension_lines = ( 100 * (network.lines.s_nom_opt - network.lines.s_nom_min) @@ -1668,6 +1664,7 @@ def plot_background_grid(network, ax): color_geomap=True, ) + def demand_side_management(self, buses, snapshots, agg="5h", used=False): """Calculate shifting potential of demand side management @@ -2051,7 +2048,6 @@ def flexibility_usage( ) elif flexibility == "battery": - df = pd.DataFrame(index=self.network.snapshots[snapshots]) su = self.network.storage_units[ @@ -2105,7 +2101,9 @@ def flexibility_usage( fig_e.savefig(pre_path + f"stored_e_{flexibility}") -def plot_carrier(network, carrier_links=["AC"], carrier_buses=["AC"], cartopy=True): +def plot_carrier( + network, carrier_links=["AC"], carrier_buses=["AC"], cartopy=True +): """ Parameters ---------- @@ -2138,13 +2136,11 @@ def plot_carrier(network, carrier_links=["AC"], carrier_buses=["AC"], cartopy=Tr link_width = pd.Series(index=network.links.index, data=2) if len(carrier_links) > 0: - link_width.loc[~network.links.carrier.isin(carrier_links)] = 0 bus_sizes = pd.Series(index=network.buses.index, data=0.0005) if len(carrier_buses) > 0: - bus_sizes.loc[~network.buses.carrier.isin(carrier_buses)] = 0 link_colors = network.links.carrier.map(colors) @@ -3259,7 +3255,7 @@ def plot_heat_summary(self, t_resolution="20H", stacked=True, save_path=False): data.resample(t_resolution).mean().plot( ax=ax, label=i, legend=True ) - + heat_store_dispatch_hb.resample(t_resolution).mean().plot.line( ax=ax, legend=True, @@ -3279,6 +3275,7 @@ def plot_heat_summary(self, t_resolution="20H", stacked=True, save_path=False): if save_path: plt.savefig(save_path, dpi=300) + def shifted_energy(self, carrier, buses): """Calulate shifted energy for a specific carrier @@ -3337,6 +3334,7 @@ def shifted_energy(self, carrier, buses): shifted = supply - demand return shifted + def flexibility_duration_curve(etrago, etrago_lowflex, filename=None): """Plot duration curves of flexibility options @@ -3356,57 +3354,96 @@ def flexibility_duration_curve(etrago, etrago_lowflex, filename=None): """ colors = coloring() - value = 'p' - + value = "p" + df = pd.DataFrame() - - dsm_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('dsm')] - df['dsm_positive'] = etrago.network.stores_t[value][dsm_stores.index].clip(lower=0).sum(axis=1) - df['dsm_negative'] = etrago.network.stores_t[value][dsm_stores.index].clip(upper=0).sum(axis=1) + + dsm_stores = etrago.network.stores[ + etrago.network.stores.carrier.str.contains("dsm") + ] + df["dsm_positive"] = ( + etrago.network.stores_t[value][dsm_stores.index] + .clip(lower=0) + .sum(axis=1) + ) + df["dsm_negative"] = ( + etrago.network.stores_t[value][dsm_stores.index] + .clip(upper=0) + .sum(axis=1) + ) emob_static = etrago_lowflex.network.loads[ - etrago_lowflex.network.loads.carrier=='land transport EV'] - + etrago_lowflex.network.loads.carrier == "land transport EV" + ] + emob_static_t = etrago_lowflex.network.loads_t.p_set[emob_static.index] - + emob_static_t = emob_static_t.loc[:, emob_static.index] - + emob_static_t.columns = emob_static.bus.values - - emob_flex = etrago.network.links[etrago.network.links.carrier.str.contains('BEV')] - + + emob_flex = etrago.network.links[ + etrago.network.links.carrier.str.contains("BEV") + ] + emob_flex_t = etrago.network.links_t.p0[emob_flex.index] - + emob_flex_t = emob_flex_t.loc[:, emob_flex.index] - + emob_flex_t.columns = emob_flex.bus0.values emob_flex_t - emob_static_t - df['BEV charger_positive'] = (emob_flex_t - emob_static_t).clip(lower=0).sum(axis=1) - df['BEV charger_negative'] = (emob_flex_t - emob_static_t).clip(upper=0).sum(axis=1) + df["BEV charger_positive"] = ( + (emob_flex_t - emob_static_t).clip(lower=0).sum(axis=1) + ) + df["BEV charger_negative"] = ( + (emob_flex_t - emob_static_t).clip(upper=0).sum(axis=1) + ) - heat_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('heat')] - df['heat_positive'] = etrago.network.stores_t[value][heat_stores.index].clip(lower=0).sum(axis=1) - df['heat_negative'] = etrago.network.stores_t[value][heat_stores.index].clip(upper=0).sum(axis=1) + heat_stores = etrago.network.stores[ + etrago.network.stores.carrier.str.contains("heat") + ] + df["heat_positive"] = ( + etrago.network.stores_t[value][heat_stores.index] + .clip(lower=0) + .sum(axis=1) + ) + df["heat_negative"] = ( + etrago.network.stores_t[value][heat_stores.index] + .clip(upper=0) + .sum(axis=1) + ) - h2_stores = etrago.network.stores[etrago.network.stores.carrier.str.contains('H2')] - df['H2_positive'] = etrago.network.stores_t[value][h2_stores.index].clip(lower=0).sum(axis=1) - df['H2_negative'] = etrago.network.stores_t[value][h2_stores.index].clip(upper=0).sum(axis=1) + h2_stores = etrago.network.stores[ + etrago.network.stores.carrier.str.contains("H2") + ] + df["H2_positive"] = ( + etrago.network.stores_t[value][h2_stores.index] + .clip(lower=0) + .sum(axis=1) + ) + df["H2_negative"] = ( + etrago.network.stores_t[value][h2_stores.index] + .clip(upper=0) + .sum(axis=1) + ) fig, ax = plt.subplots(figsize=(15, 8)) for c in df.columns: result = pd.Series(dtype=float) - color = colors[c.split('_')[0]] - for p in range(0,100): - result[ - p*df[c].abs().max() - *np.sign(df[c].sum())/100] = ( - df[c][df[c].abs()>p*0.01*df[c].abs().max()].size / df[c].size) *100 - - data_to_plot = pd.DataFrame(index = result.values, data = result.index*1e-3) - data_to_plot.columns = [c.split('_')[0]] - data_to_plot.plot(ax=ax, color = color, linewidth=3.0) - plt.axhline(y = 0.0, color = 'grey', linestyle = 'dotted') + color = colors[c.split("_")[0]] + for p in range(0, 100): + result[p * df[c].abs().max() * np.sign(df[c].sum()) / 100] = ( + df[c][df[c].abs() > p * 0.01 * df[c].abs().max()].size + / df[c].size + ) * 100 + + data_to_plot = pd.DataFrame( + index=result.values, data=result.index * 1e-3 + ) + data_to_plot.columns = [c.split("_")[0]] + data_to_plot.plot(ax=ax, color=color, linewidth=3.0) + plt.axhline(y=0.0, color="grey", linestyle="dotted") ax.set_xlim(0, 80) ax.set_xlabel("time in %") ax.set_ylabel("flexibility usage in GW") From b95fda944820f2d96e5e60105ae5abdd7f851c47 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Tue, 19 Sep 2023 13:47:57 +0200 Subject: [PATCH 17/20] Apply black --- etrago/tools/calc_results.py | 324 +++++++++++++++++++++-------------- 1 file changed, 195 insertions(+), 129 deletions(-) diff --git a/etrago/tools/calc_results.py b/etrago/tools/calc_results.py index fca593a97..f3e3338dd 100755 --- a/etrago/tools/calc_results.py +++ b/etrago/tools/calc_results.py @@ -22,7 +22,8 @@ calc_results.py defines methods to calculate results of eTraGo """ import os -if 'READTHEDOCS' not in os.environ: + +if "READTHEDOCS" not in os.environ: import time import logging @@ -31,16 +32,18 @@ logger = logging.getLogger(__name__) -__copyright__ = ("Flensburg University of Applied Sciences, " - "Europa-Universität Flensburg, " - "Centre for Sustainable Energy Systems, " - "DLR-Institute for Networked Energy Systems") +__copyright__ = ( + "Flensburg University of Applied Sciences, " + "Europa-Universität Flensburg, " + "Centre for Sustainable Energy Systems, " + "DLR-Institute for Networked Energy Systems" +) __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" __author__ = "ulfmueller, s3pp, wolfbunke, mariusves, lukasol" def _calc_storage_expansion(self): - """ Function that calulates storage expansion in MW + """Function that calulates storage expansion in MW Returns ------- @@ -48,14 +51,18 @@ def _calc_storage_expansion(self): storage expansion in MW """ - return (self.network.storage_units.p_nom_opt - - self.network.storage_units.p_nom_min - )[self.network.storage_units.p_nom_extendable]\ - .groupby(self.network.storage_units.carrier).sum() + return ( + ( + self.network.storage_units.p_nom_opt + - self.network.storage_units.p_nom_min + )[self.network.storage_units.p_nom_extendable] + .groupby(self.network.storage_units.carrier) + .sum() + ) def _calc_store_expansion(self): - """ Function that calulates store expansion in MW + """Function that calulates store expansion in MW Returns ------- @@ -63,13 +70,13 @@ def _calc_store_expansion(self): store expansion in MW """ - return (self.network.stores.e_nom_opt - - self.network.stores.e_nom_min - )[self.network.stores.e_nom_extendable] + return (self.network.stores.e_nom_opt - self.network.stores.e_nom_min)[ + self.network.stores.e_nom_extendable + ] def _calc_sectorcoupling_link_expansion(self): - """ Function that calulates expansion of sectorcoupling links in MW + """Function that calulates expansion of sectorcoupling links in MW Returns ------- @@ -81,21 +88,21 @@ def _calc_sectorcoupling_link_expansion(self): links = [0, 0, 0, 0] - l1 = ext_links[ext_links.carrier=='H2_to_power'] - l2 = ext_links[ext_links.carrier=='power_to_H2'] - l3 = ext_links[ext_links.carrier=='H2_to_CH4'] - l4 = ext_links[ext_links.carrier=='CH4_to_H2'] + l1 = ext_links[ext_links.carrier == "H2_to_power"] + l2 = ext_links[ext_links.carrier == "power_to_H2"] + l3 = ext_links[ext_links.carrier == "H2_to_CH4"] + l4 = ext_links[ext_links.carrier == "CH4_to_H2"] - links[0] = (l1.p_nom_opt-l1.p_nom_min).sum() - links[1] = (l2.p_nom_opt-l2.p_nom_min).sum() - links[2] = (l3.p_nom_opt-l3.p_nom_min).sum() - links[3] = (l4.p_nom_opt-l4.p_nom_min).sum() + links[0] = (l1.p_nom_opt - l1.p_nom_min).sum() + links[1] = (l2.p_nom_opt - l2.p_nom_min).sum() + links[2] = (l3.p_nom_opt - l3.p_nom_min).sum() + links[3] = (l4.p_nom_opt - l4.p_nom_min).sum() return links def _calc_network_expansion(self): - """ Function that calulates electrical network expansion in MW + """Function that calulates electrical network expansion in MW Returns ------- @@ -106,21 +113,20 @@ def _calc_network_expansion(self): network = self.network - lines = (network.lines.s_nom_opt - - network.lines.s_nom_min - )[network.lines.s_nom_extendable] + lines = (network.lines.s_nom_opt - network.lines.s_nom_min)[ + network.lines.s_nom_extendable + ] ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] + ext_dc_lines = ext_links[ext_links.carrier == "DC"] - dc_links = (ext_dc_lines.p_nom_opt - - ext_dc_lines.p_nom_min) + dc_links = ext_dc_lines.p_nom_opt - ext_dc_lines.p_nom_min return lines, dc_links def calc_investment_cost(self): - """ Function that calulates overall annualized investment costs. + """Function that calulates overall annualized investment costs. Returns ------- @@ -141,30 +147,40 @@ def calc_investment_cost(self): ext_lines = network.lines[network.lines.s_nom_extendable] ext_trafos = network.transformers[network.transformers.s_nom_extendable] ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] + ext_dc_lines = ext_links[ext_links.carrier == "DC"] if not ext_lines.empty: - network_costs[0] = ((ext_lines.s_nom_opt-ext_lines.s_nom_min - )*ext_lines.capital_cost).sum() + network_costs[0] = ( + (ext_lines.s_nom_opt - ext_lines.s_nom_min) + * ext_lines.capital_cost + ).sum() if not ext_trafos.empty: - network_costs[0] = network_costs[0]+(( - ext_trafos.s_nom_opt-ext_trafos.s_nom - )*ext_trafos.capital_cost).sum() + network_costs[0] = ( + network_costs[0] + + ( + (ext_trafos.s_nom_opt - ext_trafos.s_nom) + * ext_trafos.capital_cost + ).sum() + ) if not ext_dc_lines.empty: - network_costs[1] = ((ext_dc_lines.p_nom_opt-ext_dc_lines.p_nom_min - )*ext_dc_lines.capital_cost).sum() + network_costs[1] = ( + (ext_dc_lines.p_nom_opt - ext_dc_lines.p_nom_min) + * ext_dc_lines.capital_cost + ).sum() # links in other sectors / coupling different sectors link_costs = 0 - ext_links = ext_links[ext_links.carrier!='DC'] + ext_links = ext_links[ext_links.carrier != "DC"] if not ext_links.empty: - link_costs = ((ext_links.p_nom_opt-ext_links.p_nom_min - )*ext_links.capital_cost).sum() + link_costs = ( + (ext_links.p_nom_opt - ext_links.p_nom_min) + * ext_links.capital_cost + ).sum() # storage and store costs @@ -174,12 +190,10 @@ def calc_investment_cost(self): ext_store = network.stores[network.stores.e_nom_extendable] if not ext_storage.empty: - sto_costs[0] = (ext_storage.p_nom_opt* - ext_storage.capital_cost).sum() + sto_costs[0] = (ext_storage.p_nom_opt * ext_storage.capital_cost).sum() if not ext_store.empty: - sto_costs[1] = (ext_store.e_nom_opt* - ext_store.capital_cost).sum() + sto_costs[1] = (ext_store.e_nom_opt * ext_store.capital_cost).sum() return network_costs, link_costs, sto_costs @@ -196,21 +210,35 @@ def calc_marginal_cost(self): """ network = self.network - gen = network.generators_t.p.mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.generators.marginal_cost).sum() - link = abs(network.links_t.p0).mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.links.marginal_cost).sum() - stor = network.storage_units_t.p.mul( - network.snapshot_weightings.objective, axis=0).sum(axis=0).mul( - network.storage_units.marginal_cost).sum() + gen = ( + network.generators_t.p.mul( + network.snapshot_weightings.objective, axis=0 + ) + .sum(axis=0) + .mul(network.generators.marginal_cost) + .sum() + ) + link = ( + abs(network.links_t.p0) + .mul(network.snapshot_weightings.objective, axis=0) + .sum(axis=0) + .mul(network.links.marginal_cost) + .sum() + ) + stor = ( + network.storage_units_t.p.mul( + network.snapshot_weightings.objective, axis=0 + ) + .sum(axis=0) + .mul(network.storage_units.marginal_cost) + .sum() + ) marginal_cost = gen + link + stor return marginal_cost def calc_etrago_results(self): - """ Function that calculates main results of grid optimization + """Function that calculates main results of grid optimization and adds them to Etrago object. Returns @@ -218,99 +246,137 @@ def calc_etrago_results(self): None. """ - self.results = pd.DataFrame(columns=['unit', 'value'], - index=['annual system costs', - 'annual investment costs', - 'annual marginal costs', - 'annual electrical grid investment costs', - 'annual ac grid investment costs', - 'annual dc grid investment costs', - 'annual links investment costs', - 'annual storage+store investment costs', - 'annual electrical storage investment costs', - 'annual store investment costs', - 'battery storage expansion', - 'store expansion', - 'H2 store expansion', - 'CH4 store expansion', - 'heat store expansion', - 'storage+store expansion', - 'fuel cell links expansion', - 'electrolyzer links expansion', - 'methanisation links expansion', - 'Steam Methane Reformation links expansion', - 'abs. electrical grid expansion', - 'abs. electrical ac grid expansion', - 'abs. electrical dc grid expansion', - 'rel. electrical ac grid expansion', - 'rel. electrical dc grid expansion']) - - self.results.unit[self.results.index.str.contains('cost')] = 'EUR/a' - self.results.unit[self.results.index.str.contains('expansion')] = 'MW' - self.results.unit[self.results.index.str.contains('rel.')] = 'p.u.' + self.results = pd.DataFrame( + columns=["unit", "value"], + index=[ + "annual system costs", + "annual investment costs", + "annual marginal costs", + "annual electrical grid investment costs", + "annual ac grid investment costs", + "annual dc grid investment costs", + "annual links investment costs", + "annual storage+store investment costs", + "annual electrical storage investment costs", + "annual store investment costs", + "battery storage expansion", + "store expansion", + "H2 store expansion", + "CH4 store expansion", + "heat store expansion", + "storage+store expansion", + "fuel cell links expansion", + "electrolyzer links expansion", + "methanisation links expansion", + "Steam Methane Reformation links expansion", + "abs. electrical grid expansion", + "abs. electrical ac grid expansion", + "abs. electrical dc grid expansion", + "rel. electrical ac grid expansion", + "rel. electrical dc grid expansion", + ], + ) + + self.results.unit[self.results.index.str.contains("cost")] = "EUR/a" + self.results.unit[self.results.index.str.contains("expansion")] = "MW" + self.results.unit[self.results.index.str.contains("rel.")] = "p.u." # system costs - self.results.value['annual ac grid investment costs'] = calc_investment_cost(self)[0][0] - self.results.value['annual dc grid investment costs'] = calc_investment_cost(self)[0][1] - self.results.value['annual electrical grid investment costs'] = sum(calc_investment_cost(self)[0]) - - self.results.value['annual links investment costs'] = calc_investment_cost(self)[1] - - self.results.value['annual electrical storage investment costs'] = calc_investment_cost(self)[2][0] - self.results.value['annual store investment costs'] = calc_investment_cost(self)[2][1] - self.results.value['annual storage+store investment costs'] = sum(calc_investment_cost(self)[2]) - - - self.results.value['annual investment costs'] = \ - sum(calc_investment_cost(self)[0]) + calc_investment_cost(self)[1] + sum(calc_investment_cost(self)[2]) - self.results.value['annual marginal costs'] = calc_marginal_cost(self) - - self.results.value['annual system costs'] = \ - self.results.value['annual investment costs'] + self.results.value['annual marginal costs'] + self.results.value[ + "annual ac grid investment costs" + ] = calc_investment_cost(self)[0][0] + self.results.value[ + "annual dc grid investment costs" + ] = calc_investment_cost(self)[0][1] + self.results.value["annual electrical grid investment costs"] = sum( + calc_investment_cost(self)[0] + ) + + self.results.value["annual links investment costs"] = calc_investment_cost( + self + )[1] + + self.results.value[ + "annual electrical storage investment costs" + ] = calc_investment_cost(self)[2][0] + self.results.value["annual store investment costs"] = calc_investment_cost( + self + )[2][1] + self.results.value["annual storage+store investment costs"] = sum( + calc_investment_cost(self)[2] + ) + + self.results.value["annual investment costs"] = ( + sum(calc_investment_cost(self)[0]) + + calc_investment_cost(self)[1] + + sum(calc_investment_cost(self)[2]) + ) + self.results.value["annual marginal costs"] = calc_marginal_cost(self) + + self.results.value["annual system costs"] = ( + self.results.value["annual investment costs"] + + self.results.value["annual marginal costs"] + ) # storage and store expansion network = self.network if not network.storage_units[network.storage_units.p_nom_extendable].empty: - - self.results.value['battery storage expansion'] = \ - _calc_storage_expansion(self).sum() + self.results.value[ + "battery storage expansion" + ] = _calc_storage_expansion(self).sum() store = _calc_store_expansion(self) - self.results.value['store expansion'] = store.sum() - self.results.value['H2 store expansion'] = \ - store[store.index.str.contains('H2')].sum() - self.results.value['CH4 store expansion'] = \ - store[store.index.str.contains('CH4')].sum() - self.results.value['heat store expansion'] = \ - store[store.index.str.contains('heat')].sum() - - self.results.value['storage+store expansion'] = \ - self.results.value['battery storage expansion'] + self.results.value['store expansion'] + self.results.value["store expansion"] = store.sum() + self.results.value["H2 store expansion"] = store[ + store.index.str.contains("H2") + ].sum() + self.results.value["CH4 store expansion"] = store[ + store.index.str.contains("CH4") + ].sum() + self.results.value["heat store expansion"] = store[ + store.index.str.contains("heat") + ].sum() + + self.results.value["storage+store expansion"] = ( + self.results.value["battery storage expansion"] + + self.results.value["store expansion"] + ) # links expansion if not network.links[network.links.p_nom_extendable].empty: - links = _calc_sectorcoupling_link_expansion(self) - self.results.value['fuel cell links expansion'] = links[0] - self.results.value['electrolyzer links expansion'] = links[1] - self.results.value['methanisation links expansion'] = links[2] - self.results.value['Steam Methane Reformation links expansion'] = links[3] + self.results.value["fuel cell links expansion"] = links[0] + self.results.value["electrolyzer links expansion"] = links[1] + self.results.value["methanisation links expansion"] = links[2] + self.results.value[ + "Steam Methane Reformation links expansion" + ] = links[3] # grid expansion if not network.lines[network.lines.s_nom_extendable].empty: - - self.results.value['abs. electrical ac grid expansion'] = _calc_network_expansion(self)[0].sum() - self.results.value['abs. electrical dc grid expansion'] = _calc_network_expansion(self)[1].sum() - self.results.value['abs. electrical grid expansion'] = self.results.value['abs. electrical ac grid expansion'] + self.results.value['abs. electrical dc grid expansion'] + self.results.value[ + "abs. electrical ac grid expansion" + ] = _calc_network_expansion(self)[0].sum() + self.results.value[ + "abs. electrical dc grid expansion" + ] = _calc_network_expansion(self)[1].sum() + self.results.value["abs. electrical grid expansion"] = ( + self.results.value["abs. electrical ac grid expansion"] + + self.results.value["abs. electrical dc grid expansion"] + ) ext_lines = network.lines[network.lines.s_nom_extendable] ext_links = network.links[network.links.p_nom_extendable] - ext_dc_lines = ext_links[ext_links.carrier=='DC'] - - self.results.value['rel. electrical ac grid expansion'] = (_calc_network_expansion(self)[0].sum() / ext_lines.s_nom.sum()) - self.results.value['rel. electrical dc grid expansion'] = (_calc_network_expansion(self)[1].sum() / ext_dc_lines.p_nom.sum()) \ No newline at end of file + ext_dc_lines = ext_links[ext_links.carrier == "DC"] + + self.results.value["rel. electrical ac grid expansion"] = ( + _calc_network_expansion(self)[0].sum() / ext_lines.s_nom.sum() + ) + self.results.value["rel. electrical dc grid expansion"] = ( + _calc_network_expansion(self)[1].sum() / ext_dc_lines.p_nom.sum() + ) From e5a8bcf40eb3eb54c769d69bebafed99693bf2a8 Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 25 Sep 2023 14:56:58 +0200 Subject: [PATCH 18/20] Add shifted_energy function to etrago object --- etrago/tools/network.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etrago/tools/network.py b/etrago/tools/network.py index 8bd954326..95dbf3f3c 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -72,6 +72,7 @@ plot_h2_summary, plot_heat_loads, plot_heat_summary, + shifted_energy, ) from etrago.tools.utilities import ( add_missing_components, @@ -321,6 +322,8 @@ def __init__( manual_fixes_datamodel = manual_fixes_datamodel + shifted_energy = shifted_energy + def dc_lines(self): return self.filter_links_by_carrier("DC", like=False) From c081a174533fda2a10d925e938ecb1d48925cfba Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 25 Sep 2023 15:42:28 +0200 Subject: [PATCH 19/20] Import db functions from etrago --- etrago/tools/network.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/etrago/tools/network.py b/etrago/tools/network.py index a98a45f1e..eeb8dd02b 100644 --- a/etrago/tools/network.py +++ b/etrago/tools/network.py @@ -30,14 +30,13 @@ import pandas as pd if "READTHEDOCS" not in os.environ: - from egoio.tools import db + from etrago.tools import db from etrago import __version__ from etrago.cluster.disaggregation import run_disaggregation from etrago.cluster.electrical import ehv_clustering, run_spatial_clustering from etrago.cluster.gas import run_spatial_clustering_gas from etrago.cluster.snapshot import skip_snapshots, snapshot_clustering -from etrago.tools import db from etrago.tools.calc_results import calc_etrago_results from etrago.tools.execute import ( dispatch_disaggregation, From 9cb4e5f3fb00b46060bcbfe0c316a2dd31226def Mon Sep 17 00:00:00 2001 From: ClaraBuettner Date: Mon, 25 Sep 2023 15:44:12 +0200 Subject: [PATCH 20/20] Apply isort --- etrago/tools/utilities.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etrago/tools/utilities.py b/etrago/tools/utilities.py index 9f99d4598..d44171bc1 100755 --- a/etrago/tools/utilities.py +++ b/etrago/tools/utilities.py @@ -36,10 +36,11 @@ import sqlalchemy.exc if "READTHEDOCS" not in os.environ: - from etrago.tools import db from shapely.geometry import Point import geopandas as gpd + from etrago.tools import db + logger = logging.getLogger(__name__)