mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
126
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1db1a543c7 | ||
|
|
3e92a0c40d | ||
|
|
f3c461cbd9 | ||
|
|
012408d19e | ||
|
|
f7e563e71a | ||
|
|
81c6d39c1a | ||
|
|
d682443e1d | ||
|
|
c065b19ef8 | ||
|
|
b20a4c3c3d | ||
|
|
d66e75c183 | ||
|
|
31b4c47379 | ||
|
|
71bba499e0 | ||
|
|
7a08fa42d9 | ||
|
|
18a008462a | ||
|
|
d81da59398 | ||
|
|
3ab1eabe75 | ||
|
|
cf4f860db8 | ||
|
|
c68e3337ef | ||
|
|
db1ae613d6 | ||
|
|
a800816cda | ||
|
|
d4ef06c7c1 | ||
|
|
95d1d231c9 | ||
|
|
10b278e26f | ||
|
|
0550eef2eb | ||
|
|
73eb9919eb | ||
|
|
9116009b0b | ||
|
|
4e4ceb5074 | ||
|
|
d79e2ff187 | ||
|
|
d4a2594239 | ||
|
|
b666162bdf | ||
|
|
d705accaed | ||
|
|
d93917b081 | ||
|
|
ceff5f3083 | ||
|
|
97762756f8 | ||
|
|
2c49e991b4 | ||
|
|
c2a8f38ef5 | ||
|
|
f8a41fce08 | ||
|
|
624ae826eb | ||
|
|
d47dc0687e | ||
|
|
117e5222e4 | ||
|
|
b1c7a77f37 | ||
|
|
7b833390f1 | ||
|
|
ae08642116 | ||
|
|
c1905aa7e1 | ||
|
|
97ece018aa | ||
|
|
7f0102a881 | ||
|
|
786923bdbf | ||
|
|
deb9b2069f | ||
|
|
9308a73e8e | ||
|
|
869e116ad0 | ||
|
|
a2f3d22001 | ||
|
|
2e360943b2 | ||
|
|
8976f054c7 | ||
|
|
7bce725c63 | ||
|
|
5c83d67865 | ||
|
|
6e52b1681e | ||
|
|
f27b2cc586 | ||
|
|
1ed5d69bf4 | ||
|
|
5bb6cc40fe | ||
|
|
4c0a12dcf9 | ||
|
|
a308af41e0 | ||
|
|
02db91f3d7 | ||
|
|
4cf4015579 | ||
|
|
291b97ac9b | ||
|
|
b04e367e72 | ||
|
|
81d58122d6 | ||
|
|
874f592cf4 | ||
|
|
9b0bdd1e63 | ||
|
|
d934b5e381 | ||
|
|
14549330b9 | ||
|
|
2487bec6d6 | ||
|
|
4e1acfecdc | ||
|
|
c63c776989 | ||
|
|
44a8be6be3 | ||
|
|
a5a64f2080 | ||
|
|
16ee5a90e4 | ||
|
|
7ca6e69526 | ||
|
|
279fa0bf5e | ||
|
|
abe24611b3 | ||
|
|
17a18dde18 | ||
|
|
044818072e | ||
|
|
8bd791b2c4 | ||
|
|
c8d0d0c212 | ||
|
|
d31be61af8 | ||
|
|
a8a408b5d5 | ||
|
|
ff9d25412c | ||
|
|
de7f3e63b1 | ||
|
|
879c151524 | ||
|
|
7990a60d8b | ||
|
|
8aa0e25da2 | ||
|
|
1e6a578890 | ||
|
|
1dca9b98df | ||
|
|
de180b3635 | ||
|
|
5ca763ac8c | ||
|
|
188486f33a | ||
|
|
bc08d06bb1 | ||
|
|
05e039011a | ||
|
|
7640123299 | ||
|
|
e6dd983f97 | ||
|
|
002ebc5928 | ||
|
|
84486c03ed | ||
|
|
dc7dfb2414 | ||
|
|
ee01beb844 | ||
|
|
a31e2127e7 | ||
|
|
68b62a5630 | ||
|
|
990d44dd07 | ||
|
|
819ae41c00 | ||
|
|
bf95b7f7e6 | ||
|
|
861b78b928 | ||
|
|
a29df8f904 | ||
|
|
08c414a66e | ||
|
|
97ebf9324a | ||
|
|
0112ad63d9 | ||
|
|
bcbb440ad4 | ||
|
|
57a80d00aa | ||
|
|
70eae5f7d2 | ||
|
|
e2a65e2cdd | ||
|
|
f03b74614e | ||
|
|
532b3fd7fd | ||
|
|
64df4129d4 | ||
|
|
f6e35e2045 | ||
|
|
a97717a624 | ||
|
|
3f650de52f | ||
|
|
1f4bda7976 | ||
|
|
a4423e45f8 | ||
|
|
1386c592bf |
No files matched your search
+47
-2
@@ -24,6 +24,13 @@ stages:
|
|||||||
- antivirus
|
- antivirus
|
||||||
- release
|
- release
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# PYINSTALLER VARIABLES #
|
||||||
|
#########################
|
||||||
|
|
||||||
|
variables:
|
||||||
|
HIDDEN_IMPORTS: "--hiddenimport rasterio --collect-submodules rasterio"
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# DOWNLOADS #
|
# DOWNLOADS #
|
||||||
#############
|
#############
|
||||||
@@ -31,6 +38,7 @@ stages:
|
|||||||
variables:
|
variables:
|
||||||
MAGE_8_VERSION: "permalink/latest"
|
MAGE_8_VERSION: "permalink/latest"
|
||||||
ADISTS_VERSION: "permalink/latest"
|
ADISTS_VERSION: "permalink/latest"
|
||||||
|
RUBAR_VERSION: "permalink/latest"
|
||||||
|
|
||||||
dl-mage8-doc:
|
dl-mage8-doc:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -104,6 +112,36 @@ dl-adists-windows:
|
|||||||
paths:
|
paths:
|
||||||
- adists-windows/adists.exe
|
- adists-windows/adists.exe
|
||||||
|
|
||||||
|
dl-rubar-linux:
|
||||||
|
stage: downloads
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- mkdir -p rubar-linux
|
||||||
|
- cd rubar-linux
|
||||||
|
- curl -L -o rubar.tgz https://forge.inrae.fr/river-hydraulics/rubarbe/-/releases/$RUBAR_VERSION/downloads/packages/rubar_linux.tgz
|
||||||
|
- tar xf rubar.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- rubar-linux/rubarbe
|
||||||
|
|
||||||
|
dl-rubar-windows:
|
||||||
|
stage: downloads
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- mkdir -p rubar-windows
|
||||||
|
- cd rubar-windows
|
||||||
|
- curl -L -o rubar.tgz https://forge.inrae.fr/river-hydraulics/rubarbe/-/releases/$RUBAR_VERSION/downloads/packages/rubar_windows.tgz
|
||||||
|
- tar xf rubar.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- rubar-windows/rubarbe.exe
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# CONFIGURE #
|
# CONFIGURE #
|
||||||
#############
|
#############
|
||||||
@@ -266,6 +304,8 @@ build-linux:
|
|||||||
needs:
|
needs:
|
||||||
- job: dl-adists-linux
|
- job: dl-adists-linux
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
- job: dl-rubar-linux
|
||||||
|
artifacts: true
|
||||||
- job: dl-mage8-linux
|
- job: dl-mage8-linux
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: dl-mage8-doc
|
- job: dl-mage8-doc
|
||||||
@@ -292,7 +332,7 @@ build-linux:
|
|||||||
- pip3 install -r ../requirements.txt
|
- pip3 install -r ../requirements.txt
|
||||||
- pip3 install -U -r ../requirements.txt
|
- pip3 install -U -r ../requirements.txt
|
||||||
# Run Pyinstaller
|
# Run Pyinstaller
|
||||||
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
- pyinstaller -y $HIDDEN_IMPORTS --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir -p pamhyr
|
- mkdir -p pamhyr
|
||||||
- mkdir -p pamhyr/_internal
|
- mkdir -p pamhyr/_internal
|
||||||
@@ -307,6 +347,9 @@ build-linux:
|
|||||||
# Copy adists
|
# Copy adists
|
||||||
- mkdir -p pamhyr/adists
|
- mkdir -p pamhyr/adists
|
||||||
- cp -v ../adists-linux/* pamhyr/adists/
|
- cp -v ../adists-linux/* pamhyr/adists/
|
||||||
|
# Copy rubar
|
||||||
|
- mkdir -p pamhyr/rubar
|
||||||
|
- cp -v ../rubar-linux/* pamhyr/rubar/
|
||||||
# Copy Pamhyr
|
# Copy Pamhyr
|
||||||
- cp -r dist/pamhyr/* pamhyr/
|
- cp -r dist/pamhyr/* pamhyr/
|
||||||
# Pamhyr script to force x11
|
# Pamhyr script to force x11
|
||||||
@@ -372,6 +415,8 @@ build-windows:
|
|||||||
artifacts: true
|
artifacts: true
|
||||||
- job: dl-adists-windows
|
- job: dl-adists-windows
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
- job: dl-rubar-windows
|
||||||
|
artifacts: true
|
||||||
- job: dl-mage8-doc
|
- job: dl-mage8-doc
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: set-version
|
- job: set-version
|
||||||
@@ -395,7 +440,7 @@ build-windows:
|
|||||||
- python -m pip install -U -r ..\requirements.txt
|
- python -m pip install -U -r ..\requirements.txt
|
||||||
# Run Pyinstaller
|
# Run Pyinstaller
|
||||||
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
||||||
- pyinstaller -i ../src/View/ui/ressources/icon.ico --hide-console hide-early -y ..\src\pamhyr.py
|
- pyinstaller -i ../src/View/ui/ressources/icon.ico $HIDDEN_IMPORTS --hide-console hide-early -y ..\src\pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir pamhyr
|
- mkdir pamhyr
|
||||||
- dir
|
- dir
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
+2
-1
@@ -19,4 +19,5 @@
|
|||||||
"python-pyqt@5" "python-pyqt5-sip"
|
"python-pyqt@5" "python-pyqt5-sip"
|
||||||
"python-pyqtgraph" "python-qscintilla"
|
"python-pyqtgraph" "python-qscintilla"
|
||||||
"python-numpy@1" "python-shapely" "python-pyshp"
|
"python-numpy@1" "python-shapely" "python-pyshp"
|
||||||
"python-matplotlib" "python-rasterio"))
|
"python-matplotlib" "python-colorama"
|
||||||
|
"python-rasterio"))
|
||||||
@@ -46,6 +46,10 @@ copy /y ..\mage8-windows\mage_extraire.exe pamhyr\mage8\
|
|||||||
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
|
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
|
||||||
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
|
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
|
||||||
|
|
||||||
|
rem rubar
|
||||||
|
mkdir pamhyr\rubar
|
||||||
|
copy /y ..\adists-windows\rubarbe.exe pamhyr\rubar\
|
||||||
|
|
||||||
rem adists
|
rem adists
|
||||||
mkdir pamhyr\adists
|
mkdir pamhyr\adists
|
||||||
copy /y ..\adists-windows\adists.exe pamhyr\adists\
|
copy /y ..\adists-windows\adists.exe pamhyr\adists\
|
||||||
|
|||||||
+106
-76
@@ -17,7 +17,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from numpy import sign
|
from numpy import sign, interp
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from tools import logger_color_red, logger_color_reset, logger_exception
|
from tools import logger_color_red, logger_color_reset, logger_exception
|
||||||
@@ -40,20 +40,24 @@ class InternalMeshing(AMeshingTool):
|
|||||||
step: float = 50,
|
step: float = 50,
|
||||||
limites=[-1, -1],
|
limites=[-1, -1],
|
||||||
linear: bool = True):
|
linear: bool = True):
|
||||||
if reach is None or len(reach.profiles) == 0:
|
|
||||||
return reach
|
|
||||||
|
|
||||||
if limites[0] > limites[1]:
|
# pre process
|
||||||
lim = limites[1]
|
|
||||||
limites[1] = limites[0]
|
|
||||||
limites[0] = lim
|
|
||||||
elif limites[0] == limites[1]:
|
|
||||||
return reach
|
|
||||||
|
|
||||||
# we never modify original profiles, we work on copies
|
profiles = self.get_profiles(reach, limites)
|
||||||
m_profiles = self.st_to_m(reach, limites)
|
if profiles is None:
|
||||||
new_profiles = self.interpolate_transversal_step(m_profiles,
|
return []
|
||||||
step)
|
|
||||||
|
for p in profiles:
|
||||||
|
if len(p) < 1:
|
||||||
|
return []
|
||||||
|
|
||||||
|
guide_list = self.get_guide_list(reach, profiles)
|
||||||
|
if guide_list is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# we never modify original profiles, we work on the copies
|
||||||
|
m_profiles = self.st_to_m(profiles, guide_list)
|
||||||
|
new_profiles = self.interpolate_transversal_step(m_profiles, step)
|
||||||
|
|
||||||
for new_profiles2 in new_profiles:
|
for new_profiles2 in new_profiles:
|
||||||
for p in new_profiles2:
|
for p in new_profiles2:
|
||||||
@@ -61,52 +65,31 @@ class InternalMeshing(AMeshingTool):
|
|||||||
|
|
||||||
return new_profiles
|
return new_profiles
|
||||||
|
|
||||||
def st_to_m(self, reach, limites):
|
def st_to_m(self, profiles, guide_list):
|
||||||
|
|
||||||
gl = reach.compute_guidelines()
|
guide_list = ["un"] + guide_list + ["np"]
|
||||||
profiles = [reach.profile(i).copy()
|
max_values = [0] * (len(guide_list) - 1)
|
||||||
for i in range(limites[0], limites[1]+1)
|
max_values_index = [0] * (len(guide_list) - 1)
|
||||||
]
|
|
||||||
|
|
||||||
# we make sure that the lines are in the left-to-right order
|
|
||||||
guide_list = [
|
|
||||||
x.name
|
|
||||||
for x in profiles[0].named_points()
|
|
||||||
if x.name in gl[0]
|
|
||||||
]
|
|
||||||
|
|
||||||
gl1 = [""] + guide_list
|
|
||||||
gl2 = guide_list + [""]
|
|
||||||
max_values = [0] * (len(guide_list) + 1)
|
|
||||||
max_values_index = [0] * (len(guide_list) + 1)
|
|
||||||
# we work between each couple of guidelines
|
# we work between each couple of guidelines
|
||||||
for j, p in enumerate(profiles):
|
for j, p in enumerate(profiles):
|
||||||
index1 = 0
|
|
||||||
index2 = p.named_point_index(guide_list[0])
|
|
||||||
if index2 - index1 > max_values[0]:
|
|
||||||
max_values[0] = index2 - index1
|
|
||||||
max_values_index[0] = j
|
|
||||||
for i in range(len(guide_list) - 1):
|
for i in range(len(guide_list) - 1):
|
||||||
index1 = p.named_point_index(guide_list[i])
|
index1 = p.named_point_index(guide_list[i])
|
||||||
index2 = p.named_point_index(guide_list[i+1])
|
index2 = p.named_point_index(guide_list[i+1])
|
||||||
if index2 - index1 > max_values[i+1]:
|
if index2 - index1 > max_values[i]:
|
||||||
max_values[i+1] = index2 - index1
|
max_values[i] = index2 - index1
|
||||||
max_values_index[i+1] = j
|
max_values_index[i] = j
|
||||||
index1 = p.named_point_index(guide_list[-1])
|
|
||||||
index2 = len(p) - 1
|
|
||||||
if index2 - index1 > max_values[-1]:
|
|
||||||
max_values[-1] = index2 - index1
|
|
||||||
max_values_index[-1] = j
|
|
||||||
|
|
||||||
for i in range(len(max_values)):
|
for i in range(len(max_values)):
|
||||||
for isect in range(max_values_index[i], len(profiles)-1):
|
for isect in range(max_values_index[i], len(profiles)-1):
|
||||||
self.compl_sect(profiles[isect],
|
self.compl_sect(profiles[isect],
|
||||||
profiles[isect+1],
|
profiles[isect+1],
|
||||||
gl1[i], gl2[i])
|
guide_list[i],
|
||||||
|
guide_list[i+1])
|
||||||
for isect in reversed(range(0, max_values_index[i])):
|
for isect in reversed(range(0, max_values_index[i])):
|
||||||
self.compl_sect(profiles[isect+1],
|
self.compl_sect(profiles[isect+1],
|
||||||
profiles[isect],
|
profiles[isect],
|
||||||
gl1[i], gl2[i])
|
guide_list[i],
|
||||||
|
guide_list[i+1])
|
||||||
return profiles
|
return profiles
|
||||||
|
|
||||||
def interpolate_transversal_step(self,
|
def interpolate_transversal_step(self,
|
||||||
@@ -156,26 +139,17 @@ class InternalMeshing(AMeshingTool):
|
|||||||
# len1 and 2: number of intervals
|
# len1 and 2: number of intervals
|
||||||
# len1: target len
|
# len1: target len
|
||||||
|
|
||||||
if tag1 == '': # left end point
|
start1 = sect1.named_point_index(tag1)
|
||||||
start1 = 0
|
start2 = sect2.named_point_index(tag1)
|
||||||
start2 = 0
|
|
||||||
else:
|
|
||||||
start1 = sect1.named_point_index(tag1)
|
|
||||||
start2 = sect2.named_point_index(tag1)
|
|
||||||
|
|
||||||
if tag2 == '': # right end point
|
end1 = sect1.named_point_index(tag2)
|
||||||
end1 = sect1.nb_points-1
|
end2 = sect2.named_point_index(tag2)
|
||||||
end2 = sect2.nb_points-1
|
|
||||||
else:
|
|
||||||
end1 = sect1.named_point_index(tag2)
|
|
||||||
end2 = sect2.named_point_index(tag2)
|
|
||||||
|
|
||||||
len1 = end1 - start1
|
len1 = end1 - start1
|
||||||
len2 = end2 - start2
|
len2 = end2 - start2
|
||||||
|
|
||||||
if len1 < len2:
|
if len1 < len2:
|
||||||
self.compl_sect(sect2, sect1, start2, start1,
|
self.compl_sect(sect2, sect1, tag1, tag2)
|
||||||
len2, len1, tag1, tag2)
|
|
||||||
return
|
return
|
||||||
elif len1 == len2:
|
elif len1 == len2:
|
||||||
return
|
return
|
||||||
@@ -194,23 +168,21 @@ class InternalMeshing(AMeshingTool):
|
|||||||
for i in range(len2):
|
for i in range(len2):
|
||||||
ltot2 += sect2.point(start2+i).dist(sect2.point(start2+i+1))
|
ltot2 += sect2.point(start2+i).dist(sect2.point(start2+i+1))
|
||||||
beta.append(ltot2)
|
beta.append(ltot2)
|
||||||
beta = list(map(lambda x: x/ltot2, beta)) # current ratios
|
|
||||||
for i in range(len1 - len2):
|
|
||||||
beta.append(1.0)
|
|
||||||
beta.append(0.0) # beta[-1]
|
|
||||||
if len2 < 1 or ltot2 < 0.0001:
|
if len2 < 1 or ltot2 < 0.0001:
|
||||||
# unique point (copy len1 times)
|
# unique point (copy len1 times)
|
||||||
# we are at an edge of the profile
|
# we are at an edge of the profile
|
||||||
for i in range(len1-len2):
|
for i in range(len1-len2):
|
||||||
p = sect2.point(start2).copy()
|
p = sect2.point(start2).copy()
|
||||||
sect2.insert_point(start2, p)
|
sect2.insert_point(start2, p)
|
||||||
if tag1 == '': # left end point
|
len2 += 1
|
||||||
sect2.point(start2).name = ''
|
|
||||||
if tag2 == '': # left end point
|
|
||||||
sect2.point(start2+1).name = ''
|
|
||||||
elif ltot1 < 0.0001:
|
elif ltot1 < 0.0001:
|
||||||
sect2.add_npoints(len1-len2)
|
sect2.add_npoints(len1-len2)
|
||||||
|
len2 = len1
|
||||||
else: # regular case
|
else: # regular case
|
||||||
|
beta = list(map(lambda x: x/ltot2, beta)) # current ratios
|
||||||
|
for i in range(len1 - len2):
|
||||||
|
beta.append(1.0)
|
||||||
|
beta.append(0.0) # beta[-1]
|
||||||
# loop on the points to insert
|
# loop on the points to insert
|
||||||
for k in range(len1-len2):
|
for k in range(len1-len2):
|
||||||
trouve = False
|
trouve = False
|
||||||
@@ -269,11 +241,13 @@ class InternalMeshing(AMeshingTool):
|
|||||||
p = sect2.point(start2+len2).copy()
|
p = sect2.point(start2+len2).copy()
|
||||||
sect2.insert_point(start2+len2, p)
|
sect2.insert_point(start2+len2, p)
|
||||||
sect2.point(start2+len2).name = ''
|
sect2.point(start2+len2).name = ''
|
||||||
sect2.point(start2).name = tag1
|
if tag1 != "un":
|
||||||
sect2.point(start2+len2).name = tag2
|
sect2.point(start2).name = tag1
|
||||||
|
if tag1 != "np":
|
||||||
|
sect2.point(start2+len2).name = tag2
|
||||||
sect2.modified()
|
sect2.modified()
|
||||||
|
|
||||||
def update_rk(self, reach,
|
def update_rk(self, reach, begin_rk, end_rk,
|
||||||
step: float = 50,
|
step: float = 50,
|
||||||
limites=[-1, -1],
|
limites=[-1, -1],
|
||||||
origin=0,
|
origin=0,
|
||||||
@@ -297,15 +271,27 @@ class InternalMeshing(AMeshingTool):
|
|||||||
# 1: up -> downstream
|
# 1: up -> downstream
|
||||||
# 2: down -> upstream
|
# 2: down -> upstream
|
||||||
# else: keep current orientation
|
# else: keep current orientation
|
||||||
|
old_orientation = sign(reach.profiles[-1].rk - reach.profiles[0].rk)
|
||||||
if orientation == 1:
|
if orientation == 1:
|
||||||
sgn = 1.0
|
sgn = 1.0
|
||||||
elif orientation == 2:
|
elif orientation == 2:
|
||||||
sgn = -1.0
|
sgn = -1.0
|
||||||
else:
|
else:
|
||||||
sgn = sign(reach.profiles[-1].rk - reach.profiles[0].rk)
|
sgn = old_orientation
|
||||||
|
if abs(sgn) < 0.5:
|
||||||
|
sgn = 1.0
|
||||||
|
|
||||||
rk = [0.0]*nprof
|
new_rk = [0.0]*nprof
|
||||||
rk[origin] = origin_value
|
new_rk[origin] = origin_value
|
||||||
|
|
||||||
|
frictions = reach._parent.frictions
|
||||||
|
|
||||||
|
old_begin_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
begin_rk))
|
||||||
|
old_end_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
end_rk))
|
||||||
|
old_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
reach.get_rk()))
|
||||||
|
|
||||||
if origin < nprof - 1:
|
if origin < nprof - 1:
|
||||||
for i in range(origin+1, nprof):
|
for i in range(origin+1, nprof):
|
||||||
@@ -316,7 +302,7 @@ class InternalMeshing(AMeshingTool):
|
|||||||
d2 = reach.profiles[i-1].named_point(
|
d2 = reach.profiles[i-1].named_point(
|
||||||
directrices[1]
|
directrices[1]
|
||||||
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
||||||
rk[i] = rk[i-1] + (sgn * (d1 + d2) / 2)
|
new_rk[i] = new_rk[i-1] + (sgn * (d1 + d2) / 2)
|
||||||
if origin > 0:
|
if origin > 0:
|
||||||
for i in reversed(range(0, origin)):
|
for i in reversed(range(0, origin)):
|
||||||
# 2D
|
# 2D
|
||||||
@@ -326,6 +312,50 @@ class InternalMeshing(AMeshingTool):
|
|||||||
d2 = reach.profiles[i+1].named_point(
|
d2 = reach.profiles[i+1].named_point(
|
||||||
directrices[1]
|
directrices[1]
|
||||||
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
||||||
rk[i] = rk[i+1] - (sgn * (d1 + d2) / 2)
|
new_rk[i] = new_rk[i+1] - (sgn * (d1 + d2) / 2)
|
||||||
|
|
||||||
return rk
|
new_begin_rk = interp(old_begin_rk, old_rk, new_rk)
|
||||||
|
new_end_rk = interp(old_end_rk, old_rk, new_rk)
|
||||||
|
if abs(sgn - old_orientation) > 0.1: # orientation changed
|
||||||
|
return new_rk, new_end_rk, new_begin_rk
|
||||||
|
else:
|
||||||
|
return new_rk, new_begin_rk, new_end_rk
|
||||||
|
|
||||||
|
def get_guide_list(self, reach, profiles):
|
||||||
|
|
||||||
|
gl = reach.compute_guidelines()
|
||||||
|
|
||||||
|
# we make sure that the lines are in the left-to-right order
|
||||||
|
guide_list = [
|
||||||
|
[
|
||||||
|
x.name
|
||||||
|
for x in p.named_points()
|
||||||
|
if x.name in gl[0]
|
||||||
|
]
|
||||||
|
for p in profiles]
|
||||||
|
|
||||||
|
# we make sure the lines never cross
|
||||||
|
for gl in guide_list:
|
||||||
|
for i in range(len(guide_list[0])):
|
||||||
|
if gl[i] != guide_list[0][i]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return guide_list[0]
|
||||||
|
|
||||||
|
def get_profiles(self, reach, limites):
|
||||||
|
|
||||||
|
if reach is None or len(reach.profiles) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if limites[0] > limites[1]:
|
||||||
|
lim = limites[1]
|
||||||
|
limites[1] = limites[0]
|
||||||
|
limites[0] = lim
|
||||||
|
elif limites[0] == limites[1]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
profiles = [reach.profile(i).copy()
|
||||||
|
for i in range(limites[0], limites[1]+1)
|
||||||
|
]
|
||||||
|
|
||||||
|
return profiles
|
||||||
@@ -582,10 +582,10 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
self._data.index(bc)
|
self._data.index(bc)
|
||||||
|
|
||||||
def get_i(self, index):
|
def get_i(self, index):
|
||||||
if len(self.data) == 0:
|
if len(self._data) == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.data[index]
|
return self._data[index]
|
||||||
|
|
||||||
def get_range(self, _range):
|
def get_range(self, _range):
|
||||||
lst = []
|
lst = []
|
||||||
|
|||||||
@@ -0,0 +1,368 @@
|
|||||||
|
# GeoTIFF.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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 struct
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class GeoTIFF(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, enabled=True,
|
||||||
|
name="", description="",
|
||||||
|
path="", coordinates=None,
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(GeoTIFF, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._enabled = enabled
|
||||||
|
self._name = f"GeoTIFF #{self._pamhyr_id}" if name == "" else name
|
||||||
|
self._description = description
|
||||||
|
|
||||||
|
self._file_bytes = b''
|
||||||
|
if coordinates is None:
|
||||||
|
self._coordinates = {
|
||||||
|
"bottom": 0.0,
|
||||||
|
"top": 0.0,
|
||||||
|
"left": 0.0,
|
||||||
|
"right": 0.0,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self._coordinates = coordinates
|
||||||
|
self._file_name = ""
|
||||||
|
|
||||||
|
if path != "":
|
||||||
|
self.read_file(path)
|
||||||
|
|
||||||
|
self._memfile = None
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if key == "enabled":
|
||||||
|
value = self._enabled
|
||||||
|
elif key == "name":
|
||||||
|
value = self.name
|
||||||
|
elif key == "description":
|
||||||
|
value = self.description
|
||||||
|
elif key == "file_name":
|
||||||
|
value = self.file_name
|
||||||
|
elif key == "coordinates":
|
||||||
|
value = self.coordinates
|
||||||
|
elif key == "coordinates_bottom":
|
||||||
|
value = self.coordinates["bottom"]
|
||||||
|
elif key == "coordinates_top":
|
||||||
|
value = self.coordinates["top"]
|
||||||
|
elif key == "coordinates_left":
|
||||||
|
value = self.coordinates["left"]
|
||||||
|
elif key == "coordinates_right":
|
||||||
|
value = self.coordinates["right"]
|
||||||
|
elif key == "memfile":
|
||||||
|
value = self.memfile
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if key == "enabled":
|
||||||
|
self.enabled = value
|
||||||
|
elif key == "name":
|
||||||
|
self.name = value
|
||||||
|
elif key == "description":
|
||||||
|
self.description = value
|
||||||
|
elif key == "file_name":
|
||||||
|
if self._file_name != value:
|
||||||
|
self.read_file(value)
|
||||||
|
elif key == "coordinates":
|
||||||
|
self.coordinates = value
|
||||||
|
elif key == "coordinates_bottom" or key == "bottom":
|
||||||
|
self.coordinates["bottom"] = value
|
||||||
|
elif key == "coordinates_top" or key == "top":
|
||||||
|
self.coordinates["top"] = value
|
||||||
|
elif key == "coordinates_left" or key == "left":
|
||||||
|
self.coordinates["left"] = value
|
||||||
|
elif key == "coordinates_right" or key == "right":
|
||||||
|
self.coordinates["right"] = value
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@description.setter
|
||||||
|
def description(self, description):
|
||||||
|
self._description = description
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_name(self):
|
||||||
|
return self._file_name
|
||||||
|
|
||||||
|
@file_name.setter
|
||||||
|
def file_name(self, file_name):
|
||||||
|
self._file_name = file_name
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coordinates(self):
|
||||||
|
return self._coordinates
|
||||||
|
|
||||||
|
@coordinates.setter
|
||||||
|
def coordinates(self, coordinates):
|
||||||
|
self._coordinates = coordinates
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_bottom(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["bottom"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_top(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["top"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_left(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["left"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_right(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["right"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def memfile(self):
|
||||||
|
if not _rasterio_loaded:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self._file_bytes == b'':
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self._memfile is None:
|
||||||
|
self._memfile = MemoryFile()
|
||||||
|
self._memfile.write(self._file_bytes)
|
||||||
|
|
||||||
|
return self._memfile
|
||||||
|
|
||||||
|
def read_file(self, path):
|
||||||
|
logger.debug(f"Read GeoTIFF file at : '{path}'")
|
||||||
|
|
||||||
|
self._file_name = path
|
||||||
|
self._file_bytes = b''
|
||||||
|
self._memfile = None
|
||||||
|
|
||||||
|
nbytes = 0
|
||||||
|
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
|
||||||
|
nbytes += len(data)
|
||||||
|
self._file_bytes += data
|
||||||
|
|
||||||
|
logger.debug(f"Read GeoTIFF: {nbytes} bytes readed")
|
||||||
|
|
||||||
|
def write_file(self, path):
|
||||||
|
with open(path, "w+b") as f:
|
||||||
|
f.write(self._file_bytes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE geotiff{ext} (
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
file_name TEXT NOT NULL,
|
||||||
|
file_bytes BLOB NOT NULL,
|
||||||
|
coordinates_bottom REAL NOT NULL,
|
||||||
|
coordinates_top REAL NOT NULL,
|
||||||
|
coordinates_left REAL NOT NULL,
|
||||||
|
coordinates_right REAL NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
if major == "0" and int(minor) == 2:
|
||||||
|
if int(release) < 3:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, description, file_name, file_bytes, " +
|
||||||
|
"coordinates_bottom, coordinates_top, " +
|
||||||
|
"coordinates_left, coordinates_right, " +
|
||||||
|
"scenario " +
|
||||||
|
"FROM geotiff " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
it = iter(row)
|
||||||
|
|
||||||
|
id = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
description = next(it)
|
||||||
|
file_name = next(it)
|
||||||
|
file_bytes = next(it)
|
||||||
|
coordinates_bottom = next(it)
|
||||||
|
coordinates_top = next(it)
|
||||||
|
coordinates_left = next(it)
|
||||||
|
coordinates_right = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
f = cls(
|
||||||
|
id=id, enabled=enabled, name=name,
|
||||||
|
description=description, coordinates={
|
||||||
|
"bottom": coordinates_bottom,
|
||||||
|
"top": coordinates_top,
|
||||||
|
"left": coordinates_left,
|
||||||
|
"right": coordinates_right,
|
||||||
|
},
|
||||||
|
status=data['status'],
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
f.set_as_deleted()
|
||||||
|
|
||||||
|
f._file_bytes = file_bytes
|
||||||
|
|
||||||
|
loaded.add(id)
|
||||||
|
new.append(f)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO geotiff (" +
|
||||||
|
"pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, description, file_name, file_bytes, " +
|
||||||
|
"coordinates_bottom, coordinates_top, " +
|
||||||
|
"coordinates_left, coordinates_right, " +
|
||||||
|
"scenario) " +
|
||||||
|
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
|
self._pamhyr_id,
|
||||||
|
self._enabled,
|
||||||
|
self.is_deleted(),
|
||||||
|
self.name,
|
||||||
|
self.description,
|
||||||
|
self.file_name,
|
||||||
|
self._file_bytes,
|
||||||
|
self.coordinates['bottom'],
|
||||||
|
self.coordinates['top'],
|
||||||
|
self.coordinates['left'],
|
||||||
|
self.coordinates['right'],
|
||||||
|
self._status.scenario_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# GeoTIFFList.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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.PamhyrListExt import PamhyrModelList
|
||||||
|
from Model.GeoTIFF.GeoTIFF import GeoTIFF
|
||||||
|
|
||||||
|
|
||||||
|
class GeoTIFFList(PamhyrModelList):
|
||||||
|
_sub_classes = [GeoTIFF]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
|
new._lst = GeoTIFF._db_load(execute, data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
# Delete previous data
|
||||||
|
execute(
|
||||||
|
"DELETE FROM geotiff " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for gt in self._lst:
|
||||||
|
ok &= gt._db_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
@property
|
||||||
|
def files(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = GeoTIFF(status=self._status)
|
||||||
|
self.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
@@ -76,12 +76,23 @@ class Profile(object):
|
|||||||
return self.points[index]
|
return self.points[index]
|
||||||
|
|
||||||
def named_point(self, name):
|
def named_point(self, name):
|
||||||
return next((p for p in self.points if p.name == name), None)
|
if name == "un":
|
||||||
|
return self.points[0]
|
||||||
|
elif name == "np":
|
||||||
|
return self.points[-1]
|
||||||
|
else:
|
||||||
|
return next((p for p in self.points if p.name == name), None)
|
||||||
|
|
||||||
def named_point_index(self, name):
|
def named_point_index(self, name):
|
||||||
return next(
|
if name == "un":
|
||||||
(p for p in enumerate(self.points) if p[1].name == name), None
|
return 0
|
||||||
)[0]
|
elif name == "np":
|
||||||
|
return len(self.points) - 1
|
||||||
|
else:
|
||||||
|
return next(
|
||||||
|
(p for p in enumerate(self.points) if p[1].name == name),
|
||||||
|
None
|
||||||
|
)[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
|
|||||||
@@ -749,8 +749,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
if zz[i] >= z and zz[i+1] < z:
|
if zz[i] >= z and zz[i+1] < z:
|
||||||
y = np.interp(
|
y = np.interp(
|
||||||
z,
|
z,
|
||||||
[zz[i], zz[i+1]],
|
[zz[i+1], zz[i]],
|
||||||
[station[i], station[i+1]]
|
[station[i+1], station[i]]
|
||||||
)
|
)
|
||||||
line.append([y, z])
|
line.append([y, z])
|
||||||
|
|
||||||
@@ -839,11 +839,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
for i in range(self.number_points-1):
|
for i in range(self.number_points-1):
|
||||||
if zz[i] > z and zz[i+1] <= z:
|
if zz[i] > z and zz[i+1] <= z:
|
||||||
y = np.interp(
|
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||||
z,
|
y = station[i] + fact * (station[i+1] - station[i])
|
||||||
[zz[i], zz[i+1]],
|
|
||||||
[station[i], station[i+1]]
|
|
||||||
)
|
|
||||||
start.append(y)
|
start.append(y)
|
||||||
|
|
||||||
end = []
|
end = []
|
||||||
@@ -852,11 +849,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
for i in reversed(range(self.number_points-1)):
|
for i in reversed(range(self.number_points-1)):
|
||||||
if zz[i] <= z and zz[i+1] > z:
|
if zz[i] <= z and zz[i+1] > z:
|
||||||
y = np.interp(
|
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||||
z,
|
y = station[i] + fact * (station[i+1] - station[i])
|
||||||
[zz[i], zz[i+1]],
|
|
||||||
[station[i], station[i+1]]
|
|
||||||
)
|
|
||||||
end.append(y)
|
end.append(y)
|
||||||
|
|
||||||
if len(start) != len(end):
|
if len(start) != len(end):
|
||||||
@@ -887,33 +881,31 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
# Interpolate points at river left side
|
# Interpolate points at river left side
|
||||||
if (i_left > 0):
|
if (i_left > 0):
|
||||||
x = np.interp(
|
if abs(self.point(i_left - 1).z - self.point(i_left).z) < 1e-20:
|
||||||
z,
|
pt_left = self.point(i_left)
|
||||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
else:
|
||||||
[self.point(i_left).x, self.point(i_left - 1).x]
|
fact = (z - self.point(i_left).z) / \
|
||||||
)
|
(self.point(i_left - 1).z - self.point(i_left).z)
|
||||||
y = np.interp(
|
x = self.point(i_left).x + fact * \
|
||||||
z,
|
(self.point(i_left - 1).x - self.point(i_left).x)
|
||||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
y = self.point(i_left).y + fact * \
|
||||||
[self.point(i_left).y, self.point(i_left - 1).y]
|
(self.point(i_left - 1).y - self.point(i_left).y)
|
||||||
)
|
pt_left = PointXYZ(x=x, y=y, z=z, name="wl_left")
|
||||||
pt_left = PointXYZ(x, y, z, name="wl_left")
|
|
||||||
else:
|
else:
|
||||||
pt_left = self.point(0)
|
pt_left = self.point(0)
|
||||||
|
|
||||||
# Interpolate points at river right side
|
# Interpolate points at river right side
|
||||||
if (i_right < self.number_points - 1):
|
if (i_right < self.number_points - 1):
|
||||||
x = np.interp(
|
if abs(self.point(i_right + 1).z - self.point(i_right).z) < 1e-20:
|
||||||
z,
|
pt_right = self.point(i_right)
|
||||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
else:
|
||||||
[self.point(i_right).x, self.point(i_right + 1).x]
|
fact = (z - self.point(i_right).z) / \
|
||||||
)
|
(self.point(i_right + 1).z - self.point(i_right).z)
|
||||||
y = np.interp(
|
x = self.point(i_right).x + fact * \
|
||||||
z,
|
(self.point(i_right + 1).x - self.point(i_right).x)
|
||||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
y = self.point(i_right).y + fact * \
|
||||||
[self.point(i_right).y, self.point(i_right + 1).y]
|
(self.point(i_right + 1).y - self.point(i_right).y)
|
||||||
)
|
pt_right = PointXYZ(x=x, y=y, z=z, name="wl_right")
|
||||||
pt_right = PointXYZ(x, y, z, name="wl_right")
|
|
||||||
else:
|
else:
|
||||||
pt_right = self.point(self.number_points - 1)
|
pt_right = self.point(self.number_points - 1)
|
||||||
|
|
||||||
@@ -1109,11 +1101,9 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
self.point(i+1).z = 0.5 * self.point(i).z + 0.5 * self.point(i+2).z
|
self.point(i+1).z = 0.5 * self.point(i).z + 0.5 * self.point(i+2).z
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
p = ProfileXYZ(id=self.id,
|
p = ProfileXYZ(name=self.name,
|
||||||
name=self.name,
|
|
||||||
rk=self.rk,
|
rk=self.rk,
|
||||||
reach=self.reach,
|
reach=self.reach,
|
||||||
num=self.num,
|
|
||||||
status=self._status)
|
status=self._status)
|
||||||
for i, k in enumerate(self.points):
|
for i, k in enumerate(self.points):
|
||||||
p.insert_point(i, k.copy())
|
p.insert_point(i, k.copy())
|
||||||
|
|||||||
@@ -195,7 +195,9 @@ class Reach(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
if profile in self._profiles:
|
if profile in self._profiles:
|
||||||
self.undelete([profile])
|
self.undelete([profile])
|
||||||
|
profile.num = index
|
||||||
else:
|
else:
|
||||||
|
profile.num = index
|
||||||
self._profiles.insert(index, profile)
|
self._profiles.insert(index, profile)
|
||||||
|
|
||||||
self.modified()
|
self.modified()
|
||||||
|
|||||||
@@ -537,7 +537,10 @@ class InitialConditions(SQLSubModel):
|
|||||||
strickler = 25.0
|
strickler = 25.0
|
||||||
|
|
||||||
if not compute_discharge:
|
if not compute_discharge:
|
||||||
discharge = data_discharge[profile.rk]
|
if profile.rk in data_discharge:
|
||||||
|
discharge = data_discharge[profile.rk]
|
||||||
|
else:
|
||||||
|
discharge = 0.0
|
||||||
else:
|
else:
|
||||||
discharge = (
|
discharge = (
|
||||||
# ((width * 0.8)
|
# ((width * 0.8)
|
||||||
@@ -605,7 +608,10 @@ class InitialConditions(SQLSubModel):
|
|||||||
strickler = 25.0
|
strickler = 25.0
|
||||||
|
|
||||||
if not compute_height:
|
if not compute_height:
|
||||||
height = data_height[profile.rk]
|
if profile.rk in data_height:
|
||||||
|
height = data_height[profile.rk]
|
||||||
|
else:
|
||||||
|
height = 0.0
|
||||||
else:
|
else:
|
||||||
if abs(incline) <= 0:
|
if abs(incline) <= 0:
|
||||||
height = 0.0
|
height = 0.0
|
||||||
@@ -656,7 +662,10 @@ class InitialConditions(SQLSubModel):
|
|||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
|
|
||||||
if not compute_discharge:
|
if not compute_discharge:
|
||||||
d = data_discharge[profile.rk]
|
if profile.rk in data_discharge:
|
||||||
|
d = data_discharge[profile.rk]
|
||||||
|
else:
|
||||||
|
d = 0.0
|
||||||
else:
|
else:
|
||||||
d = discharge
|
d = discharge
|
||||||
elevation = interp(profile.rk,
|
elevation = interp(profile.rk,
|
||||||
|
|||||||
@@ -307,6 +307,21 @@ class Pollutants(SQLSubModel):
|
|||||||
def data(self):
|
def data(self):
|
||||||
return self._data
|
return self._data
|
||||||
|
|
||||||
|
@data.setter
|
||||||
|
def data(self, data):
|
||||||
|
self._data = [PollutantCharacteristics(type=int(data[0]),
|
||||||
|
diametre=float(data[1]),
|
||||||
|
rho=float(data[2]),
|
||||||
|
porosity=float(data[3]),
|
||||||
|
cdc_riv=float(data[4]),
|
||||||
|
cdc_cas=float(data[5]),
|
||||||
|
apd=float(data[6]),
|
||||||
|
ac=float(data[7]),
|
||||||
|
bc=float(data[8]),
|
||||||
|
pollutant=self,
|
||||||
|
status=self._status
|
||||||
|
)]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute, ext=""):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute(f"""
|
execute(f"""
|
||||||
@@ -397,7 +412,7 @@ class Pollutants(SQLSubModel):
|
|||||||
|
|
||||||
data["pollutant"] = new_pollutant
|
data["pollutant"] = new_pollutant
|
||||||
new_pollutant._data = PollutantCharacteristics._db_load(
|
new_pollutant._data = PollutantCharacteristics._db_load(
|
||||||
execute, data.copy()
|
execute, data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
loaded.add(pid)
|
loaded.add(pid)
|
||||||
@@ -421,7 +436,7 @@ class Pollutants(SQLSubModel):
|
|||||||
f"AND scenario = {self._status.scenario_id}"
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
execute(
|
execute(
|
||||||
f"DELETE FROM pollutants_characteristics " +
|
"DELETE FROM pollutants_characteristics " +
|
||||||
f"WHERE pollutant = {self.id} " +
|
f"WHERE pollutant = {self.id} " +
|
||||||
f"AND scenario = {self._status.scenario_id}"
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ class Reservoir(SQLSubModel):
|
|||||||
new_reservoir.set_as_deleted()
|
new_reservoir.set_as_deleted()
|
||||||
|
|
||||||
new_reservoir._node = None
|
new_reservoir._node = None
|
||||||
if node_id != -1:
|
if node_id != -1 and node_id is not None:
|
||||||
new_reservoir._node = next(
|
new_reservoir._node = next(
|
||||||
filter(
|
filter(
|
||||||
lambda n: n.id == node_id, data["nodes"]
|
lambda n: n.id == node_id, data["nodes"]
|
||||||
|
|||||||
+172
-14
@@ -29,8 +29,134 @@ from Model.Results.River.River import River
|
|||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class AdditionalData(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
|
||||||
|
def __init__(self, id=-1, study=None, data=None):
|
||||||
|
super(AdditionalData, self).__init__(
|
||||||
|
id=id, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
|
self._study = study
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE results_add_data{ext} (
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
result INTEGER NOT NULL,
|
||||||
|
type_x TEXT NOT NULL,
|
||||||
|
type_y TEXT NOT NULL,
|
||||||
|
legend TEXT NOT NULL,
|
||||||
|
unit TEXT NOT NULL,
|
||||||
|
data_len INTEGER NOT NULL,
|
||||||
|
x BLOB NOT NULL,
|
||||||
|
y BLOB NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(result) REFERENCES results(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, result, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == "0" and int(minor) == 2 and int(release) <= 1:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
study = data['study']
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, type_x, type_y, " +
|
||||||
|
"legend, unit, data_len, x, y, " +
|
||||||
|
"scenario " +
|
||||||
|
"FROM results_add_data " +
|
||||||
|
f"WHERE scenario = {scenario.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
for v in table:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
type_x = next(it)
|
||||||
|
type_y = next(it)
|
||||||
|
legend = next(it)
|
||||||
|
unit = next(it)
|
||||||
|
data_len = next(it)
|
||||||
|
bx = next(it)
|
||||||
|
by = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
data_format = ">" + ''.join(itertools.repeat("d", data_len))
|
||||||
|
x = struct.unpack(data_format, bx)
|
||||||
|
y = struct.unpack(data_format, by)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'type_x': type_x,
|
||||||
|
'type_y': type_y,
|
||||||
|
'legend': legend,
|
||||||
|
'unit': unit,
|
||||||
|
'x': x, 'y': y
|
||||||
|
}
|
||||||
|
|
||||||
|
new_data = cls(study=study)
|
||||||
|
new_data._data = data
|
||||||
|
new.append(new_data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if self._status.scenario.id != self._owner_scenario:
|
||||||
|
return
|
||||||
|
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
data_len = len(self._data["x"])
|
||||||
|
|
||||||
|
data_format = ">" + ''.join(itertools.repeat("d", data_len))
|
||||||
|
bx = struct.pack(data_format, *self._data["x"])
|
||||||
|
by = struct.pack(data_format, *self._data["y"])
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"results_add_data (pamhyr_id, result, " +
|
||||||
|
"type_x, type_y, " +
|
||||||
|
"legend, unit, data_len, x, y, " +
|
||||||
|
"scenario) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
self._pamhyr_id, data["result"],
|
||||||
|
self._data["type_x"], self._data["type_y"],
|
||||||
|
self._data["legend"], self._data["unit"],
|
||||||
|
data_len, bx, by, self._owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Results(SQLSubModel):
|
class Results(SQLSubModel):
|
||||||
_sub_classes = [River]
|
_sub_classes = [River, AdditionalData]
|
||||||
|
|
||||||
def __init__(self, id=-1, study=None, solver=None,
|
def __init__(self, id=-1, study=None, solver=None,
|
||||||
repertory="", name="0"):
|
repertory="", name="0"):
|
||||||
@@ -50,8 +176,12 @@ class Results(SQLSubModel):
|
|||||||
# Keep results creation date
|
# Keep results creation date
|
||||||
"creation_date": datetime.now(),
|
"creation_date": datetime.now(),
|
||||||
"study_revision": study.status.version,
|
"study_revision": study.status.version,
|
||||||
|
"additional_data": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if solver is not None:
|
||||||
|
self.set("solver_type", solver._type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
date = self._meta_data["creation_date"]
|
date = self._meta_data["creation_date"]
|
||||||
@@ -112,7 +242,10 @@ class Results(SQLSubModel):
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return True
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version, data=None):
|
def _db_update(cls, execute, version, data=None):
|
||||||
@@ -147,7 +280,7 @@ class Results(SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if table is None:
|
if table is None:
|
||||||
yield new
|
yield
|
||||||
|
|
||||||
if len(table) > 1:
|
if len(table) > 1:
|
||||||
logger.warning("Multiple results for this scenario")
|
logger.warning("Multiple results for this scenario")
|
||||||
@@ -178,23 +311,43 @@ class Results(SQLSubModel):
|
|||||||
data["timestamps"] = sorted(ts)
|
data["timestamps"] = sorted(ts)
|
||||||
new_results._river = River._db_load(execute, data)
|
new_results._river = River._db_load(execute, data)
|
||||||
|
|
||||||
new = new_results
|
new_results.set(
|
||||||
|
"additional_data",
|
||||||
|
AdditionalData._db_load(execute, data)
|
||||||
|
)
|
||||||
|
|
||||||
yield new
|
yield (solver_type, new_results)
|
||||||
|
|
||||||
|
def _db_save_clear(self, execute, solver_type, data=None):
|
||||||
|
old_pid = execute(
|
||||||
|
"SELECT pamhyr_id FROM results " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND solver_type = '{solver_type}'"
|
||||||
|
)
|
||||||
|
if len(old_pid) != 0:
|
||||||
|
for pid in old_pid:
|
||||||
|
pid = pid[0]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND solver_type = '{solver_type}'"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results_data " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND result = {pid}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results_add_data " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND result = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
if self._status.scenario.id != self._owner_scenario:
|
if self._status.scenario.id != self._owner_scenario:
|
||||||
return
|
return
|
||||||
|
|
||||||
execute(
|
|
||||||
"DELETE FROM results " +
|
|
||||||
f"WHERE scenario = {self._owner_scenario}"
|
|
||||||
)
|
|
||||||
execute(
|
|
||||||
"DELETE FROM results_data " +
|
|
||||||
f"WHERE scenario = {self._owner_scenario}"
|
|
||||||
)
|
|
||||||
|
|
||||||
pid = self._pamhyr_id
|
pid = self._pamhyr_id
|
||||||
if self._solver is None:
|
if self._solver is None:
|
||||||
solver_name = self.get("solver_name")
|
solver_name = self.get("solver_name")
|
||||||
@@ -203,6 +356,8 @@ class Results(SQLSubModel):
|
|||||||
solver_name = self._solver._name
|
solver_name = self._solver._name
|
||||||
solver_type = self._solver._type
|
solver_type = self._solver._type
|
||||||
|
|
||||||
|
self._db_save_clear(execute, solver_type, data=data)
|
||||||
|
|
||||||
ts = sorted(self.get("timestamps"))
|
ts = sorted(self.get("timestamps"))
|
||||||
sf = ">" + ''.join(itertools.repeat("d", len(ts)))
|
sf = ">" + ''.join(itertools.repeat("d", len(ts)))
|
||||||
|
|
||||||
@@ -220,4 +375,7 @@ class Results(SQLSubModel):
|
|||||||
data["result"] = self._pamhyr_id
|
data["result"] = self._pamhyr_id
|
||||||
self._river._db_save(execute, data)
|
self._river._db_save(execute, data)
|
||||||
|
|
||||||
|
for add_data in self.get("additional_data"):
|
||||||
|
add_data._db_save(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -50,6 +50,9 @@ class Results(object):
|
|||||||
|
|
||||||
self._phys_var_list = ["C", "G", "M", "D", "L", "N", "R"]
|
self._phys_var_list = ["C", "G", "M", "D", "L", "N", "R"]
|
||||||
|
|
||||||
|
if solver is not None:
|
||||||
|
self.set("solver_type", solver._type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
date = self._meta_data["creation_date"]
|
date = self._meta_data["creation_date"]
|
||||||
|
|||||||
@@ -105,16 +105,6 @@ class Profile(SQLSubModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version, data=None):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
create = False
|
|
||||||
|
|
||||||
if major == "0" and int(minor) < 2:
|
|
||||||
cls._db_create(execute)
|
|
||||||
create = True
|
|
||||||
|
|
||||||
if major == "0" and int(minor) == 2:
|
|
||||||
if int(release) < 1 and not create:
|
|
||||||
cls._db_create(execute)
|
|
||||||
create = True
|
|
||||||
|
|
||||||
return cls._update_submodel(execute, version, data)
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
@@ -227,7 +217,7 @@ class Profile(SQLSubModel):
|
|||||||
values = list(map(float, values))
|
values = list(map(float, values))
|
||||||
sf = ">" + ''.join(itertools.repeat("f", len(values)))
|
sf = ">" + ''.join(itertools.repeat("f", len(values)))
|
||||||
len_values = len(values)
|
len_values = len(values)
|
||||||
elif key is "sl":
|
elif key == "sl":
|
||||||
# HACK: Some dirty code to transforme list of list of
|
# HACK: Some dirty code to transforme list of list of
|
||||||
# tuple to list of values and ensure the values is
|
# tuple to list of values and ensure the values is
|
||||||
# float type...
|
# float type...
|
||||||
|
|||||||
+23
-5
@@ -59,6 +59,7 @@ from Model.LateralContributionsAdisTS.LateralContributionsAdisTSList \
|
|||||||
import LateralContributionsAdisTSList
|
import LateralContributionsAdisTSList
|
||||||
from Model.D90AdisTS.D90AdisTSList import D90AdisTSList
|
from Model.D90AdisTS.D90AdisTSList import D90AdisTSList
|
||||||
from Model.DIFAdisTS.DIFAdisTSList import DIFAdisTSList
|
from Model.DIFAdisTS.DIFAdisTSList import DIFAdisTSList
|
||||||
|
from Model.GeoTIFF.GeoTIFFList import GeoTIFFList
|
||||||
from Model.Results.Results import Results
|
from Model.Results.Results import Results
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
@@ -468,6 +469,7 @@ class River(Graph):
|
|||||||
LateralContributionsAdisTSList,
|
LateralContributionsAdisTSList,
|
||||||
D90AdisTSList,
|
D90AdisTSList,
|
||||||
DIFAdisTSList,
|
DIFAdisTSList,
|
||||||
|
GeoTIFFList,
|
||||||
Results
|
Results
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -505,7 +507,9 @@ class River(Graph):
|
|||||||
self._D90AdisTS = D90AdisTSList(status=self._status)
|
self._D90AdisTS = D90AdisTSList(status=self._status)
|
||||||
self._DIFAdisTS = DIFAdisTSList(status=self._status)
|
self._DIFAdisTS = DIFAdisTSList(status=self._status)
|
||||||
|
|
||||||
self._results = None
|
self._geotiff = GeoTIFFList(status=self._status)
|
||||||
|
|
||||||
|
self._results = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute):
|
||||||
@@ -617,10 +621,15 @@ class River(Graph):
|
|||||||
|
|
||||||
new._DIFAdisTS = DIFAdisTSList._db_load(execute, data)
|
new._DIFAdisTS = DIFAdisTSList._db_load(execute, data)
|
||||||
|
|
||||||
|
new._geotiff = GeoTIFFList._db_load(execute, data)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_load_results(self, execute, data=None):
|
def _db_load_results(self, execute, data=None):
|
||||||
self._results = Results._db_load(execute, data)
|
results_lst = Results._db_load(execute, data)
|
||||||
|
|
||||||
|
for solv_type, results in results_lst:
|
||||||
|
self._results[solv_type] = results
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
self._db_save_delete_artefact(execute, data)
|
self._db_save_delete_artefact(execute, data)
|
||||||
@@ -647,8 +656,10 @@ class River(Graph):
|
|||||||
objs.append(self._D90AdisTS)
|
objs.append(self._D90AdisTS)
|
||||||
objs.append(self._DIFAdisTS)
|
objs.append(self._DIFAdisTS)
|
||||||
|
|
||||||
if self.results is not None:
|
objs.append(self._geotiff)
|
||||||
objs.append(self.results)
|
|
||||||
|
for solv_type in self.results:
|
||||||
|
objs.append(self.results[solv_type])
|
||||||
|
|
||||||
self._save_submodel(execute, objs, data)
|
self._save_submodel(execute, objs, data)
|
||||||
return True
|
return True
|
||||||
@@ -723,6 +734,7 @@ class River(Graph):
|
|||||||
self._BoundaryConditionsAdisTS,
|
self._BoundaryConditionsAdisTS,
|
||||||
self._LateralContributionsAdisTS,
|
self._LateralContributionsAdisTS,
|
||||||
self._D90AdisTS, self._DIFAdisTS,
|
self._D90AdisTS, self._DIFAdisTS,
|
||||||
|
self._geotiff,
|
||||||
]
|
]
|
||||||
|
|
||||||
for solver in self._parameters:
|
for solver in self._parameters:
|
||||||
@@ -815,6 +827,10 @@ Last export at: @date."""
|
|||||||
def additional_files(self):
|
def additional_files(self):
|
||||||
return self._additional_files
|
return self._additional_files
|
||||||
|
|
||||||
|
@property
|
||||||
|
def geotiff(self):
|
||||||
|
return self._geotiff
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rep_lines(self):
|
def rep_lines(self):
|
||||||
return self._rep_lines
|
return self._rep_lines
|
||||||
@@ -902,7 +918,9 @@ Last export at: @date."""
|
|||||||
|
|
||||||
@results.setter
|
@results.setter
|
||||||
def results(self, results):
|
def results(self, results):
|
||||||
self._results = results
|
solv_type = results.get("solver_type")
|
||||||
|
|
||||||
|
self._results[solv_type] = results
|
||||||
|
|
||||||
def _split_reach(self, reach, profile):
|
def _split_reach(self, reach, profile):
|
||||||
node1 = reach.node1
|
node1 = reach.node1
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Scenario(SQLSubModel):
|
|||||||
id: int = -1,
|
id: int = -1,
|
||||||
name: str = "",
|
name: str = "",
|
||||||
description: str = "",
|
description: str = "",
|
||||||
x: int = 0.0, y: int = 0.0,
|
x: int = 1000.0, y: int = 1000.0,
|
||||||
revision: int = 0,
|
revision: int = 0,
|
||||||
parent=None):
|
parent=None):
|
||||||
super(Scenario, self).__init__()
|
super(Scenario, self).__init__()
|
||||||
@@ -276,7 +276,7 @@ class Scenario(SQLSubModel):
|
|||||||
if self.id != 0:
|
if self.id != 0:
|
||||||
srep = os.path.join(
|
srep = os.path.join(
|
||||||
self.parent.workdir(),
|
self.parent.workdir(),
|
||||||
"senario_" + str(self.id)
|
"scenario_" + str(self.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
return srep
|
return srep
|
||||||
+82
-26
@@ -37,14 +37,17 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
|
|
||||||
class Study(SQLModel):
|
class Study(SQLModel):
|
||||||
_version = "0.2.1"
|
_version = "0.2.3"
|
||||||
|
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
Scenario,
|
Scenario,
|
||||||
River,
|
River,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, filename=None, init_new=True):
|
def __init__(self, filename=None, init_new=True, copy=False):
|
||||||
|
if copy:
|
||||||
|
return
|
||||||
|
|
||||||
# Metadata
|
# Metadata
|
||||||
self.creation_date = datetime.now()
|
self.creation_date = datetime.now()
|
||||||
self.last_modification_date = datetime.now()
|
self.last_modification_date = datetime.now()
|
||||||
@@ -476,31 +479,10 @@ class Study(SQLModel):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def reload_from_scenario(self, scenario):
|
def reload_from_scenario(self, scenario):
|
||||||
if scenario in self._river_scenario_cache:
|
river = self.load_scenario(scenario)
|
||||||
self._river = self._river_scenario_cache[scenario]
|
self._river = river
|
||||||
self.status.scenario = scenario
|
|
||||||
else:
|
|
||||||
def sql_exec(sql):
|
|
||||||
return self.execute(
|
|
||||||
sql, fetch_one=False, commit=True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.status.scenario = scenario
|
self.status.scenario = scenario
|
||||||
data = {
|
|
||||||
"status": self.status,
|
|
||||||
"loaded_pid": set(),
|
|
||||||
"scenario": scenario
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reload river data
|
|
||||||
river = River._db_load(
|
|
||||||
sql_exec, data=data
|
|
||||||
)
|
|
||||||
data["study"] = self
|
|
||||||
river._db_load_results(sql_exec, data=data)
|
|
||||||
|
|
||||||
self._river_scenario_cache[scenario] = river
|
|
||||||
self._river = river
|
|
||||||
|
|
||||||
if reduce(
|
if reduce(
|
||||||
lambda a, s: a or (s.parent is scenario),
|
lambda a, s: a or (s.parent is scenario),
|
||||||
@@ -511,6 +493,80 @@ class Study(SQLModel):
|
|||||||
else:
|
else:
|
||||||
self.status.set_as_editable()
|
self.status.set_as_editable()
|
||||||
|
|
||||||
|
def load_scenario(self, scenario):
|
||||||
|
if scenario in self._river_scenario_cache:
|
||||||
|
return self._river_scenario_cache[scenario]
|
||||||
|
|
||||||
|
def sql_exec(sql):
|
||||||
|
return self.execute(
|
||||||
|
sql, fetch_one=False, commit=True
|
||||||
|
)
|
||||||
|
|
||||||
|
old_scenario = self.status.scenario
|
||||||
|
self.status.scenario = scenario
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"status": self.status,
|
||||||
|
"loaded_pid": set(),
|
||||||
|
"scenario": scenario
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load river data
|
||||||
|
river = River._db_load(
|
||||||
|
sql_exec, data=data
|
||||||
|
)
|
||||||
|
data["study"] = self
|
||||||
|
river._db_load_results(sql_exec, data=data)
|
||||||
|
|
||||||
|
self._river_scenario_cache[scenario] = river
|
||||||
|
self.status.scenario = old_scenario
|
||||||
|
|
||||||
|
return river
|
||||||
|
|
||||||
|
def copy_from_scenario(self, scenario):
|
||||||
|
new = self._copy()
|
||||||
|
|
||||||
|
new._river = self.load_scenario(scenario)
|
||||||
|
|
||||||
|
def set_status(obj):
|
||||||
|
obj._status = new.status
|
||||||
|
|
||||||
|
new.river._data_traversal(
|
||||||
|
modifier=lambda obj, data: set_status(obj),
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _copy(self):
|
||||||
|
"""
|
||||||
|
This method make a copy of current study. This copy is like an
|
||||||
|
empty shell, it's not fully functional. Study object use
|
||||||
|
SQLite connection to file, this copy as no valid connection.
|
||||||
|
|
||||||
|
(!) Please use this copy as read only object!
|
||||||
|
"""
|
||||||
|
new = Study(copy=True)
|
||||||
|
|
||||||
|
new._filename = ""
|
||||||
|
new.creation_date = self.creation_date
|
||||||
|
new.last_modification_date = self.last_modification_date
|
||||||
|
new.last_save_date = self.last_save_date
|
||||||
|
|
||||||
|
new._name = self._name
|
||||||
|
new.description = self.description
|
||||||
|
|
||||||
|
new._time_system = self._time_system
|
||||||
|
new._date = self._date
|
||||||
|
|
||||||
|
new.status = StudyStatus()
|
||||||
|
new.scenarios = self.scenarios
|
||||||
|
new.status.scenario = self.status.scenario
|
||||||
|
|
||||||
|
new._river = self._river
|
||||||
|
new._river_scenario_cache = self._river_scenario_cache
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
def duplicate_current_scenario(self):
|
def duplicate_current_scenario(self):
|
||||||
source = self.status.scenario_id
|
source = self.status.scenario_id
|
||||||
new = self.scenarios.new(
|
new = self.scenarios.new(
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class Modules(IterableFlag):
|
|||||||
SEDIMENT_LAYER = auto()
|
SEDIMENT_LAYER = auto()
|
||||||
ADDITIONAL_FILES = auto()
|
ADDITIONAL_FILES = auto()
|
||||||
OUTPUT_RK = auto()
|
OUTPUT_RK = auto()
|
||||||
|
GEOTIFF = auto()
|
||||||
|
|
||||||
# Results
|
# Results
|
||||||
RESULTS = auto()
|
RESULTS = auto()
|
||||||
@@ -81,6 +82,7 @@ class Modules(IterableFlag):
|
|||||||
cls.RESULTS,
|
cls.RESULTS,
|
||||||
cls.WINDOW_LIST,
|
cls.WINDOW_LIST,
|
||||||
cls.OUTPUT_RK,
|
cls.OUTPUT_RK,
|
||||||
|
cls.GEOTIFF
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -99,6 +101,7 @@ class Modules(IterableFlag):
|
|||||||
| cls.HYDRAULIC_STRUCTURES
|
| cls.HYDRAULIC_STRUCTURES
|
||||||
| cls.RESERVOIR
|
| cls.RESERVOIR
|
||||||
| cls.SEDIMENT_LAYER
|
| cls.SEDIMENT_LAYER
|
||||||
|
| cls.GEOTIFF
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -114,6 +117,7 @@ class Modules(IterableFlag):
|
|||||||
cls.HYDRAULIC_STRUCTURES,
|
cls.HYDRAULIC_STRUCTURES,
|
||||||
cls.RESERVOIR,
|
cls.RESERVOIR,
|
||||||
cls.SEDIMENT_LAYER,
|
cls.SEDIMENT_LAYER,
|
||||||
|
cls.GEOTIFF,
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -129,6 +133,7 @@ class Modules(IterableFlag):
|
|||||||
cls.HYDRAULIC_STRUCTURES: "Hydraulic structures",
|
cls.HYDRAULIC_STRUCTURES: "Hydraulic structures",
|
||||||
cls.RESERVOIR: "Reservoir",
|
cls.RESERVOIR: "Reservoir",
|
||||||
cls.SEDIMENT_LAYER: "Sediment layer",
|
cls.SEDIMENT_LAYER: "Sediment layer",
|
||||||
|
cls.GEOTIFF: "GeoTIFF",
|
||||||
}
|
}
|
||||||
|
|
||||||
def impact(self):
|
def impact(self):
|
||||||
@@ -168,4 +173,5 @@ _impact = {
|
|||||||
Modules.HYDRAULIC_STRUCTURES: [],
|
Modules.HYDRAULIC_STRUCTURES: [],
|
||||||
Modules.RESERVOIR: [],
|
Modules.RESERVOIR: [],
|
||||||
Modules.SEDIMENT_LAYER: [],
|
Modules.SEDIMENT_LAYER: [],
|
||||||
|
Modules.GEOTIFF: [],
|
||||||
}
|
}
|
||||||
+68
-6
@@ -96,6 +96,69 @@ class AdisTS(CommandLineSolver):
|
|||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Export #
|
||||||
|
##########
|
||||||
|
|
||||||
|
_alph = list(
|
||||||
|
map(
|
||||||
|
chr,
|
||||||
|
chain(
|
||||||
|
range(48, 58), # 0..9
|
||||||
|
range(65, 91), # A..Z
|
||||||
|
range(97, 123) # a..z
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
_l_alph = len(_alph)
|
||||||
|
|
||||||
|
_nodes_cnt = 0
|
||||||
|
_nodes_names = {}
|
||||||
|
_nodes_views = set()
|
||||||
|
|
||||||
|
def get_reach_name(self, reach):
|
||||||
|
return f"Reach_{reach.pamhyr_id:>3}".replace(" ", "0")
|
||||||
|
|
||||||
|
def get_node_name(self, node):
|
||||||
|
"""Generate a 3 char name for node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: The node
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A 3 char name string
|
||||||
|
"""
|
||||||
|
n = node.pamhyr_id
|
||||||
|
|
||||||
|
if n in self._nodes_names:
|
||||||
|
return self._nodes_names[n]
|
||||||
|
|
||||||
|
name = ""
|
||||||
|
|
||||||
|
checked_new = False
|
||||||
|
while not checked_new:
|
||||||
|
self._nodes_cnt += 1
|
||||||
|
nc = self._nodes_cnt
|
||||||
|
|
||||||
|
name = "".join(
|
||||||
|
map(
|
||||||
|
lambda i: self._alph[i % self._l_alph],
|
||||||
|
[
|
||||||
|
int(nc / (self._l_alph * self._l_alph)),
|
||||||
|
int(nc / self._l_alph),
|
||||||
|
nc
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checked_new = name not in self._nodes_views
|
||||||
|
|
||||||
|
self._nodes_views.add(name)
|
||||||
|
self._nodes_names[n] = name
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
def cmd_args(self, study):
|
def cmd_args(self, study):
|
||||||
lst = super(AdisTS, self).cmd_args(study)
|
lst = super(AdisTS, self).cmd_args(study)
|
||||||
return lst
|
return lst
|
||||||
@@ -197,7 +260,7 @@ class AdisTS(CommandLineSolver):
|
|||||||
_nodes_views = set()
|
_nodes_views = set()
|
||||||
|
|
||||||
def get_reach_name(self, reach):
|
def get_reach_name(self, reach):
|
||||||
return f"Reach_{reach.id:>3}".replace(" ", "0")
|
return f"Reach_{reach.pamhyr_id:>3}".replace(" ", "0")
|
||||||
|
|
||||||
def get_node_name(self, node):
|
def get_node_name(self, node):
|
||||||
"""Generate a 3 char name for node
|
"""Generate a 3 char name for node
|
||||||
@@ -208,7 +271,7 @@ class AdisTS(CommandLineSolver):
|
|||||||
Returns:
|
Returns:
|
||||||
A 3 char name string
|
A 3 char name string
|
||||||
"""
|
"""
|
||||||
n = node.id
|
n = node.pamhyr_id
|
||||||
|
|
||||||
# print("node name id: ", n)
|
# print("node name id: ", n)
|
||||||
|
|
||||||
@@ -338,9 +401,9 @@ class AdisTSwc(AdisTS):
|
|||||||
) as f:
|
) as f:
|
||||||
for LC in POL_LC:
|
for LC in POL_LC:
|
||||||
reach = next(filter(
|
reach = next(filter(
|
||||||
lambda edge: edge.id == LC.edge, study.river.edges()
|
lambda edge: edge.id == LC.edge, study.river.enable_edges()
|
||||||
)) # .name
|
)) # .name
|
||||||
reach_name = self.get_reach_name(self, reach)
|
reach_name = self.get_reach_name(reach)
|
||||||
f.write(f"${reach_name} {LC.begin_rk} {LC.end_rk}\n")
|
f.write(f"${reach_name} {LC.begin_rk} {LC.end_rk}\n")
|
||||||
f.write(f"*temps |débit massique (kg/s)\n")
|
f.write(f"*temps |débit massique (kg/s)\n")
|
||||||
f.write(f"*---------++++++++++\n")
|
f.write(f"*---------++++++++++\n")
|
||||||
@@ -365,8 +428,7 @@ class AdisTSwc(AdisTS):
|
|||||||
node = next(filter(
|
node = next(filter(
|
||||||
lambda x: x.id == BC.node, study.river._nodes
|
lambda x: x.id == BC.node, study.river._nodes
|
||||||
))
|
))
|
||||||
node_name = f"{node.id:3}".replace(" ", "x")
|
f.write(f"${self.get_node_name(node)}\n")
|
||||||
f.write(f"${node_name}\n")
|
|
||||||
|
|
||||||
if BC.type == "Concentration":
|
if BC.type == "Concentration":
|
||||||
f.write(f"*temps |concentration\n")
|
f.write(f"*temps |concentration\n")
|
||||||
|
|||||||
+6
-4
@@ -177,15 +177,15 @@ class Mage(CommandLineSolver):
|
|||||||
return lst
|
return lst
|
||||||
|
|
||||||
def input_param(self):
|
def input_param(self):
|
||||||
name = self._study.name
|
name = self._study.name.replace(" ", "_")
|
||||||
return f"{name}.REP"
|
return f"{name}.REP"
|
||||||
|
|
||||||
def output_param(self):
|
def output_param(self):
|
||||||
name = self._study.name
|
name = self._study.name.replace(" ", "_")
|
||||||
return f"{name}.BIN"
|
return f"{name}.BIN"
|
||||||
|
|
||||||
def log_file(self):
|
def log_file(self):
|
||||||
name = self._study.name
|
name = self._study.name.replace(" ", "_")
|
||||||
return f"{name}.TRA"
|
return f"{name}.TRA"
|
||||||
|
|
||||||
def _export_REP_additional_lines(self, study, rep_file):
|
def _export_REP_additional_lines(self, study, rep_file):
|
||||||
@@ -819,7 +819,8 @@ class Mage(CommandLineSolver):
|
|||||||
repertory=repertory,
|
repertory=repertory,
|
||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
fname = os.path.join(repertory, f"{name}.BIN")
|
|
||||||
|
fname = os.path.join(repertory, f"{name}.BIN".replace(" ", "_"))
|
||||||
if not os.path.isfile(fname):
|
if not os.path.isfile(fname):
|
||||||
logger.info(f"Result file {name}.BIN does not exist")
|
logger.info(f"Result file {name}.BIN does not exist")
|
||||||
return None
|
return None
|
||||||
@@ -1374,6 +1375,7 @@ class Mage8(Mage):
|
|||||||
results = super(Mage8, self).results(study, repertory, qlog, name=name)
|
results = super(Mage8, self).results(study, repertory, qlog, name=name)
|
||||||
if results is None:
|
if results is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if with_gra:
|
if with_gra:
|
||||||
self.read_gra(study, repertory, results, qlog, name=name)
|
self.read_gra(study, repertory, results, qlog, name=name)
|
||||||
|
|
||||||
|
|||||||
+105
-61
@@ -52,8 +52,8 @@ class Rubar3(CommandLineSolver):
|
|||||||
("rubarbe_condav", "3"),
|
("rubarbe_condav", "3"),
|
||||||
("rubarbe_regime", "0"),
|
("rubarbe_regime", "0"),
|
||||||
("rubarbe_iodev", "n"),
|
("rubarbe_iodev", "n"),
|
||||||
# ("rubarbe_iodebord", ""),
|
("rubarbe_iodebord", ""),
|
||||||
# ("rubarbe_iostockage", ""),
|
("rubarbe_iostockage", ""),
|
||||||
("rubarbe_iopdt", "y"),
|
("rubarbe_iopdt", "y"),
|
||||||
("rubarbe_iovis", "n"),
|
("rubarbe_iovis", "n"),
|
||||||
("rubarbe_rep", "n"),
|
("rubarbe_rep", "n"),
|
||||||
@@ -73,36 +73,37 @@ class Rubar3(CommandLineSolver):
|
|||||||
("rubarbe_tf_4", "y"),
|
("rubarbe_tf_4", "y"),
|
||||||
("rubarbe_tf_5", "y"),
|
("rubarbe_tf_5", "y"),
|
||||||
("rubarbe_tf_6", "n"),
|
("rubarbe_tf_6", "n"),
|
||||||
("rubarbe_trased", "y"),
|
("rubarbe_trased", "n"),
|
||||||
# ("rubarbe_optfpc", "0"),
|
("rubarbe_optfpc", "0"),
|
||||||
# ("rubarbe_ros", "2650.0"),
|
# trased parameters
|
||||||
# ("rubarbe_dm", "0.1"),
|
("rubarbe_ros", "2650.0"),
|
||||||
# ("rubarbe_segma", "1.0"),
|
("rubarbe_dm", "0.1"),
|
||||||
|
("rubarbe_segma", "1.0"),
|
||||||
# Sediment parameters
|
# Sediment parameters
|
||||||
# ("rubarbe_sediment_ros", "2650.0"),
|
("rubarbe_sediment_ros", "2650.0"),
|
||||||
# ("rubarbe_sediment_por", "0.4"),
|
("rubarbe_sediment_por", "0.4"),
|
||||||
# ("rubarbe_sediment_dcharg", "0.0"),
|
("rubarbe_sediment_dcharg", "0.0"),
|
||||||
# ("rubarbe_sediment_halfa", "1.0"),
|
("rubarbe_sediment_halfa", "1.0"),
|
||||||
# ("rubarbe_sediment_mult_1", "1.0"),
|
("rubarbe_sediment_mult_1", "1.0"),
|
||||||
# ("rubarbe_sediment_mult_2", ""),
|
("rubarbe_sediment_mult_2", ""),
|
||||||
# ("rubarbe_sediment_mult_3", ""),
|
("rubarbe_sediment_mult_3", ""),
|
||||||
# ("rubarbe_sediment_mult_4", ""),
|
("rubarbe_sediment_mult_4", ""),
|
||||||
# ("rubarbe_sediment_mult_5", ""),
|
("rubarbe_sediment_mult_5", ""),
|
||||||
# ("rubarbe_sediment_visc", "0.047"),
|
("rubarbe_sediment_visc", "0.047"),
|
||||||
# ("rubarbe_sediment_opts", "6"),
|
("rubarbe_sediment_opts", "6"),
|
||||||
# ("rubarbe_sediment_odchar", "0"),
|
("rubarbe_sediment_odchar", "0"),
|
||||||
# ("rubarbe_sediment_unisol", "1"),
|
("rubarbe_sediment_unisol", "1"),
|
||||||
# ("rubarbe_sediment_typdef", "3"),
|
("rubarbe_sediment_typdef", "3"),
|
||||||
# ("rubarbe_sediment_depot", "2"),
|
("rubarbe_sediment_depot", "2"),
|
||||||
# ("rubarbe_sediment_choixc", "2"),
|
("rubarbe_sediment_choixc", "2"),
|
||||||
# ("rubarbe_sediment_option", "2"),
|
("rubarbe_sediment_option", "2"),
|
||||||
# ("rubarbe_sediment_capsol", "1"),
|
("rubarbe_sediment_capsol", "1"),
|
||||||
# ("rubarbe_sediment_bmiu", "0.85"),
|
("rubarbe_sediment_bmiu", "0.85"),
|
||||||
# ("rubarbe_sediment_demix", "0"),
|
("rubarbe_sediment_demix", "0"),
|
||||||
# ("rubarbe_sediment_defond", "1"),
|
("rubarbe_sediment_defond", "1"),
|
||||||
# ("rubarbe_sediment_varcons", "1"),
|
("rubarbe_sediment_varcons", "1"),
|
||||||
# ("rubarbe_sediment_dchard", "0.0"),
|
("rubarbe_sediment_dchard", "0.0"),
|
||||||
# ("rubarbe_sediment_dchars", "0.0"),
|
("rubarbe_sediment_dchars", "0.0"),
|
||||||
]
|
]
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
@@ -168,9 +169,8 @@ class Rubar3(CommandLineSolver):
|
|||||||
|
|
||||||
it = iter(params)
|
it = iter(params)
|
||||||
|
|
||||||
line = 0
|
param = next(it, None)
|
||||||
while line < 25:
|
while param != None:
|
||||||
param = next(it)
|
|
||||||
name = param.name
|
name = param.name
|
||||||
value = param.value
|
value = param.value
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ class Rubar3(CommandLineSolver):
|
|||||||
# New line
|
# New line
|
||||||
f.write(f"\n")
|
f.write(f"\n")
|
||||||
|
|
||||||
line += 1
|
param = next(it, None)
|
||||||
|
|
||||||
def _export_ts(self, study, repertory, qlog, name="0"):
|
def _export_ts(self, study, repertory, qlog, name="0"):
|
||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
@@ -394,25 +394,59 @@ class Rubar3(CommandLineSolver):
|
|||||||
lm = len(reach) + 1
|
lm = len(reach) + 1
|
||||||
f.write(f"{lm:>6}\n")
|
f.write(f"{lm:>6}\n")
|
||||||
|
|
||||||
def get_stricklers_from_rk(rk):
|
lst = list(filter(
|
||||||
return next(
|
lambda f: f.is_full_defined(),
|
||||||
map(
|
edge.frictions.frictions
|
||||||
lambda s: (
|
))
|
||||||
s.begin_strickler.medium if version == "2"
|
|
||||||
else s.begin_strickler.minor
|
rk_min = 9999999.9
|
||||||
),
|
rk_max = -9999999.9
|
||||||
filter(
|
coeff_min = -1.0
|
||||||
lambda f: rk in f,
|
coeff_max = -1.0
|
||||||
edge.frictions.lst
|
for s in lst: # TODO optimise ?
|
||||||
)
|
if s.begin_rk > rk_max:
|
||||||
|
rk_max = s.begin_rk
|
||||||
|
coeff_max = s.begin_strickler
|
||||||
|
if s.begin_rk < rk_min:
|
||||||
|
rk_min = s.begin_rk
|
||||||
|
coeff_min = s.begin_strickler
|
||||||
|
if s.end_rk > rk_max:
|
||||||
|
rk_max = s.end_rk
|
||||||
|
coeff_max = s.end_strickler
|
||||||
|
if s.end_rk < rk_min:
|
||||||
|
rk_min = s.end_rk
|
||||||
|
coeff_min = s.end_strickler
|
||||||
|
|
||||||
|
def get_stricklers_from_rk(rk, lst):
|
||||||
|
|
||||||
|
coeff = None
|
||||||
|
if rk > rk_max:
|
||||||
|
coeff = coeff_max
|
||||||
|
elif rk < rk_min:
|
||||||
|
coeff = coeff_min
|
||||||
|
else:
|
||||||
|
for s in lst:
|
||||||
|
print(s.begin_rk, s.end_rk)
|
||||||
|
if (rk >= s.begin_rk and rk <= s.end_rk or
|
||||||
|
rk <= s.begin_rk and rk >= s.end_rk):
|
||||||
|
coeff = s.begin_strickler # TODO: inerpolate
|
||||||
|
break
|
||||||
|
|
||||||
|
# TODO interpolation if rk is not in frictons
|
||||||
|
|
||||||
|
if coeff is None:
|
||||||
|
logger.error(
|
||||||
|
"Study frictions are not fully defined"
|
||||||
)
|
)
|
||||||
)
|
return None
|
||||||
|
|
||||||
|
return coeff.medium if version == "2" else coeff.minor
|
||||||
|
|
||||||
ind = 1
|
ind = 1
|
||||||
for mail in edge.reach.inter_profiles_rk():
|
for mail in edge.reach.inter_profiles_rk():
|
||||||
coef = get_stricklers_from_rk(mail)
|
coef = get_stricklers_from_rk(mail, lst)
|
||||||
|
if coef is not None:
|
||||||
f.write(f"{ind:>6} {coef:>12.5f}")
|
f.write(f"{ind:>6} {coef:>12.5f}")
|
||||||
|
|
||||||
ind += 1
|
ind += 1
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
@@ -540,8 +574,12 @@ class Rubar3(CommandLineSolver):
|
|||||||
|
|
||||||
for bc in bcs:
|
for bc in bcs:
|
||||||
f.write(f"{len(bc)}\n")
|
f.write(f"{len(bc)}\n")
|
||||||
for d0, d1 in bc.data:
|
if bc.bctype == "ZD":
|
||||||
f.write(f"{d1} {d0}\n")
|
for d0, d1 in bc.data:
|
||||||
|
f.write(f"{d1} {d0}\n")
|
||||||
|
else:
|
||||||
|
for d0, d1 in bc.data:
|
||||||
|
f.write(f"{d0} {d1}\n")
|
||||||
|
|
||||||
def read_profil(self, study, fname, results, qlog=None, name="0"):
|
def read_profil(self, study, fname, results, qlog=None, name="0"):
|
||||||
logger.info(f"read: profil.{name}")
|
logger.info(f"read: profil.{name}")
|
||||||
@@ -555,7 +593,10 @@ class Rubar3(CommandLineSolver):
|
|||||||
|
|
||||||
def read_data_line(f):
|
def read_data_line(f):
|
||||||
line = f.readline().split()
|
line = f.readline().split()
|
||||||
return tuple(map(float, line))
|
if len(line) > 3:
|
||||||
|
return tuple(map(float, line))
|
||||||
|
else:
|
||||||
|
return (0.0, 0.0, 0.0, 0.0)
|
||||||
|
|
||||||
def set_and_compute_limites(reach, ind, z, q, s):
|
def set_and_compute_limites(reach, ind, z, q, s):
|
||||||
reach.set(ind, timestamp, "Z", z)
|
reach.set(ind, timestamp, "Z", z)
|
||||||
@@ -583,27 +624,30 @@ class Rubar3(CommandLineSolver):
|
|||||||
|
|
||||||
for reach, lm in reachs:
|
for reach, lm in reachs:
|
||||||
# First profile
|
# First profile
|
||||||
e, s, q, z = read_data_line(f)
|
h, s, q, z = read_data_line(f)
|
||||||
set_and_compute_limites(reach, 0, z, q, s)
|
set_and_compute_limites(reach, 0, z+h, q, s)
|
||||||
|
|
||||||
# For each profile
|
# For each profile
|
||||||
ind = 1
|
ind = 1
|
||||||
pe, ps, pq, pz = read_data_line(f)
|
ph, ps, pq, pz = read_data_line(f)
|
||||||
while ind < lm - 2:
|
while ind < lm - 2:
|
||||||
e, s, q, z = read_data_line(f)
|
h, s, q, z = read_data_line(f)
|
||||||
set_and_compute_limites(
|
set_and_compute_limites(
|
||||||
reach, ind,
|
reach, ind,
|
||||||
(pz + z) / 2,
|
(pz + z + ph + h) / 2,
|
||||||
(pq + q) / 2,
|
(pq + q) / 2,
|
||||||
(ps + s) / 2
|
(ps + s) / 2
|
||||||
)
|
)
|
||||||
|
|
||||||
pe, ps, pq, pz = z, s, q, e
|
ph = h
|
||||||
|
ps = s
|
||||||
|
pq = q
|
||||||
|
pz = z
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
# Last profile
|
# Last profile
|
||||||
e, s, q, z = read_data_line(f)
|
h, s, q, z = read_data_line(f)
|
||||||
set_and_compute_limites(reach, ind, z, q, s)
|
set_and_compute_limites(reach, ind, z+h, q, s)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def results(self, study, repertory, qlog=None, name="0"):
|
def results(self, study, repertory, qlog=None, name="0"):
|
||||||
|
|||||||
@@ -58,7 +58,11 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
class TableModel(PamhyrTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def get_true_data_row(self, row):
|
def get_true_data_row(self, row):
|
||||||
bc = self._data.get_i(row)
|
|
||||||
|
if len(self._data.data) > 0:
|
||||||
|
bc = self._data.data[row]
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
return next(
|
return next(
|
||||||
map(
|
map(
|
||||||
@@ -83,6 +87,7 @@ class TableModel(PamhyrTableModel):
|
|||||||
value = QVariant()
|
value = QVariant()
|
||||||
|
|
||||||
if 0 <= column < 2:
|
if 0 <= column < 2:
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
v = self._data.get_i(row)[column]
|
v = self._data.get_i(row)[column]
|
||||||
if self._data.get_type_column(column) == float:
|
if self._data.get_type_column(column) == float:
|
||||||
if type(v) is str:
|
if type(v) is str:
|
||||||
@@ -106,13 +111,16 @@ class TableModel(PamhyrTableModel):
|
|||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetDataCommand(
|
SetDataCommand(
|
||||||
self._data, row, column, value
|
self._data, row,
|
||||||
|
column, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(e)
|
logger.warning(e)
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|||||||
@@ -83,13 +83,13 @@ class AddCommand(QUndoCommand):
|
|||||||
self._new = None
|
self._new = None
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
self._data.delete_i([self._index])
|
self._new.set_as_deleted()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._new is None:
|
if self._new is None:
|
||||||
self._new = self._data.add(self._index)
|
self._new = self._data.add(self._index)
|
||||||
else:
|
else:
|
||||||
self._data.insert(self._index, self._new)
|
self._new.set_as_not_deleted()
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
@@ -101,15 +101,16 @@ class DelCommand(QUndoCommand):
|
|||||||
|
|
||||||
self._bc = []
|
self._bc = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
self._bc.append((row, self._data.get_i(row)))
|
self._bc.append(self._data.get_i(row))
|
||||||
self._bc.sort()
|
self._bc.sort()
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for row, el in self._bc:
|
for el in self._bc:
|
||||||
self._data.insert(row, el)
|
el.set_as_not_deleted()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
self._data.delete_i(self._rows)
|
for el in self._bc:
|
||||||
|
el.set_as_deleted()
|
||||||
|
|
||||||
|
|
||||||
class SortCommand(QUndoCommand):
|
class SortCommand(QUndoCommand):
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
@@ -92,7 +93,8 @@ class ReplWindow(PamhyrWindow):
|
|||||||
value = exec(rich_code)
|
value = exec(rich_code)
|
||||||
value = self.__debug_exec_result__
|
value = self.__debug_exec_result__
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
value = f"<font color=\"red\">" + str(e) + "</font>"
|
value = f"<font color=\"red\">" + str(e) + "</font>\n"
|
||||||
|
value += f"<font color=\"grey\">{traceback.format_exc()}</font>"
|
||||||
|
|
||||||
# Display code
|
# Display code
|
||||||
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
||||||
|
|||||||
@@ -274,15 +274,14 @@ class FrictionTableModel(PamhyrTableModel):
|
|||||||
with open(file_name, encoding="utf-8") as rug_file:
|
with open(file_name, encoding="utf-8") as rug_file:
|
||||||
for line in rug_file:
|
for line in rug_file:
|
||||||
if line.upper().startswith("K"):
|
if line.upper().startswith("K"):
|
||||||
line = line.split()
|
if int(line[1:4]) == reach_id:
|
||||||
if int(line[1]) == reach_id:
|
data.append(line[4:].split())
|
||||||
data.append(line[1:])
|
|
||||||
|
|
||||||
new_data = []
|
new_data = []
|
||||||
for d in data:
|
for d in data:
|
||||||
new = None
|
new = None
|
||||||
minor = float(d[3])
|
minor = float(d[2])
|
||||||
medium = float(d[4])
|
medium = float(d[3])
|
||||||
for s in self._study.river.stricklers.stricklers:
|
for s in self._study.river.stricklers.stricklers:
|
||||||
if s.minor == minor and s.medium == medium:
|
if s.minor == minor and s.medium == medium:
|
||||||
new = s
|
new = s
|
||||||
@@ -292,5 +291,5 @@ class FrictionTableModel(PamhyrTableModel):
|
|||||||
self._study.river.stricklers))
|
self._study.river.stricklers))
|
||||||
new.minor = minor
|
new.minor = minor
|
||||||
new.medium = medium
|
new.medium = medium
|
||||||
new_data.append([self._data, float(d[1]), float(d[2]), new, new])
|
new_data.append([self._data, float(d[0]), float(d[1]), new, new])
|
||||||
self.replace_data(new_data)
|
self.replace_data(new_data)
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
# Window.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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 Modules import Modules
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QLabel, QPlainTextEdit, QPushButton, QCheckBox,
|
||||||
|
QFileDialog, QVBoxLayout, QDoubleSpinBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QSettings
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.GeoTIFF.Translate import GeoTIFFTranslate
|
||||||
|
from View.GeoTIFF.UndoCommand import (
|
||||||
|
SetCommand
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
|
from View.PlotXY import PlotXY
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class EditGeoTIFFWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "GeoTIFF"
|
||||||
|
_pamhyr_name = "Edit GeoTIFF"
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None, geotiff=None,
|
||||||
|
trad=None, undo=None, parent=None):
|
||||||
|
|
||||||
|
super(EditGeoTIFFWindow, self).__init__(
|
||||||
|
title=self._pamhyr_name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._geotiff = geotiff
|
||||||
|
self._file_name = geotiff.file_name
|
||||||
|
|
||||||
|
self._hash_data.append(self._geotiff)
|
||||||
|
|
||||||
|
self._undo = undo
|
||||||
|
|
||||||
|
self.setup_values()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connection()
|
||||||
|
|
||||||
|
def setup_graph(self):
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas")
|
||||||
|
self.plot_layout = self.find(QVBoxLayout,
|
||||||
|
"verticalLayout_geotiff")
|
||||||
|
self._toolbar = PamhyrPlotToolbar(
|
||||||
|
self.canvas, self,
|
||||||
|
items=["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
|
)
|
||||||
|
self.plot_layout.addWidget(self._toolbar)
|
||||||
|
self.plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self.plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=self._study.river.enable_edges(),
|
||||||
|
trad=self._trad,
|
||||||
|
toolbar=None,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
|
self._plot_img = None
|
||||||
|
|
||||||
|
memfile = self._geotiff.memfile
|
||||||
|
if memfile is not None:
|
||||||
|
self.draw_geotiff(memfile=memfile)
|
||||||
|
|
||||||
|
def setup_values(self):
|
||||||
|
self.set_check_box("checkBox", self._geotiff.enabled)
|
||||||
|
self.set_line_edit_text("lineEdit_name", self._geotiff.name)
|
||||||
|
self.set_line_edit_text("lineEdit_description",
|
||||||
|
self._geotiff.description)
|
||||||
|
|
||||||
|
bounds = list(self._geotiff.coordinates.values())
|
||||||
|
self._set_values_from_bounds(bounds)
|
||||||
|
self._set_default_values_from_bounds(bounds)
|
||||||
|
self._reset_spinboxes()
|
||||||
|
|
||||||
|
if self._study.is_read_only():
|
||||||
|
self.set_check_box_enable("checkBox", False)
|
||||||
|
self.set_line_edit_enable("lineEdit_name", False)
|
||||||
|
self.set_line_edit_enable("lineEdit_description", False)
|
||||||
|
|
||||||
|
for button in ["import", "bottom", "top", "left", "right"]:
|
||||||
|
self.find(QPushButton, f"pushButton_{button}")\
|
||||||
|
.setEnabled(False)
|
||||||
|
|
||||||
|
for spin in ["bottom", "top", "left", "right"]:
|
||||||
|
self.find(QDoubleSpinBox, f"doubleSpinBox_{spin}")\
|
||||||
|
.setEnabled(False)
|
||||||
|
|
||||||
|
def _set_values_from_bounds(self, bounds):
|
||||||
|
self._values = {
|
||||||
|
"bottom": bounds[0],
|
||||||
|
"top": bounds[1],
|
||||||
|
"left": bounds[2],
|
||||||
|
"right": bounds[3],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _set_default_values_from_bounds(self, bounds):
|
||||||
|
self._values_default = {
|
||||||
|
"bottom": bounds[0],
|
||||||
|
"top": bounds[1],
|
||||||
|
"left": bounds[2],
|
||||||
|
"right": bounds[3],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _reset_spinboxes(self):
|
||||||
|
for key in self._values:
|
||||||
|
self._reset_spinbox(key)
|
||||||
|
|
||||||
|
def _reset_spinbox(self, key):
|
||||||
|
self.set_double_spin_box(
|
||||||
|
f"doubleSpinBox_{key}", self._values_default[key]
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_connection(self):
|
||||||
|
self.find(QPushButton, "pushButton_cancel")\
|
||||||
|
.clicked.connect(self.close)
|
||||||
|
self.find(QPushButton, "pushButton_ok")\
|
||||||
|
.clicked.connect(self.accept)
|
||||||
|
self.find(QPushButton, "pushButton_import")\
|
||||||
|
.clicked.connect(self._import)
|
||||||
|
|
||||||
|
self.find(QPushButton, "pushButton_bottom")\
|
||||||
|
.clicked.connect(lambda: self._reset_spinbox("bottom"))
|
||||||
|
self.find(QPushButton, "pushButton_top")\
|
||||||
|
.clicked.connect(lambda: self._reset_spinbox("top"))
|
||||||
|
self.find(QPushButton, f"pushButton_left")\
|
||||||
|
.clicked.connect(lambda: self._reset_spinbox("left"))
|
||||||
|
self.find(QPushButton, f"pushButton_right")\
|
||||||
|
.clicked.connect(lambda: self._reset_spinbox("right"))
|
||||||
|
|
||||||
|
self.find(QDoubleSpinBox, f"doubleSpinBox_bottom")\
|
||||||
|
.valueChanged.connect(
|
||||||
|
lambda: self.update_values_from_spinbox("bottom")
|
||||||
|
)
|
||||||
|
self.find(QDoubleSpinBox, f"doubleSpinBox_top")\
|
||||||
|
.valueChanged.connect(
|
||||||
|
lambda: self.update_values_from_spinbox("top")
|
||||||
|
)
|
||||||
|
self.find(QDoubleSpinBox, f"doubleSpinBox_left")\
|
||||||
|
.valueChanged.connect(
|
||||||
|
lambda: self.update_values_from_spinbox("left")
|
||||||
|
)
|
||||||
|
self.find(QDoubleSpinBox, f"doubleSpinBox_right")\
|
||||||
|
.valueChanged.connect(
|
||||||
|
lambda: self.update_values_from_spinbox("right")
|
||||||
|
)
|
||||||
|
|
||||||
|
def update_values_from_spinbox(self, key):
|
||||||
|
self._values[key] = self.get_double_spin_box(f"doubleSpinBox_{key}")
|
||||||
|
|
||||||
|
left = self._values["left"]
|
||||||
|
right = self._values["right"]
|
||||||
|
bottom = self._values["bottom"]
|
||||||
|
top = self._values["top"]
|
||||||
|
|
||||||
|
self._plot_img.set_extent((left, right, bottom, top))
|
||||||
|
self.plot.idle()
|
||||||
|
|
||||||
|
def draw_geotiff(self, memfile=None):
|
||||||
|
if not _rasterio_loaded:
|
||||||
|
return
|
||||||
|
|
||||||
|
if memfile is None:
|
||||||
|
if self._file_name == "":
|
||||||
|
return
|
||||||
|
|
||||||
|
with rasterio.open(self._file_name) as data:
|
||||||
|
img = data.read()
|
||||||
|
b = data.bounds[:] # left, bottom, right, top
|
||||||
|
|
||||||
|
if b[2] > b[0] and b[1] < b[3]:
|
||||||
|
coord = [b[1], b[3], b[0], b[2]]
|
||||||
|
else:
|
||||||
|
xlim = self.canvas.axes.get_xlim()
|
||||||
|
ylim = self.canvas.axes.get_ylim()
|
||||||
|
coord = ylim + xlim
|
||||||
|
|
||||||
|
self._set_values_from_bounds(coord)
|
||||||
|
self._set_default_values_from_bounds(coord)
|
||||||
|
else:
|
||||||
|
with memfile.open() as gt:
|
||||||
|
img = gt.read()
|
||||||
|
|
||||||
|
if self._plot_img is not None:
|
||||||
|
self._plot_img.remove()
|
||||||
|
|
||||||
|
left = self._values["left"]
|
||||||
|
right = self._values["right"]
|
||||||
|
bottom = self._values["bottom"]
|
||||||
|
top = self._values["top"]
|
||||||
|
|
||||||
|
self._plot_img = self.canvas.axes.imshow(
|
||||||
|
img.transpose((1, 2, 0)),
|
||||||
|
extent=(left, right, bottom, top)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.plot.idle()
|
||||||
|
self._reset_spinboxes()
|
||||||
|
|
||||||
|
def _import(self):
|
||||||
|
options = QFileDialog.Options()
|
||||||
|
settings = QSettings(QSettings.IniFormat,
|
||||||
|
QSettings.UserScope, 'MyOrg', )
|
||||||
|
options |= QFileDialog.DontUseNativeDialog
|
||||||
|
|
||||||
|
file_types = [
|
||||||
|
self._trad["file_geotiff"],
|
||||||
|
self._trad["file_all"],
|
||||||
|
]
|
||||||
|
|
||||||
|
filename, _ = QFileDialog.getOpenFileName(
|
||||||
|
self,
|
||||||
|
self._trad["open_file"],
|
||||||
|
"",
|
||||||
|
";; ".join(file_types),
|
||||||
|
options=options
|
||||||
|
)
|
||||||
|
|
||||||
|
if filename != "":
|
||||||
|
self._file_name = filename
|
||||||
|
self.draw_geotiff()
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
if self._study.is_editable():
|
||||||
|
is_enabled = self.get_check_box("checkBox")
|
||||||
|
name = self.get_line_edit_text("lineEdit_name")
|
||||||
|
description = self.get_line_edit_text("lineEdit_description")
|
||||||
|
|
||||||
|
coord_bottom = self.get_double_spin_box("doubleSpinBox_bottom")
|
||||||
|
coord_top = self.get_double_spin_box("doubleSpinBox_top")
|
||||||
|
coord_left = self.get_double_spin_box("doubleSpinBox_left")
|
||||||
|
coord_right = self.get_double_spin_box("doubleSpinBox_right")
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
SetCommand(
|
||||||
|
self._geotiff, enabled=is_enabled,
|
||||||
|
name=name, description=description,
|
||||||
|
coordinates_bottom=coord_bottom,
|
||||||
|
coordinates_top=coord_top,
|
||||||
|
coordinates_left=coord_left,
|
||||||
|
coordinates_right=coord_right,
|
||||||
|
file_name=self._file_name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._propagate_update(key=Modules.GEOTIFF)
|
||||||
|
|
||||||
|
self.close()
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# List.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QColor, QBrush,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrList import PamhyrListModel
|
||||||
|
from View.GeoTIFF.UndoCommand import (
|
||||||
|
AddCommand, DelCommand
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class ListModel(PamhyrListModel):
|
||||||
|
def get_true_data_row(self, row):
|
||||||
|
el = self._data.get(row)
|
||||||
|
|
||||||
|
return next(
|
||||||
|
map(
|
||||||
|
lambda e: e[0],
|
||||||
|
filter(
|
||||||
|
lambda e: e[1] == el,
|
||||||
|
enumerate(self._data._lst)
|
||||||
|
)
|
||||||
|
), 0
|
||||||
|
)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
file = self._data.files[row]
|
||||||
|
|
||||||
|
if role == Qt.ForegroundRole:
|
||||||
|
color = Qt.gray
|
||||||
|
|
||||||
|
if file.is_enabled():
|
||||||
|
color = QColor("black")
|
||||||
|
else:
|
||||||
|
color = QColor("grey")
|
||||||
|
|
||||||
|
return QBrush(color)
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole:
|
||||||
|
text = f"{file.name}: '{file.description}'"
|
||||||
|
|
||||||
|
if not file.is_enabled():
|
||||||
|
text += " (disabled)"
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def add(self, row):
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
AddCommand(
|
||||||
|
self._data, row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def delete(self, row):
|
||||||
|
self._undo.push(
|
||||||
|
DelCommand(
|
||||||
|
self._data, self._data.files[row]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.update()
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Translate.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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 GeoTIFFTranslate(MainTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(GeoTIFFTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._dict["GeoTIFF files"] = _translate(
|
||||||
|
"GeoTIFF", "GeoTIFF files"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._dict["Edit additional file"] = _translate(
|
||||||
|
"GeoTIFF", "Edit GeoTIFF file"
|
||||||
|
)
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# UndoCommand.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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 PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SetCommand(QUndoCommand):
|
||||||
|
def __init__(self, geotiff, **kwargs):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._geotiff = geotiff
|
||||||
|
self._new = kwargs
|
||||||
|
self._old = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
f = self._geotiff
|
||||||
|
|
||||||
|
for key in self._old:
|
||||||
|
f[key] = self._old[key]
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
f = self._geotiff
|
||||||
|
|
||||||
|
if self._old is None:
|
||||||
|
self._old = {}
|
||||||
|
for key in self._new:
|
||||||
|
self._old[key] = f[key]
|
||||||
|
|
||||||
|
for key in self._new:
|
||||||
|
f[key] = self._new[key]
|
||||||
|
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, files, row):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._files = files
|
||||||
|
self._row = row
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._new.set_as_deleted()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._files.new(self._row)
|
||||||
|
else:
|
||||||
|
self._new.set_as_not_deleted()
|
||||||
|
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, files, line):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._files = files
|
||||||
|
self._line = line
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._line.set_as_not_deleted()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._line.set_as_deleted()
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
# Window.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 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 PyQt5.QtWidgets import (
|
||||||
|
QAction, QListView, QVBoxLayout,
|
||||||
|
)
|
||||||
|
|
||||||
|
from matplotlib.patches import Rectangle
|
||||||
|
|
||||||
|
from Modules import Modules
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
|
||||||
|
from View.GeoTIFF.List import ListModel
|
||||||
|
from View.GeoTIFF.Translate import GeoTIFFTranslate
|
||||||
|
from View.GeoTIFF.Edit.Window import EditGeoTIFFWindow
|
||||||
|
|
||||||
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
|
from View.PlotXY import PlotXY
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class GeoTIFFListWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "GeoTIFFList"
|
||||||
|
_pamhyr_name = "GeoTIFF files"
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None,
|
||||||
|
parent=None):
|
||||||
|
trad = GeoTIFFTranslate()
|
||||||
|
name = trad[self._pamhyr_name] + " - " + study.name
|
||||||
|
|
||||||
|
super(GeoTIFFListWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_list()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
def setup_list(self):
|
||||||
|
lst = self.find(QListView, "listView")
|
||||||
|
self._list = ListModel(
|
||||||
|
list_view=lst,
|
||||||
|
data=self._study.river.geotiff,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
trad=self._trad,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_graph(self):
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas")
|
||||||
|
self._plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
self._toolbar = PamhyrPlotToolbar(
|
||||||
|
self.canvas, self,
|
||||||
|
items=["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
|
)
|
||||||
|
self._plot_layout.addWidget(self._toolbar)
|
||||||
|
self._plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self._plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=self._study.river.enable_edges(),
|
||||||
|
geotiff=self._study.river.geotiff,
|
||||||
|
trad=self._trad,
|
||||||
|
toolbar=None,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self._plot_rect = []
|
||||||
|
|
||||||
|
self._plot.update()
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
if self._study.is_editable():
|
||||||
|
self.find(QAction, "action_add").triggered.connect(self.add)
|
||||||
|
self.find(QAction, "action_delete").triggered.connect(self.delete)
|
||||||
|
else:
|
||||||
|
self.find(QAction, "action_add").setEnabled(False)
|
||||||
|
self.find(QAction, "action_delete").setEnabled(False)
|
||||||
|
|
||||||
|
self.find(QAction, "action_edit").triggered.connect(self.edit)
|
||||||
|
|
||||||
|
self.find(QListView, "listView")\
|
||||||
|
.selectionModel()\
|
||||||
|
.selectionChanged\
|
||||||
|
.connect(self._update_rectangle)
|
||||||
|
|
||||||
|
def _propagated_update(self, key=Modules(0)):
|
||||||
|
if Modules.GEOMETRY not in key and Modules.GEOTIFF not in key:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self._list.update()
|
||||||
|
self._plot.update()
|
||||||
|
|
||||||
|
self._update_rectangle()
|
||||||
|
|
||||||
|
def _update_rectangle(self):
|
||||||
|
for rect in self._plot_rect:
|
||||||
|
rect.remove()
|
||||||
|
|
||||||
|
self._plot_rect = []
|
||||||
|
|
||||||
|
rows = self.selected_rows()
|
||||||
|
if len(rows) <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
files = self._study.river.geotiff.files
|
||||||
|
if len(files) <= row:
|
||||||
|
continue
|
||||||
|
|
||||||
|
geotiff = files[row]
|
||||||
|
coord = geotiff.coordinates
|
||||||
|
|
||||||
|
xy = (coord["left"], coord["bottom"])
|
||||||
|
width = abs(coord["right"] - coord["left"])
|
||||||
|
height = abs(coord["top"] - coord["bottom"])
|
||||||
|
|
||||||
|
rect = Rectangle(
|
||||||
|
xy, width, height,
|
||||||
|
edgecolor='red', facecolor='none',
|
||||||
|
lw=2
|
||||||
|
)
|
||||||
|
|
||||||
|
self._plot_rect.append(rect)
|
||||||
|
|
||||||
|
self.canvas.axes.add_patch(
|
||||||
|
rect
|
||||||
|
)
|
||||||
|
|
||||||
|
self._plot.idle()
|
||||||
|
|
||||||
|
def selected_rows(self):
|
||||||
|
lst = self.find(QListView, f"listView")
|
||||||
|
return list(map(lambda i: i.row(), lst.selectedIndexes()))
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
rows = self.selected_rows()
|
||||||
|
if len(rows) > 0:
|
||||||
|
row = rows[0]
|
||||||
|
else:
|
||||||
|
row = 0
|
||||||
|
|
||||||
|
self._list.add(row)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
rows = self.selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._list.delete(rows[0])
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def edit(self):
|
||||||
|
rows = self.selected_rows()
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
geotiff = self._study.river.geotiff.files[row]
|
||||||
|
|
||||||
|
if self.sub_window_exists(
|
||||||
|
EditGeoTIFFWindow,
|
||||||
|
data=[self._study, self._config, geotiff]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
win = EditGeoTIFFWindow(
|
||||||
|
study=self._study,
|
||||||
|
config=self._config,
|
||||||
|
geotiff=geotiff,
|
||||||
|
trad=self._trad,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
parent=self,
|
||||||
|
)
|
||||||
|
win.show()
|
||||||
|
|
||||||
|
def _undo(self):
|
||||||
|
self._undo_stack.undo()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def _redo(self):
|
||||||
|
self._undo_stack.redo()
|
||||||
|
self.update()
|
||||||
@@ -251,11 +251,23 @@ class GeometryReachTableModel(PamhyrTableModel):
|
|||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def meshing(self, mesher, data, tableView):
|
def meshing(self, mesher, data, tableView):
|
||||||
|
|
||||||
|
new_profiles = mesher.meshing(
|
||||||
|
self._data,
|
||||||
|
**data
|
||||||
|
)
|
||||||
|
|
||||||
|
if new_profiles is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(new_profiles) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
MeshingCommand(
|
MeshingCommand(
|
||||||
self._data, mesher, data, tableView
|
self._data, new_profiles, data, tableView
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -237,34 +237,51 @@ class UpdateRKCommand(QUndoCommand):
|
|||||||
self._data = data
|
self._data = data
|
||||||
self._mesher = mesher
|
self._mesher = mesher
|
||||||
self._rks = reach.get_rk()
|
self._rks = reach.get_rk()
|
||||||
|
self._frictions = [f for f in reach._parent.frictions.frictions
|
||||||
|
if f.is_full_defined()]
|
||||||
|
self._begin_rk = [f.begin_rk for f in self._frictions]
|
||||||
|
self._end_rk = [f.end_rk for f in self._frictions]
|
||||||
|
|
||||||
self._new_rks = None
|
self._new_rks = None
|
||||||
|
self._new_begin_rk = None
|
||||||
|
self._new_end_rk = None
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for rk, profile in zip(self._rks, self._reach.profiles):
|
for rk, profile in zip(self._rks, self._reach.profiles):
|
||||||
profile.rk = rk
|
profile.rk = rk
|
||||||
|
|
||||||
|
for begin_rk, end_rk, friction in zip(self._begin_rk,
|
||||||
|
self._end_rk,
|
||||||
|
self._frictions):
|
||||||
|
friction.begin_rk = begin_rk
|
||||||
|
friction.end_rk = end_rk
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._new_rks is None:
|
if self._new_rks is None:
|
||||||
self._new_rks = self._mesher.update_rk(
|
self._new_rks, self._new_begin_rk, self._new_end_rk = \
|
||||||
self._reach,
|
self._mesher.update_rk(
|
||||||
**self._data
|
self._reach, self._begin_rk, self._end_rk,
|
||||||
)
|
**self._data
|
||||||
|
)
|
||||||
|
|
||||||
for rk, profile in zip(self._new_rks, self._reach.profiles):
|
for rk, profile in zip(self._new_rks, self._reach.profiles):
|
||||||
profile.rk = rk
|
profile.rk = rk
|
||||||
|
for begin_rk, end_rk, friction in zip(self._new_begin_rk,
|
||||||
|
self._new_end_rk,
|
||||||
|
self._frictions):
|
||||||
|
friction.begin_rk = begin_rk
|
||||||
|
friction.end_rk = end_rk
|
||||||
|
|
||||||
|
|
||||||
class MeshingCommand(QUndoCommand):
|
class MeshingCommand(QUndoCommand):
|
||||||
def __init__(self, reach, mesher, data, tableView):
|
def __init__(self, reach, new_profiles, data, tableView):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._data = data
|
self._data = data
|
||||||
self._limites = data["limites"]
|
self._limites = data["limites"]
|
||||||
self._mesher = mesher
|
|
||||||
|
|
||||||
self._new_profiles = None
|
self._new_profiles = new_profiles
|
||||||
self._new_profiles_indexes = None
|
self._new_profiles_indexes = None
|
||||||
self._tableView = tableView
|
self._tableView = tableView
|
||||||
self._indexes = tableView.selectionModel().selection()
|
self._indexes = tableView.selectionModel().selection()
|
||||||
@@ -290,12 +307,6 @@ class MeshingCommand(QUndoCommand):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._new_profiles is None:
|
|
||||||
self._new_profiles = self._mesher.meshing(
|
|
||||||
self._reach,
|
|
||||||
**self._data
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._new_profiles_indexes is None:
|
if self._new_profiles_indexes is None:
|
||||||
k = self._limites[0]
|
k = self._limites[0]
|
||||||
self._new_profiles_indexes = []
|
self._new_profiles_indexes = []
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
|||||||
|
|
||||||
from View.SelectReach.Window import SelectReachWindow
|
from View.SelectReach.Window import SelectReachWindow
|
||||||
|
|
||||||
|
from View.WaitingDialog import WaitingDialog
|
||||||
|
|
||||||
from Meshing.Internal import InternalMeshing
|
from Meshing.Internal import InternalMeshing
|
||||||
|
|
||||||
from View.Geometry.Table import GeometryReachTableModel
|
from View.Geometry.Table import GeometryReachTableModel
|
||||||
@@ -326,7 +328,19 @@ class GeometryWindow(PamhyrWindow):
|
|||||||
def _edit_meshing(self, data):
|
def _edit_meshing(self, data):
|
||||||
try:
|
try:
|
||||||
mesher = InternalMeshing()
|
mesher = InternalMeshing()
|
||||||
self._table.meshing(mesher, data, self.tableView)
|
tableview = self.tableView
|
||||||
|
|
||||||
|
def fn():
|
||||||
|
self._table.meshing(mesher, data, tableview)
|
||||||
|
# self._table.meshing(mesher, data, tableview)
|
||||||
|
dlg2 = WaitingDialog(
|
||||||
|
payload_fn=fn,
|
||||||
|
title="waiting_mesh",
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
dlg2.exec_()
|
||||||
|
self._table.update()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger_exception(e)
|
logger_exception(e)
|
||||||
|
|
||||||
|
|||||||
@@ -330,9 +330,27 @@ class InitialConditionTableModel(PamhyrTableModel):
|
|||||||
if not (line.startswith("#") or
|
if not (line.startswith("#") or
|
||||||
line.startswith("*") or
|
line.startswith("*") or
|
||||||
line.startswith("$")):
|
line.startswith("$")):
|
||||||
line = line.split()
|
line_split = line.split()
|
||||||
if int(line[0]) == reach_id:
|
formated = False
|
||||||
data.append([line[4], line[2], line[3]])
|
if len(line_split[0]) > 3:
|
||||||
|
formated = True
|
||||||
|
elif len(line_split[2]) > 10:
|
||||||
|
formated = True
|
||||||
|
elif len(line_split[3]) > 11:
|
||||||
|
formated = True
|
||||||
|
elif len(line_split[4]) > 9:
|
||||||
|
formated = True
|
||||||
|
|
||||||
|
if formated: # old PamHyr format
|
||||||
|
if int(line[1:4]) == reach_id:
|
||||||
|
data.append([line[31:40],
|
||||||
|
line[10:20],
|
||||||
|
line[20:31]])
|
||||||
|
else:
|
||||||
|
if int(line_split[0]) == reach_id:
|
||||||
|
data.append([line_split[4],
|
||||||
|
line_split[2],
|
||||||
|
line_split[3]])
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
ReplaceDataCommand(
|
ReplaceDataCommand(
|
||||||
|
|||||||
@@ -224,6 +224,8 @@ class InitialConditionsWindow(PamhyrWindow):
|
|||||||
def _update_plot(self):
|
def _update_plot(self):
|
||||||
self.plot_1.draw()
|
self.plot_1.draw()
|
||||||
self.plot_2.draw()
|
self.plot_2.draw()
|
||||||
|
self.plot_1.idle()
|
||||||
|
self.plot_2.idle()
|
||||||
|
|
||||||
def _propagated_update(self, key=Modules(0)):
|
def _propagated_update(self, key=Modules(0)):
|
||||||
if Modules.GEOMETRY not in key:
|
if Modules.GEOMETRY not in key:
|
||||||
@@ -320,10 +322,12 @@ class InitialConditionsWindow(PamhyrWindow):
|
|||||||
def _import_from_results(self, results):
|
def _import_from_results(self, results):
|
||||||
logger.debug(f"import from results: {results}")
|
logger.debug(f"import from results: {results}")
|
||||||
self._table.import_from_results(results)
|
self._table.import_from_results(results)
|
||||||
|
self._update()
|
||||||
|
|
||||||
def _import_from_ini_file(self, file_name):
|
def _import_from_ini_file(self, file_name):
|
||||||
logger.debug(f"import from INI file: {file_name}")
|
logger.debug(f"import from INI file: {file_name}")
|
||||||
self._table.read_from_ini(file_name)
|
self._table.read_from_ini(file_name)
|
||||||
|
self._update()
|
||||||
|
|
||||||
def move_up(self):
|
def move_up(self):
|
||||||
row = self.index_selected_row()
|
row = self.index_selected_row()
|
||||||
|
|||||||
+243
-100
@@ -32,7 +32,7 @@ from platformdirs import user_cache_dir
|
|||||||
from Solver.AdisTS import AdisTS
|
from Solver.AdisTS import AdisTS
|
||||||
from Solver.Mage import Mage8
|
from Solver.Mage import Mage8
|
||||||
from Solver.RubarBE import Rubar3
|
from Solver.RubarBE import Rubar3
|
||||||
from tools import logger_exception, pamhyr_db_need_update
|
from tools import logger_exception, pamhyr_db_need_update, timer
|
||||||
|
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
@@ -47,7 +47,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QMainWindow, QApplication, QAction,
|
QMainWindow, QApplication, QAction,
|
||||||
QFileDialog, QShortcut, QMenu, QToolBar,
|
QFileDialog, QShortcut, QMenu, QToolBar,
|
||||||
QMessageBox, QProgressDialog, QTabWidget,
|
QMessageBox, QProgressDialog, QTabWidget,
|
||||||
QDialog, QVBoxLayout, QLabel,
|
QDialog, QVBoxLayout, QLabel, QInputDialog,
|
||||||
)
|
)
|
||||||
from PyQt5.uic import loadUi
|
from PyQt5.uic import loadUi
|
||||||
|
|
||||||
@@ -79,15 +79,18 @@ from View.Frictions.Window import FrictionsWindow
|
|||||||
from View.SedimentLayers.Window import SedimentLayersWindow
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
|
from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
|
||||||
from View.AdditionalFiles.Window import AddFileListWindow
|
from View.AdditionalFiles.Window import AddFileListWindow
|
||||||
|
from View.GeoTIFF.Window import GeoTIFFListWindow
|
||||||
from View.REPLines.Window import REPLineListWindow
|
from View.REPLines.Window import REPLineListWindow
|
||||||
from View.SolverParameters.Window import SolverParametersWindow
|
from View.SolverParameters.Window import SolverParametersWindow
|
||||||
from View.RunSolver.Window import (
|
from View.RunSolver.Window import (
|
||||||
SelectSolverWindow,
|
SelectSolverWindow,
|
||||||
SolverLogWindow,
|
SolverLogWindow,
|
||||||
CompareSolversWindow
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.Results.Window import ResultsWindow
|
from View.Results.Window import ResultsWindow
|
||||||
|
from View.Results.CompareDialog import (
|
||||||
|
CompareScenariosWindow
|
||||||
|
)
|
||||||
|
|
||||||
from View.RunSolver.WindowAdisTS import (
|
from View.RunSolver.WindowAdisTS import (
|
||||||
SelectSolverWindowAdisTS,
|
SelectSolverWindowAdisTS,
|
||||||
@@ -128,8 +131,8 @@ no_model_action = [
|
|||||||
model_action = [
|
model_action = [
|
||||||
"action_menu_close", "action_menu_edit", "action_menu_save",
|
"action_menu_close", "action_menu_edit", "action_menu_save",
|
||||||
"action_menu_save_as", "action_toolBar_close", "action_toolBar_save",
|
"action_menu_save_as", "action_toolBar_close", "action_toolBar_save",
|
||||||
"action_menu_numerical_parameter", "action_open_results_from_file",
|
"action_menu_numerical_parameter", "action_menu_open_results_from_file",
|
||||||
"action_open_results_adists",
|
"action_menu_open_results_adists",
|
||||||
]
|
]
|
||||||
|
|
||||||
other_model_action = [
|
other_model_action = [
|
||||||
@@ -150,11 +153,12 @@ define_model_action = [
|
|||||||
"action_menu_run_solver", "action_menu_sediment_layers",
|
"action_menu_run_solver", "action_menu_sediment_layers",
|
||||||
"action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs",
|
"action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs",
|
||||||
"action_menu_edit_hydraulic_structures", "action_menu_additional_file",
|
"action_menu_edit_hydraulic_structures", "action_menu_additional_file",
|
||||||
"action_menu_results_last", "action_open_results_from_file",
|
"action_menu_results_last", "action_menu_open_results_from_file",
|
||||||
"action_compare_results", "action_menu_boundary_conditions_sediment",
|
"action_menu_compare_scenarios_results",
|
||||||
|
"action_menu_boundary_conditions_sediment",
|
||||||
"action_menu_rep_additional_lines", "action_menu_output_rk",
|
"action_menu_rep_additional_lines", "action_menu_output_rk",
|
||||||
"action_menu_run_adists", "action_menu_pollutants",
|
"action_menu_run_adists", "action_menu_pollutants",
|
||||||
"action_menu_d90", "action_menu_dif",
|
"action_menu_d90", "action_menu_dif", "action_menu_edit_geotiff"
|
||||||
]
|
]
|
||||||
|
|
||||||
action = (
|
action = (
|
||||||
@@ -273,8 +277,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
"action_menu_new": self.open_new_study,
|
"action_menu_new": self.open_new_study,
|
||||||
"action_menu_edit": self.open_edit_study,
|
"action_menu_edit": self.open_edit_study,
|
||||||
"action_menu_open": self.open_model,
|
"action_menu_open": self.open_model,
|
||||||
"action_menu_save": self.save_study,
|
"action_menu_save": lambda: self.save_study(),
|
||||||
"action_menu_save_as": self.save_as_study,
|
"action_menu_save_as": lambda: self.save_as_study(),
|
||||||
"action_menu_numerical_parameter": self.open_solver_parameters,
|
"action_menu_numerical_parameter": self.open_solver_parameters,
|
||||||
"action_menu_edit_scenarios": self.open_scenarios,
|
"action_menu_edit_scenarios": self.open_scenarios,
|
||||||
"action_menu_edit_network": self.open_network,
|
"action_menu_edit_network": self.open_network,
|
||||||
@@ -294,11 +298,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
self.open_reach_sediment_layers,
|
self.open_reach_sediment_layers,
|
||||||
"action_menu_additional_file": self.open_additional_files,
|
"action_menu_additional_file": self.open_additional_files,
|
||||||
"action_menu_rep_additional_lines": self.open_rep_lines,
|
"action_menu_rep_additional_lines": self.open_rep_lines,
|
||||||
|
"action_menu_edit_geotiff": self.open_geotiff,
|
||||||
"action_menu_close": self.close_model,
|
"action_menu_close": self.close_model,
|
||||||
"action_menu_results_last": self.open_last_results,
|
"action_menu_results_last": self.open_last_results,
|
||||||
"action_open_results_from_file": self.open_results_from_file,
|
"action_menu_open_results_from_file": self.open_results_from_file,
|
||||||
"action_compare_results": self.compare_results,
|
"action_menu_compare_scenarios_results":
|
||||||
"action_open_results_adists": self.open_results_adists,
|
self.compare_results_scenarios,
|
||||||
|
"action_menu_open_results_adists": self.open_results_adists,
|
||||||
# Help
|
# Help
|
||||||
"action_menu_pamhyr_users_wiki": self.open_doc_user,
|
"action_menu_pamhyr_users_wiki": self.open_doc_user,
|
||||||
"action_menu_pamhyr_developers_pdf":
|
"action_menu_pamhyr_developers_pdf":
|
||||||
@@ -309,7 +315,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
"action_menu_about": self.open_about,
|
"action_menu_about": self.open_about,
|
||||||
# ToolBar action
|
# ToolBar action
|
||||||
"action_toolBar_open": self.open_model,
|
"action_toolBar_open": self.open_model,
|
||||||
"action_toolBar_save": self.save_study,
|
"action_toolBar_save": lambda: self.save_study(),
|
||||||
"action_toolBar_close": self.close_model,
|
"action_toolBar_close": self.close_model,
|
||||||
"action_toolBar_run_solver": self.run_lasest_solver,
|
"action_toolBar_run_solver": self.run_lasest_solver,
|
||||||
# Current actions
|
# Current actions
|
||||||
@@ -596,7 +602,21 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
if self._study is None:
|
if self._study is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self._study.results
|
results = self._study.results
|
||||||
|
if self._last_solver._type in results:
|
||||||
|
return self._study.results[self._last_solver._type]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_last_results(self, solver):
|
||||||
|
if self._study is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
results = self._study.results
|
||||||
|
if solver in results:
|
||||||
|
return self._study.results[solver]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
@last_results.setter
|
@last_results.setter
|
||||||
def last_results(self, results):
|
def last_results(self, results):
|
||||||
@@ -629,7 +649,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
logger.info(f"Open Study - {self._study.name}")
|
logger.info(f"Open Study - {self._study.name}")
|
||||||
self.set_title()
|
self.set_title()
|
||||||
|
|
||||||
def save_study(self):
|
def _save(self, source):
|
||||||
|
self.save_study(progress_parent=source)
|
||||||
|
|
||||||
|
def save_study(self, progress_parent=None):
|
||||||
"""Save current study
|
"""Save current study
|
||||||
|
|
||||||
Save current study, if study as no associate file, open a
|
Save current study, if study as no associate file, open a
|
||||||
@@ -659,11 +682,15 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
self._backup_timer.blockSignals(True)
|
self._backup_timer.blockSignals(True)
|
||||||
self._save_mutex.lock()
|
self._save_mutex.lock()
|
||||||
|
|
||||||
|
parent = self
|
||||||
|
if progress_parent is not None:
|
||||||
|
parent = progress_parent
|
||||||
|
|
||||||
sql_request_count = self._study.sql_save_request_count()
|
sql_request_count = self._study.sql_save_request_count()
|
||||||
progress = QProgressDialog(
|
progress = QProgressDialog(
|
||||||
"Saving...", None,
|
"Saving...", None,
|
||||||
0, sql_request_count,
|
0, sql_request_count,
|
||||||
parent=self
|
parent=parent
|
||||||
)
|
)
|
||||||
progress.setWindowModality(Qt.WindowModal)
|
progress.setWindowModality(Qt.WindowModal)
|
||||||
progress.setValue(0)
|
progress.setValue(0)
|
||||||
@@ -676,6 +703,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
progress=lambda: progress.setValue(progress.value() + 1)
|
progress=lambda: progress.setValue(progress.value() + 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
progress.close()
|
||||||
status += " Done"
|
status += " Done"
|
||||||
logger.info(status)
|
logger.info(status)
|
||||||
self.statusbar.showMessage(status, 3000)
|
self.statusbar.showMessage(status, 3000)
|
||||||
@@ -750,6 +778,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
|
|
||||||
progress.setValue(progress.value() + 1)
|
progress.setValue(progress.value() + 1)
|
||||||
|
|
||||||
|
progress.close()
|
||||||
|
|
||||||
def save_as_study_single_scenario(self, sid=-1):
|
def save_as_study_single_scenario(self, sid=-1):
|
||||||
sql_request_count = self._study.sql_save_request_count()
|
sql_request_count = self._study.sql_save_request_count()
|
||||||
|
|
||||||
@@ -774,6 +804,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
|
|
||||||
status += " Done"
|
status += " Done"
|
||||||
|
progress.close()
|
||||||
logger.info(status)
|
logger.info(status)
|
||||||
self.statusbar.showMessage(status, 3000)
|
self.statusbar.showMessage(status, 3000)
|
||||||
|
|
||||||
@@ -1175,6 +1206,31 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing
|
Nothing
|
||||||
"""
|
"""
|
||||||
|
if self._study is None:
|
||||||
|
return
|
||||||
|
if self._study.filename is None or self._study.filename == "":
|
||||||
|
self.message_box(
|
||||||
|
window_title=self._trad["Warning"],
|
||||||
|
text=self._trad["mb_unsaved_study_title"],
|
||||||
|
informative_text=self._trad["mb_unsaved_studyh_msg"]
|
||||||
|
)
|
||||||
|
|
||||||
|
options = QFileDialog.Options()
|
||||||
|
options |= QFileDialog.DontUseNativeDialog
|
||||||
|
|
||||||
|
file_name, _ = QFileDialog.getSaveFileName(
|
||||||
|
self, "Save File",
|
||||||
|
"", "Pamhyr(*.pamhyr)",
|
||||||
|
options=options,
|
||||||
|
)
|
||||||
|
if file_name is None or file_name == "":
|
||||||
|
return
|
||||||
|
|
||||||
|
if file_name.rsplit(".", 1)[-1] == "pamhyr":
|
||||||
|
self._study.filename = file_name
|
||||||
|
else:
|
||||||
|
self._study.filename = file_name + ".pamhyr"
|
||||||
|
|
||||||
if self._study is not None:
|
if self._study is not None:
|
||||||
if self.sub_window_exists(
|
if self.sub_window_exists(
|
||||||
ScenariosWindow,
|
ScenariosWindow,
|
||||||
@@ -1331,6 +1387,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
self.additonal_files.show()
|
self.additonal_files.show()
|
||||||
|
|
||||||
|
def open_geotiff(self):
|
||||||
|
if self._study is not None:
|
||||||
|
if self.sub_window_exists(
|
||||||
|
GeoTIFFListWindow,
|
||||||
|
data=[self._study, None]
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.geotiff = GeoTIFFListWindow(
|
||||||
|
study=self._study, parent=self
|
||||||
|
)
|
||||||
|
self.geotiff.show()
|
||||||
|
|
||||||
def open_rep_lines(self):
|
def open_rep_lines(self):
|
||||||
if self._study is not None:
|
if self._study is not None:
|
||||||
if self.sub_window_exists(
|
if self.sub_window_exists(
|
||||||
@@ -1507,7 +1576,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def open_solver_results(self, solver, results=None):
|
def open_solver_results(self, solver, results=None):
|
||||||
logger.info(f"{solver} {results}")
|
logger.info(f"Open results for '{solver}' ({results})")
|
||||||
|
|
||||||
def reading_fn():
|
def reading_fn():
|
||||||
self._tmp_results = results
|
self._tmp_results = results
|
||||||
@@ -1515,14 +1584,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
# If no specific results, get last results
|
# If no specific results, get last results
|
||||||
if results is None:
|
if results is None:
|
||||||
def reading_fn():
|
def reading_fn():
|
||||||
self._tmp_results = self.last_results
|
self._tmp_results = solver.results(
|
||||||
|
self._study,
|
||||||
|
self._solver_workdir(solver),
|
||||||
|
)
|
||||||
|
|
||||||
if self.last_results is None:
|
if solver == self._last_solver:
|
||||||
def reading_fn():
|
def reading_fn():
|
||||||
self._tmp_results = solver.results(
|
self._tmp_results = self.last_results
|
||||||
self._study,
|
|
||||||
self._solver_workdir(solver),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Open from file
|
# Open from file
|
||||||
if type(results) is str:
|
if type(results) is str:
|
||||||
@@ -1547,13 +1616,16 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
dlg.exec_()
|
dlg.exec_()
|
||||||
results = self._tmp_results
|
results = self._tmp_results
|
||||||
|
# self.last_results = results
|
||||||
|
|
||||||
# No results available
|
# No results available
|
||||||
if results is None:
|
if results is None:
|
||||||
|
self.msg_open_results_no_results()
|
||||||
return
|
return
|
||||||
|
|
||||||
# results does not have values, for example if geometry missmatch
|
# results does not have values, for example if geometry missmatch
|
||||||
if not results.is_valid:
|
if not results.is_valid:
|
||||||
|
self.msg_open_results_invalid_results()
|
||||||
return
|
return
|
||||||
|
|
||||||
if results.get('study_revision') != self._study.status.version:
|
if results.get('study_revision') != self._study.status.version:
|
||||||
@@ -1579,6 +1651,20 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
res.show()
|
res.show()
|
||||||
|
|
||||||
|
def msg_open_results_no_results(self):
|
||||||
|
self.message_box(
|
||||||
|
window_title=self._trad["Warning"],
|
||||||
|
text=self._trad["mb_open_results_title"],
|
||||||
|
informative_text=self._trad["mb_open_results_no_results_msg"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def msg_open_results_invalid_results(self):
|
||||||
|
self.message_box(
|
||||||
|
window_title=self._trad["Error"],
|
||||||
|
text=self._trad["mb_open_results_title"],
|
||||||
|
informative_text=self._trad["mb_open_results_invalid_results_msg"]
|
||||||
|
)
|
||||||
|
|
||||||
def open_solver_results_adists(self, solver, results=None):
|
def open_solver_results_adists(self, solver, results=None):
|
||||||
def reading_fn():
|
def reading_fn():
|
||||||
self._tmp_results = results
|
self._tmp_results = results
|
||||||
@@ -1607,8 +1693,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
os.path.dirname(results),
|
os.path.dirname(results),
|
||||||
name=name
|
name=name
|
||||||
)
|
)
|
||||||
|
dlg = WaitingDialog(
|
||||||
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
|
payload_fn=reading_fn,
|
||||||
|
title="waiting_result",
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
dlg.exec_()
|
dlg.exec_()
|
||||||
results = self._tmp_results
|
results = self._tmp_results
|
||||||
|
|
||||||
@@ -1637,26 +1726,63 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
res.show()
|
res.show()
|
||||||
|
|
||||||
def _solver_workdir(self, solver):
|
def _solver_workdir(self, solver, scenario=None):
|
||||||
|
if scenario is None:
|
||||||
|
scenario = self._study.status.scenario
|
||||||
|
|
||||||
workdir = os.path.join(
|
workdir = os.path.join(
|
||||||
os.path.dirname(self._study.filename),
|
os.path.dirname(self._study.filename),
|
||||||
"_PAMHYR_",
|
"_PAMHYR_",
|
||||||
self._study.name.replace(" ", "_"),
|
self._study.name.replace(" ", "_"),
|
||||||
solver.name.replace(" ", "_"),
|
solver.name.replace(" ", "_"),
|
||||||
|
scenario.workdir(),
|
||||||
)
|
)
|
||||||
|
|
||||||
return workdir
|
return workdir
|
||||||
|
|
||||||
|
def is_solver_workdir_exists(self, solver, scenario=None):
|
||||||
|
return os.path.exists(
|
||||||
|
self._solver_workdir(solver, scenario)
|
||||||
|
)
|
||||||
|
|
||||||
def open_last_results(self):
|
def open_last_results(self):
|
||||||
if self._last_solver is None:
|
if self._last_solver is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
solver_type = self._study.results
|
||||||
|
|
||||||
|
solver_name, ok = QInputDialog.getItem(
|
||||||
|
self, self._trad['Solver'],
|
||||||
|
self._trad['Solver'] + ":",
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda s: s.name,
|
||||||
|
filter(
|
||||||
|
lambda s: (self.is_solver_workdir_exists(s)
|
||||||
|
or s._type in solver_type),
|
||||||
|
self.conf.solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not ok:
|
||||||
|
return
|
||||||
|
|
||||||
|
solver = next(
|
||||||
|
filter(
|
||||||
|
lambda s: s.name == solver_name,
|
||||||
|
self.conf.solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if self._last_solver._type == "mage8":
|
if self._last_solver._type == "mage8":
|
||||||
self.open_solver_results(self._last_solver,
|
self.open_solver_results(
|
||||||
self.last_results)
|
solver, # self.last_results
|
||||||
|
)
|
||||||
elif self._last_solver._type == "adistswc":
|
elif self._last_solver._type == "adistswc":
|
||||||
self.open_solver_results_adists(self._last_solver,
|
self.open_solver_results_adists(
|
||||||
self.last_results)
|
solver, # self.last_results
|
||||||
|
)
|
||||||
|
|
||||||
def open_results_from_file(self):
|
def open_results_from_file(self):
|
||||||
if self._study is None:
|
if self._study is None:
|
||||||
@@ -1697,32 +1823,36 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
results=file_name[0]
|
results=file_name[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
def compare_results(self):
|
def compare_results_scenarios(self):
|
||||||
if self._study is None:
|
if self._study is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
run = CompareSolversWindow(
|
dlg = CompareScenariosWindow(
|
||||||
study=self._study,
|
study=self._study,
|
||||||
config=self.conf,
|
config=self.conf,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
if run.exec():
|
if not dlg.exec():
|
||||||
results = self.diff_results(run.solver1,
|
|
||||||
run.solver2)
|
|
||||||
else:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
results = self.diff_results(
|
||||||
|
dlg.solver1, dlg.solver2,
|
||||||
|
scenario1=dlg.scenario1,
|
||||||
|
scenario2=dlg.scenario2
|
||||||
|
)
|
||||||
|
|
||||||
# At least one result not available
|
# At least one result not available
|
||||||
if results is None:
|
if results is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Windows already opened
|
# Windows already opened
|
||||||
if self.sub_window_exists(
|
if self.sub_window_exists(
|
||||||
ResultsWindow,
|
CompareScenariosWindow,
|
||||||
data=[self._study, None] +
|
data=[self._study, None] +
|
||||||
[r._solver for r in results] +
|
[r._solver for r in results] +
|
||||||
[r._repertory for r in results] +
|
[r._repertory for r in results] +
|
||||||
[r._name for r in results]
|
[r._name for r in results] +
|
||||||
|
[dlg.scenario1, dlg.scenario2]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1733,97 +1863,109 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
res.show()
|
res.show()
|
||||||
|
|
||||||
def diff_results(self, solver1, solver2):
|
def msg_diff_results_param(self):
|
||||||
if solver1 is None:
|
self.message_box(
|
||||||
# TODO message
|
window_title=self._trad["Error"],
|
||||||
return None
|
text=self._trad["mb_diff_results_title"],
|
||||||
if solver2 is None:
|
informative_text=self._trad["mb_diff_results_param_msg"]
|
||||||
# TODO message
|
)
|
||||||
|
|
||||||
|
def msg_diff_results_compatibility(self):
|
||||||
|
self.message_box(
|
||||||
|
window_title=self._trad["Error"],
|
||||||
|
text=self._trad["mb_diff_results_title"],
|
||||||
|
informative_text=self._trad["mb_diff_results_compatibility_msg"]
|
||||||
|
)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def diff_results(self, solver1, solver2,
|
||||||
|
scenario1=None, scenario2=None):
|
||||||
|
if solver1 is None or solver2 is None:
|
||||||
|
self.msg_diff_results_param()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
solver3 = GenericSolver(solver1.name+" - "+solver2.name)
|
study1 = self._study
|
||||||
solver4 = GenericSolver(solver1.name)
|
study2 = self._study
|
||||||
solver5 = GenericSolver(solver2.name)
|
|
||||||
|
s3_name = solver1.name + " <> " + solver2.name
|
||||||
|
|
||||||
|
if not (scenario2 is None or scenario2 is None):
|
||||||
|
study1 = self._study.copy_from_scenario(scenario1)
|
||||||
|
study2 = self._study.copy_from_scenario(scenario2)
|
||||||
|
|
||||||
|
s3_name = scenario1.name + " <> " + scenario2.name
|
||||||
|
|
||||||
|
solver3 = GenericSolver(s3_name)
|
||||||
|
|
||||||
result1 = solver1.results(
|
result1 = solver1.results(
|
||||||
self._study,
|
study1,
|
||||||
self._solver_workdir(solver1),
|
self._solver_workdir(solver1, scenario=scenario1),
|
||||||
)
|
)
|
||||||
|
|
||||||
if result1 is None:
|
|
||||||
# TODO message
|
|
||||||
return None
|
|
||||||
|
|
||||||
result2 = solver2.results(
|
result2 = solver2.results(
|
||||||
self._study,
|
study2,
|
||||||
self._solver_workdir(solver2),
|
self._solver_workdir(solver2, scenario=scenario2),
|
||||||
)
|
)
|
||||||
|
|
||||||
if result2 is None:
|
if result1 is None or result2 is None:
|
||||||
# TODO message
|
self.msg_diff_results_param()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if result2.get("nb_reach") != result1.get("nb_reach"):
|
if result1.get("nb_reach") != result2.get("nb_reach"):
|
||||||
# TODO message
|
self.msg_diff_results_compatibility()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if result2.get("nb_profile") != result1.get("nb_profile"):
|
if result1.get("nb_profile") != result2.get("nb_profile"):
|
||||||
# TODO message
|
self.msg_diff_results_compatibility()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# return [result1, result2]
|
return self._diff_results(
|
||||||
|
solver1, solver2, solver3,
|
||||||
|
result1, result2,
|
||||||
|
)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def _diff_results(self, solver1, solver2, solver3, result1, result2):
|
||||||
|
result3 = Results(study=self._study, solver=solver3)
|
||||||
|
ts = sorted(
|
||||||
|
list(
|
||||||
|
result1.get("timestamps").intersection(
|
||||||
|
result2.get("timestamps")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
result3 = Results(self._study, solver3)
|
|
||||||
result4 = Results(self._study, solver1)
|
|
||||||
result5 = Results(self._study, solver2)
|
|
||||||
result3.set("nb_reach", result1.get("nb_reach"))
|
result3.set("nb_reach", result1.get("nb_reach"))
|
||||||
result4.set("nb_reach", result1.get("nb_reach"))
|
|
||||||
result5.set("nb_reach", result1.get("nb_reach"))
|
|
||||||
result3.set("nb_profile", result1.get("nb_profile"))
|
result3.set("nb_profile", result1.get("nb_profile"))
|
||||||
result4.set("nb_profile", result1.get("nb_profile"))
|
|
||||||
result5.set("nb_profile", result1.get("nb_profile"))
|
|
||||||
ts = sorted(list(result1.get("timestamps").intersection(
|
|
||||||
result2.get("timestamps"))))
|
|
||||||
result3.set("timestamps", ts)
|
result3.set("timestamps", ts)
|
||||||
result4.set("timestamps", ts)
|
|
||||||
result5.set("timestamps", ts)
|
|
||||||
|
|
||||||
for i in range(int(result1.get("nb_reach"))):
|
for i in range(int(result1.get("nb_reach"))):
|
||||||
# Add reach to results reach list
|
|
||||||
r = result3.river.add(i)
|
r = result3.river.add(i)
|
||||||
r = result4.river.add(i)
|
|
||||||
r = result5.river.add(i)
|
|
||||||
|
|
||||||
for timestamp in result3.get("timestamps"):
|
for timestamp in result3.get("timestamps"):
|
||||||
for r in range(int(result1.get("nb_reach"))):
|
for r in range(int(result1.get("nb_reach"))):
|
||||||
reach1 = result1.river.reach(r)
|
reach1 = result1.river.reach(r)
|
||||||
reach2 = result2.river.reach(r)
|
reach2 = result2.river.reach(r)
|
||||||
reach3 = result3.river.reach(r)
|
reach3 = result3.river.reach(r)
|
||||||
reach4 = result4.river.reach(r)
|
|
||||||
reach5 = result5.river.reach(r)
|
for profile1, profile2, profile3 in zip(
|
||||||
for p, (profile1, profile2) in enumerate(zip(
|
reach1.profiles,
|
||||||
reach1.profiles, reach2.profiles)):
|
reach2.profiles,
|
||||||
|
reach3.profiles):
|
||||||
for key in ["Z", "Q", "V"]:
|
for key in ["Z", "Q", "V"]:
|
||||||
d1 = profile1.get_ts_key(timestamp, key)
|
d1 = profile1.get_ts_key(timestamp, key)
|
||||||
d2 = profile2.get_ts_key(timestamp, key)
|
d2 = profile2.get_ts_key(timestamp, key)
|
||||||
d = d1-d2
|
d = d1 - d2
|
||||||
reach3.set(p, timestamp, key, d)
|
|
||||||
reach4.set(p, timestamp, key, d1)
|
|
||||||
reach5.set(p, timestamp, key, d2)
|
|
||||||
limits = reach3.profile(p).geometry.get_water_limits(
|
|
||||||
reach3.profile(p).get_ts_key(timestamp, "Z")
|
|
||||||
)
|
|
||||||
reach3.set(
|
|
||||||
p, timestamp,
|
|
||||||
"water_limits",
|
|
||||||
limits
|
|
||||||
)
|
|
||||||
limits = profile1.get_ts_key(timestamp, "water_limits")
|
|
||||||
reach4.set(p, timestamp, "water_limits", limits)
|
|
||||||
limits = profile2.get_ts_key(timestamp, "water_limits")
|
|
||||||
reach5.set(p, timestamp, "water_limits", limits)
|
|
||||||
|
|
||||||
return [result4, result5, result3]
|
profile3.set(timestamp, key, d)
|
||||||
|
|
||||||
|
limits = profile3.geometry\
|
||||||
|
.get_water_limits(
|
||||||
|
profile3.get_ts_key(timestamp, "Z")
|
||||||
|
)
|
||||||
|
profile3.set(timestamp, "water_limits", limits)
|
||||||
|
|
||||||
|
return [result1, result2, result3]
|
||||||
|
|
||||||
def open_results_adists(self):
|
def open_results_adists(self):
|
||||||
if self._study is None:
|
if self._study is None:
|
||||||
@@ -1866,6 +2008,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
solver_results_adists = solver_results.results(
|
solver_results_adists = solver_results.results(
|
||||||
self._study,
|
self._study,
|
||||||
repertory=dir_path, qlog=None) # self._output)
|
repertory=dir_path, qlog=None) # self._output)
|
||||||
|
|
||||||
logger.info(f"Select results: {dir_path}")
|
logger.info(f"Select results: {dir_path}")
|
||||||
if len(bin_list) >= 2 and ("total_sediment.bin" in bin_list):
|
if len(bin_list) >= 2 and ("total_sediment.bin" in bin_list):
|
||||||
self.open_solver_results_adists(
|
self.open_solver_results_adists(
|
||||||
|
|||||||
@@ -27,6 +27,20 @@ from View.Tools.PamhyrWidget import PamhyrWidget
|
|||||||
|
|
||||||
from PyQt5.QtWidgets import QVBoxLayout
|
from PyQt5.QtWidgets import QVBoxLayout
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
@@ -104,10 +118,12 @@ class WidgetInfo(PamhyrWidget):
|
|||||||
self.plot = PlotXY(
|
self.plot = PlotXY(
|
||||||
canvas=self.canvas,
|
canvas=self.canvas,
|
||||||
data=self._study.river.enable_edges(),
|
data=self._study.river.enable_edges(),
|
||||||
|
geotiff=self._study.river.geotiff,
|
||||||
trad=self.parent._trad,
|
trad=self.parent._trad,
|
||||||
toolbar=self._toolbar_xy,
|
toolbar=self._toolbar_xy,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
|
|
||||||
def set_network_values(self):
|
def set_network_values(self):
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ class GraphWidget(QGraphicsView):
|
|||||||
def setup_scene(self, min_size, max_size, size):
|
def setup_scene(self, min_size, max_size, size):
|
||||||
scene = QGraphicsScene(self)
|
scene = QGraphicsScene(self)
|
||||||
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
|
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
|
||||||
scene.setSceneRect(0, 0, 2000, 2000)
|
scene.setSceneRect(0, 0, 6000, 6000)
|
||||||
|
|
||||||
self.setScene(scene)
|
self.setScene(scene)
|
||||||
self.setCacheMode(QGraphicsView.CacheBackground)
|
self.setCacheMode(QGraphicsView.CacheBackground)
|
||||||
@@ -492,6 +492,7 @@ class GraphWidget(QGraphicsView):
|
|||||||
|
|
||||||
self.scale(1, 1)
|
self.scale(1, 1)
|
||||||
self.previousScale = 1
|
self.previousScale = 1
|
||||||
|
self.centerOn(1000.0, 1000.0)
|
||||||
|
|
||||||
if min_size:
|
if min_size:
|
||||||
self.setMinimumSize(*min_size)
|
self.setMinimumSize(*min_size)
|
||||||
|
|||||||
+65
-6
@@ -27,12 +27,26 @@ from PyQt5.QtCore import (
|
|||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import QApplication, QTableView
|
from PyQt5.QtWidgets import QApplication, QTableView
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
_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, geotiff=None,
|
||||||
table=None, parent=None):
|
toolbar=None, table=None, parent=None):
|
||||||
super(PlotXY, self).__init__(
|
super(PlotXY, self).__init__(
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
trad=trad,
|
trad=trad,
|
||||||
@@ -43,10 +57,14 @@ class PlotXY(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
|
self._geotiff = geotiff
|
||||||
|
|
||||||
self.label_x = self._trad["x"]
|
self.label_x = self._trad["x"]
|
||||||
self.label_y = self._trad["y"]
|
self.label_y = self._trad["y"]
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
|
self._plot_img = {}
|
||||||
|
|
||||||
self._isometric_axis = True
|
self._isometric_axis = True
|
||||||
|
|
||||||
self._auto_relim_update = True
|
self._auto_relim_update = True
|
||||||
@@ -69,7 +87,12 @@ class PlotXY(PamhyrPlot):
|
|||||||
if data.reach.number_profiles != 0:
|
if data.reach.number_profiles != 0:
|
||||||
self.draw_xy(data.reach)
|
self.draw_xy(data.reach)
|
||||||
self.draw_lr(data.reach)
|
self.draw_lr(data.reach)
|
||||||
self.idle()
|
|
||||||
|
if self._geotiff is not None:
|
||||||
|
self.draw_geotiff(self._geotiff.files)
|
||||||
|
|
||||||
|
self.idle()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def draw_xy(self, reach):
|
def draw_xy(self, reach):
|
||||||
@@ -78,9 +101,9 @@ class PlotXY(PamhyrPlot):
|
|||||||
line_xy.append(np.column_stack(xy))
|
line_xy.append(np.column_stack(xy))
|
||||||
|
|
||||||
line_xy_collection = collections.LineCollection(
|
line_xy_collection = collections.LineCollection(
|
||||||
line_xy,
|
line_xy,
|
||||||
colors=self.color_plot_river_bottom
|
colors=self.color_plot_river_bottom
|
||||||
)
|
)
|
||||||
self.canvas.axes.add_collection(line_xy_collection)
|
self.canvas.axes.add_collection(line_xy_collection)
|
||||||
|
|
||||||
def draw_lr(self, reach):
|
def draw_lr(self, reach):
|
||||||
@@ -113,6 +136,42 @@ class PlotXY(PamhyrPlot):
|
|||||||
)
|
)
|
||||||
self.line_lr.append(line)
|
self.line_lr.append(line)
|
||||||
|
|
||||||
|
def draw_geotiff(self, lst):
|
||||||
|
if not _rasterio_loaded:
|
||||||
|
return
|
||||||
|
|
||||||
|
for img in self._plot_img:
|
||||||
|
self._plot_img[img].remove()
|
||||||
|
|
||||||
|
self._plot_img = {}
|
||||||
|
|
||||||
|
for geotiff in lst:
|
||||||
|
if geotiff.is_deleted():
|
||||||
|
continue
|
||||||
|
|
||||||
|
memfile = geotiff.memfile
|
||||||
|
if memfile is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
with memfile.open() as gt:
|
||||||
|
img = gt.read()
|
||||||
|
coords = geotiff.coordinates
|
||||||
|
|
||||||
|
left = coords["left"]
|
||||||
|
right = coords["right"]
|
||||||
|
bottom = coords["bottom"]
|
||||||
|
top = coords["top"]
|
||||||
|
|
||||||
|
self._plot_img[geotiff] = self.canvas.axes.imshow(
|
||||||
|
img.transpose((1, 2, 0)),
|
||||||
|
extent=(left, right, bottom, top)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not geotiff.is_enabled():
|
||||||
|
self._plot_img[geotiff].set(alpha=0.5)
|
||||||
|
|
||||||
|
self.idle()
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self):
|
def update(self):
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class AddCommand(QUndoCommand):
|
|||||||
self._new = self._pollutants_lst.new(
|
self._new = self._pollutants_lst.new(
|
||||||
self._pollutants_lst, self._index
|
self._pollutants_lst, self._index
|
||||||
)
|
)
|
||||||
self._new._data = [[0, 0., 0., 0., 0., 0., 0., 0., 0.]]
|
self._new.data = [0, 0., 0., 0., 0., 0., 0., 0., 0.]
|
||||||
self._new_ic_adists = self._data.new(self._index, self._new.id)
|
self._new_ic_adists = self._data.new(self._index, self._new.id)
|
||||||
else:
|
else:
|
||||||
self._pollutants_lst.insert(self._index, self._new)
|
self._pollutants_lst.insert(self._index, self._new)
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from queue import Queue
|
||||||
|
from tools import trace, timer, logger_exception
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrDialog, PamhyrWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect, QTimer, QProcess,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
QTextEdit,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.WaitingDialog import WaitingDialog
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class CompareScenariosWindow(PamhyrDialog):
|
||||||
|
_pamhyr_ui = "CompareScenarios"
|
||||||
|
_pamhyr_name = "Compare scenarios"
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None,
|
||||||
|
parent=None):
|
||||||
|
self._solvers = []
|
||||||
|
self._scenarios = []
|
||||||
|
|
||||||
|
name = _translate("Solver", "Compare solvers")
|
||||||
|
super(CompareScenariosWindow, self).__init__(
|
||||||
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_solvers()
|
||||||
|
self.setup_scenarios()
|
||||||
|
self.setup_connections()
|
||||||
|
self.select_last_solver()
|
||||||
|
|
||||||
|
def setup_solvers(self):
|
||||||
|
solvers = self._config.solvers
|
||||||
|
solvers_name = list(
|
||||||
|
map(
|
||||||
|
self._format_solver_name, solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.combobox_add_items("comboBoxSolver1", solvers_name)
|
||||||
|
self.combobox_add_items("comboBoxSolver2", solvers_name)
|
||||||
|
|
||||||
|
def setup_scenarios(self):
|
||||||
|
scenarios = self._study.scenarios.lst
|
||||||
|
scenarios_name = list(
|
||||||
|
map(
|
||||||
|
lambda s: s.name, scenarios
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.combobox_add_items("comboBoxScenario1", scenarios_name)
|
||||||
|
self.combobox_add_items("comboBoxScenario2", scenarios_name)
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
|
||||||
|
self.find(QPushButton, "pushButton_cancel")\
|
||||||
|
.clicked.connect(self.reject)
|
||||||
|
|
||||||
|
def select_last_solver(self):
|
||||||
|
solvers = self._config.solvers
|
||||||
|
last = self._config.last_solver_name
|
||||||
|
|
||||||
|
solver = list(
|
||||||
|
filter(
|
||||||
|
lambda s: s.name == last,
|
||||||
|
solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(solver) != 0:
|
||||||
|
self.set_combobox_text(
|
||||||
|
"comboBoxSolver1",
|
||||||
|
self._format_solver_name(solver[0])
|
||||||
|
)
|
||||||
|
self.set_combobox_text(
|
||||||
|
"comboBoxSolver2",
|
||||||
|
self._format_solver_name(solver[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
def _format_solver_name(self, solver):
|
||||||
|
return f"{solver.name} - ({solver._type})"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solver1(self):
|
||||||
|
return self._solvers[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solver2(self):
|
||||||
|
return self._solvers[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scenario1(self):
|
||||||
|
return self._scenarios[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scenario2(self):
|
||||||
|
return self._scenarios[1]
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
for cb in ["comboBoxSolver1", "comboBoxSolver2"]:
|
||||||
|
name = self.get_combobox_text(cb)
|
||||||
|
name = name.rsplit(" - ", 1)[0]
|
||||||
|
self._solvers.append(
|
||||||
|
next(
|
||||||
|
filter(
|
||||||
|
lambda s: s.name == name,
|
||||||
|
self._config.solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for cb in ["comboBoxScenario1", "comboBoxScenario2"]:
|
||||||
|
name = self.get_combobox_text(cb)
|
||||||
|
self._scenarios.append(
|
||||||
|
next(
|
||||||
|
filter(
|
||||||
|
lambda s: s.name == name,
|
||||||
|
self._study.scenarios.lst
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
super(CompareScenariosWindow, self).accept()
|
||||||
@@ -599,13 +599,7 @@ class CustomPlot(PamhyrPlot):
|
|||||||
self.lines["wet_area"] = line
|
self.lines["wet_area"] = line
|
||||||
|
|
||||||
# Legend
|
# Legend
|
||||||
lns = reduce(
|
self.update_legend()
|
||||||
lambda acc, line: acc + line,
|
|
||||||
map(lambda line: self.lines[line], self.lines),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
labs = list(map(lambda line: self._trad[line], self.lines))
|
|
||||||
self.canvas.axes.legend(lns, labs, loc="best")
|
|
||||||
|
|
||||||
def _redraw_rk(self):
|
def _redraw_rk(self):
|
||||||
results = self.data[self._current_res_id]
|
results = self.data[self._current_res_id]
|
||||||
@@ -1103,13 +1097,7 @@ class CustomPlot(PamhyrPlot):
|
|||||||
self._customize_x_axes_time(ts)
|
self._customize_x_axes_time(ts)
|
||||||
|
|
||||||
# Legend
|
# Legend
|
||||||
lns = reduce(
|
self.update_legend()
|
||||||
lambda acc, line: acc + line,
|
|
||||||
map(lambda line: self.lines[line], self.lines),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
labs = list(map(lambda line: self._trad[line], self.lines))
|
|
||||||
self.canvas.axes.legend(lns, labs, loc="best")
|
|
||||||
|
|
||||||
def _redraw_time(self):
|
def _redraw_time(self):
|
||||||
|
|
||||||
@@ -1419,3 +1407,25 @@ class CustomPlot(PamhyrPlot):
|
|||||||
x = self._timestamp
|
x = self._timestamp
|
||||||
self._current.set_data([x, x], self.canvas.axes.get_ylim())
|
self._current.set_data([x, x], self.canvas.axes.get_ylim())
|
||||||
self.canvas.draw_idle()
|
self.canvas.draw_idle()
|
||||||
|
|
||||||
|
def update_legend(self):
|
||||||
|
lns = reduce(
|
||||||
|
lambda acc, line: acc + line,
|
||||||
|
map(lambda line: self.lines[line], self.lines),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
labs = list(map(lambda line: self._trad[line], self.lines))
|
||||||
|
self.canvas.axes.legend(lns, labs, loc="best")
|
||||||
|
|
||||||
|
def add_imported_plot(self, data):
|
||||||
|
if (data["type_x"] == self._x and
|
||||||
|
data["type_y"] in self._y):
|
||||||
|
while data["legend"] in self.lines:
|
||||||
|
data["legend"] += '*'
|
||||||
|
self._trad._dict[data["legend"]] = data["legend"] + data["unit"]
|
||||||
|
self.lines[data["legend"]] = self.canvas.axes.plot(data["x"],
|
||||||
|
data["y"],
|
||||||
|
marker="+",
|
||||||
|
linestyle="--")
|
||||||
|
self.update_legend()
|
||||||
|
self.idle()
|
||||||
@@ -55,6 +55,9 @@ class CustomPlotTranslate(ResultsTranslate):
|
|||||||
self._dict['wet_perimeter'] = self._dict["unit_wet_perimeter"]
|
self._dict['wet_perimeter'] = self._dict["unit_wet_perimeter"]
|
||||||
self._dict['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
self._dict['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
||||||
self._dict['froude'] = self._dict["unit_froude"]
|
self._dict['froude'] = self._dict["unit_froude"]
|
||||||
|
self._dict['user_imported'] = _translate(
|
||||||
|
"CustomPlot", "user_imported"
|
||||||
|
)
|
||||||
|
|
||||||
# Unit corresponding long name (plot axes display)
|
# Unit corresponding long name (plot axes display)
|
||||||
|
|
||||||
|
|||||||
@@ -149,8 +149,17 @@ class PlotAC(PamhyrPlot):
|
|||||||
self.annotation = []
|
self.annotation = []
|
||||||
self.cgl, self.igl = reach.geometry.compute_guidelines()
|
self.cgl, self.igl = reach.geometry.compute_guidelines()
|
||||||
|
|
||||||
lcomplete = list(self.cgl)
|
# we make sure that the lines are in the left-to-right order
|
||||||
lincomplete = list(self.igl)
|
lcomplete = [
|
||||||
|
x.name
|
||||||
|
for x in profile.geometry.named_points()
|
||||||
|
if x.name in self.cgl
|
||||||
|
]
|
||||||
|
lincomplete = [
|
||||||
|
x.name
|
||||||
|
for x in profile.geometry.named_points()
|
||||||
|
if x.name in self.igl
|
||||||
|
]
|
||||||
|
|
||||||
self.color_complete_gl = self.colors
|
self.color_complete_gl = self.colors
|
||||||
self.color_incomplete_gl = 2 * ["grey"]
|
self.color_incomplete_gl = 2 * ["grey"]
|
||||||
@@ -170,7 +179,7 @@ class PlotAC(PamhyrPlot):
|
|||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
color = self.color_incomplete_gl[
|
color = self.color_incomplete_gl[
|
||||||
lincomplete.index(txt)
|
lincomplete.index(txt) % len(self.color_incomplete_gl)
|
||||||
]
|
]
|
||||||
|
|
||||||
annotation = self.canvas.axes.annotate(
|
annotation = self.canvas.axes.annotate(
|
||||||
|
|||||||
@@ -31,6 +31,20 @@ from PyQt5.QtCore import (
|
|||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import QApplication, QTableView
|
from PyQt5.QtWidgets import QApplication, QTableView
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
@@ -52,6 +66,8 @@ class PlotXY(PamhyrPlot):
|
|||||||
self.line_gl = []
|
self.line_gl = []
|
||||||
self.overflow = []
|
self.overflow = []
|
||||||
|
|
||||||
|
self._plot_img = {}
|
||||||
|
|
||||||
self._timestamps = parent._timestamps
|
self._timestamps = parent._timestamps
|
||||||
self._current_timestamp = max(self._timestamps)
|
self._current_timestamp = max(self._timestamps)
|
||||||
self._current_reach_id = reach_id
|
self._current_reach_id = reach_id
|
||||||
@@ -153,6 +169,7 @@ class PlotXY(PamhyrPlot):
|
|||||||
reach = results.river.reach(self._current_reach_id)
|
reach = results.river.reach(self._current_reach_id)
|
||||||
reaches = results.river.reachs
|
reaches = results.river.reachs
|
||||||
|
|
||||||
|
self.draw_geotiff()
|
||||||
self.draw_profiles(reach, reaches)
|
self.draw_profiles(reach, reaches)
|
||||||
self.draw_water_elevation(reach)
|
self.draw_water_elevation(reach)
|
||||||
self.draw_water_elevation_max(reach)
|
self.draw_water_elevation_max(reach)
|
||||||
@@ -166,6 +183,7 @@ class PlotXY(PamhyrPlot):
|
|||||||
if reach.geometry.number_profiles == 0:
|
if reach.geometry.number_profiles == 0:
|
||||||
self._init = False
|
self._init = False
|
||||||
return
|
return
|
||||||
|
|
||||||
self.line_xy = []
|
self.line_xy = []
|
||||||
# TODO uncomment to draw all the reaches
|
# TODO uncomment to draw all the reaches
|
||||||
# self.draw_other_profiles(reaches)
|
# self.draw_other_profiles(reaches)
|
||||||
@@ -306,6 +324,41 @@ class PlotXY(PamhyrPlot):
|
|||||||
alpha=0.7
|
alpha=0.7
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def draw_geotiff(self):
|
||||||
|
if not _rasterio_loaded:
|
||||||
|
return
|
||||||
|
|
||||||
|
lst = self._data[0]._study.river._geotiff.lst
|
||||||
|
|
||||||
|
for img in self._plot_img:
|
||||||
|
self._plot_img[img].remove()
|
||||||
|
|
||||||
|
self._plot_img = {}
|
||||||
|
|
||||||
|
for geotiff in lst:
|
||||||
|
memfile = geotiff.memfile
|
||||||
|
if memfile is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
with memfile.open() as gt:
|
||||||
|
img = gt.read()
|
||||||
|
coords = geotiff.coordinates
|
||||||
|
|
||||||
|
left = coords["left"]
|
||||||
|
right = coords["right"]
|
||||||
|
bottom = coords["bottom"]
|
||||||
|
top = coords["top"]
|
||||||
|
|
||||||
|
self._plot_img[geotiff] = self.canvas.axes.imshow(
|
||||||
|
img.transpose((1, 2, 0)),
|
||||||
|
extent=(left, right, bottom, top)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not geotiff.is_enabled():
|
||||||
|
self._plot_img[geotiff].set(alpha=0.5)
|
||||||
|
|
||||||
|
self.idle()
|
||||||
|
|
||||||
def set_reach(self, reach_id):
|
def set_reach(self, reach_id):
|
||||||
self._current_reach_id = reach_id
|
self._current_reach_id = reach_id
|
||||||
self._current_profile_id = 0
|
self._current_profile_id = 0
|
||||||
|
|||||||
@@ -160,8 +160,6 @@ class TableModel(PamhyrTableModel):
|
|||||||
self._lst = _river.reachs
|
self._lst = _river.reachs
|
||||||
elif self._opt_data == "profile" or self._opt_data == "raw_data":
|
elif self._opt_data == "profile" or self._opt_data == "raw_data":
|
||||||
self._lst = _river.reach(reach).profiles
|
self._lst = _river.reach(reach).profiles
|
||||||
# self._lst = list(compress(_river.reach(reach).profiles,
|
|
||||||
# _river.reach(reach).profile_mask))
|
|
||||||
elif self._opt_data == "solver":
|
elif self._opt_data == "solver":
|
||||||
self._lst = self._parent._solvers
|
self._lst = self._parent._solvers
|
||||||
|
|
||||||
|
|||||||
+201
-51
@@ -19,7 +19,19 @@
|
|||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
import logging
|
import logging
|
||||||
# import rasterio
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
from numpy import sqrt
|
from numpy import sqrt
|
||||||
|
|
||||||
@@ -44,9 +56,12 @@ from PyQt5.QtWidgets import (
|
|||||||
QFileDialog, QTableView, QAbstractItemView,
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
QUndoStack, QShortcut, QAction, QItemDelegate,
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
QSlider, QLabel, QWidget, QGridLayout, QTabBar
|
QSlider, QLabel, QWidget, QGridLayout, QTabBar,
|
||||||
|
QInputDialog,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from Model.Results.Results import AdditionalData
|
||||||
|
|
||||||
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
@@ -132,11 +147,14 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
profile_id=[0])
|
profile_id=[0])
|
||||||
|
|
||||||
self.update_table_selection_solver(0)
|
self.update_table_selection_solver(0)
|
||||||
|
self.update_plot_additional_data()
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["reach", "profile", "raw_data", "solver"]:
|
for t in ["reach", "profile", "raw_data", "solver"]:
|
||||||
table = self.find(QTableView, f"tableView_{t}")
|
table = self.find(QTableView, f"tableView_{t}")
|
||||||
|
|
||||||
self._table[t] = TableModel(
|
self._table[t] = TableModel(
|
||||||
table_view=table,
|
table_view=table,
|
||||||
table_headers=self._trad.get_dict(f"table_headers_{t}"),
|
table_headers=self._trad.get_dict(f"table_headers_{t}"),
|
||||||
@@ -145,8 +163,11 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
opt_data=t,
|
opt_data=t,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
self._table[t]._timestamp = self._timestamps[
|
self._table[t]._timestamp = self._timestamps[
|
||||||
self._slider_time.value()]
|
self._slider_time.value()
|
||||||
|
]
|
||||||
|
|
||||||
if len(self._results) <= 1:
|
if len(self._results) <= 1:
|
||||||
table = self.find(QTableView, f"tableView_solver")
|
table = self.find(QTableView, f"tableView_solver")
|
||||||
table.hide()
|
table.hide()
|
||||||
@@ -177,12 +198,15 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
|
|
||||||
def setup_plots(self):
|
def setup_plots(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
|
||||||
tab_widget = self.find(QTabWidget, f"tabWidget")
|
tab_widget = self.find(QTabWidget, f"tabWidget")
|
||||||
|
|
||||||
tab_widget.setTabsClosable(True)
|
tab_widget.setTabsClosable(True)
|
||||||
tab_widget.tabCloseRequested.connect(self.delete_tab)
|
tab_widget.tabCloseRequested.connect(self.delete_tab)
|
||||||
tab_widget.tabBar().setTabButton(0, QTabBar.RightSide, None)
|
tab_widget.tabBar().setTabButton(0, QTabBar.RightSide, None)
|
||||||
tab_widget.tabBar().setTabButton(1, QTabBar.RightSide, None)
|
tab_widget.tabBar().setTabButton(1, QTabBar.RightSide, None)
|
||||||
tab_widget.tabBar().setTabButton(2, QTabBar.RightSide, None)
|
tab_widget.tabBar().setTabButton(2, QTabBar.RightSide, None)
|
||||||
|
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamhyrPlotToolbar(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self, items=[
|
self.canvas, self, items=[
|
||||||
@@ -190,6 +214,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
"iso", "back/forward"
|
"iso", "back/forward"
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
self.plot_layout.addWidget(self.toolbar)
|
self.plot_layout.addWidget(self.toolbar)
|
||||||
self.plot_layout.addWidget(self.canvas)
|
self.plot_layout.addWidget(self.canvas)
|
||||||
@@ -337,10 +362,13 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
"action_add": self._add_custom_plot,
|
"action_add": self._add_custom_plot,
|
||||||
"action_export": self._export,
|
"action_export": self._export,
|
||||||
# "action_export": self.export_current,
|
# "action_export": self.export_current,
|
||||||
"action_Geo_tiff": self.import_geotiff
|
"action_import_data": self.import_data
|
||||||
}
|
}
|
||||||
self.find(QAction, "action_Geo_tiff").setEnabled(False)
|
if _rasterio_loaded:
|
||||||
self.find(QAction, "action_Geo_tiff").setVisible(False)
|
actions["action_Geo_tiff"] = self.import_geotiff
|
||||||
|
else:
|
||||||
|
self.find(QAction, "action_Geo_tiff")\
|
||||||
|
.setEnabled(False)
|
||||||
|
|
||||||
if len(self._results) > 1:
|
if len(self._results) > 1:
|
||||||
self.find(QAction, "action_reload").setEnabled(False)
|
self.find(QAction, "action_reload").setEnabled(False)
|
||||||
@@ -703,7 +731,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
select_file="AnyFile",
|
select_file="AnyFile",
|
||||||
callback=lambda f: self.export_to(f[0], x, y, envelop, solver_id),
|
callback=lambda f: self.export_to(f[0], x, y, envelop, solver_id),
|
||||||
default_suffix=".csv",
|
default_suffix=".csv",
|
||||||
file_filter=["CSV (*.csv)"],
|
file_filter=[self._trad["file_csv"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
def export_to(self, filename, x, y, envelop, solver_id):
|
def export_to(self, filename, x, y, envelop, solver_id):
|
||||||
@@ -1169,48 +1197,170 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
self.update_table_selection_profile(profile_id)
|
self.update_table_selection_profile(profile_id)
|
||||||
|
|
||||||
def import_geotiff(self):
|
def import_geotiff(self):
|
||||||
# options = QFileDialog.Options()
|
options = QFileDialog.Options()
|
||||||
# settings = QSettings(QSettings.IniFormat,
|
settings = QSettings(QSettings.IniFormat,
|
||||||
# QSettings.UserScope, 'MyOrg', )
|
QSettings.UserScope, 'MyOrg', )
|
||||||
# options |= QFileDialog.DontUseNativeDialog
|
options |= QFileDialog.DontUseNativeDialog
|
||||||
#
|
|
||||||
# file_types = [
|
file_types = [
|
||||||
# self._trad["file_geotiff"],
|
self._trad["file_geotiff"],
|
||||||
# self._trad["file_all"],
|
self._trad["file_all"],
|
||||||
# ]
|
]
|
||||||
#
|
|
||||||
# filename, _ = QFileDialog.getOpenFileName(
|
filename, _ = QFileDialog.getOpenFileName(
|
||||||
# self,
|
self,
|
||||||
# self._trad["open_file"],
|
self._trad["open_file"],
|
||||||
# "",
|
"",
|
||||||
# ";; ".join(file_types),
|
";; ".join(file_types),
|
||||||
# options=options
|
options=options
|
||||||
# )
|
)
|
||||||
#
|
|
||||||
# if filename != "":
|
if filename != "":
|
||||||
# with rasterio.open(filename) as data:
|
with rasterio.open(filename) as data:
|
||||||
# img = data.read()
|
img = data.read()
|
||||||
# b = data.bounds[:]
|
b = data.bounds[:]
|
||||||
# # b[0] left
|
# b[0] left
|
||||||
# # b[1] bottom
|
# b[1] bottom
|
||||||
# # b[2] right
|
# b[2] right
|
||||||
# # b[3] top
|
# b[3] top
|
||||||
# xlim = self.canvas.axes.get_xlim()
|
xlim = self.canvas.axes.get_xlim()
|
||||||
# ylim = self.canvas.axes.get_ylim()
|
ylim = self.canvas.axes.get_ylim()
|
||||||
# if b[2] > b[0] and b[1] < b[3]:
|
if b[2] > b[0] and b[1] < b[3]:
|
||||||
# self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||||
# extent=[b[0], b[2], b[1], b[3]])
|
extent=[b[0], b[2], b[1], b[3]])
|
||||||
# else:
|
else:
|
||||||
# dlg = CoordinatesDialog(
|
dlg = CoordinatesDialog(
|
||||||
# xlim,
|
xlim, ylim,
|
||||||
# ylim,
|
trad=self._trad,
|
||||||
# trad=self._trad,
|
parent=self
|
||||||
# parent=self
|
)
|
||||||
# )
|
if dlg.exec():
|
||||||
# if dlg.exec():
|
self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||||
# self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
extent=dlg.values)
|
||||||
# extent=dlg.values)
|
self.plot_xy.idle()
|
||||||
# self.plot_xy.idle()
|
self.canvas.axes.set_xlim(xlim)
|
||||||
# self.canvas.axes.set_xlim(xlim)
|
self.canvas.axes.set_ylim(ylim)
|
||||||
# self.canvas.axes.set_ylim(ylim)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def import_data(self):
|
||||||
|
file_types = [
|
||||||
|
self._trad["file_csv"],
|
||||||
|
self._trad["file_all"],
|
||||||
|
]
|
||||||
|
|
||||||
|
self.file_dialog(
|
||||||
|
select_file="Existing_file",
|
||||||
|
callback=lambda f: self.read_csv_file(f[0]),
|
||||||
|
default_suffix=".csv",
|
||||||
|
file_filter=file_types,
|
||||||
|
directory=self._results[self._current_results[0]]._repertory,
|
||||||
|
)
|
||||||
|
|
||||||
|
def read_csv_file(self, filename):
|
||||||
|
if filename == "":
|
||||||
|
return
|
||||||
|
|
||||||
|
x, y = self.read_csv_file_data(filename)
|
||||||
|
data = self.read_csv_file_format(x, y)
|
||||||
|
|
||||||
|
results = self._results[self._current_results[0]]
|
||||||
|
data_lst = results.get("additional_data")
|
||||||
|
data_lst.append(
|
||||||
|
AdditionalData(
|
||||||
|
study=self._study,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.update_plot_additional_data()
|
||||||
|
|
||||||
|
def read_csv_file_data(self, filename):
|
||||||
|
sep = ","
|
||||||
|
x = []
|
||||||
|
y = []
|
||||||
|
|
||||||
|
with open(filename, 'r', newline='') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
for line in lines:
|
||||||
|
if line[0] != "*" and line[0] != "#" and line[0] != "$":
|
||||||
|
row = line.split(sep)
|
||||||
|
|
||||||
|
if len(row) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
fx, fy = float(row[0]), float(row[1])
|
||||||
|
x.append(fx)
|
||||||
|
y.append(fy)
|
||||||
|
except Exception as e:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
def read_csv_file_format(self, x, y):
|
||||||
|
data_type_lst = ['Q(t)', 'Z(t)', 'Z(x)']
|
||||||
|
data_type, ok = QInputDialog.getItem(
|
||||||
|
self, 'Data type',
|
||||||
|
'Chose the type of data:',
|
||||||
|
data_type_lst
|
||||||
|
)
|
||||||
|
if not ok:
|
||||||
|
return
|
||||||
|
|
||||||
|
legend, ok = QInputDialog.getText(self, 'Legend', 'Legend:')
|
||||||
|
if not ok:
|
||||||
|
return
|
||||||
|
|
||||||
|
if legend.strip() == '':
|
||||||
|
legend = '*'
|
||||||
|
|
||||||
|
tmp_dict = {'Z': 'water_elevation',
|
||||||
|
'Q': 'discharge',
|
||||||
|
'x': 'rk',
|
||||||
|
't': 'time'}
|
||||||
|
|
||||||
|
tmp_unit = {'Z': ' (m)',
|
||||||
|
'Q': ' (m³/s)'}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'type_x': tmp_dict[data_type[2]],
|
||||||
|
'type_y': tmp_dict[data_type[0]],
|
||||||
|
'legend': legend,
|
||||||
|
'unit': tmp_unit[data_type[0]],
|
||||||
|
'x': x, 'y': y
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def update_plot_additional_data(self):
|
||||||
|
results = self._results[self._current_results[0]]
|
||||||
|
|
||||||
|
for data in results.get("additional_data"):
|
||||||
|
data = data._data
|
||||||
|
x, y = data['x'], data['y']
|
||||||
|
legend = data['legend']
|
||||||
|
unit = data['unit']
|
||||||
|
|
||||||
|
if (
|
||||||
|
data['type_x'] == 'water_elevation' and
|
||||||
|
data['type_y'] == 'time'
|
||||||
|
):
|
||||||
|
line = self.canvas_2.axes.plot(
|
||||||
|
x, y, marker="+",
|
||||||
|
label=legend + ' ' + unit
|
||||||
|
)
|
||||||
|
self.plot_rkc.canvas.draw_idle()
|
||||||
|
self.plot_rkc.update_idle()
|
||||||
|
|
||||||
|
if data['type_x'] == 'time' and data['type_y'] == 'discharge':
|
||||||
|
line = self.canvas_4.axes.plot(
|
||||||
|
x, y, marker="+",
|
||||||
|
label=legend + ' ' + unit
|
||||||
|
)
|
||||||
|
self.plot_h._line.append(line)
|
||||||
|
self.plot_h.enable_legend()
|
||||||
|
self.plot_h.canvas.draw_idle()
|
||||||
|
self.plot_h.update_idle()
|
||||||
|
|
||||||
|
for p in self._additional_plot:
|
||||||
|
self._additional_plot[p].add_imported_plot(data)
|
||||||
@@ -53,9 +53,6 @@ class ResultsTranslate(MainTranslate):
|
|||||||
"Results",
|
"Results",
|
||||||
"Max water elevation"
|
"Max water elevation"
|
||||||
)
|
)
|
||||||
self._dict["file_all"] = _translate("Results", "All files (*)")
|
|
||||||
self._dict["file_geotiff"] = _translate(
|
|
||||||
"Results", "GeoTIFF file (*.tiff *.tif)")
|
|
||||||
self._dict["ImageCoordinates"] = _translate(
|
self._dict["ImageCoordinates"] = _translate(
|
||||||
"Results", "Image coordinates"
|
"Results", "Image coordinates"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -138,107 +138,6 @@ class SelectSolverWindow(PamhyrDialog):
|
|||||||
super(SelectSolverWindow, self).accept()
|
super(SelectSolverWindow, self).accept()
|
||||||
|
|
||||||
|
|
||||||
class CompareSolversWindow(PamhyrDialog):
|
|
||||||
_pamhyr_ui = "CompareSolvers"
|
|
||||||
_pamhyr_name = "Compare solvers"
|
|
||||||
|
|
||||||
def __init__(self, study=None, config=None,
|
|
||||||
parent=None):
|
|
||||||
self._solver1 = None
|
|
||||||
self._solver2 = None
|
|
||||||
|
|
||||||
name = _translate("Solver", "Compare solvers")
|
|
||||||
super(CompareSolversWindow, self).__init__(
|
|
||||||
title=name,
|
|
||||||
study=study,
|
|
||||||
config=config,
|
|
||||||
options=[],
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
|
|
||||||
self.setup_combobox1()
|
|
||||||
self.setup_combobox2()
|
|
||||||
self.setup_connections()
|
|
||||||
self.select_last_solver()
|
|
||||||
|
|
||||||
def setup_combobox1(self):
|
|
||||||
solvers = self._config.solvers
|
|
||||||
solvers_name = list(
|
|
||||||
map(
|
|
||||||
self._format_solver_name,
|
|
||||||
solvers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.combobox_add_items("comboBox1", solvers_name)
|
|
||||||
|
|
||||||
def setup_combobox2(self):
|
|
||||||
solvers = self._config.solvers
|
|
||||||
solvers_name = list(
|
|
||||||
map(
|
|
||||||
self._format_solver_name,
|
|
||||||
solvers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.combobox_add_items("comboBox2", solvers_name)
|
|
||||||
|
|
||||||
def setup_connections(self):
|
|
||||||
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
|
|
||||||
self.find(QPushButton, "pushButton_cancel")\
|
|
||||||
.clicked.connect(self.reject)
|
|
||||||
|
|
||||||
def select_last_solver(self):
|
|
||||||
solvers = self._config.solvers
|
|
||||||
last = self._config.last_solver_name
|
|
||||||
|
|
||||||
solver = list(
|
|
||||||
filter(
|
|
||||||
lambda s: s.name == last,
|
|
||||||
solvers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(solver) != 0:
|
|
||||||
self.set_combobox_text(
|
|
||||||
"comboBox1",
|
|
||||||
self._format_solver_name(solver[0])
|
|
||||||
)
|
|
||||||
|
|
||||||
def _format_solver_name(self, solver):
|
|
||||||
return f"{solver.name} - ({solver._type})"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def solver1(self):
|
|
||||||
return self._solver1
|
|
||||||
|
|
||||||
@property
|
|
||||||
def solver2(self):
|
|
||||||
return self._solver2
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
solver_name1 = self.get_combobox_text("comboBox1")
|
|
||||||
solver_name1 = solver_name1.rsplit(" - ", 1)[0]
|
|
||||||
|
|
||||||
self._solver1 = next(
|
|
||||||
filter(
|
|
||||||
lambda s: s.name == solver_name1,
|
|
||||||
self._config.solvers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
solver_name2 = self.get_combobox_text("comboBox2")
|
|
||||||
solver_name2 = solver_name2.rsplit(" - ", 1)[0]
|
|
||||||
|
|
||||||
self._solver2 = next(
|
|
||||||
filter(
|
|
||||||
lambda s: s.name == solver_name2,
|
|
||||||
self._config.solvers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
super(CompareSolversWindow, self).accept()
|
|
||||||
|
|
||||||
|
|
||||||
class SolverLogWindow(PamhyrWindow):
|
class SolverLogWindow(PamhyrWindow):
|
||||||
_pamhyr_ui = "SolverLog"
|
_pamhyr_ui = "SolverLog"
|
||||||
_pamhyr_name = "Solver Log"
|
_pamhyr_name = "Solver Log"
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
from View.RunSolver.Log.Window import SolverLogFileWindow
|
from View.RunSolver.Log.Window import SolverLogFileWindow
|
||||||
from View.Results.ReadingResultsDialog import ReadingResultsDialog
|
from View.Results.ReadingResultsDialog import ReadingResultsDialog
|
||||||
|
from View.WaitingDialog import WaitingDialog
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from signal import SIGTERM, SIGSTOP, SIGCONT
|
from signal import SIGTERM, SIGSTOP, SIGCONT
|
||||||
@@ -82,7 +83,8 @@ class SelectSolverWindowAdisTS(PamhyrDialog):
|
|||||||
# solvers = self._config.solvers
|
# solvers = self._config.solvers
|
||||||
# solvers mage
|
# solvers mage
|
||||||
solvers = list(filter(
|
solvers = list(filter(
|
||||||
lambda x: "mage" not in x._type, self._config.solvers
|
lambda x: "mage" not in x._type and "rubar" not in x._type,
|
||||||
|
self._config.solvers
|
||||||
))
|
))
|
||||||
solvers_name = list(
|
solvers_name = list(
|
||||||
map(
|
map(
|
||||||
@@ -425,7 +427,9 @@ class SolverLogWindowAdisTS(PamhyrWindow):
|
|||||||
self._study, dir_path, qlog=self._output
|
self._study, dir_path, qlog=self._output
|
||||||
)
|
)
|
||||||
|
|
||||||
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
|
dlg = WaitingDialog(payload_fn=reading_fn,
|
||||||
|
title="waiting_result",
|
||||||
|
parent=self)
|
||||||
dlg.exec_()
|
dlg.exec_()
|
||||||
|
|
||||||
self._parent.set_results(self._solver, self._results)
|
self._parent.set_results(self._solver, self._results)
|
||||||
|
|||||||
@@ -182,25 +182,40 @@ class PamhyrWindow(ASubMainWindow, ListedSubWindow, PamhyrWindowTools):
|
|||||||
|
|
||||||
self._set_title()
|
self._set_title()
|
||||||
self._set_icon()
|
self._set_icon()
|
||||||
|
self._setup_save_sc()
|
||||||
|
|
||||||
def _set_title(self):
|
def _set_title(self):
|
||||||
title = self._title
|
title = self._title
|
||||||
|
|
||||||
if self._study.is_read_only():
|
if self._study is not None:
|
||||||
title = "⛔ " + title
|
if self._study.is_read_only():
|
||||||
|
title = "⛔ " + title
|
||||||
|
|
||||||
scenario = self._study.status.scenario
|
scenario = self._study.status.scenario
|
||||||
if scenario is not None and scenario.name != "default":
|
if scenario is not None and scenario.name != "default":
|
||||||
title += f" | {scenario.name}"
|
title += f" | {scenario.name}"
|
||||||
|
|
||||||
self.ui.setWindowTitle(title)
|
self.ui.setWindowTitle(title)
|
||||||
|
|
||||||
|
def _setup_save_sc(self):
|
||||||
|
if self._parent is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._save_sc = QShortcut(QKeySequence("Ctrl+S"), self)
|
||||||
|
self._save_sc.activated.connect(lambda: self._save(self))
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
self._close_sub_window()
|
self._close_sub_window()
|
||||||
self._propagate_update(Modules.WINDOW_LIST)
|
self._propagate_update(Modules.WINDOW_LIST)
|
||||||
|
|
||||||
super(PamhyrWindow, self).closeEvent(event)
|
super(PamhyrWindow, self).closeEvent(event)
|
||||||
|
|
||||||
|
def _save(self, source):
|
||||||
|
if self._parent is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
return self._parent._save(source)
|
||||||
|
|
||||||
|
|
||||||
class PamhyrDialog(ASubWindow, ListedSubWindow, PamhyrWindowTools):
|
class PamhyrDialog(ASubWindow, ListedSubWindow, PamhyrWindowTools):
|
||||||
_pamhyr_ui = "dummy"
|
_pamhyr_ui = "dummy"
|
||||||
|
|||||||
@@ -54,6 +54,18 @@ class CommonWordTranslate(PamhyrTranslate):
|
|||||||
|
|
||||||
self._dict["method"] = _translate("CommonWord", "Method")
|
self._dict["method"] = _translate("CommonWord", "Method")
|
||||||
|
|
||||||
|
# Files
|
||||||
|
self._dict["open_file"] = _translate(
|
||||||
|
"CommonWord", "Open file"
|
||||||
|
)
|
||||||
|
self._dict["file_all"] = _translate("CommonWord", "All files (*)")
|
||||||
|
self._dict["file_geotiff"] = _translate(
|
||||||
|
"CommonWord", "GeoTIFF file (*.tiff *.tif)"
|
||||||
|
)
|
||||||
|
self._dict["file_csv"] = _translate(
|
||||||
|
"CommonWord", "CSV file (*.csv)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UnitTranslate(CommonWordTranslate):
|
class UnitTranslate(CommonWordTranslate):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -180,6 +192,9 @@ class MainTranslate(UnitTranslate):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Message box
|
# Message box
|
||||||
|
self._dict["Error"] = _translate(
|
||||||
|
"MainWindow", "Error"
|
||||||
|
)
|
||||||
self._dict["Warning"] = _translate(
|
self._dict["Warning"] = _translate(
|
||||||
"MainWindow", "Warning"
|
"MainWindow", "Warning"
|
||||||
)
|
)
|
||||||
@@ -228,6 +243,39 @@ class MainTranslate(UnitTranslate):
|
|||||||
"Do you still want to open those results?"
|
"Do you still want to open those results?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._dict["mb_diff_results_title"] = _translate(
|
||||||
|
"MainWindow", "Results compare"
|
||||||
|
)
|
||||||
|
self._dict["mb_diff_results_param_msg"] = _translate(
|
||||||
|
"MainWindow", "Results comparison parameters is invalid"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._dict["mb_open_results_title"] = _translate(
|
||||||
|
"MainWindow", "Open results"
|
||||||
|
)
|
||||||
|
self._dict["mb_open_results_no_results_msg"] = _translate(
|
||||||
|
"MainWindow", "No results found"
|
||||||
|
)
|
||||||
|
self._dict["mb_open_results_invalid_results_msg"] = _translate(
|
||||||
|
"MainWindow", "Failed to read results"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._dict["mb_diff_results_compatibility_msg"] = _translate(
|
||||||
|
"MainWindow",
|
||||||
|
"Results comparison with two "
|
||||||
|
"incompatible study version"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
self._dict["mb_unsaved_study_title"] = _translate(
|
||||||
|
"MainWindow", "Open scenarios window"
|
||||||
|
)
|
||||||
|
self._dict["mb_unsaved_studyh_msg"] = _translate(
|
||||||
|
"MainWindow",
|
||||||
|
"You must save your study to open "
|
||||||
|
"the scenario windows"
|
||||||
|
)
|
||||||
|
|
||||||
self._dict["x"] = _translate("MainWindow", "X (m)")
|
self._dict["x"] = _translate("MainWindow", "X (m)")
|
||||||
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
||||||
self._dict["Yes"] = _translate("MainWindow", "Yes")
|
self._dict["Yes"] = _translate("MainWindow", "Yes")
|
||||||
@@ -235,3 +283,4 @@ class MainTranslate(UnitTranslate):
|
|||||||
self._dict["Cancel"] = _translate("MainWindow", "Cancel")
|
self._dict["Cancel"] = _translate("MainWindow", "Cancel")
|
||||||
self._dict["Save"] = _translate("MainWindow", "Save")
|
self._dict["Save"] = _translate("MainWindow", "Save")
|
||||||
self._dict["Close"] = _translate("MainWindow", "Close")
|
self._dict["Close"] = _translate("MainWindow", "Close")
|
||||||
|
self._dict["Solver"] = _translate("MainWindow", "Solver")
|
||||||
@@ -63,7 +63,7 @@ class WaitingDialog(PamhyrDialog):
|
|||||||
". ", ". ",
|
". ", ". ",
|
||||||
".. ", ".. ",
|
".. ", ".. ",
|
||||||
"...", "..."],
|
"...", "..."],
|
||||||
["o ", " o ", " o ", " o", " o ", " o "],
|
["o ", " o ", " o ", " o", " o ", " o "],
|
||||||
["█▓▒░", "▓█▓▒", "▒▓█▓", "░▒▓█", "▒▓█▓", "▓█▓▒"],
|
["█▓▒░", "▓█▓▒", "▒▓█▓", "░▒▓█", "▒▓█▓", "▓█▓▒"],
|
||||||
"▖▘▝▗",
|
"▖▘▝▗",
|
||||||
"αβγδεζηθικλμνξοπρστυφχψω",
|
"αβγδεζηθικλμνξοπρστυφχψω",
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>488</width>
|
||||||
|
<height>117</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<property name="locale">
|
||||||
|
<locale language="English" country="Europe"/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBoxSolver1"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBoxSolver2"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBoxScenario1"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBoxScenario2"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_cancel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_ok">
|
||||||
|
<property name="text">
|
||||||
|
<string>OK</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>896</width>
|
||||||
|
<height>504</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<property name="locale">
|
||||||
|
<locale language="English" country="Europe"/>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="2" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_cancel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_ok">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ok</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Informations</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enabled</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_description">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The relative file path on executable directory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="lineEdit_name"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>GeoTIFF file</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_import">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import GeoTIFF file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_geotiff"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_left">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_right">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Right coordinate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_right">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_left">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_bottom">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="pushButton_top">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_right">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_top">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_top">
|
||||||
|
<property name="text">
|
||||||
|
<string>Top coordinate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_bottom">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>99999999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_left">
|
||||||
|
<property name="text">
|
||||||
|
<string>Left coordinate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_bottom">
|
||||||
|
<property name="text">
|
||||||
|
<string>Bottom coordinate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>896</width>
|
||||||
|
<height>504</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QListView" name="listView"/>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="action_add"/>
|
||||||
|
<addaction name="action_delete"/>
|
||||||
|
<addaction name="action_edit"/>
|
||||||
|
</widget>
|
||||||
|
<action name="action_add">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/add.png</normaloff>ressources/add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add a new file</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_delete">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/del.png</normaloff>ressources/del.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete selected file(s)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_edit">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit file</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -129,6 +129,7 @@
|
|||||||
<string>&Geometry</string>
|
<string>&Geometry</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="action_menu_edit_geometry"/>
|
<addaction name="action_menu_edit_geometry"/>
|
||||||
|
<addaction name="action_menu_edit_geotiff"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_run">
|
<widget class="QMenu" name="menu_run">
|
||||||
<property name="locale">
|
<property name="locale">
|
||||||
@@ -160,9 +161,9 @@
|
|||||||
<string>&Results</string>
|
<string>&Results</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="action_menu_results_last"/>
|
<addaction name="action_menu_results_last"/>
|
||||||
<addaction name="action_open_results_from_file"/>
|
<addaction name="action_menu_open_results_from_file"/>
|
||||||
<addaction name="action_compare_results"/>
|
<addaction name="action_menu_compare_scenarios_results"/>
|
||||||
<addaction name="action_open_results_adists"/>
|
<addaction name="action_menu_open_results_adists"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_help">
|
<widget class="QMenu" name="menu_help">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -726,7 +727,7 @@
|
|||||||
<string>Edit hydraulic structures</string>
|
<string>Edit hydraulic structures</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_open_results_from_file">
|
<action name="action_menu_open_results_from_file">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
@@ -787,12 +788,15 @@
|
|||||||
<string>DIF</string>
|
<string>DIF</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_compare_results">
|
<action name="action_menu_compare_results">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Compare results</string>
|
<string>Compare results</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_open_results_adists">
|
<action name="action_menu_open_results_adists">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
@@ -800,6 +804,19 @@
|
|||||||
<string>Open results AdisTS</string>
|
<string>Open results AdisTS</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_menu_compare_scenarios_results">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Compare results</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_menu_edit_geotiff">
|
||||||
|
<property name="text">
|
||||||
|
<string>GeoTIFF</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|||||||
@@ -239,6 +239,7 @@
|
|||||||
<addaction name="action_export"/>
|
<addaction name="action_export"/>
|
||||||
<addaction name="action_reload"/>
|
<addaction name="action_reload"/>
|
||||||
<addaction name="action_Geo_tiff"/>
|
<addaction name="action_Geo_tiff"/>
|
||||||
|
<addaction name="action_import_data"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="action_add">
|
<action name="action_add">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
@@ -288,6 +289,18 @@
|
|||||||
<string>Import background image</string>
|
<string>Import background image</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_import_data">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/import.png</normaloff>ressources/import.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Import data</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Import data from SCV file</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
+31
-1
@@ -37,7 +37,7 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
class Config(SQL):
|
class Config(SQL):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._version = '0.0.6'
|
self._version = '0.0.7'
|
||||||
self.filename = Config.filename()
|
self.filename = Config.filename()
|
||||||
self.set_default_value()
|
self.set_default_value()
|
||||||
|
|
||||||
@@ -165,6 +165,29 @@ class Config(SQL):
|
|||||||
"WHERE name='default-AdisTS'"
|
"WHERE name='default-AdisTS'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if int(release) < 7:
|
||||||
|
posix = os.name == 'posix'
|
||||||
|
ext = "" if posix else ".exe"
|
||||||
|
|
||||||
|
self.execute(f"""
|
||||||
|
INSERT INTO solver VALUES (
|
||||||
|
'rubar3',
|
||||||
|
'default-Rubar3',
|
||||||
|
'Default Pamhyr2 Rubar 3 version',
|
||||||
|
|
||||||
|
'', '', '',
|
||||||
|
|
||||||
|
'',
|
||||||
|
'@install_dir/rubar/rubar3{ext} @args @input',
|
||||||
|
''
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
self.execute(
|
||||||
|
"UPDATE solver SET cmd_solver=" +
|
||||||
|
f"'@install_dir/rubar/rubar3{ext} @args @input' "
|
||||||
|
"WHERE name='default-Rubar3'"
|
||||||
|
)
|
||||||
|
|
||||||
self.execute(
|
self.execute(
|
||||||
f"UPDATE info SET value='{self._version}' " +
|
f"UPDATE info SET value='{self._version}' " +
|
||||||
"WHERE key='version'"
|
"WHERE key='version'"
|
||||||
@@ -337,6 +360,13 @@ class Config(SQL):
|
|||||||
new._cmd_solver = f""""@install_dir/adists/adists{ext}" @args @input"""
|
new._cmd_solver = f""""@install_dir/adists/adists{ext}" @args @input"""
|
||||||
self._solvers.append(new)
|
self._solvers.append(new)
|
||||||
|
|
||||||
|
# Rubar3
|
||||||
|
ctor = solver_type_list["rubar3"]
|
||||||
|
new = ctor("default-Rubar3")
|
||||||
|
new._description = "Default Pamhyr2 Rubar 3 version"
|
||||||
|
new._cmd_solver = f""""@install_dir/rubar/rubar3{ext}" @args @input"""
|
||||||
|
self._solvers.append(new)
|
||||||
|
|
||||||
# Mage fake 7
|
# Mage fake 7
|
||||||
# ctor = solver_type_list["mage_fake7"]
|
# ctor = solver_type_list["mage_fake7"]
|
||||||
# new = ctor("default-mage-fake-7")
|
# new = ctor("default-mage-fake-7")
|
||||||
|
|||||||
+511
-218
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Reference in new issue
Block a user