Public Documentation

These functions and types are to be used for transfer matrix calculation based on the sources used. If you wish to modify any of the steps in the calculation, refer to the private API.

Index

Transfer Matrix Functions

TransferMatrix.TransferResultType
TransferResult{T}

Container for reflectance and transmittance results from transfer matrix calculations.

Fields

  • Tpp::T: p-polarized transmittance (p-in → p-out)
  • Tss::T: s-polarized transmittance (s-in → s-out)
  • Tps::T: cross-polarized transmittance (p-in → s-out)
  • Tsp::T: cross-polarized transmittance (s-in → p-out)
  • Rpp::T: p-polarized reflectance (p-in → p-out)
  • Rss::T: s-polarized reflectance (s-in → s-out)
  • Rps::T: cross-polarized reflectance (p-in → s-out)
  • Rsp::T: cross-polarized reflectance (s-in → p-out)

For single-wavelength calculations via transfer(), T is Float64. For sweep calculations via sweep_angle() or sweep_thickness(), T is Matrix{Float64}.

Cross-polarization terms

The cross-polarization terms (Tps, Tsp, Rps, Rsp) are zero for isotropic media and become non-zero for anisotropic (birefringent) materials.

Examples

# Single wavelength - returns TransferResult{Float64}
result = transfer(1.0, layers)
result.Tpp  # Float64

# Sweep - returns TransferResult{Matrix{Float64}}
result = sweep_angle(λs, θs, layers)
result.Tpp  # Matrix{Float64}

# Destructuring works
(; Tpp, Rpp) = transfer(1.0, layers)
source
TransferMatrix.calculate_trMethod
calculate_tr(Γ)

Calculate reflectance and transmittance for the total stack. This takes the matrix Γ* in Passler, et al., but for brevity we call it Γ in this function.

The original formalism is from: Yeh, 1979, https://doi.org/10.1364/JOSA.69.000742

but the ordering of reflection/transmission coefficients is modified in Passler, et al. 2017 https://doi.org/10.1364/JOSAB.34.002128

source
TransferMatrix.calculate_trMethod
calculate_tr(S::Poynting)

Calculate transmittance and reflectance from the Poynting vector struct, which contains incident, transmitted, and reflected energy flux for both p-polarized and s-polarized waves.

Returns (Tpp, Tss, Rpp, Rss).

Sign Convention

The reflected Poynting vector z-component is negative (pointing in -z direction), so the negative sign in Rpp = -S.refl_p[3] / S.in_p[3] yields positive reflectance.

source
TransferMatrix.efieldMethod
efield(λ, layers; θ=0.0, μ=1.0, dz=0.001)

Calculate the electric field profile throughout the layered structure.

Returns an ElectricField struct containing:

  • z: Position coordinates along the structure
  • p: Electric field components (Ex, Ey, Ez) for p-polarized incidence
  • s: Electric field components (Ex, Ey, Ez) for s-polarized incidence
  • boundaries: z-positions of layer interfaces

Arguments

  • λ: Wavelength in μm (must match units used for layer thicknesses)
  • layers: Vector of Layer objects representing the stack
  • θ: Angle of incidence in radians (default: 0.0, normal incidence)
  • μ: Relative magnetic permeability (default: 1.0, non-magnetic)
  • dz: Spatial step size in μm for field sampling (default: 0.001)

Wave Propagation Convention

  • Light propagates in the +z direction (from first layer toward last layer)
  • z = 0 is at the first interface (between layer 1 and layer 2)
  • Negative z values are inside the first (incident) layer
  • θ is measured from the surface normal (z-axis)

Units

  • All lengths (λ, thickness, dz, z): μm (micrometers) recommended
  • Angle: radians
  • Electric field: arbitrary units (normalized to incident field)
source
TransferMatrix.sweep_thicknessMethod
sweep_thickness(λs, ts, layers, t_index; θ=0.0, threads=true, verbose=false)

Sweep the thickness of a specific layer and calculate transmittance/reflectance spectra.

Returns a TransferResult with fields Tpp, Tss, Rpp, Rss, each a matrix of size (length(ts), length(λs)).

Arguments

  • λs: Vector of wavelengths in μm
  • ts: Vector of thicknesses in μm to sweep
  • layers: AbstractVector{<:Layer} representing the stack
  • t_index: Index of the layer (1-based) whose thickness to vary
  • θ: Angle of incidence in radians (default: 0.0, normal incidence)
  • threads: Enable multithreading (default: true)
  • verbose: Print thread count info (default: false)

