diff --git a/flow360/component/simulation/conversion.py b/flow360/component/simulation/conversion.py index 109cd97af..2b418cbcc 100644 --- a/flow360/component/simulation/conversion.py +++ b/flow360/component/simulation/conversion.py @@ -134,10 +134,11 @@ def unit_converter(dimension, params, required_by: List[str] = None): def get_base_length(): require(["private_attribute_asset_cache", "project_length_unit"], required_by, params) - base_length = params.private_attribute_asset_cache.project_length_unit.to("m").v.item() + base_length = params.base_length.v.item() return base_length def get_base_temperature(): +<<<<<<< HEAD require(["operating_condition", "thermal_state", "temperature"], required_by, params) base_temperature = params.operating_condition.thermal_state.temperature.to("K").v.item() return base_temperature @@ -145,14 +146,30 @@ def get_base_temperature(): def get_base_velocity(): require(["operating_condition", "thermal_state", "temperature"], required_by, params) base_velocity = params.operating_condition.thermal_state.speed_of_sound.to("m/s").v.item() +======= + if params.operating_condition.type_name != "LiquidOperatingCondition": + # Temperature in Liquid condition has no effect because the thermal features will be disabled. + # Also the viscosity will be constant. + # pylint:disable = no-member + require(["operating_condition", "thermal_state", "temperature"], required_by, params) + base_temperature = params.base_temperature.v.item() + return base_temperature + + def get_base_velocity(): + if params.operating_condition.type_name != "LiquidOperatingCondition": + require(["operating_condition", "thermal_state", "temperature"], required_by, params) + base_velocity = params.base_velocity.v.item() +>>>>>>> 7fa70e72 (Add Base Units and Unit System as SimulationParams's property (#1130)) return base_velocity def get_base_time(): - base_length = get_base_length() - base_velocity = get_base_velocity() - base_time = base_length / base_velocity + base_time = params.base_time.v.item() return base_time + def get_base_mass(): + base_mass = params.base_mass.v.item() + return base_mass + def get_base_angular_velocity(): base_time = get_base_time() base_angular_velocity = 1 / base_time @@ -160,9 +177,15 @@ def get_base_angular_velocity(): return base_angular_velocity def get_base_density(): +<<<<<<< HEAD require(["operating_condition", "thermal_state", "density"], required_by, params) base_density = params.operating_condition.thermal_state.density.to("kg/m**3").v.item() +======= + if params.operating_condition.type_name != "LiquidOperatingCondition": + require(["operating_condition", "thermal_state", "density"], required_by, params) + base_density = params.base_density.v.item() +>>>>>>> 7fa70e72 (Add Base Units and Unit System as SimulationParams's property (#1130)) return base_density def get_base_viscosity(): @@ -241,6 +264,10 @@ def get_base_thermal_conductivity(): base_length = get_base_length() flow360_conversion_unit_system.base_length = base_length + elif dimension == u.dimensions.mass: + base_mass = get_base_mass() + flow360_conversion_unit_system.base_mass = base_mass + elif dimension == u.dimensions.temperature: base_temperature = get_base_temperature() flow360_conversion_unit_system.base_temperature = base_temperature diff --git a/flow360/component/simulation/simulation_params.py b/flow360/component/simulation/simulation_params.py index 3db172191..6c7dc264b 100644 --- a/flow360/component/simulation/simulation_params.py +++ b/flow360/component/simulation/simulation_params.py @@ -7,8 +7,12 @@ from typing import Annotated, List, Optional, Union import pydantic as pd +import unyt as u -from flow360.component.simulation.conversion import unit_converter +from flow360.component.simulation.conversion import ( + LIQUID_IMAGINARY_FREESTREAM_MACH, + unit_converter, +) from flow360.component.simulation.framework.base_model import Flow360BaseModel from flow360.component.simulation.framework.entity_registry import EntityRegistry from flow360.component.simulation.framework.param_utils import ( @@ -52,10 +56,15 @@ ) from flow360.component.simulation.time_stepping.time_stepping import Steady, Unsteady from flow360.component.simulation.unit_system import ( + AbsoluteTemperatureType, + DensityType, DimensionedTypes, LengthType, + MassType, + TimeType, UnitSystem, UnitSystemType, + VelocityType, is_flow360_unit, unit_system_manager, unyt_quantity, @@ -505,6 +514,70 @@ def _update_entity_private_attrs(self, registry: EntityRegistry) -> EntityRegist return registry + @property + def base_length(self) -> LengthType: + """Get base length unit for non-dimensionalization""" + # pylint:disable=no-member + return self.private_attribute_asset_cache.project_length_unit.to("m") + + @property + def base_temperature(self) -> AbsoluteTemperatureType: + """Get base temperature unit for non-dimensionalization""" + # pylint:disable=no-member + if self.operating_condition.type_name == "LiquidOperatingCondition": + # Temperature in this condition has no effect because the thermal features will be disabled. + # Also the viscosity will be constant. + # pylint:disable = no-member + return 273 * u.K + return self.operating_condition.thermal_state.temperature.to("K") + + @property + def base_velocity(self) -> VelocityType: + """Get base velocity unit for non-dimensionalization""" + # pylint:disable=no-member + if self.operating_condition.type_name == "LiquidOperatingCondition": + # Provides an imaginary "speed of sound" + # Resulting in a hardcoded freestream mach of `LIQUID_IMAGINARY_FREESTREAM_MACH` + # To ensure incompressible range. + if self.operating_condition.velocity_magnitude.value != 0: + return ( + self.operating_condition.velocity_magnitude / LIQUID_IMAGINARY_FREESTREAM_MACH + ).to("m/s") + return ( + self.operating_condition.reference_velocity_magnitude + / LIQUID_IMAGINARY_FREESTREAM_MACH + ).to("m/s") + return self.operating_condition.thermal_state.speed_of_sound.to("m/s") + + @property + def base_density(self) -> DensityType: + """Get base density unit for non-dimensionalization""" + # pylint:disable=no-member + if self.operating_condition.type_name == "LiquidOperatingCondition": + return self.operating_condition.material.density.to("kg/m**3") + return self.operating_condition.thermal_state.density.to("kg/m**3") + + @property + def base_mass(self) -> MassType: + """Get base mass unit for non-dimensionalization""" + return self.base_density * self.base_length**3 + + @property + def base_time(self) -> TimeType: + """Get base time unit for non-dimensionalization""" + return self.base_length / self.base_velocity + + @property + def flow360_unit_system(self) -> u.UnitSystem: + """Get the unit system for non-dimensionalization""" + return u.UnitSystem( + name="flow360_nondim", + length_unit=self.base_length, + mass_unit=self.base_mass, + time_unit=self.base_time, + temperature_unit=self.base_temperature, + ) + @property def used_entity_registry(self) -> EntityRegistry: """ diff --git a/tests/simulation/framework/test_entities_v2.py b/tests/simulation/framework/test_entities_v2.py index debed903f..36795dfdc 100644 --- a/tests/simulation/framework/test_entities_v2.py +++ b/tests/simulation/framework/test_entities_v2.py @@ -211,6 +211,10 @@ class TempSimulationParam(_ParamModelBase): udd: Optional[TempUserDefinedDynamic] = pd.Field(None) private_attribute_asset_cache: AssetCache = pd.Field(AssetCache(), frozen=True) + @property + def base_length(self) -> LengthType: + return self.private_attribute_asset_cache.project_length_unit.to("m") + def preprocess(self): """ Supply self._supplementary_registry to the construction of