mirror of
https://github.com/meteoinfo/MeteoInfo.git
synced 2025-12-08 20:36:05 +00:00
90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
"""
|
|
Contains calculation of various derived indices.
|
|
|
|
Ported from MetPy.
|
|
"""
|
|
|
|
import mipylib.numeric as np
|
|
from .tools import _remove_nans, get_layer
|
|
from .thermo import mixing_ratio, saturation_vapor_pressure
|
|
from .. import constants
|
|
|
|
|
|
__all__ = ['precipitable_water']
|
|
|
|
|
|
def precipitable_water(pressure, dewpoint, bottom=None, top=None):
|
|
r"""Calculate precipitable water through the depth of a sounding.
|
|
|
|
Formula used is:
|
|
|
|
.. math:: -\frac{1}{\rho_l g} \int\limits_{p_\text{bottom}}^{p_\text{top}} r dp
|
|
|
|
from [Salby1996]_, p. 28
|
|
|
|
Parameters
|
|
----------
|
|
pressure : `hPa`
|
|
Atmospheric pressure profile
|
|
|
|
dewpoint : `kelvin`
|
|
Atmospheric dewpoint profile
|
|
|
|
bottom: `hPa`, optional
|
|
Bottom of the layer, specified in pressure. Defaults to None (highest pressure).
|
|
|
|
top: `hPa`, optional
|
|
Top of the layer, specified in pressure. Defaults to None (lowest pressure).
|
|
|
|
Returns
|
|
-------
|
|
`millimeters`
|
|
Precipitable water in the layer
|
|
|
|
Examples
|
|
--------
|
|
>>> from mipylib.meteolib.calc import precipitable_water
|
|
>>> from mipylib.meteolib import constants as cons
|
|
>>> pressure = np.array([1000, 950, 900])
|
|
>>> dewpoint = np.array([20, 15, 10]) + cons.degCtoK
|
|
>>> pw = precipitable_water(pressure, dewpoint)
|
|
(11.7702606153 millimeter)
|
|
|
|
Notes
|
|
-----
|
|
Only functions on 1D profiles (not higher-dimension vertical cross sections or grids).
|
|
|
|
"""
|
|
# Sort pressure and dewpoint to be in decreasing pressure order (increasing height)
|
|
sort_inds = np.argsort(pressure)[::-1]
|
|
pressure = pressure[sort_inds]
|
|
dewpoint = dewpoint[sort_inds]
|
|
|
|
pressure, dewpoint = _remove_nans(pressure, dewpoint)
|
|
|
|
min_pressure = np.min(pressure)
|
|
max_pressure = np.max(pressure)
|
|
|
|
if top is None:
|
|
top = min_pressure
|
|
elif not min_pressure <= top <= max_pressure:
|
|
raise ValueError('The pressure and dewpoint profile ranges from {} to '
|
|
'{}, after removing missing values. {} is outside '
|
|
'this range.'.format(max_pressure, min_pressure, top))
|
|
|
|
if bottom is None:
|
|
bottom = max_pressure
|
|
elif not min_pressure <= bottom <= max_pressure:
|
|
raise ValueError('The pressure and dewpoint profile ranges from {} to '
|
|
'{}, after removing missing values. {} is outside '
|
|
'this range.'.format(max_pressure, min_pressure, bottom))
|
|
|
|
pres_layer, dewpoint_layer = get_layer(pressure, dewpoint, bottom=bottom,
|
|
depth=bottom - top)
|
|
|
|
w = mixing_ratio(saturation_vapor_pressure(dewpoint_layer), pres_layer)
|
|
|
|
# Since pressure is in decreasing order, pw will be the opposite sign of that expected.
|
|
pw = -np.trapezoid(w, pres_layer) / (constants.g * constants.rho_l)
|
|
return pw * 1e5
|