Skip to content
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

Using Virtual Temperature in CAPE/CIN calculations #2437

Merged
merged 31 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8a83ef0
first cut at using virtual temperature in parcel profile
mgrover1 Apr 15, 2022
7ab2e47
fix linting with new parcel path class
mgrover1 Apr 15, 2022
1536c9b
fix bugs in initial implementation
mgrover1 Mar 28, 2023
7b7f23e
fix flake8 in thermo
mgrover1 Mar 28, 2023
036be15
Add suggestions from Dan
mgrover1 Mar 29, 2023
84fccfe
compute virtual temperature at the end
mgrover1 Mar 29, 2023
62d4985
revert to original thermo/tests
mgrover1 Apr 3, 2023
911a941
add reverted thermo module
mgrover1 Apr 3, 2023
742a27a
Merge branch 'main' into use-virtual-temp-parcel
mgrover1 Apr 3, 2023
b6aa39a
add missing sweat index calc
mgrover1 Apr 3, 2023
0d9f1fd
add new virtual temperature from dewpoint function
mgrover1 Apr 3, 2023
d393916
add new function to overrides
mgrover1 Apr 3, 2023
22aeec6
use virtual temperature for CAPE
mgrover1 Apr 3, 2023
1af6af1
fix last few failing tests
mgrover1 Apr 3, 2023
994b00b
fix linting issues
mgrover1 Apr 3, 2023
fb7b8e6
update docstring values
mgrover1 Apr 3, 2023
be33d31
fix units for virtual temperature
mgrover1 Apr 3, 2023
7356935
Fix use of parcel moisture profile
mgrover1 Apr 12, 2023
d8c78ac
Add fixed booleans
mgrover1 Apr 13, 2023
404147f
fix failing tests
mgrover1 Apr 13, 2023
c8d13ab
fix line continuation
mgrover1 Apr 13, 2023
dc8ec57
fix the docstring values
mgrover1 Apr 13, 2023
370e091
update docstrings to include virtual temperature
mgrover1 Apr 13, 2023
9015cb2
Update src/metpy/calc/thermo.py
mgrover1 Apr 18, 2023
1a01193
Remove above LCL
mgrover1 Apr 19, 2023
87f718a
Fix variable names in numpy.where
mgrover1 Apr 19, 2023
39e26f8
fix misspelled pressure
mgrover1 Apr 19, 2023
4086007
fix mlcin
mgrover1 Apr 19, 2023
01d94bd
update sensitive sounding test
mgrover1 Apr 24, 2023
612eeba
add suggestion from ryan
mgrover1 Apr 24, 2023
cf9e387
use dewpoint instead of temperature
mgrover1 Apr 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/_templates/overrides/metpy.calc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Moist Thermodynamics
vertical_velocity_pressure
virtual_potential_temperature
virtual_temperature
virtual_temperature_from_dewpoint
wet_bulb_temperature


Expand Down
89 changes: 82 additions & 7 deletions src/metpy/calc/thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,65 @@ def virtual_temperature(
/ (molecular_weight_ratio * (1 + mixing_ratio)))


@exporter.export
@preprocess_and_wrap(wrap_like='temperature', broadcast=('pressure',
'temperature',
'dewpoint'))
@check_units('[pressure]', '[temperature]', '[temperature]')
def virtual_temperature_from_dewpoint(
pressure, temperature, dewpoint, molecular_weight_ratio=mpconsts.nounit.epsilon
):
r"""Calculate virtual temperature.

This calculation must be given an air parcel's temperature and mixing ratio.
The implementation uses the formula outlined in [Hobbs2006]_ pg.80.

Parameters
----------
pressure: `pint.Quantity`
Total atmospheric pressure

temperature: `pint.Quantity`
Air temperature

dewpoint : `pint.Quantity`
Dewpoint temperature

molecular_weight_ratio : `pint.Quantity` or float, optional
The ratio of the molecular weight of the constituent gas to that assumed
for air. Defaults to the ratio for water vapor to dry air.
(:math:`\epsilon\approx0.622`)

Returns
-------
`pint.Quantity`
Corresponding virtual temperature of the parcel

Examples
--------
>>> from metpy.calc import virtual_temperature_from_dewpoint
>>> from metpy.units import units
>>> virtual_temperature_from_dewpoint(1000 * units.hPa, 30 * units.degC, 25 * units.degC)
<Quantity(33.6739865, 'degree_Celsius')>

Notes
-----
.. math:: T_v = T \frac{\text{w} + \epsilon}{\epsilon\,(1 + \text{w})}

.. versionchanged:: 1.0
Renamed ``mixing`` parameter to ``mixing_ratio``

"""
# Convert the dewpoint to specific humidity
specific_humidity = specific_humidity_from_dewpoint(pressure, dewpoint)

