Skip to content

Commit fa9d6b1

Browse files
3D Lift & Drag Pressure-based Coefficients (#2426)
* 3D Pressure Lift Coeff by ONERA M6 wing * more compact * Comments & To Do * drag coeff pressure 3d * comments * long run * typo * Update examples/p4est_3d_dgsem/elixir_euler_OMNERA_M6_wing.jl * Apply suggestions from code review Co-authored-by: Arpit Babbar <arpitbabbar@gmail.com> * changed docstring --------- Co-authored-by: Arpit Babbar <arpitbabbar@gmail.com>
1 parent 214cb71 commit fa9d6b1

File tree

6 files changed

+359
-17
lines changed

6 files changed

+359
-17
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using Trixi
2+
using OrdinaryDiffEqSSPRK
3+
using LinearAlgebra: norm
4+
5+
###############################################################################
6+
# semidiscretization of the compressible Euler equations
7+
8+
equations = CompressibleEulerEquations3D(1.4)
9+
10+
### Inviscid transonic flow over the ONERA M6 wing ###
11+
# See for reference
12+
#
13+
# https://www.grc.nasa.gov/www/wind/valid/m6wing/m6wing.html
14+
# https://www.grc.nasa.gov/www/wind/valid/m6wing/m6wing01/m6wing01.html
15+
#
16+
# which are test cases for the viscous flow.
17+
#
18+
# A tutorial for the invscid case can be found for the SU2 Code (https://github.com/su2code/SU2):
19+
# https://su2code.github.io/tutorials/Inviscid_ONERAM6/
20+
21+
@inline function initial_condition(x, t, equations::CompressibleEulerEquations3D)
22+
# set the freestream flow parameters
23+
rho_freestream = 1.4
24+
25+
# v_total = 0.84 = Mach (for c = 1)
26+
27+
# AoA = 3.06
28+
v1 = 0.8388023121403883
29+
v2 = 0.0448406193973588
30+
v3 = 0.0
31+
32+
p_freestream = 1.0
33+
34+
prim = SVector(rho_freestream, v1, v2, v3, p_freestream)
35+
return prim2cons(prim, equations)
36+
end
37+
38+
bc_farfield = BoundaryConditionDirichlet(initial_condition)
39+
40+
# Ensure that rho and p are the same across symmetry line and allow only
41+
# tangential velocity.
42+
# Somewhat naive implementation of `boundary_condition_slip_wall`.
43+
# Used here to avoid confusion between wing (body) and symmetry plane.
44+
@inline function bc_symmetry(u_inner, normal_direction::AbstractVector, x, t,
45+
surface_flux_function,
46+
equations::CompressibleEulerEquations3D)
47+
norm_ = norm(normal_direction)
48+
normal = normal_direction / norm_
49+
50+
# compute the primitive variables
51+
rho, v1, v2, v3, p = cons2prim(u_inner, equations)
52+
53+
v_normal = normal[1] * v1 + normal[2] * v2 + normal[3] * v3
54+
55+
u_mirror = prim2cons(SVector(rho,
56+
v1 - 2 * v_normal * normal[1],
57+
v2 - 2 * v_normal * normal[2],
58+
v3 - 2 * v_normal * normal[3],
59+
p), equations)
60+
61+
flux = surface_flux_function(u_inner, u_mirror, normal, equations) * norm_
62+
63+
return flux
64+
end
65+
66+
polydeg = 2
67+
basis = LobattoLegendreBasis(polydeg)
68+
surface_flux = flux_lax_friedrichs
69+
volume_flux = flux_ranocha
70+
71+
# Flux Differencing is required, shock capturing not!
72+
volume_integral = VolumeIntegralFluxDifferencing(volume_flux)
73+
74+
solver = DGSEM(polydeg = polydeg, surface_flux = surface_flux,
75+
volume_integral = volume_integral)
76+
77+
# This is a sanitized mesh obtained from the original mesh available at
78+
# https://www.grc.nasa.gov/www/wind/valid/m6wing/m6wing01/m6wing01.html
79+
#
80+
# which has been merged into a single gmsh mesh file by the HiSA team,
81+
# see the case description (for the viscous case, but the mesh is the same)
82+
# https://hisa.gitlab.io/archive/nparc/oneraM6/notes/oneraM6.html
83+
#
84+
# The base mesh is available at
85+
# https://gitlab.com/hisa/hisa/-/blob/master/examples/oneraM6/mesh/p3dMesh/m6wing.msh?ref_type=heads
86+
#
87+
# The sanitized, i.e., higher-order ready mesh was subsequently created by Daniel Doehring
88+
# and is available at
89+
mesh_file = Trixi.download("https://github.com/DanielDoehring/AerodynamicMeshes/raw/refs/heads/main/ONERA_M6_Wing/ONERA_M6_Wing_sanitized.inp",
90+
joinpath(@__DIR__, "ONERA_M6_sanitized.inp"))
91+
92+
# Boundary symbols follow from nodesets in the mesh file
93+
boundary_symbols = [:Symmetry, :FarField, :BottomWing, :TopWing]
94+
mesh = P4estMesh{3}(mesh_file; polydeg = polydeg, boundary_symbols = boundary_symbols)
95+
96+
boundary_conditions = Dict(:Symmetry => bc_symmetry, # Could use `boundary_condition_slip_wall` here as well
97+
:FarField => bc_farfield,
98+
:BottomWing => boundary_condition_slip_wall,
99+
:TopWing => boundary_condition_slip_wall)
100+
101+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver;
102+
boundary_conditions = boundary_conditions)
103+
104+
# This is an extremely long (weeks!) simulation
105+
tspan = (0.0, 6.0)
106+
ode = semidiscretize(semi, tspan)
107+
108+
###############################################################################
109+
110+
summary_callback = SummaryCallback()
111+
112+
force_boundary_names = (:BottomWing, :TopWing)
113+
114+
aoa() = deg2rad(3.06)
115+
116+
rho_inf() = 1.4
117+
u_inf(equations) = 0.84
118+
119+
### Wing projected area calculated from geometry information provided at ###
120+
### https://www.grc.nasa.gov/www/wind/valid/m6wing/m6wing.html ###
121+
122+
height = 1.0 # Mesh we use normalizes wing height to one
123+
124+
g_I = tan(deg2rad(30)) * height
125+
126+
base = 0.8059 / 1.1963 # Mesh we use normalizes wing height to one
127+
128+
g_II = base - g_I
129+
g_III = tan(deg2rad(15.8)) * height
130+
A = height * (0.5 * (g_I + g_III) + g_II)
131+
132+
lift_coefficient = AnalysisSurfaceIntegral(force_boundary_names,
133+
LiftCoefficientPressure3D(aoa(), rho_inf(),
134+
u_inf(equations), A))
135+
drag_coefficient = AnalysisSurfaceIntegral(force_boundary_names,
136+
DragCoefficientPressure3D(aoa(), rho_inf(),
137+
u_inf(equations), A))
138+
139+
analysis_interval = 100_000
140+
analysis_callback = AnalysisCallback(semi, interval = analysis_interval,
141+
analysis_errors = Symbol[], # Turn off error computation
142+
analysis_integrals = (lift_coefficient,
143+
drag_coefficient))
144+
145+
alive_callback = AliveCallback(alive_interval = 50)
146+
147+
save_sol_interval = 50_000
148+
save_solution = SaveSolutionCallback(interval = save_sol_interval,
149+
save_initial_solution = false,
150+
save_final_solution = true,
151+
solution_variables = cons2prim,
152+
output_directory = "out/")
153+
154+
save_restart = SaveRestartCallback(interval = save_sol_interval)
155+
156+
callbacks = CallbackSet(summary_callback,
157+
alive_callback, analysis_callback,
158+
save_solution, save_restart)
159+
160+
###############################################################################
161+
162+
sol = solve(ode, SSPRK43(); abstol = 1.0e-6, reltol = 1.0e-6,
163+
dt = 1e-8,
164+
ode_default_options()..., callback = callbacks);

