mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Merge: Merge branch 'sediment' with sediment export and result for mage.
This commit is contained in:
commit
7429952168
57 files changed
+3995
-76
No files matched your search
@@ -83,7 +83,8 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
def _get_ctor_from_type(cls, t):
|
def _get_ctor_from_type(cls, t):
|
||||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||||
NotDefined, PonctualContribution,
|
NotDefined, PonctualContribution,
|
||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
TimeOverZ, TimeOverDischarge, ZOverDischarge,
|
||||||
|
Solid,
|
||||||
)
|
)
|
||||||
|
|
||||||
res = NotDefined
|
res = NotDefined
|
||||||
@@ -95,6 +96,8 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
res = TimeOverDischarge
|
res = TimeOverDischarge
|
||||||
elif t == "ZD":
|
elif t == "ZD":
|
||||||
res = ZOverDischarge
|
res = ZOverDischarge
|
||||||
|
elif t == "SL":
|
||||||
|
res = Solid
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
|||||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||||
NotDefined,
|
NotDefined,
|
||||||
PonctualContribution,
|
PonctualContribution,
|
||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
TimeOverZ, TimeOverDischarge, ZOverDischarge,
|
||||||
|
Solid,
|
||||||
)
|
)
|
||||||
|
|
||||||
class BoundaryConditionList(SQLSubModel):
|
class BoundaryConditionList(SQLSubModel):
|
||||||
|
|||||||
@@ -83,3 +83,16 @@ class ZOverDischarge(BoundaryCondition):
|
|||||||
@property
|
@property
|
||||||
def _default_0(self):
|
def _default_0(self):
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
class Solid(BoundaryCondition):
|
||||||
|
def __init__(self, id:int = -1, name:str = "", status = None):
|
||||||
|
super(Solid, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
|
self._type = "SL"
|
||||||
|
self._header = ["time", "solid"]
|
||||||
|
self._types = [TimeOverDischarge.time_convert, float]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def compatibility(cls):
|
||||||
|
return ["solid"]
|
||||||
@@ -19,12 +19,29 @@
|
|||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
class Point(object):
|
class Point(object):
|
||||||
def __init__(self, name:str = "", status = None):
|
def __init__(self, name:str = "", profile=None, status = None):
|
||||||
super(Point, self).__init__()
|
super(Point, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
|
self._profile = profile
|
||||||
|
self._sl = None
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sl(self):
|
||||||
|
if self._sl is None:
|
||||||
|
return self._profile.sl
|
||||||
|
|
||||||
|
return self._sl
|
||||||
|
|
||||||
|
@sl.setter
|
||||||
|
def sl(self, sl):
|
||||||
|
if sl == self._profile.sl:
|
||||||
|
self._sl = None
|
||||||
|
|
||||||
|
self._sl = sl
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def __init__(self, x:float = 0.0, y:float = 0.0, z:float = 0.0,
|
def __init__(self, x:float = 0.0, y:float = 0.0, z:float = 0.0,
|
||||||
name:str = "", status = None):
|
name:str = "", profile = None, status = None):
|
||||||
super(PointXYZ, self).__init__(name=name, status=status)
|
super(PointXYZ, self).__init__(name=name, profile=profile, status=status)
|
||||||
|
|
||||||
self._x = float(x)
|
self._x = float(x)
|
||||||
self._y = float(y)
|
self._y = float(y)
|
||||||
@@ -44,7 +44,9 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
y INTEGER NOT NULL,
|
y INTEGER NOT NULL,
|
||||||
z INTEGER NOT NULL,
|
z INTEGER NOT NULL,
|
||||||
profile INTEGER NOT NULL,
|
profile INTEGER NOT NULL,
|
||||||
FOREIGN KEY(profile) REFERENCES profileXYZ(id)
|
sl INTEGER,
|
||||||
|
FOREIGN KEY(profile) REFERENCES profileXYZ(id),
|
||||||
|
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -53,6 +55,17 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _sql_update(cls, execute, version):
|
def _sql_update(cls, execute, version):
|
||||||
cls._update_submodel(execute, version)
|
cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"""
|
||||||
|
ALTER TABLE geometry_pointXYZ
|
||||||
|
ADD COLUMN sl INTEGER
|
||||||
|
REFERENCES sedimentary_layer(id)
|
||||||
|
"""
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -63,9 +76,9 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT ind, name, x, y, z " +
|
"SELECT ind, name, x, y, z, sl " +
|
||||||
"FROM geometry_pointXYZ " +
|
"FROM geometry_pointXYZ " +
|
||||||
f"WHERE profile = {profile}"
|
f"WHERE profile = {profile.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create points list
|
# Create points list
|
||||||
@@ -79,13 +92,25 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
x = row[2]
|
x = row[2]
|
||||||
y = row[3]
|
y = row[3]
|
||||||
z = row[4]
|
z = row[4]
|
||||||
|
sl = row[5]
|
||||||
|
|
||||||
new = cls(
|
new = cls(
|
||||||
name = name,
|
name = name,
|
||||||
x = x, y = y, z = z,
|
x = x, y = y, z = z,
|
||||||
|
profile = profile,
|
||||||
status = status
|
status = status
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if sl == -1 or sl == None:
|
||||||
|
new._sl = None
|
||||||
|
else:
|
||||||
|
new._sl = next(
|
||||||
|
filter(
|
||||||
|
lambda s: s.id == sl,
|
||||||
|
data["sediment_layers_list"].sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
points[ind] = new
|
points[ind] = new
|
||||||
|
|
||||||
return points
|
return points
|
||||||
@@ -94,13 +119,15 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
|
sl = self._sl.id if self._sl is not None else -1
|
||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"geometry_pointXYZ(ind, name, x, y, z, profile) "+
|
"geometry_pointXYZ(ind, name, x, y, z, profile, sl) "+
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, '{self._sql_format(self._name)}', " +
|
f"{ind}, '{self._sql_format(self._name)}', " +
|
||||||
f"{self.x}, {self.y}, {self.z}, " +
|
f"{self.x}, {self.y}, {self.z}, " +
|
||||||
f"{profile}" +
|
f"{profile.id}, {sl}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
@@ -117,7 +144,7 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
*data
|
*data
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
valid_header = {'name', 'x', 'y', 'z'}
|
valid_header = {'name', 'x', 'y', 'z', 'profile'}
|
||||||
d = {}
|
d = {}
|
||||||
for i, v in enumerate(data):
|
for i, v in enumerate(data):
|
||||||
h = header[i].strip().lower().split(' ')[0]
|
h = header[i].strip().lower().split(' ')[0]
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class Profile(object):
|
|||||||
self._kp = float(kp)
|
self._kp = float(kp)
|
||||||
self._name = str(name)
|
self._name = str(name)
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
|
self._sl = None
|
||||||
|
|
||||||
self._points: List[Point] = []
|
self._points: List[Point] = []
|
||||||
|
|
||||||
@@ -63,6 +64,9 @@ class Profile(object):
|
|||||||
def points(self):
|
def points(self):
|
||||||
return self._points.copy()
|
return self._points.copy()
|
||||||
|
|
||||||
|
def point(self, index):
|
||||||
|
return self._points[index]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
return self._reach
|
return self._reach
|
||||||
@@ -136,6 +140,19 @@ class Profile(object):
|
|||||||
self._name = value.strip()
|
self._name = value.strip()
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sl(self):
|
||||||
|
"""
|
||||||
|
Returns:
|
||||||
|
Profile sediment layers.
|
||||||
|
"""
|
||||||
|
return self._sl
|
||||||
|
|
||||||
|
@sl.setter
|
||||||
|
def sl(self, value):
|
||||||
|
self._sl = value
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def profile_type(self):
|
def profile_type(self):
|
||||||
"""
|
"""
|
||||||
@@ -274,6 +291,39 @@ class Profile(object):
|
|||||||
)
|
)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
# Sediment Layers
|
||||||
|
|
||||||
|
def get_sl(self):
|
||||||
|
"""Get sediment layer height of points
|
||||||
|
|
||||||
|
Get sediment layer of points (without spesific point sl)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of sediment layers height
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
psl = [point.sl for point in self.points]
|
||||||
|
|
||||||
|
# Compute max number of layers
|
||||||
|
sl_max = 0
|
||||||
|
for sl in psl:
|
||||||
|
n = 0 if sl is None else len(sl)
|
||||||
|
sl_max = max(n, sl_max)
|
||||||
|
|
||||||
|
# Create list of height for each sl and each layer
|
||||||
|
for i in range(0, sl_max):
|
||||||
|
cur = []
|
||||||
|
# Compute new layer line for each sl
|
||||||
|
for sl in psl:
|
||||||
|
if sl is not None and i < len(sl):
|
||||||
|
cur.append(sl.get(i).height)
|
||||||
|
else:
|
||||||
|
cur.append(0)
|
||||||
|
# Add layer line to result
|
||||||
|
res.append(cur)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
# Abstract method, must be implemented for in non abstract class
|
# Abstract method, must be implemented for in non abstract class
|
||||||
def get_station(self):
|
def get_station(self):
|
||||||
raise NotImplementedMethodeError(self, self.get_station)
|
raise NotImplementedMethodeError(self, self.get_station)
|
||||||
@@ -76,7 +76,9 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
num INTEGER NOT NULL,
|
num INTEGER NOT NULL,
|
||||||
code1 INTEGER NOT NULL,
|
code1 INTEGER NOT NULL,
|
||||||
code2 INTEGER NOT NULL,
|
code2 INTEGER NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
sl INTEGER,
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(id),
|
||||||
|
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -84,6 +86,17 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_update(cls, execute, version):
|
def _sql_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"""
|
||||||
|
ALTER TABLE geometry_profileXYZ
|
||||||
|
ADD COLUMN sl INTEGER
|
||||||
|
REFERENCES sedimentary_layer(id)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -93,7 +106,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ind, name, kp, num, code1, code2 " +
|
"SELECT id, ind, name, kp, num, code1, code2, sl " +
|
||||||
"FROM geometry_profileXYZ " +
|
"FROM geometry_profileXYZ " +
|
||||||
f"WHERE reach = {reach}"
|
f"WHERE reach = {reach}"
|
||||||
)
|
)
|
||||||
@@ -109,6 +122,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
num = row[5]
|
num = row[5]
|
||||||
code1 = row[5]
|
code1 = row[5]
|
||||||
code2 = row[6]
|
code2 = row[6]
|
||||||
|
sl = row[7]
|
||||||
|
|
||||||
new = cls(
|
new = cls(
|
||||||
id=id, num = num,
|
id=id, num = num,
|
||||||
@@ -118,7 +132,17 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
status = status
|
status = status
|
||||||
)
|
)
|
||||||
|
|
||||||
data["profile"] = id
|
if sl == -1 or sl == None:
|
||||||
|
new._sl = None
|
||||||
|
else:
|
||||||
|
new._sl = next(
|
||||||
|
filter(
|
||||||
|
lambda s: s.id == sl,
|
||||||
|
data["sediment_layers_list"].sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data["profile"] = new
|
||||||
new._points = PointXYZ._sql_load(execute, data)
|
new._points = PointXYZ._sql_load(execute, data)
|
||||||
|
|
||||||
profiles[ind] = new
|
profiles[ind] = new
|
||||||
@@ -129,18 +153,20 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
ok = True
|
ok = True
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
|
sl = self._sl.id if self._sl is not None else -1
|
||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"geometry_profileXYZ(id, ind, name, reach, kp, num, code1, code2) "+
|
"geometry_profileXYZ(id, ind, name, reach, kp, num, code1, code2, sl) "+
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
||||||
f"{self.reach.id}, {self.kp}, {self.num}, " +
|
f"{self.reach.id}, {self.kp}, {self.num}, " +
|
||||||
f"{self.code1}, {self.code1}" +
|
f"{self.code1}, {self.code1}, {sl}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
|
|
||||||
data["profile"] = self.id
|
data["profile"] = self
|
||||||
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
|
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
@@ -178,11 +204,11 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
try:
|
try:
|
||||||
if len(header) == 0:
|
if len(header) == 0:
|
||||||
point = PointXYZ(
|
point = PointXYZ(
|
||||||
*data, status=self._status
|
*data, profile=self, status=self._status
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
valid_header = {'name', 'x', 'y', 'z'}
|
valid_header = {'name', 'x', 'y', 'z'}
|
||||||
d = {"status": self._status}
|
d = {"status": self._status, "profile": self}
|
||||||
for i, v in enumerate(data):
|
for i, v in enumerate(data):
|
||||||
h = header[i].strip().lower().split(' ')[0]
|
h = header[i].strip().lower().split(' ')[0]
|
||||||
if h in valid_header:
|
if h in valid_header:
|
||||||
@@ -235,7 +261,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
for point in list_points:
|
for point in list_points:
|
||||||
pt = PointXYZ(*point, status=self._status)
|
pt = PointXYZ(*point, profile=self, status=self._status)
|
||||||
self._points.append(pt)
|
self._points.append(pt)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -259,7 +285,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
point_xyz = PointXYZ(0., 0., 0., status=self._status)
|
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
||||||
self._points.append(point_xyz)
|
self._points.append(point_xyz)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -272,7 +298,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
The new point.
|
The new point.
|
||||||
"""
|
"""
|
||||||
point = PointXYZ(0., 0., 0., status=self._status)
|
point = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
||||||
self._points.insert(index, point)
|
self._points.insert(index, point)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return point
|
return point
|
||||||
|
|||||||
@@ -276,6 +276,39 @@ class Reach(SQLSubModel):
|
|||||||
return max(self.get_kp())
|
return max(self.get_kp())
|
||||||
|
|
||||||
|
|
||||||
|
# Sediment Layers
|
||||||
|
|
||||||
|
def get_sl(self):
|
||||||
|
"""Get sediment layer height of profile
|
||||||
|
|
||||||
|
Get sediment layer of profile (without spesific point sl)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of sediment layers height
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
psl = [profile.sl for profile in self.profiles]
|
||||||
|
|
||||||
|
# Compute max number of layers
|
||||||
|
sl_max = 0
|
||||||
|
for sl in psl:
|
||||||
|
n = 0 if sl is None else len(sl)
|
||||||
|
sl_max = max(n, sl_max)
|
||||||
|
|
||||||
|
# Create list of height for each sl and each layer
|
||||||
|
for i in range(0, sl_max):
|
||||||
|
cur = []
|
||||||
|
# Compute new layer line for each sl
|
||||||
|
for sl in psl:
|
||||||
|
if sl is not None and i < len(sl):
|
||||||
|
cur.append(sl.get(i).height)
|
||||||
|
else:
|
||||||
|
cur.append(0)
|
||||||
|
# Add layer line to result
|
||||||
|
res.append(cur)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
# Guidelines
|
# Guidelines
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ class River(object):
|
|||||||
def reach(self, id):
|
def reach(self, id):
|
||||||
return self._reachs[id]
|
return self._reachs[id]
|
||||||
|
|
||||||
|
def has_reach(self, id):
|
||||||
|
return 0 <= id < len(self._reachs)
|
||||||
|
|
||||||
def add(self, reach_id):
|
def add(self, reach_id):
|
||||||
reachs = self._study.river.enable_edges()
|
reachs = self._study.river.enable_edges()
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import flatten
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.DB import SQLSubModel
|
||||||
|
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
@@ -31,6 +33,7 @@ from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
|
|||||||
from Model.Stricklers.StricklersList import StricklersList
|
from Model.Stricklers.StricklersList import StricklersList
|
||||||
from Model.Friction.FrictionList import FrictionList
|
from Model.Friction.FrictionList import FrictionList
|
||||||
from Model.SolverParameters.SolverParametersList import SolverParametersList
|
from Model.SolverParameters.SolverParametersList import SolverParametersList
|
||||||
|
from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
||||||
|
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
|
|
||||||
@@ -208,6 +211,7 @@ class River(Graph, SQLSubModel):
|
|||||||
InitialConditionsDict,
|
InitialConditionsDict,
|
||||||
StricklersList,
|
StricklersList,
|
||||||
SolverParametersList,
|
SolverParametersList,
|
||||||
|
SedimentLayerList,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status=None):
|
def __init__(self, status=None):
|
||||||
@@ -223,6 +227,7 @@ class River(Graph, SQLSubModel):
|
|||||||
self._initial_conditions = InitialConditionsDict(status=self._status)
|
self._initial_conditions = InitialConditionsDict(status=self._status)
|
||||||
self._stricklers = StricklersList(status=self._status)
|
self._stricklers = StricklersList(status=self._status)
|
||||||
self._parameters = {}
|
self._parameters = {}
|
||||||
|
self._sediment_layers = SedimentLayerList(status=self._status)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
@@ -246,6 +251,14 @@ class River(Graph, SQLSubModel):
|
|||||||
)
|
)
|
||||||
data["stricklers"] = new._stricklers
|
data["stricklers"] = new._stricklers
|
||||||
|
|
||||||
|
|
||||||
|
# Initial conditions
|
||||||
|
new._sediment_layers = SedimentLayerList._sql_load(
|
||||||
|
execute,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
data["sediment_layers_list"] = new._sediment_layers
|
||||||
|
|
||||||
# Network
|
# Network
|
||||||
new._nodes = RiverNode._sql_load(
|
new._nodes = RiverNode._sql_load(
|
||||||
execute,
|
execute,
|
||||||
@@ -289,6 +302,7 @@ class River(Graph, SQLSubModel):
|
|||||||
objs.append(self._boundary_condition)
|
objs.append(self._boundary_condition)
|
||||||
objs.append(self._initial_conditions)
|
objs.append(self._initial_conditions)
|
||||||
objs.append(self._lateral_contribution)
|
objs.append(self._lateral_contribution)
|
||||||
|
objs.append(self._sediment_layers)
|
||||||
objs.append(self._stricklers)
|
objs.append(self._stricklers)
|
||||||
|
|
||||||
for solver in self._parameters:
|
for solver in self._parameters:
|
||||||
@@ -317,6 +331,10 @@ class River(Graph, SQLSubModel):
|
|||||||
def initial_conditions(self):
|
def initial_conditions(self):
|
||||||
return self._initial_conditions
|
return self._initial_conditions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sediment_layers(self):
|
||||||
|
return self._sediment_layers
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stricklers(self):
|
def stricklers(self):
|
||||||
return self._stricklers
|
return self._stricklers
|
||||||
@@ -366,3 +384,16 @@ class River(Graph, SQLSubModel):
|
|||||||
|
|
||||||
def set_current_reach(self, reach):
|
def set_current_reach(self, reach):
|
||||||
self._current_reach = reach
|
self._current_reach = reach
|
||||||
|
|
||||||
|
def has_sediment(self):
|
||||||
|
has = len(self._sediment_layers) != 0
|
||||||
|
has &= any(
|
||||||
|
filter(
|
||||||
|
lambda p: p.sl != None,
|
||||||
|
flatten(
|
||||||
|
map(lambda e: e.reach.profiles, self.edges())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return has
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.DB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
class Layer(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
id:int = -1, name:str = "",
|
||||||
|
type = "",
|
||||||
|
height = 0.0, d50 = 0.0, sigma = 0.0,
|
||||||
|
critical_constraint = 0.0,
|
||||||
|
sl = None, status = None):
|
||||||
|
super(Layer, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._type = type
|
||||||
|
|
||||||
|
self._height = height
|
||||||
|
self._d50 = d50
|
||||||
|
self._sigma = sigma
|
||||||
|
self._critical_constraint = critical_constraint
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = Layer._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
Layer._id_cnt = max(id, Layer._id_cnt+1)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self._type
|
||||||
|
|
||||||
|
@type.setter
|
||||||
|
def type(self, type):
|
||||||
|
self._type = type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
return self._height
|
||||||
|
|
||||||
|
@height.setter
|
||||||
|
def height(self, height):
|
||||||
|
self._height = float(height)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def d50(self):
|
||||||
|
return self._d50
|
||||||
|
|
||||||
|
@d50.setter
|
||||||
|
def d50(self, d50):
|
||||||
|
self._d50 = float(d50)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sigma(self):
|
||||||
|
return self._sigma
|
||||||
|
|
||||||
|
@sigma.setter
|
||||||
|
def sigma(self, sigma):
|
||||||
|
self._sigma = float(sigma)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def critical_constraint(self):
|
||||||
|
return self._critical_constraint
|
||||||
|
|
||||||
|
@critical_constraint.setter
|
||||||
|
def critical_constraint(self, critical_constraint):
|
||||||
|
self._critical_constraint = float(critical_constraint)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE sedimentary_layer_layer(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
ind INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
height REAL NOT NULL,
|
||||||
|
d50 REAL NOT NULL,
|
||||||
|
sigma REAL NOT NULL,
|
||||||
|
critical_constraint REAL NOT NULL,
|
||||||
|
sl INTEGER,
|
||||||
|
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 2:
|
||||||
|
cls._sql_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
new = []
|
||||||
|
sl = data["sl"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, ind, name, type, height, d50, sigma, critical_constraint " +
|
||||||
|
"FROM sedimentary_layer_layer " +
|
||||||
|
f"WHERE sl = {sl}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for _ in table:
|
||||||
|
new.append(None)
|
||||||
|
|
||||||
|
for row in table:
|
||||||
|
ind = row[1]
|
||||||
|
|
||||||
|
layer = cls(
|
||||||
|
id = row[0], name = row[2],
|
||||||
|
type = row[3], height = row[4],
|
||||||
|
d50 = row[5], sigma = row[6],
|
||||||
|
critical_constraint = row[7],
|
||||||
|
sl = sl, status = data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
new[ind] = layer
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
ind = data["ind"]
|
||||||
|
sl = data["sl"]
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO " +
|
||||||
|
"sedimentary_layer_layer(id, ind, name, type, height, d50, sigma, critical_constraint, sl) "+
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
||||||
|
f"'{self._sql_format(self._type)}', {self._height}, " +
|
||||||
|
f"{self._d50}, {self._sigma}, {self._critical_constraint}, " +
|
||||||
|
f"{sl.id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class SedimentLayer(SQLSubModel):
|
||||||
|
_sub_classes = [Layer]
|
||||||
|
_id_cnt = 0
|
||||||
|
|
||||||
|
def __init__(self, id:int = -1,
|
||||||
|
name:str = "", comment:str = "",
|
||||||
|
status = None):
|
||||||
|
super(SedimentLayer, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._name = name
|
||||||
|
self._comment = comment
|
||||||
|
self._layers = []
|
||||||
|
|
||||||
|
if id == -1:
|
||||||
|
self.id = SedimentLayer._id_cnt
|
||||||
|
else:
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
SedimentLayer._id_cnt = max(id, SedimentLayer._id_cnt+1)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = f"{self.name} ({len(self)})"
|
||||||
|
|
||||||
|
if self.comment != "":
|
||||||
|
s += f" - {self.comment}"
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._layers)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def layers(self):
|
||||||
|
return self._layers.copy()
|
||||||
|
|
||||||
|
def height(self):
|
||||||
|
return list(
|
||||||
|
map(lambda l: l.height, self._layers)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
def names(self):
|
||||||
|
return list(
|
||||||
|
map(lambda l: l.name, self._layers)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comment(self):
|
||||||
|
return self._comment
|
||||||
|
|
||||||
|
@comment.setter
|
||||||
|
def comment(self, comment):
|
||||||
|
self._comment = comment
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
execute("""
|
||||||
|
CREATE TABLE sedimentary_layer(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
comment TEXT NOT NULL
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 2:
|
||||||
|
cls._sql_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT id, name, comment " +
|
||||||
|
"FROM sedimentary_layer "
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in table:
|
||||||
|
sl = cls(
|
||||||
|
id = row[0],
|
||||||
|
name = row[1],
|
||||||
|
comment = row[2],
|
||||||
|
status = data['status']
|
||||||
|
)
|
||||||
|
|
||||||
|
data["sl"] = sl.id
|
||||||
|
sl._layers = Layer._sql_load(execute, data)
|
||||||
|
|
||||||
|
new.append(sl)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO sedimentary_layer (id, name, comment) " +
|
||||||
|
f"VALUES ({self.id}, '{self._sql_format(self._name)}', " +
|
||||||
|
f"'{self._sql_format(self._comment)}')"
|
||||||
|
)
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
data["sl"] = self
|
||||||
|
|
||||||
|
ind = 0
|
||||||
|
for l in self._layers:
|
||||||
|
data["ind"] = ind
|
||||||
|
l._sql_save(execute, data)
|
||||||
|
ind += 1
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get(self, index):
|
||||||
|
return self._layers[index]
|
||||||
|
|
||||||
|
def set(self, index, new):
|
||||||
|
self._layers[index] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def insert(self, index, new):
|
||||||
|
self._layers.insert(index, new)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = Layer(sl=self, status = self._status)
|
||||||
|
self.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def delete(self, els):
|
||||||
|
for el in els:
|
||||||
|
self._layers.remove(el)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
els = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._layers)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(els)
|
||||||
|
|
||||||
|
def move_up(self, index):
|
||||||
|
if index >= 0:
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
l = self._layers
|
||||||
|
l[index], l[next] = l[next], l[index]
|
||||||
|
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, index):
|
||||||
|
if index + 1 < len(self._layers):
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
l = self._layers
|
||||||
|
l[index], l[prev] = l[prev], l[index]
|
||||||
|
|
||||||
|
self._status.modified()
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.DB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
|
||||||
|
class SedimentLayerList(SQLSubModel):
|
||||||
|
_sub_classes = [SedimentLayer]
|
||||||
|
|
||||||
|
def __init__(self, status = None):
|
||||||
|
super(SedimentLayerList, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._sl = []
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._sl)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data = None):
|
||||||
|
new = cls(status = data["status"])
|
||||||
|
|
||||||
|
new._sl = SedimentLayer._sql_load(execute, data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data = None):
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
# Delete previous data
|
||||||
|
execute("DELETE FROM sedimentary_layer")
|
||||||
|
execute("DELETE FROM sedimentary_layer_layer")
|
||||||
|
|
||||||
|
for sl in self._sl:
|
||||||
|
ok &= sl._sql_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sediment_layers(self):
|
||||||
|
return self._sl.copy()
|
||||||
|
|
||||||
|
def get(self, index):
|
||||||
|
return self._sl[index]
|
||||||
|
|
||||||
|
def set(self, index, new):
|
||||||
|
self._sl[index] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def insert(self, index, new):
|
||||||
|
self._sl.insert(index, new)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = SedimentLayer(status = self._status)
|
||||||
|
self.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def delete(self, els):
|
||||||
|
for el in els:
|
||||||
|
self._sl.remove(el)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
els = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._sl)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(els)
|
||||||
|
|
||||||
|
def move_up(self, index):
|
||||||
|
if index < len(self._sl):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
l = self._sl
|
||||||
|
l[index], l[next] = l[next], l[index]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, index):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
l = self._sl
|
||||||
|
l[index], l[prev] = l[prev], l[index]
|
||||||
|
self._status.modified()
|
||||||
@@ -93,6 +93,13 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_update(cls, execute, version):
|
def _sql_update(cls, execute, version):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) < 3:
|
||||||
|
execute(f"UPDATE solver_parameter SET name='mage_implicitation' WHERE name='mage_implication'")
|
||||||
|
execute(f"UPDATE solver_parameter SET name='mage_iteration_type' WHERE name='mage_iter_type'")
|
||||||
|
|
||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -160,6 +167,17 @@ class SolverParametersList(SQLSubModel):
|
|||||||
def get(self, index):
|
def get(self, index):
|
||||||
return self._parameters[index]
|
return self._parameters[index]
|
||||||
|
|
||||||
|
def get_by_key(self, key):
|
||||||
|
try:
|
||||||
|
return next(
|
||||||
|
filter(
|
||||||
|
lambda p: p["name"] == key,
|
||||||
|
self._parameters
|
||||||
|
)
|
||||||
|
)["value"]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
def set(self, index, new):
|
def set(self, index, new):
|
||||||
self._parameters[index] = new
|
self._parameters[index] = new
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
def __init__(self, filename = None, init_new = True):
|
def __init__(self, filename = None, init_new = True):
|
||||||
# Metadata
|
# Metadata
|
||||||
self._version = "0.0.1"
|
self._version = "0.0.3"
|
||||||
self.creation_date = datetime.now()
|
self.creation_date = datetime.now()
|
||||||
self.last_modification_date = datetime.now()
|
self.last_modification_date = datetime.now()
|
||||||
self.last_save_date = datetime.now()
|
self.last_save_date = datetime.now()
|
||||||
|
|||||||
+44
-21
@@ -86,6 +86,7 @@ class AbstractSolver(object):
|
|||||||
("all_init_time", "000:00:00:00"),
|
("all_init_time", "000:00:00:00"),
|
||||||
("all_final_time", "999:99:00:00"),
|
("all_final_time", "999:99:00:00"),
|
||||||
("all_timestep", "300.0"),
|
("all_timestep", "300.0"),
|
||||||
|
("all_command_line_arguments", ""),
|
||||||
]
|
]
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
@@ -153,6 +154,17 @@ class AbstractSolver(object):
|
|||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog = None):
|
||||||
raise NotImplementedMethodeError(self, self.export)
|
raise NotImplementedMethodeError(self, self.export)
|
||||||
|
|
||||||
|
def cmd_args(self, study):
|
||||||
|
"""Return solver command line arguments list
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Command line arguments list
|
||||||
|
"""
|
||||||
|
params = study.river.get_params(self.type)
|
||||||
|
args = params.get_by_key("all_command_line_arguments")
|
||||||
|
|
||||||
|
return args.split(" ")
|
||||||
|
|
||||||
def input_param(self):
|
def input_param(self):
|
||||||
"""Return input command line parameter(s)
|
"""Return input command line parameter(s)
|
||||||
|
|
||||||
@@ -190,7 +202,7 @@ class AbstractSolver(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _format_command(self, cmd, path = ""):
|
def _format_command(self, study, cmd, path = ""):
|
||||||
"""Format command line
|
"""Format command line
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -206,6 +218,7 @@ class AbstractSolver(object):
|
|||||||
cmd = cmd.replace("@path", path.replace(" ", "\ "))
|
cmd = cmd.replace("@path", path.replace(" ", "\ "))
|
||||||
cmd = cmd.replace("@input", self.input_param())
|
cmd = cmd.replace("@input", self.input_param())
|
||||||
cmd = cmd.replace("@dir", self._process.workingDirectory())
|
cmd = cmd.replace("@dir", self._process.workingDirectory())
|
||||||
|
cmd = cmd.replace("@args", " ".join(self.cmd_args(study)))
|
||||||
|
|
||||||
logger.debug(f"! {cmd}")
|
logger.debug(f"! {cmd}")
|
||||||
|
|
||||||
@@ -213,23 +226,33 @@ class AbstractSolver(object):
|
|||||||
# Command line executable path is between " char
|
# Command line executable path is between " char
|
||||||
cmd = cmd.split("\"")
|
cmd = cmd.split("\"")
|
||||||
exe = cmd[1].replace("\ ", " ")
|
exe = cmd[1].replace("\ ", " ")
|
||||||
args = "\"".join(cmd[2:]).split(" ")[1:]
|
args = list(
|
||||||
|
filter(
|
||||||
|
lambda s: s != "",
|
||||||
|
"\"".join(cmd[2:]).split(" ")[1:]
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# We suppose the command line executable path as no space char
|
# We suppose the command line executable path as no space char
|
||||||
cmd = cmd.replace("\ ", "&_&").split(" ")
|
cmd = cmd.replace("\ ", "&_&").split(" ")
|
||||||
exe = cmd[0].replace("&_&", " ")
|
exe = cmd[0].replace("&_&", " ")
|
||||||
args = list(map(lambda s: s.replace("&_&", "\ "), cmd[1:]))
|
args = list(
|
||||||
|
filter(
|
||||||
|
lambda s: s != "",
|
||||||
|
map(lambda s: s.replace("&_&", "\ "), cmd[1:])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"! {exe} {args}")
|
logger.info(f"! {exe} {args}")
|
||||||
return exe, args
|
return exe, args
|
||||||
|
|
||||||
def run_input_data_fomater(self):
|
def run_input_data_fomater(self, study):
|
||||||
if self._cmd_input == "":
|
if self._cmd_input == "":
|
||||||
self._run_next()
|
self._run_next(study)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd = self._cmd_input
|
cmd = self._cmd_input
|
||||||
exe, args = self._format_command(cmd, self._path_input)
|
exe, args = self._format_command(study, cmd, self._path_input)
|
||||||
|
|
||||||
if not os.path.exists(exe):
|
if not os.path.exists(exe):
|
||||||
error = f"[ERROR] Path {exe} do not exists"
|
error = f"[ERROR] Path {exe} do not exists"
|
||||||
@@ -242,13 +265,13 @@ class AbstractSolver(object):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run_solver(self):
|
def run_solver(self, study):
|
||||||
if self._cmd_solver == "":
|
if self._cmd_solver == "":
|
||||||
self._run_next()
|
self._run_next(study)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd = self._cmd_solver
|
cmd = self._cmd_solver
|
||||||
exe, args = self._format_command(cmd, self._path_solver)
|
exe, args = self._format_command(study, cmd, self._path_solver)
|
||||||
|
|
||||||
if not os.path.exists(exe):
|
if not os.path.exists(exe):
|
||||||
error = f"[ERROR] Path {exe} do not exists"
|
error = f"[ERROR] Path {exe} do not exists"
|
||||||
@@ -262,13 +285,13 @@ class AbstractSolver(object):
|
|||||||
self._status = STATUS.RUNNING
|
self._status = STATUS.RUNNING
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run_output_data_fomater(self):
|
def run_output_data_fomater(self, study):
|
||||||
if self._cmd_output == "":
|
if self._cmd_output == "":
|
||||||
self._run_next()
|
self._run_next(study)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd = self._cmd_output
|
cmd = self._cmd_output
|
||||||
exe, args = self._format_command(cmd, self._path_output)
|
exe, args = self._format_command(study, cmd, self._path_output)
|
||||||
|
|
||||||
if not os.path.exists(exe):
|
if not os.path.exists(exe):
|
||||||
error = f"[ERROR] Path {exe} do not exists"
|
error = f"[ERROR] Path {exe} do not exists"
|
||||||
@@ -287,29 +310,29 @@ class AbstractSolver(object):
|
|||||||
for x in s.split('\n'):
|
for x in s.split('\n'):
|
||||||
self._output.put(x)
|
self._output.put(x)
|
||||||
|
|
||||||
def _run_next(self):
|
def _run_next(self, study):
|
||||||
self._step += 1
|
self._step += 1
|
||||||
if self._step < len(self._runs):
|
if self._step < len(self._runs):
|
||||||
res = self._runs[self._step]()
|
res = self._runs[self._step](study)
|
||||||
if res is not True:
|
if res is not True:
|
||||||
self._output.put(res)
|
self._output.put(res)
|
||||||
else:
|
else:
|
||||||
self._status = STATUS.STOPED
|
self._status = STATUS.STOPED
|
||||||
|
|
||||||
def _finished(self, exit_code, exit_status):
|
def _finished(self, study, exit_code, exit_status):
|
||||||
if self._output is not None:
|
if self._output is not None:
|
||||||
self._output.put(exit_code)
|
self._output.put(exit_code)
|
||||||
|
|
||||||
self._run_next()
|
self._run_next(study)
|
||||||
|
|
||||||
def run(self, process = None, output_queue = None):
|
def run(self, study, process = None, output_queue = None):
|
||||||
if process is not None:
|
if process is not None:
|
||||||
self._process = process
|
self._process = process
|
||||||
if output_queue is not None:
|
if output_queue is not None:
|
||||||
self._output = output_queue
|
self._output = output_queue
|
||||||
|
|
||||||
self._process.readyRead.connect(self._data_ready)
|
self._process.readyRead.connect(self._data_ready)
|
||||||
self._process.finished.connect(self._finished)
|
self._process.finished.connect(lambda c, s: self._finished(study, c, s))
|
||||||
|
|
||||||
self._runs = [
|
self._runs = [
|
||||||
self.run_input_data_fomater,
|
self.run_input_data_fomater,
|
||||||
@@ -318,7 +341,7 @@ class AbstractSolver(object):
|
|||||||
]
|
]
|
||||||
self._step = 0
|
self._step = 0
|
||||||
# Run first step
|
# Run first step
|
||||||
res = self._runs[0]()
|
res = self._runs[0](study)
|
||||||
if res is not True:
|
if res is not True:
|
||||||
self._output.put(res)
|
self._output.put(res)
|
||||||
|
|
||||||
@@ -330,14 +353,14 @@ class AbstractSolver(object):
|
|||||||
self._status = STATUS.STOPED
|
self._status = STATUS.STOPED
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def start(self, process = None):
|
def start(self, study, process = None):
|
||||||
if _signal:
|
if _signal:
|
||||||
if self._status == STATUS.PAUSED:
|
if self._status == STATUS.PAUSED:
|
||||||
os.kill(self._process.pid(), SIGCONT)
|
os.kill(self._process.pid(), SIGCONT)
|
||||||
self._status = STATUS.RUNNING
|
self._status = STATUS.RUNNING
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.run(process)
|
self.run(study, process)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
|
|||||||
+247
-11
@@ -61,11 +61,11 @@ class Mage(AbstractSolver):
|
|||||||
("mage_timestep_tra", "3600"),
|
("mage_timestep_tra", "3600"),
|
||||||
("mage_timestep_bin", "0"),
|
("mage_timestep_bin", "0"),
|
||||||
# ("mage_timestep_melissa", "0"),
|
# ("mage_timestep_melissa", "0"),
|
||||||
("mage_implication", "0.70"),
|
("mage_implicitation", "0.70"),
|
||||||
("mage_continuity_discretization", "S"),
|
("mage_continuity_discretization", "S"),
|
||||||
("mage_qsj_discretization", "B"),
|
("mage_qsj_discretization", "B"),
|
||||||
("mage_stop_criterion_iterations", "R"),
|
("mage_stop_criterion_iterations", "R"),
|
||||||
("mage_iter_type", "0"),
|
("mage_iteration_type", "0"),
|
||||||
("mage_smooth_coef", "0"),
|
("mage_smooth_coef", "0"),
|
||||||
("mage_cfl_max", "-1."),
|
("mage_cfl_max", "-1."),
|
||||||
("mage_min_height", "0.1"),
|
("mage_min_height", "0.1"),
|
||||||
@@ -97,6 +97,13 @@ class Mage(AbstractSolver):
|
|||||||
# Export #
|
# Export #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
|
def cmd_args(self, study):
|
||||||
|
l = super(Mage, self).cmd_args(study)
|
||||||
|
|
||||||
|
l.append("-r")
|
||||||
|
|
||||||
|
return l
|
||||||
|
|
||||||
def input_param(self):
|
def input_param(self):
|
||||||
return "0.REP"
|
return "0.REP"
|
||||||
|
|
||||||
@@ -127,23 +134,47 @@ class Mage(AbstractSolver):
|
|||||||
with mage_file_open(os.path.join(repertory, f"{name}.ST"), "w+") as f:
|
with mage_file_open(os.path.join(repertory, f"{name}.ST"), "w+") as f:
|
||||||
files.append(f"{name}.ST")
|
files.append(f"{name}.ST")
|
||||||
|
|
||||||
|
cnt_num = 1
|
||||||
for profile in edge.reach.profiles:
|
for profile in edge.reach.profiles:
|
||||||
num = f"{profile.num:>6}"
|
num = f"{cnt_num:>6}"
|
||||||
c1 = f"{profile.code1:>6}"
|
c1 = f"{profile.code1:>6}"
|
||||||
c2 = f"{profile.code2:>6}"
|
c2 = f"{profile.code2:>6}"
|
||||||
t = f"{len(profile.points):>6}"
|
t = f"{len(profile.points):>6}"
|
||||||
kp = f"{profile.kp:>13.4f}"
|
kp = f"{profile.kp:>13.4f}"
|
||||||
name = profile.name
|
pname = profile.name
|
||||||
|
if profile.name == "":
|
||||||
|
pname = f"p{profile.id:>3}".replace(" ", "p")
|
||||||
|
name = f"{pname}"
|
||||||
|
|
||||||
f.write(f"{num}{c1}{c2}{t}{kp} {name}\n")
|
sediment = ""
|
||||||
|
if profile.sl is not None:
|
||||||
|
if not any(filter(lambda f: ".GRA" in f, files)):
|
||||||
|
files.append("0.GRA")
|
||||||
|
|
||||||
|
nl = len(profile.sl)
|
||||||
|
sediment = f" {nl:>3}"
|
||||||
|
for l in profile.sl.layers:
|
||||||
|
sediment += f" {l.height:>10} {l.d50:>10} {l.sigma:>10} {l.critical_constraint:>10}"
|
||||||
|
|
||||||
|
f.write(f"{num}{c1}{c2}{t}{kp} {name} {sediment}\n")
|
||||||
|
cnt_num += 1
|
||||||
|
|
||||||
for point in profile.points:
|
for point in profile.points:
|
||||||
x = f"{point.x:>13.4f}"
|
x = f"{point.x:>13.4f}"
|
||||||
y = f"{point.y:>13.4f}"
|
y = f"{point.y:>13.4f}"
|
||||||
z = f"{point.z:>13.4f}"
|
z = f"{point.z:>13.4f}"
|
||||||
n = point.name
|
n = f"{point.name:<3}"
|
||||||
|
|
||||||
f.write(f"{x}{y}{z} {n}\n")
|
sediment = ""
|
||||||
|
prev = point.z
|
||||||
|
if point.sl is not None:
|
||||||
|
nl = len(point.sl)
|
||||||
|
sediment = f"{nl:>3}"
|
||||||
|
for l in point.sl.layers:
|
||||||
|
prev = round(prev - l.height, 5)
|
||||||
|
sediment += f" {prev:>10} {l.d50:>10} {l.sigma:>10} {l.critical_constraint:>10}"
|
||||||
|
|
||||||
|
f.write(f"{x}{y}{z} {n} {sediment}\n")
|
||||||
|
|
||||||
f.write(f" 999.9990 999.9990 999.9990\n")
|
f.write(f" 999.9990 999.9990 999.9990\n")
|
||||||
|
|
||||||
@@ -170,7 +201,7 @@ class Mage(AbstractSolver):
|
|||||||
f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
|
f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
|
||||||
|
|
||||||
for d in bound.data:
|
for d in bound.data:
|
||||||
f.write(f"{d[0]:10.3f}{d[1]:10.3f}\n")
|
f.write(f"{d[0]:10}{d[1]:10}\n")
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@@ -182,6 +213,7 @@ class Mage(AbstractSolver):
|
|||||||
AVA = []
|
AVA = []
|
||||||
HYD = []
|
HYD = []
|
||||||
LIM = []
|
LIM = []
|
||||||
|
QSO = []
|
||||||
|
|
||||||
for tab in ["liquid", "solid", "suspenssion"]:
|
for tab in ["liquid", "solid", "suspenssion"]:
|
||||||
for bound in lst.get_tab(tab):
|
for bound in lst.get_tab(tab):
|
||||||
@@ -191,10 +223,13 @@ class Mage(AbstractSolver):
|
|||||||
HYD.append(bound)
|
HYD.append(bound)
|
||||||
elif bound.bctype == "TZ":
|
elif bound.bctype == "TZ":
|
||||||
LIM.append(bound)
|
LIM.append(bound)
|
||||||
|
elif bound.bctype == "SL":
|
||||||
|
QSO.append(bound)
|
||||||
|
|
||||||
files = files + self._export_BC("AVA", AVA, repertory, qlog)
|
files = files + self._export_BC("AVA", AVA, repertory, qlog)
|
||||||
files = files + self._export_BC("HYD", HYD, repertory, qlog)
|
files = files + self._export_BC("HYD", HYD, repertory, qlog)
|
||||||
files = files + self._export_BC("LIM", LIM, repertory, qlog)
|
files = files + self._export_BC("LIM", LIM, repertory, qlog)
|
||||||
|
files = files + self._export_QSO(QSO, repertory, qlog)
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@@ -332,12 +367,20 @@ class Mage(AbstractSolver):
|
|||||||
for file in files:
|
for file in files:
|
||||||
EXT = file.split('.')[1]
|
EXT = file.split('.')[1]
|
||||||
|
|
||||||
f.write(f"{EXT} {file}\n")
|
if EXT not in ["ST", "GRA"]:
|
||||||
|
f.write(f"{EXT} {file}\n")
|
||||||
|
|
||||||
f.write("* OUTPUT\n")
|
f.write("* OUTPUT\n")
|
||||||
f.write(f"TRA 0.TRA\n")
|
f.write(f"TRA 0.TRA\n")
|
||||||
f.write(f"BIN 0.BIN\n")
|
f.write(f"BIN 0.BIN\n")
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
EXT = file.split('.')[1]
|
||||||
|
|
||||||
|
if EXT in ["GRA"]:
|
||||||
|
f.write(f"{EXT} {file}\n")
|
||||||
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog = None):
|
||||||
self._export_ST(study, repertory, qlog)
|
self._export_ST(study, repertory, qlog)
|
||||||
@@ -404,6 +447,14 @@ class Mage8(Mage):
|
|||||||
# Export #
|
# Export #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
|
def cmd_args(self, study):
|
||||||
|
l = super(Mage8, self).cmd_args(study)
|
||||||
|
|
||||||
|
if study.river.has_sediment():
|
||||||
|
l.append("-c=3")
|
||||||
|
|
||||||
|
return l
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def _export_PAR(self, study, repertory, qlog = None):
|
def _export_PAR(self, study, repertory, qlog = None):
|
||||||
files = []
|
files = []
|
||||||
@@ -423,7 +474,6 @@ class Mage8(Mage):
|
|||||||
|
|
||||||
f.write(f"{name} {value}\n")
|
f.write(f"{name} {value}\n")
|
||||||
|
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
@@ -459,11 +509,37 @@ class Mage8(Mage):
|
|||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def _export_QSO(self, bounds, repertory, qlog):
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if len(bounds) == 0:
|
||||||
|
return files
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put(f"Export QSO file")
|
||||||
|
|
||||||
|
with mage_file_open(os.path.join(repertory, f"0.QSO"), "w+") as f:
|
||||||
|
files.append(f"0.QSO")
|
||||||
|
|
||||||
|
for bound in bounds:
|
||||||
|
name = f"{bound.node.id:3}".replace(" ", "x")
|
||||||
|
f.write(f"* {bound.node.name} ({name}) {bound.bctype}\n")
|
||||||
|
f.write(f"${name}\n")
|
||||||
|
header = bound.header
|
||||||
|
f.write(f"*{header[0]:>9}|{header[1]:>10}\n")
|
||||||
|
|
||||||
|
for d in bound.data:
|
||||||
|
f.write(f"{d[0]:10.3f}{d[1]:10.3f}\n")
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog = None):
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
self._export_ST(study, repertory, qlog)
|
files = self._export_ST(study, repertory, qlog)
|
||||||
files = files + self._export_PAR(study, repertory, qlog)
|
files = files + self._export_PAR(study, repertory, qlog)
|
||||||
files = files + self._export_NET(study, repertory, qlog)
|
files = files + self._export_NET(study, repertory, qlog)
|
||||||
files = files + self._export_bound_cond(study, repertory, qlog)
|
files = files + self._export_bound_cond(study, repertory, qlog)
|
||||||
@@ -477,6 +553,7 @@ class Mage8(Mage):
|
|||||||
# RESULTS #
|
# RESULTS #
|
||||||
###########
|
###########
|
||||||
|
|
||||||
|
@timer
|
||||||
def read_bin(self, study, repertory, results, qlog = None):
|
def read_bin(self, study, repertory, results, qlog = None):
|
||||||
logger.info(f"read_bin: Start ...")
|
logger.info(f"read_bin: Start ...")
|
||||||
|
|
||||||
@@ -597,3 +674,162 @@ class Mage8(Mage):
|
|||||||
logger.debug(reachs[0].profiles[0]._data)
|
logger.debug(reachs[0].profiles[0]._data)
|
||||||
results.set("timestamps", ts)
|
results.set("timestamps", ts)
|
||||||
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def read_gra(self, study, repertory, results, qlog = None):
|
||||||
|
if not study.river.has_sediment():
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(f"read_gra: Start ...")
|
||||||
|
|
||||||
|
with mage_file_open(os.path.join(repertory, f"0.GRA"), "r") as f:
|
||||||
|
newline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
||||||
|
endline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
||||||
|
|
||||||
|
read_int = lambda size: np.fromfile(f, dtype=np.int32, count=size)
|
||||||
|
read_float = lambda size: np.fromfile(f, dtype=np.float32, count=size)
|
||||||
|
read_float64 = lambda size: np.fromfile(f, dtype=np.float64, count=size)
|
||||||
|
|
||||||
|
# Meta data (1st line)
|
||||||
|
newline()
|
||||||
|
|
||||||
|
data = read_int(3)
|
||||||
|
|
||||||
|
nb_reach = data[0]
|
||||||
|
nb_profile = data[1]
|
||||||
|
mage_version = data[2]
|
||||||
|
|
||||||
|
logger.debug(f"read_gra: nb_reach = {nb_reach}")
|
||||||
|
logger.debug(f"read_gra: nb_profile = {nb_profile}")
|
||||||
|
logger.debug(f"read_gra: mage_version = {mage_version}")
|
||||||
|
|
||||||
|
if mage_version <= 80:
|
||||||
|
msg = (
|
||||||
|
"Read GRA files: " +
|
||||||
|
f"Possible incompatible mage version '{mage_version}', " +
|
||||||
|
"please check your solver configuration..."
|
||||||
|
)
|
||||||
|
logger.warning(msg)
|
||||||
|
|
||||||
|
if qlog is not None:
|
||||||
|
qlog.put("[WARNING] " + msg)
|
||||||
|
|
||||||
|
results.set("gra_solver_version", f"Mage8 ({mage_version})")
|
||||||
|
results.set("gra_nb_reach", f"{nb_reach}")
|
||||||
|
results.set("gra_nb_profile", f"{nb_profile}")
|
||||||
|
|
||||||
|
endline()
|
||||||
|
|
||||||
|
# Reach information (2nd line)
|
||||||
|
newline()
|
||||||
|
|
||||||
|
reachs = []
|
||||||
|
iprofiles = {}
|
||||||
|
reach_offset = {}
|
||||||
|
|
||||||
|
data = read_int(2*nb_reach)
|
||||||
|
|
||||||
|
for i in range(nb_reach):
|
||||||
|
# Get results reach to reach list
|
||||||
|
r = results.river.reach(i)
|
||||||
|
reachs.append(r)
|
||||||
|
|
||||||
|
# ID of first and last reach profiles
|
||||||
|
i1 = data[2*i] - 1
|
||||||
|
i2 = data[2*i+1] - 1
|
||||||
|
|
||||||
|
# Add profile id correspondance to reach
|
||||||
|
key = (i1, i2)
|
||||||
|
iprofiles[key] = r
|
||||||
|
|
||||||
|
# Profile ID offset
|
||||||
|
reach_offset[r] = i1
|
||||||
|
|
||||||
|
logger.debug(f"read_gra: iprofiles = {iprofiles}")
|
||||||
|
|
||||||
|
endline()
|
||||||
|
|
||||||
|
# X (3rd line)
|
||||||
|
newline()
|
||||||
|
_ = read_float(nb_profile)
|
||||||
|
endline()
|
||||||
|
|
||||||
|
# npts (4th line)
|
||||||
|
newline()
|
||||||
|
_ = read_int(nb_profile)
|
||||||
|
endline()
|
||||||
|
|
||||||
|
# Data
|
||||||
|
ip_to_r = lambda i: iprofiles[
|
||||||
|
next(
|
||||||
|
filter(
|
||||||
|
lambda k: k[0] <= i <= k[1],
|
||||||
|
iprofiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
ip_to_ri = lambda r, i: i - reach_offset[r]
|
||||||
|
|
||||||
|
ts = set()
|
||||||
|
ind = 0
|
||||||
|
end = False
|
||||||
|
|
||||||
|
newline()
|
||||||
|
while not end:
|
||||||
|
n = read_int(1)[0]
|
||||||
|
timestamp = read_float64(1)[0]
|
||||||
|
|
||||||
|
logger.debug(f"read_gra: timestamp = {timestamp} sec")
|
||||||
|
ts.add(timestamp)
|
||||||
|
|
||||||
|
endline()
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
newline()
|
||||||
|
nsl = read_int(1)[0]
|
||||||
|
endline()
|
||||||
|
|
||||||
|
# Get current profile id
|
||||||
|
reach = ip_to_r(i)
|
||||||
|
ri = ip_to_ri(reach, i)
|
||||||
|
|
||||||
|
if nsl > 1:
|
||||||
|
logger.warning(
|
||||||
|
"read_gra: " +
|
||||||
|
"Multiple sediment layers for one profile " +
|
||||||
|
"is not implemented yet..."
|
||||||
|
)
|
||||||
|
|
||||||
|
for j in range(nsl):
|
||||||
|
newline()
|
||||||
|
nl = read_int(1)[0]
|
||||||
|
endline()
|
||||||
|
|
||||||
|
sl = []
|
||||||
|
|
||||||
|
for k in range(nl):
|
||||||
|
newline()
|
||||||
|
data = read_float64(3)
|
||||||
|
endline()
|
||||||
|
|
||||||
|
h = data[0]
|
||||||
|
d50 = data[1]
|
||||||
|
sigma = data[2]
|
||||||
|
|
||||||
|
sl.append((h, d50, sigma))
|
||||||
|
|
||||||
|
reach.set(ri, timestamp, "sl", sl)
|
||||||
|
|
||||||
|
ind += 1
|
||||||
|
end = newline().size <= 0
|
||||||
|
|
||||||
|
logger.debug(reachs[0].profiles[0]._data)
|
||||||
|
results.set("timestamps", ts)
|
||||||
|
logger.info(f"read_gra: ... end with {len(ts)} timestamp read")
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def results(self, study, repertory, qlog = None):
|
||||||
|
results = super(Mage8, self).results(study, repertory, qlog)
|
||||||
|
self.read_gra(study, repertory, results, qlog)
|
||||||
|
|
||||||
|
return results
|
||||||
@@ -26,5 +26,6 @@ table_headers = {
|
|||||||
"time": _translate("BoundaryCondition", "Time"),
|
"time": _translate("BoundaryCondition", "Time"),
|
||||||
"date": _translate("BoundaryCondition", "Date"),
|
"date": _translate("BoundaryCondition", "Date"),
|
||||||
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
|
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
|
||||||
"z": _translate("BoundaryCondition", "Z (m)")
|
"z": _translate("BoundaryCondition", "Z (m)"),
|
||||||
|
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,8 @@ from PyQt5.QtCore import QCoreApplication
|
|||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||||
NotDefined, PonctualContribution,
|
NotDefined, PonctualContribution,
|
||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
TimeOverZ, TimeOverDischarge, ZOverDischarge,
|
||||||
|
Solid
|
||||||
)
|
)
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
@@ -31,6 +32,7 @@ long_types = {
|
|||||||
"TZ": _translate("BoundaryCondition", "Time over Z"),
|
"TZ": _translate("BoundaryCondition", "Time over Z"),
|
||||||
"TD": _translate("BoundaryCondition", "Time over Discharge"),
|
"TD": _translate("BoundaryCondition", "Time over Discharge"),
|
||||||
"ZD": _translate("BoundaryCondition", "Z over Discharge"),
|
"ZD": _translate("BoundaryCondition", "Z over Discharge"),
|
||||||
|
"SL": _translate("BoundaryCondition", "Solid"),
|
||||||
}
|
}
|
||||||
|
|
||||||
table_headers = {
|
table_headers = {
|
||||||
@@ -44,5 +46,6 @@ BC_types = {
|
|||||||
"PC": PonctualContribution,
|
"PC": PonctualContribution,
|
||||||
"TZ": TimeOverZ,
|
"TZ": TimeOverZ,
|
||||||
"TD": TimeOverDischarge,
|
"TD": TimeOverDischarge,
|
||||||
"ZD": ZOverDischarge
|
"ZD": ZOverDischarge,
|
||||||
|
"SL": Solid,
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ from View.Frictions.Table import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
from View.Geometry.PlotKPC import PlotKPC
|
from View.Geometry.PlotKPZ import PlotKPZ
|
||||||
from View.Frictions.PlotStricklers import PlotStricklers
|
from View.Frictions.PlotStricklers import PlotStricklers
|
||||||
from View.Frictions.translate import *
|
from View.Frictions.translate import *
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
|
||||||
self.plot_layout.addWidget(self.canvas)
|
self.plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
self.plot = PlotKPC(
|
self.plot = PlotKPZ(
|
||||||
canvas = self.canvas,
|
canvas = self.canvas,
|
||||||
data = self._reach.reach,
|
data = self._reach.reach,
|
||||||
toolbar = None,
|
toolbar = None,
|
||||||
@@ -193,7 +193,7 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
sec = self._frictions.get(rows[0])
|
sec = self._frictions.get(rows[0])
|
||||||
highlight = (sec.begin_kp, sec.end_kp)
|
highlight = (sec.begin_kp, sec.end_kp)
|
||||||
|
|
||||||
self.plot = PlotKPC(
|
self.plot = PlotKPZ(
|
||||||
canvas = self.canvas,
|
canvas = self.canvas,
|
||||||
data = reach,
|
data = reach,
|
||||||
toolbar = None,
|
toolbar = None,
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ _translate = QCoreApplication.translate
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class PlotKPC(APlot):
|
class PlotKPZ(APlot):
|
||||||
def __init__(self, canvas=None, data=None, toolbar=None,
|
def __init__(self, canvas=None, data=None, toolbar=None,
|
||||||
display_current=True):
|
display_current=True):
|
||||||
super(PlotKPC, self).__init__(
|
super(PlotKPZ, self).__init__(
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
data=data,
|
data=data,
|
||||||
toolbar=toolbar
|
toolbar=toolbar
|
||||||
@@ -64,7 +64,7 @@ class PlotKPC(APlot):
|
|||||||
color='green', fontsize=12
|
color='green', fontsize=12
|
||||||
)
|
)
|
||||||
self.canvas.axes.set_ylabel(
|
self.canvas.axes.set_ylabel(
|
||||||
_translate("MainWindow_reach", "Cote (m)"),
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
color='green', fontsize=12
|
color='green', fontsize=12
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ class PlotKPC(APlot):
|
|||||||
kp, z_complete[i]
|
kp, z_complete[i]
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to update graphic KPC: {e}")
|
logger.warning(f"Failed to update graphic KPZ: {e}")
|
||||||
|
|
||||||
self.canvas.axes.autoscale_view(True, True, True)
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
self.canvas.figure.canvas.draw_idle()
|
self.canvas.figure.canvas.draw_idle()
|
||||||
@@ -38,7 +38,7 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Geometry.PlotXY import PlotXY
|
from View.Geometry.PlotXY import PlotXY
|
||||||
from View.Geometry.PlotKPC import PlotKPC
|
from View.Geometry.PlotKPZ import PlotKPZ
|
||||||
from View.Geometry.PlotAC import PlotAC
|
from View.Geometry.PlotAC import PlotAC
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, WindowToolKit
|
from View.ASubWindow import ASubMainWindow, WindowToolKit
|
||||||
@@ -230,7 +230,7 @@ class GeometryWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def plot_kpc(self):
|
def plot_kpc(self):
|
||||||
self.tableView.model().blockSignals(True)
|
self.tableView.model().blockSignals(True)
|
||||||
|
|
||||||
self._plot_kpc = PlotKPC(
|
self._plot_kpc = PlotKPZ(
|
||||||
canvas = self.ui.canvas_2,
|
canvas = self.ui.canvas_2,
|
||||||
data = self._reach,
|
data = self._reach,
|
||||||
toolbar = self.ui.toolbar_2
|
toolbar = self.ui.toolbar_2
|
||||||
|
|||||||
+39
-1
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import subprocess
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
@@ -49,6 +50,8 @@ from View.LateralContribution.Window import LateralContributionWindow
|
|||||||
from View.InitialConditions.Window import InitialConditionsWindow
|
from View.InitialConditions.Window import InitialConditionsWindow
|
||||||
from View.Stricklers.Window import StricklersWindow
|
from View.Stricklers.Window import StricklersWindow
|
||||||
from View.Frictions.Window import FrictionsWindow
|
from View.Frictions.Window import FrictionsWindow
|
||||||
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
|
from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
|
||||||
from View.SolverParameters.Window import SolverParametersWindow
|
from View.SolverParameters.Window import SolverParametersWindow
|
||||||
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
|
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
|
||||||
from View.CheckList.Window import CheckListWindow
|
from View.CheckList.Window import CheckListWindow
|
||||||
@@ -87,7 +90,8 @@ define_model_action = [
|
|||||||
"action_menu_edit_network", "action_menu_edit_geometry",
|
"action_menu_edit_network", "action_menu_edit_geometry",
|
||||||
"action_menu_boundary_conditions", "action_menu_initial_conditions",
|
"action_menu_boundary_conditions", "action_menu_initial_conditions",
|
||||||
"action_menu_edit_friction", "action_menu_edit_lateral_contribution",
|
"action_menu_edit_friction", "action_menu_edit_lateral_contribution",
|
||||||
"action_menu_run_solver",
|
"action_menu_run_solver", "action_menu_sediment_layers",
|
||||||
|
"action_menu_edit_reach_sediment_layers"
|
||||||
]
|
]
|
||||||
|
|
||||||
action = (
|
action = (
|
||||||
@@ -170,6 +174,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
"action_menu_edit_friction": self.open_frictions,
|
"action_menu_edit_friction": self.open_frictions,
|
||||||
"action_menu_edit_lateral_contribution": self.open_lateral_contrib,
|
"action_menu_edit_lateral_contribution": self.open_lateral_contrib,
|
||||||
"action_menu_run_solver": self.run_solver,
|
"action_menu_run_solver": self.run_solver,
|
||||||
|
"action_menu_sediment_layers": self.open_sediment_layers,
|
||||||
|
"action_menu_edit_reach_sediment_layers": self.open_reach_sediment_layers,
|
||||||
## Help
|
## Help
|
||||||
"action_menu_about": self.open_about,
|
"action_menu_about": self.open_about,
|
||||||
# ToolBar action
|
# ToolBar action
|
||||||
@@ -258,15 +264,22 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
self.debug_action.setStatusTip("Debug")
|
self.debug_action.setStatusTip("Debug")
|
||||||
self.debug_action.triggered.connect(self.open_debug)
|
self.debug_action.triggered.connect(self.open_debug)
|
||||||
|
|
||||||
|
self.debug_sqlite_action = QAction("Debug SQLite", self)
|
||||||
|
self.debug_sqlite_action.setStatusTip("Open SQLite debuging tool (sqlitebrowser)")
|
||||||
|
self.debug_sqlite_action.triggered.connect(self.open_sqlite)
|
||||||
|
|
||||||
if self.conf.debug:
|
if self.conf.debug:
|
||||||
menu.addAction(self.debug_action)
|
menu.addAction(self.debug_action)
|
||||||
|
menu.addAction(self.debug_sqlite_action)
|
||||||
self.set_debug_lvl(debug = True)
|
self.set_debug_lvl(debug = True)
|
||||||
else:
|
else:
|
||||||
if self.conf.debug:
|
if self.conf.debug:
|
||||||
menu.addAction(self.debug_action)
|
menu.addAction(self.debug_action)
|
||||||
|
menu.addAction(self.debug_sqlite_action)
|
||||||
self.set_debug_lvl(debug = True)
|
self.set_debug_lvl(debug = True)
|
||||||
else:
|
else:
|
||||||
menu.removeAction(self.debug_action)
|
menu.removeAction(self.debug_action)
|
||||||
|
menu.removeAction(self.debug_sqlite_action)
|
||||||
self.set_debug_lvl(debug = False)
|
self.set_debug_lvl(debug = False)
|
||||||
|
|
||||||
#########
|
#########
|
||||||
@@ -617,6 +630,20 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
else:
|
else:
|
||||||
params.activateWindow()
|
params.activateWindow()
|
||||||
|
|
||||||
|
def open_sediment_layers(self):
|
||||||
|
sl = SedimentLayersWindow(
|
||||||
|
study = self.model,
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
sl.show()
|
||||||
|
|
||||||
|
def open_reach_sediment_layers(self):
|
||||||
|
sl = ReachSedimentLayersWindow(
|
||||||
|
study = self.model,
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
sl.show()
|
||||||
|
|
||||||
def run_solver(self):
|
def run_solver(self):
|
||||||
if self.model is None:
|
if self.model is None:
|
||||||
return
|
return
|
||||||
@@ -683,6 +710,17 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||||||
)
|
)
|
||||||
repl.show()
|
repl.show()
|
||||||
|
|
||||||
|
def open_sqlite(self):
|
||||||
|
if self.model is None:
|
||||||
|
logger.debug("No study open for sql debuging...")
|
||||||
|
return
|
||||||
|
|
||||||
|
file = self.model.filename
|
||||||
|
_ = subprocess.Popen(
|
||||||
|
f"sqlitebrowser {file}",
|
||||||
|
shell=True
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: Delete me !
|
# TODO: Delete me !
|
||||||
###############
|
###############
|
||||||
# DUMMY STUFF #
|
# DUMMY STUFF #
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
from View.Plot.APlot import APlot
|
from View.Plot.APlot import APlot
|
||||||
@@ -34,14 +35,14 @@ logger = logging.getLogger()
|
|||||||
class PlotH(APlot):
|
class PlotH(APlot):
|
||||||
def __init__(self, canvas=None, results=None,
|
def __init__(self, canvas=None, results=None,
|
||||||
reach_id=0, profile_id=0,
|
reach_id=0, profile_id=0,
|
||||||
toolbar=None, display_current=True):
|
toolbar=None):
|
||||||
super(PlotH, self).__init__(
|
super(PlotH, self).__init__(
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
data=results,
|
data=results,
|
||||||
toolbar=toolbar
|
toolbar=toolbar
|
||||||
)
|
)
|
||||||
|
|
||||||
self.display_current = display_current
|
self._mode = "time"
|
||||||
|
|
||||||
self._current_timestamp = max(results.get("timestamps"))
|
self._current_timestamp = max(results.get("timestamps"))
|
||||||
self._current_reach_id = reach_id
|
self._current_reach_id = reach_id
|
||||||
@@ -99,6 +100,10 @@ class PlotH(APlot):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.canvas.axes.set_ylim(
|
||||||
|
[min(min(y),0), max(y)]
|
||||||
|
)
|
||||||
|
|
||||||
self._line = [
|
self._line = [
|
||||||
self.canvas.axes.plot(
|
self.canvas.axes.plot(
|
||||||
x, y, lw=1.,
|
x, y, lw=1.,
|
||||||
@@ -107,8 +112,47 @@ class PlotH(APlot):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
self.canvas.axes.autoscale_view(True, True, True)
|
# Custom time display
|
||||||
self.canvas.axes.autoscale()
|
nb = len(x)
|
||||||
|
mod = int(nb / 5)
|
||||||
|
mod = mod if mod > 0 else nb
|
||||||
|
|
||||||
|
fx = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] % mod == 0,
|
||||||
|
enumerate(x)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._mode == "time":
|
||||||
|
t0 = datetime.fromtimestamp(0)
|
||||||
|
xt = list(
|
||||||
|
map(
|
||||||
|
lambda v: (
|
||||||
|
str(
|
||||||
|
datetime.fromtimestamp(v) - t0
|
||||||
|
).split(",")[0]\
|
||||||
|
.replace("days", _translate("Results", "days"))\
|
||||||
|
.replace("day", _translate("Results", "day"))
|
||||||
|
),
|
||||||
|
fx
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
xt = list(
|
||||||
|
map(
|
||||||
|
lambda v: str(datetime.fromtimestamp(v).date()),
|
||||||
|
fx
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.axes.set_xticks(ticks=fx, labels=xt, rotation=45)
|
||||||
|
|
||||||
|
# self.canvas.axes.autoscale_view(True, True, True)
|
||||||
|
# self.canvas.axes.autoscale()
|
||||||
self.canvas.figure.tight_layout()
|
self.canvas.figure.tight_layout()
|
||||||
self.canvas.figure.canvas.draw_idle()
|
self.canvas.figure.canvas.draw_idle()
|
||||||
if self.toolbar is not None:
|
if self.toolbar is not None:
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import timer
|
||||||
|
from View.Plot.APlot import APlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class PlotSedProfile(APlot):
|
||||||
|
def __init__(self, canvas=None, study=None, results=None,
|
||||||
|
reach_id=0, profile_id=0,
|
||||||
|
toolbar=None):
|
||||||
|
super(PlotSedProfile, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
data=study,
|
||||||
|
toolbar=toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
self._results = results
|
||||||
|
|
||||||
|
self._current_timestamp = max(results.get("timestamps"))
|
||||||
|
self._current_reach_id = reach_id
|
||||||
|
self._current_profile_id = profile_id
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.canvas.axes.cla()
|
||||||
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
if self.data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
reach = self._results.river.reach(self._current_reach_id)
|
||||||
|
profile = reach.profile(self._current_profile_id)
|
||||||
|
if profile.geometry.number_points == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlabel(
|
||||||
|
_translate("MainWindow_reach", "X (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
self.canvas.axes.set_ylabel(
|
||||||
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
|
||||||
|
x = profile.geometry.get_station()
|
||||||
|
z = profile.geometry.z()
|
||||||
|
|
||||||
|
psl = list(
|
||||||
|
map(
|
||||||
|
lambda sl: sl[0],
|
||||||
|
profile.get_ts_key(self._current_timestamp, "sl")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
sl = []
|
||||||
|
for i in range(len(psl)):
|
||||||
|
cur = []
|
||||||
|
for p in range(profile.geometry.number_points):
|
||||||
|
cur.append(psl[i])
|
||||||
|
sl.append(cur)
|
||||||
|
|
||||||
|
# logger.info(sl)
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlim(
|
||||||
|
left = min(x), right = max(x)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Compute sediment layer in function to point z
|
||||||
|
z_sl = reduce(
|
||||||
|
lambda acc, v: acc + [
|
||||||
|
list(
|
||||||
|
map(lambda x, y: y - x, v, acc[-1])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
sl,
|
||||||
|
[z]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.line_kp_sl = []
|
||||||
|
for i, zsl in enumerate(reversed(z_sl)):
|
||||||
|
self.line_kp_sl.append(None)
|
||||||
|
self.line_kp_sl[i], = self.canvas.axes.plot(
|
||||||
|
x, zsl,
|
||||||
|
linestyle="solid" if i == len(z_sl) - 1 else "--",
|
||||||
|
lw=1.8,
|
||||||
|
color='grey' if i == len(z_sl) - 1 else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.figure.tight_layout()
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
if self.toolbar is not None:
|
||||||
|
self.toolbar.update()
|
||||||
|
|
||||||
|
self._init = False
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if self._init == False:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
if ind is None:
|
||||||
|
logger.info("TODO: Update")
|
||||||
|
|
||||||
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
|
||||||
|
def set_reach(self, reach_id):
|
||||||
|
self._current_reach_id = reach_id
|
||||||
|
self._current_profile_id = 0
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
def set_profile(self, profile_id):
|
||||||
|
self._current_profile_id = profile_id
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
def set_timestamp(self, timestamp):
|
||||||
|
self._current_timestamp = timestamp
|
||||||
|
self.draw()
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import timer
|
||||||
|
from View.Plot.APlot import APlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class PlotSedReach(APlot):
|
||||||
|
def __init__(self, canvas=None, study=None, results=None,
|
||||||
|
reach_id=0, profile_id=0,
|
||||||
|
toolbar=None):
|
||||||
|
super(PlotSedReach, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
data=study,
|
||||||
|
toolbar=toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
self._results = results
|
||||||
|
|
||||||
|
self._current_timestamp = max(results.get("timestamps"))
|
||||||
|
self._current_reach_id = reach_id
|
||||||
|
self._current_profile_id = profile_id
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.canvas.axes.cla()
|
||||||
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
if self.data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
reach = self._results.river.reach(self._current_reach_id)
|
||||||
|
if reach.geometry.number_profiles == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlabel(
|
||||||
|
_translate("MainWindow_reach", "Kp (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
self.canvas.axes.set_ylabel(
|
||||||
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
|
||||||
|
kp = reach.geometry.get_kp()
|
||||||
|
z_min = reach.geometry.get_z_min()
|
||||||
|
z_max = reach.geometry.get_z_max()
|
||||||
|
|
||||||
|
psl = list(
|
||||||
|
map(
|
||||||
|
# Get SL list for profile p
|
||||||
|
lambda p: p.get_ts_key(self._current_timestamp, "sl"),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
max_sl = reduce(
|
||||||
|
lambda acc, sl: max(acc, len(sl)),
|
||||||
|
psl,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
sl = []
|
||||||
|
for i in range(max_sl):
|
||||||
|
cur = []
|
||||||
|
for csl in psl:
|
||||||
|
if i < len(csl):
|
||||||
|
cur.append(csl[i][0])
|
||||||
|
else:
|
||||||
|
cur.append(0)
|
||||||
|
sl.append(cur)
|
||||||
|
|
||||||
|
# logger.info(f"sl = {sl}")
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlim(
|
||||||
|
left = min(kp), right = max(kp)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Compute sediment layer in function to profile z_min
|
||||||
|
z_sl = reduce(
|
||||||
|
lambda acc, v: acc + [
|
||||||
|
list(
|
||||||
|
map(lambda x, y: y - x, v, acc[-1])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
sl,
|
||||||
|
[z_min]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.line_kp_sl = []
|
||||||
|
for i, z in enumerate(reversed(z_sl)):
|
||||||
|
self.line_kp_sl.append(None)
|
||||||
|
self.line_kp_sl[i], = self.canvas.axes.plot(
|
||||||
|
kp, z,
|
||||||
|
linestyle="solid" if i == len(z_sl) - 1 else "--",
|
||||||
|
lw=1.8,
|
||||||
|
color='grey' if i == len(z_sl) - 1 else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.figure.tight_layout()
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
if self.toolbar is not None:
|
||||||
|
self.toolbar.update()
|
||||||
|
|
||||||
|
self._init = False
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if self._init == False:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
def set_reach(self, reach_id):
|
||||||
|
self._current_reach_id = reach_id
|
||||||
|
self._current_profile_id = 0
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
def set_profile(self, profile_id):
|
||||||
|
self._current_profile_id = profile_id
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
def set_timestamp(self, timestamp):
|
||||||
|
self._current_timestamp = timestamp
|
||||||
|
self.draw()
|
||||||
@@ -46,6 +46,8 @@ from View.Results.PlotXY import PlotXY
|
|||||||
from View.Results.PlotAC import PlotAC
|
from View.Results.PlotAC import PlotAC
|
||||||
from View.Results.PlotKPC import PlotKPC
|
from View.Results.PlotKPC import PlotKPC
|
||||||
from View.Results.PlotH import PlotH
|
from View.Results.PlotH import PlotH
|
||||||
|
from View.Results.PlotSedReach import PlotSedReach
|
||||||
|
from View.Results.PlotSedProfile import PlotSedProfile
|
||||||
|
|
||||||
from View.Results.Table import TableModel
|
from View.Results.Table import TableModel
|
||||||
from View.Results.translate import *
|
from View.Results.translate import *
|
||||||
@@ -180,6 +182,38 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
)
|
)
|
||||||
self.plot_h.draw()
|
self.plot_h.draw()
|
||||||
|
|
||||||
|
self.canvas_5 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas_5.setObjectName("canvas_5")
|
||||||
|
self.plot_layout_5 = self.find(QVBoxLayout, "verticalLayout_sed_reach")
|
||||||
|
self.plot_layout_5.addWidget(self.canvas_5)
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_reach = PlotSedReach(
|
||||||
|
canvas = self.canvas_5,
|
||||||
|
results = self._results,
|
||||||
|
study = self._study,
|
||||||
|
reach_id = 0,
|
||||||
|
profile_id = 0,
|
||||||
|
toolbar = None
|
||||||
|
)
|
||||||
|
self.plot_sed_reach.draw()
|
||||||
|
|
||||||
|
self.canvas_6 = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas_6.setObjectName("canvas_6")
|
||||||
|
self.plot_layout_6 = self.find(QVBoxLayout, "verticalLayout_sed_profile")
|
||||||
|
self.plot_layout_6.addWidget(self.canvas_6)
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_profile = PlotSedProfile(
|
||||||
|
canvas = self.canvas_6,
|
||||||
|
results = self._results,
|
||||||
|
study = self._study,
|
||||||
|
reach_id = 0,
|
||||||
|
profile_id = 0,
|
||||||
|
toolbar = None
|
||||||
|
)
|
||||||
|
self.plot_sed_profile.draw()
|
||||||
|
|
||||||
def setup_connections(self):
|
def setup_connections(self):
|
||||||
self.undo_sc.activated.connect(self.undo)
|
self.undo_sc.activated.connect(self.undo)
|
||||||
self.redo_sc.activated.connect(self.redo)
|
self.redo_sc.activated.connect(self.redo)
|
||||||
@@ -210,22 +244,38 @@ class ResultsWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.plot_ac.set_reach(reach_id)
|
self.plot_ac.set_reach(reach_id)
|
||||||
self.plot_kpc.set_reach(reach_id)
|
self.plot_kpc.set_reach(reach_id)
|
||||||
self.plot_h.set_reach(reach_id)
|
self.plot_h.set_reach(reach_id)
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_reach.set_reach(reach_id)
|
||||||
|
self.plot_sed_profile.set_reach(reach_id)
|
||||||
if profile_id is not None:
|
if profile_id is not None:
|
||||||
self.plot_xy.set_profile(profile_id)
|
self.plot_xy.set_profile(profile_id)
|
||||||
self.plot_ac.set_profile(profile_id)
|
self.plot_ac.set_profile(profile_id)
|
||||||
self.plot_kpc.set_profile(profile_id)
|
self.plot_kpc.set_profile(profile_id)
|
||||||
self.plot_h.set_profile(profile_id)
|
self.plot_h.set_profile(profile_id)
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_reach.set_profile(profile_id)
|
||||||
|
self.plot_sed_profile.set_profile(profile_id)
|
||||||
if timestamp is not None:
|
if timestamp is not None:
|
||||||
self.plot_xy.set_timestamp(timestamp)
|
self.plot_xy.set_timestamp(timestamp)
|
||||||
self.plot_ac.set_timestamp(timestamp)
|
self.plot_ac.set_timestamp(timestamp)
|
||||||
self.plot_kpc.set_timestamp(timestamp)
|
self.plot_kpc.set_timestamp(timestamp)
|
||||||
self.plot_h.set_timestamp(timestamp)
|
self.plot_h.set_timestamp(timestamp)
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_reach.set_timestamp(timestamp)
|
||||||
|
self.plot_sed_profile.set_timestamp(timestamp)
|
||||||
|
|
||||||
self.plot_xy.draw()
|
self.plot_xy.draw()
|
||||||
self.plot_ac.draw()
|
self.plot_ac.draw()
|
||||||
self.plot_kpc.draw()
|
self.plot_kpc.draw()
|
||||||
self.plot_h.draw()
|
self.plot_h.draw()
|
||||||
|
|
||||||
|
if self._study.river.has_sediment():
|
||||||
|
self.plot_sed_reach.draw()
|
||||||
|
self.plot_sed_profile.draw()
|
||||||
|
|
||||||
|
|
||||||
def _set_current_reach(self):
|
def _set_current_reach(self):
|
||||||
table = self.find(QTableView, f"tableView_reach")
|
table = self.find(QTableView, f"tableView_reach")
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self._log(f" *** Run solver {self._solver.name}", color="blue")
|
self._log(f" *** Run solver {self._solver.name}", color="blue")
|
||||||
self._solver.run(
|
self._solver.run(
|
||||||
|
study,
|
||||||
process = self._process,
|
process = self._process,
|
||||||
output_queue = self._output
|
output_queue = self._output
|
||||||
)
|
)
|
||||||
@@ -220,7 +221,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self._log(" *** Start", color="blue")
|
self._log(" *** Start", color="blue")
|
||||||
self._results = None
|
self._results = None
|
||||||
self._solver.start(self._process)
|
self._solver.start(self._study, process = self._process)
|
||||||
|
|
||||||
self.find(QAction, "action_start").setEnabled(False)
|
self.find(QAction, "action_start").setEnabled(False)
|
||||||
if _signal:
|
if _signal:
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import timer
|
||||||
|
from View.Plot.APlot import APlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class Plot(APlot):
|
||||||
|
def __init__(self, canvas=None, data=None, toolbar=None,
|
||||||
|
display_current=True):
|
||||||
|
super(Plot, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
data=data,
|
||||||
|
toolbar=toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
self._display_current = display_current
|
||||||
|
|
||||||
|
self.line_kp_zmin = None
|
||||||
|
self.line_kp_sl = []
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.canvas.axes.cla()
|
||||||
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
# self.canvas.axes.set_xlabel(
|
||||||
|
# _translate("MainWindow_reach", "X (m)"),
|
||||||
|
# color='green', fontsize=12
|
||||||
|
# )
|
||||||
|
self.canvas.axes.axes.get_xaxis().set_visible(False)
|
||||||
|
self.canvas.axes.set_ylabel(
|
||||||
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
x = [0,1]
|
||||||
|
z = [0,0]
|
||||||
|
sl = self.data.height()
|
||||||
|
names = ["bottom"] + self.data.names()
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlim(
|
||||||
|
left = min(x), right = max(x)
|
||||||
|
)
|
||||||
|
|
||||||
|
lsl = []
|
||||||
|
for i in range(len(sl)):
|
||||||
|
cur = []
|
||||||
|
for _ in x:
|
||||||
|
cur.append(sl[i])
|
||||||
|
lsl.append(cur)
|
||||||
|
|
||||||
|
# Compute sediment layer in function to point z
|
||||||
|
z_sl = reduce(
|
||||||
|
lambda acc, v: acc + [
|
||||||
|
list(
|
||||||
|
map(lambda x, y: y - x, v, acc[-1])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
lsl,
|
||||||
|
[z]
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, zsl in enumerate(reversed(z_sl)):
|
||||||
|
self.line_kp_sl.append(None)
|
||||||
|
self.line_kp_sl[i], = self.canvas.axes.plot(
|
||||||
|
x, zsl,
|
||||||
|
label=names[-(i+1)],
|
||||||
|
linestyle="solid" if i == len(names) - 1 else "--",
|
||||||
|
lw=1.8,
|
||||||
|
color='grey' if i == len(names) - 1 else None
|
||||||
|
)
|
||||||
|
self.canvas.axes.text(x[0] + 0.01, zsl[0] + 0.01, f'{names[-(i+1)]}')
|
||||||
|
|
||||||
|
self.canvas.figure.tight_layout()
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
if self.toolbar is not None:
|
||||||
|
self.toolbar.update()
|
||||||
|
|
||||||
|
self._init = True
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if self._init == False:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
if ind is None:
|
||||||
|
logger.info("TODO: Update")
|
||||||
|
|
||||||
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Edit.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Edit.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class TableModel(QAbstractTableModel):
|
||||||
|
def __init__(self, study=None, sl=None, undo=None):
|
||||||
|
super(QAbstractTableModel, self).__init__()
|
||||||
|
self._headers = list(table_headers.keys())
|
||||||
|
self._study = study
|
||||||
|
self._undo = undo
|
||||||
|
self._sl = sl
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||||
|
options |= Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._sl)
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return len(self._headers)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
return self._sl.get(row).name
|
||||||
|
elif self._headers[column] == "type":
|
||||||
|
return self._sl.get(row).type
|
||||||
|
elif self._headers[column] == "height":
|
||||||
|
return self._sl.get(row).height
|
||||||
|
elif self._headers[column] == "d50":
|
||||||
|
return self._sl.get(row).d50
|
||||||
|
elif self._headers[column] == "sigma":
|
||||||
|
return self._sl.get(row).sigma
|
||||||
|
elif self._headers[column] == "critical_constraint":
|
||||||
|
return self._sl.get(row).critical_constraint
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def headerData(self, friction, orientation, role):
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||||
|
return table_headers[self._headers[friction]]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
|
return False
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
self._undo.push(
|
||||||
|
SetNameCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "type":
|
||||||
|
self._undo.push(
|
||||||
|
SetTypeCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "height":
|
||||||
|
self._undo.push(
|
||||||
|
SetHeightCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "d50":
|
||||||
|
self._undo.push(
|
||||||
|
SetD50Command(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "sigma":
|
||||||
|
self._undo.push(
|
||||||
|
SetSigmaCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "critical_constraint":
|
||||||
|
self._undo.push(
|
||||||
|
SetCriticalConstraintCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def add(self, row, parent=QModelIndex()):
|
||||||
|
self.beginInsertRows(parent, row, row - 1)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
AddCommand(
|
||||||
|
self._sl, row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endInsertRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def delete(self, rows, parent=QModelIndex()):
|
||||||
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
DelCommand(
|
||||||
|
self._sl, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def move_up(self, row, parent=QModelIndex()):
|
||||||
|
if row <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
target = row + 2
|
||||||
|
|
||||||
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._sl, "up", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endMoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def move_down(self, row, parent=QModelIndex()):
|
||||||
|
if row + 1 >= len(self._sl):
|
||||||
|
return
|
||||||
|
|
||||||
|
target = row
|
||||||
|
|
||||||
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._sl, "down", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endMoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
||||||
|
|
||||||
|
class SetNameCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).name
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).name = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).name = self._new
|
||||||
|
|
||||||
|
class SetTypeCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).type
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).type = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).type = self._new
|
||||||
|
|
||||||
|
class SetHeightCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).height
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).height = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).height = self._new
|
||||||
|
|
||||||
|
class SetD50Command(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).d50
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).d50 = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).d50 = self._new
|
||||||
|
|
||||||
|
class SetSigmaCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).sigma
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).sigma = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).sigma = self._new
|
||||||
|
|
||||||
|
class SetCriticalConstraintCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers.get(self._index).critical_constraint
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.get(self._index).critical_constraint = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.get(self._index).critical_constraint = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers.delete_i([self._index])
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._sediment_layers.new(self._index)
|
||||||
|
else:
|
||||||
|
self._sediment_layers.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._rows = rows
|
||||||
|
|
||||||
|
self._sl_pos = []
|
||||||
|
for row in rows:
|
||||||
|
self._sl_pos.append((row, self._sediment_layers.get(row)))
|
||||||
|
self._sl_pos.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._sl_pos:
|
||||||
|
self._sediment_layers.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers.delete_i(self._rows)
|
||||||
|
|
||||||
|
class MoveCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers, up, i):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers = sediment_layers
|
||||||
|
self._up = up == "up"
|
||||||
|
self._i = i
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._up:
|
||||||
|
self._sediment_layers.move_up(self._i)
|
||||||
|
else:
|
||||||
|
self._sediment_layers.move_down(self._i)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._up:
|
||||||
|
self._sediment_layers.move_up(self._i)
|
||||||
|
else:
|
||||||
|
self._sediment_layers.move_down(self._i)
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from View.ASubWindow import ASubMainWindow
|
||||||
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
|
|
||||||
|
from View.SedimentLayers.Edit.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Edit.Table import *
|
||||||
|
from View.SedimentLayers.Edit.Plot import Plot
|
||||||
|
from View.SedimentLayers.Edit.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class EditSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
||||||
|
def __init__(self, title="Edit Sediment Layers",
|
||||||
|
study=None, sl=None, parent=None):
|
||||||
|
self._study = study
|
||||||
|
self._sl = sl
|
||||||
|
|
||||||
|
self.setup_title(title)
|
||||||
|
|
||||||
|
super(EditSedimentLayersWindow, self).__init__(
|
||||||
|
name=self._title, ui="EditSedimentLayers", parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_sc()
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_title(self, title):
|
||||||
|
name = self._sl.name
|
||||||
|
if name == "":
|
||||||
|
name = _translate("SedimentLayers", "(no name)")
|
||||||
|
|
||||||
|
self._title = (
|
||||||
|
title + " - " + self._study.name + " - " + name
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_sc(self):
|
||||||
|
self._undo_stack = QUndoStack()
|
||||||
|
|
||||||
|
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
||||||
|
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
||||||
|
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
||||||
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
self._table = {}
|
||||||
|
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
study = self._study,
|
||||||
|
sl = self._sl,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
)
|
||||||
|
table.setModel(self._table)
|
||||||
|
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
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.plot_layout.addWidget(self.canvas)
|
||||||
|
self._set_plot()
|
||||||
|
|
||||||
|
def _set_plot(self):
|
||||||
|
self.plot = Plot(
|
||||||
|
canvas = self.canvas,
|
||||||
|
data = self._sl,
|
||||||
|
toolbar = None,
|
||||||
|
display_current = False
|
||||||
|
)
|
||||||
|
self.plot.draw()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QAction, "action_add").triggered.connect(self.add)
|
||||||
|
self.find(QAction, "action_del").triggered.connect(self.delete)
|
||||||
|
self.find(QAction, "action_move_up").triggered.connect(self.move_up)
|
||||||
|
self.find(QAction, "action_move_down").triggered.connect(self.move_down)
|
||||||
|
|
||||||
|
self.undo_sc.activated.connect(self.undo)
|
||||||
|
self.redo_sc.activated.connect(self.redo)
|
||||||
|
self.copy_sc.activated.connect(self.copy)
|
||||||
|
self.paste_sc.activated.connect(self.paste)
|
||||||
|
|
||||||
|
self._table.dataChanged.connect(self._set_plot)
|
||||||
|
self._table.layoutChanged.connect(self._set_plot)
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._sl) == 0 or len(rows) == 0:
|
||||||
|
self._table.add(0)
|
||||||
|
else:
|
||||||
|
self._table.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.delete(rows)
|
||||||
|
|
||||||
|
def move_up(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.move_up(rows[0])
|
||||||
|
|
||||||
|
def move_down(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.move_down(rows[0])
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
|
def paste(self):
|
||||||
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._table.redo()
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
table_headers = {
|
||||||
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
|
"type": _translate("SedimentLayers", "Type"),
|
||||||
|
"height": _translate("Sedimentlayers", "Height"),
|
||||||
|
"d50": _translate("Sedimentlayers", "D50"),
|
||||||
|
"sigma": _translate("Sedimentlayers", "Sigma"),
|
||||||
|
"critical_constraint": _translate("Sedimentlayers", "Critical constraint"),
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import timer
|
||||||
|
from View.Plot.APlot import APlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class Plot(APlot):
|
||||||
|
def __init__(self, canvas=None, data=None, toolbar=None,
|
||||||
|
display_current=True):
|
||||||
|
super(Plot, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
data=data,
|
||||||
|
toolbar=toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
self._display_current = display_current
|
||||||
|
|
||||||
|
self.line_kp_zmin = None
|
||||||
|
self.line_kp_sl = []
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.canvas.axes.cla()
|
||||||
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
if self.data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.data.number_profiles == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlabel(
|
||||||
|
_translate("MainWindow_reach", "Kp (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
self.canvas.axes.set_ylabel(
|
||||||
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
|
||||||
|
kp = self.data.get_kp()
|
||||||
|
sl = self.data.get_sl()
|
||||||
|
z_min = self.data.get_z_min()
|
||||||
|
z_max = self.data.get_z_max()
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlim(
|
||||||
|
left = min(kp), right = max(kp)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Compute sediment layer in function to profile z_min
|
||||||
|
z_sl = reduce(
|
||||||
|
lambda acc, v: acc + [
|
||||||
|
list(
|
||||||
|
map(lambda x, y: y - x, v, acc[-1])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
sl,
|
||||||
|
[z_min]
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, z in enumerate(reversed(z_sl)):
|
||||||
|
self.line_kp_sl.append(None)
|
||||||
|
self.line_kp_sl[i], = self.canvas.axes.plot(
|
||||||
|
kp, z,
|
||||||
|
linestyle="solid" if i == len(z_sl) - 1 else "--",
|
||||||
|
lw=1.8,
|
||||||
|
color='grey' if i == len(z_sl) - 1 else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.figure.tight_layout()
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
if self.toolbar is not None:
|
||||||
|
self.toolbar.update()
|
||||||
|
|
||||||
|
self._init = True
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if self._init == False:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
if ind is None:
|
||||||
|
kp = self.data.get_kp()
|
||||||
|
z_min = self.data.get_z_min()
|
||||||
|
z_max = self.data.get_z_max()
|
||||||
|
|
||||||
|
self.line_kp_zmin.set_data(kp, z_min)
|
||||||
|
|
||||||
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import timer
|
||||||
|
from View.Plot.APlot import APlot
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication
|
||||||
|
)
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class Plot(APlot):
|
||||||
|
def __init__(self, canvas=None, data=None, toolbar=None,
|
||||||
|
display_current=True):
|
||||||
|
super(Plot, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
data=data,
|
||||||
|
toolbar=toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
self._display_current = display_current
|
||||||
|
|
||||||
|
self.line_kp_zmin = None
|
||||||
|
self.line_kp_sl = []
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.canvas.axes.cla()
|
||||||
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
if self.data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.data.number_points == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlabel(
|
||||||
|
_translate("MainWindow_reach", "X (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
self.canvas.axes.set_ylabel(
|
||||||
|
_translate("MainWindow_reach", "Height (m)"),
|
||||||
|
color='green', fontsize=12
|
||||||
|
)
|
||||||
|
|
||||||
|
x = self.data.get_station()
|
||||||
|
z = self.data.z()
|
||||||
|
sl = self.data.get_sl()
|
||||||
|
|
||||||
|
self.canvas.axes.set_xlim(
|
||||||
|
left = min(x), right = max(x)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Compute sediment layer in function to point z
|
||||||
|
z_sl = reduce(
|
||||||
|
lambda acc, v: acc + [
|
||||||
|
list(
|
||||||
|
map(lambda x, y: y - x, v, acc[-1])
|
||||||
|
)
|
||||||
|
],
|
||||||
|
sl,
|
||||||
|
[z]
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, zsl in enumerate(reversed(z_sl)):
|
||||||
|
self.line_kp_sl.append(None)
|
||||||
|
self.line_kp_sl[i], = self.canvas.axes.plot(
|
||||||
|
x, zsl,
|
||||||
|
linestyle="solid" if i == len(z_sl) - 1 else "--",
|
||||||
|
lw=1.8,
|
||||||
|
color='grey' if i == len(z_sl) - 1 else None
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.figure.tight_layout()
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
|
if self.toolbar is not None:
|
||||||
|
self.toolbar.update()
|
||||||
|
|
||||||
|
self._init = True
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self, ind=None):
|
||||||
|
if self._init == False:
|
||||||
|
self.draw()
|
||||||
|
return
|
||||||
|
|
||||||
|
if ind is None:
|
||||||
|
logger.info("TODO: Update")
|
||||||
|
|
||||||
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
|
self.canvas.figure.canvas.draw_idle()
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Reach.Profile.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Reach.Profile.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, study=None, parent=None):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._study = study
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
self.editor.addItems(
|
||||||
|
# [_translate("SedimentLayers", "Not defined")] +
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda sl: str(sl),
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setCurrentText(index.data(Qt.DisplayRole))
|
||||||
|
return self.editor
|
||||||
|
|
||||||
|
def setEditorData(self, editor, index):
|
||||||
|
value = index.data(Qt.DisplayRole)
|
||||||
|
self.editor.currentTextChanged.connect(self.currentItemChanged)
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
text = str(editor.currentText())
|
||||||
|
model.setData(index, text)
|
||||||
|
editor.close()
|
||||||
|
editor.deleteLater()
|
||||||
|
|
||||||
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
|
r = QRect(option.rect)
|
||||||
|
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
||||||
|
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
||||||
|
editor.setGeometry(r)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def currentItemChanged(self):
|
||||||
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
|
class TableModel(QAbstractTableModel):
|
||||||
|
def __init__(self, study=None, profile=None, undo=None):
|
||||||
|
super(QAbstractTableModel, self).__init__()
|
||||||
|
self._headers = list(table_headers.keys())
|
||||||
|
self._study = study
|
||||||
|
self._undo = undo
|
||||||
|
self._profile = profile
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||||
|
if self._headers[column] == "sl":
|
||||||
|
options |= Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return self._profile.number_points
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return len(self._headers)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
return self._profile.point(row).name
|
||||||
|
elif self._headers[column] == "sl":
|
||||||
|
value = self._profile.point(row).sl
|
||||||
|
if value == None:
|
||||||
|
text = _translate("SedimentLayers", "Not defined")
|
||||||
|
return text
|
||||||
|
return str(value)
|
||||||
|
elif self._headers[column] == "x":
|
||||||
|
return self._profile.point(row).x
|
||||||
|
elif self._headers[column] == "y":
|
||||||
|
return self._profile.point(row).y
|
||||||
|
elif self._headers[column] == "z":
|
||||||
|
return self._profile.point(row).z
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def headerData(self, friction, orientation, role):
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||||
|
return table_headers[self._headers[friction]]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
|
return False
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "sl":
|
||||||
|
new = None
|
||||||
|
if value != _translate("SedimentLayers", "Not defined"):
|
||||||
|
new = next(
|
||||||
|
filter(
|
||||||
|
lambda sl: str(sl) == value,
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
SetSLCommand(
|
||||||
|
self._profile, row, new
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Geometry.Reach import Reach
|
||||||
|
from Model.Geometry.Profile import Profile
|
||||||
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class SetSLCommand(QUndoCommand):
|
||||||
|
def __init__(self, profile, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._profile = profile
|
||||||
|
self._index = index
|
||||||
|
self._old = self._profile.point(self._index).sl
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._profile.point(self._index).sl = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._profile.point(self._index).sl = self._new
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from View.ASubWindow import ASubMainWindow
|
||||||
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Reach.Profile.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Reach.Profile.Table import *
|
||||||
|
from View.SedimentLayers.Reach.Profile.Plot import Plot
|
||||||
|
|
||||||
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
|
from View.SedimentLayers.Reach.Profile.translate import *
|
||||||
|
|
||||||
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class ProfileSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
||||||
|
def __init__(self, title="Profile sediment layers", study=None, profile=None, parent=None):
|
||||||
|
self._study = study
|
||||||
|
self._sediment_layers = self._study.river.sediment_layers
|
||||||
|
self._profile = profile
|
||||||
|
self._reach = self._study.river.current_reach().reach
|
||||||
|
|
||||||
|
self.setup_title(title)
|
||||||
|
|
||||||
|
super(ProfileSedimentLayersWindow, self).__init__(
|
||||||
|
name=self._title, ui="ProfileSedimentLayers", parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_sc()
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_title(self, title):
|
||||||
|
rname = self._reach.name
|
||||||
|
if rname == "":
|
||||||
|
rname = _translate("SedimentLayers", "(no name)")
|
||||||
|
|
||||||
|
pname = self._profile.name
|
||||||
|
if pname == "":
|
||||||
|
pname = _translate(
|
||||||
|
"SedimentLayers",
|
||||||
|
"(no name - @kp)").replace("@kp", str(self._profile.kp)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._title = (
|
||||||
|
title + " - "
|
||||||
|
+ self._study.name + " - "
|
||||||
|
+ rname + " - " + pname
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_sc(self):
|
||||||
|
self._undo_stack = QUndoStack()
|
||||||
|
|
||||||
|
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
||||||
|
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
||||||
|
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
||||||
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
study = self._study,
|
||||||
|
profile = self._profile,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
)
|
||||||
|
table.setModel(self._table)
|
||||||
|
|
||||||
|
self._delegate_stricklers = ComboBoxDelegate(
|
||||||
|
study = self._study,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
table.setItemDelegateForColumn(
|
||||||
|
list(table_headers).index("sl"),
|
||||||
|
self._delegate_stricklers
|
||||||
|
)
|
||||||
|
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
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.plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self._update_plot()
|
||||||
|
|
||||||
|
def _update_plot(self):
|
||||||
|
self.plot = Plot(
|
||||||
|
canvas = self.canvas,
|
||||||
|
data = self._profile,
|
||||||
|
toolbar = None,
|
||||||
|
display_current = False
|
||||||
|
)
|
||||||
|
self.plot.draw()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.undo_sc.activated.connect(self.undo)
|
||||||
|
self.redo_sc.activated.connect(self.redo)
|
||||||
|
self.copy_sc.activated.connect(self.copy)
|
||||||
|
self.paste_sc.activated.connect(self.paste)
|
||||||
|
|
||||||
|
self._table.layoutChanged\
|
||||||
|
.connect(self._update_plot)
|
||||||
|
self._table.dataChanged\
|
||||||
|
.connect(self._update_plot)
|
||||||
|
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
|
def paste(self):
|
||||||
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._table.redo()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
table_headers = {
|
||||||
|
"x": _translate("SedimentLayers", "X (m)"),
|
||||||
|
"y": _translate("SedimentLayers", "Y (m)"),
|
||||||
|
"z": _translate("SedimentLazers", "Z (m)"),
|
||||||
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
|
"sl": _translate("SedimentLayers", "Sediment layers"),
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from View.ASubWindow import ASubWindow
|
||||||
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QComboBox, QUndoStack, QShortcut,
|
||||||
|
QDoubleSpinBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Reach.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
class SLDialog(ASubWindow, ListedSubWindow):
|
||||||
|
def __init__(self, title="SL", study=None, parent=None):
|
||||||
|
self._study = study
|
||||||
|
|
||||||
|
super(SLDialog, self).__init__(
|
||||||
|
name=title, ui="SLDialog", parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_combobox()
|
||||||
|
|
||||||
|
self.value = None
|
||||||
|
|
||||||
|
def setup_combobox(self):
|
||||||
|
self.combobox_add_items(
|
||||||
|
"comboBox",
|
||||||
|
[_translate("SedimentLayers", "Not defined")] +
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda sl: str(sl),
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sl(self):
|
||||||
|
if self.value == _translate("SedimentLayers", "Not defined"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return next(
|
||||||
|
filter(
|
||||||
|
lambda sl: str(sl) == self.value,
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
self.value = self.get_combobox_text("comboBox")
|
||||||
|
super().accept()
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Reach.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Reach.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
|
def __init__(self, study=None, parent=None):
|
||||||
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
|
self._study = study
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
|
self.editor.addItems(
|
||||||
|
[_translate("SedimentLayers", "Not defined")] +
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda sl: str(sl),
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setCurrentText(index.data(Qt.DisplayRole))
|
||||||
|
return self.editor
|
||||||
|
|
||||||
|
def setEditorData(self, editor, index):
|
||||||
|
value = index.data(Qt.DisplayRole)
|
||||||
|
self.editor.currentTextChanged.connect(self.currentItemChanged)
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
text = str(editor.currentText())
|
||||||
|
model.setData(index, text)
|
||||||
|
editor.close()
|
||||||
|
editor.deleteLater()
|
||||||
|
|
||||||
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
|
r = QRect(option.rect)
|
||||||
|
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
||||||
|
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
||||||
|
editor.setGeometry(r)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def currentItemChanged(self):
|
||||||
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
|
class TableModel(QAbstractTableModel):
|
||||||
|
def __init__(self, study=None, reach=None, undo=None):
|
||||||
|
super(QAbstractTableModel, self).__init__()
|
||||||
|
self._headers = list(table_headers.keys())
|
||||||
|
self._study = study
|
||||||
|
self._undo = undo
|
||||||
|
self._reach = reach
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||||
|
if self._headers[column] == "sl":
|
||||||
|
options |= Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return self._reach.number_profiles
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return len(self._headers)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
return self._reach.profile(row).name
|
||||||
|
if self._headers[column] == "kp":
|
||||||
|
return self._reach.profile(row).kp
|
||||||
|
if self._headers[column] == "sl":
|
||||||
|
value = self._reach.profile(row).sl
|
||||||
|
if value == None:
|
||||||
|
text = _translate("SedimentLayers", "Not defined")
|
||||||
|
return text
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def headerData(self, friction, orientation, role):
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||||
|
return table_headers[self._headers[friction]]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
|
return False
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "sl":
|
||||||
|
new = None
|
||||||
|
if value != _translate("SedimentLayers", "Not defined"):
|
||||||
|
new = next(
|
||||||
|
filter(
|
||||||
|
lambda sl: str(sl) == value,
|
||||||
|
self._study.river.sediment_layers.sediment_layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
SetSLCommand(
|
||||||
|
self._reach, row, new
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def apply_sl_each_profile(self, sl):
|
||||||
|
self._undo.push(
|
||||||
|
ApplySLCommand(
|
||||||
|
self._reach, sl
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.Geometry.Reach import Reach
|
||||||
|
from Model.Geometry.Profile import Profile
|
||||||
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class SetSLCommand(QUndoCommand):
|
||||||
|
def __init__(self, reach, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._reach = reach
|
||||||
|
self._index = index
|
||||||
|
self._old = self._reach.profile(self._index).sl
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._reach.profile(self._index).sl = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._reach.profile(self._index).sl = self._new
|
||||||
|
|
||||||
|
|
||||||
|
class ApplySLCommand(QUndoCommand):
|
||||||
|
def __init__(self, reach, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._reach = reach
|
||||||
|
self._old = []
|
||||||
|
for profile in self._reach.profiles:
|
||||||
|
self._old.append(profile.sl)
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for i, profile in enumerate(self._reach.profiles):
|
||||||
|
profile.sl = self._old[i]
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
for profile in self._reach.profiles:
|
||||||
|
profile.sl = self._new
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from View.ASubWindow import ASubMainWindow
|
||||||
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.Reach.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Reach.Table import *
|
||||||
|
from View.SedimentLayers.Reach.Plot import Plot
|
||||||
|
from View.SedimentLayers.Reach.SLDialog import SLDialog
|
||||||
|
|
||||||
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
|
from View.SedimentLayers.Reach.translate import *
|
||||||
|
|
||||||
|
from View.SedimentLayers.Window import SedimentLayersWindow
|
||||||
|
from View.SedimentLayers.Reach.Profile.Window import ProfileSedimentLayersWindow
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class ReachSedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
||||||
|
def __init__(self, title="Reach sediment layers", study=None, parent=None):
|
||||||
|
self._study = study
|
||||||
|
self._sediment_layers = self._study.river.sediment_layers
|
||||||
|
self._reach = self._study.river.current_reach().reach
|
||||||
|
|
||||||
|
self.setup_title(title)
|
||||||
|
|
||||||
|
super(ReachSedimentLayersWindow, self).__init__(
|
||||||
|
name=self._title, ui="ReachSedimentLayers", parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_sc()
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_title(self, title):
|
||||||
|
self._title = (
|
||||||
|
title + " - " + self._study.name + " - " + self._reach.name
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_sc(self):
|
||||||
|
self._undo_stack = QUndoStack()
|
||||||
|
|
||||||
|
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
||||||
|
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
||||||
|
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
||||||
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
study = self._study,
|
||||||
|
reach = self._reach,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
)
|
||||||
|
table.setModel(self._table)
|
||||||
|
|
||||||
|
self._delegate_stricklers = ComboBoxDelegate(
|
||||||
|
study = self._study,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
table.setItemDelegateForColumn(
|
||||||
|
list(table_headers).index("sl"),
|
||||||
|
self._delegate_stricklers
|
||||||
|
)
|
||||||
|
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
def setup_graph(self):
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas")
|
||||||
|
self.plot_layout = self.find(QVBoxLayout, "verticalLayout_2")
|
||||||
|
self.plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self._update_plot()
|
||||||
|
|
||||||
|
def _update_plot(self):
|
||||||
|
self.plot = Plot(
|
||||||
|
canvas = self.canvas,
|
||||||
|
data = self._reach,
|
||||||
|
toolbar = None,
|
||||||
|
display_current = False
|
||||||
|
)
|
||||||
|
self.plot.draw()
|
||||||
|
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QAction, "action_edit").triggered.connect(self.edit_profile)
|
||||||
|
|
||||||
|
self.find(QPushButton, "pushButton_edit")\
|
||||||
|
.clicked\
|
||||||
|
.connect(self.edit_sl)
|
||||||
|
self.find(QPushButton, "pushButton_apply")\
|
||||||
|
.clicked\
|
||||||
|
.connect(self.apply_sl_each_profile)
|
||||||
|
|
||||||
|
self.undo_sc.activated.connect(self.undo)
|
||||||
|
self.redo_sc.activated.connect(self.redo)
|
||||||
|
self.copy_sc.activated.connect(self.copy)
|
||||||
|
self.paste_sc.activated.connect(self.paste)
|
||||||
|
|
||||||
|
self._table.layoutChanged\
|
||||||
|
.connect(self._update_plot)
|
||||||
|
self._table.dataChanged\
|
||||||
|
.connect(self._update_plot)
|
||||||
|
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
|
def paste(self):
|
||||||
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
self._update_plot()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._table.redo()
|
||||||
|
self._update_plot()
|
||||||
|
|
||||||
|
def apply_sl_each_profile(self):
|
||||||
|
slw = SLDialog(
|
||||||
|
study = self._study,
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
if slw.exec():
|
||||||
|
sl = slw.sl
|
||||||
|
self._table.apply_sl_each_profile(sl)
|
||||||
|
|
||||||
|
self._update_plot()
|
||||||
|
|
||||||
|
def edit_profile(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
slw = ProfileSedimentLayersWindow(
|
||||||
|
study = self._study,
|
||||||
|
profile = self._reach.profile(row),
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
slw.show()
|
||||||
|
|
||||||
|
|
||||||
|
def edit_sl(self):
|
||||||
|
slw = SedimentLayersWindow(
|
||||||
|
study = self._study,
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
slw.show()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
table_headers = {
|
||||||
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
|
"kp": _translate("SedimentLayers", "KP (m)"),
|
||||||
|
"sl": _translate("SedimentLayers", "Sediment layers"),
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.UndoCommand import *
|
||||||
|
from View.SedimentLayers.translate import *
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class TableModel(QAbstractTableModel):
|
||||||
|
def __init__(self, study=None, undo=None):
|
||||||
|
super(QAbstractTableModel, self).__init__()
|
||||||
|
self._headers = list(table_headers.keys())
|
||||||
|
self._study = study
|
||||||
|
self._undo = undo
|
||||||
|
self._sl = self._study.river.sediment_layers
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
||||||
|
options |= Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self._sl)
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return len(self._headers)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
return self._sl.get(row).name
|
||||||
|
elif self._headers[column] == "comment":
|
||||||
|
return self._sl.get(row).comment
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def headerData(self, friction, orientation, role):
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||||
|
return table_headers[self._headers[friction]]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
|
return False
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
|
||||||
|
if self._headers[column] == "name":
|
||||||
|
self._undo.push(
|
||||||
|
SetNameCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self._headers[column] == "comment":
|
||||||
|
self._undo.push(
|
||||||
|
SetCommentCommand(
|
||||||
|
self._sl, row, value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def add(self, row, parent=QModelIndex()):
|
||||||
|
self.beginInsertRows(parent, row, row - 1)
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
AddCommand(
|
||||||
|
self._sl, row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endInsertRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def delete(self, rows, parent=QModelIndex()):
|
||||||
|
self.beginRemoveRows(parent, rows[0], rows[-1])
|
||||||
|
|
||||||
|
self._undo.push(
|
||||||
|
DelCommand(
|
||||||
|
self._sl, rows
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def move_up(self, row, parent=QModelIndex()):
|
||||||
|
if row <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
target = row + 2
|
||||||
|
|
||||||
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
||||||
|
|
||||||
|
self._undo_stack.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._sl, "up", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endMoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
|
if row > len(self._sl):
|
||||||
|
return
|
||||||
|
|
||||||
|
target = row
|
||||||
|
|
||||||
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
||||||
|
|
||||||
|
self._undo_stack.push(
|
||||||
|
MoveCommand(
|
||||||
|
self._sl, "down", row
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.endMoveRows()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._undo.undo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._undo.redo()
|
||||||
|
self.layoutChanged.emit()
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QMessageBox, QUndoCommand, QUndoStack,
|
||||||
|
)
|
||||||
|
|
||||||
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
||||||
|
|
||||||
|
class SetNameCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers_list, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers_list = sediment_layers_list
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers_list.get(self._index).name
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers_list.get(self._index).name = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers_list.get(self._index).name = self._new
|
||||||
|
|
||||||
|
class SetCommentCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers_list, index, new_value):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers_list = sediment_layers_list
|
||||||
|
self._index = index
|
||||||
|
self._old = self._sediment_layers_list.get(self._index).comment
|
||||||
|
self._new = new_value
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers_list.get(self._index).comment = self._old
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers_list.get(self._index).comment = self._new
|
||||||
|
|
||||||
|
class AddCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers_list, index):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers_list = sediment_layers_list
|
||||||
|
self._index = index
|
||||||
|
self._new = None
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._sediment_layers_list.delete_i([self._index])
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._new is None:
|
||||||
|
self._new = self._sediment_layers_list.new(self._index)
|
||||||
|
else:
|
||||||
|
self._sediment_layers_list.insert(self._index, self._new)
|
||||||
|
|
||||||
|
class DelCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers_list, rows):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers_list = sediment_layers_list
|
||||||
|
self._rows = rows
|
||||||
|
|
||||||
|
self._sl_pos = []
|
||||||
|
for row in rows:
|
||||||
|
self._sl_pos.append((row, self._sediment_layers_list.get(row)))
|
||||||
|
self._sl_pos.sort()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
for row, el in self._sl_pos:
|
||||||
|
self._sediment_layers_list.insert(row, el)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._sediment_layers_list.delete_i(self._rows)
|
||||||
|
|
||||||
|
class MoveCommand(QUndoCommand):
|
||||||
|
def __init__(self, sediment_layers_list, up, i):
|
||||||
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._sediment_layers_list = sediment_layers_list
|
||||||
|
self._up = up == "up"
|
||||||
|
self._i = i
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self._up:
|
||||||
|
self._sediment_layers_list.move_up(self._i)
|
||||||
|
else:
|
||||||
|
self._sediment_layers_list.move_down(self._i)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self._up:
|
||||||
|
self._sediment_layers_list.move_up(self._i)
|
||||||
|
else:
|
||||||
|
self._sediment_layers_list.move_down(self._i)
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from View.ASubWindow import ASubMainWindow
|
||||||
|
from View.ListedSubWindow import ListedSubWindow
|
||||||
|
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QKeySequence,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
Qt, QVariant, QAbstractTableModel,
|
||||||
|
QCoreApplication, QModelIndex, pyqtSlot,
|
||||||
|
QRect,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialogButtonBox, QPushButton, QLineEdit,
|
||||||
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from View.SedimentLayers.UndoCommand import *
|
||||||
|
from View.SedimentLayers.Table import *
|
||||||
|
|
||||||
|
from View.SedimentLayers.Edit.Plot import Plot
|
||||||
|
|
||||||
|
from View.Plot.MplCanvas import MplCanvas
|
||||||
|
from View.SedimentLayers.translate import *
|
||||||
|
|
||||||
|
from View.SedimentLayers.Edit.Window import EditSedimentLayersWindow
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
class SedimentLayersWindow(ASubMainWindow, ListedSubWindow):
|
||||||
|
def __init__(self, title="SedimentLayersList", study=None, parent=None):
|
||||||
|
self._study = study
|
||||||
|
self._sediment_layers = self._study.river.sediment_layers
|
||||||
|
|
||||||
|
self.setup_title(title)
|
||||||
|
|
||||||
|
super(SedimentLayersWindow, self).__init__(
|
||||||
|
name=self._title, ui="SedimentLayersList", parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.setup_sc()
|
||||||
|
self.setup_table()
|
||||||
|
self.setup_graph()
|
||||||
|
self.setup_connections()
|
||||||
|
|
||||||
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
|
def setup_title(self, title):
|
||||||
|
self._title = (
|
||||||
|
title + " - " + self._study.name
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_sc(self):
|
||||||
|
self._undo_stack = QUndoStack()
|
||||||
|
|
||||||
|
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
||||||
|
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
||||||
|
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
||||||
|
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
||||||
|
|
||||||
|
def setup_table(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
self._table = TableModel(
|
||||||
|
study = self._study,
|
||||||
|
undo = self._undo_stack,
|
||||||
|
)
|
||||||
|
table.setModel(self._table)
|
||||||
|
|
||||||
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
table.setAlternatingRowColors(True)
|
||||||
|
|
||||||
|
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.plot_layout.addWidget(self.canvas)
|
||||||
|
|
||||||
|
def setup_connections(self):
|
||||||
|
self.find(QAction, "action_add").triggered.connect(self.add)
|
||||||
|
self.find(QAction, "action_del").triggered.connect(self.delete)
|
||||||
|
self.find(QAction, "action_edit").triggered.connect(self.edit_sediment_layers)
|
||||||
|
|
||||||
|
self.undo_sc.activated.connect(self.undo)
|
||||||
|
self.redo_sc.activated.connect(self.redo)
|
||||||
|
self.copy_sc.activated.connect(self.copy)
|
||||||
|
self.paste_sc.activated.connect(self.paste)
|
||||||
|
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
table.selectionModel()\
|
||||||
|
.selectionChanged\
|
||||||
|
.connect(self._set_current_sl)
|
||||||
|
|
||||||
|
self._table.dataChanged\
|
||||||
|
.connect(self._set_current_sl)
|
||||||
|
|
||||||
|
def _set_current_sl(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.plot = Plot(
|
||||||
|
canvas = self.canvas,
|
||||||
|
data = self._sediment_layers.get(rows[0]),
|
||||||
|
toolbar = None,
|
||||||
|
display_current = False
|
||||||
|
)
|
||||||
|
self.plot.draw()
|
||||||
|
|
||||||
|
|
||||||
|
def index_selected_rows(self):
|
||||||
|
table = self.find(QTableView, f"tableView")
|
||||||
|
return list(
|
||||||
|
# Delete duplicate
|
||||||
|
set(
|
||||||
|
map(
|
||||||
|
lambda i: i.row(),
|
||||||
|
table.selectedIndexes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(self._sediment_layers) == 0 or len(rows) == 0:
|
||||||
|
self._table.add(0)
|
||||||
|
else:
|
||||||
|
self._table.add(rows[0])
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
if len(rows) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._table.delete(rows)
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
|
def paste(self):
|
||||||
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
self._table.undo()
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
self._table.redo()
|
||||||
|
|
||||||
|
def edit_sediment_layers(self):
|
||||||
|
rows = self.index_selected_rows()
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
slw = EditSedimentLayersWindow(
|
||||||
|
study = self._study,
|
||||||
|
sl = self._sediment_layers.get(row),
|
||||||
|
parent = self
|
||||||
|
)
|
||||||
|
slw.show()
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
table_headers = {
|
||||||
|
"name": _translate("SedimentLayers", "Name"),
|
||||||
|
"comment": _translate("SedimentLayers", "Comment"),
|
||||||
|
}
|
||||||
@@ -55,15 +55,16 @@ def init():
|
|||||||
"all_init_time": _translate("SolverParameters", "Initial time (jj:hh:mm:ss)"),
|
"all_init_time": _translate("SolverParameters", "Initial time (jj:hh:mm:ss)"),
|
||||||
"all_final_time": _translate("SolverParameters", "Final time (jj:hh:mm:ss)"),
|
"all_final_time": _translate("SolverParameters", "Final time (jj:hh:mm:ss)"),
|
||||||
"all_timestep": _translate("SolverParameters", "Timestep (second)"),
|
"all_timestep": _translate("SolverParameters", "Timestep (second)"),
|
||||||
|
"all_command_line_arguments": _translate("SolverParameters", "Command line arguments"),
|
||||||
# Mage specific parameters
|
# Mage specific parameters
|
||||||
"mage_min_timestep": _translate("SolverParameters", "Minimum timestep (second)"),
|
"mage_min_timestep": _translate("SolverParameters", "Minimum timestep (second)"),
|
||||||
"mage_timestep_tra": _translate("SolverParameters", "Time step of writing on .TRA"),
|
"mage_timestep_tra": _translate("SolverParameters", "Time step of writing on .TRA"),
|
||||||
"mage_timestep_bin": _translate("SolverParameters", "Time step of writing on .BIN"),
|
"mage_timestep_bin": _translate("SolverParameters", "Time step of writing on .BIN"),
|
||||||
"mage_implication": _translate("SolverParameters", "Implicitation parameter"),
|
"mage_implicitation": _translate("SolverParameters", "Implicitation parameter"),
|
||||||
"mage_continuity_discretization": _translate("SolverParameters", "Continuity discretization type (S/L)"),
|
"mage_continuity_discretization": _translate("SolverParameters", "Continuity discretization type (S/L)"),
|
||||||
"mage_qsj_discretization": _translate("SolverParameters", "QSJ discretization (A/B)"),
|
"mage_qsj_discretization": _translate("SolverParameters", "QSJ discretization (A/B)"),
|
||||||
"mage_stop_criterion_iterations": _translate("SolverParameters", "Stop criterion iterations (G/A/R)"),
|
"mage_stop_criterion_iterations": _translate("SolverParameters", "Stop criterion iterations (G/A/R)"),
|
||||||
"mage_iter_type": _translate("SolverParameters", "Iteration type"),
|
"mage_iteration_type": _translate("SolverParameters", "Iteration type"),
|
||||||
"mage_smooth_coef": _translate("SolverParameters", "Smoothing coefficient"),
|
"mage_smooth_coef": _translate("SolverParameters", "Smoothing coefficient"),
|
||||||
"mage_cfl_max": _translate("SolverParameters", "Maximun accepted number of CFL"),
|
"mage_cfl_max": _translate("SolverParameters", "Maximun accepted number of CFL"),
|
||||||
"mage_min_height": _translate("SolverParameters", "Minimum water height (meter)"),
|
"mage_min_height": _translate("SolverParameters", "Minimum water height (meter)"),
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?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>960</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>960</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<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_del"/>
|
||||||
|
<addaction name="action_move_up"/>
|
||||||
|
<addaction name="action_move_down"/>
|
||||||
|
</widget>
|
||||||
|
<action name="action_add">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add a new sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_del">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete selected sediment layer(s)</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_move_up">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/up.png</normaloff>ressources/up.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Move up</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Move up</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_move_down">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/down.png</normaloff>ressources/down.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Move down</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Move down</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -165,10 +165,18 @@
|
|||||||
<addaction name="action_menu_help_mage"/>
|
<addaction name="action_menu_help_mage"/>
|
||||||
<addaction name="action_menu_about"/>
|
<addaction name="action_menu_about"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuSediment">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Sediment</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="action_menu_sediment_layers"/>
|
||||||
|
<addaction name="action_menu_edit_reach_sediment_layers"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menu_File"/>
|
<addaction name="menu_File"/>
|
||||||
<addaction name="menu_network"/>
|
<addaction name="menu_network"/>
|
||||||
<addaction name="menu_geometry"/>
|
<addaction name="menu_geometry"/>
|
||||||
<addaction name="menu_Hydraulics"/>
|
<addaction name="menu_Hydraulics"/>
|
||||||
|
<addaction name="menuSediment"/>
|
||||||
<addaction name="menu_run"/>
|
<addaction name="menu_run"/>
|
||||||
<addaction name="menu_plot"/>
|
<addaction name="menu_plot"/>
|
||||||
<addaction name="menu_cartography"/>
|
<addaction name="menu_cartography"/>
|
||||||
@@ -878,6 +886,16 @@
|
|||||||
<string>Define initial conditions</string>
|
<string>Define initial conditions</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_menu_sediment_layers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sediment layers</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_menu_edit_reach_sediment_layers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit reach sediment layers</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?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>960</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>960</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<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_sediment_layers"/>
|
||||||
|
<addaction name="action_delete_sediment_layers"/>
|
||||||
|
<addaction name="action_edit_sediment_layers"/>
|
||||||
|
</widget>
|
||||||
|
<action name="action_add_sediment_layers">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add sediment layers</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add specific sediment layers on selected point(s)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_delete_sediment_layers">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete sediment layers</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete specific sediment layers of selected point(s)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_edit_sediment_layers">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit sediment layers</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit sediment layers list</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<?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>960</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit sediment layers list</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_apply">
|
||||||
|
<property name="text">
|
||||||
|
<string>Apply sediment layers on all reach</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget_2">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>960</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<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_edit"/>
|
||||||
|
</widget>
|
||||||
|
<action name="action_edit">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit profile</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit profile sediment layer</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
+27
-1
@@ -30,7 +30,7 @@
|
|||||||
<widget class="QTableView" name="tableView_reach"/>
|
<widget class="QTableView" name="tableView_reach"/>
|
||||||
<widget class="QTableView" name="tableView_profile"/>
|
<widget class="QTableView" name="tableView_profile"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="">
|
<widget class="QWidget" name="layoutWidget">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
@@ -75,6 +75,32 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_3">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Sediment</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter_5">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget_4">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_sed_reach"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget_5">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_sed_profile"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?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>194</width>
|
||||||
|
<height>76</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QComboBox" name="comboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?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>960</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>960</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<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_del"/>
|
||||||
|
<addaction name="action_edit"/>
|
||||||
|
</widget>
|
||||||
|
<action name="action_add">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-add.png</normaloff>ressources/gtk-add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add sediment layer</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_del">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete sediment layer</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 sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit sediment layer</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999999</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user