Skip to content
2 changes: 1 addition & 1 deletion flow360/component/simulation/unit_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def _check_if_input_has_delta_unit(quant):
# pylint: disable=no-member
def _has_dimensions(quant, dim, expect_delta_unit: bool):
"""
Checks the argument has the right dimensionality.
Checks the argument has the right dimensions.
"""

try:
Expand Down
42 changes: 22 additions & 20 deletions flow360/component/simulation/user_code/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,18 +643,18 @@ def disable_relative_temperature_scale(cls, value: str) -> str:
return value

@pd.model_validator(mode="after")
def check_output_units_matches_dimensionality(self) -> str:
"""Check that the output units have the same dimensionality as the expression"""
def check_output_units_matches_dimensions(self) -> str:
"""Check that the output units have the same dimensions as the expression"""
if not self.output_units:
return self
if self.output_units in ("SI_unit_system", "CGS_unit_system", "Imperial_unit_system"):
return self
output_units_dimensionality = u.Unit(self.output_units).dimensions
expression_dimensionality = self.dimensionality
if output_units_dimensionality != expression_dimensionality:
output_units_dimensions = u.Unit(self.output_units).dimensions
expression_dimensions = self.dimensions
if output_units_dimensions != expression_dimensions:
raise ValueError(
f"Output units '{self.output_units}' have different dimensionality "
f"{output_units_dimensionality} than the expression {expression_dimensionality}."
f"Output units '{self.output_units}' have different dimensions "
f"{output_units_dimensions} than the expression {expression_dimensions}."
)

return self
Expand Down Expand Up @@ -873,16 +873,16 @@ def __eq__(self, other):
return super().__eq__(other)

@property
def dimensionality(self):
"""The physical dimensionality of the expression."""
def dimensions(self):
"""The physical dimensions of the expression."""
value = self.evaluate(raise_on_non_evaluable=False, force_evaluate=True)
assert isinstance(
value, (unyt_array, unyt_quantity, list, Number)
), "Non unyt array so no dimensionality"
), "Non unyt array so no dimensions"
if isinstance(value, (unyt_array, unyt_quantity)):
return value.units.dimensions
if isinstance(value, list):
_check_list_items_are_same_dimensionality(value)
_check_list_items_are_same_dimensions(value)
return value[0].units.dimensions
return u.Unit("dimensionless").dimensions

Expand All @@ -891,10 +891,12 @@ def length(self):
"""The number of elements in the expression. 0 for scalar and anything else for vector."""
value = self.evaluate(raise_on_non_evaluable=False, force_evaluate=True)
assert isinstance(
value, (unyt_array, unyt_quantity, list, Number)
value, (unyt_array, unyt_quantity, list, Number, np.ndarray)
), f"Unexpected evaluated result type: {type(value)}"
if isinstance(value, list):
return len(value)
if isinstance(value, np.ndarray):
return 0 if value.shape == () else value.shape[0]
return 0 if isinstance(value, (unyt_quantity, Number)) else value.shape[0]

def __len__(self):
Expand All @@ -905,20 +907,20 @@ def get_output_units(self, input_params=None):
Get the output units of the expression.

- If self.output_units is None, derive the default output unit based on the
value's dimensionality and current unit system.
value's dimensions and current unit system.

- If self.output_units is valid u.Unit string, deserialize it and return it.

- If self.output_units is valid unit system name, derive the default output
unit based on the value's dimensionality and the **given** unit system.
unit based on the value's dimensions and the **given** unit system.

- If expression is a number constant, return None.

- Else raise ValueError.
"""

def get_unit_from_unit_system(expression: Expression, unit_system_name: str):
"""Derive the default output unit based on the value's dimensionality and current unit system"""
"""Derive the default output unit based on the value's dimensions and current unit system"""
numerical_value = expression.evaluate(raise_on_non_evaluable=False, force_evaluate=True)
if isinstance(numerical_value, list):
numerical_value = numerical_value[0]
Expand Down Expand Up @@ -951,16 +953,16 @@ def get_unit_from_unit_system(expression: Expression, unit_system_name: str):
return result


def _check_list_items_are_same_dimensionality(value: list) -> bool:
def _check_list_items_are_same_dimensions(value: list) -> bool:
if all(isinstance(item, Expression) for item in value):
_check_list_items_are_same_dimensionality(
_check_list_items_are_same_dimensions(
[item.evaluate(raise_on_non_evaluable=False, force_evaluate=True) for item in value]
)
return
if all(isinstance(item, unyt_quantity) for item in value):
# ensure all items have the same dimensionality
# ensure all items have the same dimensions
if not all(item.units.dimensions == value[0].units.dimensions for item in value):
raise ValueError("All items in the list must have the same dimensionality.")
raise ValueError("All items in the list must have the same dimensions.")
return
# Also raise when some elements is Number and others are unyt_quantity
if any(isinstance(item, Number) for item in value) and any(
Expand Down Expand Up @@ -1049,7 +1051,7 @@ def _handle_legacy_unyt_values(value):
# Handle list of unyt_quantities:
if isinstance(value, list):
# Only checking when list[unyt_quantity]
_check_list_items_are_same_dimensionality(value)
_check_list_items_are_same_dimensions(value)
if all(isinstance(item, (unyt_quantity, Number)) for item in value):
# try limiting the number of types we need to handle
return unyt_array(value, dtype=np.float64)
Expand Down
Loading
Loading