src/Trixi.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ export SummaryCallback, SteadyStateCallback, AnalysisCallback, AliveCallback,
289289
GlmSpeedCallback, LBMCollisionCallback, EulerAcousticsCouplingCallback,
290290
TrivialCallback, AnalysisCallbackCoupled,
291291
AnalysisSurfaceIntegral, DragCoefficientPressure2D, LiftCoefficientPressure2D,
292-
DragCoefficientShearStress2D, LiftCoefficientShearStress2D
292+
DragCoefficientShearStress2D, LiftCoefficientShearStress2D,
293+
DragCoefficientPressure3D, LiftCoefficientPressure3D
293294

294295
# TODO: deprecation introduced in v0.11
295296
@deprecate DragCoefficientPressure DragCoefficientPressure2D

src/callbacks_step/analysis_surface_integral.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,5 @@ function pretty_form_utf(::AnalysisSurfaceIntegral{<:DragCoefficientShearStress{
127127
end
128128

129129
include("analysis_surface_integral_2d.jl")
130+
include("analysis_surface_integral_3d.jl")
130131
end # muladd

src/callbacks_step/analysis_surface_integral_2d.jl

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@ In 2D, the freestream-normal unit vector ``\psi_L`` is given by
2020
```
2121
where ``\alpha`` is the angle of attack.
2222
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
23-
which stores the boundary information and semidiscretization.
23+
which stores the the to-be-computed variables (for instance `LiftCoefficientPressure2D`)
24+
and boundary information.
2425
2526
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
2627
- `rho_inf::Real`: Free-stream density
2728
- `u_inf::Real`: Free-stream velocity
2829
- `l_inf::Real`: Reference length of geometry (e.g. airfoil chord length)
2930
"""
3031
function LiftCoefficientPressure2D(aoa, rho_inf, u_inf, l_inf)
31-
# psi_lift is the normal unit vector to the freestream direction.
32-
# Note: The choice of the normal vector psi_lift = (-sin(aoa), cos(aoa))
32+
# `psi_lift` is the normal unit vector to the freestream direction.
33+
# Note: The choice of the normal vector `psi_lift = (-sin(aoa), cos(aoa))`
3334
# leads to positive lift coefficients for positive angles of attack for airfoils.
34-
# One could also use psi_lift = (sin(aoa), -cos(aoa)) which results in the same
35+
# One could also use `psi_lift = (sin(aoa), -cos(aoa))` which results in the same
3536
# value, but with the opposite sign.
3637
psi_lift = (-sin(aoa), cos(aoa))
3738
return LiftCoefficientPressure(ForceState(psi_lift, rho_inf, u_inf, l_inf))
@@ -53,7 +54,8 @@ In 2D, the freestream-tangent unit vector ``\psi_D`` is given by
5354
where ``\alpha`` is the angle of attack.
5455
5556
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
56-
which stores the boundary information and semidiscretization.
57+
which stores the the to-be-computed variables (for instance `DragCoefficientPressure2D`)
58+
and boundary information.
5759
5860
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
5961
- `rho_inf::Real`: Free-stream density
@@ -81,18 +83,19 @@ In 2D, the freestream-normal unit vector ``\psi_L`` is given by
8183
```
8284
where ``\alpha`` is the angle of attack.
8385
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
84-
which stores the boundary information and semidiscretization.
86+
which stores the the to-be-computed variables (for instance `LiftCoefficientShearStress2D`)
87+
and boundary information.
8588
8689
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
8790
- `rho_inf::Real`: Free-stream density
8891
- `u_inf::Real`: Free-stream velocity
8992
- `l_inf::Real`: Reference length of geometry (e.g. airfoil chord length)
9093
"""
9194
function LiftCoefficientShearStress2D(aoa, rho_inf, u_inf, l_inf)
92-
# psi_lift is the normal unit vector to the freestream direction.
93-
# Note: The choice of the normal vector psi_lift = (-sin(aoa), cos(aoa))
95+
# `psi_lift` is the normal unit vector to the freestream direction.
96+
# Note: The choice of the normal vector `psi_lift = (-sin(aoa), cos(aoa))`
9497
# leads to negative lift coefficients for airfoils.
95-
# One could also use psi_lift = (sin(aoa), -cos(aoa)) which results in the same
98+
# One could also use `psi_lift = (sin(aoa), -cos(aoa))` which results in the same
9699
# value, but with the opposite sign.
97100
psi_lift = (-sin(aoa), cos(aoa))
98101
return LiftCoefficientShearStress(ForceState(psi_lift, rho_inf, u_inf, l_inf))
@@ -113,7 +116,8 @@ In 2D, the freestream-tangent unit vector ``\psi_D`` is given by
113116
```
114117
where ``\alpha`` is the angle of attack.
115118
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
116-
which stores the boundary information and semidiscretization.
119+
which stores the the to-be-computed variables (for instance `DragCoefficientShearStress2D`)
120+
and boundary information.
117121
118122
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
119123
- `rho_inf::Real`: Free-stream density
@@ -196,6 +200,8 @@ function (drag_coefficient::DragCoefficientShearStress{RealT, 2})(u, normal_dire
196200
(0.5f0 * rho_inf * u_inf^2 * l_inf)
197201
end
198202

203+
# 2D version of the `analyze` function for `AnalysisSurfaceIntegral`, i.e.,
204+
# `LiftCoefficientPressure` and `DragCoefficientPressure`.
199205
function analyze(surface_variable::AnalysisSurfaceIntegral, du, u, t,
200206
mesh::P4estMesh{2},
201207
equations, dg::DGSEM, cache, semi)
@@ -220,8 +226,8 @@ function analyze(surface_variable::AnalysisSurfaceIntegral, du, u, t,
220226
i_node = i_node_start
221227
j_node = j_node_start
222228
for node_index in index_range
223-
u_node = Trixi.get_node_vars(cache.boundaries.u, equations, dg, node_index,
224-
boundary)
229+
u_node = Trixi.get_node_vars(cache.boundaries.u, equations, dg,
230+
node_index, boundary)
225231
# Extract normal direction at nodes which points from the elements outwards,
226232
# i.e., *into* the structure.
227233
normal_direction = get_normal_direction(direction, contravariant_vectors,
@@ -247,8 +253,12 @@ function analyze(surface_variable::AnalysisSurfaceIntegral, du, u, t,
247253
return surface_integral
248254
end
249255

250-
function analyze(surface_variable::AnalysisSurfaceIntegral{Variable},
251-
du, u, t, mesh::P4estMesh{2},
256+
# 2D version of the `analyze` function for `AnalysisSurfaceIntegral` of viscous, i.e.,
257+
# variables that require gradients of the solution variables.
258+
# These are for parabolic equations readily available.
259+
# Examples are `LiftCoefficientShearStress` and `DragCoefficientShearStress`.
260+
function analyze(surface_variable::AnalysisSurfaceIntegral{Variable}, du, u, t,
261+
mesh::P4estMesh{2},
252262
equations, equations_parabolic,
253263
dg::DGSEM, cache, semi,
254264
cache_parabolic) where {Variable <: VariableViscous}
@@ -279,8 +289,8 @@ function analyze(surface_variable::AnalysisSurfaceIntegral{Variable},
279289
i_node = i_node_start
280290
j_node = j_node_start
281291
for node_index in index_range
282-
u_node = Trixi.get_node_vars(cache.boundaries.u, equations, dg, node_index,
283-
boundary)
292+
u_node = Trixi.get_node_vars(cache.boundaries.u, equations, dg,
293+
node_index, boundary)
284294
# Extract normal direction at nodes which points from the elements outwards,
285295
# i.e., *into* the structure.
286296
normal_direction = get_normal_direction(direction, contravariant_vectors,

0 commit comments

Comments
 (0)