Skip to content

Validate against EMEFieldMonitor with EMELengthSweep #2698

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

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Giving opposite boundaries different names no longer causes a symmetry validator failure.
- Fixed issue with parameters in `InverseDesignResult` sometimes being outside of the valid parameter range.
- Disallow `EMEFieldMonitor` in EME simulations with `EMELengthSweep`.

## [2.9.0rc2] - 2025-07-17

Expand Down
33 changes: 22 additions & 11 deletions tests/test_components/test_eme.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,23 +492,30 @@ def test_eme_simulation():
assert sim_tmp._monitor_num_freqs(monitor=sim_tmp.monitors[0]) == 1

# test sweep
sweep_sim = sim.updated_copy(
with pytest.raises(SetupError):
_ = sim.updated_copy(
sweep_spec=td.EMELengthSweep(scale_factors=list(np.linspace(1, 2, 10)))
)
sim_no_field = sim.updated_copy(
monitors=[mnt for mnt in sim.monitors if not isinstance(mnt, td.EMEFieldMonitor)]
)
sweep_sim = sim_no_field.updated_copy(
sweep_spec=td.EMELengthSweep(scale_factors=list(np.linspace(1, 2, 10)))
)
assert sweep_sim._sweep_cells
assert not sweep_sim._sweep_interfaces
assert sweep_sim._num_sweep_cells == 10
assert sweep_sim._num_sweep_interfaces == 1
assert sweep_sim._num_sweep_modes == 1
_ = sim.updated_copy(
_ = sim_no_field.updated_copy(
sweep_spec=td.EMELengthSweep(
scale_factors=np.stack((np.linspace(1, 2, 7), np.linspace(1, 2, 7)))
)
),
)
with pytest.raises(SetupError):
_ = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[]))
_ = sim_no_field.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[]))
with pytest.raises(SetupError):
_ = sim.updated_copy(
_ = sim_no_field.updated_copy(
sweep_spec=td.EMELengthSweep(
scale_factors=np.stack(
(
Expand All @@ -520,12 +527,14 @@ def test_eme_simulation():
)
# second shape of length sweep must equal number of cells
with pytest.raises(SetupError):
_ = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=np.array([[1, 2], [3, 4]])))
_ = sim_no_field.updated_copy(
sweep_spec=td.EMELengthSweep(scale_factors=np.array([[1, 2], [3, 4]]))
)
_ = sim.updated_copy(sweep_spec=td.EMEModeSweep(num_modes=list(np.arange(1, 5))))
# test sweep size limit
with pytest.raises(SetupError):
_ = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[]))
sim_bad = sim.updated_copy(
_ = sim_no_field.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[]))
sim_bad = sim_no_field.updated_copy(
sweep_spec=td.EMELengthSweep(scale_factors=list(np.linspace(1, 2, 200)))
)
with pytest.raises(SetupError):
Expand Down Expand Up @@ -562,7 +571,7 @@ def test_eme_simulation():
sim = sim.updated_copy(sweep_spec=None)
assert sim._num_sweep == 1
assert not sim._sweep_modes
sim = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[1, 2]))
sim = sim_no_field.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=[1, 2]))
assert not sim._sweep_modes
assert sim._num_sweep == 2
sim = sim.updated_copy(sweep_spec=td.EMEFreqSweep(freq_scale_factors=[1, 2]))
Expand Down Expand Up @@ -1090,9 +1099,11 @@ def test_eme_sim_data():

# test smatrix in basis with sweep
smatrix = _get_eme_smatrix_dataset(num_modes_1=5, num_modes_2=5, num_sweep=10)
sim = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=np.linspace(1, 2, 10)))
sim_sweep = sim.updated_copy(
sweep_spec=td.EMELengthSweep(scale_factors=np.linspace(1, 2, 10)), monitors=[]
)
sim_data = td.EMESimulationData(
simulation=sim, data=data, smatrix=smatrix, port_modes_raw=port_modes
simulation=sim_sweep, data=[], smatrix=smatrix, port_modes_raw=port_modes
)

# test smatrix_in_basis
Expand Down
6 changes: 6 additions & 0 deletions tidy3d/components/eme/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,12 @@ def _validate_sweep_spec(self):
"must equal the number of EME cells in the simulation, which is "
f"'{self.eme_grid.num_cells}'."
)
for i, monitor in enumerate(self.monitors):
if isinstance(monitor, EMEFieldMonitor):
raise SetupError(
f"Monitor at 'monitors[{i}]' is an 'EMEFieldMonitor', "
Copy link
Collaborator

Choose a reason for hiding this comment

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

For GUI it's nice to also have the monitor name, we recently switched to including that for a lot of similar validator errors. So let's do Monitor {monitor.name} at 'monitors[{i}]' is here.

"which is not compatible with 'EMELengthSweep'."
)
elif isinstance(self.sweep_spec, EMEFreqSweep):
for i, scale_factor in enumerate(self.sweep_spec.freq_scale_factors):
scaled_freqs = np.array(self.freqs) * scale_factor
Expand Down
Loading