mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
49
Commits
adists_new
..
v0.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4554d38c1 | ||
|
|
4deed897ff | ||
|
|
460450f524 | ||
|
|
60336c25f1 | ||
|
|
82093bcf95 | ||
|
|
7b8191e2f0 | ||
|
|
88dd9cf15a | ||
|
|
7d4091eb24 | ||
|
|
59fc80a10b | ||
|
|
ea146cbe87 | ||
|
|
c6b28ba3a0 | ||
|
|
fe57890da4 | ||
|
|
8cd9ec939b | ||
|
|
872ff0ef62 | ||
|
|
052faed48d | ||
|
|
31b37a7792 | ||
|
|
dfe12c8bcb | ||
|
|
89d5b2d576 | ||
|
|
601ef73b5d | ||
|
|
e4f8bc347d | ||
|
|
6c4b67d93a | ||
|
|
2ee8420b94 | ||
|
|
bbe127865b | ||
|
|
50686e1b65 | ||
|
|
7b3c3d891d | ||
|
|
98feca7fca | ||
|
|
e45eb3fd69 | ||
|
|
dd86b8b461 | ||
|
|
57d43cd5d3 | ||
|
|
14b5b5e3df | ||
|
|
a7e43ca6a7 | ||
|
|
8ca21c413f | ||
|
|
61fd54c496 | ||
|
|
b017127b3a | ||
|
|
52f2d15280 | ||
|
|
5c86e46c72 | ||
|
|
a5648851f2 | ||
|
|
cb41520a20 | ||
|
|
537612e5e3 | ||
|
|
4e0c671f68 | ||
|
|
507cfb9d53 | ||
|
|
2013009e8a | ||
|
|
f1a1d08458 | ||
|
|
7de6cc4468 | ||
|
|
783d83e4cc | ||
|
|
c366a1a4e7 | ||
|
|
b784cab94b | ||
|
|
78e361d486 | ||
|
|
f745dce04e |
No files matched your search
@@ -9,8 +9,6 @@
|
|||||||
*.class
|
*.class
|
||||||
|
|
||||||
tmp
|
tmp
|
||||||
mage8
|
|
||||||
adists
|
|
||||||
|
|
||||||
*.tar
|
*.tar
|
||||||
*.tar.*
|
*.tar.*
|
||||||
|
|||||||
+7
-2
@@ -29,7 +29,7 @@ stages:
|
|||||||
#############
|
#############
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
MAGE_8_VERSION: "v8.3.5"
|
MAGE_8_VERSION: "v8.3.6"
|
||||||
|
|
||||||
dl-mage8-doc:
|
dl-mage8-doc:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -262,6 +262,11 @@ 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
|
||||||
@@ -333,7 +338,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 --hide-console hide-early -y ..\src\pamhyr.py
|
- pyinstaller -i ../src/View/ui/ressources/icon.ico --hide-console hide-early -y ..\src\pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir pamhyr
|
- mkdir pamhyr
|
||||||
- dir
|
- dir
|
||||||
|
|||||||
Generated
-3
@@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
-6
@@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
Generated
-7
@@ -1,7 +0,0 @@
|
|||||||
<?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
@@ -1,8 +0,0 @@
|
|||||||
<?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
@@ -1,14 +0,0 @@
|
|||||||
<?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
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,7 @@
|
|||||||
!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.
+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 guide line checker")
|
self._name = _translate("Checker", "Mage geometry guideline checker")
|
||||||
self._description = _translate(
|
self._description = _translate(
|
||||||
"Checker",
|
"Checker",
|
||||||
"Check if exists geometry guide line is correctly defined \
|
"Check if exists geometry guidelines are correctly defined \
|
||||||
for each reaches of the study"
|
for each reach"
|
||||||
)
|
)
|
||||||
self._solver = version
|
self._solver = version
|
||||||
self._modules = Modules.GEOMETRY
|
self._modules = Modules.GEOMETRY
|
||||||
@@ -241,7 +241,7 @@ for each reaches of the study"
|
|||||||
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_guileline_defined"
|
self._summary = "no_standard_guideline_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 network reach checker")
|
self._name = _translate("Checker", "Study reach network checker")
|
||||||
self._description = _translate(
|
self._description = _translate(
|
||||||
"Checker", "Check if exists at least one reach for study"
|
"Checker", "Check if exists at least one reach exists"
|
||||||
)
|
)
|
||||||
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 exists geometry for each reach of study"
|
"Checker", "Check if the geometry of each reach exists"
|
||||||
)
|
)
|
||||||
self._modules = Modules.GEOMETRY
|
self._modules = Modules.GEOMETRY
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -371,7 +371,8 @@ 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
|
||||||
|
|
||||||
@@ -400,7 +401,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"{lplan} {lm} {linear} " +
|
f"{orientation} {lm} {linear} " +
|
||||||
f"{origin} "
|
f"{origin} "
|
||||||
)
|
)
|
||||||
proc.start(
|
proc.start(
|
||||||
@@ -413,7 +414,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],
|
||||||
lplan, lm, linear, origin, origin_value
|
orientation, lm, linear, origin, origin_value
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -315,6 +315,9 @@ 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]
|
||||||
|
|
||||||
|
|||||||
@@ -1,221 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
# 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,7 +64,6 @@ 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,
|
||||||
@@ -139,7 +138,6 @@ 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
|
||||||
|
|||||||
@@ -1,272 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# 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,
|
|
||||||
)
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
# 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,14 +45,6 @@ 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 = []
|
||||||
@@ -236,13 +228,6 @@ 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):
|
||||||
@@ -266,13 +251,6 @@ 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):
|
||||||
@@ -347,22 +325,6 @@ 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):
|
||||||
@@ -382,14 +344,6 @@ 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
|
||||||
|
|
||||||
@@ -512,34 +466,6 @@ 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]
|
||||||
|
|||||||
+17
-2
@@ -22,10 +22,19 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
|
|
||||||
class SavedStatus(object):
|
class SavedStatus(object):
|
||||||
def __init__(self):
|
def __init__(self, version=0):
|
||||||
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
|
||||||
|
|
||||||
@@ -34,5 +43,11 @@ class SavedStatus(object):
|
|||||||
self._saved = True
|
self._saved = True
|
||||||
|
|
||||||
def modified(self):
|
def modified(self):
|
||||||
# logger.debug("model status set as modified")
|
if self._saved:
|
||||||
|
self._version += 1
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
"STATUS: Model status set as modified " +
|
||||||
|
f"at version {self._version}"
|
||||||
|
)
|
||||||
self._saved = False
|
self._saved = False
|
||||||
+35
-10
@@ -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.9"
|
self._version = "0.0.10"
|
||||||
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,6 +117,9 @@ 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()
|
||||||
|
|
||||||
@@ -209,7 +212,12 @@ class Study(SQLModel):
|
|||||||
def _create(self):
|
def _create(self):
|
||||||
# Info (metadata)
|
# Info (metadata)
|
||||||
self.execute(
|
self.execute(
|
||||||
"CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
|
"INSERT INTO info VALUES ('study_release', '0')"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)}')",
|
||||||
@@ -218,19 +226,20 @@ 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(
|
||||||
f"INSERT INTO info VALUES ('date', " +
|
"INSERT INTO info VALUES ('date', " +
|
||||||
"'{self._date.timestamp()}')"
|
f"'{self._date.timestamp()}')"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.execute(
|
self.execute(
|
||||||
f"INSERT INTO info VALUES ('creation_date', " +
|
"INSERT INTO info VALUES ('creation_date', " +
|
||||||
"'{self.creation_time.timestamp()}')"
|
f"'{self.creation_date.timestamp()}')"
|
||||||
)
|
)
|
||||||
self.execute(
|
self.execute(
|
||||||
f"INSERT INTO info VALUES ('last_save_date', " +
|
"INSERT INTO info VALUES ('last_save_date', " +
|
||||||
"'{self.last_save_time.timestamp()}')"
|
f"'{self.last_save_date.timestamp()}')"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._create_submodel()
|
self._create_submodel()
|
||||||
@@ -245,6 +254,12 @@ 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'"
|
||||||
@@ -258,6 +273,11 @@ 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(
|
||||||
@@ -292,6 +312,11 @@ 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,7 +54,6 @@ 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()
|
||||||
@@ -78,7 +77,6 @@ class Modules(IterableFlag):
|
|||||||
cls.ADDITIONAL_FILES,
|
cls.ADDITIONAL_FILES,
|
||||||
cls.RESULTS,
|
cls.RESULTS,
|
||||||
cls.WINDOW_LIST,
|
cls.WINDOW_LIST,
|
||||||
cls.OUTPUT_KP,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -1,731 +0,0 @@
|
|||||||
# 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,7 +980,6 @@ 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
|
||||||
@@ -1013,8 +1012,6 @@ 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:
|
||||||
@@ -1050,7 +1047,6 @@ 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,7 +23,6 @@ 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
|
||||||
|
|
||||||
@@ -32,8 +31,7 @@ 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 = {
|
||||||
@@ -41,6 +39,5 @@ 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.dataChanged.emit(index, index)
|
self.update()
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
def paste(self, row, header, data):
|
def paste(self, row, header, data):
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
@@ -190,4 +190,13 @@ 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,6 +195,7 @@ 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", "Ponctual contribution"),
|
"PC": _translate("BoundaryCondition", "Point sources"),
|
||||||
"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)"),
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
# 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]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
# 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()
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# 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"),
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
# 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()
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# 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]
|
|
||||||
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
# 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()
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# 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")
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
# 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")
|
||||||
|
|
||||||
|
|||||||
@@ -1,217 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
# 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)
|
|
||||||
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# 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"),
|
|
||||||
}
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
# 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)
|
|
||||||
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# 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"),
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Adists.py -- Pamhyr study checkers
|
# PlotKPC.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
|
||||||
@@ -16,36 +16,35 @@
|
|||||||
|
|
||||||
# -*- 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 AdistsOutputKpChecker(AbstractModelChecker):
|
class PlotKPZ(PlotKPC):
|
||||||
def __init__(self):
|
def __init__(self, canvas=None, trad=None, toolbar=None,
|
||||||
super(AdistsOutputKpChecker, self).__init__()
|
river=None, reach=None, profile=None,
|
||||||
|
parent=None):
|
||||||
self._name = _translate("Checker", "AdisTS output Kp checker")
|
super(PlotKPC, self).__init__(
|
||||||
self._description = _translate(
|
canvas=canvas,
|
||||||
"Checker", "Check output Kp"
|
trad=trad,
|
||||||
|
data=river,
|
||||||
|
toolbar=toolbar,
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
self._modules = Modules.OUTPUT_KP
|
|
||||||
|
|
||||||
def run(self, study):
|
self._current_reach = reach
|
||||||
ok = True
|
self._current_profile = profile
|
||||||
nerror = 0
|
|
||||||
self._summary = "ok"
|
|
||||||
self._status = STATUS.OK
|
|
||||||
|
|
||||||
if not self.basic_check(study):
|
self.label_x = self._trad["unit_kp"]
|
||||||
return False
|
self.label_y = self._trad["unit_elevation"]
|
||||||
|
|
||||||
return ok
|
self._isometric_axis = False
|
||||||
|
|
||||||
|
self._auto_relim_update = True
|
||||||
|
self._autoscale_update = True
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
def onpick(self, event):
|
||||||
|
return
|
||||||
@@ -42,7 +42,7 @@ class PlotStricklers(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.label_x = self._trad["kp"]
|
self.label_x = self._trad["kp"]
|
||||||
self.label_y = self._trad["stricklers"]
|
self.label_y = self._trad["strickler_plot"]
|
||||||
|
|
||||||
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.Geometry.PlotKPZ import PlotKPZ
|
from View.Frictions.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,9 +135,11 @@ class FrictionsWindow(PamhyrWindow):
|
|||||||
|
|
||||||
self.plot = PlotKPZ(
|
self.plot = PlotKPZ(
|
||||||
canvas=self.canvas,
|
canvas=self.canvas,
|
||||||
data=self._reach.reach,
|
reach=self._reach,
|
||||||
|
river=self._study.river,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
toolbar=None,
|
toolbar=None,
|
||||||
|
parent=self
|
||||||
)
|
)
|
||||||
self.plot.draw()
|
self.plot.draw()
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ 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"
|
||||||
)
|
)
|
||||||
@@ -39,8 +42,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", "Begin kp (m)"),
|
"begin_kp": _translate("Frictions", "Start (m)"),
|
||||||
"end_kp": _translate("Frictions", "End kp (m)"),
|
"end_kp": _translate("Frictions", "End (m)"),
|
||||||
"begin_strickler": _translate("Frictions", "Begin strickler"),
|
"begin_strickler": _translate("Frictions", "Start coefficient"),
|
||||||
"end_strickler": _translate("Frictions", "End strickler"),
|
"end_strickler": _translate("Frictions", "End coefficient"),
|
||||||
}
|
}
|
||||||
@@ -125,14 +125,6 @@ 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
|
||||||
@@ -165,15 +157,9 @@ 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,6 +98,7 @@ 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:
|
||||||
@@ -106,12 +107,16 @@ 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)
|
||||||
|
|
||||||
@@ -160,6 +165,9 @@ 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()
|
||||||
|
|
||||||
@@ -171,6 +179,10 @@ 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([], [])
|
||||||
@@ -180,18 +192,23 @@ 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()
|
||||||
|
|||||||
+200
-131
@@ -20,6 +20,11 @@ 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()
|
||||||
|
|
||||||
@@ -27,7 +32,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,
|
||||||
parent=None):
|
table=None, parent=None):
|
||||||
self._study = study
|
self._study = study
|
||||||
|
|
||||||
super(PlotKPZ, self).__init__(
|
super(PlotKPZ, self).__init__(
|
||||||
@@ -35,6 +40,7 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
trad=trad,
|
trad=trad,
|
||||||
data=data,
|
data=data,
|
||||||
toolbar=toolbar,
|
toolbar=toolbar,
|
||||||
|
table=table,
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,6 +57,111 @@ 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):
|
||||||
@@ -74,8 +185,7 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.draw_z_line()
|
self.draw_z_line()
|
||||||
self.draw_z_line_highlight()
|
self.draw_lr()
|
||||||
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)
|
||||||
@@ -88,76 +198,60 @@ 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.color_plot,
|
color=self._colors,
|
||||||
lw=1.
|
linestyle=self._style,
|
||||||
|
lw=1.,
|
||||||
|
picker=10,
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_z_line_highlight(self):
|
def color_hightlight(self):
|
||||||
if self._highlight_data is not None:
|
rows = sorted(list(
|
||||||
kp = self.data.get_kp_complete_profiles()
|
set(
|
||||||
z_min = self.data.get_z_min()
|
(i.row() for i in self.parent.tableView.selectedIndexes())
|
||||||
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 indexes_filter(data): return list(
|
def draw_lr(self):
|
||||||
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()
|
||||||
z_min = self.data.get_z_min()
|
lz = []
|
||||||
z_max = self.data.get_z_max()
|
rz = []
|
||||||
|
|
||||||
self.plot_selected, = self.canvas.axes.plot(
|
self.line_lr = []
|
||||||
(kp[0], kp[0]),
|
for z in self.data.get_z():
|
||||||
(z_min[0], z_max[0]),
|
lz.append(z[0])
|
||||||
color=self.color_plot_current, lw=1.5
|
rz.append(z[-1])
|
||||||
)
|
|
||||||
self.plot_selected.set_visible(False)
|
|
||||||
|
|
||||||
self.before_plot_selected, = self.canvas.axes.plot(
|
line = self.canvas.axes.plot(
|
||||||
(kp[0], kp[0]),
|
kp, lz,
|
||||||
(z_min[0], z_max[0]),
|
color=self.color_plot_river_bottom,
|
||||||
color=self.color_plot_previous, lw=1.5, linestyle='--'
|
linestyle="dotted",
|
||||||
|
lw=1.,
|
||||||
)
|
)
|
||||||
self.before_plot_selected.set_visible(False)
|
self.line_lr.append(line)
|
||||||
|
|
||||||
self.after_plot_selected, = self.canvas.axes.plot(
|
line = self.canvas.axes.plot(
|
||||||
(kp[0], kp[0]),
|
kp, rz,
|
||||||
(z_min[0], z_max[0]),
|
color=self.color_plot_river_bottom,
|
||||||
color=self.color_plot_next, lw=1.5, linestyle='--'
|
linestyle="dotted",
|
||||||
|
lw=1.,
|
||||||
)
|
)
|
||||||
self.after_plot_selected.set_visible(False)
|
self.line_lr.append(line)
|
||||||
|
|
||||||
def draw_gl(self):
|
def draw_gl(self):
|
||||||
kp = self.data.get_kp_complete_profiles()
|
kp = self.data.get_kp_complete_profiles()
|
||||||
@@ -191,30 +285,34 @@ 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,
|
||||||
self._study.river.hydraulic_structures.lst
|
filter(
|
||||||
|
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
|
||||||
z_min = reach.get_z_min()
|
if x is not None:
|
||||||
z_max = reach.get_z_max()
|
z_min = reach.get_z_min()
|
||||||
|
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):
|
||||||
@@ -222,6 +320,7 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
self.draw()
|
self.draw()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.update_lr()
|
||||||
self.update_gl()
|
self.update_gl()
|
||||||
self.update_current()
|
self.update_current()
|
||||||
|
|
||||||
@@ -229,52 +328,9 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
|
|
||||||
def update_current(self):
|
def update_current(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
ind = self._current_data
|
self._colors, self._style = self.color_hightlight()
|
||||||
before = ind - 1
|
self.line_kp_zmin_zmax.set_colors(self._colors)
|
||||||
after = ind + 1
|
self.line_kp_zmin_zmax.set_linestyle(self._style)
|
||||||
|
|
||||||
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:
|
||||||
@@ -286,12 +342,19 @@ class PlotKPZ(PamhyrPlot):
|
|||||||
|
|
||||||
self.line_kp_zmin.set_data(kp, z_min)
|
self.line_kp_zmin.set_data(kp, z_min)
|
||||||
|
|
||||||
self.line_kp_zmin_zmax.remove()
|
# TODO comprendre à quoi sert ce bout de code
|
||||||
self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
# ========>
|
||||||
x=kp,
|
# self.line_kp_zmin_zmax.remove()
|
||||||
ymin=z_min, ymax=z_max,
|
# self._colors, self._style = self.color_hightlight()
|
||||||
color='r', lw=1.
|
# self.line_kp_zmin_zmax = self.canvas.axes.vlines(
|
||||||
)
|
# 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:
|
||||||
@@ -301,3 +364,9 @@ 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()
|
||||||
+167
-90
@@ -18,22 +18,27 @@
|
|||||||
|
|
||||||
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
|
QCoreApplication, Qt, QItemSelectionModel,
|
||||||
|
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,
|
||||||
parent=None):
|
table=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
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,6 +51,116 @@ 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):
|
||||||
@@ -63,33 +178,42 @@ 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 x, y, kp in zip(self.data.get_x(),
|
for xy in zip(self.data.get_x(), self.data.get_y()):
|
||||||
self.data.get_y(),
|
self.line_xy.append(np.column_stack(xy))
|
||||||
kp):
|
|
||||||
line = self.canvas.axes.plot(
|
self._colors, self._style = self.color_hightlight()
|
||||||
x, y,
|
self.line_xy_collection = collections.LineCollection(
|
||||||
color=color_hightlight(kp),
|
self.line_xy,
|
||||||
**self.plot_default_kargs
|
colors=self._colors,
|
||||||
|
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 = []
|
||||||
@@ -136,33 +260,6 @@ 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:
|
||||||
@@ -183,21 +280,24 @@ 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())
|
||||||
|
|
||||||
for i in range(self.data.number_profiles):
|
# TODO comprendre à quoi sert ce bout de code
|
||||||
if i < len(self.line_xy):
|
# ========>
|
||||||
self.line_xy[i][0].set_data(
|
# for i in range(self.data.number_profiles):
|
||||||
self.data.profile(i).x(),
|
# if i < len(self.line_xy):
|
||||||
self.data.profile(i).y()
|
# self.line_xy[i][0].set_data(
|
||||||
)
|
# self.data.profile(i).x(),
|
||||||
else:
|
# self.data.profile(i).y()
|
||||||
self.line_xy.append(
|
# )
|
||||||
self.canvas.axes.plot(
|
# else:
|
||||||
self.data.profile(i).x(),
|
# self.line_xy.append(
|
||||||
self.data.profile(i).y(),
|
# self.canvas.axes.plot(
|
||||||
color='r',
|
# self.data.profile(i).x(),
|
||||||
**self.plot_default_kargs
|
# self.data.profile(i).y(),
|
||||||
)
|
# 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):
|
||||||
@@ -215,32 +315,9 @@ class PlotXY(PamhyrPlot):
|
|||||||
|
|
||||||
def update_current(self):
|
def update_current(self):
|
||||||
if self._current_data_update:
|
if self._current_data_update:
|
||||||
ind = self._current_data
|
self._colors, self._style = self.color_hightlight()
|
||||||
before = ind - 1
|
self.line_xy_collection.set_colors(self._colors)
|
||||||
after = ind + 1
|
self.line_xy_collection.set_linestyle(self._style)
|
||||||
|
|
||||||
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,10 +24,12 @@ 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
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ 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
|
||||||
@@ -68,40 +71,86 @@ 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:
|
||||||
modifiers = QApplication.keyboardModifiers()
|
|
||||||
if modifiers != Qt.ControlModifier:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
_, hyd = self.highlight
|
modifiers = QApplication.keyboardModifiers()
|
||||||
|
if modifiers not in [Qt.ControlModifier,
|
||||||
|
Qt.NoModifier,
|
||||||
|
Qt.ShiftModifier]:
|
||||||
|
return
|
||||||
|
|
||||||
ind, point = self._closer_point(event)
|
self._onpickevent = 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():
|
if z < self.data.z_min() or event.button.value == 2:
|
||||||
|
self.highlight = (points, None)
|
||||||
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
a, p, w = self._compute_hydrolics(z)
|
a, p, w = self._compute_hydraulics(z)
|
||||||
|
|
||||||
logger.debug(f"{z, a, p, w}")
|
logger.debug(f"{z, a, p, w}")
|
||||||
|
|
||||||
@@ -110,7 +159,7 @@ class Plot(PamhyrPlot):
|
|||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
def select_points_from_indexes(self, indexes):
|
def select_points_from_indices(self, indices):
|
||||||
data = self.data
|
data = self.data
|
||||||
_, hyd = self.highlight
|
_, hyd = self.highlight
|
||||||
|
|
||||||
@@ -118,7 +167,7 @@ class Plot(PamhyrPlot):
|
|||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1],
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] in indexes,
|
lambda e: e[0] in indices,
|
||||||
enumerate(
|
enumerate(
|
||||||
zip(data.get_station(), data.z())
|
zip(data.get_station(), data.z())
|
||||||
)
|
)
|
||||||
@@ -133,9 +182,13 @@ 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 = self._table.model().index(ind, 0)
|
index = QItemSelection()
|
||||||
|
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 |
|
||||||
@@ -143,10 +196,27 @@ class Plot(PamhyrPlot):
|
|||||||
QItemSelectionModel.Select
|
QItemSelectionModel.Select
|
||||||
)
|
)
|
||||||
|
|
||||||
self._table.scrollTo(index)
|
if len(ind) > 0:
|
||||||
|
self._table.scrollTo(self._table.model().index(ind[-1], 0))
|
||||||
self._table.blockSignals(False)
|
self._table.blockSignals(False)
|
||||||
|
|
||||||
def _closer_point(self, event):
|
def _select_range_in_table(self, ind1, ind2):
|
||||||
|
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()
|
||||||
@@ -166,22 +236,62 @@ class Plot(PamhyrPlot):
|
|||||||
|
|
||||||
def dist_mouse(point):
|
def dist_mouse(point):
|
||||||
x, y = point[1]
|
x, y = point[1]
|
||||||
d = sqrt(
|
d2 = ((mx - x) / ratio) ** 2 + ((my - y) ** 2)
|
||||||
(((mx - x) / ratio) ** 2) +
|
return d2
|
||||||
((my - y) ** 2)
|
|
||||||
)
|
|
||||||
return d
|
|
||||||
|
|
||||||
closer = min(
|
closest = min(
|
||||||
points, key=dist_mouse
|
points, key=dist_mouse
|
||||||
)
|
)
|
||||||
|
|
||||||
return closer
|
return closest
|
||||||
|
|
||||||
def _get_z_from_click(self, event):
|
def _get_z_from_click(self, event):
|
||||||
return event.ydata
|
return event.ydata
|
||||||
|
|
||||||
def _compute_hydrolics(self, z):
|
def rect_select_callback(self, eclick, erelease):
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -210,7 +320,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=30
|
picker=10
|
||||||
)
|
)
|
||||||
|
|
||||||
self.draw_annotation(x, y)
|
self.draw_annotation(x, y)
|
||||||
@@ -269,12 +379,16 @@ 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 = (
|
||||||
@@ -299,6 +413,7 @@ 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,
|
||||||
@@ -310,12 +425,15 @@ 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,16 +82,6 @@ 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
|
||||||
|
|
||||||
@@ -104,16 +94,6 @@ 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):
|
||||||
@@ -250,11 +230,11 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
|||||||
self.endMoveRows()
|
self.endMoveRows()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def purge(self):
|
def purge(self, np_purge):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
PurgeCommand(
|
PurgeCommand(
|
||||||
self._data, 24
|
self._data, np_purge
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ 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
|
from tools import trace, timer, logger_exception
|
||||||
from Modules import Modules
|
from Modules import Modules
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
@@ -46,9 +47,12 @@ 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"
|
||||||
@@ -111,7 +115,8 @@ 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()
|
||||||
|
|
||||||
@@ -142,7 +147,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_indexes(rows)
|
self._plot.select_points_from_indices(rows)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.update_plot()
|
self.update_plot()
|
||||||
@@ -165,7 +170,6 @@ 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)
|
||||||
|
|
||||||
@@ -258,6 +262,19 @@ 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()
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# 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):
|
def purge(self, np_purge):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
PurgeCommand(
|
PurgeCommand(
|
||||||
self._data, 24
|
self._data, np_purge
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
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", "File mage geometry (*.ST *.st)")
|
"Geometry", "Mage geometry file (*.ST *.st)")
|
||||||
self._dict["file_m"] = _translate(
|
self._dict["file_m"] = _translate(
|
||||||
"Geometry", "File mage meshed geometry (*.M *.m)")
|
"Geometry", "Mage meshed geometry file (*.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 file (*)")
|
self._dict["file_all"] = _translate("Geometry", "All files (*)")
|
||||||
|
|
||||||
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 means between the two guide-lines"
|
"the mean over the two guide-lines"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# MeshingDialog.py -- Pamhyr
|
# UpdateKPDialog.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,
|
QDoubleSpinBox, QButtonGroup,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -50,14 +50,20 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
self._init_default_values()
|
self._init_default_values()
|
||||||
|
|
||||||
def _init_default_values(self):
|
def _init_default_values(self):
|
||||||
self._space_step = 50.0
|
gl, _ = self._reach.compute_guidelines()
|
||||||
self._lplan = False
|
self._gl = list(gl)
|
||||||
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
|
||||||
|
|
||||||
@@ -69,8 +75,19 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
|
|
||||||
self.combobox_add_items("comboBox_origin", profiles)
|
self.combobox_add_items("comboBox_origin", profiles)
|
||||||
|
|
||||||
self.find(QComboBox, "comboBox_origin").currentIndexChanged.connect(
|
self.find(QComboBox, "comboBox_origin")\
|
||||||
self.changed_profile)
|
.currentIndexChanged\
|
||||||
|
.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")
|
||||||
@@ -102,11 +119,8 @@ class UpdateKPDialog(PamhyrDialog):
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
def _init_default_values_guidelines(self):
|
def _init_default_values_guidelines(self):
|
||||||
gl, _ = self._reach.compute_guidelines()
|
bgl = ['un'] + self._gl + ['np']
|
||||||
gl = list(gl)
|
egl = ['un'] + self._gl + ['np']
|
||||||
|
|
||||||
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)
|
||||||
@@ -114,6 +128,10 @@ 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
|
||||||
@@ -133,11 +151,12 @@ 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()
|
||||||
|
|
||||||
|
|||||||
+40
-66
@@ -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, QSlider, QPushButton, QVBoxLayout,
|
QAction, QPushButton, QVBoxLayout,
|
||||||
QLabel, QAbstractItemView,
|
QLabel, QAbstractItemView,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,6 +57,7 @@ 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
|
||||||
|
|
||||||
@@ -96,7 +97,6 @@ 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,6 +157,9 @@ 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)
|
||||||
@@ -197,13 +200,6 @@ 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\
|
||||||
@@ -224,7 +220,6 @@ 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)
|
||||||
@@ -298,10 +293,8 @@ 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)
|
||||||
@@ -334,6 +327,7 @@ 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:
|
||||||
@@ -360,7 +354,9 @@ 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()
|
||||||
|
|
||||||
@@ -379,7 +375,9 @@ 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()
|
||||||
|
|
||||||
@@ -405,7 +403,6 @@ 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)
|
||||||
|
|
||||||
@@ -433,27 +430,11 @@ 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 len(self.tableView.selectedIndexes()) > 0:
|
if row is not None:
|
||||||
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)
|
||||||
@@ -464,33 +445,6 @@ 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())
|
||||||
@@ -511,29 +465,37 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
self._table.delete(rows)
|
self._table.delete(rows)
|
||||||
|
|
||||||
def index_selected_row(self):
|
def index_selected_row(self):
|
||||||
return self.tableView\
|
r = self.tableView\
|
||||||
.selectionModel()\
|
.selectionModel()\
|
||||||
.selectedRows()[0]\
|
.selectedRows()
|
||||||
.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()
|
||||||
|
|
||||||
@@ -541,6 +503,18 @@ 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 Structures"
|
"BasicHydraulicStructures", "Basic Hydraulic Structure"
|
||||||
)
|
)
|
||||||
|
|
||||||
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,8 +20,9 @@ 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
|
QCoreApplication, Qt,
|
||||||
)
|
)
|
||||||
|
from PyQt5.QtWidgets import QApplication
|
||||||
|
|
||||||
from matplotlib.collections import LineCollection
|
from matplotlib.collections import LineCollection
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ 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):
|
||||||
@@ -91,7 +93,14 @@ 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:
|
||||||
@@ -99,7 +108,8 @@ 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):
|
||||||
@@ -163,3 +173,40 @@ 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,7 +141,8 @@ 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,18 +52,41 @@ class PlotDischarge(PamhyrPlot):
|
|||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
def draw_data(self):
|
def draw_data(self):
|
||||||
kp = self.data.reach.reach.get_kp()
|
self.line_discharge = []
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
self.line_kp_zmin = self.canvas.axes.plot(
|
line, = 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):
|
||||||
self.draw()
|
if not self._init:
|
||||||
|
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,6 +138,7 @@ 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)
|
||||||
@@ -154,6 +155,7 @@ 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,8 +194,13 @@ 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()
|
||||||
|
|||||||
@@ -1,237 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
# 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)
|
|
||||||
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# 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.dataChanged.emit(index, index)
|
self.update()
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
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.layoutChanged.emit()
|
self.update()
|
||||||
|
|
||||||
def paste(self, row, header, data):
|
def paste(self, row, header, data):
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
@@ -190,4 +190,13 @@ 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,6 +137,7 @@ 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