# Convert the specific humidity to mixing ratio
mixing_ratio = mixing_ratio_from_specific_humidity(specific_humidity)

# Calculate virtual temperature with given parameters
return virtual_temperature(temperature, mixing_ratio, molecular_weight_ratio)


@exporter.export
@preprocess_and_wrap(
wrap_like='temperature',
Expand Down Expand Up @@ -2242,7 +2301,7 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom'
>>> prof = parcel_profile(p, T[0], Td[0]).to('degC')
>>> # calculate surface based CAPE/CIN
>>> cape_cin(p, T, Td, prof)
(<Quantity(4578.94162, 'joule / kilogram')>, <Quantity(0, 'joule / kilogram')>)
(<Quantity(4703.77306, 'joule / kilogram')>, <Quantity(0, 'joule / kilogram')>)

See Also
--------
Expand All @@ -2252,9 +2311,11 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom'
-----
Formula adopted from [Hobbs1977]_.

.. math:: \text{CAPE} = -R_d \int_{LFC}^{EL} (T_{parcel} - T_{env}) d\text{ln}(p)
.. math:: \text{CAPE} = -R_d \int_{LFC}^{EL}
(T_{{v}_{parcel}} - T_{{v}_{env}}) d\text{ln}(p)

.. math:: \text{CIN} = -R_d \int_{SFC}^{LFC} (T_{parcel} - T_{env}) d\text{ln}(p)
.. math:: \text{CIN} = -R_d \int_{SFC}^{LFC}
(T_{{v}_{parcel}} - T_{{v}_{env}}) d\text{ln}(p)


* :math:`CAPE` is convective available potential energy
Expand All @@ -2264,8 +2325,8 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom'
* :math:`SFC` is the level of the surface or beginning of parcel path
* :math:`R_d` is the gas constant
* :math:`g` is gravitational acceleration
* :math:`T_{parcel}` is the parcel temperature
* :math:`T_{env}` is environment temperature
* :math:`T_{{v}_{parcel}}` is the parcel virtual temperature
* :math:`T_{{v}_{env}}` is environment virtual temperature
* :math:`p` is atmospheric pressure

Only functions on 1D profiles (not higher-dimension vertical cross sections or grids).
Expand All @@ -2278,6 +2339,20 @@ def cape_cin(pressure, temperature, dewpoint, parcel_profile, which_lfc='bottom'
"""
pressure, temperature, dewpoint, parcel_profile = _remove_nans(pressure, temperature,
dewpoint, parcel_profile)

pressure_lcl, _ = lcl(pressure[0], temperature[0], dewpoint[0])
below_lcl = pressure > pressure_lcl
above_lcl = pressure <= pressure_lcl

# The mixing ratio of the parcel comes from the dewpoint below the LCL, is saturated
# based on the temperature above the LCL
parcel_mixing_ratio = np.where(below_lcl, saturation_mixing_ratio(press, dewp),
saturation_mixing_ratio(press, temp))

# Convert the temperature/parcel profile to virtual temperature
temperature = virtual_temperature_from_dewpoint(pressure, temperature, dewpoint)
parcel_profile = virtual_temperature(parcel_profile, parcel_mixing_ratio)

# Calculate LFC limit of integration
lfc_pressure, _ = lfc(pressure, temperature, dewpoint,
parcel_temperature_profile=parcel_profile, which=which_lfc)
Expand Down Expand Up @@ -2834,7 +2909,7 @@ def most_unstable_cape_cin(pressure, temperature, dewpoint, **kwargs):
>>> Td = dewpoint_from_relative_humidity(T, rh)
>>> # calculate most unstbale CAPE/CIN
>>> most_unstable_cape_cin(p, T, Td)
(<Quantity(4585.43188, 'joule / kilogram')>, <Quantity(0, 'joule / kilogram')>)
(<Quantity(4703.77306, 'joule / kilogram')>, <Quantity(0, 'joule / kilogram')>)

See Also
--------
Expand Down Expand Up @@ -2910,7 +2985,7 @@ def mixed_layer_cape_cin(pressure, temperature, dewpoint, **kwargs):
>>> # calculate dewpoint
>>> Td = dewpoint_from_relative_humidity(T, rh)
>>> mixed_layer_cape_cin(p, T, Td, depth=50 * units.hPa)
(<Quantity(587.144138, 'joule / kilogram')>, <Quantity(-46.8016713, 'joule / kilogram')>)
(<Quantity(711.239032, 'joule / kilogram')>, <Quantity(0, 'joule / kilogram')>)

See Also
--------
Expand Down
Loading