Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/callbacks_step/analysis_surface_integral_3d.jl
2055 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
@doc raw"""
9
LiftCoefficientPressure3D(aoa, rho_inf, u_inf, a_inf)
10
11
Compute the lift coefficient
12
```math
13
C_{L,p} \coloneqq \frac{\oint_{\partial \Omega} p \boldsymbol n \cdot \psi_L \, \mathrm{d} S}
14
{0.5 \rho_{\infty} U_{\infty}^2 A_{\infty}}
15
```
16
based on the pressure distribution along a boundary.
17
In 3D, the freestream-normal unit vector ``\psi_L`` is given by
18
```math
19
\psi_L \coloneqq \begin{pmatrix} -\sin(\alpha) \\ \cos(\alpha) \\ 0 \end{pmatrix}
20
```
21
where ``\alpha`` is the angle of attack.
22
This employs the convention that the wing is oriented such that the streamwise flow is in
23
x-direction, the angle of attack rotates the flow into the y-direction, and that wing extends spanwise in the z-direction.
24
25
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
26
which stores the the to-be-computed variables (for instance `LiftCoefficientPressure3D`)
27
and boundary information.
28
29
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
30
- `rho_inf::Real`: Free-stream density
31
- `u_inf::Real`: Free-stream velocity
32
- `a_inf::Real`: Reference area of geometry (e.g. projected wing surface)
33
"""
34
function LiftCoefficientPressure3D(aoa, rho_inf, u_inf, a_inf)
35
# `psi_lift` is the normal unit vector to the freestream direction.
36
# Note: The choice of the normal vector `psi_lift = (-sin(aoa), cos(aoa), 0)`
37
# leads to positive lift coefficients for positive angles of attack for airfoils.
38
# One could also use `psi_lift = (sin(aoa), -cos(aoa), 0)` which results in the same
39
# value, but with the opposite sign.
40
psi_lift = (-sin(aoa), cos(aoa), zero(aoa))
41
return LiftCoefficientPressure(ForceState(psi_lift, rho_inf, u_inf, a_inf))
42
end
43
44
@doc raw"""
45
DragCoefficientPressure3D(aoa, rho_inf, u_inf, a_inf)
46
47
Compute the drag coefficient
48
```math
49
C_{D,p} \coloneqq \frac{\oint_{\partial \Omega} p \boldsymbol n \cdot \psi_D \, \mathrm{d} S}
50
{0.5 \rho_{\infty} U_{\infty}^2 A_{\infty}}
51
```
52
based on the pressure distribution along a boundary.
53
In 3D, the freestream-tangent unit vector ``\psi_D`` is given by
54
```math
55
\psi_D \coloneqq \begin{pmatrix} \cos(\alpha) \\ \sin(\alpha) \\ 0 \end{pmatrix}
56
```
57
where ``\alpha`` is the angle of attack.
58
This employs the convention that the wing is oriented such that the streamwise flow is in
59
x-direction, the angle of attack rotates the flow into the y-direction, and that wing extends spanwise in the z-direction.
60
61
Supposed to be used in conjunction with [`AnalysisSurfaceIntegral`](@ref)
62
which stores the the to-be-computed variables (for instance `DragCoefficientPressure3D`)
63
and boundary information.
64
65
- `aoa::Real`: Angle of attack in radians (for airfoils etc.)
66
- `rho_inf::Real`: Free-stream density
67
- `u_inf::Real`: Free-stream velocity
68
- `a_inf::Real`: Reference area of geometry (e.g. projected wing surface)
69
"""
70
function DragCoefficientPressure3D(aoa, rho_inf, u_inf, a_inf)
71
# `psi_drag` is the unit vector tangent to the freestream direction
72
psi_drag = (cos(aoa), sin(aoa), zero(aoa))
73
return DragCoefficientPressure(ForceState(psi_drag, rho_inf, u_inf, a_inf))
74
end
75
76
# 3D version of the `analyze` function for `AnalysisSurfaceIntegral`, i.e.,
77
# `LiftCoefficientPressure` and `DragCoefficientPressure`.
78
function analyze(surface_variable::AnalysisSurfaceIntegral, du, u, t,
79
mesh::P4estMesh{3},
80
equations, dg::DGSEM, cache, semi)
81
@unpack boundaries = cache
82
@unpack surface_flux_values, node_coordinates, contravariant_vectors = cache.elements
83
@unpack weights = dg.basis
84
85
@unpack variable, boundary_symbols = surface_variable
86
@unpack boundary_symbol_indices = semi.boundary_conditions
87
boundary_indices = get_boundary_indices(boundary_symbols, boundary_symbol_indices)
88
89
surface_integral = zero(eltype(u))
90
index_range = eachnode(dg)
91
for boundary in boundary_indices
92
element = boundaries.neighbor_ids[boundary]
93
node_indices = boundaries.node_indices[boundary]
94
direction = indices2direction(node_indices)
95
96
i_node_start, i_node_step = index_to_start_step_3d(node_indices[1], index_range)
97
j_node_start, j_node_step = index_to_start_step_3d(node_indices[2], index_range)
98
k_node_start, k_node_step = index_to_start_step_3d(node_indices[3], index_range)
99
100
# In 3D, boundaries are surfaces => `node_index1`, `node_index2`
101
for node_index1 in index_range
102
# Reset node indices
103
i_node = i_node_start
104
j_node = j_node_start
105
k_node = k_node_start
106
for node_index2 in index_range
107
u_node = Trixi.get_node_vars(cache.boundaries.u, equations, dg,
108
node_index1, node_index2, boundary)
109
# Extract normal direction at nodes which points from the elements outwards,
110
# i.e., *into* the structure.
111
normal_direction = get_normal_direction(direction,
112
contravariant_vectors,
113
i_node, j_node, k_node, element)
114
115
# Coordinates at a boundary node
116
x = get_node_coords(node_coordinates, equations, dg,
117
i_node, j_node, k_node, element)
118
119
# L2 norm of normal direction (contravariant_vector) is the surface element
120
dS = weights[node_index1] * weights[node_index2] *
121
norm(normal_direction)
122
123
# Integral over entire boundary surface. Note, it is assumed that the
124
# `normal_direction` is normalized to be a normal vector within the
125
# function `variable` and the division of the normal scaling factor
126
# `norm(normal_direction)` is then accounted for with the `dS` quantity.
127
surface_integral += variable(u_node, normal_direction, x, t,
128
equations) * dS
129
130
i_node += i_node_step
131
j_node += j_node_step
132
k_node += k_node_step
133
end
134
end
135
end
136
return surface_integral
137
end
138
end # muladd
139
140