@@ -10,7 +10,7 @@ using KernelAbstractions: @kernel, @index, @inbounds
1010include (" climaocean_helpers.jl" )
1111
1212"""
13- OceananigansSimulation{SIM, A, OPROP, REMAP}
13+ OceananigansSimulation{SIM, A, OPROP, REMAP, SIC }
1414
1515The ClimaCoupler simulation object used to run with Oceananigans.
1616This 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
3032end
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)
183188end
184189
185190"""
@@ -193,6 +198,9 @@ degrees latitude, and make sure the ocean fraction is 0 there.
193198
194199The land fraction is expected to be set to 1 at the poles before calling this function,
195200and 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"""
197205function 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
219230end
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
342351end
343352
@@ -369,14 +378,7 @@ so a sign change is needed when we convert from precipitation to salinity flux.
369378function 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