Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/docs/literate/src/files/DGSEM_FluxDiff.jl
5591 views
1
#src # DGSEM with flux differencing
2
3
# This tutorial starts with a presentation of the weak formulation of the discontinuous Galerkin
4
# spectral element method (DGSEM) in order to fix the notation of the used operators.
5
# Then, the DGSEM formulation with flux differencing (split form DGSEM) and its implementation in
6
# [Trixi.jl](https://github.com/trixi-framework/Trixi.jl) is shown.
7
8
# We start with the one-dimensional conservation law
9
# ```math
10
# u_t + f(u)_x = 0, \qquad t\in \mathbb{R}^+, x\in\Omega
11
# ```
12
# with the physical flux $f$.
13
14
# We split the domain $\Omega$ into elements $K$ with center $x_K$ and size $\Delta x$. With the
15
# transformation mapping $x(\xi)=x_K + \frac{\Delta x}{2} \xi$ we can transform the reference element
16
# $[-1,1]$ to every physical element. So, the equation can be restricted to the reference element using the
17
# determinant of the Jacobian matrix of the transformation mapping
18
# $J=\frac{\partial x}{\partial \xi}=\frac{\Delta x}{2}$.
19
# ```math
20
# J u_t + f(u)_{\xi} = 0, \qquad t\in \mathbb{R}^+, \xi\in [-1,1]
21
# ```
22
23
# ## The weak form of the DGSEM
24
# We consider the so-called discontinuous Galerkin spectral element method (DGSEM) with collocation.
25
# It results from choosing a nodal DG ansatz using $N+1$ Gauss-Lobatto nodes $\xi_i$ in $[-1,1]$
26
# with matching interpolation weights $w_i$, which are used for numerical integration and interpolation with
27
# the Lagrange polynomial basis $l_i$ of degree $N$. The Lagrange functions are created with those nodes and
28
# hence fulfil a Kronecker property at the GL nodes.
29
# The weak formulation of the DGSEM for one element is
30
# ```math
31
# J \underline{\dot{u}}(t) = - M^{-1} B \underline{f}^* + M^{-1} D^T M \underline{f}
32
# ```
33
# where $\underline{u}=(u_0, u_1, \dots, u_N)^T\in\mathbb{R}^{N+1}$ is the collected pointwise evaluation
34
# of $u$ at the discretization nodes and $\dot{u} = \partial u / \partial t = u_t$ is the temporal derivative.
35
# The nodal values of the flux function $f$ results with collocation in $\underline{f}$, since
36
# $\underline{f}_j=f(\underline{u}_j)$. Moreover, we got the numerical flux $f^*=f^*(u^-, u^+)$.
37
38
# We will now have a short overview over the operators we used.
39
40
# The **derivative matrix** $D\in\mathbb{R}^{(N+1)\times (N+1)}$ mimics a spatial derivation on a
41
# discrete level with $\underline{f}_x \approx D \underline{f}$. It is defined by $D_{ij} = l_j'(\xi_i)$.
42
43
# The diagonal **mass matrix** $M$ is defined by $M_{ij}=\langle l_j, l_i\rangle_N$ with the
44
# numerical scalar product $\langle \cdot, \cdot\rangle_N$ defined for functions $f$ and $g$ by
45
# ```math
46
# \langle f, g\rangle_N := \int_{-1, N}^1 f(\xi) g(\xi) d\xi := \sum_{k=0}^N f(\xi_k) g(\xi_k) w_k.
47
# ```
48
# The multiplication by $M$ matches a discrete integration
49
# ```math
50
# \int_{-1}^1 f(\xi) \underline{l}(\xi) d\xi \approx M \underline{f},
51
# ```
52
53
# The **boundary matrix** $B=\text{diag}([-1, 0,..., 0, 1])$ represents an evaluation of a
54
# function at the boundaries $\xi_0=-1$ and $\xi_N=1$.
55
56
# For these operators the following property holds:
57
# ```math
58
# M D + (M D)^T = B.
59
# ```
60
# This is called the summation-by-parts (SBP) property since it mimics integration by parts on a
61
# discrete level ([Gassner (2013)](https://doi.org/10.1137/120890144)).
62
63
# The explicit definitions of the operators and the construction of the 1D algorithm can be found
64
# for instance in the tutorial [introduction to DG methods](@ref scalar_linear_advection_1d)
65
# or in more detail in [Kopriva (2009)](https://link.springer.com/book/10.1007/978-90-481-2261-5).
66
67
# This property shows the equivalence between the weak form and the following strong formulation
68
# of the DGSEM.
69
# ```math
70
# \begin{align*}
71
# J \underline{\dot{u}}(t)
72
# &= - M^{-1} B \underline{f}^* + M^{-1} D^T M \underline{f}\\[5pt]
73
# &= - M^{-1} B \underline{f}^* + M^{-1} (B - MD) \underline{f}\\[5pt]
74
# &= - M^{-1} B (\underline{f}^* - \underline{f}) - D \underline{f}
75
# \end{align*}
76
# ```
77
# More information about the equivalence you can find in [Kopriva, Gassner (2010)](https://doi.org/10.1007/s10915-010-9372-3).
78
79
# ## DGSEM with flux differencing
80
# When using the diagonal SBP property it is possible to rewrite the application of the derivative
81
# operator $D$ in the calculation of the volume integral into a subcell based finite volume type
82
# differencing formulation ([Fisher, Carpenter (2013)](https://doi.org/10.1016/j.jcp.2013.06.014)).
83
# Generalizing
84
# ```math
85
# (D \underline{f})_i = \sum_j D_{i,j} \underline{f}_j
86
# = 2\sum_j \frac{1}{2} D_{i,j} (\underline{f}_j + \underline{f}_i)
87
# \eqqcolon 2\sum_j D_{i,j} f_\text{central}(u_i, u_j),
88
# ```
89
# we replace $D \underline{f}$ in the strong form by $2D \underline{f}_{vol}(u^-, u^+)$ with
90
# the consistent two-point volume flux $f_{vol}$ and receive the DGSEM formulation with flux differencing
91
# (split form DGSEM) ([Gassner, Winters, Kopriva (2016)](https://doi.org/10.1016/j.jcp.2016.09.013)).
92
# The above manipulations are possible due to the "telescoping" property of the derivative matrix ``D``, see
93
# [Fisher, Carpenter (2013)](https://doi.org/10.1016/j.jcp.2013.06.014).
94
# In particular, we can check that every row sum ``\sum_j D_{i,j}`` is zero, which makes the
95
# above manipulations possible:
96
using Trixi
97
98
N = 3
99
basis = LobattoLegendreBasis(N)
100
D = basis.derivative_matrix
101
sum(D, dims = 2)
102
103
# ```math
104
# \begin{align*}
105
# J \underline{\dot{u}}(t) &= - M^{-1} B (\underline{f}^* - \underline{f}) - 2D \underline{f}_{vol}(u^-, u^+)\\[5pt]
106
# &= - M^{-1} B (\underline{f}^* - \underline{f}_{vol}(\underline{u}, \underline{u})) - 2D \underline{f}_{vol}(u^-, u^+)\\[5pt]
107
# &= - M^{-1} B \underline{f}_{surface}^* - (2D - M^{-1} B) \underline{f}_{vol}\\[5pt]
108
# &= - M^{-1} B \underline{f}_{surface}^* - D_{split} \underline{f}_{vol}
109
# \end{align*}
110
# ```
111
# This formulation is in a weak form type formulation and can be implemented by using the derivative
112
# split matrix $D_{split}=(2D-M^{-1}B)$ and two different fluxes. We divide between the surface
113
# flux $f=f_{surface}$ used for the numerical flux $f_{surface}^*$ and the already mentioned volume
114
# flux $f_{vol}$ especially for this formulation.
115
116
# This formulation creates a more stable version of DGSEM, because it fulfils entropy stability.
117
# Moreover it allows the construction of entropy conserving discretizations without relying on
118
# exact integration. This is achieved when using a symmetric two-point entropy conserving flux function as
119
# volume flux in the volume flux differencing formulation.
120
# Then, the numerical surface flux ``\underline{f}_{surface}^*`` can be used to control the
121
# dissipation of the discretization and to guarantee decreasing entropy, i.e. entropy stability.
122
123
# ## [Implementation in Trixi.jl](@id fluxDiffExample)
124
# Now, we have a look at the implementation of DGSEM with flux differencing with [Trixi.jl](https://github.com/trixi-framework/Trixi.jl).
125
using OrdinaryDiffEqLowStorageRK
126
127
# We implement a simulation for the compressible Euler equations in 2D
128
# ```math
129
# \partial_t \begin{pmatrix} \rho \\ \rho v_1 \\ \rho v_2 \\ \rho e \end{pmatrix}
130
# + \partial_x \begin{pmatrix} \rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ (\rho e +p) v_1 \end{pmatrix}
131
# + \partial_y \begin{pmatrix} \rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ (\rho e +p) v_2 \end{pmatrix}
132
# = \begin{pmatrix} 0 \\ 0 \\ 0 \\ 0 \end{pmatrix}
133
# ```
134
# for an ideal gas with ratio of specific heats $\gamma=1.4$.
135
# Here, $\rho$ is the density, $v_1$, $v_2$ the velocities, $e$ the specific total energy and
136
# ```math
137
# p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2) \right)
138
# ```
139
# the pressure.
140
141
gamma = 1.4
142
equations = CompressibleEulerEquations2D(gamma)
143
144
# As our initial condition we will use a weak blast wave from [Hennemann, Gassner (2020)](https://arxiv.org/abs/2008.12044).
145
# The primitive variables are defined by
146
# ```math
147
# \begin{pmatrix} \rho \\ v_1 \\ v_2 \\ p \end{pmatrix}
148
# = \begin{pmatrix} 1.0 \\ 0.0 \\ 0.0 \\ 1.0 \end{pmatrix} \text{if } \|x\|_2 > 0.5,\;
149
# \text{and } \begin{pmatrix} \rho \\ v_1 \\ v_2 \\ p \end{pmatrix}
150
# = \begin{pmatrix} 1.1691 \\ 0.1882 * \cos(\phi) \\ 0.1882 * \sin(\phi) \\ 1.245 \end{pmatrix} \text{else}
151
# ```
152
# with $\phi = \tan^{-1}(\frac{x_2}{x_1})$.
153
154
# This initial condition is implemented in Trixi.jl under the name [`initial_condition_weak_blast_wave`](@ref).
155
initial_condition = initial_condition_weak_blast_wave
156
157
# In Trixi.jl, flux differencing for the volume integral can be implemented with
158
# [`VolumeIntegralFluxDifferencing`](@ref) using symmetric two-point volume fluxes.
159
# First, we set up a simulation with the entropy conserving and kinetic energy preserving
160
# flux [`flux_ranocha`](@ref) by [Hendrik Ranocha (2018)](https://cuvillier.de/en/shop/publications/7743)
161
# as surface and volume flux.
162
163
# We will confirm the entropy conservation property numerically.
164
165
volume_flux = flux_ranocha # = f_vol
166
solver = DGSEM(polydeg = N, surface_flux = volume_flux,
167
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))
168
169
# Now, we implement Trixi.jl's `mesh`, `semi` and `ode` in a simple framework. For more information please
170
# have a look at the documentation, the basic tutorial [introduction to DG methods](@ref scalar_linear_advection_1d)
171
# or some basic elixirs.
172
coordinates_min = (-2.0, -2.0)
173
coordinates_max = (2.0, 2.0)
174
mesh = TreeMesh(coordinates_min, coordinates_max,
175
initial_refinement_level = 5,
176
n_cells_max = 10_000,
177
periodicity = true)
178
179
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
180
boundary_conditions = boundary_condition_periodic)
181
182
## ODE solvers
183
tspan = (0.0, 0.4)
184
ode = semidiscretize(semi, tspan);
185
186
# To analyse the entropy conservation of the approximation, we will use the analysis callback
187
# implemented in Trixi. It provides some information about the approximation including the entropy change.
188
analysis_callback = AnalysisCallback(semi, interval = 100);
189
190
# We now run the simulation using `flux_ranocha` for both surface and volume flux.
191
sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6,
192
ode_default_options()..., callback = analysis_callback);
193
# A look at the change in entropy $\sum \partial S/\partial U \cdot U_t$ in the analysis callback
194
# confirms that the flux is entropy conserving since the change is about machine precision.
195
196
# We can plot the approximated solution at the time `t=0.4`.
197
using Plots
198
plot(sol)
199
200
# Now, we can use for instance the dissipative flux [`flux_lax_friedrichs`](@ref) as surface flux
201
# to get an entropy stable method.
202
using OrdinaryDiffEqLowStorageRK, Trixi
203
204
gamma = 1.4
205
equations = CompressibleEulerEquations2D(gamma)
206
207
initial_condition = initial_condition_weak_blast_wave
208
209
volume_flux = flux_ranocha # = f_vol
210
solver = DGSEM(polydeg = 3, surface_flux = flux_lax_friedrichs,
211
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))
212
213
coordinates_min = (-2.0, -2.0)
214
coordinates_max = (2.0, 2.0)
215
mesh = TreeMesh(coordinates_min, coordinates_max,
216
initial_refinement_level = 5,
217
n_cells_max = 10_000,
218
periodicity = true)
219
220
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
221
boundary_conditions = boundary_condition_periodic)
222
223
## ODE solvers
224
tspan = (0.0, 0.4)
225
ode = semidiscretize(semi, tspan);
226
227
analysis_callback = AnalysisCallback(semi, interval = 100);
228
229
# We now run the simulation using the volume flux `flux_ranocha` and surface flux `flux_lax_friedrichs`.
230
sol = solve(ode, RDPK3SpFSAL49(); abstol = 1.0e-6, reltol = 1.0e-6,
231
ode_default_options()..., callback = analysis_callback);
232
# The change in entropy confirms the expected entropy stability.
233
234
using Plots
235
plot(sol)
236
237
# Of course, you can use more than these two fluxes in Trixi. Here, we will give a short list
238
# of possible fluxes for the compressible Euler equations.
239
# For the volume flux Trixi.jl provides for example [`flux_ranocha`](@ref), [`flux_shima_etal`](@ref),
240
# [`flux_chandrashekar`](@ref), [`flux_kennedy_gruber`](@ref).
241
# As surface flux you can use all volume fluxes and additionally for instance [`flux_lax_friedrichs`](@ref),
242
# [`flux_hll`](@ref), [`flux_hllc`](@ref).
243
244
# ## Package versions
245
246
# These results were obtained using the following versions.
247
248
using InteractiveUtils
249
versioninfo()
250
251
using Pkg
252
Pkg.status(["Trixi", "OrdinaryDiffEqLowStorageRK", "Plots"],
253
mode = PKGMODE_MANIFEST)
254
255