Coverage for recovery/tests/test_meng2015.py: 100%

1"""Define the unit tests for the :mod:`colour.recovery.meng2015` module."""

2

3 from __future__ import annotations

4

5 import numpy as np

6 import pytest

7

8 from colour.colorimetry import (

9 MSDS_CMFS,

10 SDS_ILLUMINANTS,

11 SpectralShape,

12 reshape_msds,

13 reshape_sd,

14 sd_to_XYZ_integration,

15)

16 from colour.constants import TOLERANCE_ABSOLUTE_TESTS

17 from colour.recovery import XYZ_to_sd_Meng2015

18 from colour.utilities import domain_range_scale, is_scipy_installed

19

20 __author__ = "Colour Developers"

21 __copyright__ = "Copyright 2013 Colour Developers"

22 __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"

23 __maintainer__ = "Colour Developers"

24 __email__ = "colour-developers@colour-science.org"

25 __status__ = "Production"

26

27 __all__ = [

28 "TestXYZ_to_sd_Meng2015",

29]

30

31

32 class TestXYZ_to_sd_Meng2015:

33 """

34 Define :func:`colour.recovery.meng2015.XYZ_to_sd_Meng2015` definition unit

35 tests methods.

36 """

37

38 def setup_method(self) -> None:

39 """Initialise the common tests attributes."""

40

41 self._cmfs = reshape_msds(

42 MSDS_CMFS["CIE 1931 2 Degree Standard Observer"],

43 SpectralShape(360, 780, 10),

44 )

45 self._sd_D65 = reshape_sd(SDS_ILLUMINANTS["D65"], self._cmfs.shape)

46 self._sd_E = reshape_sd(SDS_ILLUMINANTS["E"], self._cmfs.shape)

47

48 def test_XYZ_to_sd_Meng2015(self) -> None:

49 """Test :func:`colour.recovery.meng2015.XYZ_to_sd_Meng2015` definition."""

50

51 if not is_scipy_installed(): # pragma: no cover

52 return

53

54 XYZ = np.array([0.20654008, 0.12197225, 0.05136952])

55 np.testing.assert_allclose(

56 sd_to_XYZ_integration(

57 XYZ_to_sd_Meng2015(XYZ, self._cmfs, self._sd_D65),

58 self._cmfs,

59 self._sd_D65,

60 )

61 / 100,

62 XYZ,

63 atol=TOLERANCE_ABSOLUTE_TESTS,

64 )

65

66 np.testing.assert_allclose(

67 sd_to_XYZ_integration(

68 XYZ_to_sd_Meng2015(XYZ, self._cmfs, self._sd_E),

69 self._cmfs,

70 self._sd_E,

71 )

72 / 100,

73 XYZ,

74 atol=TOLERANCE_ABSOLUTE_TESTS,

75 )

76

77 np.testing.assert_allclose(

78 sd_to_XYZ_integration(

79 XYZ_to_sd_Meng2015(

80 XYZ,

81 self._cmfs,

82 self._sd_D65,

83 optimisation_kwargs={

84 "options": {

85 "ftol": 1e-10,

86 }

87 },

88 ),

89 self._cmfs,

90 self._sd_D65,

91 )

92 / 100,

93 XYZ,

94 atol=TOLERANCE_ABSOLUTE_TESTS,

95 )

96

97 shape = SpectralShape(400, 700, 5)

98 cmfs = reshape_msds(self._cmfs, shape)

99 np.testing.assert_allclose(

100 sd_to_XYZ_integration(

101 XYZ_to_sd_Meng2015(XYZ, cmfs, self._sd_D65), cmfs, self._sd_D65

102 )

103 / 100,

104 XYZ,

105 atol=TOLERANCE_ABSOLUTE_TESTS,

106 )

107

108 def test_raise_exception_XYZ_to_sd_Meng2015(self) -> None:

109 """

110 Test :func:`colour.recovery.meng2015.XYZ_to_sd_Meng2015`

111 definition raised exception.

112 """

113

114 if not is_scipy_installed(): # pragma: no cover

115 return

116

117 pytest.raises(

118 RuntimeError,

119 XYZ_to_sd_Meng2015,

120 np.array([0.0, 0.0, 1.0]),

121 optimisation_kwargs={

122 "options": {"maxiter": 10},

123 },

124 )

125

126 def test_domain_range_scale_XYZ_to_sd_Meng2015(self) -> None:

127 """

128 Test :func:`colour.recovery.meng2015.XYZ_to_sd_Meng2015` definition

129 domain and range scale support.

130 """

131

132 if not is_scipy_installed(): # pragma: no cover

133 return

134

135 XYZ_i = np.array([0.20654008, 0.12197225, 0.05136952])

136 XYZ_o = sd_to_XYZ_integration(

137 XYZ_to_sd_Meng2015(XYZ_i, self._cmfs, self._sd_D65),

138 self._cmfs,

139 self._sd_D65,

140 )

141

142 d_r = (("reference", 1, 1), ("1", 1, 0.01), ("100", 100, 1))

143 for scale, factor_a, factor_b in d_r:

144 with domain_range_scale(scale):

145 np.testing.assert_allclose(

146 sd_to_XYZ_integration(

147 XYZ_to_sd_Meng2015(XYZ_i * factor_a, self._cmfs, self._sd_D65),

148 self._cmfs,

149 self._sd_D65,

150 ),

151 XYZ_o * factor_b,

152 atol=TOLERANCE_ABSOLUTE_TESTS,

153 )