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

36 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

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

2 

3from __future__ import annotations 

4 

5import numpy as np 

6import pytest 

7 

8from colour.colorimetry import ( 

9 MSDS_CMFS, 

10 SDS_ILLUMINANTS, 

11 SpectralShape, 

12 reshape_msds, 

13 reshape_sd, 

14 sd_to_XYZ_integration, 

15) 

16from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

17from colour.recovery import XYZ_to_sd_Meng2015 

18from 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 

32class 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 )