ExamplesMeep Examples

Oblique Source Waveguide

Eigenmode source injection in a rotated waveguide with transmission analysis

Oblique Source Waveguide

This example demonstrates eigenmode source injection in a rotated waveguide, computing transmission and mode coefficients for arbitrary propagation directions.

Overview

Oblique waveguide sources are essential for:

  • Photonic circuit design: Non-axis-aligned components
  • Grating couplers: Angled light injection
  • Waveguide bends: Smooth direction changes
  • Mode converters: Angled transitions

The eigenmode source automatically adapts to the local waveguide orientation.

Simulation Parameters

ParameterDefault ValueDescription
resolution50Pixels per μm
w1.0Waveguide width
rot_angle20°Rotation angle (CCW)
fsrc0.15Source frequency
bnum1Band number
epsilon12Waveguide permittivity

Physical Setup

The simulation geometry:

  1. Rotated waveguide: Infinite slab at angle θ to x-axis
  2. Eigenmode source: Automatically oriented along waveguide
  3. k-point: Aligned with waveguide direction
  4. Flux monitor: Measures transmitted power

The e1 and e2 vectors define the rotated coordinate system for the waveguide block geometry.

Python Code

"""
Oblique Source Waveguide Simulation with OptixLog Integration

Demonstrates eigenmode source in a rotated waveguide,
computing transmission and field profiles.

Based on the Meep tutorial: oblique-source.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 oblique source waveguide."""
    
    if not optixlog.is_master_process():
        return
    
    try:
        # Simulation parameters
        resolution = 50
        w = 1.0
        rot_angle = np.radians(20)
        rot_angle_degrees = 20
        fsrc = 0.15
        bnum = 1
        compute_flux = True
        eig_src = True
        
        client = optixlog.init(
            api_key=api_key,
            api_url=api_url,
            project=project_name,
            run_name=f"oblique_source_rot{rot_angle_degrees}deg",
            config={
                "simulation_type": "oblique_source",
                "rotation_angle_degrees": rot_angle_degrees,
            },
            create_project_if_not_exists=True
        )
        
        client.log(
            step=0,
            resolution=resolution,
            waveguide_width=w,
            rotation_angle_degrees=rot_angle_degrees,
            frequency=fsrc,
        )
        
        cell_size = mp.Vector3(14, 14)
        pml_layers = [mp.PML(thickness=2)]
        
        # Rotated waveguide geometry
        geometry = [
            mp.Block(
                center=mp.Vector3(),
                size=mp.Vector3(mp.inf, w, mp.inf),
                e1=mp.Vector3(x=1).rotate(mp.Vector3(z=1), rot_angle),
                e2=mp.Vector3(y=1).rotate(mp.Vector3(z=1), rot_angle),
                material=mp.Medium(epsilon=12),
            )
        ]
        
        kpoint = mp.Vector3(x=1).rotate(mp.Vector3(z=1), rot_angle)
        
        if eig_src:
            sources = [
                mp.EigenModeSource(
                    src=mp.GaussianSource(fsrc, fwidth=0.2 * fsrc),
                    center=mp.Vector3(),
                    size=mp.Vector3(y=3 * w),
                    direction=mp.NO_DIRECTION,
                    eig_kpoint=kpoint,
                    eig_band=bnum,
                    eig_parity=mp.ODD_Z,
                    eig_match_freq=True,
                )
            ]
        else:
            sources = [
                mp.Source(
                    src=mp.GaussianSource(fsrc, fwidth=0.2 * fsrc),
                    center=mp.Vector3(),
                    size=mp.Vector3(y=3 * w),
                    component=mp.Ez,
                )
            ]
        
        sim = mp.Simulation(
            cell_size=cell_size,
            resolution=resolution,
            boundary_layers=pml_layers,
            sources=sources,
            geometry=geometry,
        )
        
        if compute_flux:
            tran = sim.add_flux(
                fsrc, 0, 1,
                mp.FluxRegion(center=mp.Vector3(x=5), size=mp.Vector3(y=14))
            )
            
            sim.run(until_after_sources=50)
            
            res = sim.get_eigenmode_coefficients(
                tran,
                [1],
                eig_parity=mp.ODD_Z,
                direction=mp.NO_DIRECTION,
                kpoint_func=lambda f, n: kpoint,
            )
            
            flux_value = mp.get_fluxes(tran)[0]
            mode_coefficient = abs(res.alpha[0, 0, 0]) ** 2
            
            client.log(
                step=1,
                transmission_flux=float(flux_value),
                mode_coefficient_squared=float(mode_coefficient),
            )
        
    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 oblique source simulation
python oblique-source.py

Results and Analysis

Transmission Measurement

The simulation computes:

  • Total flux: Power passing through monitor
  • Mode coefficient: Power in the fundamental mode
  • Transmission efficiency: Ratio of mode power to total flux

Field Pattern

The Ez field shows:

  • Clean mode propagation along rotated waveguide
  • No significant scattering or radiation
  • Phase fronts perpendicular to propagation direction

OptixLog Metrics

  • rotation_angle_degrees: Waveguide rotation
  • transmission_flux: Total transmitted power
  • mode_coefficient_squared: Power in eigenmode
  • transmission_efficiency: Mode purity

The eigenmode source with direction=mp.NO_DIRECTION and explicit eig_kpoint allows injection at arbitrary angles.

Physical Insights

Coordinate Rotation

The waveguide is rotated using:

  • e1: New x-axis direction
  • e2: New y-axis direction
  • Both rotated by rot_angle around z-axis

k-point Selection

For oblique propagation:

  • k-point must align with waveguide
  • kpoint = Vector3(x=1).rotate(Vector3(z=1), angle)
  • Ensures correct phase matching

On this page