Repository: colour-science/colour

Issue:
Implement support for "hdr-CIELab" and "hdr-IPT" colourspaces.
References
-----------

- http://www.ingentaconnect.com/content/ist/cic/2010/00002010/00000001/art00057?crawler=true
- https://www.youtube.com/watch?v=fjt7VHarVu4

Discussion:

Patch:
diff --git a/colour/__init__.py b/colour/__init__.py
index 9a861e285..e8b3fec8d 100644
--- a/colour/__init__.py
+++ b/colour/__init__.py
@@ -13,6 +13,7 @@ Subpackages
 -   adaptation: Chromatic adaptation models and transformations.
 -   algebra: Algebra utilities.
 -   appearance: Colour appearance models.
+-   biochemistry: Biochemistry computations.
 -   characterisation: Colour fitting and camera characterisation.
 -   colorimetry: Core objects for colour computations.
 -   constants: *CIE* and *CODATA* constants.
@@ -40,6 +41,8 @@ from .adaptation import *  # noqa
 from . import adaptation  # noqa
 from .algebra import *  # noqa
 from . import algebra  # noqa
+from .biochemistry import *  # noqa
+from . import biochemistry  # noqa
 from .colorimetry import *  # noqa
 from . import colorimetry  # noqa
 from .appearance import *  # noqa
@@ -80,6 +83,7 @@ __all__ = []
 __all__ += utilities.__all__
 __all__ += adaptation.__all__
 __all__ += algebra.__all__
+__all__ += biochemistry.__all__
 __all__ += colorimetry.__all__
 __all__ += appearance.__all__
 __all__ += constants.__all__
