Models
------

The ``pydirectional`` package currently implements the following BRDF models:

* Ross-Thick Li-Sparse (RTLS)
* Maignan
* Roujean
* Rahman-Pinty-Verstraete (RPV)
* Hapke

.. note::

    Several models use the phase angle, g, defined as 

    .. math::

        cos(g) = cos(\varphi_{s}) \cdot cos(\varphi_{v}) + sin(\varphi_{s}) \cdot sin(\varphi_{v}) \cdot cos(\phi)


Model Overview
^^^^^^^^^^^^^^^

.. csv-table:: 
    :header: "BRDF Model", "Name of Model Class", "Model Input Parameters"
    :widths: 10, 10, 30

    "RTLS", "`RTLSBRDF`", "'iso', 'vol', 'geo'"
    "Maignan", "`MaignanBRDF`", "'iso', 'vol', 'geo'"
    "Roujean", "`RoujeanBRDF`", "'iso', 'vol', 'geo'"
    "RPV", "`RPVBRDF`", "'rho_0', 'k', 'theta', 'rho_c'"
    "RPVOmega", "`RPVOmegaBRDF`", "'rho_0', 'k', 'theta', 'omega'"
    "Hapke: 6-Parameter", "`HapkeEradiateBRDF`", "'w', 'B_0', 'h', 'b', 'c', 'theta'"
    "Hapke: 4-Parameter", "`Hapke6SBRDF`", "'w', 'B_0', 'h', 'b'"
    "Hapke: 3-Parameter", "`HapkeLibradtranBRDF`", "'w', 'B_0', 'h'"

.. note::

    If the 3 parameter implementation of the RPV model is being used, enter 'rho_c' as equal
    to the 'rho_0' data.

RTLS
^^^^

The Ross-Thick Li-Sparse (RTLS) model is a kernel-based model. The kernel-based models implemened
within `pydirectional` all consist of three kernels: an isotropic element; a volumetric kernel representing
surface structures; a geometric kernel representing shadowing effects. The RTLS model uses the
Ross-Thick volumetic kernel and the Li-Sparse geometric kernel. The model parameters for the RTLS model
are coefficients for each kernel, named iso, vol, and geo. 

.. math:: 

    BRF_{RTLS} = iso + vol \cdot F_{Ross-Thick} + geo \cdot F_{Li-Sparse} 

.. math::

    F_{Ross-Thick} = \frac{1}{\varphi_{s} + \varphi_{v}} \cdot [(\frac{\pi}{2} - g) \cdot cos(g) + sin(g)] - \frac{\pi}{4}

.. math::

    F_{Li-Sparse} = \frac{cos(\varphi_{s}) + cos(\varphi_{v})}{cos(\varphi_{s}) \cdot cos(\varphi_{v})} \cdot (\frac{t - sin(t) \cdot cos(t)}{\pi} - 1) + \frac{1}{2} \cdot (1 + \frac{cos(g)}{cos})

.. math::

    cos(t) = 2 \frac{cos(\varphi_{s}) + cos(\varphi_{v})}{cos(\varphi_{s}) \cdot cos(\varphi_{v})} \cdot \sqrt{D^2 + tan^2(\varphi_{s}) \cdot tan^2(\varphi_{v}) \cdot sin(\phi)}

.. math::

    D = \sqrt{tan^2(\varphi_{s}) + tan^2(\varphi_{v}) - 2tan(\varphi_{s}) \cdot tan(\varphi_{v}) \cdot cos(\phi)}

Maignan
^^^^^^^^

The Maignan model is a kernel-based model which uses the same isotropic and geometric
components as RTLS however, rather than teh Ross-Thick kernel, the Maignan volumetric
kernel is used.

.. math::

    BRF_{RTLS} = iso + vol \cdot F_{Maignan} + geo \cdot F_{Li-Sparse}
    
.. math::

    F_{Maignan} = \frac{1}{cos(\varphi_{s}) + cos(\varphi_{v})} \cdot [(\frac{\pi}{2} - \phi) \cdot cos(\phi) + sin(\phi)] \cdot (1 + (1 + \frac{\phi}{\phi_{0}})^{-1}) - \frac{\pi}{4}

