Skip to content

Commit

Permalink
Merge pull request #353 from MetOffice/352_inflow_properties_additon
Browse files Browse the repository at this point in the history
Adds inflow layer properties diagnostic
  • Loading branch information
jfrost-mo authored May 24, 2024
2 parents e019eec + 80282cc commit 5975e93
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 42 deletions.
12 changes: 12 additions & 0 deletions cset-workflow/includes/deterministic_plot_inflow_properties.cylc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% if DETERMINISTIC_PLOT_INFLOW_PROPERTIES %}
[runtime]
[[parallel_inflow_layer_properties]]
inherit = PARALLEL
[[[environment]]]
CSET_RECIPE_NAME = "inflow_layer_properties_plot.yaml"

[[collate_inflow_layer_properties]]
inherit = COLLATE
[[[environment]]]
CSET_RECIPE_NAME = "inflow_layer_properties_plot.yaml"
{% endif %}
8 changes: 8 additions & 0 deletions cset-workflow/meta/rose-meta.conf
Original file line number Diff line number Diff line change
Expand Up @@ -523,3 +523,11 @@ help=Recommend looking at the input data to get these values. Uses the grid's na
type=real
sort-key=subsection2
compulsory=true

[template variables=DETERMINISTIC_PLOT_INFLOW_PROPERTIES]
ns=Diagnostics
description=Extracts data required for, and calculates the inflow properties diagnostic, plotting on a map.
Required STASH m01s20i119, m01s00i025, m01s00i033.
help=See includes/deterministic_plot_inflow_properties.cylc
type=python_boolean
compulsory=true
180 changes: 147 additions & 33 deletions src/CSET/operators/convection.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
"""

import copy
import logging
import warnings

import iris
import iris.cube
import numpy as np


Expand All @@ -32,16 +35,14 @@ def cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-75.0):
----------
SBCAPE: Cube
Surface-based convective available potential energy as calculated by the
model.
Stash: m01s20i114
model. If using the UM please use STASH ``m01s20i114``
MUCAPE: Cube
Most-unstable convective available potential energy as calculated by the
model.
Stash: m01s20i112
model. If using the UM please use STASH ``m01s20i112``
MUCIN: Cube
Most-unstable convective inhibition associated with the most-unstable
ascent as calculated by the model.
Stash: m01s20i113
ascent as calculated by the model. If using the UM please use STASH
``m01s20i113``
MUCIN_thresh: float, optional, default is -75. J/kg.
Threshold to filter the MUCAPE by values are realistically realisable.
Expand All @@ -51,13 +52,14 @@ def cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-75.0):
Notes
-----
This diagnostic is based on Clark et al. (2012) [1]_. It is based around the idea
that for elevated convection the convective instability is not based at the
surface. This utilises two flavours of CAPE: the surface-based CAPE (SBCAPE)
and the most-unstable CAPE (MUCAPE). The MUCAPE is filtered by the MUCIN
associated with that parcel's ascent to ensure that any CAPE can at least
theoretically be released. The default value is set at -75 J/kg but it can
be changes depending on location and users requirements.
This diagnostic is based on Clark et al. (2012) [Clarketal2012]_. It is
based around the idea that for elevated convection the convective
instability is not based at the surface. This utilises two flavours of CAPE:
the surface-based CAPE (SBCAPE) and the most-unstable CAPE (MUCAPE). The
MUCAPE is filtered by the MUCIN associated with that parcel's ascent to
ensure that any CAPE can at least theoretically be released. The default
value is set at -75 J/kg but it can be changes depending on location and
users requirements.
.. math:: 1 - (\frac{SBCAPE}{MUCAPE})
Expand All @@ -73,29 +75,29 @@ def cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-75.0):
surface-based convection is more likely.
Further details about this diagnostic for elevated convection identification
can be found in Flack et al. (2023) [2]_.
can be found in Flack et al. (2023) [FlackCAPE2023]_.
Expected applicability ranges: Convective-scale models will be noisier than
parametrized models as they are more responsive to the convection, and thus
it may be more sensible to view as a larger spatial average rather than
on the native resolution.
it may be more sensible to view as a larger spatial average rather than on
the native resolution.
Interpretation notes: UM stash for CAPE and CIN are calculated at the end of
the timestep. Therefore this diagnostic is applicable after precipitation has
occurred, not before as is the usual interpretation of CAPE related diagnostics.
the timestep. Therefore this diagnostic is applicable after precipitation
has occurred, not before as is the usual interpretation of CAPE related
diagnostics.
References
----------
.. [1] Clark, A. J., Kain J. S., Marsh P. T., Correia J., Xue M., and Kong
F., (2012) "Forecasting tornado pathlengths using a three-dimensional
object identification algorithm applied to convection-allowing
forecasts." Weather and Forecasting, vol. 27, 1090–1113, doi:
10.1175/WAF-D-11-00147.1
.. [2] Flack, D.L.A., Lehnert, M., Lean, H.W., and Willington, S. (2023)
"Characteristics of Diagnostics for Identifying Elevated
.. [Clarketal2012] Clark, A. J., Kain J. S., Marsh P. T., Correia J., Xue
M., and Kong F., (2012) "Forecasting tornado pathlengths using a
three-dimensional object identification algorithm applied to
convection-allowing forecasts." Weather and Forecasting, vol. 27,
1090–1113, doi: 10.1175/WAF-D-11-00147.1
.. [FlackCAPE2023] Flack, D.L.A., Lehnert, M., Lean, H.W., and Willington,
S. (2023) "Characteristics of Diagnostics for Identifying Elevated
Convection over the British Isles in a Convection-Allowing Model."
Weather and Forecasting, vol. 30, 1079-1094, doi:
10.1175/WAF-D-22-0219.1
Weather and Forecasting, vol. 30, 1079-1094, doi: 10.1175/WAF-D-22-0219.1
Examples
--------
Expand All @@ -116,15 +118,18 @@ def cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-75.0):
>>> plt.show()
"""
# Load in the data into the new arrays.
SBCAPE_data = copy.deepcopy(SBCAPE.data)
MUCAPE_data = copy.deepcopy(MUCAPE.data)
# Filter MUCAPE by MUCIN to all for possible (realistic) MUCAPE.
MUCAPE_data[MUCIN.data <= MUCIN_thresh] = 0.0
# Now calculate the main diagnostic
if isinstance(MUCAPE_data, np.ma.MaskedArray):
MUCAPE_data = MUCAPE_data.filled(np.nan)
# Remove all MUCAPE below MUCIN threshold.
MUCAPE_data[MUCIN.data <= MUCIN_thresh] = np.nan
with warnings.catch_warnings():
# Ignore possible divide by zero warnings, as they are replaced by NaNs.
warnings.simplefilter("ignore", RuntimeWarning)
EC_Flagb = 1 - (SBCAPE_data / MUCAPE_data)
warnings.filterwarnings("ignore", category=RuntimeWarning)
# Now calculate the main diagnostic.
EC_Flagb = 1 - (SBCAPE.data / MUCAPE_data)
if isinstance(EC_Flagb, np.ma.MaskedArray):
EC_Flagb = EC_Flagb.filled(np.nan)
# Filter to reduce NaN values and -inf values for plotting ease.
# There are multiple types of NaN values so need to convert them all to same type.
EC_Flagb[np.isnan(EC_Flagb)] = np.nan
Expand All @@ -136,3 +141,112 @@ def cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-75.0):
cape_ratio_cube.var_name = "cape_ratio"
cape_ratio_cube.attributes.pop("STASH", None)
return cape_ratio_cube


