Skip to content

[Hotfix 25.2]: Add BET Validator to check initial_blade_direction in an unsteady simulation #1144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

from pydantic import ValidationInfo

from flow360.component.simulation.validation.validation_context import (
TimeSteppingType,
get_validation_info,
)


def _check_bet_disk_initial_blade_direction_and_blade_line_chord(bet_disk):
if bet_disk.blade_line_chord > 0 and bet_disk.initial_blade_direction is None:
Expand All @@ -20,6 +25,7 @@ def _check_bet_disk_initial_blade_direction_and_blade_line_chord(bet_disk):


# pylint: disable=unused-argument
# This is to enable getting name from the info.
def _check_bet_disk_alphas_in_order(value, info: ValidationInfo):
if any(value != sorted(value)):
raise ValueError("the alphas are not in increasing order.")
Expand Down Expand Up @@ -51,6 +57,18 @@ def _check_bet_disk_duplicate_twists(value, info: ValidationInfo):
return value


def _check_bet_disk_initial_blade_direction(value, info: ValidationInfo):
validation_info = get_validation_info()
if validation_info is None:
return value

if validation_info.time_stepping == TimeSteppingType.UNSTEADY and value is None:
raise ValueError(
"The initial_blade_direction must be specified if performing an unsteady BET Line simulation."
)
return value


def _check_bet_disk_sectional_radius_and_polars(bet_disk):
radiuses = bet_disk.sectional_radiuses
polars = bet_disk.sectional_polars
Expand Down
7 changes: 7 additions & 0 deletions flow360/component/simulation/models/volume_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
_check_bet_disk_alphas_in_order,
_check_bet_disk_duplicate_chords,
_check_bet_disk_duplicate_twists,
_check_bet_disk_initial_blade_direction,
_check_bet_disk_initial_blade_direction_and_blade_line_chord,
_check_bet_disk_sectional_radius_and_polars,
)
Expand Down Expand Up @@ -741,6 +742,12 @@ def check_bet_disk_duplicate_twists(cls, value, info: pd.ValidationInfo):
"""validate duplicates in twists in BET disks"""
return _check_bet_disk_duplicate_twists(value, info)

@pd.field_validator("initial_blade_direction", mode="after")
@classmethod
def invalid_growth_rate(cls, value, info: pd.ValidationInfo):
"""Ensure initial_blade_direction is specified in an unsteady simulation"""
return _check_bet_disk_initial_blade_direction(value, info)

@pd.model_validator(mode="after")
@_validator_append_instance_name
def check_bet_disk_sectional_radius_and_polars(self):
Expand Down
33 changes: 32 additions & 1 deletion flow360/component/simulation/validation/validation_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""

import contextvars
from enum import Enum
from functools import wraps
from typing import Any, Callable, List, Literal, Union

Expand All @@ -26,6 +27,26 @@
# when running validation with ALL, it will report errors happing in all scenarios in one validation pass
ALL = "All"


class TimeSteppingType(Enum):
"""
Enum for time stepping type

Attributes
----------
STEADY : str
Represents a steady simulation.
UNSTEADY : str
Represents an unsteady simulation.
UNSET : str
The time stepping is unset.
"""

STEADY = "Steady"
UNSTEADY = "Unsteady"
UNSET = "Unset"


_validation_level_ctx = contextvars.ContextVar("validation_levels", default=None)
_validation_info_ctx = contextvars.ContextVar("validation_info", default=None)

Expand All @@ -47,7 +68,7 @@ class ParamsValidationInfo: # pylint:disable=too-few-public-methods
on mesher option (auto or quasi 3d).
"""

__slots__ = ["auto_farfield_method", "is_beta_mesher"]
__slots__ = ["auto_farfield_method", "is_beta_mesher", "time_stepping"]

@classmethod
def _get_auto_farfield_method_(cls, param_as_dict: dict):
Expand All @@ -71,9 +92,19 @@ def _get_is_beta_mesher_(cls, param_as_dict: dict):
except KeyError:
return False

@classmethod
def _get_time_stepping_(cls, param_as_dict: dict):
try:
if param_as_dict["time_stepping"]["type_name"] == "Unsteady":
return TimeSteppingType.UNSTEADY
return TimeSteppingType.STEADY
except KeyError:
return TimeSteppingType.UNSET

def __init__(self, param_as_dict: dict):
self.auto_farfield_method = self._get_auto_farfield_method_(param_as_dict=param_as_dict)
self.is_beta_mesher = self._get_is_beta_mesher_(param_as_dict=param_as_dict)
self.time_stepping = self._get_time_stepping_(param_as_dict=param_as_dict)


class ValidationContext:
Expand Down
24 changes: 24 additions & 0 deletions tests/simulation/params/test_validators_bet_disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import pytest

import flow360.component.simulation.units as u
from flow360.component.simulation import services
from flow360.component.simulation.models.volume_models import BETDisk
from flow360.component.simulation.simulation_params import SimulationParams
from flow360.component.simulation.time_stepping.time_stepping import Unsteady
from tests.simulation.translator.utils.xv15_bet_disk_helper import createBETDiskSteady
from tests.simulation.translator.utils.xv15BETDisk_param_generator import (
_BET_cylinder,
Expand Down Expand Up @@ -56,6 +58,28 @@ def test_bet_disk_initial_blade_direction_with_bet_name(create_steady_bet_disk):
bet_disk.blade_line_chord = 0.1 * u.inch


def test_bet_disk_initial_blade_direction_with_unsteady_simulation(create_steady_bet_disk):
with u.SI_unit_system:
params = SimulationParams(
models=[create_steady_bet_disk],
time_stepping=Unsteady(
step_size=0.01 * u.s,
steps=120,
),
)

params, errors, _ = services.validate_model(
params_as_dict=params.model_dump(mode="json"),
validated_by=services.ValidationCalledBy.LOCAL,
root_item_type="VolumeMesh",
validation_level="Case",
)
assert len(errors) == 1
assert errors[0]["msg"] == (
"Value error, The initial_blade_direction must be specified if performing an unsteady BET Line simulation."
)


def test_bet_disk_disorder_alphas(create_steady_bet_disk):
bet_disk = create_steady_bet_disk
with pytest.raises(
Expand Down