Skip to content

Commit a462523

Browse files
Fixes for flux computation + add fluxes regression tests (#271)
* avoid extra step * Update atmosphere_ocean_fluxes.jl * put atmosphere rotation in interpolation * some improvement * try adding Manifest * run the tests * try new manifest * correct fluxes * add tests * correct regression * remove Manifest * fix tests * add units * fix tests and update Oceananigans * update oceananigans * run tests * now it should work
1 parent a4c405f commit a462523

File tree

8 files changed

+98
-11
lines changed

8 files changed

+98
-11
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ JLD2 = "0.4, 0.5"
4242
KernelAbstractions = "0.9"
4343
MPI = "0.20"
4444
NCDatasets = "0.12, 0.13, 0.14"
45-
Oceananigans = "0.94.2 - 0.99"
45+
Oceananigans = "0.94.3 - 0.99"
4646
OffsetArrays = "1.14"
4747
OrthogonalSphericalShellGrids = "0.1.8"
4848
Scratch = "1"

src/DataWrangling/ECCO/ECCO.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,12 @@ function ECCO_field(metadata::ECCOMetadata;
191191
# data by 180 degrees in longitude
192192
if metadata.version isa ECCO4Monthly
193193
Nx = size(data, 1)
194-
data = circshift(data, (Nx ÷ 2, 0, 0))
194+
if variable_is_three_dimensional(metadata)
195+
shift = (Nx ÷ 2, 0, 0)
196+
else
197+
shift = (Nx ÷ 2, 0)
198+
end
199+
data = circshift(data, shift)
195200
end
196201

197202
set!(field, data)

src/DataWrangling/ECCO/ECCO_metadata.jl

+5-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ ECCO4_short_names = Dict(
166166
:u_velocity => "EVEL",
167167
:v_velocity => "NVEL",
168168
:sea_ice_thickness => "SIheff",
169-
:sea_ice_area_fraction => "SIarea"
169+
:sea_ice_area_fraction => "SIarea",
170+
:net_heat_flux => "oceQnet"
170171
)
171172

172173
ECCO2_short_names = Dict(
@@ -175,14 +176,16 @@ ECCO2_short_names = Dict(
175176
:u_velocity => "UVEL",
176177
:v_velocity => "VVEL",
177178
:sea_ice_thickness => "SIheff",
178-
:sea_ice_area_fraction => "SIarea"
179+
:sea_ice_area_fraction => "SIarea",
180+
:net_heat_flux => "oceQnet"
179181
)
180182

181183
ECCO_location = Dict(
182184
:temperature => (Center, Center, Center),
183185
:salinity => (Center, Center, Center),
184186
:sea_ice_thickness => (Center, Center, Nothing),
185187
:sea_ice_area_fraction => (Center, Center, Nothing),
188+
:net_heat_flux => (Center, Center, Nothing),
186189
:u_velocity => (Face, Center, Center),
187190
:v_velocity => (Center, Face, Center),
188191
)

src/OceanSeaIceModels/CrossRealmFluxes/atmosphere_ocean_fluxes.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,9 @@ end
365365
time = Time(clock.time)
366366

367367
@inbounds begin
368-
Tₒ = ocean_temperature[i, j, 1]
368+
Tₒ = ocean_temperature[i, j, kᴺ]
369369
Tₒ = convert_to_kelvin(ocean_temperature_units, Tₒ)
370-
Sₒ = ocean_salinity[i, j, 1]
370+
Sₒ = ocean_salinity[i, j, kᴺ]
371371

372372
Qs = downwelling_radiation.shortwave[i, j, 1]
373373
Qℓ = downwelling_radiation.longwave[i, j, 1]

src/OceanSeaIceModels/CrossRealmFluxes/similarity_theory_turbulent_fluxes.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,9 @@ end
310310
# Iterating condition for the characteristic scales solvers
311311
@inline function iterating(Σ★, iteration, maxiter, solver)
312312
havent_started = iteration == 0
313-
not_converged = norm(Σ★) > solver.tolerance
314-
havent_reached_maxiter = iteration < maxiter
315-
return havent_started | not_converged | havent_reached_maxiter
313+
converged = norm(Σ★) < solver.tolerance
314+
reached_maxiter = iteration maxiter
315+
return !(converged | reached_maxiter) | havent_started
316316
end
317317

318318
"""

src/OceanSeaIceModels/OceanSeaIceModels.jl

+4
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,8 @@ const NoAtmosphereModel = OceanSeaIceModel{<:Any, Nothing}
6262

6363
compute_atmosphere_ocean_fluxes!(coupled_model::NoAtmosphereModel) = nothing
6464

65+
const NoSeaIceModel = OceanSeaIceModel{Nothing}
66+
67+
compute_sea_ice_ocean_fluxes!(cm::NoSeaIceModel) = nothing
68+
6569
end # module

src/OceanSeaIceModels/time_step_ocean_sea_ice_model.jl

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ function time_step!(coupled_model::OceanSeaIceModel, Δt; callbacks=[], compute_
2929
end
3030

3131
# TODO after ice time-step:
32-
# - Adjust ocean heat flux if the ice completely melts?
33-
32+
# - Adjust ocean heat flux if the ice completely melts?
3433
ocean.Δt = Δt
3534
time_step!(ocean)
3635

test/test_surface_fluxes.jl

+76
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ using ClimaOcean.OceanSeaIceModels.CrossRealmFluxes:
1010
using Thermodynamics
1111
using CUDA
1212
using KernelAbstractions: @kernel, @index
13+
using Oceananigans.TimeSteppers: update_state!
14+
using Oceananigans.Units: hours, days
15+
16+
using Statistics: mean, std
1317

1418
import ClimaOcean.OceanSeaIceModels.CrossRealmFluxes: water_saturation_specific_humidity
1519

@@ -196,4 +200,76 @@ _fractional_indices(at_node, grid, ::Nothing, ::Nothing, ::Nothing) = (nothing,
196200
end
197201
end
198202

203+
@testset "Fluxes regression" begin
204+
for arch in test_architectures
205+
@info "Testing fluxes regression..."
206+
207+
grid = LatitudeLongitudeGrid(arch;
208+
size = (20, 20, 20),
209+
latitude = (-60, 60),
210+
longitude = (0, 360),
211+
z = (-5000, 0))
212+
213+
# Speed up compilation by removing all the unnecessary stuff
214+
momentum_advection = nothing
215+
tracer_advection = nothing
216+
tracers = (:T, :S)
217+
buoyancy = nothing
218+
closure = nothing
219+
coriolis = nothing
220+
221+
ocean = ocean_simulation(grid; momentum_advection, tracer_advection, closure, tracers, coriolis)
222+
223+
T_metadata = ECCOMetadata(:temperature)
224+
S_metadata = ECCOMetadata(:salinity)
225+
226+
set!(ocean.model; T=T_metadata, S=S_metadata)
227+
228+
atmosphere = JRA55_prescribed_atmosphere(1:10; grid, architecture = arch, backend = InMemory())
229+
radiation = Radiation(ocean_albedo=0.1, ocean_emissivity=1.0)
230+
sea_ice = nothing
231+
232+
coupled_model = OceanSeaIceModel(ocean, sea_ice; atmosphere, radiation)
233+
234+
times = 0:1hours:1days
235+
Ntimes = length(times)
236+
237+
# average the fluxes over one day
238+
Jᵀ = interior(ocean.model.tracers.T.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
239+
= interior(ocean.model.tracers.S.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
240+
τˣ = interior(ocean.model.velocities.u.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
241+
τʸ = interior(ocean.model.velocities.v.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
242+
243+
for time in times[2:end]
244+
coupled_model.clock.time = time
245+
update_state!(coupled_model)
246+
Jᵀ .+= interior(ocean.model.tracers.T.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
247+
.+= interior(ocean.model.tracers.S.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
248+
τˣ .+= interior(ocean.model.velocities.u.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
249+
τʸ .+= interior(ocean.model.velocities.v.boundary_conditions.top.condition, :, :, 1) ./ Ntimes
250+
end
251+
252+
Jᵀ_mean = mean(Jᵀ)
253+
Jˢ_mean = mean(Jˢ)
254+
τˣ_mean = mean(τˣ)
255+
τʸ_mean = mean(τʸ)
256+
257+
Jᵀ_std = std(Jᵀ)
258+
Jˢ_std = std(Jˢ)
259+
τˣ_std = std(τˣ)
260+
τʸ_std = std(τʸ)
261+
262+
# Regression test
263+
@test Jᵀ_mean -3.526464713488678e-5
264+
@test Jˢ_mean 1.1470078542716042e-6
265+
@test τˣ_mean -1.0881334225579832e-5
266+
@test τʸ_mean 5.653281786086694e-6
267+
268+
@test Jᵀ_std 7.477575901188957e-5
269+
@test Jˢ_std 3.7416720607945508e-6
270+
@test τˣ_std 0.00011349625113971719
271+
@test τʸ_std 7.627885224680635e-5
272+
end
273+
end
274+
199275

0 commit comments

Comments
 (0)