-
Notifications
You must be signed in to change notification settings - Fork 65
Bringing back symmetries into the mode solver #201
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
Conversation
tidy3d/plugins/mode/mode_solver.py
Outdated
# Truncate according to symmetries | ||
solver_coords = [coords.copy() for coords in plane_coords] | ||
plane_shape = list(eps_wg_xx.shape) | ||
for ic, coords in enumerate(solver_coords): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did pylint let you get away with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, no, it does complain
tidy3d/plugins/mode/mode_solver.py
Outdated
if mode_spec.symmetries[0] != 0: | ||
sym_val = mode_spec.symmetries[0] | ||
# Pad symmetry-tangential E fields | ||
e_full[[1, 2], 1:Nx//2, :, :] = sym_val * e_full[[1, 2], :Nx//2:-1, :, :] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we should think about generalizing these a bit in a symmetry padding function, it's a bit unwieldy
tidy3d/plugins/mode/mode_solver.py
Outdated
|
||
# Rotate back to original coordinates | ||
(Ex, Ey, Ez), (Hx, Hy, Hz) = rotate_field_coords(E, H) | ||
(Ex, Ey, Ez), (Hx, Hy, Hz) = rotate_field_coords(e_full, h_full) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems rotate_field_coords
does the same thing to e_full and h_gull
Should we make this a function of a single argument and call it twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if these are pedantic comments. I feel like this is probably good enough. But, if we have time, we could refactor a little bit more to help ourselves as we build upon this (or replicate similar things in other places (near2far most notably).)
I completely agree about the reorganization. I just wanted to get it done before leaving in case it's needed (by a user). I guess it wasn't. I guess since it doesn't seem urgent I can work on the symmetries further. I like your idea of potentially incorporating the unfolding in the FieldData, will be useful for monitors in simulations with symmetries too. Also symmetries are always really annoying and edge case-y, e.g. like we discussed for example what happens if someone has put the mode plane in a way such that its center doesn't match a simulation cell, or the discretization has an odd number of cells (the symmetry implementation currently assumes even). And these things are even more problematic if they're using non-uniform mesh. Basically we need to ensure that the discretized gird itself has the required symmetry. Last we talked about this I think we decided to just remove the option for symmetries in the ModeSolver unless e.g. the plane center matches the simulation center in that direction, and the simulation is defined with having the same symmetry. This should ensure that the discretized grid is then also symmetric. It feels a bit restrictive, but I think it covers many use cases. P.S. Actually I think even this doesn't ensure that the discretized grid would be symmetric because of numerical precision issues when the plane size is "exactly" multiple of the grid step. But we could modify the discretize function for simulations to take symmetries into account and always return an even number of cells. |
One other thing to consider is that the symmetries are specified in both the |
I think we should be as restrictive as we need to be to ensure it works properly if only for the most simple cases. |
Yeah good point they can just be removed from the ModeSpec. I think this means substantial changes to this PR before it can be merged, as I'll need to re-enable the simulation symmetry and set up at least some of the infrastructure to handle it. I guess no rush to merge? |
No rush to merge, except that one commit I made to fix the monitor data size computation. Maybe should have done that on another branch. Do you know how to incorporate that in a different PR or just add it to develop? |
|
Alright, I just did this in #211. Feel free to merge and then remove my commit in this PR. |
I didnt cherry pick, didnt see your message in time, just made a new branch off develop and checked out that file. |
That also works for a single file. |
f3741ea
to
8c7e76e
Compare
|
8c7e76e
to
ad907b5
Compare
tidy3d/components/geometry.py
Outdated
""" | ||
return Box(center=self.center, size=self.size) | ||
|
||
def pop_axis( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I like this.. feel like it clutters things up a bit because it's for such a specific application. How many times is the called and does it make sense to just create the normal_index = size.index(0) and feed to regular pop axis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used a few times in the frontend and a few times in the backend. It seems to me that almost every time I need to use this, I have a plane
that I'm working with, so it seemed weird I have to specifically supply the normal index every time. I almost don't understand why this would be a geometry method if not for some simplifications it can provide for geometries that have a natural normal axis...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, like you say, it's used in situations where there is a natural normal axis, like cylinders and poly slabs. But note these are not toggled via size
. It's also used to compute intersections and polygons in various planes (where the plane axis is specified). So my point is that these functions are pretty generically used and I would prefer to not hardcode something for a special case if we dont have to. If it were me I'd just construct and feed it the normal axis. Or, I might try to handle it a bit differently (like define a normal_axis
property in each Geometry that returns a value used as a default in pop
/ unpop
axis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I can partly understand your resistance to this, but firstly note that the change I made doesn't brake anything as the size selection is only triggered if axis is not supplied. There are two things that feel kinda strange to me: the first is that you have to manually define the normal axis every time even for geometries that have a natural normal axis. The second one is that it's not really clear why the method as such (staticmethod) belongs in the Geometry class (perhaps the best justification is that we don't really have hanging functions in something like a utils module). But I actually like your idea about defining a normal_axis property! This can be set to the smallest size for a Box and the extrusion direction for Cylinders and Polyslabs. Then we only need to change the Geometry pop/unpop methods to allow axis=None, and raise an error if axis == None and self.normal_aixs == None (e.g. for a sphere). What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To your first point, it's because you dont always supply a normal axis to the pop_axis function, it could be anything, like the plot axis or whatever. Point is that it's generic and doesn't care about the context it's being called in.
It might not belong in the Geometry class, it only does because I feel like it's better tied to some class rather than just hanging out in a utils file, and 2nd is that it's really only used for Geometry objects (things that can be plotted, intersected, etc.). Other than that it's an arbitrary choice.
Normal axis property would work like you describe yea, but I still am a bit opposed to it unless we can define what a normal axis is and why pop_axis should have it as a default? Is it just going to be a property defining "one of these axes is not like the other 2"? for a specific geometry? I'm probably being OCD but just want to think through whether we add this if it's just to avoid a few lines in other places where normal_axis is fed. A nice thing about feeding normal axis is it's more explicit and readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it just going to be a property defining "one of these axes is not like the other 2"? for a specific geometry?
Pretty much, yeah. It seems you already have something like that actually: Planar
, where pop_axis
is called several times with self.axis
.
I'm probably being OCD but just want to think through whether we add this if it's just to avoid a few lines in other places where normal_axis is fed. A nice thing about feeding normal axis is it's more explicit and readable.
This is not a hill I want to have a long discussion on. I can revert the change. It seems that in my usage it was always tied to a plane so it felt weird to have to supply the normal every time, but I see how it's used in the plotting functions. I mean, I didn't get your point to my first point - what I was saying is that everywhere in the code up to now the axis is specifically supplied, so my change doesn't break anything. But I also see that it's not great the way it is now. So between making a normal_axis property for all geometry and just reverting the change, I'm fine with reverting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, yea if you dont mind reverting that would make me most happy :). But we can revisit this issue. What makes me feel a bit icky is adding specific behavior (like checking size) to this more generic, core function that is used in a bunch of other ways. It wouldn't break anything, but I also have been trying to avoid this out of principle in the code design (similar idea to how the components should not depend on the plugins).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few comments. Looks overall good
""" Validating setup """ | ||
|
||
@pydantic.validator("symmetry", always=True) | ||
def not_supported_yet(cls, val): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so as of this PR symmetry is only supported for mode computation? Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we should edit the docstring for Simulation.symmetry temporarily?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I am still hoping to get the main symmetries done in the next couple days... Sooo no need?
tidy3d/components/validators.py
Outdated
"is completely outside of simulation domain." | ||
) | ||
|
||
if geometric_object.type in ["ModeSource", "ModeMonitor"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like this should be a separate validator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it can be yeah
ad907b5
to
1f5ca74
Compare
Symmetries specified in a
ModeSpec
now generally work, but there are a lot of possible edge cases...Also, I have built
release-22.1.4
on the server with all the changes from last week, and set it as default here.