diff --git a/colour/biochemistry/__init__.py b/colour/biochemistry/__init__.py
new file mode 100644
index 000000000..3ab70e5e2
--- /dev/null
+++ b/colour/biochemistry/__init__.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+
+from .michaelis_menten import (
+    reaction_rate_MichealisMenten,
+    substrate_concentration_MichealisMenten)
+
+__all__ = []
+__all__ += ['reaction_rate_MichealisMenten',
+            'substrate_concentration_MichealisMenten']
diff --git a/colour/biochemistry/michaelis_menten.py b/colour/biochemistry/michaelis_menten.py
new file mode 100644
index 000000000..48b5d172a
--- /dev/null
+++ b/colour/biochemistry/michaelis_menten.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Michaelis–Menten Kinetics
+=========================
+
+Implements support for *Michaelis–Menten* kinetics, a model of enzyme kinetics:
+
+-   :func:`reaction_rate_MichealisMenten`
+-   :func:`substrate_concentration_MichealisMenten`
+
+References
+----------
+.. [1]  Wikipedia. (n.d.). Michaelis–Menten kinetics. Retrieved April 29, 2017,
+        from https://en.wikipedia.org/wiki/Michaelis–Menten_kinetics
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['reaction_rate_MichealisMenten',
+           'substrate_concentration_MichealisMenten']
+
+
+def reaction_rate_MichealisMenten(S, V_max, K_m):
+    """
+    Describes the rate of enzymatic reactions, by relating reaction rate
+    :math:`v` to concentration of a substrate :math:`S`.
+
+    Parameters
+    ----------
+    S : array_like
+        Concentration of a substrate :math:`S`.
+    V_max : array_like
+        Maximum rate :math:`V_{max}` achieved by the system, at saturating
+        substrate concentration.
+    K_m : array_like
+        Substrate concentration :math:`V_{max}` at which the reaction rate is
+        half of :math:`V_{max}`.
+
+    Returns
+    -------
+    array_like
+        Reaction rate :math:`v`.
+
+    Examples
+    --------
+    >>> reaction_rate_MichealisMenten(0.5, 2.5, 0.8)  # doctest: +ELLIPSIS
+    0.9615384...
+    """
+
+    S = np.asarray(S)
+    V_max = np.asarray(V_max)
+    K_m = np.asarray(K_m)
+
+    v = (V_max * S) / (K_m + S)
+
+    return v
+
+
+def substrate_concentration_MichealisMenten(v, V_max, K_m):
+    """
+    Describes the rate of enzymatic reactions, by relating concentration of a
+    substrate :math:`S` to reaction rate :math:`v`.
+
+    Parameters
+    ----------
+    v : array_like
+        Reaction rate :math:`v`.
+    V_max : array_like
+        Maximum rate :math:`V_{max}` achieved by the system, at saturating
+        substrate concentration.
+    K_m : array_like
+        Substrate concentration :math:`V_{max}` at which the reaction rate is
+        half of :math:`V_{max}`.
+
+    Returns
+    -------
+    array_like
+        Concentration of a substrate :math:`S`.
+
+    Examples
+    --------
+    >>> substrate_concentration_MichealisMenten(
+    ...     0.961538461538461, 2.5, 0.8)  # doctest: +ELLIPSIS
+    0.4999999...
+    """
+
+    v = np.asarray(v)
+    V_max = np.asarray(V_max)
+    K_m = np.asarray(K_m)
+
+    S = (v * K_m) / (V_max - v)
+
+    return S
diff --git a/colour/colorimetry/__init__.py b/colour/colorimetry/__init__.py
index d9bfe21e7..6b133de94 100644
--- a/colour/colorimetry/__init__.py
+++ b/colour/colorimetry/__init__.py
@@ -37,13 +37,15 @@ from .lightness import lightness
 from .lightness import (
     lightness_Glasser1958,
     lightness_Wyszecki1963,
-    lightness_CIE1976)
+    lightness_CIE1976,
+    lightness_Fairchild2010)
 from .luminance import LUMINANCE_METHODS
 from .luminance import luminance
 from .luminance import (
     luminance_Newhall1943,
     luminance_ASTMD153508,
-    luminance_CIE1976)
+    luminance_CIE1976,
+    luminance_Fairchild2010)
 from .dominant import (
     dominant_wavelength,
     complementary_wavelength,
@@ -111,12 +113,14 @@ __all__ += ['LIGHTNESS_METHODS']
 __all__ += ['lightness']
 __all__ += ['lightness_Glasser1958',
             'lightness_Wyszecki1963',
-            'lightness_CIE1976']
+            'lightness_CIE1976',
+            'lightness_Fairchild2010']
 __all__ += ['LUMINANCE_METHODS']
 __all__ += ['luminance']
 __all__ += ['luminance_Newhall1943',
             'luminance_ASTMD153508',
-            'luminance_CIE1976']
+            'luminance_CIE1976',
+            'luminance_Fairchild2010']
 __all__ += ['dominant_wavelength',
             'complementary_wavelength',
             'excitation_purity',
diff --git a/colour/colorimetry/lightness.py b/colour/colorimetry/lightness.py
index f4837b5f1..9f4e944d3 100644
--- a/colour/colorimetry/lightness.py
+++ b/colour/colorimetry/lightness.py
@@ -2,20 +2,22 @@
 # -*- coding: utf-8 -*-
 
 """
-Lightness :math:`L^*`
-=====================
+Lightness :math:`L`
+===================
 
-Defines *Lightness* :math:`L^*` computation objects.
+Defines *Lightness* :math:`L` computation objects.
 
 The following methods are available:
 
--   :func:`lightness_Glasser1958`: *Lightness* :math:`L^*` computation of given
-    *luminance* :math:`Y` using *Glasser, Mckinney, Reilly and Schnelle (1958)
-    method*.
+-   :func:`lightness_Glasser1958`: *Lightness* :math:`L` computation of given
+    *luminance* :math:`Y` using *Glasser, Mckinney, Reilly and Schnelle (1958)*
+    method.
 -   :func:`lightness_Wyszecki1963`: *Lightness* :math:`W` computation of
     given *luminance* :math:`Y` using *Wyszecki (1963)⁠⁠⁠⁠* method.
 -   :func:`lightness_CIE1976`: *Lightness* :math:`L^*` computation of given
     *luminance* :math:`Y` as per *CIE 1976* recommendation.
+-   :func:`lightness_Fairchild2010`: *Lightness* :math:`L_{hdr}` computation
+    of given *luminance* :math:`Y` using *Fairchild and Wyble (2010)* method.
 
 See Also
 --------
@@ -33,6 +35,7 @@ from __future__ import division, unicode_literals
 
 import numpy as np
 
+from colour.biochemistry import reaction_rate_MichealisMenten
 from colour.constants import CIE_E, CIE_K
 from colour.utilities import CaseInsensitiveMapping, filter_kwargs, warning
 
@@ -46,6 +49,7 @@ __status__ = 'Production'
 __all__ = ['lightness_Glasser1958',
            'lightness_Wyszecki1963',
            'lightness_CIE1976',
+           'lightness_Fairchild2010',
            'LIGHTNESS_METHODS',
            'lightness']
 
@@ -182,15 +186,63 @@ def lightness_CIE1976(Y, Y_n=100):
     return Lstar
 
 
+def lightness_Fairchild2010(Y, epsilon=2):
+    """
+    Computes *Lightness* :math:`L_{hdr}` of given *luminance* :math:`Y` using
+    *Fairchild and Wyble (2010)* method accordingly to *Michealis-Menten*
+    kinetics.
+
+    Parameters
+    ----------
+    Y : array_like
+        *luminance* :math:`Y`.
+    epsilon : numeric or array_like, optional
+        :math:`\epsilon` exponent.
+
+    Returns
+    -------
+    array_like
+        *Lightness* :math:`L_{hdr}`.
+
+    Warning
+    -------
+    The input domain of that definition is non standard!
+
+    Notes
+    -----
+    -   Input *luminance* :math:`Y` is in domain [0, :math:`\infty`].
+
+    References
+    ----------
+    .. [6]  Fairchild, M. D., & Wyble, D. R. (2010). hdr-CIELAB and hdr-IPT:
+            Simple Models for Describing the Color of High-Dynamic-Range and
+            Wide-Color-Gamut Images. In Proc. of Color and Imaging Conference
+            (pp. 322–326). ISBN:9781629932156
+
+    Examples
+    --------
+    >>> lightness_Fairchild2010(10.08 / 100, 1.836)  # doctest: +ELLIPSIS
+    24.9022902...
+    """
+
+    Y = np.asarray(Y)
+
+    L_hdr = reaction_rate_MichealisMenten(
+        Y ** epsilon, 100, 0.184 ** epsilon) + 0.02
+
+    return L_hdr
+
+
 LIGHTNESS_METHODS = CaseInsensitiveMapping(
     {'Glasser 1958': lightness_Glasser1958,
      'Wyszecki 1963': lightness_Wyszecki1963,
-     'CIE 1976': lightness_CIE1976})
+     'CIE 1976': lightness_CIE1976,
+     'Fairchild 2010': lightness_Fairchild2010})
 """
 Supported *Lightness* computations methods.
 
 LIGHTNESS_METHODS : CaseInsensitiveMapping
-    **{'Glasser 1958', 'Wyszecki 1963', 'CIE 1976'}**
+    **{'Glasser 1958', 'Wyszecki 1963', 'CIE 1976', 'Fairchild 2010'}**
 
 Aliases:
 
@@ -201,14 +253,14 @@ LIGHTNESS_METHODS['Lstar1976'] = LIGHTNESS_METHODS['CIE 1976']
 
 def lightness(Y, method='CIE 1976', **kwargs):
     """
-    Returns the *Lightness* :math:`L^*` using given method.
+    Returns the *Lightness* :math:`L` using given method.
 
     Parameters
     ----------
     Y : numeric or array_like
         *luminance* :math:`Y`.
     method : unicode, optional
-        **{'CIE 1976', 'Glasser 1958', 'Wyszecki 1963'}**,
+        **{'CIE 1976', 'Glasser 1958', 'Wyszecki 1963', 'Fairchild 2010'}**,
         Computation method.
 
     Other Parameters
@@ -216,17 +268,20 @@ def lightness(Y, method='CIE 1976', **kwargs):
     Y_n : numeric or array_like, optional
         {:func:`lightness_CIE1976`},
         White reference *luminance* :math:`Y_n`.
+    epsilon : numeric or array_like, optional
+        {:func:`lightness_Fairchild2010`},
+        :math:`\epsilon` exponent.
 
     Returns
     -------
     numeric or array_like
-        *Lightness* :math:`L^*`.
+        *Lightness* :math:`L`.
 
     Notes
     -----
     -   Input *luminance* :math:`Y` and optional :math:`Y_n` are in domain
-        [0, 100].
-    -   Output *Lightness* :math:`L^*` is in range [0, 100].
+        [0, 100] or [0, :math:`\infty`].
+    -   Output *Lightness* :math:`L` is in range [0, 100].
 
     Examples
     --------
@@ -240,6 +295,11 @@ def lightness(Y, method='CIE 1976', **kwargs):
     36.2505626...
     >>> lightness(10.08, method='Wyszecki 1963')  # doctest: +ELLIPSIS
     37.0041149...
+    >>> lightness(
+    ...     10.08 / 100,
+    ...     epsilon=1.836,
+    ...     method='Fairchild 2010')  # doctest: +ELLIPSIS
+    24.9022902...
     """
 
     function = LIGHTNESS_METHODS[method]
diff --git a/colour/colorimetry/luminance.py b/colour/colorimetry/luminance.py
index 323220e8a..9316e6831 100644
--- a/colour/colorimetry/luminance.py
+++ b/colour/colorimetry/luminance.py
@@ -16,6 +16,8 @@ The following methods are available:
     *Munsell* value :math:`V` using *ASTM D1535-08e1* method.
 -   :func:`luminance_CIE1976`: *luminance* :math:`Y` computation of given
     *Lightness* :math:`L^*` as per *CIE 1976* recommendation.
+-   :func:`luminance_Fairchild2010`: *luminance* :math:`Y` computation of given
+    *Lightness* :math:`L_{hdr}` using *Fairchild and Wyble (2010)* method.
 
 See Also
 --------
@@ -28,6 +30,7 @@ from __future__ import division, unicode_literals
 
 import numpy as np
 
+from colour.biochemistry import substrate_concentration_MichealisMenten
 from colour.constants import CIE_E, CIE_K
 from colour.utilities import CaseInsensitiveMapping, filter_kwargs
 
@@ -41,6 +44,7 @@ __status__ = 'Production'
 __all__ = ['luminance_Newhall1943',
            'luminance_ASTMD153508',
            'luminance_CIE1976',
+           'luminance_Fairchild2010',
            'LUMINANCE_METHODS',
            'luminance']
 
@@ -174,15 +178,64 @@ def luminance_CIE1976(Lstar, Y_n=100):
     return Y
 
 
+def luminance_Fairchild2010(L_hdr, epsilon=2):
+    """
+    Computes *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
+    *Fairchild and Wyble (2010)* method accordingly to *Michealis-Menten*
+    kinetics.
+
+    Parameters
+    ----------
+    L_hdr : array_like
+        *Lightness* :math:`L_{hdr}`.
+    epsilon : numeric or array_like, optional
+        :math:`\epsilon` exponent.
+
+    Returns
+    -------
+    array_like
+        *luminance* :math:`Y`.
+
+    Warning
+    -------
+    The output range of that definition is non standard!
+
+    Notes
+    -----
+    -   Output *luminance* :math:`Y` is in range [0, math:`\infty`].
+
+    References
+    ----------
+    .. [4]  Fairchild, M. D., & Wyble, D. R. (2010). hdr-CIELAB and hdr-IPT:
+            Simple Models for Describing the Color of High-Dynamic-Range and
+            Wide-Color-Gamut Images. In Proc. of Color and Imaging Conference
+            (pp. 322–326). ISBN:9781629932156
+
+    Examples
+    --------
+    >>> luminance_Fairchild2010(
+    ...     24.902290269546651, 1.836)  # doctest: +ELLIPSIS
+    0.1007999...
+    """
+
+    L_hdr = np.asarray(L_hdr)
+
+    Y = np.exp(np.log(substrate_concentration_MichealisMenten(
+        L_hdr - 0.02, 100, 0.184 ** epsilon)) / epsilon)
+
+    return Y
+
+
 LUMINANCE_METHODS = CaseInsensitiveMapping(
     {'Newhall 1943': luminance_Newhall1943,
      'ASTM D1535-08': luminance_ASTMD153508,
-     'CIE 1976': luminance_CIE1976})
+     'CIE 1976': luminance_CIE1976,
+     'Fairchild 2010': luminance_Fairchild2010})
 """
 Supported *luminance* computations methods.
 
 LUMINANCE_METHODS : CaseInsensitiveMapping
-    **{'Newhall 1943', 'ASTM D1535-08', 'CIE 1976'}**
+    **{'Newhall 1943', 'ASTM D1535-08', 'CIE 1976', 'Fairchild 2010'}**
 
 Aliases:
 
@@ -205,7 +258,7 @@ def luminance(LV, method='CIE 1976', **kwargs):
     LV : numeric or array_like
         *Lightness* :math:`L^*` or *Munsell* value :math:`V`.
     method : unicode, optional
-        **{'CIE 1976', 'Newhall 1943', 'ASTM D1535-08'}**,
+        **{'CIE 1976', 'Newhall 1943', 'ASTM D1535-08', 'Fairchild 2010'}**,
         Computation method.
 
     Other Parameters
@@ -213,6 +266,9 @@ def luminance(LV, method='CIE 1976', **kwargs):
     Y_n : numeric or array_like, optional
         {:func:`luminance_CIE1976`},
         White reference *luminance* :math:`Y_n`.
+    epsilon : numeric or array_like, optional
+        {:func:`lightness_Fairchild2010`},
+        :math:`\epsilon` exponent.
 
     Returns
     -------
@@ -221,9 +277,10 @@ def luminance(LV, method='CIE 1976', **kwargs):
 
     Notes
     -----
-    -   Input *LV* is in domain [0, 100] or [0, 10] and optional *luminance*
-        :math:`Y_n` is in domain [0, 100].
-    -   Output *luminance* :math:`Y` is in range [0, 100].
+    -   Input *LV* is in domain [0, 100], [0, 10] or [0, 1] and optional
+        *luminance* :math:`Y_n` is in domain [0, 100].
+    -   Output *luminance* :math:`Y` is in range [0, 100] or
+        [0, math:`\infty`].
 
     Examples
     --------
@@ -237,6 +294,11 @@ def luminance(LV, method='CIE 1976', **kwargs):
     10.4089874...
     >>> luminance(3.74629715, method='ASTM D1535-08')  # doctest: +ELLIPSIS
     10.1488096...
+    >>> luminance(
+    ...     24.902290269546651,
+    ...     epsilon=1.836,
+    ...     method='Fairchild 2010')  # doctest: +ELLIPSIS
+    0.1007999...
     """
 
     function = LUMINANCE_METHODS[method]
