mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-29 19:10:42 +01:00
RubarBE: export sediment layers and bed limits in geomac-i, and refuse invalid layers or markers
This commit is contained in:
1 parent
7103fdcb46
commit
33a2107876
2 files changed
+164
-45
No files matched your search
+130
-45
@@ -176,6 +176,7 @@ class Rubar3(CommandLineSolver):
|
|||||||
# Check the hydraulic data before writing any file
|
# Check the hydraulic data before writing any file
|
||||||
try:
|
try:
|
||||||
hydraulics = self._hydraulic_data(study, values)
|
hydraulics = self._hydraulic_data(study, values)
|
||||||
|
geometry = self._geometry_data(hydraulics["edge"], trased)
|
||||||
except RubarExportError as error:
|
except RubarExportError as error:
|
||||||
self._cancel(qlog, str(error))
|
self._cancel(qlog, str(error))
|
||||||
return False
|
return False
|
||||||
@@ -190,7 +191,7 @@ class Rubar3(CommandLineSolver):
|
|||||||
if trased:
|
if trased:
|
||||||
if not self._export_ts(study, repertory, qlog, name=name):
|
if not self._export_ts(study, repertory, qlog, name=name):
|
||||||
return False
|
return False
|
||||||
self._export_geomac_i(study, repertory, qlog, name=name)
|
self._export_geomac_i(geometry, repertory, qlog, name=name)
|
||||||
self._export_mail(study, repertory, qlog, name=name)
|
self._export_mail(study, repertory, qlog, name=name)
|
||||||
self._export_devers(study, repertory, qlog, name=name)
|
self._export_devers(study, repertory, qlog, name=name)
|
||||||
self._export_condin(hydraulics, repertory, qlog, name=name)
|
self._export_condin(hydraulics, repertory, qlog, name=name)
|
||||||
@@ -252,6 +253,119 @@ class Rubar3(CommandLineSolver):
|
|||||||
"warnings": warnings,
|
"warnings": warnings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
############
|
||||||
|
# Geometry #
|
||||||
|
############
|
||||||
|
|
||||||
|
# Point names giving the limits of the main channel (G, D) and of the
|
||||||
|
# active bed (g, d) in GEOMAC-I (rubar_init.f90). Other names are not
|
||||||
|
# written
|
||||||
|
_point_markers = {"rg": "G", "rd": "D", "g": "g", "d": "d"}
|
||||||
|
# RubarBE never erodes a compartment whose critical stress is above
|
||||||
|
# 999 Pa (rubarbe.f90, EROSEC)
|
||||||
|
_hard_stress = 999.999
|
||||||
|
# CSMAX (variables.f90)
|
||||||
|
_max_compartments = 10
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _profile_label(profile):
|
||||||
|
name = profile.name if profile.name != "" else "#"
|
||||||
|
return f"{name} (rk {profile.rk:g})"
|
||||||
|
|
||||||
|
def _geometry_data(self, edge, trased):
|
||||||
|
"""Check the GEOMAC-I data of the reach and return its sections
|
||||||
|
[(rk, [(marker, y, [(z_top, d, s, tau_c), ...]), ...]), ...].
|
||||||
|
Raise RubarExportError with a user message"""
|
||||||
|
sections = []
|
||||||
|
for profile in edge.reach.profiles:
|
||||||
|
points = profile.points
|
||||||
|
markers = self._markers(edge, profile, points, trased)
|
||||||
|
station = profile.get_station()
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i, (point, marker, y) in enumerate(
|
||||||
|
zip(points, markers, station)):
|
||||||
|
if trased:
|
||||||
|
compartments = self._compartments(
|
||||||
|
edge, profile, i + 1, point)
|
||||||
|
else:
|
||||||
|
# Only the bed level is used by the hydraulics
|
||||||
|
compartments = [(point.z, 1.0, 1.0, self._hard_stress)]
|
||||||
|
rows.append((marker, y, compartments))
|
||||||
|
|
||||||
|
sections.append((self._section_rk(profile), rows))
|
||||||
|
return sections
|
||||||
|
|
||||||
|
def _markers(self, edge, profile, points, trased):
|
||||||
|
trad = RunSolverTranslate()
|
||||||
|
markers = [self._point_markers.get(p.name.strip(), " ")
|
||||||
|
for p in points]
|
||||||
|
names = {v: k for k, v in self._point_markers.items()}
|
||||||
|
for marker in "GDgd":
|
||||||
|
if markers.count(marker) > 1:
|
||||||
|
raise RubarExportError(trad["duplicate_point_name"].format(
|
||||||
|
name=names[marker], profile=self._profile_label(profile),
|
||||||
|
reach=edge.name))
|
||||||
|
|
||||||
|
# Defaults of RubarBE: first and last points for G and D, G and D
|
||||||
|
# for g and d. Erosion only applies strictly between g and d
|
||||||
|
def index(marker, default):
|
||||||
|
return markers.index(marker) if marker in markers else default
|
||||||
|
|
||||||
|
left = index("G", 0)
|
||||||
|
right = index("D", len(points) - 1)
|
||||||
|
limits = [("main_channel", "rg", "rd", left, right)]
|
||||||
|
if trased:
|
||||||
|
limits.append(("active_bed", "g", "d",
|
||||||
|
index("g", left), index("d", right)))
|
||||||
|
for bed, lname, rname, i, j in limits:
|
||||||
|
if j - i < 2:
|
||||||
|
raise RubarExportError(trad["bed_limits_invalid"].format(
|
||||||
|
bed=trad[bed], left=lname, right=rname,
|
||||||
|
profile=self._profile_label(profile), reach=edge.name))
|
||||||
|
return markers
|
||||||
|
|
||||||
|
def _compartments(self, edge, profile, number, point):
|
||||||
|
"""Sediment layers of a point as RubarBE compartments, from the
|
||||||
|
top: (top elevation, D, S, critical stress). A non erodible
|
||||||
|
compartment is added under an erodible last layer, so that the
|
||||||
|
layer thicknesses are kept"""
|
||||||
|
trad = RunSolverTranslate()
|
||||||
|
sl = point.sl
|
||||||
|
if sl is None or sl.is_deleted() or len(sl) == 0:
|
||||||
|
raise RubarExportError(trad["missing_sediment_layers"].format(
|
||||||
|
point=number, profile=self._profile_label(profile),
|
||||||
|
reach=edge.name))
|
||||||
|
|
||||||
|
layers = sl.layers
|
||||||
|
for layer in layers:
|
||||||
|
if not (layer.height >= 0 and layer.d50 > 0 and
|
||||||
|
layer.sigma >= 1 and layer.critical_constraint >= 0):
|
||||||
|
raise RubarExportError(trad["invalid_sediment_layer"].format(
|
||||||
|
layer=layer.name, sl=sl.name,
|
||||||
|
profile=self._profile_label(profile), reach=edge.name))
|
||||||
|
|
||||||
|
top = point.z
|
||||||
|
compartments = []
|
||||||
|
for layer in layers:
|
||||||
|
if layer.height == 0:
|
||||||
|
continue
|
||||||
|
compartments.append((top, layer.d50, layer.sigma,
|
||||||
|
layer.critical_constraint))
|
||||||
|
top -= layer.height
|
||||||
|
|
||||||
|
if not compartments or compartments[-1][3] <= 999:
|
||||||
|
last = layers[-1]
|
||||||
|
compartments.append((top, last.d50, last.sigma,
|
||||||
|
self._hard_stress))
|
||||||
|
|
||||||
|
if len(compartments) > self._max_compartments:
|
||||||
|
raise RubarExportError(trad["too_many_compartments"].format(
|
||||||
|
sl=sl.name, count=len(compartments),
|
||||||
|
maximum=self._max_compartments,
|
||||||
|
profile=self._profile_label(profile), reach=edge.name))
|
||||||
|
return compartments
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _seconds(value):
|
def _seconds(value):
|
||||||
if ":" in value:
|
if ":" in value:
|
||||||
@@ -664,54 +778,25 @@ class Rubar3(CommandLineSolver):
|
|||||||
self._write_parameters(repertory, f"ts.{name}", lines)
|
self._write_parameters(repertory, f"ts.{name}", lines)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _export_geomac_i(self, study, repertory, qlog, name="0"):
|
def _export_geomac_i(self, geometry, repertory, qlog, name="0"):
|
||||||
|
"""GEOMAC-I: number of sections, then for each section its
|
||||||
|
header and one line per point (A1, 1X, F11.5, then up to 10
|
||||||
|
compartments in F13.5, 2F15.10, F15.5; rubar_init.f90)"""
|
||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
qlog.put("Export GEOMAC-i file")
|
qlog.put("Export GEOMAC-i file")
|
||||||
|
|
||||||
with open(
|
lines = [f"{len(geometry):>4} {0.0:>12.3f}\n"]
|
||||||
os.path.join(
|
for i, (rk, rows) in enumerate(geometry, 1):
|
||||||
repertory, f"geomac-i.{name}"
|
lines.append(f"{i:>4} {rk:>11.3f} {len(rows):>4}\n")
|
||||||
), "w+"
|
for marker, y, compartments in rows:
|
||||||
) as f:
|
lines.append(
|
||||||
for edge in study.river.enable_edges():
|
f"{marker} {y:>11.5f}" +
|
||||||
reach = edge.reach
|
"".join(f"{z:>13.5f}{d:>15.10f}{s:>15.10f}{t:>15.5f}"
|
||||||
n_profiles = len(reach)
|
for z, d, s, t in compartments) +
|
||||||
time = 0.0
|
"\n"
|
||||||
|
)
|
||||||
|
|
||||||
f.write(f"{n_profiles:>5} {time:>11.3f}\n")
|
self._write_parameters(repertory, f"geomac-i.{name}", lines)
|
||||||
|
|
||||||
ind = 1
|
|
||||||
for profile in reach.profiles:
|
|
||||||
rk = profile.rk
|
|
||||||
n_points = len(profile)
|
|
||||||
|
|
||||||
f.write(f"{ind:>4} {rk:>11.3f} {n_points:>4}\n")
|
|
||||||
|
|
||||||
station = profile.get_station()
|
|
||||||
for i, point in enumerate(profile.points):
|
|
||||||
label = point.name.lower()
|
|
||||||
if label != "":
|
|
||||||
if label[0] == "r":
|
|
||||||
label = label[1].upper()
|
|
||||||
else:
|
|
||||||
label = " "
|
|
||||||
else:
|
|
||||||
label = " "
|
|
||||||
|
|
||||||
y = station[i]
|
|
||||||
z = point.z
|
|
||||||
dcs = 1.0
|
|
||||||
scs = 1.0
|
|
||||||
tmcs = 0.0
|
|
||||||
|
|
||||||
f.write(
|
|
||||||
f"{label} {y:>11.5f}" +
|
|
||||||
f"{z:>13.5f}{dcs:>15.10f}" +
|
|
||||||
f"{scs:>15.10f}{tmcs:>15.5f}" +
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
ind += 1
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _section_rk(profile):
|
def _section_rk(profile):
|
||||||
|
|||||||
@@ -121,6 +121,40 @@ class RunSolverTranslate(PamhyrTranslate):
|
|||||||
"Export cancelled: initial discharges of reach {reach} must be "
|
"Export cancelled: initial discharges of reach {reach} must be "
|
||||||
"greater than -500 m3/s."
|
"greater than -500 m3/s."
|
||||||
)
|
)
|
||||||
|
self._dict["duplicate_point_name"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: several points are named '{name}' in "
|
||||||
|
"profile {profile} of reach {reach}."
|
||||||
|
)
|
||||||
|
self._dict["main_channel"] = _translate("Solver", "main channel")
|
||||||
|
self._dict["active_bed"] = _translate("Solver", "active bed")
|
||||||
|
self._dict["bed_limits_invalid"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: in profile {profile} of reach {reach}, the "
|
||||||
|
"{bed} limits (points '{left}' and '{right}', or the profile "
|
||||||
|
"ends) must be ordered from left to right with at least one "
|
||||||
|
"point between them."
|
||||||
|
)
|
||||||
|
self._dict["missing_sediment_layers"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: point {point} of profile {profile} of reach "
|
||||||
|
"{reach} has no sediment layer, which the sediment transport "
|
||||||
|
"requires."
|
||||||
|
)
|
||||||
|
self._dict["invalid_sediment_layer"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: layer '{layer}' of sediment layers '{sl}' "
|
||||||
|
"(profile {profile} of reach {reach}) must have a thickness "
|
||||||
|
">= 0, D50 > 0 m, sigma >= 1 (1 for a uniform sediment) and a "
|
||||||
|
"critical constraint >= 0 Pa."
|
||||||
|
)
|
||||||
|
self._dict["too_many_compartments"] = _translate(
|
||||||
|
"Solver",
|
||||||
|
"Export cancelled: sediment layers '{sl}' (profile {profile} of "
|
||||||
|
"reach {reach}) give {count} compartments, RubarBE accepts at "
|
||||||
|
"most {maximum}. A non erodible compartment is added under an "
|
||||||
|
"erodible last layer."
|
||||||
|
)
|
||||||
self._dict["export_failed"] = _translate(
|
self._dict["export_failed"] = _translate(
|
||||||
"Solver", "Export failed; task cancelled"
|
"Solver", "Export failed; task cancelled"
|
||||||
)
|
)
|
||||||
Reference in new issue
Block a user