Skip to content
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
54 changes: 31 additions & 23 deletions flow360/component/results/results_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from flow360.component.simulation.models.volume_models import BETDisk
from flow360.component.simulation.simulation_params import SimulationParams
from flow360.component.simulation.user_code.core.types import Expression
from flow360.exceptions import Flow360ValueError
from flow360.log import log

Expand Down Expand Up @@ -75,21 +76,28 @@ def _vector_to_np3(vec):
raise Flow360ValueError(f"Invalid vector: {vec}") from exc


def _get_reference_geometry(params: SimulationParams):
def _get_reference_geometry_in_flow360_unit(params: SimulationParams):
# pylint:disable=import-outside-toplevel, no-member, protected-access
from flow360.component.simulation.primitives import ReferenceGeometry

# Fill defaults using preprocessed params
reference_geometry_filled = ReferenceGeometry.fill_defaults(params.reference_geometry, params)

reference_geometry_filled_flow360: ReferenceGeometry = reference_geometry_filled.preprocess(
params=params
)
evaluated_area = None
if isinstance(reference_geometry_filled.area, Expression):
evaluated_area = reference_geometry_filled.area.evaluate(
raise_on_non_evaluable=True, force_evaluate=True
)
else:
evaluated_area = reference_geometry_filled.area
# Fill defaults using preprocessed params

# Extract dimensionless area (in Flow360 units)
area_flow360 = float(reference_geometry_filled_flow360.area.value)
area_flow360 = float(evaluated_area.in_base(params.flow360_unit_system).value)

# Extract dimensionless moment_length
moment_length_flow360 = reference_geometry_filled_flow360.moment_length
moment_length_flow360 = reference_geometry_filled.moment_length.in_base(
params.flow360_unit_system
)

# Convert to numpy array properly - handle both arrays and scalars
try:
Expand All @@ -109,7 +117,7 @@ def _get_reference_geometry(params: SimulationParams):
moment_length_vec_flow360 = np.array([scalar_val, scalar_val, scalar_val], dtype=float)

