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
2055 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
performance_counter::PerformanceCounter
29
cache::Cache
30
31
function SemidiscretizationEulerAcoustics{SemiAcoustics, SemiEuler, Cache}(semi_acoustics,
32
semi_euler,
33
cache) where {
34
SemiAcoustics,
35
SemiEuler,
36
Cache
37
}
38
39
# Currently both semidiscretizations need to use a shared mesh
40
@assert semi_acoustics.mesh == semi_euler.mesh
41
42
# Check if both solvers use the same polynomial basis
43
@assert semi_acoustics.solver.basis == semi_euler.solver.basis
44
45
performance_counter = PerformanceCounter()
46
new(semi_acoustics, semi_euler, performance_counter, cache)
47
end
48
end
49
50
function SemidiscretizationEulerAcoustics(semi_acoustics::SemiAcoustics,
51
semi_euler::SemiEuler;
52
source_region = x -> true,
53
weights = x -> 1.0) where
54
{Mesh,
55
SemiAcoustics <:
56
SemidiscretizationHyperbolic{Mesh, <:AbstractAcousticPerturbationEquations},
57
SemiEuler <:
58
SemidiscretizationHyperbolic{Mesh, <:AbstractCompressibleEulerEquations}}
59
cache = create_cache(SemidiscretizationEulerAcoustics, source_region, weights,
60
mesh_equations_solver_cache(semi_acoustics)...)
61
62
return SemidiscretizationEulerAcoustics{typeof(semi_acoustics), typeof(semi_euler),
63
typeof(cache)}(semi_acoustics, semi_euler,
64
cache)
65
end
66
67
function create_cache(::Type{SemidiscretizationEulerAcoustics}, source_region, weights,
68
mesh, equations::AcousticPerturbationEquations2D, dg::DGSEM,
69
cache)
70
coupled_element_ids = get_coupled_element_ids(source_region, equations, dg, cache)
71
72
acoustic_source_terms = zeros(eltype(cache.elements),
73
(ndims(equations), nnodes(dg), nnodes(dg),
74
length(coupled_element_ids)))
75
76
acoustic_source_weights = precompute_weights(source_region, weights,
77
coupled_element_ids,
78
equations, dg, cache)
79
80
return (; acoustic_source_terms, acoustic_source_weights, coupled_element_ids)
81
end
82
83
function get_coupled_element_ids(source_region, equations, dg::DGSEM, cache)
84
coupled_element_ids = Vector{Int}(undef, 0)
85
86
for element in eachelement(dg, cache)
87
for j in eachnode(dg), i in eachnode(dg)
88
x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,
89
element)
90
if source_region(x)
91
push!(coupled_element_ids, element)
92
break
93
end
94
end
95
end
96
97
return coupled_element_ids
98
end
99
100
function precompute_weights(source_region, weights, coupled_element_ids, equations,
101
dg::DGSEM, cache)
102
acoustic_source_weights = zeros(eltype(cache.elements),
103
(nnodes(dg), nnodes(dg),
104
length(coupled_element_ids)))
105
106
@threaded for k in eachindex(coupled_element_ids)
107
element = coupled_element_ids[k]
108
for j in eachnode(dg), i in eachnode(dg)
109
x = get_node_coords(cache.elements.node_coordinates, equations, dg, i, j,
110
element)
111
acoustic_source_weights[i, j, k] = source_region(x) ? weights(x) :
112
zero(weights(x))
113
end
114
end
115
116
return acoustic_source_weights
117
end
118
119
function Base.show(io::IO, semi::SemidiscretizationEulerAcoustics)
120
@nospecialize semi # reduce precompilation time
121
122
print(io, "SemidiscretizationEulerAcoustics(")
123
print(io, semi.semi_acoustics)
124
print(io, ", ", semi.semi_euler)
125
print(io, ", cache(")
126
for (idx, key) in enumerate(keys(semi.cache))
127
idx > 1 && print(io, " ")
128
print(io, key)
129
end
130
print(io, "))")
131
end
132
133
function Base.show(io::IO, mime::MIME"text/plain",
134
semi::SemidiscretizationEulerAcoustics)
135
@nospecialize semi # reduce precompilation time
136
137
if get(io, :compact, false)
138
show(io, semi)
139
else
140
summary_header(io, "SemidiscretizationEulerAcoustics")
141
summary_line(io, "semidiscretization Euler",
142
semi.semi_euler |> typeof |> nameof)
143
show(increment_indent(io), mime, semi.semi_euler)
144
summary_line(io, "semidiscretization acoustics",
145
semi.semi_acoustics |> typeof |> nameof)
146
show(increment_indent(io), mime, semi.semi_acoustics)
147
summary_footer(io)
148
end
149
end
150
151
# The acoustics semidiscretization is the main semidiscretization.
152
@inline function mesh_equations_solver_cache(semi::SemidiscretizationEulerAcoustics)
153
return mesh_equations_solver_cache(semi.semi_acoustics)
154
end
155
156
@inline Base.ndims(semi::SemidiscretizationEulerAcoustics) = ndims(semi.semi_acoustics)
157
@inline Base.real(semi::SemidiscretizationEulerAcoustics) = real(semi.semi_acoustics)
158
159
# Computes the coefficients of the initial condition
160
@inline function compute_coefficients(t, semi::SemidiscretizationEulerAcoustics)
161
compute_coefficients(t, semi.semi_acoustics)
162
end
163
164
@inline function compute_coefficients!(u_ode, t, semi::SemidiscretizationEulerAcoustics)
165
compute_coefficients!(u_ode, t, semi.semi_acoustics)
166
end
167
168
@inline function calc_error_norms(func, u, t, analyzer,
169
semi::SemidiscretizationEulerAcoustics,
170
cache_analysis)
171
calc_error_norms(func, u, t, analyzer, semi.semi_acoustics, cache_analysis)
172
end
173
174
function rhs!(du_ode, u_ode, semi::SemidiscretizationEulerAcoustics, t)
175
@unpack semi_acoustics, cache = semi
176
@unpack acoustic_source_terms, acoustic_source_weights, coupled_element_ids = cache
177
178
du_acoustics = wrap_array(du_ode, semi_acoustics)
179
180
time_start = time_ns()
181
182
@trixi_timeit timer() "acoustics rhs!" rhs!(du_ode, u_ode, semi_acoustics, t)
183
184
@trixi_timeit timer() "add acoustic source terms" begin
185
add_acoustic_source_terms!(du_acoustics, acoustic_source_terms,
186
acoustic_source_weights, coupled_element_ids,
187
mesh_equations_solver_cache(semi_acoustics)...)
188
end
189
190
runtime = time_ns() - time_start
191
put!(semi.performance_counter, runtime)
192
193
return nothing
194
end
195
196
function add_acoustic_source_terms!(du_acoustics, acoustic_source_terms, source_weights,
197
coupled_element_ids, mesh::TreeMesh{2}, equations,
198
dg::DGSEM,
199
cache)
200
@threaded for k in eachindex(coupled_element_ids)
201
element = coupled_element_ids[k]
202
203
for j in eachnode(dg), i in eachnode(dg)
204
du_acoustics[1, i, j, element] += source_weights[i, j, k] *
205
acoustic_source_terms[1, i, j, k]
206
du_acoustics[2, i, j, element] += source_weights[i, j, k] *
207
acoustic_source_terms[2, i, j, k]
208
end
209
end
210
211
return nothing
212
end
213
end # @muladd
214
215