Skip to content

Commit

Permalink
Merge pull request #236 from SanPen/devel
Browse files Browse the repository at this point in the history
Devel 5.0.3
  • Loading branch information
SanPen authored Nov 22, 2023
2 parents 0f8de4b + ae0bf00 commit bd88596
Show file tree
Hide file tree
Showing 20 changed files with 382 additions and 289 deletions.
179 changes: 115 additions & 64 deletions .idea/workspace.xml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions doc/auto_document_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def write_dataframes_to_rst2(w, data_frames: Dict[str, pd.DataFrame], tilte):
def write_models_to_rst(filename):
with open(filename, 'w') as w:

w.write("Other Data Models\n")
w.write("Data Models\n")
w.write("==========================\n\n")

cgmes_info = get_cgmes_data_frames()
Expand All @@ -150,7 +150,7 @@ def write_models_to_rst(filename):
# cgmes_info = get_cgmes_data_frames()
# psse_info = get_psse_data_frames()
# roseta_info = get_gridcal_data_frames()

#
# write_dataframes_to_excel(cgmes_info, 'cgmes_clases.xlsx')
# write_dataframes_to_excel(psse_info, 'psse_clases.xlsx')
# write_dataframes_to_excel(roseta_info, 'roseta_clases.xlsx')
Expand Down
Binary file added doc/rst_source/figures/Roseta_grid_converter.dia
Binary file not shown.
Binary file added doc/rst_source/figures/Roseta_grid_converter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 40 additions & 40 deletions doc/rst_source/other_data_models.rst

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions src/GridCal/Gui/GridEditorWidget/substation/bus_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,10 @@ def recolour_mode(self):

self.label.setDefaultTextColor(ACTIVE['text'])
self.set_tile_color(self.color)
for e in self.api_object.get_devices_list():
if e.graphic_obj is not None:
e.graphic_obj.recolour_mode()

for e in self.shunt_children:
if e is not None:
e.recolour_mode()

def set_label(self, val: str):
"""
Expand Down
5 changes: 4 additions & 1 deletion src/GridCal/Gui/Main/SubClasses/base_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,10 @@ def file_name(self, val: str):
:param val: file name
"""
self._file_name = val
self.ui.file_information_label.setText(self._file_name)
if not isinstance(self._file_name, list):
self.ui.file_information_label.setText(self._file_name)
else:
self.ui.file_information_label.setText("")

@staticmethod
def collect_memory() -> None:
Expand Down
27 changes: 18 additions & 9 deletions src/GridCal/Gui/Main/SubClasses/simulations.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,11 +750,15 @@ def run_short_circuit(self):
# get the short circuit selected buses
sel_buses = list()
self_short_circuit_types = list()
for i, bus in enumerate(self.circuit.buses):
if bus.graphic_obj is not None:
if bus.graphic_obj.any_short_circuit():
sel_buses.append(i)
self_short_circuit_types.append(bus.graphic_obj.sc_type)

for diagram_widget in self.diagram_widgets_list:

if isinstance(diagram_widget, BusBranchEditorWidget):

for i, bus, graphic_object in diagram_widget.get_buses():
if graphic_object.any_short_circuit():
sel_buses.append(i)
self_short_circuit_types.append(graphic_object.sc_type)

if len(sel_buses) > 1:
error_msg("GridCal only supports one short circuit bus at the time", "Short circuit")
Expand Down Expand Up @@ -2670,10 +2674,15 @@ def post_delete_and_reduce_selected_objects(self):
"""
if self.delete_and_reduce_driver is not None:

for bus in self.delete_and_reduce_driver.buses_merged:
if bus.graphic_obj is not None:
bus.graphic_obj.create_children_widgets()
bus.graphic_obj.arrange_children()
for diagram_widget in self.diagram_widgets_list:
if isinstance(diagram_widget, BusBranchEditorWidget):
for bus in self.delete_and_reduce_driver.buses_merged:

graphic_object = diagram_widget.diagram.query_point(bus)

if graphic_object is not None:
graphic_object.create_children_widgets()
graphic_object.arrange_children()

self.redraw_current_diagram()

Expand Down
2 changes: 1 addition & 1 deletion src/GridCal/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
_current_year_ = datetime.datetime.now().year

# do not forget to keep a three-number version!!!
__GridCal_VERSION__ = "5.0.2"
__GridCal_VERSION__ = "5.0.3"

url = 'https://github.com/SanPen/GridCal'

Expand Down
2 changes: 1 addition & 1 deletion src/GridCalEngine/Core/Devices/editable_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def __init__(self,

self.properties_with_profile: Dict[str, Optional[Any]] = dict()

self.register(key='name', units='', tpe=str, definition='Name of the branch.')
self.register(key='idtag', units='', tpe=str, definition='Unique ID', editable=False)
self.register(key='name', units='', tpe=str, definition='Name of the branch.')
self.register(key='code', units='', tpe=str, definition='Secondary ID')

@property
Expand Down
2 changes: 1 addition & 1 deletion src/GridCalEngine/IO/cim/cgmes_2_4_15/cgmes_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ def __init__(self,
def parse_files(self, files: List[str], delete_unused=True, detect_circular_references=False):
"""
Parse CGMES files into this class
:param files: list of CGMES files
:param files: list of CGMES files (.zip / .xml)
:param delete_unused: Detele the unused boundary set?
:param detect_circular_references: report the circular references
"""
Expand Down
72 changes: 18 additions & 54 deletions src/GridCalEngine/IO/cim/cgmes_2_4_15/cgmes_data_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import os
from collections import defaultdict
from typing import Dict, List, Union, Callable, Tuple
import xml.etree.ElementTree as ET
from GridCalEngine.data_logger import DataLogger
Expand Down Expand Up @@ -187,44 +188,7 @@ def read_cgmes_files(cim_files: Union[List[str], str]) -> Dict[str, List[str]]:
return data


from collections import defaultdict


def topological_sort(graph):
def dfs(node):
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
dfs(neighbor)
result.append(node)

visited = set()
result = []

for node in graph:
if node not in visited:
dfs(node)

return result[::-1]


def get_dependency_order(file_dependency):
graph = defaultdict(list)
nodes = set()

for file, dependency in file_dependency:
nodes.add(file)
if dependency is not None:
graph[dependency].append(file)

for file in nodes:
if file not in graph:
graph[file] = []

return topological_sort(graph)


def sort_cgmes_files(links: List[Tuple[str, str, str]]):
def sort_cgmes_files(links: List[Tuple[str, str, str]]) -> List[str]:
"""
Sorts the CIM files in the preferred reading order
:param links: list of filename, model id, dependent on model id
Expand All @@ -235,12 +199,6 @@ def sort_cgmes_files(links: List[Tuple[str, str, str]]):
for filename, model_id, dependent_id in links:
file_name_model_dict[model_id] = filename

# pairs = list()
# for filename, model_id, dependent_id in links:
# pairs.append((file_name_model_dict[model_id], file_name_model_dict.get(dependent_id, None)))
#
# items = get_dependency_order(pairs)

deps = list()
items = list()
for filename, model_id, dependent_id in links:
Expand Down Expand Up @@ -270,7 +228,8 @@ def sort_cgmes_files(links: List[Tuple[str, str, str]]):
def parse_xml_text(text_lines: List[str]) -> Dict:
"""
Fill the XML into the objects
:param text_lines:
:param text_lines: list of text lines
:return Dictionary representing the XML
"""

xml_string = "".join(text_lines)
Expand All @@ -290,42 +249,45 @@ def __init__(self,
logger=DataLogger()):
"""
CIM circuit constructor
:param text_func: text callback function (optional)
:param progress_func: progress callback function (optional)
:param logger: DataLogger
"""
BaseCircuit.__init__(self)

self.logger: DataLogger = logger

self.text_func = text_func
self.progress_func = progress_func
self.logger: DataLogger = logger

# file: Cim data of the file
self.parsed_data = dict()

