Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/Whitespace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Whitespace

permissions: {}

on:
push:
branches:
- 'main'
pull_request:

jobs:
whitespace:
name: Check whitespace
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: Checkout the repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Checkout the JuliaLang/julia repository
uses: actions/checkout@v6
with:
persist-credentials: false
repository: 'JuliaLang/julia'
# Clone Julia in a subdir.
path: '.julia'
# Check out a fixed revision to avoid surprises in case the script is
# changed in the future.
ref: '3b12a882e887753e4d2e9e9db65d99d3f7d9e26b'
- uses: julia-actions/setup-julia@v2
with:
version: '1.12.4'
- name: Check whitespace
run: |
.julia/contrib/check-whitespace.jl
18 changes: 9 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Oceananigans.jl is a Julia package for fast, friendly, flexible, ocean-flavored fluid dynamics simulations on CPUs and GPUs.
It provides a framework for solving the incompressible (or Boussinesq) Navier-Stokes equations with various model configurations including:
- Nonhydrostatic models with free surfaces
- Hydrostatic models for large-scale ocean simulations
- Hydrostatic models for large-scale ocean simulations
- Shallow water models
- Support for a variety of grids: RectilinearGrid, LatitudeLongitudeGrid, CubedSphereGrid
- Support for complex domains using ImmersedBoundaryGrid
Expand All @@ -22,10 +22,10 @@ It provides a framework for solving the incompressible (or Boussinesq) Navier-St
1. **Explicit Imports**: Use `ExplicitImports.jl` style - explicitly import all used functions/types
- Import from modules explicitly (already done in src/Oceananigans.jl)
- Tests automatically check for proper imports

2. **Type Stability**: Prioritize type-stable code for performance
- All structs must be concretely typed

3. **Kernel Functions**: For GPU compatibility:
- Use KernelAbstractions.jl syntax for kernels, eg `@kernel`, `@index`
- Keep kernels type-stable and allocation-free
Expand All @@ -35,7 +35,7 @@ It provides a framework for solving the incompressible (or Boussinesq) Navier-St
- Mark functions called inside kernels with `@inline`
- **Never use loops outside kernels**: Always replace `for` loops that iterate over grid points
with kernels launched via `launch!`. This ensures code works on both CPU and GPU.

4. **Documentation**:
- Use DocStringExtensions.jl for consistent docstrings
- Include `$(SIGNATURES)` for automatic signature documentation
Expand All @@ -53,7 +53,7 @@ It provides a framework for solving the incompressible (or Boussinesq) Navier-St
- **NonhydrostaticModel**: `NonhydrostaticModel(grid; ...)` - `grid` is positional
- **ShallowWaterModel**: `ShallowWaterModel(grid; gravitational_acceleration, ...)` - both `grid` and `gravitational_acceleration` are positional
- **Important**: When there are no keyword arguments, omit the semicolon:
- ✅ `NonhydrostaticModel(grid)`
- ✅ `NonhydrostaticModel(grid)`
- ❌ `NonhydrostaticModel(grid;)`
- When keyword arguments are present, use the semicolon:
- ✅ `NonhydrostaticModel(grid; closure=nothing)`
Expand Down Expand Up @@ -350,7 +350,7 @@ serve(dir="docs/build")
When implementing a simulation from a published paper:

### 1. Parameter Extraction
- **Read the paper carefully** and extract ALL parameters: domain size, resolution, physical constants,
- **Read the paper carefully** and extract ALL parameters: domain size, resolution, physical constants,
boundary conditions, initial conditions, forcing, closure parameters
- Look for parameter tables (often "Table 1" or similar)
- Check figure captions for additional details
Expand Down Expand Up @@ -393,11 +393,11 @@ Before running a long simulation:
- Quantitative comparison: compute the same diagnostics as the paper

