SolverParameters: Add solver parameter window base.

mesh
Pierre-Antoine Rouby 2023-06-12 15:33:25 +02:00
parent eb6d218b8e
commit 9cd8fadcd1
13 changed files with 616 additions and 45 deletions

View File

@ -12,6 +12,7 @@ from Model.LateralContribution.LateralContributionList import LateralContributio
from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
from Model.Stricklers.StricklersList import StricklersList
from Model.Section.SectionList import SectionList
from Model.SolverParameters.SolverParametersList import SolverParametersList
class RiverNode(Node):
def __init__(self, id:str, name:str,
@ -69,6 +70,7 @@ class River(Graph):
self._lateral_contribution = LateralContributionList(status=self._status)
self._initial_conditions = InitialConditionsDict(status=self._status)
self._stricklers = StricklersList(status=self._status)
self._parameters = {}
@property
def boundary_condition(self):
@ -99,6 +101,20 @@ class River(Graph):
return ret[0]
@property
def parameters(self):
return self._parameters
def get_params(self, solver):
if solver in self._parameters:
return self._parameters[solver]
new = SolverParametersList(status = self._status)
self._parameters[solver] = new
self._status.modified()
return self._parameters[solver]
def has_current_reach(self):
return self._current_reach is not None

View File

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
from copy import copy
from tools import trace, timer
class Parameter(object):
def __init__(self, status = None):
self._status = status
self._name = ""
self._value = ""
@property
def name(self):
return self._name
@property
def value(self):
return self._value
def __getitem__(self, key):
if key == "name":
return self._name
elif key == "value":
return self._value
return None
def __setitem__(self, key, value):
if key == "name":
self._name = str(value)
elif key == "value":
self._value = str(value)
self._status.modified()
class SolverParametersList(object):
def __init__(self, status = None):
super(SolverParametersList, self).__init__()
self._status = status
self._parameters = []
def __len__(self):
return len(self._parameters)
@property
def parameters(self):
return self._parameters.copy()
def get(self, index):
return self._parameters[index]
def set(self, index, new):
self._parameters[index] = new
self._status.modified()
def new(self, index):
n = Parameter(status = self._status)
self._parameters.insert(index, n)
self._status.modified()
return n
def insert(self, index, new):
self._parameters.insert(index, new)
self._status.modified()
def delete(self, parameters):
for parameter in parameters:
self._parameters.remove(parameter)
self._status.modified()
def delete_i(self, indexes):
parameters = list(
map(
lambda x: x[1],
filter(
lambda x: x[0] in indexes,
enumerate(self._parameters)
)
)
)
self.delete(parameters)
def sort(self, reverse=False, key=None):
self._parameters.sort(reverse=reverse, key=key)
self._status.modified()
def move_up(self, index):
if index < len(self._parameters):
next = index - 1
l = self._parameters
l[index], l[next] = l[next], l[index]
self._status.modified()
def move_down(self, index):
if index >= 0:
prev = index + 1
l = self._parameters
l[index], l[prev] = l[prev], l[index]
self._status.modified()

View File

@ -29,7 +29,11 @@ class Study(Serializable):
self.last_save_date = datetime.now()
# Study data
self.river = River(status=self.status)
self._river = River(status = self.status)
@property
def river(self):
return self._river
@property
def is_saved(self):

View File

@ -14,81 +14,84 @@ class AbstractSolver(object):
def __init__(self, name):
super(AbstractSolver, self).__init__()
self.current_process = None
self.status = STATUS.STOPED
self._current_process = None
self._status = STATUS.STOPED
# Informations
self._type = ""
self.name = name
self.description = ""
self._name = name
self._description = ""
self.path_input = ""
self.path_solver = ""
self.path_output = ""
self._path_input = ""
self._path_solver = ""
self._path_output = ""
self.cmd_input = ""
self.cmd_solver = ""
self.cmd_output = ""
self._cmd_input = ""
self._cmd_solver = ""
self._cmd_output = ""
def __str__(self):
return f"{self.name} : {self._type} : {self.description}"
return f"{self._name} : {self._type} : {self._description}"
# Getter
def get_status(self):
return self.status
@classmethod
def default_parameters(cls):
return []
def get_type(self):
@property
def name(self):
return self.name
@property
def description(self):
return self.description
@property
def status(self):
return self._status
@property
def type(self):
return self._type
def __getitem__(self, name):
ret = None
@status.setter
def status(self, status):
self._status = status
if name == "name":
ret = self.name
elif name == "description":
ret = self.description
elif name == "type":
ret = self._type
@name.setter
def name(self, name):
self._name = name
return ret
# Setter
def set_status(self, status):
self.status = status
def set_name(self, name):
self.name = name
def set_description(self, description):
self.description = description
@description.setter
def description(self, description):
self._description = description
def set_input(self, path, cmd):
self.path_input = path
self.cmd_input = cmd
self._path_input = path
self._cmd_input = cmd
def set_solver(self, path, cmd):
self.path_solver = path
self.cmd_solver = cmd
self._path_solver = path
self._cmd_solver = cmd
def set_output(self, path, cmd):
self.path_output = path
self.cmd_output = cmd
self._path_output = path
self._cmd_output = cmd
# Run
def run_input_data_fomater(self):
if self.cmd_input == "":
if self._cmd_input == "":
return True
return False
def run_solver(self):
if self.cmd_solver == "":
if self._cmd_solver == "":
return True
return False
def run_output_data_fomater(self, ):
if self.cmd_output == "":
if self._cmd_output == "":
return True
return False

View File

@ -9,3 +9,9 @@ class GenericSolver(AbstractSolver):
super(GenericSolver, self).__init__(name)
self._type = "generic"
@classmethod
def default_parameters(cls):
lst = super(Mage, cls).default_parameters()
return lst

48
src/Solver/Mage.py Normal file
View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from Solver.GenericSolver import GenericSolver
class Mage(GenericSolver):
def __init__(self, name):
super(Mage, self).__init__(name)
self._type = "mage"
self._cmd_input = ""
self._cmd_solver = "@path @input -o @output"
self._cmd_output = ""
@classmethod
def default_parameters(cls):
lst = super(Mage, cls).default_parameters()
lst += [
("time_step", "300"),
]
return lst
class Mage7(Mage):
def __init__(self, name):
super(Mage7, self).__init__(name)
self._type = "mage7"
@classmethod
def default_parameters(cls):
lst = super(Mage7, cls).default_parameters()
return lst
class Mage8(Mage):
def __init__(self, name):
super(Mage8, self).__init__(name)
self._type = "mage8"
@classmethod
def default_parameters(cls):
lst = super(Mage8, cls).default_parameters()
return lst

View File

@ -27,6 +27,7 @@ from View.LateralContribution.Window import LateralContributionWindow
from View.InitialConditions.Window import InitialConditionsWindow
from View.Stricklers.Window import StricklersWindow
from View.Sections.Window import SectionsWindow
from View.SolverParameters.Window import SolverParametersWindow
from Model.Study import Study
@ -125,7 +126,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_toolBar_network": self.open_network,
"action_toolBar_geometry": self.open_geometry,
"action_toolBar_mesh": lambda: self.open_dummy("Mesh"),
"action_toolBar_run_meshing_tool": lambda: self.open_dummy("Lancement mailleur externe"),
"action_toolBar_run_meshing_tool": self.open_solver_parameters,
"action_toolBar_boundary_cond": self.open_boundary_cond,
"action_toolBar_lateral_contrib": self.open_lateral_contrib,
"action_toolBar_spills": lambda: self.open_dummy("Deversement"),
@ -361,6 +362,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
self.initial.show()
def open_solver_parameters(self):
self.params = SolverParametersWindow(
study = self.model,
parent = self
)
self.params.show()
# TODO: Delete me !
###############
# DUMMY STUFF #

View File

@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox,
)
from View.SolverParameters.UndoCommand import *
from View.SolverParameters.translate import *
_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
def __init__(self, data=None, undo=None, tab=""):
super(QAbstractTableModel, self).__init__()
self._headers = list(table_headers.keys())
self._data = data
self._undo = undo
self._tab = tab
self._params = self._data.get_params(self._tab)
def flags(self, index):
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if self._headers[self._column] == "value":
options |= Qt.ItemIsEditable
return options
def rowCount(self, parent):
return len(self._params)
def columnCount(self, parent):
return len(self._headers)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
if 0 <= column < len(self._headers):
return self._params.get(row)[self._headers[column]]
return QVariant()
def headerData(self, section, orientation, role):
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
return table_headers[self._headers[section]]
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
row = index.row()
column = index.column()
if self._headers[column] == "value":
self._undo.push(
SetCommand(
self._params, row, "value", value
)
)
self.dataChanged.emit(index, index)
return True
# def add(self, row, parent=QModelIndex()):
# self.beginInsertRows(parent, row, row - 1)
# self._undo.push(
# AddCommand(
# self._params, row
# )
# )
# self.endInsertRows()
# self.layoutChanged.emit()
# def delete(self, rows, parent=QModelIndex()):
# self.beginRemoveRows(parent, rows[0], rows[-1])
# self._undo.push(
# DelCommand(
# self._params, rows
# )
# )
# self.endRemoveRows()
# self.layoutChanged.emit()
# def sort(self, _reverse, parent=QModelIndex()):
# self.layoutAboutToBeChanged.emit()
# self._undo.push(
# SortCommand(
# self._params, False
# )
# )
# self.layoutAboutToBeChanged.emit()
# self.layoutChanged.emit()
# def move_up(self, row, parent=QModelIndex()):
# if row <= 0:
# return
# target = row + 2
# self.beginMoveRows(parent, row - 1, row - 1, parent, target)
# self._undo_stack.push(
# MoveCommand(
# self._params, "up", row
# )
# )
# self.endMoveRows()
# self.layoutChanged.emit()
# def move_down(self, index, parent=QModelIndex()):
# if row > len(self._params):
# return
# target = row
# self.beginMoveRows(parent, row + 1, row + 1, parent, target)
# self._undo_stack.push(
# MoveCommand(
# self._params, "down", row
# )
# )
# self.endMoveRows()
# self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
from Model.SolverParameters.SolverParametersList import SolverParametersList
class SetCommand(QUndoCommand):
def __init__(self, data, index, column, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._column = column
self._old = self._data.get(self._index)[column]
self._new = new_value
def undo(self):
self._data.get(self._index)[column] = self._old
def redo(self):
self._data.get(self._index)[column] = self._new

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
)
from View.SolverParameters.UndoCommand import *
from View.SolverParameters.Table import TableModel
from View.SolverParameters.translate import *
_translate = QCoreApplication.translate
class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Solver parameters", study=None, parent=None):
title = title + " - " + study.name
super(SolverParametersWindow, self).__init__(
name=title, ui="SolverParameters", parent=parent
)
self._study = study
self._params = self._study.river.parameters
self.setup_sc()
self.setup_table()
self.setup_connections()
self.ui.setWindowTitle(title)
def setup_sc(self):
self._undo_stack = QUndoStack()
self.undo_sc = QShortcut(QKeySequence.Undo, self)
self.redo_sc = QShortcut(QKeySequence.Redo, self)
self.copy_sc = QShortcut(QKeySequence.Copy, self)
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
self._table = {}
for t in ["mage"]:
table = self.find(QTableView, f"tableView_{t}")
self._table[t] = TableModel(
data = self._study.river,
undo = self._undo_stack,
tab = t,
)
table.setModel(self._table[t])
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True)
def setup_connections(self):
self.undo_sc.activated.connect(self.undo)
self.redo_sc.activated.connect(self.redo)
self.copy_sc.activated.connect(self.copy)
self.paste_sc.activated.connect(self.paste)
def current_tab(self):
return self.find(QTabWidget, "tabWidget")\
.currentWidget()\
.objectName()\
.replace("tab_", "")
def undo(self):
tab = self.current_tab()
self._table[tab].undo()
self._set_current_reach()
def redo(self):
tab = self.current_tab()
self._table[tab].redo()
self._set_current_reach()
def copy(self):
print("TODO")
def paste(self):
print("TODO")

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
_translate = QCoreApplication.translate
table_headers = {
"name": _translate("LateralContribution", "Name"),
"value": _translate("LateralContribution", "Value")
}
# Used to translate user parameter with value yes or no
yes_no = {
"yes": _translate("SolverParameters", "Yes"),
"no": _translate("SolverParameters", "No"),
"y": _translate("SolverParameters", "Y"),
"n": _translate("SolverParameters", "N"),
# Reverse
_translate("SolverParameters", "Yes"): "Yes",
_translate("SolverParameters", "No"): "No",
_translate("SolverParameters", "Y"): "y",
_translate("SolverParameters", "N"): "n",
}
names = {
"mage_time_step": _translate("SolverParameters", "Time step in second")
}

View File

@ -113,6 +113,9 @@
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<property name="text">
<string>Input formater</string>
</property>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_mage">
<attribute name="title">
<string>Mage</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTableView" name="tableView_mage"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_rubarbe">
<attribute name="title">
<string>Rubarbe</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Not implemented yet !</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>