ExamplesMeep Examples
Angular Reflectance
Compute reflectance of a dielectric interface as a function of wavelength and angle
Angular Reflectance Simulation
This example computes the reflectance of a dielectric interface as a function of wavelength at oblique incidence, comparing with Fresnel theory.
Overview
Angular reflectance analysis is essential for:
- Anti-reflection coatings: Designing AR layers
- Total internal reflection: Waveguide design
- Brewster angle: Polarization control
- Thin-film optics: Multilayer design
Simulation Parameters
| Parameter | Default Value | Description |
|---|---|---|
resolution | 200 | Pixels per μm |
theta | 0° | Incidence angle |
wvl_min | 0.4 μm | Minimum wavelength |
wvl_max | 0.8 μm | Maximum wavelength |
n_dielectric | 3.5 | Substrate index |
nfreq | 50 | Frequency points |
Physical Setup
- Air half-space: Incident medium (n=1)
- Dielectric substrate: High-index material (n=3.5)
- Oblique incidence: Variable k-vector angle
- Flux normalization: Reference and sample runs
The simulation uses a 1D cell for normal incidence (θ=0) and a 3D cell with Bloch periodicity for oblique incidence.
Python Code
"""
Angular Reflectance Simulation with OptixLog Integration
Computes the reflectance of a dielectric interface as a function
of wavelength at oblique incidence.
"""
import os
import math
import argparse
import optixlog
import meep as mp
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt
import numpy as np
api_key = os.getenv("OPTIX_API_KEY", "")
project_name = os.getenv("OPTIX_PROJECT", "MeepExamples")
def compute_reflectance(resolution, theta):
"""Compute reflectance spectrum for given angle."""
dpml = 1.0
sz = 10 + 2 * dpml
cell_size = mp.Vector3(0, 0, sz)
pml_layers = [mp.PML(dpml)]
wvl_min, wvl_max = 0.4, 0.8
fmin, fmax = 1 / wvl_max, 1 / wvl_min
fcen = 0.5 * (fmin + fmax)
df = fmax - fmin
nfreq = 50
theta_r = math.radians(theta)
k = mp.Vector3(math.sin(theta_r), 0, math.cos(theta_r)).scale(fmin)
dimensions = 1 if theta_r == 0 else 3
sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(0, 0, -0.5 * sz + dpml))]
# Reference simulation (empty)
sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=k, dimensions=dimensions, resolution=resolution)
refl = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, -0.25 * sz)))
sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ex, mp.Vector3(0, 0, -0.5 * sz + dpml), 1e-9))
empty_flux = mp.get_fluxes(refl)
empty_data = sim.get_flux_data(refl)
sim.reset_meep()
# With dielectric
n_dielectric = 3.5
geometry = [mp.Block(size=mp.Vector3(mp.inf, mp.inf, 0.5 * sz), center=mp.Vector3(0, 0, 0.25 * sz), material=mp.Medium(index=n_dielectric))]
sim = mp.Simulation(cell_size=cell_size, geometry=geometry, boundary_layers=pml_layers, sources=sources, k_point=k, dimensions=dimensions, resolution=resolution)
refl = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, -0.25 * sz)))
sim.load_minus_flux_data(refl, empty_data)
sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ex, mp.Vector3(0, 0, -0.5 * sz + dpml), 1e-9))
refl_flux = mp.get_fluxes(refl)
freqs = mp.get_flux_freqs(refl)
return {'wavelengths': [1/f for f in freqs], 'reflectances': [-refl_flux[i]/empty_flux[i] for i in range(nfreq)]}
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-res", type=int, default=200)
parser.add_argument("-theta", type=float, default=0)
args = parser.parse_args()
if not optixlog.is_master_process():
return
try:
client = optixlog.init(api_key=os.getenv("OPTIX_API_KEY"), project="MeepExamples", run_name=f"angular_reflectance_theta{args.theta}", config={"simulation_type": "reflectance"}, create_project_if_not_exists=True)
client.log(step=0, resolution=args.res, incidence_angle=args.theta)
results = compute_reflectance(args.res, args.theta)
client.log(step=1, max_reflectance=float(max(results['reflectances'])), mean_reflectance=float(np.mean(results['reflectances'])))
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()How to Run
# Normal incidence
python refl-angular.py -theta 0
# Oblique incidence
python refl-angular.py -theta 30
python refl-angular.py -theta 60Results and Analysis
Reflectance Spectrum
Results show:
- Normal incidence: R = ((n-1)/(n+1))² ≈ 30% for n=3.5
- Oblique angles: Varies with polarization and angle
- Brewster angle: Zero reflectance for p-polarization
Fresnel Comparison
The s-polarization reflectance:
Rs = |n₁cosθ₁ - n₂cosθ₂|² / |n₁cosθ₁ + n₂cosθ₂|²OptixLog Metrics
incidence_angle_degrees: Input anglefresnel_theory_reflectance: Analytical predictionmeep_mean_reflectance: FDTD result
Related Examples
- Binary Grating - Diffraction
- Faraday Rotation - Polarization effects