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

Gradient between vertical levels #2030

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
11 changes: 6 additions & 5 deletions improver/cli/gradient_between_vertical_levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ def process(*cubes: cli.inputcubelist):

Input cubes can be provided at height or pressure levels. If the cubes are provided
at a pressure level, the height above sea level is extracted from height_of_pressure_levels
cube. If the cubes are provided at height levels this is assumed to be a height above ground
level and the height above sea level is calculated by adding the height of the orography to
the "height" coordinate of the cube. It is possible for one cube to be defined at height
levels and the other at pressure levels.
cube. If exactly one of the cubes are provided at height levels this is assumed to be a
height above ground level and the height above sea level is calculated by adding the height
of the orography to the "height" coordinate of the cube. If both cubes have height coordinates
no additional cubes are required.
It is possible for one cube to be defined at height levels and the other at pressure levels.

Args:
cubes (iris.cube.CubeList):
Contains two cubes of a diagnostic at two different vertical levels. The cubes must
either have a height coordinate or a pressure coordinate. If either cube is defined at
either have a height coordinate or a pressure coordinate. If only one cube is defined at
height levels, an orography cube must also be provided. If either cube is defined at
pressure levels, a geopotential_height cube must also be provided.

Expand Down
20 changes: 12 additions & 8 deletions improver/utilities/gradient_between_vertical_levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ def gradient_over_vertical_levels(

If the cubes are provided at height levels this is assumed to be a height above ground level
and the height above sea level is calculated by adding the height of the orography to the
height coordinate.If the cubes are provided at pressure levels, the height above sea level
is extracted from a geopotential_height cube.
height coordinate. If the cubes are provided at pressure levels, the height above sea level
is extracted from a geopotential_height cube.If both cubes have a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
is extracted from a geopotential_height cube.If both cubes have a
is extracted from a geopotential_height cube. If both cubes have a

height coordinate then no additional cubes are required.

Args:
cubes:
Expand All @@ -67,15 +68,15 @@ def gradient_over_vertical_levels(
the height above sea level at the pressure level of the input cubes.
orography:
Optional cube containing the orography height above sea level. This cube is required
if any input cube is defined at height levels and is used to convert the height
above ground level to height above sea level.
if exactly one input cube is defined at height levels and is used to convert the
height above ground level to height above sea level.

Returns:
A cube containing the gradient between the cubes between two vertical levels.

Raises:
ValueError: If either input cube is defined at height levels and no orography cube is
provided.
ValueError: If exactly one input cube is defined at height levels and no orography cube
is provided.
ValueError: If either input cube is defined at pressure levels and no
geopotential_height cube is provided.
"""
Expand All @@ -98,6 +99,8 @@ def gradient_over_vertical_levels(
else:
if orography:
height_ASL = orography + cube_height
elif not (orography or geopotential_height):
height_ASL = cube_height
else:
raise ValueError(
"""No orography cube provided but one of the input cubes has height
Expand All @@ -121,10 +124,11 @@ def process(self, *cubes: CubeList) -> Cube:
cubes:
A cubelist of two cubes containing a diagnostic at two vertical levels.
The cubes must contain either a height or pressure scalar coordinate.
If either of the cubes contain a height scalar coordinate this is assumed
If exactly one of the cubes contain a height scalar coordinate this is assumed
to be a height above ground level and a cube with the name "surface_altitude"
must also be provided. If either cube contains a pressure scalar coordinate
a cube with the name "geopotential_height" must be provided.
a cube with the name "geopotential_height" must be provided.If both cubes are
on height levels then no additional cubes are required.

Returns:
A cube containing the gradient between two vertical levels. The cube will be
Expand Down
16 changes: 6 additions & 10 deletions improver_tests/utilities/test_GradientBetweenVerticalLevels.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,28 +68,24 @@ def test_height_and_pressure(
"""Test that the plugin produces the expected result with cubes defined either
both on height or pressure levels. Also check the plugin produces the expected
result with one cube defined on height levels and the other on pressure levels."""
cubes = [orography, height_of_pressure_levels]
if height_or_pressure == "height_both":
temperature_at_850hPa.add_aux_coord(
iris.coords.AuxCoord(101.5, long_name="height", units="m")
)
temperature_at_850hPa.remove_coord("pressure")
cubes = []
elif height_or_pressure == "pressure_both":
temperature_at_screen_level.add_aux_coord(
iris.coords.AuxCoord(100000, long_name="pressure", units="Pa")
)
temperature_at_screen_level.remove_coord("height")
cubes = [height_of_pressure_levels]

cubes.append([temperature_at_850hPa, temperature_at_screen_level])

expected = [[0.03, 0.01], [-0.01, -0.03]]
result = GradientBetweenVerticalLevels()(
iris.cube.CubeList(
[
temperature_at_850hPa,
temperature_at_screen_level,
height_of_pressure_levels,
orography,
]
)
)
result = GradientBetweenVerticalLevels()(iris.cube.CubeList(cubes))
np.testing.assert_array_almost_equal(result.data, expected)
assert result.name() == "gradient_of_air_temperature"
assert result.units == "K/m"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While considering the time metadata, I've discovered that the scalar coordinates are unexpected. In the mixed inputs case, the output has both the height (1.5m) and pressure (85000 Pa) scalar coords while I would expect it to have neither.

The height_both case has no time or forecast_period coord on the output if I change the time of the temperature on pressure levels cube by an hour.

Expand Down
Loading