From 784ee243db01e6ff7e5b9a2f84b0482612dce6d8 Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Wed, 1 Apr 2026 11:09:41 +0000 Subject: [PATCH 1/8] new validator and tests --- .../meshing_param/snappy/snappy_params.py | 9 +++ .../test_refinements_validation.py | 78 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_params.py b/flow360/component/simulation/meshing_param/snappy/snappy_params.py index b5f1097ca..034fc3647 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_params.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_params.py @@ -58,6 +58,15 @@ def _check_body_refinements_w_defaults(self): if isinstance(refinement, BodyRefinement): if refinement.min_spacing is None and refinement.max_spacing is None: continue + + if refinement.min_spacing is None and refinement.proximity_spacing: + if refinement.proximity_spacing > self.defaults.min_spacing: + log.warning( + f"Proximity spacing ({refinement.proximity_spacing}) was set higher than the minimal spacing" + + f"({self.defaults.min_spacing}), setting proximity spacing to minimal spacing." + ) + refinement.proximity_spacing = self.defaults.min_spacing + if refinement.min_spacing is None and self.defaults.min_spacing.to( "m" ) > refinement.max_spacing.to("m"): diff --git a/tests/simulation/params/meshing_validation/test_refinements_validation.py b/tests/simulation/params/meshing_validation/test_refinements_validation.py index 13fcfda77..5b97aabdd 100644 --- a/tests/simulation/params/meshing_validation/test_refinements_validation.py +++ b/tests/simulation/params/meshing_validation/test_refinements_validation.py @@ -207,3 +207,81 @@ def test_snappy_body_refinement_validator(): snappy.BodyRefinement( bodies=SnappyBody(name="body1", surfaces=[Surface(name="surface")]), gap_resolution=2 * u.mm ) + + +def test_snappy_proximity_spacing_clamped_to_default_min_spacing(): + """When min_spacing is not set on a BodyRefinement but proximity_spacing exceeds + defaults.min_spacing, proximity_spacing should be clamped to defaults.min_spacing.""" + with SI_unit_system: + body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) + params = snappy.SurfaceMeshingParams( + defaults=snappy.SurfaceMeshingDefaults( + min_spacing=3 * u.mm, max_spacing=10 * u.mm, gap_resolution=0.1 * u.mm + ), + refinements=[ + snappy.BodyRefinement( + bodies=body, + proximity_spacing=5 * u.mm, + max_spacing=10 * u.mm, + ), + ], + ) + # proximity_spacing (5 mm) > defaults.min_spacing (3 mm) => clamped to 3 mm + assert params.refinements[0].proximity_spacing == 3 * u.mm + + +def test_snappy_proximity_spacing_not_clamped_when_below_default_min_spacing(): + """When proximity_spacing is already <= defaults.min_spacing, it should remain unchanged.""" + with SI_unit_system: + body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) + params = snappy.SurfaceMeshingParams( + defaults=snappy.SurfaceMeshingDefaults( + min_spacing=3 * u.mm, max_spacing=10 * u.mm, gap_resolution=0.1 * u.mm + ), + refinements=[ + snappy.BodyRefinement( + bodies=body, + proximity_spacing=2 * u.mm, + max_spacing=10 * u.mm, + ), + ], + ) + # proximity_spacing (2 mm) <= defaults.min_spacing (3 mm) => unchanged + assert params.refinements[0].proximity_spacing == 2 * u.mm + + +def test_snappy_proximity_spacing_with_explicit_min_spacing_uses_entity_validator(): + """When both min_spacing and proximity_spacing are set on the refinement, + the entity-level validator clamps proximity_spacing to min_spacing (not defaults).""" + with SI_unit_system: + body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) + refinement = snappy.BodyRefinement( + bodies=body, + min_spacing=4 * u.mm, + proximity_spacing=6 * u.mm, + max_spacing=10 * u.mm, + ) + # Entity-level validator: proximity_spacing (6 mm) > min_spacing (4 mm) => clamped to 4 mm + assert refinement.proximity_spacing == 4 * u.mm + + +def test_snappy_proximity_spacing_not_clamped_when_min_spacing_is_set(): + """When min_spacing is explicitly set, the general validator should not interfere.""" + with SI_unit_system: + body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) + params = snappy.SurfaceMeshingParams( + defaults=snappy.SurfaceMeshingDefaults( + min_spacing=1 * u.mm, max_spacing=10 * u.mm, gap_resolution=0.1 * u.mm + ), + refinements=[ + snappy.BodyRefinement( + bodies=body, + min_spacing=4 * u.mm, + proximity_spacing=3 * u.mm, + max_spacing=10 * u.mm, + ), + ], + ) + # min_spacing is set => general validator skipped, entity validator sees + # proximity_spacing (3 mm) < min_spacing (4 mm) => no clamping + assert params.refinements[0].proximity_spacing == 3 * u.mm From 14a89f236b69adacaa0b5029b65dfb47eed1ce1a Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Wed, 1 Apr 2026 12:05:46 +0000 Subject: [PATCH 2/8] sorted --- .../component/simulation/meshing_param/snappy/snappy_params.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_params.py b/flow360/component/simulation/meshing_param/snappy/snappy_params.py index 034fc3647..048a816d4 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_params.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_params.py @@ -66,7 +66,7 @@ def _check_body_refinements_w_defaults(self): + f"({self.defaults.min_spacing}), setting proximity spacing to minimal spacing." ) refinement.proximity_spacing = self.defaults.min_spacing - + if refinement.min_spacing is None and self.defaults.min_spacing.to( "m" ) > refinement.max_spacing.to("m"): From ffffe2daad2a13871b42f92f47c83328bb78d80e Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Wed, 1 Apr 2026 12:07:45 +0000 Subject: [PATCH 3/8] bugbot --- .../simulation/meshing_param/snappy/snappy_params.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_params.py b/flow360/component/simulation/meshing_param/snappy/snappy_params.py index 048a816d4..69a22646f 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_params.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_params.py @@ -56,17 +56,17 @@ def _check_body_refinements_w_defaults(self): return self for refinement in self.refinements: if isinstance(refinement, BodyRefinement): - if refinement.min_spacing is None and refinement.max_spacing is None: - continue - if refinement.min_spacing is None and refinement.proximity_spacing: if refinement.proximity_spacing > self.defaults.min_spacing: log.warning( - f"Proximity spacing ({refinement.proximity_spacing}) was set higher than the minimal spacing" + f"Proximity spacing ({refinement.proximity_spacing}) was set higher than the minimal spacing " + f"({self.defaults.min_spacing}), setting proximity spacing to minimal spacing." ) refinement.proximity_spacing = self.defaults.min_spacing + if refinement.min_spacing is None and refinement.max_spacing is None: + continue + if refinement.min_spacing is None and self.defaults.min_spacing.to( "m" ) > refinement.max_spacing.to("m"): From 0b854ce92fedc19353192d7efbad39943213cedc Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Wed, 1 Apr 2026 12:20:11 +0000 Subject: [PATCH 4/8] linter --- .../simulation/meshing_param/snappy/snappy_params.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_params.py b/flow360/component/simulation/meshing_param/snappy/snappy_params.py index 69a22646f..139a17f44 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_params.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_params.py @@ -59,8 +59,9 @@ def _check_body_refinements_w_defaults(self): if refinement.min_spacing is None and refinement.proximity_spacing: if refinement.proximity_spacing > self.defaults.min_spacing: log.warning( - f"Proximity spacing ({refinement.proximity_spacing}) was set higher than the minimal spacing " - + f"({self.defaults.min_spacing}), setting proximity spacing to minimal spacing." + f"Proximity spacing ({refinement.proximity_spacing}) was set higher " + + f"than the minimal spacing ({self.defaults.min_spacing}), " + + "setting proximity spacing to minimal spacing." ) refinement.proximity_spacing = self.defaults.min_spacing From 79c7a20878af766412285a58c598cae087502d0b Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Thu, 2 Apr 2026 14:44:05 +0000 Subject: [PATCH 5/8] changed warning to error --- .../snappy/snappy_mesh_refinements.py | 7 +--- .../meshing_param/snappy/snappy_params.py | 8 ++-- .../test_refinements_validation.py | 41 ++++++++----------- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py index 0beed13d3..655455ab3 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py @@ -12,8 +12,6 @@ from flow360.component.simulation.meshing_param.volume_params import UniformRefinement from flow360.component.simulation.primitives import SnappyBody, Surface from flow360.component.simulation.unit_system import AngleType, LengthType -from flow360.log import log - class SnappyEntityRefinement(Flow360BaseModel, metaclass=ABCMeta): """ @@ -36,11 +34,10 @@ def _check_spacing_order(self) -> Self: def _check_proximity_spacing(self) -> Self: if self.min_spacing and self.proximity_spacing: if self.proximity_spacing > self.min_spacing: - log.warning( + raise ValueError( f"Proximity spacing ({self.proximity_spacing}) was set higher than the minimal spacing" - + f"({self.min_spacing}), setting proximity spacing to minimal spacing." + + f"({self.min_spacing})." ) - self.proximity_spacing = self.min_spacing return self diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_params.py b/flow360/component/simulation/meshing_param/snappy/snappy_params.py index 139a17f44..44328b81d 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_params.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_params.py @@ -58,12 +58,10 @@ def _check_body_refinements_w_defaults(self): if isinstance(refinement, BodyRefinement): if refinement.min_spacing is None and refinement.proximity_spacing: if refinement.proximity_spacing > self.defaults.min_spacing: - log.warning( - f"Proximity spacing ({refinement.proximity_spacing}) was set higher " - + f"than the minimal spacing ({self.defaults.min_spacing}), " - + "setting proximity spacing to minimal spacing." + raise ValueError( + f"Proximity spacing for a BodyRefinement ({refinement.proximity_spacing}) was set higher " + + f"than the minimal spacing ({self.defaults.min_spacing})." ) - refinement.proximity_spacing = self.defaults.min_spacing if refinement.min_spacing is None and refinement.max_spacing is None: continue diff --git a/tests/simulation/params/meshing_validation/test_refinements_validation.py b/tests/simulation/params/meshing_validation/test_refinements_validation.py index 5b97aabdd..d984a1d8f 100644 --- a/tests/simulation/params/meshing_validation/test_refinements_validation.py +++ b/tests/simulation/params/meshing_validation/test_refinements_validation.py @@ -209,29 +209,27 @@ def test_snappy_body_refinement_validator(): ) -def test_snappy_proximity_spacing_clamped_to_default_min_spacing(): +def test_snappy_proximity_spacing_error_when_exceeds_default_min_spacing(): """When min_spacing is not set on a BodyRefinement but proximity_spacing exceeds - defaults.min_spacing, proximity_spacing should be clamped to defaults.min_spacing.""" - with SI_unit_system: - body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) - params = snappy.SurfaceMeshingParams( + defaults.min_spacing, a ValueError should be raised.""" + message = "Proximity spacing for a BodyRefinement (5.0 mm) was set higher than the minimal spacing (3.0 mm)." + with SI_unit_system, pytest.raises(pd.ValidationError, match=re.escape(message)): + snappy.SurfaceMeshingParams( defaults=snappy.SurfaceMeshingDefaults( min_spacing=3 * u.mm, max_spacing=10 * u.mm, gap_resolution=0.1 * u.mm ), refinements=[ snappy.BodyRefinement( - bodies=body, + bodies=SnappyBody(name="body1", surfaces=[Surface(name="surface")]), proximity_spacing=5 * u.mm, max_spacing=10 * u.mm, ), ], ) - # proximity_spacing (5 mm) > defaults.min_spacing (3 mm) => clamped to 3 mm - assert params.refinements[0].proximity_spacing == 3 * u.mm -def test_snappy_proximity_spacing_not_clamped_when_below_default_min_spacing(): - """When proximity_spacing is already <= defaults.min_spacing, it should remain unchanged.""" +def test_snappy_proximity_spacing_ok_when_below_default_min_spacing(): + """When proximity_spacing is already <= defaults.min_spacing, no error should be raised.""" with SI_unit_system: body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) params = snappy.SurfaceMeshingParams( @@ -246,27 +244,24 @@ def test_snappy_proximity_spacing_not_clamped_when_below_default_min_spacing(): ), ], ) - # proximity_spacing (2 mm) <= defaults.min_spacing (3 mm) => unchanged assert params.refinements[0].proximity_spacing == 2 * u.mm -def test_snappy_proximity_spacing_with_explicit_min_spacing_uses_entity_validator(): - """When both min_spacing and proximity_spacing are set on the refinement, - the entity-level validator clamps proximity_spacing to min_spacing (not defaults).""" - with SI_unit_system: - body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) - refinement = snappy.BodyRefinement( - bodies=body, +def test_snappy_proximity_spacing_error_with_explicit_min_spacing(): + """When both min_spacing and proximity_spacing are set on the refinement + and proximity_spacing > min_spacing, the entity-level validator raises.""" + message = "Proximity spacing (6.0 mm) was set higher than the minimal spacing(4.0 mm)." + with SI_unit_system, pytest.raises(pd.ValidationError, match=re.escape(message)): + snappy.BodyRefinement( + bodies=SnappyBody(name="body1", surfaces=[Surface(name="surface")]), min_spacing=4 * u.mm, proximity_spacing=6 * u.mm, max_spacing=10 * u.mm, ) - # Entity-level validator: proximity_spacing (6 mm) > min_spacing (4 mm) => clamped to 4 mm - assert refinement.proximity_spacing == 4 * u.mm -def test_snappy_proximity_spacing_not_clamped_when_min_spacing_is_set(): - """When min_spacing is explicitly set, the general validator should not interfere.""" +def test_snappy_proximity_spacing_ok_when_min_spacing_is_set(): + """When min_spacing is explicitly set and proximity_spacing <= min_spacing, no error.""" with SI_unit_system: body = SnappyBody(name="body1", surfaces=[Surface(name="surface")]) params = snappy.SurfaceMeshingParams( @@ -282,6 +277,4 @@ def test_snappy_proximity_spacing_not_clamped_when_min_spacing_is_set(): ), ], ) - # min_spacing is set => general validator skipped, entity validator sees - # proximity_spacing (3 mm) < min_spacing (4 mm) => no clamping assert params.refinements[0].proximity_spacing == 3 * u.mm From 96970c389d54ed3c731461b1f4c9f0f1ceff50c2 Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Thu, 2 Apr 2026 14:52:00 +0000 Subject: [PATCH 6/8] black --- .../simulation/meshing_param/snappy/snappy_mesh_refinements.py | 1 + 1 file changed, 1 insertion(+) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py index 655455ab3..10d8616ba 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py @@ -13,6 +13,7 @@ from flow360.component.simulation.primitives import SnappyBody, Surface from flow360.component.simulation.unit_system import AngleType, LengthType + class SnappyEntityRefinement(Flow360BaseModel, metaclass=ABCMeta): """ Base refinement for snappyHexMesh. From 60d64f049b0cf83ec4c540f2c076c7fd9d833d1b Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Thu, 2 Apr 2026 15:19:58 +0000 Subject: [PATCH 7/8] bugbot --- .../simulation/meshing_param/snappy/snappy_mesh_refinements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py index 10d8616ba..34645afdd 100644 --- a/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py +++ b/flow360/component/simulation/meshing_param/snappy/snappy_mesh_refinements.py @@ -36,7 +36,7 @@ def _check_proximity_spacing(self) -> Self: if self.min_spacing and self.proximity_spacing: if self.proximity_spacing > self.min_spacing: raise ValueError( - f"Proximity spacing ({self.proximity_spacing}) was set higher than the minimal spacing" + f"Proximity spacing ({self.proximity_spacing}) was set higher than the minimal spacing " + f"({self.min_spacing})." ) return self From a4a4adfc2fd067bc725a78cb2a5cb427080d00c1 Mon Sep 17 00:00:00 2001 From: piotrkluba Date: Thu, 2 Apr 2026 15:29:32 +0000 Subject: [PATCH 8/8] tests adjusted --- .../params/meshing_validation/test_refinements_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simulation/params/meshing_validation/test_refinements_validation.py b/tests/simulation/params/meshing_validation/test_refinements_validation.py index d984a1d8f..fe5df3001 100644 --- a/tests/simulation/params/meshing_validation/test_refinements_validation.py +++ b/tests/simulation/params/meshing_validation/test_refinements_validation.py @@ -250,7 +250,7 @@ def test_snappy_proximity_spacing_ok_when_below_default_min_spacing(): def test_snappy_proximity_spacing_error_with_explicit_min_spacing(): """When both min_spacing and proximity_spacing are set on the refinement and proximity_spacing > min_spacing, the entity-level validator raises.""" - message = "Proximity spacing (6.0 mm) was set higher than the minimal spacing(4.0 mm)." + message = "Proximity spacing (6.0 mm) was set higher than the minimal spacing (4.0 mm)." with SI_unit_system, pytest.raises(pd.ValidationError, match=re.escape(message)): snappy.BodyRefinement( bodies=SnappyBody(name="body1", surfaces=[Surface(name="surface")]),