Skip to content

Commit

Permalink
Merge branch 'Unidata:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
winash12 authored Dec 29, 2023
2 parents 93b68ca + e15cb00 commit d7034c3
Show file tree
Hide file tree
Showing 11 changed files with 342 additions and 10 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 150
fetch-tags: true

- name: Get tags
run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*

- name: Install using PyPI
uses: ./.github/actions/install-pypi
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 10
fetch-tags: true

- name: Set up Python
id: setup
Expand Down
2 changes: 1 addition & 1 deletion ci/extra_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cartopy==0.22.0
dask==2023.12.0
dask==2023.12.1
shapely==2.0.2
2 changes: 1 addition & 1 deletion ci/linting_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ruff==0.1.8
ruff==0.1.9

flake8==6.1.0
pycodestyle==2.11.1
Expand Down
2 changes: 1 addition & 1 deletion ci/test_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ packaging==23.2
pytest==7.4.3
pytest-mpl==0.16.1
netCDF4==1.6.5
coverage==7.3.3
coverage==7.4.0
1 change: 1 addition & 0 deletions docs/_templates/overrides/metpy.calc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Soundings
cross_totals
downdraft_cape
el
galvez_davison_index
k_index
lcl
lfc
Expand Down
4 changes: 4 additions & 0 deletions docs/api/references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ References
Services and Supporting Research, 2003.
`FCM-R19-2003 <../_static/FCM-R19-2003-WindchillReport.pdf>`_, 75 pp.
.. [Galvez2015] Galvez, J. M. and Michel Davison, 2015. “The Gálvez-Davison Index for Tropical
Convection.” `GDI_Manuscript_V20161021
<https://www.wpc.ncep.noaa.gov/international/gdi/GDI_Manuscript_V20161021.pdf>`_.
.. [Galway1956] Galway, J. G., 1956: The Lifted Index as a Predictor of Latent Instability.
*American Meteorology Society*,
doi:`10.1175/1520-0477-37.10.528
Expand Down
6 changes: 6 additions & 0 deletions examples/calculations/Sounding_Calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ def effective_layer(p, t, td, h, height_layer=False):
sped = df['speed'].values * units.knot
height = df['height'].values * units.meter

###########################################
# Compute needed variables from our data file and attach units
relhum = mpcalc.relative_humidity_from_dewpoint(T, Td)
mixrat = mpcalc.mixing_ratio_from_relative_humidity(p, T, relhum)

###########################################
# Compute the wind components
u, v = mpcalc.wind_components(sped, wdir)
Expand All @@ -96,6 +101,7 @@ def effective_layer(p, t, td, h, height_layer=False):
# Compute common sounding index parameters
ctotals = mpcalc.cross_totals(p, T, Td)
kindex = mpcalc.k_index(p, T, Td)
gdi = mpcalc.galvez_davison_index(p, T, mixrat, p[0])
showalter = mpcalc.showalter_index(p, T, Td)
total_totals = mpcalc.total_totals_index(p, T, Td)
vert_totals = mpcalc.vertical_totals(p, T)
Expand Down
175 changes: 175 additions & 0 deletions src/metpy/calc/thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4497,6 +4497,181 @@ def k_index(pressure, temperature, dewpoint, vertical_dim=0):
return ((t850 - t500) + td850 - (t700 - td700)).to(units.degC)


@exporter.export
@add_vertical_dim_from_xarray
@preprocess_and_wrap(broadcast=('pressure', 'temperature', 'mixing_ratio'))
@check_units('[pressure]', '[temperature]', '[dimensionless]', '[pressure]')
def galvez_davison_index(pressure, temperature, mixing_ratio, surface_pressure,
vertical_dim=0):
"""
Calculate GDI from the pressure, temperature, mixing ratio, and surface pressure.
Calculation of the GDI relies on temperatures and mixing ratios at 950,
850, 700, and 500 hPa. These four levels define three layers: A) Boundary,
B) Trade Wind Inversion (TWI), C) Mid-Troposphere.
GDI formula derived from [Galvez2015]_:
.. math:: GDI = CBI + MWI + II + TC
where:
* :math:`CBI` is the Column Buoyancy Index
* :math:`MWI` is the Mid-tropospheric Warming Index
* :math:`II` is the Inversion Index
* :math:`TC` is the Terrain Correction [optional]
.. list-table:: GDI Values & Corresponding Convective Regimes
:widths: 15 75
:header-rows: 1
* - GDI Value
- Expected Convective Regime
* - >=45
- Scattered to widespread thunderstorms likely.
* - 35 to 45
- Scattered thunderstorms and/or scattered to widespread rain showers.
* - 25 to 35
- Isolated to scattered thunderstorms and/or scattered showers.
* - 15 to 25
- Isolated thunderstorms and/or isolated to scattered showers.
* - 5 to 10
- Isolated to scattered showers.
* - <5
- Strong TWI likely, light rain possible.
Parameters
----------
pressure : `pint.Quantity`
Pressure level(s)
temperature : `pint.Quantity`
Temperature corresponding to pressure
mixing_ratio : `pint.Quantity`
Mixing ratio values corresponding to pressure
surface_pressure : `pint.Quantity`
Pressure of the surface.
vertical_dim : int, optional
The axis corresponding to vertical, defaults to 0. Automatically determined from
xarray DataArray arguments.
Returns
-------
`pint.Quantity`
GDI Index
Examples
--------
>>> from metpy.calc import mixing_ratio_from_relative_humidity
>>> from metpy.units import units
>>> # pressure
>>> p = [1008., 1000., 950., 900., 850., 800., 750., 700., 650., 600.,
... 550., 500., 450., 400., 350., 300., 250., 200.,
... 175., 150., 125., 100., 80., 70., 60., 50.,
... 40., 30., 25., 20.] * units.hPa
>>> # temperature
>>> T = [29.3, 28.1, 23.5, 20.9, 18.4, 15.9, 13.1, 10.1, 6.7, 3.1,
... -0.5, -4.5, -9.0, -14.8, -21.5, -29.7, -40.0, -52.4,
... -59.2, -66.5, -74.1, -78.5, -76.0, -71.6, -66.7, -61.3,
... -56.3, -51.7, -50.7, -47.5] * units.degC
>>> # relative humidity
>>> rh = [.85, .65, .36, .39, .82, .72, .75, .86, .65, .22, .52,
... .66, .64, .20, .05, .75, .76, .45, .25, .48, .76, .88,
... .56, .88, .39, .67, .15, .04, .94, .35] * units.dimensionless
>>> # calculate mixing ratio
>>> mixrat = mixing_ratio_from_relative_humidity(p, T, rh)
>>> galvez_davison_index(p, T, mixrat, p[0])
<Quantity(-8.78797532, 'dimensionless')>
"""
if np.any(np.max(pressure, axis=vertical_dim) < 950 * units.hectopascal):
indices_without_950 = np.where(
np.max(pressure, axis=vertical_dim) < 950 * units.hectopascal
)
raise ValueError(
f'Data not provided for 950hPa or higher pressure. '
f'GDI requires 950hPa temperature and dewpoint data, '
f'see referenced paper section 3.d. in docstring for discussion of'
f' extrapolating sounding data below terrain surface in high-'
f'elevation regions.\nIndices without a 950hPa or higher datapoint'
f':\n{indices_without_950}'
f'\nMax provided pressures:'
f'\n{np.max(pressure, axis=0)[indices_without_950]}'
)

potential_temp = potential_temperature(pressure, temperature)

# Interpolate to appropriate level with appropriate units
(
(t950, t850, t700, t500),
(r950, r850, r700, r500),
(th950, th850, th700, th500)
) = interpolate_1d(
units.Quantity([950, 850, 700, 500], 'hPa'),
pressure, temperature.to('K'), mixing_ratio, potential_temp.to('K'),
axis=vertical_dim,
)

# L_v definition preserved from referenced paper
# Value differs heavily from metpy.constants.Lv in tropical context
# and using MetPy value affects resulting GDI
l_0 = units.Quantity(2.69e6, 'J/kg')

# Calculate adjusted equivalent potential temperatures
alpha = units.Quantity(-10, 'K')
eptp_a = th950 * np.exp(l_0 * r950 / (mpconsts.Cp_d * t850))
eptp_b = ((th850 + th700) / 2
* np.exp(l_0 * (r850 + r700) / 2 / (mpconsts.Cp_d * t850)) + alpha)
eptp_c = th500 * np.exp(l_0 * r500 / (mpconsts.Cp_d * t850)) + alpha

# Calculate Column Buoyanci Index (CBI)
# Apply threshold to low and mid levels
beta = units.Quantity(303, 'K')
l_e = eptp_a - beta
m_e = eptp_c - beta

# Gamma unit - likely a typo from the paper, should be units of K^(-2) to
# result in dimensionless CBI
gamma = units.Quantity(6.5e-2, '1/K^2')

column_buoyancy_index = np.atleast_1d(gamma * l_e * m_e)
column_buoyancy_index[l_e <= 0] = 0

# Calculate Mid-tropospheric Warming Index (MWI)
# Apply threshold to 500-hPa temperature
tau = units.Quantity(263.15, 'K')
t_diff = t500 - tau

mu = units.Quantity(-7, '1/K') # Empirical adjustment
mid_tropospheric_warming_index = np.atleast_1d(mu * t_diff)
mid_tropospheric_warming_index[t_diff <= 0] = 0

# Calculate Inversion Index (II)
s = t950 - t700
d = eptp_b - eptp_a
inv_sum = s + d

sigma = units.Quantity(1.5, '1/K') # Empirical scaling constant
inversion_index = np.atleast_1d(sigma * inv_sum)
inversion_index[inv_sum >= 0] = 0

# Calculate Terrain Correction
terrain_correction = 18 - 9000 / (surface_pressure.m_as('hPa') - 500)

# Calculate G.D.I.
gdi = (column_buoyancy_index
+ mid_tropospheric_warming_index
+ inversion_index
+ terrain_correction)

if gdi.size == 1:
return gdi[0]
else:
return gdi


@exporter.export
@add_vertical_dim_from_xarray
@preprocess_and_wrap(
Expand Down
4 changes: 2 additions & 2 deletions tests/calc/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,14 +709,14 @@ def test_smooth_window_1d_dataarray():
temperature = xr.DataArray(
[37., 32., 34., 29., 28., 24., 26., 24., 27., 30.],
dims=('time',),
coords={'time': pd.date_range('2020-01-01', periods=10, freq='H')},
coords={'time': pd.date_range('2020-01-01', periods=10, freq='h')},
attrs={'units': 'degF'})
smoothed = smooth_window(temperature, window=np.ones(3) / 3, normalize_weights=False)
truth = xr.DataArray(
[37., 34.33333333, 31.66666667, 30.33333333, 27., 26., 24.66666667,
25.66666667, 27., 30.] * units.degF,
dims=('time',),
coords={'time': pd.date_range('2020-01-01', periods=10, freq='H')}
coords={'time': pd.date_range('2020-01-01', periods=10, freq='h')}
)
xr.testing.assert_allclose(smoothed, truth)

Expand Down
Loading

0 comments on commit d7034c3

Please sign in to comment.