Skip to content

Commit

Permalink
Merge branch 'main' into feature-t8code-cubed-sphere-setup
Browse files Browse the repository at this point in the history
  • Loading branch information
benegee authored Dec 18, 2024
2 parents 4abf64a + 1f31fd4 commit d6075f2
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ installation and postprocessing procedures. Its features include:
* Compressible Navier-Stokes equations
* Magnetohydrodynamics (MHD) equations
* Multi-component compressible Euler and MHD equations
* Multi-ion compressible MHD equations
* Linearized Euler and acoustic perturbation equations
* Hyperbolic diffusion equations for elliptic problems
* Lattice-Boltzmann equations (D2Q9 and D3Q27 schemes)
Expand Down
7 changes: 7 additions & 0 deletions examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667),

initial_condition = initial_condition_weak_blast_wave

# Entropy conservative numerical fluxes
volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal)
surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal)
# For provably entropy-stable surface fluxes, use
# surface_flux = (FluxPlusDissipation(flux_ruedaramirez_etal, DissipationLaxFriedrichsEntropyVariables()),
# flux_nonconservative_ruedaramirez_etal)
# For a standard local Lax-Friedrichs surface flux, use
# surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)

solver = DGSEM(polydeg = 3, surface_flux = surface_flux,
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))

Expand Down
1 change: 1 addition & 0 deletions src/Trixi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle,
flux_chan_etal, flux_nonconservative_chan_etal, flux_winters_etal,
hydrostatic_reconstruction_audusse_etal, flux_nonconservative_audusse_etal,
FluxPlusDissipation, DissipationGlobalLaxFriedrichs, DissipationLocalLaxFriedrichs,
DissipationLaxFriedrichsEntropyVariables,
FluxLaxFriedrichs, max_abs_speed_naive,
FluxHLL, min_max_speed_naive, min_max_speed_davis, min_max_speed_einfeldt,
FluxLMARS,
Expand Down
210 changes: 209 additions & 1 deletion src/equations/ideal_glm_mhd_multiion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@

have_nonconservative_terms(::AbstractIdealGlmMhdMultiIonEquations) = True()

# Variable names for the multi-ion GLM-MHD equation
# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference
# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization
# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.
# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).
# The first three entries of the state vector `cons[1:3]` are the magnetic field components. After that, we have chunks
# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `cons[end]` is the divergence
# cleaning field.
function varnames(::typeof(cons2cons), equations::AbstractIdealGlmMhdMultiIonEquations)
cons = ("B1", "B2", "B3")
for i in eachcomponent(equations)
Expand Down Expand Up @@ -86,7 +94,7 @@ end

