Skip to content

A low resolution coupled simulation #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 91 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
3114f74
this works best?
simone-silvestri Nov 22, 2024
9101d57
One degree simulation take 4
simone-silvestri Nov 22, 2024
5833d19
add a biharmonic viscosity
simone-silvestri Nov 22, 2024
96a64a2
Merge branch 'main' into ss/one-degree-take3
navidcy Nov 23, 2024
0aa74dc
infer maximum delta t
simone-silvestri Nov 23, 2024
ea8708f
Merge branch 'ss/one-degree-take3' of github.com:CliMA/ClimaOcean.jl …
simone-silvestri Nov 23, 2024
3a77b67
Merge remote-tracking branch 'origin/main' into ss/one-degree-take3
simone-silvestri Nov 26, 2024
7c87f2b
changes
simone-silvestri Nov 26, 2024
bddeae3
add statistics
simone-silvestri Nov 26, 2024
f129a1d
infer -> compute
simone-silvestri Dec 2, 2024
c0e2038
compute -> infer
simone-silvestri Dec 2, 2024
8de801a
Merge branch 'ss/one-degree-take3' of github.com:CliMA/ClimaOcean.jl …
simone-silvestri Dec 2, 2024
1857737
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 3, 2024
75bd857
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 3, 2024
9d08000
default for distribtued grid
simone-silvestri Dec 4, 2024
2ffa919
Merge branch 'ss/one-degree-take3' of github.com:CliMA/ClimaOcean.jl …
simone-silvestri Dec 4, 2024
9ead323
all_reduce instead of allreduce
simone-silvestri Dec 4, 2024
9425908
update other packages
simone-silvestri Dec 10, 2024
1cde9b9
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 11, 2024
d887392
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 13, 2024
60a4eac
Merge branch 'main' into ss/one-degree-take3
navidcy Dec 15, 2024
fa2eea4
let's see if it works
simone-silvestri Dec 15, 2024
22126cb
try it out
simone-silvestri Dec 15, 2024
7ddd356
run simulation
simone-silvestri Dec 15, 2024
1803be5
remove all instances of diffusion
simone-silvestri Dec 15, 2024
afe79e4
try a zstar grid
simone-silvestri Dec 15, 2024
2f57e3c
need a manifest for this
simone-silvestri Dec 15, 2024
48d70c9
regrid the bathymetry
simone-silvestri Dec 15, 2024
2b88745
better
simone-silvestri Dec 15, 2024
c8c446a
make it work
simone-silvestri Dec 22, 2024
28f95d6
Update Project.toml
simone-silvestri Dec 22, 2024
44d16ce
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 22, 2024
c36c867
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Dec 22, 2024
53b898a
fix docs
simone-silvestri Dec 22, 2024
5c6bf40
fix docs
simone-silvestri Dec 22, 2024
c081671
update project
simone-silvestri Dec 23, 2024
3035819
just remove it for now
simone-silvestri Dec 23, 2024
915320d
Merge remote-tracking branch 'origin/main' into ss/one-degree-take3
simone-silvestri Dec 23, 2024
3ec643c
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Jan 19, 2025
63c8f97
try out correct settings
simone-silvestri Jan 19, 2025
bf0da6d
Update examples/one_degree_simulation.jl
simone-silvestri Jan 23, 2025
d3d7a58
should work now
simone-silvestri Feb 2, 2025
1f0f98d
Merge branch 'main' into ss/one-degree-take3
navidcy Feb 2, 2025
0bbb834
literate one-degree example
navidcy Feb 12, 2025
c161d72
use GPU
navidcy Feb 12, 2025
36cf425
nuke znode
navidcy Feb 12, 2025
c4e21d0
add CairoMakie 0.13 compat
navidcy Feb 12, 2025
90fc47a
explain that there is also e
navidcy Feb 12, 2025
fc0e6cf
add comment for OrthogonalSphericalShellGrids
navidcy Feb 12, 2025
00ca95e
add comment for coupled ocean--sea ice
navidcy Feb 12, 2025
cfe530c
nuke ExplicitTimeDiscretization and fix typo
navidcy Feb 12, 2025
6c275c0
this should work
simone-silvestri Feb 13, 2025
de65394
add another restoring file
simone-silvestri Feb 13, 2025
4a4f6b2
correct videos
simone-silvestri Feb 13, 2025
1d404e1
Merge remote-tracking branch 'origin/main' into ss/one-degree-take3
simone-silvestri Feb 15, 2025
5f90f0c
tamper with the time step
simone-silvestri Feb 15, 2025
0961bd9
bugfix
simone-silvestri Feb 15, 2025
90d5a44
Merge branch 'main' into ss/one-degree-take3
simone-silvestri Feb 16, 2025
2372660
remove for the moment
simone-silvestri Feb 16, 2025
e792172
fix examples
simone-silvestri Feb 17, 2025
ac7a7c0
already some bugfix
simone-silvestri Feb 17, 2025
1956702
this should work?
simone-silvestri Feb 17, 2025
9ff934f
go ahead
simone-silvestri Feb 17, 2025
66f3b7b
some changes
simone-silvestri Feb 20, 2025
4670e14
some more changes
simone-silvestri Feb 20, 2025
79101eb
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 20, 2025
56310cd
some fixes
simone-silvestri Feb 20, 2025
de44377
Merge branch 'ss/new-coupled-sim' of github.com:CliMA/ClimaOcean.jl i…
simone-silvestri Feb 20, 2025
2fa10bb
this should run
simone-silvestri Feb 20, 2025
05595e7
we do not need to remove fluxes as we adjust the ocean interior
simone-silvestri Feb 20, 2025
6e14364
don't need to do that
simone-silvestri Feb 20, 2025
faa3ed1
also don't need this
simone-silvestri Feb 20, 2025
8569a21
adjust temperature
simone-silvestri Feb 20, 2025
0af383a
remove unused stuff
simone-silvestri Feb 20, 2025
4202331
remove other stuff
simone-silvestri Feb 21, 2025
8937795
bugfixes
simone-silvestri Feb 21, 2025
25303b1
changes
simone-silvestri Feb 22, 2025
b1dd30e
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 24, 2025
a066a5e
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 24, 2025
da2d756
add some tests
simone-silvestri Feb 25, 2025
088f6ce
remo this line
simone-silvestri Feb 25, 2025
96a9f3d
fix tests
simone-silvestri Feb 25, 2025
9656238
some bugfixes
simone-silvestri Feb 26, 2025
b033e1a
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 26, 2025
51149e0
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 26, 2025
b743917
Update coefficient_based_turbulent_fluxes.jl
simone-silvestri Feb 26, 2025
025986e
Update interface_states.jl
simone-silvestri Feb 26, 2025
05297e2
bugfix
simone-silvestri Feb 26, 2025
6b23b5e
Merge branch 'ss/new-coupled-sim' of github.com:CliMA/ClimaOcean.jl i…
simone-silvestri Feb 26, 2025
24eb5b5
correct tests
simone-silvestri Feb 26, 2025
2718b00
Merge branch 'main' into ss/new-coupled-sim
simone-silvestri Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ OrthogonalSphericalShellGrids = "c2be9673-fb75-4747-82dc-aa2bb9f4aed0"
SeawaterPolynomials = "d496a93d-167e-4197-9f49-d3af4ff8fe40"

