-
Notifications
You must be signed in to change notification settings - Fork 631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Non-reproducible outputs from adjoint solver (memory leak?) #1262
Comments
Workaround: call |
Weird. This should be resolved with #1242. But I'll test it just to make sure. Thanks for the heads up and the detailed bug report. |
I've traced the issue down to this line: meep/python/adjoint/optimization_problem.py Line 229 in 1c5bdbf
What's weird is that the actual forward fields and adjoint fields themselves are calculated and stored properly. But you occasionally get weird results once you multiply. Since this routine is completely changed in #1242 (all of this will be done in C) I don't think it's worth looking into right now. I will make sure this issue doesn't happen with the new routine, however. |
Yes, I traced some warnings down to that line too. The value of Raw code: import numpy as np
import meep as mp
import sys
sys.path.append("/Users/ryan.hamerly/Documents/Research/Code/meep/python")
import adjoint as mpa # Note unconventional way of loading meep.adjoint
import autograd.numpy as npa
import matplotlib.pyplot as plt
import nlopt
# Constants
lam = 0.532; f0 = 1/lam; df = 0.2*f0; res = 20
n_SiO2 = 1.45; SiO2 = mp.Medium(index=n_SiO2)
spc = 1; dpml = 1
(sx, sy) = (10, 7)
(Sx, Sy) = (sx+2*dpml, sy+2*dpml)
# Design region parameters
dr_res = 10
dr = mp.Volume(center=mp.Vector3(0, -2.4), size=mp.Vector3(sx, 0.2))
dv = mpa.BilinearInterpolationBasis(volume=dr, resolution=dr_res)
(Nx, Ny) = (dv.Nx, dv.Ny)
# Define optimization problem.
src_gauss = [mp.Source(mp.GaussianSource(f0, fwidth=df),
center=mp.Vector3(0, -(sy/2-0.1)), size=mp.Vector3(sx, 0), component=mp.Ez)]
geom = [mp.Block(center=dr.center, size=dr.size, epsilon_func=dv.func())]
sim = mp.Simulation(cell_size=mp.Vector3(Sx, Sy), resolution=res, boundary_layers=[mp.PML(dpml)],
geometry=geom, sources=src_gauss, default_material=SiO2, eps_averaging=False)
TE0 = mpa.EigenmodeCoefficient(sim, mp.Volume(center=mp.Vector3(0, 2.6), size=mp.Vector3(0.7*lam, 0)), mode=1,
eig_parity=mp.ODD_Z)
def J(alpha): return npa.abs(alpha)**2
opt = mpa.OptimizationProblem(sim, J, [TE0], [dv], fcen=f0, df=0, nf=1, decay_fields=[mp.Ez])
# Show problem geometry and optimization region.
x0 = n_SiO2**2 * np.ones(Nx*Ny)
opt.update_design([x0])
opt.plot2D(True, eps_parameters=dict(cmap='binary_r'))
plt.savefig("Note14c-setup.pdf", format="pdf")
plt.show()
# Run optimizer twice.
mp.quiet(True)
(J0_1, dJ_1, dg_1) = opt([x0])
(J0_2, dJ_2, dg_2) = opt([x0])
# Plot dJ and phase curve that it *should* follow
# In addition, the two results *should* be the same but aren't (off by a constant offset).
(f, (ax1, ax2)) = plt.subplots(2, 1, figsize=(8, 4.5))
for (ax, dJ, n) in zip([ax1, ax2], [dJ_1, dJ_2], [1, 2]):
X = np.linspace(-sx/2, sx/2, 501)
Y = -(-sy/2+spc-0.1) - (dr.center.y)
ax.plot(X, np.cos(n_SiO2*2*np.pi/lam*(np.sqrt(X**2 + Y**2) - Y)))
cax = ax.imshow(np.squeeze(dJ).T, extent=[-sx/2, sx/2, -0.1, 0.1], origin='lower')
ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_title(f"[Run {n}]: " + r"Phase $e^{i k r}$ (line), Gradient $dJ/d\epsilon$ (fill)")
f.colorbar(cax, ax=ax, orientation='vertical').set_label(r"$dJ/d\epsilon$")
plt.tight_layout(); plt.savefig("Note14c-phase.pdf", format="pdf"); plt.show()
# Plot forward and adjoint runs to convince ourselves the simulation is set up right
(f, (ax1, ax2)) = plt.subplots(1, 2, figsize=(9, 4))
opt.prepare_forward_run()
opt.sim.run(until=20)
opt.sim.plot2D(ax=ax1, fields=mp.Ez, eps_parameters=dict(alpha=0)); ax1.set_title("Forward, $t=20$")
opt.adjoint_run()
opt.sim.reset_meep()
opt.sim.run(until=20)
opt.sim.plot2D(ax=ax2, fields=mp.Ez, eps_parameters=dict(alpha=0)); ax2.set_title("Adjoint, $t=20$")
plt.tight_layout(); plt.savefig("Note14c-sims.pdf", format="pdf"); plt.show() |
Okay, I think I got it. The source you are specifying is polarized out of plane ( All of my test cases involved eigenmode sources, which have components in-plane and out-of-plane. So I never picked up on this. We should modify the field storage routines to account for this (currently In the meantime, a clever hack is to specify a source in-plane with zero amplitude: src_gauss = [mp.Source(mp.GaussianSource(f0, fwidth=df),
center=mp.Vector3(0, -(sy/2-0.1)), size=mp.Vector3(sx, 0), component=mp.Ez),
mp.Source(mp.GaussianSource(f0, fwidth=df),
center=mp.Vector3(0, -(sy/2-0.1)), size=mp.Vector3(sx, 0),amplitude=0, component=mp.Ex)] |
Yes, I can confirm that the workaround works. Thanks! |
Under certain conditions, when I create an an
OptimizationProblem
instanceopt = mpa.OptimizationProblem(...)
and then runopt([x])
multiple times, the result can be very different for the first run (oftennan
), e.g. if I runI find that
dJ_a
differs fromdJ_b
,dJ_c
and is often very large,inf
, ornan
. It's only the calculation ofdJ
that gets messed up; the actual simulations look fine (figures below). One possibility ismeep.adjoint
is reading from the array memory that hasn't been initialized or is already freed (I've run into this with autograd elsewhere).Note14b-dJ.pdf
Note14b-sims.pdf
Full code below:
The text was updated successfully, but these errors were encountered: