-
Notifications
You must be signed in to change notification settings - Fork 43
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
Added EME solver #1453
Added EME solver #1453
Conversation
@@ -650,6 +653,47 @@ class HeatDataArray(DataArray): | |||
_dims = "T" | |||
|
|||
|
|||
class EMEScalarFieldDataArray(AbstractSpatialDataArray): |
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.
This class is different than ScalarModeFieldDataArray in that it has an additional port_index dimension. Should validate that it is always has coords [0, 1].
There is an issue that num_modes may be different at the two ports. Current plan is to have nans in the dataarray when the mode_index, port_index pair doesn't make sense. The smatrix plugin has this same issue, I assume it handles it similarly.
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.
The S matrix doesn't really have a field monitor, so not sure if there's anything there to which the comment applies?
NaN may be fine. An alternative path could be to remove port_index
from this (which would actually make it equivalent to ScalarModeFieldDataArray
in terms of dimensions, but it could be kept separate because the associated physical meaning is different). Then EMEFieldData
could become EMEPortFieldData
and EMEFieldData
(i.e. what is eventually returned by an EMEFieldMonitor
) could carry two instances of EMEPortFieldData
, something like eme_field_data.port0
and eme_field_data.port1
. Not sure if this (or something along these lines) makes sense though....
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.
For the smatrix plugin, I'm referring to this:
max_mode_index_out, max_mode_index_in = self.max_mode_index |
Each port may have a different number of modes, so it just uses the max when setting up the DataArray 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.
yeah, I actually initially had it behave something like that. The difficulty I had was that I wanted EMEFieldData
to inherit from ElectromagneticFieldData
. In this setup, EMEPortFieldData
could inherit from ElectromagneticFieldData
, except that there is supposed to be a one-to-one correspondence between Monitor
s and MonitorData
s.
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.
My comment here might be related to this discussion.
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.
port_index
in EMEFieldData
labels the actual device port. EMEFieldData
has nothing to do with the EME grid, it is rather defined on the FDTD grid.
) | ||
return data | ||
|
||
def plot_field( |
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.
Unfortunately, I had to copy this from components/sim_data.py
. Would it make sense to move some of this field plotting functionality into base_sim?
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 what would rather make sense is to have some intermediate level abstract class from which both EME and FDTD simulations inherit (and probably mode in the future, as ModeSolver
has a plot_field
method too), but not Heat and e.g. charge in the future. It is either that or decoupling the plot function completely in 3.0, something like plot_field(sim_data, ...)
instead of sim_data.plot_field(...)
. But for the time being an AbstractElectromagneticSimulationData
with a plot_field
method that both Simulation
and EMESimultion
inherit maybe makes most sense?
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.
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 sounds reasonable to me
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.
Interestingly, this is the kind of problem we're trying to fix for 3.0 :) Now that we have all these types of simulations, it gets really annoying to have to use inheritance to specify how all of these methods work.
I think the approach momchil suggested probably makes some sense for now.
However, how I'm thinking about it for 3.0 is that the simulation has some properties or methods that simply separate the optical parts out, and then we have some plot_optical
or plot_thermal
etc. that filter by these properties and plot them in a generic way.
Related, but I'm thinking that the Simulation and SimulationData might want to be unified in a single object, so SimulationData.plot_field(mnt_name)
would just work as is now and just continue to error if the mnt_name
was not a FieldMonitor
.
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 let me clarify, I dont mean that in 3.0 Simualtion gets unified with SimulationData. I mean that maybe we want to throw EME, Heat, FDTD, etc all into a single Simulation object (and same with their data) basically not distinguishing between the solvers besides the various monitors and sources that are contained within.
18e9a3e
to
56198a1
Compare
fe2caf9
to
83f9a91
Compare
b42e035
to
b694d4a
Compare
c17f6ec
to
2d99ef7
Compare
e4afd2b
to
e3ce9c7
Compare
@tylerflex I added |
That's great! So overall it refactored pretty nicely? eg. without a lot of rough edges? If so, that's a good sign for the future. Next I'll implement the mode solver as an |
Yeah, I think it refactored nicely. I might still change a bit before EME pre-release (e.g. consolidating size validators). |
7b5f134
to
0bab6b9
Compare
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
## [Unreleased] | |||
- 2D heat simulations are now fully supported. | |||
|
|||
### Added | |||
- EME solver through `EMESimulation` class. |
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.
7000 lines PR, 5 words changelog :D
(I think that's fine, just funny)
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.
:D
if ( | ||
field_data.coords[coord_name].size <= 1 | ||
or coord_name == "eme_port_index" | ||
or coord_name == "mode_index" |
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 I see why but out of curiosity what is the problem if this goes to interp
given that the values should always be integer and effectively no interpolation should happen?
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.
da = xr.DataArray(
data=[[0, np.nan, np.nan], [1, np.nan, np.nan]],
dims=("x", "y"),
coords={"x": [0, 1], "y": [0, 1, 2]},
)
print(da.interp(y=0))
print(da.sel(y=0))
<xarray.DataArray (x: 2)> Size: 16B
array([nan, nan])
Coordinates:
* x (x) int64 16B 0 1
y int64 8B 0
<xarray.DataArray (x: 2)> Size: 16B
array([0., 1.])
Coordinates:
* x (x) int64 16B 0 1
y int64 8B 0
Seems to be a weird issue with xarray multidimensional interpolation when nans are present?
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 ok so I didn't actually see. :) Makes sense.
""" | ||
Custom implementation of Maxwell’s equations which represents the physical model to be solved using the FDTD |
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.
This seems like quite a mess in the diff here but in practice it should be pretty small changes I assume? Could you summarize what happened?
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.
Hmm from what I can tell it's just organising AbstractYeeGridSimulation and Simulation in the same file. I'm wondering (although maybe a bit painful) if it makes sense to move this to the base_sim/abstract_yee_grid
maybe thingking that at some point 3.0 it might also make sense to rename our current simulation class FDTDSimulation
although we can also move this later too! Maybe @tylerflex has some thoughts too
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 moved all of the fields and methods that weren't FDTD-specific but involve EM fields on Yee grid to AbstractYeeGridSimulation
. I left duplicates of some methods and fields in Simulation
when their docstrings had information specific to FDTD simulations.
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 related to this review specifically)
You know I was thinking about this fields/methods code duplicates issue recently. I believe we won't be able to escape it fundamentally in an inheritance-based data scheme (which is good and bad for different reasons), but the alternative which is strongly-typed methods that operate on data container classes have their own set of problems too I guess more on the "user-friendly linking methods to data classes" aspect. This might just be fundamental to having multiple classes have "slightly different variations of the same method" be it in docstrings or implementation. Problems can become more prevalent if we have classmethods using otherclassmethods in a breaking manner that I think we generally try to avoid by writing pure class functions. It is very strongly coupled to the way we choose to represent our data really and have users interact with it, and any approach involves considerable work. There might be a conceptual point of having to draw the line of how exactly we want to interact with our data, and in a way maybe these quirks could be part of it. The real question is the effect this has on scalability and integration with other methods, and how much this affects our development understanding and maintenance of the code. These are not easy questions but I think @tylerflex was thinking about this too in his concept
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.
Hmm from what I can tell it's just organising AbstractYeeGridSimulation and Simulation in the same file. I'm wondering (although maybe a bit painful) if it makes sense to move this to the
base_sim/abstract_yee_grid
maybe thingking that at some point 3.0 it might also make sense to rename our current simulation classFDTDSimulation
although we can also move this later too! Maybe @tylerflex has some thoughts too
I think this makes sense, but it can be made in a separate PR. We could also go more closely over whether some of the code duplication may be avoided. I'm also down to rename it to FDTDSimulation
. We may still do something like both import FDTDSimulation
and import FDTDSimulation as Simulation
in tidy3d init if we want to keep some backwards compatibility.
tidy3d/components/eme/simulation.py
Outdated
|
||
|
||
# eme specific simulation parameters | ||
MAX_NUM_FREQS = 100 |
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.
This seems unnecessarily limiting? But I might see your reasoning since the computation can become quite heavy for a large number of freqs.
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, when we use a lot of frequencies we can run into performance issues and memory issues in the mode solver I believe
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'm guessing the EME sweep helpers will be worked on in another PR, right? In that case, this is looking good to me.
docs/api/index.rst
Outdated
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.
Docs structures look good so far!
ecfb48a
to
a0ea252
Compare
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.
11/10 job! Congratulations, so much effort here, and it's really good!
I made a few tiny comments that maybe we can also address in the 3.0 refactor really, but it's great
return boundary_planes | ||
|
||
@property | ||
def cells(self) -> List[Box]: |
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.
Maybe naive question. This is interesting, just out of curiousity, is this how it gets constructed in the backend too in the sense that if a user makes a custom grid fucntion based on box cells it would also work?
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 not far off. In principle the EME cells are just a list of cells, yes, so in that sense it can be decoupled from the actual simulation geometry a bit. This could be useful for periodic repetition of cells or other reuse of mode solving in the future
""" | ||
Custom implementation of Maxwell’s equations which represents the physical model to be solved using the FDTD |
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.
Hmm from what I can tell it's just organising AbstractYeeGridSimulation and Simulation in the same file. I'm wondering (although maybe a bit painful) if it makes sense to move this to the base_sim/abstract_yee_grid
maybe thingking that at some point 3.0 it might also make sense to rename our current simulation class FDTDSimulation
although we can also move this later too! Maybe @tylerflex has some thoughts too
@@ -16,14 +16,14 @@ def run_async( | |||
simulation_type: str = "tidy3d", | |||
parent_tasks: Dict[str, List[str]] = None, | |||
) -> BatchData: | |||
"""Submits a set of Union[:class:`.Simulation`, :class:`.HeatSimulation`] objects to server, | |||
"""Submits a set of Union[:class:`.Simulation`, :class:`.HeatSimulation`, :class:`.EMESimulation`] objects to server, |
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.
This is maybe something we should add later, but I believe we would benefit from having a SolverSimulationType
definition, also in the context of 3.0, so that all these methods can just use that type both at the docstring and parameter typing check level @tylerflex
9c8b2c8
to
2a785aa
Compare
b8b26b2
to
9447df2
Compare
I left some comments below about some key aspects of the organization.
Todo:
storage_size
AbstractYeeGridSimulation
as abstract superclass ofEMESimulation
andSimulation
, and similarly forsim_data
.