Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/solvers/dgsem/calc_volume_integral.jl
5591 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
# The following `volume_integral_kernel!` and `calc_volume_integral!` functions are
9
# dimension and meshtype agnostic, i.e., valid for all 1D, 2D, and 3D meshes.
10
11
@inline function volume_integral_kernel!(du, u, element, MeshT,
12
have_nonconservative_terms, equations,
13
volume_integral::VolumeIntegralWeakForm,
14
dg, cache, alpha = true)
15
weak_form_kernel!(du, u, element, MeshT,
16
have_nonconservative_terms, equations,
17
dg, cache, alpha)
18
19
return nothing
20
end
21
22
@inline function volume_integral_kernel!(du, u, element, MeshT,
23
have_nonconservative_terms, equations,
24
volume_integral::VolumeIntegralFluxDifferencing,
25
dg, cache, alpha = true)
26
@unpack volume_flux = volume_integral # Volume integral specific data
27
28
flux_differencing_kernel!(du, u, element, MeshT,
29
have_nonconservative_terms, equations,
30
volume_flux, dg, cache, alpha)
31
32
return nothing
33
end
34
35
@inline function volume_integral_kernel!(du, u, element, MeshT,
36
have_nonconservative_terms, equations,
37
volume_integral::VolumeIntegralPureLGLFiniteVolume,
38
dg::DGSEM, cache, alpha = true)
39
@unpack volume_flux_fv = volume_integral # Volume integral specific data
40
41
fv_kernel!(du, u, MeshT,
42
have_nonconservative_terms, equations,
43
volume_flux_fv, dg, cache, element, alpha)
44
45
return nothing
46
end
47
48
@inline function volume_integral_kernel!(du, u, element, MeshT,
49
have_nonconservative_terms, equations,
50
volume_integral::VolumeIntegralPureLGLFiniteVolumeO2,
51
dg::DGSEM, cache, alpha = true)
52
# Unpack volume integral specific data
53
@unpack (sc_interface_coords, volume_flux_fv, reconstruction_mode, slope_limiter,
54
cons2recon, recon2cons) = volume_integral
55
56
fvO2_kernel!(du, u, MeshT,
57
have_nonconservative_terms, equations,
58
volume_flux_fv, dg, cache, element,
59
sc_interface_coords, reconstruction_mode, slope_limiter,
60
cons2recon, recon2cons,
61
alpha)
62
63
return nothing
64
end
65
66
@inline function volume_integral_kernel!(du, u, element, MeshT,
67
have_nonconservative_terms, equations,
68
volume_integral::VolumeIntegralAdaptive{<:IndicatorEntropyChange},
69
dg::DGSEM, cache)
70
@unpack volume_integral_default, volume_integral_stabilized, indicator = volume_integral
71
@unpack maximum_entropy_increase = indicator
72
73
volume_integral_kernel!(du, u, element, MeshT,
74
have_nonconservative_terms, equations,
75
volume_integral_default, dg, cache)
76
77
# Compute entropy production of the default volume integral.
78
# Minus sign because of the flipped sign of the volume term in the DG RHS.
79
# No scaling by inverse Jacobian here, as there is no Jacobian multiplication
80
# in `integrate_reference_element`.
81
dS_default = -entropy_change_reference_element(du, u, element,
82
MeshT, equations, dg, cache)
83
84
# Compute true entropy change given by surface integral of the entropy potential
85
dS_true = surface_integral_reference_element(entropy_potential, u, element,
86
MeshT, equations, dg, cache)
87
88
entropy_change = dS_default - dS_true
89
if entropy_change > maximum_entropy_increase # Recompute using EC FD volume integral
90
# Reset default volume integral contribution.
91
# Note that this assumes that the volume terms are computed first,
92
# before any surface terms are added.
93
du[.., element] .= zero(eltype(du))
94
95
volume_integral_kernel!(du, u, element, MeshT,
96
have_nonconservative_terms, equations,
97
volume_integral_stabilized, dg, cache)
98
end
99
100
return nothing
101
end
102
103
@inline function volume_integral_kernel!(du, u, element, MeshT,
104
have_nonconservative_terms, equations,
105
volume_integral::VolumeIntegralEntropyCorrection,
106
dg::DGSEM, cache)
107
@unpack volume_integral_default, volume_integral_stabilized, indicator = volume_integral
108
@unpack scaling = indicator
109
@unpack alpha = indicator.cache
110
du_element_threaded = indicator.cache.volume_integral_values_threaded
111
112
# run default volume integral
113
volume_integral_kernel!(du, u, element, MeshT,
114
have_nonconservative_terms, equations,
115
volume_integral_default, dg, cache)
116
117
# Check entropy production of "high order" volume integral.
118
#
119
# Note that, for `TreeMesh`, `dS_volume_integral` and `dS_true` are calculated
120
# on the reference element. For other mesh types, because ``dS_volume_integral`
121
# incorporates the scaled contravariant vectors, `dS_true` should
122
# be calculated on the physical element instead.
123
#
124
# Minus sign because of the flipped sign of the volume term in the DG RHS.
125
# No scaling by inverse Jacobian here, as there is no Jacobian multiplication
126
# in `integrate_reference_element`.
127
dS_volume_integral = -entropy_change_reference_element(du, u, element,
128
MeshT, equations,
129
dg, cache)
130
131
# Compute true entropy change given by surface integral of the entropy potential
132
dS_true = surface_integral_reference_element(entropy_potential, u, element,
133
MeshT, equations, dg, cache)
134
135
# This quantity should be ≤ 0 for an entropy stable volume integral, and
136
# exactly zero for an entropy conservative volume integral.
137
entropy_residual = dS_volume_integral - dS_true
138
139
if entropy_residual > 0
140
# Store "high order" result
141
du_FD_element = du_element_threaded[Threads.threadid()]
142
@views du_FD_element .= du[.., element]
143
144
# Reset pure flux-differencing volume integral
145
# Note that this assumes that the volume terms are computed first,
146
# before any surface terms are added.
147
du[.., element] .= zero(eltype(du))
148
149
# Calculate entropy stable volume integral contribution
150
volume_integral_kernel!(du, u, element, MeshT,
151
have_nonconservative_terms, equations,
152
volume_integral_stabilized, dg, cache)
153
154
dS_volume_integral_stabilized = -entropy_change_reference_element(du, u,
155
element,
156
MeshT,
157
equations, dg,
158
cache)
159
160
# Calculate difference between high and low order FV entropy production;
161
# this should provide positive entropy dissipation if `entropy_residual > 0`,
162
# assuming the stabilized volume integral is entropy stable.
163
entropy_dissipation = dS_volume_integral_stabilized - dS_volume_integral
164
165
# Calculate DG-FV blending factor
166
ratio = regularized_ratio(-entropy_residual, entropy_dissipation)
167
alpha_element = min(1, scaling * ratio) # TODO: replacing this with a differentiable version of `min`
168
169
# Save blending coefficient for visualization
170
alpha[element] = alpha_element
171
172
# Blend the high order method back in
173
@views du[.., element] .= alpha_element .* du[.., element] .+
174
(1 - alpha_element) .* du_FD_element
175
end
176
177
return nothing
178
end
179
180
function calc_volume_integral!(backend::Nothing, du, u, mesh,
181
have_nonconservative_terms, equations,
182
volume_integral, dg::DGSEM, cache)
183
@threaded for element in eachelement(dg, cache)
184
volume_integral_kernel!(du, u, element, typeof(mesh),
185
have_nonconservative_terms, equations,
186
volume_integral, dg, cache)
187
end
188
189
return nothing
190
end
191
192
function calc_volume_integral!(backend::Backend, du, u, mesh,
193
have_nonconservative_terms, equations,
194
volume_integral, dg::DGSEM, cache)
195
nelements(dg, cache) == 0 && return nothing
196
kernel! = volume_integral_KAkernel!(backend)
197
kernel_cache = kernel_filter_cache(cache)
198
kernel!(du, u, typeof(mesh), have_nonconservative_terms, equations,
199
volume_integral, dg, kernel_cache,
200
ndrange = nelements(dg, cache))
201
return nothing
202
end
203
204
@kernel function volume_integral_KAkernel!(du, u, MeshT,
205
have_nonconservative_terms, equations,
206
volume_integral, dg::DGSEM, cache)
207
element = @index(Global)
208
volume_integral_kernel!(du, u, element, MeshT, have_nonconservative_terms,
209
equations, volume_integral, dg, cache)
210
end
211
212
@inline function calc_volume_integral!(backend::Nothing, du, u, mesh,
213
have_nonconservative_terms, equations,
214
volume_integral::VolumeIntegralAdaptive{<:IndicatorHennemannGassner},
215
dg::DGSEM, cache)
216
@unpack volume_integral_default, volume_integral_stabilized, indicator = volume_integral
217
218
# Calculate a-priori stabilization indicator
219
alpha = @trixi_timeit timer() "indicator" indicator(u, mesh, equations,
220
dg, cache)
221
222
# For `Float64`, this gives 1.8189894035458565e-12
223
# For `Float32`, this gives 1.1920929f-5
224
RealT = eltype(alpha)
225
atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0))
226
@threaded for element in eachelement(dg, cache)
227
alpha_element = alpha[element]
228
# Clip blending factor for values close to zero (-> default volume integral)
229
default_volume_integral = isapprox(alpha_element, 0, atol = atol)
230
231
if default_volume_integral
232
volume_integral_kernel!(du, u, element, typeof(mesh),
233
have_nonconservative_terms, equations,
234
volume_integral_default, dg, cache)
235
else
236
volume_integral_kernel!(du, u, element, typeof(mesh),
237
have_nonconservative_terms, equations,
238
volume_integral_stabilized, dg, cache)
239
end
240
end
241
242
return nothing
243
end
244
245
function calc_volume_integral!(backend::Nothing, du, u, mesh,
246
have_nonconservative_terms, equations,
247
volume_integral::VolumeIntegralShockCapturingHGType,
248
dg::DGSEM, cache)
249
@unpack (indicator, volume_integral_default,
250
volume_integral_blend_high_order, volume_integral_blend_low_order) = volume_integral
251
252
# Calculate DG-FV blending factors α a-priori for: u_{DG-FV} = u_DG * (1 - α) + u_FV * α
253
alpha = @trixi_timeit timer() "blending factors" indicator(u, mesh, equations,
254
dg, cache)
255
256
# For `Float64`, this gives 1.8189894035458565e-12
257
# For `Float32`, this gives 1.1920929f-5
258
RealT = eltype(alpha)
259
atol = max(100 * eps(RealT), eps(RealT)^convert(RealT, 0.75f0))
260
@threaded for element in eachelement(dg, cache)
261
alpha_element = alpha[element]
262
# Clip blending factor for values close to zero (-> pure DG)
263
dg_only = isapprox(alpha_element, 0, atol = atol)
264
265
if dg_only
266
volume_integral_kernel!(du, u, element, typeof(mesh),
267
have_nonconservative_terms, equations,
268
volume_integral_default, dg, cache)
269
else
270
# Calculate DG volume integral contribution
271
volume_integral_kernel!(du, u, element, typeof(mesh),
272
have_nonconservative_terms, equations,
273
volume_integral_blend_high_order, dg, cache,
274
1 - alpha_element)
275
276
# Calculate FV volume integral contribution
277
volume_integral_kernel!(du, u, element, typeof(mesh),
278
have_nonconservative_terms, equations,
279
volume_integral_blend_low_order, dg, cache,
280
alpha_element)
281
end
282
end
283
284
return nothing
285
end
286
287
function calc_volume_integral!(backend::Nothing, du, u, mesh,
288
have_nonconservative_terms, equations,
289
volume_integral::VolumeIntegralEntropyCorrectionShockCapturingCombined,
290
dg::DGSEM, cache)
291
(; volume_integral_default, volume_integral_stabilized, indicator) = volume_integral
292
(; indicator_entropy_correction, indicator_shock_capturing) = indicator
293
(; scaling) = indicator_entropy_correction
294
du_element_threaded = indicator_entropy_correction.cache.volume_integral_values_threaded
295
296
# Calculate DG-FV blending factors α a-priori for: u_{DG-FV} = u_DG * (1 - α) + u_FV * α
297
# Note that we also reuse the `alpha_shock_capturing` array to store the indicator values for visualization.
298
alpha_shock_capturing = @trixi_timeit timer() "blending factors" indicator_shock_capturing(u,
299
mesh,
300
equations,
301
dg,
302
cache)
303
304
@threaded for element in eachelement(dg, cache)
305
# run default volume integral
306
volume_integral_kernel!(du, u, element, typeof(mesh),
307
have_nonconservative_terms, equations,
308
volume_integral_default, dg, cache)
309
310
# Check entropy production of "high order" volume integral.
311
#
312
# Note that, for `TreeMesh`, both volume and surface integrals are calculated
313
# on the reference element. For other mesh types, because the volume integral
314
# incorporates the scaled contravariant vectors, the surface integral should
315
# be calculated on the physical element instead.
316
#
317
# Minus sign because of the flipped sign of the volume term in the DG RHS.
318
# No scaling by inverse Jacobian here, as there is no Jacobian multiplication
319
# in `integrate_reference_element`.
320
dS_volume_integral = -entropy_change_reference_element(du, u, element,
321
typeof(mesh), equations,
322
dg, cache)
323
324
# Compute true entropy change given by surface integral of the entropy potential
325
dS_true = surface_integral_reference_element(entropy_potential, u, element,
326
typeof(mesh), equations, dg, cache)
327
328
# This quantity should be ≤ 0 for an entropy stable volume integral, and
329
# exactly zero for an entropy conservative volume integral.
330
entropy_residual = dS_volume_integral - dS_true
331
332
if entropy_residual > 0
333
# Store "high order" result
334
du_FD_element = du_element_threaded[Threads.threadid()]
335
@views du_FD_element .= du[.., element]
336
337
# Reset pure flux-differencing volume integral
338
# Note that this assumes that the volume terms are computed first,
339
# before any surface terms are added.
340
du[.., element] .= zero(eltype(du))
341
342
# Calculate entropy stable volume integral contribution
343
volume_integral_kernel!(du, u, element, typeof(mesh),
344
have_nonconservative_terms, equations,
345
volume_integral_stabilized, dg, cache)
346
347
dS_volume_integral_stabilized = -entropy_change_reference_element(du, u,
348
element,
349
typeof(mesh),
350
equations,
351
dg,
352
cache)
353
354
# Calculate difference between high and low order FV entropy production;
355
# this should provide positive entropy dissipation if `entropy_residual > 0`,
356
# assuming the stabilized volume integral is entropy stable.
357
entropy_dissipation = dS_volume_integral_stabilized - dS_volume_integral
358
359
# Calculate DG-FV blending factor as the minimum between the entropy correction
360
# indicator and shock capturing indicator
361
# TODO: replacing this with a differentiable version of `min`
362
ratio = regularized_ratio(-entropy_residual, entropy_dissipation)
363
alpha_element = min(1, max(alpha_shock_capturing[element], scaling * ratio))
364
365
# Save blending coefficient for visualization. Note that we overwrite the data
366
# in `alpha_shock_capturing[element]`.
367
alpha_shock_capturing[element] = alpha_element
368
369
# Blend the high order method back in
370
@views du[.., element] .= alpha_element .* du[.., element] .+
371
(1 - alpha_element) .* du_FD_element
372
end
373
end
374
375
return nothing
376
end
377
end # @muladd
378
379