Skip to content

Commit 08f1b4d

Browse files
Clean up ECCO functionality (#169)
* Clean up ECCO stuff * Update for ECCO * Import propagate_inbounds * ecco -> ECCO in make.jl * Fix ecco -> ECCO * Update src/ClimaOcean.jl Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com> * Update src/DataWrangling/ECCO/ECCO_metadata.jl Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com> * Add a README to ECCO * Update README.md * Update ECCO_metadata.jl * Fix capitalization in tests * Case sensitivity * Capitalization again --------- Co-authored-by: Simone Silvestri <silvestri.simone0@gmail.com>
1 parent ddea939 commit 08f1b4d

File tree

11 files changed

+239
-259
lines changed

11 files changed

+239
-259
lines changed

docs/make.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ const EXAMPLES_DIR = joinpath(@__DIR__, "..", "examples")
1515
const OUTPUT_DIR = joinpath(@__DIR__, "src/literated")
1616

1717
to_be_literated = [
18-
# "inspect_ecco_data.jl",
18+
# "inspect_ECCO_data.jl",
1919
"generate_bathymetry.jl",
2020
"generate_surface_fluxes.jl",
2121
# "single_column_simulation.jl",
22-
# "mediterranean_simulation_with_ecco_restoring.jl",
22+
# "mediterranean_simulation_with_ECCO_restoring.jl",
2323
"near_global_ocean_simulation.jl"
2424
]
2525

@@ -52,11 +52,11 @@ pages = [
5252
],
5353

5454
"Examples" => [
55-
# "Inspect ECCO2 data" => "literated/inspect_ecco_data.md",
55+
# "Inspect ECCO2 data" => "literated/inspect_ECCO_data.md",
5656
"Generate bathymetry" => "literated/generate_bathymetry.md",
5757
"Surface fluxes" => "literated/generate_surface_fluxes.md",
5858
# "Single column simulation" => "literated/single_column_simulation.md",
59-
# "Mediterranean simulation with ECCO restoring" => "literated/mediterranean_simulation_with_ecco_restoring.md",
59+
# "Mediterranean simulation with ECCO restoring" => "literated/mediterranean_simulation_with_ECCO_restoring.md",
6060
"Near-global Ocean simulation" => "literated/near_global_ocean_simulation.md",
6161
]
6262
]

examples/generate_surface_fluxes.jl

Lines changed: 43 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,21 @@ using ClimaOcean.OceanSimulations
1616
using Oceananigans
1717
using CairoMakie
1818

19-
# We start by defining a grid. The ECCO2 grid is a good starting point.
20-
# The ECCO2 grid is not "immersed" by default, but we can use the ECCO mask
21-
# to define the "bathymetry" of the ECCO fields.
22-
# `ecco2_center_mask` produces a field with `true` values where data is missing (i.e., in immersed cells).
23-
# We can use this mask as an immersed boundary for our grid.
24-
# Let's create the grid and visualize the mask.
25-
26-
mask = ecco_mask()
19+
# # Computing fluxes on the ECCO2 grid
20+
#
21+
# We start by building the ECCO2 grid, using `ECCO_mask`
22+
# to identify missing cells.
23+
24+
mask = ECCO_mask()
2725
grid = mask.grid
2826
grid = ImmersedBoundaryGrid(grid, GridFittedBoundary(mask))
2927

3028
fig = Figure()
3129
ax = Axis(fig[1, 1])
3230
heatmap!(ax, interior(grid.immersed_boundary.mask, :, :, grid.Nz))
31+
save("ECCO_continents.png", fig) # hide
3332

34-
save("ecco_continents.png", fig)
35-
nothing #hide
36-
37-
# ![](ecco_continents.png)
33+
# ![](ECCO_continents.png)
3834

