Tracer variance equation
The TracerVarianceEquation module provides diagnostics for the tracer variance budget. Tracer variance is a second-order quantity that measures the intensity of tracer fluctuations and is central to understanding mixing in ocean simulations. For a tracer $c$, the variance $c^2$ evolves according to
\[\partial_t c^2 = 2c\,\partial_t c = -2c\,\partial_j(u_j c) + 2c\,\partial_j F_j + 2c\,F^c\]
where $F_j$ is the diffusive flux of $c$ in the $j$-th direction and $F^c$ is any applied forcing. This budget can be further decomposed into a diffusive transport term and a dissipation rate:
\[2c\,\partial_j F_j = \partial_j(2c\,F_j) - 2\,\partial_j c \cdot F_j\]
The second term, $\chi = 2\,\partial_j c \cdot F_j$, is the tracer variance dissipation rate. For Fickian diffusion with diffusivity $\kappa$, this reduces to the familiar form $\chi = 2\kappa |\nabla c|^2$. The dissipation rate is always positive and represents the irreversible destruction of tracer variance by molecular or subgrid diffusion – it is a direct measure of mixing.
All diagnostics are computed at (Center, Center, Center).
Example
julia> using Oceananigans, Oceanostics
julia> grid = RectilinearGrid(size=(4, 4, 4), extent=(1, 1, 1));
julia> model = NonhydrostaticModel(grid; tracers=:b, closure=SmagorinskyLilly());
julia> χ = TracerVarianceEquation.TracerVarianceDissipationRate(model, :b)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 4×4×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── kernel_function: tracer_variance_dissipation_rate_ccc (generic function with 1 method)
└── arguments: ("Oceananigans.TurbulenceClosures.Smagorinskys.Smagorinsky", "NamedTuple", "Val", "Field", "Clock", "NamedTuple", "Nothing")
julia> diff = TracerVarianceEquation.TracerVarianceDiffusion(model, :b)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 4×4×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── kernel_function: c∇_dot_qᶜ (generic function with 1 method)
└── arguments: ("Oceananigans.TurbulenceClosures.Smagorinskys.Smagorinsky", "NamedTuple", "Val", "Field", "Clock", "NamedTuple", "Nothing")Tendency
Oceanostics.TracerVarianceEquation.TracerVarianceTendency — Type
TracerVarianceTendency(model, tracer_name; location)
Return a KernelFunctionOperation that computes the tracer variance tendency:
TEND = 2 c ∂ₜcwhere c is the tracer and ∂ₜc is the tracer tendency (computed using Oceananigans' tracer tendency kernel).
julia> using Oceananigans, Oceanostics
julia> grid = RectilinearGrid(size = (1, 1, 4), extent = (1, 1, 1));
julia> model = NonhydrostaticModel(grid; tracers=:b);
julia> χ = TracerVarianceEquation.TracerVarianceTendency(model, :b)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 1×1×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×3 halo
├── kernel_function: c∂ₜcᶜᶜᶜ (generic function with 1 method)
└── arguments: ("Val", "Val", "Centered", "Nothing", "Nothing", "Nothing", "Nothing", "Oceananigans.Models.NonhydrostaticModels.BackgroundFields", "NamedTuple", "NamedTuple", "NamedTuple", "Nothing", "Clock", "Returns")Diffusion
Oceanostics.TracerVarianceEquation.TracerVarianceDiffusion — Type
TracerVarianceDiffusion(model, tracer_name; location)
Return a KernelFunctionOperation that computes the diffusive term of the tracer variance prognostic equation using Oceananigans' diffusive tracer flux divergence kernel:
DIFF = 2 c ∂ⱼFⱼwhere c is the tracer, and Fⱼ is the tracer's diffusive flux in the j-th direction.
julia> using Oceananigans, Oceanostics
julia> grid = RectilinearGrid(size=(4, 4, 4), extent=(1, 1, 1));
julia> model = NonhydrostaticModel(grid; tracers=:b, closure=SmagorinskyLilly());
julia> DIFF = TracerVarianceEquation.TracerVarianceDiffusion(model, :b)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 4×4×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── kernel_function: c∇_dot_qᶜ (generic function with 1 method)
└── arguments: ("Oceananigans.TurbulenceClosures.Smagorinskys.Smagorinsky", "NamedTuple", "Val", "Field", "Clock", "NamedTuple", "Nothing")Dissipation rate
Oceanostics.TracerVarianceEquation.TracerVarianceDissipationRate — Type
TracerVarianceDissipationRate(
model,
tracer_name;
tracer,
location
)
Return a KernelFunctionOperation that computes the isotropic variance dissipation rate for tracer_name in model.tracers. The isotropic variance dissipation rate is defined as
χ = 2 ∂ⱼc ⋅ Fⱼwhere Fⱼ is the diffusive flux of c in the j-th direction and ∂ⱼ is the gradient operator. χ is implemented in its conservative formulation based on the equation above.
Note that often χ is written as χ = 2κ (∇c ⋅ ∇c), which is the special case for Fickian diffusion (κ is the tracer diffusivity).
Here tracer_name is needed even when passing tracer in order to get the appropriate tracer_index. When passing tracer, this function should be used as
julia> using Oceananigans, Oceanostics
julia> grid = RectilinearGrid(size=(4, 4, 4), extent=(1, 1, 1));
julia> model = NonhydrostaticModel(grid; tracers=:b, closure=SmagorinskyLilly());
julia> χ = TracerVarianceEquation.TracerVarianceDissipationRate(model, :b)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 4×4×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── kernel_function: tracer_variance_dissipation_rate_ccc (generic function with 1 method)
└── arguments: ("Oceananigans.TurbulenceClosures.Smagorinskys.Smagorinsky", "NamedTuple", "Val", "Field", "Clock", "NamedTuple", "Nothing")
julia> b̄ = Field(Average(model.tracers.b, dims=(1,2)));
julia> b′ = model.tracers.b - b̄;
julia> χb = TracerVarianceEquation.TracerVarianceDissipationRate(model, :b, tracer=b′)
KernelFunctionOperation at (Center, Center, Center)
├── grid: 4×4×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo
├── kernel_function: tracer_variance_dissipation_rate_ccc (generic function with 1 method)
└── arguments: ("Oceananigans.TurbulenceClosures.Smagorinskys.Smagorinsky", "NamedTuple", "Val", "Oceananigans.AbstractOperations.BinaryOperation", "Clock", "NamedTuple", "Nothing")