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_2d.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
LinearScalarAdvectionEquation2D
10
11
The linear scalar advection equation
12
```math
13
\partial_t u + a_1 \partial_1 u + a_2 \partial_2 u = 0
14
```
15
in two space dimensions with constant velocity `a`.
16
"""
17
struct LinearScalarAdvectionEquation2D{RealT <: Real} <:
18
AbstractLinearScalarAdvectionEquation{2}
19
advection_velocity::SVector{2, RealT}
20
end
21
22
function LinearScalarAdvectionEquation2D(a::NTuple{2, <:Real})
23
LinearScalarAdvectionEquation2D(SVector(a))
24
end
25
26
function LinearScalarAdvectionEquation2D(a1::Real, a2::Real)
27
LinearScalarAdvectionEquation2D(SVector(a1, a2))
28
end
29
30
varnames(::typeof(cons2cons), ::LinearScalarAdvectionEquation2D) = ("scalar",)
31
varnames(::typeof(cons2prim), ::LinearScalarAdvectionEquation2D) = ("scalar",)
32
33
# Calculates translated coordinates `x` for a periodic domain
34
function x_trans_periodic_2d(x, domain_length = SVector(10, 10), center = SVector(0, 0))
35
x_normalized = x .- center
36
x_shifted = x_normalized .% domain_length
37
x_offset = ((x_shifted .< -0.5f0 * domain_length) -
38
(x_shifted .> 0.5f0 * domain_length)) .* domain_length
39
return center + x_shifted + x_offset
40
end
41
42
# Set initial conditions at physical location `x` for time `t`
43
"""
44
initial_condition_constant(x, t, equations::LinearScalarAdvectionEquation2D)
45
46
A constant initial condition to test free-stream preservation.
47
"""
48
function initial_condition_constant(x, t, equation::LinearScalarAdvectionEquation2D)
49
RealT = eltype(x)
50
return SVector(RealT(2))
51
end
52
53
"""
54
initial_condition_convergence_test(x, t, equations::LinearScalarAdvectionEquation2D)
55
56
A smooth initial condition used for convergence tests.
57
"""
58
function initial_condition_convergence_test(x, t,
59
equation::LinearScalarAdvectionEquation2D)
60
# Store translated coordinate for easy use of exact solution
61
RealT = eltype(x)
62
x_trans = x - equation.advection_velocity * t
63
64
c = 1
65
A = 0.5f0
66
L = 2
67
f = 1.0f0 / L
68
omega = 2 * convert(RealT, pi) * f
69
scalar = c + A * sin(omega * sum(x_trans))
70
return SVector(scalar)
71
end
72
73
"""
74
initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation2D)
75
76
A Gaussian pulse used together with
77
[`BoundaryConditionDirichlet(initial_condition_gauss)`](@ref).
78
"""
79
function initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation2D)
80
# Store translated coordinate for easy use of exact solution
81
x_trans = x_trans_periodic_2d(x - equation.advection_velocity * t)
82
83
scalar = exp(-(x_trans[1]^2 + x_trans[2]^2))
84
return SVector(scalar)
85
end
86
87
"""
88
initial_condition_sin_sin(x, t, equations::LinearScalarAdvectionEquation2D)
89
90
A sine wave in the conserved variable.
91
"""
92
function initial_condition_sin_sin(x, t, equation::LinearScalarAdvectionEquation2D)
93
# Store translated coordinate for easy use of exact solution
94
x_trans = x - equation.advection_velocity * t
95
96
scalar = sinpi(2 * x_trans[1]) * sinpi(2 * x_trans[2])
97
return SVector(scalar)
98
end
99
100
"""
101
initial_condition_linear_x_y(x, t, equations::LinearScalarAdvectionEquation2D)
102
103
A linear function of `x[1] + x[2]` used together with
104
[`boundary_condition_linear_x_y`](@ref).
105
"""
106
function initial_condition_linear_x_y(x, t, equation::LinearScalarAdvectionEquation2D)
107
# Store translated coordinate for easy use of exact solution
108
x_trans = x - equation.advection_velocity * t
109
110
return SVector(sum(x_trans))
111
end
112
113
"""
114
boundary_condition_linear_x_y(u_inner, orientation, direction, x, t,
115
surface_flux_function,
116
equation::LinearScalarAdvectionEquation2D)
117
118
Boundary conditions for
119
[`initial_condition_linear_x_y`](@ref).
120
"""
121
function boundary_condition_linear_x_y(u_inner, orientation, direction, x, t,
122
surface_flux_function,
123
equation::LinearScalarAdvectionEquation2D)
124
u_boundary = initial_condition_linear_x_y(x, t, equation)
125
126
# Calculate boundary flux
127
if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
128
flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
129
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
130
flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
131
end
132
133
return flux
134
end
135
136
"""
137
initial_condition_linear_x(x, t, equations::LinearScalarAdvectionEquation2D)
138
139
A linear function of `x[1]` used together with
140
[`boundary_condition_linear_x`](@ref).
141
"""
142
function initial_condition_linear_x(x, t, equation::LinearScalarAdvectionEquation2D)
143
# Store translated coordinate for easy use of exact solution
144
x_trans = x - equation.advection_velocity * t
145
146
return SVector(x_trans[1])
147
end
148
149
"""
150
boundary_condition_linear_x(u_inner, orientation, direction, x, t,
151
surface_flux_function,
152
equation::LinearScalarAdvectionEquation2D)
153
154
Boundary conditions for
155
[`initial_condition_linear_x`](@ref).
156
"""
157
function boundary_condition_linear_x(u_inner, orientation, direction, x, t,
158
surface_flux_function,
159
equation::LinearScalarAdvectionEquation2D)
160
u_boundary = initial_condition_linear_x(x, t, equation)
161
162
# Calculate boundary flux
163
if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
164
flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
165
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
166
flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
167
end
168
169
return flux
170
end
171
172
"""
173
initial_condition_linear_y(x, t, equations::LinearScalarAdvectionEquation2D)
174
175
A linear function of `x[1]` used together with
176
[`boundary_condition_linear_y`](@ref).
177
"""
178
function initial_condition_linear_y(x, t, equation::LinearScalarAdvectionEquation2D)
179
# Store translated coordinate for easy use of exact solution
180
x_trans = x - equation.advection_velocity * t
181
182
return SVector(x_trans[2])
183
end
184
185
"""
186
boundary_condition_linear_y(u_inner, orientation, direction, x, t,
187
surface_flux_function,
188
equation::LinearScalarAdvectionEquation2D)
189
190
Boundary conditions for
191
[`initial_condition_linear_y`](@ref).
192
"""
193
function boundary_condition_linear_y(u_inner, orientation, direction, x, t,
194
surface_flux_function,
195
equation::LinearScalarAdvectionEquation2D)
196
u_boundary = initial_condition_linear_y(x, t, equation)
197
198
# Calculate boundary flux
199
if direction in (2, 4) # u_inner is "left" of boundary, u_boundary is "right" of boundary
200
flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
201
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
202
flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
203
end
204
205
return flux
206
end
207
208
# Pre-defined source terms should be implemented as
209
# function source_terms_WHATEVER(u, x, t, equations::LinearScalarAdvectionEquation2D)
210
211
# Calculate 1D flux for a single point
212
@inline function flux(u, orientation::Integer,
213
equation::LinearScalarAdvectionEquation2D)
214
a = equation.advection_velocity[orientation]
215
return a * u
216
end
217
218
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
219
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
220
equation::LinearScalarAdvectionEquation2D)
221
return abs(equation.advection_velocity[orientation])
222
end
223
224
# Calculate 1D flux for a single point in the normal direction
225
# Note, this directional vector is not normalized
226
@inline function flux(u, normal_direction::AbstractVector,
227
equation::LinearScalarAdvectionEquation2D)
228
a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction
229
return a * u
230
end
231
232
# Calculate maximum wave speed in the normal direction for local Lax-Friedrichs-type dissipation
233
@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,
234
equation::LinearScalarAdvectionEquation2D)
235
a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction
236
return abs(a)
237
end
238
239
"""
240
flux_godunov(u_ll, u_rr, orientation_or_normal_direction,
241
equations::LinearScalarAdvectionEquation2D)
242
243
Godunov (upwind) flux for the 2D linear scalar advection equation.
244
Essentially first order upwind, see e.g. https://math.stackexchange.com/a/4355076/805029 .
245
"""
246
function flux_godunov(u_ll, u_rr, orientation::Integer,
247
equation::LinearScalarAdvectionEquation2D)
248
u_L = u_ll[1]
249
u_R = u_rr[1]
250
251
v_normal = equation.advection_velocity[orientation]
252
if v_normal >= 0
253
return SVector(v_normal * u_L)
254
else
255
return SVector(v_normal * u_R)
256
end
257
end
258
259
function flux_godunov(u_ll, u_rr, normal_direction::AbstractVector,
260
equation::LinearScalarAdvectionEquation2D)
261
u_L = u_ll[1]
262
u_R = u_rr[1]
263
264
a_normal = dot(equation.advection_velocity, normal_direction)
265
if a_normal >= 0
266
return SVector(a_normal * u_L)
267
else
268
return SVector(a_normal * u_R)
269
end
270
end
271
272
@inline have_constant_speed(::LinearScalarAdvectionEquation2D) = True()
273
274
@inline function max_abs_speeds(equation::LinearScalarAdvectionEquation2D)
275
return abs.(equation.advection_velocity)
276
end
277
278
# Convert conservative variables to primitive
279
@inline cons2prim(u, equation::LinearScalarAdvectionEquation2D) = u
280
281
# Convert conservative variables to entropy variables
282
@inline cons2entropy(u, equation::LinearScalarAdvectionEquation2D) = u
283
284
# Calculate entropy for a conservative state `cons`
285
@inline entropy(u::Real, ::LinearScalarAdvectionEquation2D) = 0.5f0 * u^2
286
@inline entropy(u, equation::LinearScalarAdvectionEquation2D) = entropy(u[1], equation)
287
288
# Calculate total energy for a conservative state `cons`
289
@inline energy_total(u::Real, ::LinearScalarAdvectionEquation2D) = 0.5f0 * u^2
290
@inline function energy_total(u, equation::LinearScalarAdvectionEquation2D)
291
energy_total(u[1], equation)
292
end
293
end # @muladd
294
295