mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
67
Commits
v0.0.8
..
adists_new
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ae16ca6ec | ||
|
|
c7406d3bce | ||
|
|
cb8ecc752b | ||
|
|
4c522ae050 | ||
|
|
689d5a7592 | ||
|
|
c118d4fae8 | ||
|
|
1baf2e8dd5 | ||
|
|
1fcdaa8b81 | ||
|
|
71729578dd | ||
|
|
abe7bf969a | ||
|
|
673ae3908c | ||
|
|
1a31c9122e | ||
|
|
c53d7d9c25 | ||
|
|
02f14ffdf1 | ||
|
|
84fd841f86 | ||
|
|
629b856788 | ||
|
|
f3007e2fe2 | ||
|
|
a7a1a4ddd1 | ||
|
|
0719db17ed | ||
|
|
018192714c | ||
|
|
501000fa6b | ||
|
|
75149000db | ||
|
|
3c82148f44 | ||
|
|
7f2ff9d341 | ||
|
|
57be80bcd4 | ||
|
|
29b5c97345 | ||
|
|
b171eb7d32 | ||
|
|
0e18d43496 | ||
|
|
bd4222adfa | ||
|
|
1e4761609d | ||
|
|
de72e2e96b | ||
|
|
95a0dabe68 | ||
|
|
9f53ad685e | ||
|
|
02c597d109 | ||
|
|
510bee115b | ||
|
|
ed250f836d | ||
|
|
a47410a0f1 | ||
|
|
704130966e | ||
|
|
b927aa81b3 | ||
|
|
d154ac96c2 | ||
|
|
6067ba601e | ||
|
|
716d0af96f | ||
|
|
f917dd9284 | ||
|
|
cd68bebf03 | ||
|
|
35cc348f03 | ||
|
|
6f3e1e31f0 | ||
|
|
7df0750c58 | ||
|
|
bcf825a4f7 | ||
|
|
3afd9f5025 | ||
|
|
3cb47ee5c8 | ||
|
|
1535247e1b | ||
|
|
37dd4ebaef | ||
|
|
1e8949067b | ||
|
|
1945e94190 | ||
|
|
1ba971af24 | ||
|
|
0b5357d12a | ||
|
|
3be361b03c | ||
|
|
7681b5d326 | ||
|
|
0a35d387f7 | ||
|
|
b40efc2426 | ||
|
|
59aae7fd40 | ||
|
|
a633e4bccf | ||
|
|
b56b8099ab | ||
|
|
f9fe5c9b6c | ||
|
|
13b954d580 | ||
|
|
f53289ef1b | ||
|
|
1b3ce91582 |
No files matched your search
@@ -9,6 +9,8 @@
|
|||||||
*.class
|
*.class
|
||||||
|
|
||||||
tmp
|
tmp
|
||||||
|
mage8
|
||||||
|
adists
|
||||||
|
|
||||||
*.tar
|
*.tar
|
||||||
*.tar.*
|
*.tar.*
|
||||||
|
|||||||
+2
-7
@@ -29,7 +29,7 @@ stages:
|
|||||||
#############
|
#############
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
MAGE_8_VERSION: "v8.3.6"
|
MAGE_8_VERSION: "v8.3.5"
|
||||||
|
|
||||||
dl-mage8-doc:
|
dl-mage8-doc:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -262,11 +262,6 @@ build-linux:
|
|||||||
- cp -v ../mage8-linux/* pamhyr/mage8/
|
- cp -v ../mage8-linux/* pamhyr/mage8/
|
||||||
# Copy Pamhyr
|
# Copy Pamhyr
|
||||||
- cp -r dist/pamhyr/* pamhyr/
|
- cp -r dist/pamhyr/* pamhyr/
|
||||||
# Pamhyr script to force x11
|
|
||||||
- echo '#!/usr/bin/env bash' > pamhyr/pamhyr-x11
|
|
||||||
- echo "" >> pamhyr/pamhyr-x11
|
|
||||||
- echo "GDK_BACKEND=x11 ./pamhyr $@" >> pamhyr/pamhyr-x11
|
|
||||||
- chmod +x pamhyr/pamhyr-x11
|
|
||||||
# Copy Pamhyr resources
|
# Copy Pamhyr resources
|
||||||
- mkdir -p pamhyr/_internal/View
|
- mkdir -p pamhyr/_internal/View
|
||||||
- mkdir -p pamhyr/_internal/View/ui
|
- mkdir -p pamhyr/_internal/View/ui
|
||||||
@@ -338,7 +333,7 @@ build-windows:
|
|||||||
- python -m pip install -U -r ..\requirements.txt
|
- python -m pip install -U -r ..\requirements.txt
|
||||||
# Run Pyinstaller
|
# Run Pyinstaller
|
||||||
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
||||||
- pyinstaller -i ../src/View/ui/ressources/icon.ico --hide-console hide-early -y ..\src\pamhyr.py
|
- pyinstaller --hide-console hide-early -y ..\src\pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir pamhyr
|
- mkdir pamhyr
|
||||||
- dir
|
- dir
|
||||||
|
|||||||
Generated
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.10 (pamhyr)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pamhyr)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/pamhyr.iml" filepath="$PROJECT_DIR$/.idea/pamhyr.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.10 (pamhyr)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -3,7 +3,6 @@
|
|||||||
!define LIC_NAME "LICENSE"
|
!define LIC_NAME "LICENSE"
|
||||||
!define APP_NAME "PAMHYR"
|
!define APP_NAME "PAMHYR"
|
||||||
|
|
||||||
Icon "pamhyr\_internal\View\ui\ressources\icon.ico"
|
|
||||||
Name "Pamhyr2"
|
Name "Pamhyr2"
|
||||||
OutFile "pamhyr-windows.exe"
|
OutFile "pamhyr-windows.exe"
|
||||||
LicenseData "pamhyr\_internal\LICENSE"
|
LicenseData "pamhyr\_internal\LICENSE"
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
# PlotKPC.py -- Pamhyr
|
# Adists.py -- Pamhyr study checkers
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2024 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -16,35 +16,36 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
from View.HydraulicStructures.PlotKPC import PlotKPC
|
|
||||||
|
from Modules import Modules
|
||||||
|
from Checker.Checker import AbstractModelChecker, STATUS
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class PlotKPZ(PlotKPC):
|
class AdistsOutputKpChecker(AbstractModelChecker):
|
||||||
def __init__(self, canvas=None, trad=None, toolbar=None,
|
def __init__(self):
|
||||||
river=None, reach=None, profile=None,
|
super(AdistsOutputKpChecker, self).__init__()
|
||||||
parent=None):
|
|
||||||
super(PlotKPC, self).__init__(
|
self._name = _translate("Checker", "AdisTS output Kp checker")
|
||||||
canvas=canvas,
|
self._description = _translate(
|
||||||
trad=trad,
|
"Checker", "Check output Kp"
|
||||||
data=river,
|
|
||||||
toolbar=toolbar,
|
|
||||||
parent=parent
|
|
||||||
)
|
)
|
||||||
|
self._modules = Modules.OUTPUT_KP
|
||||||
|
|
||||||
self._current_reach = reach
|
def run(self, study):
|
||||||
self._current_profile = profile
|
ok = True
|
||||||
|
nerror = 0
|
||||||
|
self._summary = "ok"
|
||||||
|
self._status = STATUS.OK
|
||||||
|
|
||||||
self.label_x = self._trad["unit_kp"]
|
if not self.basic_check(study):
|
||||||
self.label_y = self._trad["unit_elevation"]
|
return False
|
||||||
|
|
||||||
self._isometric_axis = False
|
return ok
|
||||||
|
|
||||||
self._auto_relim_update = True
|
|
||||||
self._autoscale_update = True
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
def onpick(self, event):
|
|
||||||
return
|
|
||||||
+4
-4
@@ -206,11 +206,11 @@ class MageGeometryGuideLineChecker(StudyGeometryChecker):
|
|||||||
def __init__(self, version="mage8"):
|
def __init__(self, version="mage8"):
|
||||||
super(MageGeometryGuideLineChecker, self).__init__()
|
super(MageGeometryGuideLineChecker, self).__init__()
|
||||||
|
|
||||||
self._name = _translate("Checker", "Mage geometry guideline checker")
|
self._name = _translate("Checker", "Mage geometry guide line checker")
|
||||||
self._description = _translate(
|
self._description = _translate(
|
||||||
"Checker",
|
"Checker",
|
||||||
"Check if exists geometry guidelines are correctly defined \
|
"Check if exists geometry guide line is correctly defined \
|
||||||
for each reach"
|
for each reaches of the study"
|
||||||
)
|
)
|
||||||
self._solver = version
|
self._solver = version
|
||||||
self._modules = Modules.GEOMETRY
|
self._modules = Modules.GEOMETRY
|
||||||
@@ -241,7 +241,7 @@ for each reach"
|
|||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
if not profile.has_standard_named_points():
|
if not profile.has_standard_named_points():
|
||||||
self._status = STATUS.WARNING
|
self._status = STATUS.WARNING
|
||||||
self._summary = "no_standard_guideline_defined"
|
self._summary = "no_standard_guileline_defined"
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for gl in gls[1:]:
|
for gl in gls[1:]:
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ class StudyNetworkReachChecker(AbstractModelChecker):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(StudyNetworkReachChecker, self).__init__()
|
super(StudyNetworkReachChecker, self).__init__()
|
||||||
|
|
||||||
self._name = _translate("Checker", "Study reach network checker")
|
self._name = _translate("Checker", "Study network reach checker")
|
||||||
self._description = _translate(
|
self._description = _translate(
|
||||||
"Checker", "Check if exists at least one reach exists"
|
"Checker", "Check if exists at least one reach for study"
|
||||||
)
|
)
|
||||||
self._modules = Modules.NETWORK
|
self._modules = Modules.NETWORK
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class StudyGeometryChecker(AbstractModelChecker):
|
|||||||
|
|
||||||
self._name = _translate("Checker", "Study geometry checker")
|
self._name = _translate("Checker", "Study geometry checker")
|
||||||
self._description = _translate(
|
self._description = _translate(
|
||||||
"Checker", "Check if the geometry of each reach exists"
|
"Checker", "Check if exists geometry for each reach of study"
|
||||||
)
|
)
|
||||||
self._modules = Modules.GEOMETRY
|
self._modules = Modules.GEOMETRY
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -371,8 +371,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
lplan: bool = False,
|
lplan: bool = False,
|
||||||
lm: int = 3,
|
lm: int = 3,
|
||||||
linear: bool = False,
|
linear: bool = False,
|
||||||
origin_value=0.0,
|
origin_value=0.0):
|
||||||
orientation=0):
|
|
||||||
if reach is None or len(reach.profiles) == 0:
|
if reach is None or len(reach.profiles) == 0:
|
||||||
return reach
|
return reach
|
||||||
|
|
||||||
@@ -401,7 +400,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
f"{str(step)} " +
|
f"{str(step)} " +
|
||||||
f"{limites[0]} {limites[1]} " +
|
f"{limites[0]} {limites[1]} " +
|
||||||
f"{directrices[0]} {directrices[1]} " +
|
f"{directrices[0]} {directrices[1]} " +
|
||||||
f"{orientation} {lm} {linear} " +
|
f"{lplan} {lm} {linear} " +
|
||||||
f"{origin} "
|
f"{origin} "
|
||||||
)
|
)
|
||||||
proc.start(
|
proc.start(
|
||||||
@@ -414,7 +413,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
"update_kp", step,
|
"update_kp", step,
|
||||||
limites[0], limites[1],
|
limites[0], limites[1],
|
||||||
directrices[0], directrices[1],
|
directrices[0], directrices[1],
|
||||||
orientation, lm, linear, origin, origin_value
|
lplan, lm, linear, origin, origin_value
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -315,9 +315,6 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
self._data.sort(reverse=_reverse, key=key)
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def index(self, bc):
|
|
||||||
self._data.index(bc)
|
|
||||||
|
|
||||||
def get_i(self, index):
|
def get_i(self, index):
|
||||||
return self.data[index]
|
return self.data[index]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
# BoundaryConditionsAdisTS.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 (
|
||||||
|
trace, timer,
|
||||||
|
old_pamhyr_date_to_timestamp,
|
||||||
|
date_iso_to_timestamp,
|
||||||
|
date_dmy_to_timestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class BoundaryConditionAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1,
|
||||||
|
pollutant: int = -1, status=None):
|
||||||
|
super(BoundaryConditionAdisTS, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = BoundaryConditionAdisTS._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._type = ""
|
||||||
|
self._node = None
|
||||||
|
self._pollutant = pollutant
|
||||||
|
self._data = []
|
||||||
|
self._header = []
|
||||||
|
self._types = [self.time_convert, float]
|
||||||
|
|
||||||
|
BoundaryConditionAdisTS._id_cnt = max(BoundaryConditionAdisTS._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE boundary_condition_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
pollutant INTEGER NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
node INTEGER,
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(id),
|
||||||
|
FOREIGN KEY(node) REFERENCES river_node(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE boundary_condition_data_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
data0 TEXT NOT NULL,
|
||||||
|
data1 TEXT NOT NULL,
|
||||||
|
bc INTEGER,
|
||||||
|
FOREIGN KEY(bc) REFERENCES boundary_condition_adists(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, pollutant, type, node " +
|
||||||
|
"FROM boundary_condition_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
bc = cls(
|
||||||
|
id=row[0],
|
||||||
|
pollutant=row[1],
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
bc.type = row[2]
|
||||||
|
|
||||||
|
bc.node = None
|
||||||
|
if row[3] != -1:
|
||||||
|
bc.node = next(filter(lambda n: n.id == row[3], data["nodes"])).id
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT data0, data1 FROM boundary_condition_data_adists " +
|
||||||
|
f"WHERE bc = '{bc.id}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write data
|
||||||
|
for v in values:
|
||||||
|
data0 = bc._types[0](v[0])
|
||||||
|
data1 = bc._types[1](v[1])
|
||||||
|
# Replace data at pos ind
|
||||||
|
bc._data.append((data0, data1))
|
||||||
|
|
||||||
|
new.append(bc)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
|
||||||
|
execute(f"DELETE FROM boundary_condition_adists WHERE id = {self.id}")
|
||||||
|
execute(f"DELETE FROM boundary_condition_data_adists WHERE bc = {self.id}")
|
||||||
|
|
||||||
|
node = -1
|
||||||
|
if self._node is not None:
|
||||||
|
node = self._node
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"boundary_condition_adists(id, pollutant, type, node) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._pollutant}, " +
|
||||||
|
f"'{self._db_format(self._type)}', {node}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
data0 = self._db_format(str(d[0]))
|
||||||
|
data1 = self._db_format(str(d[1]))
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"boundary_condition_data_adists(data0, data1, bc) " +
|
||||||
|
f"VALUES ('{data0}', {data1}, {self.id})"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def time_convert(cls, data):
|
||||||
|
if type(data) is str:
|
||||||
|
if data.count("-") == 2:
|
||||||
|
return date_iso_to_timestamp(data)
|
||||||
|
if data.count("/") == 2:
|
||||||
|
return date_dmy_to_timestamp(data)
|
||||||
|
if data.count(":") == 3:
|
||||||
|
return old_pamhyr_date_to_timestamp(data)
|
||||||
|
if data.count(":") == 2:
|
||||||
|
return old_pamhyr_date_to_timestamp("00:" + data)
|
||||||
|
if data.count(".") == 1:
|
||||||
|
return round(float(data))
|
||||||
|
|
||||||
|
return int(data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node(self):
|
||||||
|
return self._node
|
||||||
|
|
||||||
|
@node.setter
|
||||||
|
def node(self, node):
|
||||||
|
self._node = node
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def header(self):
|
||||||
|
return self._header.copy()
|
||||||
|
|
||||||
|
@header.setter
|
||||||
|
def header(self, header):
|
||||||
|
self._header = header
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pollutant(self):
|
||||||
|
return self._pollutant
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self._type
|
||||||
|
|
||||||
|
@type.setter
|
||||||
|
def type(self, type):
|
||||||
|
self._type = type
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data.copy()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# BoundaryConditionsAdisTSList.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 copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS
|
||||||
|
|
||||||
|
class BoundaryConditionsAdisTSList(PamhyrModelList):
|
||||||
|
_sub_classes = [
|
||||||
|
BoundaryConditionAdisTS,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
new._lst = BoundaryConditionAdisTS._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute("DELETE FROM boundary_condition_adists")
|
||||||
|
execute("DELETE FROM boundary_condition_data_adists")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for bc in self._lst:
|
||||||
|
bc._db_save(execute, data=data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def new(self, index, pollutant):
|
||||||
|
n = BoundaryConditionAdisTS(pollutant=pollutant, status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BCs_AdisTS_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
# D90AdisTS.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 functools import reduce
|
||||||
|
|
||||||
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from Model.D90AdisTS.D90AdisTSSpec import D90AdisTSSpec
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class D90AdisTS(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
D90AdisTSSpec,
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
|
status=None):
|
||||||
|
super(D90AdisTS, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = D90AdisTS._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._d90 = None
|
||||||
|
self._enabled = True
|
||||||
|
self._data = []
|
||||||
|
|
||||||
|
D90AdisTS._id_cnt = max(
|
||||||
|
D90AdisTS._id_cnt + 1,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE d90_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
d90 REAL NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, name, d90, enabled " +
|
||||||
|
"FROM d90_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
d90_id = row[0]
|
||||||
|
name = row[1]
|
||||||
|
d90 = row[2]
|
||||||
|
enabled = (row[3] == 1)
|
||||||
|
|
||||||
|
D90 = cls(
|
||||||
|
id=d90_id,
|
||||||
|
name=name,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
D90.d90 = d90
|
||||||
|
D90.enabled = enabled
|
||||||
|
|
||||||
|
data['d90_default_id'] = d90_id
|
||||||
|
D90._data = D90AdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
|
new.append(D90)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute(f"DELETE FROM d90_adists WHERE id = {self.id}")
|
||||||
|
|
||||||
|
d90 = -1.
|
||||||
|
if self.d90 is not None:
|
||||||
|
d90 = self.d90
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"d90_adists(" +
|
||||||
|
"id, name, d90, enabled" +
|
||||||
|
") " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, '{self._db_format(self._name)}', " +
|
||||||
|
f"{d90}, {self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
data['d90_default_id'] = self.id
|
||||||
|
execute(
|
||||||
|
"DELETE FROM d90_spec " +
|
||||||
|
f"WHERE d90_default = {self.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for d90_spec in self._data:
|
||||||
|
d90_spec._db_save(execute, data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def d90(self):
|
||||||
|
return self._d90
|
||||||
|
|
||||||
|
@d90.setter
|
||||||
|
def d90(self, d90):
|
||||||
|
self._d90 = d90
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = D90AdisTSSpec(status=self._status)
|
||||||
|
self._data.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def delete(self, data):
|
||||||
|
self._data = list(
|
||||||
|
filter(
|
||||||
|
lambda x: x not in data,
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
for ind in indexes:
|
||||||
|
del self._data[ind]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def insert(self, index, data):
|
||||||
|
self._data.insert(index, data)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# D90AdisTSList.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 copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.D90AdisTS.D90AdisTS import D90AdisTS
|
||||||
|
|
||||||
|
class D90AdisTSList(PamhyrModelList):
|
||||||
|
_sub_classes = [
|
||||||
|
D90AdisTS,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
new._lst = D90AdisTS._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute("DELETE FROM d90_adists")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for d90 in self._lst:
|
||||||
|
d90._db_save(execute, data=data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = D90AdisTS(status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
@property
|
||||||
|
def D90_AdisTS_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
# D90AdisTSSpec.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 trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class D90AdisTSSpec(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
status=None):
|
||||||
|
super(D90AdisTSSpec, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = D90AdisTSSpec._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name_section = name
|
||||||
|
self._reach = None
|
||||||
|
self._start_kp = None
|
||||||
|
self._end_kp = None
|
||||||
|
self._d90 = None
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
|
D90AdisTSSpec._id_cnt = max(D90AdisTSSpec._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE d90_spec(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
d90_default INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
reach INTEGER NOT NULL,
|
||||||
|
start_kp REAL NOT NULL,
|
||||||
|
end_kp REAL NOT NULL,
|
||||||
|
d90 REAL NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
FOREIGN KEY(d90_default) REFERENCES d90_adists(id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, d90_default, name, reach, start_kp, end_kp, " +
|
||||||
|
"d90, enabled " +
|
||||||
|
"FROM d90_spec " +
|
||||||
|
f"WHERE d90_default = {data['d90_default_id']} "
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in table:
|
||||||
|
id = row[0]
|
||||||
|
name = row[2]
|
||||||
|
reach = row[3]
|
||||||
|
start_kp = row[4]
|
||||||
|
end_kp = row[5]
|
||||||
|
d90 = row[6]
|
||||||
|
enabled = (row[7] == 1)
|
||||||
|
|
||||||
|
new_spec = cls(
|
||||||
|
id=id,
|
||||||
|
name=name,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
new_spec.reach = reach
|
||||||
|
new_spec.start_kp = start_kp
|
||||||
|
new_spec.end_kp = end_kp
|
||||||
|
new_spec.d90 = d90
|
||||||
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
new.append(new_spec)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
d90_default = data['d90_default_id']
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"d90_spec(id, d90_default, name, reach, " +
|
||||||
|
"start_kp, end_kp, d90, enabled) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, " +
|
||||||
|
f"{d90_default}, " +
|
||||||
|
f"'{self._db_format(self._name_section)}', " +
|
||||||
|
f"{self._reach}, " +
|
||||||
|
f"{self._start_kp}, " +
|
||||||
|
f"{self._end_kp}, " +
|
||||||
|
f"{self._d90}, " +
|
||||||
|
f"{self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name_section
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name_section = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reach(self):
|
||||||
|
return self._reach
|
||||||
|
|
||||||
|
@reach.setter
|
||||||
|
def reach(self, reach):
|
||||||
|
self._reach = reach
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start_kp(self):
|
||||||
|
return self._start_kp
|
||||||
|
|
||||||
|
@start_kp.setter
|
||||||
|
def start_kp(self, start_kp):
|
||||||
|
self._start_kp = start_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_kp(self):
|
||||||
|
return self._end_kp
|
||||||
|
|
||||||
|
@end_kp.setter
|
||||||
|
def end_kp(self, end_kp):
|
||||||
|
self._end_kp = end_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def d90(self):
|
||||||
|
return self._d90
|
||||||
|
|
||||||
|
@d90.setter
|
||||||
|
def d90(self, d90):
|
||||||
|
self._d90 = d90
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
# DIFAdisTS.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 functools import reduce
|
||||||
|
|
||||||
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from Model.DIFAdisTS.DIFAdisTSSpec import DIFAdisTSSpec
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class DIFAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
DIFAdisTSSpec,
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
|
status=None):
|
||||||
|
super(DIFAdisTS, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = DIFAdisTS._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._method = None
|
||||||
|
self._dif = None
|
||||||
|
self._b = None
|
||||||
|
self._c = None
|
||||||
|
self._enabled = True
|
||||||
|
self._types = ["iwasa", "fisher", "elder", "constante", "generique"]
|
||||||
|
self._data = []
|
||||||
|
|
||||||
|
DIFAdisTS._id_cnt = max(
|
||||||
|
DIFAdisTS._id_cnt + 1,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE dif_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
method TEXT NOT NULL,
|
||||||
|
dif REAL NOT NULL,
|
||||||
|
b REAL,
|
||||||
|
c REAL,
|
||||||
|
enabled BOOLEAN NOT NULL
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, name, method, dif, b, c, enabled " +
|
||||||
|
"FROM dif_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
dif_id = row[0]
|
||||||
|
name = row[1]
|
||||||
|
method = row[2]
|
||||||
|
dif = row[3]
|
||||||
|
b = row[4]
|
||||||
|
c = row[5]
|
||||||
|
enabled = (row[6] == 1)
|
||||||
|
|
||||||
|
DIF = cls(
|
||||||
|
id=dif_id,
|
||||||
|
name=name,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
DIF.method = method
|
||||||
|
DIF.dif = dif
|
||||||
|
DIF.b = b
|
||||||
|
DIF.c = c
|
||||||
|
DIF.enabled = enabled
|
||||||
|
|
||||||
|
data['dif_default_id'] = dif_id
|
||||||
|
DIF._data = DIFAdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
|
new.append(DIF)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute(f"DELETE FROM dif_adists WHERE id = {self.id}")
|
||||||
|
|
||||||
|
method = ""
|
||||||
|
if self.method is not None:
|
||||||
|
method = self.method
|
||||||
|
|
||||||
|
dif = -1.
|
||||||
|
if self.dif is not None:
|
||||||
|
dif = self.dif
|
||||||
|
|
||||||
|
b = -1.
|
||||||
|
if self.b is not None:
|
||||||
|
b = self.b
|
||||||
|
|
||||||
|
c = -1.
|
||||||
|
if self.dif is not None:
|
||||||
|
c = self.c
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"dif_adists(" +
|
||||||
|
"id, name, method, dif, b, c, enabled" +
|
||||||
|
") " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, '{self._db_format(self._name)}', " +
|
||||||
|
f"'{self._db_format(self._method)}', " +
|
||||||
|
f"{dif}, {b}, {c}, {self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
data['dif_default_id'] = self.id
|
||||||
|
execute(
|
||||||
|
"DELETE FROM dif_spec " +
|
||||||
|
f"WHERE dif_default = {self.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for dif_spec in self._data:
|
||||||
|
dif_spec._db_save(execute, data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def method(self):
|
||||||
|
return self._method
|
||||||
|
|
||||||
|
@method.setter
|
||||||
|
def method(self, method):
|
||||||
|
self._method = method
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def types(self):
|
||||||
|
return self._types
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dif(self):
|
||||||
|
return self._dif
|
||||||
|
|
||||||
|
@dif.setter
|
||||||
|
def dif(self, dif):
|
||||||
|
self._dif = dif
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def b(self):
|
||||||
|
return self._b
|
||||||
|
|
||||||
|
@b.setter
|
||||||
|
def b(self, b):
|
||||||
|
self._b = b
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c(self):
|
||||||
|
return self._c
|
||||||
|
|
||||||
|
@c.setter
|
||||||
|
def c(self, c):
|
||||||
|
self._c = c
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = DIFAdisTSSpec(status=self._status)
|
||||||
|
self._data.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def delete(self, data):
|
||||||
|
self._data = list(
|
||||||
|
filter(
|
||||||
|
lambda x: x not in data,
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
for ind in indexes:
|
||||||
|
del self._data[ind]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def insert(self, index, data):
|
||||||
|
self._data.insert(index, data)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# DIFAdisTSList.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 copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.DIFAdisTS.DIFAdisTS import DIFAdisTS
|
||||||
|
|
||||||
|
class DIFAdisTSList(PamhyrModelList):
|
||||||
|
_sub_classes = [
|
||||||
|
DIFAdisTS,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
new._lst = DIFAdisTS._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute("DELETE FROM dif_adists")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for dif in self._lst:
|
||||||
|
dif._db_save(execute, data=data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = DIFAdisTS(status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DIF_AdisTS_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
# DIFAdisTSSpec.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 trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class DIFAdisTSSpec(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, method: str = "",
|
||||||
|
status=None):
|
||||||
|
super(DIFAdisTSSpec, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = DIFAdisTSSpec._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._method = method
|
||||||
|
self._reach = None
|
||||||
|
self._start_kp = None
|
||||||
|
self._end_kp = None
|
||||||
|
self._dif = None
|
||||||
|
self._b = None
|
||||||
|
self._c = None
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
|
DIFAdisTSSpec._id_cnt = max(DIFAdisTSSpec._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE dif_spec(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
dif_default INTEGER NOT NULL,
|
||||||
|
method TEXT NOT NULL,
|
||||||
|
reach INTEGER NOT NULL,
|
||||||
|
start_kp REAL NOT NULL,
|
||||||
|
end_kp REAL NOT NULL,
|
||||||
|
dif REAL NOT NULL,
|
||||||
|
b REAL,
|
||||||
|
c REAL,
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
FOREIGN KEY(dif_default) REFERENCES dif_adists(id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, dif_default, method, reach, start_kp, end_kp, " +
|
||||||
|
"dif, b, c, enabled " +
|
||||||
|
"FROM dif_spec " +
|
||||||
|
f"WHERE dif_default = {data['dif_default_id']} "
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in table:
|
||||||
|
id = row[0]
|
||||||
|
method = row[2]
|
||||||
|
reach = row[3]
|
||||||
|
start_kp = row[4]
|
||||||
|
end_kp = row[5]
|
||||||
|
dif = row[6]
|
||||||
|
b = row[7]
|
||||||
|
c = row[8]
|
||||||
|
enabled = (row[9] == 1)
|
||||||
|
|
||||||
|
new_spec = cls(
|
||||||
|
id=id,
|
||||||
|
method=method,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
new_spec.reach = reach
|
||||||
|
new_spec.start_kp = start_kp
|
||||||
|
new_spec.end_kp = end_kp
|
||||||
|
new_spec.dif = dif
|
||||||
|
new_spec.b = b
|
||||||
|
new_spec.c = c
|
||||||
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
new.append(new_spec)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
dif_default = data['dif_default_id']
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"dif_spec(id, dif_default, method, reach, " +
|
||||||
|
"start_kp, end_kp, dif, b, c, enabled) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, " +
|
||||||
|
f"{dif_default}, " +
|
||||||
|
f"'{self._db_format(self._method)}', " +
|
||||||
|
f"{self._reach}, " +
|
||||||
|
f"{self._start_kp}, " +
|
||||||
|
f"{self._end_kp}, " +
|
||||||
|
f"{self._dif}, " +
|
||||||
|
f"{self._b}, " +
|
||||||
|
f"{self._c}, " +
|
||||||
|
f"{self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def method(self):
|
||||||
|
return self._method
|
||||||
|
|
||||||
|
@method.setter
|
||||||
|
def method(self, method):
|
||||||
|
self._method = method
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reach(self):
|
||||||
|
return self._reach
|
||||||
|
|
||||||
|
@reach.setter
|
||||||
|
def reach(self, reach):
|
||||||
|
self._reach = reach
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start_kp(self):
|
||||||
|
return self._start_kp
|
||||||
|
|
||||||
|
@start_kp.setter
|
||||||
|
def start_kp(self, start_kp):
|
||||||
|
self._start_kp = start_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_kp(self):
|
||||||
|
return self._end_kp
|
||||||
|
|
||||||
|
@end_kp.setter
|
||||||
|
def end_kp(self, end_kp):
|
||||||
|
self._end_kp = end_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dif(self):
|
||||||
|
return self._dif
|
||||||
|
|
||||||
|
@dif.setter
|
||||||
|
def dif(self, dif):
|
||||||
|
self._dif = dif
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def b(self):
|
||||||
|
return self._b
|
||||||
|
|
||||||
|
@b.setter
|
||||||
|
def b(self, b):
|
||||||
|
self._b = b
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def c(self):
|
||||||
|
return self._c
|
||||||
|
|
||||||
|
@c.setter
|
||||||
|
def c(self, c):
|
||||||
|
self._c = c
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -64,6 +64,7 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute):
|
||||||
|
|
||||||
execute("""
|
execute("""
|
||||||
CREATE TABLE hydraulic_structures(
|
CREATE TABLE hydraulic_structures(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
@@ -138,6 +139,7 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
print("save hs unit")
|
||||||
execute(f"DELETE FROM hydraulic_structures WHERE id = {self.id}")
|
execute(f"DELETE FROM hydraulic_structures WHERE id = {self.id}")
|
||||||
|
|
||||||
input_reach_id = -1
|
input_reach_id = -1
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
# InitialConditionsAdisTS.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 functools import reduce
|
||||||
|
|
||||||
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSSpec import ICAdisTSSpec
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class InitialConditionsAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
ICAdisTSSpec,
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
|
pollutant: int = -1, status=None):
|
||||||
|
super(InitialConditionsAdisTS, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = InitialConditionsAdisTS._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._pollutant = pollutant
|
||||||
|
self._concentration = None
|
||||||
|
self._eg = None
|
||||||
|
self._em = None
|
||||||
|
self._ed = None
|
||||||
|
self._enabled = True
|
||||||
|
self._data = []
|
||||||
|
|
||||||
|
InitialConditionsAdisTS._id_cnt = max(
|
||||||
|
InitialConditionsAdisTS._id_cnt + 1,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE initial_conditions_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
pollutant INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
concentration REAL NOT NULL,
|
||||||
|
eg REAL NOT NULL,
|
||||||
|
em REAL NOT NULL,
|
||||||
|
ed REAL NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, pollutant, name, concentration, eg, em, ed, " +
|
||||||
|
"enabled " +
|
||||||
|
"FROM initial_conditions_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
IC_id = row[0]
|
||||||
|
pollutant = row[1]
|
||||||
|
name = row[2]
|
||||||
|
concentration = row[3]
|
||||||
|
eg = row[4]
|
||||||
|
em = row[5]
|
||||||
|
ed = row[6]
|
||||||
|
enabled = (row[7] == 1)
|
||||||
|
|
||||||
|
IC = cls(
|
||||||
|
id=IC_id,
|
||||||
|
name=name,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
IC.pollutant = pollutant
|
||||||
|
IC.concentration = concentration
|
||||||
|
IC.eg = eg
|
||||||
|
IC.em = em
|
||||||
|
IC.ed = ed
|
||||||
|
IC.enabled = enabled
|
||||||
|
|
||||||
|
data['ic_default_id'] = IC_id
|
||||||
|
IC._data = ICAdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
|
new.append(IC)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute(f"DELETE FROM initial_conditions_adists WHERE id = {self.id}")
|
||||||
|
|
||||||
|
pollutant = -1
|
||||||
|
if self.pollutant is not None:
|
||||||
|
pollutant = self.pollutant
|
||||||
|
|
||||||
|
concentration = -1.
|
||||||
|
if self.concentration is not None:
|
||||||
|
concentration = self.concentration
|
||||||
|
|
||||||
|
eg = -1.
|
||||||
|
if self.eg is not None:
|
||||||
|
eg = self.eg
|
||||||
|
|
||||||
|
em = -1.
|
||||||
|
if self.em is not None:
|
||||||
|
em = self.em
|
||||||
|
|
||||||
|
ed = -1.
|
||||||
|
if self.ed is not None:
|
||||||
|
ed = self.ed
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"initial_conditions_adists(" +
|
||||||
|
"id, pollutant, name, concentration, " +
|
||||||
|
"eg, em, ed, enabled" +
|
||||||
|
") " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {pollutant}, '{self._db_format(self._name)}', " +
|
||||||
|
f"{concentration}, {eg}, {em}, {ed}, {self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
data['ic_default_id'] = self.id
|
||||||
|
execute(
|
||||||
|
"DELETE FROM initial_conditions_spec " +
|
||||||
|
f"WHERE ic_default = {self.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for ic_spec in self._data:
|
||||||
|
ic_spec._db_save(execute, data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pollutant(self):
|
||||||
|
return self._pollutant
|
||||||
|
|
||||||
|
@pollutant.setter
|
||||||
|
def pollutant(self, pollutant):
|
||||||
|
self._pollutant = pollutant
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def concentration(self):
|
||||||
|
return self._concentration
|
||||||
|
|
||||||
|
@concentration.setter
|
||||||
|
def concentration(self, concentration):
|
||||||
|
self._concentration = concentration
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def eg(self):
|
||||||
|
return self._eg
|
||||||
|
|
||||||
|
@eg.setter
|
||||||
|
def eg(self, eg):
|
||||||
|
self._eg = eg
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def em(self):
|
||||||
|
return self._em
|
||||||
|
|
||||||
|
@em.setter
|
||||||
|
def em(self, em):
|
||||||
|
self._em = em
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ed(self):
|
||||||
|
return self._ed
|
||||||
|
|
||||||
|
@ed.setter
|
||||||
|
def ed(self, ed):
|
||||||
|
self._ed = ed
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = ICAdisTSSpec(status=self._status)
|
||||||
|
self._data.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def delete(self, data):
|
||||||
|
self._data = list(
|
||||||
|
filter(
|
||||||
|
lambda x: x not in data,
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
for ind in indexes:
|
||||||
|
del self._data[ind]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def insert(self, index, data):
|
||||||
|
self._data.insert(index, data)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# InitialConditionsAdisTSList.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 copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTS import InitialConditionsAdisTS
|
||||||
|
|
||||||
|
class InitialConditionsAdisTSList(PamhyrModelList):
|
||||||
|
_sub_classes = [
|
||||||
|
InitialConditionsAdisTS,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
new._lst = InitialConditionsAdisTS._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute("DELETE FROM initial_conditions_adists")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for ic in self._lst:
|
||||||
|
ic._db_save(execute, data=data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def new(self, index, pollutant):
|
||||||
|
n = InitialConditionsAdisTS(pollutant=pollutant, status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Initial_Conditions_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
# InitialConditionsAdisTSSpec.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 trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class ICAdisTSSpec(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
status=None):
|
||||||
|
super(ICAdisTSSpec, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = ICAdisTSSpec._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name_section = name
|
||||||
|
self._reach = None
|
||||||
|
self._start_kp = None
|
||||||
|
self._end_kp = None
|
||||||
|
self._concentration = None
|
||||||
|
self._eg = None
|
||||||
|
self._em = None
|
||||||
|
self._ed = None
|
||||||
|
self._rate = None
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
|
ICAdisTSSpec._id_cnt = max(ICAdisTSSpec._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE initial_conditions_spec(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
ic_default INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
reach INTEGER NOT NULL,
|
||||||
|
start_kp REAL NOT NULL,
|
||||||
|
end_kp REAL NOT NULL,
|
||||||
|
concentration REAL NOT NULL,
|
||||||
|
eg REAL NOT NULL,
|
||||||
|
em REAL NOT NULL,
|
||||||
|
ed REAL NOT NULL,
|
||||||
|
rate REAL NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
FOREIGN KEY(ic_default) REFERENCES initial_conditions_adists(id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 6:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, ic_default, name, reach, start_kp, end_kp, " +
|
||||||
|
"concentration, eg, em, ed, rate, enabled " +
|
||||||
|
"FROM initial_conditions_spec " +
|
||||||
|
f"WHERE ic_default = {data['ic_default_id']} "
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in table:
|
||||||
|
id = row[0]
|
||||||
|
name = row[2]
|
||||||
|
reach = row[3]
|
||||||
|
start_kp = row[4]
|
||||||
|
end_kp = row[5]
|
||||||
|
concentration = row[6]
|
||||||
|
eg = row[7]
|
||||||
|
em = row[8]
|
||||||
|
ed = row[9]
|
||||||
|
rate = row[10]
|
||||||
|
enabled = (row[11] == 1)
|
||||||
|
|
||||||
|
#new_spec = [name, reach, start_kp, end_kp, concentration, eg, em, ed, rate, enabled]
|
||||||
|
|
||||||
|
new_spec = cls(
|
||||||
|
id=id,
|
||||||
|
name=name,
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
new_spec.reach = reach
|
||||||
|
new_spec.start_kp = start_kp
|
||||||
|
new_spec.end_kp = end_kp
|
||||||
|
new_spec.concentration = concentration
|
||||||
|
new_spec.eg = eg
|
||||||
|
new_spec.em = em
|
||||||
|
new_spec.ed = ed
|
||||||
|
new_spec.rate = rate
|
||||||
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
new.append(new_spec)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
ic_default = data['ic_default_id']
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"initial_conditions_spec(id, ic_default, name, reach, " +
|
||||||
|
"start_kp, end_kp, concentration, eg, em, ed, rate, enabled) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, " +
|
||||||
|
f"{ic_default}, " +
|
||||||
|
f"'{self._db_format(self._name_section)}', " +
|
||||||
|
f"{self._reach}, " +
|
||||||
|
f"{self._start_kp}, " +
|
||||||
|
f"{self._end_kp}, " +
|
||||||
|
f"{self._concentration}, " +
|
||||||
|
f"{self._eg}, " +
|
||||||
|
f"{self._em}, " +
|
||||||
|
f"{self._ed}, " +
|
||||||
|
f"{self._rate}, " +
|
||||||
|
f"{self._enabled}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name_section
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name_section = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reach(self):
|
||||||
|
return self._reach
|
||||||
|
|
||||||
|
@reach.setter
|
||||||
|
def reach(self, reach):
|
||||||
|
self._reach = reach
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start_kp(self):
|
||||||
|
return self._start_kp
|
||||||
|
|
||||||
|
@start_kp.setter
|
||||||
|
def start_kp(self, start_kp):
|
||||||
|
self._start_kp = start_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_kp(self):
|
||||||
|
return self._end_kp
|
||||||
|
|
||||||
|
@end_kp.setter
|
||||||
|
def end_kp(self, end_kp):
|
||||||
|
self._end_kp = end_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def concentration(self):
|
||||||
|
return self._concentration
|
||||||
|
|
||||||
|
@concentration.setter
|
||||||
|
def concentration(self, concentration):
|
||||||
|
self._concentration = concentration
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def eg(self):
|
||||||
|
return self._eg
|
||||||
|
|
||||||
|
@eg.setter
|
||||||
|
def eg(self, eg):
|
||||||
|
self._eg = eg
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def em(self):
|
||||||
|
return self._em
|
||||||
|
|
||||||
|
@em.setter
|
||||||
|
def em(self, em):
|
||||||
|
self._em = em
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ed(self):
|
||||||
|
return self._ed
|
||||||
|
|
||||||
|
@ed.setter
|
||||||
|
def ed(self, ed):
|
||||||
|
self._ed = ed
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rate(self):
|
||||||
|
return self._rate
|
||||||
|
|
||||||
|
@rate.setter
|
||||||
|
def rate(self, rate):
|
||||||
|
self._rate = rate
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
# LateralContributionAdisTS.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 (
|
||||||
|
trace, timer,
|
||||||
|
old_pamhyr_date_to_timestamp,
|
||||||
|
date_iso_to_timestamp,
|
||||||
|
date_dmy_to_timestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class LateralContributionAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, pollutant: int = -1, name: str = "", status=None):
|
||||||
|
super(LateralContributionAdisTS, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = LateralContributionAdisTS._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._pollutant = pollutant
|
||||||
|
self._edge = None
|
||||||
|
self._begin_kp = 0.0
|
||||||
|
self._end_kp = 0.0
|
||||||
|
self._data = []
|
||||||
|
self._header = ["time", "rate"]
|
||||||
|
self._types = [self.time_convert, float]
|
||||||
|
|
||||||
|
LateralContributionAdisTS._id_cnt = max(
|
||||||
|
LateralContributionAdisTS._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE lateral_contribution_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
pollutant INTEGER NOT NULL,
|
||||||
|
edge INTEGER NOT NULL,
|
||||||
|
begin_kp REAL NOT NULL,
|
||||||
|
end_kp REAL NOT NULL,
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(id),
|
||||||
|
FOREIGN KEY(edge) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE lateral_contribution_data_adists(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
data0 TEXT NOT NULL,
|
||||||
|
data1 TEXT NOT NULL,
|
||||||
|
lc INTEGER,
|
||||||
|
FOREIGN KEY(lc) REFERENCES lateral_contribution(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, pollutant, edge, begin_kp, end_kp " +
|
||||||
|
"FROM lateral_contribution_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
lc = cls(
|
||||||
|
id=row[0],
|
||||||
|
pollutant=row[1],
|
||||||
|
status=data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
lc.edge = row[2]
|
||||||
|
lc.begin_kp = row[3]
|
||||||
|
lc.end_kp = row[4]
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT data0, data1 FROM lateral_contribution_data_adists " +
|
||||||
|
f"WHERE lc = '{lc.id}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write data
|
||||||
|
for v in values:
|
||||||
|
data0 = lc._types[0](v[0])
|
||||||
|
data1 = lc._types[1](v[1])
|
||||||
|
# Replace data at pos ind
|
||||||
|
lc._data.append((data0, data1))
|
||||||
|
|
||||||
|
new.append(lc)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
|
||||||
|
execute(f"DELETE FROM lateral_contribution_adists WHERE id = {self.id}")
|
||||||
|
execute(f"DELETE FROM lateral_contribution_data_adists WHERE lc = {self.id}")
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"lateral_contribution_adists(id, pollutant, edge, begin_kp, end_kp) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._pollutant}, {self.edge}, " +
|
||||||
|
f"{self._begin_kp}, {self._end_kp}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
data0 = self._db_format(str(d[0]))
|
||||||
|
data1 = self._db_format(str(d[1]))
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"lateral_contribution_data_adists(data0, data1, lc) " +
|
||||||
|
f"VALUES ('{data0}', {data1}, {self.id})"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def time_convert(cls, data):
|
||||||
|
if type(data) is str:
|
||||||
|
if data.count("-") == 2:
|
||||||
|
return date_iso_to_timestamp(data)
|
||||||
|
if data.count("/") == 2:
|
||||||
|
return date_dmy_to_timestamp(data)
|
||||||
|
if data.count(":") == 3:
|
||||||
|
return old_pamhyr_date_to_timestamp(data)
|
||||||
|
if data.count(":") == 2:
|
||||||
|
return old_pamhyr_date_to_timestamp("00:" + data)
|
||||||
|
if data.count(".") == 1:
|
||||||
|
return round(float(data))
|
||||||
|
|
||||||
|
return int(data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def edge(self):
|
||||||
|
return self._edge
|
||||||
|
|
||||||
|
@edge.setter
|
||||||
|
def edge(self, edge):
|
||||||
|
self._edge = edge
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def header(self):
|
||||||
|
return self._header.copy()
|
||||||
|
|
||||||
|
@header.setter
|
||||||
|
def header(self, header):
|
||||||
|
self._header = header
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pollutant(self):
|
||||||
|
return self._pollutant
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data.copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def begin_kp(self):
|
||||||
|
return self._begin_kp
|
||||||
|
|
||||||
|
@begin_kp.setter
|
||||||
|
def begin_kp(self, begin_kp):
|
||||||
|
self._begin_kp = begin_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_kp(self):
|
||||||
|
return self._end_kp
|
||||||
|
|
||||||
|
@end_kp.setter
|
||||||
|
def end_kp(self, end_kp):
|
||||||
|
self._end_kp = end_kp
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# LateralContributionsAdisTSList.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 copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
from Model.LateralContributionsAdisTS.LateralContributionAdisTS import LateralContributionAdisTS
|
||||||
|
|
||||||
|
class LateralContributionsAdisTSList(PamhyrModelList):
|
||||||
|
_sub_classes = [
|
||||||
|
LateralContributionAdisTS,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
new._lst = LateralContributionAdisTS._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
execute("DELETE FROM lateral_contribution_adists")
|
||||||
|
execute("DELETE FROM lateral_condition_data_adists")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for lc in self._lst:
|
||||||
|
lc._db_save(execute, data=data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def new(self, index, pollutant):
|
||||||
|
n = LateralContributionAdisTS(pollutant=pollutant, status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Lat_Cont_List(self):
|
||||||
|
return self.lst
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
# OutputKpAdists.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 (
|
||||||
|
trace, timer,
|
||||||
|
old_pamhyr_date_to_timestamp,
|
||||||
|
date_iso_to_timestamp,
|
||||||
|
date_dmy_to_timestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class OutputKpAdists(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, reach = None, kp = None, title: str = "", status=None):
|
||||||
|
super(OutputKpAdists, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = OutputKpAdists._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._reach = reach
|
||||||
|
self._kp = kp
|
||||||
|
self._title = str(title)
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
|
OutputKpAdists._id_cnt = max(
|
||||||
|
OutputKpAdists._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reach(self):
|
||||||
|
return self._reach
|
||||||
|
|
||||||
|
@reach.setter
|
||||||
|
def reach(self, reach_id):
|
||||||
|
self._reach = reach_id
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kp(self):
|
||||||
|
return self._kp
|
||||||
|
|
||||||
|
@kp.setter
|
||||||
|
def kp(self, profile_id):
|
||||||
|
self._kp = profile_id
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def title(self):
|
||||||
|
return self._title
|
||||||
|
|
||||||
|
@title.setter
|
||||||
|
def title(self, title):
|
||||||
|
self._title = title
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"CREATE TABLE OutputKpAdists(" +
|
||||||
|
"id INTEGER NOT NULL PRIMARY KEY, " +
|
||||||
|
"reach INTEGER NOT NULL, " +
|
||||||
|
"kp REAL NOT NULL, " +
|
||||||
|
"title TEXT NOT NULL, " +
|
||||||
|
"FOREIGN KEY(reach) REFERENCES river_reach(id)" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
#reach = data["reach"]
|
||||||
|
#profile = data["profile"]
|
||||||
|
status = data["status"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, reach, kp, title " +
|
||||||
|
f"FROM OutputKpAdists"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
id = row[0]
|
||||||
|
id_reach = row[1]
|
||||||
|
id_kp = row[2]
|
||||||
|
title = row[3]
|
||||||
|
|
||||||
|
new_output = cls(
|
||||||
|
id=id, reach=id_reach,
|
||||||
|
kp=id_kp, title=title,
|
||||||
|
status=status
|
||||||
|
)
|
||||||
|
|
||||||
|
new.append(new_output)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
|
||||||
|
execute(f"DELETE FROM OutputKpAdists WHERE id = {self.id}")
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"OutputKpAdists(id, reach, kp, title) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._reach}, {self._kp}, " +
|
||||||
|
f"'{self._db_format(self._title)}'" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# OutputKpListAdists.py -- Pamhyr
|
||||||
|
# Copyright (C) 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 trace, timer
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.OutputKpAdists.OutputKpAdists import OutputKpAdists
|
||||||
|
|
||||||
|
|
||||||
|
class OutputKpAdistsList(PamhyrModelList):
|
||||||
|
_sub_classes = [OutputKpAdists]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
|
new._lst = OutputKpAdists._db_load(execute, data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
# Delete previous data
|
||||||
|
execute("DELETE FROM OutputKpAdists")
|
||||||
|
|
||||||
|
for sl in self._lst:
|
||||||
|
ok &= sl._db_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
@property
|
||||||
|
def OutputKp_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
def new(self, lst, index):
|
||||||
|
n = OutputKpAdists(status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
# Pollutants.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 (
|
||||||
|
trace, timer,
|
||||||
|
old_pamhyr_date_to_timestamp,
|
||||||
|
date_iso_to_timestamp,
|
||||||
|
date_dmy_to_timestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class Pollutants(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
|
super(Pollutants, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = Pollutants._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
self._name = str(name)
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
|
self._data = []
|
||||||
|
|
||||||
|
Pollutants._id_cnt = max(
|
||||||
|
Pollutants._id_cnt + 1, self.id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data.copy()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE Pollutants(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE Pollutants_characteristics(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
type INTEGER NOT NULL,
|
||||||
|
diametre REAL NOT NULL,
|
||||||
|
rho REAL NOT NULL,
|
||||||
|
porosity REAL NOT NULL,
|
||||||
|
cdc_riv REAL NOT NULL,
|
||||||
|
cdc_cas REAL NOT NULL,
|
||||||
|
apd REAL NOT NULL,
|
||||||
|
ac REAL NOT NULL,
|
||||||
|
bc REAL NOT NULL,
|
||||||
|
pollutant INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
status = data["status"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, name " +
|
||||||
|
f"FROM Pollutants"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
id = row[0]
|
||||||
|
name = row[1]
|
||||||
|
|
||||||
|
new_pollutant = cls(
|
||||||
|
id=id, name=name,
|
||||||
|
status=status
|
||||||
|
)
|
||||||
|
|
||||||
|
new_data = []
|
||||||
|
table = execute(
|
||||||
|
"SELECT * " +
|
||||||
|
"FROM Pollutants_characteristics " +
|
||||||
|
f"WHERE pollutant = {id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for t in table:
|
||||||
|
new_data = t[1:]
|
||||||
|
|
||||||
|
new_pollutant._data.append(new_data)
|
||||||
|
|
||||||
|
new.append(new_pollutant)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
|
||||||
|
execute(f"DELETE FROM Pollutants WHERE id = {self.id}")
|
||||||
|
execute(f"DELETE FROM Pollutants_characteristics WHERE pollutant = {self.id}")
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"Pollutants(id, name) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, " +
|
||||||
|
f"'{self._db_format(self._name)}'" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"Pollutants_characteristics(type, diametre, rho, porosity, " +
|
||||||
|
"cdc_riv, cdc_cas, apd, ac, bc, pollutant) " +
|
||||||
|
f"VALUES ({d[0]}, {d[1]}, {d[2]},{d[3]}, {d[4]}, "
|
||||||
|
f"{d[5]}, {d[6]}, {d[7]}, {d[8]}, {self.id})"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def is_define(self):
|
||||||
|
return len(self._data) != 0
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# PollutantsList.py -- Pamhyr
|
||||||
|
# Copyright (C) 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 trace, timer
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
from Model.Pollutants.Pollutants import Pollutants
|
||||||
|
|
||||||
|
|
||||||
|
class PollutantsList(PamhyrModelList):
|
||||||
|
_sub_classes = [Pollutants]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
|
new._lst = Pollutants._db_load(execute, data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
# Delete previous data
|
||||||
|
execute("DELETE FROM Pollutants")
|
||||||
|
|
||||||
|
for sl in self._lst:
|
||||||
|
ok &= sl._db_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Pollutants_List(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
def new(self, lst, index):
|
||||||
|
n = Pollutants(status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# Results.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/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import numpy as np
|
||||||
|
import os, glob
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from Model.Results.River.RiverAdisTS import River
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class Results(object):
|
||||||
|
def __init__(self, study=None, solver=None,
|
||||||
|
repertory="", name="0"):
|
||||||
|
self._study = study
|
||||||
|
self._solver = solver
|
||||||
|
self._repertory = repertory
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
self._river = River(self._study)
|
||||||
|
|
||||||
|
self._meta_data = {
|
||||||
|
# Keep results creation date
|
||||||
|
"creation_date": datetime.now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
repertory_results = os.path.join(repertory, "resultats")
|
||||||
|
self._pollutants_list = [el.split("/")[-1][0:-4] for el in glob.glob(repertory_results + "/*.bin")]
|
||||||
|
|
||||||
|
self._phys_var_list = ["C", "G", "M", "D", "L", "N", "R"]
|
||||||
|
|
||||||
|
print("*********files names resultats from Results Object: ", self._pollutants_list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def date(self):
|
||||||
|
date = self._meta_data["creation_date"]
|
||||||
|
return f"{date.isoformat(sep=' ')}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def river(self):
|
||||||
|
return self._river
|
||||||
|
|
||||||
|
@property
|
||||||
|
def study(self):
|
||||||
|
return self._study
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pollutants_list(self):
|
||||||
|
return self._pollutants_list
|
||||||
|
|
||||||
|
@property
|
||||||
|
def phys_var_list(self):
|
||||||
|
return self._phys_var_list
|
||||||
|
|
||||||
|
def set(self, key, value):
|
||||||
|
self._meta_data[key] = value
|
||||||
|
|
||||||
|
def get(self, key):
|
||||||
|
return self._meta_data[key]
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
return self._solver.results(
|
||||||
|
self._study,
|
||||||
|
self._repertory,
|
||||||
|
qlog=None,
|
||||||
|
)
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
# River.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/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class Profile(object):
|
||||||
|
def __init__(self, profile, study):
|
||||||
|
self._study = study
|
||||||
|
self._profile = profile # Source profile in the study
|
||||||
|
self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...}
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._profile.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kp(self):
|
||||||
|
return self._profile.kp
|
||||||
|
|
||||||
|
@property
|
||||||
|
def geometry(self):
|
||||||
|
return self._profile
|
||||||
|
|
||||||
|
def set(self, timestamp, key, data):
|
||||||
|
if timestamp not in self._data:
|
||||||
|
self._data[timestamp] = {}
|
||||||
|
|
||||||
|
self._data[timestamp][key] = data
|
||||||
|
|
||||||
|
def get_ts(self, timestamp):
|
||||||
|
return self._data[timestamp]
|
||||||
|
|
||||||
|
def get_key(self, key):
|
||||||
|
return list(
|
||||||
|
map(lambda ts: self._data[ts][key], self._data)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_ts_key(self, timestamp, key):
|
||||||
|
return self._data[timestamp][key]
|
||||||
|
|
||||||
|
def has_sediment(self):
|
||||||
|
return any(map(lambda ts: "sl" in self._data[ts], self._data))
|
||||||
|
|
||||||
|
|
||||||
|
class Reach(object):
|
||||||
|
def __init__(self, reach, study):
|
||||||
|
self._study = study
|
||||||
|
self._reach = reach # Source reach in the study
|
||||||
|
self._profiles = list(
|
||||||
|
map(
|
||||||
|
lambda p: Profile(p, self._study),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._profiles)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._reach.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def geometry(self):
|
||||||
|
return self._reach
|
||||||
|
|
||||||
|
@property
|
||||||
|
def profiles(self):
|
||||||
|
return self._profiles.copy()
|
||||||
|
|
||||||
|
def profile(self, id):
|
||||||
|
return self._profiles[id]
|
||||||
|
|
||||||
|
def set(self, profile_id, timestamp, key, data):
|
||||||
|
self._profiles[profile_id].set(timestamp, key, data)
|
||||||
|
|
||||||
|
def has_sediment(self):
|
||||||
|
return any(map(lambda profile: profile.has_sediment(), self._profiles))
|
||||||
|
|
||||||
|
|
||||||
|
class River(object):
|
||||||
|
def __init__(self, study):
|
||||||
|
self._study = study
|
||||||
|
|
||||||
|
# Dict with timestamps as key
|
||||||
|
self._reachs = []
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._reachs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reachs(self):
|
||||||
|
return self._reachs.copy()
|
||||||
|
|
||||||
|
def reach(self, id):
|
||||||
|
return self._reachs[id]
|
||||||
|
|
||||||
|
def has_reach(self, id):
|
||||||
|
return 0 <= id < len(self._reachs)
|
||||||
|
|
||||||
|
def add(self, reach_id):
|
||||||
|
reachs = self._study.river.enable_edges()
|
||||||
|
|
||||||
|
new = Reach(reachs[reach_id].reach, self._study)
|
||||||
|
|
||||||
|
self._reachs.append(new)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def get_reach_by_geometry(self, geometry_reach):
|
||||||
|
return next(
|
||||||
|
filter(
|
||||||
|
lambda r: r.geometry is geometry_reach,
|
||||||
|
self._reachs
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -45,6 +45,14 @@ from Model.REPLine.REPLineList import REPLineList
|
|||||||
|
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
|
|
||||||
|
from Model.OutputKpAdists.OutputKpListAdists import OutputKpAdistsList
|
||||||
|
from Model.Pollutants.PollutantsList import PollutantsList
|
||||||
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList import InitialConditionsAdisTSList
|
||||||
|
from Model.BoundaryConditionsAdisTS.BoundaryConditionsAdisTSList import BoundaryConditionsAdisTSList
|
||||||
|
from Model.LateralContributionsAdisTS.LateralContributionsAdisTSList import LateralContributionsAdisTSList
|
||||||
|
from Model.D90AdisTS.D90AdisTSList import D90AdisTSList
|
||||||
|
from Model.DIFAdisTS.DIFAdisTSList import DIFAdisTSList
|
||||||
|
|
||||||
|
|
||||||
class RiverNode(Node, SQLSubModel):
|
class RiverNode(Node, SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
@@ -228,6 +236,13 @@ class River(Graph, SQLSubModel):
|
|||||||
HydraulicStructureList,
|
HydraulicStructureList,
|
||||||
AddFileList,
|
AddFileList,
|
||||||
REPLineList,
|
REPLineList,
|
||||||
|
OutputKpAdistsList,
|
||||||
|
PollutantsList,
|
||||||
|
InitialConditionsAdisTSList,
|
||||||
|
BoundaryConditionsAdisTSList,
|
||||||
|
LateralContributionsAdisTSList,
|
||||||
|
D90AdisTSList,
|
||||||
|
DIFAdisTSList,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status=None):
|
def __init__(self, status=None):
|
||||||
@@ -251,6 +266,13 @@ class River(Graph, SQLSubModel):
|
|||||||
)
|
)
|
||||||
self._additional_files = AddFileList(status=self._status)
|
self._additional_files = AddFileList(status=self._status)
|
||||||
self._rep_lines = REPLineList(status=self._status)
|
self._rep_lines = REPLineList(status=self._status)
|
||||||
|
self._Output_kp_adists = OutputKpAdistsList(status=self._status)
|
||||||
|
self._Pollutants = PollutantsList(status=self._status)
|
||||||
|
self._InitialConditionsAdisTS = InitialConditionsAdisTSList(status=self._status)
|
||||||
|
self._BoundaryConditionsAdisTS = BoundaryConditionsAdisTSList(status=self._status)
|
||||||
|
self._LateralContributionsAdisTS = LateralContributionsAdisTSList(status=self._status)
|
||||||
|
self._D90AdisTS = D90AdisTSList(status=self._status)
|
||||||
|
self._DIFAdisTS = DIFAdisTSList(status=self._status)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute):
|
||||||
@@ -325,6 +347,22 @@ class River(Graph, SQLSubModel):
|
|||||||
)
|
)
|
||||||
new._rep_lines = REPLineList._db_load(execute, data)
|
new._rep_lines = REPLineList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._Output_kp_adists = OutputKpAdistsList._db_load(
|
||||||
|
execute, data
|
||||||
|
)
|
||||||
|
|
||||||
|
new._Pollutants = PollutantsList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._InitialConditionsAdisTS = InitialConditionsAdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._BoundaryConditionsAdisTS = BoundaryConditionsAdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._LateralContributionsAdisTS = LateralContributionsAdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._D90AdisTS = D90AdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._DIFAdisTS = DIFAdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
@@ -344,6 +382,14 @@ class River(Graph, SQLSubModel):
|
|||||||
for solver in self._parameters:
|
for solver in self._parameters:
|
||||||
objs.append(self._parameters[solver])
|
objs.append(self._parameters[solver])
|
||||||
|
|
||||||
|
objs.append(self._Output_kp_adists)
|
||||||
|
objs.append(self._Pollutants)
|
||||||
|
objs.append(self._InitialConditionsAdisTS)
|
||||||
|
objs.append(self._BoundaryConditionsAdisTS)
|
||||||
|
objs.append(self._LateralContributionsAdisTS)
|
||||||
|
objs.append(self._D90AdisTS)
|
||||||
|
objs.append(self._DIFAdisTS)
|
||||||
|
|
||||||
self._save_submodel(execute, objs, data)
|
self._save_submodel(execute, objs, data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -466,6 +512,34 @@ Last export at: @date."""
|
|||||||
def parameters(self):
|
def parameters(self):
|
||||||
return self._parameters
|
return self._parameters
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Output_kp_adists(self):
|
||||||
|
return self._Output_kp_adists
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Pollutants(self):
|
||||||
|
return self._Pollutants
|
||||||
|
|
||||||
|
@property
|
||||||
|
def initial_conditions_adists(self):
|
||||||
|
return self._InitialConditionsAdisTS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def boundary_conditions_adists(self):
|
||||||
|
return self._BoundaryConditionsAdisTS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lateral_contributions_adists(self):
|
||||||
|
return self._LateralContributionsAdisTS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def d90_adists(self):
|
||||||
|
return self._D90AdisTS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dif_adists(self):
|
||||||
|
return self._DIFAdisTS
|
||||||
|
|
||||||
def get_params(self, solver):
|
def get_params(self, solver):
|
||||||
if solver in self._parameters:
|
if solver in self._parameters:
|
||||||
return self._parameters[solver]
|
return self._parameters[solver]
|
||||||
|
|||||||
+2
-17
@@ -22,19 +22,10 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
|
|
||||||
class SavedStatus(object):
|
class SavedStatus(object):
|
||||||
def __init__(self, version=0):
|
def __init__(self):
|
||||||
super(SavedStatus, self).__init__()
|
super(SavedStatus, self).__init__()
|
||||||
self._version = version
|
|
||||||
self._saved = True
|
self._saved = True
|
||||||
|
|
||||||
@property
|
|
||||||
def version(self):
|
|
||||||
return self._version
|
|
||||||
|
|
||||||
@version.setter
|
|
||||||
def version(self, version):
|
|
||||||
self._version = version
|
|
||||||
|
|
||||||
def is_saved(self):
|
def is_saved(self):
|
||||||
return self._saved
|
return self._saved
|
||||||
|
|
||||||
@@ -43,11 +34,5 @@ class SavedStatus(object):
|
|||||||
self._saved = True
|
self._saved = True
|
||||||
|
|
||||||
def modified(self):
|
def modified(self):
|
||||||
if self._saved:
|
# logger.debug("model status set as modified")
|
||||||
self._version += 1
|
|
||||||
|
|
||||||
logger.debug(
|
|
||||||
"STATUS: Model status set as modified " +
|
|
||||||
f"at version {self._version}"
|
|
||||||
)
|
|
||||||
self._saved = False
|
self._saved = False
|
||||||
+10
-35
@@ -41,7 +41,7 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
def __init__(self, filename=None, init_new=True):
|
def __init__(self, filename=None, init_new=True):
|
||||||
# Metadata
|
# Metadata
|
||||||
self._version = "0.0.10"
|
self._version = "0.0.9"
|
||||||
self.creation_date = datetime.now()
|
self.creation_date = datetime.now()
|
||||||
self.last_modification_date = datetime.now()
|
self.last_modification_date = datetime.now()
|
||||||
self.last_save_date = datetime.now()
|
self.last_save_date = datetime.now()
|
||||||
@@ -72,7 +72,7 @@ class Study(SQLModel):
|
|||||||
StudyNetworkReachChecker(),
|
StudyNetworkReachChecker(),
|
||||||
StudyGeometryChecker(),
|
StudyGeometryChecker(),
|
||||||
StudyInitialConditionsChecker(),
|
StudyInitialConditionsChecker(),
|
||||||
StudyBoundaryConditionChecker(),
|
#StudyBoundaryConditionChecker(),
|
||||||
# DummyOK(),
|
# DummyOK(),
|
||||||
# DummyWARNING(),
|
# DummyWARNING(),
|
||||||
# DummyERROR(),
|
# DummyERROR(),
|
||||||
@@ -117,9 +117,6 @@ class Study(SQLModel):
|
|||||||
if ".backup" in self.filename:
|
if ".backup" in self.filename:
|
||||||
is_new = True
|
is_new = True
|
||||||
|
|
||||||
if not os.path.exists(self.filename):
|
|
||||||
is_new = True
|
|
||||||
|
|
||||||
self._init_db_file(self.filename, is_new=is_new)
|
self._init_db_file(self.filename, is_new=is_new)
|
||||||
self.commit()
|
self.commit()
|
||||||
|
|
||||||
@@ -212,12 +209,7 @@ class Study(SQLModel):
|
|||||||
def _create(self):
|
def _create(self):
|
||||||
# Info (metadata)
|
# Info (metadata)
|
||||||
self.execute(
|
self.execute(
|
||||||
"INSERT INTO info VALUES ('study_release', '0')"
|
"CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
|
||||||
)
|
|
||||||
|
|
||||||
self.execute(
|
|
||||||
"CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)"
|
|
||||||
)
|
|
||||||
self.execute(
|
self.execute(
|
||||||
"INSERT INTO info VALUES ('version', " +
|
"INSERT INTO info VALUES ('version', " +
|
||||||
f"'{self._db_format(self._version)}')",
|
f"'{self._db_format(self._version)}')",
|
||||||
@@ -226,20 +218,19 @@ class Study(SQLModel):
|
|||||||
self.execute("INSERT INTO info VALUES ('name', '')")
|
self.execute("INSERT INTO info VALUES ('name', '')")
|
||||||
self.execute("INSERT INTO info VALUES ('description', '')")
|
self.execute("INSERT INTO info VALUES ('description', '')")
|
||||||
self.execute(
|
self.execute(
|
||||||
f"INSERT INTO info VALUES ('time_system', '{self._time_system}')"
|
f"INSERT INTO info VALUES ('time_system', '{self._time_system}')")
|
||||||
)
|
|
||||||
self.execute(
|
self.execute(
|
||||||
"INSERT INTO info VALUES ('date', " +
|
f"INSERT INTO info VALUES ('date', " +
|
||||||
f"'{self._date.timestamp()}')"
|
"'{self._date.timestamp()}')"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.execute(
|
self.execute(
|
||||||
"INSERT INTO info VALUES ('creation_date', " +
|
f"INSERT INTO info VALUES ('creation_date', " +
|
||||||
f"'{self.creation_date.timestamp()}')"
|
"'{self.creation_time.timestamp()}')"
|
||||||
)
|
)
|
||||||
self.execute(
|
self.execute(
|
||||||
"INSERT INTO info VALUES ('last_save_date', " +
|
f"INSERT INTO info VALUES ('last_save_date', " +
|
||||||
f"'{self.last_save_date.timestamp()}')"
|
"'{self.last_save_time.timestamp()}')"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._create_submodel()
|
self._create_submodel()
|
||||||
@@ -254,12 +245,6 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
logger.debug("Update database")
|
logger.debug("Update database")
|
||||||
|
|
||||||
major, minor, release = version[0].split('.')
|
|
||||||
if major == "0" and minor == "0" and int(release) < 10:
|
|
||||||
self.execute(
|
|
||||||
"INSERT INTO info VALUES ('study_release', '0')"
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._update_submodel(version[0]):
|
if self._update_submodel(version[0]):
|
||||||
self.execute(
|
self.execute(
|
||||||
f"UPDATE info SET value='{self._version}' WHERE key='version'"
|
f"UPDATE info SET value='{self._version}' WHERE key='version'"
|
||||||
@@ -273,11 +258,6 @@ class Study(SQLModel):
|
|||||||
def _load(cls, filename):
|
def _load(cls, filename):
|
||||||
new = cls(init_new=False, filename=filename)
|
new = cls(init_new=False, filename=filename)
|
||||||
|
|
||||||
version = new.execute(
|
|
||||||
"SELECT value FROM info WHERE key='study_release'"
|
|
||||||
)
|
|
||||||
new.status.version = int(version[0])
|
|
||||||
|
|
||||||
# TODO: Load metadata
|
# TODO: Load metadata
|
||||||
new.name = new.execute("SELECT value FROM info WHERE key='name'")[0]
|
new.name = new.execute("SELECT value FROM info WHERE key='name'")[0]
|
||||||
new.description = new.execute(
|
new.description = new.execute(
|
||||||
@@ -312,11 +292,6 @@ class Study(SQLModel):
|
|||||||
def _save(self, progress=None):
|
def _save(self, progress=None):
|
||||||
progress = progress if progress is not None else lambda: None
|
progress = progress if progress is not None else lambda: None
|
||||||
|
|
||||||
self.execute(
|
|
||||||
"INSERT INTO info VALUES ('study_release', " +
|
|
||||||
f"'{self.status.version}')"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.execute(
|
self.execute(
|
||||||
f"UPDATE info SET " +
|
f"UPDATE info SET " +
|
||||||
f"value='{self._db_format(self.name)}' WHERE key='name'"
|
f"value='{self._db_format(self.name)}' WHERE key='name'"
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class Modules(IterableFlag):
|
|||||||
RESERVOIR = auto()
|
RESERVOIR = auto()
|
||||||
SEDIMENT_LAYER = auto()
|
SEDIMENT_LAYER = auto()
|
||||||
ADDITIONAL_FILES = auto()
|
ADDITIONAL_FILES = auto()
|
||||||
|
OUTPUT_KP = auto()
|
||||||
|
|
||||||
# Results
|
# Results
|
||||||
RESULTS = auto()
|
RESULTS = auto()
|
||||||
@@ -77,6 +78,7 @@ class Modules(IterableFlag):
|
|||||||
cls.ADDITIONAL_FILES,
|
cls.ADDITIONAL_FILES,
|
||||||
cls.RESULTS,
|
cls.RESULTS,
|
||||||
cls.WINDOW_LIST,
|
cls.WINDOW_LIST,
|
||||||
|
cls.OUTPUT_KP,
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -0,0 +1,731 @@
|
|||||||
|
# AdisTS.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, glob
|
||||||
|
import logging
|
||||||
|
from http.cookiejar import reach
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from tools import (
|
||||||
|
trace, timer, logger_exception,
|
||||||
|
timestamp_to_old_pamhyr_date,
|
||||||
|
old_pamhyr_date_to_timestamp,
|
||||||
|
timestamp_to_old_pamhyr_date_adists
|
||||||
|
)
|
||||||
|
|
||||||
|
from Solver.CommandLine import CommandLineSolver
|
||||||
|
|
||||||
|
from Model.Results.ResultsAdisTS import Results
|
||||||
|
from Model.Results.River.River import River, Reach, Profile
|
||||||
|
|
||||||
|
from Checker.Adists import (
|
||||||
|
AdistsOutputKpChecker,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
def adists_file_open(filepath, mode):
|
||||||
|
f = open(filepath, mode)
|
||||||
|
|
||||||
|
if "w" in mode:
|
||||||
|
# Write header
|
||||||
|
comment = "*"
|
||||||
|
if ".ST" in filepath:
|
||||||
|
comment = "#"
|
||||||
|
|
||||||
|
f.write(
|
||||||
|
f"{comment} " +
|
||||||
|
"This file is generated by PAMHYR, please don't modify\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
return f
|
||||||
|
|
||||||
|
class AdisTS(CommandLineSolver):
|
||||||
|
_type = "adists"
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super(AdisTS, self).__init__(name)
|
||||||
|
|
||||||
|
self._type = "adists"
|
||||||
|
|
||||||
|
self._cmd_input = ""
|
||||||
|
self._cmd_solver = "@path @input -o @output"
|
||||||
|
self._cmd_output = ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_parameters(cls):
|
||||||
|
lst = super(AdisTS, cls).default_parameters()
|
||||||
|
|
||||||
|
lst += [
|
||||||
|
("adists_implicitation_parameter", "0.5"),
|
||||||
|
("adists_timestep_screen", "60"),
|
||||||
|
("adists_timestep_bin", "60"),
|
||||||
|
("adists_timestep_csv", "60"),
|
||||||
|
("adists_timestep_mage", "60"),
|
||||||
|
("adists_initial_concentration", "60"),
|
||||||
|
]
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def checkers(cls):
|
||||||
|
lst = [
|
||||||
|
AdistsOutputKpChecker(),
|
||||||
|
]
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def cmd_args(self, study):
|
||||||
|
lst = super(AdisTS, self).cmd_args(study)
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def input_param(self):
|
||||||
|
name = self._study.name
|
||||||
|
return f"{name}.REP"
|
||||||
|
|
||||||
|
def log_file(self):
|
||||||
|
name = self._study.name
|
||||||
|
return f"{name}.TRA"
|
||||||
|
|
||||||
|
def _export_REP_additional_lines(self, study, rep_file):
|
||||||
|
lines = filter(
|
||||||
|
lambda line: line.is_enabled(),
|
||||||
|
study.river.rep_lines.lines
|
||||||
|
)
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
rep_file.write(line.line)
|
||||||
|
|
||||||
|
def _export_REP(self, study, repertory, mage_rep, files, qlog, name="0"):
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export REP file")
|
||||||
|
|
||||||
|
# Write header
|
||||||
|
with adists_file_open(
|
||||||
|
os.path.join(
|
||||||
|
repertory, f"{name}.REP"
|
||||||
|
), "w+"
|
||||||
|
) as f:
|
||||||
|
|
||||||
|
f.write(f"NET ../{mage_rep}/{name}.NET\n")
|
||||||
|
f.write(f"REP ../{mage_rep}/{name}.REP\n")
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
EXT = file.split('.')[1]
|
||||||
|
f.write(f"{EXT} {file}\n")
|
||||||
|
|
||||||
|
self._export_REP_additional_lines(study, f)
|
||||||
|
|
||||||
|
path_mage_net = os.path.join(os.path.abspath(os.path.join(repertory, os.pardir)), f"{mage_rep}/net")
|
||||||
|
path_adists_net = os.path.join(repertory, "net")
|
||||||
|
|
||||||
|
if os.path.exists(path_mage_net):
|
||||||
|
shutil.copytree(path_mage_net, path_adists_net, dirs_exist_ok=True)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def export(self, study, repertory, qlog=None):
|
||||||
|
self._study = study
|
||||||
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
|
self.export_additional_files(study, repertory, qlog, name=name)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
###########
|
||||||
|
# RESULTS #
|
||||||
|
###########
|
||||||
|
|
||||||
|
def read_bin(self, study, repertory, results, qlog=None, name="0"):
|
||||||
|
return
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def results(self, study, repertory, qlog=None, name="0"):
|
||||||
|
results = Results(
|
||||||
|
study=study,
|
||||||
|
solver=self,
|
||||||
|
repertory=repertory,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
self.read_bin(study, repertory, results, qlog, name=name)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def output_param(self):
|
||||||
|
name = ""
|
||||||
|
return f"{name}"
|
||||||
|
|
||||||
|
################################
|
||||||
|
# Adis-TS in low coupling mode #
|
||||||
|
################################
|
||||||
|
|
||||||
|
|
||||||
|
class AdisTSlc(AdisTS):
|
||||||
|
_type = "adistslc"
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
super(AdisTSlc, self).__init__(name)
|
||||||
|
|
||||||
|
self._type = "adistslc"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_parameters(cls):
|
||||||
|
lst = super(AdisTSlc, cls).default_parameters()
|
||||||
|
|
||||||
|
# Insert new parameters at specific position
|
||||||
|
names = list(map(lambda t: t[0], lst))
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Export #
|
||||||
|
##########
|
||||||
|
|
||||||
|
def cmd_args(self, study):
|
||||||
|
lst = super(AdisTSlc, self).cmd_args(study)
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def _export_POLs(self, study, repertory, qlog=None, name="0"):
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export POLS files")
|
||||||
|
|
||||||
|
pollutants = study.river.Pollutants.Pollutants_List
|
||||||
|
|
||||||
|
for pollutant in pollutants:
|
||||||
|
name = pollutant.name
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{name}.POL"), "w+") as f:
|
||||||
|
files.append(f"{name}.POL")
|
||||||
|
f.write(f"*Polluant A contaminé aux PCB\n")
|
||||||
|
f.write(f"name = {name}\n")
|
||||||
|
|
||||||
|
self._export_POL_Characteristics(study, pollutant._data, f, qlog)
|
||||||
|
|
||||||
|
POL_ICs = next(filter(lambda ic: ic.pollutant == pollutant.id,\
|
||||||
|
study.river.initial_conditions_adists.Initial_Conditions_List))
|
||||||
|
|
||||||
|
if POL_ICs.concentration != None:
|
||||||
|
f.write(f"file_ini = {name}.INI\n")
|
||||||
|
self._export_ICs_AdisTS(study, repertory, POL_ICs, qlog, name)
|
||||||
|
|
||||||
|
POL_BCs = list(filter(lambda bc: bc.pollutant == pollutant.id,\
|
||||||
|
study.river.boundary_conditions_adists.BCs_AdisTS_List))
|
||||||
|
|
||||||
|
if len(POL_BCs) != 0:
|
||||||
|
f.write(f"file_cl = {name}.CDT\n")
|
||||||
|
self._export_BCs_AdisTS(study, repertory, POL_BCs, qlog, name)
|
||||||
|
|
||||||
|
POL_LAT_Cont = list(filter(lambda lc: lc.pollutant == pollutant.id,\
|
||||||
|
study.river.lateral_contributions_adists.Lat_Cont_List))
|
||||||
|
|
||||||
|
if len(POL_LAT_Cont) != 0:
|
||||||
|
f.write(f"file_ald = {name}.ALD\n")
|
||||||
|
f.write(f"*\n")
|
||||||
|
self._export_Lat_AdisTS(study, repertory, POL_LAT_Cont, qlog, name)
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _export_Lat_AdisTS(self, study, repertory, POL_LC, qlog, POL_name):
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export POL LCs files")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{POL_name}.ALD"), "w+") as f:
|
||||||
|
for LC in POL_LC:
|
||||||
|
reach_name = next(filter(lambda edge: edge.id == LC.edge, study.river.edges())).name
|
||||||
|
f.write(f"${reach_name} {LC.begin_kp} {LC.end_kp}\n")
|
||||||
|
f.write(f"*temps |débit massique (kg/s)\n")
|
||||||
|
f.write(f"*---------++++++++++\n")
|
||||||
|
|
||||||
|
for LC_data in LC._data:
|
||||||
|
f.write(f"{timestamp_to_old_pamhyr_date_adists(int(LC_data[0]))} {LC_data[1]}\n")
|
||||||
|
f.write(f"*\n")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _export_BCs_AdisTS(self, study, repertory, POL_BC, qlog, POL_name):
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export POL BCs files")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{POL_name}.CDT"), "w+") as f:
|
||||||
|
for BC in POL_BC:
|
||||||
|
node_name = next(filter(lambda x: x.id == BC.node, study.river._nodes)).name
|
||||||
|
f.write(f"${node_name}\n")
|
||||||
|
|
||||||
|
if BC.type == "Concentration":
|
||||||
|
f.write(f"*temps |concentration\n")
|
||||||
|
f.write(f"*JJ:HH:MM | (g/L)\n")
|
||||||
|
f.write(f"*---------++++++++++\n")
|
||||||
|
else:
|
||||||
|
f.write(f"*temps |rate\n")
|
||||||
|
f.write(f"*JJ:HH:MM | (kg/s)\n")
|
||||||
|
f.write(f"*---------++++++++++\n")
|
||||||
|
|
||||||
|
for BC_data in BC._data:
|
||||||
|
f.write(f"{timestamp_to_old_pamhyr_date_adists(int(BC_data[0]))} {BC_data[1]}\n")
|
||||||
|
f.write(f"*\n")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _export_ICs_AdisTS(self, study, repertory, POL_IC_default, qlog, POL_name):
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export POL ICs files")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{POL_name}.INI"), "w+") as f:
|
||||||
|
f.write(f"*État initial pour le polluant {POL_name}\n")
|
||||||
|
f.write(f"{POL_IC_default.name} = {POL_IC_default.concentration} {POL_IC_default.eg} "+
|
||||||
|
f"{POL_IC_default.em} {POL_IC_default.ed}\n")
|
||||||
|
|
||||||
|
if len(POL_IC_default._data) != 0:
|
||||||
|
self._export_ICs_AdisTS_Spec(study, POL_IC_default._data, f, qlog)
|
||||||
|
|
||||||
|
def _export_ICs_AdisTS_Spec(self, study, pol_ics_spec_data, f, qlog, name="0"):
|
||||||
|
|
||||||
|
for ic_spec in pol_ics_spec_data:
|
||||||
|
f.write(f"{ic_spec.name} = {ic_spec.reach} {ic_spec.start_kp} {ic_spec.end_kp} " +
|
||||||
|
f"{ic_spec.concentration} {ic_spec.eg} {ic_spec.em} {ic_spec.ed} {ic_spec.rate}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _export_POL_Characteristics(self, study, pol_data, f, qlog, name="0"):
|
||||||
|
|
||||||
|
list_characteristics = ["type", "diametre", "rho", "porosity", "cdc_riv", "cdc_cas", "apd", "ac", "bc"]
|
||||||
|
|
||||||
|
if len(list_characteristics) == (len(pol_data[0])-1):
|
||||||
|
for l in range(len(list_characteristics)):
|
||||||
|
f.write(f"{list_characteristics[l]} = {pol_data[0][l]}\n")
|
||||||
|
|
||||||
|
def _export_D90(self, study, repertory, qlog=None, name="0"):
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export D90 file")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{name}.D90"), "w+") as f:
|
||||||
|
files.append(f"{name}.D90")
|
||||||
|
|
||||||
|
f.write(f"*Diamètres caractéristiques du fond stable\n")
|
||||||
|
|
||||||
|
d90AdisTS = study.river.d90_adists.D90_AdisTS_List
|
||||||
|
|
||||||
|
f.write(f"{d90AdisTS[0].name} = {d90AdisTS[0].d90}\n")
|
||||||
|
|
||||||
|
self._export_d90_spec(study, d90AdisTS[0]._data, f, qlog)
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _export_d90_spec(self, study, d90_spec_data, f, qlog, name="0"):
|
||||||
|
|
||||||
|
for d90_spec in d90_spec_data:
|
||||||
|
if (d90_spec.name is None) or (d90_spec.reach is None) or (d90_spec.start_kp is None) or \
|
||||||
|
(d90_spec.end_kp is None) or (d90_spec.d90 is None):
|
||||||
|
return
|
||||||
|
|
||||||
|
edges = study.river.enable_edges()
|
||||||
|
|
||||||
|
id_edges = list(map(lambda x: x.id, edges))
|
||||||
|
|
||||||
|
id_reach = d90_spec.reach
|
||||||
|
|
||||||
|
if id_reach not in id_edges:
|
||||||
|
return
|
||||||
|
|
||||||
|
f.write(f"{d90_spec.name} = {id_reach} {d90_spec.start_kp} {d90_spec.end_kp} {d90_spec.d90}\n")
|
||||||
|
|
||||||
|
def _export_DIF(self, study, repertory, qlog=None, name="0"):
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export DIF file")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{name}.DIF"), "w+") as f:
|
||||||
|
files.append(f"{name}.DIF")
|
||||||
|
|
||||||
|
f.write(f"*Définition des paramètres des fonctions de calcul du\n")
|
||||||
|
f.write(f"*coefficient de diffusion\n")
|
||||||
|
|
||||||
|
difAdisTS = study.river.dif_adists.DIF_AdisTS_List
|
||||||
|
|
||||||
|
if difAdisTS[0].method != "generique":
|
||||||
|
f.write(f"defaut = {difAdisTS[0].method} {difAdisTS[0].dif }\n")
|
||||||
|
else:
|
||||||
|
f.write(f"defaut = {difAdisTS[0].method} {difAdisTS[0].dif} {difAdisTS[0].b} {difAdisTS[0].c}\n")
|
||||||
|
|
||||||
|
self._export_dif_spec(study, difAdisTS[0]._data, f, qlog)
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _export_dif_spec(self, study, dif_spec_data, f, qlog, name="0"):
|
||||||
|
|
||||||
|
for dif_spec in dif_spec_data:
|
||||||
|
if (dif_spec.reach is None) or (dif_spec.start_kp is None) or \
|
||||||
|
(dif_spec.end_kp is None) or (dif_spec.dif is None) or (dif_spec.b is None) or (dif_spec.c is None):
|
||||||
|
return
|
||||||
|
|
||||||
|
edges = study.river.enable_edges()
|
||||||
|
|
||||||
|
id_edges = list(map(lambda x: x.id, edges))
|
||||||
|
|
||||||
|
id_reach = dif_spec.reach
|
||||||
|
|
||||||
|
if id_reach not in id_edges:
|
||||||
|
return
|
||||||
|
|
||||||
|
if dif_spec.method != "generique":
|
||||||
|
f.write(f"{dif_spec.method} = {id_reach} {dif_spec.start_kp} {dif_spec.end_kp} {dif_spec.dif}\n")
|
||||||
|
else:
|
||||||
|
f.write(f"{dif_spec.method} = {id_reach} {dif_spec.start_kp} {dif_spec.end_kp} {dif_spec.dif}" +
|
||||||
|
f"{dif_spec.b} {dif_spec.c}\n")
|
||||||
|
|
||||||
|
def _export_NUM(self, study, repertory, qlog=None, name="0"):
|
||||||
|
|
||||||
|
dict_names = {"init_time":"start_date",
|
||||||
|
"final_time":"end_date",
|
||||||
|
"timestep":"dt0",
|
||||||
|
"implicitation_parameter":"theta",
|
||||||
|
"timestep_screen":"dtscr",
|
||||||
|
"timestep_bin":"dtbin",
|
||||||
|
"timestep_csv":"dtcsv",
|
||||||
|
"timestep_mage":"dtMage",
|
||||||
|
"initial_concentration":"c_initiale"}
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("Export NUM file")
|
||||||
|
|
||||||
|
with adists_file_open(os.path.join(repertory, f"{name}.NUM"), "w+") as f:
|
||||||
|
files.append(f"{name}.NUM")
|
||||||
|
|
||||||
|
params = study.river.get_params(self.type).parameters
|
||||||
|
for p in params:
|
||||||
|
name = p.name\
|
||||||
|
.replace("all_", "")\
|
||||||
|
.replace("adists_", "")
|
||||||
|
value = p.value
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"export: NUM: {name}: {value} ({p.value})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if name != "command_line_arguments":
|
||||||
|
f.write(f"{dict_names[name]} = {value}\n")
|
||||||
|
|
||||||
|
outputkps = study.river.Output_kp_adists.OutputKp_List
|
||||||
|
|
||||||
|
for outputkp in outputkps:
|
||||||
|
self._export_outputkp(study, outputkp, f, qlog)
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _export_outputkp(self, study, outputkp, f, qlog, name="0"):
|
||||||
|
if (outputkp.reach is None) or (outputkp.kp is None) or (outputkp.title is None):
|
||||||
|
return
|
||||||
|
|
||||||
|
edges = study.river.enable_edges()
|
||||||
|
|
||||||
|
id_edges = list(map(lambda x: x.id, edges))
|
||||||
|
|
||||||
|
id_reach = outputkp.reach
|
||||||
|
kp = outputkp.kp
|
||||||
|
title = outputkp.title
|
||||||
|
|
||||||
|
if id_reach not in id_edges:
|
||||||
|
return
|
||||||
|
|
||||||
|
f.write(f"output = {id_reach} {kp} {title}\n")
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def read_bin(self, study, repertory, results, qlog=None, name="0"):
|
||||||
|
repertory_results = os.path.join(repertory, "resultats")
|
||||||
|
|
||||||
|
files_bin_names = [el.split("/")[-1] for el in glob.glob(repertory_results+"/*.bin")]
|
||||||
|
print("files names resultats: ", files_bin_names)
|
||||||
|
|
||||||
|
ifilename = os.path.join(repertory_results, files_bin_names[0])
|
||||||
|
|
||||||
|
logger.info(f"read_bin: Start reading '{ifilename}' ...")
|
||||||
|
|
||||||
|
print("reading ", ifilename)
|
||||||
|
with open(ifilename, 'rb') as f:
|
||||||
|
# header
|
||||||
|
# first line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=3)
|
||||||
|
ibmax = data[0] # number of reaches
|
||||||
|
ismax = data[1] # total number of cross sections
|
||||||
|
kbl = data[2] * -1 # block size for .BIN header
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# second line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
ibu = np.fromfile(f, dtype=np.int32, count=ibmax)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# third line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=2 * ibmax)
|
||||||
|
is1 = np.zeros(ibmax, dtype=np.int32)
|
||||||
|
is2 = np.zeros(ibmax, dtype=np.int32)
|
||||||
|
print("nombre de biefs : ", ibmax)
|
||||||
|
|
||||||
|
logger.debug(f"read_bin: nb_reach = {ibmax}")
|
||||||
|
logger.debug(f"read_bin: nb_profile = {ismax}")
|
||||||
|
|
||||||
|
results.set("nb_reach", f"{ibmax}")
|
||||||
|
results.set("nb_profile", f"{ismax}")
|
||||||
|
|
||||||
|
reachs = []
|
||||||
|
iprofiles = {}
|
||||||
|
reach_offset = {}
|
||||||
|
|
||||||
|
for i in range(ibmax):
|
||||||
|
# Add results reach to reach list
|
||||||
|
r = results.river.add(i)
|
||||||
|
reachs.append(r)
|
||||||
|
|
||||||
|
is1[i] = data[2 * i] - 1 # first section of reach i (FORTRAN numbering)
|
||||||
|
is2[i] = data[2 * i + 1] - 1 # last section of reach i (FORTRAN numbering)
|
||||||
|
|
||||||
|
key = (is1[i], is2[i])
|
||||||
|
iprofiles[key] = r
|
||||||
|
|
||||||
|
reach_offset[r] = is1[i]
|
||||||
|
|
||||||
|
logger.debug(f"read_bin: iprofiles = {iprofiles}")
|
||||||
|
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# fourth line
|
||||||
|
pk = np.zeros(ismax, dtype=np.float32)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
pk[k:min(k + kbl, ismax)] = np.fromfile(f, dtype=np.float32, count=min(k + kbl, ismax) - k)
|
||||||
|
print("pk : ", pk)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
|
||||||
|
# fifth line (useless)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
zmin_OLD = np.fromfile(f, dtype=np.float32, count=1)[0]
|
||||||
|
print("zmin_OLD : ", zmin_OLD)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# sixth line
|
||||||
|
zf = np.zeros(ismax, dtype=np.float32)
|
||||||
|
z = np.zeros(ismax * 3, dtype=np.float32)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
z[3 * k:3 * min(k + kbl, ismax)] = np.fromfile(f, dtype=np.float32,
|
||||||
|
count=3 * (min(k + kbl, ismax) - k))
|
||||||
|
# z[i*3+1] and z[i*3+2] are useless
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
zf = [z[i * 3] for i in range(ismax)]
|
||||||
|
print("zf : ", zf)
|
||||||
|
# seventh line (useless)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
zero = np.fromfile(f, dtype=np.int32, count=ismax)
|
||||||
|
print("zero : ", zero)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# end header
|
||||||
|
|
||||||
|
def ip_to_r(i): return iprofiles[
|
||||||
|
next(
|
||||||
|
filter(
|
||||||
|
lambda k: k[0] <= i <= k[1],
|
||||||
|
iprofiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def ip_to_ri(r, i): return i - reach_offset[r]
|
||||||
|
|
||||||
|
path_files = map(lambda file: os.path.join(repertory_results, file), files_bin_names)
|
||||||
|
|
||||||
|
data_tmp = {}
|
||||||
|
|
||||||
|
for file_bin in path_files:
|
||||||
|
key_pol = file_bin.split("/")[-1][0:-4]
|
||||||
|
data_tmp[key_pol] = {}
|
||||||
|
with open(file_bin, 'rb') as f:
|
||||||
|
# header
|
||||||
|
# first line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=3)
|
||||||
|
ibmax = data[0] # number of reaches
|
||||||
|
ismax = data[1] # total number of cross sections
|
||||||
|
kbl = data[2] * -1 # block size for .BIN header
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# second line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
ibu = np.fromfile(f, dtype=np.int32, count=ibmax)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# third line
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=2 * ibmax)
|
||||||
|
is1 = np.zeros(ibmax, dtype=np.int32)
|
||||||
|
is2 = np.zeros(ibmax, dtype=np.int32)
|
||||||
|
for i in range(ibmax):
|
||||||
|
is1[i] = data[2 * i] # first section of reach i (FORTRAN numbering)
|
||||||
|
is2[i] = data[2 * i + 1] # last section of reach i (FORTRAN numbering)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# fourth line
|
||||||
|
pk = np.zeros(ismax, dtype=np.float32)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
pk[k:min(k + kbl, ismax)] = np.fromfile(f, dtype=np.float32, count=min(k + kbl, ismax) - k)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# fifth line (useless)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
zmin_OLD = np.fromfile(f, dtype=np.float32, count=1)[0]
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# sixth line
|
||||||
|
zf = np.zeros(ismax, dtype=np.float32)
|
||||||
|
z = np.zeros(ismax * 3, dtype=np.float32)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
z[3 * k:3 * min(k + kbl, ismax)] = np.fromfile(f, dtype=np.float32,
|
||||||
|
count=3 * (min(k + kbl, ismax) - k))
|
||||||
|
# z[i*3+1] and z[i*3+2] are useless
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
zf = [z[i * 3] for i in range(ismax)]
|
||||||
|
# seventh line (useless)
|
||||||
|
for k in range(0, ismax, kbl):
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
zero = np.fromfile(f, dtype=np.int32, count=ismax)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
# end header
|
||||||
|
# data
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
while data.size > 0:
|
||||||
|
ismax = np.fromfile(f, dtype=np.int32, count=1)[0]
|
||||||
|
t = np.fromfile(f, dtype=np.float64, count=1)[0]
|
||||||
|
if not t in data_tmp[key_pol]:
|
||||||
|
data_tmp[key_pol][t] = {}
|
||||||
|
c = np.fromfile(f, dtype=np.byte, count=1)
|
||||||
|
# possible values :
|
||||||
|
# sediment : C, G, M, D, L, N, R
|
||||||
|
# polutant : C, G, M, D
|
||||||
|
phys_var = bytearray(c).decode()
|
||||||
|
data_tmp[key_pol][t][phys_var] = {}
|
||||||
|
real_data = np.fromfile(f, dtype=np.float32, count=ismax)
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (end)
|
||||||
|
data_tmp[key_pol][t][phys_var] = real_data
|
||||||
|
data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start)
|
||||||
|
# end data
|
||||||
|
|
||||||
|
###print("dta tmp AAA")
|
||||||
|
###print("-----------")
|
||||||
|
###print(data_tmp["AAA-silt"])
|
||||||
|
|
||||||
|
pollutants_keys = list(data_tmp.keys())
|
||||||
|
timestamps_keys = list(data_tmp[pollutants_keys[0]].keys())
|
||||||
|
phys_data_names = list(data_tmp[pollutants_keys[0]][timestamps_keys[0]].keys())
|
||||||
|
|
||||||
|
###print("pol keys: ", pollutants_keys)
|
||||||
|
###print("t keys: ", timestamps_keys)
|
||||||
|
###print("phys var: ", phys_data_names)
|
||||||
|
#print("set timestamps keys: ", set(timestamps_keys))
|
||||||
|
#print("isma")
|
||||||
|
###print("iprofiles: ", iprofiles)
|
||||||
|
|
||||||
|
pi_tmp = []
|
||||||
|
reach_tmp = []
|
||||||
|
|
||||||
|
for i in range(ismax-1):
|
||||||
|
#print("first i: ", i)
|
||||||
|
reach = ip_to_r(i)
|
||||||
|
reach_tmp.append(reach)
|
||||||
|
#print("reach i:", reach)
|
||||||
|
#print("second i: ", i)
|
||||||
|
p_i = ip_to_ri(reach, i)
|
||||||
|
pi_tmp.append(p_i)
|
||||||
|
|
||||||
|
for t_data in timestamps_keys:
|
||||||
|
pol_view = []
|
||||||
|
for pol in pollutants_keys:
|
||||||
|
#print("pol results: ", type(list(data_tmp[pol][t_data].values())))
|
||||||
|
pol_view.append(tuple( list(map(lambda data_el: data_el[p_i], list(data_tmp[pol][t_data].values()))) ))
|
||||||
|
|
||||||
|
reach.set(p_i, t_data, "pols", pol_view)
|
||||||
|
|
||||||
|
###print("pi_tmp: ", pi_tmp)
|
||||||
|
###print("pol view: ", pol_view)
|
||||||
|
###print("reach from i: ", reach_tmp)
|
||||||
|
#print("pol view: ", pol_view)
|
||||||
|
#print("results: ", results)
|
||||||
|
results.set("timestamps", set(timestamps_keys))
|
||||||
|
#print("------------------------set timestamps results meta data: ", set(timestamps_keys))
|
||||||
|
|
||||||
|
###print("debug profiles for draw:")
|
||||||
|
###print("------------------------")
|
||||||
|
###print(data_tmp["AAA-silt"][0.0]["C"][0])
|
||||||
|
###print(data_tmp["AAA-silt"][600.0]["C"][0])
|
||||||
|
###print(data_tmp["AAA-silt"][1205.7208829578194]["C"][0])
|
||||||
|
###print("========================")
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def results(self, study, repertory, qlog=None, name=None):
|
||||||
|
self._study = study
|
||||||
|
if name is None:
|
||||||
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
|
results = super(AdisTSlc, self).results(study, repertory, qlog, name=name)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def export_func_dict(self):
|
||||||
|
return [
|
||||||
|
self._export_NUM,
|
||||||
|
self._export_DIF,
|
||||||
|
self._export_D90,
|
||||||
|
self._export_POLs,
|
||||||
|
]
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def export(self, study, repertory, mage_rep, qlog=None, name="0"):
|
||||||
|
print("cmd solver adistslc : ", self._cmd_solver)
|
||||||
|
self._study = study
|
||||||
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
|
# Generate files
|
||||||
|
files = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
for func in self.export_func_dict():
|
||||||
|
files = files + func(study, repertory, qlog, name=name)
|
||||||
|
|
||||||
|
self.export_additional_files(study, repertory, qlog, name=name)
|
||||||
|
self._export_REP(study, repertory, mage_rep, files, qlog, name=name)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to export study to {self._type}")
|
||||||
|
logger_exception(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -980,6 +980,7 @@ class Mage8(Mage):
|
|||||||
|
|
||||||
# Add profile id correspondance to reach
|
# Add profile id correspondance to reach
|
||||||
key = (i1, i2)
|
key = (i1, i2)
|
||||||
|
print("mage keys reachs: ", key)
|
||||||
iprofiles[key] = r
|
iprofiles[key] = r
|
||||||
|
|
||||||
# Profile ID offset
|
# Profile ID offset
|
||||||
@@ -1012,6 +1013,8 @@ class Mage8(Mage):
|
|||||||
]
|
]
|
||||||
def ip_to_ri(r, i): return i - reach_offset[r]
|
def ip_to_ri(r, i): return i - reach_offset[r]
|
||||||
|
|
||||||
|
print("mage iprofiles: ", iprofiles)
|
||||||
|
|
||||||
ts = set()
|
ts = set()
|
||||||
end = False
|
end = False
|
||||||
while not end:
|
while not end:
|
||||||
@@ -1047,6 +1050,7 @@ class Mage8(Mage):
|
|||||||
|
|
||||||
logger.debug(reachs[0].profiles[0]._data)
|
logger.debug(reachs[0].profiles[0]._data)
|
||||||
results.set("timestamps", ts)
|
results.set("timestamps", ts)
|
||||||
|
print("set timestamps mage: ", ts)
|
||||||
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from Solver.Mage import (
|
|||||||
Mage7, Mage8, MageFake7,
|
Mage7, Mage8, MageFake7,
|
||||||
)
|
)
|
||||||
from Solver.RubarBE import RubarBE
|
from Solver.RubarBE import RubarBE
|
||||||
|
from Solver.AdisTS import AdisTSlc
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
@@ -31,7 +32,8 @@ solver_long_name = {
|
|||||||
# "mage7": "Mage v7",
|
# "mage7": "Mage v7",
|
||||||
"mage8": "Mage v8",
|
"mage8": "Mage v8",
|
||||||
# "mage_fake7": "Mage fake v7",
|
# "mage_fake7": "Mage fake v7",
|
||||||
# "rubarbe": "RubarBE",
|
"rubarbe": "RubarBE",
|
||||||
|
"adistslc": "Adis-TS_LC",
|
||||||
}
|
}
|
||||||
|
|
||||||
solver_type_list = {
|
solver_type_list = {
|
||||||
@@ -39,5 +41,6 @@ solver_type_list = {
|
|||||||
# "mage7": Mage7,
|
# "mage7": Mage7,
|
||||||
"mage8": Mage8,
|
"mage8": Mage8,
|
||||||
# "mage_fake7": MageFake7,
|
# "mage_fake7": MageFake7,
|
||||||
# "rubarbe": RubarBE,
|
"rubarbe": RubarBE,
|
||||||
|
"adistslc": AdisTSlc,
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
logger.info(e)
|
logger.info(e)
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
|
|
||||||
self.update()
|
self.dataChanged.emit(index, index)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def add(self, row, parent=QModelIndex()):
|
def add(self, row, parent=QModelIndex()):
|
||||||
@@ -112,7 +112,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def delete(self, rows, parent=QModelIndex()):
|
def delete(self, rows, parent=QModelIndex()):
|
||||||
self.beginRemoveRows(parent, rows[0], rows[-1])
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
||||||
@@ -135,7 +135,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_up(self, row, parent=QModelIndex()):
|
def move_up(self, row, parent=QModelIndex()):
|
||||||
if row <= 0:
|
if row <= 0:
|
||||||
@@ -152,7 +152,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_down(self, index, parent=QModelIndex()):
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
if row > len(self._data):
|
if row > len(self._data):
|
||||||
@@ -169,7 +169,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def paste(self, row, header, data):
|
def paste(self, row, header, data):
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
@@ -190,13 +190,4 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.update()
|
|
||||||
|
|
||||||
def auto_sort(self):
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
|
||||||
self._data.sort(key=lambda x: x[0])
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
# self.auto_sort()
|
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
@@ -195,7 +195,6 @@ class EditBoundaryConditionWindow(PamhyrWindow):
|
|||||||
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
||||||
|
|
||||||
self._table.dataChanged.connect(self.update)
|
self._table.dataChanged.connect(self.update)
|
||||||
self._table.layoutChanged.connect(self.update)
|
|
||||||
|
|
||||||
if self._is_solid:
|
if self._is_solid:
|
||||||
self._d50sigma.d50Changed.connect(self.d50_changed)
|
self._d50sigma.d50Changed.connect(self.d50_changed)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class BCTranslate(MainTranslate):
|
|||||||
|
|
||||||
self._sub_dict["long_types"] = {
|
self._sub_dict["long_types"] = {
|
||||||
"ND": self._dict["not_defined"],
|
"ND": self._dict["not_defined"],
|
||||||
"PC": _translate("BoundaryCondition", "Point sources"),
|
"PC": _translate("BoundaryCondition", "Ponctual contribution"),
|
||||||
"TZ": _translate("BoundaryCondition", "Z(t)"),
|
"TZ": _translate("BoundaryCondition", "Z(t)"),
|
||||||
"TD": _translate("BoundaryCondition", "Q(t)"),
|
"TD": _translate("BoundaryCondition", "Q(t)"),
|
||||||
"ZD": _translate("BoundaryCondition", "Q(Z)"),
|
"ZD": _translate("BoundaryCondition", "Q(Z)"),
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# Plot.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 datetime import datetime
|
||||||
|
|
||||||
|
from tools import timer, trace
|
||||||
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class Plot(PamhyrPlot):
|
||||||
|
def __init__(self, mode="time", data=None,
|
||||||
|
trad=None, canvas=None, toolbar=None,
|
||||||
|
parent=None):
|
||||||
|
super(Plot, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
trad=trad,
|
||||||
|
data=data,
|
||||||
|
toolbar=toolbar,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._table_headers = self._trad.get_dict("table_headers")
|
||||||
|
|
||||||
|
header = self.data.header
|
||||||
|
|
||||||
|
self.label_x = self._table_headers[header[0]]
|
||||||
|
self.label_y = self._table_headers[header[1]]
|
||||||
|
|
||||||
|
self._mode = mode
|
||||||
|
self._isometric_axis = False
|
||||||
|
|
||||||
|
self._auto_relim_update = True
|
||||||
|
self._autoscale_update = True
|
||||||
|
|
||||||
|
def custom_ticks(self):
|
||||||
|
if self.data.header[0] != "time":
|
||||||
|
return
|
||||||
|
|
||||||
|
self.set_ticks_time_formater()
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.init_axes()
|
||||||
|
|
||||||
|
if len(self.data) == 0:
|
||||||
|
self._init = False
|
||||||
|
return
|
||||||
|
|
||||||
|
self.draw_data()
|
||||||
|
self.custom_ticks()
|
||||||
|
|
||||||
|
self.idle()
|
||||||
|
self._init = True
|
||||||
|
|
||||||
|
def draw_data(self):
|
||||||
|
# Plot data
|
||||||
|
x = list(map(lambda v: v[0], self.data.data))
|
||||||
|
y = list(map(lambda v: v[1], self.data.data))
|
||||||
|
|
||||||
|
self._line, = self.canvas.axes.plot(
|
||||||
|
x, y,
|
||||||
|
color=self.color_plot,
|
||||||
|
**self.plot_default_kargs
|
||||||
|
)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if not self._init:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.update_data()
|
||||||
|
|
||||||
|
self.update_idle()
|
||||||
|
|
||||||
|
def update_data(self):
|
||||||
|
x = list(map(lambda v: v[0], self.data.data))
|
||||||
|
y = list(map(lambda v: v[1], self.data.data))
|
||||||
|
|
||||||
|
self._line.set_data(x, y)
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# 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 datetime import date, time, datetime, timedelta
|
||||||
|
|
||||||
|
from tools import (
|
||||||
|
trace, timer,
|
||||||
|
timestamp_to_old_pamhyr_date,
|
||||||
|
old_pamhyr_date_to_timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect, QTime, QDateTime,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QTableView, QAbstractItemView, QSpinBox,
|
||||||
|
QTimeEdit, QDateTimeEdit, QItemDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.BoundaryConditionsAdisTS.Edit.UndoCommand import (
|
||||||
|
AddCommand, DelCommand, SetDataCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class TableModel(PamhyrTableModel):
|
||||||
|
def data(self, index, role):
|
||||||
|
if role == Qt.TextAlignmentRole:
|
||||||
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
value = QVariant()
|
||||||
|
|
||||||
|
if 0 <= column < 2:
|
||||||
|
v = self._data._data[row][column]
|
||||||
|
if self._data._types[column] == float:
|
||||||
|
value = f"{v:.4f}"
|
||||||
|
elif self._data.header[column] == "time":
|
||||||
|
if self._opt_data == "time":
|
||||||
|
value = timestamp_to_old_pamhyr_date(int(v))
|
||||||
|
else:
|
||||||
|
value = str(datetime.fromtimestamp(v))
|
||||||
|
else:
|
||||||
|
value = f"{v}"
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
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:
|
||||||
|
self._undo.push(
|
||||||
|
SetDataCommand(
|
||||||
|
self._data, row, 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._data, row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endInsertRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def delete(self, rows, parent=QModelIndex()):
|
||||||
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
DelCommand(
|
||||||
|
self._data, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class SetDataCommand(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._data[self._index][self._column]
|
||||||
|
_type = self._data._types[self._column]
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == 0:
|
||||||
|
self._data._data[self._index] = (self._old,self._data._data[self._index][1])
|
||||||
|
else:
|
||||||
|
self._data._data[self._index] = (self._data._data[self._index][0], self._old)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == 0:
|
||||||
|
self._data._data[self._index] = (self._new,self._data._data[self._index][1])
|
||||||
|
else:
|
||||||
|
self._data._data[self._index] = (self._data._data[self._index][0], self._new)
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
del self._data._data[self._index]
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._data._data.insert(self._index, (self._data._types[0](0), self._data._types[1](0.0)))
|
||||||
|
else:
|
||||||
|
self._data._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._rows = rows
|
||||||
|
|
||||||
|
self._bc = []
|
||||||
|
for row in rows:
|
||||||
|
self._bc.append((row, self._data._data[row]))
|
||||||
|
self._bc.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._bc:
|
||||||
|
self._data._data.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
for row in self._rows:
|
||||||
|
del self._data._data[row]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
# 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 logging
|
||||||
|
|
||||||
|
from tools import timer, trace
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
from View.Tools.PamhyrWidget import PamhyrWidget
|
||||||
|
from View.Tools.PamhyrDelegate import PamhyrExTimeDelegate
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel, QCoreApplication,
|
||||||
|
pyqtSlot, pyqtSignal,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QHeaderView, QDoubleSpinBox, QVBoxLayout,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
|
from View.BoundaryConditionsAdisTS.Edit.translate import BCETranslate
|
||||||
|
from View.BoundaryConditionsAdisTS.Edit.Table import TableModel
|
||||||
|
from View.BoundaryConditionsAdisTS.Edit.Plot import Plot
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class EditBoundaryConditionWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "EditBoundaryConditionsAdisTS"
|
||||||
|
_pamhyr_name = "Edit Boundary Conditions AdisTS"
|
||||||
|
|
||||||
|
def __init__(self, data=None, study=None, config=None, parent=None):
|
||||||
|
self._data = data
|
||||||
|
trad = BCETranslate()
|
||||||
|
|
||||||
|
name = trad[self._pamhyr_name]
|
||||||
|
|
||||||
|
super(EditBoundaryConditionWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._data is not None:
|
||||||
|
n = self._data.node
|
||||||
|
node_name = next(filter(lambda x: x.id == n, self._study.river._nodes)).name
|
||||||
|
name += (
|
||||||
|
f" - {study.name} " +
|
||||||
|
f"({node_name})"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._hash_data.append(data)
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_plot()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
if self._data.type == "Concentration":
|
||||||
|
self._data.header = ["time", "concentration"]
|
||||||
|
else:
|
||||||
|
self._data.header = ["time", "rate"]
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
table_headers = self._trad.get_dict("table_headers")
|
||||||
|
for h in self._data.header:
|
||||||
|
headers[h] = table_headers[h]
|
||||||
|
|
||||||
|
self._delegate_time = PamhyrExTimeDelegate(
|
||||||
|
data=self._data,
|
||||||
|
mode=self._study.time_system,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
table = self.find(QTableView, "tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
table_view=table,
|
||||||
|
table_headers=headers,
|
||||||
|
editable_headers=self._data.header,
|
||||||
|
delegates={
|
||||||
|
# "time": self._delegate_time,
|
||||||
|
},
|
||||||
|
data=self._data,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
opt_data=self._study.time_system
|
||||||
|
)
|
||||||
|
|
||||||
|
table.setModel(self._table)
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
def setup_plot(self):
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas")
|
||||||
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
|
self.canvas, self
|
||||||
|
)
|
||||||
|
self.verticalLayout.addWidget(self.toolbar)
|
||||||
|
self.verticalLayout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self.plot = Plot(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=self._data,
|
||||||
|
mode=self._study.time_system,
|
||||||
|
trad=self._trad,
|
||||||
|
toolbar=self.toolbar,
|
||||||
|
)
|
||||||
|
self.plot.draw()
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QAction, "action_add").triggered.connect(self.add)
|
||||||
|
self.find(QAction, "action_del").triggered.connect(self.delete)
|
||||||
|
|
||||||
|
self._table.dataChanged.connect(self.update)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
def index_selected_row(self):
|
||||||
|
table = self.find(QTableView, "tableView")
|
||||||
|
return table.selectionModel()\
|
||||||
|
.selectedRows()[0]\
|
||||||
|
.row()
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
table = self.find(QTableView, "tableView")
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._data) == 0 or len(rows) == 0:
|
||||||
|
self._table.add(0)
|
||||||
|
else:
|
||||||
|
self._table.add(rows[0])
|
||||||
|
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.delete(rows)
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
def sort(self):
|
||||||
|
self._table.sort(False)
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
def _copy(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
|
||||||
|
table = []
|
||||||
|
table.append(self._data.header)
|
||||||
|
|
||||||
|
data = self._data.data
|
||||||
|
for row in rows:
|
||||||
|
table.append(list(data[row]))
|
||||||
|
|
||||||
|
self.copyTableIntoClipboard(table)
|
||||||
|
|
||||||
|
def _undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
def _redo(self):
|
||||||
|
self._table.redo()
|
||||||
|
self.plot.update()
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from View.BoundaryCondition.translate import BCTranslate
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class BCETranslate(BCTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(BCETranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["Edit Boundary Conditions AdisTS"] = _translate(
|
||||||
|
"BoundaryConditionAdisTS", "Edit boundary conditions AdisTS"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"time": self._dict["time"],
|
||||||
|
"date": self._dict["date"],
|
||||||
|
"rate": _translate("BoundaryConditionAdisTS", "Rate"),
|
||||||
|
"concentration": _translate("BoundaryConditionAdisTS", "Concentration"),
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
# 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 Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||||
|
NotDefined, PonctualContribution,
|
||||||
|
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
|
from View.BoundaryConditionsAdisTS.UndoCommand import (
|
||||||
|
SetNodeCommand, SetTypeCommand,
|
||||||
|
AddCommand, DelCommand,
|
||||||
|
)
|
||||||
|
from View.BoundaryCondition.translate import BC_types
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, data=None, mode="type", tab="",
|
||||||
|
trad=None, parent=None):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._mode = mode
|
||||||
|
self._tab = tab
|
||||||
|
self._trad = trad
|
||||||
|
|
||||||
|
self._long_types = {}
|
||||||
|
if self._trad is not None:
|
||||||
|
self._long_types = self._trad.get_dict("long_types")
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
if self._mode == "type":
|
||||||
|
lst = [self._trad["not_associated"], "Concentration", "Rate"]
|
||||||
|
self.editor.addItems(
|
||||||
|
lst
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.editor.addItems(
|
||||||
|
[self._trad["not_associated"]] +
|
||||||
|
self._data.nodes_names()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setCurrentText(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 TableModel(PamhyrTableModel):
|
||||||
|
def __init__(self, pollutant=None, bc_list =None, trad=None, **kwargs):
|
||||||
|
self._trad = trad
|
||||||
|
self._bc_list = bc_list
|
||||||
|
self._pollutant = pollutant
|
||||||
|
|
||||||
|
super(TableModel, self).__init__(trad=trad, **kwargs)
|
||||||
|
|
||||||
|
def _setup_lst(self):
|
||||||
|
self._lst = self._bc_list.lst
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if len(self._lst) != 0:
|
||||||
|
data = list(filter(lambda x: x.pollutant == self._pollutant,
|
||||||
|
self._lst))
|
||||||
|
else:
|
||||||
|
data = []
|
||||||
|
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "type":
|
||||||
|
n = data[row].type
|
||||||
|
if n is None or n == "":
|
||||||
|
return self._trad["not_associated"]
|
||||||
|
return n
|
||||||
|
elif self._headers[column] == "node":
|
||||||
|
n = data[row].node
|
||||||
|
if n is None:
|
||||||
|
return self._trad["not_associated"]
|
||||||
|
return next(filter(lambda x: x.id == n, self._data._nodes)).name
|
||||||
|
|
||||||
|
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] == "type":
|
||||||
|
self._undo.push(
|
||||||
|
SetTypeCommand(
|
||||||
|
self._lst, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self._headers[column] == "node":
|
||||||
|
self._undo.push(
|
||||||
|
SetNodeCommand(
|
||||||
|
self._lst, row, self._data.node(value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
print(value, self._data.node(value).id)
|
||||||
|
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._pollutant, self._bc_list, 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 undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# 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.BoundaryConditionsAdisTS.BoundaryConditionAdisTS import BoundaryConditionAdisTS
|
||||||
|
from Model.BoundaryConditionsAdisTS.BoundaryConditionsAdisTSList import BoundaryConditionsAdisTSList
|
||||||
|
|
||||||
|
class SetNodeCommand(QUndoCommand):
|
||||||
|
def __init__(self, bcs, index, node):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._bcs = bcs
|
||||||
|
self._index = index
|
||||||
|
self._old = self._bcs[self._index].node
|
||||||
|
self._new = node.id
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._bcs[self._index].node = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._bcs[self._index].node = self._new
|
||||||
|
|
||||||
|
class SetTypeCommand(QUndoCommand):
|
||||||
|
def __init__(self, bcs, index, _type):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._bcs = bcs
|
||||||
|
self._index = index
|
||||||
|
self._type = _type
|
||||||
|
self._old = self._bcs[self._index].type
|
||||||
|
self._new = self._type
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._bcs[self._index].type = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._bcs[self._index].type = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, pollutant, bcs_list, bcs, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._bcs = bcs
|
||||||
|
self._bc_list = bcs_list
|
||||||
|
self._pollutant = pollutant
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
del self._bcs[self._index]
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._bc_list.new(self._index, self._pollutant)
|
||||||
|
else:
|
||||||
|
self._bcs.insert(self._index, self._new)
|
||||||
|
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, bcs, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._bcs = bcs
|
||||||
|
self._rows = rows
|
||||||
|
|
||||||
|
self._bc = []
|
||||||
|
for row in rows:
|
||||||
|
self._bc.append((row, self._bcs[row]))
|
||||||
|
self._bc.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._bc:
|
||||||
|
self._bcs.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
for row in self._rows:
|
||||||
|
del self._bcs[row]
|
||||||
|
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
# 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 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,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.BoundaryConditionsAdisTS.Table import (
|
||||||
|
TableModel, ComboBoxDelegate
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Network.GraphWidget import GraphWidget
|
||||||
|
from View.BoundaryConditionsAdisTS.translate import BCAdisTSTranslate
|
||||||
|
from View.BoundaryConditionsAdisTS.Edit.Window import EditBoundaryConditionWindow
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class BoundaryConditionAdisTSWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "BoundaryConditionsAdisTS"
|
||||||
|
_pamhyr_name = "Boundary conditions AdisTS"
|
||||||
|
|
||||||
|
def __init__(self, pollutant=None, study=None, config=None, parent=None):
|
||||||
|
trad = BCAdisTSTranslate()
|
||||||
|
name = (
|
||||||
|
trad[self._pamhyr_name] +
|
||||||
|
" - " + study.name
|
||||||
|
)
|
||||||
|
|
||||||
|
self._pollutant = pollutant
|
||||||
|
|
||||||
|
super(BoundaryConditionAdisTSWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._bcs = self._study.river.boundary_conditions_adists
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
self._delegate_type = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
mode="type",
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self._delegate_node = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
mode="node",
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
table_view=table,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
editable_headers=["type", "node"],
|
||||||
|
delegates={
|
||||||
|
"type": self._delegate_type,
|
||||||
|
"node": self._delegate_node,
|
||||||
|
},
|
||||||
|
trad=self._trad,
|
||||||
|
bc_list = self._study.river.boundary_conditions_adists,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
pollutant=self._pollutant,
|
||||||
|
data=self._study.river
|
||||||
|
)
|
||||||
|
table.setModel(self._table)
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
def setup_graph(self):
|
||||||
|
self.graph_widget = GraphWidget(
|
||||||
|
self._study.river,
|
||||||
|
min_size=None, size=(200, 200),
|
||||||
|
only_display=True,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self.graph_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
self.graph_layout.addWidget(self.graph_widget)
|
||||||
|
|
||||||
|
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_edit").triggered.connect(self.edit)
|
||||||
|
|
||||||
|
def index_selected_row(self):
|
||||||
|
tab = "liquid"
|
||||||
|
table = self.find(QTableView, f"tableView_{tab}")
|
||||||
|
return table.selectionModel()\
|
||||||
|
.selectedRows()[0]\
|
||||||
|
.row()
|
||||||
|
|
||||||
|
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._bcs) == 0 or len(rows) == 0:
|
||||||
|
self._table.add(0)
|
||||||
|
else:
|
||||||
|
self._table.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.delete(rows)
|
||||||
|
|
||||||
|
def _copy(self):
|
||||||
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
|
def _paste(self):
|
||||||
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
|
def _undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
|
||||||
|
def _redo(self):
|
||||||
|
self._table.redo()
|
||||||
|
|
||||||
|
def edit(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
for row in rows:
|
||||||
|
data = self._bcs.lst[row]
|
||||||
|
|
||||||
|
if self.sub_window_exists(
|
||||||
|
EditBoundaryConditionWindow,
|
||||||
|
data=[self._study, None, data]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
win = EditBoundaryConditionWindow(
|
||||||
|
data=data,
|
||||||
|
study=self._study,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
win.show()
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 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 BCAdisTSTranslate(MainTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(BCAdisTSTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["Boundary conditions AdisTS"] = _translate(
|
||||||
|
"BoundaryConditionsAdisTS", "Boundary conditions AdisTS"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"type": self._dict["type"],
|
||||||
|
"node": _translate("BoundaryCondition", "Node")
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
# WindowAdisTS.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 trace, timer
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, QRect, QThread,
|
||||||
|
pyqtSlot, pyqtSignal,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
QProgressBar, QLabel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.CheckList.Table import TableModel
|
||||||
|
from View.CheckList.Worker import Worker
|
||||||
|
from View.CheckList.Translate import CheckListTranslate
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class CheckListWindowAdisTS(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "CheckList"
|
||||||
|
_pamhyr_name = "Check list"
|
||||||
|
|
||||||
|
signalStatus = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self, autorun: bool = True,
|
||||||
|
study=None, config=None,
|
||||||
|
solver=None, parent=None, mage_rep=None):
|
||||||
|
trad = CheckListTranslate()
|
||||||
|
|
||||||
|
self._autorun = autorun
|
||||||
|
self._solver = solver
|
||||||
|
self._mage_rep = mage_rep
|
||||||
|
|
||||||
|
name = trad[self._pamhyr_name] + " - " + study.name
|
||||||
|
|
||||||
|
super(CheckListWindowAdisTS, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add solver to hash computation data
|
||||||
|
self._hash_data.append(self._solver)
|
||||||
|
|
||||||
|
self._checker_list = (
|
||||||
|
self._study.checkers() +
|
||||||
|
self._solver.checkers()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_progress_bar()
|
||||||
|
self.setup_connections()
|
||||||
|
self.setup_thread()
|
||||||
|
self.setup_statusbar()
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
table_view=table,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
data=self._checker_list,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_progress_bar(self):
|
||||||
|
self._progress = self.find(QProgressBar, f"progressBar")
|
||||||
|
self._p = 0 # Progress current step
|
||||||
|
|
||||||
|
self._progress.setRange(0, len(self._checker_list))
|
||||||
|
self._progress.setValue(self._p)
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
|
||||||
|
self.find(QPushButton, "pushButton_retry").clicked.connect(self.retry)
|
||||||
|
self.find(QPushButton, "pushButton_cancel")\
|
||||||
|
.clicked.connect(self.reject)
|
||||||
|
|
||||||
|
def setup_thread(self):
|
||||||
|
self._worker = Worker(self._study, self._checker_list)
|
||||||
|
self._worker_thread = QThread()
|
||||||
|
self._worker.moveToThread(self._worker_thread)
|
||||||
|
|
||||||
|
# Connect any worker signals
|
||||||
|
self._worker.signalStatus.connect(self.update)
|
||||||
|
self._worker_thread.started.connect(self._worker.process)
|
||||||
|
|
||||||
|
self._worker_thread.start()
|
||||||
|
|
||||||
|
def retry(self):
|
||||||
|
self._worker_thread.terminate()
|
||||||
|
self._worker_thread.wait()
|
||||||
|
|
||||||
|
self.find(QPushButton, "pushButton_retry").setEnabled(False)
|
||||||
|
self.find(QPushButton, "pushButton_ok").setEnabled(False)
|
||||||
|
|
||||||
|
self.setup_thread()
|
||||||
|
|
||||||
|
def _compute_status(self):
|
||||||
|
ok = len(list(filter(lambda c: c.is_ok(), self._checker_list)))
|
||||||
|
warning = len(
|
||||||
|
list(filter(lambda c: c.is_warning(), self._checker_list)))
|
||||||
|
error = len(list(filter(lambda c: c.is_error(), self._checker_list)))
|
||||||
|
|
||||||
|
return ok, warning, error
|
||||||
|
|
||||||
|
def _compute_status_label(self):
|
||||||
|
ok, warning, error = self._compute_status()
|
||||||
|
return (f"<font color=\"Green\">Ok: {ok} </font> |" +
|
||||||
|
f"<font color=\"Orange\">Warning: {warning} </font> |" +
|
||||||
|
f"<font color=\"Red\">Error: {error}</font>")
|
||||||
|
|
||||||
|
def setup_statusbar(self):
|
||||||
|
txt = self._compute_status_label()
|
||||||
|
self._status_label = QLabel(txt)
|
||||||
|
self.statusbar.addPermanentWidget(self._status_label)
|
||||||
|
|
||||||
|
def update_statusbar(self):
|
||||||
|
txt = self._compute_status_label()
|
||||||
|
self._status_label.setText(txt)
|
||||||
|
|
||||||
|
def progress(self):
|
||||||
|
self._p += 1
|
||||||
|
self._progress.setValue(self._p)
|
||||||
|
self._table.update()
|
||||||
|
|
||||||
|
def start_compute(self):
|
||||||
|
self._p = 0
|
||||||
|
self._progress.setValue(self._p)
|
||||||
|
|
||||||
|
def info_compute(self, str):
|
||||||
|
self.statusbar.showMessage(str, 3000)
|
||||||
|
|
||||||
|
def end_compute(self):
|
||||||
|
self._table.layoutChanged.emit()
|
||||||
|
self.find(QPushButton, "pushButton_retry").setEnabled(True)
|
||||||
|
|
||||||
|
errors = any(filter(lambda c: c.is_error(), self._checker_list))
|
||||||
|
if not errors:
|
||||||
|
self.find(QPushButton, "pushButton_ok").setEnabled(True)
|
||||||
|
if self._autorun:
|
||||||
|
self._parent.solver_log_adists(self._solver, self._mage_rep)
|
||||||
|
self.end()
|
||||||
|
|
||||||
|
self.update_statusbar()
|
||||||
|
|
||||||
|
def update(self, key: str):
|
||||||
|
if key == "start":
|
||||||
|
self.start_compute()
|
||||||
|
self.info_compute("Starting ...")
|
||||||
|
elif key == "end":
|
||||||
|
self.info_compute("Finish")
|
||||||
|
self.end_compute()
|
||||||
|
elif key == "progress":
|
||||||
|
self.progress()
|
||||||
|
else:
|
||||||
|
self.info_compute(key)
|
||||||
|
|
||||||
|
self.update_statusbar()
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
# self._worker.join()b
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def reject(self):
|
||||||
|
self.end()
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
self._parent.solver_log_adists(self._solver, self._mage_rep)
|
||||||
|
# self.end()
|
||||||
@@ -46,7 +46,7 @@ class Worker(QObject):
|
|||||||
self.signalStatus.emit(checker.name)
|
self.signalStatus.emit(checker.name)
|
||||||
|
|
||||||
# Run checker
|
# Run checker
|
||||||
checker.run(self._study)
|
checker._run(self._study)
|
||||||
|
|
||||||
self.signalStatus.emit("progress")
|
self.signalStatus.emit("progress")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
# 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.D90AdisTS.UndoCommand import (
|
||||||
|
SetCommand, AddCommand, SetCommandSpec,
|
||||||
|
DelCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, data=None, ic_spec_lst=None, trad=None, parent=None, mode="reaches"):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._mode = mode
|
||||||
|
self._trad = trad
|
||||||
|
self._ic_spec_lst = ic_spec_lst
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
val = []
|
||||||
|
if self._mode == "kp":
|
||||||
|
reach_id = self._ic_spec_lst[index.row()].reach
|
||||||
|
|
||||||
|
reach = next(filter(lambda edge: edge.id == reach_id, self._data.edges()))
|
||||||
|
|
||||||
|
if reach_id is not None:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda kp: str(kp), reach.reach.get_kp()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda n: n.name, self._data.edges()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.addItems(
|
||||||
|
[self._trad['not_associated']] +
|
||||||
|
val
|
||||||
|
)
|
||||||
|
|
||||||
|
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 D90TableModel(PamhyrTableModel):
|
||||||
|
def __init__(self, river=None, data=None, **kwargs):
|
||||||
|
self._river = river
|
||||||
|
|
||||||
|
super(D90TableModel, self).__init__(data=data, **kwargs)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
def _setup_lst(self):
|
||||||
|
self._lst = self._data._data
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "name":
|
||||||
|
n = self._lst[row].name
|
||||||
|
if n is None or n == "":
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "reach":
|
||||||
|
n = self._lst[row].reach
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return next(filter(lambda edge: edge.id == n, self._river.edges())).name
|
||||||
|
elif self._headers[column] is "start_kp":
|
||||||
|
n = self._lst[row].start_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "end_kp":
|
||||||
|
n = self._lst[row].end_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "d90":
|
||||||
|
n = self._lst[row].d90
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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] != "reach":
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self._headers[column] == "reach":
|
||||||
|
print(self._river.edge(value).id)
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], self._river.edge(value).id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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._data, 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._data, self._lst, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# 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.D90AdisTS.UndoCommand import (
|
||||||
|
SetCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
class D90TableDefaultModel(PamhyrTableModel):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(D90TableDefaultModel, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "name":
|
||||||
|
return self._data[row].name
|
||||||
|
elif self._headers[column] is "d90":
|
||||||
|
n = self._data[row].d90
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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._data, 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 undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# 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.D90AdisTS.D90AdisTS import D90AdisTS
|
||||||
|
from Model.D90AdisTS.D90AdisTSList import D90AdisTSList
|
||||||
|
|
||||||
|
|
||||||
|
class SetCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "name":
|
||||||
|
self._old = self._data[self._row].name
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._old = self._data[self._row].d90
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "name":
|
||||||
|
_type = str
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._old
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._data[self._row].d90 = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._new
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._data[self._row].d90 = self._new
|
||||||
|
|
||||||
|
class SetCommandSpec(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "name":
|
||||||
|
self._old = self._data[self._row].name
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._old = self._data[self._row].reach
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._old = self._data[self._row].start_kp
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._old = self._data[self._row].end_kp
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._old = self._data[self._row].d90
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "name":
|
||||||
|
_type = str
|
||||||
|
elif column == "reach":
|
||||||
|
_type = int
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._old
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._old
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._old
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._old
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._data[self._row].d90 = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._new
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._new
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._new
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._new
|
||||||
|
elif self._column == "d90":
|
||||||
|
self._data[self._row].d90 = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._data.delete_i([self._index])
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._data.new(self._index)
|
||||||
|
else:
|
||||||
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._rows = rows
|
||||||
|
#self._data = data
|
||||||
|
|
||||||
|
self._ic = []
|
||||||
|
for row in rows:
|
||||||
|
self._ic.append((row, self._ics_spec[row]))
|
||||||
|
self._ic.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._ic:
|
||||||
|
self._data.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._data.delete_i(self._rows)
|
||||||
|
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
# 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, QIcon,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect, QItemSelectionModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
QVBoxLayout, QToolBar, QAction, QToolButton,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Modules import Modules
|
||||||
|
|
||||||
|
from View.InitialConditionsAdisTS.UndoCommand import (
|
||||||
|
SetCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.D90AdisTS.TableDefault import (
|
||||||
|
D90TableDefaultModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.D90AdisTS.Table import (
|
||||||
|
D90TableModel, ComboBoxDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.D90AdisTS.translate import D90AdisTSTranslate
|
||||||
|
|
||||||
|
from Solver.Mage import Mage8
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class D90AdisTSWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "D90AdisTS"
|
||||||
|
_pamhyr_name = "D90 AdisTS"
|
||||||
|
|
||||||
|
def __init__(self, data=None, study=None, config=None, parent=None):
|
||||||
|
self._data = []
|
||||||
|
self._data.append(data)
|
||||||
|
trad = D90AdisTSTranslate()
|
||||||
|
|
||||||
|
name = (
|
||||||
|
trad[self._pamhyr_name] +
|
||||||
|
" - " + study.name +
|
||||||
|
" - " + self._data[0].name
|
||||||
|
)
|
||||||
|
|
||||||
|
super(D90AdisTSWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._hash_data.append(data)
|
||||||
|
|
||||||
|
self._d90_adists_lst = study.river.d90_adists
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
|
||||||
|
path_icons = os.path.join(self._get_ui_directory(), f"ressources")
|
||||||
|
|
||||||
|
table_default = self.find(QTableView, f"tableView")
|
||||||
|
|
||||||
|
self._table = D90TableDefaultModel(
|
||||||
|
table_view=table_default,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
editable_headers=["name", "d90"],
|
||||||
|
delegates={},
|
||||||
|
data=self._data,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad
|
||||||
|
)
|
||||||
|
|
||||||
|
table_default.setModel(self._table)
|
||||||
|
table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table_default.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table_default.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
layout = self.find(QVBoxLayout, f"verticalLayout_1")
|
||||||
|
toolBar = QToolBar()
|
||||||
|
layout.addWidget(toolBar)
|
||||||
|
|
||||||
|
action_add = QAction(self)
|
||||||
|
action_add.setIcon(QIcon(os.path.join(path_icons, f"add.png")))
|
||||||
|
action_add.triggered.connect(self.add)
|
||||||
|
action_delete = QAction(self)
|
||||||
|
action_delete.setIcon(QIcon(os.path.join(path_icons, f"del.png")))
|
||||||
|
action_delete.triggered.connect(self.delete)
|
||||||
|
|
||||||
|
toolBar.addAction(action_add)
|
||||||
|
toolBar.addAction(action_delete)
|
||||||
|
|
||||||
|
self.table_spec = QTableView()
|
||||||
|
layout.addWidget(self.table_spec)
|
||||||
|
|
||||||
|
self._delegate_reach = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="reaches"
|
||||||
|
)
|
||||||
|
self._delegate_kp = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="kp"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._table_spec = D90TableModel(
|
||||||
|
table_view=self.table_spec,
|
||||||
|
table_headers=self._trad.get_dict("table_headers_spec"),
|
||||||
|
editable_headers=["name", "reach", "start_kp", "end_kp", "d90"],
|
||||||
|
delegates={
|
||||||
|
"reach": self._delegate_reach,
|
||||||
|
"start_kp": self._delegate_kp,
|
||||||
|
"end_kp": self._delegate_kp
|
||||||
|
},
|
||||||
|
data=self._data[0],
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad,
|
||||||
|
river=self._study.river
|
||||||
|
)
|
||||||
|
|
||||||
|
self.table_spec.setModel(self._table_spec)
|
||||||
|
self.table_spec.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.table_spec.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
self.table_spec.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
selectionModel = self.table_spec.selectionModel()
|
||||||
|
index = self.table_spec.model().index(0, 0)
|
||||||
|
|
||||||
|
selectionModel.select(
|
||||||
|
index,
|
||||||
|
QItemSelectionModel.Rows |
|
||||||
|
QItemSelectionModel.ClearAndSelect |
|
||||||
|
QItemSelectionModel.Select
|
||||||
|
)
|
||||||
|
self.table_spec.scrollTo(index)
|
||||||
|
|
||||||
|
def index_selected_row(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
rows = table.selectionModel()\
|
||||||
|
.selectedRows()
|
||||||
|
|
||||||
|
if len(rows) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return rows[0].row()
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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(
|
||||||
|
"D90: 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 add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._data[0]._data) == 0 or len(rows) == 0:
|
||||||
|
self._table_spec.add(0)
|
||||||
|
else:
|
||||||
|
self._table_spec.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
print("del")
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
print("len 0")
|
||||||
|
return
|
||||||
|
self._table_spec.delete(rows)
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# 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 D90AdisTSTranslate(MainTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(D90AdisTSTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["D90 AdisTS"] = _translate(
|
||||||
|
"D90AdisTS", "D90 AdisTS")
|
||||||
|
|
||||||
|
self._dict["kp"] = self._dict["unit_kp"]
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"name": self._dict["name"],
|
||||||
|
"d90": _translate("Unit", "D90"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self._sub_dict["table_headers_spec"] = {
|
||||||
|
"name": self._dict["name"],
|
||||||
|
"reach": self._dict["reach"],
|
||||||
|
"start_kp": _translate("Unit", "Start_KP (m)"),
|
||||||
|
"end_kp": _translate("Unit", "End_KP (m)"),
|
||||||
|
"d90": _translate("Unit", "D90"),
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# 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.DIFAdisTS.UndoCommand import (
|
||||||
|
SetCommand, AddCommand, SetCommandSpec,
|
||||||
|
DelCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, data=None, ic_spec_lst=None, trad=None, parent=None, mode="reaches"):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._mode = mode
|
||||||
|
self._trad = trad
|
||||||
|
self._ic_spec_lst = ic_spec_lst
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
val = []
|
||||||
|
if self._mode == "kp":
|
||||||
|
reach_id = self._ic_spec_lst[index.row()].reach
|
||||||
|
|
||||||
|
reach = next(filter(lambda edge: edge.id == reach_id, self._data.edges()))
|
||||||
|
|
||||||
|
if reach_id is not None:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda kp: str(kp), reach.reach.get_kp()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self._mode == "method":
|
||||||
|
val = self._data.dif_adists.lst[0].types
|
||||||
|
else:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda n: n.name, self._data.edges()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.addItems(
|
||||||
|
[self._trad['not_associated']] +
|
||||||
|
val
|
||||||
|
)
|
||||||
|
|
||||||
|
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 DIFTableModel(PamhyrTableModel):
|
||||||
|
def __init__(self, river=None, data=None, **kwargs):
|
||||||
|
self._river = river
|
||||||
|
|
||||||
|
super(DIFTableModel, self).__init__(data=data, **kwargs)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
def _setup_lst(self):
|
||||||
|
self._lst = self._data._data
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "method":
|
||||||
|
n = self._lst[row].method
|
||||||
|
if n is None or n == "":
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "reach":
|
||||||
|
n = self._lst[row].reach
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return next(filter(lambda edge: edge.id == n, self._river.edges())).name
|
||||||
|
elif self._headers[column] is "start_kp":
|
||||||
|
n = self._lst[row].start_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "end_kp":
|
||||||
|
n = self._lst[row].end_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "dif":
|
||||||
|
n = self._lst[row].dif
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "b":
|
||||||
|
n = self._lst[row].b
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "c":
|
||||||
|
n = self._lst[row].c
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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] != "reach":
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self._headers[column] == "reach":
|
||||||
|
print(self._river.edge(value).id)
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], self._river.edge(value).id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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._data, 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._data, self._lst, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
# 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.DIFAdisTS.UndoCommand import (
|
||||||
|
SetCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
class DIFTableDefaultModel(PamhyrTableModel):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(DIFTableDefaultModel, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "method":
|
||||||
|
n = self._data[row].method
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "dif":
|
||||||
|
n = self._data[row].dif
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "b":
|
||||||
|
n = self._data[row].b
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "c":
|
||||||
|
n = self._data[row].c
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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._data, 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 undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
# 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.DIFAdisTS.DIFAdisTS import DIFAdisTS
|
||||||
|
from Model.DIFAdisTS.DIFAdisTSList import DIFAdisTSList
|
||||||
|
|
||||||
|
|
||||||
|
class SetCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "method":
|
||||||
|
self._old = self._data[self._row].method
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._old = self._data[self._row].dif
|
||||||
|
elif self._column == "b":
|
||||||
|
self._old = self._data[self._row].b
|
||||||
|
elif self._column == "c":
|
||||||
|
self._old = self._data[self._row].c
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "method":
|
||||||
|
_type = str
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "method":
|
||||||
|
self._data[self._row].method = self._old
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._data[self._row].dif = self._old
|
||||||
|
elif self._column == "b":
|
||||||
|
self._data[self._row].b = self._old
|
||||||
|
elif self._column == "c":
|
||||||
|
self._data[self._row].c = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "method":
|
||||||
|
self._data[self._row].method = self._new
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._data[self._row].dif = self._new
|
||||||
|
elif self._column == "b":
|
||||||
|
self._data[self._row].b = self._new
|
||||||
|
elif self._column == "c":
|
||||||
|
self._data[self._row].c = self._new
|
||||||
|
|
||||||
|
class SetCommandSpec(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "method":
|
||||||
|
self._old = self._data[self._row].method
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._old = self._data[self._row].reach
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._old = self._data[self._row].start_kp
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._old = self._data[self._row].end_kp
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._old = self._data[self._row].dif
|
||||||
|
elif self._column == "b":
|
||||||
|
self._old = self._data[self._row].b
|
||||||
|
elif self._column == "c":
|
||||||
|
self._old = self._data[self._row].c
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "method":
|
||||||
|
_type = str
|
||||||
|
elif column == "reach":
|
||||||
|
_type = int
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "method":
|
||||||
|
self._data[self._row].method = self._old
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._old
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._old
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._old
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._data[self._row].dif = self._old
|
||||||
|
elif self._column == "b":
|
||||||
|
self._data[self._row].b = self._old
|
||||||
|
elif self._column == "c":
|
||||||
|
self._data[self._row].c = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "method":
|
||||||
|
self._data[self._row].method = self._new
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._new
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._new
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._new
|
||||||
|
elif self._column == "dif":
|
||||||
|
self._data[self._row].dif = self._new
|
||||||
|
elif self._column == "b":
|
||||||
|
self._data[self._row].b = self._new
|
||||||
|
elif self._column == "c":
|
||||||
|
self._data[self._row].c = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._data.delete_i([self._index])
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._data.new(self._index)
|
||||||
|
else:
|
||||||
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._rows = rows
|
||||||
|
#self._data = data
|
||||||
|
|
||||||
|
self._ic = []
|
||||||
|
for row in rows:
|
||||||
|
self._ic.append((row, self._ics_spec[row]))
|
||||||
|
self._ic.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._ic:
|
||||||
|
self._data.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._data.delete_i(self._rows)
|
||||||
|
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
# 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, QIcon,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect, QItemSelectionModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
QVBoxLayout, QToolBar, QAction, QToolButton,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Modules import Modules
|
||||||
|
|
||||||
|
from View.DIFAdisTS.TableDefault import (
|
||||||
|
DIFTableDefaultModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.DIFAdisTS.Table import (
|
||||||
|
DIFTableModel, ComboBoxDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.DIFAdisTS.translate import DIFAdisTSTranslate
|
||||||
|
|
||||||
|
from Solver.Mage import Mage8
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class DIFAdisTSWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "DIFAdisTS"
|
||||||
|
_pamhyr_name = "DIF AdisTS"
|
||||||
|
|
||||||
|
def __init__(self, data=None, study=None, config=None, parent=None):
|
||||||
|
self._data = []
|
||||||
|
self._data.append(data)
|
||||||
|
trad = DIFAdisTSTranslate()
|
||||||
|
|
||||||
|
name = (
|
||||||
|
trad[self._pamhyr_name] +
|
||||||
|
" - " + study.name +
|
||||||
|
" - " + self._data[0].name
|
||||||
|
)
|
||||||
|
|
||||||
|
super(DIFAdisTSWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._hash_data.append(data)
|
||||||
|
|
||||||
|
self._dif_adists_lst = study.river.dif_adists
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
|
||||||
|
path_icons = os.path.join(self._get_ui_directory(), f"ressources")
|
||||||
|
|
||||||
|
table_default = self.find(QTableView, f"tableView")
|
||||||
|
|
||||||
|
self._delegate_method = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="method"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._table = DIFTableDefaultModel(
|
||||||
|
table_view=table_default,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
editable_headers=["method", "dif", "b", "c"],
|
||||||
|
delegates={
|
||||||
|
"method": self._delegate_method
|
||||||
|
},
|
||||||
|
data=self._data,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad
|
||||||
|
)
|
||||||
|
|
||||||
|
table_default.setModel(self._table)
|
||||||
|
table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table_default.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table_default.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
layout = self.find(QVBoxLayout, f"verticalLayout_1")
|
||||||
|
toolBar = QToolBar()
|
||||||
|
layout.addWidget(toolBar)
|
||||||
|
|
||||||
|
action_add = QAction(self)
|
||||||
|
action_add.setIcon(QIcon(os.path.join(path_icons, f"add.png")))
|
||||||
|
action_add.triggered.connect(self.add)
|
||||||
|
action_delete = QAction(self)
|
||||||
|
action_delete.setIcon(QIcon(os.path.join(path_icons, f"del.png")))
|
||||||
|
action_delete.triggered.connect(self.delete)
|
||||||
|
|
||||||
|
toolBar.addAction(action_add)
|
||||||
|
toolBar.addAction(action_delete)
|
||||||
|
|
||||||
|
self.table_spec = QTableView()
|
||||||
|
layout.addWidget(self.table_spec)
|
||||||
|
|
||||||
|
self._delegate_reach = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="reaches"
|
||||||
|
)
|
||||||
|
self._delegate_kp = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="kp"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._table_spec = DIFTableModel(
|
||||||
|
table_view=self.table_spec,
|
||||||
|
table_headers=self._trad.get_dict("table_headers_spec"),
|
||||||
|
editable_headers=["method", "reach", "start_kp", "end_kp", "dif", "b", "c"],
|
||||||
|
delegates={
|
||||||
|
"method": self._delegate_method,
|
||||||
|
"reach": self._delegate_reach,
|
||||||
|
"start_kp": self._delegate_kp,
|
||||||
|
"end_kp": self._delegate_kp
|
||||||
|
},
|
||||||
|
data=self._data[0],
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad,
|
||||||
|
river=self._study.river
|
||||||
|
)
|
||||||
|
|
||||||
|
self.table_spec.setModel(self._table_spec)
|
||||||
|
self.table_spec.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.table_spec.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
self.table_spec.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
selectionModel = self.table_spec.selectionModel()
|
||||||
|
index = self.table_spec.model().index(0, 0)
|
||||||
|
|
||||||
|
selectionModel.select(
|
||||||
|
index,
|
||||||
|
QItemSelectionModel.Rows |
|
||||||
|
QItemSelectionModel.ClearAndSelect |
|
||||||
|
QItemSelectionModel.Select
|
||||||
|
)
|
||||||
|
self.table_spec.scrollTo(index)
|
||||||
|
|
||||||
|
def index_selected_row(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
rows = table.selectionModel()\
|
||||||
|
.selectedRows()
|
||||||
|
|
||||||
|
if len(rows) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return rows[0].row()
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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(
|
||||||
|
"DIF: 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 add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._data[0]._data) == 0 or len(rows) == 0:
|
||||||
|
self._table_spec.add(0)
|
||||||
|
else:
|
||||||
|
self._table_spec.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
print("del")
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
print("len 0")
|
||||||
|
return
|
||||||
|
self._table_spec.delete(rows)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# 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 DIFAdisTSTranslate(MainTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(DIFAdisTSTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["DIF AdisTS"] = _translate(
|
||||||
|
"DIFAdisTS", "DIF AdisTS")
|
||||||
|
|
||||||
|
self._dict["kp"] = self._dict["unit_kp"]
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"method": self._dict["method"],
|
||||||
|
"dif": _translate("Unit", "DIF"),
|
||||||
|
"b": _translate("Unit", "Coeff b"),
|
||||||
|
"c": _translate("Unit", "Coeff c"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self._sub_dict["table_headers_spec"] = {
|
||||||
|
"method": self._dict["method"],
|
||||||
|
"reach": self._dict["reach"],
|
||||||
|
"start_kp": _translate("Unit", "Start_KP (m)"),
|
||||||
|
"end_kp": _translate("Unit", "End_KP (m)"),
|
||||||
|
"dif": _translate("Unit", "DIF"),
|
||||||
|
"b": _translate("Unit", "Coeff b"),
|
||||||
|
"c": _translate("Unit", "Coeff c"),
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ class PlotStricklers(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.label_x = self._trad["kp"]
|
self.label_x = self._trad["kp"]
|
||||||
self.label_y = self._trad["strickler_plot"]
|
self.label_y = self._trad["stricklers"]
|
||||||
|
|
||||||
self.line_kp_elevation = [None, None]
|
self.line_kp_elevation = [None, None]
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ from View.Frictions.Table import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
from View.Frictions.PlotKPZ import PlotKPZ
|
from View.Geometry.PlotKPZ import PlotKPZ
|
||||||
from View.Frictions.PlotStricklers import PlotStricklers
|
from View.Frictions.PlotStricklers import PlotStricklers
|
||||||
from View.Frictions.translate import FrictionsTranslate
|
from View.Frictions.translate import FrictionsTranslate
|
||||||
|
|
||||||
@@ -135,11 +135,9 @@ class FrictionsWindow(PamhyrWindow):
|
|||||||
|
|
||||||
self.plot = PlotKPZ(
|
self.plot = PlotKPZ(
|
||||||
canvas=self.canvas,
|
canvas=self.canvas,
|
||||||
reach=self._reach,
|
data=self._reach.reach,
|
||||||
river=self._study.river,
|
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=None,
|
toolbar=None,
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
self.plot.draw()
|
self.plot.draw()
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ class FrictionsTranslate(MainTranslate):
|
|||||||
super(FrictionsTranslate, self).__init__()
|
super(FrictionsTranslate, self).__init__()
|
||||||
|
|
||||||
self._dict["kp"] = self._dict["unit_kp"]
|
self._dict["kp"] = self._dict["unit_kp"]
|
||||||
self._dict["strickler_plot"] = _translate(
|
|
||||||
"Frictions", "Strickler ($m^{1/3}/s$)"
|
|
||||||
)
|
|
||||||
self._dict["stricklers"] = _translate(
|
self._dict["stricklers"] = _translate(
|
||||||
"Frictions", "Stricklers"
|
"Frictions", "Stricklers"
|
||||||
)
|
)
|
||||||
@@ -42,8 +39,8 @@ class FrictionsTranslate(MainTranslate):
|
|||||||
self._sub_dict["table_headers"] = {
|
self._sub_dict["table_headers"] = {
|
||||||
# "name": self._dict["name"],
|
# "name": self._dict["name"],
|
||||||
# "edge": self._dict["reach"],
|
# "edge": self._dict["reach"],
|
||||||
"begin_kp": _translate("Frictions", "Start (m)"),
|
"begin_kp": _translate("Frictions", "Begin kp (m)"),
|
||||||
"end_kp": _translate("Frictions", "End (m)"),
|
"end_kp": _translate("Frictions", "End kp (m)"),
|
||||||
"begin_strickler": _translate("Frictions", "Start coefficient"),
|
"begin_strickler": _translate("Frictions", "Begin strickler"),
|
||||||
"end_strickler": _translate("Frictions", "End coefficient"),
|
"end_strickler": _translate("Frictions", "End strickler"),
|
||||||
}
|
}
|
||||||
@@ -125,6 +125,14 @@ class MeshingDialog(PamhyrDialog):
|
|||||||
def lplan(self):
|
def lplan(self):
|
||||||
return self._lplan
|
return self._lplan
|
||||||
|
|
||||||
|
@property
|
||||||
|
def origin(self):
|
||||||
|
return self._origin
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lm(self):
|
||||||
|
return int(self._lm)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def linear(self):
|
def linear(self):
|
||||||
return self._linear
|
return self._linear
|
||||||
@@ -157,9 +165,15 @@ class MeshingDialog(PamhyrDialog):
|
|||||||
self._begin_cs = self.profiles.index(p1)
|
self._begin_cs = self.profiles.index(p1)
|
||||||
self._end_cs = self.profiles.index(p2)
|
self._end_cs = self.profiles.index(p2)
|
||||||
|
|
||||||
|
origin = self.get_combobox_text("comboBox_origin")
|
||||||
|
self._origin = self.profiles.index(origin)
|
||||||
|
|
||||||
self._begin_dir = self.get_combobox_text("comboBox_begin_gl")
|
self._begin_dir = self.get_combobox_text("comboBox_begin_gl")
|
||||||
self._end_dir = self.get_combobox_text("comboBox_end_gl")
|
self._end_dir = self.get_combobox_text("comboBox_end_gl")
|
||||||
|
|
||||||
|
r_lm_dict = self._trad.get_dict("r_lm_dict")
|
||||||
|
self._lm = r_lm_dict[self.get_combobox_text("comboBox_lm")]
|
||||||
|
|
||||||
super().accept()
|
super().accept()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ class PlotAC(PamhyrPlot):
|
|||||||
label=self.label_next_plot_selected,
|
label=self.label_next_plot_selected,
|
||||||
color=self.color_plot_next, lw=1.6, linestyle='--'
|
color=self.color_plot_next, lw=1.6, linestyle='--'
|
||||||
)
|
)
|
||||||
self.canvas.axes.set_visible(False)
|
|
||||||
|
|
||||||
def draw_gl(self):
|
def draw_gl(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
@@ -107,16 +106,12 @@ class PlotAC(PamhyrPlot):
|
|||||||
profile_id = 0
|
profile_id = 0
|
||||||
|
|
||||||
profile = self.data.profile(profile_id)
|
profile = self.data.profile(profile_id)
|
||||||
if profile is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
station = profile.get_station()
|
station = profile.get_station()
|
||||||
elevation = profile.z()
|
elevation = profile.z()
|
||||||
gl = profile.names()
|
gl = profile.names()
|
||||||
|
|
||||||
self.annotation = []
|
self.annotation = []
|
||||||
self.complete_gl, self.incomplete_gl = self.data.compute_guidelines()
|
self.complete_gl, self.incomplete_gl = self.data.compute_guidelines()
|
||||||
|
|
||||||
lcomplete = list(self.complete_gl)
|
lcomplete = list(self.complete_gl)
|
||||||
lincomplete = list(self.incomplete_gl)
|
lincomplete = list(self.incomplete_gl)
|
||||||
|
|
||||||
@@ -165,9 +160,6 @@ class PlotAC(PamhyrPlot):
|
|||||||
self.draw()
|
self.draw()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.data is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.update_current()
|
self.update_current()
|
||||||
self.update_gl()
|
self.update_gl()
|
||||||
|
|
||||||
@@ -179,10 +171,6 @@ class PlotAC(PamhyrPlot):
|
|||||||
previous_id = profile_id - 1
|
previous_id = profile_id - 1
|
||||||
next_id = profile_id + 1
|
next_id = profile_id + 1
|
||||||
|
|
||||||
self.previous_plot_selected.set_visible(False)
|
|
||||||
self.plot_selected.set_visible(False)
|
|
||||||
self.next_plot_selected.set_visible(False)
|
|
||||||
|
|
||||||
self.previous_plot_selected.set_data([], [])
|
self.previous_plot_selected.set_data([], [])
|
||||||
self.plot_selected.set_data([], [])
|
self.plot_selected.set_data([], [])
|
||||||
self.next_plot_selected.set_data([], [])
|
self.next_plot_selected.set_data([], [])
|
||||||
@@ -192,23 +180,18 @@ class PlotAC(PamhyrPlot):
|
|||||||
self.data.profile(previous_id).get_station(),
|
self.data.profile(previous_id).get_station(),
|
||||||
self.data.profile(previous_id).z()
|
self.data.profile(previous_id).z()
|
||||||
)
|
)
|
||||||
self.previous_plot_selected.set_visible(True)
|
|
||||||
|
|
||||||
if 0 <= profile_id < self.data.number_profiles:
|
if 0 <= profile_id < self.data.number_profiles:
|
||||||
self.plot_selected.set_data(
|
self.plot_selected.set_data(
|
||||||
self.data.profile(profile_id).get_station(),
|
self.data.profile(profile_id).get_station(),
|
||||||
self.data.profile(profile_id).z()
|
self.data.profile(profile_id).z()
|
||||||
)
|
)
|
||||||
self.plot_selected.set_visible(True)
|
|
||||||
|
|
||||||
if 0 <= next_id < self.data.number_profiles:
|
if 0 <= next_id < self.data.number_profiles:
|
||||||
self.next_plot_selected.set_data(
|
self.next_plot_selected.set_data(
|
||||||
self.data.profile(next_id).get_station(),
|
self.data.profile(next_id).get_station(),
|
||||||
self.data.profile(next_id).z()
|
self.data.profile(next_id).z()
|
||||||
)
|
)
|
||||||
self.next_plot_selected.set_visible(True)
|
|
||||||
|
|
||||||
self.canvas.axes.set_visible(True)
|
|
||||||
|
|
||||||
def update_full(self):
|
def update_full(self):
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|||||||
+132
-201
@@ -20,11 +20,6 @@ import logging
|
|||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
from PyQt5.QtCore import (
|
|
||||||
Qt, QItemSelectionModel,
|
|
||||||
QItemSelection, QItemSelectionRange,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -32,7 +27,7 @@ logger = logging.getLogger()
|
|||||||
class PlotKPZ(PamhyrPlot):
|
class PlotKPZ(PamhyrPlot):
|
||||||
def __init__(self, canvas=None, trad=None,
|
def __init__(self, canvas=None, trad=None,
|
||||||
study=None, data=None, toolbar=None,
|
study=None, data=None, toolbar=None,
|
||||||
table=None, parent=None):
|
parent=None):
|
||||||
self._study = study
|
self._study = study
|
||||||
|
|
||||||
super(PlotKPZ, self).__init__(
|
super(PlotKPZ, self).__init__(
|
||||||
@@ -40,7 +35,6 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
trad=trad,
|
trad=trad,
|
||||||
data=data,
|
data=data,
|
||||||
toolbar=toolbar,
|
toolbar=toolbar,
|
||||||
table=table,
|
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,111 +51,6 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
self.before_plot_selected = None
|
self.before_plot_selected = None
|
||||||
self.plot_selected = None
|
self.plot_selected = None
|
||||||
self.after_plot_selected = None
|
self.after_plot_selected = None
|
||||||
self.parent = parent
|
|
||||||
self._table = table
|
|
||||||
self._colors = []
|
|
||||||
|
|
||||||
def onpick(self, event):
|
|
||||||
if event.mouseevent.inaxes != self.canvas.axes:
|
|
||||||
return
|
|
||||||
if event.mouseevent.button.value != 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
if modifiers not in [Qt.ControlModifier,
|
|
||||||
Qt.NoModifier,
|
|
||||||
Qt.ShiftModifier]:
|
|
||||||
return
|
|
||||||
|
|
||||||
ind, point = self._closest_kp(event)
|
|
||||||
if self.parent._table is None:
|
|
||||||
return
|
|
||||||
self.parent._table.blockSignals(True)
|
|
||||||
if modifiers == Qt.ControlModifier:
|
|
||||||
rows = list(
|
|
||||||
set(
|
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ind in rows:
|
|
||||||
rows.remove(ind)
|
|
||||||
else:
|
|
||||||
rows.append(ind)
|
|
||||||
self._select_in_table(rows)
|
|
||||||
elif modifiers == Qt.ShiftModifier:
|
|
||||||
rows = sorted(list(
|
|
||||||
set(
|
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
|
||||||
)
|
|
||||||
))
|
|
||||||
if len(rows) > 0:
|
|
||||||
i1 = min(rows[0], rows[-1], ind)
|
|
||||||
i2 = max(rows[0], rows[-1], ind)
|
|
||||||
else:
|
|
||||||
i1 = ind
|
|
||||||
i2 = ind
|
|
||||||
self._select_range_in_table(i1, i2)
|
|
||||||
else:
|
|
||||||
self._select_in_table([ind])
|
|
||||||
self.parent._table.blockSignals(False)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _closest_kp(self, event):
|
|
||||||
|
|
||||||
s = event.artist.get_segments()
|
|
||||||
x = [i[0, 0] for i in s]
|
|
||||||
mx = event.mouseevent.xdata
|
|
||||||
points = enumerate(x)
|
|
||||||
|
|
||||||
def dist_mouse(point):
|
|
||||||
x = point[1]
|
|
||||||
d = abs(mx - x)
|
|
||||||
return d
|
|
||||||
|
|
||||||
closest = min(
|
|
||||||
points, key=dist_mouse
|
|
||||||
)
|
|
||||||
|
|
||||||
return closest
|
|
||||||
|
|
||||||
def _select_in_table(self, ind):
|
|
||||||
if self._table is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._table.setFocus()
|
|
||||||
selection = self._table.selectionModel()
|
|
||||||
index = QItemSelection()
|
|
||||||
|
|
||||||
if len(ind) == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
for i in ind:
|
|
||||||
index.append(QItemSelectionRange(self._table.model().index(i, 0)))
|
|
||||||
|
|
||||||
selection.select(
|
|
||||||
index,
|
|
||||||
QItemSelectionModel.Rows |
|
|
||||||
QItemSelectionModel.ClearAndSelect |
|
|
||||||
QItemSelectionModel.Select
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(ind) > 0:
|
|
||||||
self._table.scrollTo(self._table.model().index(ind[-1], 0))
|
|
||||||
|
|
||||||
def _select_range_in_table(self, ind1, ind2):
|
|
||||||
if self._table is not None:
|
|
||||||
self._table.setFocus()
|
|
||||||
selection = self._table.selectionModel()
|
|
||||||
index = QItemSelection(self._table.model().index(ind1, 0),
|
|
||||||
self._table.model().index(ind2, 0))
|
|
||||||
selection.select(
|
|
||||||
index,
|
|
||||||
QItemSelectionModel.Rows |
|
|
||||||
QItemSelectionModel.ClearAndSelect |
|
|
||||||
QItemSelectionModel.Select
|
|
||||||
)
|
|
||||||
self._table.scrollTo(self._table.model().index(ind2, 0))
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def draw(self):
|
def draw(self):
|
||||||
@@ -185,7 +74,8 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.draw_z_line()
|
self.draw_z_line()
|
||||||
self.draw_lr()
|
self.draw_z_line_highlight()
|
||||||
|
self.draw_current()
|
||||||
self.draw_gl()
|
self.draw_gl()
|
||||||
self.draw_bottom()
|
self.draw_bottom()
|
||||||
self.draw_profiles_hs(self._data)
|
self.draw_profiles_hs(self._data)
|
||||||
@@ -198,60 +88,76 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
z_min = self.data.get_z_min()
|
z_min = self.data.get_z_min()
|
||||||
z_max = self.data.get_z_max()
|
z_max = self.data.get_z_max()
|
||||||
|
|
||||||
self._colors, self._style = self.color_hightlight()
|
|
||||||
|
|
||||||
self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
||||||
x=kp, ymin=z_min, ymax=z_max,
|
x=kp, ymin=z_min, ymax=z_max,
|
||||||
color=self._colors,
|
color=self.color_plot,
|
||||||
linestyle=self._style,
|
lw=1.
|
||||||
lw=1.,
|
|
||||||
picker=10,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def color_hightlight(self):
|
def draw_z_line_highlight(self):
|
||||||
rows = sorted(list(
|
if self._highlight_data is not None:
|
||||||
set(
|
kp = self.data.get_kp_complete_profiles()
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
z_min = self.data.get_z_min()
|
||||||
|
z_max = self.data.get_z_max()
|
||||||
|
|
||||||
|
kp_min, kp_max = self._highlight_data
|
||||||
|
|
||||||
|
indexes = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[0],
|
||||||
|
filter(
|
||||||
|
lambda x: kp_min <= x[1] <= kp_max,
|
||||||
|
enumerate(kp)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
))
|
|
||||||
colors = [self.color_plot for row in range(len(self._data))]
|
|
||||||
style = ["-" for row in range(len(self._data))]
|
|
||||||
if len(rows) > 0:
|
|
||||||
for row in rows:
|
|
||||||
colors[row] = self.color_plot_current
|
|
||||||
if rows[0] > 0:
|
|
||||||
colors[rows[0]-1] = self.color_plot_previous
|
|
||||||
style[rows[0]-1] = "--"
|
|
||||||
if rows[-1] < len(self._data)-1:
|
|
||||||
colors[rows[-1]+1] = self.color_plot_next
|
|
||||||
style[rows[-1]+1] = "--"
|
|
||||||
return colors, style
|
|
||||||
|
|
||||||
def draw_lr(self):
|
def indexes_filter(data): return list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
ikp = indexes_filter(kp)
|
||||||
|
imin = indexes_filter(z_min)
|
||||||
|
imax = indexes_filter(z_max)
|
||||||
|
|
||||||
|
self.line_kp_zmin_zmax_highlight = self.canvas.axes.vlines(
|
||||||
|
x=ikp,
|
||||||
|
ymin=imin, ymax=imax,
|
||||||
|
color=self.color_plot_highlight,
|
||||||
|
lw=1.
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_current(self):
|
||||||
kp = self.data.get_kp_complete_profiles()
|
kp = self.data.get_kp_complete_profiles()
|
||||||
lz = []
|
z_min = self.data.get_z_min()
|
||||||
rz = []
|
z_max = self.data.get_z_max()
|
||||||
|
|
||||||
self.line_lr = []
|
self.plot_selected, = self.canvas.axes.plot(
|
||||||
for z in self.data.get_z():
|
(kp[0], kp[0]),
|
||||||
lz.append(z[0])
|
(z_min[0], z_max[0]),
|
||||||
rz.append(z[-1])
|
color=self.color_plot_current, lw=1.5
|
||||||
|
|
||||||
line = self.canvas.axes.plot(
|
|
||||||
kp, lz,
|
|
||||||
color=self.color_plot_river_bottom,
|
|
||||||
linestyle="dotted",
|
|
||||||
lw=1.,
|
|
||||||
)
|
)
|
||||||
self.line_lr.append(line)
|
self.plot_selected.set_visible(False)
|
||||||
|
|
||||||
line = self.canvas.axes.plot(
|
self.before_plot_selected, = self.canvas.axes.plot(
|
||||||
kp, rz,
|
(kp[0], kp[0]),
|
||||||
color=self.color_plot_river_bottom,
|
(z_min[0], z_max[0]),
|
||||||
linestyle="dotted",
|
color=self.color_plot_previous, lw=1.5, linestyle='--'
|
||||||
lw=1.,
|
|
||||||
)
|
)
|
||||||
self.line_lr.append(line)
|
self.before_plot_selected.set_visible(False)
|
||||||
|
|
||||||
|
self.after_plot_selected, = self.canvas.axes.plot(
|
||||||
|
(kp[0], kp[0]),
|
||||||
|
(z_min[0], z_max[0]),
|
||||||
|
color=self.color_plot_next, lw=1.5, linestyle='--'
|
||||||
|
)
|
||||||
|
self.after_plot_selected.set_visible(False)
|
||||||
|
|
||||||
def draw_gl(self):
|
def draw_gl(self):
|
||||||
kp = self.data.get_kp_complete_profiles()
|
kp = self.data.get_kp_complete_profiles()
|
||||||
@@ -285,34 +191,30 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
def draw_profiles_hs(self, reach):
|
def draw_profiles_hs(self, reach):
|
||||||
lhs = filter(
|
lhs = filter(
|
||||||
lambda hs: hs._input_reach.reach is reach,
|
lambda hs: hs._input_reach.reach is reach,
|
||||||
filter(
|
self._study.river.hydraulic_structures.lst
|
||||||
lambda hs: hs._input_reach is not None,
|
|
||||||
self._study.river.hydraulic_structures.lst
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for hs in lhs:
|
for hs in lhs:
|
||||||
x = hs.input_kp
|
x = hs.input_kp
|
||||||
if x is not None:
|
z_min = reach.get_z_min()
|
||||||
z_min = reach.get_z_min()
|
z_max = reach.get_z_max()
|
||||||
z_max = reach.get_z_max()
|
|
||||||
|
|
||||||
self.canvas.axes.plot(
|
self.canvas.axes.plot(
|
||||||
[x, x],
|
[x, x],
|
||||||
[min(z_min), max(z_max)],
|
[min(z_min), max(z_max)],
|
||||||
linestyle="--",
|
linestyle="--",
|
||||||
lw=1.,
|
lw=1.,
|
||||||
color=self.color_plot_previous,
|
color=self.color_plot_previous,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.canvas.axes.annotate(
|
self.canvas.axes.annotate(
|
||||||
" > " + hs.name,
|
" > " + hs.name,
|
||||||
(x, max(z_max)),
|
(x, max(z_max)),
|
||||||
horizontalalignment='left',
|
horizontalalignment='left',
|
||||||
verticalalignment='top',
|
verticalalignment='top',
|
||||||
annotation_clip=True,
|
annotation_clip=True,
|
||||||
fontsize=9, color=self.color_plot_previous,
|
fontsize=9, color=self.color_plot_previous,
|
||||||
)
|
)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self):
|
def update(self):
|
||||||
@@ -320,7 +222,6 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
self.draw()
|
self.draw()
|
||||||
return
|
return
|
||||||
|
|
||||||
self.update_lr()
|
|
||||||
self.update_gl()
|
self.update_gl()
|
||||||
self.update_current()
|
self.update_current()
|
||||||
|
|
||||||
@@ -328,9 +229,52 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
|
|
||||||
def update_current(self):
|
def update_current(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
self._colors, self._style = self.color_hightlight()
|
ind = self._current_data
|
||||||
self.line_kp_zmin_zmax.set_colors(self._colors)
|
before = ind - 1
|
||||||
self.line_kp_zmin_zmax.set_linestyle(self._style)
|
after = ind + 1
|
||||||
|
|
||||||
|
self.before_plot_selected.set_visible(False)
|
||||||
|
self.plot_selected.set_visible(False)
|
||||||
|
self.after_plot_selected.set_visible(False)
|
||||||
|
|
||||||
|
if 0 <= before < self.data.number_profiles:
|
||||||
|
profile = self.data.profile(before)
|
||||||
|
if len(profile) > 0:
|
||||||
|
kp_i = profile.kp
|
||||||
|
z_min_i = profile.z_min()
|
||||||
|
z_max_i = profile.z_max()
|
||||||
|
|
||||||
|
self.before_plot_selected.set_data(
|
||||||
|
(kp_i, kp_i),
|
||||||
|
(z_min_i, z_max_i)
|
||||||
|
)
|
||||||
|
self.before_plot_selected.set_visible(True)
|
||||||
|
|
||||||
|
if 0 <= ind < self.data.number_profiles:
|
||||||
|
profile = self.data.profile(ind)
|
||||||
|
if len(profile) > 0:
|
||||||
|
kp_i = profile.kp
|
||||||
|
z_min_i = profile.z_min()
|
||||||
|
z_max_i = profile.z_max()
|
||||||
|
|
||||||
|
self.plot_selected.set_data(
|
||||||
|
(kp_i, kp_i),
|
||||||
|
(z_min_i, z_max_i)
|
||||||
|
)
|
||||||
|
self.plot_selected.set_visible(True)
|
||||||
|
|
||||||
|
if 0 <= after < self.data.number_profiles:
|
||||||
|
profile = self.data.profile(after)
|
||||||
|
if len(profile) > 0:
|
||||||
|
kp_i = profile.kp
|
||||||
|
z_min_i = profile.z_min()
|
||||||
|
z_max_i = profile.z_max()
|
||||||
|
|
||||||
|
self.after_plot_selected.set_data(
|
||||||
|
(kp_i, kp_i),
|
||||||
|
(z_min_i, z_max_i)
|
||||||
|
)
|
||||||
|
self.after_plot_selected.set_visible(True)
|
||||||
|
|
||||||
def update_gl(self):
|
def update_gl(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
@@ -342,19 +286,12 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
|
|
||||||
self.line_kp_zmin.set_data(kp, z_min)
|
self.line_kp_zmin.set_data(kp, z_min)
|
||||||
|
|
||||||
# TODO comprendre à quoi sert ce bout de code
|
self.line_kp_zmin_zmax.remove()
|
||||||
# ========>
|
self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
||||||
# self.line_kp_zmin_zmax.remove()
|
x=kp,
|
||||||
# self._colors, self._style = self.color_hightlight()
|
ymin=z_min, ymax=z_max,
|
||||||
# self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
color='r', lw=1.
|
||||||
# x=kp,
|
)
|
||||||
# ymin=z_min,
|
|
||||||
# ymax=z_max,
|
|
||||||
# color=self._colors,
|
|
||||||
# linestyle = self._style,
|
|
||||||
# lw=1.
|
|
||||||
# )
|
|
||||||
# <========
|
|
||||||
|
|
||||||
z_complete = self.data.get_guidelines_z()
|
z_complete = self.data.get_guidelines_z()
|
||||||
try:
|
try:
|
||||||
@@ -364,9 +301,3 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to update graphic KPZ: {e}")
|
logger.warning(f"Failed to update graphic KPZ: {e}")
|
||||||
|
|
||||||
def update_lr(self):
|
|
||||||
for line in self.line_lr:
|
|
||||||
line[0].remove()
|
|
||||||
|
|
||||||
self.draw_lr()
|
|
||||||
+90
-167
@@ -18,27 +18,22 @@
|
|||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
from matplotlib import collections
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
QCoreApplication, Qt, QItemSelectionModel,
|
QCoreApplication
|
||||||
QItemSelection, QItemSelectionRange,
|
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class PlotXY(PamhyrPlot):
|
class PlotXY(PamhyrPlot):
|
||||||
def __init__(self, canvas=None, trad=None, data=None, toolbar=None,
|
def __init__(self, canvas=None, trad=None, data=None, toolbar=None,
|
||||||
table=None, parent=None):
|
parent=None):
|
||||||
super(PlotXY, self).__init__(
|
super(PlotXY, self).__init__(
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
trad=trad,
|
trad=trad,
|
||||||
data=data,
|
data=data,
|
||||||
toolbar=toolbar,
|
toolbar=toolbar,
|
||||||
table=table,
|
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,116 +46,6 @@ class PlotXY(PamhyrPlot):
|
|||||||
self.before_plot_selected = None
|
self.before_plot_selected = None
|
||||||
self.plot_selected = None
|
self.plot_selected = None
|
||||||
self.after_plot_selected = None
|
self.after_plot_selected = None
|
||||||
self.parent = parent
|
|
||||||
self.line_xy_collection = None
|
|
||||||
self._table = table
|
|
||||||
self._colors = []
|
|
||||||
self._style = []
|
|
||||||
|
|
||||||
def onpick(self, event):
|
|
||||||
if event.mouseevent.inaxes != self.canvas.axes:
|
|
||||||
return
|
|
||||||
if event.mouseevent.button.value != 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
if modifiers not in [Qt.ControlModifier,
|
|
||||||
Qt.NoModifier,
|
|
||||||
Qt.ShiftModifier]:
|
|
||||||
return
|
|
||||||
|
|
||||||
ind, point = self._closest_section(event)
|
|
||||||
if self._table is None:
|
|
||||||
return
|
|
||||||
self._table.blockSignals(True)
|
|
||||||
if modifiers == Qt.ControlModifier:
|
|
||||||
rows = list(
|
|
||||||
set(
|
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ind in rows:
|
|
||||||
rows.remove(ind)
|
|
||||||
self._select_in_table(rows)
|
|
||||||
else:
|
|
||||||
self._select_in_table(rows + [ind])
|
|
||||||
elif modifiers == Qt.ShiftModifier:
|
|
||||||
rows = list(
|
|
||||||
set(
|
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if len(rows) > 0:
|
|
||||||
i1 = min(rows[0], rows[-1], ind)
|
|
||||||
i2 = max(rows[0], rows[-1], ind)
|
|
||||||
else:
|
|
||||||
i1 = ind
|
|
||||||
i2 = ind
|
|
||||||
self._select_range_in_table(i1, i2)
|
|
||||||
else:
|
|
||||||
self._select_in_table([ind])
|
|
||||||
self._table.blockSignals(False)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _closest_section(self, event):
|
|
||||||
axes = self.canvas.axes
|
|
||||||
mx = event.mouseevent.xdata
|
|
||||||
my = event.mouseevent.ydata
|
|
||||||
bx, by = axes.get_xlim(), axes.get_ylim()
|
|
||||||
ratio = (bx[0] - bx[1]) / (by[0] - by[1])
|
|
||||||
|
|
||||||
segments = event.artist.get_segments()
|
|
||||||
ind = event.ind
|
|
||||||
|
|
||||||
points = []
|
|
||||||
for i in ind:
|
|
||||||
points = points + [[i, j] for j in segments[i]]
|
|
||||||
|
|
||||||
def dist_mouse(point):
|
|
||||||
x, y = point[1]
|
|
||||||
d2 = (((mx - x) / ratio) ** 2) + ((my - y) ** 2)
|
|
||||||
return d2
|
|
||||||
|
|
||||||
closest = min(
|
|
||||||
points, key=dist_mouse
|
|
||||||
)
|
|
||||||
|
|
||||||
return closest
|
|
||||||
|
|
||||||
def _select_in_table(self, ind):
|
|
||||||
if self._table is None:
|
|
||||||
return
|
|
||||||
self._table.setFocus()
|
|
||||||
selection = self._table.selectionModel()
|
|
||||||
index = QItemSelection()
|
|
||||||
if len(ind) == 0:
|
|
||||||
return
|
|
||||||
for i in ind:
|
|
||||||
index.append(QItemSelectionRange(self._table.model().index(i, 0)))
|
|
||||||
selection.select(
|
|
||||||
index,
|
|
||||||
QItemSelectionModel.Rows |
|
|
||||||
QItemSelectionModel.ClearAndSelect |
|
|
||||||
QItemSelectionModel.Select
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(ind) > 0:
|
|
||||||
self._table.scrollTo(self._table.model().index(ind[-1], 0))
|
|
||||||
|
|
||||||
def _select_range_in_table(self, ind1, ind2):
|
|
||||||
if self._table is not None:
|
|
||||||
self._table.setFocus()
|
|
||||||
selection = self._table.selectionModel()
|
|
||||||
index = QItemSelection(self._table.model().index(ind1, 0),
|
|
||||||
self._table.model().index(ind2, 0))
|
|
||||||
selection.select(
|
|
||||||
index,
|
|
||||||
QItemSelectionModel.Rows |
|
|
||||||
QItemSelectionModel.ClearAndSelect |
|
|
||||||
QItemSelectionModel.Select
|
|
||||||
)
|
|
||||||
self._table.scrollTo(self._table.model().index(ind2, 0))
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def draw(self):
|
def draw(self):
|
||||||
@@ -178,42 +63,33 @@ class PlotXY(PamhyrPlot):
|
|||||||
self.draw_xy()
|
self.draw_xy()
|
||||||
self.draw_lr()
|
self.draw_lr()
|
||||||
self.draw_gl()
|
self.draw_gl()
|
||||||
|
self.draw_current()
|
||||||
|
|
||||||
self.idle()
|
self.idle()
|
||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
def draw_xy(self):
|
def draw_xy(self):
|
||||||
|
kp = self.data.get_kp_complete_profiles()
|
||||||
|
|
||||||
|
kp_min, kp_max = (-1, -1)
|
||||||
|
if self._highlight_data is not None:
|
||||||
|
kp_min, kp_max = self._highlight_data
|
||||||
|
|
||||||
|
def color_hightlight(kp):
|
||||||
|
if kp_min <= kp <= kp_max:
|
||||||
|
return self.color_plot_highlight
|
||||||
|
return self.color_plot
|
||||||
|
|
||||||
self.line_xy = []
|
self.line_xy = []
|
||||||
for xy in zip(self.data.get_x(), self.data.get_y()):
|
for x, y, kp in zip(self.data.get_x(),
|
||||||
self.line_xy.append(np.column_stack(xy))
|
self.data.get_y(),
|
||||||
|
kp):
|
||||||
self._colors, self._style = self.color_hightlight()
|
line = self.canvas.axes.plot(
|
||||||
self.line_xy_collection = collections.LineCollection(
|
x, y,
|
||||||
self.line_xy,
|
color=color_hightlight(kp),
|
||||||
colors=self._colors,
|
**self.plot_default_kargs
|
||||||
linestyle=self._style,
|
|
||||||
picker=10
|
|
||||||
)
|
|
||||||
self.canvas.axes.add_collection(self.line_xy_collection)
|
|
||||||
|
|
||||||
def color_hightlight(self):
|
|
||||||
rows = sorted(list(
|
|
||||||
set(
|
|
||||||
(i.row() for i in self.parent.tableView.selectedIndexes())
|
|
||||||
)
|
)
|
||||||
))
|
self.line_xy.append(line)
|
||||||
colors = [self.color_plot for row in range(len(self._data))]
|
|
||||||
style = ["-" for row in range(len(self._data))]
|
|
||||||
if len(rows) > 0:
|
|
||||||
for row in rows:
|
|
||||||
colors[row] = self.color_plot_current
|
|
||||||
if rows[0] > 0:
|
|
||||||
colors[rows[0]-1] = self.color_plot_previous
|
|
||||||
style[rows[0]-1] = "--"
|
|
||||||
if rows[-1] < len(self._data)-1:
|
|
||||||
colors[rows[-1]+1] = self.color_plot_next
|
|
||||||
style[rows[-1]+1] = "--"
|
|
||||||
return colors, style
|
|
||||||
|
|
||||||
def draw_lr(self):
|
def draw_lr(self):
|
||||||
lx = []
|
lx = []
|
||||||
@@ -260,6 +136,33 @@ class PlotXY(PamhyrPlot):
|
|||||||
self.line_gl.append(line)
|
self.line_gl.append(line)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
|
def draw_current(self):
|
||||||
|
# Previous profile
|
||||||
|
self.before_plot_selected, = self.canvas.axes.plot(
|
||||||
|
self.data.profile(0).x(),
|
||||||
|
self.data.profile(0).y(),
|
||||||
|
color=self.color_plot_previous, linestyle="--",
|
||||||
|
**self.plot_default_kargs
|
||||||
|
)
|
||||||
|
self.before_plot_selected.set_visible(False)
|
||||||
|
|
||||||
|
# Current profile
|
||||||
|
self.plot_selected, = self.canvas.axes.plot(
|
||||||
|
self.data.profile(0).x(),
|
||||||
|
self.data.profile(0).y(),
|
||||||
|
color=self.color_plot_current, **self.plot_default_kargs
|
||||||
|
)
|
||||||
|
self.plot_selected.set_visible(False)
|
||||||
|
|
||||||
|
# Next profile
|
||||||
|
self.after_plot_selected, = self.canvas.axes.plot(
|
||||||
|
self.data.profile(0).x(),
|
||||||
|
self.data.profile(0).y(),
|
||||||
|
color=self.color_plot_next, linestyle='--',
|
||||||
|
**self.plot_default_kargs
|
||||||
|
)
|
||||||
|
self.after_plot_selected.set_visible(False)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self):
|
def update(self):
|
||||||
if not self._init:
|
if not self._init:
|
||||||
@@ -280,24 +183,21 @@ class PlotXY(PamhyrPlot):
|
|||||||
x_complete = list(self.data.get_guidelines_x())
|
x_complete = list(self.data.get_guidelines_x())
|
||||||
y_complete = list(self.data.get_guidelines_y())
|
y_complete = list(self.data.get_guidelines_y())
|
||||||
|
|
||||||
# TODO comprendre à quoi sert ce bout de code
|
for i in range(self.data.number_profiles):
|
||||||
# ========>
|
if i < len(self.line_xy):
|
||||||
# for i in range(self.data.number_profiles):
|
self.line_xy[i][0].set_data(
|
||||||
# if i < len(self.line_xy):
|
self.data.profile(i).x(),
|
||||||
# self.line_xy[i][0].set_data(
|
self.data.profile(i).y()
|
||||||
# self.data.profile(i).x(),
|
)
|
||||||
# self.data.profile(i).y()
|
else:
|
||||||
# )
|
self.line_xy.append(
|
||||||
# else:
|
self.canvas.axes.plot(
|
||||||
# self.line_xy.append(
|
self.data.profile(i).x(),
|
||||||
# self.canvas.axes.plot(
|
self.data.profile(i).y(),
|
||||||
# self.data.profile(i).x(),
|
color='r',
|
||||||
# self.data.profile(i).y(),
|
**self.plot_default_kargs
|
||||||
# color='r',
|
)
|
||||||
# **self.plot_default_kargs
|
)
|
||||||
# )
|
|
||||||
# )
|
|
||||||
# <========
|
|
||||||
|
|
||||||
for i in range(len(x_complete)):
|
for i in range(len(x_complete)):
|
||||||
if i < len(self.line_gl):
|
if i < len(self.line_gl):
|
||||||
@@ -315,9 +215,32 @@ class PlotXY(PamhyrPlot):
|
|||||||
|
|
||||||
def update_current(self):
|
def update_current(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
self._colors, self._style = self.color_hightlight()
|
ind = self._current_data
|
||||||
self.line_xy_collection.set_colors(self._colors)
|
before = ind - 1
|
||||||
self.line_xy_collection.set_linestyle(self._style)
|
after = ind + 1
|
||||||
|
|
||||||
|
self.before_plot_selected.set_visible(False)
|
||||||
|
self.plot_selected.set_visible(False)
|
||||||
|
self.after_plot_selected.set_visible(False)
|
||||||
|
|
||||||
|
if 0 <= before < self.data.number_profiles:
|
||||||
|
self.before_plot_selected.set_data(
|
||||||
|
self.data.profile(before).x(),
|
||||||
|
self.data.profile(before).y()
|
||||||
|
)
|
||||||
|
self.before_plot_selected.set_visible(True)
|
||||||
|
|
||||||
|
if 0 <= ind < self.data.number_profiles:
|
||||||
|
self.plot_selected.set_data(self.data.profile(ind).x(),
|
||||||
|
self.data.profile(ind).y())
|
||||||
|
self.plot_selected.set_visible(True)
|
||||||
|
|
||||||
|
if 0 <= after < self.data.number_profiles:
|
||||||
|
self.after_plot_selected.set_data(
|
||||||
|
self.data.profile(after).x(),
|
||||||
|
self.data.profile(after).y()
|
||||||
|
)
|
||||||
|
self.after_plot_selected.set_visible(True)
|
||||||
|
|
||||||
def update_lr(self):
|
def update_lr(self):
|
||||||
for line in self.line_lr:
|
for line in self.line_lr:
|
||||||
|
|||||||
@@ -24,12 +24,10 @@ from tools import timer, trace
|
|||||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt, QCoreApplication, QItemSelectionModel,
|
Qt, QCoreApplication, QItemSelectionModel
|
||||||
QItemSelection, QItemSelectionRange,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication
|
||||||
from matplotlib.widgets import RectangleSelector
|
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
@@ -48,7 +46,6 @@ class Plot(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._table = table
|
self._table = table
|
||||||
self._parent = parent
|
|
||||||
self._z_note = None
|
self._z_note = None
|
||||||
self._z_line = None
|
self._z_line = None
|
||||||
self._z_fill_between = None
|
self._z_fill_between = None
|
||||||
@@ -71,86 +68,40 @@ class Plot(PamhyrPlot):
|
|||||||
None # Hydrolic values (z, wet_area,
|
None # Hydrolic values (z, wet_area,
|
||||||
# wet_preimeter, water_width)
|
# wet_preimeter, water_width)
|
||||||
)
|
)
|
||||||
self._onpickevent = None
|
|
||||||
self._rect_select = RectangleSelector(
|
|
||||||
ax=self.canvas.axes,
|
|
||||||
onselect=self.rect_select_callback,
|
|
||||||
useblit=True,
|
|
||||||
button=[1], # don't use middle nor right button
|
|
||||||
minspanx=2.0,
|
|
||||||
minspany=2.0,
|
|
||||||
spancoords='pixels',
|
|
||||||
interactive=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def onrelease(self, event):
|
|
||||||
# we need to do that to prevent conflicst
|
|
||||||
# between onpick and rect_select_callback
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
points, hyd = self.highlight
|
|
||||||
if self._onpickevent is not None:
|
|
||||||
ind, point = self._closest_point(self._onpickevent)
|
|
||||||
if modifiers == Qt.ControlModifier:
|
|
||||||
rows = self._parent.index_selected_rows()
|
|
||||||
if ind in rows:
|
|
||||||
rows.remove(ind)
|
|
||||||
del (points[ind])
|
|
||||||
self.highlight = (points, hyd)
|
|
||||||
self._select_in_table(rows)
|
|
||||||
else:
|
|
||||||
self.highlight = (points+[point], hyd)
|
|
||||||
self._select_in_table(rows+[ind])
|
|
||||||
elif modifiers == Qt.ShiftModifier:
|
|
||||||
rows = self._parent.index_selected_rows()
|
|
||||||
if len(rows) > 0:
|
|
||||||
i1 = min(rows[0], rows[-1], ind)
|
|
||||||
i2 = max(rows[0], rows[-1], ind)
|
|
||||||
p = [
|
|
||||||
[self.data.points[i].x, self.data.points[i].y]
|
|
||||||
for i in range(i1, i2)
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
i1 = ind
|
|
||||||
i2 = ind
|
|
||||||
p = [point]
|
|
||||||
self.highlight = (p, hyd)
|
|
||||||
self._select_range_in_table(i1, i2)
|
|
||||||
else:
|
|
||||||
self.highlight = ([point], hyd)
|
|
||||||
self._select_in_table([ind])
|
|
||||||
|
|
||||||
self._onpickevent = None
|
|
||||||
|
|
||||||
def onpick(self, event):
|
def onpick(self, event):
|
||||||
if event.mouseevent.inaxes != self.canvas.axes:
|
if event.mouseevent.inaxes != self.canvas.axes:
|
||||||
return
|
return
|
||||||
if event.mouseevent.button.value != 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
modifiers = QApplication.keyboardModifiers()
|
||||||
if modifiers not in [Qt.ControlModifier,
|
if modifiers != Qt.ControlModifier:
|
||||||
Qt.NoModifier,
|
|
||||||
Qt.ShiftModifier]:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self._onpickevent = event
|
_, hyd = self.highlight
|
||||||
|
|
||||||
|
ind, point = self._closer_point(event)
|
||||||
|
|
||||||
|
self.highlight = ([point], hyd)
|
||||||
|
self._select_in_table(ind)
|
||||||
|
|
||||||
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
def onclick(self, event):
|
def onclick(self, event):
|
||||||
if event.inaxes != self.canvas.axes:
|
if event.inaxes != self.canvas.axes:
|
||||||
return
|
return
|
||||||
if event.button.value == 1:
|
|
||||||
|
modifiers = QApplication.keyboardModifiers()
|
||||||
|
if modifiers != Qt.ShiftModifier:
|
||||||
return
|
return
|
||||||
|
|
||||||
points, _ = self.highlight
|
points, _ = self.highlight
|
||||||
|
|
||||||
z = self._get_z_from_click(event)
|
z = self._get_z_from_click(event)
|
||||||
if z < self.data.z_min() or event.button.value == 2:
|
if z < self.data.z_min():
|
||||||
self.highlight = (points, None)
|
|
||||||
self.update()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
a, p, w = self._compute_hydraulics(z)
|
a, p, w = self._compute_hydrolics(z)
|
||||||
|
|
||||||
logger.debug(f"{z, a, p, w}")
|
logger.debug(f"{z, a, p, w}")
|
||||||
|
|
||||||
@@ -159,7 +110,7 @@ class Plot(PamhyrPlot):
|
|||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
def select_points_from_indices(self, indices):
|
def select_points_from_indexes(self, indexes):
|
||||||
data = self.data
|
data = self.data
|
||||||
_, hyd = self.highlight
|
_, hyd = self.highlight
|
||||||
|
|
||||||
@@ -167,7 +118,7 @@ class Plot(PamhyrPlot):
|
|||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1],
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] in indices,
|
lambda e: e[0] in indexes,
|
||||||
enumerate(
|
enumerate(
|
||||||
zip(data.get_station(), data.z())
|
zip(data.get_station(), data.z())
|
||||||
)
|
)
|
||||||
@@ -182,13 +133,9 @@ class Plot(PamhyrPlot):
|
|||||||
if self._table is not None:
|
if self._table is not None:
|
||||||
self._table.blockSignals(True)
|
self._table.blockSignals(True)
|
||||||
self._table.setFocus()
|
self._table.setFocus()
|
||||||
|
|
||||||
selection = self._table.selectionModel()
|
selection = self._table.selectionModel()
|
||||||
index = QItemSelection()
|
index = self._table.model().index(ind, 0)
|
||||||
if len(ind) > 0:
|
|
||||||
for i in ind:
|
|
||||||
index.append(QItemSelectionRange(
|
|
||||||
self._table.model().index(i, 0))
|
|
||||||
)
|
|
||||||
selection.select(
|
selection.select(
|
||||||
index,
|
index,
|
||||||
QItemSelectionModel.Rows |
|
QItemSelectionModel.Rows |
|
||||||
@@ -196,27 +143,10 @@ class Plot(PamhyrPlot):
|
|||||||
QItemSelectionModel.Select
|
QItemSelectionModel.Select
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(ind) > 0:
|
self._table.scrollTo(index)
|
||||||
self._table.scrollTo(self._table.model().index(ind[-1], 0))
|
|
||||||
self._table.blockSignals(False)
|
self._table.blockSignals(False)
|
||||||
|
|
||||||
def _select_range_in_table(self, ind1, ind2):
|
def _closer_point(self, event):
|
||||||
if self._table is not None:
|
|
||||||
self._table.blockSignals(True)
|
|
||||||
self._table.setFocus()
|
|
||||||
selection = self._table.selectionModel()
|
|
||||||
index = QItemSelection(self._table.model().index(ind1, 0),
|
|
||||||
self._table.model().index(ind2, 0))
|
|
||||||
selection.select(
|
|
||||||
index,
|
|
||||||
QItemSelectionModel.Rows |
|
|
||||||
QItemSelectionModel.ClearAndSelect |
|
|
||||||
QItemSelectionModel.Select
|
|
||||||
)
|
|
||||||
self._table.scrollTo(self._table.model().index(ind2, 0))
|
|
||||||
self._table.blockSignals(False)
|
|
||||||
|
|
||||||
def _closest_point(self, event):
|
|
||||||
points_ind = event.ind
|
points_ind = event.ind
|
||||||
axes = self.canvas.axes
|
axes = self.canvas.axes
|
||||||
bx, by = axes.get_xlim(), axes.get_ylim()
|
bx, by = axes.get_xlim(), axes.get_ylim()
|
||||||
@@ -236,62 +166,22 @@ class Plot(PamhyrPlot):
|
|||||||
|
|
||||||
def dist_mouse(point):
|
def dist_mouse(point):
|
||||||
x, y = point[1]
|
x, y = point[1]
|
||||||
d2 = ((mx - x) / ratio) ** 2 + ((my - y) ** 2)
|
d = sqrt(
|
||||||
return d2
|
(((mx - x) / ratio) ** 2) +
|
||||||
|
((my - y) ** 2)
|
||||||
|
)
|
||||||
|
return d
|
||||||
|
|
||||||
closest = min(
|
closer = min(
|
||||||
points, key=dist_mouse
|
points, key=dist_mouse
|
||||||
)
|
)
|
||||||
|
|
||||||
return closest
|
return closer
|
||||||
|
|
||||||
def _get_z_from_click(self, event):
|
def _get_z_from_click(self, event):
|
||||||
return event.ydata
|
return event.ydata
|
||||||
|
|
||||||
def rect_select_callback(self, eclick, erelease):
|
def _compute_hydrolics(self, z):
|
||||||
|
|
||||||
points, hyd = self.highlight
|
|
||||||
x1, y1 = eclick.xdata, eclick.ydata
|
|
||||||
x2, y2 = erelease.xdata, erelease.ydata
|
|
||||||
|
|
||||||
if (max(abs(x1-x2), abs(y1-y2)) < 0.001):
|
|
||||||
return
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
|
|
||||||
x1, y1 = eclick.xdata, eclick.ydata
|
|
||||||
x2, y2 = erelease.xdata, erelease.ydata
|
|
||||||
|
|
||||||
inds, points2 = self._points_in_rectangle(x1, y1, x2, y2)
|
|
||||||
self._onclickevent = None
|
|
||||||
if modifiers == Qt.ControlModifier:
|
|
||||||
rows = self._parent.index_selected_rows()
|
|
||||||
if all(i in rows for i in inds):
|
|
||||||
for ind in sorted(inds, reverse=True):
|
|
||||||
rows.remove(ind)
|
|
||||||
del (points[ind])
|
|
||||||
self.highlight = (points, hyd)
|
|
||||||
self._select_in_table(rows)
|
|
||||||
else:
|
|
||||||
self.highlight = (points+points2, hyd)
|
|
||||||
self._select_in_table(rows+inds)
|
|
||||||
else:
|
|
||||||
self.highlight = (points2, hyd)
|
|
||||||
self._select_in_table(inds)
|
|
||||||
return
|
|
||||||
|
|
||||||
def _points_in_rectangle(self, x1, y1, x2, y2):
|
|
||||||
# TODO: use lambdas
|
|
||||||
listi = []
|
|
||||||
listp = []
|
|
||||||
station = self.data._get_station(self.data.points)
|
|
||||||
for i, p in enumerate(self.data.points):
|
|
||||||
if (min(x1, x2) < station[i] < max(x1, x2)
|
|
||||||
and min(y1, y2) < p.z < max(y1, y2)):
|
|
||||||
listi.append(i)
|
|
||||||
listp.append((station[i], p.z))
|
|
||||||
return listi, listp
|
|
||||||
|
|
||||||
def _compute_hydraulics(self, z):
|
|
||||||
profile = self.data
|
profile = self.data
|
||||||
|
|
||||||
points = profile.wet_points(z)
|
points = profile.wet_points(z)
|
||||||
@@ -320,7 +210,7 @@ class Plot(PamhyrPlot):
|
|||||||
self.profile_line2D, = self.canvas.axes.plot(
|
self.profile_line2D, = self.canvas.axes.plot(
|
||||||
x, y, color=self.color_plot,
|
x, y, color=self.color_plot,
|
||||||
lw=1.5, markersize=7, marker='+',
|
lw=1.5, markersize=7, marker='+',
|
||||||
picker=10
|
picker=30
|
||||||
)
|
)
|
||||||
|
|
||||||
self.draw_annotation(x, y)
|
self.draw_annotation(x, y)
|
||||||
@@ -379,16 +269,12 @@ class Plot(PamhyrPlot):
|
|||||||
x, y,
|
x, y,
|
||||||
color=self.color_plot_highlight,
|
color=self.color_plot_highlight,
|
||||||
lw=1.5, markersize=7, marker='+',
|
lw=1.5, markersize=7, marker='+',
|
||||||
|
picker=30
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if hyd is not None:
|
if hyd is not None:
|
||||||
self.draw_highligth_z_line(*hyd)
|
self.draw_highligth_z_line(*hyd)
|
||||||
else:
|
|
||||||
if self._z_note is not None:
|
|
||||||
self._z_note.set_visible(False)
|
|
||||||
self._z_line[0].set_visible(False)
|
|
||||||
self._z_fill_between.set_visible(False)
|
|
||||||
|
|
||||||
def draw_highligth_z_line(self, z, a, p, w):
|
def draw_highligth_z_line(self, z, a, p, w):
|
||||||
text = (
|
text = (
|
||||||
@@ -413,7 +299,6 @@ class Plot(PamhyrPlot):
|
|||||||
xlim, [z, z],
|
xlim, [z, z],
|
||||||
color=self.color_plot_river_water
|
color=self.color_plot_river_water
|
||||||
)
|
)
|
||||||
self._z_line[0].set_visible(True)
|
|
||||||
|
|
||||||
self._z_note = self.canvas.axes.annotate(
|
self._z_note = self.canvas.axes.annotate(
|
||||||
text, pos,
|
text, pos,
|
||||||
@@ -425,15 +310,12 @@ class Plot(PamhyrPlot):
|
|||||||
fontweight='bold',
|
fontweight='bold',
|
||||||
alpha=0.7
|
alpha=0.7
|
||||||
)
|
)
|
||||||
self._z_note.set_visible(True)
|
|
||||||
else:
|
else:
|
||||||
self.draw_highligth_z_line_fill(x, y, z)
|
self.draw_highligth_z_line_fill(x, y, z)
|
||||||
|
|
||||||
self._z_line[0].set_data(xlim, [z, z])
|
self._z_line[0].set_data(xlim, [z, z])
|
||||||
self._z_note.set_position(pos)
|
self._z_note.set_position(pos)
|
||||||
self._z_note.set_text(text)
|
self._z_note.set_text(text)
|
||||||
self._z_line[0].set_visible(True)
|
|
||||||
self._z_note.set_visible(True)
|
|
||||||
|
|
||||||
def draw_highligth_z_line_fill(self, x, y, z):
|
def draw_highligth_z_line_fill(self, x, y, z):
|
||||||
if self._z_fill_between is not None:
|
if self._z_fill_between is not None:
|
||||||
|
|||||||
@@ -82,6 +82,16 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
|||||||
elif value == self._data.z_max():
|
elif value == self._data.z_max():
|
||||||
return QColor("blue")
|
return QColor("blue")
|
||||||
|
|
||||||
|
if role == Qt.ToolTipRole:
|
||||||
|
if value == self._data.z_min():
|
||||||
|
return _translate("MainWindowProfile",
|
||||||
|
"La cote du fond",
|
||||||
|
"Z minimale")
|
||||||
|
elif value == self._data.z_max():
|
||||||
|
return _translate("MainWindowProfile",
|
||||||
|
"La cote maximale",
|
||||||
|
"Z maximale")
|
||||||
|
|
||||||
if index.column() == 3:
|
if index.column() == 3:
|
||||||
value = self._data.point(index.row()).name
|
value = self._data.point(index.row()).name
|
||||||
|
|
||||||
@@ -94,6 +104,16 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
|||||||
if role == Qt.ForegroundRole:
|
if role == Qt.ForegroundRole:
|
||||||
return QColor("darkRed")
|
return QColor("darkRed")
|
||||||
|
|
||||||
|
if role == Qt.ToolTipRole:
|
||||||
|
if value.strip().upper() == "RG":
|
||||||
|
return _translate(
|
||||||
|
"MainWindowProfile", "Rive gauche"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return _translate(
|
||||||
|
"MainWindowProfile", "Rive droite"
|
||||||
|
)
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
@@ -230,11 +250,11 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
|||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def purge(self, np_purge):
|
def purge(self):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
PurgeCommand(
|
PurgeCommand(
|
||||||
self._data, np_purge
|
self._data, 24
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,8 @@ import copy
|
|||||||
import sys
|
import sys
|
||||||
import csv
|
import csv
|
||||||
from time import time
|
from time import time
|
||||||
import logging
|
|
||||||
|
|
||||||
from tools import trace, timer, logger_exception
|
from tools import trace, timer
|
||||||
from Modules import Modules
|
from Modules import Modules
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
@@ -47,12 +46,9 @@ from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
|||||||
from View.Geometry.Profile.Plot import Plot
|
from View.Geometry.Profile.Plot import Plot
|
||||||
from View.Geometry.Profile.Table import GeometryProfileTableModel
|
from View.Geometry.Profile.Table import GeometryProfileTableModel
|
||||||
from View.Geometry.Profile.Translate import GeometryProfileTranslate
|
from View.Geometry.Profile.Translate import GeometryProfileTranslate
|
||||||
from View.Geometry.PurgeDialog import PurgeDialog
|
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
logger = logging.getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileWindow(PamhyrWindow):
|
class ProfileWindow(PamhyrWindow):
|
||||||
_pamhyr_ui = "GeometryCrossSection"
|
_pamhyr_ui = "GeometryCrossSection"
|
||||||
@@ -115,8 +111,7 @@ class ProfileWindow(PamhyrWindow):
|
|||||||
data=self._profile,
|
data=self._profile,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=self._toolbar,
|
toolbar=self._toolbar,
|
||||||
table=self.find(QTableView, "tableView"),
|
table=self.find(QTableView, "tableView")
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
self._plot.draw()
|
self._plot.draw()
|
||||||
|
|
||||||
@@ -147,7 +142,7 @@ class ProfileWindow(PamhyrWindow):
|
|||||||
|
|
||||||
def update_points_selection(self):
|
def update_points_selection(self):
|
||||||
rows = self.index_selected_rows()
|
rows = self.index_selected_rows()
|
||||||
self._plot.select_points_from_indices(rows)
|
self._plot.select_points_from_indexes(rows)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.update_plot()
|
self.update_plot()
|
||||||
@@ -170,6 +165,7 @@ class ProfileWindow(PamhyrWindow):
|
|||||||
if Modules.GEOMETRY not in key:
|
if Modules.GEOMETRY not in key:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.debug("TOTO")
|
||||||
self._tablemodel.layoutChanged.emit()
|
self._tablemodel.layoutChanged.emit()
|
||||||
self._update(redraw=True, propagate=False)
|
self._update(redraw=True, propagate=False)
|
||||||
|
|
||||||
@@ -262,19 +258,6 @@ class ProfileWindow(PamhyrWindow):
|
|||||||
self._tablemodel.purge()
|
self._tablemodel.purge()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def purge(self):
|
|
||||||
try:
|
|
||||||
dlg = PurgeDialog(
|
|
||||||
trad=self._trad,
|
|
||||||
parent=self
|
|
||||||
)
|
|
||||||
if dlg.exec():
|
|
||||||
self._tablemodel.purge(dlg.np_purge)
|
|
||||||
self._plot.draw()
|
|
||||||
except Exception as e:
|
|
||||||
logger_exception(e)
|
|
||||||
return
|
|
||||||
|
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
self._tablemodel.reverse()
|
self._tablemodel.reverse()
|
||||||
self.update()
|
self.update()
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
# PurgeDialog.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 (
|
|
||||||
QUndoStack, QShortcut, QSpinBox,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class PurgeDialog(PamhyrDialog):
|
|
||||||
_pamhyr_ui = "PurgeOptions"
|
|
||||||
_pamhyr_name = "Purge"
|
|
||||||
|
|
||||||
def __init__(self, trad=None, parent=None):
|
|
||||||
super(PurgeDialog, self).__init__(
|
|
||||||
title=trad[self._pamhyr_name],
|
|
||||||
trad=trad,
|
|
||||||
options=[],
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
|
|
||||||
self._init_default_values()
|
|
||||||
|
|
||||||
def _init_default_values(self):
|
|
||||||
self._np_purge = 24
|
|
||||||
|
|
||||||
@property
|
|
||||||
def np_purge(self):
|
|
||||||
return self._np_purge
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
self._np_purge = self.get_spin_box("spinBox_np_purge")
|
|
||||||
super().accept()
|
|
||||||
|
|
||||||
def reject(self):
|
|
||||||
self.close()
|
|
||||||
@@ -259,11 +259,11 @@ class GeometryReachTableModel(PamhyrTableModel):
|
|||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def purge(self, np_purge):
|
def purge(self):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
PurgeCommand(
|
PurgeCommand(
|
||||||
self._data, np_purge
|
self._data, 24
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
@@ -33,12 +33,12 @@ class GeometryTranslate(MainTranslate):
|
|||||||
|
|
||||||
self._dict["open_file"] = _translate("Geometry", "Open a file")
|
self._dict["open_file"] = _translate("Geometry", "Open a file")
|
||||||
self._dict["file_st"] = _translate(
|
self._dict["file_st"] = _translate(
|
||||||
"Geometry", "Mage geometry file (*.ST *.st)")
|
"Geometry", "File mage geometry (*.ST *.st)")
|
||||||
self._dict["file_m"] = _translate(
|
self._dict["file_m"] = _translate(
|
||||||
"Geometry", "Mage meshed geometry file (*.M *.m)")
|
"Geometry", "File mage meshed geometry (*.M *.m)")
|
||||||
self._dict["file_shp"] = _translate(
|
self._dict["file_shp"] = _translate(
|
||||||
"Geometry", "Shapefile (*.SHP *.shp)")
|
"Geometry", "Shapefile (*.SHP *.shp)")
|
||||||
self._dict["file_all"] = _translate("Geometry", "All files (*)")
|
self._dict["file_all"] = _translate("Geometry", "All file (*)")
|
||||||
|
|
||||||
self._dict["cross_section"] = _translate("Geometry", "cross-section")
|
self._dict["cross_section"] = _translate("Geometry", "cross-section")
|
||||||
self._dict["cross_sections"] = _translate("Geometry", "cross-sections")
|
self._dict["cross_sections"] = _translate("Geometry", "cross-sections")
|
||||||
@@ -70,7 +70,7 @@ class GeometryTranslate(MainTranslate):
|
|||||||
"2": _translate("Geometry", "the second guide-line"),
|
"2": _translate("Geometry", "the second guide-line"),
|
||||||
"3": _translate(
|
"3": _translate(
|
||||||
"Geometry",
|
"Geometry",
|
||||||
"the mean over the two guide-lines"
|
"the means between the two guide-lines"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# UpdateKPDialog.py -- Pamhyr
|
# MeshingDialog.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2024 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -28,7 +28,7 @@ from PyQt5.QtCore import (
|
|||||||
|
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QDialogButtonBox, QComboBox, QUndoStack, QShortcut,
|
QDialogButtonBox, QComboBox, QUndoStack, QShortcut,
|
||||||
QDoubleSpinBox, QButtonGroup,
|
QDoubleSpinBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -50,20 +50,14 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
self._init_default_values()
|
self._init_default_values()
|
||||||
|
|
||||||
def _init_default_values(self):
|
def _init_default_values(self):
|
||||||
gl, _ = self._reach.compute_guidelines()
|
self._space_step = 50.0
|
||||||
self._gl = list(gl)
|
self._lplan = False
|
||||||
|
self._lm = "3"
|
||||||
|
self._linear = False
|
||||||
|
self._begin_cs = -1
|
||||||
|
self._end_cs = -1
|
||||||
self._begin_dir = "un"
|
self._begin_dir = "un"
|
||||||
self._end_dir = "np"
|
self._end_dir = "np"
|
||||||
|
|
||||||
lower_gl = list(map(str.lower, self._gl))
|
|
||||||
for i, gl in enumerate(lower_gl):
|
|
||||||
if gl == "rd":
|
|
||||||
self._begin_dir = self._gl[i]
|
|
||||||
elif gl == "rg":
|
|
||||||
self._end_dir = self._gl[i]
|
|
||||||
|
|
||||||
self._orientation = 0
|
|
||||||
self._origin = self._reach.profile(0)
|
self._origin = self._reach.profile(0)
|
||||||
self._origin_value = self._reach.profile(0).kp
|
self._origin_value = self._reach.profile(0).kp
|
||||||
|
|
||||||
@@ -75,19 +69,8 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
|
|
||||||
self.combobox_add_items("comboBox_origin", profiles)
|
self.combobox_add_items("comboBox_origin", profiles)
|
||||||
|
|
||||||
self.find(QComboBox, "comboBox_origin")\
|
self.find(QComboBox, "comboBox_origin").currentIndexChanged.connect(
|
||||||
.currentIndexChanged\
|
self.changed_profile)
|
||||||
.connect(
|
|
||||||
self.changed_profile
|
|
||||||
)
|
|
||||||
|
|
||||||
buttonbox = self.find(QButtonGroup, "buttonGroup_orientation")
|
|
||||||
|
|
||||||
for button in buttonbox.buttons():
|
|
||||||
name = button.objectName()
|
|
||||||
i = int(name.split('_')[-1])
|
|
||||||
|
|
||||||
buttonbox.setId(button, i)
|
|
||||||
|
|
||||||
def changed_profile(self):
|
def changed_profile(self):
|
||||||
origin = self.get_combobox_text("comboBox_origin")
|
origin = self.get_combobox_text("comboBox_origin")
|
||||||
@@ -119,8 +102,11 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
def _init_default_values_guidelines(self):
|
def _init_default_values_guidelines(self):
|
||||||
bgl = ['un'] + self._gl + ['np']
|
gl, _ = self._reach.compute_guidelines()
|
||||||
egl = ['un'] + self._gl + ['np']
|
gl = list(gl)
|
||||||
|
|
||||||
|
bgl = ['un'] + gl + ['np']
|
||||||
|
egl = ['un'] + gl + ['np']
|
||||||
|
|
||||||
self.combobox_add_items("comboBox_begin_gl", bgl)
|
self.combobox_add_items("comboBox_begin_gl", bgl)
|
||||||
self.combobox_add_items("comboBox_end_gl", egl)
|
self.combobox_add_items("comboBox_end_gl", egl)
|
||||||
@@ -128,10 +114,6 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
self.set_combobox_text("comboBox_begin_gl", self._begin_dir)
|
self.set_combobox_text("comboBox_begin_gl", self._begin_dir)
|
||||||
self.set_combobox_text("comboBox_end_gl", self._end_dir)
|
self.set_combobox_text("comboBox_end_gl", self._end_dir)
|
||||||
|
|
||||||
@property
|
|
||||||
def orientation(self):
|
|
||||||
return self._orientation
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def origin(self):
|
def origin(self):
|
||||||
return self._origin
|
return self._origin
|
||||||
@@ -151,12 +133,11 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
def accept(self):
|
def accept(self):
|
||||||
origin = self.get_combobox_text("comboBox_origin")
|
origin = self.get_combobox_text("comboBox_origin")
|
||||||
self._origin = self.profiles.index(origin)
|
self._origin = self.profiles.index(origin)
|
||||||
|
|
||||||
self._origin_value = self.get_double_spin_box("doubleSpinBox_origin")
|
self._origin_value = self.get_double_spin_box("doubleSpinBox_origin")
|
||||||
|
|
||||||
self._begin_dir = self.get_combobox_text("comboBox_begin_gl")
|
self._begin_dir = self.get_combobox_text("comboBox_begin_gl")
|
||||||
self._end_dir = self.get_combobox_text("comboBox_end_gl")
|
self._end_dir = self.get_combobox_text("comboBox_end_gl")
|
||||||
self._orientation = self.get_checked_id_button_group(
|
|
||||||
"buttonGroup_orientation"
|
|
||||||
)
|
|
||||||
|
|
||||||
super().accept()
|
super().accept()
|
||||||
|
|
||||||
|
|||||||
+66
-40
@@ -36,7 +36,7 @@ from PyQt5.QtCore import (
|
|||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication, QMainWindow, QFileDialog, QCheckBox,
|
QApplication, QMainWindow, QFileDialog, QCheckBox,
|
||||||
QUndoStack, QShortcut, QTableView, QHeaderView,
|
QUndoStack, QShortcut, QTableView, QHeaderView,
|
||||||
QAction, QPushButton, QVBoxLayout,
|
QAction, QSlider, QPushButton, QVBoxLayout,
|
||||||
QLabel, QAbstractItemView,
|
QLabel, QAbstractItemView,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,7 +57,6 @@ from View.Geometry.PlotAC import PlotAC
|
|||||||
from View.Geometry.PlotKPZ import PlotKPZ
|
from View.Geometry.PlotKPZ import PlotKPZ
|
||||||
from View.Geometry.MeshingDialog import MeshingDialog
|
from View.Geometry.MeshingDialog import MeshingDialog
|
||||||
from View.Geometry.UpdateKPDialog import UpdateKPDialog
|
from View.Geometry.UpdateKPDialog import UpdateKPDialog
|
||||||
from View.Geometry.PurgeDialog import PurgeDialog
|
|
||||||
from View.Geometry.Translate import GeometryTranslate
|
from View.Geometry.Translate import GeometryTranslate
|
||||||
from View.Geometry.Profile.Window import ProfileWindow
|
from View.Geometry.Profile.Window import ProfileWindow
|
||||||
|
|
||||||
@@ -97,6 +96,7 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self.setup_plots()
|
self.setup_plots()
|
||||||
self.setup_statusbar()
|
self.setup_statusbar()
|
||||||
self.setup_connections()
|
self.setup_connections()
|
||||||
|
self.changed_slider_value()
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table_headers = self._trad.get_dict("table_headers")
|
table_headers = self._trad.get_dict("table_headers")
|
||||||
@@ -157,9 +157,6 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
|
|
||||||
def _compute_status_label(self):
|
def _compute_status_label(self):
|
||||||
row = self.index_selected_row()
|
row = self.index_selected_row()
|
||||||
if row is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
profile = self._reach.profile(row)
|
profile = self._reach.profile(row)
|
||||||
|
|
||||||
name = profile.name + " " + str(profile.kp)
|
name = profile.name + " " + str(profile.kp)
|
||||||
@@ -200,6 +197,13 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self.find(QAction, action)\
|
self.find(QAction, action)\
|
||||||
.triggered.connect(actions[action])
|
.triggered.connect(actions[action])
|
||||||
|
|
||||||
|
self.find(QSlider, "verticalSlider").valueChanged.connect(
|
||||||
|
self.changed_slider_value)
|
||||||
|
self.find(QPushButton, "pushButton_up").clicked.connect(
|
||||||
|
self.decrement_value_slider)
|
||||||
|
self.find(QPushButton, "pushButton_down").clicked.connect(
|
||||||
|
self.increment_value_slider)
|
||||||
|
|
||||||
# Profile selection when line change in table
|
# Profile selection when line change in table
|
||||||
self.find(QTableView, "tableView").selectionModel()\
|
self.find(QTableView, "tableView").selectionModel()\
|
||||||
.selectionChanged\
|
.selectionChanged\
|
||||||
@@ -220,6 +224,7 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self._plot_ac.draw()
|
self._plot_ac.draw()
|
||||||
|
|
||||||
self.select_current_profile()
|
self.select_current_profile()
|
||||||
|
self.changed_slider_value()
|
||||||
|
|
||||||
if propagate:
|
if propagate:
|
||||||
self._propagate_update(key=Modules.GEOMETRY)
|
self._propagate_update(key=Modules.GEOMETRY)
|
||||||
@@ -293,8 +298,10 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
data = {
|
data = {
|
||||||
"step": dlg.space_step,
|
"step": dlg.space_step,
|
||||||
"limites": [dlg.begin_cs, dlg.end_cs],
|
"limites": [dlg.begin_cs, dlg.end_cs],
|
||||||
|
"origin": dlg.origin,
|
||||||
"directrices": [dlg.begin_dir, dlg.end_dir],
|
"directrices": [dlg.begin_dir, dlg.end_dir],
|
||||||
"lplan": dlg.lplan,
|
"lplan": dlg.lplan,
|
||||||
|
"lm": dlg.lm,
|
||||||
"linear": dlg.linear,
|
"linear": dlg.linear,
|
||||||
}
|
}
|
||||||
self._edit_meshing(data)
|
self._edit_meshing(data)
|
||||||
@@ -327,7 +334,6 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
"origin": dlg.origin,
|
"origin": dlg.origin,
|
||||||
"directrices": [dlg.begin_dir, dlg.end_dir],
|
"directrices": [dlg.begin_dir, dlg.end_dir],
|
||||||
"origin_value": dlg.origin_value,
|
"origin_value": dlg.origin_value,
|
||||||
"orientation": dlg.orientation,
|
|
||||||
}
|
}
|
||||||
self._update_kp(data)
|
self._update_kp(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -354,9 +360,7 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
canvas=self._canvas_xy,
|
canvas=self._canvas_xy,
|
||||||
data=self._reach,
|
data=self._reach,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=self._toolbar_xy,
|
toolbar=self._toolbar_xy
|
||||||
table=self.find(QTableView, "tableView"),
|
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
self._plot_xy.draw()
|
self._plot_xy.draw()
|
||||||
|
|
||||||
@@ -375,9 +379,7 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
study=self._study,
|
study=self._study,
|
||||||
data=self._reach,
|
data=self._reach,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=self._toolbar_kpc,
|
toolbar=self._toolbar_kpc
|
||||||
table=self.find(QTableView, "tableView"),
|
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
self._plot_kpc.draw()
|
self._plot_kpc.draw()
|
||||||
|
|
||||||
@@ -403,6 +405,7 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
|
|
||||||
def update_plot_ac(self, ind: int):
|
def update_plot_ac(self, ind: int):
|
||||||
self.tableView.model().blockSignals(True)
|
self.tableView.model().blockSignals(True)
|
||||||
|
self._plot_ac.current = ind
|
||||||
self._plot_ac.update()
|
self._plot_ac.update()
|
||||||
self.tableView.model().blockSignals(False)
|
self.tableView.model().blockSignals(False)
|
||||||
|
|
||||||
@@ -430,11 +433,27 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self._plot_ac.update()
|
self._plot_ac.update()
|
||||||
self.tableView.model().blockSignals(False)
|
self.tableView.model().blockSignals(False)
|
||||||
|
|
||||||
|
def select_row_profile_slider(self, ind: int = 0):
|
||||||
|
if self.tableView is not None:
|
||||||
|
selectionModel = self.tableView.selectionModel()
|
||||||
|
index = self.tableView.model().index(ind, 0)
|
||||||
|
|
||||||
|
selectionModel.select(
|
||||||
|
index,
|
||||||
|
QItemSelectionModel.Rows |
|
||||||
|
QItemSelectionModel.ClearAndSelect |
|
||||||
|
QItemSelectionModel.Select
|
||||||
|
)
|
||||||
|
|
||||||
|
self.tableView.scrollTo(index)
|
||||||
|
|
||||||
def select_current_profile(self):
|
def select_current_profile(self):
|
||||||
self.tableView.model().blockSignals(True)
|
self.tableView.model().blockSignals(True)
|
||||||
row = self.index_selected_row()
|
|
||||||
|
|
||||||
if row is not None:
|
if len(self.tableView.selectedIndexes()) > 0:
|
||||||
|
row = self.index_selected_row()
|
||||||
|
|
||||||
|
self.find(QSlider, "verticalSlider").setValue(row)
|
||||||
self.select_plot_xy(row)
|
self.select_plot_xy(row)
|
||||||
self.select_plot_kpc(row)
|
self.select_plot_kpc(row)
|
||||||
self.select_plot_ac(row)
|
self.select_plot_ac(row)
|
||||||
@@ -445,6 +464,33 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
|
|
||||||
self.tableView.model().blockSignals(False)
|
self.tableView.model().blockSignals(False)
|
||||||
|
|
||||||
|
def changed_slider_value(self):
|
||||||
|
self.tableView.model().blockSignals(True)
|
||||||
|
|
||||||
|
if self._table.rowCount() != 0:
|
||||||
|
slider = self.find(QSlider, "verticalSlider")
|
||||||
|
slider.setMaximum(self._table.rowCount() - 1)
|
||||||
|
|
||||||
|
slider_value = slider.value()
|
||||||
|
kp = self._reach.profile(slider_value).kp
|
||||||
|
|
||||||
|
self.select_plot_xy(slider_value)
|
||||||
|
self.select_plot_kpc(slider_value)
|
||||||
|
self.select_row_profile_slider(slider_value)
|
||||||
|
self.update_statusbar()
|
||||||
|
|
||||||
|
self.tableView.model().blockSignals(False)
|
||||||
|
|
||||||
|
def increment_value_slider(self):
|
||||||
|
slider = self.find(QSlider, "verticalSlider")
|
||||||
|
if 0 <= slider.value() < self._table.rowCount() - 1:
|
||||||
|
slider.setValue(slider.value() + 1)
|
||||||
|
|
||||||
|
def decrement_value_slider(self):
|
||||||
|
slider = self.find(QSlider, "verticalSlider")
|
||||||
|
if 0 < slider.value() < self._table.rowCount():
|
||||||
|
slider.setValue(slider.value() - 1)
|
||||||
|
|
||||||
def add(self):
|
def add(self):
|
||||||
if len(self.tableView.selectedIndexes()) == 0:
|
if len(self.tableView.selectedIndexes()) == 0:
|
||||||
self._table.add(self._table.rowCount())
|
self._table.add(self._table.rowCount())
|
||||||
@@ -465,37 +511,29 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self._table.delete(rows)
|
self._table.delete(rows)
|
||||||
|
|
||||||
def index_selected_row(self):
|
def index_selected_row(self):
|
||||||
r = self.tableView\
|
return self.tableView\
|
||||||
.selectionModel()\
|
.selectionModel()\
|
||||||
.selectedRows()
|
.selectedRows()[0]\
|
||||||
|
.row()
|
||||||
if len(r) == 1:
|
|
||||||
return r[0].row()
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def sort_ascending(self):
|
def sort_ascending(self):
|
||||||
self._table.sort_profiles(False)
|
self._table.sort_profiles(False)
|
||||||
self.select_current_profile()
|
self.select_current_profile()
|
||||||
|
self.changed_slider_value()
|
||||||
|
|
||||||
def sort_descending(self):
|
def sort_descending(self):
|
||||||
self._table.sort_profiles(True)
|
self._table.sort_profiles(True)
|
||||||
|
|
||||||
self.select_current_profile()
|
self.select_current_profile()
|
||||||
|
self.changed_slider_value()
|
||||||
|
|
||||||
def move_up(self):
|
def move_up(self):
|
||||||
row = self.index_selected_row()
|
row = self.index_selected_row()
|
||||||
if row is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._table.move_up(row)
|
self._table.move_up(row)
|
||||||
self.select_current_profile()
|
self.select_current_profile()
|
||||||
|
|
||||||
def move_down(self):
|
def move_down(self):
|
||||||
row = self.index_selected_row()
|
row = self.index_selected_row()
|
||||||
if row is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._table.move_down(row)
|
self._table.move_down(row)
|
||||||
self.select_current_profile()
|
self.select_current_profile()
|
||||||
|
|
||||||
@@ -503,18 +541,6 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self._table.purge()
|
self._table.purge()
|
||||||
self.update_redraw()
|
self.update_redraw()
|
||||||
|
|
||||||
def purge(self):
|
|
||||||
try:
|
|
||||||
dlg = PurgeDialog(
|
|
||||||
trad=self._trad,
|
|
||||||
parent=self
|
|
||||||
)
|
|
||||||
if dlg.exec():
|
|
||||||
self._table.purge(dlg.np_purge)
|
|
||||||
except Exception as e:
|
|
||||||
logger_exception(e)
|
|
||||||
return
|
|
||||||
|
|
||||||
def duplicate(self):
|
def duplicate(self):
|
||||||
rows = [
|
rows = [
|
||||||
row.row() for row in
|
row.row() for row in
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class BasicHydraulicStructuresTranslate(MainTranslate):
|
|||||||
super(BasicHydraulicStructuresTranslate, self).__init__()
|
super(BasicHydraulicStructuresTranslate, self).__init__()
|
||||||
|
|
||||||
self._dict["Basic Hydraulic Structures"] = _translate(
|
self._dict["Basic Hydraulic Structures"] = _translate(
|
||||||
"BasicHydraulicStructures", "Basic Hydraulic Structure"
|
"BasicHydraulicStructures", "Basic Hydraulic Structures"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._dict['msg_type_change_title'] = _translate(
|
self._dict['msg_type_change_title'] = _translate(
|
||||||
@@ -138,7 +138,7 @@ hydraulic structure values?"
|
|||||||
"BasicHydraulicStructures", "Check valve"
|
"BasicHydraulicStructures", "Check valve"
|
||||||
),
|
),
|
||||||
"UD": _translate(
|
"UD": _translate(
|
||||||
"BasicHydraulicStructures", "User-defined"
|
"BasicHydraulicStructures", "User defined"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,8 @@ from tools import timer
|
|||||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
QCoreApplication, Qt,
|
QCoreApplication
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
|
|
||||||
from matplotlib.collections import LineCollection
|
from matplotlib.collections import LineCollection
|
||||||
|
|
||||||
@@ -51,7 +50,6 @@ class PlotKPC(PamhyrPlot):
|
|||||||
|
|
||||||
self._auto_relim_update = True
|
self._auto_relim_update = True
|
||||||
self._autoscale_update = True
|
self._autoscale_update = True
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def river(self):
|
def river(self):
|
||||||
@@ -93,14 +91,7 @@ class PlotKPC(PamhyrPlot):
|
|||||||
self.line_kp_zmin, = self.canvas.axes.plot(
|
self.line_kp_zmin, = self.canvas.axes.plot(
|
||||||
kp, z_min,
|
kp, z_min,
|
||||||
color=self.color_plot_river_bottom,
|
color=self.color_plot_river_bottom,
|
||||||
lw=1.,
|
lw=1.
|
||||||
)
|
|
||||||
|
|
||||||
self.line_kp_zmax, = self.canvas.axes.plot(
|
|
||||||
kp, z_max,
|
|
||||||
color=self.color_plot_river_bottom,
|
|
||||||
lw=1.,
|
|
||||||
alpha=0.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(kp) != 0:
|
if len(kp) != 0:
|
||||||
@@ -108,8 +99,7 @@ class PlotKPC(PamhyrPlot):
|
|||||||
x=kp,
|
x=kp,
|
||||||
ymin=z_min, ymax=z_max,
|
ymin=z_min, ymax=z_max,
|
||||||
color=self.color_plot,
|
color=self.color_plot,
|
||||||
lw=1.,
|
lw=1.
|
||||||
picker=10
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_current(self):
|
def draw_current(self):
|
||||||
@@ -173,40 +163,3 @@ class PlotKPC(PamhyrPlot):
|
|||||||
self.profile.set_data([], [])
|
self.profile.set_data([], [])
|
||||||
|
|
||||||
self.canvas.figure.canvas.draw_idle()
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
|
||||||
def onpick(self, event):
|
|
||||||
if event.mouseevent.inaxes != self.canvas.axes:
|
|
||||||
return
|
|
||||||
if event.mouseevent.button.value != 1:
|
|
||||||
return
|
|
||||||
|
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
if modifiers not in [Qt.ControlModifier,
|
|
||||||
Qt.NoModifier,
|
|
||||||
Qt.ShiftModifier]:
|
|
||||||
return
|
|
||||||
|
|
||||||
closest = self._closest_profile(event)
|
|
||||||
index = self.parent.tableView.selectedIndexes()
|
|
||||||
if self.parent._table is not None:
|
|
||||||
self.parent._table.setData(index[2], closest)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _closest_profile(self, event):
|
|
||||||
|
|
||||||
s = event.artist.get_segments()
|
|
||||||
x = [i[0, 0] for i in s]
|
|
||||||
mx = event.mouseevent.xdata
|
|
||||||
points = enumerate(x)
|
|
||||||
|
|
||||||
def dist_mouse(point):
|
|
||||||
x = point[1]
|
|
||||||
d = abs(mx - x)
|
|
||||||
return d
|
|
||||||
|
|
||||||
closest = min(
|
|
||||||
points, key=dist_mouse
|
|
||||||
)
|
|
||||||
|
|
||||||
return closest[1]
|
|
||||||
@@ -141,8 +141,7 @@ class HydraulicStructuresWindow(PamhyrWindow):
|
|||||||
reach=None,
|
reach=None,
|
||||||
profile=None,
|
profile=None,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=self.toolbar,
|
toolbar=self.toolbar
|
||||||
parent=self
|
|
||||||
)
|
)
|
||||||
self.plot_kpc.draw()
|
self.plot_kpc.draw()
|
||||||
|
|
||||||
|
|||||||
@@ -52,41 +52,18 @@ class PlotDischarge(PamhyrPlot):
|
|||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
def draw_data(self):
|
def draw_data(self):
|
||||||
self.line_discharge = []
|
kp = self.data.reach.reach.get_kp()
|
||||||
|
|
||||||
if len(self.data) != 0:
|
if len(self.data) != 0:
|
||||||
kp = self.data.get_kp()
|
kp = self.data.get_kp()
|
||||||
discharge = self.data.get_discharge()
|
discharge = self.data.get_discharge()
|
||||||
|
|
||||||
line, = self.canvas.axes.plot(
|
self.line_kp_zmin = self.canvas.axes.plot(
|
||||||
kp, discharge,
|
kp, discharge,
|
||||||
color=self.color_plot,
|
color=self.color_plot,
|
||||||
**self.plot_default_kargs
|
**self.plot_default_kargs
|
||||||
)
|
)
|
||||||
self.line_discharge.append(line)
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self, ind=None):
|
def update(self, ind=None):
|
||||||
if not self._init:
|
self.draw()
|
||||||
self.draw()
|
|
||||||
|
|
||||||
self.update_data()
|
|
||||||
|
|
||||||
self.update_idle()
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
if len(self.data) == len(self.line_discharge):
|
|
||||||
kp = self.data.get_kp()
|
|
||||||
discharge = self.data.get_discharge()
|
|
||||||
|
|
||||||
line, = self.canvas.axes.plot(
|
|
||||||
kp, discharge,
|
|
||||||
color=self.color_plot,
|
|
||||||
**self.plot_default_kargs
|
|
||||||
)
|
|
||||||
self.line_discharge.append(line)
|
|
||||||
else:
|
|
||||||
for line in self.line_discharge:
|
|
||||||
line.remove()
|
|
||||||
|
|
||||||
self._draw_data()
|
|
||||||
@@ -138,7 +138,6 @@ class MoveCommand(QUndoCommand):
|
|||||||
else:
|
else:
|
||||||
self._ics.move_down(self._i)
|
self._ics.move_down(self._i)
|
||||||
|
|
||||||
|
|
||||||
class InsertCommand(QUndoCommand):
|
class InsertCommand(QUndoCommand):
|
||||||
def __init__(self, ics, row, ic):
|
def __init__(self, ics, row, ic):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -155,7 +154,6 @@ class InsertCommand(QUndoCommand):
|
|||||||
for ic in self._ic:
|
for ic in self._ic:
|
||||||
self._ics.insert(self._row, ic)
|
self._ics.insert(self._row, ic)
|
||||||
|
|
||||||
|
|
||||||
class DuplicateCommand(QUndoCommand):
|
class DuplicateCommand(QUndoCommand):
|
||||||
def __init__(self, ics, rows, ic):
|
def __init__(self, ics, rows, ic):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|||||||
@@ -194,13 +194,8 @@ class InitialConditionsWindow(PamhyrWindow):
|
|||||||
return rows[0].row()
|
return rows[0].row()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.update(propagate=False)
|
|
||||||
|
|
||||||
def _update(self, propagate=True):
|
|
||||||
self._update_plot()
|
self._update_plot()
|
||||||
|
self._propagate_update(key=Modules.INITIAL_CONDITION)
|
||||||
if propagate:
|
|
||||||
self._propagate_update(key=Modules.INITIAL_CONDITION)
|
|
||||||
|
|
||||||
def _update_plot(self):
|
def _update_plot(self):
|
||||||
self.plot_1.draw()
|
self.plot_1.draw()
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
# 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.InitialConditionsAdisTS.UndoCommand import (
|
||||||
|
SetCommand, AddCommand, SetCommandSpec,
|
||||||
|
DelCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, data=None, ic_spec_lst=None, trad=None, parent=None, mode="reaches"):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._mode = mode
|
||||||
|
self._trad = trad
|
||||||
|
self._ic_spec_lst = ic_spec_lst
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
val = []
|
||||||
|
if self._mode == "kp":
|
||||||
|
reach_id = self._ic_spec_lst[index.row()].reach
|
||||||
|
|
||||||
|
reach = next(filter(lambda edge: edge.id == reach_id, self._data.edges()))
|
||||||
|
|
||||||
|
if reach_id is not None:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda kp: str(kp), reach.reach.get_kp()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
val = list(
|
||||||
|
map(
|
||||||
|
lambda n: n.name, self._data.edges()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.addItems(
|
||||||
|
[self._trad['not_associated']] +
|
||||||
|
val
|
||||||
|
)
|
||||||
|
|
||||||
|
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, river=None, data=None, **kwargs):
|
||||||
|
self._river = river
|
||||||
|
|
||||||
|
super(InitialConditionTableModel, self).__init__(data=data, **kwargs)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
def _setup_lst(self):
|
||||||
|
self._lst = self._data._data
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._lst)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "name":
|
||||||
|
n = self._lst[row].name
|
||||||
|
if n is None or n == "":
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "reach":
|
||||||
|
n = self._lst[row].reach
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return next(filter(lambda edge: edge.id == n, self._river.edges())).name
|
||||||
|
elif self._headers[column] is "start_kp":
|
||||||
|
n = self._lst[row].start_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "end_kp":
|
||||||
|
n = self._lst[row].end_kp
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "concentration":
|
||||||
|
n = self._lst[row].concentration
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "eg":
|
||||||
|
n = self._lst[row].eg
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "em":
|
||||||
|
n = self._lst[row].em
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "ed":
|
||||||
|
n = self._lst[row].ed
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "rate":
|
||||||
|
n = self._lst[row].rate
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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] != "reach":
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self._headers[column] == "reach":
|
||||||
|
print(self._river.edge(value).id)
|
||||||
|
self._undo.push(
|
||||||
|
SetCommandSpec(
|
||||||
|
self._lst, row, self._headers[column], self._river.edge(value).id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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._data, 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._data, self._lst, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# 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.InitialConditionsAdisTS.UndoCommand import (
|
||||||
|
SetCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
class InitialConditionTableDefaultModel(PamhyrTableModel):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(InitialConditionTableDefaultModel, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] is "name":
|
||||||
|
return self._data[row].name
|
||||||
|
elif self._headers[column] is "concentration":
|
||||||
|
n = self._data[row].concentration
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "eg":
|
||||||
|
n = self._data[row].eg
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "em":
|
||||||
|
n = self._data[row].em
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
elif self._headers[column] is "ed":
|
||||||
|
n = self._data[row].ed
|
||||||
|
if n is None:
|
||||||
|
return self._trad['not_associated']
|
||||||
|
return n
|
||||||
|
|
||||||
|
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._data, 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 undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
@@ -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.InitialConditionsAdisTS.InitialConditionsAdisTS import InitialConditionsAdisTS
|
||||||
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList import InitialConditionsAdisTSList
|
||||||
|
|
||||||
|
|
||||||
|
class SetCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "name":
|
||||||
|
self._old = self._data[self._row].name
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._old = self._data[self._row].concentration
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._old = self._data[self._row].eg
|
||||||
|
elif self._column == "em":
|
||||||
|
self._old = self._data[self._row].em
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._old = self._data[self._row].ed
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "name":
|
||||||
|
_type = str
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._old
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._data[self._row].concentration = self._old
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._data[self._row].eg = self._old
|
||||||
|
elif self._column == "em":
|
||||||
|
self._data[self._row].em = self._old
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._data[self._row].ed = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._new
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._data[self._row].concentration = self._new
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._data[self._row].eg = self._new
|
||||||
|
elif self._column == "em":
|
||||||
|
self._data[self._row].em = self._new
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._data[self._row].ed = self._new
|
||||||
|
|
||||||
|
class SetCommandSpec(QUndoCommand):
|
||||||
|
def __init__(self, data, row, column, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._row = row
|
||||||
|
self._column = column
|
||||||
|
|
||||||
|
if self._column == "name":
|
||||||
|
self._old = self._data[self._row].name
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._old = self._data[self._row].reach
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._old = self._data[self._row].start_kp
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._old = self._data[self._row].end_kp
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._old = self._data[self._row].concentration
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._old = self._data[self._row].eg
|
||||||
|
elif self._column == "em":
|
||||||
|
self._old = self._data[self._row].em
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._old = self._data[self._row].ed
|
||||||
|
elif self._column == "rate":
|
||||||
|
self._old = self._data[self._row].rate
|
||||||
|
|
||||||
|
_type = float
|
||||||
|
if column == "name":
|
||||||
|
_type = str
|
||||||
|
elif column == "reach":
|
||||||
|
_type = int
|
||||||
|
|
||||||
|
self._new = _type(new_value)
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._old
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._old
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._old
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._old
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._data[self._row].concentration = self._old
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._data[self._row].eg = self._old
|
||||||
|
elif self._column == "em":
|
||||||
|
self._data[self._row].em = self._old
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._data[self._row].ed = self._old
|
||||||
|
elif self._column == "rate":
|
||||||
|
self._data[self._row].rate = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._column == "name":
|
||||||
|
self._data[self._row].name = self._new
|
||||||
|
elif self._column == "reach":
|
||||||
|
self._data[self._row].reach = self._new
|
||||||
|
elif self._column == "start_kp":
|
||||||
|
self._data[self._row].start_kp = self._new
|
||||||
|
elif self._column == "end_kp":
|
||||||
|
self._data[self._row].end_kp = self._new
|
||||||
|
elif self._column == "concentration":
|
||||||
|
self._data[self._row].concentration = self._new
|
||||||
|
elif self._column == "eg":
|
||||||
|
self._data[self._row].eg = self._new
|
||||||
|
elif self._column == "em":
|
||||||
|
self._data[self._row].em = self._new
|
||||||
|
elif self._column == "ed":
|
||||||
|
self._data[self._row].ed = self._new
|
||||||
|
elif self._column == "rate":
|
||||||
|
self._data[self._row].rate = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._data.delete_i([self._index])
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._data.new(self._index)
|
||||||
|
else:
|
||||||
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, data, ics_spec, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._ics_spec = ics_spec
|
||||||
|
self._rows = rows
|
||||||
|
#self._data = data
|
||||||
|
|
||||||
|
self._ic = []
|
||||||
|
for row in rows:
|
||||||
|
self._ic.append((row, self._ics_spec[row]))
|
||||||
|
self._ic.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._ic:
|
||||||
|
self._data.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._data.delete_i(self._rows)
|
||||||
|
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
# 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, QIcon,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect, QItemSelectionModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
QVBoxLayout, QToolBar, QAction, QToolButton,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Modules import Modules
|
||||||
|
|
||||||
|
from View.InitialConditionsAdisTS.UndoCommand import (
|
||||||
|
SetCommand,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.InitialConditionsAdisTS.TableDefault import (
|
||||||
|
InitialConditionTableDefaultModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.InitialConditionsAdisTS.Table import (
|
||||||
|
InitialConditionTableModel, ComboBoxDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.InitialConditionsAdisTS.translate import IcAdisTSTranslate
|
||||||
|
|
||||||
|
from Solver.Mage import Mage8
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class InitialConditionsAdisTSWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "InitialConditionsAdisTS"
|
||||||
|
_pamhyr_name = "Initial condition AdisTS"
|
||||||
|
|
||||||
|
def __init__(self, data=None, study=None, config=None, parent=None):
|
||||||
|
self._data = []
|
||||||
|
self._data.append(data)
|
||||||
|
trad = IcAdisTSTranslate()
|
||||||
|
|
||||||
|
name = (
|
||||||
|
trad[self._pamhyr_name] +
|
||||||
|
" - " + study.name +
|
||||||
|
" - " + self._data[0].name
|
||||||
|
)
|
||||||
|
|
||||||
|
super(InitialConditionsAdisTSWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._hash_data.append(data)
|
||||||
|
|
||||||
|
self._ics_adists_lst = study.river.initial_conditions_adists
|
||||||
|
|
||||||
|
self.setup_table()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
|
||||||
|
path_icons = os.path.join(self._get_ui_directory(), f"ressources")
|
||||||
|
|
||||||
|
table_default = self.find(QTableView, f"tableView")
|
||||||
|
|
||||||
|
self._table = InitialConditionTableDefaultModel(
|
||||||
|
table_view=table_default,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
editable_headers=["name", "concentration", "eg", "em", "ed"],
|
||||||
|
delegates={},
|
||||||
|
data=self._data,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad
|
||||||
|
)
|
||||||
|
|
||||||
|
table_default.setModel(self._table)
|
||||||
|
table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table_default.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table_default.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
layout = self.find(QVBoxLayout, f"verticalLayout_1")
|
||||||
|
toolBar = QToolBar()
|
||||||
|
layout.addWidget(toolBar)
|
||||||
|
|
||||||
|
action_add = QAction(self)
|
||||||
|
action_add.setIcon(QIcon(os.path.join(path_icons, f"add.png")))
|
||||||
|
action_add.triggered.connect(self.add)
|
||||||
|
action_delete = QAction(self)
|
||||||
|
action_delete.setIcon(QIcon(os.path.join(path_icons, f"del.png")))
|
||||||
|
action_delete.triggered.connect(self.delete)
|
||||||
|
|
||||||
|
toolBar.addAction(action_add)
|
||||||
|
toolBar.addAction(action_delete)
|
||||||
|
|
||||||
|
self.table_spec = QTableView()
|
||||||
|
layout.addWidget(self.table_spec)
|
||||||
|
|
||||||
|
self._delegate_reach = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="reaches"
|
||||||
|
)
|
||||||
|
self._delegate_kp = ComboBoxDelegate(
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
ic_spec_lst=self._data[0]._data,
|
||||||
|
parent=self,
|
||||||
|
mode="kp"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._table_spec = InitialConditionTableModel(
|
||||||
|
table_view=self.table_spec,
|
||||||
|
table_headers=self._trad.get_dict("table_headers_spec"),
|
||||||
|
editable_headers=["name", "reach", "start_kp", "end_kp", "concentration", "eg", "em", "ed", "rate"],
|
||||||
|
delegates={
|
||||||
|
"reach": self._delegate_reach,
|
||||||
|
"start_kp": self._delegate_kp,
|
||||||
|
"end_kp": self._delegate_kp
|
||||||
|
},
|
||||||
|
data=self._data[0],
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad,
|
||||||
|
river=self._study.river
|
||||||
|
)
|
||||||
|
|
||||||
|
self.table_spec.setModel(self._table_spec)
|
||||||
|
self.table_spec.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.table_spec.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
self.table_spec.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
selectionModel = self.table_spec.selectionModel()
|
||||||
|
index = self.table_spec.model().index(0, 0)
|
||||||
|
|
||||||
|
selectionModel.select(
|
||||||
|
index,
|
||||||
|
QItemSelectionModel.Rows |
|
||||||
|
QItemSelectionModel.ClearAndSelect |
|
||||||
|
QItemSelectionModel.Select
|
||||||
|
)
|
||||||
|
self.table_spec.scrollTo(index)
|
||||||
|
|
||||||
|
def index_selected_row(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
rows = table.selectionModel()\
|
||||||
|
.selectedRows()
|
||||||
|
|
||||||
|
if len(rows) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return rows[0].row()
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
#table = self.find(QTableView, f"tableView")
|
||||||
|
table = self.table_spec
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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 add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._data[0]._data) == 0 or len(rows) == 0:
|
||||||
|
self._table_spec.add(0)
|
||||||
|
else:
|
||||||
|
self._table_spec.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
print("del")
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
print("len 0")
|
||||||
|
return
|
||||||
|
self._table_spec.delete(rows)
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# 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 IcAdisTSTranslate(MainTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(IcAdisTSTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["Initial condition AdisTS"] = _translate(
|
||||||
|
"InitialConditionAdisTS", "Initial condition AdisTS")
|
||||||
|
|
||||||
|
self._dict["kp"] = self._dict["unit_kp"]
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"name": self._dict["name"],
|
||||||
|
"concentration": self._dict["unit_concentration"],
|
||||||
|
"eg": _translate("Unit", "EG (m)"),
|
||||||
|
"em": _translate("Unit", "EM (m)"),
|
||||||
|
"ed": _translate("Unit", "ED (m)"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self._sub_dict["table_headers_spec"] = {
|
||||||
|
"name": self._dict["name"],
|
||||||
|
"reach": self._dict["reach"],
|
||||||
|
"start_kp": _translate("Unit", "Start_KP (m)"),
|
||||||
|
"end_kp": _translate("Unit", "End_KP (m)"),
|
||||||
|
"concentration": self._dict["unit_concentration"],
|
||||||
|
"eg": _translate("Unit", "EG (m)"),
|
||||||
|
"em": _translate("Unit", "EM (m)"),
|
||||||
|
"ed": _translate("Unit", "ED (m)"),
|
||||||
|
"rate": _translate("Unit", "Rate"),
|
||||||
|
}
|
||||||
@@ -99,7 +99,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
logger.info(e)
|
logger.info(e)
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
|
|
||||||
self.update()
|
self.dataChanged.emit(index, index)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def add(self, row, parent=QModelIndex()):
|
def add(self, row, parent=QModelIndex()):
|
||||||
@@ -112,7 +112,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def delete(self, rows, parent=QModelIndex()):
|
def delete(self, rows, parent=QModelIndex()):
|
||||||
self.beginRemoveRows(parent, rows[0], rows[-1])
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
||||||
@@ -135,7 +135,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_up(self, row, parent=QModelIndex()):
|
def move_up(self, row, parent=QModelIndex()):
|
||||||
if row <= 0:
|
if row <= 0:
|
||||||
@@ -152,7 +152,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_down(self, index, parent=QModelIndex()):
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
if row > len(self._data):
|
if row > len(self._data):
|
||||||
@@ -169,7 +169,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.update()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def paste(self, row, header, data):
|
def paste(self, row, header, data):
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
@@ -190,13 +190,4 @@ class TableModel(PamhyrTableModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.update()
|
|
||||||
|
|
||||||
def auto_sort(self):
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
|
||||||
self._data.sort(key=lambda x: x[0])
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
# self.auto_sort()
|
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
@@ -137,7 +137,6 @@ class EditLateralContributionWindow(PamhyrWindow):
|
|||||||
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
||||||
|
|
||||||
self._table.dataChanged.connect(self.update)
|
self._table.dataChanged.connect(self.update)
|
||||||
self._table.layoutChanged.connect(self.update)
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
|
|||||||
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user