diff --git a/flow360/component/simulation/models/surface_models.py b/flow360/component/simulation/models/surface_models.py index 7e1dc17c2..9065fa9d1 100644 --- a/flow360/component/simulation/models/surface_models.py +++ b/flow360/component/simulation/models/surface_models.py @@ -308,7 +308,9 @@ class WallRotation(Flow360BaseModel): # pylint: disable=no-member center: LengthType.Point = pd.Field(description="The center of rotation") axis: Axis = pd.Field(description="The axis of rotation.") - angular_velocity: AngularVelocityType = pd.Field("The value of the angular velocity.") + angular_velocity: AngularVelocityType = pd.Field( + description="The value of the angular velocity." + ) type_name: Literal["WallRotation"] = pd.Field("WallRotation", frozen=True) private_attribute_circle_mode: Optional[dict] = pd.Field(None) @@ -321,6 +323,7 @@ class WallRotation(Flow360BaseModel): WallVelocityModelTypes = Annotated[ Union[SlaterPorousBleed, WallRotation], pd.Field(discriminator="type_name") ] +WALL_VELOCITY_MODEL_ADAPTER = pd.TypeAdapter(WallVelocityModelTypes) class WallFunction(Flow360BaseModel): @@ -476,6 +479,15 @@ def _normalize_wall_function(cls, value): return None return value + @pd.field_validator("velocity", mode="before") + @classmethod + def _normalize_velocity(cls, value): + # Sadly we cannot add a discriminator to `velocity` directly because the alternative + # branch is `VelocityVectorType`, which compiles to a tuple schema instead of a model variant. + if isinstance(value, dict) and value.get("type_name") is not None: + return WALL_VELOCITY_MODEL_ADAPTER.validate_python(value) + return value + @pd.model_validator(mode="after") def check_wall_function_conflict(self): """Check no setting is conflicting with the usage of wall function""" diff --git a/tests/simulation/params/test_rotation.py b/tests/simulation/params/test_rotation.py index 72a74e5c2..024852dd7 100644 --- a/tests/simulation/params/test_rotation.py +++ b/tests/simulation/params/test_rotation.py @@ -1,4 +1,5 @@ import pytest +from pydantic import ValidationError from flow360 import u from flow360.component.simulation.models.surface_models import Wall, WallRotation @@ -49,6 +50,34 @@ def test_wall_angular_velocity(): ) +def test_wall_rotation_missing_angular_velocity_reports_required_field(): + with pytest.raises(ValidationError) as exc_info: + Wall.model_validate( + { + "name": "Wheel Front", + "type": "Wall", + "entities": {"stored_entities": []}, + "velocity": { + "axis": [0, -1, 0], + "center": {"value": [0, 0, 0], "units": "m"}, + "type_name": "WallRotation", + }, + } + ) + + errors = exc_info.value.errors() + angular_velocity_errors = [error for error in errors if error["loc"][-1] == "angular_velocity"] + assert len(angular_velocity_errors) == 1 + assert angular_velocity_errors[0]["msg"] == "Field required" + assert all( + not any( + isinstance(segment, str) and ("tuple[" in segment or "function-plain[" in segment) + for segment in error["loc"] + ) + for error in errors + ) + + def test_rotation_expression_with_t_seconds(): with pytest.raises(