diff --git a/improver/psychrometric_calculations/cloud_condensation_level.py b/improver/psychrometric_calculations/cloud_condensation_level.py index 24859753a1..485b90e412 100644 --- a/improver/psychrometric_calculations/cloud_condensation_level.py +++ b/improver/psychrometric_calculations/cloud_condensation_level.py @@ -141,6 +141,8 @@ def humidity_delta(p2, p, t, q): def process(self, *cubes: Union[Cube, CubeList]) -> Tuple[Cube, Cube]: """ Calculates the cloud condensation level from the near-surface inputs. + Values will be limited to the surface values where the calculated pressure is greater than + the original pressure, which can occur in super-saturated conditions. Args: cubes: @@ -157,6 +159,11 @@ def process(self, *cubes: Union[Cube, CubeList]) -> Tuple[Cube, Cube]: ["air_temperature", "surface_air_pressure", "humidity_mixing_ratio"] ) ccl_pressure, ccl_temperature = self._iterate_to_ccl() + # Limit values so they are no greater than the original pressure. + # This occurs in super-saturated conditions. + mask = ccl_pressure > self.pressure.data + ccl_pressure = np.where(mask, self.pressure.data, ccl_pressure) + ccl_temperature = np.where(mask, self.temperature.data, ccl_temperature) return ( self._make_ccl_cube(ccl_temperature, is_temperature=True), self._make_ccl_cube(ccl_pressure, is_temperature=False), diff --git a/improver_tests/acceptance/SHA256SUMS b/improver_tests/acceptance/SHA256SUMS index 2f6b32572d..98e1f79eb5 100644 --- a/improver_tests/acceptance/SHA256SUMS +++ b/improver_tests/acceptance/SHA256SUMS @@ -274,8 +274,8 @@ e1a002ee954978e9ab5830320f700a05f3f067c39bba9853587d79cd047564b8 ./clip/gridded 9ae995a600331cf97ca5c64be4dd9a34adc9be7c5b5f987d3735af0d7973d7c3 ./cloud-condensation-level/pressure_at_surface.nc 5d964d04169737f4116505c6b4ad5e2a894592c789303460f9d292fa204b3775 ./cloud-condensation-level/relative_humidity.nc 0425846305d3e15ef78f303855254f902c6a06d33caa38ac1d12540da88e4a7d ./cloud-condensation-level/temperature.nc -d0053b55f2abaeeefa3d5d58df597bbaf5b07a2bfbb614c1ff404fb695700d2c ./cloud-condensation-level/with_id_attr/kgo.nc -957efd30f9de7d789727c7763fc07b01a68a8e19a82e74d30842af3f160adbd8 ./cloud-condensation-level/without_id_attr/kgo.nc +39063e415ea1bbdcb7de77758735085c81519e4529f59d8109c5df057eb6ba11 ./cloud-condensation-level/with_id_attr/kgo.nc +e7d3fb9ddb8753439ccb38e170edcfb885e3c80ca36a02d76711e7731259c91d ./cloud-condensation-level/without_id_attr/kgo.nc 6d00c62a3716bd7df53113a370205224b833e9a9ba01178be344031f799a6a3d ./cloud-top-temperature/cloud_condensation_level.nc 5788b1228fbd7cce6c92a2ff6448c4f14d78d868bb45743a816f728b70c6b47d ./cloud-top-temperature/temperature_on_pressure_levels.nc d350e329f47d18c819f75a91a0168dff0c8cce404df2e3992e41c4b78925699b ./cloud-top-temperature/with_id_attr/kgo.nc diff --git a/improver_tests/psychrometric_calculations/cloud_condensation_level/test_CloudCondensationLevel.py b/improver_tests/psychrometric_calculations/cloud_condensation_level/test_CloudCondensationLevel.py index 06dc705476..bfc5e77152 100644 --- a/improver_tests/psychrometric_calculations/cloud_condensation_level/test_CloudCondensationLevel.py +++ b/improver_tests/psychrometric_calculations/cloud_condensation_level/test_CloudCondensationLevel.py @@ -129,6 +129,33 @@ def test_basic( assert np.isclose(result[1].data, expected_p, atol=1e-0).all() +@pytest.mark.parametrize( + "temperature_value, pressure_value, humidity_value", + ( + (293, 100000, 2.7e-1), + (300, 100000, 1.0e-1), + (189, 60300, 0.334), # This case was found in MOGREPS-G outputs. + ), +) +def test_for_limited_values( + temperature, + pressure, + humidity, + temperature_value, + pressure_value, + humidity_value, +): + """Check that for each pair of values, we get the surface temperature and pressure returned + and that the metadata are as expected.""" + temperature.data = np.full_like(temperature.data, temperature_value) + pressure.data = np.full_like(pressure.data, pressure_value) + humidity.data = np.full_like(humidity.data, humidity_value) + result = CloudCondensationLevel()([temperature, pressure, humidity]) + metadata_ok(result, temperature) + assert np.isclose(result[0].data, temperature_value, atol=1e-2).all() + assert np.isclose(result[1].data, pressure_value, atol=1e-0).all() + + @pytest.mark.parametrize("model_id_attr", ("mosg__model_configuration", None)) def test_model_id_attr(temperature, pressure, humidity, model_id_attr): """Check that tests pass if model_id_attr is set on inputs and is applied or not"""