adists_num
Youcef AOUAD 2024-06-07 16:34:28 +02:00
parent 3afd9f5025
commit bcf825a4f7
11 changed files with 1208 additions and 3 deletions

View File

@ -0,0 +1,54 @@
# DialogDischarge.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from View.Tools.PamhyrWindow import PamhyrDialog
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QComboBox, QUndoStack, QShortcut,
QDoubleSpinBox,
)
class DischargeDialog(PamhyrDialog):
_pamhyr_ui = "InitialConditions_Dialog_Generator_Discharge"
_pamhyr_name = "Discharge"
def __init__(self, title="Discharge", trad=None, parent=None):
super(DischargeDialog, self).__init__(
title=trad[self._pamhyr_name],
options=[],
trad=trad,
parent=parent
)
self.value = None
def accept(self):
self.value = self.find(QDoubleSpinBox, "doubleSpinBox").value()
super().accept()
def reject(self):
self.close()

View File

@ -0,0 +1,54 @@
# DialogHeight.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from View.Tools.PamhyrWindow import PamhyrDialog
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QComboBox, QUndoStack, QShortcut,
QDoubleSpinBox,
)
class HeightDialog(PamhyrDialog):
_pamhyr_ui = "InitialConditions_Dialog_Generator_Height"
_pamhyr_name = "Height"
def __init__(self, trad=None, parent=None):
super(HeightDialog, self).__init__(
title=trad[self._pamhyr_name],
options=[],
trad=trad,
parent=parent
)
self.value = None
def accept(self):
self.value = self.find(QDoubleSpinBox, "doubleSpinBox").value()
super().accept()
def reject(self):
self.close()

View File

@ -0,0 +1,107 @@
# PlotDKP.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from tools import timer
from View.Tools.PamhyrPlot import PamhyrPlot
from PyQt5.QtCore import (
QCoreApplication
)
logger = logging.getLogger()
_translate = QCoreApplication.translate
class PlotDKP(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
data=None, parent=None):
super(PlotDKP, self).__init__(
canvas=canvas,
trad=trad,
data=data,
toolbar=toolbar,
parent=parent
)
self.label_x = self._trad["kp"]
self.label_y = self._trad["elevation"]
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
@timer
def draw(self, highlight=None):
self.init_axes()
if self.data is None:
return
self.draw_river_bottom()
self.draw_water()
self.idle()
self._init = True
def draw_river_bottom(self):
kp = self.data.reach.reach.get_kp()
z_min = self.data.reach.reach.get_z_min()
self.line_kp_zmin = self.canvas.axes.plot(
kp, z_min,
color=self.color_plot_river_bottom,
lw=1.
)
def draw_water(self):
if len(self.data) != 0:
kp = self.data.get_kp()
elevation = self.data.get_elevation()
self.line_kp_elevation = self.canvas.axes.plot(
kp, elevation,
color=self.color_plot_river_water,
**self.plot_default_kargs
)
z_min = self.data.reach.reach.get_z_min()
geometry_kp = self.data.reach.reach.get_kp()
filtred_elevation = list(
map(
lambda x: elevation[x[0]],
filter(
lambda x: x[1] in geometry_kp,
enumerate(kp)
)
)
)
self.collection = self.canvas.axes.fill_between(
geometry_kp, z_min, filtred_elevation,
color=self.color_plot_river_water_zone,
alpha=0.7, interpolate=True
)
@timer
def update(self, ind=None):
self.draw()

View File

@ -0,0 +1,69 @@
# PlotDischarge.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import timer
from View.Tools.PamhyrPlot import PamhyrPlot
class PlotDischarge(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
data=None, parent=None):
super(PlotDischarge, self).__init__(
canvas=canvas,
trad=trad,
data=data,
toolbar=toolbar,
parent=parent
)
self.label_x = self._trad["kp"]
self.label_y = self._trad["discharge"]
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
@timer
def draw(self):
self.init_axes()
if self.data is None:
return
self.draw_data()
self.idle()
self._init = True
def draw_data(self):
kp = self.data.reach.reach.get_kp()
if len(self.data) != 0:
kp = self.data.get_kp()
discharge = self.data.get_discharge()
self.line_kp_zmin = self.canvas.axes.plot(
kp, discharge,
color=self.color_plot,
**self.plot_default_kargs
)
@timer
def update(self, ind=None):
self.draw()

View File

