Ocean models

The following describes the currently implemented ocean models, some prescribed sea surface temperature (not dependent on the state of other variables) others are active (dependent on the atmospheric state). All but SlabOcean force the atmosphere, as the sea surface temperatures are used to calculate surface heat fluxes. SlabOcean interacts with both Atmosphere and SeaIce. All models can be used with PrimitiveDry and PrimitiveWet models; for the former, only surface heat fluxes are applied, albeit not the humidity fluxes.

using SpeedyWeather
subtypes(SpeedyWeather.AbstractOcean)
4-element Vector{Any}:
 AquaPlanet
 ConstantOceanClimatology
 SeasonalOceanClimatology
 SlabOcean

Aqua planet

The AquaPlanet in SpeedyWeather is a prescribed sea surface temperature that only depends on latitude, applying a cosine squared between the Equator and the poles

spectral_grid = SpectralGrid(trunc=31)
ocean = AquaPlanet(spectral_grid)
AquaPlanet{Float32} <: AbstractOcean
├ temp_equator::Float32 = 302.0
├ temp_poles::Float32 = 273.0
└ mask::Bool = true

pole and equator temperatures can be modified and mask can mask the sea surface temperatures according to model.land_sea_mask. Otherwise sea surface temperatures are defined everywhere but the land-sea mask will determine their proportional contribution to surface fluxes.

Constant ocean climatology

ConstantOceanClimatology is like SeasonalOceanClimatology but constant in time. At initalize!(model) the seasonal ocean climatology is read from file and interpolated to the current time, but the sea surface temperature field is not further updated thereafter. To be created like

ocean = ConstantOceanClimatology(spectral_grid)
ConstantOceanClimatology <: AbstractOcean
├ path::String = SpeedyWeather.jl/input_data
├ file::String = sea_surface_temperature.nc
├ varname::String = sst
├ file_Grid::UnionAll = FullGaussianGrid
└ missing_value::Float64 = NaN

and passed to the model constructor as follows

model = PrimitiveWetModel(spectral_grid, ocean=ocean)
simulation = initialize!(model, time=DateTime(2000, 6, 1))

Or, equivalently, ; ocean as Julia can match keyword arguments by name, where ; just means that every argument that follows is a keyword argument.

This will use the sea surface temperature climatology from 1 June but not change it thereafter. Note that because nothing happens in the ocean time step you can use set!(simulation, sea_surface_temperature=...) to modify the sea surface temperatures further at any point after initialize!.

Seasonal ocean climatology

Created like

ocean = SeasonalOceanClimatology(spectral_grid)
SeasonalOceanClimatology{Float32, OctahedralGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}, Field{Float32, 2, Matrix{Float32}, OctahedralGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}}} <: AbstractOcean
├ grid::OctahedralGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}} = 48-ring OctahedralGaussianGrid
├ nlat_half=24 (3168 points, ~3.6˚, reduced)
└ architecture: CPU
├ path::String = SpeedyWeather.jl/input_data
├ file::String = sea_surface_temperature.nc
├ varname::String = sst
├ file_Grid::UnionAll = FullGaussianGrid
├ missing_value::Float32 = NaN
└── arrays: monthly_temperature

The SeasonalOceanClimatology reads monthly sea surface temperature fields from file, and interpolates them in time on every time step and writes them to the prognostic variables. Several options exist to load another file from path etc. For a full list of options type ?SeasonalOceanClimatology. To be passed on to the model constructor like

model = PrimitiveWetModel(spectral_grid; ocean)

The time of the year is determined by the clock in prognostic_variables.clock such that initialize!(model, time=DateTime(2000, 1, 1)) would interpolate the seasonal climatology onto the first of January.

Slab ocean

The most complex ocean model implemented is a slab ocean model: it can heat up and cool down given atmospheric fluxes and in turn warm up or cool down the atmosphere from below and provide sources or sink of humidity. The slab ocean model has only sea surface temperature as prognostic variable so the humidity flux from precipitation does not decrease salinity as there is none. You can think of the SlabOcean as a freshwater ocean. To be used like

