Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9d733ff
Add tidal potential to PrescribedAtmosphere
glwagner Mar 7, 2025
9183b20
Merge remote-tracking branch 'origin/main' into glw-ss/tidal-potential
simone-silvestri Mar 8, 2025
787b4b3
try it out
simone-silvestri Mar 8, 2025
c359118
try it out here for now
simone-silvestri Mar 8, 2025
928eea8
add it to JRA55
simone-silvestri Mar 8, 2025
7ec088c
surface layer height
simone-silvestri Mar 8, 2025
b0845a6
index
simone-silvestri Mar 8, 2025
25ec84e
finding the forcing
simone-silvestri Mar 8, 2025
141cec9
forcing
simone-silvestri Mar 8, 2025
577258a
in the potential
simone-silvestri Mar 8, 2025
9a570d6
barotropic tide
simone-silvestri Mar 8, 2025
2fffee4
keep this for the moment
simone-silvestri Mar 8, 2025
ea208b1
add a function for this
simone-silvestri Mar 9, 2025
7974435
Merge remote-tracking branch 'origin/main' into glw-ss/tidal-potential
simone-silvestri Mar 9, 2025
1c69aa9
get barotropic potential
simone-silvestri Mar 9, 2025
27524bc
small change
simone-silvestri Mar 9, 2025
baf42d6
put it up
simone-silvestri Mar 9, 2025
d8bc7ac
add boundary conditions
simone-silvestri Mar 9, 2025
22f070a
fix
simone-silvestri Mar 9, 2025
2dfcaac
small example
simone-silvestri Mar 10, 2025
4ae2e11
Merge branch 'main' into glw-ss/tidal-potential
simone-silvestri Mar 10, 2025
9590694
remove barotropic example
simone-silvestri Mar 10, 2025
8d086c5
Merge branch 'glw-ss/tidal-potential' of github.com:CliMA/ClimaOcean.…
simone-silvestri Mar 10, 2025
d4c4469
disable GPU examples
simone-silvestri Mar 10, 2025
0f47761
reenable examples
simone-silvestri Mar 10, 2025
5f459e7
interpolate tidal potential
simone-silvestri Mar 10, 2025
48a2774
bugfix
simone-silvestri Mar 10, 2025
2e76fe8
add a grid
simone-silvestri Mar 10, 2025
7b7dadf
do not compute if not there
simone-silvestri Mar 10, 2025
52af83e
updates
simone-silvestri Mar 10, 2025
0b2c78b
Merge branch 'glw-ss/tidal-potential' of github.com:CliMA/ClimaOcean.…
simone-silvestri Mar 10, 2025
51e3891
Merge remote-tracking branch 'origin/main' into glw-ss/tidal-potential
glwagner Mar 13, 2025
a564382
Updates for tidal
glwagner Mar 13, 2025
5fa08f5
Temp fix for bathy bug
glwagner Mar 13, 2025
255d80f
Merge remote-tracking branch 'origin/main' into glw-ss/tidal-potential
glwagner Mar 13, 2025
774ccf9
Merge remote-tracking branch 'origin/main' into glw-ss/tidal-potential
glwagner Mar 14, 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
3 changes: 2 additions & 1 deletion examples/near_global_ocean_simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ radiation = Radiation(arch)
# The number of snapshots that are loaded into memory is determined by
# the `backend`. Here, we load 41 snapshots at a time into memory.

atmosphere = JRA55PrescribedAtmosphere(arch; backend=JRA55NetCDFBackend(41))
tidal_potential = FieldTimeSeries("tidal_potential.jld2", "Φ")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need partly in memory or this is fine?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems fine for the moment. I will remove it before merging and after posting the outcome of this simulation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so that we do not change the example

atmosphere = JRA55PrescribedAtmosphere(arch; tidal_potential, backend=JRA55NetCDFBackend(41))

# ## The coupled simulation

Expand Down
73 changes: 73 additions & 0 deletions experiments/ocean_forced_by_tides.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

