Path: blob/main/src/equations/hyperbolic_diffusion_3d.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8HyperbolicDiffusionEquations3D910The linear hyperbolic diffusion equations in three space dimensions.11A description of this system can be found in Sec. 2.5 of the book "I Do Like CFD, Too: Vol 1".12The book is freely available at [http://www.cfdbooks.com/](http://www.cfdbooks.com/) and further analysis can be found in13the paper by Nishikawa [DOI: 10.1016/j.jcp.2007.07.029](https://doi.org/10.1016/j.jcp.2007.07.029)14"""15struct HyperbolicDiffusionEquations3D{RealT <: Real} <:16AbstractHyperbolicDiffusionEquations{3, 4}17Lr::RealT # reference length scale18inv_Tr::RealT # inverse of the reference time scale19nu::RealT # diffusion constant20end2122function HyperbolicDiffusionEquations3D(; nu = 1.0, Lr = inv(2pi))23Tr = Lr^2 / nu24HyperbolicDiffusionEquations3D(promote(Lr, inv(Tr), nu)...)25end2627function varnames(::typeof(cons2cons), ::HyperbolicDiffusionEquations3D)28("phi", "q1", "q2", "q3")29end30function varnames(::typeof(cons2prim), ::HyperbolicDiffusionEquations3D)31("phi", "q1", "q2", "q3")32end33function default_analysis_errors(::HyperbolicDiffusionEquations3D)34(:l2_error, :linf_error, :residual)35end3637"""38residual_steady_state(du, ::AbstractHyperbolicDiffusionEquations)3940Used to determine the termination criterion of a [`SteadyStateCallback`](@ref).41For hyperbolic diffusion, this checks convergence of the potential ``\\phi``.42"""43@inline function residual_steady_state(du, ::HyperbolicDiffusionEquations3D)44abs(du[1])45end4647# Set initial conditions at physical location `x` for pseudo-time `t`48function initial_condition_poisson_nonperiodic(x, t,49equations::HyperbolicDiffusionEquations3D)50# elliptic equation: -νΔϕ = f51RealT = eltype(x)52if t == 053phi = one(RealT)54q1 = one(RealT)55q2 = one(RealT)56q3 = one(RealT)57else58phi = 2 * cospi(x[1]) *59sinpi(2 * x[2]) *60sinpi(2 * x[3]) + 2 # ϕ61q1 = -2 * convert(RealT, pi) * sinpi(x[1]) *62sinpi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_x63q2 = 4 * convert(RealT, pi) * cospi(x[1]) *64cospi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_y65q3 = 4 * convert(RealT, pi) * cospi(x[1]) *66sinpi(2 * x[2]) * cospi(2 * x[3]) # ϕ_z67end68return SVector(phi, q1, q2, q3)69end7071@inline function source_terms_poisson_nonperiodic(u, x, t,72equations::HyperbolicDiffusionEquations3D)73# elliptic equation: -νΔϕ = f74# analytical solution: ϕ = 2 cos(πx)sin(2πy)sin(2πz) + 2 and f = 18 π^2 cos(πx)sin(2πy)sin(2πz)75RealT = eltype(u)76@unpack inv_Tr = equations7778x1, x2, x3 = x79du1 = 18 * convert(RealT, pi)^2 * cospi(x1) * sinpi(2 * x2) * sinpi(2 * x3)80du2 = -inv_Tr * u[2]81du3 = -inv_Tr * u[3]82du4 = -inv_Tr * u[4]8384return SVector(du1, du2, du3, du4)85end8687function boundary_condition_poisson_nonperiodic(u_inner, orientation, direction, x, t,88surface_flux_function,89equations::HyperbolicDiffusionEquations3D)90# elliptic equation: -νΔϕ = f91RealT = eltype(u_inner)92phi = 2 * cospi(x[1]) * sinpi(2 * x[2]) *93sinpi(2 * x[3]) + 2 # ϕ94q1 = -2 * convert(RealT, pi) * sinpi(x[1]) *95sinpi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_x96q2 = 4 * convert(RealT, pi) * cospi(x[1]) *97cospi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_y98q3 = 4 * convert(RealT, pi) * cospi(x[1]) *99sinpi(2 * x[2]) * cospi(2 * x[3]) # ϕ_z100u_boundary = SVector(phi, q1, q2, q3)101102# Calculate boundary flux103if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary104flux = surface_flux_function(u_inner, u_boundary, orientation, equations)105else # u_boundary is "left" of boundary, u_inner is "right" of boundary106flux = surface_flux_function(u_boundary, u_inner, orientation, equations)107end108109return flux110end111112"""113source_terms_harmonic(u, x, t, equations::HyperbolicDiffusionEquations3D)114115Source term that only includes the forcing from the hyperbolic diffusion system.116"""117@inline function source_terms_harmonic(u, x, t,118equations::HyperbolicDiffusionEquations3D)119# harmonic solution ϕ = (sinh(πx)sin(πy) + sinh(πy)sin(πx))/sinh(π), so f = 0120@unpack inv_Tr = equations121122du1 = 0123du2 = -inv_Tr * u[2]124du3 = -inv_Tr * u[3]125du4 = -inv_Tr * u[4]126127return SVector(du1, du2, du3, du4)128end129130"""131initial_condition_eoc_test_coupled_euler_gravity(x, t, equations::HyperbolicDiffusionEquations3D)132133Setup used for convergence tests of the Euler equations with self-gravity used in134- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)135A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics136[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)137in combination with [`source_terms_harmonic`](@ref).138"""139function initial_condition_eoc_test_coupled_euler_gravity(x, t,140equations::HyperbolicDiffusionEquations3D)141142# Determine phi_x, phi_y143RealT = eltype(x)144G = 1 # gravitational constant145C_grav = -4 * G / (3 * convert(RealT, pi)) # "3" is the number of spatial dimensions # 2D: -2.0*G/pi146A = convert(RealT, 0.1) # perturbation coefficient must match Euler setup147rho1 = A * sinpi(x[1] + x[2] + x[3] - t)148# initialize with ansatz of gravity potential149phi = C_grav * rho1150q1 = C_grav * A * convert(RealT, pi) *151cospi(x[1] + x[2] + x[3] - t) # = gravity acceleration in x-direction152q2 = q1 # = gravity acceleration in y-direction153q3 = q1 # = gravity acceleration in z-direction154155return SVector(phi, q1, q2, q3)156end157158# Calculate 1D flux for a single point159@inline function flux(u, orientation::Integer,160equations::HyperbolicDiffusionEquations3D)161phi, q1, q2, q3 = u162163RealT = eltype(u)164if orientation == 1165f1 = -equations.nu * q1166f2 = -phi * equations.inv_Tr167f3 = zero(RealT)168f4 = zero(RealT)169elseif orientation == 2170f1 = -equations.nu * q2171f2 = zero(RealT)172f3 = -phi * equations.inv_Tr173f4 = zero(RealT)174else175f1 = -equations.nu * q3176f2 = zero(RealT)177f3 = zero(RealT)178f4 = -phi * equations.inv_Tr179end180181return SVector(f1, f2, f3, f4)182end183184# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation185@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,186equations::HyperbolicDiffusionEquations3D)187return sqrt(equations.nu * equations.inv_Tr)188end189190"""191flux_godunov(u_ll, u_rr, orientation_or_normal_direction,192equations::HyperbolicDiffusionEquations3D)193194Godunov (upwind) flux for the 3D hyperbolic diffusion equations.195"""196@inline function flux_godunov(u_ll, u_rr, orientation::Integer,197equations::HyperbolicDiffusionEquations3D)198# Obtain left and right fluxes199phi_ll, q1_ll, q2_ll, q3_ll = u_ll200phi_rr, q1_rr, q2_rr, q3_rr = u_rr201f_ll = flux(u_ll, orientation, equations)202f_rr = flux(u_rr, orientation, equations)203204# this is an optimized version of the application of the upwind dissipation matrix:205# dissipation = 0.5*R_n*|Λ|*inv(R_n)[[u]]206λ_max = sqrt(equations.nu * equations.inv_Tr)207f1 = 0.5f0 * (f_ll[1] + f_rr[1]) - 0.5f0 * λ_max * (phi_rr - phi_ll)208if orientation == 1 # x-direction209f2 = 0.5f0 * (f_ll[2] + f_rr[2]) - 0.5f0 * λ_max * (q1_rr - q1_ll)210f3 = 0.5f0 * (f_ll[3] + f_rr[3])211f4 = 0.5f0 * (f_ll[4] + f_rr[4])212elseif orientation == 2 # y-direction213f2 = 0.5f0 * (f_ll[2] + f_rr[2])214f3 = 0.5f0 * (f_ll[3] + f_rr[3]) - 0.5f0 * λ_max * (q2_rr - q2_ll)215f4 = 0.5f0 * (f_ll[4] + f_rr[4])216else # y-direction217f2 = 0.5f0 * (f_ll[2] + f_rr[2])218f3 = 0.5f0 * (f_ll[3] + f_rr[3])219f4 = 0.5f0 * (f_ll[4] + f_rr[4]) - 0.5f0 * λ_max * (q3_rr - q3_ll)220end221222return SVector(f1, f2, f3, f4)223end224225@inline have_constant_speed(::HyperbolicDiffusionEquations3D) = True()226227@inline function max_abs_speeds(eq::HyperbolicDiffusionEquations3D)228λ = sqrt(eq.nu * eq.inv_Tr)229return λ, λ, λ230end231232# Convert conservative variables to primitive233@inline cons2prim(u, equations::HyperbolicDiffusionEquations3D) = u234235# Convert conservative variables to entropy found in I Do Like CFD, Too, Vol. 1236@inline function cons2entropy(u, equations::HyperbolicDiffusionEquations3D)237phi, q1, q2, q3 = u238w1 = phi239w2 = equations.Lr^2 * q1240w3 = equations.Lr^2 * q2241w4 = equations.Lr^2 * q3242243return SVector(w1, w2, w3, w4)244end245246# Calculate entropy for a conservative state `u` (here: same as total energy)247@inline function entropy(u, equations::HyperbolicDiffusionEquations3D)248energy_total(u, equations)249end250251# Calculate total energy for a conservative state `u`252@inline function energy_total(u, equations::HyperbolicDiffusionEquations3D)253# energy function as found in equation (2.5.12) in the book "I Do Like CFD, Vol. 1"254phi, q1, q2, q3 = u255return 0.5f0 * (phi^2 + equations.Lr^2 * (q1^2 + q2^2 + q3^2))256end257end # @muladd258259260