where :math:`\phi_0` is a constant equal to 1.5 degrees.

Roujean
^^^^^^^^

The Roujean model is a kernel-based model which uses the same isotopic and volumetric
components as RTLS however, rather than the Li-Sparse kernel, the Roujean geometric
kernel is used.

.. math:: 

    BRF_{RTLS} = iso + vol \cdot F_{Ross-Thick} + geo \cdot F_{Roujean}

.. math::

    F_{Roujean} = [(\pi - \phi) \cdot cos(\phi) + sin(\phi)] \cdot tan(\varphi_{s}) \cdot tan(\varphi_{v}) - \frac{1}{\pi} \cdot (tan(\varphi_{s}) + tan(\varphi_{v}) + D) 

RPV
^^^^

The RPV model is not kernel-based. It contains 4 parameters, :math:`\rho_{0}`,
k, :math:`\theta`, and :math:`\rho_{c}`. If the three parameter implentation is used, 
:math:`\rho_{c} = \rho_{0}`. `pydirectional` also implements the RPVOmega 
model, here :math:`\rho_c = \Omega \cdot \rho_{0}` with :math:`\Omega` as the
4th input parameter rather than :math:`\rho_{c}`.

.. math::

    BRF_{RPV} = \rho_{0} \cdot M_{1}(\varphi_{s}, \varphi_{v}, k) \cdot F_{HG}(g, \theta) \cdot H(D, \rho_{c})

.. math::

    M_{1}(\varphi_{s}, \varphi_{v}, k) = \frac{cos^{k-1}(\varphi_{s})cos^{k-1}(\varphi_{v})}{(cos(\varphi_{s}) + cos(\varphi_{v}))^{1-k}}  

.. math::

    F_{HG}(g, \theta) = \frac{1 - \theta^2}{(1 + 2\theta \cdot cos(g) +\theta^2)^{\frac{1}{2}}}

.. math::

    H(D, \rho_{c}) = 1 + \frac{1 - \rho_{c}}{1 + D}

:math:`M_1` represents the angular field shape, :math:`F_{HG}` represents the 
scattering element and :math:`H` represents the hotspot contribution.

Hapke
^^^^^^

The Hapke BRDF model was developed to describe the reflectance properties of
particulate surfaces.
Three implementations of the Hapke model are included in the `pydirectional` package:

* 3-Parameter (as used in Libradtran)
* 4-Parameter (as used in 6S)
* 6-Parameter (as used in Eradiate)

In all implementations,

.. math ::

    BRF_{Hapke} = \frac{w}{4} \cdot \frac{1}{cos(\varphi_{s}) + cos(\varphi_{v})} \cdot (p() \cdot (1 + B()) + H(cos(\varphi_{s})) \cdot H(cos(\varphi_{v})) - 1) \cdot S()

The functions, :math:`p()`, :math:`B()`, :math:`H()`, and :math:`S()` 
differ between implementations and take various parameters as inputs.
The physical basis of the functions is the same between all the implementations.
:math:`p()` is the average phase function, :math:`B()` accounts for hotspot effects, 
:math:`H()` accounts for multiple scattering, and :math:`S()` is a correction factor 
describing surface roughness. :math:`S()` is only included in the Eradiate implementation,
in other implementations it is set to 1.

The `HapkeEradiate` model uses the parameters, w, :math:`B_{0}`, h, b, c, and :math:`\theta`.
w is the single scattering albedo, b is the asymmetry parameter, c is the backscatter fraction,
:math:`B_0` is the amplitude of the backscattering function, h is the angular width of the backscattering function,
and :math:`\theta` is the roughness angle in degrees. w, b, c, and :math:`B_{0}` can take values between 
0 and 1 inclusive. h can take values between 0 and 1, excluding 0. :math:`\theta` can take
values between 0 and 90 degrees.

The `Hapke6S` model uses the parameters w, :math:`B_{0}`, h, and b. The parameters represent the same 
physical values as in the Eradiate implementation, however b can take values from -1 
to 1 inclusive.

The `HapkeLibradtran` model uses the parameters w, :math:`B_{0}`, and h. The parameters represent
the same physical values as in the Eradiate implementation.

