-
Notifications
You must be signed in to change notification settings - Fork 641
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
Computing gradients at any location within the simulation domain #1438
Comments
Older versions of the code actually did this... as you say you can pull the forward and adjoint fields directly from the yee grid and interpolate wherever you need the gradient. The advantage of the current infrastructure is that it allows multiple grids to interact (e.g. symmetries, rotations, constraints, etc.). The ugly part is backpropagating through the material grid interpolation scheme (especially when you have that much flexibility). If you don't need that flexibility you can tweak the adjoint codebase to do what was done with the initial release of adjoint solver 2.0 (#1167). Or if you are feeling extra ambitious, you can find a way to include both methods :-) |
Thanks for the response Alec. To handle symmetries, rotations, and other constraints on a grid parameterization, one could perform those operations entirely outside of Meep in a suitable automatic differentiation framework (autograd in Meep's case). In that situation you get the backpropagation through those operations for "free" and the user can compose their density array using any graph of differentiable operations. Meep would only need to receive a single array to interpolate onto the Yee grid. Here, it sounds like you're saying that your goal was to support the different cases of the All of the above is tied to a particular material type (
Are you referring to this line? Is there any advantage / difference when using that approach instead of the call to https://github.com/NanoComp/meep/blob/master/python/adjoint/optimization_problem.py#L34 |
Glad to help.
This is true for basic structures, but not generalizable. Say you have a photonic crystal-esque structure with 6 fold symmetry (or some other topological insulator). To represent that you have to wrap your cartesian design grid outside of your rectangular simulation domain and back in on itself (which meep does automatically). The current setup ensures maximum flexibility.
You are completely correct. The
Yes, that line calculates the gradient w.r.t. epsilon at each point. The original framework was meant to be agnostic to the design grid (as you point out) so that you could do whatever vector jacobian product was necessary to retrieve the gradient w.r.t to your actual design parameters ( Even though the points are staggered on the yee grid, they are "brought together" with a weighted inner product from the definition of the adjoint. Things get hairy when there are off-diagonal components though (as I'm sure you know). All of this is implemented here. You could actually generalize this routine to not check for material grids and simply run over every point in the cell. You could use a simpler version of the _get_gradient() swig wrapper too. It's probably not too much work, especially, since you are just cutting out features. The most annoying part is building the python API. |
Thanks for the explanations.
Okay, I can't picture exactly what optimization you have in mind, but fair enough :-)
I'm probably just missing it, but where does the gradient of the system matrix enter into the computation on that line (https://github.com/smartalecH/meep/blob/188ee252b60389b783d890b79ed986c61b855c62/python/adjoint/optimization_problem.py#L229)? I notice you use finite differences to get it in |
Yes, I didn't do a true "gradient of the system matrix" with the older version. Instead, I combined each vector component independently. That was a major drawback to the old method. The "flexibility" (laziness) made it hard to take that weighted inner product accurately. Now, however, it shouldn't be a problem. Here's what I would do:
There are lots of ways to get this to work, but I think this is the path of least resistance. |
Thanks, I really appreciate the detailed response Alec!
I see. I am more familiar with this calculation under FDFD, which has an expression like the one shown below. The current Meep implementation (in C/C++) looks almost identical to this expression: I'm not sure what the form of the system matrix is here, but it sounds like you're saying that the older approach introduces an error in the gradient, which makes sense.
Thanks for outlining these steps... I think this seems reasonable. I don't think that I will have the time to contribute something for this in the near future, but it's good to know what would be required and I think I better understand the current setup / rationale. |
Currently, Meep gradients may only be computed within a
DesignRegion
, where the material distribution is defined by a bilinear interpolation of a density from a numpy array.However, it would be useful if the user could compute sensitivities / gradients at any location within the simulation domain (where the material may not necessarily be defined by a material grid). In principle, such a calculation should be possible since it only requires the forward and adjoint field distributions at each frequency. It would be great if a user could provide measurement point(s) that are not aligned with the Yee grid and Meep would take care of appropriately interpolating the gradients to those location(s).
As a hack, I attempted to achieve the above functionality by using the existing
DesignRegion
, filling the interpolated array with zeros, and overlaying other geometric objects:However, Meep (correctly) returns a sensitivity map where the values overlapping with the other objects are zero:
The text was updated successfully, but these errors were encountered: