From 8fe70e11488659f98f190b9ba788af5eef3e27c6 Mon Sep 17 00:00:00 2001 From: Orhidea Shatri <140660448+scrappie1@users.noreply.github.com> Date: Wed, 20 May 2026 13:40:31 +0200 Subject: [PATCH 1/4] Harmonize printer import --- CaseStudy.py | 2 +- ExcelReader.py | 2 +- ExcelWriter.py | 2 +- nrel118-reader.py | 2 +- printer.py | 5 +++++ tests/test_ExcelReaderWriter.py | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CaseStudy.py b/CaseStudy.py index 8f1bb5f..bb0cc6e 100644 --- a/CaseStudy.py +++ b/CaseStudy.py @@ -12,7 +12,7 @@ import ExcelReader from InOutModule import Utilities -from printer import Printer +from InOutModule.printer import Printer printer = Printer.getInstance() diff --git a/ExcelReader.py b/ExcelReader.py index 6ae4ab9..d940c42 100644 --- a/ExcelReader.py +++ b/ExcelReader.py @@ -5,7 +5,7 @@ from openpyxl import load_workbook from openpyxl.utils.cell import get_column_letter -from printer import Printer +from InOutModule.printer import Printer printer = Printer.getInstance() diff --git a/ExcelWriter.py b/ExcelWriter.py index f1ee83e..9dfaccb 100644 --- a/ExcelWriter.py +++ b/ExcelWriter.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: from CaseStudy import CaseStudy from TableDefinition import CellStyle, Alignment, Font, Color, Text, Column, NumberFormat, TableDefinition -from printer import Printer +from InOutModule.printer import Printer package_directory_ExcelWriter = os.path.dirname(os.path.abspath(__file__)) diff --git a/nrel118-reader.py b/nrel118-reader.py index 3ef7ec4..784f31e 100644 --- a/nrel118-reader.py +++ b/nrel118-reader.py @@ -2,7 +2,7 @@ import pandas as pd -from printer import Printer +from InOutModule.printer import Printer printer = Printer.getInstance() diff --git a/printer.py b/printer.py index 1517c9c..19baf42 100644 --- a/printer.py +++ b/printer.py @@ -5,6 +5,11 @@ from rich.console import Console from rich.markup import escape +if __name__ == "printer": + raise ImportError( + "Import Printer as 'from InOutModule.printer import Printer', not 'from printer import Printer'" + ) + class Printer: """ diff --git a/tests/test_ExcelReaderWriter.py b/tests/test_ExcelReaderWriter.py index e33f829..baa578f 100644 --- a/tests/test_ExcelReaderWriter.py +++ b/tests/test_ExcelReaderWriter.py @@ -2,7 +2,7 @@ import ExcelReader as ExcelReader from ExcelWriter import ExcelWriter -from printer import Printer +from InOutModule.printer import Printer printer = Printer.getInstance() From 2ff322e9a35276e8262ff96be42090701ec0503b Mon Sep 17 00:00:00 2001 From: Orhidea Shatri <140660448+scrappie1@users.noreply.github.com> Date: Wed, 20 May 2026 13:41:15 +0200 Subject: [PATCH 2/4] Add check for duplicate lines --- CaseStudy.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CaseStudy.py b/CaseStudy.py index bb0cc6e..c06e4ce 100644 --- a/CaseStudy.py +++ b/CaseStudy.py @@ -256,6 +256,45 @@ def copy(self): new_self = copy.deepcopy(self) return new_self + def check_duplicate_lines_dPower_Network(self): + """ + Check dPower_Network for duplicate and parallel lines. + i -> j and j -> i are considered as the same line. + Lines with same endpoints and circuit -> error. + Lines with same endpoints and different circuits-> warning. + :return: None + """ + dPower_Network = self.dPower_Network.reset_index() + line_keys_without_circuit = dPower_Network.apply(lambda row: frozenset((row["i"], row["j"])), axis=1) + dPower_Network["_line_key_without_circuit"] = line_keys_without_circuit + line_keys = dPower_Network.apply(lambda row: (row["scenario"], line_keys_without_circuit[row.name], row["c"]), axis=1) + duplicate_lines = dPower_Network[line_keys.duplicated(keep=False)] + + if not duplicate_lines.empty: + duplicate_line = duplicate_lines.iloc[0] + raise ValueError( + f"Duplicate network line found in (at least) scenario '{duplicate_line['scenario']}' " + f"for line {duplicate_line['i']} <-> {duplicate_line['j']} " + f"with circuit '{duplicate_line['c']}'. " + "If the lines should be parallel, assign different 'c' for each parallel line." + ) + + lines_with_multiple_circuits = dPower_Network[dPower_Network.groupby(["scenario", "_line_key_without_circuit"])["c"].transform("nunique") > 1] + + if not lines_with_multiple_circuits.empty: + parallel_line = lines_with_multiple_circuits.iloc[0] # for printing the example: use first row that belongs to a parallel line group + parallel_group = lines_with_multiple_circuits[ + (lines_with_multiple_circuits["scenario"] == parallel_line["scenario"]) # same scenario + & (lines_with_multiple_circuits["_line_key_without_circuit"] == parallel_line["_line_key_without_circuit"]) + ] + circuits = parallel_group["c"].head(2).tolist() # show only first two circuit IDs + + printer.warning( + f"Parallel network lines found in (at least) scenario '{parallel_line['scenario']}' " + f"for line {parallel_line['i']} <-> {parallel_line['j']} " + f"with circuits {circuits}." + ) + def equal_to(self, cs: typing.Self) -> bool: """ Check if this CaseStudy is equal to another CaseStudy, checking all dataframes for equality. @@ -324,6 +363,7 @@ def scale_dPower_Parameters(self): self.dPower_Parameters["pMaxAngleDCOPF"] *= self.angle_to_rad_scaling_factor # Convert angle from degrees to radians def scale_dPower_Network(self): + self.check_duplicate_lines_dPower_Network() self.dPower_Network["pInvestCost"] = self.dPower_Network["pInvestCost"].fillna(0) self.dPower_Network["pPmax"] *= self.power_scaling_factor From 0bee439247d4b6789cac8fe1dbc21576ee11a0d0 Mon Sep 17 00:00:00 2001 From: Orhidea Shatri <140660448+scrappie1@users.noreply.github.com> Date: Wed, 20 May 2026 14:26:04 +0200 Subject: [PATCH 3/4] Fix pytest path --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a72a436..25294be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,4 +8,7 @@ version = "0.0.0-dev" readme = "README.md" [tool.setuptools] -py-modules = ['CaseStudy', 'ExcelReader', 'ExcelWriter', 'printer', 'PypsaReader', 'pypsa_helper', 'SQLiteWriter', 'TableDefinition'] \ No newline at end of file +py-modules = ['CaseStudy', 'ExcelReader', 'ExcelWriter', 'printer', 'PypsaReader', 'pypsa_helper', 'SQLiteWriter', 'TableDefinition'] + +[tool.pytest.ini_options] +pythonpath = [".."] From 5011208258ab66a2d26fe17c7b9b4e79a2d2db22 Mon Sep 17 00:00:00 2001 From: Orhidea Shatri <140660448+scrappie1@users.noreply.github.com> Date: Wed, 20 May 2026 14:53:39 +0200 Subject: [PATCH 4/4] Change location of function call --- CaseStudy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CaseStudy.py b/CaseStudy.py index c06e4ce..614a128 100644 --- a/CaseStudy.py +++ b/CaseStudy.py @@ -196,6 +196,8 @@ def __init__(self, printer.error(f"Error reading for '{attr_name}': {exc}") raise exc + self.check_duplicate_lines_dPower_Network() + # === SEQUENTIAL DEPENDENTS === if dPower_WeightsRP is not None: self.dPower_WeightsRP = dPower_WeightsRP @@ -363,7 +365,6 @@ def scale_dPower_Parameters(self): self.dPower_Parameters["pMaxAngleDCOPF"] *= self.angle_to_rad_scaling_factor # Convert angle from degrees to radians def scale_dPower_Network(self): - self.check_duplicate_lines_dPower_Network() self.dPower_Network["pInvestCost"] = self.dPower_Network["pInvestCost"].fillna(0) self.dPower_Network["pPmax"] *= self.power_scaling_factor