3935
# Next, we construct our atmosphere and ocean.
4036
#
@@ -50,103 +46,50 @@ nothing #hide
5046
#
5147
# We invoke the constructor with only the first two time indices, corresponding to
5248
# January 1st (at 00:00 AM and 03:00 AM).
53-
# By passing the ECCO grid, we automatically interpolate the atmospheric data onto the grid.
54-
# Note that this is recommended only for small simulations (in terms of grid size).
55-
# By omitting the grid, the interpolation will be done on the fly.
56-
#
57-
# We construct the ocean simulation without considering advection, closures, or Coriolis effects since
58-
# we will not time-step the ocean but only use it to construct the fluxes.
59-
60-
atmosphere = JRA55_prescribed_atmosphere(1:2; backend = InMemory(), grid = grid.underlying_grid)
61-
62-
ocean = ocean_simulation(grid; momentum_advection = nothing,
63-
tracer_advection = nothing,
64-
closure = nothing,
65-
coriolis = nothing)
66-
67-
# Now that we have an atmosphere and a container for the ocean, we need to populate
68-
# our ocean with initial conditions. To do this, we can use the ECCO2 dataset by
69-
# `set!`ting the model with the `ECCOMetadata`. If no date is specified,
70-
# the fields corresponding to January 1st, 1992 (the first available date in
71-
# ECCO2 dataset) are used.
72-
# This command will download the fields to the local machine.
73-
74-
set!(ocean.model;
75-
T = ECCOMetadata(:temperature),
76-
S = ECCOMetadata(:salinity))
77-
78-
# The final step is to construct a coupled model.
79-
# The coupled model requires an ocean, which we have just constructed and initialized,
80-
# an atmosphere, which we have downloaded from the JRA55 dataset, a sea ice model
81-
# (in this case we do not account for sea ice by defining `sea_ice = nothing`),
82-
# and a radiation model. The default radiation model assumes two spectral bands:
83-
# a shortwave band modeling visible and UV light, and a longwave band that accounts for
84-
# near, mid and far infrared (mostly far infrared given the low emission temperature).
85-
# By constructing the coupled model, the `update_state!` function, which calculates the fluxes,
86-
# will be triggered.
87-
88-
radiation = Radiation()
89-
sea_ice = nothing
90-
coupled_model = OceanSeaIceModel(ocean, sea_ice; atmosphere, radiation)
49+
50+
atmosphere = JRA55_prescribed_atmosphere(1:2; backend = InMemory())
51+
ocean = ocean_simulation(grid)
52+
53+
# Now that we have an atmosphere and ocean, we `set!` the ocean temperature and salinity
54+
# to the ECCO2 data by first creating T, S metadata objects,
55+
56+
T_metadata = ECCOMetadata(:temperature)
57+
S_metadata = ECCOMetadata(:salinity)
58+
59+
# Note that if a date is not provided to `ECCOMetadata`, then the default Jan 1st, 1992 is used.
60+
# To copy the ECCO state into `ocean.model`, we use `set!`,
61+
62+
set!(ocean.model; T=T_metadata, S=S_metadata)
63+
64+
# Finally, we construct a coupled model, which will compute fluxes during construction.
65+
# We omit `sea_ice` so the model is ocean-only, and use the default `Radiation()` that
66+
# uses the two-band shortwave (visible and UV) + longwave (mid and far infrared)
67+
# decomposition of the radiation spectrum.
68+
69+
coupled_model = OceanSeaIceModel(ocean; atmosphere, radiation=Radiation())
9170

9271
# Now that the surface fluxes are computed, we can extract and visualize them.
9372
# The turbulent fluxes are stored in `coupled_model.fluxes.turbulent`.
94-
#
95-
# Qs = coupled_model.fluxes.turbulent.fields.sensible_heat : the sensible heat flux (in Wm⁻²)
96-
# Ql = coupled_model.fluxes.turbulent.fields.latent_heat : the latent heat flux (in Wm⁻²)
97-
# τx = coupled_model.fluxes.turbulent.fields.x_momentum : the zonal wind stress (in Nm)
98-
# τy = coupled_model.fluxes.turbulent.fields.y_momentum : the meridional wind stress (in Nm)
99-
# Mv = coupled_model.fluxes.turbulent.fields.water_vapor : evaporation (in kg m⁻²s⁻¹)
100-
#
101-
# They are 2D fields (3D data structures with one point in the vertical). To extract the data, we use the
102-
# `interior` functionality from Oceananigans.
103-
104-
turbulent_fluxes = coupled_model.fluxes.turbulent.fields
10573

106-
Qs = interior(turbulent_fluxes.sensible_heat, :, :, 1)
107-
Ql = interior(turbulent_fluxes.latent_heat, :, :, 1)
108-
τx = interior(turbulent_fluxes.x_momentum, :, :, 1)
109-
τy = interior(turbulent_fluxes.y_momentum, :, :, 1)
110-
Mv = interior(turbulent_fluxes.water_vapor, :, :, 1)
111-
nothing #hide
74+
fluxes = coupled_model.fluxes.turbulent.fields
11275

11376
fig = Figure(size = (800, 400))
114-
ax = Axis(fig[1, 1], title = "Sensible heat flux (Wm⁻²)")
115-
hm = heatmap!(ax, Qs; colormap = :bwr)
116-
hidedecorations!(ax)
117-
save("sensible_heat_flux.png", fig)
118-
nothing #hide
119-
# ![](sensible_heat_flux.png)
12077

121-
fig = Figure(size = (800, 400))
122-
ax = Axis(fig[1, 2], title = "Latent heat flux (Wm⁻²)")
123-
heatmap!(ax, Ql; colormap = :bwr)
124-
hidedecorations!(ax)
125-
save("latent_heat_flux.png", fig)
126-
nothing #hide
127-
# ![](latent_heat_flux.png)
78+
ax = Axis(fig[1, 1], title = "Sensible heat flux (W m⁻²)")
79+
heatmap!(ax, fluxes.sensible_heat; colormap = :bwr)
12880

129-
fig = Figure(size = (800, 400))
130-
ax = Axis(fig[2, 1], title = "Zonal wind stress (Nm)")
131-
heatmap!(ax, τx; colormap = :bwr)
132-
hidedecorations!(ax)
133-
save("zonal_wind_stress.png", fig)
134-
nothing #hide
135-
# ![](zonal_wind_stress.png)
81+
ax = Axis(fig[1, 2], title = "Latent heat flux (W m⁻²)")
82+
heatmap!(ax, fluxes.latent_heat; colormap = :bwr)
13683

