Skip to content
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

Merged
merged 1 commit into from
Apr 6, 2024
Merged

Added EME solver #1453

merged 1 commit into from
Apr 6, 2024

Conversation

caseyflex
Copy link
Contributor

@caseyflex caseyflex commented Feb 7, 2024

I left some comments below about some key aspects of the organization.

Todo:

  • Fix derived fields plotting
  • Disallow fully anisotropic materials. Warn about other advanced materials.
  • Unit tests
  • Subgrid visualization
  • plot_grid
  • precision in storage_size
  • plot port modes and mode solver modes and coeffs
  • mode_indices -> num_modes in monitors
  • finalize or get rid of methods for converting to / from fdtd sim
  • Create AbstractYeeGridSimulation as abstract superclass of EMESimulation and Simulation, and similarly for sim_data.

@@ -650,6 +653,47 @@ class HeatDataArray(DataArray):
_dims = "T"


class EMEScalarFieldDataArray(AbstractSpatialDataArray):
Copy link
Contributor Author

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.

Copy link
Collaborator

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....

Copy link
Contributor Author

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.

Copy link
Contributor Author

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 Monitors and MonitorDatas.

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

tidy3d/components/data/data_array.py Show resolved Hide resolved
tidy3d/components/data/dataset.py Outdated Show resolved Hide resolved
tidy3d/components/eme/data/dataset.py Show resolved Hide resolved
tidy3d/components/eme/data/dataset.py Show resolved Hide resolved
)
return data

def plot_field(
Copy link
Contributor Author

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?

Copy link
Collaborator

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?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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

Copy link
Collaborator

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.

Copy link
Collaborator

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.

tidy3d/components/eme/simulation.py Show resolved Hide resolved
tidy3d/components/eme/simulation.py Show resolved Hide resolved
@caseyflex caseyflex force-pushed the casey/eme branch 3 times, most recently from e4afd2b to e3ce9c7 Compare March 26, 2024 16:32
@caseyflex
Copy link
Contributor Author

@tylerflex I added AbstractYeeGridSimulation and AbstractYeeGridSimulationData as discussed -- it saved a lot of code duplication. I generally tried to move everything related to epsilon, grids, and EM fields into these classes, while keeping things only relevant for time-domain in Simulation and things only relevant for EME in EMESimulation.

@tylerflex
Copy link
Collaborator

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 AbsttractYeeGridSimulation, probably it will reuse a lot of the same internals.

@caseyflex
Copy link
Contributor Author

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 AbsttractYeeGridSimulation, probably it will reuse a lot of the same internals.

Yeah, I think it refactored nicely. I might still change a bit before EME pre-release (e.g. consolidating size validators).

@caseyflex caseyflex force-pushed the casey/eme branch 2 times, most recently from 7b5f134 to 0bab6b9 Compare April 3, 2024 12:32
@@ -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.
Copy link
Collaborator

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)

Copy link
Contributor Author

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"
Copy link
Collaborator

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?

Copy link
Contributor Author

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?

Copy link
Collaborator

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
Copy link
Collaborator

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?

Copy link
Collaborator

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

Copy link
Contributor Author

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.

Copy link
Collaborator

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

Copy link
Collaborator

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

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.



# eme specific simulation parameters
MAX_NUM_FREQS = 100
Copy link
Collaborator

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.

Copy link
Contributor Author

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

Copy link
Collaborator

@lucas-flexcompute lucas-flexcompute left a 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.

Copy link
Collaborator

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!

@caseyflex caseyflex force-pushed the casey/eme branch 2 times, most recently from ecfb48a to a0ea252 Compare April 4, 2024 11:31
Copy link
Collaborator

@daquinteroflex daquinteroflex left a 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

tidy3d/components/data/sim_data.py Show resolved Hide resolved
tidy3d/components/eme/data/sim_data.py Show resolved Hide resolved
return boundary_planes

@property
def cells(self) -> List[Box]:
Copy link
Collaborator

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?

Copy link
Contributor Author

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

tidy3d/components/eme/simulation.py Show resolved Hide resolved
"""
Custom implementation of Maxwell’s equations which represents the physical model to be solved using the FDTD
Copy link
Collaborator

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,
Copy link
Collaborator

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

@caseyflex caseyflex force-pushed the casey/eme branch 2 times, most recently from 9c8b2c8 to 2a785aa Compare April 4, 2024 12:46
@caseyflex caseyflex marked this pull request as ready for review April 5, 2024 09:35
@caseyflex caseyflex force-pushed the casey/eme branch 4 times, most recently from b8b26b2 to 9447df2 Compare April 5, 2024 13:02
@momchil-flex momchil-flex merged commit a419339 into pre/2.7 Apr 6, 2024
13 checks passed
@momchil-flex momchil-flex deleted the casey/eme branch April 6, 2024 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.7 will go into version 2.7.* awaiting backend not to be merged as backend is not finalized
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants