Skip to content

Commit f4141cd

Browse files
committed
Warning about symmetry expansion in ModeSolver and ModeSimulation
removing 'symmetry' argument from 'subsection'
1 parent 8004632 commit f4141cd

File tree

5 files changed

+93
-7
lines changed

5 files changed

+93
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ or `Absorber` classes (or when invoking `pml()`, `stable_pml()`, or `absorber()`
2727
with fewer layers than recommended.
2828
- Warnings and error messages originating from `Structure`, `Source`, or `Monitor` classes now refer to problematic objects by their user-supplied `name` attribute, alongside their index.
2929
- File downloads are atomic. Interruptions or failures during download will no longer result in incomplete files.
30+
- Warnings are now generated (instead of errors) when instantiating `PML`, `StablePML`, or `Absorber` classes (or when invoking `pml()`, `stable_pml()`, or `absorber()` functions) with fewer layers than recommended.
31+
- `Simulation.subsection` can no longer take `symmetry` as an argument - the symmetry is always taken from the original simulation.
32+
- If a mode simulation is crossing a symmetry plane of the larger simulation domain, but the mode plane is not symmetric, a warning is issued that it will be expanded symmetrically. Previously this warning only happened during the solver run.
3033

3134
### Fixed
3235
- Arrow lengths are now scaled consistently in the X and Y directions, and their lengths no longer exceed the height of the plot window.

tests/test_components/test_mode.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,54 @@ def get_mode_sim_data():
328328
def test_mode_sim_data():
329329
sim_data = get_mode_sim_data()
330330
_ = sim_data.plot_field("Ey", ax=AX, mode_index=0, f=FS[0])
331+
332+
333+
def test_plane_crosses_symmetry_plane_warning(monkeypatch):
334+
"""Test that a warning is issued if the mode plane crosses a symmetry plane but the centers do not match."""
335+
336+
# Simulation with symmetry in x (axis 0), center at (0, 0, 0)
337+
sim_center = (0, 0, 0)
338+
sim_size = (10, 5, 5)
339+
sim_symmetry = (1, 0, 0) # symmetry in x
340+
341+
# Plane crosses x=0 (symmetry plane), but plane center != sim center
342+
plane_center = (2, 0, 0)
343+
plane_size = (5, 0, 5)
344+
plane = td.Box(center=plane_center, size=plane_size)
345+
346+
# Should warn
347+
with AssertLogLevel("WARNING"):
348+
_ = td.ModeSimulation(
349+
center=sim_center,
350+
size=sim_size,
351+
symmetry=sim_symmetry,
352+
plane=plane,
353+
mode_spec=td.ModeSpec(),
354+
freqs=[td.C_0],
355+
)
356+
357+
# Now, plane center matches sim center: should NOT warn
358+
plane_center2 = (0, 0, 0)
359+
plane2 = td.Box(center=plane_center2, size=plane_size)
360+
with AssertLogLevel("INFO"):
361+
_ = td.ModeSimulation(
362+
center=sim_center,
363+
size=sim_size,
364+
symmetry=sim_symmetry,
365+
plane=plane2,
366+
mode_spec=td.ModeSpec(),
367+
freqs=[td.C_0],
368+
)
369+
370+
# Plane does NOT cross symmetry plane: should NOT warn
371+
plane_center3 = (5, 0, 0)
372+
plane3 = td.Box(center=plane_center3, size=plane_size)
373+
with AssertLogLevel("INFO"):
374+
_ = td.ModeSimulation(
375+
center=sim_center,
376+
size=sim_size,
377+
symmetry=sim_symmetry,
378+
plane=plane3,
379+
mode_spec=td.ModeSpec(),
380+
freqs=[td.C_0],
381+
)

tidy3d/components/eme/simulation.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ def subsection(
10971097
grid_spec: Union[GridSpec, Literal["identical"]] = None,
10981098
eme_grid_spec: Union[EMEGridSpec, Literal["identical"]] = None,
10991099
symmetry: Optional[tuple[Symmetry, Symmetry, Symmetry]] = None,
1100+
warn_symmetry_expansion: bool = True,
11001101
monitors: Optional[tuple[MonitorType, ...]] = None,
11011102
remove_outside_structures: bool = True,
11021103
remove_outside_custom_mediums: bool = False,
@@ -1123,6 +1124,8 @@ def subsection(
11231124
New simulation symmetry. If ``None``, then it is inherited from the original
11241125
simulation. Note that in this case the size and placement of new simulation domain
11251126
must be commensurate with the original symmetry.
1127+
warn_symmetry_expansion : bool = True
1128+
Whether to warn when the subsection is expanded to preserve symmetry.
11261129
monitors : Tuple[MonitorType, ...] = None
11271130
New list of monitors. If ``None``, then the monitors intersecting the new simulation
11281131
domain are inherited from the original simulation.
@@ -1160,7 +1163,7 @@ def subsection(
11601163
new_sim = super().subsection(
11611164
region=new_region,
11621165
grid_spec=grid_spec,
1163-
symmetry=symmetry,
1166+
warn_symmetry_expansion=warn_symmetry_expansion,
11641167
monitors=monitors,
11651168
remove_outside_structures=remove_outside_structures,
11661169
remove_outside_custom_mediums=remove_outside_custom_mediums,

tidy3d/components/mode/mode_solver.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,30 @@ def plane_in_sim_bounds(cls, val, values):
211211
raise SetupError("'ModeSolver.plane' must intersect 'ModeSolver.simulation'.")
212212
return val
213213

214+
@pydantic.validator("plane", always=True)
215+
@skip_if_fields_missing(["simulation"])
216+
def _warn_plane_crosses_symmetry(cls, val, values):
217+
"""Warn if the mode plane crosses the symmetry plane of the underlying simulation but
218+
the centers do not match."""
219+
simulation = values.get("simulation")
220+
bounds = val.bounds
221+
# now check in each dimension whether we cross symmetry plane
222+
for dim in range(3):
223+
if simulation.symmetry[dim] != 0:
224+
crosses_symmetry = (
225+
bounds[0][dim] < simulation.center[dim]
226+
and bounds[1][dim] > simulation.center[dim]
227+
)
228+
if crosses_symmetry:
229+
if not isclose(val.center[dim], simulation.center[dim]):
230+
log.warning(
231+
f"The original simulation is symmetric along {'xyz'[dim]} direction. "
232+
"The mode simulation region does cross the symmetry plane but is "
233+
"not symmetric with respect to it. To preserve correct symmetry, "
234+
"the requested simulation region will be expanded by the solver."
235+
)
236+
return val
237+
214238
def _post_init_validators(self) -> None:
215239
self._validate_mode_plane_radius(
216240
mode_spec=self.mode_spec,
@@ -2539,6 +2563,7 @@ def reduced_simulation_copy(self):
25392563
region=new_sim_box,
25402564
monitors=[],
25412565
sources=[],
2566+
warn_symmetry_expansion=False, # we already warn upon mode solver creation
25422567
grid_spec="identical",
25432568
boundary_spec=new_bspec,
25442569
remove_outside_custom_mediums=True,

tidy3d/components/simulation.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,7 @@ def subsection(
17011701
boundary_spec: BoundarySpec = None,
17021702
grid_spec: Union[GridSpec, Literal["identical"]] = None,
17031703
symmetry: Optional[tuple[Symmetry, Symmetry, Symmetry]] = None,
1704+
warn_symmetry_expansion: bool = True,
17041705
sources: Optional[tuple[SourceType, ...]] = None,
17051706
monitors: Optional[tuple[MonitorType, ...]] = None,
17061707
remove_outside_structures: bool = True,
@@ -1728,6 +1729,8 @@ def subsection(
17281729
New simulation symmetry. If ``None``, then it is inherited from the original
17291730
simulation. Note that in this case the size and placement of new simulation domain
17301731
must be commensurate with the original symmetry.
1732+
warn_symmetry_expansion : bool = True
1733+
Whether to warn when the subsection is expanded to preserve symmetry.
17311734
sources : Tuple[SourceType, ...] = None
17321735
New list of sources. If ``None``, then the sources intersecting the new simulation
17331736
domain are inherited from the original simulation.
@@ -1805,12 +1808,13 @@ def subsection(
18051808
center = (new_bounds[0][dim] + new_bounds[1][dim]) / 2
18061809

18071810
if not math.isclose(center, self.center[dim]):
1808-
log.warning(
1809-
f"The original simulation is symmetric along {'xyz'[dim]} direction. "
1810-
"The requested new simulation region does cross the symmetry plane but is "
1811-
"not symmetric with respect to it. To preserve correct symmetry, "
1812-
"the requested simulation region is expanded symmetrically."
1813-
)
1811+
if warn_symmetry_expansion:
1812+
log.warning(
1813+
f"The original simulation is symmetric along {'xyz'[dim]} direction. "
1814+
"The requested new simulation region does cross the symmetry plane but is "
1815+
"not symmetric with respect to it. To preserve correct symmetry, "
1816+
"the requested simulation region is expanded symmetrically."
1817+
)
18141818
new_bounds[0][dim] = 2 * self.center[dim] - new_bounds[1][dim]
18151819

18161820
# symmetry and grid spec treatments could change new simulation bounds

0 commit comments

Comments
 (0)