Skip to content

Conversation

@glwagner
Copy link
Member

This PR adds a new example that builds an internal wave in saturated conditions. It also adds some features that help compute the saturation specific humidity in various configurations:

  • given the current state of the model
  • under the assumptions of saturation adjustment, when the total specific humidity is known and vapor is assumed saturated
  • under the condition that the total specific humidity is equal to the saturation specific humidity (ie rh=100%)

the addition of a utility for the last case should be useful for idealized problems I think.

@navidcy navidcy added the documentation 📜 Improvements or additions to documentation label Nov 22, 2025
@navidcy
Copy link
Member

navidcy commented Nov 24, 2025

I'm trying to fix this example because the AI generation doesn't even run ... it's not that good tbh.

What do we want to demonstrate? How a small-amplitude wavepacket moves and what dispersion relationship would follow?

Comment on lines +147 to +213
#=
@info "Simulation complete"

# ## Diagnostics: observed vs predicted buoyancy frequency

w_series = FieldTimeSeries(filename, "w")
θ_series = FieldTimeSeries(filename, "θ")
q_series = FieldTimeSeries(filename, "qᵗ")

times = w_series.times
Nt = length(times)
i_mid = Nx ÷ 2
k_mid = Nz ÷ 2

@allowscalar begin
w_signal = [w_series[i_mid, 1, k_mid, n] for n in 1:Nt]
end

function dominant_frequency(times, signal)
demeaned = signal .- mean(signal)
dt = mean(diff(times))
spectrum = abs.(rfft(demeaned))
freqs = (0:length(spectrum)-1) ./ (dt * length(signal))
idx = argmax(spectrum[2:end]) + 1 # skip zero frequency
return 2π * freqs[idx]
end

ω_observed = dominant_frequency(times, w_signal)
period_observed = 2π / ω_observed

@info "Wave frequencies" ω_dry ω_moist ω_observed

# ## Visualization

x = range(grid.x[1], grid.x[2]; length = Nx)
z = range(grid.z[1], grid.z[2]; length = Nz)
time_minutes = times ./ 60

w_snapshot = Array(permutedims(w_series[:, 1, :, end]))
w_amplitude = maximum(abs, w_signal)

dry_fit = w_amplitude * sin.(ω_dry .* (times .- times[1]))
moist_fit = w_amplitude * sin.(ω_moist .* (times .- times[1]))

fig = Figure(size = (900, 950), fontsize = 14)

ax_field = Axis(fig[1, 1]; xlabel = "x (km)", ylabel = "z (km)",
title = "Vertical velocity w at t = $(prettytime(times[end]))")
hm = heatmap!(ax_field, x ./ 1_000, z ./ 1_000, w_snapshot;
colormap = :balance, colorrange = (-w_amplitude, w_amplitude))
Colorbar(fig[1, 2], hm, label = "w (m s⁻¹)")

ax_ts = Axis(fig[2, 1]; xlabel = "time (min)", ylabel = "w (m s⁻¹)",
title = "Oscillation at domain center")
lines!(ax_ts, time_minutes, w_signal; label = "simulation", color = :black)
lines!(ax_ts, time_minutes, dry_fit; label = "dry N", color = :royalblue, linestyle = :dash)
lines!(ax_ts, time_minutes, moist_fit; label = "saturated N", color = :firebrick, linestyle = :dot)
axislegend(ax_ts; position = :rt)

ax_freq = Axis(fig[3, 1]; xlabel = "", ylabel = "ω (s⁻¹)",
title = "Dominant frequency comparison",
xticks = (1:3, ["observed", "dry", "saturated"]))
barplot!(ax_freq, 1:3, [ω_observed, ω_dry, ω_moist];
color = (:gray50, :royalblue, :firebrick))

fig
=#
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

I'll sort it... it's a WIP atm

@navidcy navidcy marked this pull request as draft November 24, 2025 23:55
@navidcy
Copy link
Member

navidcy commented Nov 25, 2025

@glwagner I think we are committing over each other. I can't see the things I was doing yesterday...

I'll leave it to you?

@giordano
Copy link
Collaborator

I don't think Greg has pushed in a while: https://github.com/NumericalEarth/Breeze.jl/activity?ref=glw/saturated-internal-wave 🤔

@navidcy
Copy link
Member

navidcy commented Nov 25, 2025

There is a chance I committed over myself? Perhaps I need to clear my head...

@giordano
Copy link
Collaborator

Maybe? There are no force-pushes at all on this branch, and you're the only one who has pushed over the last couple of days 😅

@navidcy
Copy link
Member

navidcy commented Nov 25, 2025

This might be the culprit ;)
8bd46ab

@navidcy
Copy link
Member

navidcy commented Nov 25, 2025

I think I was working on two files!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation 📜 Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants