Skip to content

Add Base Units and Unit System as SimulationParams's property #1130

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 4 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
38 changes: 14 additions & 24 deletions flow360/component/simulation/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,34 +136,22 @@ def unit_converter(dimension, params, required_by: List[str] = None) -> u.UnitSy

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():
if params.operating_condition.type_name == "LiquidOperatingCondition":
if params.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
require(["operating_condition", "thermal_state", "temperature"], required_by, params)
base_temperature = params.operating_condition.thermal_state.temperature.to("K").v.item()
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":
# Provides an imaginary "speed of sound"
# Resulting in a hardcoded freestream mach of `LIQUID_IMAGINARY_FREESTREAM_MACH`
# To ensure incompressible range.
if params.operating_condition.velocity_magnitude.value != 0:
return (
params.operating_condition.velocity_magnitude / LIQUID_IMAGINARY_FREESTREAM_MACH
)
return (
params.operating_condition.reference_velocity_magnitude
/ LIQUID_IMAGINARY_FREESTREAM_MACH
)
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":
require(["operating_condition", "thermal_state", "temperature"], required_by, params)
base_velocity = params.base_velocity.v.item()
return base_velocity

def get_base_time():
Expand All @@ -179,11 +167,9 @@ def get_base_angular_velocity():
return base_angular_velocity

def get_base_density():
if params.operating_condition.type_name == "LiquidOperatingCondition":
return params.operating_condition.material.density
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()
return base_density

def get_base_viscosity():
Expand Down Expand Up @@ -262,6 +248,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 = params.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
Expand Down
75 changes: 74 additions & 1 deletion flow360/component/simulation/simulation_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -533,6 +542,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:
"""
Expand Down
4 changes: 4 additions & 0 deletions tests/simulation/framework/test_entities_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down