Core Types

This page documents the core data types in QGYBJ+.jl.

QGParams

The main parameter structure containing all simulation settings.

QGYBJplus.QGParamsType
QGParams{T}

Container for all physical and numerical parameters of the QG-YBJ+ model.

Domain Parameters

  • nx, ny, nz: Grid resolution in x, y, z directions
  • Lx, Ly, Lz: Domain size in x, y, z in meters (REQUIRED - no default)
  • x0, y0: Domain origin in x, y (default: 0, use -Lx/2,-Ly/2 for centered domain)

Time Stepping

  • dt: Time step size
  • nt: Total number of time steps

Physical Parameters

  • f₀: Coriolis parameter (typically 1.0 for nondimensional)
  • : Buoyancy frequency squared (default 1.0)
  • W2F: DEPRECATED - no longer used (kept for backward compatibility)
  • γ: Robert-Asselin filter coefficient (typically 10⁻³)
  • linear_vert_structure: Legacy Fortran flag (0 or 1), typically 0

Viscosity/Hyperviscosity

The model uses two hyperdiffusion operators for stability:

  • νₕ, νᵥ: Legacy generic viscosity coefficients (prefer specific coefficients below)
  • νₕ₁, ilap1: First hyperviscosity coefficient and Laplacian power for mean flow
  • νₕ₂, ilap2: Second hyperviscosity coefficient and Laplacian power for mean flow
  • νₕ₁ʷ, ilap1w: First hyperviscosity for waves
  • νₕ₂ʷ, ilap2w: Second hyperviscosity for waves
  • νz: Vertical diffusion coefficient

The hyperdiffusion term is: ν₁(-∇²)^ilap1 + ν₂(-∇²)^ilap2

Physics Switches

