Skip to content

Commit e56515f

Browse files
authored
Merge branch 'main' into ts/checkpointer-for-coupled-model
2 parents 4110aca + 9efec12 commit e56515f

15 files changed

+148
-120
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name = "ClimaOcean"
22
uuid = "0376089a-ecfe-4b0e-a64f-9c555d74d754"
33
license = "MIT"
44
authors = ["Climate Modeling Alliance and contributors"]
5-
version = "0.5.1"
5+
version = "0.5.3"
66

77
[deps]
88
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
@@ -20,6 +20,7 @@ MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
2020
NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab"
2121
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
2222
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
23+
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
2324
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
2425
Scratch = "6c6a2e73-6563-6170-7368-637461726353"
2526
SeawaterPolynomials = "d496a93d-167e-4197-9f49-d3af4ff8fe40"
@@ -41,8 +42,9 @@ JLD2 = "0.4, 0.5"
4142
KernelAbstractions = "0.9"
4243
MPI = "0.20"
4344
NCDatasets = "0.12, 0.13, 0.14"
44-
Oceananigans = "0.95.26 - 0.99"
45+
Oceananigans = "0.95.27 - 0.99"
4546
OffsetArrays = "1.14"
47+
PrecompileTools = "1"
4648
Scratch = "1"
4749
SeawaterPolynomials = "0.3.4"
4850
StaticArrays = "1"

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
<!-- description -->
77
<p align="center">
8-
<strong>🌎 A framework for realistic ocean-only and coupled ocean + sea-ice simulations driven by prescribed atmospheres and based on <a href=https://github.com/CliMA/Oceananigans.jl>Oceananigans</a> and <a href=https://github.com/CliMA/ClimaSeaIce.jl>ClimaSeaIce</a></strong>.
8+
<strong>🌎 A framework for realistic ocean-only and coupled ocean + sea-ice simulations driven by prescribed atmospheres and based on <a href=https://github.com/CliMA/Oceananigans.jl>Oceananigans</a> and <a href=https://github.com/CliMA/ClimaSeaIce.jl>ClimaSeaIce</a></strong>.
99
</p>
1010

11-
###
11+
###
1212

