Skip to content

Commit f3499ad

Browse files
committed
use SIC instead of area fraction [skip ci]
1 parent bbb1305 commit f3499ad

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

experiments/ClimaEarth/components/ocean/clima_seaice.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ end
262262
Compute the fluxes between the ocean and sea ice, storing them in the `ocean_ice_fluxes`
263263
fields of the ocean and sea ice simulations.
264264
265+
This function assumes both simulations share the same grid, so no remapping is done.
266+
265267
!!! note
266268
This function must be called after the turbulent fluxes have been updated in both
267269
simulations. Here only the contributions from the sea ice/ocean interactions
@@ -275,11 +277,14 @@ function FluxCalculator.ocean_seaice_fluxes!(
275277
ocean_properties = ocean_sim.ocean_properties
276278
ice_concentration = Interfacer.get_field(ice_sim, Val(:ice_concentration))
277279

280+
# Update the sea ice concentration in the ocean simulation
281+
ocean_sim.ice_concentration .= ice_concentration
282+
278283
# Compute the fluxes and store them in the both simulations
279284
ocean_properties = (;
280285
reference_density = ocean_properties.ocean_reference_density,
281286
heat_capacity = ocean_properties.ocean_heat_capacity,
282-
) # TODO rename in constructor
287+
) # TODO rename in ocean constructor
283288
CO.OceanSeaIceModels.InterfaceComputations.compute_sea_ice_ocean_fluxes!(
284289
ice_sim.ocean_ice_fluxes,
285290
ocean_sim.ocean,

experiments/ClimaEarth/components/ocean/oceananigans.jl

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ using KernelAbstractions: @kernel, @index, @inbounds
1010
include("climaocean_helpers.jl")
1111

1212
"""
13-
OceananigansSimulation{SIM, A, OPROP, REMAP}
13+
OceananigansSimulation{SIM, A, OPROP, REMAP, SIC}
1414
1515
The ClimaCoupler simulation object used to run with Oceananigans.
1616
This type is used by the coupler to indicate that this simulation
@@ -21,12 +21,14 @@ It contains the following objects:
2121
- `area_fraction::A`: A ClimaCore Field representing the surface area fraction of this component model on the exchange grid.
2222
- `ocean_properties::OPROP`: A NamedTuple of ocean properties and parameters
2323
- `remapping::REMAP`: Objects needed to remap from the exchange (spectral) grid to Oceananigans spaces.
24+
- `ice_concentration::SIC`: An Oceananigans Field representing the sea ice concentration on the ocean/sea ice grid.
2425
"""
25-
struct OceananigansSimulation{SIM, A, OPROP, REMAP} <: Interfacer.OceanModelSimulation
26+
struct OceananigansSimulation{SIM, A, OPROP, REMAP, SIC} <: Interfacer.OceanModelSimulation
2627
ocean::SIM
2728
area_fraction::A
2829
ocean_properties::OPROP
2930
remapping::REMAP
31+
ice_concentration::SIC
3032
end
3133

3234
"""
@@ -178,8 +180,11 @@ function OceananigansSimulation(
178180
ocean.output_writers[:diagnostics] = netcdf_writer
179181
end
180182

181-
sim = OceananigansSimulation(ocean, area_fraction, ocean_properties, remapping)
182-
return sim
183+
# Initialize with 0 ice concentration; this will be updated in `resolve_ocean_ice_fractions!`
184+
# if the ocean is coupled to a non-prescribed sea ice model.
185+
ice_concentration = OC.Field{OC.Center, OC.Center, Nothing}(grid)
186+
187+
return OceananigansSimulation(ocean, area_fraction, ocean_properties, remapping, ice_concentration)
183188
end
184189

185190
"""
@@ -193,6 +198,9 @@ degrees latitude, and make sure the ocean fraction is 0 there.
193198
194199
The land fraction is expected to be set to 1 at the poles before calling this function,
195200
and doesn't need to be set again since its fraction is static.
201+
202+
This function also updates the ice concentration field in the ocean simulation
203+
so that it can be used for weighting flux updates.
196204
"""
197205
function FieldExchanger.resolve_ocean_ice_fractions!(
198206
ocean_sim::OceananigansSimulation,
@@ -215,6 +223,9 @@ function FieldExchanger.resolve_ocean_ice_fractions!(
215223
@. ice_fraction = ifelse.(polar_mask == FT(1), FT(1) - land_fraction, ice_fraction)
216224
@. ocean_fraction = ifelse.(polar_mask == FT(1), FT(0), ocean_fraction)
217225
end
226+
227+
# Update the ice concentration field in the ocean simulation
228+
ocean_sim.ice_concentration .= Interfacer.get_field(ice_sim, Val(:ice_concentration))
218229
return nothing
219230
end
220231

@@ -268,14 +279,7 @@ function FluxCalculator.update_turbulent_fluxes!(sim::OceananigansSimulation, fi
268279
# TODO clarify where we need to add and where we set fluxes directly
269280
(; F_lh, F_sh, F_turb_ρτxz, F_turb_ρτyz, F_turb_moisture) = fields
270281
grid = sim.ocean.model.grid
271-
272-
# Remap the area fraction from the boundary space to the Oceananigans grid
273-
CC.Remapping.interpolate!(
274-
sim.remapping.scratch_arr3,
275-
sim.remapping.remapper_cc,
276-
sim.area_fraction,
277-
)
278-
area_fraction = sim.remapping.scratch_arr3
282+
ice_concentration = sim.ice_concentration
279283

280284
# Remap momentum fluxes onto reduced 2D Center, Center fields using scratch arrays and fields
281285
CC.Remapping.interpolate!(
@@ -295,6 +299,11 @@ function FluxCalculator.update_turbulent_fluxes!(sim::OceananigansSimulation, fi
295299
F_turb_ρτxz_cc = sim.remapping.scratch_cc1
296300
F_turb_ρτyz_cc = sim.remapping.scratch_cc2
297301

302+
# Weight by (1 - sea ice concentration)
303+
# TODO does this work with OC fields?
304+
OC.interior(F_turb_ρτxz_cc, :, :, 1) .= OC.interior(F_turb_ρτxz_cc, :, :, 1) .* (1.0 .- ice_concentration)
305+
OC.interior(F_turb_ρτyz_cc, :, :, 1) .= OC.interior(F_turb_ρτyz_cc, :, :, 1) .* (1.0 .- ice_concentration)
306+
298307
# Set the momentum flux BCs at the correct locations using the remapped scratch fields
299308
oc_flux_u = surface_flux(sim.ocean.model.velocities.u)
300309
oc_flux_v = surface_flux(sim.ocean.model.velocities.v)
@@ -303,7 +312,7 @@ function FluxCalculator.update_turbulent_fluxes!(sim::OceananigansSimulation, fi
303312
grid,
304313
F_turb_ρτxz_cc,
305314
F_turb_ρτyz_cc,
306-
) # TODO multiply by area_fraction?
315+
)
307316

308317
(; ocean_reference_density, ocean_heat_capacity, ocean_fresh_water_density) =
309318
sim.ocean_properties
@@ -322,7 +331,7 @@ function FluxCalculator.update_turbulent_fluxes!(sim::OceananigansSimulation, fi
322331
oc_flux_T = surface_flux(sim.ocean.model.tracers.T)
323332
OC.interior(oc_flux_T, :, :, 1) .=
324333
OC.interior(oc_flux_T, :, :, 1) .+
325-
area_fraction .* (remapped_F_lh .+ remapped_F_sh) ./
334+
(1.0 .- ice_concetration) .* (remapped_F_lh .+ remapped_F_sh) ./
326335
(ocean_reference_density * ocean_heat_capacity)
327336

328337
# Add the part of the salinity flux that comes from the moisture flux, we also need to
@@ -337,7 +346,7 @@ function FluxCalculator.update_turbulent_fluxes!(sim::OceananigansSimulation, fi
337346
surface_salinity = OC.interior(sim.ocean.model.tracers.S, :, :, 1)
338347
OC.interior(oc_flux_S, :, :, 1) .=
339348
OC.interior(oc_flux_S, :, :, 1) .-
340-
area_fraction .* surface_salinity .* moisture_fresh_water_flux
349+
(1.0 .- ice_concetration) .* surface_salinity .* moisture_fresh_water_flux
341350
return nothing
342351
end
343352

@@ -369,14 +378,7 @@ so a sign change is needed when we convert from precipitation to salinity flux.
369378
function FieldExchanger.update_sim!(sim::OceananigansSimulation, csf)
370379
(; ocean_reference_density, ocean_heat_capacity, ocean_fresh_water_density) =
371380
sim.ocean_properties
372-
# TODO use SIC instead?
373-
# Remap the area fraction from the boundary space to the Oceananigans grid
374-
CC.Remapping.interpolate!(
375-
sim.remapping.scratch_arr3,
376-
sim.remapping.remapper_cc,
377-
sim.area_fraction,
378-
)
379-
area_fraction = sim.remapping.scratch_arr3
381+
ice_concentration = sim.ice_concentration
380382

381383
# Remap radiative flux onto scratch array; rename for clarity
382384
CC.Remapping.interpolate!(
@@ -401,7 +403,7 @@ function FieldExchanger.update_sim!(sim::OceananigansSimulation, csf)
401403
α = Interfacer.get_field(sim, Val(:surface_direct_albedo)) # scalar
402404
ϵ = Interfacer.get_field(sim, Val(:emissivity)) # scalar
403405
OC.interior(oc_flux_T, :, :, 1) .=
404-
area_fraction .* (
406+
(1.0 .- ice_concetration) .* (
405407
-(1 - α) .* remapped_SW_d .-
406408
ϵ * (
407409
remapped_LW_d .-
@@ -413,20 +415,21 @@ function FieldExchanger.update_sim!(sim::OceananigansSimulation, csf)
413415
CC.Remapping.interpolate!(
414416
sim.remapping.scratch_arr1,
415417
sim.remapping.remapper_cc,
416-
sim.area_fraction .* csf.P_liq,
418+
csf.P_liq,
417419
)
418420
CC.Remapping.interpolate!(
419421
sim.remapping.scratch_arr2,
420422
sim.remapping.remapper_cc,
421-
sim.area_fraction .* csf.P_snow,
423+
csf.P_snow,
422424
)
423425
remapped_P_liq = sim.remapping.scratch_arr1
424426
remapped_P_snow = sim.remapping.scratch_arr2
425427

426428
# Virtual salt flux
429+
# TODO why is this split on multiple lines?
427430
oc_flux_S = surface_flux(sim.ocean.model.tracers.S)
428431
precipitating_fresh_water_flux =
429-
area_fraction .* (remapped_P_liq .+ remapped_P_snow) ./ ocean_fresh_water_density
432+
(1.0 .- ice_concetration) .* (remapped_P_liq .+ remapped_P_snow) ./ ocean_fresh_water_density
430433
surface_salinity_flux =
431434
OC.interior(sim.ocean.model.tracers.S, :, :, 1) .* precipitating_fresh_water_flux
432435
OC.interior(oc_flux_S, :, :, 1) .=

0 commit comments

Comments
 (0)