diff --git a/Project.toml b/Project.toml index ac7cc1f90f..9515cd291a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Oceananigans" uuid = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" authors = ["Climate Modeling Alliance and contributors"] -version = "0.90.11" +version = "0.90.12" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" diff --git a/docs/src/model_setup/background_fields.md b/docs/src/model_setup/background_fields.md index c99dc7421e..d9cbac2493 100644 --- a/docs/src/model_setup/background_fields.md +++ b/docs/src/model_setup/background_fields.md @@ -58,7 +58,7 @@ 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 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo ├── clock: Clock(time=0 seconds, iteration=0, last_Δt=Inf days) └── parameters: nothing ``` @@ -101,7 +101,7 @@ 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 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo ├── clock: Clock(time=0 seconds, iteration=0, last_Δt=Inf days) └── parameters: (α = 3.14, N = 1.0, f = 0.1) ``` diff --git a/docs/src/model_setup/boundary_conditions.md b/docs/src/model_setup/boundary_conditions.md index 857b5f1f45..0f73bbd614 100644 --- a/docs/src/model_setup/boundary_conditions.md +++ b/docs/src/model_setup/boundary_conditions.md @@ -454,11 +454,11 @@ julia> velocity_bcs = FieldBoundaryConditions(immersed=ValueBoundaryCondition(0. julia> model = NonhydrostaticModel(; grid, boundary_conditions=(u=velocity_bcs, v=velocity_bcs, w=velocity_bcs)); ┌ Warning: `ImmersedBoundaryCondition` is experimental. -└ @ Oceananigans.ImmersedBoundaries ~/repos/Oceananigans.jl3/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 +└ @ Oceananigans.ImmersedBoundaries ~/Oceananigans.jl/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 ┌ Warning: `ImmersedBoundaryCondition` is experimental. -└ @ Oceananigans.ImmersedBoundaries ~/repos/Oceananigans.jl3/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 +└ @ Oceananigans.ImmersedBoundaries ~/Oceananigans.jl/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 ┌ Warning: `ImmersedBoundaryCondition` is experimental. -└ @ Oceananigans.ImmersedBoundaries ~/repos/Oceananigans.jl3/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 +└ @ Oceananigans.ImmersedBoundaries ~/Oceananigans.jl/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 julia> model.velocities.w.boundary_conditions.immersed ImmersedBoundaryCondition: @@ -477,7 +477,7 @@ cells may also be specified by manually building an `ImmersedBoundaryCondition`: ```jldoctest; filter = r".*@ Oceananigans.ImmersedBoundaries.*" julia> bottom_drag_bc = ImmersedBoundaryCondition(bottom=ValueBoundaryCondition(0.0)) ┌ Warning: `ImmersedBoundaryCondition` is experimental. -└ @ Oceananigans.ImmersedBoundaries ~/repos/Oceananigans.jl3/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 +└ @ Oceananigans.ImmersedBoundaries ~/Oceananigans.jl/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 ImmersedBoundaryCondition: ├── west: Nothing ├── east: Nothing @@ -532,7 +532,7 @@ FluxBoundaryCondition: ContinuousBoundaryFunction immersed_linear_drag at (Nothi julia> u_immersed_bc = ImmersedBoundaryCondition(bottom = immersed_drag_u) ┌ Warning: `ImmersedBoundaryCondition` is experimental. -└ @ Oceananigans.ImmersedBoundaries ~/repos/Oceananigans.jl3/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 +└ @ Oceananigans.ImmersedBoundaries ~/Oceananigans.jl/src/ImmersedBoundaries/immersed_boundary_condition.jl:54 ImmersedBoundaryCondition: ├── west: Nothing ├── east: Nothing diff --git a/docs/src/model_setup/output_writers.md b/docs/src/model_setup/output_writers.md index 20ce934d17..8d1ee230b3 100644 --- a/docs/src/model_setup/output_writers.md +++ b/docs/src/model_setup/output_writers.md @@ -205,7 +205,7 @@ JLD2OutputWriter scheduled on TimeInterval(20 minutes): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 27.4 KiB +└── file size: 27.2 KiB ``` and a time- and horizontal-average of tracer `c` every 20 minutes of simulation time @@ -223,7 +223,7 @@ JLD2OutputWriter scheduled on TimeInterval(20 minutes): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 17.5 KiB +└── file size: 17.3 KiB ``` @@ -280,5 +280,5 @@ JLD2OutputWriter scheduled on TimeInterval(4 days): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 26.7 KiB +└── file size: 26.5 KiB ``` diff --git a/src/AbstractOperations/binary_operations.jl b/src/AbstractOperations/binary_operations.jl index 31a0a80245..45956d239f 100644 --- a/src/AbstractOperations/binary_operations.jl +++ b/src/AbstractOperations/binary_operations.jl @@ -169,7 +169,7 @@ julia> c, d = (CenterField(RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1))) fo julia> plus_or_times(c, d) BinaryOperation at (Center, Center, Center) -├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo └── tree: plus_or_times at (Center, Center, Center)    ├── 1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU diff --git a/src/AbstractOperations/conditional_operations.jl b/src/AbstractOperations/conditional_operations.jl index 0b36c967a2..3b8ccc2879 100644 --- a/src/AbstractOperations/conditional_operations.jl +++ b/src/AbstractOperations/conditional_operations.jl @@ -61,7 +61,7 @@ julia> c = CenterField(RectilinearGrid(size=(2, 1, 1), extent=(1, 1, 1))); julia> f(i, j, k, grid, c) = i < 2; d = condition_operand(cos, c, f, 10) ConditionalOperation at (Center, Center, Center) ├── operand: 2×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU -├── grid: 2×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×1×1 halo ├── func: cos (generic function with 40 methods) ├── condition: f (generic function with 1 method) └── mask: 10 diff --git a/src/AbstractOperations/grid_metrics.jl b/src/AbstractOperations/grid_metrics.jl index a04dcb50b1..c7bee46871 100644 --- a/src/AbstractOperations/grid_metrics.jl +++ b/src/AbstractOperations/grid_metrics.jl @@ -49,7 +49,7 @@ julia> c = CenterField(RectilinearGrid(size=(1, 1, 1), extent=(1, 2, 3))); julia> c_dz = c * Δz # returns BinaryOperation between Field and GridMetricOperation BinaryOperation at (Center, Center, Center) -├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo └── tree: * at (Center, Center, Center)    ├── 1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU @@ -89,7 +89,7 @@ julia> c .= 1; julia> c_dV = c * volume BinaryOperation at (Center, Center, Center) -├── grid: 2×2×2 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×2×2 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×2×2 halo └── tree: * at (Center, Center, Center)    ├── 2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU diff --git a/src/AbstractOperations/kernel_function_operation.jl b/src/AbstractOperations/kernel_function_operation.jl index dbd89365ac..16363bb51c 100644 --- a/src/AbstractOperations/kernel_function_operation.jl +++ b/src/AbstractOperations/kernel_function_operation.jl @@ -29,13 +29,13 @@ struct KernelFunctionOperation{LX, LY, LZ, G, T, K, D} <: AbstractOperation{LX, grid = RectilinearGrid(size=(1, 8, 8), extent=(1, 1, 1)); random_kernel_function(i, j, k, grid) = rand(); # use CUDA.rand on the GPU - + kernel_op = KernelFunctionOperation{Center, Center, Center}(random_kernel_function, grid) # output KernelFunctionOperation at (Center, Center, Center) - ├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo + ├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×3×3 halo ├── kernel_function: random_kernel_function (generic function with 1 method) └── arguments: () ``` @@ -47,15 +47,15 @@ struct KernelFunctionOperation{LX, LY, LZ, G, T, K, D} <: AbstractOperation{LX, using Oceananigans.Operators: ζ₃ᶠᶠᶜ # called with signature ζ₃ᶠᶠᶜ(i, j, k, grid, u, v) model = HydrostaticFreeSurfaceModel(; grid); - + u, v, w = model.velocities; - + ζ_op = KernelFunctionOperation{Face, Face, Center}(ζ₃ᶠᶠᶜ, grid, u, v) # output KernelFunctionOperation at (Face, Face, Center) - ├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo + ├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×3×3 halo ├── kernel_function: ζ₃ᶠᶠᶜ (generic function with 1 method) └── arguments: ("1×8×8 Field{Face, Center, Center} on RectilinearGrid on CPU", "1×8×8 Field{Center, Face, Center} on RectilinearGrid on CPU") ``` diff --git a/src/AbstractOperations/multiary_operations.jl b/src/AbstractOperations/multiary_operations.jl index b09168c4d0..f9301da5e4 100644 --- a/src/AbstractOperations/multiary_operations.jl +++ b/src/AbstractOperations/multiary_operations.jl @@ -80,7 +80,7 @@ julia> c, d, e = Tuple(CenterField(RectilinearGrid(size=(1, 1, 1), extent=(1, 1, julia> harmonic_plus(c, d, e) # before magic @multiary transformation BinaryOperation at (Center, Center, Center) -├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo └── tree: * at (Center, Center, Center)    ├── 0.3333333333333333 @@ -103,7 +103,7 @@ Set{Any} with 3 elements: julia> harmonic_plus(c, d, e) MultiaryOperation at (Center, Center, Center) -├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo └── tree: harmonic_plus at (Center, Center, Center)    ├── 1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU diff --git a/src/AbstractOperations/unary_operations.jl b/src/AbstractOperations/unary_operations.jl index 7c917a2132..4515c84951 100644 --- a/src/AbstractOperations/unary_operations.jl +++ b/src/AbstractOperations/unary_operations.jl @@ -72,7 +72,7 @@ julia> c = CenterField(RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1))); julia> square_it(c) UnaryOperation at (Center, Center, Center) -├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×1×1 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×1×1 halo └── tree: square_it at (Center, Center, Center) via identity    └── 1×1×1 Field{Center, Center, Center} on RectilinearGrid on CPU diff --git a/src/BuoyancyModels/buoyancy.jl b/src/BuoyancyModels/buoyancy.jl index 7ae87e40b1..8acf985821 100644 --- a/src/BuoyancyModels/buoyancy.jl +++ b/src/BuoyancyModels/buoyancy.jl @@ -30,7 +30,7 @@ model = NonhydrostaticModel(; grid, buoyancy, tracers=:b) # output NonhydrostaticModel{CPU, RectilinearGrid}(time = 0 seconds, iteration = 0) -├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 1×8×8 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 1×3×3 halo ├── timestepper: QuasiAdamsBashforth2TimeStepper ├── advection scheme: Centered reconstruction order 2 ├── tracers: b diff --git a/src/Fields/field.jl b/src/Fields/field.jl index d0b82dcedd..13f3b21b35 100644 --- a/src/Fields/field.jl +++ b/src/Fields/field.jl @@ -122,10 +122,10 @@ julia> grid = RectilinearGrid(size=(2, 3, 4), extent=(1, 1, 1)); julia> ω = Field{Face, Face, Center}(grid) 2×3×4 Field{Face, Face, Center} on RectilinearGrid on CPU -├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo ├── boundary conditions: FieldBoundaryConditions │ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux -└── data: 8×9×10 OffsetArray(::Array{Float64, 3}, -2:5, -2:6, -2:7) with eltype Float64 with indices -2:5×-2:6×-2:7 +└── data: 6×9×10 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, -2:7) with eltype Float64 with indices -1:4×-2:6×-2:7 └── max=0.0, min=0.0, mean=0.0 ``` @@ -138,24 +138,24 @@ julia> u = XFaceField(grid); v = YFaceField(grid); julia> ωₛ = Field(∂x(v) - ∂y(u), indices=(:, :, grid.Nz)) 2×3×1 Field{Face, Face, Center} on RectilinearGrid on CPU -├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo ├── boundary conditions: FieldBoundaryConditions │ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux ├── indices: (:, :, 4:4) ├── operand: BinaryOperation at (Face, Face, Center) ├── status: time=0.0 -└── data: 8×9×1 OffsetArray(::Array{Float64, 3}, -2:5, -2:6, 4:4) with eltype Float64 with indices -2:5×-2:6×4:4 +└── data: 6×9×1 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, 4:4) with eltype Float64 with indices -1:4×-2:6×4:4 └── max=0.0, min=0.0, mean=0.0 julia> compute!(ωₛ) 2×3×1 Field{Face, Face, Center} on RectilinearGrid on CPU -├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo ├── boundary conditions: FieldBoundaryConditions │ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: Nothing, top: Nothing, immersed: ZeroFlux ├── indices: (:, :, 4:4) ├── operand: BinaryOperation at (Face, Face, Center) ├── status: time=0.0 -└── data: 8×9×1 OffsetArray(::Array{Float64, 3}, -2:5, -2:6, 4:4) with eltype Float64 with indices -2:5×-2:6×4:4 +└── data: 6×9×1 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, 4:4) with eltype Float64 with indices -1:4×-2:6×4:4 └── max=0.0, min=0.0, mean=0.0 ``` """ @@ -276,21 +276,21 @@ julia> grid = RectilinearGrid(size=(2, 3, 4), x=(0, 1), y=(0, 1), z=(0, 1)); julia> c = CenterField(grid) 2×3×4 Field{Center, Center, Center} on RectilinearGrid on CPU -├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo ├── boundary conditions: FieldBoundaryConditions │ └── west: Periodic, east: Periodic, south: Periodic, north: Periodic, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux -└── data: 8×9×10 OffsetArray(::Array{Float64, 3}, -2:5, -2:6, -2:7) with eltype Float64 with indices -2:5×-2:6×-2:7 +└── data: 6×9×10 OffsetArray(::Array{Float64, 3}, -1:4, -2:6, -2:7) with eltype Float64 with indices -1:4×-2:6×-2:7 └── max=0.0, min=0.0, mean=0.0 julia> c .= rand(size(c)...); julia> v = view(c, :, 2:3, 1:2) 2×2×2 Field{Center, Center, Center} on RectilinearGrid on CPU -├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 3×3×3 halo +├── grid: 2×3×4 RectilinearGrid{Float64, Periodic, Periodic, Bounded} on CPU with 2×3×3 halo ├── boundary conditions: FieldBoundaryConditions │ └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: Nothing, top: Nothing, immersed: ZeroFlux ├── indices: (:, 2:3, 1:2) -└── data: 8×2×2 OffsetArray(view(::Array{Float64, 3}, :, 5:6, 4:5), -2:5, 2:3, 1:2) with eltype Float64 with indices -2:5×2:3×1:2 +└── data: 6×2×2 OffsetArray(view(::Array{Float64, 3}, :, 5:6, 4:5), -1:4, 2:3, 1:2) with eltype Float64 with indices -1:4×2:3×1:2 └── max=0.972136, min=0.0149088, mean=0.59198 julia> size(v) diff --git a/src/Grids/automatic_halo_sizing.jl b/src/Grids/automatic_halo_sizing.jl index 12a96ab0db..bfc6870923 100644 --- a/src/Grids/automatic_halo_sizing.jl +++ b/src/Grids/automatic_halo_sizing.jl @@ -1,7 +1,7 @@ """ required_halo_size(tendency_term) -Returns the required size of halos for a term appearing +Return the required size of halos for a term appearing in the tendency for a velocity field or tracer field. Example diff --git a/src/Grids/input_validation.jl b/src/Grids/input_validation.jl index 55b55ce589..5007b1b55e 100644 --- a/src/Grids/input_validation.jl +++ b/src/Grids/input_validation.jl @@ -4,7 +4,9 @@ using Oceananigans: tupleit ##### Some validation tools ##### -# Tuple inflation for topologies with Flat dimensions +# Tuple inflation/deflation for topologies with Flat dimensions + +"adds tup element with `default` value for flat dimensions" inflate_tuple(TX, TY, TZ, tup; default) = tup inflate_tuple(::Type{Flat}, TY, TZ, tup; default) = tuple(default, tup[1], tup[2]) @@ -17,13 +19,26 @@ inflate_tuple(::Type{Flat}, ::Type{Flat}, TZ, tup; default) = (default, default, inflate_tuple(::Type{Flat}, ::Type{Flat}, ::Type{Flat}, tup; default) = (default, default, default) +"removes tup elements that correspond to flat dimensions" +deflate_tuple(TX, TY, TZ, tup) = tup + +deflate_tuple(::Type{Flat}, TY, TZ, tup) = tuple(tup[2], tup[3]) +deflate_tuple(TY, ::Type{Flat}, TZ, tup) = tuple(tup[1], tup[3]) +deflate_tuple(TY, TZ, ::Type{Flat}, tup) = tuple(tup[1], tup[2]) + +deflate_tuple(TX, ::Type{Flat}, ::Type{Flat}, tup) = (tup[1],) +deflate_tuple(::Type{Flat}, TY, ::Type{Flat}, tup) = (tup[2],) +deflate_tuple(::Type{Flat}, ::Type{Flat}, TZ, tup) = (tup[3],) + +deflate_tuple(::Type{Flat}, ::Type{Flat}, ::Type{Flat}, tup) = () + topological_tuple_length(TX, TY, TZ) = sum(T === Flat ? 0 : 1 for T in (TX, TY, TZ)) """Validate that an argument tuple is the right length and has elements of type `argtype`.""" function validate_tupled_argument(arg, argtype, argname, len=3; greater_than=0) - length(arg) == len || throw(ArgumentError("length($argname) must be $len.")) - all(isa.(arg, argtype)) || throw(ArgumentError("$argname=$arg must contain $(argtype)s.")) - all(arg .> greater_than) || throw(ArgumentError("Elements of $argname=$arg must be > $(greater_than)!")) + length(arg) == len || throw(ArgumentError("length($argname) must be $len.")) + all(isa.(arg, argtype)) || throw(ArgumentError("$argname=$arg must contain $(argtype)s.")) + all(arg .> greater_than) || throw(ArgumentError("Elements of $argname=$arg must be > $(greater_than)!")) return nothing end @@ -49,21 +64,31 @@ function validate_size(TX, TY, TZ, sz) return inflate_tuple(TX, TY, TZ, sz, default=1) end -# Note that the default halo size is specified to be 1 in the following function. -# This is easily changed but many of the tests will fail so this situation needs to be +# Note that if provided with halo=nothing, the default halo size for coord i +# is the min(default_halo_size, size[i]). +# While this is easy to change, many of tests might fail so this situation needs to be # cleaned up. -function validate_halo(TX, TY, TZ, ::Nothing) - halo = Tuple(3 for i = 1:topological_tuple_length(TX, TY, TZ)) - return validate_halo(TX, TY, TZ, halo) +function validate_halo(TX, TY, TZ, size, ::Nothing) + maximum_halo = size + default_halo = (3, 3, 3) + halo = map(min, default_halo, maximum_halo) + halo = deflate_tuple(TX, TY, TZ, halo) + return validate_halo(TX, TY, TZ, size, halo) end -function validate_halo(TX, TY, TZ, halo) +coordinate_name(i) = i == 1 ? "x" : i == 2 ? "y" : "z" + +function validate_halo(TX, TY, TZ, size, halo) halo = tupleit(halo) validate_tupled_argument(halo, Integer, "halo", topological_tuple_length(TX, TY, TZ)) - return inflate_tuple(TX, TY, TZ, halo, default=0) -end + halo = inflate_tuple(TX, TY, TZ, halo, default=0) -coordinate_name(i) = i == 1 ? "x" : i == 2 ? "y" : "z" + for i in 1:2 + !(halo[i] ≤ size[i]) && throw(ArgumentError("halo must be ≤ size for coordinate $(coordinate_name(i))")) + end + + return halo +end function validate_dimension_specification(T, ξ, dir, N, FT) diff --git a/src/Grids/latitude_longitude_grid.jl b/src/Grids/latitude_longitude_grid.jl index 91e28b1318..eab9f81dd2 100644 --- a/src/Grids/latitude_longitude_grid.jl +++ b/src/Grids/latitude_longitude_grid.jl @@ -272,7 +272,7 @@ function validate_lat_lon_grid_args(topology, size, halo, FT, latitude, longitud latitude = validate_dimension_specification(TY, latitude, :latitude, Nφ, FT) z = validate_dimension_specification(TZ, z, :z, Nz, FT) - halo = validate_halo(TX, TY, TZ, halo) + halo = validate_halo(TX, TY, TZ, size, halo) topology = (TX, TY, TZ) return topology, size, halo, latitude, longitude, z, precompute_metrics diff --git a/src/Grids/orthogonal_spherical_shell_grid.jl b/src/Grids/orthogonal_spherical_shell_grid.jl index e160b41360..6cb488917e 100644 --- a/src/Grids/orthogonal_spherical_shell_grid.jl +++ b/src/Grids/orthogonal_spherical_shell_grid.jl @@ -790,17 +790,15 @@ function conformal_cubed_sphere_panel(filepath::AbstractString, architecture = C TX, TY, TZ = topology Hx, Hy, Hz = halo - ## Use a regular rectilinear grid for the vertical grid ## The vertical coordinates can come out of the regular rectilinear grid! - ξ, η = (-1, 1), (-1, 1) - ξη_grid = RectilinearGrid(architecture, FT; size = (1, 1, Nz), x = ξ, y = η, z, topology, halo) + z_grid = RectilinearGrid(architecture, FT; size = Nz, z, topology=(Flat, Flat, topology[3]), halo=halo[3]) - zᵃᵃᶠ = ξη_grid.zᵃᵃᶠ - zᵃᵃᶜ = ξη_grid.zᵃᵃᶜ - Δzᵃᵃᶜ = ξη_grid.Δzᵃᵃᶜ - Δzᵃᵃᶠ = ξη_grid.Δzᵃᵃᶠ - Lz = ξη_grid.Lz + zᵃᵃᶠ = z_grid.zᵃᵃᶠ + zᵃᵃᶜ = z_grid.zᵃᵃᶜ + Δzᵃᵃᶜ = z_grid.Δzᵃᵃᶜ + Δzᵃᵃᶠ = z_grid.Δzᵃᵃᶠ + Lz = z_grid.Lz ## Read everything else from the file @@ -851,7 +849,7 @@ function conformal_cubed_sphere_panel(filepath::AbstractString, architecture = C φᶠᶜᵃ = offset_data(zeros(FT, architecture, Txᶠᶜ, Tyᶠᶜ), loc_fc, topology[1:2], N[1:2], H[1:2]) φᶜᶠᵃ = offset_data(zeros(FT, architecture, Txᶜᶠ, Tyᶜᶠ), loc_cf, topology[1:2], N[1:2], H[1:2]) - conformal_mapping = (; ξ, η) + conformal_mapping = (ξ = (-1, 1), η = (-1, 1)) return OrthogonalSphericalShellGrid{TX, TY, TZ}(architecture, Nξ, Nη, Nz, Hx, Hy, Hz, Lz, λᶜᶜᵃ, λᶠᶜᵃ, λᶜᶠᵃ, λᶠᶠᵃ, diff --git a/src/Grids/rectilinear_grid.jl b/src/Grids/rectilinear_grid.jl index 90deab5bbf..56cb892d4e 100644 --- a/src/Grids/rectilinear_grid.jl +++ b/src/Grids/rectilinear_grid.jl @@ -289,7 +289,7 @@ end function validate_rectilinear_grid_args(topology, size, halo, FT, extent, x, y, z) TX, TY, TZ = topology = validate_topology(topology) size = validate_size(TX, TY, TZ, size) - halo = validate_halo(TX, TY, TZ, halo) + halo = validate_halo(TX, TY, TZ, size, halo) # Validate the rectilinear domain x, y, z = validate_rectilinear_domain(TX, TY, TZ, FT, size, extent, x, y, z) diff --git a/src/Models/HydrostaticFreeSurfaceModels/distributed_split_explicit_free_surface.jl b/src/Models/HydrostaticFreeSurfaceModels/distributed_split_explicit_free_surface.jl index 0dbcd5eb66..6f0afa5a26 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/distributed_split_explicit_free_surface.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/distributed_split_explicit_free_surface.jl @@ -84,8 +84,8 @@ end Rx, Ry, _ = architecture(grid).ranks - Ax = Rx == 1 ? old_halos[1] : step_halo - Ay = Ry == 1 ? old_halos[2] : step_halo + Ax = Rx == 1 ? old_halos[1] : max(step_halo, old_halos[1]) + Ay = Ry == 1 ? old_halos[2] : max(step_halo, old_halos[2]) return (Ax, Ay, old_halos[3]) end diff --git a/src/Models/HydrostaticFreeSurfaceModels/explicit_free_surface.jl b/src/Models/HydrostaticFreeSurfaceModels/explicit_free_surface.jl index 5138a4f755..56fd8d0049 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/explicit_free_surface.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/explicit_free_surface.jl @@ -28,10 +28,7 @@ on_architecture(to, free_surface::ExplicitFreeSurface) = ExplicitFreeSurface(on_architecture(to, free_surface.η), on_architecture(to, free_surface.gravitational_acceleration)) -##### -##### Interface to HydrostaticFreeSurfaceModel -##### - +# Internal function for HydrostaticFreeSurfaceModel function materialize_free_surface(free_surface::ExplicitFreeSurface{Nothing}, velocities, grid) η = free_surface_displacement_field(velocities, free_surface, grid) g = convert(eltype(grid), free_surface.gravitational_acceleration) diff --git a/src/Models/HydrostaticFreeSurfaceModels/set_hydrostatic_free_surface_model.jl b/src/Models/HydrostaticFreeSurfaceModels/set_hydrostatic_free_surface_model.jl index 113568457b..915d0989d8 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/set_hydrostatic_free_surface_model.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/set_hydrostatic_free_surface_model.jl @@ -60,6 +60,7 @@ model.velocities.u @apply_regionally set!(ϕ, value) end + initialize!(model) update_state!(model) return nothing diff --git a/src/Models/HydrostaticFreeSurfaceModels/single_column_model_mode.jl b/src/Models/HydrostaticFreeSurfaceModels/single_column_model_mode.jl index e3e5d8b3c5..99679aec10 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/single_column_model_mode.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/single_column_model_mode.jl @@ -108,7 +108,7 @@ end ColumnEnsembleSize(; Nz, ensemble=(0, 0), Hz=1) = ColumnEnsembleSize(ensemble, Nz, Hz) validate_size(TX, TY, TZ, e::ColumnEnsembleSize) = tuple(e.ensemble[1], e.ensemble[2], e.Nz) -validate_halo(TX, TY, TZ, e::ColumnEnsembleSize) = tuple(0, 0, e.Hz) +validate_halo(TX, TY, TZ, size, e::ColumnEnsembleSize) = tuple(0, 0, e.Hz) @inline function time_discretization(closure_array::AbstractArray) first_closure = @allowscalar first(closure_array) # assumes all closures have same time-discretization diff --git a/src/Models/HydrostaticFreeSurfaceModels/slice_ensemble_model_mode.jl b/src/Models/HydrostaticFreeSurfaceModels/slice_ensemble_model_mode.jl index 2dec04fc46..d9fda68ef1 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/slice_ensemble_model_mode.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/slice_ensemble_model_mode.jl @@ -41,7 +41,7 @@ end SliceEnsembleSize(; size, ensemble=0, halo=(1, 1)) = SliceEnsembleSize(ensemble, size[1], size[2], halo[1], halo[2]) validate_size(TX, TY, TZ, e::SliceEnsembleSize) = tuple(e.ensemble, e.Ny, e.Nz) -validate_halo(TX, TY, TZ, e::SliceEnsembleSize) = tuple(0, e.Hy, e.Hz) +validate_halo(TX, TY, TZ, size, e::SliceEnsembleSize) = tuple(0, e.Hy, e.Hz) ##### ##### CATKEVerticalDiffusivity helpers diff --git a/src/Models/HydrostaticFreeSurfaceModels/split_explicit_free_surface_kernels.jl b/src/Models/HydrostaticFreeSurfaceModels/split_explicit_free_surface_kernels.jl index 1700126983..cc80086529 100644 --- a/src/Models/HydrostaticFreeSurfaceModels/split_explicit_free_surface_kernels.jl +++ b/src/Models/HydrostaticFreeSurfaceModels/split_explicit_free_surface_kernels.jl @@ -347,7 +347,7 @@ const FTS = FixedTimeStepSize # we set a minimum number of substeps to execute to avoid numerical issues const MINIMUM_SUBSTEPS = 5 -@inline calculate_substeps(substepping::FNS, Δt) = length(substepping.averaging_weights) +@inline calculate_substeps(substepping::FNS, Δt=nothing) = length(substepping.averaging_weights) @inline calculate_substeps(substepping::FTS, Δt) = max(MINIMUM_SUBSTEPS, ceil(Int, 2 * Δt / substepping.Δt_barotropic)) @inline calculate_adaptive_settings(substepping::FNS, substeps) = substepping.fractional_step_size, substepping.averaging_weights diff --git a/src/MultiRegion/cubed_sphere_connectivity.jl b/src/MultiRegion/cubed_sphere_connectivity.jl index fb2a534e74..117744314f 100644 --- a/src/MultiRegion/cubed_sphere_connectivity.jl +++ b/src/MultiRegion/cubed_sphere_connectivity.jl @@ -73,8 +73,8 @@ struct CubedSphereRegionalConnectivity{S, FS, R} <: AbstractConnectivity julia> CubedSphereRegionalConnectivity(1, 2, East(), West()) CubedSphereRegionalConnectivity - ├── from: Oceananigans.MultiRegion.West side, region 2 - ├── to: Oceananigans.MultiRegion.East side, region 1 + ├── from: Oceananigans.MultiRegion.West side, region 2 + ├── to: Oceananigans.MultiRegion.East side, region 1 └── no rotation ``` @@ -84,8 +84,8 @@ struct CubedSphereRegionalConnectivity{S, FS, R} <: AbstractConnectivity ```jldoctest cubedsphereconnectivity julia> CubedSphereRegionalConnectivity(1, 3, North(), East(), ↺()) CubedSphereRegionalConnectivity - ├── from: Oceananigans.MultiRegion.East side, region 3 - ├── to: Oceananigans.MultiRegion.North side, region 1 + ├── from: Oceananigans.MultiRegion.East side, region 3 + ├── to: Oceananigans.MultiRegion.North side, region 1 └── counter-clockwise rotation ↺ ``` """ diff --git a/src/MultiRegion/multi_region_cubed_sphere_grid.jl b/src/MultiRegion/multi_region_cubed_sphere_grid.jl index 27ba7f3e60..4a665e39c5 100644 --- a/src/MultiRegion/multi_region_cubed_sphere_grid.jl +++ b/src/MultiRegion/multi_region_cubed_sphere_grid.jl @@ -152,28 +152,28 @@ julia> using Oceananigans.MultiRegion: East, North, West, South julia> for region in 1:length(grid); println(grid.connectivity.connections[region].south); end CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.North side, region 6 -├── to: Oceananigans.MultiRegion.South side, region 1 +├── from: Oceananigans.MultiRegion.North side, region 6 +├── to: Oceananigans.MultiRegion.South side, region 1 └── no rotation CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.East side, region 6 -├── to: Oceananigans.MultiRegion.South side, region 2 +├── from: Oceananigans.MultiRegion.East side, region 6 +├── to: Oceananigans.MultiRegion.South side, region 2 └── counter-clockwise rotation ↺ CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.North side, region 2 -├── to: Oceananigans.MultiRegion.South side, region 3 +├── from: Oceananigans.MultiRegion.North side, region 2 +├── to: Oceananigans.MultiRegion.South side, region 3 └── no rotation CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.East side, region 2 -├── to: Oceananigans.MultiRegion.South side, region 4 +├── from: Oceananigans.MultiRegion.East side, region 2 +├── to: Oceananigans.MultiRegion.South side, region 4 └── counter-clockwise rotation ↺ CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.North side, region 4 -├── to: Oceananigans.MultiRegion.South side, region 5 +├── from: Oceananigans.MultiRegion.North side, region 4 +├── to: Oceananigans.MultiRegion.South side, region 5 └── no rotation CubedSphereRegionalConnectivity -├── from: Oceananigans.MultiRegion.East side, region 4 -├── to: Oceananigans.MultiRegion.South side, region 6 +├── from: Oceananigans.MultiRegion.East side, region 4 +├── to: Oceananigans.MultiRegion.South side, region 6 └── counter-clockwise rotation ↺ ``` """ diff --git a/src/MultiRegion/multi_region_grid.jl b/src/MultiRegion/multi_region_grid.jl index 225134031d..0e789f17dd 100644 --- a/src/MultiRegion/multi_region_grid.jl +++ b/src/MultiRegion/multi_region_grid.jl @@ -51,7 +51,7 @@ minimum_spacing(dir, grid::MultiRegionGrid, ℓx, ℓy, ℓz) = # the default free surface solver; see Models.HydrostaticFreeSurfaceModels default_free_surface(grid::MultiRegionGrid; gravitational_acceleration=g_Earth) = - ImplicitFreeSurface(; gravitational_acceleration) + SplitExplicitFreeSurface(; substeps=50, gravitational_acceleration) """ MultiRegionGrid(global_grid; partition = XPartition(2), @@ -82,22 +82,23 @@ Keyword Arguments Example ======= -```@example +```jldoctest; filter = r".*@ Oceananigans.MultiRegion.*" julia> using Oceananigans -julia> grid = RectilinearGrid(size=(10, 12), extent=(1, 1), topology=(Bounded, Bounded, Flat)) -10×12×1 RectilinearGrid{Float64, Bounded, Bounded, Flat} on CPU with 3×3×0 halo -├── Bounded x ∈ [0.0, 1.0] regularly spaced with Δx=0.1 +julia> grid = RectilinearGrid(size=(12, 12), extent=(1, 1), topology=(Bounded, Bounded, Flat)) +12×12×1 RectilinearGrid{Float64, Bounded, Bounded, Flat} on CPU with 3×3×0 halo +├── Bounded x ∈ [0.0, 1.0] regularly spaced with Δx=0.0833333 ├── Bounded y ∈ [0.0, 1.0] regularly spaced with Δy=0.0833333 └── Flat z -julia> multi_region_grid = MultiRegionGrid(grid, partition = XPartition(5)) +julia> multi_region_grid = MultiRegionGrid(grid, partition = XPartition(4)) ┌ Warning: MultiRegion functionalities are experimental: help the development by reporting bugs or non-implemented features! -└ @ Oceananigans.MultiRegion ~/Research/OC.jl/src/MultiRegion/multi_region_grid.jl:53 -MultiRegionGrid{Float64, Bounded, Bounded, Flat} partitioned on CPU(): -├── grids: 2×12×1 RectilinearGrid{Float64, RightConnected, Bounded, Flat} on CPU with 3×3×0 halo -├── partitioning: Equal partitioning in X with (5 regions) -└── devices: (CPU(), CPU(), CPU(), CPU(), CPU()) +└ @ Oceananigans.MultiRegion ~/Research/OC11.jl/src/MultiRegion/multi_region_grid.jl:108 +MultiRegionGrid{Float64, Bounded, Bounded, Flat} partitioned on CPU(): +├── grids: 3×12×1 RectilinearGrid{Float64, RightConnected, Bounded, Flat} on CPU with 3×3×0 halo +├── partitioning: Equal partitioning in X with (4 regions) +├── connectivity: MultiRegionObject{Tuple{@NamedTuple{west::Nothing, east::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.East, Oceananigans.MultiRegion.West}, north::Nothing, south::Nothing}, @NamedTuple{west::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.West, Oceananigans.MultiRegion.East}, east::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.East, Oceananigans.MultiRegion.West}, north::Nothing, south::Nothing}, @NamedTuple{west::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.West, Oceananigans.MultiRegion.East}, east::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.East, Oceananigans.MultiRegion.West}, north::Nothing, south::Nothing}, @NamedTuple{west::Oceananigans.MultiRegion.RegionalConnectivity{Oceananigans.MultiRegion.West, Oceananigans.MultiRegion.East}, east::Nothing, north::Nothing, south::Nothing}}, NTuple{4, CPU}} +└── devices: (CPU(), CPU(), CPU(), CPU()) ``` """ function MultiRegionGrid(global_grid; partition = XPartition(2), diff --git a/src/MultiRegion/multi_region_split_explicit_free_surface.jl b/src/MultiRegion/multi_region_split_explicit_free_surface.jl index 67246b3615..fb36463b39 100644 --- a/src/MultiRegion/multi_region_split_explicit_free_surface.jl +++ b/src/MultiRegion/multi_region_split_explicit_free_surface.jl @@ -2,7 +2,9 @@ using Oceananigans.Utils using Oceananigans.AbstractOperations: GridMetricOperation, Δz using Oceananigans.Models.HydrostaticFreeSurfaceModels: SplitExplicitFreeSurface, SplitExplicitSettings, - SplitExplicitState + SplitExplicitState, + FixedSubstepNumber, FixedTimeStepSize, + calculate_substeps import Oceananigans.Models.HydrostaticFreeSurfaceModels: materialize_free_surface, SplitExplicitAuxiliaryFields @@ -44,14 +46,17 @@ end # Internal function for HydrostaticFreeSurfaceModel function materialize_free_surface(free_surface::SplitExplicitFreeSurface, velocities, grid::MultiRegionGrids) - settings = SplitExplicitSettings(grid; free_surface.settings.settings_kwargs...) + settings.substepping isa FixedTimeStepSize && + throw(ArgumentError("SplitExplicitFreeSurface on MultiRegionGrids only suports FixedSubstepNumber; re-initialize SplitExplicitFreeSurface using substeps kwarg")) + switch_device!(grid.devices[1]) + old_halos = halo_size(getregion(grid, 1)) - Nsubsteps = length(settings.substepping.averaging_weights) + Nsubsteps = calculate_substeps(settings.substepping) - new_halos = multiregion_split_explicit_halos(old_halos, Nsubsteps+1, grid.partition) + new_halos = multiregion_split_explicit_halos(old_halos, Nsubsteps+1, grid.partition) new_grid = with_halo(new_halos, grid) η = ZFaceField(new_grid, indices = (:, :, size(new_grid, 3)+1)) @@ -63,5 +68,5 @@ function materialize_free_surface(free_surface::SplitExplicitFreeSurface, veloci free_surface.settings) end -@inline multiregion_split_explicit_halos(old_halos, step_halo, ::XPartition) = (step_halo, old_halos[2], old_halos[3]) -@inline multiregion_split_explicit_halos(old_halos, step_halo, ::YPartition) = (old_halos[1], step_halo, old_halos[3]) +@inline multiregion_split_explicit_halos(old_halos, step_halo, ::XPartition) = (max(step_halo, old_halos[1]), old_halos[2], old_halos[3]) +@inline multiregion_split_explicit_halos(old_halos, step_halo, ::YPartition) = (old_halos[1], max(step_halo, old_halo[2]), old_halos[3]) diff --git a/src/OutputWriters/jld2_output_writer.jl b/src/OutputWriters/jld2_output_writer.jl index 1298a1c584..b97ccbf2b4 100644 --- a/src/OutputWriters/jld2_output_writer.jl +++ b/src/OutputWriters/jld2_output_writer.jl @@ -141,7 +141,7 @@ JLD2OutputWriter scheduled on TimeInterval(20 minutes): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 27.4 KiB +└── file size: 27.2 KiB ``` and a time- and horizontal-average of tracer ``c`` every 20 minutes of simulation time @@ -159,7 +159,7 @@ JLD2OutputWriter scheduled on TimeInterval(20 minutes): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 17.5 KiB +└── file size: 17.3 KiB ``` """ function JLD2OutputWriter(model, outputs; filename, schedule, diff --git a/src/OutputWriters/windowed_time_average.jl b/src/OutputWriters/windowed_time_average.jl index 1a49615f48..914b33aa53 100644 --- a/src/OutputWriters/windowed_time_average.jl +++ b/src/OutputWriters/windowed_time_average.jl @@ -78,7 +78,7 @@ JLD2OutputWriter scheduled on TimeInterval(4 days): ├── array type: Array{Float64} ├── including: [:grid, :coriolis, :buoyancy, :closure] ├── file_splitting: NoFileSplitting -└── file size: 26.7 KiB +└── file size: 26.5 KiB ``` """ function AveragedTimeInterval(interval; window=interval, stride=1) diff --git a/test/test_boundary_conditions_integration.jl b/test/test_boundary_conditions_integration.jl index d817dc9180..1f7a9ae84a 100644 --- a/test/test_boundary_conditions_integration.jl +++ b/test/test_boundary_conditions_integration.jl @@ -222,7 +222,7 @@ test_boundary_conditions(C, FT, ArrayType) = (integer_bc(C, FT, ArrayType), bottom(x, y) = 0 ib = GridFittedBottom(bottom) - grid_kw = (size = (1, 1, 2), x = (0, Lx), y = (0, Ly)) + grid_kw = (size = (2, 2, 2), x = (0, Lx), y = (0, Ly)) rectilinear_grid(topology) = RectilinearGrid(arch; topology, z=(0, Lz), grid_kw...) immersed_rectilinear_grid(topology) = ImmersedBoundaryGrid(RectilinearGrid(arch; topology, z=(-Lz, Lz), grid_kw...), ib) diff --git a/test/test_dynamics.jl b/test/test_dynamics.jl index 9fb74e37d3..99b03f6699 100644 --- a/test/test_dynamics.jl +++ b/test/test_dynamics.jl @@ -36,7 +36,7 @@ function test_diffusion_budget(fieldname, field, model, κ, Δ, order=2) update_state!(model) Δt = 1e-4 * Δ^order / κ # small to suppress non-conservative time-discretization error - for n = 1:10 + for _ in 1:10 time_step!(model, Δt) end @@ -63,15 +63,18 @@ function test_ScalarBiharmonicDiffusivity_budget(fieldname, model) end function test_diffusion_cosine(fieldname, grid, closure, ξ, tracers=:c) - κ, m = 1, 2 # diffusivity and cosine wavenumber model = NonhydrostaticModel(; grid, closure, tracers, buoyancy=nothing) field = fields(model)[fieldname] + + m = 2 # cosine wavenumber field .= cos.(m * ξ) update_state!(model) - # Step forward with small time-step relative to diff. time-scale + κ = 1 # the diffusivity + + # Step forward with small time-step relative to diffusive time scale Δt = 1e-6 * grid.Lz^2 / κ - for n = 1:5 + for _ = 1:5 time_step!(model, Δt) end @@ -86,7 +89,7 @@ function test_immersed_diffusion(Nz, z, time_discretization) closure = ScalarDiffusivity(time_discretization, κ = 1) underlying_grid = RectilinearGrid(size=Nz, z=z, topology=(Flat, Flat, Bounded)) grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(() -> 0)) - + Δz_min = minimum(underlying_grid.Δzᵃᵃᶜ) model_kwargs = (tracers=:c, buoyancy=nothing, velocities=PrescribedVelocityFields()) @@ -99,7 +102,7 @@ function test_immersed_diffusion(Nz, z, time_discretization) Δt = Δz_min^2 / closure.κ * 1e-1 - for n = 1:100 + for _ in 1:100 time_step!(full_model, Δt) time_step!(immersed_model, Δt) end @@ -142,12 +145,12 @@ function test_3D_immersed_diffusion(Nz, z, time_discretization) Δt = Δz_min^2 / closure.κ * 1e-1 - for n = 1:100 + for _ in 1:100 time_step!(full_model , Δt) time_step!(immersed_model, Δt) end - half = Int(grid.Nz/2 + 1) + half = Int(grid.Nz/2 + 1) assesment = Array{Bool}(undef, 4) @@ -176,7 +179,7 @@ function passive_tracer_advection_test(timestepper; N=128, κ=1e-12, Nt=100, bac Δt = 0.05 * L/N / sqrt(U^2 + V^2) - T(x, y, z, t) = exp( -((x - U*t - x₀)^2 + (y - V*t - y₀)^2) / (2*δ^2) ) + T(x, y, z, t) = exp(-((x - U * t - x₀)^2 + (y - V * t - y₀)^2) / 2δ^2 ) u₀(x, y, z) = U v₀(x, y, z) = V T₀(x, y, z) = T(x, y, z, 0) @@ -219,8 +222,8 @@ function taylor_green_vortex_test(arch, timestepper, time_discretization; FT=Flo Δt = (1/10π) * Δx^2 / ν # Taylor-Green vortex analytic solution. - @inline u(x, y, z, t) = -sin(2π*y) * exp(-4π^2 * ν * t) - @inline v(x, y, z, t) = sin(2π*x) * exp(-4π^2 * ν * t) + @inline u(x, y, z, t) = -sin(2π * y) * exp(-4π^2 * ν * t) + @inline v(x, y, z, t) = sin(2π * x) * exp(-4π^2 * ν * t) model = NonhydrostaticModel( timestepper = timestepper, @@ -233,7 +236,7 @@ function taylor_green_vortex_test(arch, timestepper, time_discretization; FT=Flo v₀(x, y, z) = v(x, y, z, 0) set!(model, u=u₀, v=v₀) - for n in 1:Nt + for _ in 1:Nt time_step!(model, Δt) end @@ -550,7 +553,7 @@ timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) # Immersed grid cases immersed_vertical_grid = ImmersedBoundaryGrid(RectilinearGrid(arch, - size = (1, 1, 2N), + size = (2, 2, 2N), x = (0, 1), y = (0, 1), z = (0, 2L), @@ -571,7 +574,7 @@ timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) stretched_z_grid = RectilinearGrid(arch, size=N, z=center_clustered_coord(N, L, 0), topology=(Flat, Flat, Bounded)) stretched_immersed_z_grid = ImmersedBoundaryGrid(RectilinearGrid(arch, - size = (1, 1, 2N), + size = (2, 2, 2N), x = (0, 1), y = (0, 1), z = center_clustered_coord(2N, 2L, 0), @@ -586,7 +589,7 @@ timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) vertical_scalar_diffusivity, implicit_vertical_scalar_diffusivity]) append!(grids, stretched_grids) - + # Run the tests for case = 1:length(grids) closure = closures[case] @@ -600,7 +603,7 @@ timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) end end end - + #= @testset "Gaussian immersed diffusion" begin for time_discretization in (ExplicitTimeDiscretization(), VerticallyImplicitTimeDiscretization()) @@ -731,4 +734,5 @@ timesteppers = (:QuasiAdamsBashforth2, :RungeKutta3) end end end + =# end diff --git a/test/test_field.jl b/test/test_field.jl index 2392ccc896..2383afaab3 100644 --- a/test/test_field.jl +++ b/test/test_field.jl @@ -367,7 +367,7 @@ end big_halo = (3, 3, 3) small_halo = (1, 1, 1) domain = (; x=(0, 1), y=(0, 1), z=(0, 1)) - sz = (1, 1, 1) + sz = (3, 3, 3) grid = RectilinearGrid(arch, FT; halo=big_halo, size=sz, domain...) a = CenterField(grid) diff --git a/test/test_forcings.jl b/test/test_forcings.jl index 414a8301b4..51c9b30a40 100644 --- a/test/test_forcings.jl +++ b/test/test_forcings.jl @@ -134,7 +134,7 @@ function relaxed_time_stepping(arch) end function advective_and_multiple_forcing(arch) - grid = RectilinearGrid(arch, size=(2, 2, 3), extent=(1, 1, 1), halo=(4, 4, 4)) + grid = RectilinearGrid(arch, size=(4, 5, 6), extent=(1, 1, 1), halo=(4, 4, 4)) constant_slip = AdvectiveForcing(w=1) zero_slip = AdvectiveForcing(w=0) diff --git a/test/test_grids.jl b/test/test_grids.jl index 3d9204893c..8e008e143b 100644 --- a/test/test_grids.jl +++ b/test/test_grids.jl @@ -295,17 +295,17 @@ function test_flat_size_regular_rectilinear_grid(FT) @test flat_size_regular_rectilinear_grid(FT, topology=(Flat, Flat, Flat), size=(), extent=()) === (1, 1, 1) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Periodic), size=(1, 1), extent=(1, 1), halo=nothing) === (0, 3, 3) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Bounded), size=(1, 1), extent=(1, 1), halo=nothing) === (3, 0, 3) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Bounded, Flat), size=(1, 1), extent=(1, 1), halo=nothing) === (3, 3, 0) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Periodic), size=(3, 3), extent=(1, 1), halo=nothing) === (0, 3, 3) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Bounded), size=(3, 3), extent=(1, 1), halo=nothing) === (3, 0, 3) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Bounded, Flat), size=(3, 3), extent=(1, 1), halo=nothing) === (3, 3, 0) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Periodic), size=(1, 1), extent=(1, 1), halo=(2, 3)) === (0, 2, 3) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Bounded), size=(1, 1), extent=(1, 1), halo=(2, 3)) === (2, 0, 3) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Bounded, Flat), size=(1, 1), extent=(1, 1), halo=(2, 3)) === (2, 3, 0) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Periodic), size=(3, 3), extent=(1, 1), halo=(2, 3)) === (0, 2, 3) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Bounded), size=(3, 3), extent=(1, 1), halo=(2, 3)) === (2, 0, 3) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Bounded, Flat), size=(3, 3), extent=(1, 1), halo=(2, 3)) === (2, 3, 0) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Flat), size=1, extent=1, halo=2) === (2, 0, 0) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Flat), size=1, extent=1, halo=2) === (0, 2, 0) - @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Flat, Bounded), size=1, extent=1, halo=2) === (0, 0, 2) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Periodic, Flat, Flat), size=2, extent=1, halo=2) === (2, 0, 0) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Periodic, Flat), size=2, extent=1, halo=2) === (0, 2, 0) + @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Flat, Bounded), size=2, extent=1, halo=2) === (0, 0, 2) @test flat_halo_regular_rectilinear_grid(FT, topology=(Flat, Flat, Flat), size=(), extent=(), halo=()) === (0, 0, 0) diff --git a/test/test_hydrostatic_free_surface_immersed_boundaries.jl b/test/test_hydrostatic_free_surface_immersed_boundaries.jl index d262813b66..887c55e3f1 100644 --- a/test/test_hydrostatic_free_surface_immersed_boundaries.jl +++ b/test/test_hydrostatic_free_surface_immersed_boundaries.jl @@ -58,7 +58,7 @@ using Oceananigans.TurbulenceClosures # A spherical domain underlying_grid = LatitudeLongitudeGrid(arch, - size = (Nx, Ny, 1), + size = (Nx, Ny, 2), longitude = (-30, 30), latitude = (15, 75), z = (-4000, 0)) @@ -104,7 +104,6 @@ using Oceananigans.TurbulenceClosures tracers = nothing, buoyancy = nothing) - simulation = Simulation(model, Δt=3600, stop_iteration=1) run!(simulation) @@ -124,12 +123,12 @@ using Oceananigans.TurbulenceClosures extent = (Nx, Ny, 3), topology = (Periodic, Periodic, Bounded)) - # B for bathymetry - B = [-3. for i=1:Nx, j=1:Ny ] - B[2:Nx-1, 2:Ny-1] .= [-2 for i=2:Nx-1, j=2:Ny-1 ] - B[3:Nx-2, 3:Ny-2] .= [-1 for i=3:Nx-2, j=3:Ny-2 ] + bathymetry = [-3.0 for j=1:Ny, i=1:Nx] + bathymetry[2:Nx-1, 2:Ny-1] .= [-2 for j=2:Ny-1, i=2:Nx-1] + bathymetry[3:Nx-2, 3:Ny-2] .= [-1 for j=3:Ny-2, i=3:Nx-2] + bathymetry = on_architecture(arch, bathymetry) - grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(B)) + grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(bathymetry)) model = HydrostaticFreeSurfaceModel(; grid, free_surface = ImplicitFreeSurface(solver_method = :PreconditionedConjugateGradient), diff --git a/test/test_hydrostatic_free_surface_models.jl b/test/test_hydrostatic_free_surface_models.jl index 58c15a1455..c2c48d4133 100644 --- a/test/test_hydrostatic_free_surface_models.jl +++ b/test/test_hydrostatic_free_surface_models.jl @@ -119,7 +119,7 @@ topos_3d = ((Periodic, Periodic, Bounded), @test_throws ArgumentError HydrostaticFreeSurfaceModel(grid=grid, closure=hcabd_closure) # Big enough - bigger_grid = RectilinearGrid(topology=topo, size=(1, 1, 1), extent=(1, 2, 3), halo=(3, 3, 3)) + bigger_grid = RectilinearGrid(topology=topo, size=(3, 3, 1), extent=(1, 2, 3), halo=(3, 3, 3)) model = HydrostaticFreeSurfaceModel(grid=bigger_grid, closure=hcabd_closure) @test model isa HydrostaticFreeSurfaceModel @@ -174,16 +174,19 @@ topos_3d = ((Periodic, Periodic, Bounded), z_face_generator(; Nz=1, p=1, H=1) = k -> -H + (k / (Nz+1))^p # returns a generating function - rectilinear_grid = RectilinearGrid(arch, size=(1, 1, 1), extent=(1, 1, 1), halo=(3, 3, 3)) + rectilinear_grid = RectilinearGrid(arch, size=(3, 3, 1), extent=(1, 1, 1), halo=(3, 3, 3)) + vertically_stretched_grid = RectilinearGrid(arch, size=(3, 3, 1), x=(0, 1), y=(0, 1), z=z_face_generator(), halo=(3, 3, 3)) - lat_lon_sector_grid = LatitudeLongitudeGrid(arch, size=(1, 1, 1), longitude=(0, 60), latitude=(15, 75), z=(-1, 0), precompute_metrics=true) - lat_lon_strip_grid = LatitudeLongitudeGrid(arch, size=(1, 1, 1), longitude=(-180, 180), latitude=(15, 75), z=(-1, 0), precompute_metrics=true) + lat_lon_sector_grid = LatitudeLongitudeGrid(arch, size=(3, 3, 3), longitude=(0, 60), latitude=(15, 75), z=(-1, 0), precompute_metrics=true) + lat_lon_strip_grid = LatitudeLongitudeGrid(arch, size=(3, 3, 3), longitude=(-180, 180), latitude=(15, 75), z=(-1, 0), precompute_metrics=true) - vertically_stretched_grid = RectilinearGrid(arch, size=(1, 1, 1), x=(0, 1), y=(0, 1), z=z_face_generator(), halo=(3, 3, 3)) - lat_lon_sector_grid_stretched = LatitudeLongitudeGrid(arch, size=(1, 1, 1), longitude=(0, 60), latitude=(15, 75), z=z_face_generator(), precompute_metrics=true) - lat_lon_strip_grid_stretched = LatitudeLongitudeGrid(arch, size=(1, 1, 1), longitude=(-180, 180), latitude=(15, 75), z=z_face_generator(), precompute_metrics=true) + lat_lon_sector_grid_stretched = LatitudeLongitudeGrid(arch, size=(3, 3, 3), longitude=(0, 60), latitude=(15, 75), z=z_face_generator(), precompute_metrics=true) + lat_lon_strip_grid_stretched = LatitudeLongitudeGrid(arch, size=(3, 3, 3), longitude=(-180, 180), latitude=(15, 75), z=z_face_generator(), precompute_metrics=true) + + grids = (rectilinear_grid, vertically_stretched_grid, + lat_lon_sector_grid, lat_lon_strip_grid, + lat_lon_sector_grid_stretched, lat_lon_strip_grid_stretched) - grids = (rectilinear_grid, lat_lon_sector_grid, lat_lon_strip_grid, lat_lon_sector_grid_stretched, lat_lon_strip_grid_stretched, vertically_stretched_grid) free_surfaces = (ExplicitFreeSurface(), ImplicitFreeSurface(), ImplicitFreeSurface(solver_method=:HeptadiagonalIterativeSolver)) for grid in grids diff --git a/test/test_implicit_free_surface_solver.jl b/test/test_implicit_free_surface_solver.jl index 2e4bc55a2f..d56c47562a 100644 --- a/test/test_implicit_free_surface_solver.jl +++ b/test/test_implicit_free_surface_solver.jl @@ -71,8 +71,8 @@ function run_implicit_free_surface_solver_tests(arch, grid, free_surface) g = g_Earth η = model.free_surface.η - ∫ᶻ_Axᶠᶜᶜ = Field{Face, Center, Nothing}(with_halo((3, 3, 1), grid)) - ∫ᶻ_Ayᶜᶠᶜ = Field{Center, Face, Nothing}(with_halo((3, 3, 1), grid)) + ∫ᶻ_Axᶠᶜᶜ = Field((Face, Center, Nothing), grid) + ∫ᶻ_Ayᶜᶠᶜ = Field((Center, Face, Nothing), grid) vertically_integrated_lateral_areas = (xᶠᶜᶜ = ∫ᶻ_Axᶠᶜᶜ, yᶜᶠᶜ = ∫ᶻ_Ayᶜᶠᶜ) @@ -101,10 +101,11 @@ end for arch in archs A = typeof(arch) - rectilinear_grid = RectilinearGrid(arch, size = (128, 1, 5), + rectilinear_grid = RectilinearGrid(arch, size = (128, 2, 5), x = (-5000kilometers, 5000kilometers), y = (0, 100kilometers), z = (-500, 0), + halo = (3, 2, 3), topology = (Bounded, Periodic, Bounded)) Lz = rectilinear_grid.Lz @@ -112,10 +113,11 @@ end bump(x, y) = - Lz * (1 - 0.2 * exp(-x^2 / 2width^2)) - underlying_grid = RectilinearGrid(arch, size = (128, 1, 5), + underlying_grid = RectilinearGrid(arch, size = (128, 2, 5), x = (-5000kilometers, 5000kilometers), y = (0, 100kilometers), z = [-500, -300, -220, -170, -60, 0], + halo = (3, 2, 3), topology = (Bounded, Periodic, Bounded)) bumpy_vertically_stretched_rectilinear_grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(bump)) diff --git a/test/test_multi_region_advection_diffusion.jl b/test/test_multi_region_advection_diffusion.jl index fdeebbc9b8..2f11e8449f 100644 --- a/test/test_multi_region_advection_diffusion.jl +++ b/test/test_multi_region_advection_diffusion.jl @@ -8,7 +8,7 @@ Gaussian(x, y, L) = exp(-(x^2 + y^2) / 2L^2) prescribed_velocities() = PrescribedVelocityFields(u=(λ, ϕ, z, t = 0) -> 0.1 * hack_cosd(ϕ)) -function Δ_min(grid) +function Δ_min(grid) Δx_min = minimum_xspacing(grid, Center(), Center(), Center()) Δy_min = minimum_yspacing(grid, Center(), Center(), Center()) return min(Δx_min, Δy_min) @@ -22,14 +22,18 @@ function solid_body_tracer_advection_test(grid; P = XPartition, regions = 1) devices = nothing end - mrg = MultiRegionGrid(grid, partition = P(regions), devices = devices) - if grid isa RectilinearGrid L = 0.1 else - L = 24 + L = 24 # degrees end + # Tracer patch parameters + cᵢ(x, y, z) = Gaussian(x, 0, L) + eᵢ(x, y, z) = Gaussian(x, y, L) + + mrg = MultiRegionGrid(grid, partition = P(regions), devices = devices) + model = HydrostaticFreeSurfaceModel(grid = mrg, tracers = (:c, :e), velocities = prescribed_velocities(), @@ -40,10 +44,6 @@ function solid_body_tracer_advection_test(grid; P = XPartition, regions = 1) buoyancy = nothing, closure = nothing) - # Tracer patch parameters - cᵢ(x, y, z) = Gaussian(x, 0, L) - eᵢ(x, y, z) = Gaussian(x, y, L) - set!(model, c=cᵢ, e=eᵢ) # Time-scale for tracer advection across the smallest grid cell; 0.1 is maximum velocity @@ -90,7 +90,7 @@ function solid_body_rotation_test(grid; P = XPartition, regions = 1) set!(model, u=uᵢ, η=ηᵢ, c=cᵢ) - @show Δt = 0.1 * Δ_min(grid) / sqrt(g * grid.Lz) + Δt = 0.1 * Δ_min(grid) / sqrt(g * grid.Lz) for _ in 1:10 time_step!(model, Δt) @@ -99,9 +99,7 @@ function solid_body_rotation_test(grid; P = XPartition, regions = 1) return merge(model.velocities, model.tracers, (; η = model.free_surface.η)) end -function diffusion_cosine_test(grid; P = XPartition, regions = 1, closure, field_name = :c) - κ, m = 1, 2 # diffusivity and cosine wavenumber - +function diffusion_cosine_test(grid; P = XPartition, regions = 1, closure, field_name = :c) if architecture(grid) isa GPU devices = (0, 0) else @@ -110,36 +108,44 @@ function diffusion_cosine_test(grid; P = XPartition, regions = 1, closure, fiel mrg = MultiRegionGrid(grid, partition = P(regions), devices = devices) - model = HydrostaticFreeSurfaceModel(grid = mrg, - coriolis = nothing, - closure = closure, + # For MultiRegionGrids with regions > 1, the SplitExplicitFreeSurface extends the + # halo region in the horizontal. Because the extented halo region size cannot exceed + # the grid's interior size we pick here the number of substeps taking the grid's + # size into consideration. + free_surface = SplitExplicitFreeSurface(substeps = 8) + + model = HydrostaticFreeSurfaceModel(; grid = mrg, + free_surface, + closure, tracers = :c, + coriolis = nothing, buoyancy=nothing) - initial_condition(x, y, z) = cos(m * x) - - f = fields(model)[field_name] + initial_condition(x, y, z) = cos(2x) - @apply_regionally set!(f, initial_condition) - - update_state!(model) + expr = quote + # we use set!(model, ...) so that initialize!(model) is called + # initialize!(model) is required for SplitExplicitFreeSurface + # so that the barotropic transport is initialized + set!($model, $field_name = $initial_condition) + end + eval(expr) # Step forward with small time-step relative to diffusive time-scale - Δt = 1e-6 * grid.Lz^2 / κ - for _ = 1:10 + Δt = 1e-6 * cell_diffusion_timescale(model) + + for _ in 1:10 time_step!(model, Δt) end - return f + return fields(model)[field_name] end -Nx = 32 -Ny = 32 +Nx = Ny = 32 partitioning = [XPartition] for arch in archs - grid_rect = RectilinearGrid(arch, size = (Nx, Ny, 1), halo = (3, 3, 3), @@ -157,28 +163,30 @@ for arch in archs radius = 1) @testset "Testing multi region tracer advection" begin - for grid in [grid_rect, grid_lat] + for grid in (grid_rect, grid_lat) - cs, es = solid_body_tracer_advection_test(grid) + # on a single grid + cs, es = solid_body_tracer_advection_test(grid, regions=1) cs = Array(interior(cs)) es = Array(interior(es)) - for regions in [2], P in partitioning + for regions in (2,), P in partitioning @info " Testing $regions $(P)s on $(typeof(grid).name.wrapper) on the $arch" c, e = solid_body_tracer_advection_test(grid; P=P, regions=regions) c = interior(reconstruct_global_field(c)) e = interior(reconstruct_global_field(e)) - @test all(c .≈ cs) - @test all(e .≈ es) + @test all(isapprox(c, cs, atol=1e-20, rtol=1e-15)) + @test all(isapprox(e, es, atol=1e-20, rtol=1e-15)) end end end @testset "Testing multi region solid body rotation" begin - grid = LatitudeLongitudeGrid(arch, size = (Nx, Ny, 1), + grid = LatitudeLongitudeGrid(arch, + size = (Nx, Ny, 1), halo = (3, 3, 3), latitude = (-80, 80), longitude = (-160, 160), @@ -186,7 +194,8 @@ for arch in archs radius = 1, topology=(Bounded, Bounded, Bounded)) - us, vs, ws, cs, ηs = solid_body_rotation_test(grid) + # on a single grid + us, vs, ws, cs, ηs = solid_body_rotation_test(grid, regions=1) us = Array(interior(us)) vs = Array(interior(vs)) @@ -194,7 +203,7 @@ for arch in archs cs = Array(interior(cs)) ηs = Array(interior(ηs)) - for regions in [2], P in partitioning + for regions in (2,), P in partitioning @info " Testing $regions $(P)s on $(typeof(grid).name.wrapper) on the $arch" u, v, w, c, η = solid_body_rotation_test(grid; P=P, regions=regions) @@ -204,16 +213,17 @@ for arch in archs c = interior(reconstruct_global_field(c)) η = interior(reconstruct_global_field(η)) - @test all(isapprox(u, us, atol=1e-20, rtol = 1e-15)) - @test all(isapprox(v, vs, atol=1e-20, rtol = 1e-15)) - @test all(isapprox(w, ws, atol=1e-20, rtol = 1e-15)) - @test all(isapprox(c, cs, atol=1e-20, rtol = 1e-15)) - @test all(isapprox(η, ηs, atol=1e-20, rtol = 1e-15)) + @test all(isapprox(u, us, atol=1e-20, rtol=1e-15)) + @test all(isapprox(v, vs, atol=1e-20, rtol=1e-15)) + @test all(isapprox(w, ws, atol=1e-20, rtol=1e-15)) + @test all(isapprox(c, cs, atol=1e-20, rtol=1e-15)) + @test all(isapprox(η, ηs, atol=1e-20, rtol=1e-15)) end end @testset "Testing multi region gaussian diffusion" begin - grid = RectilinearGrid(arch, size = (Nx, Ny, 1), + grid = RectilinearGrid(arch, + size = (Nx, Ny, 1), halo = (3, 3, 3), topology = (Bounded, Bounded, Bounded), x = (0, 1), @@ -223,19 +233,20 @@ for arch in archs diff₂ = ScalarDiffusivity(ν = 1, κ = 1) diff₄ = ScalarBiharmonicDiffusivity(ν = 1e-5, κ = 1e-5) - for fieldname in [:u, :v, :c] - for closure in [diff₂, diff₄] + for field_name in (:u, :v, :c) + for closure in (diff₂, diff₄) - fs = diffusion_cosine_test(grid; closure, field_name = fieldname) - fs = Array(interior(fs)); + # on a single grid + fs = diffusion_cosine_test(grid; closure, field_name, regions = 1) + fs = Array(interior(fs)) - for regions in [2], P in partitioning - @info " Testing diffusion of $fieldname on $regions $(P)s with $(typeof(closure).name.wrapper) on the $arch" + for regions in (2,), P in partitioning + @info " Testing diffusion of $field_name on $regions $(P)s with $(typeof(closure).name.wrapper) on $arch" - f = diffusion_cosine_test(grid; closure, P = P, field_name = fieldname, regions = regions) + f = diffusion_cosine_test(grid; closure, P, field_name, regions) f = interior(reconstruct_global_field(f)) - @test all(f .≈ fs) + @test all(isapprox(f, fs, atol=1e-20, rtol=1e-15)) end end end diff --git a/test/test_nonhydrostatic_models.jl b/test/test_nonhydrostatic_models.jl index e6ef49d559..dedc95c9ce 100644 --- a/test/test_nonhydrostatic_models.jl +++ b/test/test_nonhydrostatic_models.jl @@ -32,8 +32,8 @@ include("dependencies_for_runtests.jl") @testset "Adjustment of halos in NonhydrostaticModel constructor" begin @info " Testing adjustment of halos in NonhydrostaticModel constructor..." - minimal_grid = RectilinearGrid(size=(1, 1, 1), extent=(1, 2, 3), halo=(1, 1, 1)) - funny_grid = RectilinearGrid(size=(1, 1, 1), extent=(1, 2, 3), halo=(1, 3, 4)) + minimal_grid = RectilinearGrid(size=(4, 4, 4), extent=(1, 2, 3), halo=(1, 1, 1)) + funny_grid = RectilinearGrid(size=(4, 4, 4), extent=(1, 2, 3), halo=(1, 3, 4)) # Model ensures that halos are at least of size 1 model = NonhydrostaticModel(grid=minimal_grid) @@ -148,10 +148,10 @@ include("dependencies_for_runtests.jl") # Test whether set! copies boundary conditions # Note: we need to cleanup broadcasting for this -- see https://github.com/CliMA/Oceananigans.jl/pull/2786/files#r1008955571 - @test_skip u_cpu[1, 1, 1] == u_cpu[Nx+1, 1, 1] # x-periodicity - @test_skip u_cpu[1, 1, 1] == u_cpu[1, Ny+1, 1] # y-periodicity - @test_skip all(u_cpu[1:Nx, 1:Ny, 1] .== u_cpu[1:Nx, 1:Ny, 0]) # free slip at bottom - @test_skip all(u_cpu[1:Nx, 1:Ny, Nz] .== u_cpu[1:Nx, 1:Ny, Nz+1]) # free slip at top + @test u_cpu[1, 1, 1] == u_cpu[Nx+1, 1, 1] # x-periodicity + @test u_cpu[1, 1, 1] == u_cpu[1, Ny+1, 1] # y-periodicity + @test all(u_cpu[1:Nx, 1:Ny, 1] .== u_cpu[1:Nx, 1:Ny, 0]) # free slip at bottom + @test all(u_cpu[1:Nx, 1:Ny, Nz] .== u_cpu[1:Nx, 1:Ny, Nz+1]) # free slip at top # Test that enforce_incompressibility works set!(model, u=0, v=0, w=1, T=0, S=0) diff --git a/test/test_shallow_water_models.jl b/test/test_shallow_water_models.jl index 2e70999669..23dbddbc38 100644 --- a/test/test_shallow_water_models.jl +++ b/test/test_shallow_water_models.jl @@ -4,7 +4,7 @@ using Oceananigans.Models.ShallowWaterModels using Oceananigans.ImmersedBoundaries: ImmersedBoundaryGrid, GridFittedBoundary function time_stepping_shallow_water_model_works(arch, topo, coriolis, advection; timestepper=:RungeKutta3) - grid = RectilinearGrid(arch, size=(1, 1), extent=(2π, 2π), topology=topo) + grid = RectilinearGrid(arch, size=(3, 3), extent=(2π, 2π), topology=topo) model = ShallowWaterModel(grid=grid, gravitational_acceleration=1, coriolis=coriolis, momentum_advection=advection, timestepper=:RungeKutta3) set!(model, h=1) @@ -16,7 +16,7 @@ function time_stepping_shallow_water_model_works(arch, topo, coriolis, advection end function time_step_wizard_shallow_water_model_works(arch, topo, coriolis) - grid = RectilinearGrid(arch, size=(1, 1), extent=(2π, 2π), topology=topo) + grid = RectilinearGrid(arch, size=(3, 3), extent=(2π, 2π), topology=topo) model = ShallowWaterModel(grid=grid, gravitational_acceleration=1, coriolis=coriolis) set!(model, h=1) @@ -29,7 +29,7 @@ function time_step_wizard_shallow_water_model_works(arch, topo, coriolis) end function shallow_water_model_tracers_and_forcings_work(arch) - grid = RectilinearGrid(arch, size=(1, 1), extent=(2π, 2π), topology=((Periodic, Periodic, Flat))) + grid = RectilinearGrid(arch, size=(3, 3), extent=(2π, 2π), topology=(Periodic, Periodic, Flat)) model = ShallowWaterModel(grid=grid, gravitational_acceleration=1, tracers=(:c, :d)) set!(model, h=1) @@ -51,9 +51,9 @@ function shallow_water_model_tracers_and_forcings_work(arch) end function test_shallow_water_diffusion_cosine(grid, formulation, fieldname, ξ) - κ, m = 1, 2 # diffusivity and cosine wavenumber + ν, m = 1, 2 # viscosity and cosine wavenumber - closure = ShallowWaterScalarDiffusivity(ν = κ) + closure = ShallowWaterScalarDiffusivity(; ν) momentum_advection = nothing tracer_advection = nothing mass_advection = nothing @@ -68,15 +68,15 @@ function test_shallow_water_diffusion_cosine(grid, formulation, fieldname, ξ) interior(field) .= on_architecture(architecture(grid), cos.(m * ξ)) update_state!(model) - # Step forward with small time-step relative to diff. time-scale - Δt = 1e-6 * grid.Lx^2 / κ - for n = 1:5 + # Step forward with small time-step relative to viscous/diffusive time scale + Δt = 1e-6 * grid.Lx^2 / closure.ν + for _ in 1:5 time_step!(model, Δt) end diffusing_cosine(ξ, t, κ, m) = exp(-κ * m^2 * t) * cos(m * ξ) analytical_solution = Field(location(field), grid) - analytical_solution .= diffusing_cosine.(ξ, model.clock.time, κ, m) + analytical_solution .= diffusing_cosine.(ξ, model.clock.time, ν, m) return isapprox(field, analytical_solution, atol=1e-6, rtol=1e-6) end @@ -98,7 +98,7 @@ end @test_throws MethodError ShallowWaterModel(architecture=GPU, grid=grid, gravitational_acceleration=1) end - topo = ( Flat, Flat, Flat ) + topo = (Flat, Flat, Flat) @testset "$topo model construction" begin @info " Testing $topo model construction..." @@ -111,8 +111,8 @@ end end topos = ( - (Bounded, Flat, Flat), - (Flat, Bounded, Flat), + (Bounded, Flat, Flat), + (Flat, Bounded, Flat), ) for topo in topos @@ -121,7 +121,7 @@ end for arch in archs, FT in float_types #arch isa GPU && topo == (Flat, Bounded, Flat) && continue - grid = RectilinearGrid(arch, FT, topology=topo, size=1, extent=1, halo=3) + grid = RectilinearGrid(arch, FT, topology=topo, size=3, extent=1, halo=3) model = ShallowWaterModel(grid=grid, gravitational_acceleration=1) @test model isa ShallowWaterModel @@ -130,9 +130,9 @@ end end topos = ( - (Periodic, Periodic, Flat), - (Periodic, Bounded, Flat), - (Bounded, Bounded, Flat), + (Periodic, Periodic, Flat), + (Periodic, Bounded, Flat), + (Bounded, Bounded, Flat), ) for topo in topos @@ -141,7 +141,7 @@ end for arch in archs, FT in float_types #arch isa GPU && topo == (Bounded, Bounded, Flat) && continue - grid = RectilinearGrid(arch, FT, topology=topo, size=(1, 1), extent=(1, 2), halo=(3, 3)) + grid = RectilinearGrid(arch, FT, topology=topo, size=(3, 3), extent=(1, 2), halo=(3, 3)) model = ShallowWaterModel(grid=grid, gravitational_acceleration=1) @test model isa ShallowWaterModel diff --git a/test/test_time_stepping.jl b/test/test_time_stepping.jl index 8a76620eaa..4c6399e97e 100644 --- a/test/test_time_stepping.jl +++ b/test/test_time_stepping.jl @@ -43,7 +43,7 @@ function time_stepping_works_with_closure(arch, FT, Closure; buoyancy=Buoyancy(m Closure === CATKEVerticalDiffusivity && push!(tracers, :e) # Use halos of size 3 to be conservative - grid = RectilinearGrid(arch, FT; size=(1, 1, 1), halo=(3, 3, 3), extent=(1, 2, 3)) + grid = RectilinearGrid(arch, FT; size=(3, 3, 3), halo=(3, 3, 3), extent=(1, 2, 3)) closure = Closure(FT) model = NonhydrostaticModel(; grid, closure, tracers, buoyancy) time_step!(model, 1, euler=true) @@ -53,7 +53,7 @@ end function time_stepping_works_with_advection_scheme(arch, advection_scheme) # Use halo=(3, 3, 3) to accomodate WENO-5 advection scheme - grid = RectilinearGrid(arch, size=(1, 1, 1), halo=(3, 3, 3), extent=(1, 2, 3)) + grid = RectilinearGrid(arch, size=(3, 3, 3), halo=(3, 3, 3), extent=(1, 2, 3)) model = NonhydrostaticModel(grid=grid, advection=advection_scheme) time_step!(model, 1, euler=true) return true # Test that no errors/crashes happen when time stepping. @@ -61,7 +61,7 @@ end function time_stepping_works_with_stokes_drift(arch, stokes_drift) # Use halo=(3, 3, 3) to accomodate WENO-5 advection scheme - grid = RectilinearGrid(arch, size=(1, 1, 1), halo=(3, 3, 3), extent=(1, 2, 3)) + grid = RectilinearGrid(arch, size=(3, 3, 3), halo=(3, 3, 3), extent=(1, 2, 3)) model = NonhydrostaticModel(; grid, stokes_drift, advection=nothing) time_step!(model, 1, euler=true) return true # Test that no errors/crashes happen when time stepping. diff --git a/test/test_turbulence_closures.jl b/test/test_turbulence_closures.jl index a93f434532..e6a4276b80 100644 --- a/test/test_turbulence_closures.jl +++ b/test/test_turbulence_closures.jl @@ -153,14 +153,14 @@ function time_step_with_tupled_closure(FT, arch) closure_tuple = (AnisotropicMinimumDissipation(FT), ScalarDiffusivity(FT)) model = NonhydrostaticModel(closure=closure_tuple, - grid=RectilinearGrid(arch, FT, size=(1, 1, 1), extent=(1, 2, 3))) + grid=RectilinearGrid(arch, FT, size=(2, 2, 2), extent=(1, 2, 3))) time_step!(model, 1, euler=true) return true end function run_time_step_with_catke_tests(arch, closure) - grid = RectilinearGrid(arch, size=(1, 1, 1), extent=(1, 2, 3)) + grid = RectilinearGrid(arch, size=(2, 2, 2), extent=(1, 2, 3)) buoyancy = BuoyancyTracer() # These shouldn't work (need :e in tracers) @@ -188,7 +188,7 @@ function run_time_step_with_catke_tests(arch, closure) end function compute_closure_specific_diffusive_cfl(closure) - grid = RectilinearGrid(CPU(), size=(1, 1, 1), extent=(1, 2, 3)) + grid = RectilinearGrid(CPU(), size=(2, 2, 2), extent=(1, 2, 3)) model = NonhydrostaticModel(; grid, closure, buoyancy=BuoyancyTracer(), tracers=:b) dcfl = DiffusiveCFL(0.1) @@ -216,7 +216,7 @@ end closure = getproperty(TurbulenceClosures, closurename)() @test closure isa TurbulenceClosures.AbstractTurbulenceClosure - grid = RectilinearGrid(CPU(), size=(1, 1, 1), extent=(1, 2, 3)) + grid = RectilinearGrid(CPU(), size=(2, 2, 2), extent=(1, 2, 3)) model = NonhydrostaticModel(grid=grid, closure=closure, tracers=:c) c = model.tracers.c u = model.velocities.u