ExamplesMeep Examples

Straight Waveguide

Basic straight waveguide transmission simulation

Straight Waveguide

This example demonstrates the fundamental simulation of electromagnetic wave propagation through a straight dielectric waveguide.

Beginner Level: This is an ideal starting point for learning Meep basics.


Physics Background

Waveguide Principle

A dielectric waveguide confines light through total internal reflection when:

$$ n_{core} > n_{cladding} $$

Guided modes satisfy the eigenvalue equation and propagate without radiation loss.

Key Parameters

  • V-number: V = (2πr/λ)√(n₁² - n₂²)
  • Single-mode: V < 2.405
  • Multi-mode: V > 2.405

Complete Code

"""
Straight Waveguide Simulation with OptixLog Integration

Basic waveguide transmission analysis.
"""

import os
import meep as mp
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt
import numpy as np
from optixlog import Optixlog


def main():
    api_key = os.getenv("OPTIX_API_KEY", "your_api_key_here")
    
    client = Optixlog(api_key=api_key)
    project = client.project(name="MeepExamples", create_if_not_exists=True)
    
    # Parameters
    resolution = 10
    cell_x = 16
    cell_y = 8
    dpml = 1.0
    w = 1.0  # waveguide width
    epsilon = 12.0
    fcen = 0.15
    df = 0.1
    nfreq = 100
    
    run = project.run(
        name="straight_waveguide",
        config={
            "simulation_type": "straight_waveguide",
            "resolution": resolution,
            "cell_size": [cell_x, cell_y],
            "waveguide_width": w,
            "waveguide_epsilon": epsilon,
            "center_frequency": fcen
        }
    )
    
    run.log(step=0, resolution=resolution, waveguide_width=w)
    
    cell = mp.Vector3(cell_x, cell_y)
    pml_layers = [mp.PML(dpml)]
    
    geometry = [
        mp.Block(
            center=mp.Vector3(),
            size=mp.Vector3(mp.inf, w, mp.inf),
            material=mp.Medium(epsilon=epsilon)
        )
    ]
    
    sources = [
        mp.Source(
            mp.GaussianSource(fcen, fwidth=df),
            component=mp.Ez,
            center=mp.Vector3(-cell_x/2 + dpml + 1, 0),
            size=mp.Vector3(0, w)
        )
    ]
    
    sim = mp.Simulation(
        cell_size=cell,
        geometry=geometry,
        sources=sources,
        boundary_layers=pml_layers,
        resolution=resolution
    )
    
    # Flux monitors
    input_fr = mp.FluxRegion(
        center=mp.Vector3(-cell_x/2 + dpml + 2, 0),
        size=mp.Vector3(0, 2*w)
    )
    input_flux = sim.add_flux(fcen, df, nfreq, input_fr)
    
    output_fr = mp.FluxRegion(
        center=mp.Vector3(cell_x/2 - dpml - 1, 0),
        size=mp.Vector3(0, 2*w)
    )
    output_flux = sim.add_flux(fcen, df, nfreq, output_fr)
    
    print("⚡ Running simulation...")
    pt = mp.Vector3(cell_x/2 - dpml - 1, 0)
    sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, pt, 1e-3))
    
    # Extract results
    input_power = mp.get_fluxes(input_flux)
    output_power = mp.get_fluxes(output_flux)
    freqs = mp.get_flux_freqs(input_flux)
    
    transmission = [output_power[i] / input_power[i] 
                   for i in range(len(freqs)) if input_power[i] > 0]
    wavelengths = [1/f for f in freqs[:len(transmission)]]
    
    # Log metrics
    run.log(step=1,
            max_transmission=float(max(transmission)),
            avg_transmission=float(np.mean(transmission)))
    
    # Create plots
    fig, axes = plt.subplots(2, 2, figsize=(14, 10))
    
    # Transmission spectrum
    axes[0, 0].plot(wavelengths, transmission, 'b-', linewidth=2)
    axes[0, 0].set_xlabel('Wavelength (μm)')
    axes[0, 0].set_ylabel('Transmission')
    axes[0, 0].set_title('Transmission Spectrum')
    axes[0, 0].grid(True, alpha=0.3)
    axes[0, 0].set_ylim(0, 1.1)
    
    # Transmission vs frequency
    axes[0, 1].plot(freqs[:len(transmission)], transmission, 'r-', linewidth=2)
    axes[0, 1].set_xlabel('Frequency (c/a)')
    axes[0, 1].set_ylabel('Transmission')
    axes[0, 1].set_title('Transmission vs Frequency')
    axes[0, 1].grid(True, alpha=0.3)
    
    # Field distribution
    ez_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Ez)
    im1 = axes[1, 0].imshow(np.real(ez_data).T, cmap='RdBu', origin='lower')
    axes[1, 0].set_title('Ez Field')
    plt.colorbar(im1, ax=axes[1, 0])
    
    # Structure
    eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric)
    im2 = axes[1, 1].imshow(eps_data.T, cmap='binary', origin='lower')
    axes[1, 1].set_title('Waveguide Structure (ε)')
    plt.colorbar(im2, ax=axes[1, 1])
    
    plt.tight_layout()
    run.log_matplotlib("waveguide_analysis", fig)
    plt.close(fig)
    
    run.log(step=2, simulation_completed=True)
    
    print(f"📊 Transmission: {np.mean(transmission):.4f}")
    print(f"\n✅ Simulation complete!")


if __name__ == "__main__":
    main()

Key Concepts

Simple Geometry

geometry = [
    mp.Block(
        center=mp.Vector3(),
        size=mp.Vector3(mp.inf, w, mp.inf),
        material=mp.Medium(epsilon=12)
    )
]

Line Source

sources = [
    mp.Source(
        mp.GaussianSource(fcen, fwidth=df),
        component=mp.Ez,
        center=mp.Vector3(x, 0),
        size=mp.Vector3(0, w)  # Line in y-direction
    )
]

Expected Results

High Transmission

A straight waveguide should have:

  • Transmission > 95% (ideally ~100%)
  • Flat spectrum across bandwidth
  • Clean mode profile

Loss Sources

Any loss comes from:

  • Numerical dispersion
  • PML absorption
  • Mode mismatch at source

OptixLog Integration

Logged Metrics

MetricDescription
waveguide_widthCore width
max_transmissionPeak T value
avg_transmissionMean T value

Logged Plots

  • waveguide_analysis — 4-panel comprehensive view

Variations

Different Polarizations

Change component=mp.Ez to mp.Hz for TM polarization.

Multi-mode Waveguide

Increase width w for higher-order modes.

Different Materials

Try silicon (ε=12) vs silicon nitride (ε=4).

On this page