-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parametrization of Large-Scale Condensation #82
Changes from 25 commits
5e2e157
0a20e2f
5beb813
32511da
1b011a4
ecdfc90
9e39c4f
13f21f4
c3499c1
f620a45
b81c4af
8f0ae2b
d8912e1
aaa43fa
67b5d99
6e25261
7bce235
76a6518
3718df0
23b238f
862be3b
551bef8
8ad13f9
1ececd4
8d0b466
12ceb2b
6b01f3c
6d9ec94
b558ad4
18aad60
c9b3e4d
ce73028
de48b60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
""" | ||
Compute the saturation vapour pressure as a function of temperature using the | ||
August-Roche-Magnus formula, | ||
|
||
eᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)), | ||
|
||
where i = 1,2 for saturation with respect to water and ice, respectively. | ||
""" | ||
function get_saturation_vapour_pressure!( | ||
sat_vap_pressure ::Array{NF,3}, | ||
temp_grid ::Array{NF,3}, | ||
model ::ModelSetup, | ||
) where {NF<:AbstractFloat} | ||
@unpack nlon, nlat, nlev = model.geospectral.geometry | ||
@unpack e₀, T₀, C₁, C₂, T₁, T₂ = model.parameters.magnus_coefs | ||
|
||
for k = 1:nlev, j = 1:nlat, i = 1:nlon | ||
if temp_grid[i, j, k] > T₀ | ||
# Saturation vapour pressure over water | ||
sat_vap_pressure[i, j, k] = e₀ * exp(C₁ * (temp_grid[i, j, k] - T₀) / (temp_grid[i, j, k] - T₁)) | ||
else | ||
# Saturation vapour pressure over ice | ||
sat_vap_pressure[i, j, k] = e₀ * exp(C₂ * (temp_grid[i, j, k] - T₀) / (temp_grid[i, j, k] - T₂)) | ||
end | ||
end | ||
|
||
return nothing | ||
end | ||
|
||
""" | ||
Compute the saturation specific humidity according to the formula, | ||
|
||
0.622 * e / (p - (1 - 0.622) * e), | ||
|
||
where e is the saturation vapour pressure, p is the pressure, and 0.622 is the ratio of | ||
the molecular weight of water to dry air. | ||
""" | ||
function get_saturation_specific_humidity!( | ||
sat_spec_humidity ::Array{NF,3}, | ||
sat_vap_pressure ::Array{NF,3}, | ||
temp_grid ::Array{NF,3}, | ||
pres ::Array{NF,2}, | ||
model ::ModelSetup, | ||
) where {NF<:AbstractFloat} | ||
@unpack nlon, nlat, nlev, σ_levels_full = model.geospectral.geometry | ||
|
||
get_saturation_vapour_pressure!(sat_vap_pressure, temp_grid, model) | ||
|
||
for k = 1:nlev, j = 1:nlat, i = 1:nlon | ||
sat_spec_humidity[i, j, k] = 0.622 * sat_vap_pressure[i, j, k] / | ||
white-alistair marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(pres[i, j] * σ_levels_full[k] - (1 - 0.622) * sat_vap_pressure[i, j, k]) | ||
end | ||
|
||
return nothing | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
function get_large_scale_condensation_tendencies!( | ||
Diag::DiagnosticVariables{NF}, | ||
M ::ModelSetup, | ||
) where {NF<:AbstractFloat} | ||
@unpack gravity, RH_thresh_max, RH_thresh_range, RH_thresh_boundary, humid_relax_time = M.constants | ||
@unpack cp, alhc = M.parameters | ||
@unpack nlon, nlat, nlev, σ_levels_full, σ_levels_thick = M.geospectral.geometry | ||
@unpack temp_grid, humid_grid, pres_surf_grid = Diag.grid_variables | ||
@unpack temp_tend, humid_tend, sat_spec_humidity, sat_vap_pressure, cloud_top, precip_large_scale = Diag.parametrization_variables | ||
|
||
pres = exp.(pres_surf_grid) # Normalised surface pressure - TODO(alistair): check pressure units throughout | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally we preallocate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be in favour of renaming Question about units: is pressure always hPa? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, if we preallocate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't know. For 16 bits we'll probably introduce some scaling anyway, so I wouldn't mind sticking to hPa for the time being.
Given that pressure is a prognostic variable, I'd assume that we calculate at the beginning of each time step the transform to grid space, then |
||
|
||
get_saturation_specific_humidity!(sat_spec_humidity, sat_vap_pressure, temp_grid, pres, M) | ||
|
||
# 1. Tendencies of humidity and temperature due to large-scale condensation | ||
for k = 2:nlev | ||
σₖ = σ_levels_full[k] | ||
RH_threshold = RH_thresh_max + RH_thresh_range * (σₖ^2 - 1) # Relative humidity threshold for condensation (Formula 24) | ||
if k == nlev | ||
RH_threshold = max(RH_threshold, RH_thresh_boundary) | ||
end | ||
|
||
# Impose a maximum heating rate to avoid grid-point storm instability | ||
humid_tend_max = 10σₖ^2 / 3600humid_relax_time # This formula does not appear in the documentation | ||
|
||
for j = 1:nlat, i = 1:nlon | ||
humid_threshold = RH_threshold * sat_spec_humidity[i, j, k] # Specific humidity threshold for condensation | ||
if humid_grid[i, j, k] > humid_threshold | ||
humid_tend[i, j, k] += -(humid_grid[i, j, k] - humid_threshold) / humid_relax_time # Formula 22 | ||
temp_tend[i, j, k] += -alhc / cp * min(humid_tend[i, j, k], humid_tend_max * pres[i, j]) # Formula 23 | ||
cloud_top[i, j] = min(k, cloud_top[i, j]) # Page 7 (last sentence) | ||
end | ||
end | ||
end | ||
|
||
# 2. Precipitation due to large-scale condensation | ||
for k = 2:nlev | ||
Δpₖ = pres * σ_levels_thick[k] # Formula 4 | ||
for j = 1:nlat, i = 1:nlon | ||
precip_large_scale[i, j] += -1 / gravity * Δpₖ[i, j] * humid_tend[i, j, k] # Formula 25 | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have both
humid_tend
andtemp_tend
also defined inTendencies
. Would it be possible to use those instead? I am not quite sure whether it'll be enough to have per prognostic variable one tendency (we probably have to split things into dynamics and physics for example, or we may want to have the tendencies from different terms independently and then a step where we add them all up...)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the
humid_tend
andtemp_tend
which are already defined inTendencies
are in spectral space.My original preference for the parameterisations was to simply add up the tendencies as we went along, rather than allocating a new array for each tendency and parameterisation and summing them at the end. However the problem I ran into here (which may be repeated for other parameterisations) is that the humidity tendency due to LSC gets re-used to calculate precipitation. So you have to allocate it either way.
For now, I think I would just pre-allocate a new array for each tendency and parameterisation (
humid_tend_lsc
,temp_tend_lsc
, ...) and then at the end we can optimise it, once we have a clearer picture of how the parameterisations interact?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is exactly where we have to start thinking about working in column vectors rather than horizontal fields. That would solve many problems. I reckon it might actually be the best to start very early with this restructuring from vert x lon x lat to lon x lat x vert (outer to inner loop). Because then there's no problem to allocate a bunch of vectors for intermediate calculations that get reused for the next horizontal grid point. That saves memory and gives us more flexibility to reuse stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's a great point, no problem allocating an 8-element vector.