1313
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7677442.svg?style=flat-square)](https://doi.org/10.5281/zenodo.7677442)
1414
[![Build status](https://badge.buildkite.com/3113cca353b83df3b5855d3f0d69827124614aef7017c835d2.svg?style=flat-square)](https://buildkite.com/clima/climaocean-ci)
@@ -32,7 +32,7 @@ For more information, see the [documentation for `Pkg.jl`](https://pkgdocs.julia
3232

3333
## Why? What's the difference between ClimaOcean and [Oceananigans](https://github.com/CliMA/Oceananigans.jl)?
3434

35-
Oceananigans is a general-purpose library for ocean-flavored fluid dynamics.
35+
Oceananigans is a general-purpose library for ocean-flavored fluid dynamics.
3636
ClimaOcean implements a framework for driving realistic Oceananigans simulations with prescribed atmospheres, and coupling them to prognostic sea ice simulations.
3737

3838
### A core abstraction: `ClimaOcean.OceanSeaIceModel`
@@ -59,9 +59,10 @@ grid = ImmersedBoundaryGrid(grid, GridFittedBottom(bathymetry))
5959

6060
# Build an ocean simulation initialized to the ECCO state estimate on Jan 1, 1993
6161
ocean = ClimaOcean.ocean_simulation(grid)
62-
dates = DateTimeProlepticGregorian(1993, 1, 1)
63-
set!(ocean.model, T = ClimaOcean.ECCOMetadata(:temperature; dates),
64-
S = ClimaOcean.ECCOMetadata(:salinity; dates))
62+
dates = DateTime(1993, 1, 1) : Month(1) : DateTime(1994, 1, 1)
63+
set!(ocean.model,
64+
T=ClimaOcean.Metadata(:temperature; dates=first(dates), dataset=ClimaOcean.ECCO4Monthly()),
65+
S=ClimaOcean.Metadata(:salinity; dates=first(dates), dataset=ClimaOcean.ECCO4Monthly()))
6566

6667
# Build and run an OceanSeaIceModel (with no sea ice component) forced by JRA55 reanalysis
6768
atmosphere = ClimaOcean.JRA55PrescribedAtmosphere(arch)

docs/src/index.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ julia> Pkg.add("ClimaOcean")
2525

2626
!!! compat "Julia 1.10 is required"
2727
ClimaOcean requires Julia 1.10 or later.
28-
28+
2929
## Quick start
3030

3131
The following script implements a near-global ocean simulation initialized from the [ECCO state estimate](https://gmd.copernicus.org/articles/8/3071/2015/) and coupled to a prescribed atmosphere derived from the [JRA55-do reanalysis](https://www.sciencedirect.com/science/article/pii/S146350031830235X):
@@ -49,9 +49,10 @@ grid = ImmersedBoundaryGrid(grid, GridFittedBottom(bathymetry))
4949

5050
# Build an ocean simulation initialized to the ECCO state estimate on Jan 1, 1993
5151
ocean = ClimaOcean.ocean_simulation(grid)
52-
date = DateTime(1993, 1, 1)
53-
set!(ocean.model, T = ClimaOcean.ECCOMetadata(:temperature; date),
54-
S = ClimaOcean.ECCOMetadata(:salinity; date))
52+
dates = DateTime(1993, 1, 1) : Month(1) : DateTime(1994, 1, 1)
53+
set!(ocean.model,
54+
T=ClimaOcean.Metadata(:temperature; dates=first(dates), dataset=ClimaOcean.ECCO4Monthly()),
55+
S=ClimaOcean.Metadata(:salinity; dates=first(dates), dataset=ClimaOcean.ECCO4Monthly()))
5556

5657
# Build and run an OceanSeaIceModel (with no sea ice component) forced by JRA55 reanalysis
5758
atmosphere = ClimaOcean.JRA55PrescribedAtmosphere(arch)

src/ClimaOcean.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,18 @@ using ClimaOcean.OceanSeaIceModels: PrescribedAtmosphere
9191
using ClimaOcean.DataWrangling.JRA55: JRA55PrescribedAtmosphere, JRA55NetCDFBackend
9292
using ClimaOcean.DataWrangling.ECCO
9393

94+
using PrecompileTools: @setup_workload, @compile_workload
95+
96+
@setup_workload begin
97+
Nx, Ny, Nz = 32, 32, 10
98+
@compile_workload begin
99+
z = exponential_z_faces(Nz=Nz, depth=6000, h=34)
100+
grid = Oceananigans.OrthogonalSphericalShellGrids.TripolarGrid(CPU(); size=(Nx, Ny, Nz), halo=(7, 7, 7), z)
101+
grid = ImmersedBoundaryGrid(grid, GridFittedBottom((x, y) -> -5000))
102+
ocean = ocean_simulation(grid)
103+
model = OceanSeaIceModel(ocean)
104+
end
105+
end
106+
94107
end # module
95108

src/OceanSeaIceModels/InterfaceComputations/atmosphere_sea_ice_fluxes.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ end
7575

7676
i, j = @index(Global, NTuple)
7777
kᴺ = size(grid, 3) # index of the top ocean cell
78-
time = Time(clock.time)
79-
FT = eltype(grid)
78+
FT = eltype(grid)
8079

8180
@inbounds begin
8281
uₐ = atmosphere_state.u[i, j, 1]

src/OceanSeaIceModels/InterfaceComputations/component_interfaces.jl

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,27 @@ using Oceananigans.Operators: ℑxᶜᵃᵃ, ℑyᵃᶜᵃ, ℑxᶠᵃᵃ, ℑy
2828

2929
using KernelAbstractions: @kernel, @index
3030

31+
import Oceananigans.Simulations: initialize!
32+
3133
#####
3234
##### Container for organizing information related to fluxes
3335
#####
3436

35-
struct AtmosphereInterface{J, F, ST, P}
37+
mutable struct AtmosphereInterface{J, F, ST, P}
3638
fluxes :: J
3739
flux_formulation :: F
3840
temperature :: ST
3941
properties :: P
4042
end
4143

42-
struct SeaIceOceanInterface{J, P, H, A}
44+
mutable struct SeaIceOceanInterface{J, P, H, A}
4345
fluxes :: J
4446
properties :: P
4547
previous_ice_thickness :: H
4648
previous_ice_concentration :: A
4749
end
4850

49-
struct ComponentInterfaces{AO, ASI, SIO, C, AP, OP, SIP, EX}
51+
mutable struct ComponentInterfaces{AO, ASI, SIO, C, AP, OP, SIP, EX}
5052
atmosphere_ocean_interface :: AO
5153
atmosphere_sea_ice_interface :: ASI
5254
sea_ice_ocean_interface :: SIO
@@ -57,30 +59,44 @@ struct ComponentInterfaces{AO, ASI, SIO, C, AP, OP, SIP, EX}
5759
net_fluxes :: C
5860
end
5961

60-
struct StateExchanger{G, AST, AEX}
62+
mutable struct StateExchanger{G, AST, AEX}
6163
exchange_grid :: G
6264
exchange_atmosphere_state :: AST
6365
atmosphere_exchanger :: AEX
6466
end
6567

68+
mutable struct ExchangeAtmosphereState{F}
69+
u :: F
70+
v :: F
71+
T :: F
72+
q :: F
73+
p :: F
74+
Qs :: F
75+
Qℓ :: F
76+
Mp :: F
77+
end
78+
79+
ExchangeAtmosphereState(grid) = ExchangeAtmosphereState(Field{Center, Center, Nothing}(grid),
80+
Field{Center, Center, Nothing}(grid),
81+
Field{Center, Center, Nothing}(grid),
82+
Field{Center, Center, Nothing}(grid),
83+
Field{Center, Center, Nothing}(grid),
84+
Field{Center, Center, Nothing}(grid),
85+
Field{Center, Center, Nothing}(grid),
86+
Field{Center, Center, Nothing}(grid))
87+
6688
# Note that Field location can also affect fractional index type.
6789
# Here we assume that we know the location of Fields that will be interpolated.
6890
fractional_index_type(FT, Topo) = FT
6991
fractional_index_type(FT, ::Flat) = Nothing
7092

93+
94+
StateExchanger(ocean::Simulation, ::Nothing) = nothing
95+
7196
function StateExchanger(ocean::Simulation, atmosphere)
7297
# TODO: generalize this
7398
exchange_grid = ocean.model.grid
74-
75-
exchange_atmosphere_state = (u = Field{Center, Center, Nothing}(exchange_grid),
76-
v = Field{Center, Center, Nothing}(exchange_grid),
77-
T = Field{Center, Center, Nothing}(exchange_grid),
78-
q = Field{Center, Center, Nothing}(exchange_grid),
79-
p = Field{Center, Center, Nothing}(exchange_grid),
80-
Qs = Field{Center, Center, Nothing}(exchange_grid),
81-
Qℓ = Field{Center, Center, Nothing}(exchange_grid),
82-
Mp = Field{Center, Center, Nothing}(exchange_grid))
83-
99+
exchange_atmosphere_state = ExchangeAtmosphereState(exchange_grid)
84100
exchanger = atmosphere_exchanger(atmosphere, exchange_grid)
85101

86102
return StateExchanger(ocean.model.grid, exchange_atmosphere_state, exchanger)
@@ -100,11 +116,20 @@ function atmosphere_exchanger(atmosphere::PrescribedAtmosphere, exchange_grid)
100116
fj = TY() isa Flat ? nothing : Field{Center, Center, Nothing}(exchange_grid, FT)
101117
frac_indices = (i=fi, j=fj) # no k needed, only horizontal interpolation
102118

119+
return frac_indices
120+
end
121+
122+
initialize!(exchanger::StateExchanger, ::Nothing) = nothing
123+
124+
function initialize!(exchanger::StateExchanger, atmosphere)
125+
atmos_grid = atmosphere.grid
126+
exchange_grid = exchanger.exchange_grid
127+
arch = architecture(exchange_grid)
128+
frac_indices = exchanger.atmosphere_exchanger
103129
kernel_parameters = interface_kernel_parameters(exchange_grid)
104130
launch!(arch, exchange_grid, kernel_parameters,
105131
_compute_fractional_indices!, frac_indices, exchange_grid, atmos_grid)
106-
107-
return frac_indices
132+
return nothing
108133
end
109134

110135
@kernel function _compute_fractional_indices!(indices_tuple, exchange_grid, atmos_grid)
@@ -141,8 +166,11 @@ const celsius_to_kelvin = 273.15
141166
Base.summary(crf::ComponentInterfaces) = "ComponentInterfaces"
142167
Base.show(io::IO, crf::ComponentInterfaces) = print(io, summary(crf))
143168

144-
function atmosphere_ocean_interface(ocean,
145-
radiation,
169+
atmosphere_ocean_interface(::Nothing, args...) = nothing
170+
171+
function atmosphere_ocean_interface(atmos,
172+
ocean,
173+
radiation,
146174
ao_flux_formulation,
147175
temperature_formulation,
148176
velocity_formulation,
@@ -170,10 +198,14 @@ function atmosphere_ocean_interface(ocean,
170198
return AtmosphereInterface(ao_fluxes, ao_flux_formulation, interface_temperature, ao_properties)
171199
end
172200

173-
atmosphere_sea_ice_interface(sea_ice, args...) = nothing
201+
atmosphere_sea_ice_interface(atmos, sea_ice, args...) = nothing
202+
atmosphere_sea_ice_interface(::Nothing, args...) = nothing
203+
atmosphere_sea_ice_interface(::Nothing, ::Nothing, args...) = nothing
204+
atmosphere_sea_ice_interface(::Nothing, ::SeaIceSimulation, args...) = nothing
174205

175-
function atmosphere_sea_ice_interface(sea_ice::SeaIceSimulation,
176-
radiation,
206+
function atmosphere_sea_ice_interface(atmos,
207+
sea_ice::SeaIceSimulation,
208+
radiation,
177209
ai_flux_formulation,
178210
temperature_formulation,
179211
velocity_formulation)
@@ -295,7 +327,8 @@ function ComponentInterfaces(atmosphere, ocean, sea_ice=nothing;
295327
freshwater_density = freshwater_density,
296328
temperature_units = ocean_temperature_units)
297329

298-
ao_interface = atmosphere_ocean_interface(ocean,
330+
ao_interface = atmosphere_ocean_interface(atmosphere,
331+
ocean,
299332
radiation,
300333
atmosphere_ocean_flux_formulation,
301334
atmosphere_ocean_interface_temperature,
@@ -304,7 +337,8 @@ function ComponentInterfaces(atmosphere, ocean, sea_ice=nothing;
304337

305338
io_interface = sea_ice_ocean_interface(sea_ice, ocean)
306339

307-
ai_interface = atmosphere_sea_ice_interface(sea_ice,
340+
ai_interface = atmosphere_sea_ice_interface(atmosphere,
341+
sea_ice,
308342
radiation,
309343
atmosphere_sea_ice_flux_formulation,
310344
atmosphere_sea_ice_interface_temperature,

src/OceanSeaIceModels/InterfaceComputations/interpolate_atmospheric_state.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,14 @@ function interpolate_atmosphere_state!(interfaces, atmosphere::PrescribedAtmosph
6363

6464
# Assumption, should be generalized
6565
ua = atmosphere.velocities.u
66-
time_interpolator = TimeInterpolator(ua, clock.time)
6766

6867
launch!(arch, grid, kernel_parameters,
6968
_interpolate_primary_atmospheric_state!,
7069
atmosphere_data,
7170
space_fractional_indices,
72-
time_interpolator,
71+
clock.time,
72+
ua.times,
73+
ua.time_indexing,
7374
exchange_grid,
7475
atmosphere_velocities,
7576
atmosphere_tracers,
@@ -119,7 +120,9 @@ end
119120

120121
@kernel function _interpolate_primary_atmospheric_state!(surface_atmos_state,
121122
space_fractional_indices,
122-
time_interpolator,
123+
time,
124+
atmos_times,
125+
time_indexing,
123126
exchange_grid,
124127
atmos_velocities,
125128
atmos_tracers,
@@ -137,7 +140,7 @@ end
137140
fj = get_fractional_index(i, j, jj)
138141

139142
x_itp = FractionalIndices(fi, fj, nothing)
140-
t_itp = time_interpolator
143+
t_itp = TimeInterpolator(time_indexing, atmos_times, time)
141144
atmos_args = (x_itp, t_itp, atmos_backend, atmos_time_indexing)
142145

143146
uₐ = interp_atmos_time_series(atmos_velocities.u, atmos_args...)

0 commit comments

Comments
 (0)