Units

  • Wavelengths and thicknesses: μm (micrometers) recommended
  • Angle: radians
source
TransferMatrix.transferMethod
transfer(λ, layers; θ=0.0, μ=1.0, validate=false)

Calculate the transmittance and reflectance of a layered structure.

Returns a TransferResult with fields Tpp, Tss, Rpp, Rss (and cross-polarization terms Tps, Tsp, Rps, Rsp).

Reflectance and transmittance calculation

Reflectance uses $R = |r|^2$ from the transfer matrix coefficients (Passler & Paarmann 2017, Eq. 17). This is exact for transparent incident media. For absorbing incident media, $|r|^2$ is not a true energy ratio — Poynting vectors become non-additive due to interference cross-terms between incident and reflected waves (Ortiz & Mochan 2005, JOSA A 22, 2827). Proper treatment of that case requires the power_entering formalism (Byrnes 2016, arXiv:1603.02720), which is not yet implemented here.

Transmittance uses Poynting vectors (energy flux ratio $S_out / S_in$) rather than $|t|^2$, because the transmitted wave propagates in a different medium than the incident wave. As noted in the 2019 erratum (JOSAB 36, 3246): $T ≠ |t|^2$ in general; only when the substrate is vacuum does $T = |t|^2$.

Arguments

  • λ: Wavelength in μm (must match units used for layer thicknesses)
  • layers: Vector of Layer objects representing the stack
  • θ: Angle of incidence in radians (default: 0.0, normal incidence)
  • μ: Relative magnetic permeability (default: 1.0, non-magnetic)
  • validate: Check energy conservation R + T ≈ 1 for non-absorbing media (default: false)

Wave Propagation Convention

  • Light propagates in the +z direction (from first layer toward last layer)
  • The first and last layers are treated as semi-infinite media
  • θ is measured from the surface normal (z-axis)

Units

  • Wavelength and thicknesses: μm (micrometers) recommended
  • Angle: radians
  • Transmittance/Reflectance: dimensionless (0 to 1)

Physics Validation

When validate=true, the function checks:

  1. Bounds: 0 ≤ R, T ≤ 1 (catches NaN, negative values, numerical instability)
  2. Energy conservation: R + T ≈ 1 for non-absorbing media (imag(n) < 1e-10)
  3. Absorption bound: R + T ≤ 1 for absorbing media

Warnings are issued for any violations.

source
TransferMatrix.LayerType
Layer(material, thickness)
Layer(nx, ny, nz, thickness)

Construct a single layer for transfer matrix calculations.

Isotropic Layer (single refractive index)

Layer(material, thickness)
  • material: Refractive material (from RefractiveIndex.jl) or a dispersion function λ -> n(λ)
  • thickness: Layer thickness in the same units as wavelength (typically μm)

Anisotropic Layer (biaxial: three refractive indices)

Layer(nx, ny, nz, thickness)
  • nx, ny, nz: Dispersion functions λ -> n(λ) for each principal axis
  • thickness: Layer thickness in μm

For uniaxial materials, set two axes equal (e.g., nx = ny for optic axis along z).

Units Convention

All length quantities (wavelength λ, thickness, dz) must use consistent units. Following RefractiveIndex.jl conventions, micrometers (μm) are recommended.

Layer is parametric as Layer{F,T} where F is the dispersion function type and T is the thickness type. For anisotropic layers, F is a Tuple of three dispersion functions.

Examples

# Isotropic: Using RefractiveIndex.jl material
n_sio2 = RefractiveMaterial("main", "SiO2", "Malitson")
layer = Layer(n_sio2, 0.1)  # 100 nm = 0.1 μm

# Isotropic: Using custom dispersion function
layer = Layer(λ -> 1.5 + 0.01im, 0.25)  # constant n = 1.5 + 0.01i

# Anisotropic: Uniaxial crystal (calcite-like, optic axis along z)
no = λ -> 1.658  # ordinary index
ne = λ -> 1.486  # extraordinary index
layer = Layer(no, no, ne, 0.5)

# Anisotropic: Biaxial crystal
layer = Layer(λ -> 1.5, λ -> 1.6, λ -> 1.7, 0.3)
source
TransferMatrix.LayerMethod
Layer(nx, ny, nz, thickness; euler=(0,0,0))

Construct an anisotropic layer with different refractive indices along each principal axis.

