Skip to content

Commit 560937b

Browse files
authored
Merge pull request #1 from navidcy/saturation-adjustment
Implement saturation adjustment for Boussinesq LES with condensation
2 parents e8c2863 + 60c8b30 commit 560937b

File tree

7 files changed

+665
-36
lines changed

7 files changed

+665
-36
lines changed

Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ authors = ["Navid C. Constantinou <[email protected]>, Madi, Greg
44
version = "0.1.0"
55

66
[deps]
7+
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
78
Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09"
9+
RootSolvers = "7181ea78-2dcb-4de3-ab41-2b8ab5a31e74"
810

911
[compat]
12+
JLD2 = "0.5.13"
1013
Oceananigans = "0.96"
14+
RootSolvers = "0.4.4"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using JLD2
2+
using AquaSkyLES
3+
using AquaSkyLES: saturation_specific_humidity, AtmosphereThermodynamics
4+
using GLMakie
5+
6+
@load "JRA55_atmospheric_state_Jan_1_1991.jld2" q T p
7+
8+
thermo = AtmosphereThermodynamics()
9+
10+
ρ = 1.2
11+
qᵛ★ = saturation_specific_humidity.(T, 1.2, Ref(thermo))
12+
= @. max(0, q - q★)
13+
14+
fig = Figure(size=(1200, 600))
15+
ax1 = Axis(fig[1, 2], title="Temperature")
16+
ax2 = Axis(fig[2, 1], title="Saturation specific humidity")
17+
ax3 = Axis(fig[1, 1], title="Total specific humidity")
18+
ax4 = Axis(fig[2, 2], title="Liquid specific humidity")
19+
# heatmap!(ax1, T, colormap=:magma)
20+
# heatmap!(ax2, qᵛ★)
21+
# heatmap!(ax3, q, colormap=:grays)
22+
# heatmap!(ax4, qˡ, colormap=:grays, colorrange=(0, 0.001))
23+
24+
# Compute cloudiness for instantaneous drop
25+
θ⁻ = T .- 10
26+
Ψ = AquaSkyLES.ThermodynamicState{Float64}.(θ⁻, q, 0)
27+
= AquaSkyLES.ReferenceState{Float64}(101325, 20)
28+
T⁻ = AquaSkyLES.temperature.(Ψ, Ref(ℛ), Ref(thermo))
29+
qᵛ★ = saturation_specific_humidity.(T⁻, 1.2, Ref(thermo))
30+
= @. max(0, q - qᵛ★)
31+
Π = AquaSkyLES.exner_function.(Ψ, Ref(ℛ), Ref(thermo))
32+
Tu = @. Π * θ⁻
33+
ΔT = T⁻ - Tu
34+
35+
heatmap!(ax1, ΔT, colormap=:magma)
36+
heatmap!(ax2, qᵛ★)
37+
heatmap!(ax3, q, colormap=:grays)
38+
heatmap!(ax4, qˡ, colormap=:grays, colorrange=(0, 0.01))
39+
display(fig)

examples/free_convection.jl

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,95 @@
11
using Oceananigans
22
using Oceananigans.Units
3+
using Printf
34
using AquaSkyLES
45

5-
Nx = Nz = 256
6-
Lz = 3 * 1024
6+
Nx = Nz = 128
7+
Lz = 4 * 1024
78
grid = RectilinearGrid(size=(Nx, Nz), x=(0, 2Lz), z=(0, Lz), topology=(Periodic, Flat, Bounded))
89

9-
ρ₀ = 1 # air density
10-
cₚ = 1e3 # air specific heat
11-
Q = 1000 # heat flux in W / m²
12-
= Q / (ρ₀ * cₚ)
13-
heating = FluxBoundaryCondition(Jθ)
14-
θ_bcs = FieldBoundaryConditions(bottom=heating)
10+
p₀ = 101325 # Pa
11+
θ₀ = 288 # K
12+
reference_state = AquaSkyLES.ReferenceState(base_pressure=p₀, potential_temperature=θ₀)
13+
buoyancy = AquaSkyLES.MoistAirBuoyancy(; reference_state)
14+
15+
ρ₀ = AquaSkyLES.base_density(buoyancy) # air density at z=0
16+
cₚ = buoyancy.thermodynamics.dry_air.heat_capacity
17+
Q₀ = 1000 # heat flux in W / m²
18+
= Q₀ / (ρ₀ * cₚ) # temperature flux
19+
θ_bcs = FieldBoundaryConditions(bottom=FluxBoundaryCondition(Jθ))
20+
21+
vapor_flux = FluxBoundaryCondition(1e-3)
22+
q_bcs = FieldBoundaryConditions(bottom=vapor_flux)
1523

1624
advection = WENO() #(momentum=WENO(), θ=WENO(), q=WENO(bounds=(0, 1)))
1725
tracers = (, :q)
18-
buoyancy = AquaSkyLES.MoistAirBuoyancy()
19-
model = NonhydrostaticModel(; grid, advection, tracers, buoyancy, boundary_conditions=(; θ=θ_bcs))
26+
model = NonhydrostaticModel(; grid, advection, buoyancy,
27+
tracers = (, :q),
28+
boundary_conditions ==θ_bcs, q=q_bcs))
2029