"""
v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u,
equations::AbstractIdealGlmMhdMultiIonEquations)
equations::AbstractIdealGlmMhdMultiIonEquations)
Compute the charge-averaged velocities (`v1`, `v2`, and `v3`) and each ion species' contribution
Expand Down Expand Up @@ -263,4 +271,204 @@ end

return SVector(cons)
end

# Specialization of [`DissipationLaxFriedrichsEntropyVariables`](@ref) for the multi-ion GLM-MHD equations
# For details on the multi-ion entropy Jacobian ``H`` see
# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization
# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.
# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).
# Since the entropy Jacobian is a sparse matrix, we do not construct it but directly compute the
# action of its product with the jump in the entropy variables.
#
# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference above.
# The first three entries of the state vector `u[1:3]` are the magnetic field components. After that, we have chunks
# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `u[end]` is the divergence
# cleaning field.
@inline function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_ll, u_rr,
orientation_or_normal_direction,
equations::AbstractIdealGlmMhdMultiIonEquations)
@unpack gammas = equations
λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,
equations)

w_ll = cons2entropy(u_ll, equations)
w_rr = cons2entropy(u_rr, equations)
prim_ll = cons2prim(u_ll, equations)
prim_rr = cons2prim(u_rr, equations)
B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations)
B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations)
psi_ll = divergence_cleaning_field(u_ll, equations)
psi_rr = divergence_cleaning_field(u_rr, equations)

# Some global averages
B1_avg = 0.5f0 * (B1_ll + B1_rr)
B2_avg = 0.5f0 * (B2_ll + B2_rr)
B3_avg = 0.5f0 * (B3_ll + B3_rr)
psi_avg = 0.5f0 * (psi_ll + psi_rr)

dissipation = zero(MVector{nvariables(equations), eltype(u_ll)})

beta_plus_ll = 0
beta_plus_rr = 0

# Compute the dissipation for the hydrodynamic quantities of each ion species `k`
#################################################################################

# The for loop below fills the entries of `dissipation` that depend on the entries of the diagonal
# blocks ``A_k`` of the entropy Jacobian ``H`` in the given reference (see equations (80)-(82)),
# but the terms that depend on the magnetic field ``B`` and divergence cleaning field ``psi`` are
# excluded here and considered below. In other words, these are the dissipation values that depend
# on the entries of the entropy Jacobian that are marked in blue in Figure 1 of the reference given above.
for k in eachcomponent(equations)
rho_ll, v1_ll, v2_ll, v3_ll, p_ll = get_component(k, prim_ll, equations)
rho_rr, v1_rr, v2_rr, v3_rr, p_rr = get_component(k, prim_rr, equations)

w1_ll, w2_ll, w3_ll, w4_ll, w5_ll = get_component(k, w_ll, equations)
w1_rr, w2_rr, w3_rr, w4_rr, w5_rr = get_component(k, w_rr, equations)

# Auxiliary variables
beta_ll = 0.5f0 * rho_ll / p_ll
beta_rr = 0.5f0 * rho_rr / p_rr
vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2
vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2

# Mean variables
rho_ln = ln_mean(rho_ll, rho_rr)
beta_ln = ln_mean(beta_ll, beta_rr)
rho_avg = 0.5f0 * (rho_ll + rho_rr)
v1_avg = 0.5f0 * (v1_ll + v1_rr)
v2_avg = 0.5f0 * (v2_ll + v2_rr)
v3_avg = 0.5f0 * (v3_ll + v3_rr)
beta_avg = 0.5f0 * (beta_ll + beta_rr)
tau = 1 / (beta_ll + beta_rr)
p_mean = 0.5f0 * rho_avg / beta_avg
p_star = 0.5f0 * rho_ln / beta_ln
vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)
vel_avg_norm = v1_avg^2 + v2_avg^2 + v3_avg^2
E_bar = p_star / (gammas[k] - 1) +
0.5f0 * rho_ln * (2 * vel_avg_norm - vel_norm_avg)

h11 = rho_ln
h12 = rho_ln * v1_avg
h13 = rho_ln * v2_avg
h14 = rho_ln * v3_avg
h15 = E_bar
d1 = -0.5f0 * λ *
(h11 * (w1_rr - w1_ll) +
h12 * (w2_rr - w2_ll) +
h13 * (w3_rr - w3_ll) +
h14 * (w4_rr - w4_ll) +
h15 * (w5_rr - w5_ll))

h21 = h12
h22 = rho_ln * v1_avg^2 + p_mean
h23 = h21 * v2_avg
h24 = h21 * v3_avg
h25 = (E_bar + p_mean) * v1_avg
d2 = -0.5f0 * λ *
(h21 * (w1_rr - w1_ll) +
h22 * (w2_rr - w2_ll) +
h23 * (w3_rr - w3_ll) +
h24 * (w4_rr - w4_ll) +
h25 * (w5_rr - w5_ll))

h31 = h13
h32 = h23
h33 = rho_ln * v2_avg^2 + p_mean
h34 = h31 * v3_avg
h35 = (E_bar + p_mean) * v2_avg
d3 = -0.5f0 * λ *
(h31 * (w1_rr - w1_ll) +
h32 * (w2_rr - w2_ll) +
h33 * (w3_rr - w3_ll) +
h34 * (w4_rr - w4_ll) +
h35 * (w5_rr - w5_ll))

h41 = h14
h42 = h24
h43 = h34
h44 = rho_ln * v3_avg^2 + p_mean
h45 = (E_bar + p_mean) * v3_avg
d4 = -0.5f0 * λ *
(h41 * (w1_rr - w1_ll) +
h42 * (w2_rr - w2_ll) +
h43 * (w3_rr - w3_ll) +
h44 * (w4_rr - w4_ll) +
h45 * (w5_rr - w5_ll))

h51 = h15
h52 = h25
h53 = h35
h54 = h45
h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln
+
vel_avg_norm * p_mean)
d5 = -0.5f0 * λ *
(h51 * (w1_rr - w1_ll) +
h52 * (w2_rr - w2_ll) +
h53 * (w3_rr - w3_ll) +
h54 * (w4_rr - w4_ll) +
h55 * (w5_rr - w5_ll))

beta_plus_ll += beta_ll
beta_plus_rr += beta_rr

set_component!(dissipation, k, d1, d2, d3, d4, d5, equations)
end

# Compute the dissipation related to the magnetic and divergence-cleaning fields
################################################################################

h_B_psi = 1 / (beta_plus_ll + beta_plus_rr)

# Dissipation for the magnetic field components due to the diagonal entries of the
# dissipation matrix ``H``. These are the dissipation values that depend on the diagonal
# entries of the entropy Jacobian that are marked in cyan in Figure 1 of the reference given above.
dissipation[1] = -0.5f0 * λ * h_B_psi * (w_rr[1] - w_ll[1])
dissipation[2] = -0.5f0 * λ * h_B_psi * (w_rr[2] - w_ll[2])
dissipation[3] = -0.5f0 * λ * h_B_psi * (w_rr[3] - w_ll[3])

# Dissipation for the divergence-cleaning field due to the diagonal entry of the
# dissipation matrix ``H``. This dissipation value depends on the single diagonal
# entry of the entropy Jacobian that is marked in red in Figure 1 of the reference given above.
dissipation[end] = -0.5f0 * λ * h_B_psi * (w_rr[end] - w_ll[end])

# Dissipation due to the off-diagonal blocks (``B_{off}``) of the dissipation matrix ``H`` and to the entries
# of the block ``A`` that depend on the magnetic field ``B`` and the divergence cleaning field ``psi``.
# See equations (80)-(82) of the given reference.
for k in eachcomponent(equations)
_, _, _, _, w5_ll = get_component(k, w_ll, equations)
_, _, _, _, w5_rr = get_component(k, w_rr, equations)

# Dissipation for the magnetic field components and divergence cleaning field due to the off-diagonal
# entries of the dissipation matrix ``H`` (block ``B^T`` in equation (80) and Figure 1 of the reference
# given above).
dissipation[1] -= 0.5f0 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll)
dissipation[2] -= 0.5f0 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll)
dissipation[3] -= 0.5f0 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll)
dissipation[end] -= 0.5f0 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll)

# Dissipation for the energy equation of species `k` depending on `w_1`, `w_2`, `w_3` and `w_end`. These are the
# values of the dissipation that depend on the off-diagonal block ``B`` of the dissipation matrix ``H`` (see equation (80)
# and Figure 1 of the reference given above.
ind_E = 3 + 5 * k # simplified version of 3 + (k - 1) * 5 + 5
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1])
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2])
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3])
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end])

# Dissipation for the energy equation of all ion species depending on `w_5`. These are the values of the dissipation
# vector that depend on the magnetic and divergence-cleaning field terms of the entries marked with a red cross in
# Figure 1 of the reference given above.
for kk in eachcomponent(equations)
ind_E = 3 + 5 * kk # simplified version of 3 + (kk - 1) * 5 + 5
dissipation[ind_E] -= 0.5f0 * λ *
(h_B_psi *
(B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2)) *
(w5_rr - w5_ll)
end
end

return dissipation
end
end
6 changes: 3 additions & 3 deletions src/equations/ideal_glm_mhd_multiion_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real,
AbstractIdealGlmMhdMultiIonEquations{2, NVARS, NCOMP}
gammas::SVector{NCOMP, RealT} # Heat capacity ratios
charge_to_mass::SVector{NCOMP, RealT} # Charge to mass ratios
electron_pressure::ElectronPressure # Function to compute the electron pressure
c_h::RealT # GLM cleaning speed
electron_pressure::ElectronPressure # Function to compute the electron pressure
c_h::RealT # GLM cleaning speed
function IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT,
ElectronPressure}(gammas
::SVector{NCOMP, RealT},
Expand Down Expand Up @@ -110,7 +110,7 @@ function initial_condition_weak_blast_wave(x, t,
# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)
# Same discontinuity in the velocities but with magnetic fields
# Set up polar coordinates
RealT = real(equations)
RealT = eltype(x)
inicenter = (0, 0)
x_norm = x[1] - inicenter[1]
y_norm = x[2] - inicenter[2]
Expand Down
40 changes: 40 additions & 0 deletions src/equations/numerical_fluxes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,46 @@ See [`FluxLaxFriedrichs`](@ref).
"""
const flux_lax_friedrichs = FluxLaxFriedrichs()