137-
fig = Figure(size = (800, 400))
138-
ax = Axis(fig[2, 2], title = "Meridional wind stress (Nm)")
139-
heatmap!(ax, τy; colormap = :bwr)
140-
hidedecorations!(ax)
141-
save("meridional_wind_stress.png", fig)
142-
nothing #hide
143-
# ![](meridional_wind_stress.png)
84+
ax = Axis(fig[2, 1], title = "Zonal wind stress (N m)")
85+
heatmap!(ax, fluxes.x_momentum; colormap = :bwr)
14486

145-
fig = Figure(size = (800, 400))
146-
ax = Axis(fig[3, 1], title = "Water vapor flux (kg m⁻²s⁻¹)")
87+
ax = Axis(fig[2, 2], title = "Meridional wind stress (N m)")
88+
heatmap!(ax, fluxes.y_momentum; colormap = :bwr)
89+
90+
ax = Axis(fig[3, 1], title = "Water vapor flux (kg m⁻² s⁻¹)")
14791
heatmap!(ax, Mv; colormap = :bwr)
148-
hidedecorations!(ax)
149-
save("water_vapor_flux.png", fig)
150-
nothing #hide
151-
# ![](water_vapor_flux.png)
92+
93+
save("fluxes.png", fig)
94+
# ![](fluxes.png)
15295

examples/inspect_ecco_data.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ using Oceananigans
1414
using CairoMakie
1515
using Printf
1616

17-
using ClimaOcean: ECCO
17+
using ClimaOcean.DataWrangling.ECCO: ECCO_field
1818

19-
# The function `ecco_field` provided by `ClimaOcean.DataWrangling.ECCO` will automatically
19+
# The function `ECCO_field` provided by `ClimaOcean.DataWrangling.ECCO` will automatically
2020
# download ECCO data if it doesn't already exist at the default location.
2121

22-
T = ECCO.ecco_field(:temperature)
23-
S = ECCO.ecco_field(:salinity)
22+
T = ECCO_field(:temperature)
23+
S = ECCO_field(:salinity)
2424

2525
# Next, we massage the ECCO data by inserting NaNs in "land cells", which
2626
# are diagnosed by having an unphysically low temperature.
@@ -50,14 +50,14 @@ grid = T.grid
5050
Nz = size(grid, 3)
5151
k = Observable(Nz)
5252

53-
Tk = @lift interior(T, :, :, $k)
54-
Sk = @lift interior(S, :, :, $k)
53+
Tk = @lift view(T, :, :, $k)
54+
Sk = @lift view(S, :, :, $k)
5555

5656
# Finally, we make a nice plot with a label that displays depth, colorbars,
5757
# and light gray within land cells.
5858

59-
hmT = heatmap!(axT, λ, φ, Tk, nan_color=:lightgray, colorrange=(-2, 30), colormap=:thermal)
60-
hmS = heatmap!(axS, λ, φ, Sk, nan_color=:lightgray, colorrange=(31, 37), colormap=:haline)
59+
hmT = heatmap!(axT, Tk, nan_color=:lightgray, colorrange=(-2, 30), colormap=:thermal)
60+
hmS = heatmap!(axS, Sk, nan_color=:lightgray, colorrange=(31, 37), colormap=:haline)
6161

6262
Colorbar(fig[1, 2], hmT, label="Temperature (ᵒC)")
6363
Colorbar(fig[2, 2], hmS, label="Salinity (psu)")

src/ClimaOcean.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ export
99
JRA55_prescribed_atmosphere,
1010
JRA55NetCDFBackend,
1111
ECCOMetadata,
12-
ecco2_field,
1312
regrid_bathymetry,
1413
retrieve_bathymetry,
1514
stretched_vertical_faces,
1615
exponential_z_faces,
1716
PowerLawStretching, LinearStretching,
1817
exponential_z_faces,
1918
JRA55_field_time_series,
20-
ecco_field, ECCOMetadata,
19+
ECCO_field, ECCOMetadata,
2120
ocean_simulation,
2221
initialize!
2322

@@ -72,7 +71,7 @@ using .OceanSeaIceModels
7271
using .OceanSimulations
7372
using .DataWrangling: JRA55, ECCO
7473
using ClimaOcean.DataWrangling.JRA55: JRA55_prescribed_atmosphere, JRA55NetCDFBackend
75-
using ClimaOcean.DataWrangling.ECCO: ecco_field, ECCOMetadata
74+
using ClimaOcean.DataWrangling.ECCO
7675

7776
end # module
7877

src/DataWrangling/DataWrangling.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ end
7373

7474
include("inpaint_mask.jl")
7575
include("JRA55.jl")
76-
include("ECCO.jl")
76+
include("ECCO/ECCO.jl")
7777

7878
using .JRA55
7979
using .ECCO

0 commit comments

Comments
 (0)