@ -0,0 +1,298 @@
# Table.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
import traceback
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.Tools.PamhyrTable import PamhyrTableModel
from View.InitialConditions.UndoCommand import (
SetCommand, AddCommand, DelCommand,
SortCommand, MoveCommand, InsertCommand,
DuplicateCommand, GenerateCommand,
)
logger = logging.getLogger()
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
def __init__(self, reach=None, parent=None):
super(ComboBoxDelegate, self).__init__(parent)
self._reach = reach.reach
def createEditor(self, parent, option, index):
self.editor = QComboBox(parent)
self.editor.addItems(
list(
map(
str,
self._reach.get_kp()
)
)
)
self.editor.setCurrentText(str(index.data(Qt.DisplayRole)))
return self.editor
def setEditorData(self, editor, index):
value = index.data(Qt.DisplayRole)
self.editor.currentTextChanged.connect(self.currentItemChanged)
def setModelData(self, editor, model, index):
text = str(editor.currentText())
model.setData(index, text)
editor.close()
editor.deleteLater()
def updateEditorGeometry(self, editor, option, index):
r = QRect(option.rect)
if self.editor.windowFlags() & Qt.Popup:
if editor.parent() is not None:
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
editor.setGeometry(r)
@pyqtSlot()
def currentItemChanged(self):
self.commitData.emit(self.sender())
class InitialConditionTableModel(PamhyrTableModel):
def __init__(self, reach=None, **kwargs):
self._reach = reach
super(InitialConditionTableModel, self).__init__(**kwargs)
def _setup_lst(self):
self._lst = self._data.river.initial_conditions.get(self._reach)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
if self._headers[column] is "speed":
z = self._lst.get(row)["elevation"]
q = self._lst.get(row)["discharge"]
profile = self._reach.reach.get_profiles_from_kp(
self._lst.get(row)["kp"]
)
if len(profile) >= 1:
speed = profile[0].speed(q, z)
return f"{speed:.4f}"
return ""
elif self._headers[column] not in ["name", "comment"]:
v = self._lst.get(row)[self._headers[column]]
return f"{v:.4f}"
else:
return self._lst.get(row)[self._headers[column]]
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()
try:
if self._headers[column] is not None:
self._undo.push(
SetCommand(
self._lst, row, self._headers[column], value
)
)
except Exception as e:
logger.info(e)
logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
def add(self, row, parent=QModelIndex()):
self.beginInsertRows(parent, row, row - 1)
self._undo.push(
AddCommand(
self._lst, row
)
)
self.endInsertRows()
self.layoutChanged.emit()
def delete(self, rows, parent=QModelIndex()):
self.beginRemoveRows(parent, rows[0], rows[-1])
self._undo.push(
DelCommand(
self._lst, rows
)
)
self.endRemoveRows()
self.layoutChanged.emit()
def sort(self, _reverse, parent=QModelIndex()):
self.layoutAboutToBeChanged.emit()
self._undo.push(
SortCommand(
self._lst, 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.push(
MoveCommand(
self._lst, "up", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def move_down(self, row, parent=QModelIndex()):
if row > len(self._lst):
return
target = row
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
self._undo.push(
MoveCommand(
self._lst, "down", row
)
)
self.endMoveRows()
self.layoutChanged.emit()
def paste(self, index, header, data):
if len(header) != 0:
logger.error("Unexpected header in IC past data")
return
if len(data) == 0:
logger.error("Empty data")
return
if len(data[0]) != 3:
logger.error(f"Unexpected data size: [{data[0]}, ...]")
return
self.layoutAboutToBeChanged.emit()
self._undo.push(
InsertCommand(
self._lst, index,
list(
map(
lambda d: self._lst.new_from_data(*d),
data
)
)
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def import_from_results(self, index, results):
if results is None:
logger.error("No results data")
return
self.layoutAboutToBeChanged.emit()
ts = max(results.get("timestamps"))
res_reach = results.river.get_reach_by_geometry(
self._reach.reach
)
data = list(
map(
lambda p: [
p.geometry.kp,
p.get_ts_key(ts, "Q"),
p.get_ts_key(ts, "Z"),
],
res_reach.profiles
)
)
self._undo.push(
InsertCommand(
self._lst, index,
list(
map(
lambda d: self._lst.new_from_data(*d),
data
)
)
)
)
self.layoutAboutToBeChanged.emit()
self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()
def generate(self, generator, param):
self._undo.push(
GenerateCommand(
self._lst, generator, param
)
)
self.layoutChanged.emit()

View File

@ -0,0 +1,192 @@
# UndoCommand.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
from Model.InitialConditions.InitialConditions import InitialConditions
from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
class SetCommand(QUndoCommand):
def __init__(self, ics, row, column, new_value):
QUndoCommand.__init__(self)
self._ics = ics
self._row = row
self._column = column
self._old = self._ics.get(self._row)[column]
_type = float
if column == "name" or column == "comment":
_type = str
self._new = _type(new_value)
def undo(self):
self._ics.get(self._row)[self._column] = self._old
def redo(self):
self._ics.get(self._row)[self._column] = self._new
class AddCommand(QUndoCommand):
def __init__(self, ics, index):
QUndoCommand.__init__(self)
self._ics = ics
self._index = index
self._new = None
def undo(self):
self._ics.delete_i([self._index])
def redo(self):
if self._new is None:
self._new = self._ics.new(self._index)
else:
self._ics.insert(self._index, self._new)
class DelCommand(QUndoCommand):
def __init__(self, ics, rows):
QUndoCommand.__init__(self)
self._ics = ics
self._rows = rows
self._ic = []
for row in rows:
self._ic.append((row, self._ics.get(row)))
self._ic.sort()
def undo(self):
for row, el in self._ic:
self._ics.insert(row, el)
def redo(self):
self._ics.delete_i(self._rows)
class SortCommand(QUndoCommand):
def __init__(self, ics, _reverse):
QUndoCommand.__init__(self)
self._ics = ics
self._reverse = _reverse
self._old = self._ics.data
self._indexes = None
def undo(self):
ll = self._ics.data
self._ics.sort(
key=lambda x: self._indexes[ll.index(x)]
)
def redo(self):
self._ics.sort(
reverse=self._reverse,
key=lambda x: x["kp"]
)
if self._indexes is None:
self._indexes = list(
map(
lambda p: self._old.index(p),
self._ics.data
)
)
self._old = None
class MoveCommand(QUndoCommand):
def __init__(self, ics, up, i):
QUndoCommand.__init__(self)
self._ics = ics
self._up = up == "up"
self._i = i
def undo(self):
if self._up:
self._ics.move_up(self._i)
else:
self._ics.move_down(self._i)
def redo(self):
if self._up:
self._ics.move_up(self._i)
else:
self._ics.move_down(self._i)
class InsertCommand(QUndoCommand):
def __init__(self, ics, row, ic):
QUndoCommand.__init__(self)
self._ics = ics
self._row = row
self._ic = deepcopy(ic)
self._ic.reverse()
def undo(self):
self._ics.delete(self._ic)
def redo(self):
for ic in self._ic:
self._ics.insert(self._row, ic)
class DuplicateCommand(QUndoCommand):
def __init__(self, ics, rows, ic):
QUndoCommand.__init__(self)
self._ics = ics
self._rows = rows
self._ic = deepcopy(ic)
self._ic.reverse()
def undo(self):
self._ics.delete(self._ic)
def redo(self):
for ic in self._ics:
self._ics.insert(self._rows[0], ic)
class GenerateCommand(QUndoCommand):
def __init__(self, ics, generator, param):
QUndoCommand.__init__(self)
self._ics = ics
self._param = param
self._copy = self._ics.data
self._generator = generator
def undo(self):
self._ics.data = self._copy
def redo(self):
if self._generator == "growing":
self._ics.generate_growing_constante_height(self._param)
elif self._generator == "discharge":
self._ics.generate_discharge(self._param)

View File

@ -0,0 +1,355 @@
# Window.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import os
import logging
from tools import trace, timer, logger_exception
from View.Tools.PamhyrWindow import PamhyrWindow
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 Modules import Modules
from View.InitialConditionsAdisTS.UndoCommand import (
SetCommand, AddCommand, DelCommand,
SortCommand, MoveCommand, InsertCommand,
DuplicateCommand,
)
from View.InitialConditionsAdisTS.Table import (
InitialConditionTableModel, ComboBoxDelegate,
)
from View.Tools.Plot.PamhyrCanvas import MplCanvas
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
from View.InitialConditionsAdisTS.PlotDKP import PlotDKP
from View.InitialConditionsAdisTS.PlotDischarge import PlotDischarge
from View.InitialConditionsAdisTS.translate import ICTranslate
from View.InitialConditionsAdisTS.DialogHeight import HeightDialog
from View.InitialConditionsAdisTS.DialogDischarge import DischargeDialog
from View.Results.ReadingResultsDialog import ReadingResultsDialog
from Solver.Mage import Mage8
_translate = QCoreApplication.translate
logger = logging.getLogger()
class InitialConditionsWindow(PamhyrWindow):
_pamhyr_ui = "InitialConditions"
_pamhyr_name = "Initial condition"
def __init__(self, study=None, config=None, reach=None, parent=None):
trad = ICTranslate()
if reach is not None:
self._reach = reach
else:
self._reach = study.river.current_reach()
name = (
trad[self._pamhyr_name] +
" - " + study.name +
" - " + self._reach.name
)
super(InitialConditionsWindow, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
parent=parent
)
# Add reach to hash computation data
self._hash_data.append(self._reach)
self._ics = study.river.initial_conditions.get(self._reach)
self.setup_table()
self.setup_plot()
self.setup_connections()
self.ui.setWindowTitle(self._title)
def setup_table(self):
table = self.find(QTableView, f"tableView")
self._delegate_kp = ComboBoxDelegate(
reach=self._reach,
parent=self
)
self._table = InitialConditionTableModel(
reach=self._reach,
table_view=table,
table_headers=self._trad.get_dict("table_headers"),
editable_headers=["kp", "discharge", "elevation", "height"],
delegates={"kp": self._delegate_kp},
data=self._study,
undo=self._undo_stack,
trad=self._trad
)
table.setModel(self._table)
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True)
def setup_plot(self):
self.canvas_1 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_1.setObjectName("canvas_1")
self.toolbar_1 = PamhyrPlotToolbar(
self.canvas_1, self
)
self.plot_layout_1 = self.find(QVBoxLayout, "verticalLayout_1")
self.plot_layout_1.addWidget(self.toolbar_1)
self.plot_layout_1.addWidget(self.canvas_1)
self.plot_1 = PlotDKP(
canvas=self.canvas_1,
data=self._ics,
trad=self._trad,
toolbar=self.toolbar_1,
parent=self
)
self.plot_1.draw()
self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
self.canvas_2.setObjectName("canvas_2")
self.toolbar_2 = PamhyrPlotToolbar(
self.canvas_2, self
)
self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
self.plot_layout_2.addWidget(self.toolbar_2)
self.plot_layout_2.addWidget(self.canvas_2)
self.plot_2 = PlotDischarge(
canvas=self.canvas_2,
data=self._ics,
trad=self._trad,
toolbar=self.toolbar_2,
parent=self
)
self.plot_2.draw()
def setup_connections(self):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_del").triggered.connect(self.delete)
self.find(QAction, "action_sort").triggered.connect(self.sort)
self.find(QAction, "action_import").triggered\
.connect(self.import_from_file)
self.find(QPushButton, "pushButton_generate_1").clicked.connect(
self.generate_growing_constante_height
)
self.find(QPushButton, "pushButton_generate_2").clicked.connect(
self.generate_discharge
)
self._table.dataChanged.connect(self._update_plot)
def index_selected_row(self):
table = self.find(QTableView, f"tableView")
rows = table.selectionModel()\
.selectedRows()
if len(rows) == 0:
return 0
return rows[0].row()
def update(self):
self._update_plot()
self._propagate_update(key=Modules.INITIAL_CONDITION)
def _update_plot(self):
self.plot_1.draw()
self.plot_2.draw()
def _propagated_update(self, key=Modules(0)):
if Modules.GEOMETRY not in key:
return
self.update()
def index_selected_rows(self):
table = self.find(QTableView, f"tableView")
return list(
# Delete duplicate
set(
map(
lambda i: i.row(),
table.selectedIndexes()
)
)
)
def add(self):
rows = self.index_selected_rows()
if len(self._ics) == 0 or len(rows) == 0:
self._table.add(0)
else:
self._table.add(rows[0])
self._update()
def delete(self):
rows = self.index_selected_rows()
if len(rows) == 0:
return
self._table.delete(rows)
self._update()
def sort(self):
self._table.sort(False)
self._update()
def import_from_file(self):
workdir = os.path.dirname(self._study.filename)
return self.file_dialog(
callback=lambda d: self._import_from_file(d[0]),
directory=workdir,
default_suffix=".BIN",
file_filter=["Mage (*.BIN)"],
)
def _import_from_file(self, file_name):
solver = Mage8("dummy")
name = os.path.basename(file_name)\
.replace(".BIN", "")
def reading():
self._tmp_results = solver.results(
self._study,
os.path.dirname(file_name),
name=name
)
dlg = ReadingResultsDialog(
reading_fn=reading,
parent=self
)
dlg.exec_()
results = self._tmp_results
self._import_from_results(results)
def _import_from_results(self, results):
logger.debug(f"import from results: {results}")
row = self.index_selected_row()
self._table.import_from_results(row, results)
def move_up(self):
row = self.index_selected_row()
self._table.move_up(row)
self._update()
def move_down(self):
row = self.index_selected_row()
self._table.move_down(row)
self._update()
def _copy(self):
rows = list(
map(
lambda row: row.row(),
self.tableView.selectionModel().selectedRows()
)
)
table = list(
map(
lambda eic: list(
map(
lambda k: eic[1][k],
["kp", "discharge", "elevation"]
)
),
filter(
lambda eic: eic[0] in rows,
enumerate(self._ics.lst())
)
)
)
self.copyTableIntoClipboard(table)
def _paste(self):
header, data = self.parseClipboardTable()
if len(data) + len(header) == 0:
return
logger.debug(
"IC: Paste: " +
f"header = {header}, " +
f"data = {data}"
)
try:
row = self.index_selected_row()
# self._table.paste(row, header, data)
self._table.paste(row, [], data)
except Exception as e:
logger_exception(e)
self._update()
def _undo(self):
self._table.undo()
self._update()
def _redo(self):
self._table.redo()
self._update()
def generate_growing_constante_height(self):
dlg = HeightDialog(trad=self._trad, parent=self)
if dlg.exec():
value = dlg.value
self._table.generate("growing", value)
self._update()
def generate_discharge(self):
dlg = DischargeDialog(trad=self._trad, parent=self)
if dlg.exec():
value = dlg.value
self._table.generate("discharge", value)
self._update()

View File

@ -0,0 +1,49 @@
# translate.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate
_translate = QCoreApplication.translate
class ICTranslate(MainTranslate):
def __init__(self):
super(ICTranslate, self).__init__()
self._dict["Initial condition"] = _translate(
"InitialCondition", "Initial condition")
self._dict["Discharge"] = _translate(
"InitialCondition", "Discharge")
self._dict["Height"] = _translate(
"InitialCondition", "Height")
self._dict["elevation"] = self._dict["unit_elevation"]
self._dict["discharge"] = self._dict["unit_discharge"]
self._dict["kp"] = self._dict["unit_kp"]
self._sub_dict["table_headers"] = {
# "name": _translate("InitialCondition", "Name"),
"kp": self._dict["unit_kp"],
"discharge": self._dict["unit_discharge"],
"elevation": self._dict["unit_elevation"],
"height": self._dict["unit_height"],
"speed": self._dict["unit_speed"],
# "comment": _translate("InitialCondition", "Comment"),
}

View File

@ -43,6 +43,8 @@ from View.Pollutants.Translate import PollutantsTranslate
from View.Pollutants.Edit.Window import EditPolluantWindow
from View.InitialConditionsAdisTS.Window import InitialConditionsWindow
logger = logging.getLogger()
@ -102,6 +104,7 @@ class PollutantsWindow(PamhyrWindow):
self.find(QAction, "action_add").triggered.connect(self.add)
self.find(QAction, "action_delete").triggered.connect(self.delete)
self.find(QAction, "action_edit").triggered.connect(self.edit)
self.find(QAction, "action_initial_conditions").triggered.connect(self.initial_conditions)
self._checkbox.clicked.connect(self._set_structure_state)
table = self.find(QTableView, "tableView")
@ -186,6 +189,27 @@ class PollutantsWindow(PamhyrWindow):
)
win.show()
def initial_conditions(self):
if self._study.river.has_current_reach():
reach = self._study.river.current_reach()
if self.sub_window_exists(
InitialConditionsWindow,
#data=[self._study, self.conf, reach]
data=[self._study, None, reach]
):
return
initial = InitialConditionsWindow(
study=self._study,
#config=self.conf,
reach=reach,
parent=self
)
initial.show()
else:
self.msg_select_reach()
def _set_checkbox_state(self):
row = self.index_selected_row()
if row is None:

View File

@ -34,9 +34,6 @@
</size>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout"/>
</widget>
</widget>
</item>
</layout>

View File

@ -96,6 +96,7 @@
<addaction name="action_add"/>
<addaction name="action_delete"/>
<addaction name="action_edit"/>
<addaction name="action_initial_conditions"/>
</widget>
<action name="action_add">
<property name="icon">
@ -129,6 +130,11 @@
<string>Edit selected hydraulic structure</string>
</property>
</action>
<action name="action_initial_conditions">
<property name="text">
<string>InitialConditions</string>
</property>
</action>
</widget>
<resources/>
<connections/>