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

Validate that bend radius is not smaller than half the mode plane size #2053

Merged
merged 1 commit into from
Nov 7, 2024
Merged
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
18 changes: 18 additions & 0 deletions tests/test_components/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,24 @@ def test_monitor_num_modes(log_capture, num_modes, log_level):
assert_log_level(log_capture, log_level)


def test_mode_bend_radius():
"""Test that small bend radius fails."""

with pytest.raises(ValueError):
mnt = td.ModeMonitor(
size=(5, 0, 1),
freqs=np.linspace(1e14, 2e14, 100),
name="test",
mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=1),
)
_ = td.Simulation(
size=(2, 2, 2),
run_time=1e-12,
monitors=[mnt],
grid_spec=td.GridSpec.uniform(dl=0.1),
)


def test_diffraction_validators():
# ensure error if boundaries are not periodic
boundary_spec = td.BoundarySpec(
Expand Down
16 changes: 16 additions & 0 deletions tests/test_components/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ def test_dir_vector():
assert DirectionalSource._dir_vector.fget(S) is None


def test_mode_bend_radius():
"""Test that small bend radius fails."""

with pytest.raises(ValueError):
src = td.ModeSource(
size=(1, 0, 5),
source_time=ST,
mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=0),
)
_ = td.Simulation(
size=(2, 2, 2),
run_time=1e-12,
sources=[src],
)


def test_UniformCurrentSource():
g = td.GaussianPulse(freq0=1e12, fwidth=0.1e12)

Expand Down
11 changes: 11 additions & 0 deletions tests/test_plugins/test_mode_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,3 +1034,14 @@ def test_modes_eme_sim(mock_remote_api, local):
_ = msweb.run(solver.to_fdtd_mode_solver())

_ = solver.reduced_simulation_copy


def test_mode_bend_radius():
"""Test that small bend radius fails."""

with pytest.raises(ValueError):
ms = ModeSolver(
plane=PLANE,
freqs=np.linspace(1e14, 2e14, 100),
mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=0),
)
24 changes: 23 additions & 1 deletion tidy3d/components/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@
from .structure import MeshOverrideStructure, Structure
from .subpixel_spec import SubpixelSpec
from .types import TYPE_TAG_STR, Ax, Axis, FreqBound, InterpMethod, Literal, Symmetry, annotate_type
from .validators import assert_objects_in_sim_bounds, validate_mode_objects_symmetry
from .validators import (
assert_objects_in_sim_bounds,
validate_mode_objects_symmetry,
validate_mode_plane_radius,
)
from .viz import (
PlotParams,
add_ax_if_none,
Expand Down Expand Up @@ -3245,6 +3249,24 @@ def _post_init_validators(self) -> None:
self._validate_tfsf_nonuniform_grid()
self._validate_nonlinear_specs()
self._validate_custom_source_time()
self._validate_mode_object_bends()

def _validate_mode_object_bends(self) -> None:
"""Error if any mode sources or monitors with bends have a radius that is too small."""
for imnt, monitor in enumerate(self.monitors):
if isinstance(monitor, AbstractModeMonitor):
validate_mode_plane_radius(
mode_spec=monitor.mode_spec,
plane=monitor.geometry,
msg_prefix=f"Monitor at 'monitors[{imnt}]' ",
)
for isrc, source in enumerate(self.sources):
if isinstance(source, ModeSource):
validate_mode_plane_radius(
mode_spec=source.mode_spec,
plane=source.geometry,
msg_prefix=f"Source at 'sources[{isrc}]' ",
)

def _validate_custom_source_time(self):
"""Warn if all simulation times are outside CustomSourceTime definition range."""
Expand Down
19 changes: 19 additions & 0 deletions tidy3d/components/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .base import DATA_ARRAY_MAP, skip_if_fields_missing
from .data.dataset import Dataset, FieldDataset
from .geometry.base import Box
from .mode import ModeSpec
from .types import Tuple

""" Explanation of pydantic validators:
Expand Down Expand Up @@ -396,3 +397,21 @@ def freqs_not_empty(cls, val):
return val

return freqs_not_empty


def validate_mode_plane_radius(mode_spec: ModeSpec, plane: Box, msg_prefix: str = ""):
"""Validate that the radius of a mode spec with a bend is not smaller than half the size of
the plane along the radial direction."""

if not mode_spec.bend_radius:
return

# radial axis is the plane axis that is not the bend axis
_, plane_axs = plane.pop_axis([0, 1, 2], plane.size.index(0.0))
radial_ax = plane_axs[(mode_spec.bend_axis + 1) % 2]

if np.abs(mode_spec.bend_radius) < plane.size[radial_ax] / 2:
raise ValueError(
f"{msg_prefix} bend radius is smaller than half the mode plane size "
"along the radial axis, which can produce wrong results."
)
12 changes: 11 additions & 1 deletion tidy3d/plugins/mode/mode_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@
PlotScale,
Symmetry,
)
from ...components.validators import validate_freqs_min, validate_freqs_not_empty
from ...components.validators import (
validate_freqs_min,
validate_freqs_not_empty,
validate_mode_plane_radius,
)
from ...components.viz import make_ax, plot_params_pml
from ...constants import C_0
from ...exceptions import SetupError, ValidationError
Expand Down Expand Up @@ -173,6 +177,11 @@ def plane_in_sim_bounds(cls, val, values):
raise SetupError("'ModeSolver.plane' must intersect 'ModeSolver.simulation'.")
return val

def _post_init_validators(self) -> None:
validate_mode_plane_radius(
mode_spec=self.mode_spec, plane=self.plane, msg_prefix="Mode solver"
)

@cached_property
def normal_axis(self) -> Axis:
"""Axis normal to the mode plane."""
Expand Down Expand Up @@ -1511,6 +1520,7 @@ def _validate_modes_size(self):
)

def validate_pre_upload(self, source_required: bool = True):
"""Validate the fully initialized mode solver is ok for upload to our servers."""
self._validate_modes_size()

@cached_property
Expand Down
Loading