Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/passive_tracers.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
@doc raw"""
9
PassiveTracerEquations(flow_equations; n_tracers)
10
11
Adds passive tracers to the `flow_equations`. The tracers are advected by the flow velocity.
12
These work for arbitrary dimensions with arbitrary numbers of tracers `n_tracers`, for conservative and non-conservative equations. For one dimension, with
13
one tracer ``\chi`` and flow with density and velocity ``\rho, v`` respectively, the equation of the
14
passive tracer is
15
```math
16
\frac{\partial \rho \chi}{\partial t} + \frac{\partial}{\partial x} \left( \rho v \chi \right) = 0
17
```
18
"""
19
struct PassiveTracerEquations{NDIMS, NVARS, NTracers,
20
FlowEquations <: AbstractEquations} <:
21
AbstractEquations{NDIMS, NVARS}
22
flow_equations::FlowEquations
23
end
24
25
function PassiveTracerEquations(flow_equations::AbstractEquations; n_tracers::Int)
26
return PassiveTracerEquations{ndims(flow_equations),
27
nvariables(flow_equations) + n_tracers, n_tracers,
28
typeof(flow_equations)}(flow_equations)
29
end
30
31
# Get the number of passive tracers
32
@inline ntracers(::PassiveTracerEquations{NDIMS, NVARS, NTracers, FlowEquations}) where {NDIMS, NVARS,
33
NTracers, FlowEquations} = NTracers
34
35
have_nonconservative_terms(equations::PassiveTracerEquations) = have_nonconservative_terms(equations.flow_equations)
36
37
function varnames(variables::typeof(cons2cons),
38
tracer_equations::PassiveTracerEquations)
39
@unpack flow_equations = tracer_equations
40
flow_varnames = varnames(variables, flow_equations)
41
n_tracers = ntracers(tracer_equations)
42
return (flow_varnames..., ntuple(i -> "rho_chi_$i", Val(n_tracers))...)
43
end
44
45
function varnames(variables::typeof(cons2prim),
46
tracer_equations::PassiveTracerEquations)
47
@unpack flow_equations = tracer_equations
48
flow_varnames = varnames(variables, flow_equations)
49
n_tracers = ntracers(tracer_equations)
50
return (flow_varnames..., ntuple(i -> "chi_$i", Val(n_tracers))...)
51
end
52
53
# Calculate flux for a single point
54
@inline function flux(u, orientation_or_normal,
55
tracer_equations::PassiveTracerEquations)
56
n_flow_variables = nvariables_flow(tracer_equations)
57
58
u_flow = flow_variables(u, tracer_equations)
59
60
v_normal = velocity(u_flow, orientation_or_normal, tracer_equations.flow_equations)
61
62
flux_tracer = SVector(ntuple(@inline(v->u[v + n_flow_variables] * v_normal),
63
Val(ntracers(tracer_equations))))
64
65
flux_flow = flux(u_flow, orientation_or_normal, tracer_equations.flow_equations)
66
67
return SVector(flux_flow..., flux_tracer...)
68
end
69
70
"""
71
initial_condition_density_wave(x, t, equations::PassiveTracerEquations)
72
73
Takes the [`initial_condition_density_wave`](@ref) for the flow equations and
74
takes its translated first coordinates as the initial condition for the tracers.
75
"""
76
function initial_condition_density_wave(x, t,
77
equations::PassiveTracerEquations)
78
# Store translated coordinate for easy use of exact solution
79
u_flow = initial_condition_density_wave(x, t, equations.flow_equations)
80
# Obtain `u_tracers` by translating `u_flow`
81
xc = SVector(ntuple(_ -> 0.1f0 * one(eltype(x)), Val(ndims(equations))))
82
83
tracers = SVector((initial_condition_density_wave(x + i * xc, t,
84
equations.flow_equations)[1] for i in 1:ntracers(equations))...)
85
86
u_tracers = u_flow[1] * tracers
87
return SVector(u_flow..., u_tracers...)
88
end
89
90
# Calculate the number of variables for the flow equations
91
@inline function nvariables_flow(tracer_equations::PassiveTracerEquations)
92
return nvariables(tracer_equations.flow_equations)
93
end
94
95
# Obtain the flow variables from the conservative variables. The tracers are not included.
96
@inline function flow_variables(u, tracer_equations::PassiveTracerEquations)
97
n_flow_variables = nvariables_flow(tracer_equations)
98
return SVector(ntuple(@inline(v->u[v]), Val(n_flow_variables)))
99
end
100
101
# Obtain the tracers which advect by the flow velocity by dividing the respective conservative
102
# variable by the density.
103
function tracers(u, tracer_equations::PassiveTracerEquations)
104
n_flow_variables = nvariables_flow(tracer_equations)
105
106
rho = density(u, tracer_equations)
107
return SVector(ntuple(@inline(v->u[v + n_flow_variables] / rho),
108
Val(ntracers(tracer_equations))))
109
end
110
111
# Obtain rho * tracers which are the conservative variables for the tracer equations.
112
function rho_tracers(u, tracer_equations::PassiveTracerEquations)
113
n_flow_variables = nvariables_flow(tracer_equations)
114
115
return SVector(ntuple(@inline(v->u[v + n_flow_variables]),
116
Val(ntracers(tracer_equations))))
117
end
118
119
# Primitives for the flow equations and tracers. For a tracer, the primitive variable is obtained
120
# by dividing by density.
121
@inline function cons2prim(u, tracer_equations::PassiveTracerEquations)
122
return SVector(cons2prim(flow_variables(u, tracer_equations),
123
tracer_equations.flow_equations)...,
124
tracers(u, tracer_equations)...)
125
end
126
127
# Conservative variables for the flow equations and tracers. For tracers, the conservative variable
128
# is obtained by multiplying by the density
129
@inline function prim2cons(u, tracer_equations::PassiveTracerEquations)
130
@unpack flow_equations = tracer_equations
131
u_flow = flow_variables(u, tracer_equations)
132
133
n_flow_variables = nvariables_flow(tracer_equations)
134
135
rho = density(u, tracer_equations)
136
cons_flow = prim2cons(u_flow, flow_equations)
137
cons_tracer = SVector(ntuple(@inline(v->rho * u[v + n_flow_variables]),
138
Val(ntracers(tracer_equations))))
139
return SVector(cons_flow..., cons_tracer...)
140
end
141
142
# Entropy for tracers is the L2 norm of the tracers
143
@inline function entropy(cons, tracer_equations::PassiveTracerEquations)
144
flow_entropy = entropy(flow_variables(cons, tracer_equations),
145
tracer_equations.flow_equations)
146
tracer_entropy = density(cons, tracer_equations) *
147
sum(abs2, tracers(cons, tracer_equations))
148
return flow_entropy + tracer_entropy
149
end
150
151
# Convert conservative variables to entropy
152
@inline function cons2entropy(u, tracer_equations::PassiveTracerEquations)
153
@unpack flow_equations = tracer_equations
154
flow_entropy = cons2entropy(flow_variables(u, tracer_equations), flow_equations)
155
tracers_ = tracers(u, tracer_equations)
156
157
flow_entropy_after_density = SVector(ntuple(@inline(v->flow_entropy[v + 1]),
158
Val(nvariables_flow(tracer_equations) -
159
1)))
160
variables = SVector(flow_entropy[1] - sum(tracers_ .^ 2),
161
flow_entropy_after_density...,
162
2 * tracers_...) # factor of 2 because of the L2 norm
163
return variables
164
end
165
166
# Works if the method exists for flow equations
167
@inline function velocity(u, orientation_or_normal,
168
tracer_equations::PassiveTracerEquations)
169
return velocity(flow_variables(u, tracer_equations), orientation_or_normal,
170
tracer_equations.flow_equations)
171
end
172
173
# Works if the method exists for flow equations
174
@inline function density(u, tracer_equations::PassiveTracerEquations)
175
return density(flow_variables(u, tracer_equations), tracer_equations.flow_equations)
176
end
177
178
# Works if the method exists for flow equations
179
@inline function pressure(u, tracer_equations::PassiveTracerEquations)
180
return pressure(flow_variables(u, tracer_equations),
181
tracer_equations.flow_equations)
182
end
183
184
# Works if the method exists for flow equations
185
@inline function density_pressure(u, tracer_equations::PassiveTracerEquations)
186
@unpack flow_equations = tracer_equations
187
u_flow = flow_variables(u, tracer_equations)
188
return density_pressure(u_flow, flow_equations)
189
end
190
191
# Used for local Lax-Friedrichs type dissipation, and uses only the flow equations
192
# This assumes that the `velocity` is always bounded by the estimate of the
193
# wave speed for the wrapped equations.
194
@inline function max_abs_speed_naive(u_ll, u_rr, orientation_or_normal,
195
tracer_equations::PassiveTracerEquations)
196
u_flow_ll = flow_variables(u_ll, tracer_equations)
197
u_flow_rr = flow_variables(u_rr, tracer_equations)
198
199
@unpack flow_equations = tracer_equations
200
return max_abs_speed_naive(u_flow_ll, u_flow_rr, orientation_or_normal,
201
flow_equations)
202
end
203
204
@inline function max_abs_speeds(u, tracer_equations::PassiveTracerEquations)
205
u_flow = flow_variables(u, tracer_equations)
206
207
return max_abs_speeds(u_flow, tracer_equations.flow_equations)
208
end
209
210
"""
211
FluxTracerEquationsCentral(flow_flux)
212
213
Get an entropy conserving flux for the equations with tracers corresponding to the given entropy conserving flux `flow_flux` for the flow equations. The study of this flux is part of ongoing
214
research.
215
"""
216
struct FluxTracerEquationsCentral{FlowFlux}
217
flow_flux::FlowFlux
218
end
219
220
# Entropy conserving (EC) flux for the tracer equations using EC `flow_flux` for the flow equations
221
@inline function (f::FluxTracerEquationsCentral)(u_ll, u_rr,
222
orientation_or_normal_direction,
223
tracer_equations::PassiveTracerEquations)
224
@unpack flow_equations = tracer_equations
225
u_flow_ll = flow_variables(u_ll, tracer_equations)
226
u_flow_rr = flow_variables(u_rr, tracer_equations)
227
228
flux_flow = f.flow_flux(u_flow_ll, u_flow_rr, orientation_or_normal_direction,
229
flow_equations)
230
flux_rho = density(flux_flow, flow_equations)
231
tracers_ll = tracers(u_ll, tracer_equations)
232
tracers_rr = tracers(u_rr, tracer_equations)
233
flux_tracer = 0.5f0 * SVector(ntuple(@inline(v->tracers_ll[v] + tracers_rr[v]),
234
Val(ntracers(tracer_equations))))
235
flux_tracer = flux_rho * flux_tracer
236
return SVector(flux_flow..., flux_tracer...)
237
end
238
end # muladd
239
240