[compat]
CairoMakie = "0.10.12, 0.11, 0.12"
CairoMakie = "0.10.12, 0.11, 0.12, 0.13"
DataDeps = "0.7"
Documenter = "1"
Oceananigans = "0.95.7 - 0.99"
OrthogonalSphericalShellGrids = "0.2.1"
SeawaterPolynomials = "0.3.4"
SeawaterPolynomials = "0.3.5"
2 changes: 2 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ to_be_literated = [
"generate_bathymetry.jl",
"generate_surface_fluxes.jl",
"single_column_os_papa_simulation.jl",
"one_degree_simulation.jl",
# "mediterranean_simulation_with_ecco_restoring.jl",
"near_global_ocean_simulation.jl"
]
Expand Down Expand Up @@ -46,6 +47,7 @@ pages = [
"Surface fluxes" => "literated/generate_surface_fluxes.md",
"Single-column simulation" => "literated/single_column_os_papa_simulation.md",
# "Mediterranean simulation with ECCO restoring" => "literated/mediterranean_simulation_with_ecco_restoring.md",
"One-degree Ocean simulation" => "literated/one_degree_simulation.md",
"Near-global Ocean simulation" => "literated/near_global_ocean_simulation.md",
],

Expand Down
4 changes: 2 additions & 2 deletions examples/ecco_mixed_layer_depth.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ using SeawaterPolynomials: TEOS10EquationOfState
using Oceananigans.BuoyancyFormulations: buoyancy