Arguments

  • nx, ny, nz: Dispersion functions λ -> n(λ) for each principal axis
  • thickness: Layer thickness in μm
  • euler: Optional tuple (φ, θ, ψ) of ZYZ Euler angles in radians (default: no rotation)

The dielectric tensor is constructed as a diagonal matrix with εi = ni² in the crystal frame, then rotated to the lab frame using the Euler angles.

Euler Angle Convention (ZYZ)

  • φ (phi): First rotation about z-axis
  • θ (theta): Rotation about new y-axis (tilt angle from z)
  • ψ (psi): Second rotation about new z-axis

Examples

# Uniaxial crystal with optic axis along z (no rotation needed)
layer = Layer(no, no, ne, 0.5)

# Same crystal with optic axis tilted 45° from z in the xz-plane
layer = Layer(no, no, ne, 0.5; euler=(0, π/4, 0))

# Optic axis in the xy-plane at 30° from x
layer = Layer(no, no, ne, 0.5; euler=(π/6, π/2, 0))
source
TransferMatrix.dielectric_constantMethod
dielectric_constant(n_re::Real, n_im::Real)

Return the complex dielectric function from the real and imaginary parts of the index of refraction.

The complex index of refraction, given by

    n' = n_re + i * n_im

(in terms of nre and nim), can be used to obtain the frequency-dependent complex dielectric function

    ε_r(ω) = ε' + iε''

via the relation

    (n_re + i * n_im)^2 = ε' + iε''.
source
TransferMatrix.find_boundsMethod
find_bounds(layers)

Return cumulative thickness positions measured from the start of layer 1, along with the total thickness.

The returned vector has one entry per layer, where entry i is the sum of thicknesses from layer 1 through layer i. These are not interface positions relative to z = 0; callers that need z-coordinates (e.g., efield) must subtract the first layer thickness.

source
TransferMatrix.get_euler_anglesMethod
get_euler_angles(layer::Layer)

Return the Euler angles (φ, θ, ψ) for crystal rotation.

For isotropic layers or unrotated anisotropic layers, returns (0.0, 0.0, 0.0). For rotated anisotropic layers, returns the stored angles.

source
TransferMatrix.get_refractive_indicesMethod
get_refractive_indices(layer::Layer, λ)

Return the refractive indices for a layer at wavelength λ.

For isotropic layers, returns (n, n, n) where n is the scalar refractive index. For anisotropic layers, returns (nx, ny, nz) for each principal axis.

source
TransferMatrix.isanisotropicMethod
isanisotropic(layer::Layer)

Return true if the layer has anisotropic optical properties (different refractive indices along principal axes), false for isotropic layers.

source
TransferMatrix.refractive_indexMethod
refractive_index(material::RefractiveMaterial)

Return a function that takes a wavelength and gives the complex refractive index.

The extinction coefficient availability is checked once at construction time to avoid try-catch overhead in the inner loop of spectral calculations.

source
TransferMatrix.dielectric_tensorMethod
dielectric_tensor(ε1, ε2, ε3)

Return the diagonal complex dielectric tensor

\[\varepsilon = \begin{pmatrix} \varepsilon_1 & 0 & 0 \\0 & \varepsilon_2 & 0 \\0 & 0 & \varepsilon_3 \end{pmatrix}\]

source
TransferMatrix.euler_rotation_matrixMethod
euler_rotation_matrix(φ, θ, ψ)

Return the 3×3 rotation matrix for ZYZ Euler angles (in radians).

This transforms vectors from the crystal frame to the lab frame: v_lab = R * v_crystal

The rotation is performed as: R = Rz(φ) * Ry(θ) * Rz(ψ)

Convention

  • φ (phi): First rotation about z-axis (0 to 2π)
  • θ (theta): Rotation about new y-axis (0 to π) - the tilt angle
  • ψ (psi): Second rotation about new z-axis (0 to 2π)

Common cases

  • Optic axis along z: (0, 0, 0) - no rotation needed
  • Optic axis in xz-plane at angle θ from z: (0, θ, 0)
  • Quarter-wave plate at 45°: (π/4, π/2, 0) for optic axis in xy-plane
source
TransferMatrix.rotate_dielectric_tensorMethod
rotate_dielectric_tensor(ε_diag, R)

Rotate a diagonal dielectric tensor from crystal frame to lab frame.

Given a diagonal tensor ε in the crystal's principal axis frame and a rotation matrix R, returns the rotated tensor: ε_lab = R * ε * R'

