-
Notifications
You must be signed in to change notification settings - Fork 106
/
euler_acoustics_coupling.jl
219 lines (184 loc) · 10.3 KB
/
euler_acoustics_coupling.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
# Since these FMAs can increase the performance of many numerical algorithms,
# we need to opt-in explicitly.
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
@muladd begin
#! format: noindent
@doc raw"""
EulerAcousticsCouplingCallback
!!! warning "Experimental code"
This callback is experimental and may change in any future release.
A callback that couples the acoustic perturbation equations and compressible Euler equations. Must
be used in conjunction with [`SemidiscretizationEulerAcoustics`](@ref).
This callback manages the flow solver - which is always one time step ahead of the
acoustics solver - and calculates the acoustic source term after each time step. The linearized
Lamb vector is used as the source term, i.e.
```math
\mathbf{s} = -(\mathbf{\omega'} \times \bar{\mathbf{v}}
+ \bar{\mathbf{\omega}} \times \mathbf{v'}),
```
where ``\mathbf{v}`` denotes the velocity, ``\mathbf{\omega}`` denotes the vorticity, the bar
``\bar{(\cdot)}`` indicates time-averaged quantities (see [`AveragingCallback`](@ref)) and prime
``(\cdot)'`` denotes perturbed quantities defined by ``\phi' = \phi - \bar{\phi}``. Note that
the perturbed quantities here are based entirely on the pure flow solution and should not be
confused with the state variables of the acoustic perturbation equations.
In addition, this callback manages the time step size for both solvers
and initializes the mean values of the acoustic perturbation equations using results obtained with
the [`AveragingCallback`](@ref).
- Michael Schlottke-Lakemper (2017)
A direct-hybrid method for aeroacoustic analysis
[DOI: 10.18154/RWTH-2017-04082](https://doi.org/10.18154/RWTH-2017-04082)
"""
mutable struct EulerAcousticsCouplingCallback{RealT <: Real, MeanValues,
IntegratorEuler}
stepsize_callback_acoustics::StepsizeCallback{RealT}
stepsize_callback_euler::StepsizeCallback{RealT}
mean_values::MeanValues
integrator_euler::IntegratorEuler
end
function Base.show(io::IO,
cb::DiscreteCallback{<:Any, <:EulerAcousticsCouplingCallback})
@nospecialize cb # reduce precompilation time
euler_acoustics_coupling = cb.affect!
print(io, "EulerAcousticsCouplingCallback(")
print(io, euler_acoustics_coupling.stepsize_callback_acoustics)
print(io, ", ", euler_acoustics_coupling.stepsize_callback_euler, ")")
end
function Base.show(io::IO, ::MIME"text/plain",
cb::DiscreteCallback{<:Any, <:EulerAcousticsCouplingCallback})
@nospecialize cb # reduce precompilation time
euler_acoustics_coupling = cb.affect!
summary_header(io, "EulerAcousticsCouplingCallback")
summary_line(io, "acoustics StepsizeCallback",
euler_acoustics_coupling.stepsize_callback_acoustics)
summary_line(io, "Euler StepsizeCallback",
euler_acoustics_coupling.stepsize_callback_euler)
summary_footer(io)
end
"""
EulerAcousticsCouplingCallback(ode_euler,
averaging_callback::DiscreteCallback{<:Any, <:AveragingCallback},
alg, cfl_acoustics::Real, cfl_euler::Real; kwargs...)
!!! warning "Experimental code"
This callback is experimental and may change in any future release.
Creates an [`EulerAcousticsCouplingCallback`](@ref) based on the pure flow `ODEProblem` given by
`ode_euler`. Creates an integrator using the time integration method `alg` and the keyword arguments
to solve `ode_euler` (consult the [OrdinaryDiffEq documentation](https://diffeq.sciml.ai/stable/)
for further information).
Manages the step size for both solvers by using the minimum of the maximum step size obtained with
CFL numbers `cfl_acoustics` for the acoustics solver and `cfl_euler` for and flow solver,
respectively.
The mean values for the acoustic perturbation equations are read from `averaging_callback`
(see [`AveragingCallback`](@ref)).
"""
function EulerAcousticsCouplingCallback(ode_euler,
averaging_callback::DiscreteCallback{<:Any,
<:AveragingCallback},
alg, cfl_acoustics::Real, cfl_euler::Real;
kwargs...)
@unpack mean_values = averaging_callback.affect!
return EulerAcousticsCouplingCallback(ode_euler, mean_values, alg, cfl_acoustics,
cfl_euler;
kwargs...)
end
"""
EulerAcousticsCouplingCallback(ode_euler, averaging_file::AbstractString, alg,
cfl_acoustics::Real, cfl_euler::Real; kwargs...)
!!! warning "Experimental code"
This callback is experimental and may change in any future release.
Creates an [`EulerAcousticsCouplingCallback`](@ref) based on the pure flow `ODEProblem` given by
`ode_euler`. Creates an integrator using the time integration method `alg` and the keyword arguments
to solve `ode_euler` (consult the [OrdinaryDiffEq documentation](https://diffeq.sciml.ai/stable/)
for further information).
Manages the step size for both solvers by using the minimum of the maximum step size obtained with
CFL numbers `cfl_acoustics` for the acoustics solver and `cfl_euler` for and flow solver,
respectively.
The mean values for the acoustic perturbation equations are read from `averaging_file`
(see [`AveragingCallback`](@ref)).
"""
function EulerAcousticsCouplingCallback(ode_euler, averaging_file::AbstractString, alg,
cfl_acoustics::Real, cfl_euler::Real; kwargs...)
semi_euler = ode_euler.p
mean_values = load_averaging_file(averaging_file, semi_euler)
return EulerAcousticsCouplingCallback(ode_euler, mean_values, alg, cfl_acoustics,
cfl_euler;
kwargs...)
end
function EulerAcousticsCouplingCallback(ode_euler, mean_values, alg, cfl_acoustics,
cfl_euler;
kwargs...)
# Set up ODE Integrator for Euler equations
integrator_euler = init(ode_euler, alg, save_everystep = false, dt = 1.0; kwargs...) # dt will be overwritten
euler_acoustics_coupling = EulerAcousticsCouplingCallback{typeof(cfl_acoustics),
typeof(mean_values),
typeof(integrator_euler)}(StepsizeCallback(cfl_acoustics),
StepsizeCallback(cfl_euler),
mean_values,
integrator_euler)
condition = (u, t, integrator) -> true
return DiscreteCallback(condition, euler_acoustics_coupling,
save_positions = (false, false),
initialize = initialize!)
end
# This is called before the main loop and initializes the mean values in u_ode
function initialize!(cb::DiscreteCallback{Condition, Affect!}, u_ode, t,
integrator_acoustics) where {Condition,
Affect! <:
EulerAcousticsCouplingCallback}
euler_acoustics_coupling = cb.affect!
semi = integrator_acoustics.p
@unpack semi_acoustics = semi
# Initialize mean values in u_ode
u_acoustics = wrap_array(u_ode, semi_acoustics)
@unpack mean_values = euler_acoustics_coupling
@views @. u_acoustics[4:5, .., :] = mean_values.v_mean
@views @. u_acoustics[6, .., :] = mean_values.c_mean
@views @. u_acoustics[7, .., :] = mean_values.rho_mean
# Adjust stepsize, advance the flow solver by one time step
cb.affect!(integrator_acoustics)
return nothing
end
# This function is called at the end of every time step and advances the Euler solution by one
# time step, manages the time stepsize for both the acoustics and Euler solvers and calculates the
# acoustic sources for the next acoustics time step
function (euler_acoustics_coupling::EulerAcousticsCouplingCallback)(integrator_acoustics)
@unpack stepsize_callback_acoustics, stepsize_callback_euler, integrator_euler = euler_acoustics_coupling
@assert integrator_acoustics.t == integrator_euler.t
# Use the minimum of the acoustics and Euler stepsizes for both solvers
stepsize_callback_acoustics(integrator_acoustics)
stepsize_callback_euler(integrator_euler)
dt = min(get_proposed_dt(integrator_acoustics), get_proposed_dt(integrator_euler))
set_proposed_dt!(integrator_acoustics, dt)
integrator_acoustics.opts.dtmax = dt
integrator_acoustics.dtcache = dt
set_proposed_dt!(integrator_euler, dt)
integrator_euler.opts.dtmax = dt
integrator_euler.dtcache = dt
# Advance the Euler solution by one step and check for errors
if !isfinished(integrator_euler)
@trixi_timeit timer() "Euler solver" step!(integrator_euler)
return_code = check_error(integrator_euler)
if !(SciMLBase.successful_retcode(return_code) ||
return_code != SciMLBase.ReturnCode.Default)
error("Error during compressible Euler time integration. Received return code $(return_code)")
end
end
# Calculate acoustic sources based on linearized lamb vector
semi = integrator_acoustics.p
semi_euler = integrator_euler.p
u_acoustics = wrap_array(integrator_acoustics.u, semi)
u_euler = wrap_array(integrator_euler.u, semi_euler)
@unpack acoustic_source_terms, coupled_element_ids = semi.cache
@unpack vorticity_mean = euler_acoustics_coupling.mean_values
@trixi_timeit timer() "calc acoustic source terms" begin
calc_acoustic_sources!(acoustic_source_terms, u_euler, u_acoustics,
vorticity_mean, coupled_element_ids,
mesh_equations_solver_cache(semi_euler)...)
end
# avoid re-evaluation possible FSAL stages
u_modified!(integrator_acoustics, false)
u_modified!(integrator_euler, false)
return nothing
end
include("euler_acoustics_coupling_dg2d.jl")
end # @muladd