These boolean flags control different physics modes:

  • inviscid: If true, disable all dissipation
  • linear: If true, disable nonlinear advection terms
  • no_dispersion: If true, disable wave dispersion (A=0)
  • passive_scalar: If true, waves are passive (no dispersion, no refraction)
  • ybj_plus: If true, use YBJ+ formulation; if false, use normal YBJ
  • no_feedback: If true, disable ALL wave-mean flow coupling (master switch)
  • fixed_flow: If true, mean flow doesn't evolve (ψ constant in time)
  • no_wave_feedback: If true, disable qʷ term specifically (waves don't modify PV)

Note: Wave feedback is enabled only when BOTH no_feedback=false AND no_wave_feedback=false.

Stratification Parameters (Skewed Gaussian profile)

For the skewed Gaussian N²(z) profile: N²(z) = N₁² exp(-(z-z₀)²/σ²) [1 + erf(α(z-z₀)/(σ√2))] + N₀²

  • N₀²_sg: Background N² (N₀²)
  • N₁²_sg: Peak N² amplitude (N₁²)
  • σ_sg: Width parameter (σ)
  • z₀_sg: Center depth (z₀)
  • α_sg: Skewness parameter (α)

Example

par = default_params(nx=128, ny=128, nz=64, Lx=500e3, Ly=500e3, Lz=4000.0, dt=0.001, nt=10000)

See also: default_params, with_b_ell_profile

source

Fields

FieldTypeDescription
nx, ny, nzIntGrid dimensions
Lx, Ly, LzFloat64Domain sizes (REQUIRED)
dtFloat64Time step
ntIntNumber of time steps
f₀Float64Coriolis parameter
Float64Buoyancy frequency squared
γFloat64Robert-Asselin filter coefficient
ybj_plusBoolUse YBJ+ formulation
no_feedbackBoolMaster switch: disable all wave-mean coupling
no_wave_feedbackBoolDisable wave feedback on mean flow
inviscidBoolDisable all dissipation
linearBoolDisable nonlinear terms
νₕ₁Float64First hyperviscosity coefficient (flow)
ilap1IntLaplacian power for νₕ₁
νₕ₂Float64Second hyperviscosity coefficient (flow)
ilap2IntLaplacian power for νₕ₂
νₕ₁ʷFloat64First hyperviscosity coefficient (waves)
νₕ₂ʷFloat64Second hyperviscosity coefficient (waves)
νzFloat64Vertical diffusivity

Note: Type Unicode characters using \ + name + <tab> in Julia REPL (e.g., f\_0<tab>f₀)

Constructors

# Domain size is REQUIRED (no defaults)
params = default_params(Lx=500e3, Ly=500e3, Lz=4000.0)  # 500km × 500km × 4km

# Custom parameters with domain size
params = default_params(;
    Lx = 500e3, Ly = 500e3, Lz = 4000.0,  # Domain size (REQUIRED)
    nx = 128, ny = 128, nz = 64,           # Grid dimensions
    f₀ = 1.0,
    N² = 1.0,
    ybj_plus = true,
    νₕ₂ = 10.0,
    ilap2 = 6
)

Example

# High-resolution parameters (domain size REQUIRED)
params = default_params(;
    Lx = 500e3, Ly = 500e3, Lz = 4000.0,
    nx = 256, ny = 256, nz = 128,
    ybj_plus = true,
    no_feedback = false,
    νₕ₂ = 1e-12,
    ilap2 = 8
)

Grid

The computational grid structure.

QGYBJplus.GridType
Grid{T, AT}

Numerical grid and spectral metadata for the QG-YBJ+ model.

Type Parameters

  • T: Floating point type (typically Float64)
  • AT: Array type for 2D arrays (Array{T,2} or PencilArray{T,2})

Fields

Grid Dimensions

  • nx, ny, nz::Int: Number of grid points in x, y, z directions
  • Lx, Ly, Lz::T: Domain size in x, y, z in meters (REQUIRED - no default)
  • x0, y0::T: Domain origin in x, y (0 = standard [0,Lx), -Lx/2 = centered [-Lx/2,Lx/2))
  • dx, dy::T: Grid spacing in x, y (computed as Lx/nx, Ly/ny)

Vertical Grid

  • z::Vector{T}: Staggered (cell-centered) vertical levels, length nz
  • dz::Vector{T}: Layer thicknesses between levels, length nz-1 (or length 1 containing Lz when nz=1)

Spectral Wavenumbers

  • kx::Vector{T}: x-wavenumbers following FFTW convention, length nx
  • ky::Vector{T}: y-wavenumbers following FFTW convention, length ny
  • kh2::AT: Horizontal wavenumber squared kx² + ky², size (nx, ny) in serial, or a 3D PencilArray with shape (nz, nx, ny) in parallel.

Parallel Decomposition

  • decomp::Any: PencilArrays decomposition (nothing for serial)

Wavenumber Convention

For a domain of size L with n points:

k[i] = (2π/L) × m  where m = i-1        for i ≤ (n+1)÷2
                          m = i-1-n      for i > (n+1)÷2

Example

par = default_params(nx=64, ny=64, nz=32, Lx=500e3, Ly=500e3, Lz=4000.0)
G = init_grid(par)
# G.kx[1] = 0 (mean mode)
# G.kx[33] = -32 × (2π/Lx) (most negative wavenumber)

See also: init_grid, State

source

Fields

FieldTypeDescription
nx, ny, nzIntGrid dimensions
Lx, Ly, LzFloat64Domain sizes
dx, dy, dzFloat64Grid spacings
x, y, zVector{Float64}Coordinate arrays
kx, kyVector{Float64}Wavenumber arrays
kh2Array{Float64,2}Horizontal wavenumber squared

Constructors

# Initialize grid from parameters (recommended)
params = default_params(Lx=500e3, Ly=500e3, Lz=4000.0, nx=64, ny=64, nz=32)
grid = init_grid(params)

Grid Utilities

# Get wavenumbers at local indices (works with MPI)
kx = get_kx(grid, i)   # Get kx at local index i
ky = get_ky(grid, j)   # Get ky at local index j
kh2 = get_kh2(grid, i, j)  # Get horizontal wavenumber squared

State

The simulation state containing all prognostic and diagnostic fields.

QGYBJplus.StateType
State{T, RT, CT}

Container for all prognostic and diagnostic fields in the QG-YBJ+ model.

Type Parameters

  • T: Floating point type (Float64)
  • RT: Real array type (Array{T,3} or PencilArray{T,3})
  • CT: Complex array type (Array{Complex{T},3} or PencilArray{Complex{T},3})

Prognostic Fields (evolved in time)

  • q::CT: QG potential vorticity in spectral space
  • L⁺A::CT: YBJ+ wave envelope in spectral space

Diagnostic Fields (computed from prognostic)

  • psi::CT: Streamfunction ψ (from q via elliptic inversion)
  • A::CT: Wave amplitude (from L⁺A via YBJ+ inversion)
  • C::CT: Vertical derivative C = ∂A/∂z (for wave velocities)

Velocity Fields (real space)

  • u::RT: Zonal velocity u = -∂ψ/∂y
  • v::RT: Meridional velocity v = ∂ψ/∂x
  • w::RT: Vertical velocity (from omega equation or YBJ)

Array Dimensions

All arrays have shape (nz, nx, ny).

  • Spectral fields (q, psi, A, L⁺A, C): Complex arrays
  • Real-space fields (u, v, w): Real arrays

Physical Interpretation

The prognostic variables are:

  1. q: Quasi-geostrophic potential vorticity

    • Related to ψ by: q = ∇²ψ + (f²/N²)∂²ψ/∂z²
  2. L⁺A: YBJ+ wave envelope

    • Operator definitions (from PDF):
      • L (YBJ): L = ∂/∂z(f²/N² ∂/∂z) [eq. (4)]
      • L⁺ (YBJ+): L⁺ = L - k_h²/4 [spectral space]
    • Key relation: L = L⁺ + kh²/4, so LA = L⁺A + (kh²/4)A

Example

G = init_grid(par)
S = init_state(G)

# Access fields
q_spectral = S.q          # Complex (nz, nx, ny)
u_realspace = S.u         # Real (nz, nx, ny)

See also: init_state, Grid

source

Fields

Prognostic Fields (evolved in time):

FieldTypeDescription
qArray{ComplexF64,3}QG potential vorticity (spectral)
L⁺AArray{ComplexF64,3}YBJ+ wave envelope L⁺A where L⁺ = L - k_h²/4 (spectral)

Diagnostic Fields (computed from prognostic):

FieldTypeDescription
psiArray{ComplexF64,3}Streamfunction ψ (spectral)
AArray{ComplexF64,3}Wave amplitude (spectral, from L⁺A via inversion)
CArray{ComplexF64,3}Vertical derivative ∂A/∂z (spectral)

Velocity Fields (real space):

FieldTypeDescription
uArray{Float64,3}Zonal velocity u = -∂ψ/∂y
vArray{Float64,3}Meridional velocity v = ∂ψ/∂x
wArray{Float64,3}Vertical velocity (from omega equation)
LA_realArray{Float64,3}Real part of wave velocity amplitude LA
LA_imagArray{Float64,3}Imaginary part of wave velocity amplitude LA
Leapfrog Time-Stepping

The leapfrog scheme uses separate State objects (Snm1, Sn, Snp1) rather than storing previous time levels within a single State struct. This design allows proper handling of MPI parallel arrays (PencilArrays).

Constructors

# Create empty state from grid
state = init_state(grid)

# Copy state (preserves PencilArray topology for MPI)
state_copy = copy_state(state)

Copying States

For MPI parallel runs, always use copy_state instead of deepcopy:

# CORRECT: preserves pencil topology
Snm1 = copy_state(S)

# WRONG: breaks PencilArray transpose operations
Snm1 = deepcopy(S)  # Causes "pencil topologies must be the same" error

Accessing Fields

# Prognostic field (complex, spectral)
L⁺A = state.L⁺A    # size (nz, nx, ny), uses Unicode identifier

# Diagnostic fields (complex, spectral)
psi_k = state.psi  # size (nz, nx, ny)
A = state.A        # size (nz, nx, ny)

# Physical fields (real)
u = state.u        # size (nz, nx, ny)
v = state.v        # size (nz, nx, ny)
LA_real = state.LA_real  # Real part of wave velocity amplitude
LA_imag = state.LA_imag  # Imaginary part of wave velocity amplitude

FFT Plans

FFTW plan structures for efficient transforms.

Creating Plans

# Standard plans
plans = plan_transforms!(grid)

# With optimization
plans = plan_transforms!(grid; flags=FFTW.MEASURE)

# With threading
FFTW.set_num_threads(8)
plans = plan_transforms!(grid)

Using Transforms

# Forward transform: Physical → Spectral
fft_forward!(dst, src, plans)

# Backward transform: Spectral → Physical
fft_backward!(dst, src, plans)

Setup Model

The setup_model function is the recommended way to initialize all components:

par = default_params(Lx=500e3, Ly=500e3, Lz=4000.0, nx=64, ny=64, nz=32)
G, S, plans, a_ell = setup_model(par)

This returns:

  • G: Grid structure
  • S: State structure
  • plans: FFT plans
  • a_ell: Elliptic coefficient array for PV inversion

For non-constant stratification, use:

par = default_params(Lx=500e3, Ly=500e3, Lz=4000.0, stratification=:skewed_gaussian)
G, S, plans, a_ell, N2_profile = setup_model_with_profile(par)

Type Hierarchy

QGParams{T}     - Model parameters

Grid            - Spatial grid and wavenumbers

State           - Prognostic and diagnostic fields

Type Stability

All core types are fully type-stable:

using Test
@inferred init_state(grid)
@inferred leapfrog_step!(state, grid, params, plans, a_ell)

Serialization

Types support JLD2 serialization:

using JLD2

# Save
@save "simulation.jld2" grid params state

# Load
@load "simulation.jld2" grid params state