diff --git a/colour/examples/colorimetry/examples_lightness.py b/colour/examples/colorimetry/examples_lightness.py
index 0876d315f..0a51c834c 100644
--- a/colour/examples/colorimetry/examples_lightness.py
+++ b/colour/examples/colorimetry/examples_lightness.py
@@ -38,6 +38,14 @@ print(colour.lightness(Y, method='Wyszecki 1963'))
 
 print('\n')
 
+message_box(('Computing "Lightness" using "Fairchild and Wyble (2010)" method '
+             'for given "luminance" value:\n'
+             '\n\t{0}'.format(Y)))
+print(colour.lightness_Fairchild2010(Y / 100.0))
+print(colour.lightness(Y / 100.0, method='Fairchild 2010'))
+
+print('\n')
+
 message_box(('Computing "Lightness" using "CIE 1976" method for '
              'given "luminance" value:\n'
              '\n\t{0}'.format(Y)))
diff --git a/colour/examples/colorimetry/examples_luminance.py b/colour/examples/colorimetry/examples_luminance.py
index 48766b16f..447033a0b 100644
--- a/colour/examples/colorimetry/examples_luminance.py
+++ b/colour/examples/colorimetry/examples_luminance.py
@@ -30,6 +30,15 @@ print(colour.luminance(L))
 
 print('\n')
 
+L = 23.10363383
+message_box(('Computing "luminance" using "Fairchild and Wyble (2010)" method '
+             'for given "Lightness":\n'
+             '\n\t{0}'.format(L)))
+print(colour.luminance_Fairchild2010(L) * 100)
+print(colour.luminance(L, method='Fairchild 2010') * 100)
+
+print('\n')
+
 message_box(('Computing "luminance" using "ASTM D1535-08e1" method for given '
              '"Munsell" value:\n'
              '\n\t{0}'.format(V)))