### 7. Common Issues
- **NaN blowups**: Usually from timestep too large, unstable initial conditions,
- **NaN blowups**: Usually from timestep too large, unstable initial conditions,
or if-else statements on GPU (use `ifelse` instead)
- **Nothing happening**: Check that buoyancy anomaly has the right sign,
- **Nothing happening**: Check that buoyancy anomaly has the right sign,
that initial conditions are actually applied, that forcing is active
- **Wrong direction of flow**: Check coordinate conventions (is y increasing
- **Wrong direction of flow**: Check coordinate conventions (is y increasing
upslope or downslope?)
- **GPU issues**: Avoid branching, ensure type stability, use `randn()` carefully

Expand Down
1 change: 0 additions & 1 deletion benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,3 @@ Run distributed benchmarks by running the launcher scripts for either the shallo
## Measuring performance regression

Running the `benchmark_regression.jl` script will run the nonhydrostatic model tests on the current branch and on the main branch for comparison. This is useful to test whether the current branch slows down the code or introduces any performance regression.

1 change: 0 additions & 1 deletion benchmark/benchmark_regression.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ for (case, trial) in results
println("Results for $case")
display(trial)
end

1 change: 0 additions & 1 deletion benchmark/benchmarkable_nonhydrostatic_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ for Arch in Architectures, N in Ns

SUITE[(Arch, N)] = benchmark
end

15 changes: 7 additions & 8 deletions docs/src/developer_docs/model_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ implement (or inherit sane fallbacks for) the items listed below.
- `update_state!(model, callbacks=[]; compute_tendencies=true)`: invoked by
Simulation right after `initialize!` and inside most time steppers. This is
where models fill halos, update boundary conditions, recompute auxiliary
fields, and run [`Callback`](@ref callbacks)s with an `UpdateStateCallsite`.
PDE-based models typically finish by calling `compute_tendencies!(model, callbacks)`
fields, and run [`Callback`](@ref callbacks)s with an `UpdateStateCallsite`.
PDE-based models typically finish by calling `compute_tendencies!(model, callbacks)`
so that any `TendencyCallsite` callbacks can modify tendencies before integration.
Note that `compute_tendencies!` is not part of the required interface—it is simply
a useful pattern for models that integrate differential equations.

- `time_step!(model, Δt; callbacks=[])`: advances the model clock and its
prognostic variables by one step. Simulation hands in the tuple of
`ModelCallsite` [`Callback`](@ref callbacks)s so the model can execute
`TendencyCallsite` (before tendencies are applied) and `UpdateStateCallsite`
callbacks (after auxiliary updates). The method must call `tick!(model.clock, Δt)`
`ModelCallsite` [`Callback`](@ref callbacks)s so the model can execute
`TendencyCallsite` (before tendencies are applied) and `UpdateStateCallsite`
callbacks (after auxiliary updates). The method must call `tick!(model.clock, Δt)`
(or equivalent) so that `time(model)` and `iteration(model)` remain consistent.

- `set!(model, kw...)`: not strictly required, but strongly recommended as an
Expand Down Expand Up @@ -241,8 +241,8 @@ fig

This minimal implementation inherits all other behavior from the generic
`AbstractModel` fallbacks: Simulation can query `time(sim.model)`, diagnostics
can read `sim.model.clock`, and [`Callback`](@ref callbacks)s scheduled on
`ModelCallsite`s execute because `time_step!` forwards the tuple that Simulation
can read `sim.model.clock`, and [`Callback`](@ref callbacks)s scheduled on
`ModelCallsite`s execute because `time_step!` forwards the tuple that Simulation
hands to it. Note that this model has no grid, no fields, and no time-stepper object—just
the essentials. Larger models can follow the same recipe while adding grids,
fields, closures, and time steppers as needed.
Expand Down Expand Up @@ -411,4 +411,3 @@ operators within a custom `AbstractModel`. The key additions compared to the
- Third-order Runge-Kutta (RK3) time-stepping using Williamson's low-storage scheme
- Using `fill_halo_regions!` in `update_state!` to maintain periodic boundary conditions
- Leveraging `AbstractOperations` (`∂x`) for computing spatial derivatives via broadcasting

24 changes: 12 additions & 12 deletions docs/src/developer_docs/turbulence_closures.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ Good display methods help users understand their closures:
```@example pp_closure
using Oceananigans.Utils: prettysummary

Base.summary(closure::PPVD{TD}) where TD =
Base.summary(closure::PPVD{TD}) where TD =
string("PacanowskiPhilanderVerticalDiffusivity{$TD}")

function Base.show(io::IO, closure::PPVD)
Expand Down Expand Up @@ -277,7 +277,7 @@ We'll create a helper function to set up and run simulations:
```@example pp_closure
function run_boundary_layer(closure; stop_time)
grid = RectilinearGrid(size=Nz, z=(-Lz, 0), topology=(Flat, Flat, Bounded))

u_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(τˣ))
b_bcs = FieldBoundaryConditions(top = FluxBoundaryCondition(Jᵇ))

