Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/semidiscretization/semidiscretization_euler_acoustics.jl
5586 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
"""
9
SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics, semi_euler::SemiEuler;
10
source_region=x->true, weights=x->1.0)
11
12
!!! warning "Experimental code"
13
This semidiscretization is experimental and may change in any future release.
14
15
Construct a semidiscretization of the acoustic perturbation equations that is coupled with
16
the compressible Euler equations via source terms for the perturbed velocity. Both
17
semidiscretizations have to use the same mesh and solvers with a shared basis. The coupling region
18
is described by a function `source_region` that maps the coordinates of a single node to `true` or
19
`false` depending on whether the point lies within the coupling region or not. A weighting function
20
`weights` that maps coordinates to weights is applied to the acoustic source terms.
21
Note that this semidiscretization should be used in conjunction with
22
[`EulerAcousticsCouplingCallback`](@ref) and only works in two dimensions.
23
"""
24
struct SemidiscretizationEulerAcoustics{SemiAcoustics, SemiEuler, Cache} <:
25
AbstractSemidiscretization
26
semi_acoustics::SemiAcoustics
27
semi_euler::SemiEuler
28
cache::Cache
29
performance_counter::PerformanceCounter
30
end
31
# We assume some properties of the fields of the semidiscretization, e.g.,
32
# the `equations` and the `mesh` should have the same dimension. We check these
33
# properties in the outer constructor defined below. While we could ensure
34
# them even better in an inner constructor, we do not use this approach to
35
# simplify the integration with Adapt.jl for GPU usage, see
36
# https://github.com/trixi-framework/Trixi.jl/pull/2677#issuecomment-3591789921
37
38
function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics,
39
semi_euler::SemiEuler;
40
source_region = x -> true,
41
weights = x -> 1.0) where
42
{Mesh,
43
SemiAcoustics <:
44
SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations},
45
SemiEuler <:
46
SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}}
47
# Currently both semidiscretizations need to use a shared mesh
48
@assert semi_acoustics.mesh == semi_euler.mesh
49
50
# Check if both solvers use the same polynomial basis
51
@assert semi_acoustics.solver.basis == semi_euler.solver.basis
52
53
cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights,
54
mesh_equations_solver_cache(semi_acoustics)...)
55
56
performance_counter = PerformanceCounter()
57
58
return SemidiscretizationEulerAcoustics{typeof(semi_acoustics), typeof(semi_euler),
59
typeof(cache)}(semi_acoustics, semi_euler,
60
cache, performance_counter)
61
end
62
63
function create_cache(::Type{SemidiscretizationEulerAcoustics}, source_region, weights,
64
mesh, equations::AcousticPerturbationEquations2D, dg::DGSEM,
65
cache)
66
coupled_element_ids = get_coupled_element_ids(source_region, equations, dg, cache)
67
68
acoustic_source_terms = zeros(eltype(cache.elements),
69
(ndims(equations), nnodes(dg), nnodes(dg),
70
length(coupled_element_ids)))
71
72
acoustic_source_weights = precompute_weights(source_region, weights,
73
coupled_element_ids,
74
equations, dg, cache)
75
76
return (; acoustic_source_terms, acoustic_source_weights, coupled_element_ids)
77
end
78
79
function get_coupled_element_ids(source_region, equations, dg::DGSEM, cache)
80
coupled_element_ids = Vector{Int}(undef, 0)
81
82
for element in eachelement(dg, cache)
83
for j in eachnode(dg), i in eachnode(dg)
84
x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,
85
element)
86
if source_region(x)
87
push!(coupled_element_ids, element)
88
break
89
end
90
end
91
end
92
93
return coupled_element_ids
94
end
95
96
function precompute_weights(source_region, weights, coupled_element_ids, equations,
97
dg::DGSEM, cache)
98
acoustic_source_weights = zeros(eltype(cache.elements),
99
(nnodes(dg), nnodes(dg),
100
length(coupled_element_ids)))
101
102
@threaded for k in eachindex(coupled_element_ids)
103
element = coupled_element_ids[k]
104
for j in eachnode(dg), i in eachnode(dg)
105
x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,
106
element)
107
acoustic_source_weights[i, j, k] = source_region(x) ? weights(x) :
108
zero(weights(x))
109
end
110
end
111
112
return acoustic_source_weights
113
end
114
115
function Base.show(io::IO, semi::SemidiscretizationEulerAcoustics)
116
@nospecialize semi # reduce precompilation time
117
118
print(io, "SemidiscretizationEulerAcoustics(")
119
print(io, semi.semi_acoustics)
120
print(io, ", ", semi.semi_euler)
121
print(io, ", cache(")
122
for (idx, key) in enumerate(keys(semi.cache))
123
idx > 1 && print(io, " ")
124
print(io, key)
125
end
126
print(io, "))")
127
return nothing
128
end
129
130
function Base.show(io::IO, mime::MIME"text/plain",
131
semi::SemidiscretizationEulerAcoustics)
132
@nospecialize semi # reduce precompilation time
133
134
if get(io, :compact, false)
135
show(io, semi)
136
else
137
summary_header(io, "SemidiscretizationEulerAcoustics")
138
summary_line(io, "semidiscretization Euler",
139
semi.semi_euler |> typeof |> nameof)
140
show(increment_indent(io), mime, semi.semi_euler)
141
summary_line(io, "semidiscretization acoustics",
142
semi.semi_acoustics |> typeof |> nameof)
143
show(increment_indent(io), mime, semi.semi_acoustics)
144
summary_footer(io)
145
end
146
end
147
148
# The acoustics semidiscretization is the main semidiscretization.
149
@inline function mesh_equations_solver_cache(semi::SemidiscretizationEulerAcoustics)
150
return mesh_equations_solver_cache(semi.semi_acoustics)
151
end
152
153
@inline Base.ndims(semi::SemidiscretizationEulerAcoustics) = ndims(semi.semi_acoustics)
154
@inline Base.real(semi::SemidiscretizationEulerAcoustics) = real(semi.semi_acoustics)
155
156
# Computes the coefficients of the initial condition
157
@inline function compute_coefficients(t, semi::SemidiscretizationEulerAcoustics)
158
return compute_coefficients(t, semi.semi_acoustics)
159
end
160
161
@inline function compute_coefficients!(u_ode, t, semi::SemidiscretizationEulerAcoustics)
162
return compute_coefficients!(u_ode, t, semi.semi_acoustics)
163
end
164
165
@inline function calc_error_norms(func, u, t, analyzer,
166
semi::SemidiscretizationEulerAcoustics,
167
cache_analysis)
168
return calc_error_norms(func, u, t, analyzer, semi.semi_acoustics, cache_analysis)
169
end
170
171
function rhs!(du_ode, u_ode, semi::SemidiscretizationEulerAcoustics, t)
172
@unpack semi_acoustics, cache = semi
173
@unpack acoustic_source_terms, acoustic_source_weights, coupled_element_ids = cache
174
175
du_acoustics = wrap_array(du_ode, semi_acoustics)
176
177
time_start = time_ns()
178
179
@trixi_timeit timer() "acoustics rhs!" rhs!(du_ode, u_ode, semi_acoustics, t)
180
181
@trixi_timeit timer() "add acoustic source terms" begin
182
add_acoustic_source_terms!(du_acoustics, acoustic_source_terms,
183
acoustic_source_weights, coupled_element_ids,
184
mesh_equations_solver_cache(semi_acoustics)...)
185
end
186
187
runtime = time_ns() - time_start
188
put!(semi.performance_counter, runtime)
189
190
return nothing
191
end
192
193
function add_acoustic_source_terms!(du_acoustics, acoustic_source_terms, source_weights,
194
coupled_element_ids, mesh::TreeMesh{2}, equations,
195
dg::DGSEM,
196
cache)
197
@threaded for k in eachindex(coupled_element_ids)
198
element = coupled_element_ids[k]
199
200
for j in eachnode(dg), i in eachnode(dg)
201
du_acoustics[1, i, j, element] += source_weights[i, j, k] *
202
acoustic_source_terms[1, i, j, k]
203
du_acoustics[2, i, j, element] += source_weights[i, j, k] *
204
acoustic_source_terms[2, i, j, k]
205
end
206
end
207
208
return nothing
209
end
210
end # @muladd
211
212