Path: blob/main/src/semidiscretization/semidiscretization_euler_acoustics.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"""8SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics, semi_euler::SemiEuler;9source_region=x->true, weights=x->1.0)1011!!! warning "Experimental code"12This semidiscretization is experimental and may change in any future release.1314Construct a semidiscretization of the acoustic perturbation equations that is coupled with15the compressible Euler equations via source terms for the perturbed velocity. Both16semidiscretizations have to use the same mesh and solvers with a shared basis. The coupling region17is described by a function `source_region` that maps the coordinates of a single node to `true` or18`false` depending on whether the point lies within the coupling region or not. A weighting function19`weights` that maps coordinates to weights is applied to the acoustic source terms.20Note that this semidiscretization should be used in conjunction with21[`EulerAcousticsCouplingCallback`](@ref) and only works in two dimensions.22"""23struct SemidiscretizationEulerAcoustics{SemiAcoustics, SemiEuler, Cache} <:24AbstractSemidiscretization25semi_acoustics::SemiAcoustics26semi_euler::SemiEuler27performance_counter::PerformanceCounter28cache::Cache2930function SemidiscretizationEulerAcoustics{SemiAcoustics, SemiEuler, Cache}(semi_acoustics,31semi_euler,32cache) where {33SemiAcoustics,34SemiEuler,35Cache36}3738# Currently both semidiscretizations need to use a shared mesh39@assert semi_acoustics.mesh == semi_euler.mesh4041# Check if both solvers use the same polynomial basis42@assert semi_acoustics.solver.basis == semi_euler.solver.basis4344performance_counter = PerformanceCounter()45new(semi_acoustics, semi_euler, performance_counter, cache)46end47end4849function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics,50semi_euler::SemiEuler;51source_region = x -> true,52weights = x -> 1.0) where53{Mesh,54SemiAcoustics <:55SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations},56SemiEuler <:57SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}}58cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights,59mesh_equations_solver_cache(semi_acoustics)...)6061return SemidiscretizationEulerAcoustics{typeof(semi_acoustics), typeof(semi_euler),62typeof(cache)}(semi_acoustics, semi_euler,63cache)64end6566function create_cache(::Type{SemidiscretizationEulerAcoustics}, source_region, weights,67mesh, equations::AcousticPerturbationEquations2D, dg::DGSEM,68cache)69coupled_element_ids = get_coupled_element_ids(source_region, equations, dg, cache)7071acoustic_source_terms = zeros(eltype(cache.elements),72(ndims(equations), nnodes(dg), nnodes(dg),73length(coupled_element_ids)))7475acoustic_source_weights = precompute_weights(source_region, weights,76coupled_element_ids,77equations, dg, cache)7879return (; acoustic_source_terms, acoustic_source_weights, coupled_element_ids)80end8182function get_coupled_element_ids(source_region, equations, dg::DGSEM, cache)83coupled_element_ids = Vector{Int}(undef, 0)8485for element in eachelement(dg, cache)86for j in eachnode(dg), i in eachnode(dg)87x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,88element)89if source_region(x)90push!(coupled_element_ids, element)91break92end93end94end9596return coupled_element_ids97end9899function precompute_weights(source_region, weights, coupled_element_ids, equations,100dg::DGSEM, cache)101acoustic_source_weights = zeros(eltype(cache.elements),102(nnodes(dg), nnodes(dg),103length(coupled_element_ids)))104105@threaded for k in eachindex(coupled_element_ids)106element = coupled_element_ids[k]107for j in eachnode(dg), i in eachnode(dg)108x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,109element)110acoustic_source_weights[i, j, k] = source_region(x) ? weights(x) :111zero(weights(x))112end113end114115return acoustic_source_weights116end117118function Base.show(io::IO, semi::SemidiscretizationEulerAcoustics)119@nospecialize semi # reduce precompilation time120121print(io, "SemidiscretizationEulerAcoustics(")122print(io, semi.semi_acoustics)123print(io, ", ", semi.semi_euler)124print(io, ", cache(")125for (idx, key) in enumerate(keys(semi.cache))126idx > 1 && print(io, " ")127print(io, key)128end129print(io, "))")130end131132function Base.show(io::IO, mime::MIME"text/plain",133semi::SemidiscretizationEulerAcoustics)134@nospecialize semi # reduce precompilation time135136if get(io, :compact, false)137show(io, semi)138else139summary_header(io, "SemidiscretizationEulerAcoustics")140summary_line(io, "semidiscretization Euler",141semi.semi_euler |> typeof |> nameof)142show(increment_indent(io), mime, semi.semi_euler)143summary_line(io, "semidiscretization acoustics",144semi.semi_acoustics |> typeof |> nameof)145show(increment_indent(io), mime, semi.semi_acoustics)146summary_footer(io)147end148end149150# The acoustics semidiscretization is the main semidiscretization.151@inline function mesh_equations_solver_cache(semi::SemidiscretizationEulerAcoustics)152return mesh_equations_solver_cache(semi.semi_acoustics)153end154155@inline Base.ndims(semi::SemidiscretizationEulerAcoustics) = ndims(semi.semi_acoustics)156@inline Base.real(semi::SemidiscretizationEulerAcoustics) = real(semi.semi_acoustics)157158# Computes the coefficients of the initial condition159@inline function compute_coefficients(t, semi::SemidiscretizationEulerAcoustics)160compute_coefficients(t, semi.semi_acoustics)161end162163@inline function compute_coefficients!(u_ode, t, semi::SemidiscretizationEulerAcoustics)164compute_coefficients!(u_ode, t, semi.semi_acoustics)165end166167@inline function calc_error_norms(func, u, t, analyzer,168semi::SemidiscretizationEulerAcoustics,169cache_analysis)170calc_error_norms(func, u, t, analyzer, semi.semi_acoustics, cache_analysis)171end172173function rhs!(du_ode, u_ode, semi::SemidiscretizationEulerAcoustics, t)174@unpack semi_acoustics, cache = semi175@unpack acoustic_source_terms, acoustic_source_weights, coupled_element_ids = cache176177du_acoustics = wrap_array(du_ode, semi_acoustics)178179time_start = time_ns()180181@trixi_timeit timer() "acoustics rhs!" rhs!(du_ode, u_ode, semi_acoustics, t)182183@trixi_timeit timer() "add acoustic source terms" begin184add_acoustic_source_terms!(du_acoustics, acoustic_source_terms,185acoustic_source_weights, coupled_element_ids,186mesh_equations_solver_cache(semi_acoustics)...)187end188189runtime = time_ns() - time_start190put!(semi.performance_counter, runtime)191192return nothing193end194195function add_acoustic_source_terms!(du_acoustics, acoustic_source_terms, source_weights,196coupled_element_ids, mesh::TreeMesh{2}, equations,197dg::DGSEM,198cache)199@threaded for k in eachindex(coupled_element_ids)200element = coupled_element_ids[k]201202for j in eachnode(dg), i in eachnode(dg)203du_acoustics[1, i, j, element] += source_weights[i, j, k] *204acoustic_source_terms[1, i, j, k]205du_acoustics[2, i, j, element] += source_weights[i, j, k] *206acoustic_source_terms[2, i, j, k]207end208end209210return nothing211end212end # @muladd213214215