Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
20 changes: 18 additions & 2 deletions improver/cli/uv_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,39 @@

@cli.clizefy
@cli.with_output
def process(uv_flux_down: cli.inputcube, *, model_id_attr: str = None):
def process(
uv_flux_down: cli.inputcube, *, scale_factor: float = 3.6, model_id_attr: str = None
):
"""Calculate the UV index using the data in the input cubes.

Calculate the uv index using the radiation flux in UV downward at surface.

Args:
uv_flux_down (iris.cube.Cube):
Cube of radiation flux in UV downwards at surface.
scale_factor:
The uv scale factor. Default is 3.6 (m2 W-1). This factor has
been empirically derived and should not be
changed except if there are scientific reasons to
do so. For more information see section 2.1.1 of the paper
referenced below.
Comment on lines +23 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Given that the user is now able to change the scale factor, that it has been empirically derived as 3.6 and it seems strongly encouraged to not change this, should we include a warning to the user if they put in a scale factor that is not the default?

@mo-jbeaver mo-jbeaver Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Warning has been added to the plugin, and the unit test has been updated.

model_id_attr (str):
Name of the attribute used to identify the source model for
blending.

Returns:
iris.cube.Cube:
Processed Cube.

References:
Turner, E.C, Manners, J. Morcrette, C. J, O'Hagan, J. B,
& Smedley, A.R.D. (2017): Toward a New UV Index Diagnostic
in the Met Office's Forecast Model. Journal of Advances in
Modeling Earth Systems 9, 2654-2671.
"""
from improver.uv_index import calculate_uv_index

result = calculate_uv_index(uv_flux_down, model_id_attr=model_id_attr)
result = calculate_uv_index(
uv_flux_down, scale_factor=scale_factor, model_id_attr=model_id_attr
)
return result
12 changes: 12 additions & 0 deletions improver/uv_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""Module for calculating the uv index using radiation flux in UV downward
at the surface."""

import warnings
from typing import Optional

import numpy as np
Expand Down Expand Up @@ -47,6 +48,9 @@ def calculate_uv_index(
ValueError: If uv_downward contains values that are negative or
not a number.

Warning:
- If scale_factor has been changed from the default 3.6 (m2 W-1).

References:
Turner, E.C, Manners, J. Morcrette, C. J, O'Hagan, J. B,
& Smedley, A.R.D. (2017): Toward a New UV Index Diagnostic
Expand All @@ -71,6 +75,14 @@ def calculate_uv_index(
)
raise ValueError(msg)

if scale_factor != 3.6:
msg = (
f"The scale_factor is not the default 3.6 (m2 W-1) but {scale_factor}. "
"This default factor has been empirically derived and should not be "
"changed except if there are scientific reasons to do so."
)
warnings.warn(msg)

uv_downward.convert_units("W m-2")
uv_data = (uv_downward.data * scale_factor).astype(np.float32)
attributes = generate_mandatory_attributes(
Expand Down
1 change: 1 addition & 0 deletions improver_tests/acceptance/SHA256SUMS
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,7 @@ e81c04f9f2d8dc14b8d8cd9bc9e8827ebd0da5ba016db48cf60ab738d327f968 ./train-quanti
8e2dda09c26d33fd06d68c5be17a74b93b1d75d54c60ce48f27ea3d2735bece9 ./train-quantile-regression-random-forest/without_transformation_kgo.pickle
e2cfb5e19ef5ebcfd73dc1c8504b66e9a55ad76b7b18cb79318659224079f234 ./uv-index/basic/20181210T0600Z-PT0000H00M-radiation_flux_in_uv_downward_at_surface.nc
e48c3b07bd14214a1a10c0bbf1e0acdf54cfedf93b2c6d766f594ce83a45c2b8 ./uv-index/basic/kgo.nc
71e9242b7d003c1d404de5f39a0e52b4a8a544784654e4c2825f83ad92217993 ./uv-index/non_default_scale_factor/non_default_scale_factor_kgo.nc
2226a5e95eb29664e21f8c0658101a53d65945a1450a60a19955563a2693d22d ./vertical-updraught/cape.nc
b794823053a282e758f7eb8625867d497e55cc3757862a7be504fcbd7451bc32 ./vertical-updraught/precip_rate_max.nc
064f9d2861e6312848a7ba24893b9b8ab0271e4b99793cb0d57fdda732931292 ./vertical-updraught/with_id_attr/kgo.nc
Expand Down
24 changes: 24 additions & 0 deletions improver_tests/acceptance/test_uv_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,27 @@ def test_basic(tmp_path):
]
run_cli(args)
acc.compare(output_path, kgo_path)


def test_non_default_scale_factor(tmp_path):
"""Test UV index calculation with non-default scale factor"""
kgo_dir = acc.kgo_root() / "uv-index"
kgo_path = kgo_dir / "non_default_scale_factor/non_default_scale_factor_kgo.nc"
input_paths = [
kgo_dir
/ (
"basic/20181210T0600Z-PT0000H00M-radiation_flux_in_uv_downward_at_surface.nc"
)
]
output_path = tmp_path / "output.nc"
args = [
*input_paths,
"--output",
output_path,
"--scale-factor",
"0.1",
"--model-id-attr",
"mosg__model_configuration",
]
run_cli(args)
acc.compare(output_path, kgo_path)
4 changes: 3 additions & 1 deletion improver_tests/uv_index/test_uv_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ def test_scale_factor(self):
"""Test the uv calculation works when changing the scale factor. Make
sure the output is a cube with the expected data."""
expected = np.ones_like(self.cube_uv_down.data, dtype=np.float32)
result = calculate_uv_index(self.cube_uv_down, scale_factor=10)
msg = r"The scale_factor is not the default 3\.6 \(m2 W-1\) but 10\.*"
with self.assertWarnsRegex(UserWarning, msg):
result = calculate_uv_index(self.cube_uv_down, scale_factor=10)
np.testing.assert_array_equal(result.data, expected)

def test_metadata(self):
Expand Down