# Background fields

`BackgroundField`s are velocity and tracer fields around which the resolved
velocity and tracer fields evolve. Only the _advective_ terms associated with
the interaction between background and resolved fields are included.
For example, tracer advection is described by

```math
\boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{v} c \right ) \, ,
```

where ``\boldsymbol{v}`` is the resolved velocity field and ``c`` is the resolved
tracer field corresponding to `model.tracers.c`.

When a background field ``C`` is provided, the tracer advection term becomes

```math
\boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{v} c \right )
    + \boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{v} C \right ) \, .
```

When both a background field velocity field ``\boldsymbol{U}`` and a background tracer field ``C``
are provided, then the tracer advection term becomes

```math
\boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{v} c \right )
    + \boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{v} C \right )
    + \boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{U} c \right ) \, .
```

Notice that the term ``\boldsymbol{\nabla} \boldsymbol{\cdot} \left ( \boldsymbol{U} C \right )``
is neglected: only the terms describing the advection of resolved tracer by the background
velocity field and the advection of background tracer by the resolved velocity field are included.
An analogous statement holds for the advection of background momentum by the resolved
velocity field.
Other possible terms associated with the Coriolis force, buoyancy, turbulence closures,
and surface waves acting on background fields are neglected.

!!! compat "Model compatibility"
    `BackgroundFields` are only supported by [`NonhydrostaticModel`](@ref).

## Specifying background fields

`BackgroundField`s are defined by functions of ``(x, y, z, t)`` and optional parameters. A
simple example is

```jldoctest
using Oceananigans

U(x, y, z, t) = 0.2 * z

grid = RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1))

model = NonhydrostaticModel(grid; background_fields = (u=U,))

model.background_fields.velocities.u

# output
FunctionField located at (Face, Center, Center)
├── func: U (generic function with 1 method)
├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo
├── clock: Clock{Float64, Float64}(time=0 seconds, iteration=0, last_Δt=Inf days)
└── parameters: nothing
```

`BackgroundField`s are specified by passing them to the kwarg `background_fields`
in the `NonhydrostaticModel` constructor. The kwarg `background_fields` expects
a `NamedTuple` of fields, which are internally sorted into `velocities` and `tracers`,
wrapped in `FunctionField`s, and assigned their appropriate locations.

`BackgroundField`s with parameters require using the `BackgroundField` wrapper:

```jldoctest moar_background
using Oceananigans

parameters = (α=3.14, N=1.0, f=0.1)

# Background fields are defined via function of x, y, z, t, and optional parameters
U(x, y, z, t, α) = α * z
B(x, y, z, t, p) = - p.α * p.f * y + p.N^2 * z

U_field = BackgroundField(U, parameters=parameters.α)
B_field = BackgroundField(B, parameters=parameters)

# output
BackgroundField{typeof(B), @NamedTuple{α::Float64, N::Float64, f::Float64}}
├── func: B (generic function with 1 method)
└── parameters: (α = 3.14, N = 1.0, f = 0.1)
```

When inserted into `NonhydrostaticModel`, we get

```jldoctest moar_background
grid = RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1))

model = NonhydrostaticModel(grid; background_fields = (u=U_field, b=B_field),
                            tracers=:b, buoyancy=BuoyancyTracer())

model.background_fields.tracers.b

# output
FunctionField located at (Center, Center, Center)
├── func: B (generic function with 1 method)
├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo
├── clock: Clock{Float64, Float64}(time=0 seconds, iteration=0, last_Δt=Inf days)
└── parameters: (α = 3.14, N = 1.0, f = 0.1)
```

## Turbulent fluxes of background fields

By default, only the advective interaction between the background and resolved fields is included
(as described above). Turbulent closure fluxes acting on background fields are neglected.

To include them, construct `BackgroundFields` explicitly with `background_closure_fluxes=true`
and pass it to the model:

```jldoctest
using Oceananigans
using Oceananigans.Models.NonhydrostaticModels: BackgroundFields

U(x, y, z, t) = 0.2 * z  # linear shear background velocity
background_fields = BackgroundFields(background_closure_fluxes=true, u=U)

grid = RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1))
model = NonhydrostaticModel(grid; background_fields, closure=ScalarDiffusivity(ν=1e-4, κ=1e-5))

model.background_fields.velocities.u

# output
FunctionField located at (Face, Center, Center)
├── func: U (generic function with 1 method)
├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo
├── clock: Clock{Float64, Float64}(time=0 seconds, iteration=0, last_Δt=Inf days)
└── parameters: nothing
```

This is relevant when background gradients are large enough that diffusive fluxes from the
background field contribute non-negligibly to the resolved dynamics — for example, in
strongly sheared background flows with active turbulence closures.