ocean = SlabOcean(spectral_grid)
SlabOcean{Float32, SpeedyWeather.var"#328#330"} <: AbstractOcean
├ temp_equator::Float32 = 302.0
├ temp_poles::Float32 = 271.35
├ specific_heat_capacity::Float32 = 4184.0
├ mixed_layer_depth::Float32 = 50.0
├ sea_ice_insulation::SpeedyWeather.var"#328#330" = #328
├ density::Float32 = 1000.0
├ mask::Bool = false
└ heat_capacity_mixed_layer::Float32 = 2.092e8

specific_heat_capacity, mixed_layer_depth and density determine multiplicatively the effective heat capacity of the mixed layer $C_0$. Then the temporal evolution of sea surface temperature $SST$ is given by

\[C_0 \frac{d SST}{dt} = (1-r) \left( R_{sd} - R_{su} - R_{lu} + R_{ld} - L_v*E_v - S \right)\]

with $r \in [0, 1]$ an insulating factor due to sea ice, see Thermodynamic sea ice model, by default chosen as $r = c$, i.e proportional to sea ice concentration $c$, insulating the ocean from surface fluxes at full sea ice coverage ($c=1$) and no insulation for ice-free ocean ($c=0$). The surface fluxes are $R_{sd}$ for shortwave ($s$) radiative flux downward (positive sign, heating the ocean); $R_{su}$ reflected upward shortwave flux given albedo (negative sign, cooling the ocean); $R_{lu}$ a longwave upward flux through which the ocean loses heat dependent on its sea surface temperature (negative sign); $R_{ld}$ downward longwave flux where the atmosphere warms the ocean due to its own tempreature (positive sign); $E_v$ is the upward evaporative (or surface condensation) flux, converted to $W/m^2$ through multiplication with the latent heat of condensation $L_v$ (negative sign as evaporation cools the ocean); and $S$ the sensible heat flux through turbulent transport of heat in the atmospheric boundary layer. All surface flux terms have units of $W/m^2$.

The slab ocean is then passed on to the model constructor as with all other ocean models

model = PrimitiveWetModel(spectral_grid; ocean)

Output

Sea surface temperature output is added like

add!(model, SpeedyWeather.SeaSurfaceTemperatureOutput())
NetCDFOutput{Field{Float32, 1, Vector{Float32}, FullGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}}}
├ status: inactive/uninitialized
├ write restart file: true (if active)
├ interpolator: AnvilInterpolator{Float32, SpeedyWeather.RingGrids.GridGeometry{OctahedralGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}, Vector{Float32}, Vector{Int64}}, SpeedyWeather.RingGrids.AnvilLocator{Float32, Vector{Float32}, Vector{Int64}}}
├ path: output.nc (overwrite=false)
├ frequency: 21600 seconds
└┐ variables:
 ├ v: meridional wind [m/s]
 ├ humid: specific humidity [kg/kg]
 ├ sst: sea surface temperature [degC]
 ├ temp: temperature [degC]
 ├ u: zonal wind [m/s]
 ├ pres: surface pressure [hPa]
 └ vor: relative vorticity [s^-1]

or collectively with sea ice concentration

add!(model, SpeedyWeather.OceanOutput()...)
NetCDFOutput{Field{Float32, 1, Vector{Float32}, FullGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}}}
├ status: inactive/uninitialized
├ write restart file: true (if active)
├ interpolator: AnvilInterpolator{Float32, SpeedyWeather.RingGrids.GridGeometry{OctahedralGaussianGrid{SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}, Vector{UnitRange{Int64}}, Vector{Int64}}, Vector{Float32}, Vector{Int64}}, SpeedyWeather.RingGrids.AnvilLocator{Float32, Vector{Float32}, Vector{Int64}}}
├ path: output.nc (overwrite=false)
├ frequency: 21600 seconds
└┐ variables:
 ├ v: meridional wind [m/s]
 ├ humid: specific humidity [kg/kg]
 ├ sst: sea surface temperature [degC]
 ├ sic: sea ice concentration [m^2/m^2]
 ├ temp: temperature [degC]
 ├ u: zonal wind [m/s]
 ├ pres: surface pressure [hPa]
 └ vor: relative vorticity [s^-1]

where the splatting operator ... has to be applied to unpack all output variables in the tuple, all output variable groups are defined as tuples.