diff --git a/src/Solver/RubarBE.py b/src/Solver/RubarBE.py index dc43da93..ea5f21a1 100644 --- a/src/Solver/RubarBE.py +++ b/src/Solver/RubarBE.py @@ -170,7 +170,8 @@ class Rubar3(CommandLineSolver): hydraulics = self._hydraulic_data(study, values) geometry = self._geometry_data(hydraulics["edge"], trased) solid = self._solid_boundary( - study.river, hydraulics["edge"], values, trased) + study.river, hydraulics["edge"], values, trased, + hydraulics["warnings"]) saves = self._save_data(values, hydraulics) except RubarExportError as error: self._cancel(qlog, str(error)) @@ -244,7 +245,7 @@ class Rubar3(CommandLineSolver): reach=edge.name)) warnings = [] - boundaries = self._check_boundaries(river, edge, values) + boundaries = self._check_boundaries(river, edge, values, warnings) return { "edge": edge, @@ -381,7 +382,7 @@ class Rubar3(CommandLineSolver): return float(old_pamhyr_date_to_timestamp(value)) return float(value) - def _check_boundaries(self, river, edge, values): + def _check_boundaries(self, river, edge, values, warnings): """Liquid boundary conditions used for CONDAM, REGIME and CONDAV. Return {'hydro': bc, 'condav': bc} (or None)""" trad = RunSolverTranslate() @@ -417,12 +418,12 @@ class Rubar3(CommandLineSolver): upstream = self._select_boundaries( at(edge.node1), self._upstream_types[condam], edge.node1, - {"TD": f"CONDAM={condam}"}, f"CONDAM={condam}" + {"TD": f"CONDAM={condam}"}, f"CONDAM={condam}", warnings ) downstream = self._select_boundaries( at(edge.node2), self._downstream_types[condav], edge.node2, {"ZD": f"CONDAV={condav}", "TZ": f"CONDAV={condav}"}, - f"CONDAV={condav}" + f"CONDAV={condav}", warnings ) return { @@ -430,9 +431,26 @@ class Rubar3(CommandLineSolver): "condav": downstream.get("ZD", downstream.get("TZ")), } - def _select_boundaries(self, bcs, expected, node, required_by, setting): + @staticmethod + def _ignore_empty(bcs, node, warnings): + """A boundary condition without value carries no data: it is + ignored with a warning. Return (kept, ignored)""" + trad = RunSolverTranslate() + kept, ignored = [], [] + for bc in bcs: + if len(bc) == 0: + warnings.append(trad["boundary_empty_ignored"].format( + name=bc.name, node=node.name)) + ignored.append(bc) + else: + kept.append(bc) + return kept, ignored + + def _select_boundaries(self, bcs, expected, node, required_by, setting, + warnings): trad = RunSolverTranslate() selected = {} + bcs, ignored = self._ignore_empty(bcs, node, warnings) for bc in bcs: kind = self._boundary_kinds[bc.bctype] @@ -443,9 +461,6 @@ class Rubar3(CommandLineSolver): if bc.bctype in selected: raise RubarExportError(trad["boundary_ambiguous"].format( kind=kind, node=node.name)) - if len(bc) == 0: - raise RubarExportError(trad["boundary_empty"].format( - name=bc.name, node=node.name)) times = [d[0] for d in bc.data] if bc.bctype != "ZD" and any( b < a for a, b in zip(times, times[1:])): @@ -455,13 +470,19 @@ class Rubar3(CommandLineSolver): for bctype in expected: if bctype not in selected: - raise RubarExportError(trad["boundary_missing"].format( + message = trad["boundary_missing"].format( setting=required_by[bctype], - kind=self._boundary_kinds[bctype], node=node.name)) + kind=self._boundary_kinds[bctype], node=node.name) + # The required condition may be the ignored empty one + empty = [bc.name for bc in ignored if bc.bctype == bctype] + if empty: + message += " " + trad["boundary_missing_empty"].format( + names=", ".join(empty)) + raise RubarExportError(message) return selected - def _solid_boundary(self, river, edge, values, trased): + def _solid_boundary(self, river, edge, values, trased, warnings): """Solid boundary condition written in HYDROS. RubarBE reads it at the upstream node when TRASED is enabled and CONDAM=1 (CONDAM=2 is refused), and has no downstream solid condition (rubar_init.f90, @@ -476,17 +497,19 @@ class Rubar3(CommandLineSolver): bc for bc in river.boundary_condition.get_tab("solid") if not bc.is_deleted() and bc.bctype == "SL" ] - for bc in solid: - if bc.node == edge.node2: - raise RubarExportError( - trad["solid_boundary_downstream"].format( - name=bc.name, node=edge.node2.name)) + downstream, _ = self._ignore_empty( + [bc for bc in solid if bc.node == edge.node2], edge.node2, + warnings) + if downstream: + raise RubarExportError( + trad["solid_boundary_downstream"].format( + name=downstream[0].name, node=edge.node2.name)) expected = ("SL",) if condam == "1" else () selected = self._select_boundaries( [bc for bc in solid if bc.node == edge.node1], expected, edge.node1, {"SL": f"TRASED=O, CONDAM={condam}"}, - f"CONDAM={condam}" + f"CONDAM={condam}", warnings ) bc = selected.get("SL") if bc is None: diff --git a/src/View/RunSolver/Translate.py b/src/View/RunSolver/Translate.py index c280fa33..e0f2902e 100644 --- a/src/View/RunSolver/Translate.py +++ b/src/View/RunSolver/Translate.py @@ -129,10 +129,14 @@ class RunSolverTranslate(PamhyrTranslate): "Export cancelled: several {kind} boundary conditions at node " "{node}." ) - self._dict["boundary_empty"] = _translate( + self._dict["boundary_empty_ignored"] = _translate( "Solver", - "Export cancelled: boundary condition {name} at node {node} " - "has no value." + "Boundary condition {name} at node {node} has no value: it is " + "ignored." + ) + self._dict["boundary_missing_empty"] = _translate( + "Solver", + "Empty boundary condition(s) ignored: {names}." ) self._dict["boundary_not_sorted"] = _translate( "Solver",