# merged CGMES data (dictionary representation of the xml data)
self.data: Dict[str, Dict[str, Dict[str, str]]] = dict()

# boundary set data
self.boudary_set: Dict[str, Dict[str, Dict[str, str]]] = dict()

def emit_text(self, val: str) -> None:
"""
:param val:
Emit text via the callback
:param val: text value
"""
if self.text_func is not None:
self.text_func(val)

def emit_progress(self, val: float) -> None:
"""
:param val:
Emit floating point values via the callback
:param val: numeric value
"""
if self.progress_func is not None:
self.progress_func(val)

def load_files(self, files: List[str]) -> None:
"""
Load CIM file
:param files: list of CIM files (.xml)
:param files: list of CIM files (.xml or .zip)
"""

# import the cim files' content into a dictionary
Expand All @@ -347,7 +309,7 @@ def load_files(self, files: List[str]) -> None:
# get all the FullModel id's (should only be one of these)
model_keys = list(file_cgmes_data['FullModel'])

if len(model_keys) == 1:
if len(model_keys) == 1: # there must be exacly one FullModel
model_id = model_keys[0]
model_info = file_cgmes_data['FullModel'][model_keys[0]]
depends_on = model_info.get('DependentOn', '')
Expand All @@ -368,11 +330,13 @@ def load_files(self, files: List[str]) -> None:
comment="This is not a proper CGMES file")

else:
self.logger.add_error("File does not contain FullModel",
self.logger.add_error("File does not contain any FullModel",
device=file_name,
device_class="",
device_property='FullModel', value="", expected_value="FullModel",
comment="This is not a proper CGMES file")

# emit progress
self.emit_progress((i + 1) / len(data) * 100)
i += 1

Expand Down
2 changes: 1 addition & 1 deletion src/GridCalEngine/IO/cim/cgmes_2_4_15/cgmes_to_gridcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ def cgmes_to_gridcal(cgmes_model: CgmesCircuit, logger: DataLogger) -> MultiCirc
:param logger: Logger object
:return: MultiCircuit
"""
gc_model = MultiCircuit()
gc_model = MultiCircuit() # roseta
Sbase = gc_model.Sbase

# busbar_dict = parse_bus_bars(cgmes_model, circuit, logger)
Expand Down
31 changes: 25 additions & 6 deletions src/GridCalEngine/IO/cim/cgmes_2_4_15/cgmes_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,43 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import zipfile
from io import StringIO, TextIOWrapper, BytesIO
from typing import List
from typing import List, Union, Callable
from GridCalEngine.IO.cim.cgmes_2_4_15.cgmes_enums import cgmesProfile
from GridCalEngine.IO.cim.cgmes_2_4_15.cgmes_circuit import CgmesCircuit


def write_cgmes(filename_zip: str, model: CgmesCircuit, profiles: List[cgmesProfile]):

def write_cgmes(filename_zip: str, model: CgmesCircuit, profiles: List[cgmesProfile],
text_func: Union[Callable, None] = None,
progress_func: Union[Callable, None] = None):
"""
Write a CGMES model to a zip file
:param filename_zip: name of the zip file
:param model: CgmesCircuit
:param profiles: list of profiles to export
:param text_func: text callback function (optional)
:param progress_func: progress callback function (optional)
"""
# get the cgmes XML per profile
data = model.get_model_xml(profiles)

n = len(data)

# open zip file for writing
with zipfile.ZipFile(filename_zip, 'w', zipfile.ZIP_DEFLATED) as f_zip_ptr:

# for each CGMES profile of the list
i = 0
for profile, txt in data.items():
filename = 'model_{}.xml'.format(profile.value)
print('Saving', filename)

if text_func is not None:
text_func('Saving {}'.format(filename))

f_zip_ptr.writestr(filename, txt) # save the buffer to the zip file

print("done! see", filename_zip)
if progress_func is not None:
progress_func((i + 1) / n * 100)
i += 1

if text_func is not None:
text_func('done! see: {}'.format(filename_zip))
Loading

0 comments on commit bd88596

Please sign in to comment.