Closed DurhamSmith closed 2 years ago
For this particular problem, the objective function seems to involve focusing the fields within a homogeneous medium (i.e., free space) rather than maximizing transmission into a guided mode (as in the tutorial example you referenced involving the power splitter). You should therefore be using the FourierFields
objective function of the adjoint solver rather than the EigenModeCoefficients
as the latter is better suited to computing quantities such as scattering parameters. An example that is more closely related to designing a Bayer filter is a broadband metalens which is demonstrated in https://nbviewer.org/github/NanoComp/meep/blob/master/python/examples/adjoint_optimization/Near2Far-Optimization-with-Epigraph-Formulation.ipynb. Note that if your structure is rotationally symmetric, you can set it up in cylindrical rather than Cartesian coordinates which therefore converts a 3d simulation into 2d (a potentially large savings in memory and time).
(Separately, we will soon be revamping the tutorials for the adjoint solver since currently many of them are out of date.)
Thanks @oskooi I appreciate the help! I will make the changes and see if I can get this working. I'll leave this issue open for now until I have tested them but will close if they work.
Here's a few suggestions I have:
As @oskooi mentioned, use FourierFields
, rather than EigenmodeCoefficients
. Optimize a single field component at a single spatial point for each frequency.
Since the frequencies you care about are so far apart, just define two sources. For example, something like
sources = [mp.EigenmodeSource(mp.ContinuousSource(f,fwidth=0.2*f),<<other args here>>) for f in [1/0.5, 1/0.6]]
This is actually better because the mode profile is computed at each frequency of interest. If you try to do a single source, the spatial profile is only calculated at the center frequency, and you could see some errors from mode dispersion.
Your objective function needs to properly parse where each freq focuses (if you are truly trying to replicate the paper). And you just need to optimize the frequencies you truly care about (e.q. frequencies=[1/0.5, 1/0.6]
).
@smartalecH thanks for the help! I have made these adjustments to the simulation but is seems that by changing the sources to a ContinuousSource the simulation never completes 1 forward run of the adjoint method.
I am assuming that is because ContinuousSource.end_time=1.0e20
. If I only turn on the source for 1 period i.e
sources = [mp.EigenmodeSource(mp.ContinuousSource(f,fwidth=0.2*f, end_time=1/f),<<other args here>>) for f in [1/0.5, 1/0.6]]
would that be enough for adjoint optimization in Meep or is there some other heuristic I should follow to compute how long a ContinuousSource
should be turned on for with a FourierField
objective? I take it the forward simulation doesn't end after the source is turned off and controlled by OptitimzationProblem.decay_by
?
I have tried to make the suggested changes, leaving me with my objective functions as:
the OptimizationProblem.objective_functions
as:
def J(source, top, bottom):
obj_fn = npa.array(
[
npa.mean(npa.abs(top[0] ** 2) / npa.abs(bottom[0] ** 2)),
npa.mean(npa.abs(bottom[1] ** 2) / npa.abs(top[1] ** 2)),
]
)
return obj_fn
And the cost function passed to the nlopt.LD_MMA
solver:
def f(x, grad):
f0, dJ_du = opt([x])
if grad.size > 0:
grad[:] = npa.sum(dJ_du)
evaluation_history.append(np.real(f0))
sensitivity[0] = dJ_du
cur_iter[0] = cur_iter[0] + 1
ax = plt.gca()
opt.plot2D(
False,
ax=ax,
plot_sources_flag=False,
plot_monitors_flag=False,
plot_boundaries_flag=False,
)
if mp.am_master():
plt.savefig(f"./{filename}/new_splitter_{cur_iter[0]}.png", dpi=300)
return np.real(f0)
This runs fine for the forward runs and seems to calculate the gradient in the nlopt
optimization. But right after returning from f
I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/InverseDesign/meep/new_splitter/new_splitter_freespace.py", line 421, in <module>
x[:] = solver.optimize(x)
File "/home/user/anaconda3/envs/pmp/lib/python3.9/site-packages/nlopt.py", line 335, in optimize
return _nlopt.opt_optimize(self, *args)
ValueError: nlopt invalid argument
I am not sure if this is an issue with how I am setting up J
or how I am handling the gradients in f
. It seems like grad
is the correct shape ((10000,)
both when entering and leaving J
). Any insight would be greatly appreciated.
Whoops sorry I meant multiple GaussianSource
time profiles. That was a typo.
Recall that a ContinuousSource
cannot be used with the current flavor of adjoint simulations, as the DFT fields would never converge.
Also your objective function is currently outputting two values (multi objective). You either need to do an epigraph (see the tutorials) or sum your objective so that it's scalar-valued (note this is not unique to meep, but rather an intrinsic characteristic of multi-objective optimization).
This is more of a topic for the mailing list but #1875 seems to indicate that is down with no other alternative as of yet so I am posting this here.
I would like to recreate the Bayer filter of the Faraon group in Meep.
At the moment I am trying to familiarize myself with adjoint optimization in Meep by adapting the examples to create new devices. I am currently trying to create an a 2um x 2um 2D element that focuses incoming EM radiation in the visible spectrum onto 1um plane parallel to the y axis and located 1.5um the device (along the x direction), while minimizing EM radiation focused to the region that is the mirror image of this plane along x=0. You can see this device in the figure below.
I have tried two different figures of merit to accomplish this, with no luck. They are
npa.sum(npa.abs(top / source) ** 2) / (npa.abs(bottom / source) ** 2)
andnpa.sum(npa.abs(top / source) ** 2 - 0.75 * npa.abs(bottom / source) ** 2)
I have tried to debug the issue for a few days now and have noticed a few things.
In the Design of a Symmetric Broadband Splitter the value of fwidth passed to the source is
fwidth=0.1282051282051282
. Plotting this it looks like it corresponds to the full width at half max value (ignore y-label and key value, these are from the source monitor).However when I use values of
fcen=1/0.55
andfwidth=0.3
I get the following for the values measured at the source monitor:Which doesn't give me the full width half max range between [0.4, 0.7] as I'd expect. Although the fields at each of the monitors looks good:
However the ratios of arm/source monitors are out of wack for the frequencies where the the source is very small (understandably so, since we are dividing by tiny numbers):
Keeping
fcen=1/0.55
andfwidth=0.3
but limiting the wavelengths used in the objective function to [0.535, 0.575] I have better values for the initial monitor measurements and power splitting between the focus and antifocus region:However when I run this simulation for 20 iterations I get the following plot of how my figure of merit improves seems to taper off as can be seen in this plot:
The monitor measurements and ratios are:
So it does seem I get a little bit of an improvement in focusing onto the top source monitor, it is not uniform across spectrum and hardly improves after the 8th iteration
I have not (yet) incorporated any erosion or dilation filters. I assume these, while good for incorporating manufacturing constraints would hinder device performance, rather than boost it, and I want to find the source of the flattening of the FOM curve before complicating the problem further.
I would appreciate any advice on how to fix this or how to better understand what is going on so that I can be better equipped to solve these problems by myself in the future. am rather new to computational EM and am trying to develop a better understanding of setting up and modeling devices as well as debugging any issues with the simulations.
It would also be great to know is there a way to save and load OptimizationProblems? I assume its not the same as loading and dumping simulation state as that dumps epsion but OptimizationProblems take DesignRegions which store information about the ranges of epsilon
Additionally any advice for modeling the air-polymer device in the paper I posted would be tremendously appreciated.
The code for the simulation is: