Source code for pypolar.sym_fresnel

"""
Useful routines for symbolic Fresnel calculations at planar interfaces.

The functions in this module return symbolic SymPy expressions for Fresnel
field and power coefficients at a planar interface. Light is incident from a
medium with real refractive index `n_i` (default 1), onto a medium with
complex refractive index `m`.

Angles are measured from the surface normal. Set `deg=True` when passing
angles in degrees.

Incidence-angle helpers::

    * brewster(index_of_refraction, n_i=1, deg=False)
    * critical(index_of_refraction, n_i=1, deg=False)

Field-amplitude Fresnel coefficients::

    * r_par_amplitude(index_of_refraction, angle, n_i=1, deg=False)
    * r_per_amplitude(index_of_refraction, angle, n_i=1, deg=False)
    * t_par_amplitude(index_of_refraction, angle, n_i=1, deg=False)
    * t_per_amplitude(index_of_refraction, angle, n_i=1, deg=False)

Power (irradiance) Fresnel coefficients::

    * R_par(index_of_refraction, angle, n_i=1, deg=False)
    * R_per(index_of_refraction, angle, n_i=1, deg=False)
    * T_par(index_of_refraction, angle, n_i=1, deg=False)
    * T_per(index_of_refraction, angle, n_i=1, deg=False)
    * R_unpolarized(index_of_refraction, angle, n_i=1, deg=False)
    * T_unpolarized(index_of_refraction, angle, n_i=1, deg=False)

Ellipsometry helpers::

    * ellipsometry_rho(index_of_refraction, angle, n_i=1, deg=False)
    * ellipsometry_index(rho, angle, n_i=1, deg=False)
"""

import sympy

__all__ = (
    "brewster",
    "critical",
    "r_par_amplitude",
    "r_per_amplitude",
    "t_par_amplitude",
    "t_per_amplitude",
    "R_par",
    "R_per",
    "T_par",
    "T_per",
    "R_unpolarized",
    "T_unpolarized",
    "ellipsometry_rho",
    "ellipsometry_index",
)


