Coverage for src/scores/functions.py: 100%

1 from typing import overload

2

3 import numpy as np

4 import xarray as xr

5

6 from scores.typing import XarrayLike

7

8

9 def apply_weights(values, weights=None):

10 """

11 Returns:

12 A new array with the elements of values multiplied by the specified weights.

13

14 Args:

15 - weights: The weightings to be used at every location in the values array. If weights contains additional

16 dimensions, these will be taken to mean that multiple weightings are wanted simultaneoulsy, and these

17 dimensions will be added to the new array.

18 - values: The unweighted values to be used as the basis for weighting calculation

19

20

21 Note - this weighting function is different to the .weighted method contained in xarray in that xarray's

22 method does not allow NaNs to be present in the weights or data.

23 """

24

25 if weights is not None:

26 result = values * weights

27 return result

28

29 return values

30

31

32 def create_latitude_weights(latitudes):

33 """

34 A common way of weighting errors is to make them proportional to the amount of area

35 which is contained in a particular region. This is approximated by the cosine

36 of the latitude on an LLXY grid. Nuances not accounted for include the variation in

37 latitude across the region, or the irregularity of the surface of the earth.

38

39 Returns:

40 An xarray containing the weight values to be used for area approximation

41

42 Args:

43 An xarray (or castable type) containing latitudes between +90 and -90 degrees

44

45 Note - floating point behaviour can vary between systems, precisions and other factors

46 """

47 weights = np.cos(np.deg2rad(latitudes))

48 return weights

49

50

51# Dataset input types lead to a Dataset return type

52@overload

53 def angular_difference(source_a: xr.Dataset, source_b: xr.Dataset) -> xr.Dataset:

54 ...

55

56

57# DataArray input types lead to a DataArray return type

58@overload

59 def angular_difference(source_a: xr.DataArray, source_b: xr.DataArray) -> xr.DataArray:

60 ...

61

62

63 def angular_difference(source_a: XarrayLike, source_b: XarrayLike) -> XarrayLike:

64 """

65 Determines, in degrees, the smaller of the two explementary angles between

66 two sources of directional data (e.g. wind direction).

67

68 Args:

69 source_a: direction data in degrees, first source

70 source_b: direction data in degrees, second source

71

72 Returns:

73 An array containing angles within the range [0, 180].

74 """

75 difference = np.abs(source_a - source_b) % 360

76 difference = difference.where(difference <= 180, 360 - difference)

77 return difference