# -*- coding: utf-8 -*-
"""
Defines the unit tests for the :mod:`colour.colorimetry.luminance` module.
"""

import numpy as np
import unittest

from colour.colorimetry import (
    luminance_Newhall1943, intermediate_luminance_function_CIE1976,
    luminance_CIE1976, luminance_ASTMD1535, luminance_Fairchild2010,
    luminance_Fairchild2011, luminance_Abebe2017)
from colour.colorimetry.luminance import luminance
from colour.utilities import domain_range_scale, ignore_numpy_errors

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013-2021 - Colour Developers'
__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-developers@colour-science.org'
__status__ = 'Production'

__all__ = [
    'TestLuminanceNewhall1943', 'TestLuminanceASTMD1535',
    'TestIntermediateLuminanceFunctionCIE1976', 'TestLuminanceCIE1976',
    'TestLuminanceFairchild2010', 'TestLuminanceFairchild2011',
    'TestLuminanceAbebe2017', 'TestLuminance'
]


class TestLuminanceNewhall1943(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_Newhall1943`
    definition unit tests methods.
    """

    def test_luminance_Newhall1943(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Newhall1943`
        definition.
        """

        self.assertAlmostEqual(
            luminance_Newhall1943(4.08244375), 12.550078816731881, places=7)

        self.assertAlmostEqual(
            luminance_Newhall1943(5.39132685), 23.481252371310738, places=7)

        self.assertAlmostEqual(
            luminance_Newhall1943(2.97619312), 6.4514266875601924, places=7)

    def test_n_dimensional_luminance_Newhall1943(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Newhall1943`
        definition n-dimensional arrays support.
        """

        V = 4.08244375
        Y = luminance_Newhall1943(V)

        V = np.tile(V, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(luminance_Newhall1943(V), Y, decimal=7)

        V = np.reshape(V, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(luminance_Newhall1943(V), Y, decimal=7)

        V = np.reshape(V, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(luminance_Newhall1943(V), Y, decimal=7)

    def test_domain_range_scale_luminance_Newhall1943(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Newhall1943`
        definition domain and range scale support.
        """

        Y = luminance_Newhall1943(4.08244375)

        d_r = (('reference', 1, 1), (1, 0.1, 0.01), (100, 10, 1))
        for scale, factor_a, factor_b in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_Newhall1943(4.08244375 * factor_a),
                    Y * factor_b,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_Newhall1943(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Newhall1943`
        definition nan support.
        """

        luminance_Newhall1943(
            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestLuminanceASTMD1535(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_ASTMD1535`
    definition unit tests methods.
    """

    def test_luminance_ASTMD1535(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_ASTMD1535`
        definition.
        """

        self.assertAlmostEqual(
            luminance_ASTMD1535(4.08244375), 12.236342675366036, places=7)

        self.assertAlmostEqual(
            luminance_ASTMD1535(5.39132685), 22.893999867280378, places=7)

        self.assertAlmostEqual(
            luminance_ASTMD1535(2.97619312), 6.2902253509053132, places=7)

    def test_n_dimensional_luminance_ASTMD1535(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_ASTMD1535`
        definition n-dimensional arrays support.
        """

        V = 4.08244375
        Y = luminance_ASTMD1535(V)

        V = np.tile(V, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(luminance_ASTMD1535(V), Y, decimal=7)

        V = np.reshape(V, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(luminance_ASTMD1535(V), Y, decimal=7)

        V = np.reshape(V, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(luminance_ASTMD1535(V), Y, decimal=7)

    def test_domain_range_scale_luminance_ASTMD1535(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_ASTMD1535`
        definition domain and range scale support.
        """

        Y = luminance_ASTMD1535(4.08244375)

        d_r = (('reference', 1, 1), (1, 0.1, 0.01), (100, 10, 1))
        for scale, factor_a, factor_b in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_ASTMD1535(4.08244375 * factor_a),
                    Y * factor_b,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_ASTMD1535(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_ASTMD1535`
        definition nan support.
        """

        luminance_ASTMD1535(
            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestIntermediateLuminanceFunctionCIE1976(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.\
intermediate_luminance_function_CIE1976` definition unit tests methods.
    """

    def test_intermediate_luminance_function_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.\
intermediate_luminance_function_CIE1976` definition.
        """

        self.assertAlmostEqual(
            intermediate_luminance_function_CIE1976(0.495929964178047),
            12.197225350000002,
            places=7)

        self.assertAlmostEqual(
            intermediate_luminance_function_CIE1976(0.613072093530391),
            23.042767810000004,
            places=7)

        self.assertAlmostEqual(
            intermediate_luminance_function_CIE1976(0.394876333449113),
            6.157200790000001,
            places=7)

    def test_n_dimensional_intermediate_luminance_function_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.\
intermediate_luminance_function_CIE1976` definition n-dimensional arrays
support.
        """

        f_Y_Y_n = 0.495929964178047
        Y = intermediate_luminance_function_CIE1976(f_Y_Y_n)

        f_Y_Y_n = np.tile(f_Y_Y_n, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(
            intermediate_luminance_function_CIE1976(f_Y_Y_n), Y, decimal=7)

        f_Y_Y_n = np.reshape(f_Y_Y_n, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(
            intermediate_luminance_function_CIE1976(f_Y_Y_n), Y, decimal=7)

        f_Y_Y_n = np.reshape(f_Y_Y_n, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(
            intermediate_luminance_function_CIE1976(f_Y_Y_n), Y, decimal=7)

    def test_domain_range_scale_intermediate_luminance_function_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.\
intermediate_luminance_function_CIE1976` definition domain and range scale
support.
        """

        Y = intermediate_luminance_function_CIE1976(41.527875844653451, 100)

        for scale in ('reference', 1, 100):
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    intermediate_luminance_function_CIE1976(
                        41.527875844653451, 100),
                    Y,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_intermediate_luminance_function_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.\
intermediate_luminance_function_CIE1976` definition nan support.
        """

        intermediate_luminance_function_CIE1976(
            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestLuminanceCIE1976(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_CIE1976` definition
    unit tests methods.
    """

    def test_luminance_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_CIE1976`
        definition.
        """

        self.assertAlmostEqual(
            luminance_CIE1976(41.527875844653451),
            12.197225350000002,
            places=7)

        self.assertAlmostEqual(
            luminance_CIE1976(55.116362849525402),
            23.042767810000004,
            places=7)

        self.assertAlmostEqual(
            luminance_CIE1976(29.805654680097106), 6.157200790000001, places=7)

        self.assertAlmostEqual(
            luminance_CIE1976(56.480581732417676, 50),
            12.197225349999998,
            places=7)

        self.assertAlmostEqual(
            luminance_CIE1976(47.317620274162735, 75),
            12.197225350000002,
            places=7)

        self.assertAlmostEqual(
            luminance_CIE1976(42.519930728120940, 95),
            12.197225350000005,
            places=7)

    def test_n_dimensional_luminance_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_CIE1976`
        definition n-dimensional arrays support.
        """

        L_star = 41.527875844653451
        Y = luminance_CIE1976(L_star)

        L_star = np.tile(L_star, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(luminance_CIE1976(L_star), Y, decimal=7)

        L_star = np.reshape(L_star, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(luminance_CIE1976(L_star), Y, decimal=7)

        L_star = np.reshape(L_star, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(luminance_CIE1976(L_star), Y, decimal=7)

    def test_domain_range_scale_luminance_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_CIE1976`
        definition domain and range scale support.
        """

        Y = luminance_CIE1976(41.527875844653451, 100)

        d_r = (('reference', 1), (1, 0.01), (100, 1))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_CIE1976(41.527875844653451 * factor, 100),
                    Y * factor,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_CIE1976(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_CIE1976`
        definition nan support.
        """

        luminance_CIE1976(np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestLuminanceFairchild2010(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_Fairchild2010`
    definition unit tests methods.
    """

    def test_luminance_Fairchild2010(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2010`
        definition.
        """

        self.assertAlmostEqual(
            luminance_Fairchild2010(31.996390226262736),
            0.12197225350000002,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2010(60.203153682783302),
            0.23042767809999998,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2010(11.836517240976489),
            0.06157200790000001,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2010(24.424283249379986, 2.75),
            0.12197225350000002,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2010(100.019986327374240),
            1008.00000024,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2010(100.019999997090270),
            100799.92312466,
            places=7)

    def test_n_dimensional_luminance_Fairchild2010(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2010`
        definition n-dimensional arrays support.
        """

        L_hdr = 31.996390226262736
        Y = luminance_Fairchild2010(L_hdr)

        L_hdr = np.tile(L_hdr, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(
            luminance_Fairchild2010(L_hdr), Y, decimal=7)

        L_hdr = np.reshape(L_hdr, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(
            luminance_Fairchild2010(L_hdr), Y, decimal=7)

        L_hdr = np.reshape(L_hdr, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(
            luminance_Fairchild2010(L_hdr), Y, decimal=7)

    def test_domain_range_scale_luminance_Fairchild2010(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2010`
        definition domain and range scale support.
        """

        Y = luminance_Fairchild2010(31.996390226262736)

        d_r = (('reference', 1, 1), (1, 0.01, 1), (100, 1, 100))
        for scale, factor_a, factor_b in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_Fairchild2010(31.996390226262736 * factor_a),
                    Y * factor_b,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_Fairchild2010(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2010`
        definition nan support.
        """

        luminance_Fairchild2010(
            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestLuminanceFairchild2011(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_Fairchild2011`
    definition unit tests methods.
    """

    def test_luminance_Fairchild2011(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2011`
        definition.
        """

        self.assertAlmostEqual(
            luminance_Fairchild2011(51.852958445912506),
            0.12197225350000007,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2011(65.275207956353853),
            0.23042767809999998,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2011(39.818935510715917),
            0.061572007900000038,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2011(0.13268968410139345, 2.75),
            0.12197225350000002,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2011(234.72925681957565),
            1008.00000000,
            places=7)

        self.assertAlmostEqual(
            luminance_Fairchild2011(245.57059778237573),
            100800.00000000,
            places=7)

    def test_n_dimensional_luminance_Fairchild2011(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2011`
        definition n-dimensional arrays support.
        """

        L_hdr = 51.852958445912506
        Y = luminance_Fairchild2011(L_hdr)

        L_hdr = np.tile(L_hdr, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(
            luminance_Fairchild2011(L_hdr), Y, decimal=7)

        L_hdr = np.reshape(L_hdr, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(
            luminance_Fairchild2011(L_hdr), Y, decimal=7)

        L_hdr = np.reshape(L_hdr, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(
            luminance_Fairchild2011(L_hdr), Y, decimal=7)

    def test_domain_range_scale_luminance_Fairchild2011(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2011`
        definition domain and range scale support.
        """

        Y = luminance_Fairchild2011(26.459509817572265)

        d_r = (('reference', 1, 1), (1, 0.01, 1), (100, 1, 100))
        for scale, factor_a, factor_b in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_Fairchild2011(26.459509817572265 * factor_a),
                    Y * factor_b,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_Fairchild2011(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Fairchild2011`
        definition nan support.
        """

        luminance_Fairchild2011(
            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))


class TestLuminanceAbebe2017(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance_Abebe2017`
    definition unit tests methods.
    """

    def test_luminance_Abebe2017(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Abebe2017`
        definition.
        """

        self.assertAlmostEqual(
            luminance_Abebe2017(0.486955571109229),
            12.197225350000004,
            places=7)

        self.assertAlmostEqual(
            luminance_Abebe2017(0.474544792145434, method='Stevens'),
            12.197225350000025,
            places=7)

        self.assertAlmostEqual(
            luminance_Abebe2017(0.286847428534793, 1000),
            12.197225350000046,
            places=7)

        self.assertAlmostEqual(
            luminance_Abebe2017(0.192145492588158, 4000),
            12.197225350000121,
            places=7)

        self.assertAlmostEqual(
            luminance_Abebe2017(0.170365211220992, 4000, method='Stevens'),
            12.197225349999933,
            places=7)

    def test_n_dimensional_luminance_Abebe2017(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Abebe2017`
        definition n-dimensional arrays support.
        """

        L = 0.486955571109229
        Y = luminance_Abebe2017(L)

        L = np.tile(L, 6)
        Y = np.tile(Y, 6)
        np.testing.assert_almost_equal(luminance_Abebe2017(L), Y, decimal=7)

        L = np.reshape(L, (2, 3))
        Y = np.reshape(Y, (2, 3))
        np.testing.assert_almost_equal(luminance_Abebe2017(L), Y, decimal=7)

        L = np.reshape(L, (2, 3, 1))
        Y = np.reshape(Y, (2, 3, 1))
        np.testing.assert_almost_equal(luminance_Abebe2017(L), Y, decimal=7)

    def test_domain_range_scale_luminance_Abebe2017(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Abebe2017`
        definition domain and range scale support.
        """

        L = luminance_Abebe2017(0.486955571109229)

        d_r = (('reference', 1), (1, 1), (100, 1))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    luminance_Abebe2017(0.486955571109229 * factor,
                                        100 * factor),
                    L * factor,
                    decimal=7)

    @ignore_numpy_errors
    def test_nan_luminance_Abebe2017(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance_Abebe2017`
        definition nan support.
        """

        luminance_Abebe2017(
            *[np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])] * 2)


class TestLuminance(unittest.TestCase):
    """
    Defines :func:`colour.colorimetry.luminance.luminance` definition unit
    tests methods.
    """

    def test_domain_range_scale_luminance(self):
        """
        Tests :func:`colour.colorimetry.luminance.luminance` definition
        domain and range scale support.
        """

        m = ('Newhall 1943', 'ASTM D1535', 'CIE 1976', 'Fairchild 2010',
             'Fairchild 2011', 'Abebe 2017')
        v = [luminance(41.527875844653451, method, Y_n=100) for method in m]

        d_r = (('reference', 1), (1, 0.01), (100, 1))
        for method, value in zip(m, v):
            for scale, factor in d_r:
                with domain_range_scale(scale):
                    np.testing.assert_almost_equal(
                        luminance(
                            41.527875844653451 * factor, method, Y_n=100),
                        value * factor,
                        decimal=7)


if __name__ == '__main__':
    unittest.main()