# Extract dimensionless moment_center
moment_center = reference_geometry_filled_flow360.moment_center
moment_center = reference_geometry_filled.moment_center.in_base(params.flow360_unit_system)
moment_center_flow360 = np.array(
[moment_center[0], moment_center[1], moment_center[2]],
dtype=float,
Expand Down Expand Up @@ -154,21 +162,19 @@ def _get_lift_drag_direction(params: SimulationParams):

def _get_dynamic_pressure_in_flow360_unit(params: SimulationParams):
# pylint:disable=protected-access
oc = params.operating_condition
using_liquid_op = oc.type_name == "LiquidOperatingCondition"

if using_liquid_op:
v_ref = params._liquid_reference_velocity
else:
v_ref = params.base_velocity
v_ref = params.reference_velocity

Mach_ref = params.convert_unit(value=v_ref, target_system="flow360").value
return 0.5 * Mach_ref * Mach_ref


def _build_coeff_env(params) -> Dict[str, Any]:
"""
Get data for computing aerodynamic coefficients in flow360 unit.
"""
# pylint:disable=protected-access
area, moment_length_vec, moment_center_global = _get_reference_geometry(params)
area, moment_length_vec, moment_center_global = _get_reference_geometry_in_flow360_unit(params)
dynamic_pressure = _get_dynamic_pressure_in_flow360_unit(params)
lift_dir, drag_dir = _get_lift_drag_direction(params)
return {
Expand Down Expand Up @@ -341,14 +347,16 @@ def _copy_time_columns(src: Dict[str, list]) -> Dict[str, list]:

@staticmethod
def _iter_zones(values: Dict[str, list]):
zone_names = np.unique(
[
v.split("_")[0] + "_" + v.split("_")[1]
for v in values.keys()
if v.startswith("zone_")
]
)
yield from zone_names
# Support both default "zone_<idx>_<...>" and arbitrary GenericVolume-style names
# such as "blk-2_Force_x" by extracting the prefix before Force/Moment components.
pattern = re.compile(r"^(?P<zone>.+?)_(?:Force|Moment)_[xyz]$")
zone_set = set()
for key in values.keys():
match = pattern.match(key)
if match:
zone_set.add(match.group("zone"))
# Keep deterministic order similar to np.unique behavior
yield from sorted(zone_set)

@staticmethod
def _init_zone_output(out: Dict[str, list], zone_name: str) -> Dict[str, str]:
Expand Down
4 changes: 2 additions & 2 deletions flow360/component/simulation/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def get_flow360_unit_system_liquid(params, to_flow360_unit: bool = False) -> u.U
Parameters
----------
params : SimulationParams
The parameters needed for unit conversion.
The parameters needed for unit conversion that uses liquid operating condition.
to_flow360_unit : bool, optional
Whether we want user input to be converted to flow360 unit system.
The reverse path requires different conversion logic (from solver output to non-flow360 unit system)
Expand All @@ -388,7 +388,7 @@ def get_flow360_unit_system_liquid(params, to_flow360_unit: bool = False) -> u.U
if to_flow360_unit:
base_velocity = params.base_velocity
else:
base_velocity = params._liquid_reference_velocity # pylint:disable=protected-access
base_velocity = params.reference_velocity # pylint:disable=protected-access

time_unit = params.base_length / base_velocity
return u.UnitSystem(
Expand Down
8 changes: 5 additions & 3 deletions flow360/component/simulation/simulation_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,9 +635,9 @@ def base_velocity(self) -> VelocityType:
return self.operating_condition.thermal_state.speed_of_sound.to("m/s")

@property
def _liquid_reference_velocity(self) -> VelocityType:
def reference_velocity(self) -> VelocityType:
"""
This function returns the reference velocity for liquid operating condition.
This function returns the **reference velocity**.
Note that the reference velocity is **NOT** the non-dimensionalization velocity scale

For dimensionalization of Flow360 output (converting FROM flow360 unit)
Expand All @@ -648,8 +648,10 @@ def _liquid_reference_velocity(self) -> VelocityType:
# pylint:disable=no-member
if self.operating_condition.reference_velocity_magnitude is not None:
reference_velocity = (self.operating_condition.reference_velocity_magnitude).to("m/s")
else:
elif self.operating_condition.type_name == "LiquidOperatingCondition":
reference_velocity = self.base_velocity.to("m/s") * LIQUID_IMAGINARY_FREESTREAM_MACH
else:
reference_velocity = self.operating_condition.velocity_magnitude.to("m/s")
return reference_velocity

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,106 +3,106 @@
"Disk0": {
"CFx": 0.0,
"CFy": 0.0,
"CFz": 4.22968413996175e-08,
"CMx": -1.8127217742693215e-07,
"CMy": -8.157247984211948e-08,
"CMz": 3.403336579930425e-09,
"CD": 1.0947228101901768e-08,
"CL": 4.0855611478343206e-08
"CFz": 9.995866680607329e-11,
"CMx": -4.2839428631174267e-10,
"CMy": -1.927774288402842e-10,
"CMz": 8.042987985983815e-14,
"CL": 9.655265782941001e-11,
"CD": 2.5871206692468927e-11
},
"Disk1": {
"CFx": 0.0,
"CFy": 0.0,
"CFz": 4.22968413996175e-08,
"CMx": 8.00618783635617e-08,
"CMy": -8.157247984211948e-08,
"CMz": 3.403336579930425e-09,
"CD": 1.0947228101901768e-08,
"CL": 4.0855611478343206e-08
"CFz": 9.995866680607329e-11,
"CMx": 1.8920747645435302e-10,
"CMy": -1.927774288402842e-10,
"CMz": 8.042987985983815e-14,
"CL": 9.655265782941001e-11,
"CD": 2.5871206692468927e-11
},
"Disk2": {
"CFx": 0.0,
"CFy": 0.0,
"CFz": 4.22968413996175e-08,
"CMx": -8.00618783635617e-08,
"CMy": -8.157247984211948e-08,
"CMz": 3.4033365799304168e-09,
"CD": 1.0947228101901768e-08,
"CL": 4.0855611478343206e-08
"CFz": 9.995866680607329e-11,
"CMx": -1.8920747645435302e-10,
"CMy": -1.927774288402842e-10,
"CMz": 8.042987985983795e-14,
"CL": 9.655265782941001e-11,
"CD": 2.5871206692468927e-11
},
"Disk3": {
"CFx": 0.0,
"CFy": 0.0,
"CFz": 4.22968413996175e-08,
"CMx": 1.8127217742693215e-07,
"CMy": -8.157247984211948e-08,
"CMz": 3.403336579930425e-09,
"CD": 1.0947228101901768e-08,
"CL": 4.0855611478343206e-08
"CFz": 9.995866680607329e-11,
"CMx": 4.2839428631174267e-10,
"CMy": -1.927774288402842e-10,
"CMz": 8.042987985983815e-14,
"CL": 9.655265782941001e-11,
"CD": 2.5871206692468927e-11
}
},
"BETDisk": {
"Disk0": {
"CFx": -0.0013623562270260357,
"CFy": 3.408410091892857e-05,
"CFz": 0.0007882827772506428,
"CMx": -0.002831401005472502,
"CMy": 0.0005588765009247424,
"CMz": -0.005219742604944044,
"CD": -0.0011119124686114067,
"CL": 0.0011140264307336204
"CFx": -3.219609494757832e-06,
"CFy": 8.054978041860516e-08,
"CFz": 1.8629215060223306e-06,
"CMx": -8.003490657116154e-06,
"CMy": 1.284310828124118e-06,
"CMz": -1.389477191280391e-05,
"CL": 2.632740250052527e-06,
"CD": -2.6277443962624396e-06
},
"Disk1": {
"CFx": -0.0013625962301961904,
"CFy": 3.430884768042857e-05,
"CFz": 0.0007882460542094166,
"CMx": 0.002040468650507854,
"CMy": 0.0006176229491711534,
"CMz": 0.0031976789226962144,
"CD": -0.001112153798494314,
"CL": 0.001114053076391001
"CFx": -3.2201766859741037e-06,
"CFy": 8.108091669037237e-08,
"CFz": 1.8628347197252796e-06,
"CMx": 3.5097996437133253e-06,
"CMy": 1.4219783685337042e-06,
"CMz": 5.998145947634071e-06,
"CL": 2.6328032208158226e-06,
"CD": -2.6283147228532113e-06
},
"Disk2": {
"CFx": -0.001362673711029595,
"CFy": -3.4279632118202374e-05,
"CFz": 0.0007882642235870595,
"CMx": -0.002040542978745176,
"CMy": 0.0006176049504929208,
"CMz": -0.003197903001473004,
"CD": -0.00111222393665137,
"CL": 0.0011140906801774294
"CFx": -3.220359793756006e-06,
"CFy": -8.101187255957007e-08,
"CFz": 1.862877658788949e-06,
"CMx": -3.509906765297771e-06,
"CMy": 1.4219711165652415e-06,
"CMz": -5.998589581039346e-06,
"CL": 2.632892088547641e-06,
"CD": -2.6284804779412884e-06
},
"Disk3": {
"CFx": -0.0013623581648587975,
"CFy": -3.403408826757143e-05,
"CFz": 0.0007883305725700714,
"CMx": 0.0028315934600057083,
"CMy": 0.0005589131586812199,
"CMz": 0.005219704135600682,
"CD": -0.0011119019700751836,
"CL": 0.001114073099015057
"CFx": -3.219614074371178e-06,
"CFy": -8.043158724418193e-08,
"CFz": 1.8630344590526649e-06,
"CMx": 8.003926808607675e-06,
"CMy": 1.2844656026937008e-06,
"CMz": 1.389462745437122e-05,
"CL": 2.632850539592837e-06,
"CD": -2.6277195854337923e-06
}
},
"PorousMedium": {
"zone_0": {
"CFx": 2.0891243317035,
"CFx": 0.004937155496228122,
"CFy": 0.0,
"CFz": 0.0,
"CMx": 0.0,
"CMy": 0.7578755447937788,
"CMz": -6.609346148473639e-05,
"CD": 2.017939146321301,
"CL": -0.5407051646319416
"CMy": 1.7910611420548698e-05,
"CMz": -1.561963985015805e-09,
"CL": -0.0012778298710564243,
"CD": 0.004768926002211764
},
"zone_1": {
"CFx": 18.46648378443988,
"CFx": 0.04364120436911098,
"CFy": 0.0,
"CFz": 0.0,
"CMx": 0.0,
"CMy": 6.600353840412458,
"CMz": -0.0023132093922757484,
"CD": 17.837253608138774,
"CL": -4.779477699489913
"CMy": 0.0001559838863858854,
"CMz": -5.4667279930094694e-08,
"CL": -0.01129517484193726,
"CD": 0.04215416639048362
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import flow360 as fl
from flow360.component.results.case_results import BETForcesResultCSVModel
from flow360.component.results.results_utils import _build_coeff_env
from flow360.component.simulation.framework.param_utils import AssetCache
from flow360.component.simulation.models.volume_models import BETDisk
from flow360.component.simulation.services import ValidationCalledBy, validate_model
Expand Down Expand Up @@ -172,12 +173,22 @@ def test_bet_disk_real_case_coefficients():
params_json = f.read()

params_as_dict = json.loads(params_json)
params, errors, warnings = validate_model(
params, errors, _ = validate_model(
params_as_dict=params_as_dict,
validated_by=ValidationCalledBy.LOCAL,
root_item_type=None,
)

mach_ref = params.operating_condition.mach

coeff_env = _build_coeff_env(params)
assert coeff_env["dynamic_pressure"] == 0.5 * mach_ref * mach_ref
assert coeff_env["area"] == (params.reference_geometry.area / (1.0 * fl.u.cm**2)).value
assert np.allclose(coeff_env["moment_length_vec"], [140, 140, 140])
assert np.allclose(coeff_env["moment_center_global"], [0, 0, 0])
assert np.allclose(coeff_env["lift_dir"], [-0.25881905, 0.0, 0.96592583])
assert np.allclose(coeff_env["drag_dir"], [0.96592583, -0.0, 0.25881905])

assert errors is None, f"Validation errors: {errors}"
assert params is not None

Expand Down
Loading