Skip to content

Commit

Permalink
Added external grid graphic object
Browse files Browse the repository at this point in the history
  • Loading branch information
SanPen committed Jun 26, 2023
1 parent 318eefc commit da3adf8
Show file tree
Hide file tree
Showing 9 changed files with 22,972 additions and 22,297 deletions.
181 changes: 115 additions & 66 deletions .idea/workspace.xml

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions src/GridCal/Engine/Core/Devices/Injections/external_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ExternalGrid(EditableDevice):

def __init__(self, name='External grid', idtag=None, active=True,
Vm=1.0, Va=0.0, Vm_prof=None, Va_prof=None, P=0.0, Q=0.0, P_prof=None, Q_prof=None,
mttf=0.0, mttr=0.0, cost=1200.0, mode: ExternalGridMode = ExternalGridMode.PQ):
mttf=0.0, mttr=0.0, mode: ExternalGridMode = ExternalGridMode.PQ):

EditableDevice.__init__(self,
name=name,
Expand Down Expand Up @@ -93,9 +93,6 @@ def __init__(self, name='External grid', idtag=None, active=True,
self.P_prof = P_prof
self.Q_prof = Q_prof

self.Cost = cost
self.Cost_prof = None

self.register(key='bus', units='', tpe=DeviceType.BusDevice, definition='Connection bus name', editable=False)
self.register(key='active', units='', tpe=bool, definition='Is the load active?', profile_name='active_prof')
self.register(key='mode', units='', tpe=ExternalGridMode,
Expand All @@ -106,8 +103,6 @@ def __init__(self, name='External grid', idtag=None, active=True,
self.register(key='Q', units='MVAr', tpe=float, definition='Reactive power', profile_name='Q_prof')
self.register(key='mttf', units='h', tpe=float, definition='Mean time to failure')
self.register(key='mttr', units='h', tpe=float, definition='Mean time to recovery')
self.register(key='Cost', units='e/MWh', tpe=float, definition='Cost of not served energy. Used in OPF.',
profile_name='Cost_prof')

def copy(self):

Expand Down
2 changes: 1 addition & 1 deletion src/GridCal/Engine/Core/multi_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1790,7 +1790,7 @@ def add_external_grid(self, bus: dev.Bus, api_obj=None):
if api_obj.name == 'External grid':
api_obj.name += '@' + bus.name

bus.loads.append(api_obj)
bus.external_grids.append(api_obj)

return api_obj

Expand Down
8 changes: 6 additions & 2 deletions src/GridCal/Engine/basic_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ def argparse(s):


class ExternalGridMode(Enum):
PQ = 1
VD = 2
"""
Modes of operation of external grids
"""
PQ = "PQ"
PV = "PV"
VD = "VD"

def __str__(self):
return self.value
Expand Down
31 changes: 25 additions & 6 deletions src/GridCal/Gui/GridEditorWidget/bus_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from GridCal.Gui.GridEditorWidget.static_generator_graphics import StaticGeneratorGraphicItem
from GridCal.Gui.GridEditorWidget.battery_graphics import BatteryGraphicItem
from GridCal.Gui.GridEditorWidget.shunt_graphics import ShuntGraphicItem
from GridCal.Gui.GridEditorWidget.external_grid_graphics import ExternalGridGraphicItem
from GridCal.Gui.GridEditorWidget.messages import yes_no_question
from GridCal.Engine.Core.Devices.enumerations import DeviceType, FaultType

Expand Down Expand Up @@ -396,7 +397,6 @@ def contextMenuEvent(self, event):
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"))
Expand Down Expand Up @@ -447,6 +447,12 @@ def contextMenuEvent(self, event):
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)

menu.exec_(event.screenPos())

def assign_status_to_profile(self):
Expand Down Expand Up @@ -632,7 +638,7 @@ def add_load(self, api_obj=None):
Add load object to bus
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_load(self.api_object)
api_obj = self.diagramScene.circuit.add_load(bus=self.api_object)

_grph = LoadGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
Expand All @@ -646,7 +652,7 @@ def add_shunt(self, api_obj=None):
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_shunt(self.api_object)
api_obj = self.diagramScene.circuit.add_shunt(bus=self.api_object)

_grph = ShuntGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
Expand All @@ -660,7 +666,7 @@ def add_generator(self, api_obj=None):
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_generator(self.api_object)
api_obj = self.diagramScene.circuit.add_generator(bus=self.api_object)

_grph = GeneratorGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
Expand All @@ -674,7 +680,7 @@ def add_static_generator(self, api_obj=None):
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_static_generator(self.api_object)
api_obj = self.diagramScene.circuit.add_static_generator(bus=self.api_object)

_grph = StaticGeneratorGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
Expand All @@ -688,10 +694,23 @@ def add_battery(self, api_obj=None):
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_battery(self.api_object)
api_obj = self.diagramScene.circuit.add_battery(bus=self.api_object)

_grph = BatteryGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
self.shunt_children.append(_grph)
self.arrange_children()

def add_external_grid(self, api_obj=None):
"""
Returns:
"""
if api_obj is None or type(api_obj) is bool:
api_obj = self.diagramScene.circuit.add_external_grid(bus=self.api_object)

_grph = ExternalGridGraphicItem(self, api_obj, self.diagramScene)
api_obj.graphic_obj = _grph
self.shunt_children.append(_grph)
self.arrange_children()
217 changes: 217 additions & 0 deletions src/GridCal/Gui/GridEditorWidget/external_grid_graphics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# GridCal
# Copyright (C) 2022 Santiago Peñate Vera
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from PySide6 import QtWidgets, QtGui, QtCore
from GridCal.Engine.Core.Devices.Injections.battery import Battery, DeviceType
from GridCal.Gui.GridEditorWidget.generic_graphics import ACTIVE, DEACTIVATED, OTHER, Square
from GridCal.Gui.GuiFunctions import ObjectsModel
from GridCal.Gui.GridEditorWidget.messages import yes_no_question


class ExternalGridGraphicItem(QtWidgets.QGraphicsItemGroup):
"""
ExternalGrid graphic item
"""
def __init__(self, parent, api_obj: Battery, diagramScene):
"""
:param parent:
:param api_obj:
"""
super(ExternalGridGraphicItem, self).__init__(parent)

self.parent = parent

self.api_object: Battery = api_obj

self.diagramScene = diagramScene

self.w = 40
self.h = 40

# Properties of the container:
self.setFlags(self.GraphicsItemFlag.ItemIsSelectable | self.GraphicsItemFlag.ItemIsMovable)
self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

self.width = 4
if self.api_object is not None:
if self.api_object.active:
self.style = ACTIVE['style']
self.color = ACTIVE['color']
else:
self.style = DEACTIVATED['style']
self.color = DEACTIVATED['color']
else:
self.style = OTHER['style']
self.color = OTHER['color']

# line to tie this object with the original bus (the parent)
self.nexus = QtWidgets.QGraphicsLineItem()
self.nexus.setPen(QtGui.QPen(self.color, self.width, self.style))
parent.scene().addItem(self.nexus)

pen = QtGui.QPen(self.color, self.width, self.style)

self.glyph = Square(self)
self.glyph.setRect(0, 0, self.h, self.w)
self.glyph.setPen(pen)
self.addToGroup(self.glyph)

self.label = QtWidgets.QGraphicsTextItem('E', parent=self.glyph)
self.label.setDefaultTextColor(self.color)
self.label.setPos(self.h / 4, self.w / 5)

self.setPos(self.parent.x(), self.parent.y() + 100)
self.update_line(self.pos())

def recolour_mode(self):

if self.api_object is not None:
if self.api_object.active:
self.color = ACTIVE['color']
self.style = ACTIVE['style']
else:
self.color = DEACTIVATED['color']
self.style = DEACTIVATED['style']
else:
self.color = ACTIVE['color']
self.style = ACTIVE['style']

pen = QtGui.QPen(self.color, self.width, self.style)
self.glyph.setPen(pen)
self.nexus.setPen(pen)
self.label.setDefaultTextColor(self.color)

def update_line(self, pos):
"""
Update the line that joins the parent and this object
:param pos: position of this object
"""
parent = self.parentItem()
rect = parent.rect()
self.nexus.setLine(
pos.x() + self.w / 2,
pos.y() + 0,
parent.x() + rect.width() / 2,
parent.y() + parent.terminal.y + 5,
)
self.setZValue(-1)
self.nexus.setZValue(-1)

def contextMenuEvent(self, event):
"""
Display context menu
@param event:
@return:
"""
menu = QtWidgets.QMenu()
menu.addSection("External grid")

pe = menu.addAction('Active')
pe.setCheckable(True)
pe.setChecked(self.api_object.active)
pe.triggered.connect(self.enable_disable_toggle)

pa = menu.addAction('Plot profiles')
plot_icon = QtGui.QIcon()
plot_icon.addPixmap(QtGui.QPixmap(":/Icons/icons/plot.svg"))
pa.setIcon(plot_icon)
pa.triggered.connect(self.plot)

da = menu.addAction('Delete')
del_icon = QtGui.QIcon()
del_icon.addPixmap(QtGui.QPixmap(":/Icons/icons/delete3.svg"))
da.setIcon(del_icon)
da.triggered.connect(self.remove)

menu.exec_(event.screenPos())

def remove(self, ask=True):
"""
Remove this element
@return:
"""
if ask:
ok = yes_no_question('Are you sure that you want to remove this external grid', 'Remove external grid')
else:
ok = True

if ok:
self.diagramScene.removeItem(self.nexus)
self.diagramScene.removeItem(self)
self.api_object.bus.batteries.remove(self.api_object)

def enable_disable_toggle(self):
"""
@return:
"""
if self.api_object is not None:
if self.api_object.active:
self.set_enable(False)
else:
self.set_enable(True)

if self.diagramScene.circuit.has_time_series:
ok = yes_no_question('Do you want to update the time series active status accordingly?',
'Update time series active status')

if ok:
# change the bus state (time series)
self.diagramScene.set_active_status_to_profile(self.api_object, override_question=True)

def set_enable(self, val=True):
"""
Set the enable value, graphically and in the API
@param val:
@return:
"""
self.api_object.active = val
if self.api_object is not None:
if self.api_object.active:
self.style = ACTIVE['style']
self.color = ACTIVE['color']
else:
self.style = DEACTIVATED['style']
self.color = DEACTIVATED['color']
else:
self.style = OTHER['style']
self.color = OTHER['color']
self.glyph.setPen(QtGui.QPen(self.color, self.width, self.style))
self.label.setDefaultTextColor(self.color)

def plot(self):
"""
Plot API objects profiles
"""
# time series object from the last simulation
ts = self.diagramScene.circuit.time_profile

# plot the profiles
self.api_object.plot_profiles(time=ts)

def mousePressEvent(self, QGraphicsSceneMouseEvent):
"""
mouse press: display the editor
:param QGraphicsSceneMouseEvent:
:return:
"""
mdl = ObjectsModel([self.api_object], self.api_object.editable_headers,
parent=self.diagramScene.parent().object_editor_table, editable=True, transposed=True,
dictionary_of_lists={DeviceType.Technology.value: self.diagramScene.circuit.technologies, })
self.diagramScene.parent().object_editor_table.setModel(mdl)

1 change: 1 addition & 0 deletions src/GridCal/Gui/Main/icons.qrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="Icons">
<file>icons/add_external_grid.svg</file>
<file>icons/clustering_use.svg</file>
<file>icons/clustering.svg</file>
<file>icons/zoom_out.svg</file>
Expand Down
Loading

0 comments on commit da3adf8

Please sign in to comment.