Path: blob/main/src/equations/passive_tracers.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8PassiveTracerEquations(flow_equations; n_tracers)910Adds passive tracers to the `flow_equations`. The tracers are advected by the flow velocity.11These work for arbitrary dimensions with arbitrary numbers of tracers `n_tracers`, for conservative and non-conservative equations. For one dimension, with12one tracer ``\chi`` and flow with density and velocity ``\rho, v`` respectively, the equation of the13passive tracer is14```math15\frac{\partial \rho \chi}{\partial t} + \frac{\partial}{\partial x} \left( \rho v \chi \right) = 016```17"""18struct PassiveTracerEquations{NDIMS, NVARS, NTracers,19FlowEquations <: AbstractEquations} <:20AbstractEquations{NDIMS, NVARS}21flow_equations::FlowEquations22end2324function PassiveTracerEquations(flow_equations::AbstractEquations; n_tracers::Int)25return PassiveTracerEquations{ndims(flow_equations),26nvariables(flow_equations) + n_tracers, n_tracers,27typeof(flow_equations)}(flow_equations)28end2930# Get the number of passive tracers31@inline ntracers(::PassiveTracerEquations{NDIMS, NVARS, NTracers, FlowEquations}) where {NDIMS, NVARS,32NTracers, FlowEquations} = NTracers3334have_nonconservative_terms(equations::PassiveTracerEquations) = have_nonconservative_terms(equations.flow_equations)3536function varnames(variables::typeof(cons2cons),37tracer_equations::PassiveTracerEquations)38@unpack flow_equations = tracer_equations39flow_varnames = varnames(variables, flow_equations)40n_tracers = ntracers(tracer_equations)41return (flow_varnames..., ntuple(i -> "rho_chi_$i", Val(n_tracers))...)42end4344function varnames(variables::typeof(cons2prim),45tracer_equations::PassiveTracerEquations)46@unpack flow_equations = tracer_equations47flow_varnames = varnames(variables, flow_equations)48n_tracers = ntracers(tracer_equations)49return (flow_varnames..., ntuple(i -> "chi_$i", Val(n_tracers))...)50end5152# Calculate flux for a single point53@inline function flux(u, orientation_or_normal,54tracer_equations::PassiveTracerEquations)55n_flow_variables = nvariables_flow(tracer_equations)5657u_flow = flow_variables(u, tracer_equations)5859v_normal = velocity(u_flow, orientation_or_normal, tracer_equations.flow_equations)6061flux_tracer = SVector(ntuple(@inline(v->u[v + n_flow_variables] * v_normal),62Val(ntracers(tracer_equations))))6364flux_flow = flux(u_flow, orientation_or_normal, tracer_equations.flow_equations)6566return SVector(flux_flow..., flux_tracer...)67end6869"""70initial_condition_density_wave(x, t, equations::PassiveTracerEquations)7172Takes the [`initial_condition_density_wave`](@ref) for the flow equations and73takes its translated first coordinates as the initial condition for the tracers.74"""75function initial_condition_density_wave(x, t,76equations::PassiveTracerEquations)77# Store translated coordinate for easy use of exact solution78u_flow = initial_condition_density_wave(x, t, equations.flow_equations)79# Obtain `u_tracers` by translating `u_flow`80xc = SVector(ntuple(_ -> 0.1f0 * one(eltype(x)), Val(ndims(equations))))8182tracers = SVector((initial_condition_density_wave(x + i * xc, t,83equations.flow_equations)[1] for i in 1:ntracers(equations))...)8485u_tracers = u_flow[1] * tracers86return SVector(u_flow..., u_tracers...)87end8889# Calculate the number of variables for the flow equations90@inline function nvariables_flow(tracer_equations::PassiveTracerEquations)91return nvariables(tracer_equations.flow_equations)92end9394# Obtain the flow variables from the conservative variables. The tracers are not included.95@inline function flow_variables(u, tracer_equations::PassiveTracerEquations)96n_flow_variables = nvariables_flow(tracer_equations)97return SVector(ntuple(@inline(v->u[v]), Val(n_flow_variables)))98end99100# Obtain the tracers which advect by the flow velocity by dividing the respective conservative101# variable by the density.102function tracers(u, tracer_equations::PassiveTracerEquations)103n_flow_variables = nvariables_flow(tracer_equations)104105rho = density(u, tracer_equations)106return SVector(ntuple(@inline(v->u[v + n_flow_variables] / rho),107Val(ntracers(tracer_equations))))108end109110# Obtain rho * tracers which are the conservative variables for the tracer equations.111function rho_tracers(u, tracer_equations::PassiveTracerEquations)112n_flow_variables = nvariables_flow(tracer_equations)113114return SVector(ntuple(@inline(v->u[v + n_flow_variables]),115Val(ntracers(tracer_equations))))116end117118# Primitives for the flow equations and tracers. For a tracer, the primitive variable is obtained119# by dividing by density.120@inline function cons2prim(u, tracer_equations::PassiveTracerEquations)121return SVector(cons2prim(flow_variables(u, tracer_equations),122tracer_equations.flow_equations)...,123tracers(u, tracer_equations)...)124end125126# Conservative variables for the flow equations and tracers. For tracers, the conservative variable127# is obtained by multiplying by the density128@inline function prim2cons(u, tracer_equations::PassiveTracerEquations)129@unpack flow_equations = tracer_equations130u_flow = flow_variables(u, tracer_equations)131132n_flow_variables = nvariables_flow(tracer_equations)133134rho = density(u, tracer_equations)135cons_flow = prim2cons(u_flow, flow_equations)136cons_tracer = SVector(ntuple(@inline(v->rho * u[v + n_flow_variables]),137Val(ntracers(tracer_equations))))138return SVector(cons_flow..., cons_tracer...)139end140141# Entropy for tracers is the L2 norm of the tracers142@inline function entropy(cons, tracer_equations::PassiveTracerEquations)143flow_entropy = entropy(flow_variables(cons, tracer_equations),144tracer_equations.flow_equations)145tracer_entropy = density(cons, tracer_equations) *146sum(abs2, tracers(cons, tracer_equations))147return flow_entropy + tracer_entropy148end149150# Convert conservative variables to entropy151@inline function cons2entropy(u, tracer_equations::PassiveTracerEquations)152@unpack flow_equations = tracer_equations153flow_entropy = cons2entropy(flow_variables(u, tracer_equations), flow_equations)154tracers_ = tracers(u, tracer_equations)155156flow_entropy_after_density = SVector(ntuple(@inline(v->flow_entropy[v + 1]),157Val(nvariables_flow(tracer_equations) -1581)))159variables = SVector(flow_entropy[1] - sum(tracers_ .^ 2),160flow_entropy_after_density...,1612 * tracers_...) # factor of 2 because of the L2 norm162return variables163end164165# Works if the method exists for flow equations166@inline function velocity(u, orientation_or_normal,167tracer_equations::PassiveTracerEquations)168return velocity(flow_variables(u, tracer_equations), orientation_or_normal,169tracer_equations.flow_equations)170end171172# Works if the method exists for flow equations173@inline function density(u, tracer_equations::PassiveTracerEquations)174return density(flow_variables(u, tracer_equations), tracer_equations.flow_equations)175end176177# Works if the method exists for flow equations178@inline function pressure(u, tracer_equations::PassiveTracerEquations)179return pressure(flow_variables(u, tracer_equations),180tracer_equations.flow_equations)181end182183# Works if the method exists for flow equations184@inline function density_pressure(u, tracer_equations::PassiveTracerEquations)185@unpack flow_equations = tracer_equations186u_flow = flow_variables(u, tracer_equations)187return density_pressure(u_flow, flow_equations)188end189190# Used for local Lax-Friedrichs type dissipation, and uses only the flow equations191# This assumes that the `velocity` is always bounded by the estimate of the192# wave speed for the wrapped equations.193@inline function max_abs_speed_naive(u_ll, u_rr, orientation_or_normal,194tracer_equations::PassiveTracerEquations)195u_flow_ll = flow_variables(u_ll, tracer_equations)196u_flow_rr = flow_variables(u_rr, tracer_equations)197198@unpack flow_equations = tracer_equations199return max_abs_speed_naive(u_flow_ll, u_flow_rr, orientation_or_normal,200flow_equations)201end202203@inline function max_abs_speeds(u, tracer_equations::PassiveTracerEquations)204u_flow = flow_variables(u, tracer_equations)205206return max_abs_speeds(u_flow, tracer_equations.flow_equations)207end208209"""210FluxTracerEquationsCentral(flow_flux)211212Get 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 ongoing213research.214"""215struct FluxTracerEquationsCentral{FlowFlux}216flow_flux::FlowFlux217end218219# Entropy conserving (EC) flux for the tracer equations using EC `flow_flux` for the flow equations220@inline function (f::FluxTracerEquationsCentral)(u_ll, u_rr,221orientation_or_normal_direction,222tracer_equations::PassiveTracerEquations)223@unpack flow_equations = tracer_equations224u_flow_ll = flow_variables(u_ll, tracer_equations)225u_flow_rr = flow_variables(u_rr, tracer_equations)226227flux_flow = f.flow_flux(u_flow_ll, u_flow_rr, orientation_or_normal_direction,228flow_equations)229flux_rho = density(flux_flow, flow_equations)230tracers_ll = tracers(u_ll, tracer_equations)231tracers_rr = tracers(u_rr, tracer_equations)232flux_tracer = 0.5f0 * SVector(ntuple(@inline(v->tracers_ll[v] + tracers_rr[v]),233Val(ntracers(tracer_equations))))234flux_tracer = flux_rho * flux_tracer235return SVector(flux_flow..., flux_tracer...)236end237end # muladd238239240