Metagrating

Metagrating#

The metagrating challenge entails designing a beam deflector that couples a normally-incident plane wave into one with a polar angle of 50 degrees. This problem was studied in “Validation and characterization of algorithms and software for photonics inverse design” by Chen et al.; the associated photonics-opt-testbed repo contains several example designs.

Simulating an existing design#

We’ll begin by loading, visualizing, and simulating designs from the photonics-opt-testbed repo.

import matplotlib.pyplot as plt
import numpy as onp
from skimage import measure


def load_design(name):
    path = f"../../../reference_designs/metagrating/{name}.csv"
    return onp.genfromtxt(path, delimiter=",")


names = ["device1", "device2", "device3", "device4", "device5"]
designs = [load_design(name) for name in names]

plt.figure(figsize=(7, 4))
for i, design in enumerate(designs):
    ax = plt.subplot(1, 5, i + 1)
    im = ax.imshow(1 - design, cmap="gray")
    im.set_clim([-2, 1])
    contours = measure.find_contours(design)
    for c in contours:
        plt.plot(c[:, 1], c[:, 0], "k", lw=1)
    ax.set_xticks([])
    ax.set_yticks([])
../../_images/fe6d21f9b7aa5da3b6d5f4b1b8befe873de629846b42a9a77ea9c10b946e5140.png

Now, we’ll create a metagrating challenge, which provides everything we need to simulate and optimize the metagrating.

from invrs_gym import challenges

challenge = challenges.metagrating()

To simulate the metagrating, we need to provide a totypes.types.Density2DArray object to the challenge.component.params method. Obtain dummy parameters using component.init, and then overwrite the array attribute with the reference design that we want to simulate.

import dataclasses
import jax

dummy_params = challenge.component.init(jax.random.PRNGKey(0))
params = dataclasses.replace(dummy_params, array=load_design("device1"))

# Perform simulation using component response method.
response, aux = challenge.component.response(params)

The response contains the transmission and reflection efficiency into each diffraction order, and for TE- and TM-polarized cases. However, we only care about TM diffraction into the +1 order. Fortunately, the challenge has a metrics method that extracts this value.

metrics = challenge.metrics(response, params=params, aux=aux)
print(f"TM transmission into +1 order: {metrics['average_efficiency'] * 100:.1f}%")
TM transmission into +1 order: 95.6%

Now let’s take a look at the remaining designs.

for name in names:
    params = dataclasses.replace(dummy_params, array=load_design(name))
    response, aux = challenge.component.response(params)
    metrics = challenge.metrics(response, params=params, aux=aux)
    print(
        f"{name} TM transmission into +1 order: {metrics['average_efficiency'] * 100:.1f}%"
    )
device1 TM transmission into +1 order: 95.6%
device2 TM transmission into +1 order: 93.5%
device3 TM transmission into +1 order: 95.0%
device4 TM transmission into +1 order: 91.3%
device5 TM transmission into +1 order: 83.0%

These values are all very close to those reported in the photonics-opt-testbed, indicating that our simulation is converged.