Arguments

  • ε_diag: Diagonal dielectric tensor in crystal frame
  • R: 3×3 rotation matrix from euler_rotation_matrix

Returns

Full 3×3 SMatrix (may have off-diagonal elements after rotation)

source

Miscellaneous Optics Functions

TransferMatrix.airyMethod
airy(n0, nf, ns, d, λ; θ=0.0)

Calculate the reflectance and transmittance of a single thin film using the exact Airy formula (multiple-beam interference).

Arguments

  • n0: refractive index of incident medium (can be complex)
  • nf: refractive index of the film (can be complex)
  • ns: refractive index of the substrate (can be complex)
  • d: film thickness (same units as λ)
  • λ: wavelength (same units as d)
  • θ=0.0: angle of incidence in radians

Returns

(Rs, Rp, Ts, Tp) - reflectance and transmittance for s and p polarizations.

Physics

The Airy formula accounts for all multiple reflections within the film:

\[r = \frac{r_{01} + r_{12} e^{2i\delta}}{1 + r_{01} r_{12} e^{2i\delta}}\]

where δ = 2π nf d cos(θf) / λ is the phase thickness and r₀₁, r₁₂ are the Fresnel reflection coefficients at the two interfaces.

This provides an exact analytical solution for validating numerical TMM results.

Example

# Quarter-wave anti-reflection coating
n_air, n_film, n_glass = 1.0, 1.38, 1.52
λ = 0.55  # μm
d = λ / (4 * n_film)  # quarter-wave thickness
Rs, Rp, Ts, Tp = airy(n_air, n_film, n_glass, d, λ)

See also: fresnel, fresnel_coefficients

source
TransferMatrix.dbr_reflectivityMethod
dbr_reflectivity(no, ns, n1, n2, N)

Approximate the reflectivity of a DBR structure with originating medium with refractive index no, substrate with index ns, and alternating materials with indices n1 and n2 and number of repetitions N. The repeated pair of materials are assumed to have quarter-wave thickness $nd = \lambda / 4$, where $n$ is the refractive index, $d$ is the layer thickness, and $\lambda$ is the wavelength of the light.

Distributed Bragg reflector

source
TransferMatrix.fresnelMethod
fresnel(θ, n1, n2)

Calculate the reflectance for s-polarized and p-polarized light given the incidence angle θ (in radians) and indices of refraction of two media n1 and n2 at a plane interface.

Returns (Rs, Rp) where Rs is s-polarized reflectance and Rp is p-polarized reflectance.

The Fresnel equations for reflectance are:

\[R_s = \left| \frac{n_1 \cos\theta_i - n_2 \cos\theta_t}{n_1 \cos\theta_i + n_2 \cos\theta_t} \right|^2\]

\[R_p = \left| \frac{n_2 \cos\theta_i - n_1 \cos\theta_t}{n_2 \cos\theta_i + n_1 \cos\theta_t} \right|^2\]

where $\theta_t$ is the transmitted angle given by Snell's law: $n_1 \sin\theta_i = n_2 \sin\theta_t$.

Special cases:

  • At grazing incidence (θ → π/2), returns (1.0, 1.0)
  • For total internal reflection (when n1 > n2 and θ > θ_critical), returns (1.0, 1.0)

See also: fresnel_coefficients for complex amplitude coefficients.

Fresnel equations

source
TransferMatrix.fresnel_coefficientsMethod
fresnel_coefficients(θ, n1, n2)

Calculate the Fresnel reflection and transmission amplitude coefficients for s-polarized and p-polarized light at a plane interface.

Returns (rs, rp, ts, tp) where:

  • rs, rp: reflection amplitude coefficients (complex)
  • ts, tp: transmission amplitude coefficients (complex)

These are the amplitude (not intensity) coefficients, so reflectance R = |r|² and transmittance requires the full expression T = (n2 cosθt)/(n1 cosθi) |t|².

For total internal reflection, the reflection coefficients have unit magnitude with a phase shift (evanescent wave), and transmission coefficients are zero.

See also: fresnel for intensity reflectances.

source
TransferMatrix.stopbandMethod
stopband(n1, n2)

Calculate the frequency bandwidth Δf of the photonic stopband for a distributed bragg reflector (DBR) with two alternating materials of refractive indices n1 and n2.

\[ \frac{\Delta f_0}{f_0} = \frac{4}{\pi} \arcsin \left( \frac{n_2 - n_1}{n_2 + n_1} \right)\]

Distributed Bragg reflector

source