def inflow_layer_properties(EIB, BLheight, Orography):
r"""Filter to create a binary mask identifying elevated convection.
Parameters
----------
EIB: Cube
Effective inflow layer base (precalculated or as identified by the
model). If using the UM please use STASH ``m01s20i119``.
BLheight: Cube
Boundary layer height (precalculated or as identified by the model). If
using the UM please use STASH ``m01s00i025``.
Orography: Cube
Model or actual orography, expected to be 2 dimensional. If 3 or 4
dimensional cube given converts to 2 dimensions assuming static
orography field in ensemble realization and time. If using the UM please
use STASH ``m01s00i033``.
Returns
-------
Cube
Notes
-----
This diagnostic is based on the concept of an effective inflow layer. This
concept was first introduced by Thompson et al. (2007) [Thompsonetal2007]_.
The inflow layer defined the region of air that is most likely to be
ingested into the convective event. It is defined by thresholding the CAPE
and CIN values: CAPE > 100 J/kg and \|CIN\| < 250 J/kg.
To turn this into a diagnostic for elevated convection the inflow layer base
is filtered against the boundary layer height. The model orography is added
to the boundary layer height to ensure reference height consistency as the
BL height is defined above ground level and the inflow layer base is defined
above sea level in the model output.
.. math:: EIB > BLheight + Orography
This is a binary diagnostic. It has a value of 0 to imply the environment is
suitable for surface-based convection. It has a value of 1 to indicate the
environment is suitable to produce elevated convection.
Further details about this diagnostic for elevated convection identification
can be found in Flack et al. (2023) [Flackinf2023]_.
Expected applicability ranges: Convective-scale models will be noisier than
parametrized models as they are more responsive to the convection, and thus
it may be more sensible to view as a larger spatial average rather than at
native resolution.
Interpretation notes: The effective inflow layer base diagnostic from UM
STASH is dependent upon the UM CAPE and CIN diagnostics. These diagnostics
are calculated at the end of the timestep. Therefore this diagnostic is
applicable after precipitation has occurred, not before as is the usual
interpretation of CAPE related diagnostics.
You might encounter warnings with the following text ``Orography assumed not
to vary with time or ensemble member.`` or ``Orography assumed not to vary
with time and ensemble member.`` these warnings are expected when the
orography files are not 2-dimensional, and do not cause any problems unless
ordering is not as expected.
References
----------
.. [Thompsonetal2007] Thompson, R. L. Mead, C. M., and Edwards, R., (2007)
"Effective Storm-Relative Helicity and Bulk Shear in Supercell
Thunderstorm Environments." Weather and Forecasting, vol. 22, 102-115,
doi: 10.1175/WAF969.1
.. [Flackinf2023] Flack, D.L.A., Lehnert, M., Lean, H.W., and Willington, S.
(2023) "Characteristics of Diagnostics for Identifying Elevated
Convection over the British Isles in a Convection-Allowing Model."
Weather and Forecasting, vol. 30, 1079-1094, doi: 10.1175/WAF-D-22-0219.1
Examples
--------
>>> Inflow_properties=convection.inflow_layer_properties(EIB,BLheight,Orography)
>>> iplt.pcolormesh(Inflow_properties[0,:,:],cmap=mpl.cm.Purples)
>>> plt.gca().coastlines('10m')
>>> plt.colorbar()
>>> plt.clim(0,1)
>>> plt.show()
"""
# Setup new array for output of the diagnostic.
EC_Flagd = np.zeros(EIB.shape)
# Check dimensions for Orography cube and replace with 2D array if not 2D.
if Orography.ndim == 3:
try:
Orography = Orography.slices_over("realization").next()
except iris.exceptions.CoordinateNotFoundError:
Orography = Orography.slices_over("time").next()
logging.warning("Orography assumed not to vary with time or ensemble member")
elif Orography.ndim == 4:
Orography = Orography.slices_over(("time", "realization")).next()
logging.warning("Orography assumed not to vary with time or ensemble member. ")
# Masked arrays are not respected, so convert masked values into NaNs.
if isinstance(EIB.data, np.ma.MaskedArray):
EIB.data = EIB.data.filled(np.nan)
# Change points where Effective inflow layer base is larger than boundary
# layer height to 1 implying elevated convection.
EC_Flagd[EIB.data > (BLheight.data + Orography.data)] = 1.0
# Take the coordinates from an existing cube and replace the data.
inflow_properties_cube = EIB.copy()
inflow_properties_cube.data = EC_Flagd
# Rename and remove STASH code.
inflow_properties_cube.var_name = "inflow_layer_properties"
inflow_properties_cube.attributes.pop("STASH", None)
return inflow_properties_cube
38 changes: 38 additions & 0 deletions src/CSET/recipes/inflow_layer_properties_plot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
title: Inflow layer properties plot
description: |
Extracts data required for, and calculates the Inflow properties diagnostic, plotting on a map.
parallel:
- operator: read.read_cubes
constraint:
operator: constraints.generate_time_constraint
time_start: $VALIDITY_TIME