2130
Lz = grid.Lz
22-
Δθ = 10 # ᵒC
23-
Tₛ = 20 # ᵒC
31+
Δθ = 5 # K
32+
Tₛ = reference_state.θ # K
2433
θᵢ(x, z) = Tₛ + Δθ * z / Lz + 1e-2 * Δθ * randn()
25-
qᵢ(x, z) = 1e-4 * rand()
34+
qᵢ(x, z) = 1e-2 + 1e-5 * rand()
2635
set!(model, θ=θᵢ, q=qᵢ)
2736

28-
simulation = Simulation(model, Δt=10, stop_time=1hour)
37+
simulation = Simulation(model, Δt=10, stop_time=2hours)
2938
conjure_time_step_wizard!(simulation, cfl=0.7)
30-
progress(sim) = @info string(iteration(sim), ": ", prettytime(sim))
39+
40+
T = AquaSkyLES.TemperatureField(model)
41+
= AquaSkyLES.CondensateField(model, T)
42+
qᵛ★ = AquaSkyLES.SaturationField(model, T)
43+
δ = Field(model.tracers.q - qᵛ★)
44+
45+
function progress(sim)
46+
compute!(T)
47+
compute!(qˡ)
48+
compute!(δ)
49+
q = sim.model.tracers.q
50+
θ = sim.model.tracers.θ
51+
u, v, w = sim.model.velocities
52+
53+
umax = maximum(u)
54+
vmax = maximum(v)
55+
wmax = maximum(w)
56+
57+
qmin = minimum(q)
58+
qmax = maximum(q)
59+
qˡmax = maximum(qˡ)
60+
δmax = maximum(δ)
61+
62+
θmin = minimum(θ)
63+
θmax = maximum(θ)
64+
65+
msg = @sprintf("Iter: %d, t = %s, max|u|: (%.2e, %.2e, %.2e)",
66+
iteration(sim), prettytime(sim), umax, vmax, wmax)
67+
68+
msg *= @sprintf(", extrema(q): (%.2e, %.2e), max(qˡ): %.2e, min(δ): %.2e, extrema(θ): (%.2e, %.2e)",
69+
qmin, qmax, qˡmax, δmax, θmin, θmax)
70+
71+
@info msg
72+
73+
return nothing
74+
end
75+
3176
add_callback!(simulation, progress, IterationInterval(10))
3277

