mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22771c7f3a | ||
|
|
6d60a2017c | ||
|
|
02db91f3d7 | ||
|
|
d934b5e381 | ||
|
|
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 | ||
|
|
68b62a5630 | ||
|
|
990d44dd07 | ||
|
|
819ae41c00 | ||
|
|
bf95b7f7e6 | ||
|
|
861b78b928 | ||
|
|
08c414a66e | ||
|
|
57a80d00aa | ||
|
|
70eae5f7d2 | ||
|
|
e2a65e2cdd | ||
|
|
f03b74614e | ||
|
|
532b3fd7fd | ||
|
|
64df4129d4 | ||
|
|
f6e35e2045 | ||
|
|
a97717a624 | ||
|
|
3f650de52f | ||
|
|
1f4bda7976 | ||
|
|
a4423e45f8 | ||
|
|
1386c592bf |
No files matched your search
+9
-2
@@ -24,6 +24,13 @@ stages:
|
||||
- antivirus
|
||||
- release
|
||||
|
||||
#########################
|
||||
# PYINSTALLER VARIABLES #
|
||||
#########################
|
||||
|
||||
variables:
|
||||
HIDDEN_IMPORTS: "--hiddenimport rasterio --collect-submodules rasterio"
|
||||
|
||||
#############
|
||||
# DOWNLOADS #
|
||||
#############
|
||||
@@ -292,7 +299,7 @@ build-linux:
|
||||
- pip3 install -r ../requirements.txt
|
||||
- pip3 install -U -r ../requirements.txt
|
||||
# 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
|
||||
- mkdir -p pamhyr
|
||||
- mkdir -p pamhyr/_internal
|
||||
@@ -395,7 +402,7 @@ build-windows:
|
||||
- python -m pip install -U -r ..\requirements.txt
|
||||
# Run Pyinstaller
|
||||
# - 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
|
||||
- mkdir pamhyr
|
||||
- dir
|
||||
|
||||
+2
-1
@@ -19,4 +19,5 @@
|
||||
"python-pyqt@5" "python-pyqt5-sip"
|
||||
"python-pyqtgraph" "python-qscintilla"
|
||||
"python-numpy@1" "python-shapely" "python-pyshp"
|
||||
"python-matplotlib" "python-rasterio"))
|
||||
"python-matplotlib" "python-colorama"
|
||||
"python-rasterio"))
|
||||
+23
-8
@@ -17,7 +17,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from numpy import sign
|
||||
from numpy import sign, interp
|
||||
from copy import deepcopy
|
||||
|
||||
from tools import logger_color_red, logger_color_reset, logger_exception
|
||||
@@ -273,7 +273,7 @@ class InternalMeshing(AMeshingTool):
|
||||
sect2.point(start2+len2).name = tag2
|
||||
sect2.modified()
|
||||
|
||||
def update_rk(self, reach,
|
||||
def update_rk(self, reach, begin_rk, end_rk,
|
||||
step: float = 50,
|
||||
limites=[-1, -1],
|
||||
origin=0,
|
||||
@@ -297,15 +297,25 @@ class InternalMeshing(AMeshingTool):
|
||||
# 1: up -> downstream
|
||||
# 2: down -> upstream
|
||||
# else: keep current orientation
|
||||
old_orientation = sign(reach.profiles[-1].rk - reach.profiles[0].rk)
|
||||
if orientation == 1:
|
||||
sgn = 1.0
|
||||
elif orientation == 2:
|
||||
sgn = -1.0
|
||||
else:
|
||||
sgn = sign(reach.profiles[-1].rk - reach.profiles[0].rk)
|
||||
sgn = old_orientation
|
||||
|
||||
rk = [0.0]*nprof
|
||||
rk[origin] = origin_value
|
||||
new_rk = [0.0]*nprof
|
||||
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:
|
||||
for i in range(origin+1, nprof):
|
||||
@@ -316,7 +326,7 @@ class InternalMeshing(AMeshingTool):
|
||||
d2 = reach.profiles[i-1].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:
|
||||
for i in reversed(range(0, origin)):
|
||||
# 2D
|
||||
@@ -326,6 +336,11 @@ class InternalMeshing(AMeshingTool):
|
||||
d2 = reach.profiles[i+1].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
|
||||
@@ -582,10 +582,10 @@ class BoundaryCondition(SQLSubModel):
|
||||
self._data.index(bc)
|
||||
|
||||
def get_i(self, index):
|
||||
if len(self.data) == 0:
|
||||
if len(self._data) == 0:
|
||||
return None
|
||||
|
||||
return self.data[index]
|
||||
return self._data[index]
|
||||
|
||||
def get_range(self, _range):
|
||||
lst = []
|
||||
|
||||
@@ -749,8 +749,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||
if zz[i] >= z and zz[i+1] < z:
|
||||
y = np.interp(
|
||||
z,
|
||||
[zz[i], zz[i+1]],
|
||||
[station[i], station[i+1]]
|
||||
[zz[i+1], zz[i]],
|
||||
[station[i+1], station[i]]
|
||||
)
|
||||
line.append([y, z])
|
||||
|
||||
@@ -839,11 +839,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||
|
||||
for i in range(self.number_points-1):
|
||||
if zz[i] > z and zz[i+1] <= z:
|
||||
y = np.interp(
|
||||
z,
|
||||
[zz[i], zz[i+1]],
|
||||
[station[i], station[i+1]]
|
||||
)
|
||||
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||
y = station[i] + fact * (station[i+1] - station[i])
|
||||
start.append(y)
|
||||
|
||||
end = []
|
||||
@@ -852,11 +849,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||
|
||||
for i in reversed(range(self.number_points-1)):
|
||||
if zz[i] <= z and zz[i+1] > z:
|
||||
y = np.interp(
|
||||
z,
|
||||
[zz[i], zz[i+1]],
|
||||
[station[i], station[i+1]]
|
||||
)
|
||||
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||
y = station[i] + fact * (station[i+1] - station[i])
|
||||
end.append(y)
|
||||
|
||||
if len(start) != len(end):
|
||||
@@ -887,33 +881,31 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||
|
||||
# Interpolate points at river left side
|
||||
if (i_left > 0):
|
||||
x = np.interp(
|
||||
z,
|
||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
||||
[self.point(i_left).x, self.point(i_left - 1).x]
|
||||
)
|
||||
y = np.interp(
|
||||
z,
|
||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
||||
[self.point(i_left).y, self.point(i_left - 1).y]
|
||||
)
|
||||
pt_left = PointXYZ(x, y, z, name="wl_left")
|
||||
if abs(self.point(i_left - 1).z - self.point(i_left).z) < 1e-20:
|
||||
pt_left = self.point(i_left)
|
||||
else:
|
||||
fact = (z - self.point(i_left).z) / \
|
||||
(self.point(i_left - 1).z - self.point(i_left).z)
|
||||
x = self.point(i_left).x + fact * \
|
||||
(self.point(i_left - 1).x - self.point(i_left).x)
|
||||
y = self.point(i_left).y + fact * \
|
||||
(self.point(i_left - 1).y - self.point(i_left).y)
|
||||
pt_left = PointXYZ(x=x, y=y, z=z, name="wl_left")
|
||||
else:
|
||||
pt_left = self.point(0)
|
||||
|
||||
# Interpolate points at river right side
|
||||
if (i_right < self.number_points - 1):
|
||||
x = np.interp(
|
||||
z,
|
||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
||||
[self.point(i_right).x, self.point(i_right + 1).x]
|
||||
)
|
||||
y = np.interp(
|
||||
z,
|
||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
||||
[self.point(i_right).y, self.point(i_right + 1).y]
|
||||
)
|
||||
pt_right = PointXYZ(x, y, z, name="wl_right")
|
||||
if abs(self.point(i_right + 1).z - self.point(i_right).z) < 1e-20:
|
||||
pt_right = self.point(i_right)
|
||||
else:
|
||||
fact = (z - self.point(i_right).z) / \
|
||||
(self.point(i_right + 1).z - self.point(i_right).z)
|
||||
x = self.point(i_right).x + fact * \
|
||||
(self.point(i_right + 1).x - self.point(i_right).x)
|
||||
y = self.point(i_right).y + fact * \
|
||||
(self.point(i_right + 1).y - self.point(i_right).y)
|
||||
pt_right = PointXYZ(x=x, y=y, z=z, name="wl_right")
|
||||
else:
|
||||
pt_right = self.point(self.number_points - 1)
|
||||
|
||||
|
||||
@@ -52,6 +52,9 @@ class Results(SQLSubModel):
|
||||
"study_revision": study.status.version,
|
||||
}
|
||||
|
||||
if solver is not None:
|
||||
self.set("solver_type", solver._type)
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
date = self._meta_data["creation_date"]
|
||||
@@ -112,7 +115,10 @@ class Results(SQLSubModel):
|
||||
)
|
||||
""")
|
||||
|
||||
return True
|
||||
if ext != "":
|
||||
return True
|
||||
|
||||
return cls._create_submodel(execute)
|
||||
|
||||
@classmethod
|
||||
def _db_update(cls, execute, version, data=None):
|
||||
@@ -147,7 +153,7 @@ class Results(SQLSubModel):
|
||||
)
|
||||
|
||||
if table is None:
|
||||
yield new
|
||||
yield
|
||||
|
||||
if len(table) > 1:
|
||||
logger.warning("Multiple results for this scenario")
|
||||
@@ -178,23 +184,33 @@ class Results(SQLSubModel):
|
||||
data["timestamps"] = sorted(ts)
|
||||
new_results._river = River._db_load(execute, data)
|
||||
|
||||
new = new_results
|
||||
yield (solver_type, new_results)
|
||||
|
||||
yield new
|
||||
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}"
|
||||
)
|
||||
|
||||
def _db_save(self, execute, data=None):
|
||||
if self._status.scenario.id != self._owner_scenario:
|
||||
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
|
||||
if self._solver is None:
|
||||
solver_name = self.get("solver_name")
|
||||
@@ -203,6 +219,8 @@ class Results(SQLSubModel):
|
||||
solver_name = self._solver._name
|
||||
solver_type = self._solver._type
|
||||
|
||||
self._db_save_clear(execute, solver_type, data=data)
|
||||
|
||||
ts = sorted(self.get("timestamps"))
|
||||
sf = ">" + ''.join(itertools.repeat("d", len(ts)))
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ class Profile(SQLSubModel):
|
||||
values = list(map(float, values))
|
||||
sf = ">" + ''.join(itertools.repeat("f", len(values)))
|
||||
len_values = len(values)
|
||||
elif key is "sl":
|
||||
elif key == "sl":
|
||||
# HACK: Some dirty code to transforme list of list of
|
||||
# tuple to list of values and ensure the values is
|
||||
# float type...
|
||||
|
||||
+10
-5
@@ -505,7 +505,7 @@ class River(Graph):
|
||||
self._D90AdisTS = D90AdisTSList(status=self._status)
|
||||
self._DIFAdisTS = DIFAdisTSList(status=self._status)
|
||||
|
||||
self._results = None
|
||||
self._results = {}
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute):
|
||||
@@ -620,7 +620,10 @@ class River(Graph):
|
||||
return new
|
||||
|
||||
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):
|
||||
self._db_save_delete_artefact(execute, data)
|
||||
@@ -647,8 +650,8 @@ class River(Graph):
|
||||
objs.append(self._D90AdisTS)
|
||||
objs.append(self._DIFAdisTS)
|
||||
|
||||
if self.results is not None:
|
||||
objs.append(self.results)
|
||||
for solv_type in self.results:
|
||||
objs.append(self.results[solv_type])
|
||||
|
||||
self._save_submodel(execute, objs, data)
|
||||
return True
|
||||
@@ -902,7 +905,9 @@ Last export at: @date."""
|
||||
|
||||
@results.setter
|
||||
def results(self, results):
|
||||
self._results = results
|
||||
solv_type = results.get("solver_type")
|
||||
|
||||
self._results[solv_type] = results
|
||||
|
||||
def _split_reach(self, reach, profile):
|
||||
node1 = reach.node1
|
||||
|
||||
@@ -276,7 +276,7 @@ class Scenario(SQLSubModel):
|
||||
if self.id != 0:
|
||||
srep = os.path.join(
|
||||
self.parent.workdir(),
|
||||
"senario_" + str(self.id)
|
||||
"scenario_" + str(self.id)
|
||||
)
|
||||
|
||||
return srep
|
||||
+81
-25
@@ -44,7 +44,10 @@ class Study(SQLModel):
|
||||
River,
|
||||
]
|
||||
|
||||
def __init__(self, filename=None, init_new=True):
|
||||
def __init__(self, filename=None, init_new=True, copy=False):
|
||||
if copy:
|
||||
return
|
||||
|
||||
# Metadata
|
||||
self.creation_date = datetime.now()
|
||||
self.last_modification_date = datetime.now()
|
||||
@@ -476,31 +479,10 @@ class Study(SQLModel):
|
||||
return new
|
||||
|
||||
def reload_from_scenario(self, scenario):
|
||||
if scenario in self._river_scenario_cache:
|
||||
self._river = self._river_scenario_cache[scenario]
|
||||
self.status.scenario = scenario
|
||||
else:
|
||||
def sql_exec(sql):
|
||||
return self.execute(
|
||||
sql, fetch_one=False, commit=True
|
||||
)
|
||||
river = self.load_scenario(scenario)
|
||||
self._river = river
|
||||
|
||||
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
|
||||
self.status.scenario = scenario
|
||||
|
||||
if reduce(
|
||||
lambda a, s: a or (s.parent is scenario),
|
||||
@@ -511,6 +493,80 @@ class Study(SQLModel):
|
||||
else:
|
||||
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):
|
||||
source = self.status.scenario_id
|
||||
new = self.scenarios.new(
|
||||
|
||||
+6
-4
@@ -177,15 +177,15 @@ class Mage(CommandLineSolver):
|
||||
return lst
|
||||
|
||||
def input_param(self):
|
||||
name = self._study.name
|
||||
name = self._study.name.replace(" ", "_")
|
||||
return f"{name}.REP"
|
||||
|
||||
def output_param(self):
|
||||
name = self._study.name
|
||||
name = self._study.name.replace(" ", "_")
|
||||
return f"{name}.BIN"
|
||||
|
||||
def log_file(self):
|
||||
name = self._study.name
|
||||
name = self._study.name.replace(" ", "_")
|
||||
return f"{name}.TRA"
|
||||
|
||||
def _export_REP_additional_lines(self, study, rep_file):
|
||||
@@ -819,7 +819,8 @@ class Mage(CommandLineSolver):
|
||||
repertory=repertory,
|
||||
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):
|
||||
logger.info(f"Result file {name}.BIN does not exist")
|
||||
return None
|
||||
@@ -1374,6 +1375,7 @@ class Mage8(Mage):
|
||||
results = super(Mage8, self).results(study, repertory, qlog, name=name)
|
||||
if results is None:
|
||||
return None
|
||||
|
||||
if with_gra:
|
||||
self.read_gra(study, repertory, results, qlog, name=name)
|
||||
|
||||
|
||||
+95
-57
@@ -52,8 +52,8 @@ class Rubar3(CommandLineSolver):
|
||||
("rubarbe_condav", "3"),
|
||||
("rubarbe_regime", "0"),
|
||||
("rubarbe_iodev", "n"),
|
||||
# ("rubarbe_iodebord", ""),
|
||||
# ("rubarbe_iostockage", ""),
|
||||
("rubarbe_iodebord", ""),
|
||||
("rubarbe_iostockage", ""),
|
||||
("rubarbe_iopdt", "y"),
|
||||
("rubarbe_iovis", "n"),
|
||||
("rubarbe_rep", "n"),
|
||||
@@ -73,36 +73,37 @@ class Rubar3(CommandLineSolver):
|
||||
("rubarbe_tf_4", "y"),
|
||||
("rubarbe_tf_5", "y"),
|
||||
("rubarbe_tf_6", "n"),
|
||||
("rubarbe_trased", "y"),
|
||||
# ("rubarbe_optfpc", "0"),
|
||||
# ("rubarbe_ros", "2650.0"),
|
||||
# ("rubarbe_dm", "0.1"),
|
||||
# ("rubarbe_segma", "1.0"),
|
||||
("rubarbe_trased", "n"),
|
||||
("rubarbe_optfpc", "0"),
|
||||
# trased parameters
|
||||
("rubarbe_ros", "2650.0"),
|
||||
("rubarbe_dm", "0.1"),
|
||||
("rubarbe_segma", "1.0"),
|
||||
# Sediment parameters
|
||||
# ("rubarbe_sediment_ros", "2650.0"),
|
||||
# ("rubarbe_sediment_por", "0.4"),
|
||||
# ("rubarbe_sediment_dcharg", "0.0"),
|
||||
# ("rubarbe_sediment_halfa", "1.0"),
|
||||
# ("rubarbe_sediment_mult_1", "1.0"),
|
||||
# ("rubarbe_sediment_mult_2", ""),
|
||||
# ("rubarbe_sediment_mult_3", ""),
|
||||
# ("rubarbe_sediment_mult_4", ""),
|
||||
# ("rubarbe_sediment_mult_5", ""),
|
||||
# ("rubarbe_sediment_visc", "0.047"),
|
||||
# ("rubarbe_sediment_opts", "6"),
|
||||
# ("rubarbe_sediment_odchar", "0"),
|
||||
# ("rubarbe_sediment_unisol", "1"),
|
||||
# ("rubarbe_sediment_typdef", "3"),
|
||||
# ("rubarbe_sediment_depot", "2"),
|
||||
# ("rubarbe_sediment_choixc", "2"),
|
||||
# ("rubarbe_sediment_option", "2"),
|
||||
# ("rubarbe_sediment_capsol", "1"),
|
||||
# ("rubarbe_sediment_bmiu", "0.85"),
|
||||
# ("rubarbe_sediment_demix", "0"),
|
||||
# ("rubarbe_sediment_defond", "1"),
|
||||
# ("rubarbe_sediment_varcons", "1"),
|
||||
# ("rubarbe_sediment_dchard", "0.0"),
|
||||
# ("rubarbe_sediment_dchars", "0.0"),
|
||||
("rubarbe_sediment_ros", "2650.0"),
|
||||
("rubarbe_sediment_por", "0.4"),
|
||||
("rubarbe_sediment_dcharg", "0.0"),
|
||||
("rubarbe_sediment_halfa", "1.0"),
|
||||
("rubarbe_sediment_mult_1", "1.0"),
|
||||
("rubarbe_sediment_mult_2", ""),
|
||||
("rubarbe_sediment_mult_3", ""),
|
||||
("rubarbe_sediment_mult_4", ""),
|
||||
("rubarbe_sediment_mult_5", ""),
|
||||
("rubarbe_sediment_visc", "0.047"),
|
||||
("rubarbe_sediment_opts", "6"),
|
||||
("rubarbe_sediment_odchar", "0"),
|
||||
("rubarbe_sediment_unisol", "1"),
|
||||
("rubarbe_sediment_typdef", "3"),
|
||||
("rubarbe_sediment_depot", "2"),
|
||||
("rubarbe_sediment_choixc", "2"),
|
||||
("rubarbe_sediment_option", "2"),
|
||||
("rubarbe_sediment_capsol", "1"),
|
||||
("rubarbe_sediment_bmiu", "0.85"),
|
||||
("rubarbe_sediment_demix", "0"),
|
||||
("rubarbe_sediment_defond", "1"),
|
||||
("rubarbe_sediment_varcons", "1"),
|
||||
("rubarbe_sediment_dchard", "0.0"),
|
||||
("rubarbe_sediment_dchars", "0.0"),
|
||||
]
|
||||
|
||||
return lst
|
||||
@@ -169,7 +170,7 @@ class Rubar3(CommandLineSolver):
|
||||
it = iter(params)
|
||||
|
||||
line = 0
|
||||
while line < 25:
|
||||
while line < 27:
|
||||
param = next(it)
|
||||
name = param.name
|
||||
value = param.value
|
||||
@@ -394,25 +395,59 @@ class Rubar3(CommandLineSolver):
|
||||
lm = len(reach) + 1
|
||||
f.write(f"{lm:>6}\n")
|
||||
|
||||
def get_stricklers_from_rk(rk):
|
||||
return next(
|
||||
map(
|
||||
lambda s: (
|
||||
s.begin_strickler.medium if version == "2"
|
||||
else s.begin_strickler.minor
|
||||
),
|
||||
filter(
|
||||
lambda f: rk in f,
|
||||
edge.frictions.lst
|
||||
)
|
||||
lst = list(filter(
|
||||
lambda f: f.is_full_defined(),
|
||||
edge.frictions.frictions
|
||||
))
|
||||
|
||||
rk_min = 9999999.9
|
||||
rk_max = -9999999.9
|
||||
coeff_min = -1.0
|
||||
coeff_max = -1.0
|
||||
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
|
||||
for mail in edge.reach.inter_profiles_rk():
|
||||
coef = get_stricklers_from_rk(mail)
|
||||
|
||||
f.write(f"{ind:>6} {coef:>12.5f}")
|
||||
coef = get_stricklers_from_rk(mail, lst)
|
||||
if coef is not None:
|
||||
f.write(f"{ind:>6} {coef:>12.5f}")
|
||||
|
||||
ind += 1
|
||||
f.write("\n")
|
||||
@@ -583,27 +618,30 @@ class Rubar3(CommandLineSolver):
|
||||
|
||||
for reach, lm in reachs:
|
||||
# First profile
|
||||
e, s, q, z = read_data_line(f)
|
||||
set_and_compute_limites(reach, 0, z, q, s)
|
||||
h, s, q, z = read_data_line(f)
|
||||
set_and_compute_limites(reach, 0, z+h, q, s)
|
||||
|
||||
# For each profile
|
||||
ind = 1
|
||||
pe, ps, pq, pz = read_data_line(f)
|
||||
ph, ps, pq, pz = read_data_line(f)
|
||||
while ind < lm - 2:
|
||||
e, s, q, z = read_data_line(f)
|
||||
h, s, q, z = read_data_line(f)
|
||||
set_and_compute_limites(
|
||||
reach, ind,
|
||||
(pz + z) / 2,
|
||||
(pq + q) / 2,
|
||||
(ps + s) / 2
|
||||
(ph + pz + ph + h) / 2,
|
||||
(pz + s) / 2,
|
||||
(pq + q) / 2
|
||||
)
|
||||
|
||||
pe, ps, pq, pz = z, s, q, e
|
||||
ph = h
|
||||
ps = s
|
||||
pq = q
|
||||
pz = z
|
||||
ind += 1
|
||||
|
||||
# Last profile
|
||||
e, s, q, z = read_data_line(f)
|
||||
set_and_compute_limites(reach, ind, z, q, s)
|
||||
h, s, q, z = read_data_line(f)
|
||||
set_and_compute_limites(reach, ind, z+h, q, s)
|
||||
|
||||
@timer
|
||||
def results(self, study, repertory, qlog=None, name="0"):
|
||||
|
||||
@@ -58,7 +58,7 @@ logger = logging.getLogger()
|
||||
|
||||
class TableModel(PamhyrTableModel):
|
||||
def get_true_data_row(self, row):
|
||||
bc = self._data.get_i(row)
|
||||
bc = self._data.data[row]
|
||||
|
||||
return next(
|
||||
map(
|
||||
@@ -83,6 +83,7 @@ class TableModel(PamhyrTableModel):
|
||||
value = QVariant()
|
||||
|
||||
if 0 <= column < 2:
|
||||
row = self.get_true_data_row(row)
|
||||
v = self._data.get_i(row)[column]
|
||||
if self._data.get_type_column(column) == float:
|
||||
if type(v) is str:
|
||||
@@ -106,13 +107,16 @@ class TableModel(PamhyrTableModel):
|
||||
column = index.column()
|
||||
|
||||
try:
|
||||
row = self.get_true_data_row(row)
|
||||
|
||||
self._undo.push(
|
||||
SetDataCommand(
|
||||
self._data, row, column, value
|
||||
self._data, row,
|
||||
column, value
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.info(e)
|
||||
logger.warning(e)
|
||||
logger.debug(traceback.format_exc())
|
||||
|
||||
self.update()
|
||||
|
||||
@@ -83,13 +83,13 @@ class AddCommand(QUndoCommand):
|
||||
self._new = None
|
||||
|
||||
def undo(self):
|
||||
self._data.delete_i([self._index])
|
||||
self._new.set_as_deleted()
|
||||
|
||||
def redo(self):
|
||||
if self._new is None:
|
||||
self._new = self._data.add(self._index)
|
||||
else:
|
||||
self._data.insert(self._index, self._new)
|
||||
self._new.set_as_not_deleted()
|
||||
|
||||
|
||||
class DelCommand(QUndoCommand):
|
||||
@@ -101,15 +101,16 @@ class DelCommand(QUndoCommand):
|
||||
|
||||
self._bc = []
|
||||
for row in rows:
|
||||
self._bc.append((row, self._data.get_i(row)))
|
||||
self._bc.append(self._data.get_i(row))
|
||||
self._bc.sort()
|
||||
|
||||
def undo(self):
|
||||
for row, el in self._bc:
|
||||
self._data.insert(row, el)
|
||||
for el in self._bc:
|
||||
el.set_as_not_deleted()
|
||||
|
||||
def redo(self):
|
||||
self._data.delete_i(self._rows)
|
||||
for el in self._bc:
|
||||
el.set_as_deleted()
|
||||
|
||||
|
||||
class SortCommand(QUndoCommand):
|
||||
|
||||
@@ -237,22 +237,40 @@ class UpdateRKCommand(QUndoCommand):
|
||||
self._data = data
|
||||
self._mesher = mesher
|
||||
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_begin_rk = None
|
||||
self._new_end_rk = None
|
||||
|
||||
def undo(self):
|
||||
for rk, profile in zip(self._rks, self._reach.profiles):
|
||||
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):
|
||||
if self._new_rks is None:
|
||||
self._new_rks = self._mesher.update_rk(
|
||||
self._reach,
|
||||
**self._data
|
||||
)
|
||||
self._new_rks, self._new_begin_rk, self._new_end_rk = \
|
||||
self._mesher.update_rk(
|
||||
self._reach, self._begin_rk, self._end_rk,
|
||||
**self._data
|
||||
)
|
||||
|
||||
for rk, profile in zip(self._new_rks, self._reach.profiles):
|
||||
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):
|
||||
|
||||
@@ -50,6 +50,8 @@ from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||
|
||||
from View.SelectReach.Window import SelectReachWindow
|
||||
|
||||
from View.WaitingDialog import WaitingDialog
|
||||
|
||||
from Meshing.Internal import InternalMeshing
|
||||
|
||||
from View.Geometry.Table import GeometryReachTableModel
|
||||
@@ -326,7 +328,19 @@ class GeometryWindow(PamhyrWindow):
|
||||
def _edit_meshing(self, data):
|
||||
try:
|
||||
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:
|
||||
logger_exception(e)
|
||||
|
||||
|
||||
+110
-81
@@ -32,7 +32,7 @@ from platformdirs import user_cache_dir
|
||||
from Solver.AdisTS import AdisTS
|
||||
from Solver.Mage import Mage8
|
||||
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.QtGui import (
|
||||
@@ -84,10 +84,12 @@ from View.SolverParameters.Window import SolverParametersWindow
|
||||
from View.RunSolver.Window import (
|
||||
SelectSolverWindow,
|
||||
SolverLogWindow,
|
||||
CompareSolversWindow
|
||||
)
|
||||
|
||||
from View.Results.Window import ResultsWindow
|
||||
from View.Results.CompareDialog import (
|
||||
CompareScenariosWindow
|
||||
)
|
||||
|
||||
from View.RunSolver.WindowAdisTS import (
|
||||
SelectSolverWindowAdisTS,
|
||||
@@ -128,8 +130,8 @@ no_model_action = [
|
||||
model_action = [
|
||||
"action_menu_close", "action_menu_edit", "action_menu_save",
|
||||
"action_menu_save_as", "action_toolBar_close", "action_toolBar_save",
|
||||
"action_menu_numerical_parameter", "action_open_results_from_file",
|
||||
"action_open_results_adists",
|
||||
"action_menu_numerical_parameter", "action_menu_open_results_from_file",
|
||||
"action_menu_open_results_adists",
|
||||
]
|
||||
|
||||
other_model_action = [
|
||||
@@ -150,8 +152,9 @@ define_model_action = [
|
||||
"action_menu_run_solver", "action_menu_sediment_layers",
|
||||
"action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs",
|
||||
"action_menu_edit_hydraulic_structures", "action_menu_additional_file",
|
||||
"action_menu_results_last", "action_open_results_from_file",
|
||||
"action_compare_results", "action_menu_boundary_conditions_sediment",
|
||||
"action_menu_results_last", "action_menu_open_results_from_file",
|
||||
"action_menu_compare_scenarios_results",
|
||||
"action_menu_boundary_conditions_sediment",
|
||||
"action_menu_rep_additional_lines", "action_menu_output_rk",
|
||||
"action_menu_run_adists", "action_menu_pollutants",
|
||||
"action_menu_d90", "action_menu_dif",
|
||||
@@ -296,9 +299,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
"action_menu_rep_additional_lines": self.open_rep_lines,
|
||||
"action_menu_close": self.close_model,
|
||||
"action_menu_results_last": self.open_last_results,
|
||||
"action_open_results_from_file": self.open_results_from_file,
|
||||
"action_compare_results": self.compare_results,
|
||||
"action_open_results_adists": self.open_results_adists,
|
||||
"action_menu_open_results_from_file": self.open_results_from_file,
|
||||
"action_menu_compare_scenarios_results":
|
||||
self.compare_results_scenarios,
|
||||
"action_menu_open_results_adists": self.open_results_adists,
|
||||
# Help
|
||||
"action_menu_pamhyr_users_wiki": self.open_doc_user,
|
||||
"action_menu_pamhyr_developers_pdf":
|
||||
@@ -596,7 +600,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
if self._study is 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
|
||||
|
||||
@last_results.setter
|
||||
def last_results(self, results):
|
||||
@@ -1507,7 +1515,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
return False
|
||||
|
||||
def open_solver_results(self, solver, results=None):
|
||||
logger.info(f"{solver} {results}")
|
||||
logger.info(f"Open results for '{solver}' ({results})")
|
||||
|
||||
def reading_fn():
|
||||
self._tmp_results = results
|
||||
@@ -1637,12 +1645,16 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
)
|
||||
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(
|
||||
os.path.dirname(self._study.filename),
|
||||
"_PAMHYR_",
|
||||
self._study.name.replace(" ", "_"),
|
||||
solver.name.replace(" ", "_"),
|
||||
scenario.workdir(),
|
||||
)
|
||||
|
||||
return workdir
|
||||
@@ -1697,32 +1709,36 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
results=file_name[0]
|
||||
)
|
||||
|
||||
def compare_results(self):
|
||||
def compare_results_scenarios(self):
|
||||
if self._study is None:
|
||||
return
|
||||
|
||||
run = CompareSolversWindow(
|
||||
dlg = CompareScenariosWindow(
|
||||
study=self._study,
|
||||
config=self.conf,
|
||||
parent=self
|
||||
)
|
||||
if run.exec():
|
||||
results = self.diff_results(run.solver1,
|
||||
run.solver2)
|
||||
else:
|
||||
if not dlg.exec():
|
||||
return
|
||||
|
||||
results = self.diff_results(
|
||||
dlg.solver1, dlg.solver2,
|
||||
scenario1=dlg.scenario1,
|
||||
scenario2=dlg.scenario2
|
||||
)
|
||||
|
||||
# At least one result not available
|
||||
if results is None:
|
||||
return
|
||||
|
||||
# Windows already opened
|
||||
if self.sub_window_exists(
|
||||
ResultsWindow,
|
||||
CompareScenariosWindow,
|
||||
data=[self._study, None] +
|
||||
[r._solver 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
|
||||
|
||||
@@ -1733,97 +1749,109 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
)
|
||||
res.show()
|
||||
|
||||
def diff_results(self, solver1, solver2):
|
||||
if solver1 is None:
|
||||
# TODO message
|
||||
return None
|
||||
if solver2 is None:
|
||||
# TODO message
|
||||
def msg_diff_results_param(self):
|
||||
self.message_box(
|
||||
window_title=self._trad["Error"],
|
||||
text=self._trad["mb_diff_results_title"],
|
||||
informative_text=self._trad["mb_diff_results_param_msg"]
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
solver3 = GenericSolver(solver1.name+" - "+solver2.name)
|
||||
solver4 = GenericSolver(solver1.name)
|
||||
solver5 = GenericSolver(solver2.name)
|
||||
study1 = self._study
|
||||
study2 = self._study
|
||||
|
||||
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(
|
||||
self._study,
|
||||
self._solver_workdir(solver1),
|
||||
)
|
||||
|
||||
if result1 is None:
|
||||
# TODO message
|
||||
return None
|
||||
study1,
|
||||
self._solver_workdir(solver1, scenario=scenario1),
|
||||
)
|
||||
|
||||
result2 = solver2.results(
|
||||
self._study,
|
||||
self._solver_workdir(solver2),
|
||||
)
|
||||
study2,
|
||||
self._solver_workdir(solver2, scenario=scenario2),
|
||||
)
|
||||
|
||||
if result2 is None:
|
||||
# TODO message
|
||||
if result1 is None or result2 is None:
|
||||
self.msg_diff_results_param()
|
||||
return None
|
||||
|
||||
if result2.get("nb_reach") != result1.get("nb_reach"):
|
||||
# TODO message
|
||||
if result1.get("nb_reach") != result2.get("nb_reach"):
|
||||
self.msg_diff_results_compatibility()
|
||||
return None
|
||||
|
||||
if result2.get("nb_profile") != result1.get("nb_profile"):
|
||||
# TODO message
|
||||
if result1.get("nb_profile") != result2.get("nb_profile"):
|
||||
self.msg_diff_results_compatibility()
|
||||
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"))
|
||||
result4.set("nb_reach", result1.get("nb_reach"))
|
||||
result5.set("nb_reach", result1.get("nb_reach"))
|
||||
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)
|
||||
result4.set("timestamps", ts)
|
||||
result5.set("timestamps", ts)
|
||||
|
||||
for i in range(int(result1.get("nb_reach"))):
|
||||
# Add reach to results reach list
|
||||
r = result3.river.add(i)
|
||||
r = result4.river.add(i)
|
||||
r = result5.river.add(i)
|
||||
|
||||
for timestamp in result3.get("timestamps"):
|
||||
for r in range(int(result1.get("nb_reach"))):
|
||||
reach1 = result1.river.reach(r)
|
||||
reach2 = result2.river.reach(r)
|
||||
reach3 = result3.river.reach(r)
|
||||
reach4 = result4.river.reach(r)
|
||||
reach5 = result5.river.reach(r)
|
||||
for p, (profile1, profile2) in enumerate(zip(
|
||||
reach1.profiles, reach2.profiles)):
|
||||
|
||||
for profile1, profile2, profile3 in zip(
|
||||
reach1.profiles,
|
||||
reach2.profiles,
|
||||
reach3.profiles):
|
||||
for key in ["Z", "Q", "V"]:
|
||||
d1 = profile1.get_ts_key(timestamp, key)
|
||||
d2 = profile2.get_ts_key(timestamp, key)
|
||||
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)
|
||||
d = d1 - d2
|
||||
|
||||
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):
|
||||
if self._study is None:
|
||||
@@ -1866,6 +1894,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
solver_results_adists = solver_results.results(
|
||||
self._study,
|
||||
repertory=dir_path, qlog=None) # self._output)
|
||||
|
||||
logger.info(f"Select results: {dir_path}")
|
||||
if len(bin_list) >= 2 and ("total_sediment.bin" in bin_list):
|
||||
self.open_solver_results_adists(
|
||||
|
||||
@@ -481,7 +481,7 @@ class GraphWidget(QGraphicsView):
|
||||
def setup_scene(self, min_size, max_size, size):
|
||||
scene = QGraphicsScene(self)
|
||||
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
|
||||
scene.setSceneRect(0, 0, 2000, 2000)
|
||||
scene.setSceneRect(0, 0, 6000, 6000)
|
||||
|
||||
self.setScene(scene)
|
||||
self.setCacheMode(QGraphicsView.CacheBackground)
|
||||
@@ -492,6 +492,7 @@ class GraphWidget(QGraphicsView):
|
||||
|
||||
self.scale(1, 1)
|
||||
self.previousScale = 1
|
||||
self.centerOn(1000.0, 1000.0)
|
||||
|
||||
if min_size:
|
||||
self.setMinimumSize(*min_size)
|
||||
|
||||
@@ -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
|
||||
|
||||
# Legend
|
||||
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")
|
||||
self.update_legend()
|
||||
|
||||
def _redraw_rk(self):
|
||||
results = self.data[self._current_res_id]
|
||||
@@ -1103,13 +1097,7 @@ class CustomPlot(PamhyrPlot):
|
||||
self._customize_x_axes_time(ts)
|
||||
|
||||
# Legend
|
||||
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")
|
||||
self.update_legend()
|
||||
|
||||
def _redraw_time(self):
|
||||
|
||||
@@ -1419,3 +1407,25 @@ class CustomPlot(PamhyrPlot):
|
||||
x = self._timestamp
|
||||
self._current.set_data([x, x], self.canvas.axes.get_ylim())
|
||||
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['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
||||
self._dict['froude'] = self._dict["unit_froude"]
|
||||
self._dict['user_imported'] = _translate(
|
||||
"CustomPlot", "user_imported"
|
||||
)
|
||||
|
||||
# Unit corresponding long name (plot axes display)
|
||||
|
||||
|
||||
@@ -160,8 +160,6 @@ class TableModel(PamhyrTableModel):
|
||||
self._lst = _river.reachs
|
||||
elif self._opt_data == "profile" or self._opt_data == "raw_data":
|
||||
self._lst = _river.reach(reach).profiles
|
||||
# self._lst = list(compress(_river.reach(reach).profiles,
|
||||
# _river.reach(reach).profile_mask))
|
||||
elif self._opt_data == "solver":
|
||||
self._lst = self._parent._solvers
|
||||
|
||||
|
||||
+251
-57
@@ -19,14 +19,35 @@
|
||||
import os
|
||||
import csv
|
||||
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 numpy import sqrt
|
||||
try:
|
||||
import pyaudio
|
||||
import wave
|
||||
_audio_loaded = True
|
||||
except Exception as e:
|
||||
print(f"Either 'pyaudio' or 'wave' is not available: {e}")
|
||||
_audio_loaded = False
|
||||
|
||||
from functools import reduce
|
||||
|
||||
import numpy as np
|
||||
|
||||
from datetime import datetime
|
||||
from tools import trace, timer, logger_exception
|
||||
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
from View.WaitingDialog import WaitingDialog
|
||||
|
||||
from PyQt5.QtGui import (
|
||||
QKeySequence, QIcon, QPixmap,
|
||||
@@ -44,7 +65,7 @@ from PyQt5.QtWidgets import (
|
||||
QFileDialog, QTableView, QAbstractItemView,
|
||||
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||
QSlider, QLabel, QWidget, QGridLayout, QTabBar
|
||||
QSlider, QLabel, QWidget, QGridLayout, QTabBar, QInputDialog
|
||||
)
|
||||
|
||||
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||
@@ -337,10 +358,20 @@ class ResultsWindow(PamhyrWindow):
|
||||
"action_add": self._add_custom_plot,
|
||||
"action_export": self._export,
|
||||
# "action_export": self.export_current,
|
||||
"action_Geo_tiff": self.import_geotiff
|
||||
"action_import_data": self.import_data,
|
||||
"action_play_sound": self.play_sound
|
||||
}
|
||||
self.find(QAction, "action_Geo_tiff").setEnabled(False)
|
||||
self.find(QAction, "action_Geo_tiff").setVisible(False)
|
||||
if _rasterio_loaded:
|
||||
actions["action_Geo_tiff"] = self.import_geotiff
|
||||
else:
|
||||
self.find(QAction, "action_Geo_tiff")\
|
||||
.setEnabled(False)
|
||||
|
||||
if _audio_loaded:
|
||||
actions["action_play_sound"] = self.play_sound
|
||||
else:
|
||||
self.find(QAction, "action_play_sound")\
|
||||
.setVisible(False)
|
||||
|
||||
if len(self._results) > 1:
|
||||
self.find(QAction, "action_reload").setEnabled(False)
|
||||
@@ -703,7 +734,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
select_file="AnyFile",
|
||||
callback=lambda f: self.export_to(f[0], x, y, envelop, solver_id),
|
||||
default_suffix=".csv",
|
||||
file_filter=["CSV (*.csv)"],
|
||||
file_filter=[self._trad["file_csv"]],
|
||||
)
|
||||
|
||||
def export_to(self, filename, x, y, envelop, solver_id):
|
||||
@@ -944,7 +975,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
map(
|
||||
lambda p:
|
||||
p.get_ts_key(timestamp, "V") /
|
||||
sqrt(9.81 * (
|
||||
np.sqrt(9.81 * (
|
||||
p.geometry.wet_area(
|
||||
p.get_ts_key(timestamp, "Z")) /
|
||||
p.geometry.wet_width(
|
||||
@@ -958,7 +989,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
map(
|
||||
lambda p:
|
||||
p.get_ts_key(timestamp, "V") /
|
||||
sqrt(9.81 * (
|
||||
np.sqrt(9.81 * (
|
||||
p.geometry.wet_area(
|
||||
p.get_ts_key(timestamp, "Z")) /
|
||||
p.geometry.wet_width(
|
||||
@@ -971,7 +1002,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
map(
|
||||
lambda p:
|
||||
p.get_ts_key(timestamp, "V") /
|
||||
sqrt(9.81 * (
|
||||
np.sqrt(9.81 * (
|
||||
p.geometry.wet_area(
|
||||
p.get_ts_key(timestamp, "Z")) /
|
||||
p.geometry.wet_width(
|
||||
@@ -1107,7 +1138,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
if self._current_results != 2:
|
||||
fr = my_dict[dict_y["froude"]] = list(
|
||||
map(lambda z, v:
|
||||
v / sqrt(9.81 * (
|
||||
v / np.sqrt(9.81 * (
|
||||
profile.geometry.wet_area(z) /
|
||||
profile.geometry.wet_width(z))
|
||||
), z, v)
|
||||
@@ -1116,7 +1147,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
fr1 = list(
|
||||
map(lambda z, v:
|
||||
v /
|
||||
sqrt(9.81 * (
|
||||
np.sqrt(9.81 * (
|
||||
profile1.geometry.wet_area(z) /
|
||||
profile1.geometry.wet_width(z))
|
||||
), z1, v1)
|
||||
@@ -1124,7 +1155,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
fr2 = list(
|
||||
map(lambda z, v:
|
||||
v /
|
||||
sqrt(9.81 * (
|
||||
np.sqrt(9.81 * (
|
||||
profile2.geometry.wet_area(z) /
|
||||
profile2.geometry.wet_width(z))
|
||||
), z2, v2)
|
||||
@@ -1169,48 +1200,211 @@ class ResultsWindow(PamhyrWindow):
|
||||
self.update_table_selection_profile(profile_id)
|
||||
|
||||
def import_geotiff(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 != "":
|
||||
# with rasterio.open(filename) as data:
|
||||
# img = data.read()
|
||||
# b = data.bounds[:]
|
||||
# # b[0] left
|
||||
# # b[1] bottom
|
||||
# # b[2] right
|
||||
# # b[3] top
|
||||
# xlim = self.canvas.axes.get_xlim()
|
||||
# ylim = self.canvas.axes.get_ylim()
|
||||
# if b[2] > b[0] and b[1] < b[3]:
|
||||
# self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||
# extent=[b[0], b[2], b[1], b[3]])
|
||||
# else:
|
||||
# dlg = CoordinatesDialog(
|
||||
# xlim,
|
||||
# ylim,
|
||||
# trad=self._trad,
|
||||
# parent=self
|
||||
# )
|
||||
# if dlg.exec():
|
||||
# self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||
# extent=dlg.values)
|
||||
# self.plot_xy.idle()
|
||||
# self.canvas.axes.set_xlim(xlim)
|
||||
# self.canvas.axes.set_ylim(ylim)
|
||||
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 != "":
|
||||
with rasterio.open(filename) as data:
|
||||
img = data.read()
|
||||
b = data.bounds[:]
|
||||
# b[0] left
|
||||
# b[1] bottom
|
||||
# b[2] right
|
||||
# b[3] top
|
||||
xlim = self.canvas.axes.get_xlim()
|
||||
ylim = self.canvas.axes.get_ylim()
|
||||
if b[2] > b[0] and b[1] < b[3]:
|
||||
self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||
extent=[b[0], b[2], b[1], b[3]])
|
||||
else:
|
||||
dlg = CoordinatesDialog(
|
||||
xlim,
|
||||
ylim,
|
||||
trad=self._trad,
|
||||
parent=self
|
||||
)
|
||||
if dlg.exec():
|
||||
self.canvas.axes.imshow(img.transpose((1, 2, 0)),
|
||||
extent=dlg.values)
|
||||
self.plot_xy.idle()
|
||||
self.canvas.axes.set_xlim(xlim)
|
||||
self.canvas.axes.set_ylim(ylim)
|
||||
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,
|
||||
)
|
||||
|
||||
def read_csv_file(self, filename):
|
||||
if filename == "":
|
||||
return
|
||||
|
||||
sep = " "
|
||||
|
||||
def is_float(string):
|
||||
if string.replace(".", "").isnumeric():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
with open(filename, 'r', newline='') as f:
|
||||
lines = f.readlines()
|
||||
x = []
|
||||
y = []
|
||||
for line in lines:
|
||||
if line[0] != "*" and line[0] != "#" and line[0] != "$":
|
||||
row = line.split(sep)
|
||||
if len(row) >= 2:
|
||||
if is_float(row[0]) and is_float(row[1]):
|
||||
x.append(float(row[0]))
|
||||
y.append(float(row[1]))
|
||||
|
||||
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}
|
||||
|
||||
if data_type == 'Z(x)':
|
||||
line = self.canvas_2.axes.plot(x, y, marker="+",
|
||||
label=legend + ' (m)')
|
||||
self.plot_rkc.canvas.draw_idle()
|
||||
self.plot_rkc.update_idle()
|
||||
if data_type == 'Q(t)':
|
||||
line = self.canvas_4.axes.plot(x, y, marker="+",
|
||||
label=legend + ' (m³/s)')
|
||||
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)
|
||||
|
||||
def play_sound(self):
|
||||
def get_sine_wave(frequency, duration,
|
||||
sample_rate=44100, amplitude=4096):
|
||||
t = np.linspace(0, duration, int(sample_rate*duration))
|
||||
return amplitude*np.sin(2*np.pi*frequency*t)
|
||||
|
||||
if not _audio_loaded:
|
||||
return
|
||||
|
||||
# results
|
||||
results = self._results[self._current_results[0]]
|
||||
if results is None:
|
||||
return
|
||||
|
||||
# reach
|
||||
reach = results.river.reachs[self._get_current_reach()]
|
||||
profile_id = self._get_current_profile()
|
||||
profile = reach.profile(profile_id)
|
||||
|
||||
t = self._timestamps
|
||||
q = profile.get_key("Q")
|
||||
|
||||
scale = []
|
||||
low = 30
|
||||
high = 84
|
||||
for k in range(low, high):
|
||||
note = 440*2**((k-49)/12)
|
||||
scale.append(note) # add musical note
|
||||
n_notes = len(scale) # number of musical notes
|
||||
# rescale
|
||||
# we start at low to high
|
||||
tmax = max(t)
|
||||
tmin = min(t)
|
||||
qmax = max(q)
|
||||
qmin = min(q)
|
||||
qfact = (n_notes) / (qmax - qmin + 1)
|
||||
for i in range(len(q)):
|
||||
q[i] = int((q[i] - qmin) * qfact)
|
||||
nq = [q[0]] # (notes)
|
||||
dq = [0.1] # durée
|
||||
for i in range(len(t)-1):
|
||||
if q[i] == q[i+1]:
|
||||
dq[-1] += 0.1
|
||||
else:
|
||||
nq.append(q[i+1])
|
||||
dq.append(0.1)
|
||||
wq = []
|
||||
volume = 2048
|
||||
for i in range(len(dq)):
|
||||
new_w = get_sine_wave(frequency=scale[nq[i]],
|
||||
duration=dq[i],
|
||||
amplitude=volume)
|
||||
wq = np.concatenate((wq, new_w))
|
||||
p = pyaudio.PyAudio()
|
||||
chunk = 1048
|
||||
stream = p.open(format=p.get_format_from_width(2),
|
||||
channels=1,
|
||||
rate=44100,
|
||||
output=True)
|
||||
|
||||
def fn():
|
||||
i = 0
|
||||
while i < len(wq):
|
||||
stream.write(
|
||||
wq[i:min(i+chunk, len(wq))].astype(np.int16).tobytes()
|
||||
)
|
||||
i += chunk
|
||||
|
||||
dlg = WaitingDialog(
|
||||
payload_fn=fn,
|
||||
title="playing_sound",
|
||||
parent=self
|
||||
)
|
||||
dlg.exec_()
|
||||
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
p.terminate()
|
||||
@@ -56,6 +56,8 @@ class ResultsTranslate(MainTranslate):
|
||||
self._dict["file_all"] = _translate("Results", "All files (*)")
|
||||
self._dict["file_geotiff"] = _translate(
|
||||
"Results", "GeoTIFF file (*.tiff *.tif)")
|
||||
self._dict["file_csv"] = _translate(
|
||||
"Results", "CSV file (*.csv)")
|
||||
self._dict["ImageCoordinates"] = _translate(
|
||||
"Results", "Image coordinates"
|
||||
)
|
||||
|
||||
@@ -138,107 +138,6 @@ class SelectSolverWindow(PamhyrDialog):
|
||||
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):
|
||||
_pamhyr_ui = "SolverLog"
|
||||
_pamhyr_name = "Solver Log"
|
||||
|
||||
@@ -186,12 +186,13 @@ class PamhyrWindow(ASubMainWindow, ListedSubWindow, PamhyrWindowTools):
|
||||
def _set_title(self):
|
||||
title = self._title
|
||||
|
||||
if self._study.is_read_only():
|
||||
title = "⛔ " + title
|
||||
if self._study is not None:
|
||||
if self._study.is_read_only():
|
||||
title = "⛔ " + title
|
||||
|
||||
scenario = self._study.status.scenario
|
||||
if scenario is not None and scenario.name != "default":
|
||||
title += f" | {scenario.name}"
|
||||
scenario = self._study.status.scenario
|
||||
if scenario is not None and scenario.name != "default":
|
||||
title += f" | {scenario.name}"
|
||||
|
||||
self.ui.setWindowTitle(title)
|
||||
|
||||
|
||||
@@ -228,6 +228,21 @@ class MainTranslate(UnitTranslate):
|
||||
"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_diff_results_compatibility_msg"] = _translate(
|
||||
"MainWindow",
|
||||
"Results comparison with two "
|
||||
"incompatible study version"
|
||||
)
|
||||
self._dict["playing_sound"] = _translate(
|
||||
"MainWindow", "Playing sound..."
|
||||
)
|
||||
|
||||
self._dict["x"] = _translate("MainWindow", "X (m)")
|
||||
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
||||
self._dict["Yes"] = _translate("MainWindow", "Yes")
|
||||
|
||||
@@ -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>
|
||||
@@ -160,9 +160,9 @@
|
||||
<string>&Results</string>
|
||||
</property>
|
||||
<addaction name="action_menu_results_last"/>
|
||||
<addaction name="action_open_results_from_file"/>
|
||||
<addaction name="action_compare_results"/>
|
||||
<addaction name="action_open_results_adists"/>
|
||||
<addaction name="action_menu_open_results_from_file"/>
|
||||
<addaction name="action_menu_compare_scenarios_results"/>
|
||||
<addaction name="action_menu_open_results_adists"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_help">
|
||||
<property name="title">
|
||||
@@ -726,7 +726,7 @@
|
||||
<string>Edit hydraulic structures</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_open_results_from_file">
|
||||
<action name="action_menu_open_results_from_file">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@@ -787,12 +787,15 @@
|
||||
<string>DIF</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_compare_results">
|
||||
<action name="action_menu_compare_results">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Compare results</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_open_results_adists">
|
||||
<action name="action_menu_open_results_adists">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@@ -800,6 +803,14 @@
|
||||
<string>Open results AdisTS</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_menu_compare_scenarios_results">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Compare results</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
||||
@@ -239,6 +239,8 @@
|
||||
<addaction name="action_export"/>
|
||||
<addaction name="action_reload"/>
|
||||
<addaction name="action_Geo_tiff"/>
|
||||
<addaction name="action_import_data"/>
|
||||
<addaction name="action_play_sound"/>
|
||||
</widget>
|
||||
<action name="action_add">
|
||||
<property name="icon">
|
||||
@@ -288,6 +290,30 @@
|
||||
<string>Import background image</string>
|
||||
</property>
|
||||
</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>
|
||||
<action name="action_play_sound">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>play_sound</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Play discharge as sound</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 443 B |
+393
-195
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user