Skip to content

Commit ead0cff

Browse files
committed
Add interpolation to EME
1 parent 0670c55 commit ead0cff

File tree

3 files changed

+44
-11
lines changed

3 files changed

+44
-11
lines changed

tidy3d/components/eme/data/sim_data.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,23 @@ def smatrix_in_basis(
197197
modes1 = port_modes1
198198
if not modes2_provided:
199199
modes2 = port_modes2
200-
f1 = list(modes1.field_components.values())[0].f.values
201-
f2 = list(modes2.field_components.values())[0].f.values
200+
f1 = list(modes1.monitor.freqs)
201+
f2 = list(modes2.monitor.freqs)
202202

203203
f = np.array(sorted(set(f1).intersection(f2).intersection(self.simulation.freqs)))
204204

205+
interp_spec1 = modes1.monitor.mode_spec.interp_spec
206+
interp_spec2 = modes2.monitor.mode_spec.interp_spec
207+
208+
interp_overlaps = False
209+
if interp_spec1 is not None and interp_spec2 is not None and interp_spec1 == interp_spec2:
210+
interp_overlaps = True
211+
else:
212+
if interp_spec1 is not None:
213+
modes1 = modes1.interpolated_copy
214+
if interp_spec2 is not None:
215+
modes2 = modes2.interpolated_copy
216+
205217
modes_in_1 = "mode_index" in list(modes1.field_components.values())[0].coords
206218
modes_in_2 = "mode_index" in list(modes2.field_components.values())[0].coords
207219

@@ -259,6 +271,10 @@ def smatrix_in_basis(
259271
overlaps1 = modes1.outer_dot(port_modes1, conjugate=False)
260272
if not modes_in_1:
261273
overlaps1 = overlaps1.expand_dims(dim={"mode_index_0": mode_index_1}, axis=1)
274+
if interp_overlaps:
275+
overlaps1 = modes1._interp_dataarray_in_freq(
276+
overlaps1, freqs=f, method=interp_spec1.method
277+
)
262278
O1 = overlaps1.sel(f=f, mode_index_1=keep_mode_inds1)
263279

264280
O1out = O1.rename(mode_index_0="mode_index_out", mode_index_1="mode_index_out_old")
@@ -288,6 +304,9 @@ def smatrix_in_basis(
288304
overlaps2 = modes2.outer_dot(port_modes2, conjugate=False)
289305
if not modes_in_2:
290306
overlaps2 = overlaps2.expand_dims(dim={"mode_index_0": mode_index_2}, axis=1)
307+
overlaps2 = modes2._interp_dataarray_in_freq(
308+
overlaps2, freqs=f, method=interp_spec2.method
309+
)
291310
O2 = overlaps2.sel(f=f, mode_index_1=keep_mode_inds2)
292311

293312
O2out = O2.rename(mode_index_0="mode_index_out", mode_index_1="mode_index_out_old")

tidy3d/components/eme/grid.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing
1212
from tidy3d.components.geometry.base import Box
1313
from tidy3d.components.grid.grid import Coords1D
14-
from tidy3d.components.mode_spec import ModeSpec
14+
from tidy3d.components.mode_spec import ModeInterpSpec, ModeSpec
1515
from tidy3d.components.structure import Structure
16-
from tidy3d.components.types import ArrayFloat1D, Axis, Coordinate, Size, TrackFreq
16+
from tidy3d.components.types import ArrayFloat1D, Axis, Coordinate, Size
1717
from tidy3d.constants import RADIAN, fp_eps, inf
1818
from tidy3d.exceptions import SetupError, ValidationError
1919

@@ -26,13 +26,14 @@
2626
class EMEModeSpec(ModeSpec):
2727
"""Mode spec for EME cells. Overrides some of the defaults and allowed values."""
2828

29-
track_freq: Union[TrackFreq, None] = pd.Field(
30-
None,
31-
title="Mode Tracking Frequency",
32-
description="Parameter that turns on/off mode tracking based on their similarity. "
33-
"Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to "
34-
"mode tracking based on the lowest, central, or highest frequency. "
35-
"If ``None`` no mode tracking is performed, which is the default for best performance.",
29+
interp_spec: Optional[ModeInterpSpec] = pd.Field(
30+
ModeInterpSpec(method="cheb", num_points=3),
31+
title="Mode frequency interpolation specification",
32+
description="Specification for computing modes at a reduced set of frequencies and "
33+
"interpolating to obtain results at all requested frequencies. This can significantly "
34+
"reduce computational cost for broadband simulations where modes vary smoothly with "
35+
"frequency. Requires frequency tracking to be enabled (``sort_spec.track_freq`` must "
36+
"not be ``None``) to ensure consistent mode ordering across frequencies.",
3637
)
3738

3839
angle_theta: Literal[0.0] = pd.Field(

tidy3d/components/eme/simulation.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ def mode_solver_monitors(self) -> list[ModeSolverMonitor]:
561561
freqs=freqs,
562562
mode_spec=mode_specs[i],
563563
colocate=False,
564+
reduce_data=mode_specs[i].interp_spec is not None,
564565
)
565566
monitors.append(monitor)
566567
return monitors
@@ -1009,6 +1010,18 @@ def _monitor_freqs(self, monitor: Monitor) -> list[pd.NonNegativeFloat]:
10091010
return list(self.freqs)
10101011
return list(monitor.freqs)
10111012

1013+
def _monitor_mode_freqs(self, monitor: EMEModeSolverMonitor) -> list[pd.NonNegativeFloat]:
1014+
"""Monitor frequencies."""
1015+
freqs = set()
1016+
cell_inds = self._monitor_eme_cell_indices(monitor=monitor)
1017+
for cell_ind in cell_inds:
1018+
interp_spec = self.eme_grid.mode_specs[cell_ind].interp_spec
1019+
if interp_spec is None:
1020+
freqs |= set(self.freqs)
1021+
else:
1022+
freqs |= set(interp_spec.sampling_points(self.freqs))
1023+
return list(freqs)
1024+
10121025
def _monitor_num_freqs(self, monitor: Monitor) -> int:
10131026
"""Total number of freqs included in monitor."""
10141027
return len(self._monitor_freqs(monitor=monitor))

0 commit comments

Comments
 (0)