33-
ow = JLD2Writer(model, merge(model.velocities, model.tracers),
78+
outputs = merge(model.velocities, model.tracers, (; T, qˡ, qᵛ★))
79+
80+
ow = JLD2Writer(model, outputs,
3481
filename = "free_convection.jld2",
35-
schedule = TimeInterval(1minutes),
82+
schedule = IterationInterval(10),
3683
overwrite_existing = true)
3784

3885
simulation.output_writers[:jld2] = ow
3986

4087
run!(simulation)
4188

4289
θt = FieldTimeSeries("free_convection.jld2", "θ")
90+
Tt = FieldTimeSeries("free_convection.jld2", "T")
4391
qt = FieldTimeSeries("free_convection.jld2", "q")
92+
qˡt = FieldTimeSeries("free_convection.jld2", "")
4493
times = qt.times
4594
Nt = length(θt)
4695

@@ -50,22 +99,35 @@ n = Observable(length(θt))
5099

51100
θn = @lift θt[$n]
52101
qn = @lift qt[$n]
102+
Tn = @lift Tt[$n]
103+
qˡn = @lift qˡt[$n]
53104
title = @lift "t = $(prettytime(times[$n]))"
54105

55-
fig = Figure(size=(1600, 400), fontsize=22)
106+
fig = Figure(size=(800, 400), fontsize=12)
56107
axθ = Axis(fig[1, 1], xlabel="x (m)", ylabel="z (m)")
57108
axq = Axis(fig[1, 2], xlabel="x (m)", ylabel="z (m)")
109+
axT = Axis(fig[2, 1], xlabel="x (m)", ylabel="z (m)")
110+
axqˡ = Axis(fig[2, 2], xlabel="x (m)", ylabel="z (m)")
58111

59112
fig[0, :] = Label(fig, title, fontsize=22, tellwidth=false)
60113

61-
hmθ = heatmap!(axθ, θn, colorrange=(Tₛ, Tₛ+Δθ))
62-
hmq = heatmap!(axq, qn, colorrange=(0, 8e-5), colormap=:magma)
63-
64-
Label(fig[0, 1], "θ", tellwidth=false)
65-
Label(fig[0, 2], "q", tellwidth=false)
114+
Tmin = minimum(Tt)
115+
Tmax = maximum(Tt)
66116

67-
Colorbar(fig[2, 1], hmθ, label = "[ᵒC]", vertical=false)
68-
Colorbar(fig[2, 2], hmq, label = "", vertical=false)
117+
hmθ = heatmap!(axθ, θn, colorrange=(Tₛ, Tₛ+Δθ))
118+
hmq = heatmap!(axq, qn, colorrange=(0, 2e-2), colormap=:magma)
119+
hmT = heatmap!(axT, Tn, colorrange=(Tmin, Tmax))
120+
hmqˡ = heatmap!(axqˡ, qˡn, colorrange=(0, 2e-4), colormap=:magma)
121+
122+
# Label(fig[0, 1], "θ", tellwidth=false)
123+
# Label(fig[0, 2], "q", tellwidth=false)
124+
# Label(fig[0, 1], "θ", tellwidth=false)
125+
# Label(fig[0, 2], "q", tellwidth=false)
126+
127+
Colorbar(fig[1, 0], hmθ, label = "θ [K]", vertical=true)
128+
Colorbar(fig[1, 3], hmq, label = "q", vertical=true)
129+
Colorbar(fig[2, 0], hmT, label = "T [K]", vertical=true)
130+
Colorbar(fig[2, 3], hmqˡ, label = "", vertical=true)
69131

70132
fig
71133

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using GLMakie
2+
using AquaSkyLES
3+
4+
thermo = AquaSkyLES.AtmosphereThermodynamics()
5+
6+
saturation_specific_humidity_large_yeager(T, ρ) = 640380 * exp(-5107.4 / T) / ρ
7+
8+
ρ = 1.2
9+
T₀ = 273.15
10+
T = collect(T₀:0.01:T₀+50)
11+
q★_large_yeager = saturation_specific_humidity_large_yeager.(T, ρ)
12+
q★_aqua_sky = AquaSkyLES.saturation_specific_humidity.(T, ρ, Ref(thermo))
13+
14+
fig = Figure()
15+
ax = Axis(fig[1, 1], xlabel = "Temperature (K)", ylabel = "Saturation Specific Humidity (g/kg)")
16+
lines!(ax, T, q★_large_yeager, label = "Large and Yeager (2009)")
17+
lines!(ax, T, q★_aqua_sky, label = "AquaSkyLES")
18+
Legend(fig[1, 2], ax)
19+
display(fig)

0 commit comments

Comments
 (0)