@doc raw"""
DissipationLaxFriedrichsEntropyVariables(max_abs_speed=max_abs_speed_naive)
Create a local Lax-Friedrichs-type dissipation operator that is provably entropy stable. This operator
must be used together with an entropy-conservative two-point flux function (e.g., `flux_ec`) to yield
an entropy-stable surface flux. The surface flux function can be initialized as:
```julia
flux_es = FluxPlusDissipation(flux_ec, DissipationLaxFriedrichsEntropyVariables())
```
In particular, the numerical flux has the form
```math
f^{\mathrm{ES}} = f^{\mathrm{EC}} - \frac{1}{2} \lambda_{\mathrm{max}} H (w_r - w_l),
```
where ``f^{\mathrm{EC}}`` is the entropy-conservative two-point flux function (computed with, e.g., `flux_ec`), ``\lambda_{\mathrm{max}}``
is the maximum wave speed estimated as `max_abs_speed(u_l, u_r, orientation_or_normal_direction, equations)`,
defaulting to [`max_abs_speed_naive`](@ref), ``H`` is a symmetric positive-definite dissipation matrix that
depends on the left and right states `u_l` and `u_r`, and ``(w_r - w_l)`` is the jump in entropy variables.
Ideally, ``H (w_r - w_l) = (u_r - u_l)``, such that the dissipation operator is consistent with the local
Lax-Friedrichs dissipation.
The entropy-stable dissipation operator is computed with the function
`function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_l, u_r, orientation_or_normal_direction, equations)`,
which must be specialized for each equation.
For the derivation of the dissipation matrix for the multi-ion GLM-MHD equations, see:
- A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization
of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.
[DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).
"""
struct DissipationLaxFriedrichsEntropyVariables{MaxAbsSpeed}
max_abs_speed::MaxAbsSpeed
end

