import meep as mp
import meep.adjoint as mpa
import numpy as np
import autograd.numpy as npa
import math
from matplotlib import pyplot as plt
resolution = 50 # pixels/μm
nSi = 3.45
Si = mp.Medium(index=nSi)
nSiO2 = 1.45
SiO2 = mp.Medium(index=nSiO2)
theta_d = math.radians(50.0) # deflection angle
wvl = 1.05 # wavelength
fcen = 1/wvl
px = wvl/math.sin(theta_d) # period in x
py = 0.5*wvl # period in y
dpml = 1.0 # PML thickness
gh = 0.325 # grating height
dsub = 5.0 # substrate thickness
dair = 5.0 # air padding
sz = dpml+dsub+gh+dair+dpml
cell_size = mp.Vector3(px,py,sz)
boundary_layers = [mp.PML(thickness=dpml,direction=mp.Z)]
# plane of incidence is XZ
src_pt = mp.Vector3(0,0,-0.5*sz+dpml+0.5*dsub)
sources = [mp.Source(src=mp.GaussianSource(fcen,fwidth=0.1*fcen),
size=mp.Vector3(px,py,0),
center=src_pt,
component=mp.Ex)]
design_region_resolution = 2*resolution
Nx, Ny, Nz = int(round(design_region_resolution * px)), int(round(design_region_resolution * py)), 1
design_variables = mp.MaterialGrid(mp.Vector3(Nx, Ny, Nz), mp.air, Si, do_averaging=False, grid_type="U_MEAN")
design_region = mpa.DesignRegion(design_variables,
volume=mp.Volume(center=mp.Vector3(0,0,-0.5*sz+dpml+dsub+0.5*gh),
size=mp.Vector3(px,py,gh)))
geometry = [mp.Block(center=mp.Vector3(0,0,-0.5*sz+0.5*(dpml+dsub)),
size=mp.Vector3(mp.inf,mp.inf,dpml+dsub),
material=SiO2),
mp.Block(center=design_region.center,
size=design_region.size,
material=design_variables)]
sim = mp.Simulation(resolution=resolution,
cell_size=cell_size,
sources=sources,
geometry=geometry,
boundary_layers=boundary_layers,
k_point=mp.Vector3(),
eps_averaging=False)
mode = 1
emc = mpa.EigenmodeCoefficient(sim,
mp.Volume(center=mp.Vector3(0,0,0.5*sz-dpml),size=mp.Vector3(px,py,0)),
mode)
ob_list = [emc]
def J(emc):
return npa.abs(emc[0])**2
opt = mpa.OptimizationProblem(simulation=sim,objective_functions=J,objective_arguments=ob_list,
design_regions=[design_region],fcen=fcen,df=0,nf=1,decay_by=1e-12)
np.random.seed(20221119)
x0 = 0.5*np.ones(Nx*Ny)
f0, dJ_dn = opt([x0])
db,choose = 1e-4,5
g_discrete, idx = opt.calculate_fd_gradient(num_gradients=choose,db=db)
g_discrete = np.array(g_discrete).flatten()
g_adjoint = dJ_dn.flatten()
print("Randomly selected indices: ",idx)
print("Finite-difference gradient: ",g_discrete)
print("Adjoint gradient: ",g_adjoint[idx])
plt.plot(g_discrete,g_adjoint[idx],"ro")
plt.plot(g_discrete,g_discrete,"g-",label="y=x")
plt.xlabel("Finite-difference gradient")
plt.ylabel("Adjoint gradient")
plt.legend();
The adjoint and finite-difference gradients are inconsistent when the

EigenmodeCoefficientadjoint solver in Meep is applied to a case similar to that in @oskooi's metagrating-meep.py. The tests were based on the latest version of Meep, namely, v1.25.0. The code ran with 32 processes. The comparisons between adjoint and finite-difference gradients are as follows.The code is as follows. It defines the same geometry as that in metagrating-meep.py, but does not include
DiffractedPlanewaveand the input flux.