Coverage for appearance/tests/test_atd95.py: 100%
66 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
1"""Define the unit tests for the :mod:`colour.appearance.atd95` module."""
3from __future__ import annotations
5from itertools import product
7import numpy as np
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
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"
20__all__ = [
21 "TestXYZ_to_ATD95",
22]
25class TestXYZ_to_ATD95:
26 """
27 Define :func:`colour.appearance.atd95.XYZ_to_ATD95` definition unit
28 tests methods.
29 """
31 def test_XYZ_to_ATD95(self) -> None:
32 """
33 Test :func:`colour.appearance.atd95.XYZ_to_ATD95` definition.
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 """
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 )
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 )
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 )
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 )
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 """
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)
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 )
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 )
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 )
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 """
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)
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 )
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 """
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])