Coverage for colour/appearance/tests/test_atd95.py: 100%

66 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.appearance.atd95` module.""" 

2 

3from __future__ import annotations 

4 

5from itertools import product 

6 

7import numpy as np 

8 

9from colour.appearance import XYZ_to_ATD95 

10from colour.constants import TOLERANCE_ABSOLUTE_TESTS 

11from colour.utilities import as_float_array, domain_range_scale, ignore_numpy_errors 

12 

13__author__ = "Colour Developers" 

14__copyright__ = "Copyright 2013 Colour Developers" 

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

16__maintainer__ = "Colour Developers" 

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

18__status__ = "Production" 

19 

20__all__ = [ 

21 "TestXYZ_to_ATD95", 

22] 

23 

24 

25class TestXYZ_to_ATD95: 

26 """ 

27 Define :func:`colour.appearance.atd95.XYZ_to_ATD95` definition unit 

28 tests methods. 

29 """ 

30 

31 def test_XYZ_to_ATD95(self) -> None: 

32 """ 

33 Test :func:`colour.appearance.atd95.XYZ_to_ATD95` definition. 

34 

35 Notes 

36 ----- 

37 - The test values have been generated from data of the following file 

38 by *Fairchild (2013)*: 

39 http://rit-mcsl.org/fairchild//files/AppModEx.xls 

40 """ 

41 

42 XYZ = np.array([19.01, 20.00, 21.78]) 

43 XYZ_0 = np.array([95.05, 100.00, 108.88]) 

44 Y_02 = 318.31 

45 K_1 = 0 

46 K_2 = 50 

47 sigma = 300 

48 np.testing.assert_allclose( 

49 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

50 np.array( 

51 [ 

52 1.91, 

53 1.206, 

54 0.1814, 

55 0.1788, 

56 0.0287, 

57 0.0108, 

58 0.0192, 

59 0.0205, 

60 0.0108, 

61 ] 

62 ), 

63 atol=0.01, 

64 ) 

65 

66 XYZ = np.array([57.06, 43.06, 31.96]) 

67 Y_02 = 31.83 

68 np.testing.assert_allclose( 

69 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

70 np.array( 

71 [ 

72 63.96, 

73 1.371, 

74 0.2142, 

75 0.2031, 

76 0.068, 

77 0.0005, 

78 0.0224, 

79 0.0308, 

80 0.0005, 

81 ] 

82 ), 

83 atol=0.01, 

84 ) 

85 

86 XYZ = np.array([3.53, 6.56, 2.14]) 

87 XYZ_0 = np.array([109.85, 100.00, 35.58]) 

88 Y_02 = 318.31 

89 np.testing.assert_allclose( 

90 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

91 np.array( 

92 [ 

93 -0.31, 

94 0.436, 

95 0.1075, 

96 0.1068, 

97 -0.011, 

98 0.0044, 

99 0.0106, 

100 -0.0014, 

101 0.0044, 

102 ] 

103 ), 

104 atol=0.01, 

105 ) 

106 

107 XYZ = np.array([19.01, 20.00, 21.78]) 

108 Y_02 = 31.83 

109 np.testing.assert_allclose( 

110 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

111 np.array( 

112 [ 

113 0.79, 

114 1.091, 

115 0.1466, 

116 0.146, 

117 0.0007, 

118 0.013, 

119 0.0152, 

120 0.0102, 

121 0.013, 

122 ] 

123 ), 

124 atol=0.01, 

125 ) 

126 

127 def test_n_dimensional_XYZ_to_ATD95(self) -> None: 

128 """ 

129 Test :func:`colour.appearance.atd95.XYZ_to_ATD95` definition 

130 n-dimensional support. 

131 """ 

132 

133 XYZ = np.array([19.01, 20.00, 21.78]) 

134 XYZ_0 = np.array([95.05, 100.00, 108.88]) 

135 Y_02 = 318.31 

136 K_1 = 0 

137 K_2 = 50 

138 sigma = 300 

139 specification = XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma) 

140 

141 XYZ = np.tile(XYZ, (6, 1)) 

142 specification = np.tile(specification, (6, 1)) 

143 np.testing.assert_allclose( 

144 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

145 specification, 

146 atol=TOLERANCE_ABSOLUTE_TESTS, 

147 ) 

148 

149 XYZ_0 = np.tile(XYZ_0, (6, 1)) 

150 np.testing.assert_allclose( 

151 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

152 specification, 

153 atol=TOLERANCE_ABSOLUTE_TESTS, 

154 ) 

155 

156 XYZ = np.reshape(XYZ, (2, 3, 3)) 

157 XYZ_0 = np.reshape(XYZ_0, (2, 3, 3)) 

158 specification = np.reshape(specification, (2, 3, 9)) 

159 np.testing.assert_allclose( 

160 XYZ_to_ATD95(XYZ, XYZ_0, Y_02, K_1, K_2, sigma), 

161 specification, 

162 atol=TOLERANCE_ABSOLUTE_TESTS, 

163 ) 

164 

165 @ignore_numpy_errors 

166 def test_domain_range_scale_XYZ_to_ATD95(self) -> None: 

167 """ 

168 Test :func:`colour.appearance.atd95.XYZ_to_ATD95` definition domain 

169 and range scale support. 

170 """ 

171 

172 XYZ = np.array([19.01, 20.00, 21.78]) 

173 XYZ_0 = np.array([95.05, 100.00, 108.88]) 

174 Y_0 = 318.31 

175 k_1 = 0.0 

176 k_2 = 50.0 

177 specification = XYZ_to_ATD95(XYZ, XYZ_0, Y_0, k_1, k_2) 

178 

179 d_r = ( 

180 ("reference", 1, 1), 

181 ("1", 0.01, np.array([1 / 360, 1, 1, 1, 1, 1, 1, 1, 1])), 

182 ("100", 1, np.array([100 / 360, 1, 1, 1, 1, 1, 1, 1, 1])), 

183 ) 

184 for scale, factor_a, factor_b in d_r: 

185 with domain_range_scale(scale): 

186 np.testing.assert_allclose( 

187 XYZ_to_ATD95(XYZ * factor_a, XYZ_0 * factor_a, Y_0, k_1, k_2), 

188 as_float_array(specification) * factor_b, 

189 atol=TOLERANCE_ABSOLUTE_TESTS, 

190 ) 

191 

192 @ignore_numpy_errors 

193 def test_nan_XYZ_to_ATD95(self) -> None: 

194 """ 

195 Test :func:`colour.appearance.atd95.XYZ_to_ATD95` definition nan 

196 support. 

197 """ 

198 

199 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] 

200 cases = np.array(list(set(product(cases, repeat=3)))) 

201 XYZ_to_ATD95(cases, cases, cases[..., 0], cases[..., 0], cases[..., 0])