Skip to content

Commit 1842f76

Browse files
benflexcomputeflow360-auto-hotfix-bot
authored andcommitted
Fixed a bug where the area as well as the ref Mach is not computed correctly (#1592)
* Fixed a bug where the area as well as the ref Mach is not computed correclty * Added support for PM header that does not start with zone_
1 parent eb37902 commit 1842f76

File tree

7 files changed

+202
-95
lines changed

7 files changed

+202
-95
lines changed

flow360/component/results/results_utils.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616
from flow360.component.simulation.models.volume_models import BETDisk
1717
from flow360.component.simulation.simulation_params import SimulationParams
18+
from flow360.component.simulation.user_code.core.types import Expression
1819
from flow360.exceptions import Flow360ValueError
1920
from flow360.log import log
2021

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

7778

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

82-
# Fill defaults using preprocessed params
8383
reference_geometry_filled = ReferenceGeometry.fill_defaults(params.reference_geometry, params)
8484

85-
reference_geometry_filled_flow360: ReferenceGeometry = reference_geometry_filled.preprocess(
86-
params=params
87-
)
85+
evaluated_area = None
86+
if isinstance(reference_geometry_filled.area, Expression):
87+
evaluated_area = reference_geometry_filled.area.evaluate(
88+
raise_on_non_evaluable=True, force_evaluate=True
89+
)
90+
else:
91+
evaluated_area = reference_geometry_filled.area
92+
# Fill defaults using preprocessed params
93+
8894
# Extract dimensionless area (in Flow360 units)
89-
area_flow360 = float(reference_geometry_filled_flow360.area.value)
95+
area_flow360 = float(evaluated_area.in_base(params.flow360_unit_system).value)
9096

9197
# Extract dimensionless moment_length
92-
moment_length_flow360 = reference_geometry_filled_flow360.moment_length
98+
moment_length_flow360 = reference_geometry_filled.moment_length.in_base(
99+
params.flow360_unit_system
100+
)
93101

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

111119
# Extract dimensionless moment_center
112-
moment_center = reference_geometry_filled_flow360.moment_center
120+
moment_center = reference_geometry_filled.moment_center.in_base(params.flow360_unit_system)
113121
moment_center_flow360 = np.array(
114122
[moment_center[0], moment_center[1], moment_center[2]],
115123
dtype=float,
@@ -154,21 +162,19 @@ def _get_lift_drag_direction(params: SimulationParams):
154162

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

160-
if using_liquid_op:
161-
v_ref = params._liquid_reference_velocity
162-
else:
163-
v_ref = params.base_velocity
166+
v_ref = params.reference_velocity
164167

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

168171

169172
def _build_coeff_env(params) -> Dict[str, Any]:
173+
"""
174+
Get data for computing aerodynamic coefficients in flow360 unit.
175+
"""
170176
# pylint:disable=protected-access
171-
area, moment_length_vec, moment_center_global = _get_reference_geometry(params)
177+
area, moment_length_vec, moment_center_global = _get_reference_geometry_in_flow360_unit(params)
172178
dynamic_pressure = _get_dynamic_pressure_in_flow360_unit(params)
173179
lift_dir, drag_dir = _get_lift_drag_direction(params)
174180
return {
@@ -341,14 +347,16 @@ def _copy_time_columns(src: Dict[str, list]) -> Dict[str, list]:
341347

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

353361
@staticmethod
354362
def _init_zone_output(out: Dict[str, list], zone_name: str) -> Dict[str, str]:

flow360/component/simulation/conversion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def get_flow360_unit_system_liquid(params, to_flow360_unit: bool = False) -> u.U
369369
Parameters
370370
----------
371371
params : SimulationParams
372-
The parameters needed for unit conversion.
372+
The parameters needed for unit conversion that uses liquid operating condition.
373373
to_flow360_unit : bool, optional
374374
Whether we want user input to be converted to flow360 unit system.
375375
The reverse path requires different conversion logic (from solver output to non-flow360 unit system)
@@ -388,7 +388,7 @@ def get_flow360_unit_system_liquid(params, to_flow360_unit: bool = False) -> u.U
388388
if to_flow360_unit:
389389
base_velocity = params.base_velocity
390390
else:
391-
base_velocity = params._liquid_reference_velocity # pylint:disable=protected-access
391+
base_velocity = params.reference_velocity # pylint:disable=protected-access
392392

393393
time_unit = params.base_length / base_velocity
394394
return u.UnitSystem(

flow360/component/simulation/simulation_params.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -648,9 +648,9 @@ def base_velocity(self) -> VelocityType:
648648
return self.operating_condition.thermal_state.speed_of_sound.to("m/s")
649649

650650
@property
651-
def _liquid_reference_velocity(self) -> VelocityType:
651+
def reference_velocity(self) -> VelocityType:
652652
"""
653-
This function returns the reference velocity for liquid operating condition.
653+
This function returns the **reference velocity**.
654654
Note that the reference velocity is **NOT** the non-dimensionalization velocity scale
655655
656656
For dimensionalization of Flow360 output (converting FROM flow360 unit)
@@ -661,8 +661,10 @@ def _liquid_reference_velocity(self) -> VelocityType:
661661
# pylint:disable=no-member
662662
if self.operating_condition.reference_velocity_magnitude is not None:
663663
reference_velocity = (self.operating_condition.reference_velocity_magnitude).to("m/s")
664-
else:
664+
elif self.operating_condition.type_name == "LiquidOperatingCondition":
665665
reference_velocity = self.base_velocity.to("m/s") * LIQUID_IMAGINARY_FREESTREAM_MACH
666+
else:
667+
reference_velocity = self.operating_condition.velocity_magnitude.to("m/s")
666668
return reference_velocity
667669

668670
@property

tests/simulation/data/real_case_coefficients/results/reference_coefficients.json

Lines changed: 66 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,106 +3,106 @@
33
"Disk0": {
44
"CFx": 0.0,
55
"CFy": 0.0,
6-
"CFz": 4.22968413996175e-08,
7-
"CMx": -1.8127217742693215e-07,
8-
"CMy": -8.157247984211948e-08,
9-
"CMz": 3.403336579930425e-09,
10-
"CD": 1.0947228101901768e-08,
11-
"CL": 4.0855611478343206e-08
6+
"CFz": 9.995866680607329e-11,
7+
"CMx": -4.2839428631174267e-10,
8+
"CMy": -1.927774288402842e-10,
9+
"CMz": 8.042987985983815e-14,
10+
"CL": 9.655265782941001e-11,
11+
"CD": 2.5871206692468927e-11
1212
},
1313
"Disk1": {
1414
"CFx": 0.0,
1515
"CFy": 0.0,
16-
"CFz": 4.22968413996175e-08,
17-
"CMx": 8.00618783635617e-08,
18-
"CMy": -8.157247984211948e-08,
19-
"CMz": 3.403336579930425e-09,
20-
"CD": 1.0947228101901768e-08,
21-
"CL": 4.0855611478343206e-08
16+
"CFz": 9.995866680607329e-11,
17+
"CMx": 1.8920747645435302e-10,
18+
"CMy": -1.927774288402842e-10,
19+
"CMz": 8.042987985983815e-14,
20+
"CL": 9.655265782941001e-11,
21+
"CD": 2.5871206692468927e-11
2222
},
2323
"Disk2": {
2424
"CFx": 0.0,
2525
"CFy": 0.0,
26-
"CFz": 4.22968413996175e-08,
27-
"CMx": -8.00618783635617e-08,
28-
"CMy": -8.157247984211948e-08,
29-
"CMz": 3.4033365799304168e-09,
30-
"CD": 1.0947228101901768e-08,
31-
"CL": 4.0855611478343206e-08
26+
"CFz": 9.995866680607329e-11,
27+
"CMx": -1.8920747645435302e-10,
28+
"CMy": -1.927774288402842e-10,
29+
"CMz": 8.042987985983795e-14,
30+
"CL": 9.655265782941001e-11,
31+
"CD": 2.5871206692468927e-11
3232
},
3333
"Disk3": {
3434
"CFx": 0.0,
3535
"CFy": 0.0,
36-
"CFz": 4.22968413996175e-08,
37-
"CMx": 1.8127217742693215e-07,
38-
"CMy": -8.157247984211948e-08,
39-
"CMz": 3.403336579930425e-09,
40-
"CD": 1.0947228101901768e-08,
41-
"CL": 4.0855611478343206e-08
36+
"CFz": 9.995866680607329e-11,
37+
"CMx": 4.2839428631174267e-10,
38+
"CMy": -1.927774288402842e-10,
39+
"CMz": 8.042987985983815e-14,
40+
"CL": 9.655265782941001e-11,
41+
"CD": 2.5871206692468927e-11
4242
}
4343
},
4444
"BETDisk": {
4545
"Disk0": {
46-
"CFx": -0.0013623562270260357,
47-
"CFy": 3.408410091892857e-05,
48-
"CFz": 0.0007882827772506428,
49-
"CMx": -0.002831401005472502,
50-
"CMy": 0.0005588765009247424,
51-
"CMz": -0.005219742604944044,
52-
"CD": -0.0011119124686114067,
53-
"CL": 0.0011140264307336204
46+
"CFx": -3.219609494757832e-06,
47+
"CFy": 8.054978041860516e-08,
48+
"CFz": 1.8629215060223306e-06,
49+
"CMx": -8.003490657116154e-06,
50+
"CMy": 1.284310828124118e-06,
51+
"CMz": -1.389477191280391e-05,
52+
"CL": 2.632740250052527e-06,
53+
"CD": -2.6277443962624396e-06
5454
},
5555
"Disk1": {
56-
"CFx": -0.0013625962301961904,
57-
"CFy": 3.430884768042857e-05,
58-
"CFz": 0.0007882460542094166,
59-
"CMx": 0.002040468650507854,
60-
"CMy": 0.0006176229491711534,
61-
"CMz": 0.0031976789226962144,
62-
"CD": -0.001112153798494314,
63-
"CL": 0.001114053076391001
56+
"CFx": -3.2201766859741037e-06,
57+
"CFy": 8.108091669037237e-08,
58+
"CFz": 1.8628347197252796e-06,
59+
"CMx": 3.5097996437133253e-06,
60+
"CMy": 1.4219783685337042e-06,
61+
"CMz": 5.998145947634071e-06,
62+
"CL": 2.6328032208158226e-06,
63+
"CD": -2.6283147228532113e-06
6464
},
6565
"Disk2": {
66-
"CFx": -0.001362673711029595,
67-
"CFy": -3.4279632118202374e-05,
68-
"CFz": 0.0007882642235870595,
69-
"CMx": -0.002040542978745176,
70-
"CMy": 0.0006176049504929208,
71-
"CMz": -0.003197903001473004,
72-
"CD": -0.00111222393665137,
73-
"CL": 0.0011140906801774294
66+
"CFx": -3.220359793756006e-06,
67+
"CFy": -8.101187255957007e-08,
68+
"CFz": 1.862877658788949e-06,
69+
"CMx": -3.509906765297771e-06,
70+
"CMy": 1.4219711165652415e-06,
71+
"CMz": -5.998589581039346e-06,
72+
"CL": 2.632892088547641e-06,
73+
"CD": -2.6284804779412884e-06
7474
},
7575
"Disk3": {
76-
"CFx": -0.0013623581648587975,
77-
"CFy": -3.403408826757143e-05,
78-
"CFz": 0.0007883305725700714,
79-
"CMx": 0.0028315934600057083,
80-
"CMy": 0.0005589131586812199,
81-
"CMz": 0.005219704135600682,
82-
"CD": -0.0011119019700751836,
83-
"CL": 0.001114073099015057
76+
"CFx": -3.219614074371178e-06,
77+
"CFy": -8.043158724418193e-08,
78+
"CFz": 1.8630344590526649e-06,
79+
"CMx": 8.003926808607675e-06,
80+
"CMy": 1.2844656026937008e-06,
81+
"CMz": 1.389462745437122e-05,
82+
"CL": 2.632850539592837e-06,
83+
"CD": -2.6277195854337923e-06
8484
}
8585
},
8686
"PorousMedium": {
8787
"zone_0": {
88-
"CFx": 2.0891243317035,
88+
"CFx": 0.004937155496228122,
8989
"CFy": 0.0,
9090
"CFz": 0.0,
9191
"CMx": 0.0,
92-
"CMy": 0.7578755447937788,
93-
"CMz": -6.609346148473639e-05,
94-
"CD": 2.017939146321301,
95-
"CL": -0.5407051646319416
92+
"CMy": 1.7910611420548698e-05,
93+
"CMz": -1.561963985015805e-09,
94+
"CL": -0.0012778298710564243,
95+
"CD": 0.004768926002211764
9696
},
9797
"zone_1": {
98-
"CFx": 18.46648378443988,
98+
"CFx": 0.04364120436911098,
9999
"CFy": 0.0,
100100
"CFz": 0.0,
101101
"CMx": 0.0,
102-
"CMy": 6.600353840412458,
103-
"CMz": -0.0023132093922757484,
104-
"CD": 17.837253608138774,
105-
"CL": -4.779477699489913
102+
"CMy": 0.0001559838863858854,
103+
"CMz": -5.4667279930094694e-08,
104+
"CL": -0.01129517484193726,
105+
"CD": 0.04215416639048362
106106
}
107107
}
108108
}

tests/simulation/data/real_case_coefficients/results/simulation_params.json

Lines changed: 4 additions & 0 deletions
Large diffs are not rendered by default.

tests/simulation/results_processing/test_bet_disk_coefficients.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import flow360 as fl
77
from flow360.component.results.case_results import BETForcesResultCSVModel
8+
from flow360.component.results.results_utils import _build_coeff_env
89
from flow360.component.simulation.framework.param_utils import AssetCache
910
from flow360.component.simulation.models.volume_models import BETDisk
1011
from flow360.component.simulation.services import ValidationCalledBy, validate_model
@@ -172,12 +173,22 @@ def test_bet_disk_real_case_coefficients():
172173
params_json = f.read()
173174

174175
params_as_dict = json.loads(params_json)
175-
params, errors, warnings = validate_model(
176+
params, errors, _ = validate_model(
176177
params_as_dict=params_as_dict,
177178
validated_by=ValidationCalledBy.LOCAL,
178179
root_item_type=None,
179180
)
180181

182+
mach_ref = params.operating_condition.mach
183+
184+
coeff_env = _build_coeff_env(params)
185+
assert coeff_env["dynamic_pressure"] == 0.5 * mach_ref * mach_ref
186+
assert coeff_env["area"] == (params.reference_geometry.area / (1.0 * fl.u.cm**2)).value
187+
assert np.allclose(coeff_env["moment_length_vec"], [140, 140, 140])
188+
assert np.allclose(coeff_env["moment_center_global"], [0, 0, 0])
189+
assert np.allclose(coeff_env["lift_dir"], [-0.25881905, 0.0, 0.96592583])
190+
assert np.allclose(coeff_env["drag_dir"], [0.96592583, -0.0, 0.25881905])
191+
181192
assert errors is None, f"Validation errors: {errors}"
182193
assert params is not None
183194

0 commit comments

Comments
 (0)