Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/solvers/dgsem_p4est/dg_3d_subcell_limiters.jl
5616 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
# Calculate the DG staggered volume fluxes `fhat` in subcell FV-form inside the element
9
# (**without non-conservative terms**).
10
#
11
# See also `flux_differencing_kernel!`.
12
@inline function calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, fhat3_L, fhat3_R,
13
u, ::Type{<:P4estMesh{3}},
14
nonconservative_terms::False, equations,
15
volume_flux, dg::DGSEM, element, cache)
16
(; contravariant_vectors) = cache.elements
17
(; weights, derivative_split) = dg.basis
18
(; flux_temp_threaded) = cache
19
20
flux_temp = flux_temp_threaded[Threads.threadid()]
21
22
# The FV-form fluxes are calculated in a recursive manner, i.e.:
23
# fhat_(0,1) = w_0 * FVol_0,
24
# fhat_(j,j+1) = fhat_(j-1,j) + w_j * FVol_j, for j=1,...,N-1,
25
# with the split form volume fluxes FVol_j = -2 * sum_i=0^N D_ji f*_(j,i).
26
27
# To use the symmetry of the `volume_flux`, the split form volume flux is precalculated
28
# like in `calc_volume_integral!` for the `VolumeIntegralFluxDifferencing`
29
# and saved in in `flux_temp`.
30
31
# Split form volume flux in orientation 1: x direction
32
flux_temp .= zero(eltype(flux_temp))
33
34
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
35
u_node = get_node_vars(u, equations, dg, i, j, k, element)
36
37
# pull the contravariant vectors in each coordinate direction
38
Ja1_node = get_contravariant_vector(1, contravariant_vectors,
39
i, j, k, element) # x direction
40
41
# All diagonal entries of `derivative_split` are zero. Thus, we can skip
42
# the computation of the diagonal terms. In addition, we use the symmetry
43
# of the `volume_flux` to save half of the possible two-point flux
44
# computations.
45
46
# x direction
47
for ii in (i + 1):nnodes(dg)
48
u_node_ii = get_node_vars(u, equations, dg, ii, j, k, element)
49
# pull the contravariant vectors and compute the average
50
Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors,
51
ii, j, k, element)
52
Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii)
53
54
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
55
fluxtilde1 = volume_flux(u_node, u_node_ii, Ja1_avg, equations)
56
multiply_add_to_node_vars!(flux_temp, derivative_split[i, ii], fluxtilde1,
57
equations, dg, i, j, k)
58
multiply_add_to_node_vars!(flux_temp, derivative_split[ii, i], fluxtilde1,
59
equations, dg, ii, j, k)
60
end
61
end
62
63
# FV-form flux `fhat` in x direction
64
for k in eachnode(dg), j in eachnode(dg), i in 1:(nnodes(dg) - 1)
65
for v in eachvariable(equations)
66
fhat1_L[v, i + 1, j, k] = fhat1_L[v, i, j, k] +
67
weights[i] * flux_temp[v, i, j, k]
68
fhat1_R[v, i + 1, j, k] = fhat1_L[v, i + 1, j, k]
69
end
70
end
71
72
# Split form volume flux in orientation 2: y direction
73
flux_temp .= zero(eltype(flux_temp))
74
75
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
76
u_node = get_node_vars(u, equations, dg, i, j, k, element)
77
78
# pull the contravariant vectors in each coordinate direction
79
Ja2_node = get_contravariant_vector(2, contravariant_vectors,
80
i, j, k, element)
81
82
# y direction
83
for jj in (j + 1):nnodes(dg)
84
u_node_jj = get_node_vars(u, equations, dg, i, jj, k, element)
85
# pull the contravariant vectors and compute the average
86
Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors,
87
i, jj, k, element)
88
Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj)
89
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
90
fluxtilde2 = volume_flux(u_node, u_node_jj, Ja2_avg, equations)
91
multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], fluxtilde2,
92
equations, dg, i, j, k)
93
multiply_add_to_node_vars!(flux_temp, derivative_split[jj, j], fluxtilde2,
94
equations, dg, i, jj, k)
95
end
96
end
97
98
# FV-form flux `fhat` in y direction
99
for k in eachnode(dg), j in 1:(nnodes(dg) - 1), i in eachnode(dg)
100
for v in eachvariable(equations)
101
fhat2_L[v, i, j + 1, k] = fhat2_L[v, i, j, k] +
102
weights[j] * flux_temp[v, i, j, k]
103
fhat2_R[v, i, j + 1, k] = fhat2_L[v, i, j + 1, k]
104
end
105
end
106
107
# Split form volume flux in orientation 3: z direction
108
flux_temp .= zero(eltype(flux_temp))
109
110
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
111
u_node = get_node_vars(u, equations, dg, i, j, k, element)
112
113
# pull the contravariant vectors in each coordinate direction
114
Ja3_node = get_contravariant_vector(3, contravariant_vectors,
115
i, j, k, element)
116
117
# z direction
118
for kk in (k + 1):nnodes(dg)
119
u_node_kk = get_node_vars(u, equations, dg, i, j, kk, element)
120
# pull the contravariant vectors and compute the average
121
Ja3_node_kk = get_contravariant_vector(3, contravariant_vectors,
122
i, j, kk, element)
123
Ja3_avg = 0.5f0 * (Ja3_node + Ja3_node_kk)
124
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
125
fluxtilde3 = volume_flux(u_node, u_node_kk, Ja3_avg, equations)
126
multiply_add_to_node_vars!(flux_temp, derivative_split[k, kk], fluxtilde3,
127
equations, dg, i, j, k)
128
multiply_add_to_node_vars!(flux_temp, derivative_split[kk, k], fluxtilde3,
129
equations, dg, i, j, kk)
130
end
131
end
132
133
# FV-form flux `fhat` in z direction
134
for k in 1:(nnodes(dg) - 1), j in eachnode(dg), i in eachnode(dg)
135
for v in eachvariable(equations)
136
fhat3_L[v, i, j, k + 1] = fhat3_L[v, i, j, k] +
137
weights[k] * flux_temp[v, i, j, k]
138
fhat3_R[v, i, j, k + 1] = fhat3_L[v, i, j, k + 1]
139
end
140
end
141
142
return nothing
143
end
144
145
# Calculate the DG staggered volume fluxes `fhat` in subcell FV-form inside the element
146
# (**with non-conservative terms in "local * symmetric" form**).
147
#
148
# See also `flux_differencing_kernel!`.
149
#
150
# The calculation of the non-conservative staggered "fluxes" requires non-conservative
151
# terms that can be written as a product of local and a symmetric contributions. See, e.g.,
152
#
153
# - Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts
154
# Discretizations of Non-Conservative Systems. https://arxiv.org/pdf/2211.14009.pdf.
155
#
156
@inline function calcflux_fhat!(fhat1_L, fhat1_R, fhat2_L, fhat2_R, fhat3_L, fhat3_R,
157
u, ::Type{<:P4estMesh{3}},
158
nonconservative_terms::True, equations,
159
volume_flux::Tuple{F_CONS, F_NONCONS}, dg::DGSEM,
160
element,
161
cache) where {
162
F_CONS <: Function,
163
F_NONCONS <:
164
FluxNonConservative{NonConservativeSymmetric()}
165
}
166
(; contravariant_vectors) = cache.elements
167
(; weights, derivative_split) = dg.basis
168
(; flux_temp_threaded, flux_nonconservative_temp_threaded) = cache
169
(; fhat_temp_threaded, fhat_nonconservative_temp_threaded, phi_threaded) = cache
170
171
volume_flux_cons, volume_flux_noncons = volume_flux
172
173
flux_temp = flux_temp_threaded[Threads.threadid()]
174
flux_noncons_temp = flux_nonconservative_temp_threaded[Threads.threadid()]
175
176
fhat_temp = fhat_temp_threaded[Threads.threadid()]
177
fhat_noncons_temp = fhat_nonconservative_temp_threaded[Threads.threadid()]
178
phi = phi_threaded[Threads.threadid()]
179
180
# The FV-form fluxes are calculated in a recursive manner, i.e.:
181
# fhat_(0,1) = w_0 * FVol_0,
182
# fhat_(j,j+1) = fhat_(j-1,j) + w_j * FVol_j, for j=1,...,N-1,
183
# with the split form volume fluxes FVol_j = -2 * sum_i=0^N D_ji f*_(j,i).
184
185
# To use the symmetry of the `volume_flux`, the split form volume flux is precalculated
186
# like in `calc_volume_integral!` for the `VolumeIntegralFluxDifferencing`
187
# and saved in in `flux_temp`.
188
189
# Split form volume flux in orientation 1: x direction
190
flux_temp .= zero(eltype(flux_temp))
191
flux_noncons_temp .= zero(eltype(flux_noncons_temp))
192
193
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
194
u_node = get_node_vars(u, equations, dg, i, j, k, element)
195
196
# pull the contravariant vectors in each coordinate direction
197
Ja1_node = get_contravariant_vector(1, contravariant_vectors,
198
i, j, k, element) # x direction
199
200
# All diagonal entries of `derivative_split` are zero. Thus, we can skip
201
# the computation of the diagonal terms. In addition, we use the symmetry
202
# of `volume_flux_cons` and `volume_flux_noncons` to save half of the possible two-point flux
203
# computations.
204
for ii in (i + 1):nnodes(dg)
205
u_node_ii = get_node_vars(u, equations, dg, ii, j, k, element)
206
# pull the contravariant vectors and compute the average
207
Ja1_node_ii = get_contravariant_vector(1, contravariant_vectors,
208
ii, j, k, element)
209
Ja1_avg = 0.5f0 * (Ja1_node + Ja1_node_ii)
210
211
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
212
fluxtilde1 = volume_flux_cons(u_node, u_node_ii, Ja1_avg, equations)
213
multiply_add_to_node_vars!(flux_temp, derivative_split[i, ii], fluxtilde1,
214
equations, dg, i, j, k)
215
multiply_add_to_node_vars!(flux_temp, derivative_split[ii, i], fluxtilde1,
216
equations, dg, ii, j, k)
217
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
218
# We multiply by 0.5 because that is done in other parts of Trixi
219
flux1_noncons = volume_flux_noncons(u_node, u_node_ii, Ja1_avg,
220
equations,
221
NonConservativeSymmetric(), noncons)
222
multiply_add_to_node_vars!(flux_noncons_temp,
223
0.5f0 * derivative_split[i, ii],
224
flux1_noncons,
225
equations, dg, noncons, i, j, k)
226
multiply_add_to_node_vars!(flux_noncons_temp,
227
0.5f0 * derivative_split[ii, i],
228
flux1_noncons,
229
equations, dg, noncons, ii, j, k)
230
end
231
end
232
end
233
234
# FV-form flux `fhat` in x direction
235
fhat_temp[:, 1, :, :] .= zero(eltype(fhat1_L))
236
fhat_noncons_temp[:, :, 1, :, :] .= zero(eltype(fhat1_L))
237
238
# Compute local contribution to non-conservative flux
239
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
240
u_local = get_node_vars(u, equations, dg, i, j, k, element)
241
# pull the local contravariant vector
242
Ja1_node = get_contravariant_vector(1, contravariant_vectors, i, j, k, element)
243
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
244
set_node_vars!(phi,
245
volume_flux_noncons(u_local, Ja1_node, equations,
246
NonConservativeLocal(), noncons),
247
equations, dg, noncons, i, j, k)
248
end
249
end
250
251
for k in eachnode(dg), j in eachnode(dg), i in 1:(nnodes(dg) - 1)
252
# Conservative part
253
for v in eachvariable(equations)
254
value = fhat_temp[v, i, j, k] + weights[i] * flux_temp[v, i, j, k]
255
fhat_temp[v, i + 1, j, k] = value
256
fhat1_L[v, i + 1, j, k] = value
257
fhat1_R[v, i + 1, j, k] = value
258
end
259
# Nonconservative part
260
for noncons in 1:n_nonconservative_terms(volume_flux_noncons),
261
v in eachvariable(equations)
262
263
value = fhat_noncons_temp[v, noncons, i, j, k] +
264
weights[i] * flux_noncons_temp[v, noncons, i, j, k]
265
fhat_noncons_temp[v, noncons, i + 1, j, k] = value
266
267
fhat1_L[v, i + 1, j, k] = fhat1_L[v, i + 1, j, k] +
268
phi[v, noncons, i, j, k] * value
269
fhat1_R[v, i + 1, j, k] = fhat1_R[v, i + 1, j, k] +
270
phi[v, noncons, i + 1, j, k] * value
271
end
272
end
273
274
# Split form volume flux in orientation 2: y direction
275
flux_temp .= zero(eltype(flux_temp))
276
flux_noncons_temp .= zero(eltype(flux_noncons_temp))
277
278
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
279
u_node = get_node_vars(u, equations, dg, i, j, k, element)
280
281
# pull the contravariant vectors in each coordinate direction
282
Ja2_node = get_contravariant_vector(2, contravariant_vectors,
283
i, j, k, element)
284
285
for jj in (j + 1):nnodes(dg)
286
u_node_jj = get_node_vars(u, equations, dg, i, jj, k, element)
287
# pull the contravariant vectors and compute the average
288
Ja2_node_jj = get_contravariant_vector(2, contravariant_vectors,
289
i, jj, k, element)
290
Ja2_avg = 0.5f0 * (Ja2_node + Ja2_node_jj)
291
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
292
fluxtilde2 = volume_flux_cons(u_node, u_node_jj, Ja2_avg, equations)
293
multiply_add_to_node_vars!(flux_temp, derivative_split[j, jj], fluxtilde2,
294
equations, dg, i, j, k)
295
multiply_add_to_node_vars!(flux_temp, derivative_split[jj, j], fluxtilde2,
296
equations, dg, i, jj, k)
297
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
298
# We multiply by 0.5 because that is done in other parts of Trixi
299
flux2_noncons = volume_flux_noncons(u_node, u_node_jj, Ja2_avg,
300
equations,
301
NonConservativeSymmetric(), noncons)
302
multiply_add_to_node_vars!(flux_noncons_temp,
303
0.5f0 * derivative_split[j, jj],
304
flux2_noncons,
305
equations, dg, noncons, i, j, k)
306
multiply_add_to_node_vars!(flux_noncons_temp,
307
0.5f0 * derivative_split[jj, j],
308
flux2_noncons,
309
equations, dg, noncons, i, jj, k)
310
end
311
end
312
end
313
314
# FV-form flux `fhat` in y direction
315
fhat_temp[:, :, 1, :] .= zero(eltype(fhat1_L))
316
fhat_noncons_temp[:, :, :, 1, :] .= zero(eltype(fhat1_L))
317
318
# Compute local contribution to non-conservative flux
319
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
320
u_local = get_node_vars(u, equations, dg, i, j, k, element)
321
# pull the local contravariant vector
322
Ja2_node = get_contravariant_vector(2, contravariant_vectors, i, j, k, element)
323
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
324
set_node_vars!(phi,
325
volume_flux_noncons(u_local, Ja2_node, equations,
326
NonConservativeLocal(), noncons),
327
equations, dg, noncons, i, j, k)
328
end
329
end
330
331
for k in eachnode(dg), j in 1:(nnodes(dg) - 1), i in eachnode(dg)
332
# Conservative part
333
for v in eachvariable(equations)
334
value = fhat_temp[v, i, j, k] + weights[j] * flux_temp[v, i, j, k]
335
fhat_temp[v, i, j + 1, k] = value
336
fhat2_L[v, i, j + 1, k] = value
337
fhat2_R[v, i, j + 1, k] = value
338
end
339
# Nonconservative part
340
for noncons in 1:n_nonconservative_terms(volume_flux_noncons),
341
v in eachvariable(equations)
342
343
value = fhat_noncons_temp[v, noncons, i, j, k] +
344
weights[j] * flux_noncons_temp[v, noncons, i, j, k]
345
fhat_noncons_temp[v, noncons, i, j + 1, k] = value
346
347
fhat2_L[v, i, j + 1, k] = fhat2_L[v, i, j + 1, k] +
348
phi[v, noncons, i, j, k] * value
349
fhat2_R[v, i, j + 1, k] = fhat2_R[v, i, j + 1, k] +
350
phi[v, noncons, i, j + 1, k] * value
351
end
352
end
353
354
# Split form volume flux in orientation 3: z direction
355
flux_temp .= zero(eltype(flux_temp))
356
flux_noncons_temp .= zero(eltype(flux_noncons_temp))
357
358
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
359
u_node = get_node_vars(u, equations, dg, i, j, k, element)
360
361
# pull the contravariant vectors in each coordinate direction
362
Ja3_node = get_contravariant_vector(3, contravariant_vectors,
363
i, j, k, element)
364
365
for kk in (k + 1):nnodes(dg)
366
u_node_kk = get_node_vars(u, equations, dg, i, j, kk, element)
367
# pull the contravariant vectors and compute the average
368
Ja3_node_kk = get_contravariant_vector(3, contravariant_vectors,
369
i, j, kk, element)
370
Ja3_avg = 0.5f0 * (Ja3_node + Ja3_node_kk)
371
# compute the contravariant sharp flux in the direction of the averaged contravariant vector
372
fluxtilde3 = volume_flux_cons(u_node, u_node_kk, Ja3_avg, equations)
373
multiply_add_to_node_vars!(flux_temp, derivative_split[k, kk], fluxtilde3,
374
equations, dg, i, j, k)
375
multiply_add_to_node_vars!(flux_temp, derivative_split[kk, k], fluxtilde3,
376
equations, dg, i, j, kk)
377
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
378
# We multiply by 0.5 because that is done in other parts of Trixi
379
flux3_noncons = volume_flux_noncons(u_node, u_node_kk, Ja3_avg,
380
equations,
381
NonConservativeSymmetric(), noncons)
382
multiply_add_to_node_vars!(flux_noncons_temp,
383
0.5f0 * derivative_split[k, kk],
384
flux3_noncons,
385
equations, dg, noncons, i, j, k)
386
multiply_add_to_node_vars!(flux_noncons_temp,
387
0.5f0 * derivative_split[kk, k],
388
flux3_noncons,
389
equations, dg, noncons, i, j, kk)
390
end
391
end
392
end
393
394
# FV-form flux `fhat` in z direction
395
fhat_temp[:, :, :, 1] .= zero(eltype(fhat1_L))
396
fhat_noncons_temp[:, :, :, :, 1] .= zero(eltype(fhat1_L))
397
398
# Compute local contribution to non-conservative flux
399
for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
400
u_local = get_node_vars(u, equations, dg, i, j, k, element)
401
# pull the local contravariant vector
402
Ja3_node = get_contravariant_vector(3, contravariant_vectors, i, j, k, element)
403
for noncons in 1:n_nonconservative_terms(volume_flux_noncons)
404
set_node_vars!(phi,
405
volume_flux_noncons(u_local, Ja3_node, equations,
406
NonConservativeLocal(), noncons),
407
equations, dg, noncons, i, j, k)
408
end
409
end
410
411
for k in 1:(nnodes(dg) - 1), j in eachnode(dg), i in eachnode(dg)
412
# Conservative part
413
for v in eachvariable(equations)
414
value = fhat_temp[v, i, j, k] + weights[k] * flux_temp[v, i, j, k]
415
fhat_temp[v, i, j, k + 1] = value
416
fhat3_L[v, i, j, k + 1] = value
417
fhat3_R[v, i, j, k + 1] = value
418
end
419
# Nonconservative part
420
for noncons in 1:n_nonconservative_terms(volume_flux_noncons),
421
v in eachvariable(equations)
422
423
value = fhat_noncons_temp[v, noncons, i, j, k] +
424
weights[k] * flux_noncons_temp[v, noncons, i, j, k]
425
fhat_noncons_temp[v, noncons, i, j, k + 1] = value
426
427
fhat3_L[v, i, j, k + 1] = fhat3_L[v, i, j, k + 1] +
428
phi[v, noncons, i, j, k] * value
429
fhat3_R[v, i, j, k + 1] = fhat3_R[v, i, j, k + 1] +
430
phi[v, noncons, i, j, k + 1] * value
431
end
432
end
433
434
return nothing
435
end
436
end # @muladd
437
438