#####
##### The purpose of this script is to reproduce some results from Semtner (1976)
#####
using Oceananigans
using Oceananigans.Units
using Oceananigans.Utils: Time
using Oceananigans.OutputReaders
using ClimaSeaIce
Generate a 0D grid for a single column slab model
grid = RectilinearGrid(size=(), topology=(Flat, Flat, Flat))
1×1×1 RectilinearGrid{Float64, Oceananigans.Grids.Flat, Oceananigans.Grids.Flat, Oceananigans.Grids.Flat} on Oceananigans.Architectures.CPU with 0×0×0 halo
├── Flat x
├── Flat y
└── Flat z
Forcings (Semtner 1976, table 1), originally tabulated by Fletcher (1965) Note: these are in kcal, which was deprecated in the ninth General Conference on Weights and Measures in 1948. We convert these to Joules (and then to Watts) below. Month: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
tabulated_shortwave = - [ 0, 0, 1.9, 9.9, 17.7, 19.2, 13.6, 9.0, 3.7, 0.4, 0, 0] .* 1e4 # to convert to kcal / m²
tabulated_longwave = - [10.4, 10.3, 10.3, 11.6, 15.1, 18.0, 19.1, 18.7, 16.5, 13.9, 11.2, 10.9] .* 1e4 # to convert to kcal / m²
tabulated_sensible = - [1.18, 0.76, 0.72, 0.29, -0.45, -0.39, -0.30, -0.40, -0.17, 0.1, 0.56, 0.79] .* 1e4 # to convert to kcal / m²
tabulated_latent = - [ 0, -0.02, -0.03, -0.09, -0.46, -0.70, -0.64, -0.66, -0.39, -0.19, -0.01, -0.01] .* 1e4 # to convert to kcal / m²
12-element Vector{Float64}:
-0.0
200.0
300.0
900.0
4600.0
7000.0
6400.0
6600.0
3900.0
1900.0
100.0
100.0
Pretend every month is just 30 days
Nmonths = 12
month_days = 30
year_days = month_days * Nmonths
times_days = 15:30:(year_days - 15)
times = times_days .* day # times in seconds
1.296e6:2.592e6:2.9808e7
Sea ice emissivity
ϵ = 1
1
Convert fluxes to the right units
kcal_to_joules = 4184
tabulated_shortwave .*= kcal_to_joules / (month_days * days)
tabulated_longwave .*= kcal_to_joules / (month_days * days) .* ϵ
tabulated_sensible .*= kcal_to_joules / (month_days * days)
tabulated_latent .*= kcal_to_joules / (month_days * days)
using CairoMakie
fig = Figure()
ax = Axis(fig[1, 1])
lines!(ax, times, tabulated_shortwave)
lines!(ax, times, tabulated_longwave)
lines!(ax, times, tabulated_sensible)
lines!(ax, times, tabulated_latent)
display(fig)
CairoMakie.Screen{IMAGE}
Make them into a FieldTimeSeries for better manipulation
Rs = FieldTimeSeries{Nothing, Nothing, Nothing}(grid, times; time_indexing = Cyclical())
Rl = FieldTimeSeries{Nothing, Nothing, Nothing}(grid, times; time_indexing = Cyclical())
Qs = FieldTimeSeries{Nothing, Nothing, Nothing}(grid, times; time_indexing = Cyclical())
Ql = FieldTimeSeries{Nothing, Nothing, Nothing}(grid, times; time_indexing = Cyclical())
for (i, time) in enumerate(times)
set!(Rs[i], tabulated_shortwave[i:i])
set!(Rl[i], tabulated_longwave[i:i])
set!(Qs[i], tabulated_sensible[i:i])
set!(Ql[i], tabulated_latent[i:i])
end
@inline function linearly_interpolate_flux(i, j, grid, Tₛ, clock, model_fields, flux)
t = Time(clock.time)
return flux[i, j, 1, t]
end
@inline function linearly_interpolate_solar_flux(i, j, grid, Tₛ, clock, model_fields, flux)
Q = linearly_interpolate_flux(i, j, grid, Tₛ, clock, model_fields, flux)
α = ifelse(Tₛ < -0.1, 0.75, 0.64)
return Q * (1 - α)
end
linearly_interpolate_solar_flux (generic function with 1 method)
NOTE: Semtner (1976) uses a wrong value for the Stefan-Boltzmann constant (roughly 2% higher) to match the results of Maykut & Unterstainer (196(5)). We use the same value here for comparison purposes.
σ = 5.67e-8 * 1.02 # Wrong value!!
Q_shortwave = FluxFunction(linearly_interpolate_solar_flux, parameters=Rs)
Q_longwave = FluxFunction(linearly_interpolate_flux, parameters=Rl)
Q_sensible = FluxFunction(linearly_interpolate_flux, parameters=Qs)
Q_latent = FluxFunction(linearly_interpolate_flux, parameters=Ql)
Q_emission = RadiativeEmission(emissivity=ϵ, stefan_boltzmann_constant=σ)
top_heat_flux = (Q_shortwave, Q_longwave, Q_sensible, Q_latent, Q_emission)
model = SeaIceModel(grid; top_heat_flux)
set!(model, h=0.3, ℵ=1) # We start from 300cm of ice and full concentration
simulation = Simulation(model, Δt=8hours, stop_time= 30 * 360days)
Simulation of SeaIceModel
├── Next time step: 8 hours
├── Elapsed wall time: 0 seconds
├── Wall time per iteration: NaN days
├── Stop time: 10800 days
├── Stop iteration: Inf
├── Wall time limit: Inf
├── Minimum relative step: 0.0
├── Callbacks: OrderedDict with 3 entries:
│ ├── stop_time_exceeded => Callback of stop_time_exceeded on IterationInterval(1)
│ ├── stop_iteration_exceeded => Callback of stop_iteration_exceeded on IterationInterval(1)
│ └── wall_time_limit_exceeded => Callback of wall_time_limit_exceeded on IterationInterval(1)
├── Output writers: OrderedDict with no entries
└── Diagnostics: OrderedDict with no entries
Accumulate data
series = []
function accumulate_timeseries(sim)
T = model.ice_thermodynamics.top_surface_temperature
h = model.ice_thickness
ℵ = model.ice_concentration
Qe = model.external_heat_fluxes.top
Qe = ClimaSeaIce.SeaIceThermodynamics.HeatBoundaryConditions.getflux(Qe, 1, 1, grid, first(T), model.clock, model.ice_thickness)
push!(series, (time(sim), first(h), first(T), first(ℵ), Qe))
end
simulation.callbacks[:save] = Callback(accumulate_timeseries)
run!(simulation)
[ Info: Initializing simulation...
[ Info: ... simulation initialization complete (3.056 seconds)
[ Info: Executing initial time step...
[ Info: ... initial time step complete (1.217 seconds).
[ Info: Simulation is stopping after running for 9.785 seconds.
[ Info: Simulation time 10800 days equals or exceeds stop time 10800 days.
Extract and visualize data
t = [datum[1] for datum in series]
h = [datum[2] for datum in series]
T = [datum[3] for datum in series]
ℵ = [datum[4] for datum in series]
Q = [datum[5] for datum in series]
set_theme!(Theme(fontsize=24, linewidth=4))
fig = Figure(size=(1000, 1200))
axT = Axis(fig[1, 1], xlabel="Time (days)", ylabel="Top temperature (ᵒC)")
axh = Axis(fig[2, 1], xlabel="Time (days)", ylabel="Ice thickness (m)")
axℵ = Axis(fig[3, 1], xlabel="Time (days)", ylabel="Ice concentration (-)")
axQ = Axis(fig[4, 1], xlabel="Time (days)", ylabel="Top heat flux (W/m²)")
lines!(axT, t / day, T)
lines!(axh, t / day, h)
lines!(axℵ, t / day, ℵ)
lines!(axQ, t / day, Q)
display(fig)
save("ice_timeseries.png", fig)
This page was generated using Literate.jl.