From ed1673e981baad18b5e5d8c1538b63a049f7ae67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 28 Mar 2023 18:25:30 +0200 Subject: [PATCH 001/108] Started to implement the multi-ion MHD equations --- src/equations/equations.jl | 4 + src/equations/ideal_mhd_multiion_1d.jl | 494 +++++++++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 src/equations/ideal_mhd_multiion_1d.jl diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 68612347d39..33359ea28e2 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -342,6 +342,10 @@ abstract type AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP} <: include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") +# IdealGlmMhdMultiIonEquations +abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end +include("ideal_mhd_multiion_1d.jl") + # Retrieve number of components from equation instance for the multicomponent case @inline ncomponents(::AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP """ diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl new file mode 100644 index 00000000000..b3a886c5d38 --- /dev/null +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -0,0 +1,494 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin + + +@doc raw""" + IdealGlmMhdMultiIonEquations1D + +The ideal compressible multi-ion GLM-MHD equations in one space dimension. + +* Until now, actually without GLM +""" +mutable struct IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealGlmMhdMultiIonEquations{1, NVARS, NCOMP} + gammas ::SVector{NCOMP, RealT} # Heat capacity rations + charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios + + function IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, + charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} + + NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass) + end +end + +function IdealGlmMhdMultiIonEquations1D(; gammas, charge_to_mass) + + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) +end + +@inline Base.real(::IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT + +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = True() + +function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D) + + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., tuple("rho" * string(i),"rho_v1" * string(i), "rho_v2" * string(i), "rho_v3" * string(i), "rho_e" * string(i))...) + end + + return cons +end + +function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations1D) + + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., tuple("rho" * string(i),"v1" * string(i), "v2" * string(i), "v3" * string(i), "p" * string(i))...) + end + + return prim +end + + +# """ +# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations1D) + +# An Alfvén wave as smooth initial condition used for convergence tests. +# """ +# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations1D) +# # smooth Alfvén wave test from Derigs et al. FLASH (2016) +# # domain must be set to [0, 1], γ = 5/3 + +# rho = 1.0 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# v1 = 0.0 +# si, co = sincos(2 * pi * x[1]) +# v2 = 0.1 * si +# v3 = 0.1 * co +# p = 0.1 +# B1 = 1.0 +# B2 = v2 +# B3 = v3 +# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) +# return prim2cons(vcat(prim_other, prim_rho), equations) +# end + + +# """ +# initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) + +# A weak blast wave adapted from +# - Sebastian Hennemann, Gregor J. Gassner (2020) +# A provably entropy stable subcell shock capturing approach for high order split form DG +# [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +# """ +# function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) +# # 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 +# inicenter = (0) +# x_norm = x[1] - inicenter[1] +# r = sqrt(x_norm^2) +# phi = atan(x_norm) + +# # Calculate primitive variables +# if r > 0.5 +# rho = 1.0 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# else +# rho = 1.1691 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# end +# v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) +# p = r > 0.5 ? 1.0 : 1.245 + +# prim_other = SVector{7, real(equations)}(v1, 0.0, 0.0, p, 1.0, 1.0, 1.0) + +# return prim2cons(vcat(prim_other, prim_rho), equations) +# end + + +# Calculate 1D flux in for a single point +@inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) + B1, B2, B3, _ = u + + total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + + f_B1 = 0.0 + f_B2 = v1_plus * B2 - v2_plus * B1 + f_B3 = v1_plus * B3 - v3_plus * B1 + + f = (f_B1, f_B2, f_B3) + + mag_en = 0.5*(B1^2 + B2^2 + B3^2) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1/rho + v2 = rho_v2/rho + v3 = rho_v3/rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v1 + f2 = rho_v1*v1 + p #+ mag_en - B1^2 + f3 = rho_v1*v2 #- B1*B2 + f4 = rho_v1*v3 #- B1*B3 + f5 = (kin_en + gamma*p/(gamma - 1))*v1 + + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + f = (f..., f1, f2, f3, f4, f5) + end + + return SVector{equations.NVARS, real(equations)}(f) +end + +""" +Total non-conservative two-point flux +""" +@inline function flux_nonconservative_all(u_ll, u_rr, orientation::Integer, + equations::ShallowWaterEquations1D) + + # Compute Powell + + # Compute term 2 + + # Compute term 3 + + return f +end + +# """ +# flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) + +# Entropy conserving two-point flux adapted by +# - Derigs et al. (2018) +# Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field +# divergence diminishing ideal magnetohydrodynamics equations for multi-ion +# [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +# """ +# function flux_derigs_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +# # Unpack left and right states to get velocities, pressure, and inverse temperature (called beta) +# rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll = u_ll +# rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr = u_rr +# @unpack gammas, gas_constants, cv = equations + +# rho_ll = density(u_ll, equations) +# rho_rr = density(u_rr, equations) + +# gamma_ll = totalgamma(u_ll, equations) +# gamma_rr = totalgamma(u_rr, equations) + +# rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i+7], u_rr[i+7]) for i in eachcomponent(equations)) +# rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5 * (u_ll[i+7] + u_rr[i+7]) for i in eachcomponent(equations)) + +# v1_ll = rho_v1_ll/rho_ll +# v2_ll = rho_v2_ll/rho_ll +# v3_ll = rho_v3_ll/rho_ll +# v1_rr = rho_v1_rr/rho_rr +# v2_rr = rho_v2_rr/rho_rr +# v3_rr = rho_v3_rr/rho_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 +# mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 +# mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 +# # for convenience store v⋅B +# vel_dot_mag_ll = v1_ll*B1_ll + v2_ll*B2_ll + v3_ll*B3_ll +# vel_dot_mag_rr = v1_rr*B1_rr + v2_rr*B2_rr + v3_rr*B3_rr + +# # Compute the necessary mean values needed for either direction +# v1_avg = 0.5*(v1_ll+v1_rr) +# v2_avg = 0.5*(v2_ll+v2_rr) +# v3_avg = 0.5*(v3_ll+v3_rr) +# v_sum = v1_avg + v2_avg + v3_avg +# B1_avg = 0.5*(B1_ll+B1_rr) +# B2_avg = 0.5*(B2_ll+B2_rr) +# B3_avg = 0.5*(B3_ll+B3_rr) +# vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) +# mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) +# vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) + +# enth = zero(v_sum) +# help1_ll = zero(v1_ll) +# help1_rr = zero(v1_rr) + +# for i in eachcomponent(equations) +# enth += rhok_avg[i] * gas_constants[i] +# help1_ll += u_ll[i+7] * cv[i] +# help1_rr += u_rr[i+7] * cv[i] +# end + +# T_ll = (rho_e_ll - 0.5*rho_ll * (vel_norm_ll) - 0.5*mag_norm_ll) / help1_ll +# T_rr = (rho_e_rr - 0.5*rho_rr * (vel_norm_rr) - 0.5*mag_norm_rr) / help1_rr +# T = 0.5 * (1.0/T_ll + 1.0/T_rr) +# T_log = ln_mean(1.0/T_ll, 1.0/T_rr) + +# # Calculate fluxes depending on orientation with specific direction averages +# help1 = zero(T_ll) +# help2 = zero(T_rr) + +# f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i]*v1_avg for i in eachcomponent(equations)) +# for i in eachcomponent(equations) +# help1 += f_rho[i] * cv[i] +# help2 += f_rho[i] +# end +# f1 = help2 * v1_avg + enth/T + 0.5 * mag_norm_avg - B1_avg*B1_avg +# f2 = help2 * v2_avg - B1_avg*B2_avg +# f3 = help2 * v3_avg - B1_avg*B3_avg +# f5 = 0.0 +# f6 = v1_avg*B2_avg - v2_avg*B1_avg +# f7 = v1_avg*B3_avg - v3_avg*B1_avg + +# # total energy flux is complicated and involves the previous eight components +# v1_mag_avg = 0.5*(v1_ll*mag_norm_ll + v1_rr*mag_norm_rr) + +# f4 = (help1/T_log) - 0.5 * (vel_norm_avg) * (help2) + f1 * v1_avg + f2 * v2_avg + f3 * v3_avg + +# f5 * B1_avg + f6 * B2_avg + f7 * B3_avg - 0.5*v1_mag_avg + +# B1_avg * vel_dot_mag_avg + + +# f_other = SVector{7, real(equations)}(f1, f2, f3, f4, f5, f6, f7) + +# return vcat(f_other, f_rho) +# end + +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation +# TODO: Check if this maximum wave speed is right +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) + rho_v1_ll, _ = u_ll + rho_v1_rr, _ = u_rr + + rho_ll = density(u_ll, equations) + rho_rr = density(u_rr, equations) + + # Calculate velocities (ignore orientation since it is always "1" in 1D) + # and fast magnetoacoustic wave speeds + # left + v_ll = rho_v1_ll / rho_ll + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + v_rr = rho_v1_rr / rho_rr + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end + + +# @inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations1D) +# rho_v1, _ = u + +# rho = density(u, equations) + +# v1 = rho_v1 / rho + +# cf_x_direction = calc_fast_wavespeed(u, 1, equations) + +# return (abs(v1) + cf_x_direction, ) +# end + + +# # Convert conservative variables to primitive +# function cons2prim(u, equations::IdealGlmMhdMultiIonEquations1D) +# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u + +# prim_rho = SVector{ncomponents(equations), real(equations)}(u[i+7] for i in eachcomponent(equations)) +# rho = density(u, equations) + +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# v3 = rho_v3 / rho + +# gamma = totalgamma(u, equations) + +# p = (gamma - 1) * (rho_e - 0.5*rho*(v1^2 + v2^2 + v3^2) - 0.5*(B1^2 + B2^2 + B3^2)) +# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) +# return vcat(prim_other, prim_rho) +# end + +# # Convert conservative variables to entropy +# @inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations1D) +# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u +# @unpack cv, gammas, gas_constants = equations + +# rho = density(u, equations) + +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# v3 = rho_v3 / rho +# v_square = v1^2 + v2^2 + v3^2 +# gamma = totalgamma(u, equations) +# p = (gamma - 1) * (rho_e - 0.5*rho*v_square - 0.5*(B1^2 + B2^2 + B3^2)) +# s = log(p) - gamma*log(rho) +# rho_p = rho / p + +# # MultiIon stuff +# help1 = zero(v1) + +# for i in eachcomponent(equations) +# help1 += u[i+7] * cv[i] +# end + +# T = (rho_e - 0.5 * rho * v_square - 0.5*(B1^2 + B2^2 + B3^2)) / (help1) + +# entrop_rho = SVector{ncomponents(equations), real(equations)}( -1.0 * (cv[i] * log(T) - gas_constants[i] * log(u[i+7])) + gas_constants[i] + cv[i] - (v_square / (2*T)) for i in eachcomponent(equations)) + +# w1 = v1 / T +# w2 = v2 / T +# w3 = v3 / T +# w4 = -1.0 / T +# w5 = B1 / T +# w6 = B2 / T +# w7 = B3 / T + +# entrop_other = SVector{7, real(equations)}(w1, w2, w3, w4, w5, w6, w7) + +# return vcat(entrop_other, entrop_rho) +# end + + +# # Convert primitive to conservative variables +# @inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations1D) +# v1, v2, v3, p, B1, B2, B3 = prim + +# cons_rho = SVector{ncomponents(equations), real(equations)}(prim[i+7] for i in eachcomponent(equations)) +# rho = density(prim, equations) + +# rho_v1 = rho * v1 +# rho_v2 = rho * v2 +# rho_v3 = rho * v3 + +# gamma = totalgamma(prim, equations) +# rho_e = p/(gamma-1) + 0.5 * (rho_v1*v1 + rho_v2*v2 + rho_v3*v3) + +# 0.5 * (B1^2 + B2^2 + B3^2) + +# cons_other = SVector{7, real(equations)}(rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3) + +# return vcat(cons_other, cons_rho) +# end + + +# @inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations1D) +# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u +# rho = density(u, equations) +# gamma = totalgamma(u, equations) +# p = (gamma - 1)*(rho_e - 0.5 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho +# - 0.5 * (B1^2 + B2^2 + B3^2) +# ) +# return rho * p +# end + + +# # Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue +# @inline function calc_fast_wavespeed(cons, direction, equations::IdealGlmMhdMultiIonEquations1D) +# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = cons +# rho = density(cons, equations) +# v1 = rho_v1 / rho +# v2 = rho_v2 / rho +# v3 = rho_v3 / rho +# v_mag = sqrt(v1^2 + v2^2 + v3^2) +# gamma = totalgamma(cons, equations) +# p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) +# a_square = gamma * p / rho +# sqrt_rho = sqrt(rho) +# b1 = B1 / sqrt_rho +# b2 = B2 / sqrt_rho +# b3 = B3 / sqrt_rho +# b_square = b1^2 + b2^2 + b3^2 + +# c_f = sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2)) + +# return c_f +# end + + +# @inline function density(u, equations::IdealGlmMhdMultiIonEquations1D) +# rho = zero(u[1]) + +# for i in eachcomponent(equations) +# rho += u[i+7] +# end + +# return rho +# end + + +# @inline function totalgamma(u, equations::IdealGlmMhdMultiIonEquations1D) +# @unpack cv, gammas = equations + +# help1 = zero(u[1]) +# help2 = zero(u[1]) + +# for i in eachcomponent(equations) +# help1 += u[i+7] * cv[i] * gammas[i] +# help2 += u[i+7] * cv[i] +# end + +# return help1/help2 +# end + + +# @inline function densities(u, v, equations::IdealGlmMhdMultiIonEquations1D) + +# return SVector{ncomponents(equations), real(equations)}(u[i+7]*v for i in eachcomponent(equations)) +# end + +""" +Routine to compute the auxiliary variables: +* total_electron_charge +* v*_plus: Charge-averaged velocity +* vk*_plus: Contribution of each species to the charge-averaged velocity +""" +@inline function auxiliary_variables(u, equations::IdealGlmMhdMultiIonEquations1D) + + total_electron_charge = zero(u[1]) + + vk1_plus = zeros(equations.NCOMP,u[1]) + vk2_plus = zeros(equations.NCOMP,u[1]) + vk3_plus = zeros(equations.NCOMP,u[1]) + + for k in eachcomponent(equations) + rho_k = u[(k-1)*5+4] + rho_v1_k = u[(k-1)*5+5] + rho_v2_k = u[(k-1)*5+6] + rho_v3_k = u[(k-1)*5+7] + total_electron_charge += rho_k * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1_k * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2_k * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3_k * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return total_electron_charge, v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), + SVector{ncomponents(equations), real(equations)}(vk2_plus), + SVector{ncomponents(equations), real(equations)}(vk3_plus) +end + +""" +Get the flow variables of component k +""" +@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations1D) + return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) +end + +end # @muladd From e83ce8beaa15b0e6931d3636e28841f1c014058f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 29 Mar 2023 11:58:46 +0200 Subject: [PATCH 002/108] Some progress with the 1D multi-ion MHD equations: First "working" version with only conservative flux and estimates of wavespeeds --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 57 ++++ src/Trixi.jl | 2 +- src/equations/equations.jl | 11 + src/equations/ideal_mhd_multiion_1d.jl | 287 +++++++++--------- 4 files changed, 206 insertions(+), 151 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl new file mode 100644 index 00000000000..39e1a7e5917 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -0,0 +1,57 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = flux_central +solver = DGSEM(polydeg=3, surface_flux=flux_central, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = 0.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 9a1ecea4400..0191134bb0d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -128,7 +128,7 @@ export AcousticPerturbationEquations2D, CompressibleEulerEquations1D, CompressibleEulerEquations2D, CompressibleEulerEquations3D, CompressibleEulerMulticomponentEquations1D, CompressibleEulerMulticomponentEquations2D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, - IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, + IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMultiIonEquations1D, IdealGlmMhdMulticomponentEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, LinearScalarAdvectionEquation3D, InviscidBurgersEquation1D, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 33359ea28e2..4e6659aa696 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -357,6 +357,17 @@ In particular, not the components themselves are returned. """ @inline eachcomponent(equations::AbstractIdealGlmMhdMulticomponentEquations) = Base.OneTo(ncomponents(equations)) +# Retrieve number of components from equation instance for the multi-ion case +@inline ncomponents(::AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP +""" + eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) + +Return an iterator over the indices that specify the location in relevant data structures +for the components in `AbstractIdealGlmMhdMultiIonEquations`. +In particular, not the components themselves are returned. +""" +@inline eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) = Base.OneTo(ncomponents(equations)) + # Diffusion equation: first order hyperbolic system abstract type AbstractHyperbolicDiffusionEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end include("hyperbolic_diffusion_1d.jl") diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index b3a886c5d38..7a855a9f11f 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -42,7 +42,7 @@ end @inline Base.real(::IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = True() +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = False() #TODO: Change to True() after testing fluxes function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D) @@ -89,38 +89,40 @@ end # end -# """ -# initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) +""" + initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) -# A weak blast wave adapted from -# - Sebastian Hennemann, Gregor J. Gassner (2020) -# A provably entropy stable subcell shock capturing approach for high order split form DG -# [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -# """ -# function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) -# # 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 -# inicenter = (0) -# x_norm = x[1] - inicenter[1] -# r = sqrt(x_norm^2) -# phi = atan(x_norm) - -# # Calculate primitive variables -# if r > 0.5 -# rho = 1.0 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# else -# rho = 1.1691 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# end -# v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) -# p = r > 0.5 ? 1.0 : 1.245 +A weak blast wave adapted from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) + # 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 + inicenter = (0) + x_norm = x[1] - inicenter[1] + r = sqrt(x_norm^2) + phi = atan(x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 + end + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + p = r > 0.5 ? 1.0 : 1.245 -# prim_other = SVector{7, real(equations)}(v1, 0.0, 0.0, p, 1.0, 1.0, 1.0) + prim = (1.0, 1.0, 1.0) + for i in eachcomponent(equations) + prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) + end -# return prim2cons(vcat(prim_other, prim_rho), equations) -# end + return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) +end # Calculate 1D flux in for a single point @@ -156,7 +158,7 @@ end f = (f..., f1, f2, f3, f4, f5) end - return SVector{equations.NVARS, real(equations)}(f) + return SVector{nvariables(equations), real(equations)}(f) end """ @@ -165,10 +167,10 @@ Total non-conservative two-point flux @inline function flux_nonconservative_all(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations1D) - # Compute Powell + # Compute Powell (only needed for non-constant B1) # Compute term 2 - + # Compute term 3 return f @@ -185,9 +187,9 @@ end # """ # function flux_derigs_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) # # Unpack left and right states to get velocities, pressure, and inverse temperature (called beta) -# rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll = u_ll -# rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr = u_rr -# @unpack gammas, gas_constants, cv = equations +# B1_ll, B2_ll, B3_ll, _ = u_ll +# B1_rr, B2_rr, B3_rr, _ = u_rr +# @unpack gammas = equations # rho_ll = density(u_ll, equations) # rho_rr = density(u_rr, equations) @@ -268,119 +270,96 @@ end # return vcat(f_other, f_rho) # end +""" # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation -# TODO: Check if this maximum wave speed is right + !!!ATTENTION: This routine is provisory. TODO: Update with the right max_abs_speed +""" @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) - rho_v1_ll, _ = u_ll - rho_v1_rr, _ = u_rr - - rho_ll = density(u_ll, equations) - rho_rr = density(u_rr, equations) - - # Calculate velocities (ignore orientation since it is always "1" in 1D) - # and fast magnetoacoustic wave speeds + # Calculate fast magnetoacoustic wave speeds # left - v_ll = rho_v1_ll / rho_ll cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) # right - v_rr = rho_v1_rr / rho_rr cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + # Calculate velocities (ignore orientation since it is always "1" in 1D) + v_ll = zero(u_ll[1]) + v_rr = zero(u_rr[1]) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end -# @inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations1D) -# rho_v1, _ = u - -# rho = density(u, equations) - -# v1 = rho_v1 / rho - -# cf_x_direction = calc_fast_wavespeed(u, 1, equations) - -# return (abs(v1) + cf_x_direction, ) -# end - - -# # Convert conservative variables to primitive -# function cons2prim(u, equations::IdealGlmMhdMultiIonEquations1D) -# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u - -# prim_rho = SVector{ncomponents(equations), real(equations)}(u[i+7] for i in eachcomponent(equations)) -# rho = density(u, equations) - -# v1 = rho_v1 / rho -# v2 = rho_v2 / rho -# v3 = rho_v3 / rho - -# gamma = totalgamma(u, equations) - -# p = (gamma - 1) * (rho_e - 0.5*rho*(v1^2 + v2^2 + v3^2) - 0.5*(B1^2 + B2^2 + B3^2)) -# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) -# return vcat(prim_other, prim_rho) -# end - -# # Convert conservative variables to entropy -# @inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations1D) -# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u -# @unpack cv, gammas, gas_constants = equations - -# rho = density(u, equations) - -# v1 = rho_v1 / rho -# v2 = rho_v2 / rho -# v3 = rho_v3 / rho -# v_square = v1^2 + v2^2 + v3^2 -# gamma = totalgamma(u, equations) -# p = (gamma - 1) * (rho_e - 0.5*rho*v_square - 0.5*(B1^2 + B2^2 + B3^2)) -# s = log(p) - gamma*log(rho) -# rho_p = rho / p +@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations1D) + + v1 = zero(u[1]) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + end -# # MultiIon stuff -# help1 = zero(v1) + cf_x_direction = calc_fast_wavespeed(u, 1, equations) -# for i in eachcomponent(equations) -# help1 += u[i+7] * cv[i] -# end + return (abs(v1) + cf_x_direction, ) +end -# T = (rho_e - 0.5 * rho * v_square - 0.5*(B1^2 + B2^2 + B3^2)) / (help1) -# entrop_rho = SVector{ncomponents(equations), real(equations)}( -1.0 * (cv[i] * log(T) - gas_constants[i] * log(u[i+7])) + gas_constants[i] + cv[i] - (v_square / (2*T)) for i in eachcomponent(equations)) +# Convert conservative variables to primitive +function cons2prim(u, equations::IdealGlmMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3, _ = u -# w1 = v1 / T -# w2 = v2 / T -# w3 = v3 / T -# w4 = -1.0 / T -# w5 = B1 / T -# w6 = B2 / T -# w7 = B3 / T + prim = (B1, B2, B3) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + prim = (prim..., rho, v1, v2, v3, p) + end -# entrop_other = SVector{7, real(equations)}(w1, w2, w3, w4, w5, w6, w7) + return SVector{nvariables(equations), real(equations)}(prim) +end -# return vcat(entrop_other, entrop_rho) -# end +""" +Convert conservative variables to entropy +!!!ATTENTION: Provisory. TODO: Change +""" +@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations1D) + B1, B2, B3, _ = u + + return SVector{nvariables(equations), real(equations)}(zeros(typeof(u[1]), nvariables(equations))) +end # # Convert primitive to conservative variables -# @inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations1D) -# v1, v2, v3, p, B1, B2, B3 = prim - -# cons_rho = SVector{ncomponents(equations), real(equations)}(prim[i+7] for i in eachcomponent(equations)) -# rho = density(prim, equations) - -# rho_v1 = rho * v1 -# rho_v2 = rho * v2 -# rho_v3 = rho * v3 +@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3, _ = prim -# gamma = totalgamma(prim, equations) -# rho_e = p/(gamma-1) + 0.5 * (rho_v1*v1 + rho_v2*v2 + rho_v3*v3) + -# 0.5 * (B1^2 + B2^2 + B3^2) - -# cons_other = SVector{7, real(equations)}(rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3) + cons = (B1, B2, B3) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + cons = (cons..., rho, rho_v1, rho_v2, rho_v3, rho_e) + end -# return vcat(cons_other, cons_rho) -# end + return SVector{nvariables(equations), real(equations)}(cons) +end # @inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations1D) @@ -393,28 +372,36 @@ end # return rho * p # end +""" +Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisory.. Change once the fastest wave speed is known!! +""" +@inline function calc_fast_wavespeed(cons, direction, equations::IdealGlmMhdMultiIonEquations1D) + B1, B2, B3, _ = cons -# # Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue -# @inline function calc_fast_wavespeed(cons, direction, equations::IdealGlmMhdMultiIonEquations1D) -# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = cons -# rho = density(cons, equations) -# v1 = rho_v1 / rho -# v2 = rho_v2 / rho -# v3 = rho_v3 / rho -# v_mag = sqrt(v1^2 + v2^2 + v3^2) -# gamma = totalgamma(cons, equations) -# p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) -# a_square = gamma * p / rho -# sqrt_rho = sqrt(rho) -# b1 = B1 / sqrt_rho -# b2 = B2 / sqrt_rho -# b3 = B3 / sqrt_rho -# b_square = b1^2 + b2^2 + b3^2 - -# c_f = sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2)) - -# return c_f -# end + c_f = zero(cons[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2))) + end + + return c_f +end # @inline function density(u, equations::IdealGlmMhdMultiIonEquations1D) @@ -458,9 +445,9 @@ Routine to compute the auxiliary variables: total_electron_charge = zero(u[1]) - vk1_plus = zeros(equations.NCOMP,u[1]) - vk2_plus = zeros(equations.NCOMP,u[1]) - vk3_plus = zeros(equations.NCOMP,u[1]) + vk1_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk2_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk3_plus = zeros(typeof(u[1]), ncomponents(equations)) for k in eachcomponent(equations) rho_k = u[(k-1)*5+4] From 5ec8c0bdb409c392eb2912996bd53b7ebb6e84ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 29 Mar 2023 13:39:18 +0200 Subject: [PATCH 003/108] Added entropy variables --- src/equations/ideal_mhd_multiion_1d.jl | 77 ++++++++++---------------- 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 7a855a9f11f..38a1fd11f71 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -309,7 +309,9 @@ end end -# Convert conservative variables to primitive +""" +Convert conservative variables to primitive +""" function cons2prim(u, equations::IdealGlmMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = u @@ -332,16 +334,40 @@ end """ Convert conservative variables to entropy -!!!ATTENTION: Provisory. TODO: Change """ @inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations1D) + @unpack gammas = equations B1, B2, B3, _ = u + + prim = cons2prim(u, equations) + entropy = () + rho_p_plus = zero(u[1]) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + entropy = (entropy..., w1, w2, w3, w4, w5) + end + + # Additional non-conservative variables + w6 = rho_p_plus * B1 + w7 = rho_p_plus * B2 + w8 = rho_p_plus * B3 + entropy = (w6, w7, w8, entropy...) - return SVector{nvariables(equations), real(equations)}(zeros(typeof(u[1]), nvariables(equations))) + return SVector{nvariables(equations), real(equations)}(entropy) end -# # Convert primitive to conservative variables +""" +Convert primitive to conservative variables +""" @inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = prim @@ -361,17 +387,6 @@ end return SVector{nvariables(equations), real(equations)}(cons) end - -# @inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations1D) -# rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u -# rho = density(u, equations) -# gamma = totalgamma(u, equations) -# p = (gamma - 1)*(rho_e - 0.5 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho -# - 0.5 * (B1^2 + B2^2 + B3^2) -# ) -# return rho * p -# end - """ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue !!! ATTENTION: This routine is provisory.. Change once the fastest wave speed is known!! @@ -403,38 +418,6 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco return c_f end - -# @inline function density(u, equations::IdealGlmMhdMultiIonEquations1D) -# rho = zero(u[1]) - -# for i in eachcomponent(equations) -# rho += u[i+7] -# end - -# return rho -# end - - -# @inline function totalgamma(u, equations::IdealGlmMhdMultiIonEquations1D) -# @unpack cv, gammas = equations - -# help1 = zero(u[1]) -# help2 = zero(u[1]) - -# for i in eachcomponent(equations) -# help1 += u[i+7] * cv[i] * gammas[i] -# help2 += u[i+7] * cv[i] -# end - -# return help1/help2 -# end - - -# @inline function densities(u, v, equations::IdealGlmMhdMultiIonEquations1D) - -# return SVector{ncomponents(equations), real(equations)}(u[i+7]*v for i in eachcomponent(equations)) -# end - """ Routine to compute the auxiliary variables: * total_electron_charge From bbc3a0e8e2c186817c9b9441b446a98f394298a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 30 Mar 2023 10:43:07 +0200 Subject: [PATCH 004/108] Added (most of) one EC flux for multi-ion MHD --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 3 +- src/Trixi.jl | 2 +- src/equations/ideal_mhd_multiion_1d.jl | 206 +++++++++--------- 3 files changed, 111 insertions(+), 100 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index 39e1a7e5917..e2b4f6365cf 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -9,7 +9,8 @@ equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), initial_condition = initial_condition_weak_blast_wave -volume_flux = flux_central +#volume_flux = flux_central +volume_flux = flux_ruedaramirez_etal solver = DGSEM(polydeg=3, surface_flux=flux_central, volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/src/Trixi.jl b/src/Trixi.jl index 0191134bb0d..8cd26a28959 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -143,7 +143,7 @@ export GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, - flux_nonconservative_powell, + flux_nonconservative_powell, flux_ruedaramirez_etal flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 38a1fd11f71..498501ec933 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -116,9 +116,11 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonE v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) p = r > 0.5 ? 1.0 : 1.245 - prim = (1.0, 1.0, 1.0) + prim = (0.01, 0.01, 0.01) for i in eachcomponent(equations) - prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) + #prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) + #prim = (prim..., rho, v1, 0.0, 0.0, p) + prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) end return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) @@ -164,111 +166,119 @@ end """ Total non-conservative two-point flux """ -@inline function flux_nonconservative_all(u_ll, u_rr, orientation::Integer, +@inline function flux_nonconservative_ec(u_ll, u_rr, orientation::Integer, equations::ShallowWaterEquations1D) - + # Compute Powell (only needed for non-constant B1) # Compute term 2 - - # Compute term 3 + #f2 = + 0.5*mag_norm_avg - B1_avg*B1_avg + #f3 = - B1_avg*B2_avg + #f4 = - B1_avg*B3_avg + + # Compute term 3 (only needed for NCOMP>1) return f end -# """ -# flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) +""" + flux_ec(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) + +Entropy conserving two-point flux adapted by: +- Rueda-Ramírez et al. (2023) +This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: +- Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) + !!! ATENTION: The additional induction terms depending on v_minus are missing. TODO: add! +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + + # Compute averages for global variables + v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) + v2_plus_avg = 0.5*(v2_plus_ll+v2_plus_rr) + v3_plus_avg = 0.5*(v3_plus_ll+v3_plus_rr) + B1_avg = 0.5*(B1_ll+B1_rr) + B2_avg = 0.5*(B2_ll+B2_rr) + B3_avg = 0.5*(B3_ll+B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + + # Magnetic field components from f^MHD + f6 = 0.0 + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start concatenating the flux + f = (f6, f7, f8) + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) + + v1_ll = rho_v1_ll/rho_ll + v2_ll = rho_v2_ll/rho_ll + v3_ll = rho_v3_ll/rho_ll + v1_rr = rho_v1_rr/rho_rr + v2_rr = rho_v2_rr/rho_rr + v3_rr = rho_v3_rr/rho_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 + + p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) + p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) + beta_ll = 0.5*rho_ll/p_ll + beta_rr = 0.5*rho_rr/p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5*(rho_ll+rho_rr) + rho_mean = ln_mean(rho_ll,rho_rr) + beta_mean = ln_mean(beta_ll,beta_rr) + beta_avg = 0.5*(beta_ll+beta_rr) + p_mean = 0.5*rho_avg/beta_avg + v1_avg = 0.5*(v1_ll+v1_rr) + v2_avg = 0.5*(v2_ll+v2_rr) + v3_avg = 0.5*(v3_ll+v3_rr) + vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) + vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) + vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean*v1_avg + f2 = f1*v1_avg + p_mean + f3 = f1*v2_avg + f4 = f1*v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5*(vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + ) # Terms coming from the non-conservative term 3 (induction equation! TODO!!!) -# Entropy conserving two-point flux adapted by -# - Derigs et al. (2018) -# Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field -# divergence diminishing ideal magnetohydrodynamics equations for multi-ion -# [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) -# """ -# function flux_derigs_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) -# # Unpack left and right states to get velocities, pressure, and inverse temperature (called beta) -# B1_ll, B2_ll, B3_ll, _ = u_ll -# B1_rr, B2_rr, B3_rr, _ = u_rr -# @unpack gammas = equations - -# rho_ll = density(u_ll, equations) -# rho_rr = density(u_rr, equations) - -# gamma_ll = totalgamma(u_ll, equations) -# gamma_rr = totalgamma(u_rr, equations) - -# rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i+7], u_rr[i+7]) for i in eachcomponent(equations)) -# rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5 * (u_ll[i+7] + u_rr[i+7]) for i in eachcomponent(equations)) - -# v1_ll = rho_v1_ll/rho_ll -# v2_ll = rho_v2_ll/rho_ll -# v3_ll = rho_v3_ll/rho_ll -# v1_rr = rho_v1_rr/rho_rr -# v2_rr = rho_v2_rr/rho_rr -# v3_rr = rho_v3_rr/rho_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 -# mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 -# mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 -# # for convenience store v⋅B -# vel_dot_mag_ll = v1_ll*B1_ll + v2_ll*B2_ll + v3_ll*B3_ll -# vel_dot_mag_rr = v1_rr*B1_rr + v2_rr*B2_rr + v3_rr*B3_rr - -# # Compute the necessary mean values needed for either direction -# v1_avg = 0.5*(v1_ll+v1_rr) -# v2_avg = 0.5*(v2_ll+v2_rr) -# v3_avg = 0.5*(v3_ll+v3_rr) -# v_sum = v1_avg + v2_avg + v3_avg -# B1_avg = 0.5*(B1_ll+B1_rr) -# B2_avg = 0.5*(B2_ll+B2_rr) -# B3_avg = 0.5*(B3_ll+B3_rr) -# vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) -# mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) -# vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) - -# enth = zero(v_sum) -# help1_ll = zero(v1_ll) -# help1_rr = zero(v1_rr) - -# for i in eachcomponent(equations) -# enth += rhok_avg[i] * gas_constants[i] -# help1_ll += u_ll[i+7] * cv[i] -# help1_rr += u_rr[i+7] * cv[i] -# end - -# T_ll = (rho_e_ll - 0.5*rho_ll * (vel_norm_ll) - 0.5*mag_norm_ll) / help1_ll -# T_rr = (rho_e_rr - 0.5*rho_rr * (vel_norm_rr) - 0.5*mag_norm_rr) / help1_rr -# T = 0.5 * (1.0/T_ll + 1.0/T_rr) -# T_log = ln_mean(1.0/T_ll, 1.0/T_rr) - -# # Calculate fluxes depending on orientation with specific direction averages -# help1 = zero(T_ll) -# help2 = zero(T_rr) - -# f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i]*v1_avg for i in eachcomponent(equations)) -# for i in eachcomponent(equations) -# help1 += f_rho[i] * cv[i] -# help2 += f_rho[i] -# end -# f1 = help2 * v1_avg + enth/T + 0.5 * mag_norm_avg - B1_avg*B1_avg -# f2 = help2 * v2_avg - B1_avg*B2_avg -# f3 = help2 * v3_avg - B1_avg*B3_avg -# f5 = 0.0 -# f6 = v1_avg*B2_avg - v2_avg*B1_avg -# f7 = v1_avg*B3_avg - v3_avg*B1_avg - -# # total energy flux is complicated and involves the previous eight components -# v1_mag_avg = 0.5*(v1_ll*mag_norm_ll + v1_rr*mag_norm_rr) - -# f4 = (help1/T_log) - 0.5 * (vel_norm_avg) * (help2) + f1 * v1_avg + f2 * v2_avg + f3 * v3_avg + -# f5 * B1_avg + f6 * B2_avg + f7 * B3_avg - 0.5*v1_mag_avg + -# B1_avg * vel_dot_mag_avg - - -# f_other = SVector{7, real(equations)}(f1, f2, f3, f4, f5, f6, f7) - -# return vcat(f_other, f_rho) -# end + f = (f..., f1, f2, f3, f4, f5) + end + + return SVector{nvariables(equations), real(equations)}(f) +end """ # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation From 46f2500e52d62c30964a13f6033db39a5aca46d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 30 Mar 2023 15:02:39 +0200 Subject: [PATCH 005/108] Added non-conservative term 2 (MHD term) and tested consistency in the on-species case --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 5 +- .../elixir_mhdmultiion_ec_onespecies.jl | 59 ++++++++++++++ src/Trixi.jl | 2 +- src/equations/ideal_mhd_multiion_1d.jl | 81 ++++++++++++++----- 4 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index e2b4f6365cf..c4f8f4acb8a 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -10,8 +10,9 @@ equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), initial_condition = initial_condition_weak_blast_wave #volume_flux = flux_central -volume_flux = flux_ruedaramirez_etal -solver = DGSEM(polydeg=3, surface_flux=flux_central, +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +solver = DGSEM(polydeg=3, surface_flux=surface_flux, volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl new file mode 100644 index 00000000000..74c5eb1b93e --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -0,0 +1,59 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0), + charge_to_mass = (1.0)) + +initial_condition = initial_condition_weak_blast_wave + +#volume_flux = flux_central +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +solver = DGSEM(polydeg=3, surface_flux=surface_flux, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = 0.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 8cd26a28959..4dbbf97241e 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -143,7 +143,7 @@ export GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, - flux_nonconservative_powell, flux_ruedaramirez_etal + flux_nonconservative_powell, flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 498501ec933..c3de6182292 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -42,7 +42,7 @@ end @inline Base.real(::IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = False() #TODO: Change to True() after testing fluxes +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = True() function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D) @@ -116,11 +116,12 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonE v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) p = r > 0.5 ? 1.0 : 1.245 - prim = (0.01, 0.01, 0.01) + #prim = (0.01, 0.01, 0.01) + prim = (1.0, 1.0, 1.0) for i in eachcomponent(equations) - #prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) + prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) #prim = (prim..., rho, v1, 0.0, 0.0, p) - prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) + #prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) end return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) @@ -164,25 +165,69 @@ end end """ -Total non-conservative two-point flux +Total non-conservative two-point "flux"" as described in +- Rueda-Ramírez et al. (2023) +The term is composed of three parts +* The Powell term: Only needed in 1D for non-constant B1 +* The MHD term: The only one implemented so far.. and without the electron pressure. +* The "term 3" """ -@inline function flux_nonconservative_ec(u_ll, u_rr, orientation::Integer, - equations::ShallowWaterEquations1D) - - # Compute Powell (only needed for non-constant B1) +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + # Compute important averages + B1_avg = 0.5*(B1_ll+B1_rr) + B2_avg = 0.5*(B2_ll+B2_rr) + B3_avg = 0.5*(B3_ll+B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) - # Compute term 2 - #f2 = + 0.5*mag_norm_avg - B1_avg*B1_avg - #f3 = - B1_avg*B2_avg - #f4 = - B1_avg*B3_avg + # Compute charge ratio of u_ll + charge_ratio = zeros(typeof(u_ll[1]), ncomponents(equations)) + total_electron_charge = zero(u_ll[1]) + for k in eachcomponent(equations) + rho_k = u_ll[(k-1)*5+4] + charge_ratio[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio[k] + end + charge_ratio ./= total_electron_charge + + f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean + f3 = charge_ratio[k] * (- B1_avg * B2_avg) + f4 = charge_ratio[k] * (- B1_avg * B3_avg) + f5 = zero(u_ll[1]) # TODO! pe_mean + + # Compute term 3 (only needed for NCOMP>1) + # TODO + + # Adjust non-conservative term to Trixi discretization: CHANGE!! + f2 = 2 * f2 - charge_ratio[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio[k] * B1_ll * B3_ll + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end - # Compute term 3 (only needed for NCOMP>1) + # Adjust non-conservative term to Trixi standard: - return f + return SVector{nvariables(equations), real(equations)}(f) end """ - flux_ec(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) Entropy conserving two-point flux adapted by: - Rueda-Ramírez et al. (2023) @@ -191,7 +236,7 @@ This flux (together with the MHD non-conservative term) is consistent in the cas Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field divergence diminishing ideal magnetohydrodynamics equations for multi-ion [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) - !!! ATENTION: The additional induction terms depending on v_minus are missing. TODO: add! +!!! ATENTION: The additional induction terms depending on v_minus are missing. TODO: add! """ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) @unpack gammas = equations @@ -214,7 +259,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) # Magnetic field components from f^MHD - f6 = 0.0 + f6 = zero(u_ll[1]) f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg From 7db093143008bd957781c9364898bd384824df80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 30 Mar 2023 17:06:10 +0200 Subject: [PATCH 006/108] Added non-conservative "term 3".. The multi-ion are EC for constant B1! --- src/equations/ideal_mhd_multiion_1d.jl | 39 ++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index c3de6182292..2c78975573b 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -168,9 +168,9 @@ end Total non-conservative two-point "flux"" as described in - Rueda-Ramírez et al. (2023) The term is composed of three parts -* The Powell term: Only needed in 1D for non-constant B1 -* The MHD term: The only one implemented so far.. and without the electron pressure. -* The "term 3" +* The Powell term: Only needed in 1D for non-constant B1 (TODO) +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented """ @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) @unpack charge_to_mass = equations @@ -186,7 +186,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) - # Compute charge ratio of u_ll + # Compute charge ratio of u_ll (merge into auxiliary_variables) charge_ratio = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -195,6 +195,10 @@ The term is composed of three parts total_electron_charge += charge_ratio[k] end charge_ratio ./= total_electron_charge + + # Compute auxiliary variables + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) # TODO: Add entries of Powell term for induction equation @@ -210,13 +214,23 @@ The term is composed of three parts f5 = zero(u_ll[1]) # TODO! pe_mean # Compute term 3 (only needed for NCOMP>1) - # TODO + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) # Adjust non-conservative term to Trixi discretization: CHANGE!! f2 = 2 * f2 - charge_ratio[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) f3 = 2 * f3 + charge_ratio[k] * B1_ll * B2_ll f4 = 2 * f4 + charge_ratio[k] * B1_ll * B3_ll - + f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + # Append to the flux vector f = (f..., zero(u_ll[1]), f2, f3, f4, f5) end @@ -236,7 +250,6 @@ This flux (together with the MHD non-conservative term) is consistent in the cas Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field divergence diminishing ideal magnetohydrodynamics equations for multi-ion [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) -!!! ATENTION: The additional induction terms depending on v_minus are missing. TODO: add! """ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) @unpack gammas = equations @@ -303,6 +316,16 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) # Ignore orientation since it is always "1" in 1D f1 = rho_mean*v1_avg @@ -317,7 +340,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - ) # Terms coming from the non-conservative term 3 (induction equation! TODO!!!) + - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) f = (f..., f1, f2, f3, f4, f5) end From f120f165c8870fa5217f1b4f92dc1ba9dc8a4b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 31 Mar 2023 08:44:26 +0200 Subject: [PATCH 007/108] Added central non-conservative "flux" for multi-ion MHD (needed for an LLF variant that is consistent with single species MHD) --- .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 58 +++++++++++++ src/Trixi.jl | 2 +- src/equations/ideal_mhd_multiion_1d.jl | 87 +++++++++++++++---- 3 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl new file mode 100644 index 00000000000..8b4d63b9646 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -0,0 +1,58 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) +solver = DGSEM(polydeg=3, surface_flux=surface_flux, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = 0.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 4dbbf97241e..6bca82d4b75 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -143,7 +143,7 @@ export GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, - flux_nonconservative_powell, flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal + flux_nonconservative_powell, flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, flux_nonconservative_central flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 2c78975573b..f3b338001a6 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -48,7 +48,7 @@ function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D cons = ("B1", "B2", "B3") for i in eachcomponent(equations) - cons = (cons..., tuple("rho" * string(i),"rho_v1" * string(i), "rho_v2" * string(i), "rho_v3" * string(i), "rho_e" * string(i))...) + cons = (cons..., tuple("rho_" * string(i),"rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) end return cons @@ -58,7 +58,7 @@ function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations1D prim = ("B1", "B2", "B3") for i in eachcomponent(equations) - prim = (prim..., tuple("rho" * string(i),"v1" * string(i), "v2" * string(i), "v3" * string(i), "p" * string(i))...) + prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) end return prim @@ -165,7 +165,7 @@ end end """ -Total non-conservative two-point "flux"" as described in +Total entropy-conserving non-conservative two-point "flux"" as described in - Rueda-Ramírez et al. (2023) The term is composed of three parts * The Powell term: Only needed in 1D for non-constant B1 (TODO) @@ -187,14 +187,14 @@ The term is composed of three parts mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) # Compute charge ratio of u_ll (merge into auxiliary_variables) - charge_ratio = zeros(typeof(u_ll[1]), ncomponents(equations)) + charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] - charge_ratio[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio[k] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] end - charge_ratio ./= total_electron_charge + charge_ratio_ll ./= total_electron_charge # Compute auxiliary variables total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) @@ -208,10 +208,10 @@ The term is composed of three parts # Compute term 2 (MHD) # TODO: Add electron pressure term - f2 = charge_ratio[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean - f3 = charge_ratio[k] * (- B1_avg * B2_avg) - f4 = charge_ratio[k] * (- B1_avg * B3_avg) - f5 = zero(u_ll[1]) # TODO! pe_mean + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -226,16 +226,73 @@ The term is composed of three parts f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) # Adjust non-conservative term to Trixi discretization: CHANGE!! - f2 = 2 * f2 - charge_ratio[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) - f3 = 2 * f3 + charge_ratio[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio[k] * B1_ll * B3_ll + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) # Append to the flux vector f = (f..., zero(u_ll[1]), f2, f3, f4, f5) end - # Adjust non-conservative term to Trixi standard: + return SVector{nvariables(equations), real(equations)}(f) +end + +""" +Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages +The term is composed of three parts +* The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Compute charge ratio of u_ll (merge into auxiliary_variables) + charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + total_electron_charge = zero(u_ll[1]) + for k in eachcomponent(equations) + rho_k = u_ll[(k-1)*5+4] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + + f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end return SVector{nvariables(equations), real(equations)}(f) end From b23161fa7e477c185a33301319bd4beabd3f978f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 31 Mar 2023 09:18:40 +0200 Subject: [PATCH 008/108] Added standard source terms for the multi-ion MHD equations --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 3 +- .../elixir_mhdmultiion_ec_onespecies.jl | 3 ++ .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 3 +- src/Trixi.jl | 4 +-- src/equations/ideal_mhd_multiion_1d.jl | 29 +++++++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index c4f8f4acb8a..d916b54c49f 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -22,7 +22,8 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max=10_000) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) ############################################################################### diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index 74c5eb1b93e..be2d297ffa0 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -24,6 +24,9 @@ mesh = TreeMesh(coordinates_min, coordinates_max, semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) +# In the one-species case, the source terms are not really needed, but this variant produces the same results: +# semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, +# source_terms=source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 8b4d63b9646..a5a440744a9 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -21,7 +21,8 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max=10_000) -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) ############################################################################### diff --git a/src/Trixi.jl b/src/Trixi.jl index 6bca82d4b75..2368519117e 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -143,7 +143,7 @@ export GradientVariablesPrimitive, GradientVariablesEntropy export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, - flux_nonconservative_powell, flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, flux_nonconservative_central + flux_nonconservative_powell, flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, flux_nonconservative_central, flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, @@ -174,7 +174,7 @@ export boundary_condition_do_nothing, boundary_condition_wall, BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal -export initial_condition_convergence_test, source_terms_convergence_test +export initial_condition_convergence_test, source_terms_convergence_test, source_terms_standard export source_terms_harmonic export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic, boundary_condition_poisson_nonperiodic export initial_condition_eoc_test_coupled_euler_gravity, source_terms_eoc_test_coupled_euler_gravity, source_terms_eoc_test_euler diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index f3b338001a6..cfe8d715823 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -164,6 +164,35 @@ end return SVector{nvariables(equations), real(equations)}(f) end +""" +Standard source terms of the multi-ion MHD equations +""" +function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + B1, B2, B3, _ = u + total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + + s = (zero(u[1]), zero(u[1]), zero(u[1])) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff - B2) + s3 = r_rho * (v3_diff * B1 - v1_diff - B3) + s4 = r_rho * (v1_diff * B2 - v2_diff - B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + s = (s..., zero(u[1]), s2, s3, s4, s5) + end + + return SVector{nvariables(equations), real(equations)}(s) +end + """ Total entropy-conserving non-conservative two-point "flux"" as described in - Rueda-Ramírez et al. (2023) From 89ce92c91ae82133d962f9735e912745f1286c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 31 Mar 2023 11:44:31 +0200 Subject: [PATCH 009/108] Added auxiliar variables and a shock-capturing example for 1D multi-ion MHD --- .../elixir_mhdmultiion_es_shock_capturing.jl | 70 +++++++++++++++++++ src/Trixi.jl | 2 +- src/equations/ideal_mhd_multiion_1d.jl | 20 +++++- 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl new file mode 100644 index 00000000000..64ea96f2b42 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -0,0 +1,70 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=density) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = 0.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 2368519117e..c47d5fb1a62 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -181,7 +181,7 @@ export initial_condition_eoc_test_coupled_euler_gravity, source_terms_eoc_test_c export cons2cons, cons2prim, prim2cons, cons2macroscopic, cons2state, cons2mean, cons2entropy, entropy2cons -export density, pressure, density_pressure, velocity, global_mean_vars, equilibrium_distribution, waterheight_pressure +export density, pressure, density_pressure, velocity, global_mean_vars, equilibrium_distribution, waterheight_pressure, density_product export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, cross_helicity, enstrophy export lake_at_rest_error diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index cfe8d715823..f7ae0f6fda6 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -13,7 +13,7 @@ The ideal compressible multi-ion GLM-MHD equations in one space dimension. * Until now, actually without GLM """ mutable struct IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealGlmMhdMultiIonEquations{1, NVARS, NCOMP} - gammas ::SVector{NCOMP, RealT} # Heat capacity rations + gammas ::SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios function IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, @@ -156,7 +156,7 @@ end f2 = rho_v1*v1 + p #+ mag_en - B1^2 f3 = rho_v1*v2 #- B1*B2 f4 = rho_v1*v3 #- B1*B3 - f5 = (kin_en + gamma*p/(gamma - 1))*v1 + + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) f = (f..., f1, f2, f3, f4, f5) end @@ -625,4 +625,20 @@ Get the flow variables of component k return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) end +@inline function density_product(u, equations::IdealGlmMhdMultiIonEquations1D) + prod = one(u[1]) + for k in eachcomponent(equations) + prod *= u[(k-1)*5+4] + end + return prod +end + +@inline function density(u, equations::IdealGlmMhdMultiIonEquations1D) + rho = zero(u[1]) + for k in eachcomponent(equations) + rho += u[(k-1)*5+4] + end + return rho +end + end # @muladd From 2b74f7944c360f95f77fdd7f7bed96b7dce2ead7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 20 Apr 2023 17:00:03 +0200 Subject: [PATCH 010/108] Added multi-ion MHD equations in 2D --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 60 ++ src/Trixi.jl | 3 +- src/equations/equations.jl | 1 + src/equations/ideal_mhd_multiion_1d.jl | 1 + src/equations/ideal_mhd_multiion_2d.jl | 865 ++++++++++++++++++ 5 files changed, 929 insertions(+), 1 deletion(-) create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl create mode 100644 src/equations/ideal_mhd_multiion_2d.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl new file mode 100644 index 00000000000..6228b6d87cf --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -0,0 +1,60 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +#volume_flux = flux_central +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +solver = DGSEM(polydeg=3, surface_flux=surface_flux, + volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = ( 2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index c47d5fb1a62..0f02d70f230 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -128,7 +128,8 @@ export AcousticPerturbationEquations2D, CompressibleEulerEquations1D, CompressibleEulerEquations2D, CompressibleEulerEquations3D, CompressibleEulerMulticomponentEquations1D, CompressibleEulerMulticomponentEquations2D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, - IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMultiIonEquations1D, IdealGlmMhdMulticomponentEquations2D, + IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, + IdealGlmMhdMultiIonEquations1D, IdealGlmMhdMultiIonEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, LinearScalarAdvectionEquation3D, InviscidBurgersEquation1D, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 4e6659aa696..fc4e233d672 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -345,6 +345,7 @@ include("ideal_glm_mhd_multicomponent_2d.jl") # IdealGlmMhdMultiIonEquations abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end include("ideal_mhd_multiion_1d.jl") +include("ideal_mhd_multiion_2d.jl") # Retrieve number of components from equation instance for the multicomponent case @inline ncomponents(::AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index f7ae0f6fda6..adf1a410ee8 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -127,6 +127,7 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonE return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) end +# TODO: Add initial condition equilibrium # Calculate 1D flux in for a single point @inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl new file mode 100644 index 00000000000..3e97e55ee0b --- /dev/null +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -0,0 +1,865 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin + + +@doc raw""" + IdealGlmMhdMultiIonEquations2D + +The ideal compressible multi-ion GLM-MHD equations in two space dimensions. + +* Until now, actually without GLM +""" +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 + + function IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, + charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} + + NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass) + end +end + +function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass) + + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) +end + +@inline Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT + +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations2D) = True() + +function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D) + + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., tuple("rho_" * string(i),"rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + + return cons +end + +function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D) + + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) + end + + return prim +end + + +# """ +# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) + +# An Alfvén wave as smooth initial condition used for convergence tests. +# """ +# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) +# # smooth Alfvén wave test from Derigs et al. FLASH (2016) +# # domain must be set to [0, 1], γ = 5/3 + +# rho = 1.0 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# v1 = 0.0 +# si, co = sincos(2 * pi * x[1]) +# v2 = 0.1 * si +# v3 = 0.1 * co +# p = 0.1 +# B1 = 1.0 +# B2 = v2 +# B3 = v3 +# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) +# return prim2cons(vcat(prim_other, prim_rho), equations) +# end + + +""" + initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) + +A weak blast wave adapted from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) + # 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 + inicenter = (0, 0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + phi = atan(y_norm, x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 + end + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + p = r > 0.5 ? 1.0 : 1.245 + + #prim = (0.01, 0.01, 0.01) + prim = (1.0, 1.0, 1.0) + for i in eachcomponent(equations) + prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0.0, p) + #prim = (prim..., rho, v1, 0.0, 0.0, p) + #prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) + end + + return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) +end + +# TODO: Add initial condition equilibrium + +# Calculate 1D flux in for a single point +@inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + B1, B2, B3, _ = u + + total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + + mag_en = 0.5*(B1^2 + B2^2 + B3^2) + + if orientation == 1 + f_B1 = 0.0 + f_B2 = v1_plus * B2 - v2_plus * B1 + f_B3 = v1_plus * B3 - v3_plus * B1 + + f = (f_B1, f_B2, f_B3) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1/rho + v2 = rho_v2/rho + v3 = rho_v3/rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v1 + f2 = rho_v1*v1 + p #+ mag_en - B1^2 + f3 = rho_v1*v2 #- B1*B2 + f4 = rho_v1*v3 #- B1*B3 + f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + f = (f..., f1, f2, f3, f4, f5) + end + + else #if orientation == 2 + + f_B1 = v2_plus * B1 - v1_plus * B2 + f_B2 = 0.0 + f_B3 = v2_plus * B3 - v3_plus * B2 + + f = (f_B1, f_B2, f_B3) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1/rho + v2 = rho_v2/rho + v3 = rho_v3/rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v2 + f2 = rho_v2*v1 # - B2*B1 + f3 = rho_v2*v2 + p # + mag_en - B2*B2 + f4 = rho_v2*v3 #- B2*B3 + f5 = (kin_en + gamma*p/(gamma - 1))*v2 + 2 * mag_en * vk2_plus[k] - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + f = (f..., f1, f2, f3, f4, f5) + end + end + + return SVector{nvariables(equations), real(equations)}(f) +end + +""" +Standard source terms of the multi-ion MHD equations +""" +function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + B1, B2, B3, _ = u + total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + + s = (zero(u[1]), zero(u[1]), zero(u[1])) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff - B2) + s3 = r_rho * (v3_diff * B1 - v1_diff - B3) + s4 = r_rho * (v1_diff * B2 - v2_diff - B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + s = (s..., zero(u[1]), s2, s3, s4, s5) + end + + return SVector{nvariables(equations), real(equations)}(s) +end + +""" +Total entropy-conserving non-conservative two-point "flux"" as described in +- Rueda-Ramírez et al. (2023) +The term is composed of three parts +* The Powell term: Implemented +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented +""" +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + # Compute important averages + B1_avg = 0.5*(B1_ll+B1_rr) + B2_avg = 0.5*(B2_ll+B2_rr) + B3_avg = 0.5*(B3_ll+B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + + # Compute charge ratio of u_ll (merge into auxiliary_variables) + charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + total_electron_charge = zero(u_ll[1]) + for k in eachcomponent(equations) + rho_k = u_ll[(k-1)*5+4] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f_B1 = v1_plus_ll * B1_rr + f_B2 = v2_plus_ll * B1_rr + f_B3 = v3_plus_ll * B1_rr + f = (f_B1, f_B2, f_B3) + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll + f5 =(2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) ) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end + + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f_B1 = v1_plus_ll * B2_rr + f_B2 = v2_plus_ll * B2_rr + f_B3 = v3_plus_ll * B2_rr + f = (f_B1, f_B2, f_B3) + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (- B2_avg * B1_avg) + f3 = charge_ratio_ll[k] * (- B2_avg * B2_avg + 0.5 * mag_norm_avg) # + pe_mean) + f4 = charge_ratio_ll[k] * (- B2_avg * B3_avg) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll + f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) + f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll + f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll) ) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end + end + + return SVector{nvariables(equations), real(equations)}(f) +end + +""" +Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages +The term is composed of three parts +* The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Compute charge ratio of u_ll (merge into auxiliary_variables) + charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + total_electron_charge = zero(u_ll[1]) + for k in eachcomponent(equations) + rho_k = u_ll[(k-1)*5+4] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f_B1 = v1_plus_ll * B1_rr + f_B2 = v2_plus_ll * B1_rr + f_B3 = v3_plus_ll * B1_rr + f = (f_B1, f_B2, f_B3) + for k in eachcomponent(equations) + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f_B1 = v1_plus_ll * B2_rr + f_B2 = v2_plus_ll * B2_rr + f_B3 = v3_plus_ll * B2_rr + f = (f_B1, f_B2, f_B3) + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (- B2_rr * B1_rr) + f3 = charge_ratio_ll[k] * (- B2_rr * B2_rr + 0.5 * mag_norm_rr) # + pe_mean) + f4 = charge_ratio_ll[k] * (- B2_rr * B3_rr) + f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + + B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr) ) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + end + end + + return SVector{nvariables(equations), real(equations)}(f) +end + +""" +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) + +Entropy conserving two-point flux adapted by: +- Rueda-Ramírez et al. (2023) +This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: +- Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll, _ = u_ll + B1_rr, B2_rr, B3_rr, _ = u_rr + + total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) + total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + + # Compute averages for global variables + v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) + v2_plus_avg = 0.5*(v2_plus_ll+v2_plus_rr) + v3_plus_avg = 0.5*(v3_plus_ll+v3_plus_rr) + B1_avg = 0.5*(B1_ll+B1_rr) + B2_avg = 0.5*(B2_ll+B2_rr) + B3_avg = 0.5*(B3_ll+B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + + if orientation == 1 + # Magnetic field components from f^MHD + f6 = zero(u_ll[1]) + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start concatenating the flux + f = (f6, f7, f8) + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) + + v1_ll = rho_v1_ll/rho_ll + v2_ll = rho_v2_ll/rho_ll + v3_ll = rho_v3_ll/rho_ll + v1_rr = rho_v1_rr/rho_rr + v2_rr = rho_v2_rr/rho_rr + v3_rr = rho_v3_rr/rho_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 + + p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) + p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) + beta_ll = 0.5*rho_ll/p_ll + beta_rr = 0.5*rho_rr/p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5*(rho_ll+rho_rr) + rho_mean = ln_mean(rho_ll,rho_rr) + beta_mean = ln_mean(beta_ll,beta_rr) + beta_avg = 0.5*(beta_ll+beta_rr) + p_mean = 0.5*rho_avg/beta_avg + v1_avg = 0.5*(v1_ll+v1_rr) + v2_avg = 0.5*(v2_ll+v2_rr) + v3_avg = 0.5*(v3_ll+v3_rr) + vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) + vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) + vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean*v1_avg + f2 = f1*v1_avg + p_mean + f3 = f1*v2_avg + f4 = f1*v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5*(vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) + + f = (f..., f1, f2, f3, f4, f5) + end + else #if orientation == 2 + # Magnetic field components from f^MHD + f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg + f7 = zero(u_ll[1]) + f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg + + # Start concatenating the flux + f = (f6, f7, f8) + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) + + v1_ll = rho_v1_ll/rho_ll + v2_ll = rho_v2_ll/rho_ll + v3_ll = rho_v3_ll/rho_ll + v1_rr = rho_v1_rr/rho_rr + v2_rr = rho_v2_rr/rho_rr + v3_rr = rho_v3_rr/rho_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 + + p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) + p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) + beta_ll = 0.5*rho_ll/p_ll + beta_rr = 0.5*rho_rr/p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5*(rho_ll+rho_rr) + rho_mean = ln_mean(rho_ll,rho_rr) + beta_mean = ln_mean(beta_ll,beta_rr) + beta_avg = 0.5*(beta_ll+beta_rr) + p_mean = 0.5*rho_avg/beta_avg + v1_avg = 0.5*(v1_ll+v1_rr) + v2_avg = 0.5*(v2_ll+v2_rr) + v3_avg = 0.5*(v3_ll+v3_rr) + vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) + vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) + vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean*v2_avg + f2 = f1*v1_avg + f3 = f1*v2_avg + p_mean + f4 = f1*v3_avg + + # total energy flux is complicated and involves the previous eight components + v2_plus_mag_avg = 0.5*(vk2_plus_ll[k] * mag_norm_ll + vk2_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) + + f = (f..., f1, f2, f3, f4, f5) + end + end + + return SVector{nvariables(equations), real(equations)}(f) +end + +""" +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + !!!ATTENTION: This routine is provisory. TODO: Update with the right max_abs_speed +""" +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities + v_ll = zero(u_ll[1]) + v_rr = zero(u_rr[1]) + if orientation == 1 + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + else #if orientation == 2 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v2 / rho)) + rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v2 / rho)) + end + end + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end + + +@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations2D) + + v1 = zero(u[1]) + v2 = zero(u[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + v2 = max(v2, abs(rho_v2 / rho)) + end + + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + cf_y_direction = calc_fast_wavespeed(u, 2, equations) + + return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) +end + + +""" +Convert conservative variables to primitive +""" +function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3, _ = u + + prim = (B1, B2, B3) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + prim = (prim..., rho, v1, v2, v3, p) + end + + return SVector{nvariables(equations), real(equations)}(prim) +end + +""" +Convert conservative variables to entropy +""" +@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3, _ = u + + prim = cons2prim(u, equations) + entropy = () + rho_p_plus = zero(u[1]) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + entropy = (entropy..., w1, w2, w3, w4, w5) + end + + # Additional non-conservative variables + w6 = rho_p_plus * B1 + w7 = rho_p_plus * B2 + w8 = rho_p_plus * B3 + entropy = (w6, w7, w8, entropy...) + + return SVector{nvariables(equations), real(equations)}(entropy) +end + + +""" +Convert primitive to conservative variables +""" +@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3, _ = prim + + cons = (B1, B2, B3) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + cons = (cons..., rho, rho_v1, rho_v2, rho_v3, rho_e) + end + + return SVector{nvariables(equations), real(equations)}(cons) +end + +""" +Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisory.. Change once the fastest wave speed is known!! +""" +@inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) + B1, B2, B3, _ = cons + + c_f = zero(cons[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + if orientation == 1 + c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2))) + else #if orientation == 2 + c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b2^2))) + end + end + + return c_f +end + +""" +Routine to compute the auxiliary variables: +* total_electron_charge +* v*_plus: Charge-averaged velocity +* vk*_plus: Contribution of each species to the charge-averaged velocity +""" +@inline function auxiliary_variables(u, equations::IdealGlmMhdMultiIonEquations2D) + + total_electron_charge = zero(u[1]) + + vk1_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk2_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk3_plus = zeros(typeof(u[1]), ncomponents(equations)) + + for k in eachcomponent(equations) + rho_k = u[(k-1)*5+4] + rho_v1_k = u[(k-1)*5+5] + rho_v2_k = u[(k-1)*5+6] + rho_v3_k = u[(k-1)*5+7] + total_electron_charge += rho_k * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1_k * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2_k * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3_k * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return total_electron_charge, v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), + SVector{ncomponents(equations), real(equations)}(vk2_plus), + SVector{ncomponents(equations), real(equations)}(vk3_plus) +end + +""" +Get the flow variables of component k +""" +@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) + return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) +end + +@inline function density_product(u, equations::IdealGlmMhdMultiIonEquations2D) + prod = one(u[1]) + for k in eachcomponent(equations) + prod *= u[(k-1)*5+4] + end + return prod +end + +@inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) + rho = zero(u[1]) + for k in eachcomponent(equations) + rho += u[(k-1)*5+4] + end + return rho +end + +end # @muladd From 7a91b6e5662502aabfba3b8118b1c7a3e7e22486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 21 Apr 2023 14:27:38 +0200 Subject: [PATCH 011/108] Added density_pressure function and double rotor test for multi-ion --- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 158 ++++++++++++++++++ src/equations/ideal_mhd_multiion_2d.jl | 24 +++ 2 files changed, 182 insertions(+) create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl new file mode 100644 index 00000000000..47ccb97813e --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -0,0 +1,158 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.4), + charge_to_mass = (1.0, 2.0)) + +""" + initial_condition_rotor(x, t, equations::IdealGlmMhdMultiIonEquations2D) + +The classical MHD rotor test case. Here, the setup is taken from +- Dominik Derigs, Gregor J. Gassner, Stefanie Walch & Andrew R. Winters (2018) + Entropy Stable Finite Volume Approximations for Ideal Magnetohydrodynamics + [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) +""" +function initial_condition_rotor(x, t, equations::IdealGlmMhdMultiIonEquations2D) + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + B1 = 5.0/sqrt(4.0*pi) + B2 = 0.0 + B3 = 0.0 + + # first species + dx = x[1] - 0.25 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r)/0.015 + if r <= 0.1 + rho = 10.0 + v1 = -20.0*dy + v2 = 20.0*dx + elseif r >= 0.115 + if x[1] > 0.75 + rho = 0.49 * (tanh(50 * (x[1] - 1.0)) + 1) + 0.02 + elseif x[1] > 0.25 + rho = 0.49 * (-tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + else + rho = 0.49 * (tanh(50 * (x[1])) + 1) + 0.02 + end + v1 = 0.0 + v2 = 0.0 + else + rho = 1.0 + 9.0*f + v1 = -20.0*f*dy + v2 = 20.0*f*dx + end + v3 = 0.0 + p = 1.0 + + #second species + dx = x[1] - 0.75 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r)/0.015 + if r <= 0.1 + rho2 = 10.0 + v12 = -20.0*dy + v22 = 20.0*dx + elseif r >= 0.115 + if x[1] < 0.25 + rho2 = 0.49 * (-tanh(50 * (x[1])) + 1) + 0.02 + elseif x[1] < 0.75 + rho2 = 0.49 * (tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + else + rho2 = 0.49 * (-tanh(50 * (x[1] - 1.0)) + 1) + 0.02 + end + v12 = 0.0 + v22 = 0.0 + else + rho2 = 1.0 + 9.0*f + v12 = -20.0*f*dy + v22 = 20.0*f*dx + end + v3 = 0.0 + p = 1.0 + + return prim2cons(SVector(B1, B2, B3, rho, v1, v2, v3, p, rho2, v12, v22, v3, p), equations) +end +initial_condition = initial_condition_rotor + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=density_pressure) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = (0.0, 0.0) +coordinates_max = (1.0, 1.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.15) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=10, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) +amr_indicator = IndicatorHennemannGassner(semi, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=false, + variable=density_pressure) +amr_controller = ControllerThreeLevel(semi, amr_indicator, + base_level=4, + max_level =7, max_threshold=0.01) +amr_callback = AMRCallback(semi, amr_controller, + interval=6, + adapt_initial_condition=true, + adapt_initial_condition_only_refine=true) + +save_restart = SaveRestartCallback(interval=100, + save_final_restart=true) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + amr_callback, + save_solution, + save_restart, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 3e97e55ee0b..ff6f2f34799 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -862,4 +862,28 @@ end return rho end +""" +Computes the sum of the densities times the sum of the pressures +""" +@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations2D) + B1, B2, B3, _ = u + rho_total = zero(u[1]) + p_total = zero(u[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + + p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) + + rho_total += rho + p_total += p + end + return rho_total * p_total +end + end # @muladd From 5dd9874d44059598e3450cbf3be1c27192431634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 5 May 2023 16:44:33 +0200 Subject: [PATCH 012/108] Cleaned up the multi-ion implementation a bit and added divB analysis --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- src/callbacks_step/analysis_dg2d.jl | 36 ++++++++++ src/equations/ideal_mhd_multiion_1d.jl | 30 ++++---- src/equations/ideal_mhd_multiion_2d.jl | 69 ++++++++++--------- 4 files changed, 86 insertions(+), 51 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 6228b6d87cf..2e9899886a4 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -34,7 +34,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 100 +analysis_interval = 10 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval) diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index 453474675f1..c380cb76edd 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -236,6 +236,20 @@ function analyze(::Val{:l2_divb}, du, u, t, end |> sqrt end +function analyze(::Val{:l2_divb}, du, u, t, + mesh::TreeMesh{2}, equations::IdealGlmMhdMultiIonEquations2D, + dg::DG, cache) + integrate_via_indices(u, mesh, equations, dg, cache, cache, dg.basis.derivative_matrix) do u, i, j, element, equations, dg, cache, derivative_matrix + divb = zero(eltype(u)) + for k in eachnode(dg) + divb += ( derivative_matrix[i, k] * u[1, k, j, element] + + derivative_matrix[j, k] * u[2, i, k, element] ) + end + divb *= cache.elements.inverse_jacobian[element] + divb^2 + end |> sqrt +end + function analyze(::Val{:l2_divb}, du, u, t, mesh::Union{StructuredMesh{2},UnstructuredMesh2D,P4estMesh{2}}, equations::IdealGlmMhdEquations2D, dg::DGSEM, cache) @@ -300,6 +314,28 @@ function analyze(::Val{:linf_divb}, du, u, t, return linf_divb end +function analyze(::Val{:linf_divb}, du, u, t, + mesh::TreeMesh{2}, equations::IdealGlmMhdMultiIonEquations2D, + dg::DG, cache) + @unpack derivative_matrix, weights = dg.basis + + # integrate over all elements to get the divergence-free condition errors + linf_divb = zero(eltype(u)) + for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + divb = zero(eltype(u)) + for k in eachnode(dg) + divb += ( derivative_matrix[i, k] * u[1, k, j, element] + + derivative_matrix[j, k] * u[2, i, k, element] ) + end + divb *= cache.elements.inverse_jacobian[element] + linf_divb = max(linf_divb, abs(divb)) + end + end + + return linf_divb +end + function analyze(::Val{:linf_divb}, du, u, t, mesh::Union{StructuredMesh{2},UnstructuredMesh2D,P4estMesh{2}}, equations::IdealGlmMhdEquations2D, dg::DGSEM, cache) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index adf1a410ee8..136761f19f8 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -133,7 +133,7 @@ end @inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) B1, B2, B3, _ = u - total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) f_B1 = 0.0 f_B2 = v1_plus * B2 - v2_plus * B1 @@ -171,7 +171,7 @@ Standard source terms of the multi-ion MHD equations function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations1D) @unpack charge_to_mass = equations B1, B2, B3, _ = u - total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) s = (zero(u[1]), zero(u[1]), zero(u[1])) for k in eachcomponent(equations) @@ -216,7 +216,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) - # Compute charge ratio of u_ll (merge into auxiliary_variables) + # Compute charge ratio of u_ll charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -227,8 +227,8 @@ The term is composed of three parts charge_ratio_ll ./= total_electron_charge # Compute auxiliary variables - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) # TODO: Add entries of Powell term for induction equation @@ -284,7 +284,7 @@ The term is composed of three parts # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - # Compute charge ratio of u_ll (merge into auxiliary_variables) + # Compute charge ratio of u_ll charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -295,8 +295,7 @@ The term is composed of three parts charge_ratio_ll ./= total_electron_charge # Compute auxiliary variables - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) # TODO: Add entries of Powell term for induction equation @@ -344,8 +343,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide B1_ll, B2_ll, B3_ll, _ = u_ll B1_rr, B2_rr, B3_rr, _ = u_rr - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) # Compute averages for global variables v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) @@ -584,12 +583,11 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco end """ -Routine to compute the auxiliary variables: -* total_electron_charge +Routine to compute the charge-averaged velocities: * v*_plus: Charge-averaged velocity * vk*_plus: Contribution of each species to the charge-averaged velocity """ -@inline function auxiliary_variables(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function charge_averaged_velocities(u, equations::IdealGlmMhdMultiIonEquations1D) total_electron_charge = zero(u[1]) @@ -614,9 +612,9 @@ Routine to compute the auxiliary variables: v2_plus = sum(vk2_plus) v3_plus = sum(vk3_plus) - return total_electron_charge, v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), - SVector{ncomponents(equations), real(equations)}(vk2_plus), - SVector{ncomponents(equations), real(equations)}(vk3_plus) + return v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), + SVector{ncomponents(equations), real(equations)}(vk2_plus), + SVector{ncomponents(equations), real(equations)}(vk3_plus) end """ diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index ff6f2f34799..f4162917bf3 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -64,6 +64,8 @@ function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D return prim end +default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) = (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) + # """ # initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) @@ -135,7 +137,7 @@ end @inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3, _ = u - total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) mag_en = 0.5*(B1^2 + B2^2 + B3^2) @@ -202,7 +204,7 @@ Standard source terms of the multi-ion MHD equations function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) @unpack charge_to_mass = equations B1, B2, B3, _ = u - total_electron_charge, v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = auxiliary_variables(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) s = (zero(u[1]), zero(u[1]), zero(u[1])) for k in eachcomponent(equations) @@ -247,7 +249,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) - # Compute charge ratio of u_ll (merge into auxiliary_variables) + # Compute charge ratio of u_ll charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -258,8 +260,8 @@ The term is composed of three parts charge_ratio_ll ./= total_electron_charge # Compute auxiliary variables - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -280,9 +282,9 @@ The term is composed of three parts vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -325,9 +327,9 @@ The term is composed of three parts vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -371,7 +373,7 @@ The term is composed of three parts # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - # Compute charge ratio of u_ll (merge into auxiliary_variables) + # Compute charge ratio of u_ll charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -382,8 +384,8 @@ The term is composed of three parts charge_ratio_ll ./= total_electron_charge # Compute auxiliary variables - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -400,9 +402,9 @@ The term is composed of three parts f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) @@ -433,9 +435,9 @@ The term is composed of three parts f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr) ) @@ -472,8 +474,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide B1_ll, B2_ll, B3_ll, _ = u_ll B1_rr, B2_rr, B3_rr, _ = u_rr - total_electron_charge_ll, v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = auxiliary_variables(u_ll, equations) - total_electron_charge_rr, v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = auxiliary_variables(u_rr, equations) + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) # Compute averages for global variables v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) @@ -536,9 +538,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -610,9 +612,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -804,12 +806,11 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco end """ -Routine to compute the auxiliary variables: -* total_electron_charge +Routine to compute the Charge-averaged velocities: * v*_plus: Charge-averaged velocity * vk*_plus: Contribution of each species to the charge-averaged velocity """ -@inline function auxiliary_variables(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function charge_averaged_velocities(u, equations::IdealGlmMhdMultiIonEquations2D) total_electron_charge = zero(u[1]) @@ -834,9 +835,9 @@ Routine to compute the auxiliary variables: v2_plus = sum(vk2_plus) v3_plus = sum(vk3_plus) - return total_electron_charge, v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), - SVector{ncomponents(equations), real(equations)}(vk2_plus), - SVector{ncomponents(equations), real(equations)}(vk3_plus) + return v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), + SVector{ncomponents(equations), real(equations)}(vk2_plus), + SVector{ncomponents(equations), real(equations)}(vk3_plus) end """ From 05771e86cb8695f8f9e48d3ad52da64e088a1681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 5 May 2023 16:55:23 +0200 Subject: [PATCH 013/108] Removed GLM from the struct name, as GLM is not implemented for multi-ion MHD --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../elixir_mhdmultiion_ec_onespecies.jl | 2 +- .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 2 +- .../elixir_mhdmultiion_es_shock_capturing.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 6 +- src/Trixi.jl | 2 +- src/callbacks_step/analysis_dg2d.jl | 4 +- src/equations/equations.jl | 12 ++-- src/equations/ideal_mhd_multiion_1d.jl | 66 +++++++++-------- src/equations/ideal_mhd_multiion_2d.jl | 70 +++++++++---------- 11 files changed, 83 insertions(+), 87 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index d916b54c49f..3070d1351eb 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index be2d297ffa0..edf529bff90 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0), +equations = IdealMhdMultiIonEquations1D(gammas = (2.0), charge_to_mass = (1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index a5a440744a9..cfe7cb1d2d9 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl index 64ea96f2b42..f9465890ead 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations1D(gammas = (2.0, 2.0), +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 2e9899886a4..1500408299b 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,7 +4,7 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), +equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index 47ccb97813e..8bd9033dca9 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -4,18 +4,18 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.4), +equations = IdealMhdMultiIonEquations2D(gammas = (1.4, 1.4), charge_to_mass = (1.0, 2.0)) """ - initial_condition_rotor(x, t, equations::IdealGlmMhdMultiIonEquations2D) + initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) The classical MHD rotor test case. Here, the setup is taken from - Dominik Derigs, Gregor J. Gassner, Stefanie Walch & Andrew R. Winters (2018) Entropy Stable Finite Volume Approximations for Ideal Magnetohydrodynamics [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ -function initial_condition_rotor(x, t, equations::IdealGlmMhdMultiIonEquations2D) +function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) # setup taken from Derigs et al. DMV article (2018) # domain must be [0, 1] x [0, 1], γ = 1.4 B1 = 5.0/sqrt(4.0*pi) diff --git a/src/Trixi.jl b/src/Trixi.jl index 0f02d70f230..202fbe9bb5f 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -129,7 +129,7 @@ export AcousticPerturbationEquations2D, CompressibleEulerMulticomponentEquations1D, CompressibleEulerMulticomponentEquations2D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, - IdealGlmMhdMultiIonEquations1D, IdealGlmMhdMultiIonEquations2D, + IdealMhdMultiIonEquations1D, IdealMhdMultiIonEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, LinearScalarAdvectionEquation3D, InviscidBurgersEquation1D, diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index c380cb76edd..012ebb4fb4d 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -237,7 +237,7 @@ function analyze(::Val{:l2_divb}, du, u, t, end function analyze(::Val{:l2_divb}, du, u, t, - mesh::TreeMesh{2}, equations::IdealGlmMhdMultiIonEquations2D, + mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, dg::DG, cache) integrate_via_indices(u, mesh, equations, dg, cache, cache, dg.basis.derivative_matrix) do u, i, j, element, equations, dg, cache, derivative_matrix divb = zero(eltype(u)) @@ -315,7 +315,7 @@ function analyze(::Val{:linf_divb}, du, u, t, end function analyze(::Val{:linf_divb}, du, u, t, - mesh::TreeMesh{2}, equations::IdealGlmMhdMultiIonEquations2D, + mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, dg::DG, cache) @unpack derivative_matrix, weights = dg.basis diff --git a/src/equations/equations.jl b/src/equations/equations.jl index fc4e233d672..07ddfa30247 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -342,8 +342,8 @@ abstract type AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP} <: include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") -# IdealGlmMhdMultiIonEquations -abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end +# IdealMhdMultiIonEquations +abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end include("ideal_mhd_multiion_1d.jl") include("ideal_mhd_multiion_2d.jl") @@ -359,15 +359,15 @@ In particular, not the components themselves are returned. @inline eachcomponent(equations::AbstractIdealGlmMhdMulticomponentEquations) = Base.OneTo(ncomponents(equations)) # Retrieve number of components from equation instance for the multi-ion case -@inline ncomponents(::AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP +@inline ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP """ - eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) + eachcomponent(equations::AbstractIdealMhdMultiIonEquations) Return an iterator over the indices that specify the location in relevant data structures -for the components in `AbstractIdealGlmMhdMultiIonEquations`. +for the components in `AbstractIdealMhdMultiIonEquations`. In particular, not the components themselves are returned. """ -@inline eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) = Base.OneTo(ncomponents(equations)) +@inline eachcomponent(equations::AbstractIdealMhdMultiIonEquations) = Base.OneTo(ncomponents(equations)) # Diffusion equation: first order hyperbolic system abstract type AbstractHyperbolicDiffusionEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 136761f19f8..61078e5d1a3 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -6,17 +6,15 @@ @doc raw""" - IdealGlmMhdMultiIonEquations1D + IdealMhdMultiIonEquations1D -The ideal compressible multi-ion GLM-MHD equations in one space dimension. - -* Until now, actually without GLM +The ideal compressible multi-ion MHD equations in one space dimension. """ -mutable struct IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealGlmMhdMultiIonEquations{1, NVARS, NCOMP} +mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} gammas ::SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios - function IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, + function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) @@ -25,7 +23,7 @@ mutable struct IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: Abst end end -function IdealGlmMhdMultiIonEquations1D(; gammas, charge_to_mass) +function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) @@ -37,14 +35,14 @@ function IdealGlmMhdMultiIonEquations1D(; gammas, charge_to_mass) __gammas = SVector(map(RealT, _gammas)) __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) + return IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) end -@inline Base.real(::IdealGlmMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT +@inline Base.real(::IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations1D) = True() +have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() -function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D) +function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) cons = ("B1", "B2", "B3") for i in eachcomponent(equations) @@ -54,7 +52,7 @@ function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations1D return cons end -function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations1D) +function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) prim = ("B1", "B2", "B3") for i in eachcomponent(equations) @@ -66,11 +64,11 @@ end # """ -# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations1D) +# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) # An Alfvén wave as smooth initial condition used for convergence tests. # """ -# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations1D) +# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) # # smooth Alfvén wave test from Derigs et al. FLASH (2016) # # domain must be set to [0, 1], γ = 5/3 @@ -90,14 +88,14 @@ end """ - initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) A weak blast wave adapted from - Sebastian Hennemann, Gregor J. Gassner (2020) A provably entropy stable subcell shock capturing approach for high order split form DG [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ -function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations1D) +function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) # 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 @@ -130,7 +128,7 @@ end # TODO: Add initial condition equilibrium # Calculate 1D flux in for a single point -@inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -168,7 +166,7 @@ end """ Standard source terms of the multi-ion MHD equations """ -function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations1D) +function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -202,7 +200,7 @@ The term is composed of three parts * The MHD term: Implemented without the electron pressure (TODO). * The "term 3": Implemented """ -@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -275,7 +273,7 @@ The term is composed of three parts * The MHD term: Implemented without the electron pressure (TODO). * The "term 3": Implemented """ -@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -327,7 +325,7 @@ The term is composed of three parts end """ -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations1D) Entropy conserving two-point flux adapted by: - Rueda-Ramírez et al. (2023) @@ -337,7 +335,7 @@ This flux (together with the MHD non-conservative term) is consistent in the cas divergence diminishing ideal magnetohydrodynamics equations for multi-ion [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) """ -function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -436,9 +434,9 @@ end """ # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisory. TODO: Update with the right max_abs_speed + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed """ -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations1D) +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) # Calculate fast magnetoacoustic wave speeds # left cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) @@ -459,7 +457,7 @@ end end -@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) v1 = zero(u[1]) for k in eachcomponent(equations) @@ -476,7 +474,7 @@ end """ Convert conservative variables to primitive """ -function cons2prim(u, equations::IdealGlmMhdMultiIonEquations1D) +function cons2prim(u, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = u @@ -499,7 +497,7 @@ end """ Convert conservative variables to entropy """ -@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = u @@ -532,7 +530,7 @@ end """ Convert primitive to conservative variables """ -@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations1D) +@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = prim @@ -553,9 +551,9 @@ end """ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisory.. Change once the fastest wave speed is known!! + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! """ -@inline function calc_fast_wavespeed(cons, direction, equations::IdealGlmMhdMultiIonEquations1D) +@inline function calc_fast_wavespeed(cons, direction, equations::IdealMhdMultiIonEquations1D) B1, B2, B3, _ = cons c_f = zero(cons[1]) @@ -587,7 +585,7 @@ Routine to compute the charge-averaged velocities: * v*_plus: Charge-averaged velocity * vk*_plus: Contribution of each species to the charge-averaged velocity """ -@inline function charge_averaged_velocities(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) total_electron_charge = zero(u[1]) @@ -620,11 +618,11 @@ end """ Get the flow variables of component k """ -@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) end -@inline function density_product(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function density_product(u, equations::IdealMhdMultiIonEquations1D) prod = one(u[1]) for k in eachcomponent(equations) prod *= u[(k-1)*5+4] @@ -632,7 +630,7 @@ end return prod end -@inline function density(u, equations::IdealGlmMhdMultiIonEquations1D) +@inline function density(u, equations::IdealMhdMultiIonEquations1D) rho = zero(u[1]) for k in eachcomponent(equations) rho += u[(k-1)*5+4] diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index f4162917bf3..b3d7452cddd 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -6,17 +6,15 @@ @doc raw""" - IdealGlmMhdMultiIonEquations2D + IdealMhdMultiIonEquations2D -The ideal compressible multi-ion GLM-MHD equations in two space dimensions. - -* Until now, actually without GLM +The ideal compressible multi-ion MHD equations in two space dimensions. """ -mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealGlmMhdMultiIonEquations{2, NVARS, NCOMP} +mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealMhdMultiIonEquations{2, NVARS, NCOMP} gammas ::SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios - function IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) @@ -25,7 +23,7 @@ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: Abst end end -function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass) +function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass) _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) @@ -37,14 +35,14 @@ function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass) __gammas = SVector(map(RealT, _gammas)) __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) + return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) end -@inline Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT +@inline Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations2D) = True() +have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() -function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D) +function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) cons = ("B1", "B2", "B3") for i in eachcomponent(equations) @@ -54,7 +52,7 @@ function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D return cons end -function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D) +function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) prim = ("B1", "B2", "B3") for i in eachcomponent(equations) @@ -64,15 +62,15 @@ function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D return prim end -default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) = (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +default_analysis_integrals(::IdealMhdMultiIonEquations2D) = (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) # """ -# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) +# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) # An Alfvén wave as smooth initial condition used for convergence tests. # """ -# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) +# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) # # smooth Alfvén wave test from Derigs et al. FLASH (2016) # # domain must be set to [0, 1], γ = 5/3 @@ -92,14 +90,14 @@ default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) = (entropy_timeder """ - initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) A weak blast wave adapted from - Sebastian Hennemann, Gregor J. Gassner (2020) A provably entropy stable subcell shock capturing approach for high order split form DG [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ -function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) +function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) # 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 @@ -134,7 +132,7 @@ end # TODO: Add initial condition equilibrium # Calculate 1D flux in for a single point -@inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -201,7 +199,7 @@ end """ Standard source terms of the multi-ion MHD equations """ -function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) +function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -235,7 +233,7 @@ The term is composed of three parts * The MHD term: Implemented without the electron pressure (TODO). * The "term 3": Implemented """ -@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -364,7 +362,7 @@ The term is composed of three parts * The MHD term: Implemented without the electron pressure (TODO). * The "term 3": Implemented """ -@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -458,7 +456,7 @@ The term is composed of three parts end """ -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D) +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) Entropy conserving two-point flux adapted by: - Rueda-Ramírez et al. (2023) @@ -468,7 +466,7 @@ This flux (together with the MHD non-conservative term) is consistent in the cas divergence diminishing ideal magnetohydrodynamics equations for multi-ion [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) """ -function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll, _ = u_ll @@ -643,9 +641,9 @@ end """ # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisory. TODO: Update with the right max_abs_speed + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed """ -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) # Calculate fast magnetoacoustic wave speeds # left cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) @@ -675,7 +673,7 @@ end end -@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) v1 = zero(u[1]) v2 = zero(u[1]) @@ -695,7 +693,7 @@ end """ Convert conservative variables to primitive """ -function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) +function cons2prim(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3, _ = u @@ -718,7 +716,7 @@ end """ Convert conservative variables to entropy """ -@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3, _ = u @@ -751,7 +749,7 @@ end """ Convert primitive to conservative variables """ -@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) +@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3, _ = prim @@ -772,9 +770,9 @@ end """ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisory.. Change once the fastest wave speed is known!! + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! """ -@inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) +@inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = cons c_f = zero(cons[1]) @@ -810,7 +808,7 @@ Routine to compute the Charge-averaged velocities: * v*_plus: Charge-averaged velocity * vk*_plus: Contribution of each species to the charge-averaged velocity """ -@inline function charge_averaged_velocities(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) total_electron_charge = zero(u[1]) @@ -843,11 +841,11 @@ end """ Get the flow variables of component k """ -@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) end -@inline function density_product(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function density_product(u, equations::IdealMhdMultiIonEquations2D) prod = one(u[1]) for k in eachcomponent(equations) prod *= u[(k-1)*5+4] @@ -855,7 +853,7 @@ end return prod end -@inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function density(u, equations::IdealMhdMultiIonEquations2D) rho = zero(u[1]) for k in eachcomponent(equations) rho += u[(k-1)*5+4] @@ -866,7 +864,7 @@ end """ Computes the sum of the densities times the sum of the pressures """ -@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations2D) +@inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u rho_total = zero(u[1]) p_total = zero(u[1]) From 6527aeada27bf67056a82b53820200037081e41a Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Fri, 5 May 2023 21:33:40 +0200 Subject: [PATCH 014/108] Fix (most) allocations --- src/equations/ideal_mhd_multiion_2d.jl | 154 ++++++++++++++++--------- 1 file changed, 99 insertions(+), 55 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index b3d7452cddd..e5e16f05c6c 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -139,12 +139,12 @@ end mag_en = 0.5*(B1^2 + B2^2 + B3^2) - if orientation == 1 - f_B1 = 0.0 - f_B2 = v1_plus * B2 - v2_plus * B1 - f_B3 = v1_plus * B3 - v3_plus * B1 + f = zeros(MVector{nvariables(equations), eltype(u)}) - f = (f_B1, f_B2, f_B3) + if orientation == 1 + f[1] = 0.0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) @@ -162,16 +162,18 @@ end f4 = rho_v1*v3 #- B1*B3 f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - f = (f..., f1, f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = f1 + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end else #if orientation == 2 - f_B1 = v2_plus * B1 - v1_plus * B2 - f_B2 = 0.0 - f_B3 = v2_plus * B3 - v3_plus * B2 - - f = (f_B1, f_B2, f_B3) + f[1] = v2_plus * B1 - v1_plus * B2 + f[2] = 0.0 + f[3] = v2_plus * B3 - v3_plus * B2 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) @@ -189,11 +191,15 @@ end f4 = rho_v2*v3 #- B2*B3 f5 = (kin_en + gamma*p/(gamma - 1))*v2 + 2 * mag_en * vk2_plus[k] - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - f = (f..., f1, f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = f1 + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -204,7 +210,8 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - s = (zero(u[1]), zero(u[1]), zero(u[1])) + s = zeros(MVector{nvariables(equations), eltype(u)}) + for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) v1 = rho_v1 / rho @@ -219,10 +226,14 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) s4 = r_rho * (v1_diff * B2 - v2_diff - B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 - s = (s..., zero(u[1]), s2, s3, s4, s5) + s[3 + (k - 1) * 5 + 1] = zero(u[1]) + s[3 + (k - 1) * 5 + 2] = s2 + s[3 + (k - 1) * 5 + 3] = s3 + s[3 + (k - 1) * 5 + 4] = s4 + s[3 + (k - 1) * 5 + 5] = s5 end - return SVector{nvariables(equations), real(equations)}(s) + return SVector(s) end """ @@ -248,7 +259,8 @@ The term is composed of three parts mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) # Compute charge ratio of u_ll - charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + # + charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -260,13 +272,14 @@ The term is composed of three parts # Compute auxiliary variables v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) + + f = zeros(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f_B1 = v1_plus_ll * B1_rr - f_B2 = v2_plus_ll * B1_rr - f_B3 = v3_plus_ll * B1_rr - f = (f_B1, f_B2, f_B3) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) # Compute term 2 (MHD) @@ -303,15 +316,18 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end else #if orientation == 2 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f_B1 = v1_plus_ll * B2_rr - f_B2 = v2_plus_ll * B2_rr - f_B3 = v3_plus_ll * B2_rr - f = (f_B1, f_B2, f_B3) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr for k in eachcomponent(equations) # Compute term 2 (MHD) @@ -348,11 +364,15 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -372,7 +392,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 # Compute charge ratio of u_ll - charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -384,13 +404,14 @@ The term is composed of three parts # Compute auxiliary variables v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) + + f = zeros(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f_B1 = v1_plus_ll * B1_rr - f_B2 = v2_plus_ll * B1_rr - f_B3 = v3_plus_ll * B1_rr - f = (f_B1, f_B2, f_B3) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) # Compute term 2 (MHD) # TODO: Add electron pressure term @@ -415,14 +436,17 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end else #if orientation == 2 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f_B1 = v1_plus_ll * B2_rr - f_B2 = v2_plus_ll * B2_rr - f_B3 = v3_plus_ll * B2_rr - f = (f_B1, f_B2, f_B3) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr for k in eachcomponent(equations) # Compute term 2 (MHD) @@ -448,11 +472,15 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -475,6 +503,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) + f = zeros(MVector{nvariables(equations), eltype(u_ll)}) + # Compute averages for global variables v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) v2_plus_avg = 0.5*(v2_plus_ll+v2_plus_rr) @@ -492,8 +522,10 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - # Start concatenating the flux - f = (f6, f7, f8) + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 # Iterate over all components for k in eachcomponent(equations) @@ -558,7 +590,11 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - f = (f..., f1, f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = f1 + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end else #if orientation == 2 # Magnetic field components from f^MHD @@ -566,8 +602,10 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide f7 = zero(u_ll[1]) f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg - # Start concatenating the flux - f = (f6, f7, f8) + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 # Iterate over all components for k in eachcomponent(equations) @@ -632,11 +670,15 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - f = (f..., f1, f2, f3, f4, f5) + f[3 + (k - 1) * 5 + 1] = f1 + f[3 + (k - 1) * 5 + 2] = f2 + f[3 + (k - 1) * 5 + 3] = f3 + f[3 + (k - 1) * 5 + 4] = f4 + f[3 + (k - 1) * 5 + 5] = f5 end end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -810,11 +852,11 @@ Routine to compute the Charge-averaged velocities: """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = zero(u[1]) + total_electron_charge = zero(eltype(u)) - vk1_plus = zeros(typeof(u[1]), ncomponents(equations)) - vk2_plus = zeros(typeof(u[1]), ncomponents(equations)) - vk3_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk1_plus = zeros(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zeros(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zeros(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) rho_k = u[(k-1)*5+4] @@ -833,16 +875,18 @@ Routine to compute the Charge-averaged velocities: v2_plus = sum(vk2_plus) v3_plus = sum(vk3_plus) - return v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), - SVector{ncomponents(equations), real(equations)}(vk2_plus), - SVector{ncomponents(equations), real(equations)}(vk3_plus) + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), SVector(vk3_plus) end """ Get the flow variables of component k """ @inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) - return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) + return SVector(u[(k-1)*5+4], + u[(k-1)*5+5], + u[(k-1)*5+6], + u[(k-1)*5+7], + u[(k-1)*5+8]) end @inline function density_product(u, equations::IdealMhdMultiIonEquations2D) From eac28428286c10ebbadcaec2d6df638afb1f5a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 08:50:34 +0200 Subject: [PATCH 015/108] Apply suggestions from code review (0.0 -> 0) Co-authored-by: Hendrik Ranocha --- src/equations/ideal_mhd_multiion_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index e5e16f05c6c..760af783ea1 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -142,7 +142,7 @@ end f = zeros(MVector{nvariables(equations), eltype(u)}) if orientation == 1 - f[1] = 0.0 + f[1] = 0 f[2] = v1_plus * B2 - v2_plus * B1 f[3] = v1_plus * B3 - v3_plus * B1 @@ -172,7 +172,7 @@ end else #if orientation == 2 f[1] = v2_plus * B1 - v1_plus * B2 - f[2] = 0.0 + f[2] = 0 f[3] = v2_plus * B3 - v3_plus * B2 for k in eachcomponent(equations) From 179877b50c5a963c217f5d6e94ea0d736cf6d778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 09:57:56 +0200 Subject: [PATCH 016/108] Changed all occurrences of '0.0' and 'zero(eltype(u))' to '0' --- src/equations/ideal_mhd_multiion_2d.jl | 60 +++++++++++++------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 760af783ea1..42a8fa89b9d 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -76,7 +76,7 @@ default_analysis_integrals(::IdealMhdMultiIonEquations2D) = (entropy_timederiva # rho = 1.0 # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = 0.0 +# v1 = 0 # si, co = sincos(2 * pi * x[1]) # v2 = 0.1 * si # v3 = 0.1 * co @@ -108,22 +108,22 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua phi = atan(y_norm, x_norm) # Calculate primitive variables - rho = zero(real(equations)) + rho = 0 if r > 0.5 rho = 1.0 else rho = 1.1691 end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + v1 = r > 0.5 ? 0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0 : 0.1882 * sin(phi) p = r > 0.5 ? 1.0 : 1.245 #prim = (0.01, 0.01, 0.01) prim = (1.0, 1.0, 1.0) for i in eachcomponent(equations) - prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0.0, p) - #prim = (prim..., rho, v1, 0.0, 0.0, p) - #prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) + prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0, p) + #prim = (prim..., rho, v1, 0, 0, p) + #prim = (prim..., 1.0, 1.0, 0, 0, 100) end return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) @@ -226,7 +226,7 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) s4 = r_rho * (v1_diff * B2 - v2_diff - B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 - s[3 + (k - 1) * 5 + 1] = zero(u[1]) + s[3 + (k - 1) * 5 + 1] = 0 s[3 + (k - 1) * 5 + 2] = s2 s[3 + (k - 1) * 5 + 3] = s3 s[3 + (k - 1) * 5 + 4] = s4 @@ -261,7 +261,7 @@ The term is composed of three parts # Compute charge ratio of u_ll # charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(u_ll[1]) + total_electron_charge = 0 for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -287,7 +287,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = 0 # TODO: Add "average" of electron pressure! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -316,7 +316,7 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 1] = 0 f[3 + (k - 1) * 5 + 2] = f2 f[3 + (k - 1) * 5 + 3] = f3 f[3 + (k - 1) * 5 + 4] = f4 @@ -335,7 +335,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (- B2_avg * B1_avg) f3 = charge_ratio_ll[k] * (- B2_avg * B2_avg + 0.5 * mag_norm_avg) # + pe_mean) f4 = charge_ratio_ll[k] * (- B2_avg * B3_avg) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = 0 # TODO: Add average of electron pressure! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -364,7 +364,7 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 1] = 0 f[3 + (k - 1) * 5 + 2] = f2 f[3 + (k - 1) * 5 + 3] = f3 f[3 + (k - 1) * 5 + 4] = f4 @@ -393,7 +393,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(u_ll[1]) + total_electron_charge = 0 for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -418,7 +418,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = 0 # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] @@ -436,7 +436,7 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 1] = 0 f[3 + (k - 1) * 5 + 2] = f2 f[3 + (k - 1) * 5 + 3] = f3 f[3 + (k - 1) * 5 + 4] = f4 @@ -454,7 +454,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (- B2_rr * B1_rr) f3 = charge_ratio_ll[k] * (- B2_rr * B2_rr + 0.5 * mag_norm_rr) # + pe_mean) f4 = charge_ratio_ll[k] * (- B2_rr * B3_rr) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = 0 # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] @@ -472,7 +472,7 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = zero(u_ll[1]) + f[3 + (k - 1) * 5 + 1] = 0 f[3 + (k - 1) * 5 + 2] = f2 f[3 + (k - 1) * 5 + 3] = f3 f[3 + (k - 1) * 5 + 4] = f4 @@ -518,7 +518,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide if orientation == 1 # Magnetic field components from f^MHD - f6 = zero(u_ll[1]) + f6 = 0 f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg @@ -599,7 +599,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide else #if orientation == 2 # Magnetic field components from f^MHD f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg - f7 = zero(u_ll[1]) + f7 = 0 f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg # Start building the flux @@ -693,8 +693,8 @@ end cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) # Calculate velocities - v_ll = zero(u_ll[1]) - v_rr = zero(u_rr[1]) + v_ll = 0 + v_rr = 0 if orientation == 1 for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u_ll, equations) @@ -717,8 +717,8 @@ end @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) - v1 = zero(u[1]) - v2 = zero(u[1]) + v1 = 0 + v2 = 0 for k in eachcomponent(equations) rho, rho_v1, rho_v2, _ = get_component(k, u, equations) v1 = max(v1, abs(rho_v1 / rho)) @@ -764,7 +764,7 @@ Convert conservative variables to entropy prim = cons2prim(u, equations) entropy = () - rho_p_plus = zero(u[1]) + rho_p_plus = 0 for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) s = log(p) - gammas[k] * log(rho) @@ -817,7 +817,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco @inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = cons - c_f = zero(cons[1]) + c_f = 0 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) @@ -852,7 +852,7 @@ Routine to compute the Charge-averaged velocities: """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = zero(eltype(u)) + total_electron_charge = 0 vk1_plus = zeros(MVector{ncomponents(equations), eltype(u)}) vk2_plus = zeros(MVector{ncomponents(equations), eltype(u)}) @@ -898,7 +898,7 @@ end end @inline function density(u, equations::IdealMhdMultiIonEquations2D) - rho = zero(u[1]) + rho = 0 for k in eachcomponent(equations) rho += u[(k-1)*5+4] end @@ -910,8 +910,8 @@ Computes the sum of the densities times the sum of the pressures """ @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u - rho_total = zero(u[1]) - p_total = zero(u[1]) + rho_total = 0 + p_total = 0 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) From 1e0aca54ba13087ee8dc174900d4a8ed2911b53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 10:16:21 +0200 Subject: [PATCH 017/108] Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper --- src/equations/ideal_mhd_multiion_2d.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 42a8fa89b9d..e2178719fa7 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -114,8 +114,8 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua else rho = 1.1691 end - v1 = r > 0.5 ? 0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0 : 0.1882 * sin(phi) + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) p = r > 0.5 ? 1.0 : 1.245 #prim = (0.01, 0.01, 0.01) @@ -261,7 +261,7 @@ The term is composed of three parts # Compute charge ratio of u_ll # charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = 0 + total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] From 57b8ea426a9b37113fb3d73088e720afa88a82dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 10:29:55 +0200 Subject: [PATCH 018/108] Added set_component function --- src/equations/ideal_mhd_multiion_2d.jl | 81 +++++++++----------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index e2178719fa7..b0fbe3c0f8d 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -162,11 +162,7 @@ end f4 = rho_v1*v3 #- B1*B3 f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - f[3 + (k - 1) * 5 + 1] = f1 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, f1, f2, f3, f4, f5, equations) end else #if orientation == 2 @@ -191,11 +187,7 @@ end f4 = rho_v2*v3 #- B2*B3 f5 = (kin_en + gamma*p/(gamma - 1))*v2 + 2 * mag_en * vk2_plus[k] - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - f[3 + (k - 1) * 5 + 1] = f1 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, f1, f2, f3, f4, f5, equations) end end @@ -226,11 +218,7 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) s4 = r_rho * (v1_diff * B2 - v2_diff - B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 - s[3 + (k - 1) * 5 + 1] = 0 - s[3 + (k - 1) * 5 + 2] = s2 - s[3 + (k - 1) * 5 + 3] = s3 - s[3 + (k - 1) * 5 + 4] = s4 - s[3 + (k - 1) * 5 + 5] = s5 + set_component!(s, k, 0, s2, s3, s4, s5, equations) end return SVector(s) @@ -316,11 +304,7 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = 0 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, 0, f2, f3, f4, f5, equations) end else #if orientation == 2 @@ -364,11 +348,7 @@ The term is composed of three parts f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = 0 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, 0, f2, f3, f4, f5, equations) end end @@ -436,11 +416,7 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = 0 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, 0, f2, f3, f4, f5, equations) end else #if orientation == 2 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -472,11 +448,7 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f[3 + (k - 1) * 5 + 1] = 0 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, 0, f2, f3, f4, f5, equations) end end @@ -590,11 +562,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - f[3 + (k - 1) * 5 + 1] = f1 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, f1, f2, f3, f4, f5, equations) end else #if orientation == 2 # Magnetic field components from f^MHD @@ -670,11 +638,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - f[3 + (k - 1) * 5 + 1] = f1 - f[3 + (k - 1) * 5 + 2] = f2 - f[3 + (k - 1) * 5 + 3] = f3 - f[3 + (k - 1) * 5 + 4] = f4 - f[3 + (k - 1) * 5 + 5] = f5 + set_component!(f, k, f1, f2, f3, f4, f5, equations) end end @@ -882,17 +846,30 @@ end Get the flow variables of component k """ @inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) - return SVector(u[(k-1)*5+4], - u[(k-1)*5+5], - u[(k-1)*5+6], - u[(k-1)*5+7], - u[(k-1)*5+8]) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" +Set the flow variables of component k +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::IdealMhdMultiIonEquations2D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 end @inline function density_product(u, equations::IdealMhdMultiIonEquations2D) prod = one(u[1]) for k in eachcomponent(equations) - prod *= u[(k-1)*5+4] + prod *= u[3 + (k - 1) * 5 + 1] end return prod end @@ -900,7 +877,7 @@ end @inline function density(u, equations::IdealMhdMultiIonEquations2D) rho = 0 for k in eachcomponent(equations) - rho += u[(k-1)*5+4] + rho += u[3 + (k - 1) * 5 + 1] end return rho end From 76325d0451b108e341d82e85f1831d31fc5a4c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 13:29:58 +0200 Subject: [PATCH 019/108] Fixed other potential type instabilities --- src/equations/ideal_mhd_multiion_2d.jl | 35 ++++++++++++-------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index b0fbe3c0f8d..ec6333f462c 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -76,7 +76,7 @@ default_analysis_integrals(::IdealMhdMultiIonEquations2D) = (entropy_timederiva # rho = 1.0 # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = 0 +# v1 = zero(real(equations)) # si, co = sincos(2 * pi * x[1]) # v2 = 0.1 * si # v3 = 0.1 * co @@ -108,7 +108,7 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua phi = atan(y_norm, x_norm) # Calculate primitive variables - rho = 0 + rho = zero(real(equations)) if r > 0.5 rho = 1.0 else @@ -118,12 +118,9 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) p = r > 0.5 ? 1.0 : 1.245 - #prim = (0.01, 0.01, 0.01) prim = (1.0, 1.0, 1.0) for i in eachcomponent(equations) - prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0, p) - #prim = (prim..., rho, v1, 0, 0, p) - #prim = (prim..., 1.0, 1.0, 0, 0, 100) + prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, zero(real(equations)), p) end return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) @@ -137,7 +134,7 @@ end v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - mag_en = 0.5*(B1^2 + B2^2 + B3^2) + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) f = zeros(MVector{nvariables(equations), eltype(u)}) @@ -157,9 +154,9 @@ end p = (gamma - 1) * (rho_e - kin_en - mag_en) f1 = rho_v1 - f2 = rho_v1*v1 + p #+ mag_en - B1^2 - f3 = rho_v1*v2 #- B1*B2 - f4 = rho_v1*v3 #- B1*B3 + f2 = rho_v1*v1 + p + f3 = rho_v1*v2 + f4 = rho_v1*v3 f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) set_component!(f, k, f1, f2, f3, f4, f5, equations) @@ -373,7 +370,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = 0 + total_electron_charge = zero(real(equations)) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -681,8 +678,8 @@ end @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) - v1 = 0 - v2 = 0 + v1 = zero(real(equations)) + v2 = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, rho_v2, _ = get_component(k, u, equations) v1 = max(v1, abs(rho_v1 / rho)) @@ -728,7 +725,7 @@ Convert conservative variables to entropy prim = cons2prim(u, equations) entropy = () - rho_p_plus = 0 + rho_p_plus = zero(real(equations)) for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) s = log(p) - gammas[k] * log(rho) @@ -781,7 +778,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco @inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = cons - c_f = 0 + c_f = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) @@ -816,7 +813,7 @@ Routine to compute the Charge-averaged velocities: """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = 0 + total_electron_charge = zero(real(equations)) vk1_plus = zeros(MVector{ncomponents(equations), eltype(u)}) vk2_plus = zeros(MVector{ncomponents(equations), eltype(u)}) @@ -875,7 +872,7 @@ end end @inline function density(u, equations::IdealMhdMultiIonEquations2D) - rho = 0 + rho = zero(real(equations)) for k in eachcomponent(equations) rho += u[3 + (k - 1) * 5 + 1] end @@ -887,8 +884,8 @@ Computes the sum of the densities times the sum of the pressures """ @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u - rho_total = 0 - p_total = 0 + rho_total = zero(real(equations)) + p_total = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) From 8662c8f511409e4693c28898e00be31925955ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 13:45:15 +0200 Subject: [PATCH 020/108] Changed MVectors definitions to avoid creating arrays filled with zero MVectors --- src/equations/ideal_mhd_multiion_2d.jl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index ec6333f462c..94bf9a5d4ec 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -136,7 +136,7 @@ end mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - f = zeros(MVector{nvariables(equations), eltype(u)}) + f = zero(MVector{nvariables(equations), eltype(u)}) if orientation == 1 f[1] = 0 @@ -199,7 +199,7 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - s = zeros(MVector{nvariables(equations), eltype(u)}) + s = zero(MVector{nvariables(equations), eltype(u)}) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) @@ -245,7 +245,7 @@ The term is composed of three parts # Compute charge ratio of u_ll # - charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -258,7 +258,7 @@ The term is composed of three parts v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - f = zeros(MVector{nvariables(equations), eltype(u_ll)}) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -369,7 +369,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 # Compute charge ratio of u_ll - charge_ratio_ll = zeros(MVector{ncomponents(equations), eltype(u_ll)}) + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(real(equations)) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -382,7 +382,7 @@ The term is composed of three parts v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - f = zeros(MVector{nvariables(equations), eltype(u_ll)}) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -472,7 +472,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - f = zeros(MVector{nvariables(equations), eltype(u_ll)}) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) # Compute averages for global variables v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) @@ -815,9 +815,9 @@ Routine to compute the Charge-averaged velocities: total_electron_charge = zero(real(equations)) - vk1_plus = zeros(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zeros(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zeros(MVector{ncomponents(equations), eltype(u)}) + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) rho_k = u[(k-1)*5+4] From 30636d6203bbb51218cfe9f38d7f79a13146e379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 14:27:07 +0200 Subject: [PATCH 021/108] Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper --- src/equations/ideal_mhd_multiion_2d.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 94bf9a5d4ec..7abacc42926 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -244,7 +244,6 @@ The term is composed of three parts mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) # Compute charge ratio of u_ll - # charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) @@ -654,8 +653,8 @@ end cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) # Calculate velocities - v_ll = 0 - v_rr = 0 + v_ll = zero(u_ll[1]) + v_rr = zero(u_rr[1]) if orientation == 1 for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u_ll, equations) From 968b688db71508b17d3ce0a98cd0db81e94c34c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 15:21:54 +0200 Subject: [PATCH 022/108] Use MVectors in cons2prim, prim2cons, and cons2entropy --- src/equations/ideal_mhd_multiion_2d.jl | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 7abacc42926..6255db557bc 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -699,7 +699,10 @@ function cons2prim(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3, _ = u - prim = (B1, B2, B3) + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) srho = 1 / rho @@ -709,10 +712,11 @@ function cons2prim(u, equations::IdealMhdMultiIonEquations2D) p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + B1 * B1 + B2 * B2 + B3 * B3)) - prim = (prim..., rho, v1, v2, v3, p) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) end - return SVector{nvariables(equations), real(equations)}(prim) + return SVector(prim) end """ @@ -723,7 +727,7 @@ Convert conservative variables to entropy B1, B2, B3, _ = u prim = cons2prim(u, equations) - entropy = () + entropy = zero(MVector{nvariables(equations), eltype(u)}) rho_p_plus = zero(real(equations)) for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) @@ -735,16 +739,16 @@ Convert conservative variables to entropy w4 = rho_p * v3 w5 = -rho_p rho_p_plus += rho_p - entropy = (entropy..., w1, w2, w3, w4, w5) + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) end # Additional non-conservative variables - w6 = rho_p_plus * B1 - w7 = rho_p_plus * B2 - w8 = rho_p_plus * B3 - entropy = (w6, w7, w8, entropy...) + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 - return SVector{nvariables(equations), real(equations)}(entropy) + return SVector(entropy) end @@ -755,7 +759,10 @@ Convert primitive to conservative variables @unpack gammas = equations B1, B2, B3, _ = prim - cons = (B1, B2, B3) + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) rho_v1 = rho * v1 @@ -764,10 +771,11 @@ Convert primitive to conservative variables rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + 0.5 * (B1^2 + B2^2 + B3^2) - cons = (cons..., rho, rho_v1, rho_v2, rho_v3, rho_e) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end - return SVector{nvariables(equations), real(equations)}(cons) + return SVector(cons) end """ From 29c5a518bd02235294acccbc1a4065abe5101563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 15:39:54 +0200 Subject: [PATCH 023/108] initial_condition_weak_blast_wave (2D) uses MVector --- src/equations/ideal_mhd_multiion_2d.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 6255db557bc..13a7ea2b993 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -118,12 +118,15 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) p = r > 0.5 ? 1.0 : 1.245 - prim = (1.0, 1.0, 1.0) - for i in eachcomponent(equations) - prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, zero(real(equations)), p) + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, 2^(k-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0, p, equations) end - return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) + return prim2cons(SVector(prim), equations) end # TODO: Add initial condition equilibrium From 363fca21cf6577ee7d434ca06e7d9a80bed6f246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 8 May 2023 15:58:26 +0200 Subject: [PATCH 024/108] Performance optimizations for ideal MHD multi-ion 1D --- src/equations/ideal_mhd_multiion_1d.jl | 126 +++++++++++++++---------- 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 61078e5d1a3..6814759d030 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -114,15 +114,15 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) p = r > 0.5 ? 1.0 : 1.245 - #prim = (0.01, 0.01, 0.01) - prim = (1.0, 1.0, 1.0) - for i in eachcomponent(equations) - prim = (prim..., 2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0.0, 0.0, p) - #prim = (prim..., rho, v1, 0.0, 0.0, p) - #prim = (prim..., 1.0, 1.0, 0.0, 0.0, 100.0) + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, 2^(k-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0, 0, p, equations) end - return prim2cons(SVector{nvariables(equations), real(equations)}(prim), equations) + return prim2cons(SVector(prim), equations) end # TODO: Add initial condition equilibrium @@ -133,14 +133,13 @@ end v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - f_B1 = 0.0 - f_B2 = v1_plus * B2 - v2_plus * B1 - f_B3 = v1_plus * B3 - v3_plus * B1 - - f = (f_B1, f_B2, f_B3) - mag_en = 0.5*(B1^2 + B2^2 + B3^2) + f = zero(MVector{nvariables(equations), eltype(u)}) + f[1] = 0.0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 + for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) v1 = rho_v1/rho @@ -157,10 +156,10 @@ end f4 = rho_v1*v3 #- B1*B3 f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - f = (f..., f1, f2, f3, f4, f5) + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -171,7 +170,7 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) B1, B2, B3, _ = u v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - s = (zero(u[1]), zero(u[1]), zero(u[1])) + s = zero(MVector{nvariables(equations), eltype(u)}) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) v1 = rho_v1 / rho @@ -186,10 +185,10 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) s4 = r_rho * (v1_diff * B2 - v2_diff - B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 - s = (s..., zero(u[1]), s2, s3, s4, s5) + set_component!(s, k, 0, s2, s3, s4, s5, equations) end - return SVector{nvariables(equations), real(equations)}(s) + return SVector(s) end """ @@ -215,7 +214,7 @@ The term is composed of three parts mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) # Compute charge ratio of u_ll - charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -228,7 +227,7 @@ The term is composed of three parts v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) # TODO: Add entries of Powell term for induction equation for k in eachcomponent(equations) # Compute Powell (only needed for non-constant B1) @@ -260,10 +259,10 @@ The term is composed of three parts f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -283,7 +282,7 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 # Compute charge ratio of u_ll - charge_ratio_ll = zeros(typeof(u_ll[1]), ncomponents(equations)) + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(u_ll[1]) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] @@ -295,7 +294,7 @@ The term is composed of three parts # Compute auxiliary variables v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - f = (zero(u_ll[1]), zero(u_ll[1]), zero(u_ll[1])) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) # TODO: Add entries of Powell term for induction equation for k in eachcomponent(equations) # Compute Powell (only needed for non-constant B1) @@ -318,10 +317,10 @@ The term is composed of three parts # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector - f = (f..., zero(u_ll[1]), f2, f3, f4, f5) + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -355,13 +354,17 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + # Magnetic field components from f^MHD f6 = zero(u_ll[1]) f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - # Start concatenating the flux - f = (f6, f7, f8) + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 # Iterate over all components for k in eachcomponent(equations) @@ -426,10 +429,10 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - f = (f..., f1, f2, f3, f4, f5) + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - return SVector{nvariables(equations), real(equations)}(f) + return SVector(f) end """ @@ -478,7 +481,10 @@ function cons2prim(u, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations B1, B2, B3, _ = u - prim = (B1, B2, B3) + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) srho = 1 / rho @@ -488,10 +494,11 @@ function cons2prim(u, equations::IdealMhdMultiIonEquations1D) p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + B1 * B1 + B2 * B2 + B3 * B3)) - prim = (prim..., rho, v1, v2, v3, p) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) end - return SVector{nvariables(equations), real(equations)}(prim) + return SVector(prim) end """ @@ -502,8 +509,8 @@ Convert conservative variables to entropy B1, B2, B3, _ = u prim = cons2prim(u, equations) - entropy = () - rho_p_plus = zero(u[1]) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) s = log(p) - gammas[k] * log(rho) @@ -514,16 +521,16 @@ Convert conservative variables to entropy w4 = rho_p * v3 w5 = -rho_p rho_p_plus += rho_p - entropy = (entropy..., w1, w2, w3, w4, w5) + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) end # Additional non-conservative variables - w6 = rho_p_plus * B1 - w7 = rho_p_plus * B2 - w8 = rho_p_plus * B3 - entropy = (w6, w7, w8, entropy...) + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 - return SVector{nvariables(equations), real(equations)}(entropy) + return SVector(entropy) end @@ -534,7 +541,10 @@ Convert primitive to conservative variables @unpack gammas = equations B1, B2, B3, _ = prim - cons = (B1, B2, B3) + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 for k in eachcomponent(equations) rho, v1, v2, v3, p = get_component(k, prim, equations) rho_v1 = rho * v1 @@ -543,7 +553,8 @@ Convert primitive to conservative variables rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + 0.5 * (B1^2 + B2^2 + B3^2) - cons = (cons..., rho, rho_v1, rho_v2, rho_v3, rho_e) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end return SVector{nvariables(equations), real(equations)}(cons) @@ -589,9 +600,9 @@ Routine to compute the charge-averaged velocities: total_electron_charge = zero(u[1]) - vk1_plus = zeros(typeof(u[1]), ncomponents(equations)) - vk2_plus = zeros(typeof(u[1]), ncomponents(equations)) - vk3_plus = zeros(typeof(u[1]), ncomponents(equations)) + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) rho_k = u[(k-1)*5+4] @@ -610,16 +621,31 @@ Routine to compute the charge-averaged velocities: v2_plus = sum(vk2_plus) v3_plus = sum(vk3_plus) - return v1_plus, v2_plus, v3_plus, SVector{ncomponents(equations), real(equations)}(vk1_plus), - SVector{ncomponents(equations), real(equations)}(vk2_plus), - SVector{ncomponents(equations), real(equations)}(vk3_plus) + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), SVector(vk3_plus) end """ Get the flow variables of component k """ @inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) - return SVector{5, real(equations)}(u[(k-1)*5+4:(k-1)*5+8]) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" +Set the flow variables of component k +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::IdealMhdMultiIonEquations1D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 end @inline function density_product(u, equations::IdealMhdMultiIonEquations1D) From 0b165ef9b343970dc50600a4e453983efe772d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 9 May 2023 09:11:42 +0200 Subject: [PATCH 025/108] Apply styling suggestions from code review Co-authored-by: Michael Schlottke-Lakemper --- .../elixir_mhdmultiion_ec_onespecies.jl | 1 - examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 1 - examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 14 +++++++------- src/equations/equations.jl | 1 + src/equations/ideal_mhd_multiion_2d.jl | 7 ++++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index edf529bff90..381a8759b0b 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -9,7 +9,6 @@ equations = IdealMhdMultiIonEquations1D(gammas = (2.0), initial_condition = initial_condition_weak_blast_wave -#volume_flux = flux_central volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) solver = DGSEM(polydeg=3, surface_flux=surface_flux, diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 1500408299b..a6eb89ee5ed 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -9,7 +9,6 @@ equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), initial_condition = initial_condition_weak_blast_wave -#volume_flux = flux_central volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) solver = DGSEM(polydeg=3, surface_flux=surface_flux, diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index 8bd9033dca9..13ac909f2e7 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -29,8 +29,8 @@ function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) f = (0.115 - r)/0.015 if r <= 0.1 rho = 10.0 - v1 = -20.0*dy - v2 = 20.0*dx + v1 = -20.0 * dy + v2 = 20.0 * dx elseif r >= 0.115 if x[1] > 0.75 rho = 0.49 * (tanh(50 * (x[1] - 1.0)) + 1) + 0.02 @@ -56,8 +56,8 @@ function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) f = (0.115 - r)/0.015 if r <= 0.1 rho2 = 10.0 - v12 = -20.0*dy - v22 = 20.0*dx + v12 = -20.0 * dy + v22 = 20.0 * dx elseif r >= 0.115 if x[1] < 0.25 rho2 = 0.49 * (-tanh(50 * (x[1])) + 1) + 0.02 @@ -69,9 +69,9 @@ function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) v12 = 0.0 v22 = 0.0 else - rho2 = 1.0 + 9.0*f - v12 = -20.0*f*dy - v22 = 20.0*f*dx + rho2 = 1.0 + 9.0 * f + v12 = -20.0 * f * dy + v22 = 20.0 * f * dx end v3 = 0.0 p = 1.0 diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 07ddfa30247..f945097e81f 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -360,6 +360,7 @@ In particular, not the components themselves are returned. # Retrieve number of components from equation instance for the multi-ion case @inline ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP + """ eachcomponent(equations::AbstractIdealMhdMultiIonEquations) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 13a7ea2b993..cc88f3b05d3 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -14,8 +14,8 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: Abstrac gammas ::SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, - charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, RealT}, + charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) @@ -24,7 +24,6 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: Abstrac end function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass) - _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) @@ -871,6 +870,8 @@ Set the flow variables of component k u[3 + (k - 1) * 5 + 3] = u3 u[3 + (k - 1) * 5 + 4] = u4 u[3 + (k - 1) * 5 + 5] = u5 + + return u end @inline function density_product(u, equations::IdealMhdMultiIonEquations2D) From 272bdcf8037442a6c0e1a65204337457e8cffdef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 10 May 2023 13:56:12 +0200 Subject: [PATCH 026/108] Styling changes --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 4 ++-- .../elixir_mhdmultiion_ec_onespecies.jl | 4 ++-- .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 4 ++-- .../elixir_mhdmultiion_es_shock_capturing.jl | 4 ++-- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 4 ++-- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 4 ++-- src/equations/ideal_mhd_multiion_1d.jl | 24 ++++++++----------- src/equations/ideal_mhd_multiion_2d.jl | 10 +++----- 8 files changed, 25 insertions(+), 33 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index 3070d1351eb..e247e1e2312 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index 381a8759b0b..ca7ac5ff363 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations1D(gammas = (2.0), - charge_to_mass = (1.0)) +equations = IdealMhdMultiIonEquations1D(gammas = (2.0), + charge_to_mass = (1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index cfe7cb1d2d9..37e7a87bdfc 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl index f9465890ead..41a3542efc1 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index a6eb89ee5ed..2577d217756 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index 13ac909f2e7..aab374ecaeb 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations2D(gammas = (1.4, 1.4), - charge_to_mass = (1.0, 2.0)) +equations = IdealMhdMultiIonEquations2D(gammas = (1.4, 1.4), + charge_to_mass = (1.0, 2.0)) """ initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 6814759d030..f256b54558c 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -24,7 +24,6 @@ mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: Abstrac end function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) - _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) @@ -53,7 +52,6 @@ function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) end function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) - prim = ("B1", "B2", "B3") for i in eachcomponent(equations) prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) @@ -215,7 +213,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(u_ll[1]) + total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -238,7 +236,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -283,7 +281,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(u_ll[1]) + total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -305,7 +303,7 @@ The term is composed of three parts f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) - f5 = zero(u_ll[1]) # TODO! charge_ratio_ll[k] * pe_mean + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] @@ -357,7 +355,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide f = zero(MVector{nvariables(equations), eltype(u_ll)}) # Magnetic field components from f^MHD - f6 = zero(u_ll[1]) + f6 = zero(eltype(u_ll)) f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg @@ -447,7 +445,7 @@ end cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) # Calculate velocities (ignore orientation since it is always "1" in 1D) - v_ll = zero(u_ll[1]) + v_ll = zero(eltype(u_ll)) v_rr = zero(u_rr[1]) for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u_ll, equations) @@ -461,8 +459,7 @@ end @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) - - v1 = zero(u[1]) + v1 = zero(eltype(u)) for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u, equations) v1 = max(v1, abs(rho_v1 / rho)) @@ -597,8 +594,7 @@ Routine to compute the charge-averaged velocities: * vk*_plus: Contribution of each species to the charge-averaged velocity """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) - - total_electron_charge = zero(u[1]) + total_electron_charge = zero(eltype(u)) vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) @@ -649,7 +645,7 @@ Set the flow variables of component k end @inline function density_product(u, equations::IdealMhdMultiIonEquations1D) - prod = one(u[1]) + prod = one(eltype(u)) for k in eachcomponent(equations) prod *= u[(k-1)*5+4] end @@ -657,7 +653,7 @@ end end @inline function density(u, equations::IdealMhdMultiIonEquations1D) - rho = zero(u[1]) + rho = zero(eltype(u)) for k in eachcomponent(equations) rho += u[(k-1)*5+4] end diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index cc88f3b05d3..2f769991835 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -42,7 +42,6 @@ end have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) - cons = ("B1", "B2", "B3") for i in eachcomponent(equations) cons = (cons..., tuple("rho_" * string(i),"rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) @@ -52,7 +51,6 @@ function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) end function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) - prim = ("B1", "B2", "B3") for i in eachcomponent(equations) prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) @@ -247,7 +245,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(u_ll[1]) + total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) rho_k = u_ll[(k-1)*5+4] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -655,7 +653,7 @@ end cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) # Calculate velocities - v_ll = zero(u_ll[1]) + v_ll = zero(eltype(u_ll)) v_rr = zero(u_rr[1]) if orientation == 1 for k in eachcomponent(equations) @@ -678,7 +676,6 @@ end @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) - v1 = zero(real(equations)) v2 = zero(real(equations)) for k in eachcomponent(equations) @@ -821,7 +818,6 @@ Routine to compute the Charge-averaged velocities: * vk*_plus: Contribution of each species to the charge-averaged velocity """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = zero(real(equations)) vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) @@ -875,7 +871,7 @@ Set the flow variables of component k end @inline function density_product(u, equations::IdealMhdMultiIonEquations2D) - prod = one(u[1]) + prod = one(eltype(u)) for k in eachcomponent(equations) prod *= u[3 + (k - 1) * 5 + 1] end From e6fc0172b5b4a87dd298ee567858cc73c50a0e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 10 May 2023 14:51:59 +0200 Subject: [PATCH 027/108] More styling changes --- src/equations/ideal_mhd_multiion_1d.jl | 148 +++++++++--------- src/equations/ideal_mhd_multiion_2d.jl | 206 ++++++++++++------------- 2 files changed, 177 insertions(+), 177 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index f256b54558c..a58d371c3f6 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -117,7 +117,7 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua prim[2] = 1.0 prim[3] = 1.0 for k in eachcomponent(equations) - set_component!(prim, k, 2^(k-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, 0, 0, p, equations) + set_component!(prim, k, 2^(k - 1) * (1 - 2)/(1 - 2^ncomponents(equations)) * rho, v1, 0, 0, p, equations) end return prim2cons(SVector(prim), equations) @@ -127,7 +127,7 @@ end # Calculate 1D flux in for a single point @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -140,19 +140,19 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1/rho - v2 = rho_v2/rho - v3 = rho_v3/rho + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en) f1 = rho_v1 - f2 = rho_v1*v1 + p #+ mag_en - B1^2 - f3 = rho_v1*v2 #- B1*B2 - f4 = rho_v1*v3 #- B1*B3 - f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p /(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -165,7 +165,7 @@ Standard source terms of the multi-ion MHD equations """ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) s = zero(MVector{nvariables(equations), eltype(u)}) @@ -200,22 +200,22 @@ The term is composed of three parts @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) # Compute important averages - B1_avg = 0.5*(B1_ll+B1_rr) - B2_avg = 0.5*(B2_ll+B2_rr) - B3_avg = 0.5*(B3_ll+B3_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) - rho_k = u_ll[(k-1)*5+4] + rho_k = u_ll[3 + (k - 1) * 5 + 1] charge_ratio_ll[k] = rho_k * charge_to_mass[k] total_electron_charge += charge_ratio_ll[k] end @@ -242,9 +242,9 @@ The term is composed of three parts vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -273,8 +273,8 @@ The term is composed of three parts @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 @@ -283,7 +283,7 @@ The term is composed of three parts charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) - rho_k = u_ll[(k-1)*5+4] + rho_k = u_ll[3 + (k - 1) * 5 + 1] charge_ratio_ll[k] = rho_k * charge_to_mass[k] total_electron_charge += charge_ratio_ll[k] end @@ -306,9 +306,9 @@ The term is composed of three parts f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) @@ -335,22 +335,22 @@ This flux (together with the MHD non-conservative term) is consistent in the cas function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) # Compute averages for global variables - v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) - v2_plus_avg = 0.5*(v2_plus_ll+v2_plus_rr) - v3_plus_avg = 0.5*(v3_plus_ll+v3_plus_rr) - B1_avg = 0.5*(B1_ll+B1_rr) - B2_avg = 0.5*(B2_ll+B2_rr) - B3_avg = 0.5*(B3_ll+B3_rr) + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) f = zero(MVector{nvariables(equations), eltype(u_ll)}) @@ -370,12 +370,12 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll/rho_ll - v2_ll = rho_v2_ll/rho_ll - v3_ll = rho_v3_ll/rho_ll - v1_rr = rho_v1_rr/rho_rr - v2_rr = rho_v2_rr/rho_rr - v3_rr = rho_v3_rr/rho_rr + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 @@ -388,26 +388,26 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5*(rho_ll+rho_rr) - rho_mean = ln_mean(rho_ll,rho_rr) - beta_mean = ln_mean(beta_ll,beta_rr) - beta_avg = 0.5*(beta_ll+beta_rr) - p_mean = 0.5*rho_avg/beta_avg - v1_avg = 0.5*(v1_ll+v1_rr) - v2_avg = 0.5*(v2_ll+v2_rr) - v3_avg = 0.5*(v3_ll+v3_rr) - vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) - vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) - vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr- vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr- vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr- vk3_plus_rr[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) @@ -425,7 +425,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) + - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -446,7 +446,7 @@ end # Calculate velocities (ignore orientation since it is always "1" in 1D) v_ll = zero(eltype(u_ll)) - v_rr = zero(u_rr[1]) + v_rr = zero(eltype(u_rr)) for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u_ll, equations) v_ll = max(v_ll, abs(rho_v1 / rho)) @@ -476,7 +476,7 @@ Convert conservative variables to primitive """ function cons2prim(u, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) prim = zero(MVector{nvariables(equations), eltype(u)}) prim[1] = B1 @@ -503,7 +503,7 @@ Convert conservative variables to entropy """ @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) prim = cons2prim(u, equations) entropy = zero(MVector{nvariables(equations), eltype(u)}) @@ -536,7 +536,7 @@ Convert primitive to conservative variables """ @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) @unpack gammas = equations - B1, B2, B3, _ = prim + B1, B2, B3 = magnetic_field(prim, equations) cons = zero(MVector{nvariables(equations), eltype(prim)}) cons[1] = B1 @@ -562,7 +562,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! """ @inline function calc_fast_wavespeed(cons, direction, equations::IdealMhdMultiIonEquations1D) - B1, B2, B3, _ = cons + B1, B2, B3 = magnetic_field(cons, equations) c_f = zero(cons[1]) for k in eachcomponent(equations) @@ -573,7 +573,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco v3 = rho_v3 / rho v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) + p = (gamma - 1)*(rho_e - 0.5 * rho * v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) a_square = gamma * p / rho sqrt_rho = sqrt(rho) @@ -601,14 +601,12 @@ Routine to compute the charge-averaged velocities: vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) - rho_k = u[(k-1)*5+4] - rho_v1_k = u[(k-1)*5+5] - rho_v2_k = u[(k-1)*5+6] - rho_v3_k = u[(k-1)*5+7] - total_electron_charge += rho_k * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1_k * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2_k * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3_k * equations.charge_to_mass[k] + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations::IdealMhdMultiIonEquations1D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] end vk1_plus ./= total_electron_charge vk2_plus ./= total_electron_charge @@ -644,10 +642,12 @@ Set the flow variables of component k u[3 + (k - 1) * 5 + 5] = u5 end +magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) + @inline function density_product(u, equations::IdealMhdMultiIonEquations1D) prod = one(eltype(u)) for k in eachcomponent(equations) - prod *= u[(k-1)*5+4] + prod *= u[3 + (k - 1) * 5 + 1] end return prod end @@ -655,7 +655,7 @@ end @inline function density(u, equations::IdealMhdMultiIonEquations1D) rho = zero(eltype(u)) for k in eachcomponent(equations) - rho += u[(k-1)*5+4] + rho += u[3 + (k - 1) * 5 + 1] end return rho end diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 2f769991835..17f39c9e55b 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -120,7 +120,7 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua prim[2] = 1.0 prim[3] = 1.0 for k in eachcomponent(equations) - set_component!(prim, k, 2^(k-1) * (1-2)/(1-2^ncomponents(equations)) * rho, v1, v2, 0, p, equations) + set_component!(prim, k, 2^(k-1) * (1 - 2)/(1 - 2^ncomponents(equations)) * rho, v1, v2, 0, p, equations) end return prim2cons(SVector(prim), equations) @@ -130,7 +130,7 @@ end # Calculate 1D flux in for a single point @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -145,9 +145,9 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1/rho - v2 = rho_v2/rho - v3 = rho_v3/rho + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -157,7 +157,7 @@ end f2 = rho_v1*v1 + p f3 = rho_v1*v2 f4 = rho_v1*v3 - f5 = (kin_en + gamma*p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + f5 = (kin_en + gamma * p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -170,18 +170,18 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1/rho - v2 = rho_v2/rho - v3 = rho_v3/rho + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en) f1 = rho_v2 - f2 = rho_v2*v1 # - B2*B1 - f3 = rho_v2*v2 + p # + mag_en - B2*B2 - f4 = rho_v2*v3 #- B2*B3 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_v2 * v3 f5 = (kin_en + gamma*p/(gamma - 1))*v2 + 2 * mag_en * vk2_plus[k] - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) set_component!(f, k, f1, f2, f3, f4, f5, equations) @@ -196,7 +196,7 @@ Standard source terms of the multi-ion MHD equations """ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) s = zero(MVector{nvariables(equations), eltype(u)}) @@ -232,22 +232,22 @@ The term is composed of three parts @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) # Compute important averages - B1_avg = 0.5*(B1_ll+B1_rr) - B2_avg = 0.5*(B2_ll+B2_rr) - B3_avg = 0.5*(B3_ll+B3_rr) + B1_avg = 0.5 *(B1_ll + B1_rr) + B2_avg = 0.5 *(B2_ll + B2_rr) + B3_avg = 0.5 *(B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(eltype(u_ll)) for k in eachcomponent(equations) - rho_k = u_ll[(k-1)*5+4] + rho_k = u_ll[3 + (k - 1) * 5 + 1] charge_ratio_ll[k] = rho_k * charge_to_mass[k] total_electron_charge += charge_ratio_ll[k] end @@ -361,8 +361,8 @@ The term is composed of three parts @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 @@ -371,7 +371,7 @@ The term is composed of three parts charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(real(equations)) for k in eachcomponent(equations) - rho_k = u_ll[(k-1)*5+4] + rho_k = u_ll[3 + (k - 1) * 5 + 1] charge_ratio_ll[k] = rho_k * charge_to_mass[k] total_electron_charge += charge_ratio_ll[k] end @@ -465,8 +465,8 @@ This flux (together with the MHD non-conservative term) is consistent in the cas function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll, _ = u_ll - B1_rr, B2_rr, B3_rr, _ = u_rr + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) @@ -474,15 +474,15 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide f = zero(MVector{nvariables(equations), eltype(u_ll)}) # Compute averages for global variables - v1_plus_avg = 0.5*(v1_plus_ll+v1_plus_rr) - v2_plus_avg = 0.5*(v2_plus_ll+v2_plus_rr) - v3_plus_avg = 0.5*(v3_plus_ll+v3_plus_rr) - B1_avg = 0.5*(B1_ll+B1_rr) - B2_avg = 0.5*(B2_ll+B2_rr) - B3_avg = 0.5*(B3_ll+B3_rr) + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5*(mag_norm_ll+mag_norm_rr) + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) if orientation == 1 # Magnetic field components from f^MHD @@ -501,37 +501,37 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll/rho_ll - v2_ll = rho_v2_ll/rho_ll - v3_ll = rho_v3_ll/rho_ll - v1_rr = rho_v1_rr/rho_rr - v2_rr = rho_v2_rr/rho_rr - v3_rr = rho_v3_rr/rho_rr + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 - p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) - p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) - beta_ll = 0.5*rho_ll/p_ll - beta_rr = 0.5*rho_rr/p_rr + p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5*(rho_ll+rho_rr) - rho_mean = ln_mean(rho_ll,rho_rr) - beta_mean = ln_mean(beta_ll,beta_rr) - beta_avg = 0.5*(beta_ll+beta_rr) - p_mean = 0.5*rho_avg/beta_avg - v1_avg = 0.5*(v1_ll+v1_rr) - v2_avg = 0.5*(v2_ll+v2_rr) - v3_avg = 0.5*(v3_ll+v3_rr) - vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) - vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) - vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5*(vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -545,9 +545,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # Ignore orientation since it is always "1" in 1D f1 = rho_mean*v1_avg - f2 = f1*v1_avg + p_mean - f3 = f1*v2_avg - f4 = f1*v3_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components v1_plus_mag_avg = 0.5*(vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) @@ -556,7 +556,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) + - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -577,37 +577,37 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll/rho_ll - v2_ll = rho_v2_ll/rho_ll - v3_ll = rho_v3_ll/rho_ll - v1_rr = rho_v1_rr/rho_rr - v2_rr = rho_v2_rr/rho_rr - v3_rr = rho_v3_rr/rho_rr + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 - p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) - p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) - beta_ll = 0.5*rho_ll/p_ll - beta_rr = 0.5*rho_rr/p_rr + p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5*(rho_ll+rho_rr) - rho_mean = ln_mean(rho_ll,rho_rr) - beta_mean = ln_mean(beta_ll,beta_rr) - beta_avg = 0.5*(beta_ll+beta_rr) - p_mean = 0.5*rho_avg/beta_avg - v1_avg = 0.5*(v1_ll+v1_rr) - v2_avg = 0.5*(v2_ll+v2_rr) - v3_avg = 0.5*(v3_ll+v3_rr) - vel_norm_avg = 0.5*(vel_norm_ll+vel_norm_rr) - vel_dot_mag_avg = 0.5*(vel_dot_mag_ll+vel_dot_mag_rr) - vk1_plus_avg = 0.5*(vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5*(vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5*(vk3_plus_ll[k] + vk3_plus_rr[k]) + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -621,9 +621,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # Ignore orientation since it is always "1" in 1D f1 = rho_mean*v2_avg - f2 = f1*v1_avg - f3 = f1*v2_avg + p_mean - f4 = f1*v3_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_mean + f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components v2_plus_mag_avg = 0.5*(vk2_plus_ll[k] * mag_norm_ll + vk2_plus_rr[k] * mag_norm_rr) @@ -632,7 +632,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::Ide # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) + - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -654,7 +654,7 @@ end # Calculate velocities v_ll = zero(eltype(u_ll)) - v_rr = zero(u_rr[1]) + v_rr = zero(eltype(u_rr)) if orientation == 1 for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u_ll, equations) @@ -696,7 +696,7 @@ Convert conservative variables to primitive """ function cons2prim(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) prim = zero(MVector{nvariables(equations), eltype(u)}) prim[1] = B1 @@ -723,7 +723,7 @@ Convert conservative variables to entropy """ @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) prim = cons2prim(u, equations) entropy = zero(MVector{nvariables(equations), eltype(u)}) @@ -756,7 +756,7 @@ Convert primitive to conservative variables """ @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations - B1, B2, B3, _ = prim + B1, B2, B3 = magnetic_field(prim, equations) cons = zero(MVector{nvariables(equations), eltype(prim)}) cons[1] = B1 @@ -782,7 +782,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! """ @inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3, _ = cons + B1, B2, B3 = magnetic_field(cons, equations) c_f = zero(real(equations)) for k in eachcomponent(equations) @@ -803,9 +803,9 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco b_square = b1^2 + b2^2 + b3^2 if orientation == 1 - c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2))) + c_f = max(c_f, sqrt(0.5 * (a_square + b_square) + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square*b1^2))) else #if orientation == 2 - c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b2^2))) + c_f = max(c_f, sqrt(0.5 * (a_square + b_square) + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square*b2^2))) end end @@ -825,14 +825,12 @@ Routine to compute the Charge-averaged velocities: vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) - rho_k = u[(k-1)*5+4] - rho_v1_k = u[(k-1)*5+5] - rho_v2_k = u[(k-1)*5+6] - rho_v3_k = u[(k-1)*5+7] - total_electron_charge += rho_k * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1_k * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2_k * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3_k * equations.charge_to_mass[k] + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations::IdealMhdMultiIonEquations2D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] end vk1_plus ./= total_electron_charge vk2_plus ./= total_electron_charge @@ -870,6 +868,8 @@ Set the flow variables of component k return u end +magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + @inline function density_product(u, equations::IdealMhdMultiIonEquations2D) prod = one(eltype(u)) for k in eachcomponent(equations) @@ -890,7 +890,7 @@ end Computes the sum of the densities times the sum of the pressures """ @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3, _ = u + B1, B2, B3 = magnetic_field(u, equations) rho_total = zero(real(equations)) p_total = zero(real(equations)) for k in eachcomponent(equations) @@ -902,7 +902,7 @@ Computes the sum of the densities times the sum of the pressures v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) + p = (gamma - 1)*(rho_e - 0.5 * rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) rho_total += rho p_total += p From b144498102e70182780365c5f1143e33146a9840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 10 May 2023 15:45:35 +0200 Subject: [PATCH 028/108] Added tests for multi-ion MHD in 1D and 2D --- .../elixir_mhdmultiion_es_shock_capturing.jl | 70 ------------------- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 4 +- test/test_tree_1d.jl | 3 + test/test_tree_1d_mhdmultiion.jl | 43 ++++++++++++ test/test_tree_2d_mhdmultiion.jl | 35 ++++++++++ test/test_tree_2d_part3.jl | 3 + 7 files changed, 87 insertions(+), 73 deletions(-) delete mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl create mode 100644 test/test_tree_1d_mhdmultiion.jl create mode 100644 test/test_tree_2d_mhdmultiion.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl deleted file mode 100644 index 41a3542efc1..00000000000 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl +++ /dev/null @@ -1,70 +0,0 @@ - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) - -initial_condition = initial_condition_weak_blast_wave - -volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) - -basis = LobattoLegendreBasis(3) - -indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) - -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = 0.0 -coordinates_max = 1.0 -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 0.4) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) - -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) - -stepsize_callback = StepsizeCallback(cfl=0.5) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - stepsize_callback) - - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); -summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 2577d217756..29e92e12df4 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -33,7 +33,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 10 +analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index aab374ecaeb..317b0e3d9e5 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -115,11 +115,11 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 10 +analysis_interval = 100 analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval) -save_solution = SaveSolutionCallback(interval=10, +save_solution = SaveSolutionCallback(interval=100, save_initial_solution=true, save_final_solution=true, solution_variables=cons2prim) diff --git a/test/test_tree_1d.jl b/test/test_tree_1d.jl index 80fc59c6998..dc11fbccfcf 100644 --- a/test/test_tree_1d.jl +++ b/test/test_tree_1d.jl @@ -37,6 +37,9 @@ isdir(outdir) && rm(outdir, recursive=true) # MHD Multicomponent include("test_tree_1d_mhdmulti.jl") + # MHD Multi-ion + include("test_tree_1d_mhdmultiion.jl") + # Compressible Euler with self-gravity include("test_tree_1d_eulergravity.jl") diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl new file mode 100644 index 00000000000..02d40df6187 --- /dev/null +++ b/test/test_tree_1d_mhdmultiion.jl @@ -0,0 +1,43 @@ +module TestExamples1DMHD + +using Test +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_1d_dgsem") + +@testset "MHD Multi-ion" begin + + @trixi_testset "elixir_mhdmultiion_ec_onespecies.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec_onespecies.jl"), + l2 = [4.13046273e-17, 5.47627735e-02, 5.47627735e-02, 5.85364902e-02, 8.15735949e-02, + 5.46480229e-02, 5.46480229e-02, 1.54430906e-01], + linf = [1.11022302e-16, 9.62277600e-02, 9.62277600e-02, 1.07398441e-01, 1.85851486e-01, + 9.41669606e-02, 9.41669606e-02, 4.10966135e-01]) + end + + @trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2 = [4.13046273e-17, 4.41300832e-02, 4.08698259e-02, 1.45921842e-02, 1.46195334e-01, + 1.46189460e-01, 1.47069647e-01, 1.15948953e-01, 4.17156345e-02, 2.95429888e-01, + 2.91864340e-01, 2.90281705e-01, 1.91712252e-01], + linf = [1.11022302e-16, 8.23475323e-02, 8.20044181e-02, 5.26482770e-02, 2.36978475e-01, + 1.78890885e-01, 1.83844973e-01, 3.69223717e-01, 9.49715344e-02, 4.04059325e-01, + 3.53727376e-01, 3.43908646e-01, 3.72557303e-01]) + end + + @trixi_testset "elixir_mhdmultiion_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), + l2 = [4.13046273e-17, 4.34692117e-02, 4.01800240e-02, 1.39798040e-02, 1.45588748e-01, + 1.46145114e-01, 1.47018561e-01, 1.07728669e-01, 4.13841438e-02, 2.95261011e-01, + 2.91827041e-01, 2.90260310e-01, 1.90243105e-01], + linf = [1.11022302e-16, 7.89266630e-02, 7.79256051e-02, 4.76391824e-02, 2.07007992e-01, + 1.79314301e-01, 1.84325683e-01, 3.47578503e-01, 9.30059101e-02, 3.81670634e-01, + 3.53221946e-01, 3.43511206e-01, 3.75916013e-01]) + end + +end + +end # module diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl new file mode 100644 index 00000000000..bd0f20f6040 --- /dev/null +++ b/test/test_tree_2d_mhdmultiion.jl @@ -0,0 +1,35 @@ +module TestExamples2DEulerMulticomponent + +using Test +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") + +@testset "MHD Multi-ion" begin + + @trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2 = [1.56133690e-02, 1.56211211e-02, 2.44289260e-02, 1.17053210e-02, 1.35748661e-01, + 1.35779534e-01, 1.34646112e-01, 1.34813656e-01, 1.93724876e-02, 2.70357315e-01, + 2.70356924e-01, 2.69252524e-01, 1.86315505e-01], + linf = [1.06156769e-01, 1.15019769e-01, 1.32816030e-01, 7.65402322e-02, 2.45518940e-01, + 2.46123607e-01, 1.82733442e-01, 4.24743430e-01, 1.27620999e-01, 4.58874938e-01, + 4.65364246e-01, 3.56983044e-01, 3.94035665e-01]) + end + + @trixi_testset "elixir_mhdmultiion_rotor.jl tspan = (0., 0.001)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_rotor.jl"), + l2 = [8.74074695e-03, 1.52216843e-02, 5.46908589e-06, 4.48801984e-02, 8.64335927e-02, + 8.16206313e-02, 2.79217739e-03, 1.30650336e-01, 4.48808155e-02, 8.64347180e-02, + 8.16273475e-02, 5.58430809e-03, 1.30652670e-01], + linf = [1.22933218e-01, 2.25300270e-01, 2.89189052e-05, 1.03135219e+00, 3.57199056e+00, + 3.36455287e+00, 1.44792528e-02, 4.94065455e+00, 1.03150012e+00, 3.57211417e+00, 3.36511058e+00, 2.88397185e-02, 4.94152909e+00], + tspan = (0., 0.001)) + end + +end + +end # module diff --git a/test/test_tree_2d_part3.jl b/test/test_tree_2d_part3.jl index 981b7bc9414..a8847186fc7 100644 --- a/test/test_tree_2d_part3.jl +++ b/test/test_tree_2d_part3.jl @@ -19,6 +19,9 @@ isdir(outdir) && rm(outdir, recursive=true) # MHD Multicomponent include("test_tree_2d_mhdmulti.jl") + # MHD Multi-ion + include("test_tree_2d_mhdmultiion.jl") + # Lattice-Boltzmann include("test_tree_2d_lbm.jl") From 980f7f6d4901bb60919f609c7a19c4886463c5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 11 May 2023 09:45:26 +0200 Subject: [PATCH 029/108] Attempt to improve coverage: added new 1D test and removed density_product functions (not really used) --- .../elixir_mhdmultiion_es_shock_capturing.jl | 70 +++++++++++++++++++ src/equations/ideal_mhd_multiion_1d.jl | 8 --- src/equations/ideal_mhd_multiion_2d.jl | 8 --- test/test_tree_1d_mhdmultiion.jl | 10 +++ 4 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl new file mode 100644 index 00000000000..41a3542efc1 --- /dev/null +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -0,0 +1,70 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) + +basis = LobattoLegendreBasis(3) + +indicator_sc = IndicatorHennemannGassner(equations, basis, + alpha_max=0.5, + alpha_min=0.001, + alpha_smooth=true, + variable=density) +volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; + volume_flux_dg=volume_flux, + volume_flux_fv=surface_flux) + +solver = DGSEM(basis, surface_flux, volume_integral) + +coordinates_min = 0.0 +coordinates_max = 1.0 +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level=4, + n_cells_max=10_000) + + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms=source_terms_standard) + + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval=analysis_interval) +alive_callback = AliveCallback(analysis_interval=analysis_interval) + +save_solution = SaveSolutionCallback(interval=100, + save_initial_solution=true, + save_final_solution=true, + solution_variables=cons2prim) + +stepsize_callback = StepsizeCallback(cfl=0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), + dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep=false, callback=callbacks); +summary_callback() # print the timer summary diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index a58d371c3f6..7cddf9c9934 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -644,14 +644,6 @@ end magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) -@inline function density_product(u, equations::IdealMhdMultiIonEquations1D) - prod = one(eltype(u)) - for k in eachcomponent(equations) - prod *= u[3 + (k - 1) * 5 + 1] - end - return prod -end - @inline function density(u, equations::IdealMhdMultiIonEquations1D) rho = zero(eltype(u)) for k in eachcomponent(equations) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 17f39c9e55b..1496139c191 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -870,14 +870,6 @@ end magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) -@inline function density_product(u, equations::IdealMhdMultiIonEquations2D) - prod = one(eltype(u)) - for k in eachcomponent(equations) - prod *= u[3 + (k - 1) * 5 + 1] - end - return prod -end - @inline function density(u, equations::IdealMhdMultiIonEquations2D) rho = zero(real(equations)) for k in eachcomponent(equations) diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl index 02d40df6187..c886b17dc7c 100644 --- a/test/test_tree_1d_mhdmultiion.jl +++ b/test/test_tree_1d_mhdmultiion.jl @@ -38,6 +38,16 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_1 3.53221946e-01, 3.43511206e-01, 3.75916013e-01]) end + @trixi_testset "elixir_mhdmultiion_es_shock_capturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es_shock_capturing.jl"), + l2 = [4.13046273e-17, 4.34327035e-02, 4.01429579e-02, 1.39648331e-02, 1.45589699e-01, + 1.46145036e-01, 1.47013130e-01, 1.07647870e-01, 4.13842626e-02, 2.95252636e-01, + 2.91824474e-01, 2.90263048e-01, 1.90199794e-01], + linf = [1.11022302e-16, 7.86144728e-02, 7.75970804e-02, 4.75320603e-02, 2.07019087e-01, + 1.79245486e-01, 1.84254005e-01, 3.47166288e-01, 9.16953877e-02, 3.81637525e-01, + 3.53188856e-01, 3.43474263e-01, 3.75932899e-01]) + end + end end # module From 72384e84fee1536ba43d1543fdd8ab1be0f730f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 11 May 2023 10:00:55 +0200 Subject: [PATCH 030/108] Modified multi-ion rotor test to improve coverage --- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 17 +++++++++-------- test/test_tree_2d_mhdmultiion.jl | 11 ++++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index 317b0e3d9e5..e82d74e4fce 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -125,14 +125,16 @@ save_solution = SaveSolutionCallback(interval=100, solution_variables=cons2prim) stepsize_callback = StepsizeCallback(cfl=0.5) -amr_indicator = IndicatorHennemannGassner(semi, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=false, - variable=density_pressure) -amr_controller = ControllerThreeLevel(semi, amr_indicator, + +amr_indicator = IndicatorLöhner(semi, + variable=density) + +amr_controller = ControllerThreeLevelCombined(semi, amr_indicator,indicator_sc, base_level=4, - max_level =7, max_threshold=0.01) + med_level =5, med_threshold=0.02, # med_level = current level + max_level =7, max_threshold=0.04, + max_threshold_secondary=0.2) + amr_callback = AMRCallback(semi, amr_controller, interval=6, adapt_initial_condition=true, @@ -148,7 +150,6 @@ callbacks = CallbackSet(summary_callback, save_restart, stepsize_callback) - ############################################################################### # run the simulation diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index bd0f20f6040..67fb6a6e001 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -22,11 +22,12 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 @trixi_testset "elixir_mhdmultiion_rotor.jl tspan = (0., 0.001)" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_rotor.jl"), - l2 = [8.74074695e-03, 1.52216843e-02, 5.46908589e-06, 4.48801984e-02, 8.64335927e-02, - 8.16206313e-02, 2.79217739e-03, 1.30650336e-01, 4.48808155e-02, 8.64347180e-02, - 8.16273475e-02, 5.58430809e-03, 1.30652670e-01], - linf = [1.22933218e-01, 2.25300270e-01, 2.89189052e-05, 1.03135219e+00, 3.57199056e+00, - 3.36455287e+00, 1.44792528e-02, 4.94065455e+00, 1.03150012e+00, 3.57211417e+00, 3.36511058e+00, 2.88397185e-02, 4.94152909e+00], + l2 = [9.10689060e-03, 1.57109974e-02, 5.47502000e-06, 4.33887866e-02, 6.85503869e-02, + 6.44021766e-02, 2.79487163e-03, 7.85539922e-02, 4.33883209e-02, 6.85496075e-02, + 6.44066193e-02, 5.58969701e-03, 7.85504216e-02], + linf = [1.47204796e-01, 2.33759231e-01, 2.89189051e-05, 1.06452623e+00, 3.36709456e+00, + 2.93566426e+00, 1.53123364e-02, 3.99872907e+00, 1.06455108e+00, 3.36725655e+00, + 2.93570704e+00, 3.05339471e-02, 3.99892281e+00], tspan = (0., 0.001)) end From 12606b251efdd0ce86f1275b4d801cd58a9db3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 28 Jun 2023 15:59:32 +0200 Subject: [PATCH 031/108] Fixed bugs in multi-ion MHD source term --- src/equations/ideal_mhd_multiion_1d.jl | 6 +++--- src/equations/ideal_mhd_multiion_2d.jl | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 7cddf9c9934..892b39188ed 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -178,9 +178,9 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) v2_diff = v2_plus - v2 v3_diff = v3_plus - v3 r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff - B2) - s3 = r_rho * (v3_diff * B1 - v1_diff - B3) - s4 = r_rho * (v1_diff * B2 - v2_diff - B1) + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 set_component!(s, k, 0, s2, s3, s4, s5, equations) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 1496139c191..04e0f1d4b83 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -210,9 +210,9 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) v2_diff = v2_plus - v2 v3_diff = v3_plus - v3 r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff - B2) - s3 = r_rho * (v3_diff * B1 - v1_diff - B3) - s4 = r_rho * (v1_diff * B2 - v2_diff - B1) + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) s5 = v1 * s2 + v2 * s3 + v3 * s4 set_component!(s, k, 0, s2, s3, s4, s5, equations) From 10b74b1e7d59d7baa298c5884335d15b21a44e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 17 Oct 2023 16:22:37 +0200 Subject: [PATCH 032/108] Added electron pressure terms --- src/Trixi.jl | 1 + src/equations/ideal_mhd_multiion_2d.jl | 56 ++++++++++++++++---------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 43e75483e24..51e9909a932 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -215,6 +215,7 @@ export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, enstrophy export lake_at_rest_error export ncomponents, eachcomponent +export get_component export TreeMesh, StructuredMesh, UnstructuredMesh2D, P4estMesh, T8codeMesh diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 04e0f1d4b83..dab23f64049 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -10,20 +10,23 @@ The ideal compressible multi-ion MHD equations in two space dimensions. """ -mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealMhdMultiIonEquations{2, NVARS, NCOMP} +mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real, ElectronPressure} <: AbstractIdealMhdMultiIonEquations{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 - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, RealT}, - charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}( + gammas::SVector{NCOMP, RealT}, + charge_to_mass::SVector{NCOMP, RealT}, + electron_pressure::ElectronPressure) where {NVARS, NCOMP, RealT<:Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - new(gammas, charge_to_mass) + new(gammas, charge_to_mass, electron_pressure) end end -function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass) +function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, electron_pressure = electron_pressure_zero) _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) @@ -34,7 +37,7 @@ function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass) __gammas = SVector(map(RealT, _gammas)) __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) + return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, __charge_to_mass, electron_pressure) end @inline Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT @@ -221,12 +224,20 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) return SVector(s) end +""" + electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) +Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. +""" +function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) + return zero(u[1]) +end + """ Total entropy-conserving non-conservative two-point "flux"" as described in - Rueda-Ramírez et al. (2023) The term is composed of three parts * The Powell term: Implemented -* The MHD term: Implemented without the electron pressure (TODO). +* The MHD term: Implemented * The "term 3": Implemented """ @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @@ -243,6 +254,10 @@ The term is composed of three parts mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + # Mean electron pressure + pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + + equations.electron_pressure(u_rr, equations)) + # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(eltype(u_ll)) @@ -267,11 +282,10 @@ The term is composed of three parts for k in eachcomponent(equations) # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) - f5 = 0 # TODO: Add "average" of electron pressure! charge_ratio_ll[k] * pe_mean + f5 = vk1_plus_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -311,11 +325,10 @@ The term is composed of three parts for k in eachcomponent(equations) # Compute term 2 (MHD) - # TODO: Add electron pressure term f2 = charge_ratio_ll[k] * (- B2_avg * B1_avg) - f3 = charge_ratio_ll[k] * (- B2_avg * B2_avg + 0.5 * mag_norm_avg) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) f4 = charge_ratio_ll[k] * (- B2_avg * B3_avg) - f5 = 0 # TODO: Add average of electron pressure! charge_ratio_ll[k] * pe_mean + f5 = vk2_plus_ll[k] * pe_mean # Compute term 3 (only needed for NCOMP>1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] @@ -354,8 +367,8 @@ end """ Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages The term is composed of three parts -* The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". -* The MHD term: Implemented without the electron pressure (TODO). +* The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". +* The MHD term: Implemented * The "term 3": Implemented """ @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) @@ -367,6 +380,9 @@ The term is composed of three parts # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + # Electron pressure + pe_rr = equations.electron_pressure(u_rr, equations) + # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) total_electron_charge = zero(real(equations)) @@ -390,11 +406,10 @@ The term is composed of three parts f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) - f5 = 0 # TODO! charge_ratio_ll[k] * pe_mean + f5 = vk1_plus_ll[k] * pe_rr # Compute term 3 (only needed for NCOMP>1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] @@ -422,11 +437,10 @@ The term is composed of three parts for k in eachcomponent(equations) # Compute term 2 (MHD) - # TODO: Add electron pressure term f2 = charge_ratio_ll[k] * (- B2_rr * B1_rr) - f3 = charge_ratio_ll[k] * (- B2_rr * B2_rr + 0.5 * mag_norm_rr) # + pe_mean) + f3 = charge_ratio_ll[k] * (- B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) f4 = charge_ratio_ll[k] * (- B2_rr * B3_rr) - f5 = 0 # TODO! charge_ratio_ll[k] * pe_mean + f5 = vk2_plus_ll[k] * pe_rr # Compute term 3 (only needed for NCOMP>1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] From 1ba20926010e7882e5ecbc4d45999558a859dea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 18 Oct 2023 17:11:19 +0200 Subject: [PATCH 033/108] First attempt to enable save solution with time intervals for SimpleIntegratorSSP --- Project.toml | 1 + .../elixir_euler_shockcapturing_subcell.jl | 2 +- src/Trixi.jl | 1 + src/time_integration/methods_SSP.jl | 26 ++++++++++++++----- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index d318389a6d2..a61928ca33e 100644 --- a/Project.toml +++ b/Project.toml @@ -42,6 +42,7 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" TriplotRecipes = "808ab39a-a642-4abf-81ff-4cb34ebbffa3" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" [weakdeps] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" diff --git a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl index 6b69e4db563..2b9dd466f0d 100644 --- a/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl +++ b/examples/tree_2d_dgsem/elixir_euler_shockcapturing_subcell.jl @@ -68,7 +68,7 @@ analysis_callback = AnalysisCallback(semi, interval=analysis_interval) alive_callback = AliveCallback(analysis_interval=analysis_interval) -save_solution = SaveSolutionCallback(interval=100, +save_solution = SaveSolutionCallback(dt=0.1, save_initial_solution=true, save_final_solution=true, solution_variables=cons2prim) diff --git a/src/Trixi.jl b/src/Trixi.jl index b65d03e7975..67621ad8fce 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -70,6 +70,7 @@ using TriplotBase: TriplotBase using TriplotRecipes: DGTriPseudocolor @reexport using SimpleUnPack: @unpack using SimpleUnPack: @pack! +using DataStructures: BinaryHeap, FasterForward # finite difference SBP operators using SummationByPartsOperators: AbstractDerivativeOperator, diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index a0ed889968a..8fb58213f2b 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -50,17 +50,19 @@ struct SimpleSSPRK33{StageCallbacks} <: SimpleAlgorithmSSP end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L1 -mutable struct SimpleIntegratorSSPOptions{Callback} +mutable struct SimpleIntegratorSSPOptions{Callback, TStops} callback::Callback # callbacks; used in Trixi adaptive::Bool # whether the algorithm is adaptive; ignored dtmax::Float64 # ignored maxiters::Int # maximal number of time steps - tstops::Vector{Float64} # tstops from https://diffeq.sciml.ai/v6.8/basics/common_solver_opts/#Output-Control-1; ignored + tstops::TStops # tstops from https://diffeq.sciml.ai/v6.8/basics/common_solver_opts/#Output-Control-1; ignored end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) - SimpleIntegratorSSPOptions{typeof(callback)}(callback, false, Inf, maxiters, - [last(tspan)]) + tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) + push!(tstops_internal, last(tspan)) + SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, false, Inf, maxiters, + tstops_internal) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 @@ -73,6 +75,7 @@ mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, du::uType r0::uType t::RealT + tdir::RealT dt::RealT # current time step dtcache::RealT # ignored iter::Int # current number of time steps (iteration) @@ -84,6 +87,16 @@ mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, finalstep::Bool # added for convenience end +""" + add_tstop!(integrator::SimpleIntegratorSSP, t) +Add +""" +function add_tstop!(integrator::SimpleIntegratorSSP, t) + integrator.tdir * (t - integrator.t) < zero(integrator.t) && + error("Tried to add a tstop that is behind the current time. This is strictly forbidden") + push!(integrator.opts.tstops, integrator.tdir * t) +end + # Forward integrator.stats.naccept to integrator.iter (see GitHub PR#771) function Base.getproperty(integrator::SimpleIntegratorSSP, field::Symbol) if field === :stats @@ -108,8 +121,9 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; du = similar(u) r0 = similar(u) t = first(ode.tspan) + tdir = sign(ode.tspan[end] - ode.tspan[1]) iter = 0 - integrator = SimpleIntegratorSSP(u, du, r0, t, dt, zero(dt), iter, ode.p, + integrator = SimpleIntegratorSSP(u, du, r0, t, tdir, dt, zero(dt), iter, ode.p, (prob = ode,), ode.f, alg, SimpleIntegratorSSPOptions(callback, ode.tspan; kwargs...), false) @@ -216,7 +230,7 @@ end # stop the time integration function terminate!(integrator::SimpleIntegratorSSP) integrator.finalstep = true - empty!(integrator.opts.tstops) + #empty!(integrator.opts.tstops) end # used for AMR From e05363d74ac684fce05b944029e62872b30939af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 19 Oct 2023 09:44:15 +0200 Subject: [PATCH 034/108] Importing `add_tstop!` --- src/Trixi.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index 67621ad8fce..62d66f62b4d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -37,7 +37,7 @@ using SciMLBase: CallbackSet, DiscreteCallback, import SciMLBase: get_du, get_tmp_cache, u_modified!, AbstractODEIntegrator, init, step!, check_error, get_proposed_dt, set_proposed_dt!, - terminate!, remake + terminate!, remake, add_tstop! using CodeTracking: CodeTracking using ConstructionBase: ConstructionBase using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect From 64e97843e51dc436e889aebcf46f669242f20b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 19 Oct 2023 11:10:31 +0200 Subject: [PATCH 035/108] First working version of SimpleIntegratorSSP with SaveSolutionCallback using time intervals --- Project.toml | 1 + src/Trixi.jl | 3 ++- src/time_integration/methods_SSP.jl | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index a61928ca33e..28a5b1d66d2 100644 --- a/Project.toml +++ b/Project.toml @@ -43,6 +43,7 @@ Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" TriplotRecipes = "808ab39a-a642-4abf-81ff-4cb34ebbffa3" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" [weakdeps] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" diff --git a/src/Trixi.jl b/src/Trixi.jl index 62d66f62b4d..530b61d2ac5 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -37,7 +37,8 @@ using SciMLBase: CallbackSet, DiscreteCallback, import SciMLBase: get_du, get_tmp_cache, u_modified!, AbstractODEIntegrator, init, step!, check_error, get_proposed_dt, set_proposed_dt!, - terminate!, remake, add_tstop! + terminate!, remake, add_tstop!, has_tstop, first_tstop +using OrdinaryDiffEq: modify_dt_for_tstops! using CodeTracking: CodeTracking using ConstructionBase: ConstructionBase using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 8fb58213f2b..ac70e3c870b 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -60,7 +60,7 @@ end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) - push!(tstops_internal, last(tspan)) + push!(tstops_internal, 2 * last(tspan)) SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, false, Inf, maxiters, tstops_internal) end @@ -85,6 +85,8 @@ mutable struct SimpleIntegratorSSP{RealT <: Real, uType, Params, Sol, F, Alg, alg::Alg opts::SimpleIntegratorSSPOptions finalstep::Bool # added for convenience + dtchangeable::Bool + force_stepfail::Bool end """ @@ -94,9 +96,15 @@ Add function add_tstop!(integrator::SimpleIntegratorSSP, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && error("Tried to add a tstop that is behind the current time. This is strictly forbidden") + if length(integrator.opts.tstops) > 1 + pop!(integrator.opts.tstops) + end push!(integrator.opts.tstops, integrator.tdir * t) end +has_tstop(integrator::SimpleIntegratorSSP) = !isempty(integrator.opts.tstops) +first_tstop(integrator::SimpleIntegratorSSP) = first(integrator.opts.tstops) + # Forward integrator.stats.naccept to integrator.iter (see GitHub PR#771) function Base.getproperty(integrator::SimpleIntegratorSSP, field::Symbol) if field === :stats @@ -126,7 +134,7 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; integrator = SimpleIntegratorSSP(u, du, r0, t, tdir, dt, zero(dt), iter, ode.p, (prob = ode,), ode.f, alg, SimpleIntegratorSSPOptions(callback, ode.tspan; - kwargs...), false) + kwargs...), false, true, false) # resize container resize!(integrator.p, nelements(integrator.p.solver, integrator.p.cache)) @@ -169,6 +177,8 @@ function solve!(integrator::SimpleIntegratorSSP) terminate!(integrator) end + modify_dt_for_tstops!(integrator) + @. integrator.r0 = integrator.u for stage in eachindex(alg.c) t_stage = integrator.t + integrator.dt * alg.c[stage] @@ -190,7 +200,7 @@ function solve!(integrator::SimpleIntegratorSSP) integrator.iter += 1 integrator.t += integrator.dt - + # handle callbacks if callbacks isa CallbackSet for cb in callbacks.discrete_callbacks From 05fcaaa8d8d7d6f44dfd8a307729b2242d37f3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 19 Oct 2023 11:16:06 +0200 Subject: [PATCH 036/108] Improved formatting and updated reference solution for test --- src/time_integration/methods_SSP.jl | 13 ++++++++----- test/test_tree_2d_euler.jl | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index ac70e3c870b..424c25ec398 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -61,8 +61,10 @@ end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) push!(tstops_internal, 2 * last(tspan)) - SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, false, Inf, maxiters, - tstops_internal) + SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, + false, Inf, + maxiters, + tstops_internal) end # This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77 @@ -96,7 +98,7 @@ Add function add_tstop!(integrator::SimpleIntegratorSSP, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && error("Tried to add a tstop that is behind the current time. This is strictly forbidden") - if length(integrator.opts.tstops) > 1 + if length(integrator.opts.tstops) > 1 pop!(integrator.opts.tstops) end push!(integrator.opts.tstops, integrator.tdir * t) @@ -134,7 +136,8 @@ function solve(ode::ODEProblem, alg = SimpleSSPRK33()::SimpleAlgorithmSSP; integrator = SimpleIntegratorSSP(u, du, r0, t, tdir, dt, zero(dt), iter, ode.p, (prob = ode,), ode.f, alg, SimpleIntegratorSSPOptions(callback, ode.tspan; - kwargs...), false, true, false) + kwargs...), + false, true, false) # resize container resize!(integrator.p, nelements(integrator.p.solver, integrator.p.cache)) @@ -200,7 +203,7 @@ function solve!(integrator::SimpleIntegratorSSP) integrator.iter += 1 integrator.t += integrator.dt - + # handle callbacks if callbacks isa CallbackSet for cb in callbacks.discrete_callbacks diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 1b8a261a60d..e5db2764eaa 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -65,8 +65,8 @@ EXAMPLES_DIR = pkgdir(Trixi, "examples", "tree_2d_dgsem") @trixi_testset "elixir_euler_shockcapturing_subcell.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_euler_shockcapturing_subcell.jl"), - l2 = [0.08508147906199143, 0.04510299017724501, 0.045103019801950375, 0.6930704343869766], - linf = [0.31123546471463326, 0.5616274869594462, 0.5619692712224448, 2.88670199345138]) + l2 = [0.08508152653623638, 0.04510301725066843, 0.04510304668512745, 0.6930705064715306], + linf = [0.31136518019691406, 0.5617651935473419, 0.5621200790240503, 2.8866869108596056]) end @trixi_testset "elixir_euler_blast_wave.jl" begin From 71f5c7ad348efe48c10b4a79f505645c0fe9a3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 19 Oct 2023 12:48:21 +0200 Subject: [PATCH 037/108] Modified initialization of tstops to ensure a stop at the end of the simulation --- src/time_integration/methods_SSP.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 424c25ec398..7865e1d0963 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -60,6 +60,7 @@ end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) + push!(tstops_internal, last(tspan)) push!(tstops_internal, 2 * last(tspan)) SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, false, Inf, From df34188653685d968dee8c8a8651a404a1e2d354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 11:44:54 +0200 Subject: [PATCH 038/108] Added missing docstring --- src/time_integration/methods_SSP.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 7865e1d0963..effe5a85de5 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -94,7 +94,7 @@ end """ add_tstop!(integrator::SimpleIntegratorSSP, t) -Add +Add a time stop during the time integration process. """ function add_tstop!(integrator::SimpleIntegratorSSP, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && From d04fd98125dee4ff54f544ecdc2c7ce504c8f98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 12:02:24 +0200 Subject: [PATCH 039/108] Removed OrdinaryDiffEq from Trixi's dependencies --- Project.toml | 1 - src/Trixi.jl | 2 +- src/time_integration/methods_SSP.jl | 24 ++++++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 28a5b1d66d2..a61928ca33e 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,6 @@ Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" TriplotRecipes = "808ab39a-a642-4abf-81ff-4cb34ebbffa3" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" [weakdeps] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" diff --git a/src/Trixi.jl b/src/Trixi.jl index 530b61d2ac5..ea96ad694b4 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -38,7 +38,7 @@ import SciMLBase: get_du, get_tmp_cache, u_modified!, AbstractODEIntegrator, init, step!, check_error, get_proposed_dt, set_proposed_dt!, terminate!, remake, add_tstop!, has_tstop, first_tstop -using OrdinaryDiffEq: modify_dt_for_tstops! + using CodeTracking: CodeTracking using ConstructionBase: ConstructionBase using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index effe5a85de5..f13a8b84ac8 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -247,6 +247,30 @@ function terminate!(integrator::SimpleIntegratorSSP) #empty!(integrator.opts.tstops) end +""" + modify_dt_for_tstops!(integrator::SimpleIntegratorSSP) +Modify the time-step size to match the time stops specified in integrator.opts.tstops. +To avoid adding OrdinaryDiffEq to Trixi's dependencies, this routine is a copy of +https://github.com/SciML/OrdinaryDiffEq.jl/blob/d76335281c540ee5a6d1bd8bb634713e004f62ee/src/integrators/integrator_utils.jl#L38-L54 +""" +function modify_dt_for_tstops!(integrator::SimpleIntegratorSSP) + if has_tstop(integrator) + tdir_t = integrator.tdir * integrator.t + tdir_tstop = first_tstop(integrator) + if integrator.opts.adaptive + integrator.dt = integrator.tdir * + min(abs(integrator.dt), abs(tdir_tstop - tdir_t)) # step! to the end + elseif iszero(integrator.dtcache) && integrator.dtchangeable + integrator.dt = integrator.tdir * abs(tdir_tstop - tdir_t) + elseif integrator.dtchangeable && !integrator.force_stepfail + # always try to step! with dtcache, but lower if a tstop + # however, if force_stepfail then don't set to dtcache, and no tstop worry + integrator.dt = integrator.tdir * + min(abs(integrator.dtcache), abs(tdir_tstop - tdir_t)) # step! to the end + end + end +end + # used for AMR function Base.resize!(integrator::SimpleIntegratorSSP, new_size) resize!(integrator.u, new_size) From 7aa515b5ca79a237067360fb454d1f19defe0041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 12:24:03 +0200 Subject: [PATCH 040/108] Empty tstops BinaryHeap during the call to `terminate!(integrator::SimpleIntegratorSSP)` --- src/time_integration/methods_SSP.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 09d4e91a434..2b598e1ae3b 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -249,7 +249,7 @@ end # stop the time integration function terminate!(integrator::SimpleIntegratorSSP) integrator.finalstep = true - #empty!(integrator.opts.tstops) + extract_all!(tstops_internal) end """ From 4322f5b53ec6b56c96114405a8f82553d8b335e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 13:05:12 +0200 Subject: [PATCH 041/108] Fixed bug and added explanatory comments --- src/Trixi.jl | 2 +- src/time_integration/methods_SSP.jl | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index aa947d00510..dd9fda5d324 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -71,7 +71,7 @@ using TriplotBase: TriplotBase using TriplotRecipes: DGTriPseudocolor @reexport using SimpleUnPack: @unpack using SimpleUnPack: @pack! -using DataStructures: BinaryHeap, FasterForward +using DataStructures: BinaryHeap, FasterForward, extract_all! # finite difference SBP operators using SummationByPartsOperators: AbstractDerivativeOperator, diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index 2b598e1ae3b..2234293a1ed 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -65,7 +65,10 @@ end function SimpleIntegratorSSPOptions(callback, tspan; maxiters = typemax(Int), kwargs...) tstops_internal = BinaryHeap{eltype(tspan)}(FasterForward()) + # We add last(tspan) to make sure that the time integration stops at the end time push!(tstops_internal, last(tspan)) + # We add 2 * last(tspan) because add_tstop!(integrator, t) is only called by DiffEqCallbacks.jl if tstops contains a time that is larger than t + # (https://github.com/SciML/DiffEqCallbacks.jl/blob/025dfe99029bd0f30a2e027582744528eb92cd24/src/iterative_and_periodic.jl#L92) push!(tstops_internal, 2 * last(tspan)) SimpleIntegratorSSPOptions{typeof(callback), typeof(tstops_internal)}(callback, false, Inf, @@ -99,11 +102,14 @@ end """ add_tstop!(integrator::SimpleIntegratorSSP, t) -Add a time stop during the time integration process. +Add a time stop during the time integration process. +This function is called after the periodic SaveSolutionCallback to specify the next stop to save the solution. """ function add_tstop!(integrator::SimpleIntegratorSSP, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && error("Tried to add a tstop that is behind the current time. This is strictly forbidden") + # We need to remove the first entry of tstops when a new entry is added. + # Otherwise, the simulation gets stuck at the previous tstop and dt is adjusted to zero. if length(integrator.opts.tstops) > 1 pop!(integrator.opts.tstops) end @@ -226,6 +232,10 @@ function solve!(integrator::SimpleIntegratorSSP) end end + # Empty the tstops array. + # This cannot be done in terminate!(integrator::SimpleIntegratorSSP) because DiffEqCallbacks.PeriodicCallbackAffect would return at error. + extract_all!(integrator.opts.tstops) + for stage_callback in alg.stage_callbacks finalize_callback(stage_callback, integrator.p) end @@ -249,7 +259,6 @@ end # stop the time integration function terminate!(integrator::SimpleIntegratorSSP) integrator.finalstep = true - extract_all!(tstops_internal) end """ From 772a3889711b82cddaa5ae2e17a851a233e74499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 23 Oct 2023 15:03:55 +0200 Subject: [PATCH 042/108] Updated Project.toml --- Project.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 34ddd3e4a76..2deb14217a2 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.5.47-pre" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" EllipsisNotation = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" @@ -42,7 +43,6 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3" TriplotRecipes = "808ab39a-a642-4abf-81ff-4cb34ebbffa3" -DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" [weakdeps] Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" @@ -53,6 +53,7 @@ TrixiMakieExt = "Makie" [compat] CodeTracking = "1.0.5" ConstructionBase = "1.3" +DataStructures = "0.18.15" DiffEqCallbacks = "2.25" EllipsisNotation = "1.0" FillArrays = "0.13.2, 1" From 83f89b634f67f5c7900a6c0318069b83c6878597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:11:35 +0100 Subject: [PATCH 043/108] format --- test/test_tree_1d_mhdmultiion.jl | 91 ++++++++++++++++++-------------- test/test_tree_2d_mhdmultiion.jl | 50 ++++++++++-------- 2 files changed, 80 insertions(+), 61 deletions(-) diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl index c886b17dc7c..c6b46b55c73 100644 --- a/test/test_tree_1d_mhdmultiion.jl +++ b/test/test_tree_1d_mhdmultiion.jl @@ -9,45 +9,58 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_1d_dgsem") @testset "MHD Multi-ion" begin + @trixi_testset "elixir_mhdmultiion_ec_onespecies.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec_onespecies.jl"), + l2=[4.13046273e-17, 5.47627735e-02, 5.47627735e-02, + 5.85364902e-02, 8.15735949e-02, + 5.46480229e-02, 5.46480229e-02, 1.54430906e-01], + linf=[1.11022302e-16, 9.62277600e-02, 9.62277600e-02, + 1.07398441e-01, 1.85851486e-01, + 9.41669606e-02, 9.41669606e-02, 4.10966135e-01]) + end - @trixi_testset "elixir_mhdmultiion_ec_onespecies.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec_onespecies.jl"), - l2 = [4.13046273e-17, 5.47627735e-02, 5.47627735e-02, 5.85364902e-02, 8.15735949e-02, - 5.46480229e-02, 5.46480229e-02, 1.54430906e-01], - linf = [1.11022302e-16, 9.62277600e-02, 9.62277600e-02, 1.07398441e-01, 1.85851486e-01, - 9.41669606e-02, 9.41669606e-02, 4.10966135e-01]) - end - - @trixi_testset "elixir_mhdmultiion_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), - l2 = [4.13046273e-17, 4.41300832e-02, 4.08698259e-02, 1.45921842e-02, 1.46195334e-01, - 1.46189460e-01, 1.47069647e-01, 1.15948953e-01, 4.17156345e-02, 2.95429888e-01, - 2.91864340e-01, 2.90281705e-01, 1.91712252e-01], - linf = [1.11022302e-16, 8.23475323e-02, 8.20044181e-02, 5.26482770e-02, 2.36978475e-01, - 1.78890885e-01, 1.83844973e-01, 3.69223717e-01, 9.49715344e-02, 4.04059325e-01, - 3.53727376e-01, 3.43908646e-01, 3.72557303e-01]) - end - - @trixi_testset "elixir_mhdmultiion_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), - l2 = [4.13046273e-17, 4.34692117e-02, 4.01800240e-02, 1.39798040e-02, 1.45588748e-01, - 1.46145114e-01, 1.47018561e-01, 1.07728669e-01, 4.13841438e-02, 2.95261011e-01, - 2.91827041e-01, 2.90260310e-01, 1.90243105e-01], - linf = [1.11022302e-16, 7.89266630e-02, 7.79256051e-02, 4.76391824e-02, 2.07007992e-01, - 1.79314301e-01, 1.84325683e-01, 3.47578503e-01, 9.30059101e-02, 3.81670634e-01, - 3.53221946e-01, 3.43511206e-01, 3.75916013e-01]) - end - - @trixi_testset "elixir_mhdmultiion_es_shock_capturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es_shock_capturing.jl"), - l2 = [4.13046273e-17, 4.34327035e-02, 4.01429579e-02, 1.39648331e-02, 1.45589699e-01, - 1.46145036e-01, 1.47013130e-01, 1.07647870e-01, 4.13842626e-02, 2.95252636e-01, - 2.91824474e-01, 2.90263048e-01, 1.90199794e-01], - linf = [1.11022302e-16, 7.86144728e-02, 7.75970804e-02, 4.75320603e-02, 2.07019087e-01, - 1.79245486e-01, 1.84254005e-01, 3.47166288e-01, 9.16953877e-02, 3.81637525e-01, - 3.53188856e-01, 3.43474263e-01, 3.75932899e-01]) - end - -end + @trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[4.13046273e-17, 4.41300832e-02, 4.08698259e-02, + 1.45921842e-02, 1.46195334e-01, + 1.46189460e-01, 1.47069647e-01, 1.15948953e-01, + 4.17156345e-02, 2.95429888e-01, + 2.91864340e-01, 2.90281705e-01, 1.91712252e-01], + linf=[1.11022302e-16, 8.23475323e-02, 8.20044181e-02, + 5.26482770e-02, 2.36978475e-01, + 1.78890885e-01, 1.83844973e-01, 3.69223717e-01, + 9.49715344e-02, 4.04059325e-01, + 3.53727376e-01, 3.43908646e-01, 3.72557303e-01]) + end + + @trixi_testset "elixir_mhdmultiion_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), + l2=[4.13046273e-17, 4.34692117e-02, 4.01800240e-02, + 1.39798040e-02, 1.45588748e-01, + 1.46145114e-01, 1.47018561e-01, 1.07728669e-01, + 4.13841438e-02, 2.95261011e-01, + 2.91827041e-01, 2.90260310e-01, 1.90243105e-01], + linf=[1.11022302e-16, 7.89266630e-02, 7.79256051e-02, + 4.76391824e-02, 2.07007992e-01, + 1.79314301e-01, 1.84325683e-01, 3.47578503e-01, + 9.30059101e-02, 3.81670634e-01, + 3.53221946e-01, 3.43511206e-01, 3.75916013e-01]) + end + + @trixi_testset "elixir_mhdmultiion_es_shock_capturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_mhdmultiion_es_shock_capturing.jl"), + l2=[4.13046273e-17, 4.34327035e-02, 4.01429579e-02, + 1.39648331e-02, 1.45589699e-01, + 1.46145036e-01, 1.47013130e-01, 1.07647870e-01, + 4.13842626e-02, 2.95252636e-01, + 2.91824474e-01, 2.90263048e-01, 1.90199794e-01], + linf=[1.11022302e-16, 7.86144728e-02, 7.75970804e-02, + 4.75320603e-02, 2.07019087e-01, + 1.79245486e-01, 1.84254005e-01, 3.47166288e-01, + 9.16953877e-02, 3.81637525e-01, + 3.53188856e-01, 3.43474263e-01, 3.75932899e-01]) + end +end end # module diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index 67fb6a6e001..2a4ad3de221 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -9,28 +9,34 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2d_dgsem") @testset "MHD Multi-ion" begin - - @trixi_testset "elixir_mhdmultiion_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), - l2 = [1.56133690e-02, 1.56211211e-02, 2.44289260e-02, 1.17053210e-02, 1.35748661e-01, - 1.35779534e-01, 1.34646112e-01, 1.34813656e-01, 1.93724876e-02, 2.70357315e-01, - 2.70356924e-01, 2.69252524e-01, 1.86315505e-01], - linf = [1.06156769e-01, 1.15019769e-01, 1.32816030e-01, 7.65402322e-02, 2.45518940e-01, - 2.46123607e-01, 1.82733442e-01, 4.24743430e-01, 1.27620999e-01, 4.58874938e-01, - 4.65364246e-01, 3.56983044e-01, 3.94035665e-01]) - end - - @trixi_testset "elixir_mhdmultiion_rotor.jl tspan = (0., 0.001)" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_rotor.jl"), - l2 = [9.10689060e-03, 1.57109974e-02, 5.47502000e-06, 4.33887866e-02, 6.85503869e-02, - 6.44021766e-02, 2.79487163e-03, 7.85539922e-02, 4.33883209e-02, 6.85496075e-02, - 6.44066193e-02, 5.58969701e-03, 7.85504216e-02], - linf = [1.47204796e-01, 2.33759231e-01, 2.89189051e-05, 1.06452623e+00, 3.36709456e+00, - 2.93566426e+00, 1.53123364e-02, 3.99872907e+00, 1.06455108e+00, 3.36725655e+00, - 2.93570704e+00, 3.05339471e-02, 3.99892281e+00], - tspan = (0., 0.001)) - end - + @trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[1.56133690e-02, 1.56211211e-02, 2.44289260e-02, + 1.17053210e-02, 1.35748661e-01, + 1.35779534e-01, 1.34646112e-01, 1.34813656e-01, + 1.93724876e-02, 2.70357315e-01, + 2.70356924e-01, 2.69252524e-01, 1.86315505e-01], + linf=[1.06156769e-01, 1.15019769e-01, 1.32816030e-01, + 7.65402322e-02, 2.45518940e-01, + 2.46123607e-01, 1.82733442e-01, 4.24743430e-01, + 1.27620999e-01, 4.58874938e-01, + 4.65364246e-01, 3.56983044e-01, 3.94035665e-01]) + end + + @trixi_testset "elixir_mhdmultiion_rotor.jl tspan = (0., 0.001)" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_rotor.jl"), + l2=[9.10689060e-03, 1.57109974e-02, 5.47502000e-06, + 4.33887866e-02, 6.85503869e-02, + 6.44021766e-02, 2.79487163e-03, 7.85539922e-02, + 4.33883209e-02, 6.85496075e-02, + 6.44066193e-02, 5.58969701e-03, 7.85504216e-02], + linf=[1.47204796e-01, 2.33759231e-01, 2.89189051e-05, + 1.06452623e+00, 3.36709456e+00, + 2.93566426e+00, 1.53123364e-02, 3.99872907e+00, + 1.06455108e+00, 3.36725655e+00, + 2.93570704e+00, 3.05339471e-02, 3.99892281e+00], + tspan=(0.0, 0.001)) + end end end # module From 9e15d81147740297d1013b5ba010d54e06c333f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:25:07 +0100 Subject: [PATCH 044/108] format --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 34 +- .../elixir_mhdmultiion_ec_onespecies.jl | 31 +- .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 36 +- .../elixir_mhdmultiion_es_shock_capturing.jl | 42 +- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 36 +- .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 182 +- src/Trixi.jl | 6 +- src/callbacks_step/analysis_dg2d.jl | 50 +- src/equations/equations.jl | 15 +- src/equations/ideal_mhd_multiion_1d.jl | 1346 ++++++------ src/equations/ideal_mhd_multiion_2d.jl | 1866 +++++++++-------- 11 files changed, 1879 insertions(+), 1765 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index e247e1e2312..81218f5545e 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -12,19 +11,17 @@ initial_condition = initial_condition_weak_blast_wave #volume_flux = flux_central volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - + source_terms = source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. @@ -35,26 +32,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index ca7ac5ff363..780bec048ff 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -11,15 +10,14 @@ initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) @@ -36,26 +34,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 37e7a87bdfc..4763f76ec05 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -11,19 +10,17 @@ initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - + source_terms = source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. @@ -34,26 +31,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); -summary_callback() # print the timer summary +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl index 41a3542efc1..ed7527a82de 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -15,26 +14,24 @@ surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = 0.0 coordinates_max = 1.0 mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - + source_terms = source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. @@ -45,26 +42,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 998c6aa72bb..938a0169078 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -11,19 +10,17 @@ initial_condition = initial_condition_weak_blast_wave volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -solver = DGSEM(polydeg=3, surface_flux=surface_flux, - volume_integral=VolumeIntegralFluxDifferencing(volume_flux)) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) coordinates_min = (-2.0, -2.0) -coordinates_max = ( 2.0, 2.0) +coordinates_max = (2.0, 2.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - + source_terms = source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. @@ -34,26 +31,25 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, stepsize_callback) - ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); -summary_callback() # print the timer summary +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index e82d74e4fce..ead9f4fd9fa 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi @@ -16,67 +15,68 @@ The classical MHD rotor test case. Here, the setup is taken from [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) """ function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 1.4 - B1 = 5.0/sqrt(4.0*pi) - B2 = 0.0 - B3 = 0.0 - - # first species - dx = x[1] - 0.25 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r)/0.015 - if r <= 0.1 - rho = 10.0 - v1 = -20.0 * dy - v2 = 20.0 * dx - elseif r >= 0.115 - if x[1] > 0.75 - rho = 0.49 * (tanh(50 * (x[1] - 1.0)) + 1) + 0.02 - elseif x[1] > 0.25 - rho = 0.49 * (-tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + # setup taken from Derigs et al. DMV article (2018) + # domain must be [0, 1] x [0, 1], γ = 1.4 + B1 = 5.0 / sqrt(4.0 * pi) + B2 = 0.0 + B3 = 0.0 + + # first species + dx = x[1] - 0.25 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho = 10.0 + v1 = -20.0 * dy + v2 = 20.0 * dx + elseif r >= 0.115 + if x[1] > 0.75 + rho = 0.49 * (tanh(50 * (x[1] - 1.0)) + 1) + 0.02 + elseif x[1] > 0.25 + rho = 0.49 * (-tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + else + rho = 0.49 * (tanh(50 * (x[1])) + 1) + 0.02 + end + v1 = 0.0 + v2 = 0.0 else - rho = 0.49 * (tanh(50 * (x[1])) + 1) + 0.02 + rho = 1.0 + 9.0 * f + v1 = -20.0 * f * dy + v2 = 20.0 * f * dx end - v1 = 0.0 - v2 = 0.0 - else - rho = 1.0 + 9.0*f - v1 = -20.0*f*dy - v2 = 20.0*f*dx - end - v3 = 0.0 - p = 1.0 - - #second species - dx = x[1] - 0.75 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r)/0.015 - if r <= 0.1 - rho2 = 10.0 - v12 = -20.0 * dy - v22 = 20.0 * dx - elseif r >= 0.115 - if x[1] < 0.25 - rho2 = 0.49 * (-tanh(50 * (x[1])) + 1) + 0.02 - elseif x[1] < 0.75 - rho2 = 0.49 * (tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + v3 = 0.0 + p = 1.0 + + #second species + dx = x[1] - 0.75 + dy = x[2] - 0.5 + r = sqrt(dx^2 + dy^2) + f = (0.115 - r) / 0.015 + if r <= 0.1 + rho2 = 10.0 + v12 = -20.0 * dy + v22 = 20.0 * dx + elseif r >= 0.115 + if x[1] < 0.25 + rho2 = 0.49 * (-tanh(50 * (x[1])) + 1) + 0.02 + elseif x[1] < 0.75 + rho2 = 0.49 * (tanh(50 * (x[1] - 0.5)) + 1) + 0.02 + else + rho2 = 0.49 * (-tanh(50 * (x[1] - 1.0)) + 1) + 0.02 + end + v12 = 0.0 + v22 = 0.0 else - rho2 = 0.49 * (-tanh(50 * (x[1] - 1.0)) + 1) + 0.02 + rho2 = 1.0 + 9.0 * f + v12 = -20.0 * f * dy + v22 = 20.0 * f * dx end - v12 = 0.0 - v22 = 0.0 - else - rho2 = 1.0 + 9.0 * f - v12 = -20.0 * f * dy - v22 = 20.0 * f * dx - end - v3 = 0.0 - p = 1.0 - - return prim2cons(SVector(B1, B2, B3, rho, v1, v2, v3, p, rho2, v12, v22, v3, p), equations) + v3 = 0.0 + p = 1.0 + + return prim2cons(SVector(B1, B2, B3, rho, v1, v2, v3, p, rho2, v12, v22, v3, p), + equations) end initial_condition = initial_condition_rotor @@ -86,26 +86,24 @@ surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) basis = LobattoLegendreBasis(3) indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max=0.5, - alpha_min=0.001, - alpha_smooth=true, - variable=density_pressure) + alpha_max = 0.5, + alpha_min = 0.001, + alpha_smooth = true, + variable = density_pressure) volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg=volume_flux, - volume_flux_fv=surface_flux) + volume_flux_dg = volume_flux, + volume_flux_fv = surface_flux) solver = DGSEM(basis, surface_flux, volume_integral) coordinates_min = (0.0, 0.0) coordinates_max = (1.0, 1.0) mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level=4, - n_cells_max=10_000) - + initial_refinement_level = 4, + n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms=source_terms_standard) - + source_terms = source_terms_standard) ############################################################################### # ODE solvers, callbacks etc. @@ -116,36 +114,36 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval=analysis_interval) -alive_callback = AliveCallback(analysis_interval=analysis_interval) +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) -save_solution = SaveSolutionCallback(interval=100, - save_initial_solution=true, - save_final_solution=true, - solution_variables=cons2prim) +save_solution = SaveSolutionCallback(interval = 100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl=0.5) +stepsize_callback = StepsizeCallback(cfl = 0.5) amr_indicator = IndicatorLöhner(semi, - variable=density) + variable = density) -amr_controller = ControllerThreeLevelCombined(semi, amr_indicator,indicator_sc, - base_level=4, - med_level =5, med_threshold=0.02, # med_level = current level - max_level =7, max_threshold=0.04, - max_threshold_secondary=0.2) +amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, + base_level = 4, + med_level = 5, med_threshold = 0.02, # med_level = current level + max_level = 7, max_threshold = 0.04, + max_threshold_secondary = 0.2) amr_callback = AMRCallback(semi, amr_controller, - interval=6, - adapt_initial_condition=true, - adapt_initial_condition_only_refine=true) + interval = 6, + adapt_initial_condition = true, + adapt_initial_condition_only_refine = true) -save_restart = SaveRestartCallback(interval=100, - save_final_restart=true) +save_restart = SaveRestartCallback(interval = 100, + save_final_restart = true) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, - amr_callback, + amr_callback, save_solution, save_restart, stepsize_callback) @@ -153,7 +151,7 @@ callbacks = CallbackSet(summary_callback, ############################################################################### # run the simulation -sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false), - dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep=false, callback=callbacks); -summary_callback() # print the timer summary +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary \ No newline at end of file diff --git a/src/Trixi.jl b/src/Trixi.jl index b7df5328493..f6758e8bcc7 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -164,7 +164,8 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, flux_nonconservative_powell, flux_nonconservative_powell_local_symmetric, - flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, flux_nonconservative_central, + flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, + flux_nonconservative_central, flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_es_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, @@ -201,7 +202,8 @@ export boundary_condition_do_nothing, BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal, BoundaryConditionCoupled -export initial_condition_convergence_test, source_terms_convergence_test, source_terms_standard +export initial_condition_convergence_test, source_terms_convergence_test, + source_terms_standard export source_terms_harmonic export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic, boundary_condition_poisson_nonperiodic diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index bf5dc3b7834..cf18ab3b15a 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -279,15 +279,17 @@ end function analyze(::Val{:l2_divb}, du, u, t, mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, dg::DG, cache) - integrate_via_indices(u, mesh, equations, dg, cache, cache, dg.basis.derivative_matrix) do u, i, j, element, equations, dg, cache, derivative_matrix - divb = zero(eltype(u)) - for k in eachnode(dg) - divb += ( derivative_matrix[i, k] * u[1, k, j, element] + - derivative_matrix[j, k] * u[2, i, k, element] ) - end - divb *= cache.elements.inverse_jacobian[element] - divb^2 - end |> sqrt + integrate_via_indices(u, mesh, equations, dg, cache, cache, + dg.basis.derivative_matrix) do u, i, j, element, equations, + dg, cache, derivative_matrix + divb = zero(eltype(u)) + for k in eachnode(dg) + divb += (derivative_matrix[i, k] * u[1, k, j, element] + + derivative_matrix[j, k] * u[2, i, k, element]) + end + divb *= cache.elements.inverse_jacobian[element] + divb^2 + end |> sqrt end function analyze(::Val{:l2_divb}, du, u, t, @@ -361,23 +363,23 @@ end function analyze(::Val{:linf_divb}, du, u, t, mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, dg::DG, cache) - @unpack derivative_matrix, weights = dg.basis - - # integrate over all elements to get the divergence-free condition errors - linf_divb = zero(eltype(u)) - for element in eachelement(dg, cache) - for j in eachnode(dg), i in eachnode(dg) - divb = zero(eltype(u)) - for k in eachnode(dg) - divb += ( derivative_matrix[i, k] * u[1, k, j, element] + - derivative_matrix[j, k] * u[2, i, k, element] ) - end - divb *= cache.elements.inverse_jacobian[element] - linf_divb = max(linf_divb, abs(divb)) + @unpack derivative_matrix, weights = dg.basis + + # integrate over all elements to get the divergence-free condition errors + linf_divb = zero(eltype(u)) + for element in eachelement(dg, cache) + for j in eachnode(dg), i in eachnode(dg) + divb = zero(eltype(u)) + for k in eachnode(dg) + divb += (derivative_matrix[i, k] * u[1, k, j, element] + + derivative_matrix[j, k] * u[2, i, k, element]) + end + divb *= cache.elements.inverse_jacobian[element] + linf_divb = max(linf_divb, abs(divb)) + end end - end - return linf_divb + return linf_divb end function analyze(::Val{:linf_divb}, du, u, t, diff --git a/src/equations/equations.jl b/src/equations/equations.jl index a1b02e4e2a4..a74ba22bfd6 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -437,7 +437,8 @@ include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") # IdealMhdMultiIonEquations -abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end +abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: + AbstractEquations{NDIMS, NVARS} end include("ideal_mhd_multiion_1d.jl") include("ideal_mhd_multiion_2d.jl") @@ -462,7 +463,13 @@ In particular, not the components themselves are returned. end # Retrieve number of components from equation instance for the multi-ion case -@inline ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where {NDIMS, NVARS, NCOMP} = NCOMP +@inline function ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where { + NDIMS, + NVARS, + NCOMP + } + NCOMP +end """ eachcomponent(equations::AbstractIdealMhdMultiIonEquations) @@ -471,7 +478,9 @@ Return an iterator over the indices that specify the location in relevant data s for the components in `AbstractIdealMhdMultiIonEquations`. In particular, not the components themselves are returned. """ -@inline eachcomponent(equations::AbstractIdealMhdMultiIonEquations) = Base.OneTo(ncomponents(equations)) +@inline function eachcomponent(equations::AbstractIdealMhdMultiIonEquations) + Base.OneTo(ncomponents(equations)) +end # Diffusion equation: first order hyperbolic system abstract type AbstractHyperbolicDiffusionEquations{NDIMS, NVARS} <: diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 892b39188ed..300c1d5cf59 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -3,653 +3,701 @@ # we need to opt-in explicitly. # See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin - - -@doc raw""" - IdealMhdMultiIonEquations1D - -The ideal compressible multi-ion MHD equations in one space dimension. -""" -mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT<:Real} <: AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} - gammas ::SVector{NCOMP, RealT} # Heat capacity ratios - charge_to_mass ::SVector{NCOMP, RealT} # Charge to mass ratios - - function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas ::SVector{NCOMP, RealT}, - charge_to_mass::SVector{NCOMP, RealT}) where {NVARS, NCOMP, RealT<:Real} - - NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - - new(gammas, charge_to_mass) - end -end - -function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 3 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - return IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) -end - -@inline Base.real(::IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT - -have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() - -function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) - - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., tuple("rho_" * string(i),"rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) - end - - return cons -end - -function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) - end - - return prim -end - - -# """ -# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) - -# An Alfvén wave as smooth initial condition used for convergence tests. -# """ -# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) -# # smooth Alfvén wave test from Derigs et al. FLASH (2016) -# # domain must be set to [0, 1], γ = 5/3 - -# rho = 1.0 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = 0.0 -# si, co = sincos(2 * pi * x[1]) -# v2 = 0.1 * si -# v3 = 0.1 * co -# p = 0.1 -# B1 = 1.0 -# B2 = v2 -# B3 = v3 -# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) -# return prim2cons(vcat(prim_other, prim_rho), equations) -# end - - -""" - initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) - -A weak blast wave adapted from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) - # 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 - inicenter = (0) - x_norm = x[1] - inicenter[1] - r = sqrt(x_norm^2) - phi = atan(x_norm) - - # Calculate primitive variables - rho = zero(real(equations)) - if r > 0.5 - rho = 1.0 - else - rho = 1.1691 - end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - p = r > 0.5 ? 1.0 : 1.245 - - prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 - for k in eachcomponent(equations) - set_component!(prim, k, 2^(k - 1) * (1 - 2)/(1 - 2^ncomponents(equations)) * rho, v1, 0, 0, p, equations) - end - - return prim2cons(SVector(prim), equations) -end - -# TODO: Add initial condition equilibrium - -# Calculate 1D flux in for a single point -@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - B1, B2, B3 = magnetic_field(u, equations) - - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - - mag_en = 0.5*(B1^2 + B2^2 + B3^2) - - f = zero(MVector{nvariables(equations), eltype(u)}) - f[1] = 0.0 - f[2] = v1_plus * B2 - v2_plus * B1 - f[3] = v1_plus * B3 - v3_plus * B1 - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) - - f1 = rho_v1 - f2 = rho_v1 * v1 + p - f3 = rho_v1 * v2 - f4 = rho_v1 * v3 - f5 = (kin_en + gamma * p /(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1*(vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - - return SVector(f) -end - -""" -Standard source terms of the multi-ion MHD equations -""" -function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) -end - -""" -Total entropy-conserving non-conservative two-point "flux"" as described in -- Rueda-Ramírez et al. (2023) -The term is composed of three parts -* The Powell term: Only needed in 1D for non-constant B1 (TODO) -* The MHD term: Implemented without the electron pressure (TODO). -* The "term 3": Implemented -""" -@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - # TODO: Add entries of Powell term for induction equation - for k in eachcomponent(equations) - # Compute Powell (only needed for non-constant B1) - # TODO - - # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) - f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) - f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) - f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) - - # Adjust non-conservative term to Trixi discretization: CHANGE!! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) - f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - - return SVector(f) -end - -""" -Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages -The term is composed of three parts -* The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". -* The MHD term: Implemented without the electron pressure (TODO). -* The "term 3": Implemented -""" -@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - # TODO: Add entries of Powell term for induction equation - for k in eachcomponent(equations) - # Compute Powell (only needed for non-constant B1) - # TODO - - # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) - f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) - f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) - f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + - B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - - return SVector(f) -end - -""" -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations1D) - -Entropy conserving two-point flux adapted by: -- Rueda-Ramírez et al. (2023) -This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: -- Derigs et al. (2018) - Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field - divergence diminishing ideal magnetohydrodynamics equations for multi-ion - [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) -""" -function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - # Magnetic field components from f^MHD - f6 = zero(eltype(u_ll)) - f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg - f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5*rho_ll*vel_norm_ll - 0.5*mag_norm_ll) - p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5*rho_rr*vel_norm_rr - 0.5*mag_norm_rr) - beta_ll = 0.5*rho_ll/p_ll - beta_rr = 0.5*rho_rr/p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean*v1_avg - f2 = f1*v1_avg + p_mean - f3 = f1*v2_avg - f4 = f1*v3_avg - - # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5*(vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - - return SVector(f) -end - -""" -# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed -""" -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - # Calculate fast magnetoacoustic wave speeds - # left - cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) - # right - cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) - - # Calculate velocities (ignore orientation since it is always "1" in 1D) - v_ll = zero(eltype(u_ll)) - v_rr = zero(eltype(u_rr)) - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v1 / rho)) - rho, rho_v1, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v1 / rho)) - end - - λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) -end - - -@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) - v1 = zero(eltype(u)) - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u, equations) - v1 = max(v1, abs(rho_v1 / rho)) - end - - cf_x_direction = calc_fast_wavespeed(u, 1, equations) - - return (abs(v1) + cf_x_direction, ) -end - - -""" -Convert conservative variables to primitive -""" -function cons2prim(u, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) - end - - return SVector(prim) -end - -""" -Convert conservative variables to entropy -""" -@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) - end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - - return SVector(entropy) -end - - -""" -Convert primitive to conservative variables -""" -@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) - end - - return SVector{nvariables(equations), real(equations)}(cons) -end - -""" -Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! -""" -@inline function calc_fast_wavespeed(cons, direction, equations::IdealMhdMultiIonEquations1D) - B1, B2, B3 = magnetic_field(cons, equations) - - c_f = zero(cons[1]) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - p = (gamma - 1)*(rho_e - 0.5 * rho * v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) - a_square = gamma * p / rho - sqrt_rho = sqrt(rho) - - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho - b_square = b1^2 + b2^2 + b3^2 - - c_f = max(c_f, sqrt(0.5*(a_square + b_square) + 0.5*sqrt((a_square + b_square)^2 - 4.0*a_square*b1^2))) - end - - return c_f -end - -""" -Routine to compute the charge-averaged velocities: -* v*_plus: Charge-averaged velocity -* vk*_plus: Contribution of each species to the charge-averaged velocity -""" -@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) - total_electron_charge = zero(eltype(u)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations::IdealMhdMultiIonEquations1D) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), SVector(vk3_plus) -end - -""" -Get the flow variables of component k -""" -@inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) -end - -""" -Set the flow variables of component k -""" -@inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 -end - -magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) - -@inline function density(u, equations::IdealMhdMultiIonEquations1D) - rho = zero(eltype(u)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho -end - + @doc raw""" + IdealMhdMultiIonEquations1D + + The ideal compressible multi-ion MHD equations in one space dimension. + """ + mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: + AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} + gammas :: SVector{NCOMP, RealT} # Heat capacity ratios + charge_to_mass :: SVector{NCOMP, RealT} # Charge to mass ratios + + function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + charge_to_mass::SVector{ + NCOMP, + RealT + }) where { + NVARS, + NCOMP, + RealT <: + Real + } + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass) + end + end + + function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) + end + + @inline function Base.real(::IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT + end + + have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() + + function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + + return cons + end + + function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) + end + + return prim + end + + # """ + # initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) + + # An Alfvén wave as smooth initial condition used for convergence tests. + # """ + # function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) + # # smooth Alfvén wave test from Derigs et al. FLASH (2016) + # # domain must be set to [0, 1], γ = 5/3 + + # rho = 1.0 + # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) + # v1 = 0.0 + # si, co = sincos(2 * pi * x[1]) + # v2 = 0.1 * si + # v3 = 0.1 * co + # p = 0.1 + # B1 = 1.0 + # B2 = v2 + # B3 = v3 + # prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) + # return prim2cons(vcat(prim_other, prim_rho), equations) + # end + + """ + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) + + A weak blast wave adapted from + - Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) + """ + function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) + # 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 + inicenter = (0) + x_norm = x[1] - inicenter[1] + r = sqrt(x_norm^2) + phi = atan(x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 + end + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + p = r > 0.5 ? 1.0 : 1.245 + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + 0, 0, p, equations) + end + + return prim2cons(SVector(prim), equations) + end + + # TODO: Add initial condition equilibrium + + # Calculate 1D flux in for a single point + @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) + B1, B2, B3 = magnetic_field(u, equations) + + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + + f = zero(MVector{nvariables(equations), eltype(u)}) + f[1] = 0.0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + + return SVector(f) + end + + """ + Standard source terms of the multi-ion MHD equations + """ + function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end + + return SVector(s) + end + + """ + Total entropy-conserving non-conservative two-point "flux"" as described in + - Rueda-Ramírez et al. (2023) + The term is composed of three parts + * The Powell term: Only needed in 1D for non-constant B1 (TODO) + * The MHD term: Implemented without the electron pressure (TODO). + * The "term 3": Implemented + """ + @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) + + # Adjust non-conservative term to Trixi discretization: CHANGE!! + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll + f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - + B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + + return SVector(f) + end + + """ + Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages + The term is composed of three parts + * The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". + * The MHD term: Implemented without the electron pressure (TODO). + * The "term 3": Implemented + """ + @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + + return SVector(f) + end + + """ + flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations1D) + + Entropy conserving two-point flux adapted by: + - Rueda-Ramírez et al. (2023) + This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: + - Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) + """ + function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + # Compute averages for global variables + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Magnetic field components from f^MHD + f6 = zero(eltype(u_ll)) + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5 * + (vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - + vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + + return SVector(f) + end + + """ + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed + """ + @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities (ignore orientation since it is always "1" in 1D) + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) + end + + @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) + v1 = zero(eltype(u)) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + end + + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + + return (abs(v1) + cf_x_direction,) + end + + """ + Convert conservative variables to primitive + """ + function cons2prim(u, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) + end + + return SVector(prim) + end + + """ + Convert conservative variables to entropy + """ + @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + end + + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + + return SVector(entropy) + end + + """ + Convert primitive to conservative variables + """ + @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + end + + return SVector{nvariables(equations), real(equations)}(cons) + end + + """ + Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! + """ + @inline function calc_fast_wavespeed(cons, direction, + equations::IdealMhdMultiIonEquations1D) + B1, B2, B3 = magnetic_field(cons, equations) + + c_f = zero(cons[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + end + + return c_f + end + + """ + Routine to compute the charge-averaged velocities: + * v*_plus: Charge-averaged velocity + * vk*_plus: Contribution of each species to the charge-averaged velocity + """ + @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) + total_electron_charge = zero(eltype(u)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations::IdealMhdMultiIonEquations1D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) + end + + """ + Get the flow variables of component k + """ + @inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) + end + + """ + Set the flow variables of component k + """ + @inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealMhdMultiIonEquations1D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + end + + magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) + + @inline function density(u, equations::IdealMhdMultiIonEquations1D) + rho = zero(eltype(u)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho + end end # @muladd diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index dab23f64049..0b2c11ca726 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -3,917 +3,991 @@ # we need to opt-in explicitly. # See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin + @doc raw""" + IdealMhdMultiIonEquations2D + + The ideal compressible multi-ion MHD equations in two space dimensions. + """ + mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure + } <: + AbstractIdealMhdMultiIonEquations{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 + + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}(gammas::SVector{ + NCOMP, + RealT + }, + charge_to_mass::SVector{ + NCOMP, + RealT + }, + electron_pressure::ElectronPressure) where { + NVARS, + NCOMP, + RealT <: + Real, + ElectronPressure + } + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass, electron_pressure) + end + end + + function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure) + end + + @inline function Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT + end + + have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() + + function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + + return cons + end + + function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) + end + + return prim + end + + function default_analysis_integrals(::IdealMhdMultiIonEquations2D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) + end + + # """ + # initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) + + # An Alfvén wave as smooth initial condition used for convergence tests. + # """ + # function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) + # # smooth Alfvén wave test from Derigs et al. FLASH (2016) + # # domain must be set to [0, 1], γ = 5/3 + + # rho = 1.0 + # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) + # v1 = zero(real(equations)) + # si, co = sincos(2 * pi * x[1]) + # v2 = 0.1 * si + # v3 = 0.1 * co + # p = 0.1 + # B1 = 1.0 + # B2 = v2 + # B3 = v3 + # prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) + # return prim2cons(vcat(prim_other, prim_rho), equations) + # end + + """ + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) + + A weak blast wave adapted from + - Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) + """ + function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) + # 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 + inicenter = (0, 0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + phi = atan(y_norm, x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 + end + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + p = r > 0.5 ? 1.0 : 1.245 + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + v2, 0, p, equations) + end + + return prim2cons(SVector(prim), equations) + end + + # TODO: Add initial condition equilibrium + + # Calculate 1D flux in for a single point + @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(u, equations) + + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + + f = zero(MVector{nvariables(equations), eltype(u)}) + + if orientation == 1 + f[1] = 0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end -@doc raw""" - IdealMhdMultiIonEquations2D - -The ideal compressible multi-ion MHD equations in two space dimensions. -""" -mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT<:Real, ElectronPressure} <: AbstractIdealMhdMultiIonEquations{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 - - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}( - gammas::SVector{NCOMP, RealT}, - charge_to_mass::SVector{NCOMP, RealT}, - electron_pressure::ElectronPressure) where {NVARS, NCOMP, RealT<:Real, ElectronPressure} - - NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - - new(gammas, charge_to_mass, electron_pressure) - end -end - -function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, electron_pressure = electron_pressure_zero) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 3 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, __charge_to_mass, electron_pressure) -end - -@inline Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where {NVARS, NCOMP, RealT} = RealT - -have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() - -function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., tuple("rho_" * string(i),"rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) - end - - return cons -end - -function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., tuple("rho_" * string(i),"v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) - end - - return prim -end - -default_analysis_integrals(::IdealMhdMultiIonEquations2D) = (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) - - -# """ -# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) - -# An Alfvén wave as smooth initial condition used for convergence tests. -# """ -# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) -# # smooth Alfvén wave test from Derigs et al. FLASH (2016) -# # domain must be set to [0, 1], γ = 5/3 - -# rho = 1.0 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = zero(real(equations)) -# si, co = sincos(2 * pi * x[1]) -# v2 = 0.1 * si -# v3 = 0.1 * co -# p = 0.1 -# B1 = 1.0 -# B2 = v2 -# B3 = v3 -# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) -# return prim2cons(vcat(prim_other, prim_rho), equations) -# end - - -""" - initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) - -A weak blast wave adapted from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) -""" -function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) - # 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 - inicenter = (0, 0) - x_norm = x[1] - inicenter[1] - y_norm = x[2] - inicenter[2] - r = sqrt(x_norm^2 + y_norm^2) - phi = atan(y_norm, x_norm) - - # Calculate primitive variables - rho = zero(real(equations)) - if r > 0.5 - rho = 1.0 - else - rho = 1.1691 - end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) - p = r > 0.5 ? 1.0 : 1.245 - - prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 - for k in eachcomponent(equations) - set_component!(prim, k, 2^(k-1) * (1 - 2)/(1 - 2^ncomponents(equations)) * rho, v1, v2, 0, p, equations) - end - - return prim2cons(SVector(prim), equations) -end - -# TODO: Add initial condition equilibrium - -# Calculate 1D flux in for a single point -@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(u, equations) - - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - - mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - - f = zero(MVector{nvariables(equations), eltype(u)}) - - if orientation == 1 - f[1] = 0 - f[2] = v1_plus * B2 - v2_plus * B1 - f[3] = v1_plus * B3 - v3_plus * B1 - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) - - f1 = rho_v1 - f2 = rho_v1*v1 + p - f3 = rho_v1*v2 - f4 = rho_v1*v3 - f5 = (kin_en + gamma * p/(gamma - 1))*v1 + 2 * mag_en * vk1_plus[k] - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) + else #if orientation == 2 + f[1] = v2_plus * B1 - v1_plus * B2 + f[2] = 0 + f[3] = v2_plus * B3 - v3_plus * B2 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) + + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_v2 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + end + + return SVector(f) + end + + """ + Standard source terms of the multi-ion MHD equations + """ + function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end + + return SVector(s) end - - else #if orientation == 2 - - f[1] = v2_plus * B1 - v1_plus * B2 - f[2] = 0 - f[3] = v2_plus * B3 - v3_plus * B2 - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) - - f1 = rho_v2 - f2 = rho_v2 * v1 - f3 = rho_v2 * v2 + p - f4 = rho_v2 * v3 - f5 = (kin_en + gamma*p/(gamma - 1))*v2 + 2 * mag_en * vk2_plus[k] - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) + + """ + electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) + Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. + """ + function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) + return zero(u[1]) end - end - - return SVector(f) -end - -""" -Standard source terms of the multi-ion MHD equations -""" -function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) -end - -""" - electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) -Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. -""" -function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) - return zero(u[1]) -end - -""" -Total entropy-conserving non-conservative two-point "flux"" as described in -- Rueda-Ramírez et al. (2023) -The term is composed of three parts -* The Powell term: Implemented -* The MHD term: Implemented -* The "term 3": Implemented -""" -@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - B1_avg = 0.5 *(B1_ll + B1_rr) - B2_avg = 0.5 *(B2_ll + B2_rr) - B3_avg = 0.5 *(B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - # Mean electron pressure - pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + + + """ + Total entropy-conserving non-conservative two-point "flux"" as described in + - Rueda-Ramírez et al. (2023) + The term is composed of three parts + * The Powell term: Implemented + * The MHD term: Implemented + * The "term 3": Implemented + """ + @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + # Mean electron pressure + pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + equations.electron_pressure(u_rr, equations)) - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) - f3 = charge_ratio_ll[k] * (- B1_avg * B2_avg) - f4 = charge_ratio_ll[k] * (- B1_avg * B3_avg) - f5 = vk1_plus_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + - B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) - - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) - f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 =(2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) ) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = vk1_plus_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll + f5 = (2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + - + B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) + f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) + f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) + f5 = vk2_plus_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll + f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) + f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll + f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + - + B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + end + + return SVector(f) + end + + """ + Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages + The term is composed of three parts + * The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". + * The MHD term: Implemented + * The "term 3": Implemented + """ + @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Electron pressure + pe_rr = equations.electron_pressure(u_rr, equations) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(real(equations)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr + for k in eachcomponent(equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) + f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) + f5 = vk1_plus_ll[k] * pe_rr + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr + + for k in eachcomponent(equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (-B2_rr * B1_rr) + f3 = charge_ratio_ll[k] * (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) + f4 = charge_ratio_ll[k] * (-B2_rr * B3_rr) + f5 = vk2_plus_ll[k] * pe_rr + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + + B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + end + + return SVector(f) + end + + """ + flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) + + Entropy conserving two-point flux adapted by: + - Rueda-Ramírez et al. (2023) + This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: + - Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) + """ + function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Compute averages for global variables + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + if orientation == 1 + # Magnetic field components from f^MHD + f6 = 0 + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - + vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - + vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + else #if orientation == 2 + # Magnetic field components from f^MHD + f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg + f7 = 0 + f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v2_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_mean + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + + vk2_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk2_plus_avg * mag_norm_avg - + vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - + vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - + B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + end + + return SVector(f) + end + + """ + # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed + """ + @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + if orientation == 1 + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + else #if orientation == 2 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v2 / rho)) + rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v2 / rho)) + end + end + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end - else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (- B2_avg * B1_avg) - f3 = charge_ratio_ll[k] * (- B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) - f4 = charge_ratio_ll[k] * (- B2_avg * B3_avg) - f5 = vk2_plus_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + - B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) - - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll - f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) - f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll - f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) - - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll) ) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) + v1 = zero(real(equations)) + v2 = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + v2 = max(v2, abs(rho_v2 / rho)) + end + + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + cf_y_direction = calc_fast_wavespeed(u, 2, equations) + + return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) end - end - - return SVector(f) -end - -""" -Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages -The term is composed of three parts -* The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". -* The MHD term: Implemented -* The "term 3": Implemented -""" -@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - - # Electron pressure - pe_rr = equations.electron_pressure(u_rr, equations) - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(real(equations)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) - f3 = charge_ratio_ll[k] * (- B1_rr * B2_rr) - f4 = charge_ratio_ll[k] * (- B1_rr * B3_rr) - f5 = vk1_plus_ll[k] * pe_rr - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + - B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr) ) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + + """ + Convert conservative variables to primitive + """ + function cons2prim(u, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) + end + + return SVector(prim) end - else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (- B2_rr * B1_rr) - f3 = charge_ratio_ll[k] * (- B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) - f4 = charge_ratio_ll[k] * (- B2_rr * B3_rr) - f5 = vk2_plus_ll[k] * pe_rr - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + - B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr) ) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + + """ + Convert conservative variables to entropy + """ + @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + end + + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + + return SVector(entropy) + end + + """ + Convert primitive to conservative variables + """ + @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + end + + return SVector(cons) end - end - - return SVector(f) -end - -""" -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) - -Entropy conserving two-point flux adapted by: -- Rueda-Ramírez et al. (2023) -This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: -- Derigs et al. (2018) - Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field - divergence diminishing ideal magnetohydrodynamics equations for multi-ion - [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) -""" -function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - if orientation == 1 - # Magnetic field components from f^MHD - f6 = 0 - f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg - f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) - p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5*(vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean*v1_avg - f2 = f1 * v1_avg + p_mean - f3 = f1 * v2_avg - f4 = f1 * v3_avg - - # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5*(vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) + + """ + Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! + """ + @inline function calc_fast_wavespeed(cons, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(cons, equations) + + c_f = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + if orientation == 1 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + else #if orientation == 2 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) + end + end + + return c_f end - else #if orientation == 2 - # Magnetic field components from f^MHD - f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg - f7 = 0 - f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1)*(rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) - p_rr = (gammas[k] - 1)*(rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean*v2_avg - f2 = f1 * v1_avg - f3 = f1 * v2_avg + p_mean - f4 = f1 * v3_avg - - # total energy flux is complicated and involves the previous eight components - v2_plus_mag_avg = 0.5*(vk2_plus_ll[k] * mag_norm_ll + vk2_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * ( 1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg) ) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) + + """ + Routine to compute the Charge-averaged velocities: + * v*_plus: Charge-averaged velocity + * vk*_plus: Contribution of each species to the charge-averaged velocity + """ + @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) + total_electron_charge = zero(real(equations)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations::IdealMhdMultiIonEquations2D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) end - end - - return SVector(f) -end - -""" -# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed -""" -@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - # Calculate fast magnetoacoustic wave speeds - # left - cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) - # right - cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) - - # Calculate velocities - v_ll = zero(eltype(u_ll)) - v_rr = zero(eltype(u_rr)) - if orientation == 1 - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v1 / rho)) - rho, rho_v1, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v1 / rho)) + + """ + Get the flow variables of component k + """ + @inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) end - else #if orientation == 2 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v2 / rho)) - rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v2 / rho)) + + """ + Set the flow variables of component k + """ + @inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealMhdMultiIonEquations2D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + + return u end - end - - λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) -end - - -@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) - v1 = zero(real(equations)) - v2 = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, _ = get_component(k, u, equations) - v1 = max(v1, abs(rho_v1 / rho)) - v2 = max(v2, abs(rho_v2 / rho)) - end - - cf_x_direction = calc_fast_wavespeed(u, 1, equations) - cf_y_direction = calc_fast_wavespeed(u, 2, equations) - - return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) -end - - -""" -Convert conservative variables to primitive -""" -function cons2prim(u, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) - end - - return SVector(prim) -end - -""" -Convert conservative variables to entropy -""" -@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) - end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - - return SVector(entropy) -end - - -""" -Convert primitive to conservative variables -""" -@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p/(gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) - end - - return SVector(cons) -end - -""" -Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! -""" -@inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(cons, equations) - - c_f = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - p = (gamma - 1)*(rho_e - 0.5*rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) - a_square = gamma * p / rho - sqrt_rho = sqrt(rho) - - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho - b_square = b1^2 + b2^2 + b3^2 - - if orientation == 1 - c_f = max(c_f, sqrt(0.5 * (a_square + b_square) + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square*b1^2))) - else #if orientation == 2 - c_f = max(c_f, sqrt(0.5 * (a_square + b_square) + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square*b2^2))) + + magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + + @inline function density(u, equations::IdealMhdMultiIonEquations2D) + rho = zero(real(equations)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho end - end - - return c_f -end - -""" -Routine to compute the Charge-averaged velocities: -* v*_plus: Charge-averaged velocity -* vk*_plus: Contribution of each species to the charge-averaged velocity -""" -@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = zero(real(equations)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations::IdealMhdMultiIonEquations2D) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), SVector(vk3_plus) -end - -""" -Get the flow variables of component k -""" -@inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) -end - -""" -Set the flow variables of component k -""" -@inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::IdealMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 - - return u -end - -magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) - -@inline function density(u, equations::IdealMhdMultiIonEquations2D) - rho = zero(real(equations)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho -end - -""" -Computes the sum of the densities times the sum of the pressures -""" -@inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(u, equations) - rho_total = zero(real(equations)) - p_total = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - - p = (gamma - 1)*(rho_e - 0.5 * rho*v_mag^2 - 0.5*(B1^2 + B2^2 + B3^2)) - - rho_total += rho - p_total += p - end - return rho_total * p_total -end + """ + Computes the sum of the densities times the sum of the pressures + """ + @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(u, equations) + rho_total = zero(real(equations)) + p_total = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + + rho_total += rho + p_total += p + end + return rho_total * p_total + end end # @muladd From 4859d924425194930cba36b867f2483d2c60ad89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:28:34 +0100 Subject: [PATCH 045/108] format: noindent in multi-ion equations --- src/equations/ideal_mhd_multiion_1d.jl | 1308 ++++++++--------- src/equations/ideal_mhd_multiion_2d.jl | 1822 ++++++++++++------------ 2 files changed, 1567 insertions(+), 1563 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 300c1d5cf59..4824c664778 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -3,701 +3,703 @@ # we need to opt-in explicitly. # See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin - @doc raw""" - IdealMhdMultiIonEquations1D - - The ideal compressible multi-ion MHD equations in one space dimension. - """ - mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: - AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} - gammas :: SVector{NCOMP, RealT} # Heat capacity ratios - charge_to_mass :: SVector{NCOMP, RealT} # Charge to mass ratios - - function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, - RealT}, - charge_to_mass::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } - NCOMP >= 1 || - throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - - new(gammas, charge_to_mass) - end +#! format: noindent + +@doc raw""" + IdealMhdMultiIonEquations1D + +The ideal compressible multi-ion MHD equations in one space dimension. +""" +mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: + AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} + gammas :: SVector{NCOMP, RealT} # Heat capacity ratios + charge_to_mass :: SVector{NCOMP, RealT} # Charge to mass ratios + + function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, + RealT}, + charge_to_mass::SVector{ + NCOMP, + RealT + }) where { + NVARS, + NCOMP, + RealT <: + Real + } + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass) end - - function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 3 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - return IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) +end + +function IdealMhdMultiIonEquations1D(; gammas, charge_to_mass) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(__gammas, __charge_to_mass) +end + +@inline function Base.real(::IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT +end + +have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() + +function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) end - @inline function Base.real(::IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}) where { - NVARS, - NCOMP, - RealT - } - RealT - end - - have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() + return cons +end - function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., - tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), - "rho_v3_" * string(i), "rho_e_" * string(i))...) - end - - return cons +function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) end - function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., - tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), - "v3_" * string(i), "p_" * string(i))...) - end - - return prim + return prim +end + +# """ +# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) + +# An Alfvén wave as smooth initial condition used for convergence tests. +# """ +# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) +# # smooth Alfvén wave test from Derigs et al. FLASH (2016) +# # domain must be set to [0, 1], γ = 5/3 + +# rho = 1.0 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# v1 = 0.0 +# si, co = sincos(2 * pi * x[1]) +# v2 = 0.1 * si +# v3 = 0.1 * co +# p = 0.1 +# B1 = 1.0 +# B2 = v2 +# B3 = v3 +# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) +# return prim2cons(vcat(prim_other, prim_rho), equations) +# end + +""" + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) + +A weak blast wave adapted from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) + # 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 + inicenter = (0) + x_norm = x[1] - inicenter[1] + r = sqrt(x_norm^2) + phi = atan(x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 end - - # """ - # initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) - - # An Alfvén wave as smooth initial condition used for convergence tests. - # """ - # function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) - # # smooth Alfvén wave test from Derigs et al. FLASH (2016) - # # domain must be set to [0, 1], γ = 5/3 - - # rho = 1.0 - # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) - # v1 = 0.0 - # si, co = sincos(2 * pi * x[1]) - # v2 = 0.1 * si - # v3 = 0.1 * co - # p = 0.1 - # B1 = 1.0 - # B2 = v2 - # B3 = v3 - # prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) - # return prim2cons(vcat(prim_other, prim_rho), equations) - # end - - """ - initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) - - A weak blast wave adapted from - - Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) - """ - function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) - # 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 - inicenter = (0) - x_norm = x[1] - inicenter[1] - r = sqrt(x_norm^2) - phi = atan(x_norm) - - # Calculate primitive variables - rho = zero(real(equations)) - if r > 0.5 - rho = 1.0 - else - rho = 1.1691 - end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - p = r > 0.5 ? 1.0 : 1.245 - - prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 - for k in eachcomponent(equations) - set_component!(prim, k, - 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, - 0, 0, p, equations) - end - - return prim2cons(SVector(prim), equations) + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + p = r > 0.5 ? 1.0 : 1.245 + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + 0, 0, p, equations) end - # TODO: Add initial condition equilibrium + return prim2cons(SVector(prim), equations) +end - # Calculate 1D flux in for a single point - @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) - B1, B2, B3 = magnetic_field(u, equations) +# TODO: Add initial condition equilibrium - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) +# Calculate 1D flux in for a single point +@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) + B1, B2, B3 = magnetic_field(u, equations) - mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) - f = zero(MVector{nvariables(equations), eltype(u)}) - f[1] = 0.0 - f[2] = v1_plus * B2 - v2_plus * B1 - f[3] = v1_plus * B3 - v3_plus * B1 + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + f = zero(MVector{nvariables(equations), eltype(u)}) + f[1] = 0.0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - f1 = rho_v1 - f2 = rho_v1 * v1 + p - f3 = rho_v1 * v2 - f4 = rho_v1 * v3 - f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - return SVector(f) + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - """ - Standard source terms of the multi-ion MHD equations - """ - function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) + return SVector(f) +end + +""" +Standard source terms of the multi-ion MHD equations +""" +function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) end - """ - Total entropy-conserving non-conservative two-point "flux"" as described in - - Rueda-Ramírez et al. (2023) - The term is composed of three parts - * The Powell term: Only needed in 1D for non-constant B1 (TODO) - * The MHD term: Implemented without the electron pressure (TODO). - * The "term 3": Implemented - """ - @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, - orientation::Integer, - equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, - equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - # TODO: Add entries of Powell term for induction equation - for k in eachcomponent(equations) - # Compute Powell (only needed for non-constant B1) - # TODO - - # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) - f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) - f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) - f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + - B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) - - # Adjust non-conservative term to Trixi discretization: CHANGE!! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) - f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - - return SVector(f) + return SVector(s) +end + +""" +Total entropy-conserving non-conservative two-point "flux"" as described in +- Rueda-Ramírez et al. (2023) +The term is composed of three parts +* The Powell term: Only needed in 1D for non-constant B1 (TODO) +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented +""" +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] end - - """ - Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages - The term is composed of three parts - * The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". - * The MHD term: Implemented without the electron pressure (TODO). - * The "term 3": Implemented - """ - @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] - end - charge_ratio_ll ./= total_electron_charge - - # Compute auxiliary variables - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - # TODO: Add entries of Powell term for induction equation - for k in eachcomponent(equations) - # Compute Powell (only needed for non-constant B1) - # TODO - - # Compute term 2 (MHD) - # TODO: Add electron pressure term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) - f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) - f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) - f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + - B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - - return SVector(f) + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg) # + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg) + + # Adjust non-conservative term to Trixi discretization: CHANGE!! + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll + f5 = 2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - + B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - """ - flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations1D) - - Entropy conserving two-point flux adapted by: - - Rueda-Ramírez et al. (2023) - This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: - - Derigs et al. (2018) - Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field - divergence diminishing ideal magnetohydrodynamics equations for multi-ion - [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) - """ - function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, - equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) - - # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - # Magnetic field components from f^MHD - f6 = zero(eltype(u_ll)) - f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg - f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, - equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, - equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) - p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + - vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + - vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean * v1_avg - f2 = f1 * v1_avg + p_mean - f3 = f1 * v2_avg - f4 = f1 * v3_avg - - # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5 * - (vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + - f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + - B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - - return SVector(f) + return SVector(f) +end + +""" +Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages +The term is composed of three parts +* The Powell term: Only needed in 1D for non-constant B1 (TODO). The central Powell "flux" is equivalent to the EC Powell "flux". +* The MHD term: Implemented without the electron pressure (TODO). +* The "term 3": Implemented +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] end - - """ - # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed - """ - @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations1D) - # Calculate fast magnetoacoustic wave speeds - # left - cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) - # right - cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) - - # Calculate velocities (ignore orientation since it is always "1" in 1D) - v_ll = zero(eltype(u_ll)) - v_rr = zero(eltype(u_rr)) - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v1 / rho)) - rho, rho_v1, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v1 / rho)) - end - - λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + # TODO: Add entries of Powell term for induction equation + for k in eachcomponent(equations) + # Compute Powell (only needed for non-constant B1) + # TODO + + # Compute term 2 (MHD) + # TODO: Add electron pressure term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr) # + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) + f5 = zero(eltype(u_ll)) # TODO! charge_ratio_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) - v1 = zero(eltype(u)) - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u, equations) - v1 = max(v1, abs(rho_v1 / rho)) - end - - cf_x_direction = calc_fast_wavespeed(u, 1, equations) - - return (abs(v1) + cf_x_direction,) + return SVector(f) +end + +""" +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations1D) + +Entropy conserving two-point flux adapted by: +- Rueda-Ramírez et al. (2023) +This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: +- Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + # Compute averages for global variables + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Magnetic field components from f^MHD + f6 = zero(eltype(u_ll)) + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5 * + (vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - + vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - """ - Convert conservative variables to primitive - """ - function cons2prim(u, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) - end - - return SVector(prim) + return SVector(f) +end + +""" +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed +""" +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations1D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities (ignore orientation since it is always "1" in 1D) + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) end - """ - Convert conservative variables to entropy - """ - @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) - end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - - return SVector(entropy) - end + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end - """ - Convert primitive to conservative variables - """ - @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p / (gammas[k] - 1.0) + - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) - end - - return SVector{nvariables(equations), real(equations)}(cons) +@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) + v1 = zero(eltype(u)) + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) end - """ - Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! - """ - @inline function calc_fast_wavespeed(cons, direction, - equations::IdealMhdMultiIonEquations1D) - B1, B2, B3 = magnetic_field(cons, equations) - - c_f = zero(cons[1]) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) - a_square = gamma * p / rho - sqrt_rho = sqrt(rho) - - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho - b_square = b1^2 + b2^2 + b3^2 - - c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) - end - - return c_f + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + + return (abs(v1) + cf_x_direction,) +end + +""" +Convert conservative variables to primitive +""" +function cons2prim(u, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) end - """ - Routine to compute the charge-averaged velocities: - * v*_plus: Charge-averaged velocity - * vk*_plus: Contribution of each species to the charge-averaged velocity - """ - @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) - total_electron_charge = zero(eltype(u)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealMhdMultiIonEquations1D) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), - SVector(vk3_plus) + return SVector(prim) +end + +""" +Convert conservative variables to entropy +""" +@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) end - """ - Get the flow variables of component k - """ - @inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + + return SVector(entropy) +end + +""" +Convert primitive to conservative variables +""" +@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations1D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end - """ - Set the flow variables of component k - """ - @inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 + return SVector{nvariables(equations), real(equations)}(cons) +end + +""" +Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! +""" +@inline function calc_fast_wavespeed(cons, direction, + equations::IdealMhdMultiIonEquations1D) + B1, B2, B3 = magnetic_field(cons, equations) + + c_f = zero(cons[1]) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) end - magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) - - @inline function density(u, equations::IdealMhdMultiIonEquations1D) - rho = zero(eltype(u)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho + return c_f +end + +""" +Routine to compute the charge-averaged velocities: +* v*_plus: Charge-averaged velocity +* vk*_plus: Contribution of each species to the charge-averaged velocity +""" +@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) + total_electron_charge = zero(eltype(u)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations::IdealMhdMultiIonEquations1D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) +end + +""" +Get the flow variables of component k +""" +@inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" +Set the flow variables of component k +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealMhdMultiIonEquations1D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 +end + +magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) + +@inline function density(u, equations::IdealMhdMultiIonEquations1D) + rho = zero(eltype(u)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] end + return rho +end end # @muladd diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 0b2c11ca726..a3fb4924896 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -3,991 +3,993 @@ # we need to opt-in explicitly. # See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. @muladd begin - @doc raw""" - IdealMhdMultiIonEquations2D - - The ideal compressible multi-ion MHD equations in two space dimensions. - """ - mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure - } <: - AbstractIdealMhdMultiIonEquations{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 - - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}(gammas::SVector{ - NCOMP, - RealT - }, - charge_to_mass::SVector{ - NCOMP, - RealT - }, - electron_pressure::ElectronPressure) where { - NVARS, - NCOMP, - RealT <: - Real, - ElectronPressure - } - NCOMP >= 1 || - throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - - new(gammas, charge_to_mass, electron_pressure) - end - end - - function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, - electron_pressure = electron_pressure_zero) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 3 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, - __charge_to_mass, - electron_pressure) +#! format: noindent + +@doc raw""" + IdealMhdMultiIonEquations2D + +The ideal compressible multi-ion MHD equations in two space dimensions. +""" +mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure + } <: + AbstractIdealMhdMultiIonEquations{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 + + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}(gammas::SVector{ + NCOMP, + RealT + }, + charge_to_mass::SVector{ + NCOMP, + RealT + }, + electron_pressure::ElectronPressure) where { + NVARS, + NCOMP, + RealT <: + Real, + ElectronPressure + } + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass, electron_pressure) end - - @inline function Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { - NVARS, - NCOMP, - RealT - } - RealT +end + +function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 3 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure) +end + +@inline function Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT +end + +have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() + +function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) end - have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() - - function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., - tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), - "rho_v3_" * string(i), "rho_e_" * string(i))...) - end + return cons +end - return cons +function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) end - function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., - tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), - "v3_" * string(i), "p_" * string(i))...) - end - - return prim + return prim +end + +function default_analysis_integrals(::IdealMhdMultiIonEquations2D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + +# """ +# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) + +# An Alfvén wave as smooth initial condition used for convergence tests. +# """ +# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) +# # smooth Alfvén wave test from Derigs et al. FLASH (2016) +# # domain must be set to [0, 1], γ = 5/3 + +# rho = 1.0 +# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) +# v1 = zero(real(equations)) +# si, co = sincos(2 * pi * x[1]) +# v2 = 0.1 * si +# v3 = 0.1 * co +# p = 0.1 +# B1 = 1.0 +# B2 = v2 +# B3 = v3 +# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) +# return prim2cons(vcat(prim_other, prim_rho), equations) +# end + +""" + initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) + +A weak blast wave adapted from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) + # 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 + inicenter = (0, 0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + phi = atan(y_norm, x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 end - - function default_analysis_integrals(::IdealMhdMultiIonEquations2D) - (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + p = r > 0.5 ? 1.0 : 1.245 + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + v2, 0, p, equations) end - # """ - # initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) - - # An Alfvén wave as smooth initial condition used for convergence tests. - # """ - # function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) - # # smooth Alfvén wave test from Derigs et al. FLASH (2016) - # # domain must be set to [0, 1], γ = 5/3 - - # rho = 1.0 - # prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) - # v1 = zero(real(equations)) - # si, co = sincos(2 * pi * x[1]) - # v2 = 0.1 * si - # v3 = 0.1 * co - # p = 0.1 - # B1 = 1.0 - # B2 = v2 - # B3 = v3 - # prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) - # return prim2cons(vcat(prim_other, prim_rho), equations) - # end - - """ - initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) - - A weak blast wave adapted from - - Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) - """ - function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) - # 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 - inicenter = (0, 0) - x_norm = x[1] - inicenter[1] - y_norm = x[2] - inicenter[2] - r = sqrt(x_norm^2 + y_norm^2) - phi = atan(y_norm, x_norm) - - # Calculate primitive variables - rho = zero(real(equations)) - if r > 0.5 - rho = 1.0 - else - rho = 1.1691 - end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) - p = r > 0.5 ? 1.0 : 1.245 - - prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 - for k in eachcomponent(equations) - set_component!(prim, k, - 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, - v2, 0, p, equations) - end + return prim2cons(SVector(prim), equations) +end - return prim2cons(SVector(prim), equations) - end +# TODO: Add initial condition equilibrium - # TODO: Add initial condition equilibrium +# Calculate 1D flux in for a single point +@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(u, equations) - # Calculate 1D flux in for a single point - @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + f = zero(MVector{nvariables(equations), eltype(u)}) - f = zero(MVector{nvariables(equations), eltype(u)}) + if orientation == 1 + f[1] = 0 + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 - if orientation == 1 - f[1] = 0 - f[2] = v1_plus * B2 - v2_plus * B1 - f[3] = v1_plus * B3 - v3_plus * B1 - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) - - f1 = rho_v1 - f2 = rho_v1 * v1 + p - f3 = rho_v1 * v2 - f4 = rho_v1 * v3 - f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - else #if orientation == 2 - f[1] = v2_plus * B1 - v1_plus * B2 - f[2] = 0 - f[3] = v2_plus * B3 - v3_plus * B2 - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) - - f1 = rho_v2 - f2 = rho_v2 * v1 - f3 = rho_v2 * v2 + p - f4 = rho_v2 * v3 - f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - end + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) - return SVector(f) - end + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - """ - Standard source terms of the multi-ion MHD equations - """ - function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end - s = zero(MVector{nvariables(equations), eltype(u)}) + else #if orientation == 2 + f[1] = v2_plus * B1 - v1_plus * B2 + f[2] = 0 + f[3] = v2_plus * B3 - v3_plus * B2 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) v1 = rho_v1 / rho v2 = rho_v2 / rho v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) - return SVector(s) - end + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en) - """ - electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) - Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. - """ - function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) - return zero(u[1]) - end + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_v2 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) - """ - Total entropy-conserving non-conservative two-point "flux"" as described in - - Rueda-Ramírez et al. (2023) - The term is composed of three parts - * The Powell term: Implemented - * The MHD term: Implemented - * The "term 3": Implemented - """ - @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, - orientation::Integer, - equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - # Mean electron pressure - pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + - equations.electron_pressure(u_rr, equations)) - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) - for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - charge_ratio_ll ./= total_electron_charge + end - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, - equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) + return SVector(f) +end + +""" +Standard source terms of the multi-ion MHD equations +""" +function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end - f = zero(MVector{nvariables(equations), eltype(u_ll)}) + return SVector(s) +end + +""" + electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) +Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. +""" +function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) + return zero(u[1]) +end + +""" +Total entropy-conserving non-conservative two-point "flux"" as described in +- Rueda-Ramírez et al. (2023) +The term is composed of three parts +* The Powell term: Implemented +* The MHD term: Implemented +* The "term 3": Implemented +""" +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + # Mean electron pressure + pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + + equations.electron_pressure(u_rr, equations)) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge - if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) - f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) - f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) - f5 = vk1_plus_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + - B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) - - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) - f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 = (2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) - else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) - f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) - f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) - f5 = vk2_plus_ll[k] * pe_mean - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + - B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) - - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll - f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) - f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll - f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) - - - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - end + f = zero(MVector{nvariables(equations), eltype(u_ll)}) - return SVector(f) - end + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr - """ - Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages - The term is composed of three parts - * The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". - * The MHD term: Implemented - * The "term 3": Implemented - """ - @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - # Compute important averages - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - - # Electron pressure - pe_rr = equations.electron_pressure(u_rr, equations) - - # Compute charge ratio of u_ll - charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(real(equations)) for k in eachcomponent(equations) - rho_k = u_ll[3 + (k - 1) * 5 + 1] - charge_ratio_ll[k] = rho_k * charge_to_mass[k] - total_electron_charge += charge_ratio_ll[k] + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = vk1_plus_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll + f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll + f5 = (2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + - + B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - charge_ratio_ll ./= total_electron_charge - # Compute auxiliary variables - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, - equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) - f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) - f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) - f5 = vk1_plus_ll[k] * pe_rr - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + - B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end - else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr - - for k in eachcomponent(equations) - # Compute term 2 (MHD) - f2 = charge_ratio_ll[k] * (-B2_rr * B1_rr) - f3 = charge_ratio_ll[k] * (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) - f4 = charge_ratio_ll[k] * (-B2_rr * B3_rr) - f5 = vk2_plus_ll[k] * pe_rr - - # Compute term 3 (only needed for NCOMP>1) - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + - B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr)) - - # Compute Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr - - # It's not needed to adjust to Trixi's non-conservative form - - # Append to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) - end + for k in eachcomponent(equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) + f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) + f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) + f5 = vk2_plus_ll[k] * pe_mean + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) + + # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll + f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) + f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll + f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + - + B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - - return SVector(f) end - """ - flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) - - Entropy conserving two-point flux adapted by: - - Rueda-Ramírez et al. (2023) - This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: - - Derigs et al. (2018) - Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field - divergence diminishing ideal magnetohydrodynamics equations for multi-ion - [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) - """ - function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - # Unpack left and right states to get the magnetic field - B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) - B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) - - v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, - equations) - v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, - equations) - - f = zero(MVector{nvariables(equations), eltype(u_ll)}) - - # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 - mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - - if orientation == 1 - # Magnetic field components from f^MHD - f6 = 0 - f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg - f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, - equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, - equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) - p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + - vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + - vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean * v1_avg - f2 = f1 * v1_avg + p_mean - f3 = f1 * v2_avg - f4 = f1 * v3_avg - - # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + - vk1_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + - f2 * v1_avg + f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + - B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk1_plus_avg * mag_norm_avg - - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - else #if orientation == 2 - # Magnetic field components from f^MHD - f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg - f7 = 0 - f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg - - # Start building the flux - f[1] = f6 - f[2] = f7 - f[3] = f8 - - # Iterate over all components - for k in eachcomponent(equations) - # Unpack left and right states - rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, - equations) - rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, - equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_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 - - p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) - p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr - # for convenience store vk_plus⋅B - vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + - vk3_plus_ll[k] * B3_ll - vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + - vk3_plus_rr[k] * B3_rr - - # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) - rho_mean = ln_mean(rho_ll, rho_rr) - beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) - # v_minus - vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] - vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] - vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] - vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] - vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] - vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - - # Ignore orientation since it is always "1" in 1D - f1 = rho_mean * v2_avg - f2 = f1 * v1_avg - f3 = f1 * v2_avg + p_mean - f4 = f1 * v3_avg - - # total energy flux is complicated and involves the previous eight components - v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + - vk2_plus_rr[k] * mag_norm_rr) - # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + - f2 * v1_avg + f3 * v2_avg + f4 * v3_avg - # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + - B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) - + 0.5 * vk2_plus_avg * mag_norm_avg - - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - - - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms coming from the non-conservative term 3 (induction equation!) - - set_component!(f, k, f1, f2, f3, f4, f5, equations) - end - end - - return SVector(f) + return SVector(f) +end + +""" +Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages +The term is composed of three parts +* The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". +* The MHD term: Implemented +* The "term 3": Implemented +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + # Compute important averages + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Electron pressure + pe_rr = equations.electron_pressure(u_rr, equations) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(real(equations)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] end + charge_ratio_ll ./= total_electron_charge - """ - # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed - """ - @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) - # Calculate fast magnetoacoustic wave speeds - # left - cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) - # right - cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) - - # Calculate velocities - v_ll = zero(eltype(u_ll)) - v_rr = zero(eltype(u_rr)) - if orientation == 1 - for k in eachcomponent(equations) - rho, rho_v1, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v1 / rho)) - rho, rho_v1, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v1 / rho)) - end - else #if orientation == 2 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) - v_ll = max(v_ll, abs(rho_v2 / rho)) - rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) - v_rr = max(v_rr, abs(rho_v2 / rho)) - end - end + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) - λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) - end + f = zero(MVector{nvariables(equations), eltype(u_ll)}) - @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) - v1 = zero(real(equations)) - v2 = zero(real(equations)) + if orientation == 1 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B1_rr + f[2] = v2_plus_ll * B1_rr + f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) - rho, rho_v1, rho_v2, _ = get_component(k, u, equations) - v1 = max(v1, abs(rho_v1 / rho)) - v2 = max(v2, abs(rho_v2 / rho)) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) + f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) + f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) + f5 = vk1_plus_ll[k] * pe_rr + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B1_rr + f3 += charge_ratio_ll[k] * B2_ll * B1_rr + f4 += charge_ratio_ll[k] * B3_ll * B1_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end + else #if orientation == 2 + # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + f[1] = v1_plus_ll * B2_rr + f[2] = v2_plus_ll * B2_rr + f[3] = v3_plus_ll * B2_rr - cf_x_direction = calc_fast_wavespeed(u, 1, equations) - cf_y_direction = calc_fast_wavespeed(u, 2, equations) - - return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) - end - - """ - Convert conservative variables to primitive - """ - function cons2prim(u, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) + # Compute term 2 (MHD) + f2 = charge_ratio_ll[k] * (-B2_rr * B1_rr) + f3 = charge_ratio_ll[k] * (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) + f4 = charge_ratio_ll[k] * (-B2_rr * B3_rr) + f5 = vk2_plus_ll[k] * pe_rr + + # Compute term 3 (only needed for NCOMP>1) + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + + B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr)) + + # Compute Powell term (already consistent with Trixi's non-conservative discretization) + f2 += charge_ratio_ll[k] * B1_ll * B2_rr + f3 += charge_ratio_ll[k] * B2_ll * B2_rr + f4 += charge_ratio_ll[k] * B3_ll * B2_rr + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + + # It's not needed to adjust to Trixi's non-conservative form + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) end - - return SVector(prim) end - """ - Convert conservative variables to entropy - """ - @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) + return SVector(f) +end + +""" +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) + +Entropy conserving two-point flux adapted by: +- Rueda-Ramírez et al. (2023) +This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: +- Derigs et al. (2018) + Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) + B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Compute averages for global variables + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + + if orientation == 1 + # Magnetic field components from f^MHD + f6 = 0 + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk1_plus_avg * mag_norm_avg - + vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - + vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - - return SVector(entropy) - end - - """ - Convert primitive to conservative variables - """ - @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 + else #if orientation == 2 + # Magnetic field components from f^MHD + f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg + f7 = 0 + f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + + # Iterate over all components for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p / (gammas[k] - 1.0) + - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Ignore orientation since it is always "1" in 1D + f1 = rho_mean * v2_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_mean + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + + vk2_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + 0.5 * vk2_plus_avg * mag_norm_avg - + vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - + vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + - + B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - + B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) end - - return SVector(cons) end - """ - Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! - """ - @inline function calc_fast_wavespeed(cons, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(cons, equations) - - c_f = zero(real(equations)) + return SVector(f) +end + +""" +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation + !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed +""" +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + if orientation == 1 for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) - a_square = gamma * p / rho - sqrt_rho = sqrt(rho) - - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho - b_square = b1^2 + b2^2 + b3^2 - - if orientation == 1 - c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) - else #if orientation == 2 - c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) - end + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + else #if orientation == 2 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v2 / rho)) + rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v2 / rho)) end - - return c_f end - """ - Routine to compute the Charge-averaged velocities: - * v*_plus: Charge-averaged velocity - * vk*_plus: Contribution of each species to the charge-averaged velocity - """ - @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) - total_electron_charge = zero(real(equations)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealMhdMultiIonEquations2D) +@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) + v1 = zero(real(equations)) + v2 = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + v2 = max(v2, abs(rho_v2 / rho)) + end - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), - SVector(vk3_plus) + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + cf_y_direction = calc_fast_wavespeed(u, 2, equations) + + return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) +end + +""" +Convert conservative variables to primitive +""" +function cons2prim(u, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) end - """ - Get the flow variables of component k - """ - @inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) + return SVector(prim) +end + +""" +Convert conservative variables to entropy +""" +@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) end - """ - Set the flow variables of component k - """ - @inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 - - return u + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + + return SVector(entropy) +end + +""" +Convert primitive to conservative variables +""" +@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end - magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + return SVector(cons) +end + +""" +Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue + !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! +""" +@inline function calc_fast_wavespeed(cons, orientation::Integer, + equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(cons, equations) + + c_f = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 - @inline function density(u, equations::IdealMhdMultiIonEquations2D) - rho = zero(real(equations)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] + if orientation == 1 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + else #if orientation == 2 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) end - return rho end - """ - Computes the sum of the densities times the sum of the pressures - """ - @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(u, equations) - rho_total = zero(real(equations)) - p_total = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) - - rho_total += rho - p_total += p - end - return rho_total * p_total + return c_f +end + +""" +Routine to compute the Charge-averaged velocities: +* v*_plus: Charge-averaged velocity +* vk*_plus: Contribution of each species to the charge-averaged velocity +""" +@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) + total_electron_charge = zero(real(equations)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations::IdealMhdMultiIonEquations2D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) +end + +""" +Get the flow variables of component k +""" +@inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" +Set the flow variables of component k +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealMhdMultiIonEquations2D) + # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + + return u +end + +magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + +@inline function density(u, equations::IdealMhdMultiIonEquations2D) + rho = zero(real(equations)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho +end + +""" +Computes the sum of the densities times the sum of the pressures +""" +@inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(u, equations) + rho_total = zero(real(equations)) + p_total = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + + rho_total += rho + p_total += p end + return rho_total * p_total +end end # @muladd From 1731bcaceea2ac4bbe2eb4124255a108e8489081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:31:47 +0100 Subject: [PATCH 046/108] Added empty line at the beginning of elixirs for format --- examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl | 1 + examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 1 + examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 4763f76ec05..95d1bd75bdf 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -1,3 +1,4 @@ + using OrdinaryDiffEq using Trixi diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 938a0169078..97f0d137a06 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -1,3 +1,4 @@ + using OrdinaryDiffEq using Trixi diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index ead9f4fd9fa..4dec6d9d1c5 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -1,3 +1,4 @@ + using OrdinaryDiffEq using Trixi From 7f58f919a7a981eb28d3190c91b112bb5f43ab96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:47:18 +0100 Subject: [PATCH 047/108] Removed comment --- examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index 81218f5545e..fc352096559 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -8,7 +8,6 @@ equations = IdealMhdMultiIonEquations1D(gammas = (2.0, 2.0), initial_condition = initial_condition_weak_blast_wave -#volume_flux = flux_central volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) solver = DGSEM(polydeg = 3, surface_flux = surface_flux, From 1f85e98be65b8511c6cb730e42f6bc6d9779e001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 11:54:34 +0100 Subject: [PATCH 048/108] Remove empty line --- examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 95d1bd75bdf..4763f76ec05 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -1,4 +1,3 @@ - using OrdinaryDiffEq using Trixi From db516000a414354a47dbc045ea65980e301d0fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 6 Nov 2023 12:13:24 +0100 Subject: [PATCH 049/108] Added empty lines at the end of elixirs for formatting --- examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl | 2 +- examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 4763f76ec05..4b3cb674259 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -52,4 +52,4 @@ callbacks = CallbackSet(summary_callback, sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 97f0d137a06..b774abd3047 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -53,4 +53,4 @@ callbacks = CallbackSet(summary_callback, sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl index 4dec6d9d1c5..e221fae4ca2 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl @@ -155,4 +155,4 @@ callbacks = CallbackSet(summary_callback, sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary \ No newline at end of file +summary_callback() # print the timer summary From 84966bee752c0bd1069f1e47c698a98c52c3166b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 7 Nov 2023 10:49:10 +0100 Subject: [PATCH 050/108] Updated tests of the multi-ion MHD equations after bug fixes --- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 56 ++++++ .../tree_2d_dgsem/elixir_mhdmultiion_rotor.jl | 158 ---------------- test/test_tree_1d_mhdmultiion.jl | 174 +++++++++++++----- test/test_tree_2d_mhdmultiion.jl | 71 ++++--- 4 files changed, 225 insertions(+), 234 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl delete mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl new file mode 100644 index 00000000000..6b35b915f54 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -0,0 +1,56 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_standard) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 100 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +stepsize_callback = StepsizeCallback(cfl = 0.5) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl deleted file mode 100644 index e221fae4ca2..00000000000 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_rotor.jl +++ /dev/null @@ -1,158 +0,0 @@ - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations2D(gammas = (1.4, 1.4), - charge_to_mass = (1.0, 2.0)) - -""" - initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) - -The classical MHD rotor test case. Here, the setup is taken from -- Dominik Derigs, Gregor J. Gassner, Stefanie Walch & Andrew R. Winters (2018) - Entropy Stable Finite Volume Approximations for Ideal Magnetohydrodynamics - [doi: 10.1365/s13291-018-0178-9](https://doi.org/10.1365/s13291-018-0178-9) -""" -function initial_condition_rotor(x, t, equations::IdealMhdMultiIonEquations2D) - # setup taken from Derigs et al. DMV article (2018) - # domain must be [0, 1] x [0, 1], γ = 1.4 - B1 = 5.0 / sqrt(4.0 * pi) - B2 = 0.0 - B3 = 0.0 - - # first species - dx = x[1] - 0.25 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r) / 0.015 - if r <= 0.1 - rho = 10.0 - v1 = -20.0 * dy - v2 = 20.0 * dx - elseif r >= 0.115 - if x[1] > 0.75 - rho = 0.49 * (tanh(50 * (x[1] - 1.0)) + 1) + 0.02 - elseif x[1] > 0.25 - rho = 0.49 * (-tanh(50 * (x[1] - 0.5)) + 1) + 0.02 - else - rho = 0.49 * (tanh(50 * (x[1])) + 1) + 0.02 - end - v1 = 0.0 - v2 = 0.0 - else - rho = 1.0 + 9.0 * f - v1 = -20.0 * f * dy - v2 = 20.0 * f * dx - end - v3 = 0.0 - p = 1.0 - - #second species - dx = x[1] - 0.75 - dy = x[2] - 0.5 - r = sqrt(dx^2 + dy^2) - f = (0.115 - r) / 0.015 - if r <= 0.1 - rho2 = 10.0 - v12 = -20.0 * dy - v22 = 20.0 * dx - elseif r >= 0.115 - if x[1] < 0.25 - rho2 = 0.49 * (-tanh(50 * (x[1])) + 1) + 0.02 - elseif x[1] < 0.75 - rho2 = 0.49 * (tanh(50 * (x[1] - 0.5)) + 1) + 0.02 - else - rho2 = 0.49 * (-tanh(50 * (x[1] - 1.0)) + 1) + 0.02 - end - v12 = 0.0 - v22 = 0.0 - else - rho2 = 1.0 + 9.0 * f - v12 = -20.0 * f * dy - v22 = 20.0 * f * dx - end - v3 = 0.0 - p = 1.0 - - return prim2cons(SVector(B1, B2, B3, rho, v1, v2, v3, p, rho2, v12, v22, v3, p), - equations) -end -initial_condition = initial_condition_rotor - -volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) - -basis = LobattoLegendreBasis(3) - -indicator_sc = IndicatorHennemannGassner(equations, basis, - alpha_max = 0.5, - alpha_min = 0.001, - alpha_smooth = true, - variable = density_pressure) -volume_integral = VolumeIntegralShockCapturingHG(indicator_sc; - volume_flux_dg = volume_flux, - volume_flux_fv = surface_flux) - -solver = DGSEM(basis, surface_flux, volume_integral) - -coordinates_min = (0.0, 0.0) -coordinates_max = (1.0, 1.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 4, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 0.15) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 100 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(interval = 100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -stepsize_callback = StepsizeCallback(cfl = 0.5) - -amr_indicator = IndicatorLöhner(semi, - variable = density) - -amr_controller = ControllerThreeLevelCombined(semi, amr_indicator, indicator_sc, - base_level = 4, - med_level = 5, med_threshold = 0.02, # med_level = current level - max_level = 7, max_threshold = 0.04, - max_threshold_secondary = 0.2) - -amr_callback = AMRCallback(semi, amr_controller, - interval = 6, - adapt_initial_condition = true, - adapt_initial_condition_only_refine = true) - -save_restart = SaveRestartCallback(interval = 100, - save_final_restart = true) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - amr_callback, - save_solution, - save_restart, - stepsize_callback) - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl index c6b46b55c73..877452acce8 100644 --- a/test/test_tree_1d_mhdmultiion.jl +++ b/test/test_tree_1d_mhdmultiion.jl @@ -9,58 +9,134 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_1d_dgsem") @testset "MHD Multi-ion" begin - @trixi_testset "elixir_mhdmultiion_ec_onespecies.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec_onespecies.jl"), - l2=[4.13046273e-17, 5.47627735e-02, 5.47627735e-02, - 5.85364902e-02, 8.15735949e-02, - 5.46480229e-02, 5.46480229e-02, 1.54430906e-01], - linf=[1.11022302e-16, 9.62277600e-02, 9.62277600e-02, - 1.07398441e-01, 1.85851486e-01, - 9.41669606e-02, 9.41669606e-02, 4.10966135e-01]) - end +#! format: noindent - @trixi_testset "elixir_mhdmultiion_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), - l2=[4.13046273e-17, 4.41300832e-02, 4.08698259e-02, - 1.45921842e-02, 1.46195334e-01, - 1.46189460e-01, 1.47069647e-01, 1.15948953e-01, - 4.17156345e-02, 2.95429888e-01, - 2.91864340e-01, 2.90281705e-01, 1.91712252e-01], - linf=[1.11022302e-16, 8.23475323e-02, 8.20044181e-02, - 5.26482770e-02, 2.36978475e-01, - 1.78890885e-01, 1.83844973e-01, 3.69223717e-01, - 9.49715344e-02, 4.04059325e-01, - 3.53727376e-01, 3.43908646e-01, 3.72557303e-01]) - end +@trixi_testset "elixir_mhdmultiion_ec_onespecies.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec_onespecies.jl"), + l2=[ + 4.1304627304940003e-17, + 5.4681492967955873e-02, + 5.4681492967955873e-02, + 5.8034794143785734e-02, + 8.1686107656040716e-02, + 5.4627972898756594e-02, + 5.4627972898756594e-02, + 1.5559804954845133e-01, + ], + linf=[ + 1.1102230246251565e-16, + 1.0756082592909055e-01, + 1.0756082592909055e-01, + 1.1699453974473184e-01, + 1.8782944777819507e-01, + 9.8288863211692001e-02, + 9.8288863211692001e-02, + 4.3538944922452361e-01, + ]) +end - @trixi_testset "elixir_mhdmultiion_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), - l2=[4.13046273e-17, 4.34692117e-02, 4.01800240e-02, - 1.39798040e-02, 1.45588748e-01, - 1.46145114e-01, 1.47018561e-01, 1.07728669e-01, - 4.13841438e-02, 2.95261011e-01, - 2.91827041e-01, 2.90260310e-01, 1.90243105e-01], - linf=[1.11022302e-16, 7.89266630e-02, 7.79256051e-02, - 4.76391824e-02, 2.07007992e-01, - 1.79314301e-01, 1.84325683e-01, 3.47578503e-01, - 9.30059101e-02, 3.81670634e-01, - 3.53221946e-01, 3.43511206e-01, 3.75916013e-01]) - end +@trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[ + 4.1304627304940003e-17, + 4.3626365427359211e-02, + 4.3597997802536363e-02, + 2.3507245682869861e-02, + 4.6610769145871714e-02, + 1.4848843852905394e-02, + 1.7839683917849288e-02, + 1.3457845268573115e-01, + 3.8214585380506302e-02, + 5.2755332770791419e-02, + 3.3071810251645600e-02, + 3.0160701292947324e-02, + 8.5619654328485756e-02, + ], + linf=[ + 1.1102230246251565e-16, + 9.1215410389221874e-02, + 9.1205447402732065e-02, + 7.1152999945483464e-02, + 1.2176089138259275e-01, + 3.2242944708070438e-02, + 3.8890545935514498e-02, + 3.4213021755787931e-01, + 8.5324175333816754e-02, + 1.0941185893660356e-01, + 6.7106846800977699e-02, + 6.0449563579190013e-02, + 1.8998760735672127e-01, + ]) +end - @trixi_testset "elixir_mhdmultiion_es_shock_capturing.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, - "elixir_mhdmultiion_es_shock_capturing.jl"), - l2=[4.13046273e-17, 4.34327035e-02, 4.01429579e-02, - 1.39648331e-02, 1.45589699e-01, - 1.46145036e-01, 1.47013130e-01, 1.07647870e-01, - 4.13842626e-02, 2.95252636e-01, - 2.91824474e-01, 2.90263048e-01, 1.90199794e-01], - linf=[1.11022302e-16, 7.86144728e-02, 7.75970804e-02, - 4.75320603e-02, 2.07019087e-01, - 1.79245486e-01, 1.84254005e-01, 3.47166288e-01, - 9.16953877e-02, 3.81637525e-01, - 3.53188856e-01, 3.43474263e-01, 3.75932899e-01]) - end +@trixi_testset "elixir_mhdmultiion_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), + l2=[ + 4.1304627304940003e-17, + 4.2553038586026444e-02, + 4.2527236533326879e-02, + 2.3251091453701061e-02, + 4.4654486530370789e-02, + 1.4619805774071728e-02, + 1.7643391664085059e-02, + 1.2712914702892930e-01, + 3.8469247812943669e-02, + 5.2336025462555114e-02, + 3.2727028006044219e-02, + 2.9776912791966450e-02, + 8.4012739159795263e-02, + ], + linf=[ + 1.1102230246251565e-16, + 8.2210559138160888e-02, + 8.2218565022087908e-02, + 6.5729098364666283e-02, + 1.1094270689375808e-01, + 2.4700103166055636e-02, + 3.2091406020875547e-02, + 3.1521158925312243e-01, + 8.5168856942823057e-02, + 1.0770235761746386e-01, + 5.1134001263296432e-02, + 4.3948680822294889e-02, + 1.6265858425106705e-01, + ]) +end + +@trixi_testset "elixir_mhdmultiion_es_shock_capturing.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, + "elixir_mhdmultiion_es_shock_capturing.jl"), + l2=[ + 4.1304627304940003e-17, + 4.2551420656608052e-02, + 4.2525625623064091e-02, + 2.3250220525587818e-02, + 4.4653027389729920e-02, + 1.4619390203068858e-02, + 1.7642992953968012e-02, + 1.2712366369768024e-01, + 3.8467995219616406e-02, + 5.2334692216684658e-02, + 3.2726030774880857e-02, + 2.9775868343442317e-02, + 8.4007321361367848e-02, + ], + linf=[ + 1.1102230246251565e-16, + 8.2196712187582066e-02, + 8.2204692538675128e-02, + 6.5725380494179808e-02, + 1.1093829329448765e-01, + 2.4696553126525956e-02, + 3.2087364118652505e-02, + 3.1519746333592513e-01, + 8.5161488531380058e-02, + 1.0769856292976031e-01, + 5.1128616588110090e-02, + 4.3943599376482068e-02, + 1.6265341537651956e-01, + ]) +end end end # module diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index 2a4ad3de221..6512663b506 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -9,34 +9,51 @@ include("test_trixi.jl") EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2d_dgsem") @testset "MHD Multi-ion" begin - @trixi_testset "elixir_mhdmultiion_ec.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), - l2=[1.56133690e-02, 1.56211211e-02, 2.44289260e-02, - 1.17053210e-02, 1.35748661e-01, - 1.35779534e-01, 1.34646112e-01, 1.34813656e-01, - 1.93724876e-02, 2.70357315e-01, - 2.70356924e-01, 2.69252524e-01, 1.86315505e-01], - linf=[1.06156769e-01, 1.15019769e-01, 1.32816030e-01, - 7.65402322e-02, 2.45518940e-01, - 2.46123607e-01, 1.82733442e-01, 4.24743430e-01, - 1.27620999e-01, 4.58874938e-01, - 4.65364246e-01, 3.56983044e-01, 3.94035665e-01]) - end +#! format: noindent - @trixi_testset "elixir_mhdmultiion_rotor.jl tspan = (0., 0.001)" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_rotor.jl"), - l2=[9.10689060e-03, 1.57109974e-02, 5.47502000e-06, - 4.33887866e-02, 6.85503869e-02, - 6.44021766e-02, 2.79487163e-03, 7.85539922e-02, - 4.33883209e-02, 6.85496075e-02, - 6.44066193e-02, 5.58969701e-03, 7.85504216e-02], - linf=[1.47204796e-01, 2.33759231e-01, 2.89189051e-05, - 1.06452623e+00, 3.36709456e+00, - 2.93566426e+00, 1.53123364e-02, 3.99872907e+00, - 1.06455108e+00, 3.36725655e+00, - 2.93570704e+00, 3.05339471e-02, 3.99892281e+00], - tspan=(0.0, 0.001)) - end +@trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[ + 1.5557198040058215e-02, 1.5561198523962436e-02, + 2.4410457949025310e-02, 1.1344868834133841e-02, + 1.8626149391184826e-02, 1.8719830298030603e-02, + 6.8963004644178256e-03, 1.0465244373132600e-01, + 1.8691974336498236e-02, 2.8258773607345654e-02, + 2.8130992204006531e-02, 1.3859402020143092e-02, + 8.9892546634939050e-02, + ], + linf=[ + 8.6698171128154478e-02, 8.9223437132718741e-02, + 1.0624940128583993e-01, 5.5291033171599724e-02, + 1.1495494812039142e-01, 1.0381359740462957e-01, + 4.2436775232064218e-02, 5.2806012024968041e-01, + 1.0937172169536147e-01, 2.0286418034545392e-01, + 1.9274686956407905e-01, 9.1713317178251763e-02, + 5.0302723967694263e-01, + ]) +end + +@trixi_testset "elixir_mhdmultiion_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), + l2=[ + 1.5319585024958093e-02, 1.5322497339615212e-02, + 2.4107479679804287e-02, 1.1166706297428615e-02, + 1.8044343530506653e-02, 1.8141881194840042e-02, + 6.8164634011262104e-03, 1.0315687185431269e-01, + 1.8776826173845702e-02, 2.8168829726671649e-02, + 2.8041409057574292e-02, 1.3711442812290676e-02, + 8.9987200150509539e-02, + ], + linf=[ + 4.5244015084714539e-02, 4.5229288526366540e-02, + 9.0657122074956020e-02, 4.9004662466521465e-02, + 7.5791977835092991e-02, 7.6446433484144830e-02, + 3.2763360958124675e-02, 3.6867066527392822e-01, + 1.1151774062868847e-01, 1.5930447057310282e-01, + 1.5758954335858896e-01, 6.6688837243764412e-02, + 3.6242864449799805e-01, + ]) +end end end # module From 1dd114d46b04bae6f6f22d4c472844132a0c11d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 7 Nov 2023 10:49:30 +0100 Subject: [PATCH 051/108] format --- src/equations/ideal_mhd_multiion_1d.jl | 27 +++++++++++--------------- src/equations/ideal_mhd_multiion_2d.jl | 23 ++++++++-------------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 4824c664778..3365bbfc715 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -15,17 +15,12 @@ mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: gammas :: SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass :: SVector{NCOMP, RealT} # Charge to mass ratios - function IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP, - RealT}, - charge_to_mass::SVector{ - NCOMP, - RealT - }) where { - NVARS, - NCOMP, - RealT <: - Real - } + function IdealMhdMultiIonEquations1D{NVARS, NCOMP, + RealT}(gammas + ::SVector{NCOMP, RealT}, + charge_to_mass + ::SVector{NCOMP, RealT}) where + {NVARS, NCOMP, RealT <: Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) @@ -310,7 +305,7 @@ The term is composed of three parts # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) - total_electron_charge = zero(eltype(u_ll)) + total_electron_charge = zero(real(equations)) for k in eachcomponent(equations) rho_k = u_ll[3 + (k - 1) * 5 + 1] charge_ratio_ll[k] = rho_k * charge_to_mass[k] @@ -504,7 +499,7 @@ end end @inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations1D) - v1 = zero(eltype(u)) + v1 = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, _ = get_component(k, u, equations) v1 = max(v1, abs(rho_v1 / rho)) @@ -610,7 +605,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco equations::IdealMhdMultiIonEquations1D) B1, B2, B3 = magnetic_field(cons, equations) - c_f = zero(cons[1]) + c_f = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) @@ -642,7 +637,7 @@ Routine to compute the charge-averaged velocities: * vk*_plus: Contribution of each species to the charge-averaged velocity """ @inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) - total_electron_charge = zero(eltype(u)) + total_electron_charge = zero(real(equations)) vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) @@ -696,7 +691,7 @@ end magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) @inline function density(u, equations::IdealMhdMultiIonEquations1D) - rho = zero(eltype(u)) + rho = zero(real(equations)) for k in eachcomponent(equations) rho += u[3 + (k - 1) * 5 + 1] end diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index a3fb4924896..a93ef48addf 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -17,21 +17,14 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, Electron charge_to_mass::SVector{NCOMP, RealT} # Charge to mass ratios electron_pressure::ElectronPressure # Function to compute the electron pressure - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}(gammas::SVector{ - NCOMP, - RealT - }, - charge_to_mass::SVector{ - NCOMP, - RealT - }, - electron_pressure::ElectronPressure) where { - NVARS, - NCOMP, - RealT <: - Real, - ElectronPressure - } + function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + ElectronPressure}(gammas + ::SVector{NCOMP, RealT}, + charge_to_mass + ::SVector{NCOMP, RealT}, + electron_pressure + ::ElectronPressure) where + {NVARS, NCOMP, RealT <: Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) From 4462871a64b6687b19cda33ad679e11d4ee7adc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 7 Nov 2023 10:58:06 +0100 Subject: [PATCH 052/108] format --- src/equations/ideal_mhd_multiion_1d.jl | 2 +- src/equations/ideal_mhd_multiion_2d.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 3365bbfc715..2bd6b5e09be 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -20,7 +20,7 @@ mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: ::SVector{NCOMP, RealT}, charge_to_mass ::SVector{NCOMP, RealT}) where - {NVARS, NCOMP, RealT <: Real} + {NVARS, NCOMP, RealT <: Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index a93ef48addf..c2c53332f91 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -24,7 +24,7 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, Electron ::SVector{NCOMP, RealT}, electron_pressure ::ElectronPressure) where - {NVARS, NCOMP, RealT <: Real, ElectronPressure} + {NVARS, NCOMP, RealT <: Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) From a3fb5e5ee872bbaf688da75bea9a2559e8eb3e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 12 Dec 2023 18:44:05 +0100 Subject: [PATCH 053/108] format --- test/test_tree_2d_euler.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_tree_2d_euler.jl b/test/test_tree_2d_euler.jl index 212fded51bc..65899cd5263 100644 --- a/test/test_tree_2d_euler.jl +++ b/test/test_tree_2d_euler.jl @@ -217,13 +217,13 @@ end 0.08508152653623638, 0.04510301725066843, 0.04510304668512745, - 0.6930705064715306 + 0.6930705064715306, ], linf=[ 0.31136518019691406, 0.5617651935473419, 0.5621200790240503, - 2.8866869108596056 + 2.8866869108596056, ]) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) From 86f7ab817aaca2dd811b9d8169786ccbfce2e8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 13 Dec 2023 10:35:35 +0100 Subject: [PATCH 054/108] format --- src/equations/ideal_mhd_multiion_1d.jl | 2 +- src/equations/ideal_mhd_multiion_2d.jl | 6 +++--- .../semidiscretization_euler_acoustics.jl | 10 +++++----- .../semidiscretization_euler_gravity.jl | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 2bd6b5e09be..f255b2d0bee 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -20,7 +20,7 @@ mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: ::SVector{NCOMP, RealT}, charge_to_mass ::SVector{NCOMP, RealT}) where - {NVARS, NCOMP, RealT <: Real} + {NVARS, NCOMP, RealT <: Real} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index c2c53332f91..ef333d0bb3c 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -10,8 +10,8 @@ The ideal compressible multi-ion MHD equations in two space dimensions. """ -mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure - } <: +mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, + ElectronPressure} <: AbstractIdealMhdMultiIonEquations{2, NVARS, NCOMP} gammas::SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass::SVector{NCOMP, RealT} # Charge to mass ratios @@ -24,7 +24,7 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, Electron ::SVector{NCOMP, RealT}, electron_pressure ::ElectronPressure) where - {NVARS, NCOMP, RealT <: Real, ElectronPressure} + {NVARS, NCOMP, RealT <: Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) diff --git a/src/semidiscretization/semidiscretization_euler_acoustics.jl b/src/semidiscretization/semidiscretization_euler_acoustics.jl index e49fe81177a..173523ff892 100644 --- a/src/semidiscretization/semidiscretization_euler_acoustics.jl +++ b/src/semidiscretization/semidiscretization_euler_acoustics.jl @@ -51,11 +51,11 @@ function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics, semi_euler::SemiEuler; source_region = x -> true, weights = x -> 1.0) where - {Mesh, - SemiAcoustics <: - SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} + {Mesh, + SemiAcoustics <: + SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations}, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}} cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights, mesh_equations_solver_cache(semi_acoustics)...) diff --git a/src/semidiscretization/semidiscretization_euler_gravity.jl b/src/semidiscretization/semidiscretization_euler_gravity.jl index a9a60a4ff04..4201344df80 100644 --- a/src/semidiscretization/semidiscretization_euler_gravity.jl +++ b/src/semidiscretization/semidiscretization_euler_gravity.jl @@ -117,11 +117,11 @@ Construct a semidiscretization of the compressible Euler equations with self-gra function SemidiscretizationEulerGravity(semi_euler::SemiEuler, semi_gravity::SemiGravity, parameters) where - {Mesh, - SemiEuler <: - SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, - SemiGravity <: - SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} + {Mesh, + SemiEuler <: + SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}, + SemiGravity <: + SemidiscretizationHyperbolic{Mesh, <:AbstractHyperbolicDiffusionEquations}} u_ode = compute_coefficients(zero(real(semi_gravity)), semi_gravity) du_ode = similar(u_ode) u_tmp1_ode = similar(u_ode) From 31d27ad8d6bd3449c374b058f91220de0ef03e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 19 Dec 2023 15:46:24 +0100 Subject: [PATCH 055/108] Implemented GLM divergence cleaning for multi-ion MHD --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 9 +- src/callbacks_step/glm_speed_dg.jl | 6 +- src/equations/ideal_mhd_multiion_2d.jl | 108 ++++++++++++++---- 3 files changed, 94 insertions(+), 29 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index b774abd3047..c2247869c9a 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -40,12 +40,17 @@ save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, save_final_solution = true, solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 0.5) +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, - stepsize_callback) + stepsize_callback, + glm_speed_callback) ############################################################################### # run the simulation diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index 302aae356ab..61426b0d95e 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -7,7 +7,8 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations}, + AbstractIdealGlmMhdMulticomponentEquations, + IdealMhdMultiIonEquations2D}, dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes @@ -20,7 +21,8 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations}, + AbstractIdealGlmMhdMulticomponentEquations, + IdealMhdMultiIonEquations2D}, dg::DGMulti, cache) rd = dg.basis md = mesh.md diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index ef333d0bb3c..985c260cbe7 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -16,29 +16,31 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, 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 function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, ElectronPressure}(gammas ::SVector{NCOMP, RealT}, charge_to_mass ::SVector{NCOMP, RealT}, electron_pressure - ::ElectronPressure) where + ::ElectronPressure, + c_h::RealT) where {NVARS, NCOMP, RealT <: Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) - new(gammas, charge_to_mass, electron_pressure) + new(gammas, charge_to_mass, electron_pressure, c_h) end end function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, - electron_pressure = electron_pressure_zero) + electron_pressure = electron_pressure_zero, + initial_c_h = convert(eltype(gammas), NaN)) _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - NVARS = length(_gammas) * 5 + 3 + NVARS = length(_gammas) * 5 + 4 NCOMP = length(_gammas) __gammas = SVector(map(RealT, _gammas)) @@ -46,7 +48,8 @@ function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, __charge_to_mass, - electron_pressure) + electron_pressure, + initial_c_h) end @inline function Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { @@ -66,6 +69,7 @@ function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), "rho_v3_" * string(i), "rho_e_" * string(i))...) end + cons = (cons..., "psi") return cons end @@ -77,6 +81,7 @@ function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), "v3_" * string(i), "p_" * string(i))...) end + prim = (prim..., "psi") return prim end @@ -155,16 +160,18 @@ end # Calculate 1D flux in for a single point @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) - + psi = divergence_cleaning_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + div_clean_energy = 0.5 * psi^2 f = zero(MVector{nvariables(equations), eltype(u)}) if orientation == 1 - f[1] = 0 + f[1] = equations.c_h * psi f[2] = v1_plus * B2 - v2_plus * B1 f[3] = v1_plus * B3 - v3_plus * B1 @@ -176,21 +183,21 @@ end kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) f1 = rho_v1 f2 = rho_v1 * v1 + p f3 = rho_v1 * v2 f4 = rho_v1 * v3 f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + equations.c_h * psi * B1 set_component!(f, k, f1, f2, f3, f4, f5, equations) end - + f[end] = equations.c_h * B1 else #if orientation == 2 f[1] = v2_plus * B1 - v1_plus * B2 - f[2] = 0 + f[2] = equations.c_h * psi f[3] = v2_plus * B3 - v3_plus * B2 for k in eachcomponent(equations) @@ -201,17 +208,18 @@ end kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - kin_en - mag_en) + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) f1 = rho_v2 f2 = rho_v2 * v1 f3 = rho_v2 * v2 + p f4 = rho_v2 * v3 f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + equations.c_h * psi * B2 set_component!(f, k, f1, f2, f3, f4, f5, equations) end + f[end] = equations.c_h * B2 end return SVector(f) @@ -271,6 +279,8 @@ The term is composed of three parts # Unpack left and right states to get the magnetic field 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) # Compute important averages B1_avg = 0.5 * (B1_ll + B1_rr) @@ -342,9 +352,14 @@ The term is composed of three parts f4 += charge_ratio_ll[k] * B3_ll * B1_rr f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * psi_rr + # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end + # Compute GLM term for psi + f[end] = v1_plus_ll * psi_rr else #if orientation == 2 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) @@ -386,9 +401,14 @@ The term is composed of three parts f4 += charge_ratio_ll[k] * B3_ll * B2_rr f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * psi_rr + # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end + # Compute GLM term for psi + f[end] = v2_plus_ll * psi_rr end return SVector(f) @@ -407,6 +427,8 @@ The term is composed of three parts # Unpack left and right states to get the magnetic field 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) # Compute important averages mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 @@ -457,11 +479,17 @@ The term is composed of three parts f4 += charge_ratio_ll[k] * B3_ll * B1_rr f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * psi_rr + # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end + # Compute GLM term for psi + f[end] = v1_plus_ll * psi_rr + else #if orientation == 2 # Entries of Powell term for induction equation (already in Trixi's non-conservative form) f[1] = v1_plus_ll * B2_rr @@ -488,11 +516,16 @@ The term is composed of three parts f4 += charge_ratio_ll[k] * B3_ll * B2_rr f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * psi_rr + # It's not needed to adjust to Trixi's non-conservative form # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end + # Compute GLM term for psi + f[end] = v2_plus_ll * psi_rr end return SVector(f) @@ -515,6 +548,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, # Unpack left and right states to get the magnetic field 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) v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, equations) @@ -533,17 +568,22 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) if orientation == 1 + psi_B1_avg = 0.5 * (B1_ll * psi_ll + B1_rr * psi_rr) + # Magnetic field components from f^MHD - f6 = 0 + f6 = equations.c_h * psi_avg f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + f9 = equations.c_h * B1_avg # Start building the flux f[1] = f6 f[2] = f7 f[3] = f8 + f[end] = f9 # Iterate over all components for k in eachcomponent(equations) @@ -563,9 +603,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - 0.5 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - 0.5 * psi_rr^2) beta_ll = 0.5 * rho_ll / p_ll beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B @@ -614,6 +654,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) @@ -624,15 +665,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, set_component!(f, k, f1, f2, f3, f4, f5, equations) end else #if orientation == 2 + psi_B2_avg = 0.5 * (B2_ll * psi_ll + B2_rr * psi_rr) + # Magnetic field components from f^MHD f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg - f7 = 0 + f7 = equations.c_h * psi_avg f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg - + f9 = equations.c_h * B2_avg + # Start building the flux f[1] = f6 f[2] = f7 f[3] = f8 + f[end] = f9 # Iterate over all components for k in eachcomponent(equations) @@ -652,9 +697,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll) + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - 0.5 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr) + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - 0.5 * psi_rr^2) beta_ll = 0.5 * rho_ll / p_ll beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B @@ -703,6 +748,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, # MHD part f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) @@ -772,6 +818,7 @@ Convert conservative variables to primitive function cons2prim(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) prim = zero(MVector{nvariables(equations), eltype(u)}) prim[1] = B1 @@ -786,10 +833,12 @@ function cons2prim(u, equations::IdealMhdMultiIonEquations2D) p = (gammas[k] - 1) * (rho_e - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3)) + + B1 * B1 + B2 * B2 + B3 * B3 + + psi * psi)) set_component!(prim, k, rho, v1, v2, v3, p, equations) end + prim[end] = psi return SVector(prim) end @@ -800,6 +849,7 @@ Convert conservative variables to entropy @inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) prim = cons2prim(u, equations) entropy = zero(MVector{nvariables(equations), eltype(u)}) @@ -822,6 +872,7 @@ Convert conservative variables to entropy entropy[1] = rho_p_plus * B1 entropy[2] = rho_p_plus * B2 entropy[3] = rho_p_plus * B3 + entropy[end] = rho_p_plus * psi return SVector(entropy) end @@ -832,6 +883,7 @@ Convert primitive to conservative variables @inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(prim, equations) + psi = divergence_cleaning_field(prim, equations) cons = zero(MVector{nvariables(equations), eltype(prim)}) cons[1] = B1 @@ -845,10 +897,12 @@ Convert primitive to conservative variables rho_e = p / (gammas[k] - 1.0) + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) + 0.5 * (B1^2 + B2^2 + B3^2) + + 0.5 * psi^2 set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end + cons[end] = psi return SVector(cons) end @@ -860,6 +914,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco @inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(cons, equations) + psi = divergence_cleaning_field(cons, equations) c_f = zero(real(equations)) for k in eachcomponent(equations) @@ -870,7 +925,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco v3 = rho_v3 / rho v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) a_square = gamma * p / rho sqrt_rho = sqrt(rho) @@ -953,6 +1008,7 @@ Set the flow variables of component k end magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) +divergence_cleaning_field(u, equations::IdealMhdMultiIonEquations2D) = u[end] @inline function density(u, equations::IdealMhdMultiIonEquations2D) rho = zero(real(equations)) @@ -967,6 +1023,8 @@ Computes the sum of the densities times the sum of the pressures """ @inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(cons, equations) + rho_total = zero(real(equations)) p_total = zero(real(equations)) for k in eachcomponent(equations) @@ -978,7 +1036,7 @@ Computes the sum of the densities times the sum of the pressures v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2)) + p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) rho_total += rho p_total += p From a33ad14b9ae232deda6d118cd5d359d27199c2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 24 Jan 2024 16:28:14 +0100 Subject: [PATCH 056/108] Added new ES numerical fluxes --- src/Trixi.jl | 1 + src/equations/ideal_mhd_multiion_2d.jl | 268 +++++++++++++++++++++++++ 2 files changed, 269 insertions(+) diff --git a/src/Trixi.jl b/src/Trixi.jl index 663c07a29e5..eb65828692f 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -178,6 +178,7 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, hydrostatic_reconstruction_chen_noelle, flux_nonconservative_chen_noelle, flux_hll_chen_noelle, FluxPlusDissipation, DissipationGlobalLaxFriedrichs, DissipationLocalLaxFriedrichs, + DissipationEntropyStableLump, DissipationEntropyStable, FluxLaxFriedrichs, max_abs_speed_naive, FluxHLL, min_max_speed_naive, min_max_speed_davis, min_max_speed_einfeldt, min_max_speed_chen_noelle, diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 985c260cbe7..c508b6a9fe2 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -1043,4 +1043,272 @@ Computes the sum of the densities times the sum of the pressures end return rho_total * p_total end + +""" + DissipationEntropyStableLump(max_abs_speed=max_abs_speed_naive) + +Create a local Lax-Friedrichs dissipation operator where the maximum absolute wave speed +is estimated as +`max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, +defaulting to [`max_abs_speed_naive`](@ref). +""" +struct DissipationEntropyStableLump{MaxAbsSpeed} + max_abs_speed::MaxAbsSpeed +end + +DissipationEntropyStableLump() = DissipationEntropyStableLump(max_abs_speed_naive) + +@inline function (dissipation::DissipationEntropyStableLump)(u_ll, u_rr, + orientation_or_normal_direction, + equations::IdealMhdMultiIonEquations2D) + @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.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) + + dissipation = zero(MVector{nvariables(equations), eltype(u_ll)}) + + beta_plus_ll = 0 + beta_plus_rr = 0 + # Get the lumped dissipation for all components + 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.5 * rho_ll / p_ll + beta_rr = 0.5 * 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.5 * (rho_ll + rho_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + tau = 1 / (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + p_star = 0.5 * rho_ln / beta_ln + vel_norm_avg = 0.5 * (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.5 * rho_ln * (2 * vel_avg_norm - vel_norm_avg) + + h11 = rho_ln + h22 = rho_ln * v1_avg^2 + p_mean + h33 = rho_ln * v2_avg^2 + p_mean + h44 = rho_ln * v3_avg^2 + p_mean + h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln + + vel_avg_norm * p_mean + + tau * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) + + d1 = -0.5 * λ * h11 * (w1_rr - w1_ll) + d2 = -0.5 * λ * h22 * (w2_rr - w2_ll) + d3 = -0.5 * λ * h33 * (w3_rr - w3_ll) + d4 = -0.5 * λ * h44 * (w4_rr - w4_ll) + d5 = -0.5 * λ * 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 + + # Set the magnetic field and psi terms + h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) + dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) + dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) + dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) + dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) + + return dissipation +end + +function Base.show(io::IO, d::DissipationEntropyStableLump) + print(io, "DissipationEntropyStableLump(", d.max_abs_speed, ")") +end + +""" +DissipationEntropyStable(max_abs_speed=max_abs_speed_naive) + +Create a local Lax-Friedrichs dissipation operator where the maximum absolute wave speed +is estimated as +`max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, +defaulting to [`max_abs_speed_naive`](@ref). +""" +struct DissipationEntropyStable{MaxAbsSpeed} + max_abs_speed::MaxAbsSpeed +end + +DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) + +@inline function (dissipation::DissipationEntropyStable)(u_ll, u_rr, + orientation_or_normal_direction, + equations::IdealMhdMultiIonEquations2D) + @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.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) + + dissipation = zero(MVector{nvariables(equations), eltype(u_ll)}) + + beta_plus_ll = 0 + beta_plus_rr = 0 + # Get the lumped dissipation for all components + 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.5 * rho_ll / p_ll + beta_rr = 0.5 * 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.5 * (rho_ll + rho_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + tau = 1 / (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + p_star = 0.5 * rho_ln / beta_ln + vel_norm_avg = 0.5 * (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.5 * 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.5 * λ * (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.5 * λ * (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.5 * λ * (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.5 * λ * (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 + + tau * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) + d5 = -0.5 * λ * (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 + + # Set the magnetic field and psi terms + h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) + + # diagonal entries + dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) + dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) + dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) + dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) + # Off-diagonal entries + for k in eachcomponent(equations) + _, _, _, _, w5_ll = get_component(k, w_ll, equations) + _, _, _, _, w5_rr = get_component(k, w_rr, equations) + + dissipation[1] -= 0.5 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll) + dissipation[2] -= 0.5 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll) + dissipation[3] -= 0.5 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll) + dissipation[end] -= 0.5 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll) + + ind_E = 3 + (k - 1) * 5 + 5 + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end]) + end + + return dissipation +end + +function Base.show(io::IO, d::DissipationEntropyStable) + print(io, "DissipationEntropyStable(", d.max_abs_speed, ")") +end + end # @muladd From a6b831c85bd516c51ddfcb1e9df1ec663f055500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 15 Feb 2024 15:37:17 +0100 Subject: [PATCH 057/108] Added missing terms to multi-ion ES flux --- src/equations/ideal_mhd_multiion_2d.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index c508b6a9fe2..2c94b73498f 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -1265,8 +1265,7 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) h53 = h35 h54 = h45 h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln - + vel_avg_norm * p_mean - + tau * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) + + vel_avg_norm * p_mean ) d5 = -0.5 * λ * (h51 * (w1_rr - w1_ll) + h52 * (w2_rr - w2_ll) + h53 * (w3_rr - w3_ll) + @@ -1297,11 +1296,18 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) dissipation[3] -= 0.5 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll) dissipation[end] -= 0.5 * λ * 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 ind_E = 3 + (k - 1) * 5 + 5 dissipation[ind_E] -= 0.5 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1]) dissipation[ind_E] -= 0.5 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2]) dissipation[ind_E] -= 0.5 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3]) dissipation[ind_E] -= 0.5 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end]) + + # Dissipation for the energy equation of all ion species depending on w_5 + for kk in eachcomponent(equations) + ind_E = 3 + (kk - 1) * 5 + 5 + dissipation[ind_E] -= 0.5 * λ * (h_B_psi * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) * (w5_rr - w5_ll) + end end return dissipation From 9fbd286a24e8790d9a1dc8d3ceb26749730a9477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 15 Feb 2024 15:38:19 +0100 Subject: [PATCH 058/108] Export magnetic_field and divergence_clenaing_field --- src/Trixi.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index eb65828692f..7f381fd8185 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -220,7 +220,7 @@ export density, pressure, density_pressure, velocity, global_mean_vars, equilibrium_distribution, waterheight_pressure, density_product export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, cross_helicity, - enstrophy + enstrophy, magnetic_field, divergence_cleaning_field export lake_at_rest_error export ncomponents, eachcomponent export get_component From f0f55a99549e43a28811a3552e120f20b05cac7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 21 Feb 2024 16:10:58 +0100 Subject: [PATCH 059/108] Removed 'lumped' ES flux as it is not really useful --- src/equations/ideal_mhd_multiion_2d.jl | 103 ------------------------- 1 file changed, 103 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 2c94b73498f..40d57de7ef3 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -1044,109 +1044,6 @@ Computes the sum of the densities times the sum of the pressures return rho_total * p_total end -""" - DissipationEntropyStableLump(max_abs_speed=max_abs_speed_naive) - -Create a local Lax-Friedrichs dissipation operator where the maximum absolute wave speed -is estimated as -`max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, -defaulting to [`max_abs_speed_naive`](@ref). -""" -struct DissipationEntropyStableLump{MaxAbsSpeed} - max_abs_speed::MaxAbsSpeed -end - -DissipationEntropyStableLump() = DissipationEntropyStableLump(max_abs_speed_naive) - -@inline function (dissipation::DissipationEntropyStableLump)(u_ll, u_rr, - orientation_or_normal_direction, - equations::IdealMhdMultiIonEquations2D) - @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.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) - - dissipation = zero(MVector{nvariables(equations), eltype(u_ll)}) - - beta_plus_ll = 0 - beta_plus_rr = 0 - # Get the lumped dissipation for all components - 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.5 * rho_ll / p_ll - beta_rr = 0.5 * 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.5 * (rho_ll + rho_rr) - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - tau = 1 / (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - p_star = 0.5 * rho_ln / beta_ln - vel_norm_avg = 0.5 * (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.5 * rho_ln * (2 * vel_avg_norm - vel_norm_avg) - - h11 = rho_ln - h22 = rho_ln * v1_avg^2 + p_mean - h33 = rho_ln * v2_avg^2 + p_mean - h44 = rho_ln * v3_avg^2 + p_mean - h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln - + vel_avg_norm * p_mean - + tau * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) - - d1 = -0.5 * λ * h11 * (w1_rr - w1_ll) - d2 = -0.5 * λ * h22 * (w2_rr - w2_ll) - d3 = -0.5 * λ * h33 * (w3_rr - w3_ll) - d4 = -0.5 * λ * h44 * (w4_rr - w4_ll) - d5 = -0.5 * λ * 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 - - # Set the magnetic field and psi terms - h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) - dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) - dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) - dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) - dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) - - return dissipation -end - -function Base.show(io::IO, d::DissipationEntropyStableLump) - print(io, "DissipationEntropyStableLump(", d.max_abs_speed, ")") -end - """ DissipationEntropyStable(max_abs_speed=max_abs_speed_naive) From 79ca7c0683b6b35c3c3a56fb6af7eec653c45ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 21 Feb 2024 16:12:07 +0100 Subject: [PATCH 060/108] Fixed bug in the discretization of the electron pressure! --- src/equations/ideal_mhd_multiion_2d.jl | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index 40d57de7ef3..c9e9b64311b 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -291,8 +291,9 @@ The term is composed of three parts mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) # Mean electron pressure - pe_mean = 0.5 * (equations.electron_pressure(u_ll, equations) + - equations.electron_pressure(u_rr, equations)) + pe_ll = equations.electron_pressure(u_ll, equations) + pe_rr = equations.electron_pressure(u_rr, equations) + pe_mean = 0.5 * (pe_ll + pe_rr) # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) @@ -339,12 +340,13 @@ The term is composed of three parts B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll) + f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 = (2 * f5 - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) + f5 = (2 * f5 + - vk1_plus_ll[k] * pe_ll + - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) # Compute Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B1_rr @@ -389,11 +391,12 @@ The term is composed of three parts # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll - f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll) + f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll + pe_ll) f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll - f5 = (2 * f5 - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) - - - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) + f5 = (2 * f5 + - vk2_plus_ll[k] * pe_ll + - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) # Compute Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B2_rr @@ -1047,8 +1050,10 @@ end """ DissipationEntropyStable(max_abs_speed=max_abs_speed_naive) -Create a local Lax-Friedrichs dissipation operator where the maximum absolute wave speed -is estimated as +Create a local Lax-Friedrichs-type dissipation operator that is provably entropy stable. +See: + * Rueda-Ramírez et al. (2023) +The maximum absolute wave speed is estimated as `max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, defaulting to [`max_abs_speed_naive`](@ref). """ From 9e1dbfff4fcd3b80b2692c39950efa93d76e8a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 21 Feb 2024 17:46:37 +0100 Subject: [PATCH 061/108] format --- src/equations/ideal_mhd_multiion_2d.jl | 143 +++++++++++++++---------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_mhd_multiion_2d.jl index c9e9b64311b..9aeb6f3147c 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_mhd_multiion_2d.jl @@ -161,7 +161,7 @@ end @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(u, equations) - + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) @@ -190,7 +190,8 @@ end f3 = rho_v1 * v2 f4 = rho_v1 * v3 f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - - B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + equations.c_h * psi * B1 + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B1 set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -215,7 +216,8 @@ end f3 = rho_v2 * v2 + p f4 = rho_v2 * v3 f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - - B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + equations.c_h * psi * B2 + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B2 set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -340,13 +342,17 @@ The term is composed of three parts B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! - f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + f2 = 2 * f2 - + charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll f5 = (2 * f5 - - vk1_plus_ll[k] * pe_ll - - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) + - + vk1_plus_ll[k] * pe_ll + - + B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + - + B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) # Compute Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B1_rr @@ -391,12 +397,16 @@ The term is composed of three parts # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll - f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll + pe_ll) + f3 = 2 * f3 - + charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll + pe_ll) f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll - f5 = (2 * f5 - - vk2_plus_ll[k] * pe_ll - - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) - - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) + f5 = (2 * f5 + - + vk2_plus_ll[k] * pe_ll + - + B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + - + B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) # Compute Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B2_rr @@ -606,9 +616,11 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - 0.5 * psi_ll^2) + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - + 0.5 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - 0.5 * psi_rr^2) + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - + 0.5 * psi_rr^2) beta_ll = 0.5 * rho_ll / p_ll beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B @@ -658,7 +670,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term - + 0.5 * vk1_plus_avg * mag_norm_avg - + + + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - @@ -675,7 +688,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f7 = equations.c_h * psi_avg f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg f9 = equations.c_h * B2_avg - + # Start building the flux f[1] = f6 f[2] = f7 @@ -700,9 +713,11 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - 0.5 * psi_ll^2) + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - + 0.5 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - 0.5 * psi_rr^2) + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - + 0.5 * psi_rr^2) beta_ll = 0.5 * rho_ll / p_ll beta_rr = 0.5 * rho_rr / p_rr # for convenience store vk_plus⋅B @@ -752,7 +767,8 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term - + 0.5 * vk2_plus_avg * mag_norm_avg - + + + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) - @@ -928,7 +944,8 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco v3 = rho_v3 / rho v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + p = (gamma - 1) * + (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) a_square = gamma * p / rho sqrt_rho = sqrt(rho) @@ -1039,7 +1056,8 @@ Computes the sum of the densities times the sum of the pressures v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] - p = (gamma - 1) * (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + p = (gamma - 1) * + (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) rho_total += rho p_total += p @@ -1064,12 +1082,12 @@ end DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) @inline function (dissipation::DissipationEntropyStable)(u_ll, u_rr, - orientation_or_normal_direction, - equations::IdealMhdMultiIonEquations2D) + orientation_or_normal_direction, + equations::IdealMhdMultiIonEquations2D) @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) @@ -1093,7 +1111,7 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) 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) @@ -1111,68 +1129,75 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) v2_avg = 0.5 * (v2_ll + v2_rr) v3_avg = 0.5 * (v3_ll + v3_rr) beta_avg = 0.5 * (beta_ll + beta_rr) - tau = 1 / (beta_ll + beta_rr) + tau = 1 / (beta_ll + beta_rr) p_mean = 0.5 * rho_avg / beta_avg p_star = 0.5 * rho_ln / beta_ln vel_norm_avg = 0.5 * (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.5 * rho_ln * (2 * vel_avg_norm - vel_norm_avg) - + E_bar = p_star / (gammas[k] - 1) + + 0.5 * 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.5 * λ * (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) ) + d1 = -0.5 * λ * + (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.5 * λ * (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) ) + d2 = -0.5 * λ * + (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.5 * λ * (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) ) + d3 = -0.5 * λ * + (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.5 * λ * (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) ) + d4 = -0.5 * λ * + (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.5 * λ * (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) ) + h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln + + + vel_avg_norm * p_mean) + d5 = -0.5 * λ * + (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 @@ -1181,7 +1206,7 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) end # Set the magnetic field and psi terms - h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) + h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) # diagonal entries dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) @@ -1208,7 +1233,10 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) # Dissipation for the energy equation of all ion species depending on w_5 for kk in eachcomponent(equations) ind_E = 3 + (kk - 1) * 5 + 5 - dissipation[ind_E] -= 0.5 * λ * (h_B_psi * ( B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2 )) * (w5_rr - w5_ll) + dissipation[ind_E] -= 0.5 * λ * + (h_B_psi * + (B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2)) * + (w5_rr - w5_ll) end end @@ -1218,5 +1246,4 @@ end function Base.show(io::IO, d::DissipationEntropyStable) print(io, "DissipationEntropyStable(", d.max_abs_speed, ")") end - end # @muladd From d265da63739fb7ab902e7afac4d1ec59a1e516f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 22 Nov 2024 15:41:17 +0100 Subject: [PATCH 062/108] Format --- test/test_tree_1d_mhdmultiion.jl | 16 ++++++++-------- test/test_tree_2d_mhdmultiion.jl | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl index 877452acce8..3295891eb5b 100644 --- a/test/test_tree_1d_mhdmultiion.jl +++ b/test/test_tree_1d_mhdmultiion.jl @@ -21,7 +21,7 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_1 8.1686107656040716e-02, 5.4627972898756594e-02, 5.4627972898756594e-02, - 1.5559804954845133e-01, + 1.5559804954845133e-01 ], linf=[ 1.1102230246251565e-16, @@ -31,7 +31,7 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_1 1.8782944777819507e-01, 9.8288863211692001e-02, 9.8288863211692001e-02, - 4.3538944922452361e-01, + 4.3538944922452361e-01 ]) end @@ -50,7 +50,7 @@ end 5.2755332770791419e-02, 3.3071810251645600e-02, 3.0160701292947324e-02, - 8.5619654328485756e-02, + 8.5619654328485756e-02 ], linf=[ 1.1102230246251565e-16, @@ -65,7 +65,7 @@ end 1.0941185893660356e-01, 6.7106846800977699e-02, 6.0449563579190013e-02, - 1.8998760735672127e-01, + 1.8998760735672127e-01 ]) end @@ -84,7 +84,7 @@ end 5.2336025462555114e-02, 3.2727028006044219e-02, 2.9776912791966450e-02, - 8.4012739159795263e-02, + 8.4012739159795263e-02 ], linf=[ 1.1102230246251565e-16, @@ -99,7 +99,7 @@ end 1.0770235761746386e-01, 5.1134001263296432e-02, 4.3948680822294889e-02, - 1.6265858425106705e-01, + 1.6265858425106705e-01 ]) end @@ -119,7 +119,7 @@ end 5.2334692216684658e-02, 3.2726030774880857e-02, 2.9775868343442317e-02, - 8.4007321361367848e-02, + 8.4007321361367848e-02 ], linf=[ 1.1102230246251565e-16, @@ -134,7 +134,7 @@ end 1.0769856292976031e-01, 5.1128616588110090e-02, 4.3943599376482068e-02, - 1.6265341537651956e-01, + 1.6265341537651956e-01 ]) end end diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index 6512663b506..b395053c76c 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -20,7 +20,7 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 6.8963004644178256e-03, 1.0465244373132600e-01, 1.8691974336498236e-02, 2.8258773607345654e-02, 2.8130992204006531e-02, 1.3859402020143092e-02, - 8.9892546634939050e-02, + 8.9892546634939050e-02 ], linf=[ 8.6698171128154478e-02, 8.9223437132718741e-02, @@ -29,7 +29,7 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 4.2436775232064218e-02, 5.2806012024968041e-01, 1.0937172169536147e-01, 2.0286418034545392e-01, 1.9274686956407905e-01, 9.1713317178251763e-02, - 5.0302723967694263e-01, + 5.0302723967694263e-01 ]) end @@ -42,7 +42,7 @@ end 6.8164634011262104e-03, 1.0315687185431269e-01, 1.8776826173845702e-02, 2.8168829726671649e-02, 2.8041409057574292e-02, 1.3711442812290676e-02, - 8.9987200150509539e-02, + 8.9987200150509539e-02 ], linf=[ 4.5244015084714539e-02, 4.5229288526366540e-02, @@ -51,7 +51,7 @@ end 3.2763360958124675e-02, 3.6867066527392822e-01, 1.1151774062868847e-01, 1.5930447057310282e-01, 1.5758954335858896e-01, 6.6688837243764412e-02, - 3.6242864449799805e-01, + 3.6242864449799805e-01 ]) end end From a555e558b77ad4a7c3e30ce46b5b32c59543b865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 26 Nov 2024 08:48:18 +0100 Subject: [PATCH 063/108] Removed specialized divB routines for multi-ion MHD --- src/callbacks_step/analysis_dg2d.jl | 38 ----------------------------- 1 file changed, 38 deletions(-) diff --git a/src/callbacks_step/analysis_dg2d.jl b/src/callbacks_step/analysis_dg2d.jl index e41debe8a36..e089133fa17 100644 --- a/src/callbacks_step/analysis_dg2d.jl +++ b/src/callbacks_step/analysis_dg2d.jl @@ -296,22 +296,6 @@ function analyze(::Val{:l2_divb}, du, u, t, end |> sqrt end -function analyze(::Val{:l2_divb}, du, u, t, - mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, - dg::DG, cache) - integrate_via_indices(u, mesh, equations, dg, cache, cache, - dg.basis.derivative_matrix) do u, i, j, element, equations, - dg, cache, derivative_matrix - divb = zero(eltype(u)) - for k in eachnode(dg) - divb += (derivative_matrix[i, k] * u[1, k, j, element] + - derivative_matrix[j, k] * u[2, i, k, element]) - end - divb *= cache.elements.inverse_jacobian[element] - divb^2 - end |> sqrt -end - function analyze(::Val{:l2_divb}, du, u, t, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, T8codeMesh{2}}, @@ -364,28 +348,6 @@ function analyze(::Val{:linf_divb}, du, u, t, return linf_divb end -function analyze(::Val{:linf_divb}, du, u, t, - mesh::TreeMesh{2}, equations::IdealMhdMultiIonEquations2D, - dg::DG, cache) - @unpack derivative_matrix, weights = dg.basis - - # integrate over all elements to get the divergence-free condition errors - linf_divb = zero(eltype(u)) - for element in eachelement(dg, cache) - for j in eachnode(dg), i in eachnode(dg) - divb = zero(eltype(u)) - for k in eachnode(dg) - divb += (derivative_matrix[i, k] * u[1, k, j, element] + - derivative_matrix[j, k] * u[2, i, k, element]) - end - divb *= cache.elements.inverse_jacobian[element] - linf_divb = max(linf_divb, abs(divb)) - end - end - - return linf_divb -end - function analyze(::Val{:linf_divb}, du, u, t, mesh::Union{StructuredMesh{2}, UnstructuredMesh2D, P4estMesh{2}, T8codeMesh{2}}, From ac54ebd0f60040b64b13b7627c281750a0faeb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 6 Dec 2024 16:34:36 +0100 Subject: [PATCH 064/108] Added 'GLM' to the name of the 2D multi-ion MHD equations --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 4 +- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 4 +- src/Trixi.jl | 2 +- src/callbacks_step/glm_speed_dg.jl | 4 +- src/equations/equations.jl | 2 +- ...ion_2d.jl => ideal_glm_mhd_multiion_2d.jl} | 112 +++++++++--------- 6 files changed, 66 insertions(+), 62 deletions(-) rename src/equations/{ideal_mhd_multiion_2d.jl => ideal_glm_mhd_multiion_2d.jl} (92%) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index c2247869c9a..658aa6465bc 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl index 6b35b915f54..b0dab7351ce 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealMhdMultiIonEquations2D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), + charge_to_mass = (1.0, 1.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/src/Trixi.jl b/src/Trixi.jl index aee70b75fdd..ac02bd8eb57 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -156,7 +156,7 @@ export AcousticPerturbationEquations2D, CompressibleEulerEquationsQuasi1D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, - IdealMhdMultiIonEquations1D, IdealMhdMultiIonEquations2D, + IdealMhdMultiIonEquations1D, IdealGlmMhdMultiIonEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index f8c44f37278..085dd1a7417 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -8,7 +8,7 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealMhdMultiIonEquations2D}, + IdealGlmMhdMultiIonEquations2D}, dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes @@ -30,7 +30,7 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealMhdMultiIonEquations2D}, + IdealGlmMhdMultiIonEquations2D}, dg::DGMulti, cache) rd = dg.basis md = mesh.md diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 364071ae336..1ed58759613 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -495,7 +495,7 @@ include("ideal_glm_mhd_multicomponent_2d.jl") abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end include("ideal_mhd_multiion_1d.jl") -include("ideal_mhd_multiion_2d.jl") +include("ideal_glm_mhd_multiion_2d.jl") # Retrieve number of components from equation instance for the multicomponent case @inline function ncomponents(::AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, diff --git a/src/equations/ideal_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl similarity index 92% rename from src/equations/ideal_mhd_multiion_2d.jl rename to src/equations/ideal_glm_mhd_multiion_2d.jl index 9aeb6f3147c..566b0914f96 100644 --- a/src/equations/ideal_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -6,25 +6,25 @@ #! format: noindent @doc raw""" - IdealMhdMultiIonEquations2D + IdealGlmMhdMultiIonEquations2D The ideal compressible multi-ion MHD equations in two space dimensions. """ -mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, - ElectronPressure} <: +mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, + ElectronPressure} <: AbstractIdealMhdMultiIonEquations{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 - function IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, - ElectronPressure}(gammas - ::SVector{NCOMP, RealT}, - charge_to_mass - ::SVector{NCOMP, RealT}, - electron_pressure - ::ElectronPressure, - c_h::RealT) where + function IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + ElectronPressure}(gammas + ::SVector{NCOMP, RealT}, + charge_to_mass + ::SVector{NCOMP, RealT}, + electron_pressure + ::ElectronPressure, + c_h::RealT) where {NVARS, NCOMP, RealT <: Real, ElectronPressure} NCOMP >= 1 || throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) @@ -33,9 +33,9 @@ mutable struct IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, end end -function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, - electron_pressure = electron_pressure_zero, - initial_c_h = convert(eltype(gammas), NaN)) +function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = convert(eltype(gammas), NaN)) _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) @@ -46,23 +46,24 @@ function IdealMhdMultiIonEquations2D(; gammas, charge_to_mass, __gammas = SVector(map(RealT, _gammas)) __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, - __charge_to_mass, - electron_pressure, - initial_c_h) + return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + initial_c_h) end -@inline function Base.real(::IdealMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { - NVARS, - NCOMP, - RealT - } +@inline function Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } RealT end -have_nonconservative_terms(::IdealMhdMultiIonEquations2D) = True() +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations2D) = True() -function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) +function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D) cons = ("B1", "B2", "B3") for i in eachcomponent(equations) cons = (cons..., @@ -74,7 +75,7 @@ function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations2D) return cons end -function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) +function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D) prim = ("B1", "B2", "B3") for i in eachcomponent(equations) prim = (prim..., @@ -86,16 +87,16 @@ function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations2D) return prim end -function default_analysis_integrals(::IdealMhdMultiIonEquations2D) +function default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) end # """ -# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) +# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) # An Alfvén wave as smooth initial condition used for convergence tests. # """ -# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations2D) +# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) # # smooth Alfvén wave test from Derigs et al. FLASH (2016) # # domain must be set to [0, 1], γ = 5/3 @@ -114,14 +115,15 @@ end # end """ - initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) + initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) A weak blast wave adapted from - Sebastian Hennemann, Gregor J. Gassner (2020) A provably entropy stable subcell shock capturing approach for high order split form DG [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) """ -function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations2D) +function initial_condition_weak_blast_wave(x, t, + equations::IdealGlmMhdMultiIonEquations2D) # 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 @@ -158,7 +160,8 @@ end # TODO: Add initial condition equilibrium # Calculate 1D flux in for a single point -@inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations2D) +@inline function flux(u, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(u, equations) @@ -230,7 +233,7 @@ end """ Standard source terms of the multi-ion MHD equations """ -function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) +function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) @unpack charge_to_mass = equations B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, @@ -259,10 +262,10 @@ function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations2D) end """ - electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) + electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. """ -function electron_pressure_zero(u, equations::IdealMhdMultiIonEquations2D) +function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) return zero(u[1]) end @@ -276,7 +279,7 @@ The term is composed of three parts """ @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) @@ -435,7 +438,7 @@ The term is composed of three parts * The "term 3": Implemented """ @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) @unpack charge_to_mass = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) @@ -545,7 +548,7 @@ The term is composed of three parts end """ -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealMhdMultiIonEquations2D) +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations2D) Entropy conserving two-point flux adapted by: - Rueda-Ramírez et al. (2023) @@ -556,7 +559,7 @@ This flux (together with the MHD non-conservative term) is consistent in the cas [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) """ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations # Unpack left and right states to get the magnetic field B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations) @@ -787,7 +790,7 @@ end !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed """ @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) # Calculate fast magnetoacoustic wave speeds # left cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) @@ -816,7 +819,7 @@ end λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) end -@inline function max_abs_speeds(u, equations::IdealMhdMultiIonEquations2D) +@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations2D) v1 = zero(real(equations)) v2 = zero(real(equations)) for k in eachcomponent(equations) @@ -834,7 +837,7 @@ end """ Convert conservative variables to primitive """ -function cons2prim(u, equations::IdealMhdMultiIonEquations2D) +function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(u, equations) @@ -865,7 +868,7 @@ end """ Convert conservative variables to entropy """ -@inline function cons2entropy(u, equations::IdealMhdMultiIonEquations2D) +@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(u, equations) @@ -899,7 +902,7 @@ end """ Convert primitive to conservative variables """ -@inline function prim2cons(prim, equations::IdealMhdMultiIonEquations2D) +@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(prim, equations) psi = divergence_cleaning_field(prim, equations) @@ -931,7 +934,7 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! """ @inline function calc_fast_wavespeed(cons, orientation::Integer, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(cons, equations) psi = divergence_cleaning_field(cons, equations) @@ -973,7 +976,8 @@ Routine to compute the Charge-averaged velocities: * v*_plus: Charge-averaged velocity * vk*_plus: Contribution of each species to the charge-averaged velocity """ -@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations2D) +@inline function charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations2D) total_electron_charge = zero(real(equations)) vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) @@ -982,7 +986,7 @@ Routine to compute the Charge-averaged velocities: for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) total_electron_charge += rho * equations.charge_to_mass[k] vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] @@ -1003,7 +1007,7 @@ end """ Get the flow variables of component k """ -@inline function get_component(k, u, equations::IdealMhdMultiIonEquations2D) +@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. return SVector(u[3 + (k - 1) * 5 + 1], u[3 + (k - 1) * 5 + 2], @@ -1016,7 +1020,7 @@ end Set the flow variables of component k """ @inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. u[3 + (k - 1) * 5 + 1] = u1 u[3 + (k - 1) * 5 + 2] = u2 @@ -1027,10 +1031,10 @@ Set the flow variables of component k return u end -magnetic_field(u, equations::IdealMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) -divergence_cleaning_field(u, equations::IdealMhdMultiIonEquations2D) = u[end] +magnetic_field(u, equations::IdealGlmMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) +divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations2D) = u[end] -@inline function density(u, equations::IdealMhdMultiIonEquations2D) +@inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) rho = zero(real(equations)) for k in eachcomponent(equations) rho += u[3 + (k - 1) * 5 + 1] @@ -1041,7 +1045,7 @@ end """ Computes the sum of the densities times the sum of the pressures """ -@inline function density_pressure(u, equations::IdealMhdMultiIonEquations2D) +@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(cons, equations) @@ -1083,7 +1087,7 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) @inline function (dissipation::DissipationEntropyStable)(u_ll, u_rr, orientation_or_normal_direction, - equations::IdealMhdMultiIonEquations2D) + equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations) From 8c1ab2f3793d594fd7540560cd7cb0b2f02303e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Fri, 6 Dec 2024 18:53:05 +0100 Subject: [PATCH 065/108] Improved comments for multi-ion MHD equation (2D) and renamed source_terms_standard to source_terms_lorentz --- .../tree_1d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../elixir_mhdmultiion_ec_onespecies.jl | 2 +- .../tree_1d_dgsem/elixir_mhdmultiion_es.jl | 2 +- .../elixir_mhdmultiion_es_shock_capturing.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 2 +- src/Trixi.jl | 2 +- src/callbacks_step/glm_speed.jl | 3 +- src/equations/ideal_glm_mhd_multiion_2d.jl | 236 ++++++++++-------- src/equations/ideal_mhd_multiion_1d.jl | 2 +- 10 files changed, 143 insertions(+), 112 deletions(-) diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl index fc352096559..5ea262b08c3 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec.jl @@ -20,7 +20,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) + source_terms = source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl index 780bec048ff..c8b5c3b2e0c 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_ec_onespecies.jl @@ -23,7 +23,7 @@ semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver) # In the one-species case, the source terms are not really needed, but this variant produces the same results: # semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, -# source_terms=source_terms_standard) +# source_terms=source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl index 4b3cb674259..8e2ee9c95bd 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es.jl @@ -20,7 +20,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) + source_terms = source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl index ed7527a82de..860a544b7b5 100644 --- a/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl +++ b/examples/tree_1d_dgsem/elixir_mhdmultiion_es_shock_capturing.jl @@ -31,7 +31,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) + source_terms = source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 658aa6465bc..f14da29fa21 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -21,7 +21,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) + source_terms = source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl index b0dab7351ce..10b0865b5e6 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -21,7 +21,7 @@ mesh = TreeMesh(coordinates_min, coordinates_max, n_cells_max = 10_000) semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_standard) + source_terms = source_terms_lorentz) ############################################################################### # ODE solvers, callbacks etc. diff --git a/src/Trixi.jl b/src/Trixi.jl index ac02bd8eb57..587733ed4b6 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -217,7 +217,7 @@ export boundary_condition_do_nothing, BoundaryConditionCoupled export initial_condition_convergence_test, source_terms_convergence_test, - source_terms_standard +source_terms_lorentz export source_terms_harmonic export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic, boundary_condition_poisson_nonperiodic diff --git a/src/callbacks_step/glm_speed.jl b/src/callbacks_step/glm_speed.jl index 0bd87c189bc..075e084949a 100644 --- a/src/callbacks_step/glm_speed.jl +++ b/src/callbacks_step/glm_speed.jl @@ -9,7 +9,8 @@ GlmSpeedCallback(; glm_scale=0.5, cfl, semi_indices=()) Update the divergence cleaning wave speed `c_h` according to the time step -computed in [`StepsizeCallback`](@ref) for the ideal GLM-MHD equations. +computed in [`StepsizeCallback`](@ref) for the ideal GLM-MHD equations, the multi-component +GLM-MHD equations, and the multi-ion GLM-MHD equations. The `cfl` number should be set to the same value as for the time step size calculation. The `glm_scale` ensures that the GLM wave speed is lower than the fastest physical waves in the MHD solution and should thus be set to a value within the interval [0,1]. Note that `glm_scale = 0` diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 566b0914f96..5628aa84540 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -6,9 +6,35 @@ #! format: noindent @doc raw""" - IdealGlmMhdMultiIonEquations2D - -The ideal compressible multi-ion MHD equations in two space dimensions. + IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = NaN) + +The ideal compressible multi-ion MHD equations in two space dimensions augmented with a +generalized Langange multipliers (GLM) divergence-cleaning technique. This is a +multi-species variant of the ideal GLM-MHD equations for calorically perfect plasmas +with independent momentum and energy equations for each ion species. This implementation +assumes that the equations are non-dimensionalized such, that the vacuum permeability is ``\mu_0 = 1``. + +In case of more than one ion species, the specific heat capcity ratios `gammas` and the charge-to-mass +ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. + +The argument `electron_pressure` can be used to pass a function that computes the electron +pressure as a function of the state `u` with the signature `electron_pressure(u, equations::IdealGlmMhdMultiIonEquations2D)`. +By default, the electron pressure is zero. + +The argument `initial_c_h` can be used to set the GLM divergence-cleaning speed. Note that +`initial_c_h = 0` deactivates the divergence cleaning. The callback [`GlmSpeedCallback`](@ref) +can be used to adjust the GLM divergence-cleaning speed according to the time-step size. + +References: +- G. Toth, A. Glocer, Y. Ma, D. Najib, Multi-Ion Magnetohydrodynamics 429 (2010). Numerical + Modeling of Space Plasma Flows, 213–218. +- 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. + +!!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used + with `source_terms_lorentz`. """ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure} <: @@ -91,33 +117,10 @@ function default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) end -# """ -# initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) - -# An Alfvén wave as smooth initial condition used for convergence tests. -# """ -# function initial_condition_convergence_test(x, t, equations::IdealGlmMhdMultiIonEquations2D) -# # smooth Alfvén wave test from Derigs et al. FLASH (2016) -# # domain must be set to [0, 1], γ = 5/3 - -# rho = 1.0 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = zero(real(equations)) -# si, co = sincos(2 * pi * x[1]) -# v2 = 0.1 * si -# v3 = 0.1 * co -# p = 0.1 -# B1 = 1.0 -# B2 = v2 -# B3 = v3 -# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) -# return prim2cons(vcat(prim_other, prim_rho), equations) -# end - """ initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) -A weak blast wave adapted from +A weak blast wave (adapted to multi-ion MHD) from - Sebastian Hennemann, Gregor J. Gassner (2020) A provably entropy stable subcell shock capturing approach for high order split form DG [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) @@ -157,9 +160,7 @@ function initial_condition_weak_blast_wave(x, t, return prim2cons(SVector(prim), equations) end -# TODO: Add initial condition equilibrium - -# Calculate 1D flux in for a single point +# 2D flux of the GLM-MHD equations in the direction `orientation` @inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) @@ -231,9 +232,13 @@ end end """ -Standard source terms of the multi-ion MHD equations + source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) + +Source terms due to the Lorentz' force for plasmas with more than one ion species. These source +terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for +a single-species plasma. """ -function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) +function source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) @unpack charge_to_mass = equations B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, @@ -262,20 +267,31 @@ function source_terms_standard(u, x, t, equations::IdealGlmMhdMultiIonEquations2 end """ - electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) -Returns the value of zero for the electron pressure. Consistent with the single-fluid MHD equations. + electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) + +Returns the value of zero for the electron pressure. Needed for consistency with the +single-fluid MHD equations in the limit of one ion species. """ function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) return zero(u[1]) end """ -Total entropy-conserving non-conservative two-point "flux"" as described in -- Rueda-Ramírez et al. (2023) -The term is composed of three parts -* The Powell term: Implemented -* The MHD term: Implemented -* The "term 3": Implemented + flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + +Entropy-conserving non-conservative two-point "flux"" as described in +- 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. + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a funciton of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. """ @inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, @@ -319,19 +335,19 @@ The term is composed of three parts f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) f[1] = v1_plus_ll * B1_rr f[2] = v2_plus_ll * B1_rr f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) - # Compute term 2 (MHD) + # Compute term Lorentz term f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) f5 = vk1_plus_ll[k] * pe_mean - # Compute term 3 (only needed for NCOMP>1) + # Compute multi-ion term (vanishes for NCOMP==1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] @@ -344,7 +360,7 @@ The term is composed of three parts f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + # Adjust Lorentz and multi-ion non-conservative terms to Trixi discretization f2 = 2 * f2 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll @@ -357,7 +373,7 @@ The term is composed of three parts - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) - # Compute Powell term (already consistent with Trixi's non-conservative discretization) + # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B1_rr f3 += charge_ratio_ll[k] * B2_ll * B1_rr f4 += charge_ratio_ll[k] * B3_ll * B1_rr @@ -366,26 +382,26 @@ The term is composed of three parts # Compute GLM term for the energy f5 += v1_plus_ll * psi_ll * psi_rr - # Append to the flux vector + # Add to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end # Compute GLM term for psi f[end] = v1_plus_ll * psi_rr else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) f[1] = v1_plus_ll * B2_rr f[2] = v2_plus_ll * B2_rr f[3] = v3_plus_ll * B2_rr for k in eachcomponent(equations) - # Compute term 2 (MHD) + # Compute term Lorentz term f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) f5 = vk2_plus_ll[k] * pe_mean - # Compute term 3 (only needed for NCOMP>1) + # Compute multi-ion term (vanishes for NCOMP==1) vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] @@ -398,7 +414,7 @@ The term is composed of three parts f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) - # Adjust non-conservative terms 2 and 3 to Trixi discretization: CHANGE!?! + # Adjust Lorentz and multi-ion non-conservative terms to Trixi discretization f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll f3 = 2 * f3 - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll + pe_ll) @@ -411,7 +427,7 @@ The term is composed of three parts - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) - # Compute Powell term (already consistent with Trixi's non-conservative discretization) + # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B2_rr f3 += charge_ratio_ll[k] * B2_ll * B2_rr f4 += charge_ratio_ll[k] * B3_ll * B2_rr @@ -420,7 +436,7 @@ The term is composed of three parts # Compute GLM term for the energy f5 += v2_plus_ll * psi_ll * psi_rr - # Append to the flux vector + # Add to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end # Compute GLM term for psi @@ -431,11 +447,20 @@ The term is composed of three parts end """ -Total central non-conservative two-point "flux"", where the symmetric parts are computed with standard averages -The term is composed of three parts -* The Powell term: Implemented. The central Powell "flux" is equivalent to the EC Powell "flux". -* The MHD term: Implemented -* The "term 3": Implemented + flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + +Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. +The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" +(weak-form) DGSEM discretization of the multi-ion GLM-MHD system. + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a funciton of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. """ @inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) @@ -471,25 +496,25 @@ The term is composed of three parts f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) f[1] = v1_plus_ll * B1_rr f[2] = v2_plus_ll * B1_rr f[3] = v3_plus_ll * B1_rr for k in eachcomponent(equations) - # Compute term 2 (MHD) + # Compute Lorentz term f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) f5 = vk1_plus_ll[k] * pe_rr - # Compute term 3 (only needed for NCOMP>1) + # Compute multi-ion term (vanishes for NCOMP==1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) - # Compute Powell term (already consistent with Trixi's non-conservative discretization) + # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B1_rr f3 += charge_ratio_ll[k] * B2_ll * B1_rr f4 += charge_ratio_ll[k] * B3_ll * B1_rr @@ -507,26 +532,26 @@ The term is composed of three parts f[end] = v1_plus_ll * psi_rr else #if orientation == 2 - # Entries of Powell term for induction equation (already in Trixi's non-conservative form) + # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) f[1] = v1_plus_ll * B2_rr f[2] = v2_plus_ll * B2_rr f[3] = v3_plus_ll * B2_rr for k in eachcomponent(equations) - # Compute term 2 (MHD) + # Compute Lorentz term f2 = charge_ratio_ll[k] * (-B2_rr * B1_rr) f3 = charge_ratio_ll[k] * (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) f4 = charge_ratio_ll[k] * (-B2_rr * B3_rr) f5 = vk2_plus_ll[k] * pe_rr - # Compute term 3 (only needed for NCOMP>1) + # Compute multi-ion term (vanishes for NCOMP==1) vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr)) - # Compute Powell term (already consistent with Trixi's non-conservative discretization) + # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) f2 += charge_ratio_ll[k] * B1_ll * B2_rr f3 += charge_ratio_ll[k] * B2_ll * B2_rr f4 += charge_ratio_ll[k] * B3_ll * B2_rr @@ -550,11 +575,12 @@ end """ flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations2D) -Entropy conserving two-point flux adapted by: -- Rueda-Ramírez et al. (2023) -This flux (together with the MHD non-conservative term) is consistent in the case of one species with the flux of: -- Derigs et al. (2018) - Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field +Entropy conserving two-point flux for the multi-ion GLM-MHD equations from +- 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. + +This flux (together with the MHD non-conservative term) is consistent in the case of one ion species with the flux of: +- Derigs et al. (2018). Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field divergence diminishing ideal magnetohydrodynamics equations for multi-ion [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) """ @@ -657,7 +683,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - # Ignore orientation since it is always "1" in 1D + # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v1_avg f2 = f1 * v1_avg + p_mean f3 = f1 * v2_avg @@ -676,10 +702,10 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + 0.5 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - - vk3_plus_avg * B1_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + vk3_plus_avg * B1_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - - B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -754,7 +780,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) - # Ignore orientation since it is always "1" in 1D + # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v2_avg f2 = f1 * v1_avg f3 = f1 * v2_avg + p_mean @@ -773,10 +799,10 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + 0.5 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - - vk3_plus_avg * B2_avg * B3_avg # Additional terms coming from the MHD non-conservative term (momentum eqs) + vk3_plus_avg * B2_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - - B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms coming from the non-conservative term 3 (induction equation!) + B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) set_component!(f, k, f1, f2, f3, f4, f5, equations) end @@ -785,10 +811,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, return SVector(f) end -""" # Calculate maximum wave speed for local Lax-Friedrichs-type dissipation - !!!ATTENTION: This routine is provisional. TODO: Update with the right max_abs_speed -""" +# This routine approximates the maximum wave speed as sum of the maximum ion velocity +# for all species and the maximum magnetosonic speed. @inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) # Calculate fast magnetoacoustic wave speeds @@ -834,9 +859,7 @@ end return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) end -""" -Convert conservative variables to primitive -""" +#Convert conservative variables to primitive function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) @@ -865,9 +888,7 @@ function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) return SVector(prim) end -""" -Convert conservative variables to entropy -""" +#Convert conservative variables to entropy variables @inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(u, equations) @@ -899,9 +920,7 @@ Convert conservative variables to entropy return SVector(entropy) end -""" -Convert primitive to conservative variables -""" +# Convert primitive to conservative variables @inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) @unpack gammas = equations B1, B2, B3 = magnetic_field(prim, equations) @@ -929,10 +948,10 @@ Convert primitive to conservative variables return SVector(cons) end -""" -Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue - !!! ATTENTION: This routine is provisional.. Change once the fastest wave speed is known!! -""" +# Compute the fastest wave speed for ideal multi-ion GLM-MHD equations: c_f, the fast +# magnetoacoustic eigenvalue. This routine computes the fast magnetosonic speed for each ion +# species using the single-fluid MHD expressions and approximates the multi-ion c_f as +# the maximum of these individual magnetosonic speeds. @inline function calc_fast_wavespeed(cons, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(cons, equations) @@ -972,9 +991,13 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco end """ -Routine to compute the Charge-averaged velocities: -* v*_plus: Charge-averaged velocity -* vk*_plus: Contribution of each species to the charge-averaged velocity +v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations2D) + + +Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution +to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 +are SVectors of size ncomponents(equations). """ @inline function charge_averaged_velocities(u, equations::IdealGlmMhdMultiIonEquations2D) @@ -1005,10 +1028,11 @@ Routine to compute the Charge-averaged velocities: end """ -Get the flow variables of component k + get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) + +Get the hydrodynamic variables of component (ion species) k. """ @inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. return SVector(u[3 + (k - 1) * 5 + 1], u[3 + (k - 1) * 5 + 2], u[3 + (k - 1) * 5 + 3], @@ -1017,11 +1041,13 @@ Get the flow variables of component k end """ -Set the flow variables of component k + set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealGlmMhdMultiIonEquations2D) + +Set the hydrodynamic variables of component (ion species) k. """ @inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::IdealGlmMhdMultiIonEquations2D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. u[3 + (k - 1) * 5 + 1] = u1 u[3 + (k - 1) * 5 + 2] = u2 u[3 + (k - 1) * 5 + 3] = u3 @@ -1031,9 +1057,13 @@ Set the flow variables of component k return u end +# Extract magnetic field from solution vector magnetic_field(u, equations::IdealGlmMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + +# Extract GLM divergence-cleaning field from solution vector divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations2D) = u[end] +# Get total density as the sum of the individual densities of the ion species @inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) rho = zero(real(equations)) for k in eachcomponent(equations) @@ -1042,9 +1072,7 @@ divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations2D) = u[end] return rho end -""" -Computes the sum of the densities times the sum of the pressures -""" +# Computes the sum of the densities times the sum of the pressures @inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) psi = divergence_cleaning_field(cons, equations) @@ -1074,7 +1102,9 @@ DissipationEntropyStable(max_abs_speed=max_abs_speed_naive) Create a local Lax-Friedrichs-type dissipation operator that is provably entropy stable. See: - * Rueda-Ramírez et al. (2023) +- 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. + The maximum absolute wave speed is estimated as `max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, defaulting to [`max_abs_speed_naive`](@ref). diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index f255b2d0bee..24a8db30256 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -179,7 +179,7 @@ end """ Standard source terms of the multi-ion MHD equations """ -function source_terms_standard(u, x, t, equations::IdealMhdMultiIonEquations1D) +function source_terms_lorentz(u, x, t, equations::IdealMhdMultiIonEquations1D) @unpack charge_to_mass = equations B1, B2, B3 = magnetic_field(u, equations) v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, From 7416798182433bf1d67ff866a194f094d4975bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 14:51:31 +0100 Subject: [PATCH 066/108] Added DOI --- src/equations/ideal_glm_mhd_multiion_2d.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 5628aa84540..ad12ad5e27a 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -32,6 +32,7 @@ References: Modeling of Space Plasma Flows, 213–218. - 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). !!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used with `source_terms_lorentz`. @@ -284,6 +285,7 @@ end Entropy-conserving non-conservative two-point "flux"" as described in - 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 term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and @@ -578,6 +580,7 @@ flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEq Entropy conserving two-point flux for the multi-ion GLM-MHD equations from - 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). This flux (together with the MHD non-conservative term) is consistent in the case of one ion species with the flux of: - Derigs et al. (2018). Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field @@ -1104,6 +1107,7 @@ Create a local Lax-Friedrichs-type dissipation operator that is provably entropy 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). The maximum absolute wave speed is estimated as `max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, From f66eca2170400fc98be51fb274563ba2751d4168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 16:14:46 +0100 Subject: [PATCH 067/108] Adapted 2D multi-ion MHD equations to new GLM constant update with @reset --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 11 +++++++--- src/Trixi.jl | 2 +- src/equations/ideal_glm_mhd_multiion_2d.jl | 21 +++++++++++++++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index f14da29fa21..3d6bc7b0872 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -31,7 +31,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 100 +analysis_interval = 10 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl index 10b0865b5e6..ca592e998cf 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -31,7 +31,7 @@ ode = semidiscretize(semi, tspan) summary_callback = SummaryCallback() -analysis_interval = 100 +analysis_interval = 10 analysis_callback = AnalysisCallback(semi, interval = analysis_interval) alive_callback = AliveCallback(analysis_interval = analysis_interval) @@ -40,12 +40,17 @@ save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, save_final_solution = true, solution_variables = cons2prim) -stepsize_callback = StepsizeCallback(cfl = 0.5) +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) callbacks = CallbackSet(summary_callback, analysis_callback, alive_callback, save_solution, - stepsize_callback) + stepsize_callback, + glm_speed_callback) ############################################################################### # run the simulation diff --git a/src/Trixi.jl b/src/Trixi.jl index 587733ed4b6..c3f37aa8d1d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -217,7 +217,7 @@ export boundary_condition_do_nothing, BoundaryConditionCoupled export initial_condition_convergence_test, source_terms_convergence_test, -source_terms_lorentz + source_terms_lorentz export source_terms_harmonic export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic, boundary_condition_poisson_nonperiodic diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index ad12ad5e27a..c1ddb093959 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -80,6 +80,27 @@ function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, initial_c_h) end +# Outer constructor for `@reset` works correctly +function IdealGlmMhdMultiIonEquations2D(gammas, charge_to_mass, electron_pressure, c_h) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 4 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + c_h = convert(RealT, c_h) + + return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + c_h) +end + @inline function Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { NVARS, NCOMP, From 7d5c21cef07074a08e2f6ea3363f746706776fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 17:03:36 +0100 Subject: [PATCH 068/108] Cleaned up implementation of DissipationEntropyStable and improved documentation --- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 4 ++- src/Trixi.jl | 2 +- src/equations/ideal_glm_mhd_multiion_2d.jl | 24 +------------ src/equations/numerical_fluxes.jl | 34 +++++++++++++++++++ 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl index ca592e998cf..e23f06d3196 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -9,8 +9,10 @@ equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), initial_condition = initial_condition_weak_blast_wave +flux_es = FluxPlusDissipation(flux_ruedaramirez_etal, DissipationEntropyStable()) + volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) +surface_flux = (flux_es, flux_nonconservative_central) solver = DGSEM(polydeg = 3, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/src/Trixi.jl b/src/Trixi.jl index c3f37aa8d1d..fa42e19ad9d 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -188,7 +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, - DissipationEntropyStableLump, DissipationEntropyStable, + DissipationEntropyStable, FluxLaxFriedrichs, max_abs_speed_naive, FluxHLL, min_max_speed_naive, min_max_speed_davis, min_max_speed_einfeldt, FluxLMARS, diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index c1ddb093959..590adbce018 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -1121,25 +1121,7 @@ end return rho_total * p_total end -""" -DissipationEntropyStable(max_abs_speed=max_abs_speed_naive) - -Create a local Lax-Friedrichs-type dissipation operator that is provably entropy stable. -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). - -The maximum absolute wave speed is estimated as -`max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, -defaulting to [`max_abs_speed_naive`](@ref). -""" -struct DissipationEntropyStable{MaxAbsSpeed} - max_abs_speed::MaxAbsSpeed -end - -DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) - +# Specialization of DissipationEntropyStable for the multi-ion GLM-MHD equations @inline function (dissipation::DissipationEntropyStable)(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdMultiIonEquations2D) @@ -1301,8 +1283,4 @@ DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) return dissipation end - -function Base.show(io::IO, d::DissipationEntropyStable) - print(io, "DissipationEntropyStable(", d.max_abs_speed, ")") -end end # @muladd diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index ea75b99b7f2..79ff2f2d9b8 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -221,6 +221,40 @@ See [`FluxLaxFriedrichs`](@ref). """ const flux_lax_friedrichs = FluxLaxFriedrichs() +""" + DissipationEntropyStable(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 (here `flux_ec`) to yield +an entropy-stable surface flux. The surface flux function can be initialized as: +``` +flux_es = FluxPlusDissipation(flux_ec, DissipationEntropyStable()) +``` + +In particular, the numerical flux has the form +```math +f^{ES} = f^{EC} + \frac{1}{2} λ_{max} H (w_R - w_L), +```` +where ``f^{EC}`` is the entropy-conservative two-point flux function computed with `flux_ec`, ``λ_{max}`` +is the maximum wave speed estimated as `max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, +defaulting to [`max_abs_speed_naive`](@ref), ``H`` is a symmetric positive-definite dissipation matrix that +depends on the states `u_ll` and `u_rr`, and ``(w_R - w_L)`` is the jump in entropy variables. + +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 DissipationEntropyStable{MaxAbsSpeed} + max_abs_speed::MaxAbsSpeed +end + +DissipationEntropyStable() = DissipationEntropyStable(max_abs_speed_naive) + +function Base.show(io::IO, d::DissipationEntropyStable) + print(io, "DissipationEntropyStable(", d.max_abs_speed, ")") +end + """ FluxHLL(min_max_speed=min_max_speed_davis) From fc360b3cfcd21f8fb9943ff90897db58b003290b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 20:22:53 +0100 Subject: [PATCH 069/108] Changed the strategy to compute the non-conservative terms: use local*symmetric --- src/equations/ideal_glm_mhd_multiion_2d.jl | 202 +++++++++++---------- 1 file changed, 106 insertions(+), 96 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 590adbce018..3a85796c795 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -308,6 +308,12 @@ Entropy-conserving non-conservative two-point "flux"" as described in 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). +ATTENTION: The non-conservative fluxes derived in the reference above are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied + by 0.5 whenever they are used in the Trixi code + The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and is evaluated as a funciton of the charge-averaged velocity. @@ -333,6 +339,7 @@ The term is composed of four individual non-conservative terms: mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) # Mean electron pressure pe_ll = equations.electron_pressure(u_ll, equations) @@ -358,10 +365,11 @@ The term is composed of four individual non-conservative terms: f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 - # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2.0f0 * v1_plus_ll * B1_avg + f[2] = 2.0f0 * v2_plus_ll * B1_avg + f[3] = 2.0f0 * v3_plus_ll * B1_avg for k in eachcomponent(equations) # Compute term Lorentz term @@ -383,39 +391,31 @@ The term is composed of four individual non-conservative terms: f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) - # Adjust Lorentz and multi-ion non-conservative terms to Trixi discretization - f2 = 2 * f2 - - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) - f3 = 2 * f3 + charge_ratio_ll[k] * B1_ll * B2_ll - f4 = 2 * f4 + charge_ratio_ll[k] * B1_ll * B3_ll - f5 = (2 * f5 - - - vk1_plus_ll[k] * pe_ll - - - B2_ll * (vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) - - - B3_ll * (vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll)) - - # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B1_avg + f3 += charge_ratio_ll[k] * B2_ll * B1_avg + f4 += charge_ratio_ll[k] * B3_ll * B1_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B1_avg # Compute GLM term for the energy - f5 += v1_plus_ll * psi_ll * psi_rr + f5 += v1_plus_ll * psi_ll * psi_avg - # Add to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + equations) end - # Compute GLM term for psi - f[end] = v1_plus_ll * psi_rr + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2.0f0 * v1_plus_ll * psi_avg else #if orientation == 2 - # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2.0f0 * v1_plus_ll * B2_avg + f[2] = 2.0f0 * v2_plus_ll * B2_avg + f[3] = 2.0f0 * v3_plus_ll * B2_avg for k in eachcomponent(equations) # Compute term Lorentz term @@ -437,33 +437,24 @@ The term is composed of four individual non-conservative terms: f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) - # Adjust Lorentz and multi-ion non-conservative terms to Trixi discretization - f2 = 2 * f2 + charge_ratio_ll[k] * B2_ll * B1_ll - f3 = 2 * f3 - - charge_ratio_ll[k] * (0.5 * mag_norm_ll - B2_ll * B2_ll + pe_ll) - f4 = 2 * f4 + charge_ratio_ll[k] * B2_ll * B3_ll - f5 = (2 * f5 - - - vk2_plus_ll[k] * pe_ll - - - B1_ll * (vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) - - - B3_ll * (vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll)) - - # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B2_avg + f3 += charge_ratio_ll[k] * B2_ll * B2_avg + f4 += charge_ratio_ll[k] * B3_ll * B2_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B2_avg # Compute GLM term for the energy - f5 += v2_plus_ll * psi_ll * psi_rr + f5 += v2_plus_ll * psi_ll * psi_avg - # Add to the flux vector - set_component!(f, k, 0, f2, f3, f4, f5, equations) + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + equations) end - # Compute GLM term for psi - f[end] = v2_plus_ll * psi_rr + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2.0f0 * v2_plus_ll * psi_avg end return SVector(f) @@ -475,7 +466,14 @@ end Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" -(weak-form) DGSEM discretization of the multi-ion GLM-MHD system. +(weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a +standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. + +ATTENTION: The central non-conservative fluxes are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + we omit the 0.5 when computing averages because the non-conservative flux is multiplied by + 0.5 whenever it's used in the Trixi code The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and @@ -495,9 +493,11 @@ The term is composed of four individual non-conservative terms: psi_rr = divergence_cleaning_field(u_rr, equations) # Compute important averages + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 # Electron pressure + pe_ll = equations.electron_pressure(u_ll, equations) pe_rr = equations.electron_pressure(u_rr, equations) # Compute charge ratio of u_ll @@ -519,77 +519,87 @@ The term is composed of four individual non-conservative terms: f = zero(MVector{nvariables(equations), eltype(u_ll)}) if orientation == 1 - # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B1_rr - f[2] = v2_plus_ll * B1_rr - f[3] = v3_plus_ll * B1_rr + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B1_ll + B1_rr) + f[2] = v2_plus_ll * (B1_ll + B1_rr) + f[3] = v3_plus_ll * (B1_ll + B1_rr) for k in eachcomponent(equations) # Compute Lorentz term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr) - f3 = charge_ratio_ll[k] * (-B1_rr * B2_rr) - f4 = charge_ratio_ll[k] * (-B1_rr * B3_rr) - f5 = vk1_plus_ll[k] * pe_rr + f2 = charge_ratio_ll[k] * ((0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + + (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) + f3 = charge_ratio_ll[k] * ((-B1_ll * B2_ll) + (-B1_rr * B2_rr)) + f4 = charge_ratio_ll[k] * ((-B1_ll * B3_ll) + (-B1_rr * B3_rr)) + f5 = vk1_plus_ll[k] * (pe_ll + pe_rr) - # Compute multi-ion term (vanishes for NCOMP==1) + # Compute multi-ion term, which vanishes for NCOMP==1 + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B2_ll * (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr) + - B3_ll * (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr)) - - # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B1_rr - f3 += charge_ratio_ll[k] * B2_ll * B1_rr - f4 += charge_ratio_ll[k] * B3_ll * B1_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B1_rr + f5 += (B2_ll * ((vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + + (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr)) + + B3_ll * ((vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + + (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B1_ll + B1_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B1_ll + B1_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B1_ll + B1_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B1_ll + B1_rr) # Compute GLM term for the energy - f5 += v1_plus_ll * psi_ll * psi_rr - - # It's not needed to adjust to Trixi's non-conservative form + f5 += v1_plus_ll * psi_ll * (psi_ll + psi_rr) # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end # Compute GLM term for psi - f[end] = v1_plus_ll * psi_rr + f[end] = v1_plus_ll * (psi_ll + psi_rr) else #if orientation == 2 - # Entries of Godunov-Powell term for induction equation (already in Trixi's non-conservative form) - f[1] = v1_plus_ll * B2_rr - f[2] = v2_plus_ll * B2_rr - f[3] = v3_plus_ll * B2_rr + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B2_ll + B2_rr) + f[2] = v2_plus_ll * (B2_ll + B2_rr) + f[3] = v3_plus_ll * (B2_ll + B2_rr) for k in eachcomponent(equations) # Compute Lorentz term - f2 = charge_ratio_ll[k] * (-B2_rr * B1_rr) - f3 = charge_ratio_ll[k] * (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr) - f4 = charge_ratio_ll[k] * (-B2_rr * B3_rr) - f5 = vk2_plus_ll[k] * pe_rr + f2 = charge_ratio_ll[k] * ((-B2_ll * B1_ll) + (-B2_rr * B1_rr)) + f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5 * mag_norm_ll + pe_ll) + + (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr)) + f4 = charge_ratio_ll[k] * ((-B2_ll * B3_ll) + (-B2_rr * B3_rr)) + f5 = vk2_plus_ll[k] * (pe_ll + pe_rr) # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - f5 += (B1_ll * (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr) + - B3_ll * (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr)) - - # Compute Godunov-Powell term (already consistent with Trixi's non-conservative discretization) - f2 += charge_ratio_ll[k] * B1_ll * B2_rr - f3 += charge_ratio_ll[k] * B2_ll * B2_rr - f4 += charge_ratio_ll[k] * B3_ll * B2_rr - f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * B2_rr + f5 += (B1_ll * ((vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + + (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr)) + + B3_ll * ((vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll) + + (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B2_ll + B2_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B2_ll + B2_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B2_ll + B2_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B2_ll + B2_rr) # Compute GLM term for the energy - f5 += v2_plus_ll * psi_ll * psi_rr - - # It's not needed to adjust to Trixi's non-conservative form + f5 += v2_plus_ll * psi_ll * (psi_ll + psi_rr) # Append to the flux vector set_component!(f, k, 0, f2, f3, f4, f5, equations) end # Compute GLM term for psi - f[end] = v2_plus_ll * psi_rr + f[end] = v2_plus_ll * (psi_ll + psi_rr) end return SVector(f) From 0b3db84bca99f3f8ac9c018cc71b66cda7018e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 20:39:53 +0100 Subject: [PATCH 070/108] Updated tests for 2D GLM-MHD multi-ion equations --- .../elixir_mhdmultiion_ec+llf.jl | 62 +++++++++ .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 4 +- .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 6 +- test/test_tree_2d_mhdmultiion.jl | 120 ++++++++++++++---- 4 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl new file mode 100644 index 00000000000..9be4e5e2492 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl @@ -0,0 +1,62 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) + +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_lorentz) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback, + glm_speed_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index 3d6bc7b0872..c4acdf1f32f 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -4,8 +4,8 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) initial_condition = initial_condition_weak_blast_wave diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl index e23f06d3196..97d4d87baca 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl @@ -4,15 +4,15 @@ using Trixi ############################################################################### # semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (2.0, 2.0), - charge_to_mass = (1.0, 1.0)) +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) initial_condition = initial_condition_weak_blast_wave flux_es = FluxPlusDissipation(flux_ruedaramirez_etal, DissipationEntropyStable()) volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_es, flux_nonconservative_central) +surface_flux = (flux_es, flux_nonconservative_ruedaramirez_etal) solver = DGSEM(polydeg = 3, surface_flux = surface_flux, volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index b395053c76c..56d34ec30fb 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -14,44 +14,108 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 @trixi_testset "elixir_mhdmultiion_ec.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), l2=[ - 1.5557198040058215e-02, 1.5561198523962436e-02, - 2.4410457949025310e-02, 1.1344868834133841e-02, - 1.8626149391184826e-02, 1.8719830298030603e-02, - 6.8963004644178256e-03, 1.0465244373132600e-01, - 1.8691974336498236e-02, 2.8258773607345654e-02, - 2.8130992204006531e-02, 1.3859402020143092e-02, - 8.9892546634939050e-02 + 0.018116158127836963, + 0.018242057606900185, + 0.02842532060540296, + 0.015805662470907644, + 0.018125738668209504, + 0.01841652763250858, + 0.005540867360495384, + 0.2091437538608106, + 0.021619156799420326, + 0.030561821442897923, + 0.029778012392807182, + 0.018651133866567658, + 0.1204153285953923, + 0.00017580766470956546 ], linf=[ - 8.6698171128154478e-02, 8.9223437132718741e-02, - 1.0624940128583993e-01, 5.5291033171599724e-02, - 1.1495494812039142e-01, 1.0381359740462957e-01, - 4.2436775232064218e-02, 5.2806012024968041e-01, - 1.0937172169536147e-01, 2.0286418034545392e-01, - 1.9274686956407905e-01, 9.1713317178251763e-02, - 5.0302723967694263e-01 + 0.08706810449620284, + 0.085845022468381, + 0.15301576281555795, + 0.07924698349506726, + 0.11185098353068998, + 0.10902813348518392, + 0.03512713073214368, + 1.018607282408099, + 0.11897673517549667, + 0.18757934071639615, + 0.19089795413679128, + 0.10989483685170078, + 0.6078381519649727, + 0.00673110606965085 ]) end @trixi_testset "elixir_mhdmultiion_es.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), l2=[ - 1.5319585024958093e-02, 1.5322497339615212e-02, - 2.4107479679804287e-02, 1.1166706297428615e-02, - 1.8044343530506653e-02, 1.8141881194840042e-02, - 6.8164634011262104e-03, 1.0315687185431269e-01, - 1.8776826173845702e-02, 2.8168829726671649e-02, - 2.8041409057574292e-02, 1.3711442812290676e-02, - 8.9987200150509539e-02 + 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=[ - 4.5244015084714539e-02, 4.5229288526366540e-02, - 9.0657122074956020e-02, 4.9004662466521465e-02, - 7.5791977835092991e-02, 7.6446433484144830e-02, - 3.2763360958124675e-02, 3.6867066527392822e-01, - 1.1151774062868847e-01, 1.5930447057310282e-01, - 1.5758954335858896e-01, 6.6688837243764412e-02, - 3.6242864449799805e-01 + 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 + ]) +end + +@trixi_testset "elixir_mhdmultiion_ec+llf.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec+llf.jl"), + l2=[ + 0.017668026737187294, + 0.017797845988889206, + 0.02784171335711194, + 0.015603472482130114, + 0.017849085712788024, + 0.018142011483140937, + 0.005478230098832851, + 0.20585547149049335, + 0.021301307197244185, + 0.030185081369414384, + 0.029385190432285654, + 0.01837280802521888, + 0.11810313415151609, + 0.0002962121353575025 + ], + linf=[ + 0.06594404679380572, + 0.0658741409805832, + 0.09451390288403083, + 0.06787235653416557, + 0.0891017651119973, + 0.08828137594061974, + 0.02364750099643367, + 0.8059321345611803, + 0.12243877249999213, + 0.15930897967901766, + 0.1538327998380914, + 0.08694877996306204, + 0.49493751138636366, + 0.003287414714660175 ]) end end From fef17d2432606bdba97e980eebb99b0d596c4282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 21:11:38 +0100 Subject: [PATCH 071/108] Added 2D GLM-MHD equations, examples and tests --- .../elixir_mhdmultiion_ec+llf.jl | 62 + .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 61 + src/Trixi.jl | 9 +- src/callbacks_step/glm_speed.jl | 3 +- src/callbacks_step/glm_speed_dg.jl | 6 +- src/equations/equations.jl | 25 + src/equations/ideal_glm_mhd_multiion_2d.jl | 1108 +++++++++++++++++ test/test_tree_2d_mhdmultiion.jl | 123 ++ test/test_tree_2d_part3.jl | 3 + 9 files changed, 1395 insertions(+), 5 deletions(-) create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl create mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl create mode 100644 src/equations/ideal_glm_mhd_multiion_2d.jl create mode 100644 test/test_tree_2d_mhdmultiion.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl new file mode 100644 index 00000000000..9be4e5e2492 --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl @@ -0,0 +1,62 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) + +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_lorentz) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback, + glm_speed_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl new file mode 100644 index 00000000000..c4acdf1f32f --- /dev/null +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -0,0 +1,61 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0) +coordinates_max = (2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_lorentz) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback, + glm_speed_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/src/Trixi.jl b/src/Trixi.jl index 7d557ddde38..ae3ce2ec970 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -156,6 +156,7 @@ export AcousticPerturbationEquations2D, CompressibleEulerEquationsQuasi1D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, + IdealGlmMhdMultiIonEquations2D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, @@ -179,6 +180,8 @@ export flux, flux_central, flux_lax_friedrichs, flux_hll, flux_hllc, flux_hlle, flux_godunov, flux_chandrashekar, flux_ranocha, flux_derigs_etal, flux_hindenlang_gassner, flux_nonconservative_powell, flux_nonconservative_powell_local_symmetric, + flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal, + flux_nonconservative_central, flux_kennedy_gruber, flux_shima_etal, flux_ec, flux_fjordholm_etal, flux_nonconservative_fjordholm_etal, flux_wintermeyer_etal, flux_nonconservative_wintermeyer_etal, @@ -212,7 +215,8 @@ export boundary_condition_do_nothing, BoundaryConditionNavierStokesWall, NoSlip, Adiabatic, Isothermal, BoundaryConditionCoupled -export initial_condition_convergence_test, source_terms_convergence_test +export initial_condition_convergence_test, source_terms_convergence_test, + source_terms_lorentz export source_terms_harmonic export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic, boundary_condition_poisson_nonperiodic @@ -225,9 +229,10 @@ export density, pressure, density_pressure, velocity, global_mean_vars, equilibrium_distribution, waterheight_pressure export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, cross_helicity, - enstrophy + enstrophy, magnetic_field, divergence_cleaning_field export lake_at_rest_error export ncomponents, eachcomponent +export get_component export TreeMesh, StructuredMesh, StructuredMeshView, UnstructuredMesh2D, P4estMesh, T8codeMesh diff --git a/src/callbacks_step/glm_speed.jl b/src/callbacks_step/glm_speed.jl index 0bd87c189bc..075e084949a 100644 --- a/src/callbacks_step/glm_speed.jl +++ b/src/callbacks_step/glm_speed.jl @@ -9,7 +9,8 @@ GlmSpeedCallback(; glm_scale=0.5, cfl, semi_indices=()) Update the divergence cleaning wave speed `c_h` according to the time step -computed in [`StepsizeCallback`](@ref) for the ideal GLM-MHD equations. +computed in [`StepsizeCallback`](@ref) for the ideal GLM-MHD equations, the multi-component +GLM-MHD equations, and the multi-ion GLM-MHD equations. The `cfl` number should be set to the same value as for the time step size calculation. The `glm_scale` ensures that the GLM wave speed is lower than the fastest physical waves in the MHD solution and should thus be set to a value within the interval [0,1]. Note that `glm_scale = 0` diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index 4d9e4eee23f..085dd1a7417 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -7,7 +7,8 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations}, + AbstractIdealGlmMhdMulticomponentEquations, + IdealGlmMhdMultiIonEquations2D}, dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes @@ -28,7 +29,8 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, - AbstractIdealGlmMhdMulticomponentEquations}, + AbstractIdealGlmMhdMulticomponentEquations, + IdealGlmMhdMultiIonEquations2D}, dg::DGMulti, cache) rd = dg.basis md = mesh.md diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 0304ea16cfe..70aff7613e6 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -491,6 +491,11 @@ abstract type AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP} <: include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") +# IdealMhdMultiIonEquations +abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: + AbstractEquations{NDIMS, NVARS} end +include("ideal_glm_mhd_multiion_2d.jl") + # Retrieve number of components from equation instance for the multicomponent case @inline function ncomponents(::AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, NCOMP}) where { @@ -511,6 +516,26 @@ In particular, not the components themselves are returned. Base.OneTo(ncomponents(equations)) end +# Retrieve number of components from equation instance for the multi-ion case +@inline function ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where { + NDIMS, + NVARS, + NCOMP + } + NCOMP +end + +""" + eachcomponent(equations::AbstractIdealMhdMultiIonEquations) + +Return an iterator over the indices that specify the location in relevant data structures +for the components in `AbstractIdealMhdMultiIonEquations`. +In particular, not the components themselves are returned. +""" +@inline function eachcomponent(equations::AbstractIdealMhdMultiIonEquations) + Base.OneTo(ncomponents(equations)) +end + # Diffusion equation: first order hyperbolic system abstract type AbstractHyperbolicDiffusionEquations{NDIMS, NVARS} <: AbstractEquations{NDIMS, NVARS} end diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl new file mode 100644 index 00000000000..7c376c92631 --- /dev/null +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -0,0 +1,1108 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = NaN) + +The ideal compressible multi-ion MHD equations in two space dimensions augmented with a +generalized Langange multipliers (GLM) divergence-cleaning technique. This is a +multi-species variant of the ideal GLM-MHD equations for calorically perfect plasmas +with independent momentum and energy equations for each ion species. This implementation +assumes that the equations are non-dimensionalized such, that the vacuum permeability is ``\mu_0 = 1``. + +In case of more than one ion species, the specific heat capacity ratios `gammas` and the charge-to-mass +ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. + +The argument `electron_pressure` can be used to pass a function that computes the electron +pressure as a function of the state `u` with the signature `electron_pressure(u, equations::IdealGlmMhdMultiIonEquations2D)`. +By default, the electron pressure is zero. + +The argument `initial_c_h` can be used to set the GLM divergence-cleaning speed. Note that +`initial_c_h = 0` deactivates the divergence cleaning. The callback [`GlmSpeedCallback`](@ref) +can be used to adjust the GLM divergence-cleaning speed according to the time-step size. + +References: +- G. Toth, A. Glocer, Y. Ma, D. Najib, Multi-Ion Magnetohydrodynamics 429 (2010). Numerical + Modeling of Space Plasma Flows, 213–218. +- 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). + +!!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used + with `source_terms_lorentz`. +""" +mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, + ElectronPressure} <: + AbstractIdealMhdMultiIonEquations{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 + function IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + ElectronPressure}(gammas + ::SVector{NCOMP, RealT}, + charge_to_mass + ::SVector{NCOMP, RealT}, + electron_pressure + ::ElectronPressure, + c_h::RealT) where + {NVARS, NCOMP, RealT <: Real, ElectronPressure} + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass, electron_pressure, c_h) + end +end + +function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = convert(eltype(gammas), NaN)) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 4 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + initial_c_h) +end + +# Outer constructor for `@reset` works correctly +function IdealGlmMhdMultiIonEquations2D(gammas, charge_to_mass, electron_pressure, c_h) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 4 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + c_h = convert(RealT, c_h) + + return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + c_h) +end + +@inline function Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT +end + +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations2D) = True() + +function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + cons = (cons..., "psi") + + return cons +end + +function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) + end + prim = (prim..., "psi") + + return prim +end + +function default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + +""" + initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) + +A weak blast wave (adapted to multi-ion MHD) from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, + equations::IdealGlmMhdMultiIonEquations2D) + # 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 + inicenter = (0, 0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + r = sqrt(x_norm^2 + y_norm^2) + phi = atan(y_norm, x_norm) + + # Calculate primitive variables + rho = zero(real(equations)) + if r > 0.5 + rho = 1.0 + else + rho = 1.1691 + end + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + p = r > 0.5 ? 1.0 : 1.245 + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + v2, 0, p, equations) + end + + return prim2cons(SVector(prim), equations) +end + +# 2D flux of the GLM-MHD equations in the direction `orientation` +@inline function flux(u, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + mag_en = 0.5 * (B1^2 + B2^2 + B3^2) + div_clean_energy = 0.5 * psi^2 + + f = zero(MVector{nvariables(equations), eltype(u)}) + + if orientation == 1 + f[1] = equations.c_h * psi + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) + + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B1 + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + f[end] = equations.c_h * B1 + else #if orientation == 2 + f[1] = v2_plus * B1 - v1_plus * B2 + f[2] = equations.c_h * psi + f[3] = v2_plus * B3 - v3_plus * B2 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) + + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_v2 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B2 + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + f[end] = equations.c_h * B2 + end + + return SVector(f) +end + +""" + source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) + +Source terms due to the Lorentz' force for plasmas with more than one ion species. These source +terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for +a single-species plasma. +""" +function source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end + + return SVector(s) +end + +""" + electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) + +Returns the value of zero for the electron pressure. Needed for consistency with the +single-fluid MHD equations in the limit of one ion species. +""" +function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) + return zero(u[1]) +end + +""" + flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + +Entropy-conserving non-conservative two-point "flux"" as described in +- 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). + +ATTENTION: The non-conservative fluxes derived in the reference above are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied + by 0.5 whenever they are used in the Trixi code + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a function of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. +""" +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + 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) + + # Compute important averages + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) + + # Mean electron pressure + pe_ll = equations.electron_pressure(u_ll, equations) + pe_rr = equations.electron_pressure(u_rr, equations) + pe_mean = 0.5 * (pe_ll + pe_rr) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2.0f0 * v1_plus_ll * B1_avg + f[2] = 2.0f0 * v2_plus_ll * B1_avg + f[3] = 2.0f0 * v3_plus_ll * B1_avg + + for k in eachcomponent(equations) + # Compute term Lorentz term + f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = vk1_plus_ll[k] * pe_mean + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B1_avg + f3 += charge_ratio_ll[k] * B2_ll * B1_avg + f4 += charge_ratio_ll[k] * B3_ll * B1_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B1_avg + + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * psi_avg + + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + equations) + end + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2.0f0 * v1_plus_ll * psi_avg + + else #if orientation == 2 + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2.0f0 * v1_plus_ll * B2_avg + f[2] = 2.0f0 * v2_plus_ll * B2_avg + f[3] = 2.0f0 * v3_plus_ll * B2_avg + + for k in eachcomponent(equations) + # Compute term Lorentz term + f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) + f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) + f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) + f5 = vk2_plus_ll[k] * pe_mean + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B2_avg + f3 += charge_ratio_ll[k] * B2_ll * B2_avg + f4 += charge_ratio_ll[k] * B3_ll * B2_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B2_avg + + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * psi_avg + + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + equations) + end + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2.0f0 * v2_plus_ll * psi_avg + end + + return SVector(f) +end + +""" + flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + +Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. +The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" +(weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a +standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. + +ATTENTION: The central non-conservative fluxes are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + we omit the 0.5 when computing averages because the non-conservative flux is multiplied by + 0.5 whenever it's used in the Trixi code + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a function of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + 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) + + # Compute important averages + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Electron pressure + pe_ll = equations.electron_pressure(u_ll, equations) + pe_rr = equations.electron_pressure(u_rr, equations) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(real(equations)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B1_ll + B1_rr) + f[2] = v2_plus_ll * (B1_ll + B1_rr) + f[3] = v3_plus_ll * (B1_ll + B1_rr) + for k in eachcomponent(equations) + # Compute Lorentz term + f2 = charge_ratio_ll[k] * ((0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + + (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) + f3 = charge_ratio_ll[k] * ((-B1_ll * B2_ll) + (-B1_rr * B2_rr)) + f4 = charge_ratio_ll[k] * ((-B1_ll * B3_ll) + (-B1_rr * B3_rr)) + f5 = vk1_plus_ll[k] * (pe_ll + pe_rr) + + # Compute multi-ion term, which vanishes for NCOMP==1 + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * ((vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + + (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr)) + + B3_ll * ((vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + + (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B1_ll + B1_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B1_ll + B1_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B1_ll + B1_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B1_ll + B1_rr) + + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * (psi_ll + psi_rr) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + # Compute GLM term for psi + f[end] = v1_plus_ll * (psi_ll + psi_rr) + + else #if orientation == 2 + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B2_ll + B2_rr) + f[2] = v2_plus_ll * (B2_ll + B2_rr) + f[3] = v3_plus_ll * (B2_ll + B2_rr) + + for k in eachcomponent(equations) + # Compute Lorentz term + f2 = charge_ratio_ll[k] * ((-B2_ll * B1_ll) + (-B2_rr * B1_rr)) + f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5 * mag_norm_ll + pe_ll) + + (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr)) + f4 = charge_ratio_ll[k] * ((-B2_ll * B3_ll) + (-B2_rr * B3_rr)) + f5 = vk2_plus_ll[k] * (pe_ll + pe_rr) + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B1_ll * ((vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + + (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr)) + + B3_ll * ((vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll) + + (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B2_ll + B2_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B2_ll + B2_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B2_ll + B2_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B2_ll + B2_rr) + + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * (psi_ll + psi_rr) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + # Compute GLM term for psi + f[end] = v2_plus_ll * (psi_ll + psi_rr) + end + + return SVector(f) +end + +""" +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations2D) + +Entropy conserving two-point flux for the multi-ion GLM-MHD equations from +- 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). + +This flux (together with the MHD non-conservative term) is consistent in the case of one ion species with the flux of: +- Derigs et al. (2018). Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + 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) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Compute averages for global variables + v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) + + if orientation == 1 + psi_B1_avg = 0.5 * (B1_ll * psi_ll + B1_rr * psi_rr) + + # Magnetic field components from f^MHD + f6 = equations.c_h * psi_avg + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + f9 = equations.c_h * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + f[end] = f9 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - + 0.5 * psi_ll^2) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - + 0.5 * psi_rr^2) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Fill the fluxes for the mass and momentum equations + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term + + + 0.5 * vk1_plus_avg * mag_norm_avg - + vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - + vk3_plus_avg * B1_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + else #if orientation == 2 + psi_B2_avg = 0.5 * (B2_ll * psi_ll + B2_rr * psi_rr) + + # Magnetic field components from f^MHD + f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg + f7 = equations.c_h * psi_avg + f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg + f9 = equations.c_h * B2_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + f[end] = f9 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - + 0.5 * psi_ll^2) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - + 0.5 * psi_rr^2) + beta_ll = 0.5 * rho_ll / p_ll + beta_rr = 0.5 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + + # Fill the fluxes for the mass and momentum equations + f1 = rho_mean * v2_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_mean + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + + vk2_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term + + + 0.5 * vk2_plus_avg * mag_norm_avg - + vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - + vk3_plus_avg * B2_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) + - + B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - + B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + end + + return SVector(f) +end + +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation +# This routine approximates the maximum wave speed as sum of the maximum ion velocity +# for all species and the maximum magnetosonic speed. +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + if orientation == 1 + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + else #if orientation == 2 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v2 / rho)) + rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v2 / rho)) + end + end + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end + +@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations2D) + v1 = zero(real(equations)) + v2 = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + v2 = max(v2, abs(rho_v2 / rho)) + end + + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + cf_y_direction = calc_fast_wavespeed(u, 2, equations) + + return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) +end + +#Convert conservative variables to primitive +function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3 + + psi * psi)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) + end + prim[end] = psi + + return SVector(prim) +end + +#Convert conservative variables to entropy variables +@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + end + + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + entropy[end] = rho_p_plus * psi + + return SVector(entropy) +end + +# Convert primitive to conservative variables +@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + psi = divergence_cleaning_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5 * (B1^2 + B2^2 + B3^2) + + 0.5 * psi^2 + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + end + cons[end] = psi + + return SVector(cons) +end + +# Compute the fastest wave speed for ideal multi-ion GLM-MHD equations: c_f, the fast +# magnetoacoustic eigenvalue. This routine computes the fast magnetosonic speed for each ion +# species using the single-fluid MHD expressions and approximates the multi-ion c_f as +# the maximum of these individual magnetosonic speeds. +@inline function calc_fast_wavespeed(cons, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) + B1, B2, B3 = magnetic_field(cons, equations) + psi = divergence_cleaning_field(cons, equations) + + c_f = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * + (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + if orientation == 1 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + else #if orientation == 2 + c_f = max(c_f, + sqrt(0.5 * (a_square + b_square) + + 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) + end + end + + return c_f +end + +""" +v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations2D) + + +Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution +to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 +are SVectors of size ncomponents(equations). +""" +@inline function charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations2D) + total_electron_charge = zero(real(equations)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations::IdealGlmMhdMultiIonEquations2D) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) +end + +""" + get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) + +Get the hydrodynamic variables of component (ion species) k. +""" +@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" + set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealGlmMhdMultiIonEquations2D) + +Set the hydrodynamic variables of component (ion species) k. +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealGlmMhdMultiIonEquations2D) + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + + return u +end + +# Extract magnetic field from solution vector +magnetic_field(u, equations::IdealGlmMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) + +# Extract GLM divergence-cleaning field from solution vector +divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations2D) = u[end] + +# Get total density as the sum of the individual densities of the ion species +@inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) + rho = zero(real(equations)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho +end +end # @muladd diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl new file mode 100644 index 00000000000..56d34ec30fb --- /dev/null +++ b/test/test_tree_2d_mhdmultiion.jl @@ -0,0 +1,123 @@ +module TestExamples2DEulerMulticomponent + +using Test +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") + +@testset "MHD Multi-ion" begin +#! format: noindent + +@trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[ + 0.018116158127836963, + 0.018242057606900185, + 0.02842532060540296, + 0.015805662470907644, + 0.018125738668209504, + 0.01841652763250858, + 0.005540867360495384, + 0.2091437538608106, + 0.021619156799420326, + 0.030561821442897923, + 0.029778012392807182, + 0.018651133866567658, + 0.1204153285953923, + 0.00017580766470956546 + ], + linf=[ + 0.08706810449620284, + 0.085845022468381, + 0.15301576281555795, + 0.07924698349506726, + 0.11185098353068998, + 0.10902813348518392, + 0.03512713073214368, + 1.018607282408099, + 0.11897673517549667, + 0.18757934071639615, + 0.19089795413679128, + 0.10989483685170078, + 0.6078381519649727, + 0.00673110606965085 + ]) +end + +@trixi_testset "elixir_mhdmultiion_es.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.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 + ]) +end + +@trixi_testset "elixir_mhdmultiion_ec+llf.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec+llf.jl"), + l2=[ + 0.017668026737187294, + 0.017797845988889206, + 0.02784171335711194, + 0.015603472482130114, + 0.017849085712788024, + 0.018142011483140937, + 0.005478230098832851, + 0.20585547149049335, + 0.021301307197244185, + 0.030185081369414384, + 0.029385190432285654, + 0.01837280802521888, + 0.11810313415151609, + 0.0002962121353575025 + ], + linf=[ + 0.06594404679380572, + 0.0658741409805832, + 0.09451390288403083, + 0.06787235653416557, + 0.0891017651119973, + 0.08828137594061974, + 0.02364750099643367, + 0.8059321345611803, + 0.12243877249999213, + 0.15930897967901766, + 0.1538327998380914, + 0.08694877996306204, + 0.49493751138636366, + 0.003287414714660175 + ]) +end +end + +end # module diff --git a/test/test_tree_2d_part3.jl b/test/test_tree_2d_part3.jl index 0eff564132c..42633ceae17 100644 --- a/test/test_tree_2d_part3.jl +++ b/test/test_tree_2d_part3.jl @@ -20,6 +20,9 @@ isdir(outdir) && rm(outdir, recursive = true) # MHD Multicomponent include("test_tree_2d_mhdmulti.jl") + # MHD Multi-ion + include("test_tree_2d_mhdmultiion.jl") + # Lattice-Boltzmann include("test_tree_2d_lbm.jl") From 81792ee1be4ede4a3d5345c32425864510244f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Mon, 9 Dec 2024 21:18:47 +0100 Subject: [PATCH 072/108] Fixed typos and removed non-existing function from export --- src/Trixi.jl | 2 +- src/equations/ideal_glm_mhd_multiion_2d.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index fa42e19ad9d..a4b4687bff1 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -227,7 +227,7 @@ export initial_condition_eoc_test_coupled_euler_gravity, export cons2cons, cons2prim, prim2cons, cons2macroscopic, cons2state, cons2mean, cons2entropy, entropy2cons export density, pressure, density_pressure, velocity, global_mean_vars, - equilibrium_distribution, waterheight_pressure, density_product + equilibrium_distribution, waterheight_pressure export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, cross_helicity, enstrophy, magnetic_field, divergence_cleaning_field diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 3a85796c795..03197e30d95 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -16,7 +16,7 @@ multi-species variant of the ideal GLM-MHD equations for calorically perfect pla with independent momentum and energy equations for each ion species. This implementation assumes that the equations are non-dimensionalized such, that the vacuum permeability is ``\mu_0 = 1``. -In case of more than one ion species, the specific heat capcity ratios `gammas` and the charge-to-mass +In case of more than one ion species, the specific heat capacity ratios `gammas` and the charge-to-mass ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. The argument `electron_pressure` can be used to pass a function that computes the electron @@ -316,7 +316,7 @@ ATTENTION: The non-conservative fluxes derived in the reference above are writte The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and - is evaluated as a funciton of the charge-averaged velocity. + is evaluated as a function of the charge-averaged velocity. 2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing electron pressure gradients. 3. The "multi-ion" term, which vanishes in the limit of one ion species. @@ -477,7 +477,7 @@ ATTENTION: The central non-conservative fluxes are written as the product The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and - is evaluated as a funciton of the charge-averaged velocity. + is evaluated as a function of the charge-averaged velocity. 2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing electron pressure gradients. 3. The "multi-ion" term, which vanishes in the limit of one ion species. From 76eaaf8d24c41560715fe73124e8c49f2e686140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 03:50:50 +0100 Subject: [PATCH 073/108] Remove ES test --- test/test_tree_2d_mhdmultiion.jl | 36 -------------------------------- 1 file changed, 36 deletions(-) diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index 56d34ec30fb..ac91c47a33f 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -47,42 +47,6 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 ]) end -@trixi_testset "elixir_mhdmultiion_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.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 - ]) -end - @trixi_testset "elixir_mhdmultiion_ec+llf.jl" begin @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec+llf.jl"), l2=[ From 0b17871241d806c0d3f259ea806c66767c4d9290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 04:02:35 +0100 Subject: [PATCH 074/108] Compatibility for single precision --- src/equations/ideal_glm_mhd_multiion_2d.jl | 200 +++++++++++---------- 1 file changed, 102 insertions(+), 98 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 7c376c92631..c8fc6501fdf 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -161,18 +161,18 @@ function initial_condition_weak_blast_wave(x, t, # Calculate primitive variables rho = zero(real(equations)) if r > 0.5 - rho = 1.0 + rho = 1.0f0 else - rho = 1.1691 + rho = 1.1691f0 end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) - p = r > 0.5 ? 1.0 : 1.245 + v1 = r > 0.5 ? 0.0f0 : 0.1882f0 * cos(phi) + v2 = r > 0.5 ? 0.0f0 : 0.1882f0 * sin(phi) + p = r > 0.5 ? 1.0f0 : 1.245f0 prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 + prim[1] = 1.0f0 + prim[2] = 1.0f0 + prim[3] = 1.0f0 for k in eachcomponent(equations) set_component!(prim, k, 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, @@ -191,8 +191,8 @@ end v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - div_clean_energy = 0.5 * psi^2 + mag_en = 0.5f0 * (B1^2 + B2^2 + B3^2) + div_clean_energy = 0.5f0 * psi^2 f = zero(MVector{nvariables(equations), eltype(u)}) @@ -206,7 +206,7 @@ end v1 = rho_v1 / rho v2 = rho_v2 / rho v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) @@ -232,7 +232,7 @@ end v1 = rho_v1 / rho v2 = rho_v2 / rho v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) @@ -333,18 +333,18 @@ The term is composed of four individual non-conservative terms: psi_rr = divergence_cleaning_field(u_rr, equations) # Compute important averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) + B1_avg = 0.5f0 * (B1_ll + B1_rr) + B2_avg = 0.5f0 * (B2_ll + B2_rr) + B3_avg = 0.5f0 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) # Mean electron pressure pe_ll = equations.electron_pressure(u_ll, equations) pe_rr = equations.electron_pressure(u_rr, equations) - pe_mean = 0.5 * (pe_ll + pe_rr) + pe_mean = 0.5f0 * (pe_ll + pe_rr) # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) @@ -373,7 +373,7 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute term Lorentz term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f2 = charge_ratio_ll[k] * (0.5f0 * mag_norm_avg - B1_avg * B1_avg + pe_mean) f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) f5 = vk1_plus_ll[k] * pe_mean @@ -385,9 +385,9 @@ The term is composed of four individual non-conservative terms: vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) @@ -420,7 +420,8 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute term Lorentz term f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) - f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) + f3 = charge_ratio_ll[k] * + (-B2_avg * B2_avg + 0.5f0 * mag_norm_avg + pe_mean) f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) f5 = vk2_plus_ll[k] * pe_mean @@ -431,9 +432,9 @@ The term is composed of four individual non-conservative terms: vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) @@ -525,8 +526,8 @@ The term is composed of four individual non-conservative terms: f[3] = v3_plus_ll * (B1_ll + B1_rr) for k in eachcomponent(equations) # Compute Lorentz term - f2 = charge_ratio_ll[k] * ((0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + - (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) + f2 = charge_ratio_ll[k] * ((0.5f0 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + + (0.5f0 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) f3 = charge_ratio_ll[k] * ((-B1_ll * B2_ll) + (-B1_rr * B2_rr)) f4 = charge_ratio_ll[k] * ((-B1_ll * B3_ll) + (-B1_rr * B3_rr)) f5 = vk1_plus_ll[k] * (pe_ll + pe_rr) @@ -568,8 +569,8 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute Lorentz term f2 = charge_ratio_ll[k] * ((-B2_ll * B1_ll) + (-B2_rr * B1_rr)) - f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5 * mag_norm_ll + pe_ll) + - (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr)) + f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5f0 * mag_norm_ll + pe_ll) + + (-B2_rr * B2_rr + 0.5f0 * mag_norm_rr + pe_rr)) f4 = charge_ratio_ll[k] * ((-B2_ll * B3_ll) + (-B2_rr * B3_rr)) f5 = vk2_plus_ll[k] * (pe_ll + pe_rr) @@ -635,19 +636,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f = zero(MVector{nvariables(equations), eltype(u_ll)}) # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) + v1_plus_avg = 0.5f0 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5f0 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5f0 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5f0 * (B1_ll + B1_rr) + B2_avg = 0.5f0 * (B2_ll + B2_rr) + B3_avg = 0.5f0 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) if orientation == 1 - psi_B1_avg = 0.5 * (B1_ll * psi_ll + B1_rr * psi_rr) + psi_B1_avg = 0.5f0 * (B1_ll * psi_ll + B1_rr * psi_rr) # Magnetic field components from f^MHD f6 = equations.c_h * psi_avg @@ -679,13 +680,13 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - - 0.5 * psi_ll^2) + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - - 0.5 * psi_rr^2) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll @@ -693,19 +694,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) + rho_avg = 0.5f0 * (rho_ll + rho_rr) rho_mean = ln_mean(rho_ll, rho_rr) beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -713,9 +714,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v1_avg @@ -724,17 +725,17 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + + v1_plus_mag_avg = 0.5f0 * (vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term + - 0.5 * vk1_plus_avg * mag_norm_avg - + 0.5f0 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - @@ -744,7 +745,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, set_component!(f, k, f1, f2, f3, f4, f5, equations) end else #if orientation == 2 - psi_B2_avg = 0.5 * (B2_ll * psi_ll + B2_rr * psi_rr) + psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr) # Magnetic field components from f^MHD f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg @@ -776,13 +777,13 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - - 0.5 * psi_ll^2) + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - - 0.5 * psi_rr^2) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll @@ -790,19 +791,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) + rho_avg = 0.5f0 * (rho_ll + rho_rr) rho_mean = ln_mean(rho_ll, rho_rr) beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -810,9 +811,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v2_avg @@ -821,17 +822,17 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components - v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + + v2_plus_mag_avg = 0.5f0 * (vk2_plus_ll[k] * mag_norm_ll + vk2_plus_rr[k] * mag_norm_rr) # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term + - 0.5 * vk2_plus_avg * mag_norm_avg - + 0.5f0 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - @@ -911,7 +912,7 @@ function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) v3 = srho * rho_v3 p = (gammas[k] - 1) * (rho_e - - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + B1 * B1 + B2 * B2 + B3 * B3 + psi * psi)) @@ -935,7 +936,7 @@ end rho, v1, v2, v3, p = get_component(k, prim, equations) s = log(p) - gammas[k] * log(rho) rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) w2 = rho_p * v1 w3 = rho_p * v2 w4 = rho_p * v3 @@ -971,9 +972,9 @@ end rho_v3 = rho * v3 rho_e = p / (gammas[k] - 1.0) + - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) + - 0.5 * psi^2 + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5f0 * (B1^2 + B2^2 + B3^2) + + 0.5f0 * psi^2 set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end @@ -1001,7 +1002,8 @@ end v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * - (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - + 0.5f0 * psi^2) a_square = gamma * p / rho sqrt_rho = sqrt(rho) @@ -1012,12 +1014,14 @@ end if orientation == 1 c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b1^2))) else #if orientation == 2 c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b2^2))) end end From 42dbc962dddd2ed6f529287af7e407a636f8b495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 11:39:26 +0100 Subject: [PATCH 075/108] Changed initial condition back to double precision --- src/equations/ideal_glm_mhd_multiion_2d.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index c8fc6501fdf..cdf4b92332d 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -161,18 +161,18 @@ function initial_condition_weak_blast_wave(x, t, # Calculate primitive variables rho = zero(real(equations)) if r > 0.5 - rho = 1.0f0 + rho = 1.0 else - rho = 1.1691f0 + rho = 1.1691 end - v1 = r > 0.5 ? 0.0f0 : 0.1882f0 * cos(phi) - v2 = r > 0.5 ? 0.0f0 : 0.1882f0 * sin(phi) - p = r > 0.5 ? 1.0f0 : 1.245f0 + v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) + v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) + p = r > 0.5 ? 1.0 : 1.245 prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0f0 - prim[2] = 1.0f0 - prim[3] = 1.0f0 + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 for k in eachcomponent(equations) set_component!(prim, k, 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, From 9c2f97ee467ffd18ba5aeeb7117be31ab2ceced3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 13:27:53 +0100 Subject: [PATCH 076/108] Single precision compatibility --- src/equations/ideal_glm_mhd_multiion_2d.jl | 184 +++++++++++---------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 03197e30d95..f320ac55015 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -191,8 +191,8 @@ end v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, equations) - mag_en = 0.5 * (B1^2 + B2^2 + B3^2) - div_clean_energy = 0.5 * psi^2 + mag_en = 0.5f0 * (B1^2 + B2^2 + B3^2) + div_clean_energy = 0.5f0 * psi^2 f = zero(MVector{nvariables(equations), eltype(u)}) @@ -206,7 +206,7 @@ end v1 = rho_v1 / rho v2 = rho_v2 / rho v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) @@ -232,7 +232,7 @@ end v1 = rho_v1 / rho v2 = rho_v2 / rho v3 = rho_v3 / rho - kin_en = 0.5 * rho * (v1^2 + v2^2 + v3^2) + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) @@ -333,18 +333,18 @@ The term is composed of four individual non-conservative terms: psi_rr = divergence_cleaning_field(u_rr, equations) # Compute important averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) + B1_avg = 0.5f0 * (B1_ll + B1_rr) + B2_avg = 0.5f0 * (B2_ll + B2_rr) + B3_avg = 0.5f0 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) # Mean electron pressure pe_ll = equations.electron_pressure(u_ll, equations) pe_rr = equations.electron_pressure(u_rr, equations) - pe_mean = 0.5 * (pe_ll + pe_rr) + pe_mean = 0.5f0 * (pe_ll + pe_rr) # Compute charge ratio of u_ll charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) @@ -373,7 +373,7 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute term Lorentz term - f2 = charge_ratio_ll[k] * (0.5 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f2 = charge_ratio_ll[k] * (0.5f0 * mag_norm_avg - B1_avg * B1_avg + pe_mean) f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) f5 = vk1_plus_ll[k] * pe_mean @@ -385,9 +385,9 @@ The term is composed of four individual non-conservative terms: vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) @@ -420,7 +420,8 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute term Lorentz term f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) - f3 = charge_ratio_ll[k] * (-B2_avg * B2_avg + 0.5 * mag_norm_avg + pe_mean) + f3 = charge_ratio_ll[k] * + (-B2_avg * B2_avg + 0.5f0 * mag_norm_avg + pe_mean) f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) f5 = vk2_plus_ll[k] * pe_mean @@ -431,9 +432,9 @@ The term is composed of four individual non-conservative terms: vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) @@ -525,8 +526,8 @@ The term is composed of four individual non-conservative terms: f[3] = v3_plus_ll * (B1_ll + B1_rr) for k in eachcomponent(equations) # Compute Lorentz term - f2 = charge_ratio_ll[k] * ((0.5 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + - (0.5 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) + f2 = charge_ratio_ll[k] * ((0.5f0 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + + (0.5f0 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) f3 = charge_ratio_ll[k] * ((-B1_ll * B2_ll) + (-B1_rr * B2_rr)) f4 = charge_ratio_ll[k] * ((-B1_ll * B3_ll) + (-B1_rr * B3_rr)) f5 = vk1_plus_ll[k] * (pe_ll + pe_rr) @@ -568,8 +569,8 @@ The term is composed of four individual non-conservative terms: for k in eachcomponent(equations) # Compute Lorentz term f2 = charge_ratio_ll[k] * ((-B2_ll * B1_ll) + (-B2_rr * B1_rr)) - f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5 * mag_norm_ll + pe_ll) + - (-B2_rr * B2_rr + 0.5 * mag_norm_rr + pe_rr)) + f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5f0 * mag_norm_ll + pe_ll) + + (-B2_rr * B2_rr + 0.5f0 * mag_norm_rr + pe_rr)) f4 = charge_ratio_ll[k] * ((-B2_ll * B3_ll) + (-B2_rr * B3_rr)) f5 = vk2_plus_ll[k] * (pe_ll + pe_rr) @@ -635,19 +636,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f = zero(MVector{nvariables(equations), eltype(u_ll)}) # Compute averages for global variables - v1_plus_avg = 0.5 * (v1_plus_ll + v1_plus_rr) - v2_plus_avg = 0.5 * (v2_plus_ll + v2_plus_rr) - v3_plus_avg = 0.5 * (v3_plus_ll + v3_plus_rr) - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) + v1_plus_avg = 0.5f0 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5f0 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5f0 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5f0 * (B1_ll + B1_rr) + B2_avg = 0.5f0 * (B2_ll + B2_rr) + B3_avg = 0.5f0 * (B3_ll + B3_rr) mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 - mag_norm_avg = 0.5 * (mag_norm_ll + mag_norm_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) if orientation == 1 - psi_B1_avg = 0.5 * (B1_ll * psi_ll + B1_rr * psi_rr) + psi_B1_avg = 0.5f0 * (B1_ll * psi_ll + B1_rr * psi_rr) # Magnetic field components from f^MHD f6 = equations.c_h * psi_avg @@ -679,13 +680,13 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - - 0.5 * psi_ll^2) + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - - 0.5 * psi_rr^2) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll @@ -693,19 +694,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) + rho_avg = 0.5f0 * (rho_ll + rho_rr) rho_mean = ln_mean(rho_ll, rho_rr) beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -713,9 +714,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v1_avg @@ -724,17 +725,17 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components - v1_plus_mag_avg = 0.5 * (vk1_plus_ll[k] * mag_norm_ll + + v1_plus_mag_avg = 0.5f0 * (vk1_plus_ll[k] * mag_norm_ll + vk1_plus_rr[k] * mag_norm_rr) # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v1_plus_mag_avg + + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v1_plus_mag_avg + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term + - 0.5 * vk1_plus_avg * mag_norm_avg - + 0.5f0 * vk1_plus_avg * mag_norm_avg - vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - vk3_plus_avg * B1_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - @@ -744,7 +745,7 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, set_component!(f, k, f1, f2, f3, f4, f5, equations) end else #if orientation == 2 - psi_B2_avg = 0.5 * (B2_ll * psi_ll + B2_rr * psi_rr) + psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr) # Magnetic field components from f^MHD f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg @@ -776,13 +777,13 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2 p_ll = (gammas[k] - 1) * - (rho_e_ll - 0.5 * rho_ll * vel_norm_ll - 0.5 * mag_norm_ll - - 0.5 * psi_ll^2) + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) p_rr = (gammas[k] - 1) * - (rho_e_rr - 0.5 * rho_rr * vel_norm_rr - 0.5 * mag_norm_rr - - 0.5 * psi_rr^2) - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr # for convenience store vk_plus⋅B vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + vk3_plus_ll[k] * B3_ll @@ -790,19 +791,19 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk3_plus_rr[k] * B3_rr # Compute the necessary mean values needed for either direction - rho_avg = 0.5 * (rho_ll + rho_rr) + rho_avg = 0.5f0 * (rho_ll + rho_rr) rho_mean = ln_mean(rho_ll, rho_rr) beta_mean = ln_mean(beta_ll, beta_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_rr) - vel_dot_mag_avg = 0.5 * (vel_dot_mag_ll + vel_dot_mag_rr) - vk1_plus_avg = 0.5 * (vk1_plus_ll[k] + vk1_plus_rr[k]) - vk2_plus_avg = 0.5 * (vk2_plus_ll[k] + vk2_plus_rr[k]) - vk3_plus_avg = 0.5 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) # v_minus vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] @@ -810,9 +811,9 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] - vk1_minus_avg = 0.5 * (vk1_minus_ll + vk1_minus_rr) - vk2_minus_avg = 0.5 * (vk2_minus_ll + vk2_minus_rr) - vk3_minus_avg = 0.5 * (vk3_minus_ll + vk3_minus_rr) + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) # Fill the fluxes for the mass and momentum equations f1 = rho_mean * v2_avg @@ -821,17 +822,17 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, f4 = f1 * v3_avg # total energy flux is complicated and involves the previous eight components - v2_plus_mag_avg = 0.5 * (vk2_plus_ll[k] * mag_norm_ll + + v2_plus_mag_avg = 0.5f0 * (vk2_plus_ll[k] * mag_norm_ll + vk2_plus_rr[k] * mag_norm_rr) # Euler part - f5 = f1 * 0.5 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg # MHD part - f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5 * v2_plus_mag_avg + + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v2_plus_mag_avg + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term + - 0.5 * vk2_plus_avg * mag_norm_avg - + 0.5f0 * vk2_plus_avg * mag_norm_avg - vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - vk3_plus_avg * B2_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) - @@ -911,7 +912,7 @@ function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) v3 = srho * rho_v3 p = (gammas[k] - 1) * (rho_e - - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + B1 * B1 + B2 * B2 + B3 * B3 + psi * psi)) @@ -935,7 +936,7 @@ end rho, v1, v2, v3, p = get_component(k, prim, equations) s = log(p) - gammas[k] * log(rho) rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5 * rho_p * (v1^2 + v2^2 + v3^2) + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) w2 = rho_p * v1 w3 = rho_p * v2 w4 = rho_p * v3 @@ -971,9 +972,9 @@ end rho_v3 = rho * v3 rho_e = p / (gammas[k] - 1.0) + - 0.5 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5 * (B1^2 + B2^2 + B3^2) + - 0.5 * psi^2 + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5f0 * (B1^2 + B2^2 + B3^2) + + 0.5f0 * psi^2 set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) end @@ -1001,7 +1002,8 @@ end v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * - (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - + 0.5f0 * psi^2) a_square = gamma * p / rho sqrt_rho = sqrt(rho) @@ -1012,12 +1014,14 @@ end if orientation == 1 c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b1^2))) + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b1^2))) else #if orientation == 2 c_f = max(c_f, - sqrt(0.5 * (a_square + b_square) + - 0.5 * sqrt((a_square + b_square)^2 - 4.0 * a_square * b2^2))) + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b2^2))) end end From 8919821baa4c64616e150cc1e7285531b3e6667d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 14:40:05 +0100 Subject: [PATCH 077/108] Update reference to Hennemann et al. --- src/equations/ideal_glm_mhd_multiion_2d.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index cdf4b92332d..93019645d1c 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -143,9 +143,10 @@ end initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) A weak blast wave (adapted to multi-ion MHD) from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +- Hennemann, S., Rueda-Ramírez, A. M., Hindenlang, F. J., & Gassner, G. J. (2021). A provably entropy + stable subcell shock capturing approach for high order split form DG for the compressible Euler equations. + Journal of Computational Physics, 426, 109935. [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044). + [DOI: 10.1016/j.jcp.2020.109935](https://doi.org/10.1016/j.jcp.2020.109935) """ function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) From f58ae6274a34c155d2a990d5146d9ea00172ac21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:15:35 +0100 Subject: [PATCH 078/108] Added 3D GLM-MHD equations with some repeated code --- src/Trixi.jl | 1 + src/callbacks_step/glm_speed_dg.jl | 4 +- src/equations/equations.jl | 20 +- src/equations/ideal_glm_mhd_multiion_2d.jl | 5 +- src/equations/ideal_glm_mhd_multiion_3d.jl | 1362 ++++++++++++++++++++ src/equations/ideal_mhd_multiion_1d.jl | 2 +- 6 files changed, 1379 insertions(+), 15 deletions(-) create mode 100644 src/equations/ideal_glm_mhd_multiion_3d.jl diff --git a/src/Trixi.jl b/src/Trixi.jl index a4b4687bff1..093d5a53998 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -157,6 +157,7 @@ export AcousticPerturbationEquations2D, IdealGlmMhdEquations1D, IdealGlmMhdEquations2D, IdealGlmMhdEquations3D, IdealGlmMhdMulticomponentEquations1D, IdealGlmMhdMulticomponentEquations2D, IdealMhdMultiIonEquations1D, IdealGlmMhdMultiIonEquations2D, + IdealGlmMhdMultiIonEquations3D, HyperbolicDiffusionEquations1D, HyperbolicDiffusionEquations2D, HyperbolicDiffusionEquations3D, LinearScalarAdvectionEquation1D, LinearScalarAdvectionEquation2D, diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index 085dd1a7417..dc2579a3359 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -8,7 +8,7 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealGlmMhdMultiIonEquations2D}, + AbstractIdealGlmMhdMultiIonEquations}, dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes @@ -30,7 +30,7 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealGlmMhdMultiIonEquations2D}, + AbstractIdealGlmMhdMultiIonEquations}, dg::DGMulti, cache) rd = dg.basis md = mesh.md diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 1ed58759613..3e8786ad099 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -492,10 +492,11 @@ include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") # IdealMhdMultiIonEquations -abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: +abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end include("ideal_mhd_multiion_1d.jl") include("ideal_glm_mhd_multiion_2d.jl") +include("ideal_glm_mhd_multiion_3d.jl") # Retrieve number of components from equation instance for the multicomponent case @inline function ncomponents(::AbstractIdealGlmMhdMulticomponentEquations{NDIMS, NVARS, @@ -518,22 +519,23 @@ In particular, not the components themselves are returned. end # Retrieve number of components from equation instance for the multi-ion case -@inline function ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where { - NDIMS, - NVARS, - NCOMP - } +@inline function ncomponents(::AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, + NCOMP}) where { + NDIMS, + NVARS, + NCOMP + } NCOMP end """ - eachcomponent(equations::AbstractIdealMhdMultiIonEquations) + eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) Return an iterator over the indices that specify the location in relevant data structures -for the components in `AbstractIdealMhdMultiIonEquations`. +for the components in `AbstractIdealGlmMhdMultiIonEquations`. In particular, not the components themselves are returned. """ -@inline function eachcomponent(equations::AbstractIdealMhdMultiIonEquations) +@inline function eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) Base.OneTo(ncomponents(equations)) end diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index f320ac55015..6e61ae2964b 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -39,7 +39,7 @@ References: """ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure} <: - AbstractIdealMhdMultiIonEquations{2, NVARS, NCOMP} + 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 @@ -1046,8 +1046,7 @@ are SVectors of size ncomponents(equations). vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealGlmMhdMultiIonEquations2D) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) total_electron_charge += rho * equations.charge_to_mass[k] vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] diff --git a/src/equations/ideal_glm_mhd_multiion_3d.jl b/src/equations/ideal_glm_mhd_multiion_3d.jl new file mode 100644 index 00000000000..eb7e8934fd4 --- /dev/null +++ b/src/equations/ideal_glm_mhd_multiion_3d.jl @@ -0,0 +1,1362 @@ +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +@doc raw""" + IdealGlmMhdMultiIonEquations3D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = NaN) + +The ideal compressible multi-ion MHD equations in three space dimensions augmented with a +generalized Langange multipliers (GLM) divergence-cleaning technique. This is a +multi-species variant of the ideal GLM-MHD equations for calorically perfect plasmas +with independent momentum and energy equations for each ion species. This implementation +assumes that the equations are non-dimensionalized such, that the vacuum permeability is ``\mu_0 = 1``. + +In case of more than one ion species, the specific heat capacity ratios `gammas` and the charge-to-mass +ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. + +The argument `electron_pressure` can be used to pass a function that computes the electron +pressure as a function of the state `u` with the signature `electron_pressure(u, equations::IdealGlmMhdMultiIonEquations3D)`. +By default, the electron pressure is zero. + +The argument `initial_c_h` can be used to set the GLM divergence-cleaning speed. Note that +`initial_c_h = 0` deactivates the divergence cleaning. The callback [`GlmSpeedCallback`](@ref) +can be used to adjust the GLM divergence-cleaning speed according to the time-step size. + +References: +- G. Toth, A. Glocer, Y. Ma, D. Najib, Multi-Ion Magnetohydrodynamics 429 (2010). Numerical + Modeling of Space Plasma Flows, 213–218. +- 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). + +!!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used + with `source_terms_lorentz`. +""" +mutable struct IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT <: Real, + ElectronPressure} <: + AbstractIdealGlmMhdMultiIonEquations{3, 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 + function IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT, + ElectronPressure}(gammas + ::SVector{NCOMP, RealT}, + charge_to_mass + ::SVector{NCOMP, RealT}, + electron_pressure + ::ElectronPressure, + c_h::RealT) where + {NVARS, NCOMP, RealT <: Real, ElectronPressure} + NCOMP >= 1 || + throw(DimensionMismatch("`gammas` and `charge_to_mass` have to be filled with at least one value")) + + new(gammas, charge_to_mass, electron_pressure, c_h) + end +end + +function IdealGlmMhdMultiIonEquations3D(; gammas, charge_to_mass, + electron_pressure = electron_pressure_zero, + initial_c_h = convert(eltype(gammas), NaN)) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 4 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + return IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + initial_c_h) +end + +# Outer constructor for `@reset` works correctly +function IdealGlmMhdMultiIonEquations3D(gammas, charge_to_mass, electron_pressure, c_h) + _gammas = promote(gammas...) + _charge_to_mass = promote(charge_to_mass...) + RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + + NVARS = length(_gammas) * 5 + 4 + NCOMP = length(_gammas) + + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) + + c_h = convert(RealT, c_h) + + return IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT, + typeof(electron_pressure)}(__gammas, + __charge_to_mass, + electron_pressure, + c_h) +end + +@inline function Base.real(::IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT}) where { + NVARS, + NCOMP, + RealT + } + RealT +end + +have_nonconservative_terms(::IdealGlmMhdMultiIonEquations3D) = True() + +function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations3D) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + cons = (cons..., "psi") + + return cons +end + +function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations3D) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) + end + prim = (prim..., "psi") + + return prim +end + +function default_analysis_integrals(::IdealGlmMhdMultiIonEquations3D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + +""" + initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations3D) + +A weak blast wave (adapted to multi-ion MHD) from +- Sebastian Hennemann, Gregor J. Gassner (2020) + A provably entropy stable subcell shock capturing approach for high order split form DG + [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +""" +function initial_condition_weak_blast_wave(x, t, + equations::IdealGlmMhdMultiIonEquations3D) + # 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 + RealT = eltype(x) + # Set up polar coordinates + inicenter = (0, 0, 0) + x_norm = x[1] - inicenter[1] + y_norm = x[2] - inicenter[2] + z_norm = x[3] - inicenter[3] + r = sqrt(x_norm^2 + y_norm^2 + z_norm^2) + phi = atan(y_norm, x_norm) + theta = iszero(r) ? zero(RealT) : acos(z_norm / r) + + # Calculate primitive variables + rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691) + v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi) * sin(theta) + v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) * sin(theta) + v3 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(theta) + p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245) + + prim = zero(MVector{nvariables(equations), real(equations)}) + prim[1] = 1.0 + prim[2] = 1.0 + prim[3] = 1.0 + for k in eachcomponent(equations) + set_component!(prim, k, + 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, + v2, v3, p, equations) + end + + return prim2cons(SVector(prim), equations) +end + +# 3D flux of the multi-ion GLM-MHD equations in the direction `orientation` +@inline function flux(u, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + mag_en = 0.5f0 * (B1^2 + B2^2 + B3^2) + div_clean_energy = 0.5f0 * psi^2 + + f = zero(MVector{nvariables(equations), eltype(u)}) + + if orientation == 1 + f[1] = equations.c_h * psi + f[2] = v1_plus * B2 - v2_plus * B1 + f[3] = v1_plus * B3 - v3_plus * B1 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) + + f1 = rho_v1 + f2 = rho_v1 * v1 + p + f3 = rho_v1 * v2 + f4 = rho_v1 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v1 + 2 * mag_en * vk1_plus[k] - + B1 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B1 + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + f[end] = equations.c_h * B1 + elseif orientation == 2 + f[1] = v2_plus * B1 - v1_plus * B2 + f[2] = equations.c_h * psi + f[3] = v2_plus * B3 - v3_plus * B2 + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) + + f1 = rho_v2 + f2 = rho_v2 * v1 + f3 = rho_v2 * v2 + p + f4 = rho_v2 * v3 + f5 = (kin_en + gamma * p / (gamma - 1)) * v2 + 2 * mag_en * vk2_plus[k] - + B2 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B2 + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + f[end] = equations.c_h * B2 + else #if orientation == 3 + f[1] = v3_plus * B1 - v1_plus * B3 + f[2] = v3_plus * B2 - v2_plus * B3 + f[3] = equations.c_h * psi + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) + + gamma = equations.gammas[k] + p = (gamma - 1) * (rho_e - kin_en - mag_en - div_clean_energy) + + f1 = rho_v3 + f2 = rho_v3 * v1 + f3 = rho_v3 * v2 + f4 = rho_v3 * v3 + p + f5 = (kin_en + gamma * p / (gamma - 1)) * v3 + 2 * mag_en * vk3_plus[k] - + B3 * (vk1_plus[k] * B1 + vk2_plus[k] * B2 + vk3_plus[k] * B3) + + equations.c_h * psi * B3 + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + f[end] = equations.c_h * B3 + end + + return SVector(f) +end + +""" + source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations3D) + +Source terms due to the Lorentz' force for plasmas with more than one ion species. These source +terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for +a single-species plasma. +""" +function source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations3D) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end + + return SVector(s) +end + +""" + electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations3D) + +Returns the value of zero for the electron pressure. Needed for consistency with the +single-fluid MHD equations in the limit of one ion species. +""" +function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations3D) + return zero(u[1]) +end + +""" + flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + +Entropy-conserving non-conservative two-point "flux"" as described in +- 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). + +ATTENTION: The non-conservative fluxes derived in the reference above are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied + by 0.5 whenever they are used in the Trixi code + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a function of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. +""" +@inline function flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + 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) + + # Compute important 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) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) + + # Mean electron pressure + pe_ll = equations.electron_pressure(u_ll, equations) + pe_rr = equations.electron_pressure(u_rr, equations) + pe_mean = 0.5f0 * (pe_ll + pe_rr) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(eltype(u_ll)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2 * v1_plus_ll * B1_avg + f[2] = 2 * v2_plus_ll * B1_avg + f[3] = 2 * v3_plus_ll * B1_avg + + for k in eachcomponent(equations) + # Compute term Lorentz term + f2 = charge_ratio_ll[k] * (0.5f0 * mag_norm_avg - B1_avg * B1_avg + pe_mean) + f3 = charge_ratio_ll[k] * (-B1_avg * B2_avg) + f4 = charge_ratio_ll[k] * (-B1_avg * B3_avg) + f5 = vk1_plus_ll[k] * pe_mean + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B2_ll * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) + + B3_ll * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B1_avg + f3 += charge_ratio_ll[k] * B2_ll * B1_avg + f4 += charge_ratio_ll[k] * B3_ll * B1_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B1_avg + + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * psi_avg + + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2 * f2, 2 * f3, 2 * f4, 2 * f5, + equations) + end + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2 * v1_plus_ll * psi_avg + + elseif orientation == 2 + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2 * v1_plus_ll * B2_avg + f[2] = 2 * v2_plus_ll * B2_avg + f[3] = 2 * v3_plus_ll * B2_avg + + for k in eachcomponent(equations) + # Compute term Lorentz term + f2 = charge_ratio_ll[k] * (-B2_avg * B1_avg) + f3 = charge_ratio_ll[k] * + (-B2_avg * B2_avg + 0.5f0 * mag_norm_avg + pe_mean) + f4 = charge_ratio_ll[k] * (-B2_avg * B3_avg) + f5 = vk2_plus_ll[k] * pe_mean + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) + + B3_ll * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B2_avg + f3 += charge_ratio_ll[k] * B2_ll * B2_avg + f4 += charge_ratio_ll[k] * B3_ll * B2_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B2_avg + + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * psi_avg + + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2 * f2, 2 * f3, 2 * f4, 2 * f5, + equations) + end + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2 * v2_plus_ll * psi_avg + else #if orientation == 3 + # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[1] = 2 * v1_plus_ll * B3_avg + f[2] = 2 * v2_plus_ll * B3_avg + f[3] = 2 * v3_plus_ll * B3_avg + + for k in eachcomponent(equations) + # Compute term Lorentz term + f2 = charge_ratio_ll[k] * (-B3_avg * B1_avg) + f3 = charge_ratio_ll[k] * (-B3_avg * B2_avg) + f4 = charge_ratio_ll[k] * + (-B3_avg * B3_avg + 0.5f0 * mag_norm_avg + pe_mean) + f5 = vk3_plus_ll[k] * pe_mean + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + f5 += (B1_ll * (vk3_minus_avg * B1_avg - vk1_minus_avg * B3_avg) + + B2_ll * (vk3_minus_avg * B2_avg - vk2_minus_avg * B3_avg)) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * B3_avg + f3 += charge_ratio_ll[k] * B2_ll * B3_avg + f4 += charge_ratio_ll[k] * B3_ll * B3_avg + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + B3_avg + + # Compute GLM term for the energy + f5 += v3_plus_ll * psi_ll * psi_avg + + # Add to the flux vector (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + set_component!(f, k, 0, 2 * f2, 2 * f3, 2 * f4, 2 * f5, + equations) + end + # Compute GLM term for psi (multiply by 2 because the non-conservative flux is + # multiplied by 0.5 whenever it's used in the Trixi code) + f[end] = 2 * v3_plus_ll * psi_avg + end + + return SVector(f) +end + +""" + flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + +Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. +The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" +(weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a +standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. + +ATTENTION: The central non-conservative fluxes are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + we omit the 0.5 when computing averages because the non-conservative flux is multiplied by + 0.5 whenever it's used in the Trixi code + +The term is composed of four individual non-conservative terms: +1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and + is evaluated as a function of the charge-averaged velocity. +2. The Lorentz-force term, which becomes a conservative term in the limit of one ion species for vanishing + electron pressure gradients. +3. The "multi-ion" term, which vanishes in the limit of one ion species. +4. The GLM term, which is needed for Galilean invariance. +""" +@inline function flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + @unpack charge_to_mass = equations + # Unpack left and right states to get the magnetic field + 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) + + # Compute important averages + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + + # Electron pressure + pe_ll = equations.electron_pressure(u_ll, equations) + pe_rr = equations.electron_pressure(u_rr, equations) + + # Compute charge ratio of u_ll + charge_ratio_ll = zero(MVector{ncomponents(equations), eltype(u_ll)}) + total_electron_charge = zero(real(equations)) + for k in eachcomponent(equations) + rho_k = u_ll[3 + (k - 1) * 5 + 1] + charge_ratio_ll[k] = rho_k * charge_to_mass[k] + total_electron_charge += charge_ratio_ll[k] + end + charge_ratio_ll ./= total_electron_charge + + # Compute auxiliary variables + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + if orientation == 1 + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B1_ll + B1_rr) + f[2] = v2_plus_ll * (B1_ll + B1_rr) + f[3] = v3_plus_ll * (B1_ll + B1_rr) + for k in eachcomponent(equations) + # Compute Lorentz term + f2 = charge_ratio_ll[k] * ((0.5f0 * mag_norm_ll - B1_ll * B1_ll + pe_ll) + + (0.5f0 * mag_norm_rr - B1_rr * B1_rr + pe_rr)) + f3 = charge_ratio_ll[k] * ((-B1_ll * B2_ll) + (-B1_rr * B2_rr)) + f4 = charge_ratio_ll[k] * ((-B1_ll * B3_ll) + (-B1_rr * B3_rr)) + f5 = vk1_plus_ll[k] * (pe_ll + pe_rr) + + # Compute multi-ion term, which vanishes for NCOMP==1 + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B2_ll * ((vk1_minus_ll * B2_ll - vk2_minus_ll * B1_ll) + + (vk1_minus_rr * B2_rr - vk2_minus_rr * B1_rr)) + + B3_ll * ((vk1_minus_ll * B3_ll - vk3_minus_ll * B1_ll) + + (vk1_minus_rr * B3_rr - vk3_minus_rr * B1_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B1_ll + B1_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B1_ll + B1_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B1_ll + B1_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B1_ll + B1_rr) + + # Compute GLM term for the energy + f5 += v1_plus_ll * psi_ll * (psi_ll + psi_rr) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + # Compute GLM term for psi + f[end] = v1_plus_ll * (psi_ll + psi_rr) + + elseif orientation == 2 + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B2_ll + B2_rr) + f[2] = v2_plus_ll * (B2_ll + B2_rr) + f[3] = v3_plus_ll * (B2_ll + B2_rr) + + for k in eachcomponent(equations) + # Compute Lorentz term + f2 = charge_ratio_ll[k] * ((-B2_ll * B1_ll) + (-B2_rr * B1_rr)) + f3 = charge_ratio_ll[k] * ((-B2_ll * B2_ll + 0.5f0 * mag_norm_ll + pe_ll) + + (-B2_rr * B2_rr + 0.5f0 * mag_norm_rr + pe_rr)) + f4 = charge_ratio_ll[k] * ((-B2_ll * B3_ll) + (-B2_rr * B3_rr)) + f5 = vk2_plus_ll[k] * (pe_ll + pe_rr) + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B1_ll * ((vk2_minus_ll * B1_ll - vk1_minus_ll * B2_ll) + + (vk2_minus_rr * B1_rr - vk1_minus_rr * B2_rr)) + + B3_ll * ((vk2_minus_ll * B3_ll - vk3_minus_ll * B2_ll) + + (vk2_minus_rr * B3_rr - vk3_minus_rr * B2_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B2_ll + B2_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B2_ll + B2_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B2_ll + B2_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B2_ll + B2_rr) + + # Compute GLM term for the energy + f5 += v2_plus_ll * psi_ll * (psi_ll + psi_rr) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + # Compute GLM term for psi + f[end] = v2_plus_ll * (psi_ll + psi_rr) + else #if orientation == 3 + # Entries of Godunov-Powell term for induction equation + f[1] = v1_plus_ll * (B3_ll + B3_rr) + f[2] = v2_plus_ll * (B3_ll + B3_rr) + f[3] = v3_plus_ll * (B3_ll + B3_rr) + + for k in eachcomponent(equations) + # Compute Lorentz term + f2 = charge_ratio_ll[k] * ((-B3_ll * B1_ll) + (-B3_rr * B1_rr)) + f3 = charge_ratio_ll[k] * ((-B3_ll * B2_ll) + (-B3_rr * B2_rr)) + f4 = charge_ratio_ll[k] * ((-B3_ll * B3_ll + 0.5f0 * mag_norm_ll + pe_ll) + + (-B3_rr * B3_rr + 0.5f0 * mag_norm_rr + pe_rr)) + f5 = vk3_plus_ll[k] * (pe_ll + pe_rr) + + # Compute multi-ion term (vanishes for NCOMP==1) + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + f5 += (B1_ll * ((vk3_minus_ll * B1_ll - vk1_minus_ll * B3_ll) + + (vk3_minus_rr * B1_rr - vk1_minus_rr * B3_rr)) + + B2_ll * ((vk3_minus_ll * B2_ll - vk2_minus_ll * B3_ll) + + (vk3_minus_rr * B2_rr - vk2_minus_rr * B3_rr))) + + # Compute Godunov-Powell term + f2 += charge_ratio_ll[k] * B1_ll * (B3_ll + B3_rr) + f3 += charge_ratio_ll[k] * B2_ll * (B3_ll + B3_rr) + f4 += charge_ratio_ll[k] * B3_ll * (B3_ll + B3_rr) + f5 += (v1_plus_ll * B1_ll + v2_plus_ll * B2_ll + v3_plus_ll * B3_ll) * + (B3_ll + B3_rr) + + # Compute GLM term for the energy + f5 += v3_plus_ll * psi_ll * (psi_ll + psi_rr) + + # Append to the flux vector + set_component!(f, k, 0, f2, f3, f4, f5, equations) + end + # Compute GLM term for psi + f[end] = v3_plus_ll * (psi_ll + psi_rr) + end + + return SVector(f) +end + +""" +flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations3D) + +Entropy conserving two-point flux for the multi-ion GLM-MHD equations from +- 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). + +This flux (together with the MHD non-conservative term) is consistent in the case of one ion species with the flux of: +- Derigs et al. (2018). Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field + divergence diminishing ideal magnetohydrodynamics equations for multi-ion + [DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002) +""" +function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + @unpack gammas = equations + # Unpack left and right states to get the magnetic field + 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) + + v1_plus_ll, v2_plus_ll, v3_plus_ll, vk1_plus_ll, vk2_plus_ll, vk3_plus_ll = charge_averaged_velocities(u_ll, + equations) + v1_plus_rr, v2_plus_rr, v3_plus_rr, vk1_plus_rr, vk2_plus_rr, vk3_plus_rr = charge_averaged_velocities(u_rr, + equations) + + f = zero(MVector{nvariables(equations), eltype(u_ll)}) + + # Compute averages for global variables + v1_plus_avg = 0.5f0 * (v1_plus_ll + v1_plus_rr) + v2_plus_avg = 0.5f0 * (v2_plus_ll + v2_plus_rr) + v3_plus_avg = 0.5f0 * (v3_plus_ll + v3_plus_rr) + B1_avg = 0.5f0 * (B1_ll + B1_rr) + B2_avg = 0.5f0 * (B2_ll + B2_rr) + B3_avg = 0.5f0 * (B3_ll + B3_rr) + mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2 + mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2 + mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr) + psi_avg = 0.5f0 * (psi_ll + psi_rr) + + if orientation == 1 + psi_B1_avg = 0.5f0 * (B1_ll * psi_ll + B1_rr * psi_rr) + + # Magnetic field components from f^MHD + f6 = equations.c_h * psi_avg + f7 = v1_plus_avg * B2_avg - v2_plus_avg * B1_avg + f8 = v1_plus_avg * B3_avg - v3_plus_avg * B1_avg + f9 = equations.c_h * B1_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + f[end] = f9 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5f0 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + + # Fill the fluxes for the mass and momentum equations + f1 = rho_mean * v1_avg + f2 = f1 * v1_avg + p_mean + f3 = f1 * v2_avg + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v1_plus_mag_avg = 0.5f0 * (vk1_plus_ll[k] * mag_norm_ll + + vk1_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v1_plus_mag_avg + + B1_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B1_avg # GLM term + + + 0.5f0 * vk1_plus_avg * mag_norm_avg - + vk1_plus_avg * B1_avg * B1_avg - vk2_plus_avg * B1_avg * B2_avg - + vk3_plus_avg * B1_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) + - + B2_avg * (vk1_minus_avg * B2_avg - vk2_minus_avg * B1_avg) - + B3_avg * (vk1_minus_avg * B3_avg - vk3_minus_avg * B1_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + elseif orientation == 2 + psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr) + + # Magnetic field components from f^MHD + f6 = v2_plus_avg * B1_avg - v1_plus_avg * B2_avg + f7 = equations.c_h * psi_avg + f8 = v2_plus_avg * B3_avg - v3_plus_avg * B2_avg + f9 = equations.c_h * B2_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + f[end] = f9 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5f0 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + + # Fill the fluxes for the mass and momentum equations + f1 = rho_mean * v2_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + p_mean + f4 = f1 * v3_avg + + # total energy flux is complicated and involves the previous eight components + v2_plus_mag_avg = 0.5f0 * (vk2_plus_ll[k] * mag_norm_ll + + vk2_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v2_plus_mag_avg + + B2_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B2_avg # GLM term + + + 0.5f0 * vk2_plus_avg * mag_norm_avg - + vk1_plus_avg * B2_avg * B1_avg - vk2_plus_avg * B2_avg * B2_avg - + vk3_plus_avg * B2_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) + - + B1_avg * (vk2_minus_avg * B1_avg - vk1_minus_avg * B2_avg) - + B3_avg * (vk2_minus_avg * B3_avg - vk3_minus_avg * B2_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + else #if orientation == 3 + psi_B3_avg = 0.5f0 * (B3_ll * psi_ll + B3_rr * psi_rr) + + # Magnetic field components from f^MHD + f6 = v3_plus_avg * B1_avg - v1_plus_avg * B3_avg + f7 = v3_plus_avg * B2_avg - v2_plus_avg * B3_avg + f8 = equations.c_h * psi_avg + f9 = equations.c_h * B3_avg + + # Start building the flux + f[1] = f6 + f[2] = f7 + f[3] = f8 + f[end] = f9 + + # Iterate over all components + for k in eachcomponent(equations) + # Unpack left and right states + rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll = get_component(k, u_ll, + equations) + rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, + equations) + + v1_ll = rho_v1_ll / rho_ll + v2_ll = rho_v2_ll / rho_ll + v3_ll = rho_v3_ll / rho_ll + v1_rr = rho_v1_rr / rho_rr + v2_rr = rho_v2_rr / rho_rr + v3_rr = rho_v3_rr / rho_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 + + p_ll = (gammas[k] - 1) * + (rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll - + 0.5f0 * psi_ll^2) + p_rr = (gammas[k] - 1) * + (rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr - + 0.5f0 * psi_rr^2) + beta_ll = 0.5f0 * rho_ll / p_ll + beta_rr = 0.5f0 * rho_rr / p_rr + # for convenience store vk_plus⋅B + vel_dot_mag_ll = vk1_plus_ll[k] * B1_ll + vk2_plus_ll[k] * B2_ll + + vk3_plus_ll[k] * B3_ll + vel_dot_mag_rr = vk1_plus_rr[k] * B1_rr + vk2_plus_rr[k] * B2_rr + + vk3_plus_rr[k] * B3_rr + + # Compute the necessary mean values needed for either direction + rho_avg = 0.5f0 * (rho_ll + rho_rr) + rho_mean = ln_mean(rho_ll, rho_rr) + beta_mean = ln_mean(beta_ll, beta_rr) + beta_avg = 0.5f0 * (beta_ll + beta_rr) + p_mean = 0.5f0 * rho_avg / beta_avg + v1_avg = 0.5f0 * (v1_ll + v1_rr) + v2_avg = 0.5f0 * (v2_ll + v2_rr) + v3_avg = 0.5f0 * (v3_ll + v3_rr) + vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr) + vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr) + vk1_plus_avg = 0.5f0 * (vk1_plus_ll[k] + vk1_plus_rr[k]) + vk2_plus_avg = 0.5f0 * (vk2_plus_ll[k] + vk2_plus_rr[k]) + vk3_plus_avg = 0.5f0 * (vk3_plus_ll[k] + vk3_plus_rr[k]) + # v_minus + vk1_minus_ll = v1_plus_ll - vk1_plus_ll[k] + vk2_minus_ll = v2_plus_ll - vk2_plus_ll[k] + vk3_minus_ll = v3_plus_ll - vk3_plus_ll[k] + vk1_minus_rr = v1_plus_rr - vk1_plus_rr[k] + vk2_minus_rr = v2_plus_rr - vk2_plus_rr[k] + vk3_minus_rr = v3_plus_rr - vk3_plus_rr[k] + vk1_minus_avg = 0.5f0 * (vk1_minus_ll + vk1_minus_rr) + vk2_minus_avg = 0.5f0 * (vk2_minus_ll + vk2_minus_rr) + vk3_minus_avg = 0.5f0 * (vk3_minus_ll + vk3_minus_rr) + + # Fill the fluxes for the mass and momentum equations + f1 = rho_mean * v3_avg + f2 = f1 * v1_avg + f3 = f1 * v2_avg + f4 = f1 * v3_avg + p_mean + + # total energy flux is complicated and involves the previous eight components + v3_plus_mag_avg = 0.5f0 * (vk3_plus_ll[k] * mag_norm_ll + + vk3_plus_rr[k] * mag_norm_rr) + # Euler part + f5 = f1 * 0.5f0 * (1 / (gammas[k] - 1) / beta_mean - vel_norm_avg) + + f2 * v1_avg + f3 * v2_avg + f4 * v3_avg + # MHD part + f5 += (f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v3_plus_mag_avg + + B3_avg * vel_dot_mag_avg # Same terms as in Derigs (but with v_plus) + + f9 * psi_avg - equations.c_h * psi_B3_avg # GLM term + + + 0.5f0 * vk3_plus_avg * mag_norm_avg - + vk1_plus_avg * B3_avg * B1_avg - vk2_plus_avg * B3_avg * B2_avg - + vk3_plus_avg * B3_avg * B3_avg # Additional terms related to the Lorentz non-conservative term (momentum eqs) + - + B1_avg * (vk3_minus_avg * B1_avg - vk1_minus_avg * B3_avg) - + B2_avg * (vk3_minus_avg * B2_avg - vk2_minus_avg * B3_avg)) # Terms related to the multi-ion non-conservative term (induction equation!) + + set_component!(f, k, f1, f2, f3, f4, f5, equations) + end + end + + return SVector(f) +end + +# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation +# This routine approximates the maximum wave speed as sum of the maximum ion velocity +# for all species and the maximum magnetosonic speed. +@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + # Calculate fast magnetoacoustic wave speeds + # left + cf_ll = calc_fast_wavespeed(u_ll, orientation, equations) + # right + cf_rr = calc_fast_wavespeed(u_rr, orientation, equations) + + # Calculate velocities + v_ll = zero(eltype(u_ll)) + v_rr = zero(eltype(u_rr)) + if orientation == 1 + for k in eachcomponent(equations) + rho, rho_v1, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v1 / rho)) + rho, rho_v1, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v1 / rho)) + end + elseif orientation == 2 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v2 / rho)) + rho, rho_v1, rho_v2, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v2 / rho)) + end + else #if orientation == 3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u_ll, equations) + v_ll = max(v_ll, abs(rho_v3 / rho)) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u_rr, equations) + v_rr = max(v_rr, abs(rho_v3 / rho)) + end + end + + λ_max = max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr) +end + +@inline function max_abs_speeds(u, equations::IdealGlmMhdMultiIonEquations3D) + v1 = zero(real(equations)) + v2 = zero(real(equations)) + v3 = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) + v1 = max(v1, abs(rho_v1 / rho)) + v2 = max(v2, abs(rho_v2 / rho)) + v3 = max(v3, abs(rho_v3 / rho)) + end + + cf_x_direction = calc_fast_wavespeed(u, 1, equations) + cf_y_direction = calc_fast_wavespeed(u, 2, equations) + cf_z_direction = calc_fast_wavespeed(u, 3, equations) + + return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction, + abs(v3) + cf_z_direction) +end + +#Convert conservative variables to primitive +function cons2prim(u, equations::IdealGlmMhdMultiIonEquations3D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3 + + psi * psi)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) + end + prim[end] = psi + + return SVector(prim) +end + +#Convert conservative variables to entropy variables +@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations3D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + end + + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + entropy[end] = rho_p_plus * psi + + return SVector(entropy) +end + +# Convert primitive to conservative variables +@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations3D) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + psi = divergence_cleaning_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5f0 * (B1^2 + B2^2 + B3^2) + + 0.5f0 * psi^2 + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + end + cons[end] = psi + + return SVector(cons) +end + +# Compute the fastest wave speed for ideal multi-ion GLM-MHD equations: c_f, the fast +# magnetoacoustic eigenvalue. This routine computes the fast magnetosonic speed for each ion +# species using the single-fluid MHD expressions and approximates the multi-ion c_f as +# the maximum of these individual magnetosonic speeds. +@inline function calc_fast_wavespeed(cons, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) + B1, B2, B3 = magnetic_field(cons, equations) + psi = divergence_cleaning_field(cons, equations) + + c_f = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + p = (gamma - 1) * + (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - + 0.5f0 * psi^2) + a_square = gamma * p / rho + sqrt_rho = sqrt(rho) + + b1 = B1 / sqrt_rho + b2 = B2 / sqrt_rho + b3 = B3 / sqrt_rho + b_square = b1^2 + b2^2 + b3^2 + + if orientation == 1 + c_f = max(c_f, + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 2 * a_square * b1^2))) + elseif orientation == 2 + c_f = max(c_f, + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 2 * a_square * b2^2))) + else #if orientation == 3 + c_f = max(c_f, + sqrt(0.5f0 * (a_square + b_square) + + 0.5f0 * + sqrt((a_square + b_square)^2 - 2 * a_square * b3^2))) + end + end + + return c_f +end + +""" +v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations3D) + + +Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution +to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 +are SVectors of size ncomponents(equations). +""" +@inline function charge_averaged_velocities(u, + equations::IdealGlmMhdMultiIonEquations3D) + total_electron_charge = zero(real(equations)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, + equations) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) +end + +""" + get_component(k, u, equations::IdealGlmMhdMultiIonEquations3D) + +Get the hydrodynamic variables of component (ion species) k. +""" +@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations3D) + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" + set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealGlmMhdMultiIonEquations3D) + +Set the hydrodynamic variables of component (ion species) k. +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::IdealGlmMhdMultiIonEquations3D) + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + + return u +end + +# Extract magnetic field from solution vector +magnetic_field(u, equations::IdealGlmMhdMultiIonEquations3D) = SVector(u[1], u[2], u[3]) + +# Extract GLM divergence-cleaning field from solution vector +divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations3D) = u[end] + +# Get total density as the sum of the individual densities of the ion species +@inline function density(u, equations::IdealGlmMhdMultiIonEquations3D) + rho = zero(real(equations)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho +end + +# Computes the sum of the densities times the sum of the pressures +@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations3D) + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(cons, equations) + + rho_total = zero(real(equations)) + p_total = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + + p = (gamma - 1) * + (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + + rho_total += rho + p_total += p + end + return rho_total * p_total +end +end # @muladd diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index 24a8db30256..eacc33f16b2 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -11,7 +11,7 @@ The ideal compressible multi-ion MHD equations in one space dimension. """ mutable struct IdealMhdMultiIonEquations1D{NVARS, NCOMP, RealT <: Real} <: - AbstractIdealMhdMultiIonEquations{1, NVARS, NCOMP} + AbstractIdealGlmMhdMultiIonEquations{1, NVARS, NCOMP} gammas :: SVector{NCOMP, RealT} # Heat capacity ratios charge_to_mass :: SVector{NCOMP, RealT} # Charge to mass ratios From feac4b897957410790dfbfce43175aed4f0d53dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:20:24 +0100 Subject: [PATCH 079/108] Replaced all occurrences of 2.0f0 and 4.0f0 with 2 and 4 --- src/equations/ideal_glm_mhd_multiion_2d.jl | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 93019645d1c..2422e5de9d7 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -368,9 +368,9 @@ The term is composed of four individual non-conservative terms: if orientation == 1 # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - f[1] = 2.0f0 * v1_plus_ll * B1_avg - f[2] = 2.0f0 * v2_plus_ll * B1_avg - f[3] = 2.0f0 * v3_plus_ll * B1_avg + f[1] = 2 * v1_plus_ll * B1_avg + f[2] = 2 * v2_plus_ll * B1_avg + f[3] = 2 * v3_plus_ll * B1_avg for k in eachcomponent(equations) # Compute term Lorentz term @@ -404,19 +404,19 @@ The term is composed of four individual non-conservative terms: # Add to the flux vector (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + set_component!(f, k, 0, 2 * f2, 2 * f3, 2 * f4, 2 * f5, equations) end # Compute GLM term for psi (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - f[end] = 2.0f0 * v1_plus_ll * psi_avg + f[end] = 2 * v1_plus_ll * psi_avg else #if orientation == 2 # Entries of Godunov-Powell term for induction equation (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - f[1] = 2.0f0 * v1_plus_ll * B2_avg - f[2] = 2.0f0 * v2_plus_ll * B2_avg - f[3] = 2.0f0 * v3_plus_ll * B2_avg + f[1] = 2 * v1_plus_ll * B2_avg + f[2] = 2 * v2_plus_ll * B2_avg + f[3] = 2 * v3_plus_ll * B2_avg for k in eachcomponent(equations) # Compute term Lorentz term @@ -451,12 +451,12 @@ The term is composed of four individual non-conservative terms: # Add to the flux vector (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - set_component!(f, k, 0, 2.0f0 * f2, 2.0f0 * f3, 2.0f0 * f4, 2.0f0 * f5, + set_component!(f, k, 0, 2 * f2, 2 * f3, 2 * f4, 2 * f5, equations) end # Compute GLM term for psi (multiply by 2 because the non-conservative flux is # multiplied by 0.5 whenever it's used in the Trixi code) - f[end] = 2.0f0 * v2_plus_ll * psi_avg + f[end] = 2 * v2_plus_ll * psi_avg end return SVector(f) @@ -1017,12 +1017,12 @@ end c_f = max(c_f, sqrt(0.5f0 * (a_square + b_square) + 0.5f0 * - sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b1^2))) + sqrt((a_square + b_square)^2 - 4 * a_square * b1^2))) else #if orientation == 2 c_f = max(c_f, sqrt(0.5f0 * (a_square + b_square) + 0.5f0 * - sqrt((a_square + b_square)^2 - 4.0f0 * a_square * b2^2))) + sqrt((a_square + b_square)^2 - 4 * a_square * b2^2))) end end From 2d8c833a5cc00f95cba4a08bf251f31e8645eabb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:26:37 +0100 Subject: [PATCH 080/108] Use a single elixir to test EC and EC+LLF --- .../elixir_mhdmultiion_ec+llf.jl | 62 ------------------- test/test_tree_2d_mhdmultiion.jl | 23 ++++++- 2 files changed, 20 insertions(+), 65 deletions(-) delete mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl deleted file mode 100644 index 9be4e5e2492..00000000000 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl +++ /dev/null @@ -1,62 +0,0 @@ - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), - charge_to_mass = (1.0, 2.0)) - -initial_condition = initial_condition_weak_blast_wave - -volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) - -solver = DGSEM(polydeg = 3, surface_flux = surface_flux, - volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 4, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_lorentz) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 0.4) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 10 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -cfl = 0.5 - -stepsize_callback = StepsizeCallback(cfl = cfl) - -glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - stepsize_callback, - glm_speed_callback) - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index ac91c47a33f..69de4eb6839 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -45,10 +45,18 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 0.6078381519649727, 0.00673110606965085 ]) + # 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+llf.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec+llf.jl"), +@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=[ 0.017668026737187294, 0.017797845988889206, @@ -80,7 +88,16 @@ end 0.08694877996306204, 0.49493751138636366, 0.003287414714660175 - ]) + ], + surface_flux=(flux_lax_friedrichs, flux_nonconservative_central)) + # 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 end From ffaf52f1533798e2cdf14a37497d5e9417c0507d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:32:50 +0100 Subject: [PATCH 081/108] Removed duplicated code in the outer constructor for @reset --- src/equations/ideal_glm_mhd_multiion_2d.jl | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 2422e5de9d7..94c69c5f17f 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -82,23 +82,10 @@ end # Outer constructor for `@reset` works correctly function IdealGlmMhdMultiIonEquations2D(gammas, charge_to_mass, electron_pressure, c_h) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 4 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - c_h = convert(RealT, c_h) - - return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, - typeof(electron_pressure)}(__gammas, - __charge_to_mass, - electron_pressure, - c_h) + return IdealGlmMhdMultiIonEquations2D(gammas = gammas, + charge_to_mass = charge_to_mass, + electron_pressure = electron_pressure, + initial_c_h = c_h) end @inline function Base.real(::IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT}) where { From 7cc8dc955940d04b55de66d31bea37b24502b6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:38:18 +0100 Subject: [PATCH 082/108] Renamed AbstractIdealMhdMultiIonEquations to AbstractIdealGlmMhdMultiIonEquations --- src/equations/equations.jl | 19 ++++++++++--------- src/equations/ideal_glm_mhd_multiion_2d.jl | 7 +++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 70aff7613e6..2c7506ba3ca 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -492,7 +492,7 @@ include("ideal_glm_mhd_multicomponent_1d.jl") include("ideal_glm_mhd_multicomponent_2d.jl") # IdealMhdMultiIonEquations -abstract type AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: +abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end include("ideal_glm_mhd_multiion_2d.jl") @@ -517,22 +517,23 @@ In particular, not the components themselves are returned. end # Retrieve number of components from equation instance for the multi-ion case -@inline function ncomponents(::AbstractIdealMhdMultiIonEquations{NDIMS, NVARS, NCOMP}) where { - NDIMS, - NVARS, - NCOMP - } +@inline function ncomponents(::AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, + NCOMP}) where { + NDIMS, + NVARS, + NCOMP + } NCOMP end """ - eachcomponent(equations::AbstractIdealMhdMultiIonEquations) + eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) Return an iterator over the indices that specify the location in relevant data structures -for the components in `AbstractIdealMhdMultiIonEquations`. +for the components in `AbstractIdealGlmMhdMultiIonEquations`. In particular, not the components themselves are returned. """ -@inline function eachcomponent(equations::AbstractIdealMhdMultiIonEquations) +@inline function eachcomponent(equations::AbstractIdealGlmMhdMultiIonEquations) Base.OneTo(ncomponents(equations)) end diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 94c69c5f17f..312cc535859 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -39,7 +39,7 @@ References: """ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure} <: - AbstractIdealMhdMultiIonEquations{2, NVARS, NCOMP} + 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 @@ -170,7 +170,7 @@ function initial_condition_weak_blast_wave(x, t, return prim2cons(SVector(prim), equations) end -# 2D flux of the GLM-MHD equations in the direction `orientation` +# 2D flux of the multi-ion GLM-MHD equations in the direction `orientation` @inline function flux(u, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) B1, B2, B3 = magnetic_field(u, equations) @@ -1034,8 +1034,7 @@ are SVectors of size ncomponents(equations). vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealGlmMhdMultiIonEquations2D) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) total_electron_charge += rho * equations.charge_to_mass[k] vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] From 5f3d46c4c54d97e33e42743293f375d62ad60c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 17:40:37 +0100 Subject: [PATCH 083/108] GLM callback dispatches on AbstractIdealGlmMhdMultiIonEquations --- src/callbacks_step/glm_speed_dg.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/callbacks_step/glm_speed_dg.jl b/src/callbacks_step/glm_speed_dg.jl index 085dd1a7417..dc2579a3359 100644 --- a/src/callbacks_step/glm_speed_dg.jl +++ b/src/callbacks_step/glm_speed_dg.jl @@ -8,7 +8,7 @@ function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealGlmMhdMultiIonEquations2D}, + AbstractIdealGlmMhdMultiIonEquations}, dg::DG, cache) # compute time step for GLM linear advection equation with c_h=1 for the DG discretization on # Cartesian meshes @@ -30,7 +30,7 @@ end function calc_dt_for_cleaning_speed(cfl::Real, mesh, equations::Union{AbstractIdealGlmMhdEquations, AbstractIdealGlmMhdMulticomponentEquations, - IdealGlmMhdMultiIonEquations2D}, + AbstractIdealGlmMhdMultiIonEquations}, dg::DGMulti, cache) rd = dg.basis md = mesh.md From 5e7bed5001d849192e4ffd1f462692d85a4b72ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Tue, 10 Dec 2024 18:00:34 +0100 Subject: [PATCH 084/108] Moved routines that will be used by all AbstractIdealGlmMhdMultiIonEquations from ideal_glm_mhd_multiion_2d.jl into ideal_glm_mhd_multiion.jl --- src/equations/equations.jl | 1 + src/equations/ideal_glm_mhd_multiion.jl | 255 +++++++++++++++++++++ src/equations/ideal_glm_mhd_multiion_2d.jl | 245 -------------------- 3 files changed, 256 insertions(+), 245 deletions(-) create mode 100644 src/equations/ideal_glm_mhd_multiion.jl diff --git a/src/equations/equations.jl b/src/equations/equations.jl index 2c7506ba3ca..0799a040bb6 100644 --- a/src/equations/equations.jl +++ b/src/equations/equations.jl @@ -494,6 +494,7 @@ include("ideal_glm_mhd_multicomponent_2d.jl") # IdealMhdMultiIonEquations abstract type AbstractIdealGlmMhdMultiIonEquations{NDIMS, NVARS, NCOMP} <: AbstractEquations{NDIMS, NVARS} end +include("ideal_glm_mhd_multiion.jl") include("ideal_glm_mhd_multiion_2d.jl") # Retrieve number of components from equation instance for the multicomponent case diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl new file mode 100644 index 00000000000..27062e3fcec --- /dev/null +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -0,0 +1,255 @@ +# This file includes functions that are common for all AbstractIdealGlmMhdMultiIonEquations + +# By default, Julia/LLVM does not use fused multiply-add operations (FMAs). +# Since these FMAs can increase the performance of many numerical algorithms, +# we need to opt-in explicitly. +# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details. +@muladd begin +#! format: noindent + +have_nonconservative_terms(::AbstractIdealGlmMhdMultiIonEquations) = True() + +function varnames(::typeof(cons2cons), equations::AbstractIdealGlmMhdMultiIonEquations) + cons = ("B1", "B2", "B3") + for i in eachcomponent(equations) + cons = (cons..., + tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), + "rho_v3_" * string(i), "rho_e_" * string(i))...) + end + cons = (cons..., "psi") + + return cons +end + +function varnames(::typeof(cons2prim), equations::AbstractIdealGlmMhdMultiIonEquations) + prim = ("B1", "B2", "B3") + for i in eachcomponent(equations) + prim = (prim..., + tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), + "v3_" * string(i), "p_" * string(i))...) + end + prim = (prim..., "psi") + + return prim +end + +function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + +""" + source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) + +Source terms due to the Lorentz' force for plasmas with more than one ion species. These source +terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for +a single-species plasma. +""" +function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) + @unpack charge_to_mass = equations + B1, B2, B3 = magnetic_field(u, equations) + v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, + equations) + + s = zero(MVector{nvariables(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v1_diff = v1_plus - v1 + v2_diff = v2_plus - v2 + v3_diff = v3_plus - v3 + r_rho = charge_to_mass[k] * rho + s2 = r_rho * (v2_diff * B3 - v3_diff * B2) + s3 = r_rho * (v3_diff * B1 - v1_diff * B3) + s4 = r_rho * (v1_diff * B2 - v2_diff * B1) + s5 = v1 * s2 + v2 * s3 + v3 * s4 + + set_component!(s, k, 0, s2, s3, s4, s5, equations) + end + + return SVector(s) +end + +""" + electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations) + +Returns the value of zero for the electron pressure. Needed for consistency with the +single-fluid MHD equations in the limit of one ion species. +""" +function electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations) + return zero(u[1]) +end + +""" +v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, + equations::AbstractIdealGlmMhdMultiIonEquations) + + +Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution +to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 +are SVectors of size ncomponents(equations). +""" +@inline function charge_averaged_velocities(u, + equations::AbstractIdealGlmMhdMultiIonEquations) + total_electron_charge = zero(real(equations)) + + vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) + vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) + + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) + + total_electron_charge += rho * equations.charge_to_mass[k] + vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] + vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] + vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] + end + vk1_plus ./= total_electron_charge + vk2_plus ./= total_electron_charge + vk3_plus ./= total_electron_charge + v1_plus = sum(vk1_plus) + v2_plus = sum(vk2_plus) + v3_plus = sum(vk3_plus) + + return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), + SVector(vk3_plus) +end + +""" + get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) + +Get the hydrodynamic variables of component (ion species) k. +""" +@inline function get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) + return SVector(u[3 + (k - 1) * 5 + 1], + u[3 + (k - 1) * 5 + 2], + u[3 + (k - 1) * 5 + 3], + u[3 + (k - 1) * 5 + 4], + u[3 + (k - 1) * 5 + 5]) +end + +""" + set_component!(u, k, u1, u2, u3, u4, u5, + equations::AbstractIdealGlmMhdMultiIonEquations) + +Set the hydrodynamic variables of component (ion species) k. +""" +@inline function set_component!(u, k, u1, u2, u3, u4, u5, + equations::AbstractIdealGlmMhdMultiIonEquations) + u[3 + (k - 1) * 5 + 1] = u1 + u[3 + (k - 1) * 5 + 2] = u2 + u[3 + (k - 1) * 5 + 3] = u3 + u[3 + (k - 1) * 5 + 4] = u4 + u[3 + (k - 1) * 5 + 5] = u5 + + return u +end + +# Extract magnetic field from solution vector +magnetic_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = SVector(u[1], u[2], + u[3]) + +# Extract GLM divergence-cleaning field from solution vector +divergence_cleaning_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = u[end] + +# Get total density as the sum of the individual densities of the ion species +@inline function density(u, equations::AbstractIdealGlmMhdMultiIonEquations) + rho = zero(real(equations)) + for k in eachcomponent(equations) + rho += u[3 + (k - 1) * 5 + 1] + end + return rho +end + +#Convert conservative variables to primitive +function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = zero(MVector{nvariables(equations), eltype(u)}) + prim[1] = B1 + prim[2] = B2 + prim[3] = B3 + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + srho = 1 / rho + v1 = srho * rho_v1 + v2 = srho * rho_v2 + v3 = srho * rho_v3 + + p = (gammas[k] - 1) * (rho_e - + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 + + B1 * B1 + B2 * B2 + B3 * B3 + + psi * psi)) + + set_component!(prim, k, rho, v1, v2, v3, p, equations) + end + prim[end] = psi + + return SVector(prim) +end + +#Convert conservative variables to entropy variables +@inline function cons2entropy(u, equations::AbstractIdealGlmMhdMultiIonEquations) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(u, equations) + + prim = cons2prim(u, equations) + entropy = zero(MVector{nvariables(equations), eltype(u)}) + rho_p_plus = zero(real(equations)) + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + s = log(p) - gammas[k] * log(rho) + rho_p = rho / p + w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) + w2 = rho_p * v1 + w3 = rho_p * v2 + w4 = rho_p * v3 + w5 = -rho_p + rho_p_plus += rho_p + + set_component!(entropy, k, w1, w2, w3, w4, w5, equations) + end + + # Additional non-conservative variables + entropy[1] = rho_p_plus * B1 + entropy[2] = rho_p_plus * B2 + entropy[3] = rho_p_plus * B3 + entropy[end] = rho_p_plus * psi + + return SVector(entropy) +end + +# Convert primitive to conservative variables +@inline function prim2cons(prim, equations::AbstractIdealGlmMhdMultiIonEquations) + @unpack gammas = equations + B1, B2, B3 = magnetic_field(prim, equations) + psi = divergence_cleaning_field(prim, equations) + + cons = zero(MVector{nvariables(equations), eltype(prim)}) + cons[1] = B1 + cons[2] = B2 + cons[3] = B3 + for k in eachcomponent(equations) + rho, v1, v2, v3, p = get_component(k, prim, equations) + rho_v1 = rho * v1 + rho_v2 = rho * v2 + rho_v3 = rho * v3 + + rho_e = p / (gammas[k] - 1.0) + + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + + 0.5f0 * (B1^2 + B2^2 + B3^2) + + 0.5f0 * psi^2 + + set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) + end + cons[end] = psi + + return SVector(cons) +end +end diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 312cc535859..6fdf3acebd3 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -96,36 +96,6 @@ end RealT end -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations2D) = True() - -function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations2D) - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., - tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), - "rho_v3_" * string(i), "rho_e_" * string(i))...) - end - cons = (cons..., "psi") - - return cons -end - -function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations2D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., - tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), - "v3_" * string(i), "p_" * string(i))...) - end - prim = (prim..., "psi") - - return prim -end - -function default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) - (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) -end - """ initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) @@ -241,51 +211,6 @@ end return SVector(f) end -""" - source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) - -Source terms due to the Lorentz' force for plasmas with more than one ion species. These source -terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for -a single-species plasma. -""" -function source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations2D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) -end - -""" - electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) - -Returns the value of zero for the electron pressure. Needed for consistency with the -single-fluid MHD equations in the limit of one ion species. -""" -function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations2D) - return zero(u[1]) -end - """ flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, @@ -882,95 +807,6 @@ end return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction) end -#Convert conservative variables to primitive -function cons2prim(u, equations::IdealGlmMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3 - + psi * psi)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) - end - prim[end] = psi - - return SVector(prim) -end - -#Convert conservative variables to entropy variables -@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) - end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - entropy[end] = rho_p_plus * psi - - return SVector(entropy) -end - -# Convert primitive to conservative variables -@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations2D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - psi = divergence_cleaning_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p / (gammas[k] - 1.0) + - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5f0 * (B1^2 + B2^2 + B3^2) + - 0.5f0 * psi^2 - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) - end - cons[end] = psi - - return SVector(cons) -end - # Compute the fastest wave speed for ideal multi-ion GLM-MHD equations: c_f, the fast # magnetoacoustic eigenvalue. This routine computes the fast magnetosonic speed for each ion # species using the single-fluid MHD expressions and approximates the multi-ion c_f as @@ -1015,85 +851,4 @@ end return c_f end - -""" -v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, - equations::IdealGlmMhdMultiIonEquations2D) - - -Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution -to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 -are SVectors of size ncomponents(equations). -""" -@inline function charge_averaged_velocities(u, - equations::IdealGlmMhdMultiIonEquations2D) - total_electron_charge = zero(real(equations)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), - SVector(vk3_plus) -end - -""" - get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) - -Get the hydrodynamic variables of component (ion species) k. -""" -@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations2D) - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) -end - -""" - set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealGlmMhdMultiIonEquations2D) - -Set the hydrodynamic variables of component (ion species) k. -""" -@inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealGlmMhdMultiIonEquations2D) - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 - - return u -end - -# Extract magnetic field from solution vector -magnetic_field(u, equations::IdealGlmMhdMultiIonEquations2D) = SVector(u[1], u[2], u[3]) - -# Extract GLM divergence-cleaning field from solution vector -divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations2D) = u[end] - -# Get total density as the sum of the individual densities of the ion species -@inline function density(u, equations::IdealGlmMhdMultiIonEquations2D) - rho = zero(real(equations)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho -end end # @muladd From be72d8db0ca46d6c745cbf88081de9728f5fd667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 12:26:29 +0100 Subject: [PATCH 085/108] Apply suggestions from code review Co-authored-by: Hendrik Ranocha Co-authored-by: Michael Schlottke-Lakemper --- .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 2 +- src/equations/ideal_glm_mhd_multiion.jl | 21 ++++++++++--------- test/test_tree_2d_mhdmultiion.jl | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index c4acdf1f32f..d9b66496b19 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -3,7 +3,7 @@ using OrdinaryDiffEq using Trixi ############################################################################### -# semidiscretization of the ideal MHD equations +# semidiscretization of the ideal multi-ion MHD equations equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), charge_to_mass = (1.0, 2.0)) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index 27062e3fcec..dc7d248d88a 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -38,11 +38,12 @@ function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations) end """ - source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) + source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) Source terms due to the Lorentz' force for plasmas with more than one ion species. These source terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for -a single-species plasma. +a single-species plasma. In particular, they have to be used for every +simulation of [`IdealGlmMhdMultiIonEquations2D`](@ref). """ function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) @unpack charge_to_mass = equations @@ -73,7 +74,7 @@ function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEqu end """ - electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations) + electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations) Returns the value of zero for the electron pressure. Needed for consistency with the single-fluid MHD equations in the limit of one ion species. @@ -83,13 +84,13 @@ function electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquatio end """ -v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, + v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, equations::AbstractIdealGlmMhdMultiIonEquations) -Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution -to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 -are SVectors of size ncomponents(equations). +Compute the charge-averaged velocities (`v1`, `v2`, and `v3`) and each ion species' contribution +to the charge-averaged velocities (`vk1`, `vk2`, and `vk3`). The output variables `vk1`, `vk2`, and `vk3` +are `SVectors` of size `ncomponents(equations)`. """ @inline function charge_averaged_velocities(u, equations::AbstractIdealGlmMhdMultiIonEquations) @@ -121,7 +122,7 @@ end """ get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) -Get the hydrodynamic variables of component (ion species) k. +Get the hydrodynamic variables of component (ion species) `k`. """ @inline function get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) return SVector(u[3 + (k - 1) * 5 + 1], @@ -135,7 +136,7 @@ end set_component!(u, k, u1, u2, u3, u4, u5, equations::AbstractIdealGlmMhdMultiIonEquations) -Set the hydrodynamic variables of component (ion species) k. +Set the hydrodynamic variables (`u1` to `u5`) of component (ion species) `k`. """ @inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::AbstractIdealGlmMhdMultiIonEquations) @@ -241,7 +242,7 @@ end rho_v2 = rho * v2 rho_v3 = rho * v3 - rho_e = p / (gammas[k] - 1.0) + + rho_e = p / (gammas[k] - 1) + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + 0.5f0 * (B1^2 + B2^2 + B3^2) + 0.5f0 * psi^2 diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index 69de4eb6839..2ef8b56e9e8 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -1,4 +1,4 @@ -module TestExamples2DEulerMulticomponent +module TestExamples2DIdealGlmMhdMultiIon using Test using Trixi From ad1509ab1e0b0fd416d8b5c9a56016ebe2a5b103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 13:00:06 +0100 Subject: [PATCH 086/108] Apply suggestions from code review Co-authored-by: Hendrik Ranocha --- src/equations/ideal_glm_mhd_multiion_2d.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 6fdf3acebd3..a1a8335e6fb 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -35,7 +35,7 @@ References: [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655). !!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used - with `source_terms_lorentz`. + with [`source_terms_lorentz`](@ref). """ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, ElectronPressure} <: @@ -212,7 +212,7 @@ end end """ - flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) @@ -375,11 +375,12 @@ The term is composed of four individual non-conservative terms: end """ - flux_nonconservative_central(u_ll, u_rr, orientation::Integer, - equations::IdealGlmMhdMultiIonEquations2D) + flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. -The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" +The use of this term together with [`flux_central`](@ref) +with [`VolumeIntegralFluxDifferencing`](@ref) yields a "standard" (weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. @@ -520,7 +521,7 @@ The term is composed of four individual non-conservative terms: end """ -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations2D) + flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations2D) Entropy conserving two-point flux for the multi-ion GLM-MHD equations from - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization From 6e68cafe43f3c019546638b4979adfacf561704e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 13:06:27 +0100 Subject: [PATCH 087/108] Added appropriate formatting to admonitions in docstrings --- src/equations/ideal_glm_mhd_multiion_2d.jl | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index a1a8335e6fb..ee196903c6f 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -34,7 +34,8 @@ References: 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). -!!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used +!!! info "The multi-ion GLM-MHD require source terms" + In case of more than one ion species, the multi-ion GLM-MHD equations should ALWAYS be used with [`source_terms_lorentz`](@ref). """ mutable struct IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT <: Real, @@ -221,11 +222,12 @@ Entropy-conserving non-conservative two-point "flux"" as described in 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). -ATTENTION: The non-conservative fluxes derived in the reference above are written as the product - of local and symmetric parts and are meant to be used in the same way as the conservative - fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, - the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied - by 0.5 whenever they are used in the Trixi code +!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi" + The non-conservative fluxes derived in the reference above are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied + by 0.5 whenever they are used in the Trixi code. The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and @@ -384,11 +386,12 @@ with [`VolumeIntegralFluxDifferencing`](@ref) yields a "standard" (weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. -ATTENTION: The central non-conservative fluxes are written as the product - of local and symmetric parts and are meant to be used in the same way as the conservative - fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, - we omit the 0.5 when computing averages because the non-conservative flux is multiplied by - 0.5 whenever it's used in the Trixi code +!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi" + The central non-conservative fluxes implemented in this function are written as the product + of local and symmetric parts, where the symmetric part is a standard average. These fluxes + are meant to be used in the same way as the conservative fluxes (i.e., flux + flux_noncons + in both volume and surface integrals). In this routine, the fluxes are multiplied by 2 because + the non-conservative fluxes are always multiplied by 0.5 whenever they are used in the Trixi code. The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and From f16b80fdd50a2bcfd6f8cb6ad1e9d7c3c1e76794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 13:22:17 +0100 Subject: [PATCH 088/108] Apply suggestions from code review Co-authored-by: Michael Schlottke-Lakemper --- src/equations/ideal_glm_mhd_multiion_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index ee196903c6f..9e321d85510 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -34,7 +34,7 @@ References: 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). -!!! info "The multi-ion GLM-MHD require source terms" +!!! info "The multi-ion GLM-MHD equations require source terms" In case of more than one ion species, the multi-ion GLM-MHD equations should ALWAYS be used with [`source_terms_lorentz`](@ref). """ @@ -222,7 +222,7 @@ Entropy-conserving non-conservative two-point "flux"" as described in 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). -!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi" +!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi.jl" The non-conservative fluxes derived in the reference above are written as the product of local and symmetric parts and are meant to be used in the same way as the conservative fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, From f3a3e7d98532ee1f2b0f6eb767b8a99af5e2c233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 13:30:12 +0100 Subject: [PATCH 089/108] Make multi-ion GLM-MHD's initial condition initial_condition_weak_blast_wave compatible with single precision --- src/equations/ideal_glm_mhd_multiion_2d.jl | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 9e321d85510..44ba392855d 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -111,6 +111,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 = eltype(x) inicenter = (0, 0) x_norm = x[1] - inicenter[1] y_norm = x[2] - inicenter[2] @@ -118,20 +119,15 @@ function initial_condition_weak_blast_wave(x, t, phi = atan(y_norm, x_norm) # Calculate primitive variables - rho = zero(real(equations)) - if r > 0.5 - rho = 1.0 - else - rho = 1.1691 - end - v1 = r > 0.5 ? 0.0 : 0.1882 * cos(phi) - v2 = r > 0.5 ? 0.0 : 0.1882 * sin(phi) - p = r > 0.5 ? 1.0 : 1.245 + rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691) + v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi) + v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) + p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245) prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 + prim[1] = 1 + prim[2] = 1 + prim[3] = 1 for k in eachcomponent(equations) set_component!(prim, k, 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, From ee33ce176a756cfc4571009b134dfeb841c21fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 14:29:26 +0100 Subject: [PATCH 090/108] Replaced divisions with multiplications --- src/equations/ideal_glm_mhd_multiion.jl | 15 ++++--- src/equations/ideal_glm_mhd_multiion_2d.jl | 52 ++++++++++++---------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index dc7d248d88a..71015963910 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -55,9 +55,10 @@ function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEqu for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv v1_diff = v1_plus - v1 v2_diff = v2_plus - v2 v3_diff = v3_plus - v3 @@ -177,10 +178,10 @@ function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations) prim[3] = B3 for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 + rho_inv = 1 / rho + v1 = rho_inv * rho_v1 + v2 = rho_inv * rho_v2 + v3 = rho_inv * rho_v3 p = (gammas[k] - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 44ba392855d..33ecca6d396 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -158,9 +158,10 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -184,9 +185,10 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -582,13 +584,14 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, equations) rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_rr + rho_inv_ll = 1 / rho_ll + v1_ll = rho_v1_ll * rho_inv_ll + v2_ll = rho_v2_ll * rho_inv_ll + v3_ll = rho_v3_ll * rho_inv_ll + rho_inv_rr = 1 / rho_rr + v1_rr = rho_v1_rr * rho_inv_rr + v2_rr = rho_v2_rr * rho_inv_rr + v3_rr = rho_v3_rr * rho_inv_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 @@ -680,12 +683,14 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_rr + rho_inv_ll = 1 / rho_ll + v1_ll = rho_v1_ll * rho_inv_ll + v2_ll = rho_v2_ll * rho_inv_ll + v3_ll = rho_v3_ll * rho_inv_ll + rho_inv_rr = 1 / rho_rr + v1_rr = rho_v1_rr * rho_inv_rr + v2_rr = rho_v2_rr * rho_inv_rr + v3_rr = rho_v3_rr * rho_inv_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 @@ -820,15 +825,16 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2) - a_square = gamma * p / rho + a_square = gamma * p * rho_inv sqrt_rho = sqrt(rho) b1 = B1 / sqrt_rho From 3411e3cf10fbefcbc26ed856ab70573c3f5a2071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 14:37:37 +0100 Subject: [PATCH 091/108] Changed code order... --- src/equations/ideal_glm_mhd_multiion_2d.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 33ecca6d396..073f39e5da3 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -67,13 +67,12 @@ function IdealGlmMhdMultiIonEquations2D(; gammas, charge_to_mass, _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) NVARS = length(_gammas) * 5 + 4 NCOMP = length(_gammas) - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealGlmMhdMultiIonEquations2D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, __charge_to_mass, From 2fbc1d7204c436673d2af2efb76ae38073e7ec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 14:41:43 +0100 Subject: [PATCH 092/108] Unexport get_component --- src/Trixi.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Trixi.jl b/src/Trixi.jl index ae3ce2ec970..cb50ca2e7df 100644 --- a/src/Trixi.jl +++ b/src/Trixi.jl @@ -232,7 +232,6 @@ export entropy, energy_total, energy_kinetic, energy_internal, energy_magnetic, enstrophy, magnetic_field, divergence_cleaning_field export lake_at_rest_error export ncomponents, eachcomponent -export get_component export TreeMesh, StructuredMesh, StructuredMeshView, UnstructuredMesh2D, P4estMesh, T8codeMesh From 373aab057db7bab53621bc1e570695d322823c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 15:13:30 +0100 Subject: [PATCH 093/108] Replace division with multiplication --- src/equations/ideal_glm_mhd_multiion_2d.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 073f39e5da3..8849bd6c3ff 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -834,11 +834,11 @@ end (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2) a_square = gamma * p * rho_inv - sqrt_rho = sqrt(rho) + inv_sqrt_rho = 1 / sqrt(rho) - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho + b1 = B1 * inv_sqrt_rho + b2 = B2 * inv_sqrt_rho + b3 = B3 * inv_sqrt_rho b_square = b1^2 + b2^2 + b3^2 if orientation == 1 From 79b0e29dbda74c9ffbbabbaed466c2fdd91414b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 15:23:43 +0100 Subject: [PATCH 094/108] Added unit tests for type stability --- test/test_type.jl | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/test_type.jl b/test/test_type.jl index 131f5f3e1a1..e26b34cdfc6 100644 --- a/test/test_type.jl +++ b/test/test_type.jl @@ -1503,6 +1503,75 @@ isdir(outdir) && rm(outdir, recursive = true) end end + @timed_testset "Ideal Glm Mhd MultiIon 2D" begin + for RealT in (Float32, Float64) + gammas = (RealT(2), RealT(2)) + charge_to_mass = (RealT(2), RealT(2)) + equations = @inferred IdealGlmMhdMultiIonEquations2D(gammas = gammas, + charge_to_mass = charge_to_mass) + + x = SVector(zero(RealT), zero(RealT)) + t = zero(RealT) + u = u_ll = u_rr = cons = SVector(one(RealT), one(RealT), one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT), + one(RealT)) + orientations = [1, 2] + + @test eltype(@inferred initial_condition_weak_blast_wave(x, t, equations)) == + RealT + + @test eltype(@inferred source_terms_lorentz(u, x, t, equations)) == + RealT + + for orientation in orientations + @test eltype(@inferred flux(u, orientation, equations)) == RealT + @test eltype(@inferred flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation, + equations)) == + RealT + @test eltype(@inferred flux_nonconservative_central(u_ll, u_rr, orientation, + equations)) == + RealT + @test eltype(@inferred flux_ruedaramirez_etal(u_ll, u_rr, orientation, + equations)) == RealT + + @test typeof(@inferred max_abs_speed_naive(u_ll, u_rr, orientation, + equations)) == + RealT + end + + @test eltype(@inferred Trixi.max_abs_speeds(u, equations)) == RealT + @test eltype(@inferred cons2prim(u, equations)) == RealT + @test eltype(@inferred prim2cons(u, equations)) == RealT + @test eltype(@inferred cons2entropy(u, equations)) == RealT + @test typeof(@inferred density(u, equations)) == RealT + @test eltype(@inferred magnetic_field(u, equations)) == RealT + @test typeof(@inferred divergence_cleaning_field(u, equations)) == RealT + @test typeof(@inferred Trixi.electron_pressure_zero(u, equations)) == RealT + + @test typeof(@inferred Trixi.charge_averaged_velocities(u, equations)) == + Tuple{RealT, RealT, RealT, SVector{2, RealT}, SVector{2, RealT}, + SVector{2, RealT}} + + for k in 1:2 + @test eltype(@inferred Trixi.get_component(k, u, equations)) == RealT + end + + for direction in orientations + @test typeof(Trixi.calc_fast_wavespeed(cons, direction, equations)) == RealT + end + end + end + @timed_testset "Inviscid Burgers 1D" begin for RealT in (Float32, Float64) equations = @inferred InviscidBurgersEquation1D() From b8e4a290393512c85b024f7d956c53576c149f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 15:40:22 +0100 Subject: [PATCH 095/108] Added experimental admonitions --- src/equations/ideal_glm_mhd_multiion.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index 71015963910..c76351a3750 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -92,6 +92,9 @@ end Compute the charge-averaged velocities (`v1`, `v2`, and `v3`) and each ion species' contribution to the charge-averaged velocities (`vk1`, `vk2`, and `vk3`). The output variables `vk1`, `vk2`, and `vk3` are `SVectors` of size `ncomponents(equations)`. + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. """ @inline function charge_averaged_velocities(u, equations::AbstractIdealGlmMhdMultiIonEquations) @@ -124,6 +127,9 @@ end get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) Get the hydrodynamic variables of component (ion species) `k`. + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. """ @inline function get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations) return SVector(u[3 + (k - 1) * 5 + 1], @@ -138,6 +144,9 @@ end equations::AbstractIdealGlmMhdMultiIonEquations) Set the hydrodynamic variables (`u1` to `u5`) of component (ion species) `k`. + +!!! warning "Experimental implementation" + This is an experimental feature and may change in future releases. """ @inline function set_component!(u, k, u1, u2, u3, u4, u5, equations::AbstractIdealGlmMhdMultiIonEquations) From 5909d0fc45dd0cd6c902ca9208baf499c78e01be Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Wed, 11 Dec 2024 17:00:49 +0100 Subject: [PATCH 096/108] Update src/equations/ideal_glm_mhd_multiion_2d.jl --- src/equations/ideal_glm_mhd_multiion_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 8849bd6c3ff..1f71cbd19ba 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -211,8 +211,8 @@ end """ flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, - orientation::Integer, - equations::IdealGlmMhdMultiIonEquations2D) + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations2D) Entropy-conserving non-conservative two-point "flux"" as described in - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization From e44b52e3eb9e9f721d0d5997303b703e2ceb1cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 17:18:37 +0100 Subject: [PATCH 097/108] Improved documentation for DissipationEntropyStable --- src/equations/numerical_fluxes.jl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/equations/numerical_fluxes.jl b/src/equations/numerical_fluxes.jl index 79ff2f2d9b8..976bc64acb5 100644 --- a/src/equations/numerical_fluxes.jl +++ b/src/equations/numerical_fluxes.jl @@ -225,7 +225,7 @@ const flux_lax_friedrichs = FluxLaxFriedrichs() DissipationEntropyStable(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 (here `flux_ec`) to yield +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: ``` flux_es = FluxPlusDissipation(flux_ec, DissipationEntropyStable()) @@ -233,12 +233,18 @@ flux_es = FluxPlusDissipation(flux_ec, DissipationEntropyStable()) In particular, the numerical flux has the form ```math -f^{ES} = f^{EC} + \frac{1}{2} λ_{max} H (w_R - w_L), +f^{ES} = f^{EC} + \frac{1}{2} λ_{max} H (w_r - w_l), ```` -where ``f^{EC}`` is the entropy-conservative two-point flux function computed with `flux_ec`, ``λ_{max}`` -is the maximum wave speed estimated as `max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`, +where ``f^{EC}`` is the entropy-conservative two-point flux function (computed with, e.g., `flux_ec`), ``λ_{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 states `u_ll` and `u_rr`, and ``(w_R - w_L)`` is the jump in entropy variables. +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::DissipationEntropyStable)(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 From d26713e4e9e08007c48d78fbdc26c8a9f261093c Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Wed, 11 Dec 2024 17:24:52 +0100 Subject: [PATCH 098/108] Apply suggestions from code review --- src/equations/ideal_glm_mhd_multiion_2d.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 1f71cbd19ba..3bebdefc0e3 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -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 = eltype(x) + RealT = real(equations) inicenter = (0, 0) x_norm = x[1] - inicenter[1] y_norm = x[2] - inicenter[2] @@ -123,7 +123,7 @@ function initial_condition_weak_blast_wave(x, t, v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245) - prim = zero(MVector{nvariables(equations), real(equations)}) + prim = zero(MVector{nvariables(equations), RealT}) prim[1] = 1 prim[2] = 1 prim[3] = 1 From 0eb9ddb4532f767158a910ebcec88e288ad7264c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 17:57:53 +0100 Subject: [PATCH 099/108] Moved routines that are dimension-agnostic to ideal_glm_mhd_multiion.jl --- src/equations/ideal_glm_mhd_multiion.jl | 191 ++++++++++++++++++++- src/equations/ideal_glm_mhd_multiion_2d.jl | 188 -------------------- 2 files changed, 190 insertions(+), 189 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index c76351a3750..bc13c629fd8 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -43,7 +43,8 @@ end Source terms due to the Lorentz' force for plasmas with more than one ion species. These source terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for a single-species plasma. In particular, they have to be used for every -simulation of [`IdealGlmMhdMultiIonEquations2D`](@ref). +simulation of [`IdealGlmMhdMultiIonEquations1D`](@ref), [`IdealGlmMhdMultiIonEquations2D`](@ref), +and [`IdealGlmMhdMultiIonEquations3D`](@ref). """ function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) @unpack charge_to_mass = equations @@ -175,6 +176,31 @@ divergence_cleaning_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = return rho end +# Computes the sum of the densities times the sum of the pressures +@inline function density_pressure(u, equations::AbstractIdealGlmMhdMultiIonEquations) + B1, B2, B3 = magnetic_field(u, equations) + psi = divergence_cleaning_field(cons, equations) + + rho_total = zero(real(equations)) + p_total = zero(real(equations)) + for k in eachcomponent(equations) + rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) + + v1 = rho_v1 / rho + v2 = rho_v2 / rho + v3 = rho_v3 / rho + v_mag = sqrt(v1^2 + v2^2 + v3^2) + gamma = equations.gammas[k] + + p = (gamma - 1) * + (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) + + rho_total += rho + p_total += p + end + return rho_total * p_total +end + #Convert conservative variables to primitive function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations) @unpack gammas = equations @@ -263,4 +289,167 @@ end return SVector(cons) end + +# Specialization of DissipationEntropyStable for the multi-ion GLM-MHD equations +@inline function (dissipation::DissipationEntropyStable)(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.5 * (B1_ll + B1_rr) + B2_avg = 0.5 * (B2_ll + B2_rr) + B3_avg = 0.5 * (B3_ll + B3_rr) + psi_avg = 0.5 * (psi_ll + psi_rr) + + dissipation = zero(MVector{nvariables(equations), eltype(u_ll)}) + + beta_plus_ll = 0 + beta_plus_rr = 0 + # Get the lumped dissipation for all components + 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.5 * rho_ll / p_ll + beta_rr = 0.5 * 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.5 * (rho_ll + rho_rr) + v1_avg = 0.5 * (v1_ll + v1_rr) + v2_avg = 0.5 * (v2_ll + v2_rr) + v3_avg = 0.5 * (v3_ll + v3_rr) + beta_avg = 0.5 * (beta_ll + beta_rr) + tau = 1 / (beta_ll + beta_rr) + p_mean = 0.5 * rho_avg / beta_avg + p_star = 0.5 * rho_ln / beta_ln + vel_norm_avg = 0.5 * (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.5 * 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.5 * λ * + (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.5 * λ * + (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.5 * λ * + (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.5 * λ * + (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.5 * λ * + (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 + + # Set the magnetic field and psi terms + h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) + + # diagonal entries + dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) + dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) + dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) + dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) + # Off-diagonal entries + for k in eachcomponent(equations) + _, _, _, _, w5_ll = get_component(k, w_ll, equations) + _, _, _, _, w5_rr = get_component(k, w_rr, equations) + + dissipation[1] -= 0.5 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll) + dissipation[2] -= 0.5 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll) + dissipation[3] -= 0.5 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll) + dissipation[end] -= 0.5 * λ * 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 + ind_E = 3 + (k - 1) * 5 + 5 + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3]) + dissipation[ind_E] -= 0.5 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end]) + + # Dissipation for the energy equation of all ion species depending on w_5 + for kk in eachcomponent(equations) + ind_E = 3 + (kk - 1) * 5 + 5 + dissipation[ind_E] -= 0.5 * λ * + (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 diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index f05d9d526ff..3bebdefc0e3 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -856,192 +856,4 @@ end return c_f end - -# Computes the sum of the densities times the sum of the pressures -@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations2D) - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(cons, equations) - - rho_total = zero(real(equations)) - p_total = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - - p = (gamma - 1) * - (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) - - rho_total += rho - p_total += p - end - return rho_total * p_total -end - -# Specialization of DissipationEntropyStable for the multi-ion GLM-MHD equations -@inline function (dissipation::DissipationEntropyStable)(u_ll, u_rr, - orientation_or_normal_direction, - equations::IdealGlmMhdMultiIonEquations2D) - @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.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) - - dissipation = zero(MVector{nvariables(equations), eltype(u_ll)}) - - beta_plus_ll = 0 - beta_plus_rr = 0 - # Get the lumped dissipation for all components - 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.5 * rho_ll / p_ll - beta_rr = 0.5 * 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.5 * (rho_ll + rho_rr) - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - beta_avg = 0.5 * (beta_ll + beta_rr) - tau = 1 / (beta_ll + beta_rr) - p_mean = 0.5 * rho_avg / beta_avg - p_star = 0.5 * rho_ln / beta_ln - vel_norm_avg = 0.5 * (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.5 * 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.5 * λ * - (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.5 * λ * - (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.5 * λ * - (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.5 * λ * - (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.5 * λ * - (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 - - # Set the magnetic field and psi terms - h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) - - # diagonal entries - dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) - dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) - dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) - dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) - # Off-diagonal entries - for k in eachcomponent(equations) - _, _, _, _, w5_ll = get_component(k, w_ll, equations) - _, _, _, _, w5_rr = get_component(k, w_rr, equations) - - dissipation[1] -= 0.5 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll) - dissipation[2] -= 0.5 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll) - dissipation[3] -= 0.5 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll) - dissipation[end] -= 0.5 * λ * 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 - ind_E = 3 + (k - 1) * 5 + 5 - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end]) - - # Dissipation for the energy equation of all ion species depending on w_5 - for kk in eachcomponent(equations) - ind_E = 3 + (kk - 1) * 5 + 5 - dissipation[ind_E] -= 0.5 * λ * - (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 # @muladd From 099b64fe274665f3ae0a7ff34e20492567c97817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 18:36:56 +0100 Subject: [PATCH 100/108] Improved ideal_glm_mhd_multiion_3d.jl with improvements rom the 2D PR and removed duplicated code --- .../tree_3d_dgsem/elixir_mhdmultiion_ec.jl | 61 +++ src/equations/ideal_glm_mhd_multiion_3d.jl | 413 +++--------------- 2 files changed, 133 insertions(+), 341 deletions(-) create mode 100644 examples/tree_3d_dgsem/elixir_mhdmultiion_ec.jl diff --git a/examples/tree_3d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_3d_dgsem/elixir_mhdmultiion_ec.jl new file mode 100644 index 00000000000..3d8d183a94b --- /dev/null +++ b/examples/tree_3d_dgsem/elixir_mhdmultiion_ec.jl @@ -0,0 +1,61 @@ + +using OrdinaryDiffEq +using Trixi + +############################################################################### +# semidiscretization of the ideal MHD equations +equations = IdealGlmMhdMultiIonEquations3D(gammas = (1.4, 1.667), + charge_to_mass = (1.0, 2.0)) + +initial_condition = initial_condition_weak_blast_wave + +volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +surface_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) +solver = DGSEM(polydeg = 3, surface_flux = surface_flux, + volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) + +coordinates_min = (-2.0, -2.0, -2.0) +coordinates_max = (2.0, 2.0, 2.0) +mesh = TreeMesh(coordinates_min, coordinates_max, + initial_refinement_level = 4, + n_cells_max = 10_000) + +semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, + source_terms = source_terms_lorentz) + +############################################################################### +# ODE solvers, callbacks etc. + +tspan = (0.0, 0.4) +ode = semidiscretize(semi, tspan) + +summary_callback = SummaryCallback() + +analysis_interval = 10 +analysis_callback = AnalysisCallback(semi, interval = analysis_interval) +alive_callback = AliveCallback(analysis_interval = analysis_interval) + +save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, + save_initial_solution = true, + save_final_solution = true, + solution_variables = cons2prim) + +cfl = 0.5 + +stepsize_callback = StepsizeCallback(cfl = cfl) + +glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) + +callbacks = CallbackSet(summary_callback, + analysis_callback, alive_callback, + save_solution, + stepsize_callback, + glm_speed_callback) + +############################################################################### +# run the simulation + +sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), + dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback + save_everystep = false, callback = callbacks); +summary_callback() # print the timer summary diff --git a/src/equations/ideal_glm_mhd_multiion_3d.jl b/src/equations/ideal_glm_mhd_multiion_3d.jl index eb7e8934fd4..f630f4df774 100644 --- a/src/equations/ideal_glm_mhd_multiion_3d.jl +++ b/src/equations/ideal_glm_mhd_multiion_3d.jl @@ -34,8 +34,9 @@ References: 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). -!!! ATTENTION: In case of more than one ion species, these equations should ALWAYS be used - with `source_terms_lorentz`. +!!! info "The multi-ion GLM-MHD equations require source terms" + In case of more than one ion species, the multi-ion GLM-MHD equations should ALWAYS be used + with [`source_terms_lorentz`](@ref). """ mutable struct IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT <: Real, ElectronPressure} <: @@ -66,13 +67,12 @@ function IdealGlmMhdMultiIonEquations3D(; gammas, charge_to_mass, _gammas = promote(gammas...) _charge_to_mass = promote(charge_to_mass...) RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) + __gammas = SVector(map(RealT, _gammas)) + __charge_to_mass = SVector(map(RealT, _charge_to_mass)) NVARS = length(_gammas) * 5 + 4 NCOMP = length(_gammas) - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - return IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT, typeof(electron_pressure)}(__gammas, __charge_to_mass, @@ -82,23 +82,10 @@ end # Outer constructor for `@reset` works correctly function IdealGlmMhdMultiIonEquations3D(gammas, charge_to_mass, electron_pressure, c_h) - _gammas = promote(gammas...) - _charge_to_mass = promote(charge_to_mass...) - RealT = promote_type(eltype(_gammas), eltype(_charge_to_mass)) - - NVARS = length(_gammas) * 5 + 4 - NCOMP = length(_gammas) - - __gammas = SVector(map(RealT, _gammas)) - __charge_to_mass = SVector(map(RealT, _charge_to_mass)) - - c_h = convert(RealT, c_h) - - return IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT, - typeof(electron_pressure)}(__gammas, - __charge_to_mass, - electron_pressure, - c_h) + return IdealGlmMhdMultiIonEquations3D(gammas = gammas, + charge_to_mass = charge_to_mass, + electron_pressure = electron_pressure, + initial_c_h = c_h) end @inline function Base.real(::IdealGlmMhdMultiIonEquations3D{NVARS, NCOMP, RealT}) where { @@ -109,43 +96,14 @@ end RealT end -have_nonconservative_terms(::IdealGlmMhdMultiIonEquations3D) = True() - -function varnames(::typeof(cons2cons), equations::IdealGlmMhdMultiIonEquations3D) - cons = ("B1", "B2", "B3") - for i in eachcomponent(equations) - cons = (cons..., - tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i), - "rho_v3_" * string(i), "rho_e_" * string(i))...) - end - cons = (cons..., "psi") - - return cons -end - -function varnames(::typeof(cons2prim), equations::IdealGlmMhdMultiIonEquations3D) - prim = ("B1", "B2", "B3") - for i in eachcomponent(equations) - prim = (prim..., - tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i), - "v3_" * string(i), "p_" * string(i))...) - end - prim = (prim..., "psi") - - return prim -end - -function default_analysis_integrals(::IdealGlmMhdMultiIonEquations3D) - (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) -end - """ initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations3D) A weak blast wave (adapted to multi-ion MHD) from -- Sebastian Hennemann, Gregor J. Gassner (2020) - A provably entropy stable subcell shock capturing approach for high order split form DG - [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044) +- Hennemann, S., Rueda-Ramírez, A. M., Hindenlang, F. J., & Gassner, G. J. (2021). A provably entropy + stable subcell shock capturing approach for high order split form DG for the compressible Euler equations. + Journal of Computational Physics, 426, 109935. [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044). + [DOI: 10.1016/j.jcp.2020.109935](https://doi.org/10.1016/j.jcp.2020.109935) """ function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations3D) @@ -202,9 +160,10 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -228,9 +187,10 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -254,9 +214,10 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] @@ -278,51 +239,6 @@ end return SVector(f) end -""" - source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations3D) - -Source terms due to the Lorentz' force for plasmas with more than one ion species. These source -terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for -a single-species plasma. -""" -function source_terms_lorentz(u, x, t, equations::IdealGlmMhdMultiIonEquations3D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) -end - -""" - electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations3D) - -Returns the value of zero for the electron pressure. Needed for consistency with the -single-fluid MHD equations in the limit of one ion species. -""" -function electron_pressure_zero(u, equations::IdealGlmMhdMultiIonEquations3D) - return zero(u[1]) -end - """ flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, @@ -333,11 +249,12 @@ Entropy-conserving non-conservative two-point "flux"" as described in 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). -ATTENTION: The non-conservative fluxes derived in the reference above are written as the product - of local and symmetric parts and are meant to be used in the same way as the conservative - fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, - the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied - by 0.5 whenever they are used in the Trixi code +!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi.jl" + The non-conservative fluxes derived in the reference above are written as the product + of local and symmetric parts and are meant to be used in the same way as the conservative + fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, + the fluxes are multiplied by 2 because the non-conservative fluxes are always multiplied + by 0.5 whenever they are used in the Trixi code. The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and @@ -537,15 +454,17 @@ end equations::IdealGlmMhdMultiIonEquations3D) Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. -The use of this term together with flux_central with VolumeIntegralFluxDifferencing yields a "standard" +The use of this term together with [`flux_central`](@ref) +with [`VolumeIntegralFluxDifferencing`](@ref) yields a "standard" (weak-form) DGSEM discretization of the multi-ion GLM-MHD system. This flux can also be used to construct a standard local Lax-Friedrichs flux using `surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)`. -ATTENTION: The central non-conservative fluxes are written as the product - of local and symmetric parts and are meant to be used in the same way as the conservative - fluxes (i.e., flux + flux_noncons in both volume and surface integrals). In this routine, - we omit the 0.5 when computing averages because the non-conservative flux is multiplied by - 0.5 whenever it's used in the Trixi code +!!! info "Usage and Scaling of Non-Conservative Fluxes in Trixi" + The central non-conservative fluxes implemented in this function are written as the product + of local and symmetric parts, where the symmetric part is a standard average. These fluxes + are meant to be used in the same way as the conservative fluxes (i.e., flux + flux_noncons + in both volume and surface integrals). In this routine, the fluxes are multiplied by 2 because + the non-conservative fluxes are always multiplied by 0.5 whenever they are used in the Trixi code. The term is composed of four individual non-conservative terms: 1. The Godunov-Powell term, which arises for plasmas with non-vanishing magnetic field divergence, and @@ -782,12 +701,14 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_rr + rho_inv_ll = 1 / rho_ll + v1_ll = rho_v1_ll * rho_inv_ll + v2_ll = rho_v2_ll * rho_inv_ll + v3_ll = rho_v3_ll * rho_inv_ll + rho_inv_rr = 1 / rho_rr + v1_rr = rho_v1_rr * rho_inv_rr + v2_rr = rho_v2_rr * rho_inv_rr + v3_rr = rho_v3_rr * rho_inv_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 @@ -879,12 +800,14 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_rr + rho_inv_ll = 1 / rho_ll + v1_ll = rho_v1_ll * rho_inv_ll + v2_ll = rho_v2_ll * rho_inv_ll + v3_ll = rho_v3_ll * rho_inv_ll + rho_inv_rr = 1 / rho_rr + v1_rr = rho_v1_rr * rho_inv_rr + v2_rr = rho_v2_rr * rho_inv_rr + v3_rr = rho_v3_rr * rho_inv_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 @@ -976,12 +899,14 @@ function flux_ruedaramirez_etal(u_ll, u_rr, orientation::Integer, rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr = get_component(k, u_rr, equations) - v1_ll = rho_v1_ll / rho_ll - v2_ll = rho_v2_ll / rho_ll - v3_ll = rho_v3_ll / rho_ll - v1_rr = rho_v1_rr / rho_rr - v2_rr = rho_v2_rr / rho_rr - v3_rr = rho_v3_rr / rho_rr + rho_inv_ll = 1 / rho_ll + v1_ll = rho_v1_ll * rho_inv_ll + v2_ll = rho_v2_ll * rho_inv_ll + v3_ll = rho_v3_ll * rho_inv_ll + rho_inv_rr = 1 / rho_rr + v1_rr = rho_v1_rr * rho_inv_rr + v2_rr = rho_v2_rr * rho_inv_rr + v3_rr = rho_v3_rr * rho_inv_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 @@ -1101,9 +1026,10 @@ end v3 = zero(real(equations)) for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations) - v1 = max(v1, abs(rho_v1 / rho)) - v2 = max(v2, abs(rho_v2 / rho)) - v3 = max(v3, abs(rho_v3 / rho)) + rho_inv = 1 / rho + v1 = max(v1, abs(rho_v1 * rho_inv)) + v2 = max(v2, abs(rho_v2 * rho_inv)) + v3 = max(v3, abs(rho_v3 * rho_inv)) end cf_x_direction = calc_fast_wavespeed(u, 1, equations) @@ -1114,95 +1040,6 @@ end abs(v3) + cf_z_direction) end -#Convert conservative variables to primitive -function cons2prim(u, equations::IdealGlmMhdMultiIonEquations3D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(u, equations) - - prim = zero(MVector{nvariables(equations), eltype(u)}) - prim[1] = B1 - prim[2] = B2 - prim[3] = B3 - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - srho = 1 / rho - v1 = srho * rho_v1 - v2 = srho * rho_v2 - v3 = srho * rho_v3 - - p = (gammas[k] - 1) * (rho_e - - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3 - + B1 * B1 + B2 * B2 + B3 * B3 - + psi * psi)) - - set_component!(prim, k, rho, v1, v2, v3, p, equations) - end - prim[end] = psi - - return SVector(prim) -end - -#Convert conservative variables to entropy variables -@inline function cons2entropy(u, equations::IdealGlmMhdMultiIonEquations3D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(u, equations) - - prim = cons2prim(u, equations) - entropy = zero(MVector{nvariables(equations), eltype(u)}) - rho_p_plus = zero(real(equations)) - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - s = log(p) - gammas[k] * log(rho) - rho_p = rho / p - w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2) - w2 = rho_p * v1 - w3 = rho_p * v2 - w4 = rho_p * v3 - w5 = -rho_p - rho_p_plus += rho_p - - set_component!(entropy, k, w1, w2, w3, w4, w5, equations) - end - - # Additional non-conservative variables - entropy[1] = rho_p_plus * B1 - entropy[2] = rho_p_plus * B2 - entropy[3] = rho_p_plus * B3 - entropy[end] = rho_p_plus * psi - - return SVector(entropy) -end - -# Convert primitive to conservative variables -@inline function prim2cons(prim, equations::IdealGlmMhdMultiIonEquations3D) - @unpack gammas = equations - B1, B2, B3 = magnetic_field(prim, equations) - psi = divergence_cleaning_field(prim, equations) - - cons = zero(MVector{nvariables(equations), eltype(prim)}) - cons[1] = B1 - cons[2] = B2 - cons[3] = B3 - for k in eachcomponent(equations) - rho, v1, v2, v3, p = get_component(k, prim, equations) - rho_v1 = rho * v1 - rho_v2 = rho * v2 - rho_v3 = rho * v3 - - rho_e = p / (gammas[k] - 1.0) + - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) + - 0.5f0 * (B1^2 + B2^2 + B3^2) + - 0.5f0 * psi^2 - - set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations) - end - cons[end] = psi - - return SVector(cons) -end - # Compute the fastest wave speed for ideal multi-ion GLM-MHD equations: c_f, the fast # magnetoacoustic eigenvalue. This routine computes the fast magnetosonic speed for each ion # species using the single-fluid MHD expressions and approximates the multi-ion c_f as @@ -1216,15 +1053,16 @@ end for k in eachcomponent(equations) rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, cons, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho + rho_inv = 1 / rho + v1 = rho_v1 * rho_inv + v2 = rho_v2 * rho_inv + v3 = rho_v3 * rho_inv v_mag = sqrt(v1^2 + v2^2 + v3^2) gamma = equations.gammas[k] p = (gamma - 1) * (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2) - a_square = gamma * p / rho + a_square = gamma * p * rho_inv sqrt_rho = sqrt(rho) b1 = B1 / sqrt_rho @@ -1252,111 +1090,4 @@ end return c_f end - -""" -v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u, - equations::IdealGlmMhdMultiIonEquations3D) - - -Compute the charge-averaged velocities (v1, v2, and v3) and each ion species' contribution -to the charge-averaged velocities (vk1, vk2, and vk3). The output variables vk1, vk2, and vk3 -are SVectors of size ncomponents(equations). -""" -@inline function charge_averaged_velocities(u, - equations::IdealGlmMhdMultiIonEquations3D) - total_electron_charge = zero(real(equations)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), - SVector(vk3_plus) -end - -""" - get_component(k, u, equations::IdealGlmMhdMultiIonEquations3D) - -Get the hydrodynamic variables of component (ion species) k. -""" -@inline function get_component(k, u, equations::IdealGlmMhdMultiIonEquations3D) - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) -end - -""" - set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealGlmMhdMultiIonEquations3D) - -Set the hydrodynamic variables of component (ion species) k. -""" -@inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealGlmMhdMultiIonEquations3D) - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 - - return u -end - -# Extract magnetic field from solution vector -magnetic_field(u, equations::IdealGlmMhdMultiIonEquations3D) = SVector(u[1], u[2], u[3]) - -# Extract GLM divergence-cleaning field from solution vector -divergence_cleaning_field(u, equations::IdealGlmMhdMultiIonEquations3D) = u[end] - -# Get total density as the sum of the individual densities of the ion species -@inline function density(u, equations::IdealGlmMhdMultiIonEquations3D) - rho = zero(real(equations)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho -end - -# Computes the sum of the densities times the sum of the pressures -@inline function density_pressure(u, equations::IdealGlmMhdMultiIonEquations3D) - B1, B2, B3 = magnetic_field(u, equations) - psi = divergence_cleaning_field(cons, equations) - - rho_total = zero(real(equations)) - p_total = zero(real(equations)) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v_mag = sqrt(v1^2 + v2^2 + v3^2) - gamma = equations.gammas[k] - - p = (gamma - 1) * - (rho_e - 0.5 * rho * v_mag^2 - 0.5 * (B1^2 + B2^2 + B3^2) - 0.5 * psi^2) - - rho_total += rho - p_total += p - end - return rho_total * p_total -end end # @muladd From 16bb31e5e4e826b533e3586478f14ab540f35182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 18:46:53 +0100 Subject: [PATCH 101/108] Use a single elixir to prove EC, ES, and EC+LLF for multi-ion GLM-MHD --- .../elixir_mhdmultiion_ec+llf.jl | 62 ------------------ .../tree_2d_dgsem/elixir_mhdmultiion_ec.jl | 7 +++ .../tree_2d_dgsem/elixir_mhdmultiion_es.jl | 63 ------------------- test/test_tree_2d_mhdmultiion.jl | 9 ++- 4 files changed, 13 insertions(+), 128 deletions(-) delete mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl delete mode 100644 examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl deleted file mode 100644 index 9be4e5e2492..00000000000 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec+llf.jl +++ /dev/null @@ -1,62 +0,0 @@ - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), - charge_to_mass = (1.0, 2.0)) - -initial_condition = initial_condition_weak_blast_wave - -volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_lax_friedrichs, flux_nonconservative_central) - -solver = DGSEM(polydeg = 3, surface_flux = surface_flux, - volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 4, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_lorentz) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 0.4) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 10 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -cfl = 0.5 - -stepsize_callback = StepsizeCallback(cfl = cfl) - -glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - stepsize_callback, - glm_speed_callback) - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl index d9b66496b19..907ac5d9637 100644 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl +++ b/examples/tree_2d_dgsem/elixir_mhdmultiion_ec.jl @@ -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, DissipationEntropyStable()), +# 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)) diff --git a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl b/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl deleted file mode 100644 index 97d4d87baca..00000000000 --- a/examples/tree_2d_dgsem/elixir_mhdmultiion_es.jl +++ /dev/null @@ -1,63 +0,0 @@ - -using OrdinaryDiffEq -using Trixi - -############################################################################### -# semidiscretization of the ideal MHD equations -equations = IdealGlmMhdMultiIonEquations2D(gammas = (1.4, 1.667), - charge_to_mass = (1.0, 2.0)) - -initial_condition = initial_condition_weak_blast_wave - -flux_es = FluxPlusDissipation(flux_ruedaramirez_etal, DissipationEntropyStable()) - -volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal) -surface_flux = (flux_es, flux_nonconservative_ruedaramirez_etal) -solver = DGSEM(polydeg = 3, surface_flux = surface_flux, - volume_integral = VolumeIntegralFluxDifferencing(volume_flux)) - -coordinates_min = (-2.0, -2.0) -coordinates_max = (2.0, 2.0) -mesh = TreeMesh(coordinates_min, coordinates_max, - initial_refinement_level = 4, - n_cells_max = 10_000) - -semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver, - source_terms = source_terms_lorentz) - -############################################################################### -# ODE solvers, callbacks etc. - -tspan = (0.0, 0.4) -ode = semidiscretize(semi, tspan) - -summary_callback = SummaryCallback() - -analysis_interval = 10 -analysis_callback = AnalysisCallback(semi, interval = analysis_interval) -alive_callback = AliveCallback(analysis_interval = analysis_interval) - -save_solution = SaveSolutionCallback(dt = 0.1, # interval=100, - save_initial_solution = true, - save_final_solution = true, - solution_variables = cons2prim) - -cfl = 0.5 - -stepsize_callback = StepsizeCallback(cfl = cfl) - -glm_speed_callback = GlmSpeedCallback(glm_scale = 0.5, cfl = cfl) - -callbacks = CallbackSet(summary_callback, - analysis_callback, alive_callback, - save_solution, - stepsize_callback, - glm_speed_callback) - -############################################################################### -# run the simulation - -sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false), - dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback - save_everystep = false, callback = callbacks); -summary_callback() # print the timer summary diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index b017c474d79..73fc9fb46e5 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -55,8 +55,8 @@ EXAMPLES_DIR = joinpath(pathof(Trixi) |> dirname |> dirname, "examples", "tree_2 end end -@trixi_testset "elixir_mhdmultiion_es.jl" begin - @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_es.jl"), +@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, @@ -88,7 +88,10 @@ end 0.08695364286964764, 0.4949375933243716, 0.003287251595115295 - ]) + ], + surface_flux=(FluxPlusDissipation(flux_ruedaramirez_etal, + DissipationEntropyStable()), + flux_nonconservative_ruedaramirez_etal)) # Ensure that we do not have excessive memory allocations # (e.g., from type instabilities) let From 2ee244d3ebbd718162efc0f5877d3923cabdb550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Wed, 11 Dec 2024 20:22:54 +0100 Subject: [PATCH 102/108] format --- test/test_tree_2d_mhdmultiion.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_tree_2d_mhdmultiion.jl b/test/test_tree_2d_mhdmultiion.jl index b9d197ca0db..73fc9fb46e5 100644 --- a/test/test_tree_2d_mhdmultiion.jl +++ b/test/test_tree_2d_mhdmultiion.jl @@ -101,7 +101,7 @@ end @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=[ From e84f7a339f3f9b4ecdbf73f6d82c7e772dceb922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 12 Dec 2024 12:44:47 +0100 Subject: [PATCH 103/108] Single precision compatibility for dissipation ES --- src/equations/ideal_glm_mhd_multiion.jl | 66 ++++++++++++------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index bc13c629fd8..5451301c33d 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -308,10 +308,10 @@ end psi_rr = divergence_cleaning_field(u_rr, equations) # Some global averages - B1_avg = 0.5 * (B1_ll + B1_rr) - B2_avg = 0.5 * (B2_ll + B2_rr) - B3_avg = 0.5 * (B3_ll + B3_rr) - psi_avg = 0.5 * (psi_ll + psi_rr) + 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)}) @@ -326,33 +326,33 @@ end w1_rr, w2_rr, w3_rr, w4_rr, w5_rr = get_component(k, w_rr, equations) # Auxiliary variables - beta_ll = 0.5 * rho_ll / p_ll - beta_rr = 0.5 * rho_rr / p_rr + 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.5 * (rho_ll + rho_rr) - v1_avg = 0.5 * (v1_ll + v1_rr) - v2_avg = 0.5 * (v2_ll + v2_rr) - v3_avg = 0.5 * (v3_ll + v3_rr) - beta_avg = 0.5 * (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.5 * rho_avg / beta_avg - p_star = 0.5 * rho_ln / beta_ln - vel_norm_avg = 0.5 * (vel_norm_ll + vel_norm_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.5 * rho_ln * (2 * vel_avg_norm - vel_norm_avg) + 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.5 * λ * + d1 = -0.5f0 * λ * (h11 * (w1_rr - w1_ll) + h12 * (w2_rr - w2_ll) + h13 * (w3_rr - w3_ll) + @@ -364,7 +364,7 @@ end h23 = h21 * v2_avg h24 = h21 * v3_avg h25 = (E_bar + p_mean) * v1_avg - d2 = -0.5 * λ * + d2 = -0.5f0 * λ * (h21 * (w1_rr - w1_ll) + h22 * (w2_rr - w2_ll) + h23 * (w3_rr - w3_ll) + @@ -376,7 +376,7 @@ end h33 = rho_ln * v2_avg^2 + p_mean h34 = h31 * v3_avg h35 = (E_bar + p_mean) * v2_avg - d3 = -0.5 * λ * + d3 = -0.5f0 * λ * (h31 * (w1_rr - w1_ll) + h32 * (w2_rr - w2_ll) + h33 * (w3_rr - w3_ll) + @@ -388,7 +388,7 @@ end h43 = h34 h44 = rho_ln * v3_avg^2 + p_mean h45 = (E_bar + p_mean) * v3_avg - d4 = -0.5 * λ * + d4 = -0.5f0 * λ * (h41 * (w1_rr - w1_ll) + h42 * (w2_rr - w2_ll) + h43 * (w3_rr - w3_ll) + @@ -402,7 +402,7 @@ end h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln + vel_avg_norm * p_mean) - d5 = -0.5 * λ * + d5 = -0.5f0 * λ * (h51 * (w1_rr - w1_ll) + h52 * (w2_rr - w2_ll) + h53 * (w3_rr - w3_ll) + @@ -419,31 +419,31 @@ end h_B_psi = 1 / (beta_plus_ll + beta_plus_rr) # diagonal entries - dissipation[1] = -0.5 * λ * h_B_psi * (w_rr[1] - w_ll[1]) - dissipation[2] = -0.5 * λ * h_B_psi * (w_rr[2] - w_ll[2]) - dissipation[3] = -0.5 * λ * h_B_psi * (w_rr[3] - w_ll[3]) - dissipation[end] = -0.5 * λ * h_B_psi * (w_rr[end] - w_ll[end]) + 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[end] = -0.5f0 * λ * h_B_psi * (w_rr[end] - w_ll[end]) # Off-diagonal entries for k in eachcomponent(equations) _, _, _, _, w5_ll = get_component(k, w_ll, equations) _, _, _, _, w5_rr = get_component(k, w_rr, equations) - dissipation[1] -= 0.5 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll) - dissipation[2] -= 0.5 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll) - dissipation[3] -= 0.5 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll) - dissipation[end] -= 0.5 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll) + 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 ind_E = 3 + (k - 1) * 5 + 5 - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3]) - dissipation[ind_E] -= 0.5 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end]) + 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 for kk in eachcomponent(equations) ind_E = 3 + (kk - 1) * 5 + 5 - dissipation[ind_E] -= 0.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) From 8710b8c9b74487f008ad71dec3b8d7a94b9f9fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 12 Dec 2024 13:05:51 +0100 Subject: [PATCH 104/108] Formatting --- src/equations/ideal_glm_mhd_multiion_2d.jl | 4 +-- src/equations/ideal_glm_mhd_multiion_3d.jl | 30 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 3bebdefc0e3..6a6e65c96cc 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -20,7 +20,7 @@ In case of more than one ion species, the specific heat capacity ratios `gammas` ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. The argument `electron_pressure` can be used to pass a function that computes the electron -pressure as a function of the state `u` with the signature `electron_pressure(u, equations::IdealGlmMhdMultiIonEquations2D)`. +pressure as a function of the state `u` with the signature `electron_pressure(u, equations)`. By default, the electron pressure is zero. The argument `initial_c_h` can be used to set the GLM divergence-cleaning speed. Note that @@ -214,7 +214,7 @@ end orientation::Integer, equations::IdealGlmMhdMultiIonEquations2D) -Entropy-conserving non-conservative two-point "flux"" as described in +Entropy-conserving non-conservative two-point "flux" as described in - 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). diff --git a/src/equations/ideal_glm_mhd_multiion_3d.jl b/src/equations/ideal_glm_mhd_multiion_3d.jl index f630f4df774..3211a84814c 100644 --- a/src/equations/ideal_glm_mhd_multiion_3d.jl +++ b/src/equations/ideal_glm_mhd_multiion_3d.jl @@ -20,7 +20,7 @@ In case of more than one ion species, the specific heat capacity ratios `gammas` ratios `charge_to_mass` should be passed as tuples, e.g., `gammas=(1.4, 1.667)`. The argument `electron_pressure` can be used to pass a function that computes the electron -pressure as a function of the state `u` with the signature `electron_pressure(u, equations::IdealGlmMhdMultiIonEquations3D)`. +pressure as a function of the state `u` with the signature `electron_pressure(u, equations)`. By default, the electron pressure is zero. The argument `initial_c_h` can be used to set the GLM divergence-cleaning speed. Note that @@ -127,9 +127,9 @@ function initial_condition_weak_blast_wave(x, t, p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245) prim = zero(MVector{nvariables(equations), real(equations)}) - prim[1] = 1.0 - prim[2] = 1.0 - prim[3] = 1.0 + prim[1] = 1 + prim[2] = 1 + prim[3] = 1 for k in eachcomponent(equations) set_component!(prim, k, 2^(k - 1) * (1 - 2) / (1 - 2^ncomponents(equations)) * rho, v1, @@ -240,11 +240,11 @@ end end """ - flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, - orientation::Integer, - equations::IdealGlmMhdMultiIonEquations3D) + flux_nonconservative_ruedaramirez_etal(u_ll, u_rr, + orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) -Entropy-conserving non-conservative two-point "flux"" as described in +Entropy-conserving non-conservative two-point "flux" as described in - 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). @@ -450,8 +450,8 @@ The term is composed of four individual non-conservative terms: end """ - flux_nonconservative_central(u_ll, u_rr, orientation::Integer, - equations::IdealGlmMhdMultiIonEquations3D) + flux_nonconservative_central(u_ll, u_rr, orientation::Integer, + equations::IdealGlmMhdMultiIonEquations3D) Central non-conservative two-point "flux", where the symmetric parts are computed with standard averages. The use of this term together with [`flux_central`](@ref) @@ -638,7 +638,7 @@ The term is composed of four individual non-conservative terms: end """ -flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations3D) + flux_ruedaramirez_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMultiIonEquations3D) Entropy conserving two-point flux for the multi-ion GLM-MHD equations from - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization @@ -1063,11 +1063,11 @@ end (rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2) a_square = gamma * p * rho_inv - sqrt_rho = sqrt(rho) + inv_sqrt_rho = 1 / sqrt(rho) - b1 = B1 / sqrt_rho - b2 = B2 / sqrt_rho - b3 = B3 / sqrt_rho + b1 = B1 * inv_sqrt_rho + b2 = B2 * inv_sqrt_rho + b3 = B3 * inv_sqrt_rho b_square = b1^2 + b2^2 + b3^2 if orientation == 1 From c525f688bef4cd6f6445e4e82b82d8bda87c27b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 12 Dec 2024 15:29:55 +0100 Subject: [PATCH 105/108] Fixed issue with analysis integrals in 1D and removed duplicated code --- src/equations/ideal_glm_mhd_multiion.jl | 4 - src/equations/ideal_glm_mhd_multiion_2d.jl | 4 + src/equations/ideal_glm_mhd_multiion_3d.jl | 4 + src/equations/ideal_mhd_multiion_1d.jl | 126 +-------------------- test/test_tree_1d_mhdmultiion.jl | 2 +- 5 files changed, 12 insertions(+), 128 deletions(-) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index 5451301c33d..e71a5631e6f 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -33,10 +33,6 @@ function varnames(::typeof(cons2prim), equations::AbstractIdealGlmMhdMultiIonEqu return prim end -function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations) - (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) -end - """ source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) diff --git a/src/equations/ideal_glm_mhd_multiion_2d.jl b/src/equations/ideal_glm_mhd_multiion_2d.jl index 6a6e65c96cc..1679b10e60d 100644 --- a/src/equations/ideal_glm_mhd_multiion_2d.jl +++ b/src/equations/ideal_glm_mhd_multiion_2d.jl @@ -96,6 +96,10 @@ end RealT end +function default_analysis_integrals(::IdealGlmMhdMultiIonEquations2D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + """ initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations2D) diff --git a/src/equations/ideal_glm_mhd_multiion_3d.jl b/src/equations/ideal_glm_mhd_multiion_3d.jl index 3211a84814c..090e487975d 100644 --- a/src/equations/ideal_glm_mhd_multiion_3d.jl +++ b/src/equations/ideal_glm_mhd_multiion_3d.jl @@ -96,6 +96,10 @@ end RealT end +function default_analysis_integrals(::IdealGlmMhdMultiIonEquations3D) + (entropy_timederivative, Val(:l2_divb), Val(:linf_divb)) +end + """ initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMultiIonEquations3D) diff --git a/src/equations/ideal_mhd_multiion_1d.jl b/src/equations/ideal_mhd_multiion_1d.jl index eacc33f16b2..46ed4b12328 100644 --- a/src/equations/ideal_mhd_multiion_1d.jl +++ b/src/equations/ideal_mhd_multiion_1d.jl @@ -50,8 +50,6 @@ end RealT end -have_nonconservative_terms(::IdealMhdMultiIonEquations1D) = True() - function varnames(::typeof(cons2cons), equations::IdealMhdMultiIonEquations1D) cons = ("B1", "B2", "B3") for i in eachcomponent(equations) @@ -74,28 +72,9 @@ function varnames(::typeof(cons2prim), equations::IdealMhdMultiIonEquations1D) return prim end -# """ -# initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) - -# An Alfvén wave as smooth initial condition used for convergence tests. -# """ -# function initial_condition_convergence_test(x, t, equations::IdealMhdMultiIonEquations1D) -# # smooth Alfvén wave test from Derigs et al. FLASH (2016) -# # domain must be set to [0, 1], γ = 5/3 - -# rho = 1.0 -# prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i-1) * (1-2)/(1-2^ncomponents(equations)) * rho for i in eachcomponent(equations)) -# v1 = 0.0 -# si, co = sincos(2 * pi * x[1]) -# v2 = 0.1 * si -# v3 = 0.1 * co -# p = 0.1 -# B1 = 1.0 -# B2 = v2 -# B3 = v3 -# prim_other = SVector{7, real(equations)}(v1, v2, v3, p, B1, B2, B3) -# return prim2cons(vcat(prim_other, prim_rho), equations) -# end +function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations) + (entropy_timederivative,) +end """ initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEquations1D) @@ -137,8 +116,6 @@ function initial_condition_weak_blast_wave(x, t, equations::IdealMhdMultiIonEqua return prim2cons(SVector(prim), equations) end -# TODO: Add initial condition equilibrium - # Calculate 1D flux in for a single point @inline function flux(u, orientation::Integer, equations::IdealMhdMultiIonEquations1D) B1, B2, B3 = magnetic_field(u, equations) @@ -176,36 +153,6 @@ end return SVector(f) end -""" -Standard source terms of the multi-ion MHD equations -""" -function source_terms_lorentz(u, x, t, equations::IdealMhdMultiIonEquations1D) - @unpack charge_to_mass = equations - B1, B2, B3 = magnetic_field(u, equations) - v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u, - equations) - - s = zero(MVector{nvariables(equations), eltype(u)}) - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations) - v1 = rho_v1 / rho - v2 = rho_v2 / rho - v3 = rho_v3 / rho - v1_diff = v1_plus - v1 - v2_diff = v2_plus - v2 - v3_diff = v3_plus - v3 - r_rho = charge_to_mass[k] * rho - s2 = r_rho * (v2_diff * B3 - v3_diff * B2) - s3 = r_rho * (v3_diff * B1 - v1_diff * B3) - s4 = r_rho * (v1_diff * B2 - v2_diff * B1) - s5 = v1 * s2 + v2 * s3 + v3 * s4 - - set_component!(s, k, 0, s2, s3, s4, s5, equations) - end - - return SVector(s) -end - """ Total entropy-conserving non-conservative two-point "flux"" as described in - Rueda-Ramírez et al. (2023) @@ -630,71 +577,4 @@ Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoaco return c_f end - -""" -Routine to compute the charge-averaged velocities: -* v*_plus: Charge-averaged velocity -* vk*_plus: Contribution of each species to the charge-averaged velocity -""" -@inline function charge_averaged_velocities(u, equations::IdealMhdMultiIonEquations1D) - total_electron_charge = zero(real(equations)) - - vk1_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk2_plus = zero(MVector{ncomponents(equations), eltype(u)}) - vk3_plus = zero(MVector{ncomponents(equations), eltype(u)}) - - for k in eachcomponent(equations) - rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, - equations::IdealMhdMultiIonEquations1D) - - total_electron_charge += rho * equations.charge_to_mass[k] - vk1_plus[k] = rho_v1 * equations.charge_to_mass[k] - vk2_plus[k] = rho_v2 * equations.charge_to_mass[k] - vk3_plus[k] = rho_v3 * equations.charge_to_mass[k] - end - vk1_plus ./= total_electron_charge - vk2_plus ./= total_electron_charge - vk3_plus ./= total_electron_charge - v1_plus = sum(vk1_plus) - v2_plus = sum(vk2_plus) - v3_plus = sum(vk3_plus) - - return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus), - SVector(vk3_plus) -end - -""" -Get the flow variables of component k -""" -@inline function get_component(k, u, equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - return SVector(u[3 + (k - 1) * 5 + 1], - u[3 + (k - 1) * 5 + 2], - u[3 + (k - 1) * 5 + 3], - u[3 + (k - 1) * 5 + 4], - u[3 + (k - 1) * 5 + 5]) -end - -""" -Set the flow variables of component k -""" -@inline function set_component!(u, k, u1, u2, u3, u4, u5, - equations::IdealMhdMultiIonEquations1D) - # The first 3 entries of u contain the magnetic field. The following entries contain the density, momentum (3 entries), and energy of each component. - u[3 + (k - 1) * 5 + 1] = u1 - u[3 + (k - 1) * 5 + 2] = u2 - u[3 + (k - 1) * 5 + 3] = u3 - u[3 + (k - 1) * 5 + 4] = u4 - u[3 + (k - 1) * 5 + 5] = u5 -end - -magnetic_field(u, equations::IdealMhdMultiIonEquations1D) = SVector(u[1], u[2], u[3]) - -@inline function density(u, equations::IdealMhdMultiIonEquations1D) - rho = zero(real(equations)) - for k in eachcomponent(equations) - rho += u[3 + (k - 1) * 5 + 1] - end - return rho -end end # @muladd diff --git a/test/test_tree_1d_mhdmultiion.jl b/test/test_tree_1d_mhdmultiion.jl index 3295891eb5b..da36fbd8ec5 100644 --- a/test/test_tree_1d_mhdmultiion.jl +++ b/test/test_tree_1d_mhdmultiion.jl @@ -1,4 +1,4 @@ -module TestExamples1DMHD +module TestExamples1DMHDMultiIon using Test using Trixi From 1d01d2f896302df7e26221e4f1669ae3f0a8288c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 12 Dec 2024 15:39:43 +0100 Subject: [PATCH 106/108] Fixed Euler test --- src/time_integration/methods_SSP.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/time_integration/methods_SSP.jl b/src/time_integration/methods_SSP.jl index c6533aa2005..33d1f164138 100644 --- a/src/time_integration/methods_SSP.jl +++ b/src/time_integration/methods_SSP.jl @@ -186,8 +186,6 @@ function solve!(integrator::SimpleIntegratorSSP) terminate!(integrator) end - modify_dt_for_tstops!(integrator) - @. integrator.r0 = integrator.u for stage in eachindex(alg.c) t_stage = integrator.t + integrator.dt * alg.c[stage] From 697c7bd69213d35e6ae01982514392bf785b71f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 12 Dec 2024 16:21:16 +0100 Subject: [PATCH 107/108] Fix documentation issue --- src/equations/ideal_glm_mhd_multiion.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equations/ideal_glm_mhd_multiion.jl b/src/equations/ideal_glm_mhd_multiion.jl index e71a5631e6f..2fade2d542a 100644 --- a/src/equations/ideal_glm_mhd_multiion.jl +++ b/src/equations/ideal_glm_mhd_multiion.jl @@ -39,7 +39,7 @@ end Source terms due to the Lorentz' force for plasmas with more than one ion species. These source terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for a single-species plasma. In particular, they have to be used for every -simulation of [`IdealGlmMhdMultiIonEquations1D`](@ref), [`IdealGlmMhdMultiIonEquations2D`](@ref), +simulation of [`IdealMhdMultiIonEquations1D`](@ref), [`IdealGlmMhdMultiIonEquations2D`](@ref), and [`IdealGlmMhdMultiIonEquations3D`](@ref). """ function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations) From f220df67154c19107555e0cbd913c58f37f63b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Rueda-Ram=C3=ADrez?= Date: Thu, 19 Dec 2024 17:21:54 +0100 Subject: [PATCH 108/108] Added tests for 3D multi-ion MHD --- test/test_tree_3d_mhdmultiion.jl | 156 +++++++++++++++++++++++++++++++ test/test_tree_3d_part3.jl | 3 + 2 files changed, 159 insertions(+) create mode 100644 test/test_tree_3d_mhdmultiion.jl diff --git a/test/test_tree_3d_mhdmultiion.jl b/test/test_tree_3d_mhdmultiion.jl new file mode 100644 index 00000000000..f661e0be77e --- /dev/null +++ b/test/test_tree_3d_mhdmultiion.jl @@ -0,0 +1,156 @@ +module TestExamples3DIdealGlmMhdMultiIon + +using Test +using Trixi + +include("test_trixi.jl") + +# pathof(Trixi) returns /path/to/Trixi/src/Trixi.jl, dirname gives the parent directory +EXAMPLES_DIR = joinpath(examples_dir(), "tree_3d_dgsem") + +@testset "MHD Multi-ion" begin +#! format: noindent + +@trixi_testset "elixir_mhdmultiion_ec.jl" begin + @test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_mhdmultiion_ec.jl"), + l2=[ + 0.005515090292575059, + 0.005515093229701533, + 0.0055155968594217, + 0.0034090002245163614, + 0.003709807395174228, + 0.003709808917203165, + 0.003709945123475921, + 0.04983943937107913, + 0.005484133454336887, + 0.00528293290439966, + 0.005282930490865487, + 0.005283547806305909, + 0.03352789135708704, + 3.749645231098896e-5 + ], + linf=[ + 0.21024185596950629, + 0.21025151478760273, + 0.21024912618268798, + 0.076395739096276, + 0.1563223611743002, + 0.15632884538092198, + 0.15634105391848113, + 1.0388823226534836, + 0.22150908356656462, + 0.2513262952807552, + 0.2513408613352427, + 0.25131982443776496, + 0.8504449549199755, + 0.00745904702407851 + ], tspan=(0.0, 0.05)) + # 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) + # Slightly larger values for allowed allocations due to the size of the multi-ion MHD system + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 2000 + 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.005461797766886852, + 0.0054617979185473935, + 0.005461911963493437, + 0.0034019650432160183, + 0.0036214136925153332, + 0.003621413755863293, + 0.0036214256331343125, + 0.04989956402093448, + 0.005418917526099802, + 0.005131066757973498, + 0.005131067607695321, + 0.005131172274784049, + 0.03343666846482734, + 0.0003007804111764196 + ], + linf=[ + 0.12234892772192096, + 0.1223171830655686, + 0.1278258253016613, + 0.07205879616765087, + 0.1290061932668167, + 0.12899478253220256, + 0.12899463311942488, + 1.084354847523644, + 0.17599973652527756, + 0.1673024753470816, + 0.16729366599933276, + 0.1672749128649947, + 0.9610489935515938, + 0.04894654146236637 + ], + surface_flux=(FluxPlusDissipation(flux_ruedaramirez_etal, + DissipationLaxFriedrichsEntropyVariables()), + flux_nonconservative_ruedaramirez_etal), + tspan=(0.0, 0.05)) + # 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) + # Slightly larger values for allowed allocations due to the size of the multi-ion MHD system + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 2000 + 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=[ + 0.0054618017243060245, + 0.005461801874647487, + 0.005461916115692502, + 0.0034019533360683516, + 0.0036214103139306027, + 0.003621410378506676, + 0.0036214220691497454, + 0.04989948890811091, + 0.005418894551414051, + 0.005131075328225897, + 0.005131076176988492, + 0.005131180975100698, + 0.033436687541996704, + 0.00030074542007975337 + ], + linf=[ + 0.12239622025605945, + 0.12236446866852024, + 0.12789210451104582, + 0.07208147196589526, + 0.12903267474777533, + 0.12902126950883053, + 0.12902139991772607, + 1.0843706600615892, + 0.1760697478878981, + 0.16728192094436928, + 0.16727303109462638, + 0.1672542060574919, + 0.9611095787397885, + 0.04895673952280341 + ], + surface_flux=(flux_lax_friedrichs, flux_nonconservative_central), + tspan=(0.0, 0.05)) + # 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) + # Slightly larger values for allowed allocations due to the size of the multi-ion MHD system + @test (@allocated Trixi.rhs!(du_ode, u_ode, semi, t)) < 2000 + end +end +end + +end # module diff --git a/test/test_tree_3d_part3.jl b/test/test_tree_3d_part3.jl index 9e1e8bc4dc9..fd91a106d9c 100644 --- a/test/test_tree_3d_part3.jl +++ b/test/test_tree_3d_part3.jl @@ -17,6 +17,9 @@ isdir(outdir) && rm(outdir, recursive = true) # MHD include("test_tree_3d_mhd.jl") + # Multi-ion MHD + include("test_tree_3d_mhdmultiion.jl") + # Lattice-Boltzmann include("test_tree_3d_lbm.jl")