diff --git a/improver/psychrometric_calculations/cloud_condensation_level.py b/improver/psychrometric_calculations/cloud_condensation_level.py index a65bd445ed..8f0c9440da 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 587fa4aa52..e070f4e097 100644 --- a/improver_tests/acceptance/SHA256SUMS +++ b/improver_tests/acceptance/SHA256SUMS @@ -286,8 +286,8 @@ a77fbeba45109945cf063692aee1052afb38979ebf3455fc57bc287bbda55f87 ./clip/spot_da 9ae995a600331cf97ca5c64be4dd9a34adc9be7c5b5f987d3735af0d7973d7c3 ./cloud-condensation-level/pressure_at_surface.nc 5d964d04169737f4116505c6b4ad5e2a894592c789303460f9d292fa204b3775 ./cloud-condensation-level/relative_humidity.nc 0425846305d3e15ef78f303855254f902c6a06d33caa38ac1d12540da88e4a7d ./cloud-condensation-level/temperature.nc -fa0d7f6ff288cb56c3fe4806524cd2be56f03439d02d87bcb8c1937cb311aa38 ./cloud-condensation-level/with_id_attr/kgo.nc -f800e8f5bcf717929dab5e0c9322fc9d8a72afd9a71b658721b63fbccd77c3a2 ./cloud-condensation-level/without_id_attr/kgo.nc +9e35dfe9791ceb4b2278255f808ec595d73d3e1ec50647c9dc547da0c1ef09b3 ./cloud-condensation-level/with_id_attr/kgo.nc +0751604f7ac9cb88bd9147f8f464637290bff4797b902c66f10c8dd37c6c0b45 ./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 2ccb84718d2d367baa9b0e2dcaf70a285575de23a80d007e53af0861b93b787c ./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"""