From 8ed6f269308cb0ff4d9df71805b3b11da3637ae2 Mon Sep 17 00:00:00 2001 From: santi Date: Fri, 27 Sep 2024 14:20:07 +0100 Subject: [PATCH 1/6] 5.1.44 --- src/GridCal/__version__.py | 2 +- src/GridCalEngine/__version__.py | 2 +- src/GridCalServer/__version__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GridCal/__version__.py b/src/GridCal/__version__.py index d245878ff..93b5425a2 100644 --- a/src/GridCal/__version__.py +++ b/src/GridCal/__version__.py @@ -16,7 +16,7 @@ _current_year_ = datetime.datetime.now().year # do not forget to keep a three-number version!!! -__GridCal_VERSION__ = "5.1.42" +__GridCal_VERSION__ = "5.1.44" url = 'https://github.com/SanPen/GridCal' diff --git a/src/GridCalEngine/__version__.py b/src/GridCalEngine/__version__.py index 47b7e2242..970fd3bca 100644 --- a/src/GridCalEngine/__version__.py +++ b/src/GridCalEngine/__version__.py @@ -16,7 +16,7 @@ _current_year_ = datetime.datetime.now().year # do not forget to keep a three-number version!!! -__GridCalEngine_VERSION__ = "5.1.42" +__GridCalEngine_VERSION__ = "5.1.44" url = 'https://github.com/SanPen/GridCal' diff --git a/src/GridCalServer/__version__.py b/src/GridCalServer/__version__.py index 33fb6605b..1e61083b2 100644 --- a/src/GridCalServer/__version__.py +++ b/src/GridCalServer/__version__.py @@ -16,7 +16,7 @@ _current_year_ = datetime.datetime.now().year # do not forget to keep a three-number version!!! -__GridCalServer_VERSION__ = "5.1.42" +__GridCalServer_VERSION__ = "5.1.44" url = 'https://github.com/SanPen/GridCal' From 8754ae02513912f71739a292339e547357059d2d Mon Sep 17 00:00:00 2001 From: santi Date: Fri, 27 Sep 2024 16:22:12 +0100 Subject: [PATCH 2/6] allowing newer ortools installations --- .idea/workspace.xml | 43 ++++++++++++++++++++------------------ requirements.txt | 2 +- src/GridCalEngine/setup.py | 2 +- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 7d2ed87ad..5f9bae095 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -28,8 +28,10 @@ - + - - + + + + + + - { + "keyToString": { + "ASKED_ADD_EXTERNAL_FILES": "true", + "Git.Branch.Popup.ShowAllRemotes": "true", + "MATLAB_INTERPRETER": "/usr/local/MATLAB/R2018a/bin/matlab", + "Python tests.Nosetests for test_power_flow.test_zip.executor": "Debug", + "Python tests.Nosetests for tests.test_hydro.executor": "Run", + "Python tests.Nosetests for tests.test_opf_time_series.test_opf_ts.executor": "Run", + "Python tests.Nosetests for tests.test_topology_processor.executor": "Run", + "Python tests.Nosetests in admittance_matrix_test.py.executor": "Run", + "Python tests.Nosetests in deep_copy_test.py.executor": "Run", + "Python tests.Nosetests in tests.executor": "Run", + "Python tests.pytest in tests.executor": "Run", + "Python.AnalysisDialogue.executor": "Run", + "Python.ExecuteGridCal.executor": "Run", + "Python.cgmes_rdfs_graph.executor": "Run", + "Python.cpp_clases.executor": "Debug", + "Python.new_circuit_objects.executor": "Run", + "Python.node_widget.executor": "Run", + "Python.pymoo_example.executor": "Debug", + "Python.trial_code.executor": "Run", + "Python.update_gui_file (1).executor": "Run", + "Python.update_gui_file.executor": "Run", + "Python.upload_to_pypi.executor": "Run", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "WebServerToolWindowFactoryState": "false", + "git-widget-placeholder": "199__finalize__cgmes__import", + "last_opened_file_path": "C:/Work/git_local/GridCal/doc", + "node.js.detected.package.eslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "run.code.analysis.last.selected.profile": "aDefault", + "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable", + "two.files.diff.last.used.file": "C:/WorkProjects/PycharmProjects/GridCal/src/trunk/cgmes_py_generator/cgmes_v2_4_15/cgmes_enums.py", + "vue.rearranger.settings.migration": "true" } -}]]> +} @@ -1373,7 +1379,11 @@ - + + + + + 1656059954202 @@ -1718,7 +1728,7 @@ - - @@ -1777,7 +1786,8 @@ - @@ -2299,6 +2309,17 @@ 144 @@ -2649,6 +2670,7 @@ + @@ -2657,7 +2679,7 @@ - + @@ -2673,6 +2695,7 @@ + diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py index b20bfb09c..610b85cbb 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py @@ -122,7 +122,7 @@ def add_segment(self, segment: MapLineSegment): """ self.segments_list.append(segment) - def set_colour(self, color: QColor, w, style: Qt.PenStyle, tool_tip: str = '') -> None: + def set_colour(self, color: QColor, style: Qt.PenStyle, tool_tip: str = '') -> None: """ Set color and style :param color: QColor instance @@ -133,7 +133,7 @@ def set_colour(self, color: QColor, w, style: Qt.PenStyle, tool_tip: str = '') - """ for segment in self.segments_list: segment.setToolTip(tool_tip) - segment.set_colour(color=color, w=w, style=style) + segment.set_colour(color=color, style=style) def update_connectors(self) -> None: """ diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_segment.py b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_segment.py index c5ed83920..cd32815ff 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_segment.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_segment.py @@ -76,7 +76,7 @@ def __init__(self, first: NodeGraphicItem, second: NodeGraphicItem, container: M self.first.add_position_change_callback(self.set_from_side_coordinates) self.second.add_position_change_callback(self.set_to_side_coordinates) - self.set_colour(self.color, self.width, self.style) + self.set_colour(self.color, self.style) self.update_endings() self.needsUpdate = True self.setZValue(0) @@ -115,7 +115,7 @@ def set_width(self, width: float): self.arrow_p_to.label.setScale(width) self.arrow_q_to.label.setScale(width) - def set_colour(self, color: QColor, w: float, style: Qt.PenStyle): + def set_colour(self, color: QColor, style: Qt.PenStyle): """ Set color and style :param color: QColor instance @@ -124,14 +124,13 @@ def set_colour(self, color: QColor, w: float, style: Qt.PenStyle): :return: """ - pen = QPen(color, w, style, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin) - pen.setWidthF(w) + pen = QPen(color, self.width, style, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin) self.setPen(pen) - self.arrow_p_from.set_colour(color, w, style) - self.arrow_q_from.set_colour(color, w, style) - self.arrow_p_to.set_colour(color, w, style) - self.arrow_q_to.set_colour(color, w, style) + self.arrow_p_from.set_colour(color, self.arrow_p_from.w, style) + self.arrow_q_from.set_colour(color, self.arrow_q_from.w, style) + self.arrow_p_to.set_colour(color, self.arrow_p_to.w, style) + self.arrow_q_to.set_colour(color, self.arrow_q_to.w, style) def set_from_side_coordinates(self, x: float, y: float): """ @@ -286,7 +285,7 @@ def set_enable(self, val=True): self.color = OTHER['color'] # Set pen for everyone - self.set_colour(self.color, self.width, self.style) + self.set_colour(self.color, self.style) def enable_disable_label_drawing(self): """ diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py index 499d2cdbc..e266f302b 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py @@ -84,9 +84,9 @@ def __init__(self, self.setAcceptHoverEvents(True) # Allow selecting the node - self.setFlag(self.GraphicsItemFlag.ItemIsSelectable | QGraphicsRectItem.ItemIsMovable) + self.setFlag(self.GraphicsItemFlag.ItemIsSelectable | self.GraphicsItemFlag.ItemIsMovable) - self.setCursor(QCursor(Qt.PointingHandCursor)) + self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) # Create a pen with reduced line width self.change_pen_width(0.5) @@ -113,6 +113,7 @@ def set_size(self, r: float): rect = self.rect() rect.setWidth(r) rect.setHeight(r) + self.radius = r # change the width and height while keeping the same center r2 = r / 2 @@ -121,8 +122,8 @@ def set_size(self, r: float): # Set the new rectangle with the updated dimensions self.setRect(new_x, new_y, r, r) - self.radius = r + # update the callbacks position for the lines to move accordingly self.set_callabacks(new_x + r2, new_y + r2) for vl_graphics in self.voltage_level_graphics: @@ -130,7 +131,21 @@ def set_size(self, r: float): self.update_diagram() - def set_api_object_color(self): + def resize_voltage_levels(self): + """ + + :return: + """ + max_vl = 1.0 # 1 KV + for vl_graphics in self.voltage_level_graphics: + max_vl = max(max_vl, vl_graphics.api_object.Vnom) + + for vl_graphics in self.voltage_level_graphics: + # radius here is the width, therefore we need to send W/2 + scale = vl_graphics.api_object.Vnom / max_vl * 0.5 + vl_graphics.set_size(r=self.radius * scale) + + def set_api_object_color(self) -> None: """ Gather the API object color and update this objects """ @@ -169,12 +184,20 @@ def sort_voltage_levels(self) -> None: """ Set the Zorder based on the voltage level voltage """ - # TODO: Check this - sorted_objects = sorted(self.voltage_level_graphics, key=lambda x: x.api_object.Vnom) + max_vl = 1.0 # 1 KV + for vl_graphics in self.voltage_level_graphics: + max_vl = max(max_vl, vl_graphics.api_object.Vnom) + + for vl_graphics in self.voltage_level_graphics: + scale = vl_graphics.api_object.Vnom / max_vl * 0.8 + vl_graphics.set_size(r=self.radius * scale) + vl_graphics.center_on_substation() + + sorted_objects = sorted(self.voltage_level_graphics, key=lambda x: -x.api_object.Vnom) for i, vl_graphics in enumerate(sorted_objects): vl_graphics.setZValue(i) - def update_diagram(self): + def update_diagram(self) -> None: """ Updates the element position in the diagram (to save) :return: @@ -246,7 +269,7 @@ def hoverEnterEvent(self, event: QtWidgets.QGraphicsSceneHoverEvent) -> None: # self.editor.map.view.in_item = True self.set_color(self.hoover_color, self.color) self.hovered = True - QApplication.instance().setOverrideCursor(Qt.PointingHandCursor) + QApplication.instance().setOverrideCursor(Qt.CursorShape.PointingHandCursor) def hoverLeaveEvent(self, event: QtWidgets.QGraphicsSceneHoverEvent) -> None: """ @@ -392,9 +415,8 @@ def add_voltage_level(self) -> None: self.editor.circuit.add_voltage_level(vl) self.editor.circuit.add_bus(obj=bus) - - self.editor.add_api_voltage_level(substation_graphics=self, - api_object=vl) + self.editor.add_api_voltage_level(substation_graphics=self, api_object=vl) + self.sort_voltage_levels() def set_color(self, inner_color: QColor = None, border_color: QColor = None) -> None: """ @@ -433,14 +455,6 @@ def getPos(self) -> QPointF: return center_point - # def resize(self, new_radius: float) -> None: - # """ - # Resize the node. - # :param new_radius: New radius for the node. - # """ - # self.radius = new_radius - # self.setRect(self.x - new_radius, self.y - new_radius, new_radius * 2, new_radius * 2) - def change_pen_width(self, width: float) -> None: """ Change the pen width for the node. diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Substation/voltage_level_graphic_item.py b/src/GridCal/Gui/Diagrams/MapWidget/Substation/voltage_level_graphic_item.py index f0b46d266..93ba2ed65 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/Substation/voltage_level_graphic_item.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/Substation/voltage_level_graphic_item.py @@ -26,7 +26,6 @@ from GridCalEngine.Devices.Substation.voltage_level import VoltageLevel from GridCalEngine.Devices.Substation.bus import Bus -from GridCalEngine.enumerations import DeviceType if TYPE_CHECKING: # Only imports the below statements during type checking from GridCal.Gui.Diagrams.MapWidget.grid_map_widget import GridMapWidget @@ -64,21 +63,25 @@ def __init__(self, api_object=api_object, editor=editor, draw_labels=draw_labels) - QGraphicsEllipseItem.__init__(self, parent_center.x(), parent_center.y(), r * api_object.Vnom * 0.01, - r * api_object.Vnom * 0.01, parent) + QGraphicsEllipseItem.__init__(self, + parent_center.x(), + parent_center.y(), + r * api_object.Vnom * 0.01, + r * api_object.Vnom * 0.01, + parent) parent.register_voltage_level(vl=self) self.editor: GridMapWidget = editor # to reinforce the type + self.api_object: VoltageLevel = api_object # to reinforce the type self.radius = r * api_object.Vnom * 0.01 - # print(f"VL created at x:{parent_center.x()}, y:{parent_center.y()}") self.setAcceptHoverEvents(True) # Enable hover events for the item - # self.setFlag(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable) # Allow moving the node - self.setFlag( - self.GraphicsItemFlag.ItemIsSelectable | self.GraphicsItemFlag.ItemIsMovable) # Allow selecting the node + + # Allow moving the node + self.setFlag(self.GraphicsItemFlag.ItemIsSelectable | self.GraphicsItemFlag.ItemIsMovable) # Create a pen with reduced line width self.change_pen_width(0.5) @@ -114,6 +117,26 @@ def move_to_xy(self, x: float, y: float): self.setRect(x, y, self.rect().width(), self.rect().height()) return x, y + def set_size(self, r: float): + """ + + :param r: radius in pixels + :return: + """ + # if r != self.radius: + rect = self.rect() + rect.setWidth(r) + rect.setHeight(r) + self.radius = r + + # change the width and height while keeping the same center + r2 = r / 2 + new_x = rect.x() - r2 + new_y = rect.y() - r2 + + # Set the new rectangle with the updated dimensions + self.setRect(new_x, new_y, r, r) + def updateDiagram(self) -> None: """ @@ -124,8 +147,6 @@ def updateDiagram(self) -> None: lat, long = self.editor.to_lat_lon(x=center_point.x() + real_position.x(), y=center_point.y() + real_position.y()) - print(f'Updating VL position id:{self.api_object.idtag}, lat:{lat}, lon:{long}') - self.editor.update_diagram_element(device=self.api_object, latitude=lat, longitude=long, diff --git a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py index b4fc2acdc..9f1b43f46 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py @@ -57,7 +57,7 @@ import GridCalEngine.Devices.Diagrams.palettes as palettes from GridCal.Gui.Diagrams.graphics_manager import ALL_MAP_GRAPHICS from GridCal.Gui.Diagrams.MapWidget.Tiles.tiles import Tiles -from GridCal.Gui.Diagrams.base_diagram_widget import BaseDiagramWidget, qimage_to_cv +from GridCal.Gui.Diagrams.base_diagram_widget import BaseDiagramWidget from GridCal.Gui.messages import error_msg if TYPE_CHECKING: @@ -873,7 +873,7 @@ def wheelEvent(self, event: QWheelEvent): self.update_device_sizes() - def update_device_sizes(self): + def get_branch_width(self): """ :return: @@ -882,6 +882,13 @@ def update_device_sizes(self): min_zoom = self.map.min_level zoom = self.map.zoom_factor scale = self.diagram.min_branch_width + (zoom - min_zoom) / (max_zoom - min_zoom) + return scale + + def update_device_sizes(self): + """ + + :return: + """ # rescale lines for dev_tpe in [DeviceType.LineDevice, @@ -890,7 +897,7 @@ def update_device_sizes(self): DeviceType.FluidPathDevice]: graphics_dict = self.graphics_manager.get_device_type_dict(device_type=dev_tpe) for key, lne in graphics_dict.items(): - lne.set_width_scale(scale) + lne.set_width_scale(self.get_branch_width()) # rescale substations data: Dict[str, SubstationGraphicItem] = self.graphics_manager.get_device_type_dict(DeviceType.SubstationDevice) @@ -1070,9 +1077,9 @@ def colour_results(self, weight = int( np.floor(min_branch_width + Sfnorm[i] * (max_branch_width - min_branch_width) * 0.1)) else: - weight = 0.5 + weight = self.get_branch_width() - graphic_object.set_colour(color=color, w=weight, style=style, tool_tip=tooltip) + graphic_object.set_colour(color=color, style=style, tool_tip=tooltip) if hasattr(graphic_object, 'set_arrows_with_power'): graphic_object.set_arrows_with_power( @@ -1130,7 +1137,7 @@ def colour_results(self, weight = int( np.floor(min_branch_width + Sfnorm[i] * (max_branch_width - min_branch_width) * 0.1)) else: - weight = 0.5 + weight = self.get_branch_width() tooltip = str(i) + ': ' + graphic_object.api_object.name tooltip += '\n' + loading_label + ': ' + "{:10.4f}".format( @@ -1145,7 +1152,7 @@ def colour_results(self, else: graphic_object.set_arrows_with_hvdc_power(Pf=hvdc_Pf[i], Pt=-hvdc_Pf[i]) - graphic_object.set_colour(color=color, w=weight, style=style, tool_tip=tooltip) + graphic_object.set_colour(color=color, style=style, tool_tip=tooltip) def get_image(self, transparent: bool = False) -> QImage: """ diff --git a/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py b/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py index eb295467f..a6e6a8115 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py @@ -124,7 +124,7 @@ def __init__(self, # Create a QGraphicsProxyWidget for the QLabel self.label_proxy_widget = QGraphicsProxyWidget() self.label_proxy_widget.setWidget(self.attribution_label) - self.label_proxy_widget.setFlag(QGraphicsItem.ItemIgnoresTransformations) + self.label_proxy_widget.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIgnoresTransformations) self.update_label_position() # Add the proxy widget to the scene @@ -150,6 +150,8 @@ def __init__(self, self.scale(initial_zoom_factor, initial_zoom_factor) + self.setRenderHints(QPainter.RenderHint.Antialiasing | QPainter.RenderHint.SmoothPixmapTransform) + def set_notice(self, val: str): """ From 5bfb2fe84b0062c0edc07b1987ccaeccde2ca8b0 Mon Sep 17 00:00:00 2001 From: santi Date: Tue, 1 Oct 2024 08:34:04 +0100 Subject: [PATCH 4/6] 5.1.45 --- .idea/workspace.xml | 20 ++++++-------------- src/GridCal/__version__.py | 2 +- src/GridCalEngine/__version__.py | 2 +- src/GridCalServer/__version__.py | 2 +- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 24cc1f2d5..5ddc63b0d 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -28,15 +28,7 @@ - + + + + + + + + + + + + - + + + + - - - + - + - @@ -1375,7 +1391,7 @@ - + 1656059954202 @@ -1720,7 +1736,7 @@ - @@ -1754,7 +1770,6 @@ - @@ -1779,7 +1794,8 @@ - @@ -2599,7 +2615,7 @@ - + @@ -2671,7 +2687,7 @@ - + diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py index e266f302b..6dfb0b454 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py @@ -289,34 +289,39 @@ def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent): add_menu_entry(menu=menu, text="Add voltage level", - icon_path="", + icon_path=":/Icons/icons/plus.svg", function_ptr=self.add_voltage_level) add_menu_entry(menu=menu, text="Create line from here", - icon_path="", + icon_path=":/Icons/icons/plus.svg", function_ptr=self.create_new_line) add_menu_entry(menu=menu, - text="Move to API coordinates", - icon_path="", + text="Set coordinates to DB", + icon_path=":/Icons/icons/down.svg", function_ptr=self.move_to_api_coordinates) add_menu_entry(menu=menu, - text="Remove", - icon_path="", + text="Remove from schematic", + icon_path=":/Icons/icons/delete_schematic.svg", function_ptr=self.remove_function) - add_menu_entry(menu=menu, - text="ADD node", - icon_path=":/Icons/icons/divide.svg", - function_ptr=self.add_function) + # add_menu_entry(menu=menu, + # text="ADD node", + # icon_path=":/Icons/icons/plus.svg", + # function_ptr=self.add_function) add_menu_entry(menu=menu, text="Show diagram", - icon_path="", + icon_path=":/Icons/icons/grid_icon.svg", function_ptr=self.new_substation_diagram) + add_menu_entry(menu=menu, + text="Plot", + icon_path=":/Icons/icons/plot.svg", + function_ptr=self.plot) + menu.exec_(event.screenPos()) def create_new_line(self): @@ -366,7 +371,7 @@ def remove_function(self) -> None: "Remove substation graphics") if ok: - self.editor.removeSubstation(self) + self.editor.removeSubstation(substation=self) def move_to_api_coordinates(self): """ @@ -387,6 +392,13 @@ def new_substation_diagram(self): """ self.editor.new_substation_diagram(substation=self.api_object) + def plot(self): + """ + Plot the substations data + """ + i = self.editor.circuit.get_substations().index(self.api_object) + self.editor.plot_substation(i, self.api_object) + def add_voltage_level(self) -> None: """ Add Voltage Level diff --git a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py index 9f1b43f46..cc2768b20 100644 --- a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py +++ b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py @@ -20,6 +20,9 @@ import json import numpy as np import math +import pandas as pd +from matplotlib import pyplot as plt + from PySide6.QtWidgets import QGraphicsItem from collections.abc import Callable from PySide6.QtSvg import QSvgGenerator @@ -40,9 +43,11 @@ from GridCalEngine.Devices.Substation.voltage_level import VoltageLevel from GridCalEngine.Devices.Branches.line_locations import LineLocation from GridCalEngine.Devices.multi_circuit import MultiCircuit -from GridCalEngine.enumerations import DeviceType +from GridCalEngine.enumerations import DeviceType, ResultTypes from GridCalEngine.Devices.types import ALL_DEV_TYPES from GridCalEngine.basic_structures import Logger +from GridCalEngine.Simulations.OPF.opf_ts_results import OptimalPowerFlowTimeSeriesResults +from GridCalEngine.Simulations.PowerFlow.power_flow_ts_results import PowerFlowTimeSeriesResults from GridCal.Gui.Diagrams.MapWidget.Branches.map_ac_line import MapAcLine from GridCal.Gui.Diagrams.MapWidget.Branches.map_dc_line import MapDcLine @@ -1220,6 +1225,7 @@ def copy(self) -> "GridMapWidget": logger=self.logger) return GridMapWidget( + gui=self.gui, tile_src=self.map.tile_src, start_level=self.diagram.start_level, longitude=self.diagram.longitude, @@ -1240,6 +1246,80 @@ def consolidate_coordinates(self): gelm.api_object.latitude = gelm.lat gelm.api_object.longitude = gelm.lon + def plot_substation(self, i: int, api_object: Substation): + """ + Plot branch results + :param i: bus index + :param api_object: Substation API object + :return: + """ + + fig = plt.figure(figsize=(12, 8)) + ax_1 = fig.add_subplot(211) + ax_1.set_title('Power', fontsize=14) + ax_1.set_ylabel('Injections [MW]', fontsize=11) + + ax_2 = fig.add_subplot(212, sharex=ax_1) + ax_2.set_title('Time', fontsize=14) + ax_2.set_ylabel('Voltage [p.u]', fontsize=11) + + # set time + x = self.circuit.get_time_array() + + if x is not None: + if len(x) > 0: + + # Get all devices grouped by bus + all_data = self.circuit.get_injection_devices_grouped_by_substation() + + # search drivers for voltage data + for driver, results in self.gui.session.drivers_results_iter(): + if results is not None: + if isinstance(results, PowerFlowTimeSeriesResults): + table = results.mdl(result_type=ResultTypes.BusVoltageModule) + table.plot_device(ax=ax_2, device_idx=i) + elif isinstance(results, OptimalPowerFlowTimeSeriesResults): + table = results.mdl(result_type=ResultTypes.BusVoltageModule) + table.plot_device(ax=ax_2, device_idx=i) + + # Injections + # filter injections by bus + bus_devices = all_data.get(api_object, None) + if bus_devices: + + power_data = dict() + for tpe_name, devices in bus_devices.items(): + for device in devices: + if device.device_type == DeviceType.LoadDevice: + power_data[device.name] = -device.P_prof.toarray() + elif device.device_type == DeviceType.GeneratorDevice: + power_data[device.name] = device.P_prof.toarray() + elif device.device_type == DeviceType.ShuntDevice: + power_data[device.name] = -device.G_prof.toarray() + elif device.device_type == DeviceType.StaticGeneratorDevice: + power_data[device.name] = device.P_prof.toarray() + elif device.device_type == DeviceType.ExternalGridDevice: + power_data[device.name] = device.P_prof.toarray() + elif device.device_type == DeviceType.BatteryDevice: + power_data[device.name] = device.P_prof.toarray() + else: + raise Exception("Missing shunt device for plotting") + + df = pd.DataFrame(data=power_data, index=x) + + try: + # yt area plots + df.plot.area(ax=ax_1) + except ValueError: + # use regular plots + df.plot(ax=ax_1) + + plt.legend() + fig.suptitle(api_object.name, fontsize=20) + + # plot the profiles + plt.show() + def generate_map_diagram(substations: List[Substation], voltage_levels: List[VoltageLevel], diff --git a/src/GridCal/Gui/Diagrams/SchematicWidget/Substation/bus_graphics.py b/src/GridCal/Gui/Diagrams/SchematicWidget/Substation/bus_graphics.py index b0c6fe1aa..a5cbd0596 100644 --- a/src/GridCal/Gui/Diagrams/SchematicWidget/Substation/bus_graphics.py +++ b/src/GridCal/Gui/Diagrams/SchematicWidget/Substation/bus_graphics.py @@ -452,87 +452,6 @@ def contextMenuEvent(self, event: QtWidgets.QGraphicsSceneContextMenuEvent): icon_path=":/Icons/icons/plot.svg", function_ptr=self.plot_profiles) - - # arr = menu.addAction('Arrange') - # arr_icon = QIcon() - # arr_icon.addPixmap(QPixmap(":/Icons/icons/automatic_layout.svg")) - # arr.setIcon(arr_icon) - # arr.triggered.connect(self.arrange_children) - # - # ra5 = menu.addAction('Assign active state to profile') - # ra5_icon = QIcon() - # ra5_icon.addPixmap(QPixmap(":/Icons/icons/assign_to_profile.svg")) - # ra5.setIcon(ra5_icon) - # ra5.triggered.connect(self.assign_status_to_profile) - # - # ra3 = menu.addAction('Delete all the connections') - # del2_icon = QIcon() - # del2_icon.addPixmap(QPixmap(":/Icons/icons/delete_conn.svg")) - # ra3.setIcon(del2_icon) - # ra3.triggered.connect(self.delete_all_connections) - # - # da = menu.addAction('Delete') - # del_icon = QIcon() - # del_icon.addPixmap(QPixmap(":/Icons/icons/delete_db.svg")) - # da.setIcon(del_icon) - # da.triggered.connect(self.remove) - # - # re = menu.addAction('Expand schematic') - # re_icon = QIcon() - # re_icon.addPixmap(QPixmap(":/Icons/icons/grid_icon.svg")) - # re.setIcon(re_icon) - # re.triggered.connect(self.expand_diagram_from_bus) - # - # menu.addSection("Add") - # - # al = menu.addAction('Load') - # al_icon = QIcon() - # al_icon.addPixmap(QPixmap(":/Icons/icons/add_load.svg")) - # al.setIcon(al_icon) - # al.triggered.connect(self.add_load) - # - # ac_i = menu.addAction('Current injection') - # ac_i_icon = QIcon() - # ac_i_icon.addPixmap(QPixmap(":/Icons/icons/add_load.svg")) - # ac_i.setIcon(ac_i_icon) - # ac_i.triggered.connect(self.add_current_injection) - # - # ash = menu.addAction('Shunt') - # ash_icon = QIcon() - # ash_icon.addPixmap(QPixmap(":/Icons/icons/add_shunt.svg")) - # ash.setIcon(ash_icon) - # ash.triggered.connect(self.add_shunt) - # - # acsh = menu.addAction('Controllable shunt') - # acsh_icon = QIcon() - # acsh_icon.addPixmap(QPixmap(":/Icons/icons/add_shunt.svg")) - # acsh.setIcon(acsh_icon) - # acsh.triggered.connect(self.add_controllable_shunt) - # - # acg = menu.addAction('Generator') - # acg_icon = QIcon() - # acg_icon.addPixmap(QPixmap(":/Icons/icons/add_gen.svg")) - # acg.setIcon(acg_icon) - # acg.triggered.connect(self.add_generator) - # - # asg = menu.addAction('Static generator') - # asg_icon = QIcon() - # asg_icon.addPixmap(QPixmap(":/Icons/icons/add_stagen.svg")) - # asg.setIcon(asg_icon) - # asg.triggered.connect(self.add_static_generator) - # - # ab = menu.addAction('Battery') - # ab_icon = QIcon() - # ab_icon.addPixmap(QPixmap(":/Icons/icons/add_batt.svg")) - # ab.setIcon(ab_icon) - # ab.triggered.connect(self.add_battery) - # - # aeg = menu.addAction('External grid') - # aeg_icon = QIcon() - # aeg_icon.addPixmap(QPixmap(":/Icons/icons/add_external_grid.svg")) - # aeg.setIcon(aeg_icon) - # aeg.triggered.connect(self.add_external_grid) - add_menu_entry(menu, text='Arrange', icon_path=":/Icons/icons/automatic_layout.svg", diff --git a/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py b/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py index 9b191eddf..4308fb356 100644 --- a/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py +++ b/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py @@ -53,7 +53,8 @@ from GridCalEngine.Devices.Fluid import FluidNode, FluidPath from GridCalEngine.Devices.Diagrams.schematic_diagram import SchematicDiagram from GridCalEngine.Devices.Diagrams.graphic_location import GraphicLocation -from GridCalEngine.Simulations import PowerFlowTimeSeriesResults +from GridCalEngine.Simulations.OPF.opf_ts_results import OptimalPowerFlowTimeSeriesResults +from GridCalEngine.Simulations.PowerFlow.power_flow_ts_results import PowerFlowTimeSeriesResults from GridCalEngine.enumerations import DeviceType, ResultTypes from GridCalEngine.basic_structures import Vec, CxVec, IntVec, Logger @@ -3736,7 +3737,10 @@ def plot_bus(self, i: int, api_object: Bus): if results is not None: if isinstance(results, PowerFlowTimeSeriesResults): table = results.mdl(result_type=ResultTypes.BusVoltageModule) - table.plot(ax=ax_2, selected_col_idx=[i]) + table.plot_device(ax=ax_2, device_idx=i) + elif isinstance(results, OptimalPowerFlowTimeSeriesResults): + table = results.mdl(result_type=ResultTypes.BusVoltageModule) + table.plot_device(ax=ax_2, device_idx=i) # Injections # filter injections by bus diff --git a/src/GridCal/Gui/Diagrams/base_diagram_widget.py b/src/GridCal/Gui/Diagrams/base_diagram_widget.py index 1e6f27f5e..acc0079d6 100644 --- a/src/GridCal/Gui/Diagrams/base_diagram_widget.py +++ b/src/GridCal/Gui/Diagrams/base_diagram_widget.py @@ -325,47 +325,47 @@ def plot_branch(self, i: int, api_object: Union[Line, DcLine, Transformer2W, VSC if isinstance(results, PowerFlowTimeSeriesResults): Sf_table = results.mdl(result_type=ResultTypes.BranchActivePowerFrom) - Sf_table.plot(ax=ax_1, selected_col_idx=[i]) + Sf_table.plot_device(ax=ax_1, device_idx=i) loading_table = results.mdl(result_type=ResultTypes.BranchLoading) loading_table.convert_to_cdf() - loading_table.plot(ax=ax_2, selected_col_idx=[i]) + loading_table.plot_device(ax=ax_2, device_idx=i) any_plot = True elif isinstance(results, LinearAnalysisTimeSeriesResults): Sf_table = results.mdl(result_type=ResultTypes.BranchActivePowerFrom) - Sf_table.plot(ax=ax_1, selected_col_idx=[i]) + Sf_table.plot_device(ax=ax_1, device_idx=i) loading_table = results.mdl(result_type=ResultTypes.BranchLoading) loading_table.convert_to_cdf() - loading_table.plot(ax=ax_2, selected_col_idx=[i]) + loading_table.plot_device(ax=ax_2, device_idx=i) any_plot = True elif isinstance(results, ContingencyAnalysisTimeSeriesResults): Sf_table = results.mdl(result_type=ResultTypes.MaxContingencyFlows) - Sf_table.plot(ax=ax_1, selected_col_idx=[i]) + Sf_table.plot_device(ax=ax_1, device_idx=i) loading_table = results.mdl(result_type=ResultTypes.MaxContingencyLoading) loading_table.convert_to_cdf() - loading_table.plot(ax=ax_2, selected_col_idx=[i]) + loading_table.plot_device(ax=ax_2, device_idx=i) any_plot = True elif isinstance(results, OptimalPowerFlowTimeSeriesResults): Sf_table = results.mdl(result_type=ResultTypes.BranchActivePowerFrom) - Sf_table.plot(ax=ax_1, selected_col_idx=[i]) + Sf_table.plot_device(ax=ax_1, device_idx=i) loading_table = results.mdl(result_type=ResultTypes.BranchLoading) loading_table.convert_to_cdf() - loading_table.plot(ax=ax_2, selected_col_idx=[i]) + loading_table.plot_device(ax=ax_2, device_idx=i) any_plot = True elif isinstance(results, StochasticPowerFlowResults): loading_table = results.mdl(result_type=ResultTypes.BranchLoadingAverage) loading_table.convert_to_cdf() - loading_table.plot(ax=ax_2, selected_col_idx=[i]) + loading_table.plot_device(ax=ax_2, device_idx=i) any_plot = True if any_plot: diff --git a/src/GridCal/Gui/Main/MainWindow.py b/src/GridCal/Gui/Main/MainWindow.py index f45db8489..9f507433a 100644 --- a/src/GridCal/Gui/Main/MainWindow.py +++ b/src/GridCal/Gui/Main/MainWindow.py @@ -965,8 +965,9 @@ def setupUi(self, mainWindow): self.max_node_size_spinBox = QDoubleSpinBox(self.frame_58) self.max_node_size_spinBox.setObjectName(u"max_node_size_spinBox") self.max_node_size_spinBox.setFont(font2) - self.max_node_size_spinBox.setDecimals(1) - self.max_node_size_spinBox.setMinimum(0.100000000000000) + self.max_node_size_spinBox.setDecimals(3) + self.max_node_size_spinBox.setMinimum(0.010000000000000) + self.max_node_size_spinBox.setMaximum(9999.000000000000000) self.max_node_size_spinBox.setSingleStep(0.100000000000000) self.max_node_size_spinBox.setValue(40.000000000000000) @@ -975,7 +976,9 @@ def setupUi(self, mainWindow): self.max_branch_size_spinBox = QDoubleSpinBox(self.frame_58) self.max_branch_size_spinBox.setObjectName(u"max_branch_size_spinBox") self.max_branch_size_spinBox.setFont(font2) - self.max_branch_size_spinBox.setDecimals(1) + self.max_branch_size_spinBox.setDecimals(3) + self.max_branch_size_spinBox.setMinimum(0.010000000000000) + self.max_branch_size_spinBox.setMaximum(9999.000000000000000) self.max_branch_size_spinBox.setSingleStep(0.100000000000000) self.max_branch_size_spinBox.setValue(20.000000000000000) @@ -990,17 +993,20 @@ def setupUi(self, mainWindow): self.min_node_size_spinBox = QDoubleSpinBox(self.frame_58) self.min_node_size_spinBox.setObjectName(u"min_node_size_spinBox") self.min_node_size_spinBox.setFont(font2) - self.min_node_size_spinBox.setDecimals(1) - self.min_node_size_spinBox.setMinimum(0.100000000000000) + self.min_node_size_spinBox.setDecimals(3) + self.min_node_size_spinBox.setMinimum(0.010000000000000) + self.min_node_size_spinBox.setMaximum(9999.000000000000000) self.min_node_size_spinBox.setSingleStep(0.100000000000000) - self.min_node_size_spinBox.setValue(20.000000000000000) + self.min_node_size_spinBox.setValue(5.000000000000000) self.gridLayout.addWidget(self.min_node_size_spinBox, 10, 1, 1, 1) self.min_branch_size_spinBox = QDoubleSpinBox(self.frame_58) self.min_branch_size_spinBox.setObjectName(u"min_branch_size_spinBox") self.min_branch_size_spinBox.setFont(font2) - self.min_branch_size_spinBox.setDecimals(1) + self.min_branch_size_spinBox.setDecimals(3) + self.min_branch_size_spinBox.setMinimum(0.010000000000000) + self.min_branch_size_spinBox.setMaximum(9999.000000000000000) self.min_branch_size_spinBox.setSingleStep(0.100000000000000) self.min_branch_size_spinBox.setValue(0.500000000000000) @@ -4622,7 +4628,7 @@ def setupUi(self, mainWindow): self.tabWidget.setCurrentIndex(0) self.tabWidget_3.setCurrentIndex(0) - self.tabWidget_6.setCurrentIndex(0) + self.tabWidget_6.setCurrentIndex(1) self.tabWidget_5.setCurrentIndex(0) self.tabWidget_4.setCurrentIndex(0) self.tabWidget_2.setCurrentIndex(0) diff --git a/src/GridCal/Gui/Main/MainWindow.ui b/src/GridCal/Gui/Main/MainWindow.ui index a3eb8b3a7..d7acfcb22 100644 --- a/src/GridCal/Gui/Main/MainWindow.ui +++ b/src/GridCal/Gui/Main/MainWindow.ui @@ -311,7 +311,7 @@ QProgressBar::chunk{ QTabWidget::North - 0 + 1 @@ -1076,10 +1076,13 @@ QProgressBar::chunk{ px - 1 + 3 - 0.100000000000000 + 0.010000000000000 + + + 9999.000000000000000 0.100000000000000 @@ -1100,7 +1103,13 @@ QProgressBar::chunk{ px - 1 + 3 + + + 0.010000000000000 + + + 9999.000000000000000 0.100000000000000 @@ -1133,16 +1142,19 @@ QProgressBar::chunk{ px - 1 + 3 - 0.100000000000000 + 0.010000000000000 + + + 9999.000000000000000 0.100000000000000 - 20.000000000000000 + 5.000000000000000 @@ -1157,7 +1169,13 @@ QProgressBar::chunk{ px - 1 + 3 + + + 0.010000000000000 + + + 9999.000000000000000 0.100000000000000 diff --git a/src/GridCalEngine/Devices/multi_circuit.py b/src/GridCalEngine/Devices/multi_circuit.py index 13023f964..25e1d9204 100644 --- a/src/GridCalEngine/Devices/multi_circuit.py +++ b/src/GridCalEngine/Devices/multi_circuit.py @@ -1309,6 +1309,32 @@ def change_base(self, Sbase_new: float): # assign the new base self.Sbase = Sbase_new + def get_injection_devices_grouped_by_substation(self) -> Dict[dev.Substation, Dict[DeviceType, List[INJECTION_DEVICE_TYPES]]]: + """ + Get the injection devices grouped by bus and by device type + :return: Dict[bus, Dict[DeviceType, List[Injection devs]] + """ + groups: Dict[dev.Substation, Dict[DeviceType, List[INJECTION_DEVICE_TYPES]]] = dict() + + for lst in self.get_injection_devices_lists(): + + for elm in lst: + + if elm.bus.substation is not None: + + devices_by_type = groups.get(elm.bus.substation, None) + + if devices_by_type is None: + groups[elm.bus.substation] = {elm.device_type: [elm]} + else: + lst = devices_by_type.get(elm.device_type, None) + if lst is None: + devices_by_type[elm.device_type] = [elm] + else: + devices_by_type[elm.device_type].append(elm) + + return groups + def get_injection_devices_grouped_by_bus(self) -> Dict[dev.Bus, Dict[DeviceType, List[INJECTION_DEVICE_TYPES]]]: """ Get the injection devices grouped by bus and by device type diff --git a/src/GridCalEngine/Simulations/results_table.py b/src/GridCalEngine/Simulations/results_table.py index 768c9afdf..34dca4f3b 100644 --- a/src/GridCalEngine/Simulations/results_table.py +++ b/src/GridCalEngine/Simulations/results_table.py @@ -374,3 +374,36 @@ def plot(self, ax=None, selected_col_idx=None, selected_rows=None, stacked=False df.plot(ax=ax, legend=plot_legend, stacked=stacked) except TypeError: print('No numeric data to plot...') + + def plot_device(self, ax=None, device_idx: int = 0, stacked=False): + """ + Plot the data model + :param ax: Matplotlib axis + :param device_idx: list of selected column indices + :param stacked: Stack plot? + """ + index, columns, data = self.get_data() + + columns = columns[device_idx] + data = data[:, device_idx] + + if ax is None: + fig = plt.figure(figsize=(12, 6)) + ax = fig.add_subplot(111) + + if 'voltage' in self.title.lower(): + data[data == 0] = 'nan' # to avoid plotting the zeros + + if len(columns) > 15: + plot_legend = False + else: + plot_legend = True + + df = pd.DataFrame(data=data, index=index, columns=columns) + ax.set_title(self.title, fontsize=14) + ax.set_ylabel(self.y_label, fontsize=11) + ax.set_xlabel(self.x_label, fontsize=11) + try: + df.plot(ax=ax, legend=plot_legend, stacked=stacked) + except TypeError: + print('No numeric data to plot...') From a0c30f398d39a44d4359e3d651e6d2e5390a5d56 Mon Sep 17 00:00:00 2001 From: santi Date: Tue, 1 Oct 2024 17:18:16 +0100 Subject: [PATCH 6/6] Fixed some representation issues --- .idea/workspace.xml | 112 +++++++++--------- .../Gui/Diagrams/MapWidget/grid_map_widget.py | 13 +- src/GridCal/Gui/Main/MainWindow.py | 2 +- src/GridCal/Gui/Main/MainWindow.ui | 2 +- .../Gui/Main/SubClasses/Model/time_events.py | 20 ++-- src/GridCalEngine/Devices/assets.py | 33 ++---- src/GridCalEngine/Devices/profile.py | 20 +++- src/GridCalEngine/IO/gridcal/pack_unpack.py | 18 ++- .../Simulations/results_table.py | 2 +- 9 files changed, 121 insertions(+), 101 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index dcd803103..a7a5c570c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -28,16 +28,15 @@