using ClimaOcean
using Oceananigans
using OrthogonalSphericalShellGrids
using Oceananigans.Units
using Printf

import Oceananigans.BuoyancyFormulations: ρ′
import ClimaOcean.OceanSeaIceModels: reference_density, heat_capacity

struct ZeroBuoyancy{R}
reference_density :: R
end

@inline ρ′(i, j, k, grid, ::ZeroBuoyancy, T, S) = zero(grid)
@inline reference_density(r::ZeroBuoyancy) = r.reference_density
@inline heat_capacity(r::ZeroBuoyancy) = 3990.0

# all passive tracers
equation_of_state = ZeroBuoyancy(1026.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting! but there won't be internal tides with no stratification!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, this is a small test case that I have eventually removed from the PR, but kept in the comments for documentation purposes


# A barotropic ocean
grid = TripolarGrid(size = (700, 400, 1), halo = (7, 7, 7), z = (-10, 0))
bottom_height = regrid_bathymetry(grid)
grid = ImmersedBoundaryGrid(grid, GridFittedBottom(bottom_height); active_cells_map=true)
ocean = ocean_simulation(grid; closure=nothing, bottom_drag_coefficient=0, tracer_advection=nothing, equation_of_state)

# A prescribed tidal forcing
Φ = FieldTimeSeries("tidal_potential_jra55.jld2", "Φ")
atmos = PrescribedAtmosphere.grid, Φ.times; tidal_potential=Φ)
set!(ocean.model, T=first(atmos.tracers.T), S=35)

# neutral radiation
radiation=Radiation(ocean_albedo=1, ocean_emissivity=0)

# No fluxes
struct ZeroFluxes{N, B}
solver_stop_criteria :: N
bulk_velocity :: B
end

import ClimaOcean.OceanSeaIceModels.InterfaceComputations: compute_interface_state, ComponentInterfaces
using ClimaOcean.OceanSeaIceModels.InterfaceComputations: zero_interface_state

@inline compute_interface_state(::ZeroFluxes, args...) = zero_interface_state(Float64)

interfaces = ComponentInterfaces(atmos, ocean, nothing;
atmosphere_ocean_flux_formulation=ZeroFluxes(nothing, ClimaOcean.OceanSeaIceModels.InterfaceComputations.WindVelocity()),
radiation)

barotropic_earth_model = OceanSeaIceModel(ocean, nothing; atmosphere=atmos, radiation, interfaces)

barotropic_earth = Simulation(barotropic_earth_model, Δt=20minutes, stop_time=2days)

wall_time = Ref(0.0)

function progress(barotropic_earth)
clock = barotropic_earth.model.clock
u, v, w = barotropic_earth.model.ocean.model.velocities

maxu = maximum(abs, u)
maxv = maximum(abs, v)
maxw = maximum(abs, w)

@info @sprintf("Iteration: %d, time: %s, wall_time: %s, max(|u|, |v|, |w|): %.2e %.2e %.2e\n",
clock.iteration, prettytime(clock.time), prettytime(1e-9 * (time_ns() - wall_time[])), maxu, maxv, maxw)

wall_time[] = time_ns()
end

add_callback!(barotropic_earth, progress, IterationInterval(100))

run!(barotropic_earth)
8 changes: 5 additions & 3 deletions src/DataWrangling/JRA55.jl
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ Return a `PrescribedAtmosphere` representing JRA55 reanalysis data.
function JRA55PrescribedAtmosphere(architecture::AA, time_indices=Colon();
backend = nothing,
time_indexing = Cyclical(),
reference_height = 10, # meters
surface_layer_height = 10, # meters
tidal_potential = nothing,
include_rivers_and_icebergs = false,
other_kw...)

