Material Dispersion
Extract the frequency-dependent dielectric function from dispersive material simulations
Material Dispersion Analysis
This example simulates a homogeneous dispersive material and extracts the dielectric function ε(ω) from the mode frequencies using a k-point sweep.
Overview
Material dispersion is critical for:
- Pulse propagation: Group velocity and chirp
- Resonant phenomena: Plasmonic and phononic effects
- Metamaterials: Engineering effective permittivity
- Chromatic aberration: Lens and waveguide design
This simulation uses Lorentzian susceptibilities to model realistic materials with resonances.
Simulation Parameters
| Parameter | Default Value | Description |
|---|---|---|
resolution | 20 | Pixels per μm |
fcen | 1.0 | Pulse center frequency |
df | 2.0 | Pulse frequency width |
kmin | 0.3 | Minimum k-vector |
kmax | 2.2 | Maximum k-vector |
k_interp | 99 | Number of k-points |
Material Model
The dispersive material has two Lorentzian resonances:
| Resonance | Frequency | Gamma | Sigma | Description |
|---|---|---|---|---|
| 1 | 1.1 | 1e-5 | 0.5 | Strong polaritonic gap |
| 2 | 0.5 | 0.1 | 2e-5 | Weak absorption |
Background permittivity: ε_∞ = 2.25
The Lorentzian model: ε(ω) = ε_∞ + Σ σᵢω₀ᵢ²/(ω₀ᵢ² - ω² - iωγᵢ)
Python Code
"""
Material Dispersion Analysis with OptixLog Integration
Simulates homogeneous dispersive material and extracts the
dielectric function epsilon(omega) from mode frequencies.
Based on the Meep tutorial: material-dispersion.py
"""
import os
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", "")
api_url = os.getenv("OPTIX_API_URL", "https://optixlog.com")
project_name = os.getenv("OPTIX_PROJECT", "MeepExamples")
def main():
"""Main simulation function for material dispersion analysis."""
if not optixlog.is_master_process():
return
try:
client = optixlog.init(
api_key=api_key,
api_url=api_url,
project=project_name,
run_name="material_dispersion_analysis",
config={
"simulation_type": "dispersion",
"description": "Material dispersion analysis",
},
create_project_if_not_exists=True
)
# Simulation parameters
resolution = 20
fcen = 1.0
df = 2.0
kmin = 0.3
kmax = 2.2
k_interp = 99
# Material resonances
resonance1_freq = 1.1
resonance1_gamma = 1e-5
resonance1_sigma = 0.5
resonance2_freq = 0.5
resonance2_gamma = 0.1
resonance2_sigma = 2e-5
background_epsilon = 2.25
client.log(
step=0,
resolution=resolution,
center_frequency=fcen,
k_min=kmin,
k_max=kmax,
background_epsilon=background_epsilon,
resonance1_frequency=resonance1_freq,
resonance2_frequency=resonance2_freq
)
# Set up dispersive material
susceptibilities = [
mp.LorentzianSusceptibility(
frequency=resonance1_freq,
gamma=resonance1_gamma,
sigma=resonance1_sigma
),
mp.LorentzianSusceptibility(
frequency=resonance2_freq,
gamma=resonance2_gamma,
sigma=resonance2_sigma
),
]
default_material = mp.Medium(
epsilon=background_epsilon,
E_susceptibilities=susceptibilities
)
# Set up simulation (point cell)
cell = mp.Vector3()
sources = [
mp.Source(
mp.GaussianSource(fcen, fwidth=df),
component=mp.Ez,
center=mp.Vector3()
)
]
kpts = mp.interpolate(k_interp, [mp.Vector3(kmin), mp.Vector3(kmax)])
sim = mp.Simulation(
cell_size=cell,
geometry=[],
sources=sources,
default_material=default_material,
resolution=resolution,
)
all_freqs = sim.run_k_points(200, kpts)
client.log(step=1, simulation_completed=True)
# Process results
k_data = []
freq_real_data = []
epsilon_data = []
for fs, kx in zip(all_freqs, [v.x for v in kpts]):
for f in fs:
if f.real > 0:
eps_calc = (kx / f) ** 2
k_data.append(kx)
freq_real_data.append(f.real)
epsilon_data.append(eps_calc.real)
if freq_real_data:
client.log(
step=2,
total_data_points=len(freq_real_data),
frequency_range_min=float(min(freq_real_data)),
frequency_range_max=float(max(freq_real_data)),
epsilon_range_min=float(min(epsilon_data)),
epsilon_range_max=float(max(epsilon_data))
)
except Exception as e:
print(f"Simulation Error: {e}")
if __name__ == "__main__":
main()How to Run
# Set your OptixLog API key
export OPTIX_API_KEY="your_api_key_here"
# Run the dispersion analysis
python material-dispersion.pyResults and Analysis
Dispersion Relation ω(k)
The simulation extracts the relationship between frequency and wavevector:
- Light line: Reference for vacuum propagation
- Polariton branches: Above and below the resonance
- Band gap: Region where ε < 0 (no propagating modes)
Dielectric Function ε(ω)
From the dispersion relation, ε = (k/ω)² × c²:
- Below resonance: ε > ε_∞, slower light
- At resonance: Rapid ε variation, absorption
- Above resonance: ε can be negative or approach ε_∞
Refractive Index n(ω)
The refractive index n = √ε shows:
- Normal dispersion: n increases with ω (away from resonances)
- Anomalous dispersion: n decreases near resonances
OptixLog Metrics
background_epsilon: High-frequency limitresonance1_frequency,resonance2_frequency: Resonance locationsfrequency_range_min/max: Extracted frequency rangeepsilon_range_min/max: ε(ω) variation
Near resonances, the imaginary part of ε (absorption) becomes significant. Use small gamma for sharp resonances.
Physical Insights
Lorentzian Model
The Lorentzian susceptibility models bound electron oscillators:
- Low frequency: Electrons follow field adiabatically
- At resonance: Maximum energy transfer, absorption peak
- High frequency: Electrons can't follow, ε → ε_∞
Kramers-Kronig Relations
Real and imaginary parts of ε are related:
- Strong absorption → strong dispersion nearby
- Helps validate simulation results
Related Examples
- Faraday Rotation - Magneto-optical dispersion
- Holey Waveguide Bands - Photonic band structures