-
Notifications
You must be signed in to change notification settings - Fork 40
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
Add field data to ModeMonitor (#1274) #1367
Conversation
hm, let me look into this. |
Alright, I see. Basically the adjoint test is using the emulated run function in I'll make a PR to your branch |
Awesome, thanks! How do you feel about the overall implementation here, though? Should I keep going this direction and start on the backend changes? |
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.
looks good to me! just a few comments.
tidy3d/components/monitor.py
Outdated
@@ -673,6 +693,17 @@ class ModeSolverMonitor(AbstractModeMonitor): | |||
"primal grid nodes).", | |||
) | |||
|
|||
@pydantic.root_validator(skip_on_failure=True) | |||
def deprecation_warning(cls, values): |
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.
we should ensure that this change is reflected in our notebooks after 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.
Yeah, but I think there's only one notebook that uses a ModeSolverMonitor so should be easy.
@@ -992,6 +1040,12 @@ def overlap_sort( | |||
modes is less than this threshold, a warning about a possible discontinuity is | |||
displayed. | |||
""" | |||
if len(self.field_components) == 0: | |||
# raise DataError( |
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.
resolve comment? (remove or discuss?)
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.
Yes, I feel the error would be more in line to other functions (like trying to calculate intensity without the fields present), but because we only return a copy of the original data with modes reordered, it makes sense to order an empty set of modes and not bother the user with checking if the fields exist before calling the method. So I prefer to return a copy, but I left the option to raise an error if that's preferable.
@@ -615,24 +622,29 @@ def _interpolated_tangential_fields(self, coords: ArrayFloat2D) -> Dict[str, Dat | |||
return fields | |||
|
|||
def outer_dot( |
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.
if field_data
is a ModeData
then it's field components can now be None
. do we explicitly make sure this is not the case anywhere when implementing these dot
functions? (or other functions that use the fields?)
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 think given that field_components
still returns return {field_name: field for field_name, field in fields.items() if field is not None}
, there should be no change in behavior
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.
yea, I'm more worried about if the dot functions try to grab one of those components but it is missing, whether that is handled gracefully or you just get an internal KeyError
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.
Yeah that's always been a possibility in FieldData
, so it's been handled, you should just hit this: https://github.com/flexcompute/tidy3d/blob/1f22335e92d92cf875a1f70e4832acd9515a4c8b/tidy3d/components/data/monitor_data.py#L394C1-L395
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.
That's right. All user-facing functions should handle missing components gracefully. Internal methods do not have those checks, for example: ModeData._isel
, ModeData._find_ordering_one_freq
, etc., but those are use-at-your-own-risk methods, so I guess the user should be responsible for the check.
tidy3d/components/monitor.py
Outdated
title="Propagation Direction", | ||
description="Direction of propagation along the normal axis of the monitor used for the " | ||
"computed mode field profiles.", | ||
) |
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 understand why you've done this but I think it may be confusing to have this argument but still return mode amps in both directions. Like, someone reading the api docs may think that they have to set to "-" if they're doing mode decomposition in the backward direction. It's not terrible but it's a bit annoying to have this inconsistency (direction
only affecting the mode fields but not the mode amps). However, I do agree that the other options that I see are also not great:
- Do not provide
direction
and store fields in both directions, just like amps - Store amps only for the specified
direction
So I don't know, maybe at least we should call it store_fields_direction
? Or how about make store_fields
a spec, store_fields = StoreFieldsSpec(direction="+")
? We could imagine extending this in the future to e.g. only request a subset of frequencies, like just the central freq, etc.
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.
Yes, I considered the same options when implementing this way but storing fields in both directions would be a major change and make ModeData
and ModeSolverData
interfaces incompatible.
I think your idea of using store_fields
with a spec might be the better solution here. I'll go with that for now.
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.
After implementing the StoreFieldsSpec
I think we should reconsider. This looks a lot like over-engineering to me. Maybe using store_fields_direction
makes more sense. I reverted the changes to this simpler implementation but left both in the commit history just in case.
Frequency and multiple direction selection are rare use cases, and can be accomplished by setting up multiple monitors. That way we keep the usual use case straightforward, but the advanced uses still possible.
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.
Yeah, I agree with this evaluation.
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.
Looks good to me now!
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.
looks good to me, sorry if you were waiting on me.
So I looked through this again to see about any remaining parts of the code that may need to change. I think on the backend nothing much needs to change apart from replacing some ModeSolverMonitor instances in the tests with a ModeMonitor that stores modes. The only other thing I see is not in the backend per se but in the denormalizer: ModeData now has to optionally denormalize the fields as well, if present (I'll probably ask @dbochkov-flexcompute to take a look at that), and MC has to incorporate it in GUI eventually. Well, that brings me to my main comment actually. ModeSolverData does serve a purpose that currently cannot be replaced (or doesn't make sense to be replaced) by a ModeData: namely, it is the return data structure of the ModeSolver. It doesn't make sense to be replaced by ModeData because that one currently always carries decomposition amplitudes, and optionally mode fields. Well, so there's technically two options:
|
Yes, I agree with the second option as well. I don't even think we need the warning. Just updating the tutorials and making it clear in the docs that a ModeSolverMonitor is no longer required should be enough to (slowly) move users to using a single monitor. I'll finish any pending rebase issues tomorrow morning and commit a final version for merging front and backe-ends. |
1ccad53
to
0548b5e
Compare
Signed-off-by: Lucas Heitzmann Gabrielli <lucas@flexcompute.com>
Since there's no need to remove ModeSolverDate, backend should be done. I've rebased and removed the deprecation warning. |
The implementation proposed here merges
ModeSolverData
and intoModeData
. It also deprecates the use ofModeSolverMonitor
and changes the implementation onModeSolverData
to be derived fromModeData
(to avoid most code duplication and make deprecation later easier). There are 2 issues at this point:ModeSolverData
ended up inheriting theamps
field, which will be unused.tidy3d/tidy3d/components/data/monitor_data.py
Lines 105 to 112 in fa40288
Thoughts, @tylerflex and @momchil-flex?