[docs] def brewster(m, n_i=1, deg=False): """ Brewster's angle for an interface. Args: m: complex index of refraction of medium [-] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: Brewster's angle from normal to surface [radians/degrees] """ theta_b = sympy.atan2(m, n_i) if deg: return sympy.deg(theta_b) return theta_b
[docs] def critical(m, n_i=1, deg=False): """ Critical angle for total internal reflection at interface. Args: m: complex index of refraction of medium [-] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: critical angle from normal to surface [radians/degrees] """ theta_c = sympy.asin(m / n_i) if deg: return sympy.deg(theta_c) return theta_c
def _cosines(m, theta_i, n_i=1, deg=False): """ Intermediate cosines needed for Fresnel equations. n_i * sin(theta_i) = m * sin(theta_t) Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: cos(theta_i), m*cos(theta_t), and relative index m/n_i """ if deg: theta = theta_i * sympy.pi / 180 else: theta = theta_i m_rel = m / n_i c = sympy.cos(theta) s = sympy.sin(theta) d = sympy.sqrt(m_rel * m_rel - s * s) # = m_rel*cos(theta_t) if sympy.im(m_rel) == 0: d = sympy.conjugate(d) return c, d, m_rel
[docs] def r_par_amplitude(m, theta_i, n_i=1, deg=False): """ Calculate the reflected amplitude for parallel polarized light. Args: m: complex index of refraction of medium [-] theta_i: angle from normal to surface [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected fraction of parallel field [-] """ c, d, m_rel = _cosines(m, theta_i, n_i=n_i, deg=deg) m2 = m_rel * m_rel rp = (m2 * c - d) / (m2 * c + d) return rp
[docs] def r_per_amplitude(m, theta_i, n_i=1, deg=False): """ Calculate the reflected amplitude for perpendicular polarized light. Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected fraction of perpendicular field [-] """ c, d, _ = _cosines(m, theta_i, n_i=n_i, deg=deg) rs = (c - d) / (c + d) return rs
[docs] def t_par_amplitude(m, theta_i, n_i=1, deg=False): """ Calculate the transmitted amplitude for parallel polarized light. Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: transmitted fraction of parallel field [-] """ c, d, m_rel = _cosines(m, theta_i, n_i=n_i, deg=deg) m2 = m_rel * m_rel tp = 2 * c * m_rel / (m2 * c + d) return tp
[docs] def t_per_amplitude(m, theta_i, n_i=1, deg=False): """ Calculate the transmitted amplitude for perpendicular polarized light. Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: transmitted fraction of perpendicular field [-] """ c, d, _ = _cosines(m, theta_i, n_i=n_i, deg=deg) ts = 2 * c / (c + d) return ts
[docs] def R_par(m, theta_i, n_i=1, deg=False): """ Fraction of parallel-polarized light that is reflected (R_p). Calculate reflected fraction of incident power (or flux) assuming that the E-field of the incident light is parallel to the plane of incidence Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected power [-] """ return sympy.Abs(r_par_amplitude(m, theta_i, n_i=n_i, deg=deg)) ** 2
[docs] def R_per(m, theta_i, n_i=1, deg=False): """ Fraction of perpendicular-polarized light that is reflected (R_s). Calculate reflected fraction of incident power (or flux) assuming that the E-field of the incident light is perpendicular to the plane of incidence Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected irradiance [-] """ return sympy.Abs(r_per_amplitude(m, theta_i, n_i=n_i, deg=deg)) ** 2
[docs] def T_par(m, theta_i, n_i=1, deg=False): """ Fraction of parallel-polarized light that is transmitted (T_p). Calculate transmitted fraction of incident power (or flux) assuming that the E-field of the incident light is parallel to the plane of incidence Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: transmitted irradiance [-] """ c, d, m_rel = _cosines(m, theta_i, n_i=n_i, deg=deg) m2 = m_rel * m_rel tp = 2 * c * m_rel / (m2 * c + d) return sympy.Abs(d / c * sympy.Abs(tp) ** 2)
[docs] def T_per(m, theta_i, n_i=1, deg=False): """ Fraction of perpendicular-polarized light that is transmitted (T_s). Calculate transmitted fraction of incident power (or flux) assuming that the E-field of the incident light is perpendicular to the plane of incidence Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: transmitted field amplitude [-] """ c, d, _ = _cosines(m, theta_i, n_i=n_i, deg=deg) ts = 2 * c / (c + d) return sympy.Abs(d / c * sympy.Abs(ts) ** 2)
[docs] def R_unpolarized(m, theta_i, n_i=1, deg=False): """ Fraction of unpolarized light that is reflected. Calculate reflection fraction of incident power (or flux) assuming that the incident light is unpolarized Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected irradiance [-] """ return (R_par(m, theta_i, n_i=n_i, deg=deg) + R_per(m, theta_i, n_i=n_i, deg=deg)) / 2
[docs] def T_unpolarized(m, theta_i, n_i=1, deg=False): """ Fraction of unpolarized light that is transmitted. Calculate transmitted fraction of incident power (or flux) assuming that the incident light is unpolarized Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: reflected irradiance [-] """ return (T_par(m, theta_i, n_i=n_i, deg=deg) + T_per(m, theta_i, n_i=n_i, deg=deg)) / 2
[docs] def ellipsometry_rho(m, theta_i, n_i=1, deg=False): """ Calculate the ellipsometer parameter rho. Args: m: complex index of refraction of medium [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: ellipsometer parameter rho [-] """ return r_par_amplitude(m, theta_i, n_i=n_i, deg=deg) / r_per_amplitude(m, theta_i, n_i=n_i, deg=deg)
[docs] def ellipsometry_index(rho, theta_i, n_i=1, deg=False): """ Calculate the index of refraction for an isotropic sample. Args: rho: r_par_amplitude/r_per_amplitude [-] theta_i: incidence angle from normal [radians/degrees] n_i: real refractive index of incident medium [-] deg: theta_i is in degrees [True/False] Returns: complex index of refraction [-] """ if deg: theta = theta_i * sympy.pi / 180 else: theta = theta_i e_index = sympy.sqrt(1 - 4 * rho * sympy.sin(theta) ** 2 / (1 + rho) ** 2) return n_i * sympy.tan(theta) * e_index