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.TracerVarianceTendencyType
TracerVarianceTendency(model, tracer_name; location)

Return a KernelFunctionOperation that computes the tracer variance tendency:

TEND = 2 c ∂ₜc

where 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")
source

Diffusion

Oceanostics.TracerVarianceEquation.TracerVarianceDiffusionType
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")
source

Dissipation rate

Oceanostics.TracerVarianceEquation.TracerVarianceDissipationRateType
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")
source