diff --git a/colour/examples/models/examples_models.py b/colour/examples/models/examples_models.py
index 8169f0832..dad1cc90d 100644
--- a/colour/examples/models/examples_models.py
+++ b/colour/examples/models/examples_models.py
@@ -240,3 +240,31 @@ message_box(('Converting to "CIE XYZ" tristimulus values from given "IPT" '
 print(colour.IPT_to_XYZ(IPT))
 
 print('\n')
+
+message_box(('Converting to "hdr-CIELab" colourspace from given "CIE XYZ" '
+             'tristimulus values:\n'
+             '\n\t{0}'.format(XYZ)))
+print(colour.XYZ_to_hdr_CIELab(XYZ))
+
+print('\n')
+
+Lab_hdr = (95.74235944, 5.52263656, 11.72798167)
+message_box(('Converting to "CIE XYZ" tristimulus values from given '
+             '"hdr-CIELab" colourspace values:\n'
+             '\n\t{0}'.format(Lab_hdr)))
+print(colour.hdr_CIELab_to_XYZ(Lab_hdr))
+
+print('\n')
+
+message_box(('Converting to "hdr-IPT" colourspace from given "CIE XYZ" '
+             'tristimulus values:\n'
+             '\n\t{0}'.format(XYZ)))
+print(colour.XYZ_to_hdr_IPT(XYZ))
+
+print('\n')
+
+IPT_hdr = (92.21400245, 3.0073719, 14.7243821)
+message_box(('Converting to "CIE XYZ" tristimulus values from given "hdr-IPT" '
+             'colourspace values:\n'
+             '\n\t{0}'.format(IPT_hdr)))
+print(colour.hdr_IPT_to_XYZ(IPT_hdr))
diff --git a/colour/models/__init__.py b/colour/models/__init__.py
index 3594e72d9..cbb51e7c3 100644
--- a/colour/models/__init__.py
+++ b/colour/models/__init__.py
@@ -20,12 +20,14 @@ from .cie_luv import (
     LCHuv_to_Luv)
 from .cie_ucs import XYZ_to_UCS, UCS_to_XYZ, UCS_to_uv, UCS_uv_to_xy
 from .cie_uvw import XYZ_to_UVW
+from .hdr_cie_lab import XYZ_to_hdr_CIELab, hdr_CIELab_to_XYZ
 from .hunter_lab import (
     XYZ_to_K_ab_HunterLab1966,
     XYZ_to_Hunter_Lab,
     Hunter_Lab_to_XYZ)
 from .hunter_rdab import XYZ_to_Hunter_Rdab
 from .ipt import XYZ_to_IPT, IPT_to_XYZ, IPT_hue_angle
+from .hdr_ipt import XYZ_to_hdr_IPT, hdr_IPT_to_XYZ
 from .ucs_luo2006 import (
     JMh_CIECAM02_to_CAM02LCD,
     CAM02LCD_to_JMh_CIECAM02,
@@ -57,12 +59,14 @@ __all__ += ['XYZ_to_Luv',
             'LCHuv_to_Luv']
 __all__ += ['XYZ_to_UCS', 'UCS_to_XYZ', 'UCS_to_uv', 'UCS_uv_to_xy']
 __all__ += ['XYZ_to_UVW']
+__all__ += ['XYZ_to_hdr_CIELab', 'hdr_CIELab_to_XYZ']
 __all__ += ['XYZ_to_K_ab_HunterLab1966',
             'XYZ_to_Hunter_Lab',
             'Hunter_Lab_to_XYZ',
             'XYZ_to_Hunter_Rdab']
 __all__ += ['XYZ_to_Hunter_Rdab']
 __all__ += ['XYZ_to_IPT', 'IPT_to_XYZ', 'IPT_hue_angle']
+__all__ += ['XYZ_to_hdr_IPT', 'hdr_IPT_to_XYZ']
 __all__ += ['JMh_CIECAM02_to_CAM02LCD',
             'CAM02LCD_to_JMh_CIECAM02',
             'JMh_CIECAM02_to_CAM02SCD',
diff --git a/colour/models/hdr_cie_lab.py b/colour/models/hdr_cie_lab.py
new file mode 100644
index 000000000..31363b246
--- /dev/null
+++ b/colour/models/hdr_cie_lab.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+hdr-CIELAB Colourspace
+======================
+
+Defines the *hdr-CIELAB* colourspace transformations:
+
+-   :func:`XYZ_to_hdr_CIELab`
+-   :func:`hdr_CIELab_to_XYZ`
+
+See Also
+--------
+`hdr-CIELAB Colourspace Jupyter Notebook
+<http://nbviewer.jupyter.org/github/colour-science/colour-notebooks/\
+blob/master/notebooks/models/hdr_cie_lab.ipynb>`_
+
+References
+----------
+.. [1]  Fairchild, M. D., & Wyble, D. R. (2010). hdr-CIELAB and hdr-IPT:
+        Simple Models for Describing the Color of High-Dynamic-Range and
+        Wide-Color-Gamut Images. In Proc. of Color and Imaging Conference
+        (pp. 322–326). ISBN:9781629932156
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+
+from colour.colorimetry import (
+    ILLUMINANTS,
+    lightness_Fairchild2010,
+    luminance_Fairchild2010)
+from colour.models import xy_to_xyY, xyY_to_XYZ
+from colour.utilities import tsplit, tstack
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['XYZ_to_hdr_CIELab',
+           'hdr_CIELab_to_XYZ',
+           'exponent_hdr_CIELab']
+
+
+def XYZ_to_hdr_CIELab(
+        XYZ,
+        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50'],
+        Y_s=0.2,
+        Y_abs=100):
+    """
+    Converts from *CIE XYZ* tristimulus values to *hdr-CIELAB* colourspace.
+
+    Parameters
+    ----------
+    XYZ : array_like
+        *CIE XYZ* tristimulus values.
+    illuminant : array_like, optional
+        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
+        colourspace array.
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in domain [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    ndarray
+        *hdr-CIELAB* colourspace array.
+
+    Notes
+    -----
+    -   Conversion to polar coordinates to compute the *chroma* :math:`C_{hdr}`
+        and *hue* :math:`h_{hdr}` correlates can be safely performed with
+        :func:`colour.Lab_to_LCHab` definition.
+    -   Conversion to cartesian coordinates from the *Lightness*
+        :math:`L_{hdr}`, *chroma* :math:`C_{hdr}` and *hue* :math:`h_{hdr}`
+        correlates can be safely performed with :func:`colour.LCHab_to_Lab`
+        definition.
+    -   Input *CIE XYZ* tristimulus values are in domain [0, math:`\infty`].
+    -   Input *illuminant* *xy* chromaticity coordinates or *CIE xyY*
+        colourspace array are in domain [0, :math:`\infty`].
+
+    Examples
+    --------
+    >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
+    >>> XYZ_to_hdr_CIELab(XYZ)  # doctest: +ELLIPSIS
+    array([ 24.9020664..., -46.8312760..., -10.14274843])
+    """
+
+    X, Y, Z = tsplit(XYZ)
+    X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant)))
+
+    e = exponent_hdr_CIELab(Y_s, Y_abs)
+
+    L_hdr = lightness_Fairchild2010(Y / Y_n, e)
+    a_hdr = 5 * (lightness_Fairchild2010(X / X_n, e) - L_hdr)
+    b_hdr = 2 * (L_hdr - lightness_Fairchild2010(Z / Z_n, e))
+
+    Lab_hdr = tstack((L_hdr, a_hdr, b_hdr))
+
+    return Lab_hdr
+
+
+def hdr_CIELab_to_XYZ(
+        Lab_hdr,
+        illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50'],
+        Y_s=0.2,
+        Y_abs=100):
+    """
+    Converts from *hdr-CIELAB* colourspace to *CIE XYZ* tristimulus values.
+
+    Parameters
+    ----------
+    Lab_hdr : array_like
+        *hdr-CIELAB* colourspace array.
+    illuminant : array_like, optional
+        Reference *illuminant* *xy* chromaticity coordinates or *CIE xyY*
+        colourspace array.
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in domain [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    ndarray
+        *CIE XYZ* tristimulus values.
+
+    Notes
+    -----
+    -   Input *illuminant* *xy* chromaticity coordinates or *CIE xyY*
+        colourspace array are in domain [0, :math:`\infty`].
+    -   Output *CIE XYZ* tristimulus values are in range [0, math:`\infty`].
+
+    Examples
+    --------
+    >>> Lab_hdr = np.array([24.90206646, -46.83127607, -10.14274843])
+    >>> hdr_CIELab_to_XYZ(Lab_hdr)  # doctest: +ELLIPSIS
+    array([ 0.0704953...,  0.1008    ,  0.0955831...])
+    """
+
+    L_hdr, a_hdr, b_hdr = tsplit(Lab_hdr)
+    X_n, Y_n, Z_n = tsplit(xyY_to_XYZ(xy_to_xyY(illuminant)))
+
+    e = exponent_hdr_CIELab(Y_s, Y_abs)
+
+    Y = luminance_Fairchild2010(L_hdr, e) * Y_n
+    X = luminance_Fairchild2010((a_hdr + 5 * L_hdr) / 5, e) * X_n
+    Z = luminance_Fairchild2010((-b_hdr + 2 * L_hdr) / 2, e) * Z_n
+
+    XYZ = tstack((X, Y, Z))
+
+    return XYZ
+
+
+def exponent_hdr_CIELab(Y_s, Y_abs):
+    """
+    Computes *hdr-CIELAB* colourspace *Lightness* :math:`\epsilon` exponent.
+
+    Parameters
+    ----------
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in range [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    array_like
+        *hdr-CIELAB* colourspace *Lightness* :math:`\epsilon` exponent.
+
+    Examples
+    --------
+    >>> exponent_hdr_CIELab(0.2, 100)  # doctest: +ELLIPSIS
+    1.8360198...
+    """
+
+    Y_s = np.asarray(Y_s)
+    Y_abs = np.asarray(Y_abs)
+
+    lf = np.log(318) / np.log(Y_abs)
+    sf = 1.25 - 0.25 * (Y_s / 0.184)
+    epsilon = 1.50 * sf * lf
+
+    return epsilon
diff --git a/colour/models/hdr_ipt.py b/colour/models/hdr_ipt.py
new file mode 100644
index 000000000..830fd25ef
--- /dev/null
+++ b/colour/models/hdr_ipt.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+hdr-IPT Colourspace
+===================
+
+Defines the *hdr-IPT* colourspace transformations:
+
+-   :func:`XYZ_to_hdr_IPT`
+-   :func:`hdr_IPT_to_XYZ`
+
+See Also
+--------
+`hdr-IPT Colourspace Jupyter Notebook
+<http://nbviewer.jupyter.org/github/colour-science/colour-notebooks/\
+blob/master/notebooks/models/hdr_IPT.ipynb>`_
+
+References
+----------
+.. [1]  Fairchild, M. D., & Wyble, D. R. (2010). hdr-CIELAB and hdr-IPT:
+        Simple Models for Describing the Color of High-Dynamic-Range and
+        Wide-Color-Gamut Images. In Proc. of Color and Imaging Conference
+        (pp. 322–326). ISBN:9781629932156
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+
+from colour.colorimetry import lightness_Fairchild2010, luminance_Fairchild2010
+from colour.models.ipt import (
+    IPT_XYZ_TO_LMS_MATRIX,
+    IPT_LMS_TO_XYZ_MATRIX,
+    IPT_LMS_TO_IPT_MATRIX,
+    IPT_IPT_TO_LMS_MATRIX)
+from colour.utilities import dot_vector
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['XYZ_to_hdr_IPT',
+           'hdr_IPT_to_XYZ',
+           'exponent_hdr_IPT']
+
+
+def XYZ_to_hdr_IPT(XYZ, Y_s=0.2, Y_abs=100):
+    """
+    Converts from *CIE XYZ* tristimulus values to *hdr-IPT* colourspace.
+
+    Parameters
+    ----------
+    XYZ : array_like
+        *CIE XYZ* tristimulus values.
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in domain [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    ndarray
+        *hdr-IPT* colourspace array.
+
+    Notes
+    -----
+    -   Input *CIE XYZ* tristimulus values needs to be adapted for
+        *CIE Standard Illuminant D Series* *D65*.
+
+    Examples
+    --------
+    >>> XYZ = np.array([0.96907232, 1.00000000, 1.12179215])
+    >>> XYZ_to_hdr_IPT(XYZ)  # doctest: +ELLIPSIS
+    array([ 94.6592917...,   0.3804177...,  -0.2673118...])
+    """
+
+    e = exponent_hdr_IPT(Y_s, Y_abs)[..., np.newaxis]
+
+    LMS = dot_vector(IPT_XYZ_TO_LMS_MATRIX, XYZ)
+    LMS_prime = np.sign(LMS) * np.abs(lightness_Fairchild2010(LMS, e))
+    IPT = dot_vector(IPT_LMS_TO_IPT_MATRIX, LMS_prime)
+
+    return IPT
+
+
+def hdr_IPT_to_XYZ(IPT_hdr, Y_s=0.2, Y_abs=100):
+    """
+    Converts from *hdr-IPT* colourspace to *CIE XYZ* tristimulus values.
+
+    Parameters
+    ----------
+    IPT_hdr : array_like
+        *hdr-IPT* colourspace array.
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in domain [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    ndarray
+        *CIE XYZ* tristimulus values.
+
+    Examples
+    --------
+    >>> IPT_hdr = np.array([94.65929175, 0.38041773, -0.26731187])
+    >>> hdr_IPT_to_XYZ(IPT_hdr)  # doctest: +ELLIPSIS
+    array([ 0.9690723...,  1.        ,  1.1217921...])
+    """
+
+    e = exponent_hdr_IPT(Y_s, Y_abs)[..., np.newaxis]
+
+    LMS = dot_vector(IPT_IPT_TO_LMS_MATRIX, IPT_hdr)
+    LMS_prime = np.sign(LMS) * np.abs(luminance_Fairchild2010(LMS, e))
+    XYZ = dot_vector(IPT_LMS_TO_XYZ_MATRIX, LMS_prime)
+
+    return XYZ
+
+
+def exponent_hdr_IPT(Y_s, Y_abs):
+    """
+    Computes *hdr-IPT* colourspace *Lightness* :math:`\epsilon` exponent.
+
+    Parameters
+    ----------
+    Y_s : numeric or array_like
+        Relative luminance :math:`Y_s` of the surround in range [0, 1].
+    Y_abs : numeric or array_like
+        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
+        :math:`cd/m^2`.
+
+    Returns
+    -------
+    array_like
+        *hdr-IPT* colourspace *Lightness* :math:`\epsilon` exponent.
+
+    Examples
+    --------
+    >>> exponent_hdr_IPT(0.2, 100)  # doctest: +ELLIPSIS
+    1.6891383...
+    """
+
+    Y_s = np.asarray(Y_s)
+    Y_abs = np.asarray(Y_abs)
+
+    lf = np.log(318) / np.log(Y_abs)
+    sf = 1.25 - 0.25 * (Y_s / 0.184)
+    epsilon = 1.38 * sf * lf
+
+    return epsilon


Test patch:
diff --git a/colour/biochemistry/tests/__init__.py b/colour/biochemistry/tests/__init__.py
new file mode 100644
index 000000000..faa18be5b
--- /dev/null
+++ b/colour/biochemistry/tests/__init__.py
@@ -0,0 +1,2 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
diff --git a/colour/biochemistry/tests/tests_michaelis_menten.py b/colour/biochemistry/tests/tests_michaelis_menten.py
new file mode 100644
index 000000000..c56d5ef87
--- /dev/null
+++ b/colour/biochemistry/tests/tests_michaelis_menten.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Defines unit tests for :mod:`colour.biochemistry.michaelis_menten` module.
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+import unittest
+from itertools import permutations
+
+from colour.biochemistry import (
+    reaction_rate_MichealisMenten,
+    substrate_concentration_MichealisMenten)
+from colour.utilities import ignore_numpy_errors
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['TestReactionRateMichealisMenten',
+           'TestSubstrateConcentrationMichealisMenten']
+
+
+class TestReactionRateMichealisMenten(unittest.TestCase):
+    """
+    Defines :func:`colour.biochemistry.michaelis_menten.\
+reaction_rate_MichealisMenten` definition unit tests methods.
+    """
+
+    def test_reaction_rate_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+reaction_rate_MichealisMenten` definition.
+        """
+
+        self.assertAlmostEqual(
+            reaction_rate_MichealisMenten(0.25, 0.5, 0.25),
+            0.250000000000000,
+            places=7)
+
+        self.assertAlmostEqual(
+            reaction_rate_MichealisMenten(0.5, 0.5, 0.25),
+            0.333333333333333,
+            places=7)
+
+        self.assertAlmostEqual(
+            reaction_rate_MichealisMenten(0.65, 0.75, 0.35),
+            0.487500000000000,
+            places=7)
+
+    def test_n_dimensional_reaction_rate_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+reaction_rate_MichealisMenten` definition n-dimensional arrays
+        support.
+        """
+
+        v = 0.5
+        V_max = 0.5
+        K_m = 0.25
+        S = 0.333333333333333
+        np.testing.assert_almost_equal(
+            reaction_rate_MichealisMenten(v, V_max, K_m),
+            S,
+            decimal=7)
+
+        v = np.tile(v, (6, 1))
+        S = np.tile(S, (6, 1))
+        np.testing.assert_almost_equal(
+            reaction_rate_MichealisMenten(v, V_max, K_m),
+            S,
+            decimal=7)
+
+        V_max = np.tile(V_max, (6, 1))
+        K_m = np.tile(K_m, (6, 1))
+        np.testing.assert_almost_equal(
+            reaction_rate_MichealisMenten(v, V_max, K_m),
+            S,
+            decimal=7)
+
+        v = np.reshape(v, (2, 3, 1))
+        V_max = np.reshape(V_max, (2, 3, 1))
+        K_m = np.reshape(K_m, (2, 3, 1))
+        S = np.reshape(S, (2, 3, 1))
+        np.testing.assert_almost_equal(
+            reaction_rate_MichealisMenten(v, V_max, K_m),
+            S,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_reaction_rate_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+reaction_rate_MichealisMenten` definition nan support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            v = np.array(case)
+            V_max = np.array(case)
+            K_m = np.array(case)
+            reaction_rate_MichealisMenten(v, V_max, K_m)
+
+
+class TestSubstrateConcentrationMichealisMenten(unittest.TestCase):
+    """
+    Defines :func:`colour.biochemistry.michaelis_menten.\
+reaction_rate_MichealisMenten` definition unit tests methods.
+    """
+
+    def test_substrate_concentration_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+substrate_concentration_MichealisMenten` definition.
+        """
+
+        self.assertAlmostEqual(
+            substrate_concentration_MichealisMenten(0.25, 0.5, 0.25),
+            0.250000000000000,
+            places=7)
+
+        self.assertAlmostEqual(
+            substrate_concentration_MichealisMenten(1 / 3, 0.5, 0.25),
+            0.500000000000000,
+            places=7)
+
+        self.assertAlmostEqual(
+            substrate_concentration_MichealisMenten(0.4875, 0.75, 0.35),
+            0.650000000000000,
+            places=7)
+
+    def test_n_dimensional_substrate_concentration_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+substrate_concentration_MichealisMenten` definition n-dimensional arrays
+        support.
+        """
+
+        S = 1 / 3
+        V_max = 0.5
+        K_m = 0.25
+        v = 0.5
+        np.testing.assert_almost_equal(
+            substrate_concentration_MichealisMenten(S, V_max, K_m),
+            v,
+            decimal=7)
+
+        S = np.tile(S, (6, 1))
+        v = np.tile(v, (6, 1))
+        np.testing.assert_almost_equal(
+            substrate_concentration_MichealisMenten(S, V_max, K_m),
+            v,
+            decimal=7)
+
+        V_max = np.tile(V_max, (6, 1))
+        K_m = np.tile(K_m, (6, 1))
+        np.testing.assert_almost_equal(
+            substrate_concentration_MichealisMenten(S, V_max, K_m),
+            v,
+            decimal=7)
+
+        S = np.reshape(S, (2, 3, 1))
+        V_max = np.reshape(V_max, (2, 3, 1))
+        K_m = np.reshape(K_m, (2, 3, 1))
+        v = np.reshape(v, (2, 3, 1))
+        np.testing.assert_almost_equal(
+            substrate_concentration_MichealisMenten(S, V_max, K_m),
+            v,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_substrate_concentration_MichealisMenten(self):
+        """
+        Tests :func:`colour.biochemistry.michaelis_menten.\
+substrate_concentration_MichealisMenten` definition nan support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            s = np.array(case)
+            V_max = np.array(case)
+            K_m = np.array(case)
+            substrate_concentration_MichealisMenten(s, V_max, K_m)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/colour/colorimetry/tests/tests_lightness.py b/colour/colorimetry/tests/tests_lightness.py
index 242e1d9f4..104a055ab 100644
--- a/colour/colorimetry/tests/tests_lightness.py
+++ b/colour/colorimetry/tests/tests_lightness.py
@@ -13,7 +13,8 @@ import unittest
 from colour.colorimetry import (
     lightness_Glasser1958,
     lightness_Wyszecki1963,
-    lightness_CIE1976)
+    lightness_CIE1976,
+    lightness_Fairchild2010)
 from colour.utilities import ignore_numpy_errors
 
 __author__ = 'Colour Developers'
@@ -25,7 +26,8 @@ __status__ = 'Production'
 
 __all__ = ['TestLightnessGlasser1958',
            'TestLightnessWyszecki1963',
-           'TestLightnessCIE1976']
+           'TestLightnessCIE1976',
+           'TestLightnessFairchild2010']
 
 
 class TestLightnessGlasser1958(unittest.TestCase):
@@ -259,5 +261,92 @@ class TestLightnessCIE1976(unittest.TestCase):
             np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))
 
 
+class TestLightnessFairchild2010(unittest.TestCase):
+    """
+    Defines :func:`colour.colorimetry.lightness.lightness_Fairchild2010`
+    definition unit tests methods.
+    """
+
+    def test_lightness_Fairchild2010(self):
+        """
+        Tests :func:`colour.colorimetry.lightness.lightness_Fairchild2010`
+        definition.
+        """
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(10.08 / 100),
+            23.10363383,
+            places=7)
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(56.76 / 100),
+            90.51057574,
+            places=7)
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(98.32 / 100),
+            96.636221285,
+            places=7)
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(10.08 / 100, 2.75),
+            16.06420271,
+            places=7)
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(1008),
+            100.01999667,
+            places=7)
+
+        self.assertAlmostEqual(
+            lightness_Fairchild2010(100800),
+            100.01999999,
+            places=7)
+
+    def test_n_dimensional_lightness_Fairchild2010(self):
+        """
+        Tests :func:`colour.colorimetry.lightness.lightness_Fairchild2010`
+        definition n-dimensional arrays support.
+        """
+
+        Y = 10.08 / 100
+        L = 23.10363383
+        np.testing.assert_almost_equal(
+            lightness_Fairchild2010(Y),
+            L,
+            decimal=7)
+
+        Y = np.tile(Y, 6)
+        L = np.tile(L, 6)
+        np.testing.assert_almost_equal(
+            lightness_Fairchild2010(Y),
+            L,
+            decimal=7)
+
+        Y = np.reshape(Y, (2, 3))
+        L = np.reshape(L, (2, 3))
+        np.testing.assert_almost_equal(
+            lightness_Fairchild2010(Y),
+            L,
+            decimal=7)
+
+        Y = np.reshape(Y, (2, 3, 1))
+        L = np.reshape(L, (2, 3, 1))
+        np.testing.assert_almost_equal(
+            lightness_Fairchild2010(Y),
+            L,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_lightness_Fairchild2010(self):
+        """
+        Tests :func:`colour.colorimetry.lightness.lightness_Fairchild2010`
+        definition nan support.
+        """
+
+        lightness_Fairchild2010(
+            np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]))
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/colour/colorimetry/tests/tests_luminance.py b/colour/colorimetry/tests/tests_luminance.py
index 6a16c9bd8..ec7963a00 100644
--- a/colour/colorimetry/tests/tests_luminance.py
+++ b/colour/colorimetry/tests/tests_luminance.py
@@ -13,7 +13,8 @@ import unittest
 from colour.colorimetry.luminance import (
     luminance_Newhall1943,
     luminance_CIE1976,
-    luminance_ASTMD153508)
+    luminance_ASTMD153508,
+    luminance_Fairchild2010)
 from colour.utilities import ignore_numpy_errors
 
 __author__ = 'Colour Developers'
@@ -25,7 +26,8 @@ __status__ = 'Production'
 
 __all__ = ['TestLuminanceNewhall1943',
            'TestLuminanceASTMD153508',
-           'TestLuminanceCIE1976']
+           'TestLuminanceCIE1976',
+           'TestLuminanceFairchild2010']
 
 
 class TestLuminanceNewhall1943(unittest.TestCase):
@@ -259,5 +261,92 @@ class TestLuminanceCIE1976(unittest.TestCase):
             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(23.103633825753175),
+            0.10079999,
+            places=7)
+
+        self.assertAlmostEqual(
+            luminance_Fairchild2010(90.510575738115122),
+            0.56759999,
+            places=7)
+
+        self.assertAlmostEqual(
+            luminance_Fairchild2010(96.636221285055527),
+            0.98319999,
+            places=7)
+
+        self.assertAlmostEqual(
+            luminance_Fairchild2010(16.064202706248068, 2.75),
+            0.10079999,
+            places=7)
+
+        self.assertAlmostEqual(
+            luminance_Fairchild2010(100.01999666792653),
+            1007.99999963,
+            places=7)
+
+        self.assertAlmostEqual(
+            luminance_Fairchild2010(100.01999999966679),
+            100800.82383352,
+            places=7)
+
+    def test_n_dimensional_luminance_Fairchild2010(self):
+        """
+        Tests :func:`colour.colorimetry.lightness.luminance_Fairchild2010`
+        definition n-dimensional arrays support.
+        """
+
+        L_hdr = 23.103633825753175
+        Y = 10.08 / 100
+        np.testing.assert_almost_equal(
+            luminance_Fairchild2010(L_hdr),
+            Y,
+            decimal=7)
+
+        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)
+
+    @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]))
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/colour/models/tests/tests_hdr_cie_lab.py b/colour/models/tests/tests_hdr_cie_lab.py
new file mode 100644
index 000000000..b8e64ecd7
--- /dev/null
+++ b/colour/models/tests/tests_hdr_cie_lab.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Defines unit tests for :mod:`colour.models.hdr_cie_lab` module.
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+import unittest
+from itertools import permutations
+
+from colour.models import XYZ_to_hdr_CIELab, hdr_CIELab_to_XYZ
+from colour.models.hdr_cie_lab import exponent_hdr_CIELab
+from colour.utilities import ignore_numpy_errors
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['TestXYZ_to_hdr_CIELab',
+           'TestHdr_CIELab_to_XYZ',
+           'TestExponent_hdr_CIELab']
+
+
+class TestXYZ_to_hdr_CIELab(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_cie_lab.XYZ_to_hdr_CIELab` definition unit
+    tests methods.
+    """
+
+    def test_XYZ_to_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.XYZ_to_hdr_CIELab` definition.
+        """
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(
+                np.array([0.07049534, 0.10080000, 0.09558313])),
+            np.array([24.90206646, -46.83127607, -10.14274843]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(
+                np.array([0.07049534, 0.10080000, 0.09558313]),
+                np.array([0.44757, 0.40745])),
+            np.array([24.90206646, -61.24983919, -83.63902870]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(
+                np.array([0.07049534, 0.10080000, 0.09558313]),
+                Y_s=0.5),
+            np.array([34.44227938, -36.51485775, -6.87279617]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(
+                np.array([0.07049534, 0.10080000, 0.09558313]),
+                Y_abs=1000),
+            np.array([32.39463250, -39.77445283, -7.66690737]),
+            decimal=7)
+
+    def test_n_dimensional_XYZ_to_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.XYZ_to_hdr_CIELab` definition
+        n-dimensions support.
+        """
+
+        XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
+        illuminant = np.array([0.34570, 0.35850])
+        Y_s = 0.2
+        Y_abs = 100
+        Lab_hdr = np.array([24.90206646, -46.83127607, -10.14274843])
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(XYZ, illuminant, Y_s, Y_abs),
+            Lab_hdr,
+            decimal=7)
+
+        XYZ = np.tile(XYZ, (6, 1))
+        Lab_hdr = np.tile(Lab_hdr, (6, 1))
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(XYZ, illuminant, Y_s, Y_abs),
+            Lab_hdr,
+            decimal=7)
+
+        illuminant = np.tile(illuminant, (6, 1))
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(XYZ, illuminant, Y_s, Y_abs),
+            Lab_hdr,
+            decimal=7)
+
+        XYZ = np.reshape(XYZ, (2, 3, 3))
+        illuminant = np.reshape(illuminant, (2, 3, 2))
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        Lab_hdr = np.reshape(Lab_hdr, (2, 3, 3))
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_CIELab(XYZ, illuminant, Y_s, Y_abs),
+            Lab_hdr,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_XYZ_to_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.XYZ_to_hdr_CIELab` definition
+        nan support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            XYZ = np.array(case)
+            illuminant = np.array(case[0:2])
+            Y_s = case[0]
+            Y_abs = case[0]
+            XYZ_to_hdr_CIELab(XYZ, illuminant, Y_s, Y_abs)
+
+
+class TestHdr_CIELab_to_XYZ(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_cie_lab.hdr_CIELab_to_XYZ` definition unit
+    tests methods.
+    """
+
+    def test_hdr_CIELab_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.hdr_CIELab_to_XYZ` definition.
+        """
+
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(
+                np.array([24.90206646, -46.83127607, -10.14274843])),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(
+                np.array([24.90206646, -61.24983919, -83.63902870]),
+                np.array([0.44757, 0.40745])),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(
+                np.array([34.44227938, -36.51485775, -6.87279617]),
+                Y_s=0.5),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(
+                np.array([32.39463250, -39.77445283, -7.66690737]),
+                Y_abs=1000),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+    def test_n_dimensional_hdr_CIELab_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.hdr_CIELab_to_XYZ` definition
+        n-dimensions support.
+        """
+
+        Lab_hdr = np.array([24.90206646, -46.83127607, -10.14274843])
+        illuminant = np.array([0.34570, 0.35850])
+        Y_s = 0.2
+        Y_abs = 100
+        XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(Lab_hdr, illuminant, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        Lab_hdr = np.tile(Lab_hdr, (6, 1))
+        XYZ = np.tile(XYZ, (6, 1))
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(Lab_hdr, illuminant, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        illuminant = np.tile(illuminant, (6, 1))
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(Lab_hdr, illuminant, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        Lab_hdr = np.reshape(Lab_hdr, (2, 3, 3))
+        illuminant = np.reshape(illuminant, (2, 3, 2))
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        XYZ = np.reshape(XYZ, (2, 3, 3))
+        np.testing.assert_almost_equal(
+            hdr_CIELab_to_XYZ(Lab_hdr, illuminant, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_hdr_CIELab_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.hdr_CIELab_to_XYZ` definition
+        nan support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            Lab_hdr = np.array(case)
+            illuminant = np.array(case[0:2])
+            Y_s = case[0]
+            Y_abs = case[0]
+            hdr_CIELab_to_XYZ(Lab_hdr, illuminant, Y_s, Y_abs)
+
+
+class TestExponent_hdr_CIELab(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_cie_lab.exponent_hdr_CIELab`
+    definition unit tests methods.
+    """
+
+    def test_exponent_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.exponent_hdr_CIELab`
+        definition.
+        """
+
+        self.assertAlmostEqual(
+            exponent_hdr_CIELab(0.2, 100),
+            1.836019897814665,
+            places=7)
+
+        self.assertAlmostEqual(
+            exponent_hdr_CIELab(0.4, 100),
+            1.326014370643925,
+            places=7)
+
+        self.assertAlmostEqual(
+            exponent_hdr_CIELab(0.2, 1000),
+            1.224013265209777,
+            places=7)
+
+    def test_n_dimensional_exponent_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.exponent_hdr_CIELab`
+        definition n-dimensional arrays support.
+        """
+
+        Y_s = 0.2
+        Y_abs = 100
+        e = 1.836019897814665
+        np.testing.assert_almost_equal(
+            exponent_hdr_CIELab(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        e = np.tile(e, 6)
+        np.testing.assert_almost_equal(
+            exponent_hdr_CIELab(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        e = np.reshape(e, (2, 3))
+        np.testing.assert_almost_equal(
+            exponent_hdr_CIELab(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.reshape(Y_s, (2, 3, 1))
+        Y_abs = np.reshape(Y_abs, (2, 3, 1))
+        e = np.reshape(e, (2, 3, 1))
+        np.testing.assert_almost_equal(
+            exponent_hdr_CIELab(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_exponent_hdr_CIELab(self):
+        """
+        Tests :func:`colour.models.hdr_cie_lab.exponent_hdr_CIELab`
+        definition nan support.
+        """
+
+        cases = np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])
+        exponent_hdr_CIELab(cases, cases)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/colour/models/tests/tests_hdr_ipt.py b/colour/models/tests/tests_hdr_ipt.py
new file mode 100644
index 000000000..6c205f2da
--- /dev/null
+++ b/colour/models/tests/tests_hdr_ipt.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Defines unit tests for :mod:`colour.models.hdr_ipt` module.
+"""
+
+from __future__ import division, unicode_literals
+
+import numpy as np
+import unittest
+from itertools import permutations
+
+from colour.models import XYZ_to_hdr_IPT, hdr_IPT_to_XYZ
+from colour.models.hdr_ipt import exponent_hdr_IPT
+from colour.utilities import ignore_numpy_errors
+
+__author__ = 'Colour Developers'
+__copyright__ = 'Copyright (C) 2013-2017 - Colour Developers'
+__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
+__maintainer__ = 'Colour Developers'
+__email__ = 'colour-science@googlegroups.com'
+__status__ = 'Production'
+
+__all__ = ['TestXYZ_to_hdr_IPT',
+           'TestHdr_IPT_to_XYZ',
+           'TestExponent_hdr_IPT']
+
+
+class TestXYZ_to_hdr_IPT(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_ipt.TestXYZ_to_hdr_IPT` definition unit
+    tests methods.
+    """
+
+    def test_XYZ_to_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.XYZ_to_hdr_IPT` definition.
+        """
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(
+                np.array([0.07049534, 0.10080000, 0.09558313])),
+            np.array([25.18261761, -22.62111297, 3.18511729]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(
+                np.array([0.07049534, 0.10080000, 0.09558313]),
+                Y_s=0.5),
+            np.array([34.60312115, -15.70974390, 2.26601353]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(
+                np.array([0.25506814, 0.19150000, 0.08849752]),
+                Y_abs=1000),
+            np.array([47.18074546, 32.38073691, 29.13827648]),
+            decimal=7)
+
+    def test_n_dimensional_XYZ_to_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.XYZ_to_hdr_IPT` definition
+        n-dimensions support.
+        """
+
+        XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
+        Y_s = 0.2
+        Y_abs = 100
+        IPT_hdr = np.array([25.18261761, -22.62111297, 3.18511729])
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(XYZ, Y_s, Y_abs),
+            IPT_hdr,
+            decimal=7)
+
+        XYZ = np.tile(XYZ, (6, 1))
+        IPT_hdr = np.tile(IPT_hdr, (6, 1))
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(XYZ, Y_s, Y_abs),
+            IPT_hdr,
+            decimal=7)
+
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(XYZ, Y_s, Y_abs),
+            IPT_hdr,
+            decimal=7)
+
+        XYZ = np.reshape(XYZ, (2, 3, 3))
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        IPT_hdr = np.reshape(IPT_hdr, (2, 3, 3))
+        np.testing.assert_almost_equal(
+            XYZ_to_hdr_IPT(XYZ, Y_s, Y_abs),
+            IPT_hdr,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_XYZ_to_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.XYZ_to_hdr_IPT` definition nan
+        support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            XYZ = np.array(case)
+            Y_s = case[0]
+            Y_abs = case[0]
+            XYZ_to_hdr_IPT(XYZ, Y_s, Y_abs)
+
+
+class TestHdr_IPT_to_XYZ(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_ipt.hdr_IPT_to_XYZ` definition unit tests
+    methods.
+    """
+
+    def test_hdr_IPT_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.hdr_IPT_to_XYZ` definition.
+        """
+
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(
+                np.array([25.18261761, -22.62111297, 3.18511729])),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(
+                np.array([34.60312115, -15.70974390, 2.26601353]),
+                Y_s=0.5),
+            np.array([0.07049534, 0.10080000, 0.09558313]),
+            decimal=7)
+
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(
+                np.array([47.18074546, 32.38073691, 29.13827648]),
+                Y_abs=1000),
+            np.array([0.25506814, 0.19150000, 0.08849752]),
+            decimal=7)
+
+    def test_n_dimensional_hdr_IPT_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.hdr_IPT_to_XYZ` definition
+        n-dimensions support.
+        """
+
+        IPT_hdr = np.array([25.18261761, -22.62111297, 3.18511729])
+        Y_s = 0.2
+        Y_abs = 100
+        XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(IPT_hdr, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        IPT_hdr = np.tile(IPT_hdr, (6, 1))
+        XYZ = np.tile(XYZ, (6, 1))
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(IPT_hdr, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(IPT_hdr, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+        IPT_hdr = np.reshape(IPT_hdr, (2, 3, 3))
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        XYZ = np.reshape(XYZ, (2, 3, 3))
+        np.testing.assert_almost_equal(
+            hdr_IPT_to_XYZ(IPT_hdr, Y_s, Y_abs),
+            XYZ,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_hdr_IPT_to_XYZ(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.hdr_IPT_to_XYZ` definition nan
+        support.
+        """
+
+        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
+        cases = set(permutations(cases * 3, r=3))
+        for case in cases:
+            IPT_hdr = np.array(case)
+            Y_s = case[0]
+            Y_abs = case[0]
+            hdr_IPT_to_XYZ(IPT_hdr, Y_s, Y_abs)
+
+
+class TestExponent_hdr_IPT(unittest.TestCase):
+    """
+    Defines :func:`colour.models.hdr_ipt.exponent_hdr_IPT`
+    definition unit tests methods.
+    """
+
+    def test_exponent_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.exponent_hdr_IPT`
+        definition.
+        """
+
+        self.assertAlmostEqual(
+            exponent_hdr_IPT(0.2, 100),
+            1.689138305989492,
+            places=7)
+
+        self.assertAlmostEqual(
+            exponent_hdr_IPT(0.4, 100),
+            1.219933220992410,
+            places=7)
+
+        self.assertAlmostEqual(
+            exponent_hdr_IPT(0.2, 1000),
+            1.126092203992995,
+            places=7)
+
+    def test_n_dimensional_exponent_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.exponent_hdr_IPT`
+        definition n-dimensional arrays support.
+        """
+
+        Y_s = 0.2
+        Y_abs = 100
+        e = 1.689138305989492
+        np.testing.assert_almost_equal(
+            exponent_hdr_IPT(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.tile(Y_s, 6)
+        Y_abs = np.tile(Y_abs, 6)
+        e = np.tile(e, 6)
+        np.testing.assert_almost_equal(
+            exponent_hdr_IPT(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.reshape(Y_s, (2, 3))
+        Y_abs = np.reshape(Y_abs, (2, 3))
+        e = np.reshape(e, (2, 3))
+        np.testing.assert_almost_equal(
+            exponent_hdr_IPT(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+        Y_s = np.reshape(Y_s, (2, 3, 1))
+        Y_abs = np.reshape(Y_abs, (2, 3, 1))
+        e = np.reshape(e, (2, 3, 1))
+        np.testing.assert_almost_equal(
+            exponent_hdr_IPT(Y_s, Y_abs),
+            e,
+            decimal=7)
+
+    @ignore_numpy_errors
+    def test_nan_exponent_hdr_IPT(self):
+        """
+        Tests :func:`colour.models.hdr_ipt.exponent_hdr_IPT`
+        definition nan support.
+        """
+
+        cases = np.array([-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan])
+        exponent_hdr_IPT(cases, cases)
+
+
+if __name__ == '__main__':
+    unittest.main()