Calculate Dimensional Forces#
Two snippets will demonstrate how to obtain dimensional forces in the following scenarios:
total forces on the wall boundaries
forces excluding selected boundaries
Total Forces on the Wall Boundaries#
import pandas as pd
import flow360 as fl
case = fl.Case.from_cloud(case_id="your-case-id")
# the data structure holding the force coefficients, averaged over the last 10% of pseudo steps
forces_total = case.results.total_forces.get_averages(0.1)
# gather all reference values
density = case.params.operating_condition.thermal_state.density
reference_velocity = case.params.reference_velocity
reference_area = case.params.reference_geometry.area
reference_length = case.params.reference_geometry.moment_length
# Calculate dynamic pressure
dynamic_pressure = 0.5 * density * reference_velocity**2
# Calculate forces from force coefficients (F = Cf * q * A)
force_scale = dynamic_pressure * reference_area
# Calculate moments from moment coefficients (M = Cm * q * A * L)
moment_scale = force_scale * reference_length
# Create a new series with actual forces and moments
forces_actual = {}
# Convert force coefficients to forces (N)
force_coeffs = [
"CL",
"CD",
"CFx",
"CFy",
"CFz",
"CLPressure",
"CDPressure",
"CFxPressure",
"CFyPressure",
"CFzPressure",
"CLSkinFriction",
"CDSkinFriction",
"CFxSkinFriction",
"CFySkinFriction",
"CFzSkinFriction",
]
for coeff in force_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * force_scale).to(fl.u.N)
# Convert moment coefficients to moments (N·m)
moment_x_coeffs = ["CMx", "CMxPressure", "CMxSkinFriction"]
moment_y_coeffs = ["CMy", "CMyPressure", "CMySkinFriction"]
moment_z_coeffs = ["CMz", "CMzPressure", "CMzSkinFriction"]
for coeff in moment_x_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[0]).to(
fl.u.N * fl.u.m
)
for coeff in moment_y_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[1]).to(
fl.u.N * fl.u.m
)
for coeff in moment_z_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[2]).to(
fl.u.N * fl.u.m
)
# Rename the series to indicate these are actual forces/moments
forces_actual = pd.Series(forces_actual)
# Print the results
print("\n" + "=" * 60)
print("FORCE COEFFICIENTS:")
print("=" * 60)
print(forces_total)
print("\n" + "=" * 60)
print("ACTUAL FORCES (N) AND MOMENTS (N·m):")
print("=" * 60)
print(forces_actual)
Forces Excluding Selected Boundaries#
import pandas as pd
import flow360 as fl
case = fl.Case.from_cloud(case_id="your-case-id")
# the data structure holding the force coefficients
forces_by_surface = case.results.surface_forces
# exclude the wind tunnel elements
forces_by_surface.filter(exclude="*tunnel*")
# perform averaging
forces_total = forces_by_surface.get_averages(0.1)
# gather all reference values
density = case.params.operating_condition.thermal_state.density
reference_velocity = case.params.reference_velocity
reference_area = case.params.reference_geometry.area
reference_length = case.params.reference_geometry.moment_length
# Calculate dynamic pressure
dynamic_pressure = 0.5 * density * reference_velocity**2
# Calculate forces from force coefficients (F = Cf * q * A)
force_scale = dynamic_pressure * reference_area
# Calculate moments from moment coefficients (M = Cm * q * A * L)
moment_scale = force_scale * reference_length
# Create a new series with actual forces and moments
forces_actual = {}
# Convert force coefficients to forces (N)
force_coeffs = [
"totalCL",
"totalCD",
"totalCFx",
"totalCFy",
"totalCFz",
"totalCLPressure",
"totalCDPressure",
"totalCFxPressure",
"totalCFyPressure",
"totalCFzPressure",
"totalCLSkinFriction",
"totalCDSkinFriction",
"totalCFxSkinFriction",
"totalCFySkinFriction",
"totalCFzSkinFriction",
]
for coeff in force_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * force_scale).to(fl.u.N)
# Convert moment coefficients to moments (N·m)
moment_x_coeffs = ["totalCMx", "totalCMxPressure", "totalCMxSkinFriction"]
moment_y_coeffs = ["totalCMy", "totalCMyPressure", "totalCMySkinFriction"]
moment_z_coeffs = ["totalCMz", "totalCMzPressure", "totalCMzSkinFriction"]
for coeff in moment_x_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[0]).to(
fl.u.N * fl.u.m
)
for coeff in moment_y_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[1]).to(
fl.u.N * fl.u.m
)
for coeff in moment_z_coeffs:
forces_actual[coeff.removeprefix("C")] = (forces_total[coeff] * moment_scale[2]).to(
fl.u.N * fl.u.m
)
# Rename the series to indicate these are actual forces/moments
forces_actual = pd.Series(forces_actual)
# Print the results
print("\n" + "=" * 60)
print("FORCE COEFFICIENTS - WIND TUNNEL EXCLUDED:")
print("=" * 60)
print(forces_total[forces_total.index.str.startswith("total")])
print("\n" + "=" * 60)
print("ACTUAL FORCES (N) AND MOMENTS (N·m) - WIND TUNNEL EXCLUDED:")
print("=" * 60)
print(forces_actual)
Note
The filter() method also supports an include argument for selecting only specific boundaries
(e.g., forces_by_surface.filter(include="*wing*")). Both include and exclude accept
wildcard patterns.