Skip to content

Commit f9cba31

Browse files
committed
Add tests for TriadIsopycnalSkewSymmetricDiffusivity and include clock argument checks
1 parent d17d62b commit f9cba31

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ CUDA.allowscalar() do
137137
if group == :turbulence_closures || group == :all
138138
@testset "Turbulence closures tests" begin
139139
include("test_turbulence_closures.jl")
140+
include("test_triad_isopycnal_diffusivity.jl")
140141
end
141142
end
142143

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
include("dependencies_for_runtests.jl")
2+
3+
using Oceananigans.TurbulenceClosures: TriadIsopycnalSkewSymmetricDiffusivity
4+
using Oceananigans.TurbulenceClosures: diffusive_flux_x, diffusive_flux_y, diffusive_flux_z,
5+
ExplicitTimeDiscretization, VerticallyImplicitTimeDiscretization,
6+
compute_diffusivities!
7+
8+
"""
9+
Test that TriadIsopycnalSkewSymmetricDiffusivity can be constructed and time-stepped
10+
with both explicit and vertically implicit time discretizations.
11+
"""
12+
function time_step_with_triad_isopycnal_diffusivity(arch, time_disc)
13+
grid = RectilinearGrid(arch, size=(4, 4, 8), extent=(100, 100, 100))
14+
15+
closure = TriadIsopycnalSkewSymmetricDiffusivity(time_disc, Float64,
16+
κ_skew = 100.0,
17+
κ_symmetric = 100.0)
18+
19+
# TriadIsopycnalSkewSymmetricDiffusivity only works with HydrostaticFreeSurfaceModel
20+
model = HydrostaticFreeSurfaceModel(; grid, closure,
21+
buoyancy = BuoyancyTracer(),
22+
tracers = (:b, :c))
23+
24+
# Set up a simple stratified initial condition
25+
bᵢ(x, y, z) = 1e-5 * z
26+
set!(model, b=bᵢ)
27+
28+
# Attempt to time-step
29+
time_step!(model, 1)
30+
31+
return true
32+
end
33+
34+
"""
35+
Test that flux calculations work correctly and receive the clock argument.
36+
This specifically tests for the bug where the clock argument was missing in
37+
the explicit_R₃₃_∂z_c function call.
38+
"""
39+
function test_triad_flux_calculations_with_clock(arch, time_disc)
40+
grid = RectilinearGrid(arch, size=(4, 4, 8), extent=(100, 100, 100))
41+
42+
closure = TriadIsopycnalSkewSymmetricDiffusivity(time_disc, Float64,
43+
κ_skew = 100.0,
44+
κ_symmetric = 100.0)
45+
46+
# Create necessary fields
47+
tracers = TracerFields((:b, :c), grid)
48+
clock = Clock(time=0.0)
49+
buoyancy = BuoyancyTracer()
50+
51+
# Set up a stratified state with lateral gradients
52+
b = tracers.b
53+
c = tracers.c
54+
55+
# Create a tilted isopycnal surface: b = α*x + β*z
56+
for k in 1:grid.Nz, j in 1:grid.Ny, i in 1:grid.Nx
57+
x, y, z = nodes((Center, Center, Center), grid, i, j, k)
58+
b[i, j, k] = 1e-5 * x + 1e-4 * z
59+
c[i, j, k] = 1.0 + 0.1 * sin(2π * x / 100) * sin(2π * z / 100)
60+
end
61+
62+
fill_halo_regions!(tracers)
63+
64+
# Compute diffusivity fields if needed for vertically implicit
65+
K = DiffusivityFields(grid, (:b, :c), NamedTuple(), closure)
66+
67+
if time_disc isa VerticallyImplicitTimeDiscretization
68+
# Create a mock model for compute_diffusivities!
69+
mock_model = (architecture = arch,
70+
grid = grid,
71+
clock = clock,
72+
tracers = tracers,
73+
buoyancy = buoyancy)
74+
75+
compute_diffusivities!(K, closure, mock_model)
76+
end
77+
78+
model_fields = datatuple(tracers)
79+
80+
# Test that flux calculations work without error
81+
# This will fail if clock argument is missing
82+
@allowscalar begin
83+
i, j, k = 2, 2, 4
84+
85+
# Test diffusive fluxes - these should not error
86+
# The key is that these functions internally call explicit_R₃₃_∂z_c
87+
# which now requires the clock argument
88+
flux_x = diffusive_flux_x(i, j, k, grid, closure, K, Val(1), c, clock, model_fields, buoyancy)
89+
flux_y = diffusive_flux_y(i, j, k, grid, closure, K, Val(1), c, clock, model_fields, buoyancy)
90+
flux_z = diffusive_flux_z(i, j, k, grid, closure, K, Val(1), c, clock, model_fields, buoyancy)
91+
92+
# Fluxes should be real numbers (not NaN or Inf)
93+
@test isfinite(flux_x)
94+
@test isfinite(flux_y)
95+
@test isfinite(flux_z)
96+
end
97+
98+
return true
99+
end
100+
101+
"""
102+
Test that time discretization affects flux computation correctly.
103+
Explicit should compute R₃₃ contribution, implicit should precompute it.
104+
"""
105+
function test_triad_time_discretization_behavior(arch)
106+
grid = RectilinearGrid(arch, size=(4, 4, 8), extent=(100, 100, 100))
107+
108+
# Test with both time discretizations
109+
for time_disc in (ExplicitTimeDiscretization(), VerticallyImplicitTimeDiscretization())
110+
closure = TriadIsopycnalSkewSymmetricDiffusivity(time_disc, Float64,
111+
κ_skew = 100.0,
112+
κ_symmetric = 100.0)
113+
114+
K = DiffusivityFields(grid, (:b, :c), NamedTuple(), closure)
115+
116+
if time_disc isa VerticallyImplicitTimeDiscretization
117+
# Should have ϵκR₃₃ field
118+
@test hasfield(typeof(K), :ϵκR₃₃)
119+
@test K.ϵκR₃₃ isa Field
120+
else
121+
# Should be nothing for explicit
122+
@test K === nothing
123+
end
124+
end
125+
126+
return true
127+
end
128+
129+
"""
130+
Test that the closure works with time-varying diffusivities.
131+
"""
132+
function test_triad_with_time_varying_diffusivity(arch)
133+
grid = RectilinearGrid(arch, size=(4, 4, 8), extent=(100, 100, 100))
134+
135+
# Time-varying diffusivity
136+
κ_time_varying(x, y, z, t) = 100.0 * (1.0 + 0.1 * sin(2π * t / 86400))
137+
138+
closure = TriadIsopycnalSkewSymmetricDiffusivity(ExplicitTimeDiscretization(), Float64,
139+
κ_skew = κ_time_varying,
140+
κ_symmetric = κ_time_varying)
141+
142+
model = HydrostaticFreeSurfaceModel(; grid, closure,
143+
buoyancy = BuoyancyTracer(),
144+
tracers = (:b, :c))
145+
146+
# Set up initial condition
147+
bᵢ(x, y, z) = 1e-5 * z
148+
set!(model, b=bᵢ)
149+
150+
# Time-step at different times - the clock should be passed correctly
151+
for n in 1:3
152+
time_step!(model, 1000.0) # 1000 second time steps
153+
@test model.clock.time n * 1000.0
154+
end
155+
156+
return true
157+
end
158+
159+
@testset "TriadIsopycnalSkewSymmetricDiffusivity" begin
160+
@info "Testing TriadIsopycnalSkewSymmetricDiffusivity..."
161+
162+
for arch in archs
163+
@testset "Time stepping with TriadIsopycnalSkewSymmetricDiffusivity [$arch]" begin
164+
@info " Testing time stepping with explicit time discretization on $arch..."
165+
@test time_step_with_triad_isopycnal_diffusivity(arch, ExplicitTimeDiscretization())
166+
167+
@info " Testing time stepping with vertically implicit time discretization on $arch..."
168+
@test time_step_with_triad_isopycnal_diffusivity(arch, VerticallyImplicitTimeDiscretization())
169+
end
170+
171+
@testset "Flux calculations with clock argument [$arch]" begin
172+
@info " Testing flux calculations receive clock (explicit) on $arch..."
173+
@test test_triad_flux_calculations_with_clock(arch, ExplicitTimeDiscretization())
174+
175+
@info " Testing flux calculations receive clock (implicit) on $arch..."
176+
@test test_triad_flux_calculations_with_clock(arch, VerticallyImplicitTimeDiscretization())
177+
end
178+
179+
@testset "Time discretization behavior [$arch]" begin
180+
@info " Testing time discretization affects diffusivity fields on $arch..."
181+
@test test_triad_time_discretization_behavior(arch)
182+
end
183+
184+
@testset "Time-varying diffusivity [$arch]" begin
185+
@info " Testing time-varying diffusivity with clock on $arch..."
186+
@test test_triad_with_time_varying_diffusivity(arch)
187+
end
188+
end
189+
end

0 commit comments

Comments
 (0)