mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
RubarBE: export solid lateral contributions with their D50 and sigma, attached to the liquid contribution of the same zone (hydevs), and no longer read suspension ones
This commit is contained in:
1 parent
be7b5b892a
commit
ef72e41b14
5 files changed
+124
-29
No files matched your search
@@ -223,9 +223,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
self._data = []
|
self._data = []
|
||||||
self._header = []
|
self._header = []
|
||||||
self._types = [float, float]
|
self._types = [float, float]
|
||||||
# Grain size of the sediment brought by a solid contribution:
|
|
||||||
# median diameter (m) and spread sqrt(d84/d16), as for a solid
|
|
||||||
# boundary condition
|
|
||||||
self._d50 = 0.002
|
self._d50 = 0.002
|
||||||
self._sigma = 1.0
|
self._sigma = 1.0
|
||||||
|
|
||||||
|
|||||||
+86
-22
@@ -174,7 +174,8 @@ class Rubar3(CommandLineSolver):
|
|||||||
hydraulics["warnings"])
|
hydraulics["warnings"])
|
||||||
saves = self._save_data(values, hydraulics)
|
saves = self._save_data(values, hydraulics)
|
||||||
laterals = self._lateral_data(
|
laterals = self._lateral_data(
|
||||||
study.river, hydraulics, values, hydraulics["warnings"])
|
study.river, hydraulics, values, trased,
|
||||||
|
hydraulics["warnings"])
|
||||||
structures = self._structure_data(
|
structures = self._structure_data(
|
||||||
study.river, hydraulics, hydraulics["warnings"])
|
study.river, hydraulics, hydraulics["warnings"])
|
||||||
except RubarExportError as error:
|
except RubarExportError as error:
|
||||||
@@ -546,7 +547,7 @@ class Rubar3(CommandLineSolver):
|
|||||||
# inflow in each cell of its zone, without checking this size
|
# inflow in each cell of its zone, without checking this size
|
||||||
_max_lateral_points = 3000 * 20
|
_max_lateral_points = 3000 * 20
|
||||||
|
|
||||||
def _lateral_data(self, river, hydraulics, values, warnings):
|
def _lateral_data(self, river, hydraulics, values, trased, warnings):
|
||||||
"""Lateral inflows of HYDEVS, read when IODEV=O (rubar_init.f90,
|
"""Lateral inflows of HYDEVS, read when IODEV=O (rubar_init.f90,
|
||||||
init2). Return [(first cell, last cell, [(t, q), ...]), ...]
|
init2). Return [(first cell, last cell, [(t, q), ...]), ...]
|
||||||
sorted from upstream, or None when IODEV=N.
|
sorted from upstream, or None when IODEV=N.
|
||||||
@@ -557,9 +558,17 @@ class Rubar3(CommandLineSolver):
|
|||||||
b covers the cell downstream of it (upstream of it for the last
|
b covers the cell downstream of it (upstream of it for the last
|
||||||
section). The first and last cells of the reach are never used,
|
section). The first and last cells of the reach are never used,
|
||||||
as RubarBE requires. With IODEV=N, the contributions are ignored
|
as RubarBE requires. With IODEV=N, the contributions are ignored
|
||||||
with a warning. Otherwise, solid and suspension contributions have
|
with a warning.
|
||||||
no RubarBE equivalent (their sediment cannot be linked to an
|
|
||||||
inflow): they are refused"""
|
RubarBE brings sediment only with a liquid inflow, on the same
|
||||||
|
cells: a solid contribution (kg/s, UNISOL=1) is attached to the
|
||||||
|
liquid contribution of the same zone, whose block gets its D50
|
||||||
|
and sigma; the times of both series are merged (linear
|
||||||
|
interpolation, constant outside). Several solid contributions of
|
||||||
|
a zone are summed when they have the same grain size. A solid
|
||||||
|
contribution without liquid one, or without sediment transport,
|
||||||
|
is ignored with a warning. A liquid inflow without solid
|
||||||
|
contribution brings clear water (Qs = 0, D = S = 0)."""
|
||||||
trad = RunSolverTranslate()
|
trad = RunSolverTranslate()
|
||||||
edge = hydraulics["edge"]
|
edge = hydraulics["edge"]
|
||||||
profiles = hydraulics["profiles"]
|
profiles = hydraulics["profiles"]
|
||||||
@@ -580,40 +589,50 @@ class Rubar3(CommandLineSolver):
|
|||||||
return kept
|
return kept
|
||||||
|
|
||||||
lcs = on_reach("liquid")
|
lcs = on_reach("liquid")
|
||||||
sediment = on_reach("solid") + on_reach("suspenssion")
|
solids = on_reach("solid")
|
||||||
|
|
||||||
# Not read by RubarBE: the user is warned, the computation runs
|
# Not read by RubarBE: the user is warned, the computation runs
|
||||||
# without them
|
# without them
|
||||||
if not iodev:
|
if not iodev:
|
||||||
for lc in lcs + sediment:
|
for lc in lcs + solids:
|
||||||
warnings.append(trad["lateral_iodev_disabled"].format(
|
warnings.append(trad["lateral_iodev_disabled"].format(
|
||||||
name=lc.name, reach=edge.name))
|
name=lc.name, reach=edge.name))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if sediment:
|
if not trased:
|
||||||
raise RubarExportError(trad["lateral_solid_unsupported"].format(
|
for lc in solids:
|
||||||
name=sediment[0].name, reach=edge.name))
|
warnings.append(trad["lateral_solid_no_transport"].format(
|
||||||
|
name=lc.name, reach=edge.name))
|
||||||
|
solids = []
|
||||||
|
if solids and values.get("rubarbe_sediment_unisol", "1") != "1":
|
||||||
|
raise RubarExportError(trad["lateral_solid_unisol"].format(
|
||||||
|
name=solids[0].name, reach=edge.name))
|
||||||
|
|
||||||
index = {id(p): i for i, p in enumerate(profiles, 1)}
|
index = {id(p): i for i, p in enumerate(profiles, 1)}
|
||||||
count = len(profiles)
|
count = len(profiles)
|
||||||
blocks = []
|
|
||||||
for lc in lcs:
|
def zone_and_data(lc):
|
||||||
if lc.lctype not in self._lateral_signs:
|
|
||||||
raise RubarExportError(trad["lateral_type_unsupported"].format(
|
|
||||||
name=lc.name, reach=edge.name))
|
|
||||||
if (id(lc.begin_section) not in index or
|
if (id(lc.begin_section) not in index or
|
||||||
id(lc.end_section) not in index):
|
id(lc.end_section) not in index):
|
||||||
raise RubarExportError(trad["lateral_sections"].format(
|
raise RubarExportError(trad["lateral_sections"].format(
|
||||||
name=lc.name, reach=edge.name))
|
name=lc.name, reach=edge.name))
|
||||||
b, e = sorted((index[id(lc.begin_section)],
|
b, e = sorted((index[id(lc.begin_section)],
|
||||||
index[id(lc.end_section)]))
|
index[id(lc.end_section)]))
|
||||||
first, last = (b + 1, e) if b < e else ((min(b + 1, count),) * 2)
|
zone = (b + 1, e) if b < e else ((min(b + 1, count),) * 2)
|
||||||
|
|
||||||
data = [(float(d[0]), float(d[1])) for d in lc.data]
|
data = [(float(d[0]), float(d[1])) for d in lc.data]
|
||||||
times = [t for t, _ in data]
|
times = [t for t, _ in data]
|
||||||
if any(t1 < t0 for t0, t1 in zip(times, times[1:])):
|
if any(t1 < t0 for t0, t1 in zip(times, times[1:])):
|
||||||
raise RubarExportError(trad["lateral_not_sorted"].format(
|
raise RubarExportError(trad["lateral_not_sorted"].format(
|
||||||
name=lc.name, reach=edge.name))
|
name=lc.name, reach=edge.name))
|
||||||
|
return zone, data
|
||||||
|
|
||||||
|
blocks = []
|
||||||
|
for lc in lcs:
|
||||||
|
if lc.lctype not in self._lateral_signs:
|
||||||
|
raise RubarExportError(trad["lateral_type_unsupported"].format(
|
||||||
|
name=lc.name, reach=edge.name))
|
||||||
|
(first, last), data = zone_and_data(lc)
|
||||||
sign = self._lateral_signs[lc.lctype]
|
sign = self._lateral_signs[lc.lctype]
|
||||||
blocks.append((first, last, [(t, sign * q) for t, q in data],
|
blocks.append((first, last, [(t, sign * q) for t, q in data],
|
||||||
lc.name))
|
lc.name))
|
||||||
@@ -625,13 +644,56 @@ class Rubar3(CommandLineSolver):
|
|||||||
raise RubarExportError(trad["lateral_overlap"].format(
|
raise RubarExportError(trad["lateral_overlap"].format(
|
||||||
first=name0, second=name1, reach=edge.name))
|
first=name0, second=name1, reach=edge.name))
|
||||||
|
|
||||||
|
# Solid contributions grouped by the zone of their liquid one
|
||||||
|
zones = {(first, last) for first, last, _, _ in blocks}
|
||||||
|
sediment = {}
|
||||||
|
for lc in solids:
|
||||||
|
zone, data = zone_and_data(lc)
|
||||||
|
if not (lc.d50 > 0 and lc.sigma >= 1):
|
||||||
|
raise RubarExportError(trad["lateral_solid_invalid"].format(
|
||||||
|
name=lc.name, reach=edge.name))
|
||||||
|
if zone not in zones:
|
||||||
|
warnings.append(trad["lateral_solid_unmatched"].format(
|
||||||
|
name=lc.name, reach=edge.name))
|
||||||
|
continue
|
||||||
|
sediment.setdefault(zone, []).append((lc, data))
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for first, last, data, name in blocks:
|
||||||
|
attached = sediment.get((first, last), [])
|
||||||
|
grains = {(lc.d50, lc.sigma) for lc, _ in attached}
|
||||||
|
if len(grains) > 1:
|
||||||
|
raise RubarExportError(trad["lateral_solid_conflict"].format(
|
||||||
|
names=", ".join(lc.name for lc, _ in attached),
|
||||||
|
liquid=name, reach=edge.name))
|
||||||
|
|
||||||
|
times = sorted({t for t, _ in data} |
|
||||||
|
{t for _, solid in attached for t, _ in solid})
|
||||||
|
|
||||||
|
def at(series):
|
||||||
|
return np.interp(times, [t for t, _ in series],
|
||||||
|
[v for _, v in series])
|
||||||
|
|
||||||
|
q = at(data)
|
||||||
|
qs = sum((at(solid) for _, solid in attached),
|
||||||
|
np.zeros(len(times)))
|
||||||
|
length = (self._section_rk(profiles[last - 1]) -
|
||||||
|
self._section_rk(profiles[first - 2]))
|
||||||
|
result.append((
|
||||||
|
first, last,
|
||||||
|
[(float(t), float(v), float(vs))
|
||||||
|
for t, v, vs in zip(times, q, qs)],
|
||||||
|
next(iter(grains), (0.0, 0.0)),
|
||||||
|
length,
|
||||||
|
))
|
||||||
|
|
||||||
points = sum((last - first + 1) * len(data)
|
points = sum((last - first + 1) * len(data)
|
||||||
for first, last, data, _ in blocks)
|
for first, last, data, _, _ in result)
|
||||||
if points > self._max_lateral_points:
|
if points > self._max_lateral_points:
|
||||||
raise RubarExportError(trad["lateral_too_long"].format(
|
raise RubarExportError(trad["lateral_too_long"].format(
|
||||||
count=points, maximum=self._max_lateral_points))
|
count=points, maximum=self._max_lateral_points))
|
||||||
|
|
||||||
return [block[:3] for block in blocks]
|
return result
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Structures #
|
# Structures #
|
||||||
@@ -1251,13 +1313,15 @@ class Rubar3(CommandLineSolver):
|
|||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
qlog.put("Export HYDEVS file")
|
qlog.put("Export HYDEVS file")
|
||||||
lines = []
|
lines = []
|
||||||
for first, last, data in laterals:
|
for first, last, data, (d50, sigma), length in laterals:
|
||||||
if trased:
|
if trased:
|
||||||
lines.append(f"{first} {last} {len(data)} 0.0 0.0\n")
|
lines.append(
|
||||||
lines += [f"{q!r} {t!r} 0.0 {t!r}\n" for t, q in data]
|
f"{first} {last} {len(data)} {d50!r} {sigma!r}\n")
|
||||||
|
lines += [f"{q!r} {t!r} {qs / length!r} {t!r}\n"
|
||||||
|
for t, q, qs in data]
|
||||||
else:
|
else:
|
||||||
lines.append(f"{first} {last} {len(data)}\n")
|
lines.append(f"{first} {last} {len(data)}\n")
|
||||||
lines += [f"{q!r} {t!r}\n" for t, q in data]
|
lines += [f"{q!r} {t!r}\n" for t, q, _ in data]
|
||||||
self._write_parameters(repertory, f"hydevs.{name}", lines)
|
self._write_parameters(repertory, f"hydevs.{name}", lines)
|
||||||
|
|
||||||
def _export_ouvrag(self, structures, repertory, qlog, name="0"):
|
def _export_ouvrag(self, structures, repertory, qlog, name="0"):
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ class EditLateralContributionWindow(PamhyrWindow):
|
|||||||
self._is_solid = tab == "solid"
|
self._is_solid = tab == "solid"
|
||||||
|
|
||||||
trad = LCETranslate()
|
trad = LCETranslate()
|
||||||
|
if self._is_solid:
|
||||||
|
trad.get_dict("table_headers")["discharge"] = \
|
||||||
|
trad["solid_discharge"]
|
||||||
name = trad[self._pamhyr_name]
|
name = trad[self._pamhyr_name]
|
||||||
if self._data is not None:
|
if self._data is not None:
|
||||||
edge_name = (self._data.reach.name if self._data.reach is not None
|
edge_name = (self._data.reach.name if self._data.reach is not None
|
||||||
|
|||||||
@@ -39,3 +39,7 @@ class LCETranslate(LCTranslate):
|
|||||||
"discharge": self._dict["unit_discharge"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
"z": self._dict["unit_elevation"],
|
"z": self._dict["unit_elevation"],
|
||||||
}
|
}
|
||||||
|
# Discharge column of a solid contribution
|
||||||
|
self._dict["solid_discharge"] = _translate(
|
||||||
|
"LateralContribution", "Solid discharge (kg/s)"
|
||||||
|
)
|
||||||
@@ -192,11 +192,37 @@ class RunSolverTranslate(PamhyrTranslate):
|
|||||||
"Lateral contribution {name} on reach {reach} has no value: it "
|
"Lateral contribution {name} on reach {reach} has no value: it "
|
||||||
"is ignored."
|
"is ignored."
|
||||||
)
|
)
|
||||||
self._dict["lateral_solid_unsupported"] = _translate(
|
self._dict["lateral_solid_no_transport"] = _translate(
|
||||||
"Solver",
|
"Solver",
|
||||||
"Export cancelled: solid or suspension lateral contribution "
|
"Solid lateral contribution {name} on reach {reach} is not taken "
|
||||||
"{name} on reach {reach}: RubarBE only reads the sediment of a "
|
"into account: sediment transport (rubarbe_trased) is disabled "
|
||||||
"liquid inflow, which Pamhyr2 cannot link to it. Remove it."
|
"in the solver parameters."
|
||||||
|
)
|
||||||
|
self._dict["lateral_solid_unmatched"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Solid lateral contribution {name} on reach {reach} is not taken "
|
||||||
|
"into account: RubarBE brings sediment only with water, and no "
|
||||||
|
"liquid lateral contribution has the same sections."
|
||||||
|
)
|
||||||
|
self._dict["lateral_solid_unisol"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: solid lateral contribution {name} on reach "
|
||||||
|
"{reach} gives a solid discharge in kg/s, but the solver "
|
||||||
|
"parameters set the solid unit (rubarbe_sediment_unisol) to a "
|
||||||
|
"concentration. Set it to a mass discharge (kg/s)."
|
||||||
|
)
|
||||||
|
self._dict["lateral_solid_invalid"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: solid lateral contribution {name} on reach "
|
||||||
|
"{reach} must have D50 > 0 m and sigma >= 1 (1 for a uniform "
|
||||||
|
"sediment)."
|
||||||
|
)
|
||||||
|
self._dict["lateral_solid_conflict"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: solid lateral contributions {names} on reach "
|
||||||
|
"{reach} are attached to the same liquid contribution {liquid} "
|
||||||
|
"but have different D50 or sigma. RubarBE accepts a single "
|
||||||
|
"grain size per inflow."
|
||||||
)
|
)
|
||||||
self._dict["lateral_iodev_disabled"] = _translate(
|
self._dict["lateral_iodev_disabled"] = _translate(
|
||||||
"Solver",
|
"Solver",
|
||||||
|
|||||||
Reference in new issue
Block a user