Expand All @@ -287,13 +287,13 @@ function run_boundary_layer(closure; stop_time)
tracers = :b,
coriolis = FPlane(f=f),
boundary_conditions = (u=u_bcs, b=b_bcs))

set!(model, b = z -> N² * z) # linear stratification

simulation = Simulation(model; Δt=10minutes, stop_time)
conjure_time_step_wizard!(simulation, cfl=0.5, max_Δt=10minutes)
run!(simulation)

return model
end
nothing # hide
Expand Down Expand Up @@ -331,22 +331,22 @@ z_tked = znodes(model_tked.tracers.b)
ax1 = Axis(fig[1, 1], xlabel="Buoyancy (m s⁻²)", ylabel="z (m)",
title="Buoyancy profile")

lpp = lines!(ax1, interior(model_pp.tracers.b, 1, 1, :), z_pp,
lpp = lines!(ax1, interior(model_pp.tracers.b, 1, 1, :), z_pp,
label="Pacanowski-Philander", linewidth=2)
lcatke = lines!(ax1, interior(model_catke.tracers.b, 1, 1, :), z_catke,
lcatke = lines!(ax1, interior(model_catke.tracers.b, 1, 1, :), z_catke,
label="CATKE", linewidth=2, linestyle=:dash)
ltked = lines!(ax1, interior(model_tked.tracers.b, 1, 1, :), z_tked,
ltked = lines!(ax1, interior(model_tked.tracers.b, 1, 1, :), z_tked,
label="TKE-Dissipation", linewidth=2, linestyle=:dot)

## Velocity profiles
ax2 = Axis(fig[1, 2], xlabel="Velocity (m s⁻¹)", ylabel="z (m)",
title="Zonal velocity")

lines!(ax2, interior(model_pp.velocities.u, 1, 1, :), z_pp,
lines!(ax2, interior(model_pp.velocities.u, 1, 1, :), z_pp,
label="PP", linewidth=2)
lines!(ax2, interior(model_catke.velocities.u, 1, 1, :), z_catke,
lines!(ax2, interior(model_catke.velocities.u, 1, 1, :), z_catke,
label="CATKE", linewidth=2, linestyle=:dash)
lines!(ax2, interior(model_tked.velocities.u, 1, 1, :), z_tked,
lines!(ax2, interior(model_tked.velocities.u, 1, 1, :), z_tked,
label="TKE-ϵ", linewidth=2, linestyle=:dot)

## Diffusivity profiles
Expand Down Expand Up @@ -472,7 +472,7 @@ If you'd like to contribute your closure to Oceananigans itself, here are the ad

### 1. Create a source file

Place your implementation in a file under
Place your implementation in a file under
`src/TurbulenceClosures/turbulence_closure_implementations/`. For example:

```
Expand Down
1 change: 0 additions & 1 deletion docs/src/field_time_series.md
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
# FieldTimeSeries

1 change: 0 additions & 1 deletion docs/src/gallery.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,3 @@ the fine details at the surface as it cools and the layers of different temperat
by internal waves.

[![Watch free convection with wind stress in action](https://raw.githubusercontent.com/ali-ramadhan/ali-ramadhan.Github.io/master/img/wind_stress_unstable_7500.png)](https://www.youtube.com/watch?v=ob6OMQgPfI4)

1 change: 0 additions & 1 deletion docs/src/models/stokes_drift.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,3 @@ The function signature for [`StokesDrift`](@ref) depends on the grid topology:
functions are called as `f(x, z, t)` (the ``y`` coordinate is omitted).
- When `parameters` is provided, it is passed as an additional final argument:
`f(x, y, z, t, parameters)` or `f(x, z, t, parameters)`.

2 changes: 1 addition & 1 deletion docs/src/numerical_implementation/elliptic_solvers.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ along with homogenous Neumann boundary conditions ``\boldsymbol{v} \cdot \boldsy
denotes the source term for the Poisson equation.

!!! note "Dividing small timesteps"
In practice, in order to avoid division by extremely small numbers when ``\Delta t \lesssim \epsilon``,
In practice, in order to avoid division by extremely small numbers when ``\Delta t \lesssim \epsilon``,
we solve the Poisson equation for ``p_{NH} \Delta t`` instead.
``\Delta t`` is then removed from the pressure field after the elliptic solve routine.

Expand Down
78 changes: 39 additions & 39 deletions docs/src/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ BinaryOperation at (Center, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
* at (Center, Center, Center)
   ├── 2
   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── 2
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
```

and even by chaining expressions together, which may themselves include `AbstractOperations`,
Expand All @@ -57,13 +57,13 @@ MultiaryOperation at (Center, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
+ at (Center, Center, Center)
   ├── ^ at (Center, Center, Center)
   │   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   │   └── 2
   ├── * at (Center, Center, Center)
   │   ├── 2
   │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   └── 1
├── ^ at (Center, Center, Center)
├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
├── * at (Center, Center, Center)
├── 2
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 1
```

Like `Field`s, `AbstractOperations` have a location and a grid.
Expand All @@ -77,7 +77,7 @@ UnaryOperation at (Center, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
cos at (Center, Center, Center) via identity
   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
```

```jldoctest operations
Expand All @@ -88,10 +88,10 @@ MultiaryOperation at (Center, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
+ at (Center, Center, Center)
   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   ├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
├── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
```

`UnaryOperation`, `BinaryOperation` and `MultiaryOperation` all have both an "operator", and between 1 and many.
Expand All @@ -105,7 +105,7 @@ Derivative at (Face, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
∂xᶠᶜᶜ at (Face, Center, Center) via identity
   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
```

!!! note
Expand Down Expand Up @@ -158,14 +158,14 @@ BinaryOperation at (Face, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
+ at (Face, Center, Center)
   ├── ^ at (Face, Center, Center)
   │   ├── ∂xᶠᶜᶜ at (Face, Center, Center) via identity
   │   │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   │   └── 2
   └── ^ at (Center, Center, Face)
      ├── ∂zᶜᶜᶠ at (Center, Center, Face) via identity
      │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
      └── 2
├── ^ at (Face, Center, Center)
├── ∂xᶠᶜᶜ at (Face, Center, Center) via identity
│ │ └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
└── ^ at (Center, Center, Face)
├── ∂zᶜᶜᶠ at (Center, Center, Face) via identity
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
```

Because `∂x(c)^2` is located at `(Face, Center, Center)` and `∂z(c)^2` is located at `(Center, Center, Face)`,
Expand All @@ -181,14 +181,14 @@ BinaryOperation at (Center, Center, Face)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
+ at (Center, Center, Face)
   ├── ^ at (Center, Center, Face)
   │   ├── ∂zᶜᶜᶠ at (Center, Center, Face) via identity
   │   │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   │   └── 2
   └── ^ at (Face, Center, Center)
      ├── ∂xᶠᶜᶜ at (Face, Center, Center) via identity
      │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
      └── 2
├── ^ at (Center, Center, Face)
├── ∂zᶜᶜᶠ at (Center, Center, Face) via identity
│ │ └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
└── ^ at (Face, Center, Center)
├── ∂xᶠᶜᶜ at (Face, Center, Center) via identity
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
```

ends up at `(Center, Center, Face)`. To control the location of an operation we use the macro `@at`,
Expand All @@ -201,14 +201,14 @@ BinaryOperation at (Center, Center, Center)
├── grid: 4×1×4 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 3×0×3 halo
└── tree:
+ at (Center, Center, Center)
   ├── ^ at (Center, Center, Center)
   │   ├── ∂xᶠᶜᶜ at (Center, Center, Center) via ℑxᶜᵃᵃ
   │   │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
   │   └── 2
   └── ^ at (Center, Center, Center)
      ├── ∂zᶜᶜᶠ at (Center, Center, Center) via ℑzᵃᵃᶜ
      │   └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
      └── 2
├── ^ at (Center, Center, Center)
├── ∂xᶠᶜᶜ at (Center, Center, Center) via ℑxᶜᵃᵃ
│ │ └── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
└── ^ at (Center, Center, Center)
├── ∂zᶜᶜᶠ at (Center, Center, Center) via ℑzᵃᵃᶜ
└── 4×1×4 Field{Center, Center, Center} on RectilinearGrid on CPU
└── 2
```

## Averages and integrals
Expand Down
1 change: 0 additions & 1 deletion docs/src/physics/boussinesq.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,3 @@ abuse notation a bit and denote the kinematic pressure simply as ``p``.
for an oceanographic introduction to the Boussinesq equations and Vallis (2017, Section 2.A)
for an asymptotic derivation. See Kundu (2015, Section 4.9) for an engineering
introduction.

Loading