Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/linear_scalar_advection_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
LinearScalarAdvectionEquation3D
10
11
The linear scalar advection equation
12
```math
13
\partial_t u + a_1 \partial_1 u + a_2 \partial_2 u + a_3 \partial_3 u = 0
14
```
15
in three space dimensions with constant velocity `a`.
16
"""
17
struct LinearScalarAdvectionEquation3D{RealT <: Real} <:
18
AbstractLinearScalarAdvectionEquation{3}
19
advection_velocity::SVector{3, RealT}
20
end
21
22
function LinearScalarAdvectionEquation3D(a::NTuple{3, <:Real})
23
LinearScalarAdvectionEquation3D(SVector(a))
24
end
25
26
function LinearScalarAdvectionEquation3D(a1::Real, a2::Real, a3::Real)
27
LinearScalarAdvectionEquation3D(SVector(a1, a2, a3))
28
end
29
30
varnames(::typeof(cons2cons), ::LinearScalarAdvectionEquation3D) = ("scalar",)
31
varnames(::typeof(cons2prim), ::LinearScalarAdvectionEquation3D) = ("scalar",)
32
33
# Set initial conditions at physical location `x` for time `t`
34
"""
35
initial_condition_constant(x, t, equations::LinearScalarAdvectionEquation1D)
36
37
A constant initial condition to test free-stream preservation.
38
"""
39
function initial_condition_constant(x, t, equation::LinearScalarAdvectionEquation3D)
40
RealT = eltype(x)
41
return SVector(RealT(2))
42
end
43
44
"""
45
initial_condition_convergence_test(x, t, equations::LinearScalarAdvectionEquation1D)
46
47
A smooth initial condition used for convergence tests.
48
"""
49
function initial_condition_convergence_test(x, t,
50
equation::LinearScalarAdvectionEquation3D)
51
# Store translated coordinate for easy use of exact solution
52
RealT = eltype(x)
53
x_trans = x - equation.advection_velocity * t
54
55
c = 1
56
A = 0.5f0
57
L = 2
58
f = 1.0f0 / L
59
omega = 2 * convert(RealT, pi) * f
60
scalar = c + A * sin(omega * sum(x_trans))
61
return SVector(scalar)
62
end
63
64
"""
65
initial_condition_gauss(x, t, equations::LinearScalarAdvectionEquation1D)
66
67
A Gaussian pulse.
68
"""
69
function initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation3D)
70
# Store translated coordinate for easy use of exact solution
71
x_trans = x - equation.advection_velocity * t
72
73
scalar = exp(-(x_trans[1]^2 + x_trans[2]^2 + x_trans[3]^2))
74
return SVector(scalar)
75
end
76
77
"""
78
initial_condition_sin(x, t, equations::LinearScalarAdvectionEquation1D)
79
80
A sine wave in the conserved variable.
81
"""
82
function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation3D)
83
# Store translated coordinate for easy use of exact solution
84
RealT = eltype(x)
85
x_trans = x - equation.advection_velocity * t
86
87
scalar = sinpi(2 * x_trans[1]) * sinpi(2 * x_trans[2]) * sinpi(2 * x_trans[3])
88
return SVector(scalar)
89
end
90
91
"""
92
initial_condition_linear_z(x, t, equations::LinearScalarAdvectionEquation1D)
93
94
A linear function of `x[3]` used together with
95
[`boundary_condition_linear_z`](@ref).
96
"""
97
function initial_condition_linear_z(x, t, equation::LinearScalarAdvectionEquation3D)
98
# Store translated coordinate for easy use of exact solution
99
x_trans = x - equation.advection_velocity * t
100
101
return SVector(x_trans[3])
102
end
103
104
"""
105
boundary_condition_linear_z(u_inner, orientation, direction, x, t,
106
surface_flux_function,
107
equation::LinearScalarAdvectionEquation1D)
108
109
Boundary conditions for
110
[`boundary_condition_linear_z`](@ref).
111
"""
112
function boundary_condition_linear_z(u_inner, orientation, direction, x, t,
113
surface_flux_function,
114
equation::LinearScalarAdvectionEquation3D)
115
u_boundary = initial_condition_linear_z(x, t, equation)
116
117
# Calculate boundary flux
118
if direction in (2, 4, 6) # u_inner is "left" of boundary, u_boundary is "right" of boundary
119
flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
120
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
121
flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
122
end
123
124
return flux
125
end
126
127
# Pre-defined source terms should be implemented as
128
# function source_terms_WHATEVER(u, x, t, equation::LinearScalarAdvectionEquation3D)
129
130
# Calculate 1D flux for a single point
131
@inline function flux(u, orientation::Integer,
132
equation::LinearScalarAdvectionEquation3D)
133
a = equation.advection_velocity[orientation]
134
return a * u
135
end
136
137
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
138
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
139
equation::LinearScalarAdvectionEquation3D)
140
return abs(equation.advection_velocity[orientation])
141
end
142
143
# Calculate 1D flux for a single point in the normal direction
144
# Note, this directional vector is not normalized
145
@inline function flux(u, normal_direction::AbstractVector,
146
equation::LinearScalarAdvectionEquation3D)
147
a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction
148
return a * u
149
end
150
151
# Calculate maximum wave speed in the normal direction for local Lax-Friedrichs-type dissipation
152
@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,
153
equation::LinearScalarAdvectionEquation3D)
154
a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction
155
return abs(a)
156
end
157
158
"""
159
flux_godunov(u_ll, u_rr, orientation_or_normal_direction,
160
equations::LinearScalarAdvectionEquation3D)
161
162
Godunov (upwind) flux for the 3D linear scalar advection equation.
163
Essentially first order upwind, see e.g. https://math.stackexchange.com/a/4355076/805029 .
164
"""
165
function flux_godunov(u_ll, u_rr, orientation::Integer,
166
equation::LinearScalarAdvectionEquation3D)
167
u_L = u_ll[1]
168
u_R = u_rr[1]
169
170
v_normal = equation.advection_velocity[orientation]
171
if v_normal >= 0
172
return SVector(v_normal * u_L)
173
else
174
return SVector(v_normal * u_R)
175
end
176
end
177
178
function flux_godunov(u_ll, u_rr, normal_direction::AbstractVector,
179
equation::LinearScalarAdvectionEquation3D)
180
u_L = u_ll[1]
181
u_R = u_rr[1]
182
183
a_normal = dot(equation.advection_velocity, normal_direction)
184
if a_normal >= 0
185
return SVector(a_normal * u_L)
186
else
187
return SVector(a_normal * u_R)
188
end
189
end
190
191
@inline have_constant_speed(::LinearScalarAdvectionEquation3D) = True()
192
193
@inline function max_abs_speeds(equation::LinearScalarAdvectionEquation3D)
194
return abs.(equation.advection_velocity)
195
end
196
197
# Convert conservative variables to primitive
198
@inline cons2prim(u, equation::LinearScalarAdvectionEquation3D) = u
199
200
# Convert conservative variables to entropy variables
201
@inline cons2entropy(u, equation::LinearScalarAdvectionEquation3D) = u
202
203
# Calculate entropy for a conservative state `cons`
204
@inline entropy(u::Real, ::LinearScalarAdvectionEquation3D) = 0.5f0 * u^2
205
@inline entropy(u, equation::LinearScalarAdvectionEquation3D) = entropy(u[1], equation)
206
207
# Calculate total energy for a conservative state `cons`
208
@inline energy_total(u::Real, ::LinearScalarAdvectionEquation3D) = 0.5f0 * u^2
209
@inline function energy_total(u, equation::LinearScalarAdvectionEquation3D)
210
energy_total(u[1], equation)
211
end
212
end # @muladd
213
214