- operator: convection.inflow_layer_properties
EIB:
operator: filters.filter_cubes
constraint:
operator: constraints.generate_stash_constraint
stash: m01s20i119
BLheight:
operator: filters.filter_cubes
constraint:
operator: constraints.generate_stash_constraint
stash: m01s00i025
Orography:
operator: filters.filter_cubes
constraint:
operator: constraints.generate_stash_constraint
stash: m01s00i033

- operator: write.write_cube_to_nc
filename: intermediate/inflow_layer

collate:
- operator: read.read_cube
filename: intermediate/*.nc

- operator: write.write_cube_to_nc
overwrite: True

- operator: plot.postage_stamp_contour_plot
28 changes: 19 additions & 9 deletions tests/operators/test_convection.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,32 @@
"""Tests for convection diagnostics."""

import iris
import numpy as np

import CSET.operators.convection as convection


def test_cape_ratio():
"""Compare with precalculated ratio."""
precalculated = iris.load_cube("tests/test_data/convection/ECFlagB.nc")
precalculated_2 = iris.load_cube("tests/test_data/convection/ECFlagB_2.nc")
SBCAPE = iris.load_cube("tests/test_data/convection/SBCAPE.nc")
MUCAPE = iris.load_cube("tests/test_data/convection/MUCAPE.nc")
MUCIN = iris.load_cube("tests/test_data/convection/MUCIN.nc")
assert (
convection.cape_ratio(SBCAPE, MUCAPE, MUCIN).data.all()
== precalculated.data.all()
)
assert (
convection.cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-1.5).data.all()
== precalculated_2.data.all()
cape_75 = convection.cape_ratio(SBCAPE, MUCAPE, MUCIN)
precalculated_75 = iris.load_cube("tests/test_data/convection/ECFlagB.nc")
assert np.allclose(cape_75.data, precalculated_75.data, atol=1e-5, equal_nan=True)

cape_1p5 = convection.cape_ratio(SBCAPE, MUCAPE, MUCIN, MUCIN_thresh=-1.5)
precalculated_1p5 = iris.load_cube("tests/test_data/convection/ECFlagB_2.nc")
assert np.allclose(cape_1p5.data, precalculated_1p5.data, atol=1e-5, equal_nan=True)


def test_inflow_layer_properties():
"""Compare with precalculated properties."""
EIB = iris.load_cube("tests/test_data/convection/EIB.nc")
BLheight = iris.load_cube("tests/test_data/convection/BLheight.nc")
Orography = iris.load_cube("tests/test_data/convection/Orography.nc")
inflow_layer_properties = convection.inflow_layer_properties(
EIB, BLheight, Orography
)
precalculated = iris.load_cube("tests/test_data/convection/ECFlagD.nc")
assert np.allclose(inflow_layer_properties.data, precalculated.data)
Binary file added tests/test_data/convection/BLheight.nc
Binary file not shown.
Binary file modified tests/test_data/convection/ECFlagB_2.nc
Binary file not shown.
Binary file added tests/test_data/convection/ECFlagD.nc
Binary file not shown.
Binary file added tests/test_data/convection/EIB.nc
Binary file not shown.
Binary file added tests/test_data/convection/Orography.nc
Binary file not shown.

0 comments on commit 5975e93

Please sign in to comment.