DissipationLaxFriedrichsEntropyVariables() = DissipationLaxFriedrichsEntropyVariables(max_abs_speed_naive)

function Base.show(io::IO, d::DissipationLaxFriedrichsEntropyVariables)
print(io, "DissipationLaxFriedrichsEntropyVariables(", d.max_abs_speed, ")")
end

"""
FluxHLL(min_max_speed=min_max_speed_davis)
Expand Down
49 changes: 48 additions & 1 deletion test/test_tree_2d_mhdmultiion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using Trixi
include("test_trixi.jl")

# pathof(Trixi) returns /path/to/Trixi/src/Trixi.jl, dirname gives the parent directory
EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2d_dgsem")
EXAMPLES_DIR = joinpath(examples_dir(), "tree_2d_dgsem")

@testset "MHD Multi-ion" begin
#! format: noindent
Expand Down Expand Up @@ -55,6 +55,53 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2
end
end

@trixi_testset "Provably entropy-stable LLF-type fluxes for multi-ion GLM-MHD" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"),
l2=[
0.017668017558288736,
0.01779783612885502,
0.027841673842076285,
0.015603429086471762,
0.017849042999817964,
0.01814196379994667,
0.005478212889809162,
0.20585517887094282,
0.021301245733548135,
0.03018506565829777,
0.02938517728342881,
0.01837279433780041,
0.11810307914710033,
0.0002962677911603057
],
linf=[
0.06594754030722516,
0.06587779693691242,
0.09451464686853495,
0.06787230638663028,
0.08910065803824378,
0.08828064474448032,
0.023647579422062297,
0.8059383650828509,
0.1224367642558366,
0.15930418161523857,
0.15382860284948224,
0.08695364286964764,
0.4949375933243716,
0.003287251595115295
],
surface_flux=(FluxPlusDissipation(flux_ruedaramirez_etal,
DissipationLaxFriedrichsEntropyVariables()),
flux_nonconservative_ruedaramirez_etal))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
t = sol.t[end]
u_ode = sol.u[end]
du_ode = similar(u_ode)
@test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 1000
end
end

@trixi_testset "elixir_mhdmultiion_ec.jl with local Lax-Friedrichs at the surface" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"),
l2=[
Expand Down
Loading

0 comments on commit d6075f2

Please sign in to comment.