Coverage for volume/tests/test_spectrum.py: 100%
45 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.volume.spectrum` module."""
3from __future__ import annotations
5from itertools import product
7import numpy as np
9from colour.colorimetry import (
10 MSDS_CMFS,
11 SPECTRAL_SHAPE_DEFAULT,
12 SpectralShape,
13 reshape_msds,
14)
15from colour.constants import TOLERANCE_ABSOLUTE_TESTS
16from colour.utilities import ignore_numpy_errors, is_scipy_installed
17from colour.volume import (
18 XYZ_outer_surface,
19 generate_pulse_waves,
20 is_within_visible_spectrum,
21)
23__author__ = "Colour Developers"
24__copyright__ = "Copyright 2013 Colour Developers"
25__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
26__maintainer__ = "Colour Developers"
27__email__ = "colour-developers@colour-science.org"
28__status__ = "Production"
30__all__ = [
31 "TestGeneratePulseWaves",
32 "TestXYZOuterSurface",
33 "TestIsWithinVisibleSpectrum",
34]
37class TestGeneratePulseWaves:
38 """
39 Define :func:`colour.volume.spectrum.generate_pulse_waves`
40 definition unit tests methods.
41 """
43 def test_generate_pulse_waves(self) -> None:
44 """
45 Test :func:`colour.volume.spectrum.generate_pulse_waves`
46 definition.
47 """
49 np.testing.assert_array_equal(
50 generate_pulse_waves(5),
51 np.array(
52 [
53 [0.0, 0.0, 0.0, 0.0, 0.0],
54 [1.0, 0.0, 0.0, 0.0, 0.0],
55 [0.0, 1.0, 0.0, 0.0, 0.0],
56 [0.0, 0.0, 1.0, 0.0, 0.0],
57 [0.0, 0.0, 0.0, 1.0, 0.0],
58 [0.0, 0.0, 0.0, 0.0, 1.0],
59 [1.0, 1.0, 0.0, 0.0, 0.0],
60 [0.0, 1.0, 1.0, 0.0, 0.0],
61 [0.0, 0.0, 1.0, 1.0, 0.0],
62 [0.0, 0.0, 0.0, 1.0, 1.0],
63 [1.0, 0.0, 0.0, 0.0, 1.0],
64 [1.0, 1.0, 1.0, 0.0, 0.0],
65 [0.0, 1.0, 1.0, 1.0, 0.0],
66 [0.0, 0.0, 1.0, 1.0, 1.0],
67 [1.0, 0.0, 0.0, 1.0, 1.0],
68 [1.0, 1.0, 0.0, 0.0, 1.0],
69 [1.0, 1.0, 1.0, 1.0, 0.0],
70 [0.0, 1.0, 1.0, 1.0, 1.0],
71 [1.0, 0.0, 1.0, 1.0, 1.0],
72 [1.0, 1.0, 0.0, 1.0, 1.0],
73 [1.0, 1.0, 1.0, 0.0, 1.0],
74 [1.0, 1.0, 1.0, 1.0, 1.0],
75 ]
76 ),
77 )
79 np.testing.assert_array_equal(
80 generate_pulse_waves(5, "Pulse Wave Width"),
81 np.array(
82 [
83 [0.0, 0.0, 0.0, 0.0, 0.0],
84 [1.0, 0.0, 0.0, 0.0, 0.0],
85 [1.0, 1.0, 0.0, 0.0, 0.0],
86 [1.0, 1.0, 0.0, 0.0, 1.0],
87 [1.0, 1.0, 1.0, 0.0, 1.0],
88 [0.0, 1.0, 0.0, 0.0, 0.0],
89 [0.0, 1.0, 1.0, 0.0, 0.0],
90 [1.0, 1.0, 1.0, 0.0, 0.0],
91 [1.0, 1.0, 1.0, 1.0, 0.0],
92 [0.0, 0.0, 1.0, 0.0, 0.0],
93 [0.0, 0.0, 1.0, 1.0, 0.0],
94 [0.0, 1.0, 1.0, 1.0, 0.0],
95 [0.0, 1.0, 1.0, 1.0, 1.0],
96 [0.0, 0.0, 0.0, 1.0, 0.0],
97 [0.0, 0.0, 0.0, 1.0, 1.0],
98 [0.0, 0.0, 1.0, 1.0, 1.0],
99 [1.0, 0.0, 1.0, 1.0, 1.0],
100 [0.0, 0.0, 0.0, 0.0, 1.0],
101 [1.0, 0.0, 0.0, 0.0, 1.0],
102 [1.0, 0.0, 0.0, 1.0, 1.0],
103 [1.0, 1.0, 0.0, 1.0, 1.0],
104 [1.0, 1.0, 1.0, 1.0, 1.0],
105 ]
106 ),
107 )
109 np.testing.assert_equal(
110 np.sort(generate_pulse_waves(5), axis=0),
111 np.sort(generate_pulse_waves(5, "Pulse Wave Width"), axis=0),
112 )
114 np.testing.assert_array_equal(
115 generate_pulse_waves(5, "Pulse Wave Width", True),
116 np.array(
117 [
118 [0.0, 0.0, 0.0, 0.0, 0.0],
119 [1.0, 0.0, 0.0, 0.0, 0.0],
120 [1.0, 1.0, 0.0, 0.0, 1.0],
121 [0.0, 1.0, 0.0, 0.0, 0.0],
122 [1.0, 1.0, 1.0, 0.0, 0.0],
123 [0.0, 0.0, 1.0, 0.0, 0.0],
124 [0.0, 1.0, 1.0, 1.0, 0.0],
125 [0.0, 0.0, 0.0, 1.0, 0.0],
126 [0.0, 0.0, 1.0, 1.0, 1.0],
127 [0.0, 0.0, 0.0, 0.0, 1.0],
128 [1.0, 0.0, 0.0, 1.0, 1.0],
129 [1.0, 1.0, 1.0, 1.0, 1.0],
130 ]
131 ),
132 )
135class TestXYZOuterSurface:
136 """
137 Define :func:`colour.volume.spectrum.XYZ_outer_surface`
138 definition unit tests methods.
139 """
141 def test_XYZ_outer_surface(self) -> None:
142 """
143 Test :func:`colour.volume.spectrum.XYZ_outer_surface`
144 definition.
145 """
147 shape = SpectralShape(
148 SPECTRAL_SHAPE_DEFAULT.start, SPECTRAL_SHAPE_DEFAULT.end, 84
149 )
150 cmfs = MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]
152 np.testing.assert_allclose(
153 XYZ_outer_surface(reshape_msds(cmfs, shape)),
154 np.array(
155 [
156 [0.00000000e00, 0.00000000e00, 0.00000000e00],
157 [9.63613812e-05, 2.90567768e-06, 4.49612264e-04],
158 [2.59105294e-01, 2.10312980e-02, 1.32074689e00],
159 [1.05610219e-01, 6.20382435e-01, 3.54235713e-02],
160 [7.26479803e-01, 3.54608696e-01, 2.10051491e-04],
161 [1.09718745e-02, 3.96354538e-03, 0.00000000e00],
162 [3.07925724e-05, 1.11197622e-05, 0.00000000e00],
163 [2.59201656e-01, 2.10342037e-02, 1.32119651e00],
164 [3.64715514e-01, 6.41413733e-01, 1.35617047e00],
165 [8.32090022e-01, 9.74991131e-01, 3.56336228e-02],
166 [7.37451677e-01, 3.58572241e-01, 2.10051491e-04],
167 [1.10026671e-02, 3.97466514e-03, 0.00000000e00],
168 [1.27153954e-04, 1.40254398e-05, 4.49612264e-04],
169 [3.64811875e-01, 6.41416639e-01, 1.35662008e00],
170 [1.09119532e00, 9.96022429e-01, 1.35638052e00],
171 [8.43061896e-01, 9.78954677e-01, 3.56336228e-02],
172 [7.37482470e-01, 3.58583361e-01, 2.10051491e-04],
173 [1.10990285e-02, 3.97757082e-03, 4.49612264e-04],
174 [2.59232448e-01, 2.10453234e-02, 1.32119651e00],
175 [1.09129168e00, 9.96025335e-01, 1.35683013e00],
176 [1.10216719e00, 9.99985975e-01, 1.35638052e00],
177 [8.43092689e-01, 9.78965796e-01, 3.56336228e-02],
178 [7.37578831e-01, 3.58586267e-01, 6.59663755e-04],
179 [2.70204323e-01, 2.50088688e-02, 1.32119651e00],
180 [3.64842668e-01, 6.41427759e-01, 1.35662008e00],
181 [1.10226355e00, 9.99988880e-01, 1.35683013e00],
182 [1.10219798e00, 9.99997094e-01, 1.35638052e00],
183 [8.43189050e-01, 9.78968702e-01, 3.60832350e-02],
184 [9.96684125e-01, 3.79617565e-01, 1.32140656e00],
185 [3.75814542e-01, 6.45391304e-01, 1.35662008e00],
186 [1.09132247e00, 9.96036455e-01, 1.35683013e00],
187 [1.10229434e00, 1.00000000e00, 1.35683013e00],
188 ]
189 ),
190 atol=TOLERANCE_ABSOLUTE_TESTS,
191 )
194class TestIsWithinVisibleSpectrum:
195 """
196 Define :func:`colour.volume.spectrum.is_within_visible_spectrum`
197 definition unit tests methods.
198 """
200 def test_is_within_visible_spectrum(self) -> None:
201 """
202 Test :func:`colour.volume.spectrum.is_within_visible_spectrum`
203 definition.
204 """
206 if not is_scipy_installed(): # pragma: no cover
207 return
209 assert is_within_visible_spectrum(np.array([0.3205, 0.4131, 0.5100]))
211 assert not is_within_visible_spectrum(np.array([-0.0005, 0.0031, 0.0010]))
213 assert is_within_visible_spectrum(np.array([0.4325, 0.3788, 0.1034]))
215 assert not is_within_visible_spectrum(np.array([0.0025, 0.0088, 0.0340]))
217 def test_n_dimensional_is_within_visible_spectrum(self) -> None:
218 """
219 Test :func:`colour.volume.spectrum.is_within_visible_spectrum`
220 definition n-dimensional arrays support.
221 """
223 if not is_scipy_installed(): # pragma: no cover
224 return
226 a = np.array([0.3205, 0.4131, 0.5100])
227 b = is_within_visible_spectrum(a)
229 a = np.tile(a, (6, 1))
230 b = np.tile(b, 6)
231 np.testing.assert_allclose(is_within_visible_spectrum(a), b)
233 a = np.reshape(a, (2, 3, 3))
234 b = np.reshape(b, (2, 3))
235 np.testing.assert_allclose(is_within_visible_spectrum(a), b)
237 @ignore_numpy_errors
238 def test_nan_is_within_visible_spectrum(self) -> None:
239 """
240 Test :func:`colour.volume.spectrum.is_within_visible_spectrum`
241 definition nan support.
242 """
244 if not is_scipy_installed(): # pragma: no cover
245 return
247 cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
248 cases = np.array(list(set(product(cases, repeat=3))))
249 is_within_visible_spectrum(cases)