# pylint: disable=invalid-name
"""
Useful functions for calculating light interaction at planar boundaries.
The underlying assumptions are that there a two semi-infinite media with a
planar interface. For convenience, assume the light is incident from the top.
The upper medium is characterized by a purely real index of refraction `n_i` which
has a default value of 1. The lower medium is characterized by a complex index
of refraction `m = n - n * kappa * 1j`. Note that `pypolar` assumes the sign
of the imaginary part of the index of refraction is negative.
The Fresnel equations assume that the electric field has been decomposed into
fields relative to the plane of incidence (a plane defined by the incoming
light direction and the normal to the surface).
The incidence angle is measured from the normal to the surface and is measured
in radians.
To Do::
* Make sure routines work for arrays of m or of theta_i
* fail for positive imaginary refractive indices
* fail for out-of-range angles to catch degrees/radians error
Scott Prahl
Apr 2021
"""
import numpy as np
__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'
)
[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]
"""
if deg:
return np.degrees(np.arctan2(m, n_i))
return np.arctan2(m, n_i)
[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]
"""
if deg:
return np.degrees(np.arcsin(m / n_i))
return np.arcsin(m / n_i)
def _cosines(m, theta_i, n_i, deg=False):
"""
Intermediate cosines needed for Fresnel equations.
This is split out because so that special casing for
degrees is not needed everywhere and so that algorithms
work properly when m is an array as well.
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) and cos(theta_t) [-]
"""
if deg:
theta = np.radians(theta_i)
else:
theta = theta_i
m2 = (m / n_i)**2
c = np.cos(theta)
s = np.sin(theta)
d = np.sqrt(m2 - s * s, dtype=complex) # = m*cos(theta_t)
if np.isscalar(m):
if m.imag == 0: # choose right branch for dielectrics
d = np.conjugate(d)
else:
d = np.where(m.imag == 0, np.conjugate(d), d)
return c, d
[docs]
def r_par_amplitude(m, theta_i, n_i=1, deg=False):
"""
Reflected fraction of parallel-polarized field at an interface.
This is the fraction of the incident electric field reflected at the
interface between two semi-infinite media. The incident field is assumed
to be polarized parallel (p) to the plane of incidence (transverse magnetic
or TM field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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 parallel field [-]
"""
c, d = _cosines(m, theta_i, n_i, deg)
m2 = (m / n_i)**2
rp = (m2 * c - d) / (m2 * c + d)
return np.real_if_close(rp)
[docs]
def r_per_amplitude(m, theta_i, n_i=1, deg=False):
"""
Reflected fraction of perpendicular-polarized field at an interface.
This is the fraction of the incident electric field reflected at the
interface between two semi-infinite media. The incident field is assumed
to be polarized perpendicular (s, or senkrecht) to the plane of incidence
(transverse electric or TE field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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, deg)
rs = (c - d) / (c + d)
return np.real_if_close(rs)
[docs]
def t_par_amplitude(m, theta_i, n_i=1, deg=False):
"""
Find the transmitted fraction of parallel-polarized field through an interface.
This is the fraction of the incident electric field transmitted through the
interface between two semi-infinite media. The incident field is assumed
to be polarized parallel (p) to the plane of incidence (transverse magnetic
or TM field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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 = _cosines(m, theta_i, n_i, deg)
m2 = (m / n_i)**2
tp = 2 * c * (m / n_i) / (m2 * c + d)
return np.real_if_close(tp)
[docs]
def t_per_amplitude(m, theta_i, n_i=1, deg=False):
"""
Return the transmitted fraction of perpendicular-polarized field through an interface.
This is the fraction of the incident electric field transmitted through the
interface between two semi-infinite media. The incident field is assumed
to be polarized perpendicular (s, or senkrecht) to the plane of incidence
(transverse electric or TE field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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, deg)
ts = 2 * d / (m / n_i) / (c + d)
return np.real_if_close(ts)
[docs]
def R_par(m, theta_i, n_i=1, deg=False):
"""
Reflected fraction of parallel-polarized optical power by an interface.
The reflected fraction of incident power (or flux) assuming that
the electric field of the incident light is polarized parallel (p) to the
plane of incidence (transverse magnetic or TM electric field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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 parallel-polarized irradiance [-]
"""
return np.abs(r_par_amplitude(m, theta_i, n_i, deg))**2
[docs]
def R_per(m, theta_i, n_i=1, deg=False):
"""
Return the fraction of perpendicular-polarized optical power reflectedby an interface.
The fraction of the incident power (or flux) reflected at the
interface between two semi-infinite media. The incident light is assumed
to be polarized perpendicular (s, or senkrecht) to the plane of incidence
(transverse electric or TE field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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-polarized irradiance [-]
"""
return np.abs(r_per_amplitude(m, theta_i, n_i, deg))**2
[docs]
def T_par(m, theta_i, n_i=1, deg=False):
"""
Return the transmitted fraction of parallel-polarized optical power through an interface.
The transmitted fraction of incident power (or flux) assuming that
the electric field of the incident light is polarized parallel (p) to the
plane of incidence (transverse magnetic or TM electric field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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-polarized irradiance [-]
"""
c, d = _cosines(m, theta_i, n_i, deg)
tp = 2 * c * (m / n_i) / ((m / n_i)**2 * c + d)
return np.abs(d / c * np.abs(tp)**2)
[docs]
def T_per(m, theta_i, n_i=1, deg=False):
"""
Return the transmitted fraction of perpendicular-polarized optical power through an interface.
The transmitted fraction of the incident power (or flux) through the
interface between two semi-infinite media. The incident light is assumed
to be polarized perpendicular (s, or senkrecht) to the plane of incidence
(transverse electric or TE field).
The index of refraction for medium of the incoming field defaults to 1, but
can be set any real value. The medium of the outgoing field is characterized
by an index of refraction that may be complex.
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-polarized irradiance [-]
"""
c, d = _cosines(m, theta_i, n_i, deg)
ts = 2 * c / (c + d)
return np.abs(d / c * 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:
fraction of unpolarized irradiance reflected [-]
"""
return (R_par(m, theta_i, n_i, deg) + R_per(m, theta_i, n_i, 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:
fraction of unpolarized irradiance transmitted [-]
"""
return (T_par(m, theta_i, n_i, deg) + T_per(m, theta_i, n_i, deg)) / 2