Expand Down Expand Up @@ -701,7 +702,7 @@ function JRA55PrescribedAtmosphere(architecture::AA, time_indices=Colon();

FT = eltype(ua)
boundary_layer_height = convert(FT, 600)
reference_height = convert(FT, reference_height)
surface_layer_height = convert(FT, surface_layer_height)
thermodynamics_parameters = PrescribedAtmosphereThermodynamicsParameters(FT)
grid = ua.grid
metadata = JRA55Data()
Expand All @@ -714,10 +715,11 @@ function JRA55PrescribedAtmosphere(architecture::AA, time_indices=Colon();
tracers,
freshwater_flux,
auxiliary_freshwater_flux,
tidal_potential,
downwelling_radiation,
thermodynamics_parameters,
times,
reference_height,
surface_layer_height,
boundary_layer_height)
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
using Oceananigans.Operators: intrinsic_vector
using Oceananigans.Grids: _node
using Oceananigans.Grids: _node, AbstractGrid
using Oceananigans.Fields: FractionalIndices
using Oceananigans.OutputReaders: TimeInterpolator

using ...OceanSimulations: forcing_barotropic_potential

using ClimaOcean.OceanSimulations: BarotropicPotentialForcing
using ClimaOcean.OceanSeaIceModels.PrescribedAtmospheres: PrescribedAtmosphere
import ClimaOcean.OceanSeaIceModels: interpolate_atmosphere_state!

# TODO: move to PrescribedAtmospheres
"""Interpolate the atmospheric state onto the ocean / sea-ice grid."""
function interpolate_atmosphere_state!(interfaces, atmosphere::PrescribedAtmosphere, coupled_model)
ocean = coupled_model.ocean
atmosphere_grid = atmosphere.grid

# Basic model properties
grid = ocean.model.grid
Expand Down Expand Up @@ -40,13 +40,12 @@ function interpolate_atmosphere_state!(interfaces, atmosphere::PrescribedAtmosph

# Extract info for time-interpolation
u = atmosphere.velocities.u # for example
atmosphere_times = u.times
atmosphere_backend = u.backend
atmosphere_time_indexing = u.time_indexing

atmosphere_fields = coupled_model.interfaces.exchanger.exchange_atmosphere_state
space_fractional_indices = coupled_model.interfaces.exchanger.atmosphere_exchanger
exchange_grid = coupled_model.interfaces.exchanger.exchange_grid
atmosphere_fields = interfaces.exchanger.exchange_atmosphere_state
space_fractional_indices = interfaces.exchanger.atmosphere_exchanger
exchange_grid = interfaces.exchanger.exchange_grid

# Simplify NamedTuple to reduce parameter space consumption.
# See https://github.com/CliMA/ClimaOcean.jl/issues/116.
Expand Down Expand Up @@ -106,12 +105,37 @@ function interpolate_atmosphere_state!(interfaces, atmosphere::PrescribedAtmosph
auxiliary_time_indexing)
end

# Set ocean barotropic pressure forcing
barotropic_potential = forcing_barotropic_potential(ocean)
ρₒ = coupled_model.interfaces.ocean_properties.reference_density
if !isnothing(barotropic_potential)
parent(barotropic_potential) .= parent(atmosphere_data.p) ./ ρₒ
# barotropic potential in PrescribedAtmosphere?
atmosphere_pressure = atmosphere.pressure.data
tidal_potential = atmosphere.tidal_potential

if !isnothing(tidal_potential)
tidal_potential_data = tidal_potential.data
else
tidal_potential_data = nothing
end

# Which forcing is this going to be?
u_forcing = ocean.model.forcing.u
barotropic_potential = if u_forcing isa BarotropicPotentialForcing
u_forcing.potential
else
n = findfirst(x -> x isa BarotropicPotentialForcing, u_forcing)
u_forcing[n].potential
end

launch!(arch, grid, kernel_parameters,
_compute_barotropic_potential!,
barotropic_potential,
space_fractional_indices,
time_interpolator,
atmosphere_pressure,
tidal_potential_data,
interfaces.ocean_properties.reference_density,
atmosphere_backend,
atmosphere_time_indexing)

return nothing
end

@inline get_fractional_index(i, j, ::Nothing) = nothing
Expand Down Expand Up @@ -169,6 +193,34 @@ end
end
end

@kernel function _compute_barotropic_potential!(barotropic_potential,
space_fractional_indices,
time_interpolator,
atmos_pressure,
tidal_potential,
ocean_reference_density,
atmos_backend,
atmos_time_indexing)

i, j = @index(Global, NTuple)

ρₒ = ocean_reference_density

ii = space_fractional_indices.i
jj = space_fractional_indices.j
fi = get_fractional_index(i, j, ii)
fj = get_fractional_index(i, j, jj)

x_itp = FractionalIndices(fi, fj, nothing)
t_itp = time_interpolator
atmos_args = (x_itp, t_itp, atmos_backend, atmos_time_indexing)

pa = interp_atmos_time_series(atmos_pressure, atmos_args...) # yes this is a re-interpolation
Φt = interp_atmos_time_series(tidal_potential, atmos_args...)

@inbounds barotropic_potential[i, j, 1] = pa / ρₒ + Φt
end

@kernel function _interpolate_auxiliary_freshwater_flux!(freshwater_flux,
interface_grid,
clock,
Expand Down Expand Up @@ -198,6 +250,10 @@ end
##### Utility for interpolating tuples of fields
#####

# Assumption: a Nothing object interpolates to zero!!
@inline interp_atmos_time_series(::Nothing, x_itp::FractionalIndices, args...) = zero(x_itp.i)
@inline interp_atmos_time_series(::Nothing, X, time, grid::AbstractGrid, args...) = zero(grid)

# Note: assumes loc = (c, c, nothing) (and the third location should not matter.)
@inline interp_atmos_time_series(J::AbstractArray, x_itp::FractionalIndices, t_itp, args...) =
interpolate(x_itp, t_itp, J, args...)
Expand Down
6 changes: 5 additions & 1 deletion src/OceanSeaIceModels/PrescribedAtmospheres.jl
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ const PATP = PrescribedAtmosphereThermodynamicsParameters
##### Prescribed atmosphere (as opposed to dynamically evolving / prognostic)
#####

mutable struct PrescribedAtmosphere{FT, M, G, T, U, P, C, F, I, R, TP, TI}
mutable struct PrescribedAtmosphere{FT, M, G, T, U, P, C, F, I, ΦT, R, TP, TI}
grid :: G
clock :: Clock{T}
metadata :: M
Expand All @@ -298,6 +298,7 @@ mutable struct PrescribedAtmosphere{FT, M, G, T, U, P, C, F, I, R, TP, TI}
tracers :: C
freshwater_flux :: F
auxiliary_freshwater_flux :: I
tidal_potential :: ΦT # this really belongs elsewhere, but we put it here for now
downwelling_radiation :: R
thermodynamics_parameters :: TP
times :: TI
Expand Down Expand Up @@ -375,6 +376,7 @@ end
boundary_layer_height = 600 # meters,
thermodynamics_parameters = PrescribedAtmosphereThermodynamicsParameters(FT),
auxiliary_freshwater_flux = nothing,
tidal_potential = nothing,
velocities = default_atmosphere_velocities(grid, times),
tracers = default_atmosphere_tracers(grid, times),
pressure = default_atmosphere_pressure(grid, times),
Expand All @@ -391,6 +393,7 @@ function PrescribedAtmosphere(grid, times;
boundary_layer_height = convert(eltype(grid), 600),
thermodynamics_parameters = nothing,
auxiliary_freshwater_flux = nothing,
tidal_potential = nothing,
velocities = default_atmosphere_velocities(grid, times),
tracers = default_atmosphere_tracers(grid, times),
pressure = default_atmosphere_pressure(grid, times),
Expand All @@ -410,6 +413,7 @@ function PrescribedAtmosphere(grid, times;
tracers,
freshwater_flux,
auxiliary_freshwater_flux,
tidal_potential,
downwelling_radiation,
thermodynamics_parameters,
times,
Expand Down