arch = CPU()
Nx = 360 ÷ 1
Ny = 160 ÷ 1
Nx = 360
Ny = 160

z = ClimaOcean.DataWrangling.ECCO.ECCO_z
z = z[20:end]
Expand Down
8 changes: 4 additions & 4 deletions examples/generate_surface_fluxes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ set!(ocean.model; T=T_metadata, S=S_metadata)

coupled_model = OceanSeaIceModel(ocean; atmosphere, radiation=Radiation())

# Now that the surface fluxes are computed, we can extract and visualize them.
# The turbulent fluxes are stored in `coupled_model.fluxes.turbulent`.
# # Now that the surface fluxes are computed, we can extract and visualize them.
# # The turbulent fluxes are stored in `coupled_modelinterfaces.atmosphere_ocean_interface.fluxes`.

fluxes = coupled_model.fluxes.turbulent.fields
fluxes = coupled_modelinterfaces.atmosphere_ocean_interface.fluxes
λ, φ, z = nodes(fluxes.sensible_heat)

fig = Figure(size = (800, 800), fontsize = 15)
Expand All @@ -89,4 +89,4 @@ ax = Axis(fig[3, 1], title = "Water vapor flux (kg m⁻² s⁻¹)", xlabel = "Lo
heatmap!(ax, λ, φ, interior(fluxes.water_vapor, :, :, 1); colormap = :bwr)

save("fluxes.png", fig)
# ![](fluxes.png)
![](fluxes.png)
255 changes: 255 additions & 0 deletions examples/one_degree_simulation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
# # One-degree global ocean simulation
#
# This example configures a global ocean--sea ice simulation at 1ᵒ horizontal resolution with
# realistic bathymetry and some closures.
#
# For this example, we need Oceananigans, ClimaOcean, OrthogonalSphericalShellGrids, and
# CairoMakie to visualize the simulation. Also we need CFTime and Dates for date handling.

using ClimaOcean
using ClimaOcean.ECCO: ECCO4Monthly, NearestNeighborInpainting
using Oceananigans
using Oceananigans.Units
using OrthogonalSphericalShellGrids
using CFTime
using Dates
using Printf

arch = CPU()

# ### Grid and Bathymetry

Nx = 360
Ny = 180
Nz = 100

r_faces = exponential_z_faces(; Nz, depth=5000, h=34)
z_faces = Oceananigans.MutableVerticalDiscretization(r_faces)

underlying_grid = TripolarGrid(arch;
size = (Nx, Ny, Nz),
z = z_faces,
halo = (5, 5, 4),
first_pole_longitude = 70,
north_poles_latitude = 55)

bottom_height = regrid_bathymetry(underlying_grid;
minimum_depth = 10,
interpolation_passes = 75,
major_basins = 2)

# For this bathymetry at this horizontal resolution we need to manually open the Gibraltar strait.
tampered_bottom_height = deepcopy(bottom_height)
view(tampered_bottom_height, 102:103, 124, 1) .= -400

grid = ImmersedBoundaryGrid(underlying_grid, GridFittedBottom(tampered_bottom_height);
active_cells_map=true)

# ### Restoring

# We include temperature and salinity surface restoring to ECCO2.
restoring_rate = 1 / 10days
z_below_surface = r_faces[end-1]

mask = LinearlyTaperedPolarMask(southern=(-80, -70), northern=(70, 90), z=(z_below_surface, 0))

dates = DateTimeProlepticGregorian(1993, 1, 1) : Month(1) : DateTimeProlepticGregorian(1994, 1, 1)
temperature = ECCOMetadata(:temperature; dates, version=ECCO4Monthly(), dir="./")
salinity = ECCOMetadata(:salinity; dates, version=ECCO4Monthly(), dir="./")

FT = ECCORestoring(temperature, grid; mask, rate=restoring_rate)
FS = ECCORestoring(salinity, grid; mask, rate=restoring_rate)
forcing = (T=FT, S=FS)

# ### Closures

# We include a Gent-McWilliam isopycnal diffusivity as a parameterization for the mesoscale
# eddy fluxes. For vertical mixing at the upper-ocean boundary layer we include the CATKE
# parameterization. We also include some explicit horizontal diffusivity.

using Oceananigans.TurbulenceClosures: IsopycnalSkewSymmetricDiffusivity,
DiffusiveFormulation

eddy_closure = IsopycnalSkewSymmetricDiffusivity(κ_skew=1e3, κ_symmetric=1e3,
skew_flux_formulation=DiffusiveFormulation())
vertical_mixing = ClimaOcean.OceanSimulations.default_ocean_closure()

closure = (eddy_closure, vertical_mixing)

# ### Ocean simulation

# Now we bring everything together to construct the ocean simulation.
# We use a split-explicit timestepping with 30 substeps for the barotropic
# mode.

free_surface = SplitExplicitFreeSurface(grid; substeps=30)

momentum_advection = WENOVectorInvariant(vorticity_order=3)
tracer_advection = Centered()

ocean = ocean_simulation(grid;
momentum_advection,
tracer_advection,
closure,
forcing,
free_surface)

# ### Initial condition

# We initialize the ocean from the ECCO2 state estimate.

set!(ocean.model, T=ECCOMetadata(:temperature; dates=first(dates)),
S=ECCOMetadata(:salinity; dates=first(dates)))

# ### Atmospheric forcing

# We force the simulation with an JRA55-do atmospheric reanalysis.
radiation = Radiation(arch)
atmosphere = JRA55PrescribedAtmosphere(arch; backend=JRA55NetCDFBackend(20))

# ### Coupled simulation

# Now we are ready to build the coupled ocean--sea ice model and bring everything
# together into a `simulation`.

# We use a relatively short time step initially and only run for a few days to
# avoid numerical instabilities from the initial "shock" of the adjustment of the
# flow fields.

coupled_model = OceanSeaIceModel(ocean; atmosphere, radiation)
simulation = Simulation(coupled_model; Δt=1minutes, stop_time=10days)

# ### A progress messenger
#
# We write a function that prints out a helpful progress message while the simulation runs.

wall_time = Ref(time_ns())

function progress(sim)
ocean = sim.model.ocean
u, v, w = ocean.model.velocities
T = ocean.model.tracers.T
Tmax = maximum(interior(T))
Tmin = minimum(interior(T))
umax = (maximum(abs, interior(u)),
maximum(abs, interior(v)),
maximum(abs, interior(w)))

step_time = 1e-9 * (time_ns() - wall_time[])

@info @sprintf("time: %s, iteration: %d, Δt: %s, max|u|: (%.2e, %.2e, %.2e) m s⁻¹, extrema(T): (%.2f, %.2f) ᵒC, wall time: %s \n",
prettytime(sim), iteration(sim), prettytime(sim.Δt),
umax..., Tmax, Tmin, prettytime(step_time))

wall_time[] = time_ns()

return nothing
end

# And add it as a callback to the simulation.
add_callback!(simulation, progress, IterationInterval(10))

# ### Output
#
# We are almost there! We need to save some output. Below we choose to save _only surface_
# fields using the `indices` keyword argument. We save all velocity and tracer components.
# Note, that besides temperature and salinity, the CATKE vertical mixing parameterization
# also uses a prognostic turbulent kinetic energy, `e`, to diagnose the vertical mixing length.

outputs = merge(ocean.model.tracers, ocean.model.velocities)
ocean.output_writers[:surface] = JLD2OutputWriter(ocean.model, outputs;
schedule = TimeInterval(5days),
filename = "global_surface_fields",
indices = (:, :, grid.Nz),
with_halos = true,
overwrite_existing = true,
array_type = Array{Float32})

# ### Ready to run

# We are ready to press the big red button and run the simulation.

# After we run for a short time (here we set up the simulation with `stop_time = 10days`),
# we increase the timestep and run for longer.

run!(simulation)

simulation.Δt = 20minutes
simulation.stop_time = 360days

run!(simulation)

# ### A pretty movie
#
# We load the saved output and make a pretty movie of the simulation. First we plot a snapshot:
using CairoMakie

u = FieldTimeSeries("global_surface_fields.jld2", "u"; backend = OnDisk())
v = FieldTimeSeries("global_surface_fields.jld2", "v"; backend = OnDisk())
T = FieldTimeSeries("global_surface_fields.jld2", "T"; backend = OnDisk())
e = FieldTimeSeries("global_surface_fields.jld2", "e"; backend = OnDisk())

times = u.times
Nt = length(times)

n = Observable(Nt)

# We create a land mask and use it to fill land points with `NaN`s.
land = interior(T.grid.immersed_boundary.bottom_height) .≥ 0

Tn = @lift begin
Tn = interior(T[$n])
Tn[land] .= NaN
view(Tn, :, :, 1)
end

en = @lift begin
en = interior(e[$n])
en[land] .= NaN
view(en, :, :, 1)
end

# We compute the surface speed.
un = Field{Face, Center, Nothing}(u.grid)
vn = Field{Center, Face, Nothing}(v.grid)
s = Field(sqrt(un^2 + vn^2))

sn = @lift begin
parent(un) .= parent(u[$n])
parent(vn) .= parent(v[$n])
compute!(s)
sn = interior(s)
sn[land] .= NaN
view(sn, :, :, 1)
end

# Finally, we plot a snapshot of the surface speed, temperature, and the turbulent
# eddy kinetic energy from the CATKE vertical mixing parameterization.
fig = Figure(size = (800, 1200))

axs = Axis(fig[1, 1], xlabel="Longitude (deg)", ylabel="Latitude (deg)")
axT = Axis(fig[2, 1], xlabel="Longitude (deg)", ylabel="Latitude (deg)")
axe = Axis(fig[3, 1], xlabel="Longitude (deg)", ylabel="Latitude (deg)")

hm = heatmap!(axs, sn, colorrange = (0, 0.5), colormap = :deep, nan_color=:lightgray)
Colorbar(fig[1, 2], hm, label = "Surface speed (m s⁻¹)")

hm = heatmap!(axT, Tn, colorrange = (-1, 30), colormap = :magma, nan_color=:lightgray)
Colorbar(fig[2, 2], hm, label = "Surface Temperature (ᵒC)")

hm = heatmap!(axe, en, colorrange = (0, 1e-3), colormap = :solar, nan_color=:lightgray)
Colorbar(fig[3, 2], hm, label = "Turbulent Kinetic Energy (m² s⁻²)")

save("global_snapshot.png", fig)
nothing #hide

# ![](global_snapshot.png)

# And now a movie:

record(fig, "one_degree_global_ocean_surface.mp4", 1:Nt, framerate = 8) do nn
n[] = nn
end
nothing #hide

# ![](one_degree_global_ocean_surface.mp4)
24 changes: 12 additions & 12 deletions examples/single_column_os_papa_simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ function progress(sim)
S = sim.model.ocean.model.tracers.S
e = sim.model.ocean.model.tracers.e

τx = first(sim.model.fluxes.total.ocean.momentum.u)
τy = first(sim.model.fluxes.total.ocean.momentum.v)
Q = first(sim.model.fluxes.total.ocean.heat)
τx = first(sim.model.interfaces.net_fluxes.ocean_surface.u)
τy = first(sim.model.interfaces.net_fluxes.ocean_surface.v)
Q = first(sim.model.interfaces.net_fluxes.ocean_surface.Q)

u★ = sqrt(sqrt(τx^2 + τy^2))

Expand All @@ -142,15 +142,15 @@ end
simulation.callbacks[:progress] = Callback(progress, IterationInterval(100))

# Build flux outputs
τx = coupled_model.fluxes.total.ocean.momentum.u
τy = coupled_model.fluxes.total.ocean.momentum.v
JT = coupled_model.fluxes.total.ocean.tracers.T
Js = coupled_model.fluxes.total.ocean.tracers.S
E = coupled_model.fluxes.turbulent.fields.water_vapor
Qc = coupled_model.fluxes.turbulent.fields.sensible_heat
Qv = coupled_model.fluxes.turbulent.fields.latent_heat
ρₒ = coupled_model.fluxes.ocean_reference_density
cₚ = coupled_model.fluxes.ocean_heat_capacity
τx = coupled_model.interfaces.atmosphere_ocean_interface.fluxes.x_momentum
τy = coupled_model.interfaces.atmosphere_ocean_interface.fluxes.y_momentum
JT = coupled_model.interfaces.net_fluxes.ocean_surface.T
Js = coupled_model.interfaces.net_fluxes.ocean_surface.S
E = coupled_model.interfaces.atmosphere_ocean_interface.fluxes.water_vapor
Qc = coupled_model.interfaces.atmosphere_ocean_interface.fluxes.sensible_heat
Qv = coupled_model.interfaces.atmosphere_ocean_interface.fluxes.latent_heat
ρₒ = coupled_model.interfaces.fluxes.ocean_reference_density
cₚ = coupled_model.interfaces.fluxes.ocean_heat_capacity

Q = ρₒ * cₚ * JT
ρτx = ρₒ * τx
Expand Down
Loading