Path: blob/main/src/semidiscretization/semidiscretization_euler_acoustics.jl
5586 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::SemiEuler27cache::Cache28performance_counter::PerformanceCounter29end30# We assume some properties of the fields of the semidiscretization, e.g.,31# the `equations` and the `mesh` should have the same dimension. We check these32# properties in the outer constructor defined below. While we could ensure33# them even better in an inner constructor, we do not use this approach to34# simplify the integration with Adapt.jl for GPU usage, see35# https://github.com/trixi-framework/Trixi.jl/pull/2677#issuecomment-35917899213637function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics,38semi_euler::SemiEuler;39source_region = x -> true,40weights = x -> 1.0) where41{Mesh,42SemiAcoustics <:43SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations},44SemiEuler <:45SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}}46# Currently both semidiscretizations need to use a shared mesh47@assert semi_acoustics.mesh == semi_euler.mesh4849# Check if both solvers use the same polynomial basis50@assert semi_acoustics.solver.basis == semi_euler.solver.basis5152cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights,53mesh_equations_solver_cache(semi_acoustics)...)5455performance_counter = PerformanceCounter()5657return SemidiscretizationEulerAcoustics{typeof(semi_acoustics), typeof(semi_euler),58typeof(cache)}(semi_acoustics, semi_euler,59cache, performance_counter)60end6162function create_cache(::Type{SemidiscretizationEulerAcoustics}, source_region, weights,63mesh, equations::AcousticPerturbationEquations2D, dg::DGSEM,64cache)65coupled_element_ids = get_coupled_element_ids(source_region, equations, dg, cache)6667acoustic_source_terms = zeros(eltype(cache.elements),68(ndims(equations), nnodes(dg), nnodes(dg),69length(coupled_element_ids)))7071acoustic_source_weights = precompute_weights(source_region, weights,72coupled_element_ids,73equations, dg, cache)7475return (; acoustic_source_terms, acoustic_source_weights, coupled_element_ids)76end7778function get_coupled_element_ids(source_region, equations, dg::DGSEM, cache)79coupled_element_ids = Vector{Int}(undef, 0)8081for element in eachelement(dg, cache)82for j in eachnode(dg), i in eachnode(dg)83x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,84element)85if source_region(x)86push!(coupled_element_ids, element)87break88end89end90end9192return coupled_element_ids93end9495function precompute_weights(source_region, weights, coupled_element_ids, equations,96dg::DGSEM, cache)97acoustic_source_weights = zeros(eltype(cache.elements),98(nnodes(dg), nnodes(dg),99length(coupled_element_ids)))100101@threaded for k in eachindex(coupled_element_ids)102element = coupled_element_ids[k]103for j in eachnode(dg), i in eachnode(dg)104x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,105element)106acoustic_source_weights[i, j, k] = source_region(x) ? weights(x) :107zero(weights(x))108end109end110111return acoustic_source_weights112end113114function Base.show(io::IO, semi::SemidiscretizationEulerAcoustics)115@nospecialize semi # reduce precompilation time116117print(io, "SemidiscretizationEulerAcoustics(")118print(io, semi.semi_acoustics)119print(io, ", ", semi.semi_euler)120print(io, ", cache(")121for (idx, key) in enumerate(keys(semi.cache))122idx > 1 && print(io, " ")123print(io, key)124end125print(io, "))")126return nothing127end128129function Base.show(io::IO, mime::MIME"text/plain",130semi::SemidiscretizationEulerAcoustics)131@nospecialize semi # reduce precompilation time132133if get(io, :compact, false)134show(io, semi)135else136summary_header(io, "SemidiscretizationEulerAcoustics")137summary_line(io, "semidiscretization Euler",138semi.semi_euler |> typeof |> nameof)139show(increment_indent(io), mime, semi.semi_euler)140summary_line(io, "semidiscretization acoustics",141semi.semi_acoustics |> typeof |> nameof)142show(increment_indent(io), mime, semi.semi_acoustics)143summary_footer(io)144end145end146147# The acoustics semidiscretization is the main semidiscretization.148@inline function mesh_equations_solver_cache(semi::SemidiscretizationEulerAcoustics)149return mesh_equations_solver_cache(semi.semi_acoustics)150end151152@inline Base.ndims(semi::SemidiscretizationEulerAcoustics) = ndims(semi.semi_acoustics)153@inline Base.real(semi::SemidiscretizationEulerAcoustics) = real(semi.semi_acoustics)154155# Computes the coefficients of the initial condition156@inline function compute_coefficients(t, semi::SemidiscretizationEulerAcoustics)157return compute_coefficients(t, semi.semi_acoustics)158end159160@inline function compute_coefficients!(u_ode, t, semi::SemidiscretizationEulerAcoustics)161return compute_coefficients!(u_ode, t, semi.semi_acoustics)162end163164@inline function calc_error_norms(func, u, t, analyzer,165semi::SemidiscretizationEulerAcoustics,166cache_analysis)167return calc_error_norms(func, u, t, analyzer, semi.semi_acoustics, cache_analysis)168end169170function rhs!(du_ode, u_ode, semi::SemidiscretizationEulerAcoustics, t)171@unpack semi_acoustics, cache = semi172@unpack acoustic_source_terms, acoustic_source_weights, coupled_element_ids = cache173174du_acoustics = wrap_array(du_ode, semi_acoustics)175176time_start = time_ns()177178@trixi_timeit timer() "acoustics rhs!" rhs!(du_ode, u_ode, semi_acoustics, t)179180@trixi_timeit timer() "add acoustic source terms" begin181add_acoustic_source_terms!(du_acoustics, acoustic_source_terms,182acoustic_source_weights, coupled_element_ids,183mesh_equations_solver_cache(semi_acoustics)...)184end185186runtime = time_ns() - time_start187put!(semi.performance_counter, runtime)188189return nothing190end191192function add_acoustic_source_terms!(du_acoustics, acoustic_source_terms, source_weights,193coupled_element_ids, mesh::TreeMesh{2}, equations,194dg::DGSEM,195cache)196@threaded for k in eachindex(coupled_element_ids)197element = coupled_element_ids[k]198199for j in eachnode(dg), i in eachnode(dg)200du_acoustics[1, i, j, element] += source_weights[i, j, k] *201acoustic_source_terms[1, i, j, k]202du_acoustics[2, i, j, element] += source_weights[i, j, k] *203acoustic_source_terms[2, i, j, k]204end205end206207return nothing208end209end # @muladd210211212