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_1d.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
LinearScalarAdvectionEquation1D
10
11
The linear scalar advection equation
12
```math
13
\partial_t u + a \partial_1 u = 0
14
```
15
in one space dimension with constant velocity `a`.
16
"""
17
struct LinearScalarAdvectionEquation1D{RealT <: Real} <:
18
AbstractLinearScalarAdvectionEquation{1}
19
advection_velocity::SVector{1, RealT}
20
end
21
22
function LinearScalarAdvectionEquation1D(a::Real)
23
LinearScalarAdvectionEquation1D(SVector(a))
24
end
25
26
varnames(::typeof(cons2cons), ::LinearScalarAdvectionEquation1D) = ("scalar",)
27
varnames(::typeof(cons2prim), ::LinearScalarAdvectionEquation1D) = ("scalar",)
28
29
# Set initial conditions at physical location `x` for time `t`
30
"""
31
initial_condition_constant(x, t, equations::LinearScalarAdvectionEquation1D)
32
33
A constant initial condition to test free-stream preservation.
34
"""
35
function initial_condition_constant(x, t, equation::LinearScalarAdvectionEquation1D)
36
RealT = eltype(x)
37
return SVector(RealT(2))
38
end
39
40
"""
41
initial_condition_convergence_test(x, t, equations::LinearScalarAdvectionEquation1D)
42
43
A smooth initial condition used for convergence tests
44
(in combination with [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref)
45
in non-periodic domains).
46
"""
47
function initial_condition_convergence_test(x, t,
48
equation::LinearScalarAdvectionEquation1D)
49
# Store translated coordinate for easy use of exact solution
50
RealT = eltype(x)
51
x_trans = x - equation.advection_velocity * t
52
53
c = 1
54
A = 0.5f0
55
L = 2
56
f = 1.0f0 / L
57
omega = 2 * convert(RealT, pi) * f
58
scalar = c + A * sin(omega * sum(x_trans))
59
return SVector(scalar)
60
end
61
62
"""
63
initial_condition_gauss(x, t, equations::LinearScalarAdvectionEquation1D)
64
65
A Gaussian pulse used together with
66
[`BoundaryConditionDirichlet(initial_condition_gauss)`](@ref).
67
"""
68
function initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation1D)
69
# Store translated coordinate for easy use of exact solution
70
x_trans = x - equation.advection_velocity * t
71
72
scalar = exp(-(x_trans[1]^2))
73
return SVector(scalar)
74
end
75
76
"""
77
initial_condition_sin(x, t, equations::LinearScalarAdvectionEquation1D)
78
79
A sine wave in the conserved variable.
80
"""
81
function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation1D)
82
# Store translated coordinate for easy use of exact solution
83
x_trans = x - equation.advection_velocity * t
84
85
scalar = sinpi(2 * x_trans[1])
86
return SVector(scalar)
87
end
88
89
"""
90
initial_condition_linear_x(x, t, equations::LinearScalarAdvectionEquation1D)
91
92
A linear function of `x[1]` used together with
93
[`boundary_condition_linear_x`](@ref).
94
"""
95
function initial_condition_linear_x(x, t, equation::LinearScalarAdvectionEquation1D)
96
# Store translated coordinate for easy use of exact solution
97
x_trans = x - equation.advection_velocity * t
98
99
return SVector(x_trans[1])
100
end
101
102
"""
103
boundary_condition_linear_x(u_inner, orientation, direction, x, t,
104
surface_flux_function,
105
equation::LinearScalarAdvectionEquation1D)
106
107
Boundary conditions for
108
[`initial_condition_linear_x`](@ref).
109
"""
110
function boundary_condition_linear_x(u_inner, orientation, direction, x, t,
111
surface_flux_function,
112
equation::LinearScalarAdvectionEquation1D)
113
u_boundary = initial_condition_linear_x(x, t, equation)
114
115
# Calculate boundary flux
116
if direction == 2 # u_inner is "left" of boundary, u_boundary is "right" of boundary
117
flux = surface_flux_function(u_inner, u_boundary, orientation, equation)
118
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
119
flux = surface_flux_function(u_boundary, u_inner, orientation, equation)
120
end
121
122
return flux
123
end
124
125
# Pre-defined source terms should be implemented as
126
# function source_terms_WHATEVER(u, x, t, equations::LinearScalarAdvectionEquation1D)
127
128
# Calculate 1D flux for a single point
129
@inline function flux(u, orientation::Integer,
130
equation::LinearScalarAdvectionEquation1D)
131
a = equation.advection_velocity[orientation]
132
return a * u
133
end
134
135
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
136
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Int,
137
equation::LinearScalarAdvectionEquation1D)
138
return abs(equation.advection_velocity[orientation])
139
end
140
141
"""
142
flux_godunov(u_ll, u_rr, orientation,
143
equations::LinearScalarAdvectionEquation1D)
144
145
Godunov (upwind) flux for the 1D linear scalar advection equation.
146
Essentially first order upwind, see e.g. https://math.stackexchange.com/a/4355076/805029 .
147
"""
148
function flux_godunov(u_ll, u_rr, orientation::Int,
149
equation::LinearScalarAdvectionEquation1D)
150
u_L = u_ll[1]
151
u_R = u_rr[1]
152
153
v_normal = equation.advection_velocity[orientation]
154
if v_normal >= 0
155
return SVector(v_normal * u_L)
156
else
157
return SVector(v_normal * u_R)
158
end
159
end
160
161
# See https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf ,
162
# section 4.2.5 and especially equation (4.33).
163
function flux_engquist_osher(u_ll, u_rr, orientation::Int,
164
equation::LinearScalarAdvectionEquation1D)
165
u_L = u_ll[1]
166
u_R = u_rr[1]
167
168
return SVector(0.5f0 * (flux(u_L, orientation, equation) +
169
flux(u_R, orientation, equation) -
170
abs(equation.advection_velocity[orientation]) * (u_R - u_L)))
171
end
172
173
@inline have_constant_speed(::LinearScalarAdvectionEquation1D) = True()
174
175
@inline function max_abs_speeds(equation::LinearScalarAdvectionEquation1D)
176
return abs.(equation.advection_velocity)
177
end
178
179
"""
180
splitting_lax_friedrichs(u, orientation::Integer,
181
equations::LinearScalarAdvectionEquation1D)
182
splitting_lax_friedrichs(u, which::Union{Val{:minus}, Val{:plus}}
183
orientation::Integer,
184
equations::LinearScalarAdvectionEquation1D)
185
186
Naive local Lax-Friedrichs style flux splitting of the form `f⁺ = 0.5 (f + λ u)`
187
and `f⁻ = 0.5 (f - λ u)` where ` is the absolute value of the advection
188
velocity.
189
190
Returns a tuple of the fluxes "minus" (associated with waves going into the
191
negative axis direction) and "plus" (associated with waves going into the
192
positive axis direction). If only one of the fluxes is required, use the
193
function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.
194
195
!!! warning "Experimental implementation (upwind SBP)"
196
This is an experimental feature and may change in future releases.
197
"""
198
@inline function splitting_lax_friedrichs(u, orientation::Integer,
199
equations::LinearScalarAdvectionEquation1D)
200
fm = splitting_lax_friedrichs(u, Val{:minus}(), orientation, equations)
201
fp = splitting_lax_friedrichs(u, Val{:plus}(), orientation, equations)
202
return fm, fp
203
end
204
205
@inline function splitting_lax_friedrichs(u, ::Val{:plus}, orientation::Integer,
206
equations::LinearScalarAdvectionEquation1D)
207
RealT = eltype(u)
208
a = equations.advection_velocity[1]
209
return a > 0 ? flux(u, orientation, equations) : SVector(zero(RealT))
210
end
211
212
@inline function splitting_lax_friedrichs(u, ::Val{:minus}, orientation::Integer,
213
equations::LinearScalarAdvectionEquation1D)
214
RealT = eltype(u)
215
a = equations.advection_velocity[1]
216
return a < 0 ? flux(u, orientation, equations) : SVector(zero(RealT))
217
end
218
219
# Convert conservative variables to primitive
220
@inline cons2prim(u, equation::LinearScalarAdvectionEquation1D) = u
221
222
# Convert conservative variables to entropy variables
223
@inline cons2entropy(u, equation::LinearScalarAdvectionEquation1D) = u
224
225
# Calculate entropy for a conservative state `cons`
226
@inline entropy(u::Real, ::LinearScalarAdvectionEquation1D) = 0.5f0 * u^2
227
@inline entropy(u, equation::LinearScalarAdvectionEquation1D) = entropy(u[1], equation)
228
229
# Calculate total energy for a conservative state `cons`
230
@inline energy_total(u::Real, ::LinearScalarAdvectionEquation1D) = 0.5f0 * u^2
231
@inline function energy_total(u, equation::LinearScalarAdvectionEquation1D)
232
energy_total(u[1], equation)
233
end
234
end # @muladd
235
236