Path: blob/main/src/equations/hyperbolic_diffusion_2d.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"""8HyperbolicDiffusionEquations2D910The linear hyperbolic diffusion equations in two 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 HyperbolicDiffusionEquations2D{RealT <: Real} <:16AbstractHyperbolicDiffusionEquations{2, 3}17Lr::RealT # reference length scale18inv_Tr::RealT # inverse of the reference time scale19nu::RealT # diffusion constant20end2122function HyperbolicDiffusionEquations2D(; nu = 1.0, Lr = inv(2pi))23Tr = Lr^2 / nu24HyperbolicDiffusionEquations2D(promote(Lr, inv(Tr), nu)...)25end2627varnames(::typeof(cons2cons), ::HyperbolicDiffusionEquations2D) = ("phi", "q1", "q2")28varnames(::typeof(cons2prim), ::HyperbolicDiffusionEquations2D) = ("phi", "q1", "q2")29function default_analysis_errors(::HyperbolicDiffusionEquations2D)30(:l2_error, :linf_error, :residual)31end3233@inline function residual_steady_state(du, ::HyperbolicDiffusionEquations2D)34abs(du[1])35end3637# Set initial conditions at physical location `x` for pseudo-time `t`38@inline function initial_condition_poisson_nonperiodic(x, t,39equations::HyperbolicDiffusionEquations2D)40# elliptic equation: -ν Δϕ = f in Ω, u = g on ∂Ω41RealT = eltype(x)42if iszero(t)43phi = one(RealT)44q1 = one(RealT)45q2 = one(RealT)46else47sinpi_x1, cospi_x1 = sincospi(x[1])48sinpi_2x2, cospi_2x2 = sincospi(2 * x[2])49phi = 2 * cospi_x1 * sinpi_2x2 + 2 # ϕ50q1 = -2 * convert(RealT, pi) * sinpi_x1 * sinpi_2x2 # ϕ_x51q2 = 4 * convert(RealT, pi) * cospi_x1 * cospi_2x2 # ϕ_y52end53return SVector(phi, q1, q2)54end5556@inline function source_terms_poisson_nonperiodic(u, x, t,57equations::HyperbolicDiffusionEquations2D)58# elliptic equation: -ν Δϕ = f in Ω, u = g on ∂Ω59# analytical solution: ϕ = 2cos(πx)sin(2πy) + 2 and f = 10π^2cos(πx)sin(2πy)60RealT = eltype(u)61@unpack inv_Tr = equations6263x1, x2 = x64du1 = 10 * convert(RealT, pi)^2 * cospi(x1) * sinpi(2 * x2)65du2 = -inv_Tr * u[2]66du3 = -inv_Tr * u[3]6768return SVector(du1, du2, du3)69end7071@inline function boundary_condition_poisson_nonperiodic(u_inner, orientation, direction,72x, t,73surface_flux_function,74equations::HyperbolicDiffusionEquations2D)75# elliptic equation: -ν Δϕ = f in Ω, u = g on ∂Ω76u_boundary = initial_condition_poisson_nonperiodic(x, one(t), equations)7778# Calculate boundary flux79if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary80flux = surface_flux_function(u_inner, u_boundary, orientation, equations)81else # u_boundary is "left" of boundary, u_inner is "right" of boundary82flux = surface_flux_function(u_boundary, u_inner, orientation, equations)83end8485return flux86end8788"""89source_terms_harmonic(u, x, t, equations::HyperbolicDiffusionEquations2D)9091Source term that only includes the forcing from the hyperbolic diffusion system.92"""93@inline function source_terms_harmonic(u, x, t,94equations::HyperbolicDiffusionEquations2D)95# harmonic solution ϕ = (sinh(πx)sin(πy) + sinh(πy)sin(πx))/sinh(π), so f = 096@unpack inv_Tr = equations97phi, q1, q2 = u9899du2 = -inv_Tr * q1100du3 = -inv_Tr * q2101102return SVector(0, du2, du3)103end104105"""106initial_condition_eoc_test_coupled_euler_gravity(x, t, equations::HyperbolicDiffusionEquations2D)107108Setup used for convergence tests of the Euler equations with self-gravity used in109- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)110A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics111[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)112in combination with [`source_terms_harmonic`](@ref).113"""114function initial_condition_eoc_test_coupled_euler_gravity(x, t,115equations::HyperbolicDiffusionEquations2D)116117# Determine phi_x, phi_y118RealT = eltype(x)119G = 1 # gravitational constant120C = -2 * G / convert(RealT, pi)121A = convert(RealT, 0.1) # perturbation coefficient must match Euler setup122rho1 = A * sinpi(x[1] + x[2] - t)123# initialize with ansatz of gravity potential124phi = C * rho1125q1 = C * A * convert(RealT, pi) * cospi(x[1] + x[2] - t) # = gravity acceleration in x-direction126q2 = q1 # = gravity acceleration in y-direction127128return SVector(phi, q1, q2)129end130131# Calculate 1D flux for a single point132@inline function flux(u, orientation::Integer,133equations::HyperbolicDiffusionEquations2D)134phi, q1, q2 = u135@unpack inv_Tr = equations136137RealT = eltype(u)138if orientation == 1139f1 = -equations.nu * q1140f2 = -phi * inv_Tr141f3 = zero(RealT)142else143f1 = -equations.nu * q2144f2 = zero(RealT)145f3 = -phi * inv_Tr146end147148return SVector(f1, f2, f3)149end150151# Note, this directional vector is not normalized152@inline function flux(u, normal_direction::AbstractVector,153equations::HyperbolicDiffusionEquations2D)154phi, q1, q2 = u155@unpack inv_Tr = equations156157f1 = -equations.nu * (normal_direction[1] * q1 + normal_direction[2] * q2)158f2 = -phi * inv_Tr * normal_direction[1]159f3 = -phi * inv_Tr * normal_direction[2]160161return SVector(f1, f2, f3)162end163164# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation165@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,166equations::HyperbolicDiffusionEquations2D)167sqrt(equations.nu * equations.inv_Tr)168end169170@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,171equations::HyperbolicDiffusionEquations2D)172sqrt(equations.nu * equations.inv_Tr) * norm(normal_direction)173end174175"""176flux_godunov(u_ll, u_rr, orientation_or_normal_direction,177equations::HyperbolicDiffusionEquations2D)178179Godunov (upwind) flux for the 2D hyperbolic diffusion equations.180"""181@inline function flux_godunov(u_ll, u_rr, orientation::Integer,182equations::HyperbolicDiffusionEquations2D)183# Obtain left and right fluxes184phi_ll, q1_ll, q2_ll = u_ll185phi_rr, q1_rr, q2_rr = u_rr186f_ll = flux(u_ll, orientation, equations)187f_rr = flux(u_rr, orientation, equations)188189# this is an optimized version of the application of the upwind dissipation matrix:190# dissipation = 0.5*R_n*|Λ|*inv(R_n)[[u]]191λ_max = sqrt(equations.nu * equations.inv_Tr)192f1 = 0.5f0 * (f_ll[1] + f_rr[1]) - 0.5f0 * λ_max * (phi_rr - phi_ll)193if orientation == 1 # x-direction194f2 = 0.5f0 * (f_ll[2] + f_rr[2]) - 0.5f0 * λ_max * (q1_rr - q1_ll)195f3 = 0.5f0 * (f_ll[3] + f_rr[3])196else # y-direction197f2 = 0.5f0 * (f_ll[2] + f_rr[2])198f3 = 0.5f0 * (f_ll[3] + f_rr[3]) - 0.5f0 * λ_max * (q2_rr - q2_ll)199end200201return SVector(f1, f2, f3)202end203204@inline function flux_godunov(u_ll, u_rr, normal_direction::AbstractVector,205equations::HyperbolicDiffusionEquations2D)206# Obtain left and right fluxes207phi_ll, q1_ll, q2_ll = u_ll208phi_rr, q1_rr, q2_rr = u_rr209f_ll = flux(u_ll, normal_direction, equations)210f_rr = flux(u_rr, normal_direction, equations)211212# this is an optimized version of the application of the upwind dissipation matrix:213# dissipation = 0.5*R_n*|Λ|*inv(R_n)[[u]]214λ_max = sqrt(equations.nu * equations.inv_Tr)215f1 = 0.5f0 * (f_ll[1] + f_rr[1]) -2160.5f0 * λ_max * (phi_rr - phi_ll) *217sqrt(normal_direction[1]^2 + normal_direction[2]^2)218f2 = 0.5f0 * (f_ll[2] + f_rr[2]) -2190.5f0 * λ_max * (q1_rr - q1_ll) * normal_direction[1]220f3 = 0.5f0 * (f_ll[3] + f_rr[3]) -2210.5f0 * λ_max * (q2_rr - q2_ll) * normal_direction[2]222223return SVector(f1, f2, f3)224end225226@inline have_constant_speed(::HyperbolicDiffusionEquations2D) = True()227228@inline function max_abs_speeds(eq::HyperbolicDiffusionEquations2D)229λ = sqrt(eq.nu * eq.inv_Tr)230return λ, λ231end232233# Convert conservative variables to primitive234@inline cons2prim(u, equations::HyperbolicDiffusionEquations2D) = u235236# Convert conservative variables to entropy found in I Do Like CFD, Too, Vol. 1237@inline function cons2entropy(u, equations::HyperbolicDiffusionEquations2D)238phi, q1, q2 = u239w1 = phi240w2 = equations.Lr^2 * q1241w3 = equations.Lr^2 * q2242243return SVector(w1, w2, w3)244end245246# Calculate entropy for a conservative state `u` (here: same as total energy)247@inline function entropy(u, equations::HyperbolicDiffusionEquations2D)248energy_total(u, equations)249end250251# Calculate total energy for a conservative state `u`252@inline function energy_total(u, equations::HyperbolicDiffusionEquations2D)253# energy function as found in equations (2.5.12) in the book "I Do Like CFD, Vol. 1"254phi, q1, q2 = u255return 0.5f0 * (phi^2 + equations.Lr^2 * (q1^2 + q2^2))256end257end # @muladd258259260