Skip to content

Commit 07bab00

Browse files
committed
refactor microwavemodespec to using inheritance
1 parent 655282e commit 07bab00

File tree

7 files changed

+60
-46
lines changed

7 files changed

+60
-46
lines changed

tests/test_components/test_microwave.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,10 @@ def make_mw_sim(
200200
size_port = [0, sim_width, size_sim[2]]
201201
center_port = [0, 0, center_sim[2]]
202202
impedance_specs = (td.AutoImpedanceSpec(),) * 4
203-
mode_spec = td.ModeSpec(
203+
mode_spec = td.MicrowaveModeSpec(
204204
num_modes=4,
205205
target_neff=1.8,
206-
microwave_mode_spec=td.MicrowaveModeSpec(impedance_specs=impedance_specs),
206+
impedance_specs=impedance_specs,
207207
)
208208

209209
mode_monitor = td.ModeMonitor(
@@ -484,7 +484,7 @@ def test_impedance_spec_validation():
484484
with pytest.raises(pd.ValidationError):
485485
_ = td.CustomImpedanceSpec(voltage_spec=None, current_spec=None)
486486

487-
_ = td.MicrowaveModeSpec(impedance_specs=(both, voltage_only, current_only, None))
487+
_ = td.MicrowaveModeSpec(num_modes=4, impedance_specs=(both, voltage_only, current_only, None))
488488

489489

490490
def test_path_integral_factory_voltage_validation():
@@ -697,10 +697,10 @@ def test_mode_solver_with_microwave_mode_spec():
697697
plane = td.Box(center=(0, 0, 0), size=(0, 10 * width, 2 * height + metal_thickness))
698698
num_modes = 3
699699
impedance_specs = (td.AutoImpedanceSpec(), None, None)
700-
mode_spec = td.ModeSpec(
700+
mode_spec = td.MicrowaveModeSpec(
701701
num_modes=num_modes,
702702
target_neff=2.2,
703-
microwave_mode_spec=td.MicrowaveModeSpec(impedance_specs=impedance_specs),
703+
impedance_specs=impedance_specs,
704704
)
705705
mms = ModeSolver(
706706
simulation=stripline_sim,
@@ -728,7 +728,7 @@ def test_mode_solver_with_microwave_mode_spec():
728728
),
729729
)
730730
impedance_specs = (custom_spec, None, None)
731-
mms = mms.updated_copy(path="mode_spec/microwave_mode_spec/", impedance_specs=impedance_specs)
731+
mms = mms.updated_copy(path="mode_spec/", impedance_specs=impedance_specs)
732732
mms_data: ModeSolverData = mms.data
733733

734734
# _, ax = plt.subplots(1, 1, tight_layout=True, figsize=(15, 15))

tests/test_components/test_mode.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,15 @@ def test_plane_crosses_symmetry_plane_warning(monkeypatch):
389389

390390

391391
def test_mode_spec_with_microwave_mode_spec():
392-
"""Test that the number of impedance specs is validated against the number of modes."""
392+
"""Test that the number of impedance specs is validated against the number of modes in MicrowaveModeSpec."""
393393

394394
impedance_specs = (td.AutoImpedanceSpec(),)
395-
mw_mode_spec = td.MicrowaveModeSpec(impedance_specs=impedance_specs)
395+
396+
# Should work when impedance_specs matches num_modes
397+
mw_mode_spec = td.MicrowaveModeSpec(num_modes=1, impedance_specs=impedance_specs)
398+
assert mw_mode_spec.num_modes == 1
399+
assert len(mw_mode_spec.impedance_specs) == 1
400+
401+
# Should fail when impedance_specs doesn't match num_modes
396402
with pytest.raises(pydantic.ValidationError):
397-
td.ModeSpec(num_modes=2, microwave_mode_spec=mw_mode_spec)
403+
td.MicrowaveModeSpec(num_modes=2, impedance_specs=impedance_specs)

tidy3d/components/microwave/microwave_mode_spec.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66

77
import pydantic.v1 as pd
88

9-
from tidy3d.components.base import Tidy3dBaseModel, cached_property
9+
from tidy3d.components.base import cached_property
1010
from tidy3d.components.microwave.path_integrals.impedance_spec import (
1111
AutoImpedanceSpec,
1212
ImpedanceSpecTypes,
1313
)
14+
from tidy3d.components.mode_spec import ModeSpec
1415
from tidy3d.components.types import annotate_type
16+
from tidy3d.exceptions import SetupError
1517

1618

17-
class MicrowaveModeSpec(Tidy3dBaseModel):
19+
class MicrowaveModeSpec(ModeSpec):
1820
"""
1921
The :class:`.MicrowaveModeSpec` class specifies how quantities related to transmission line
2022
modes and microwave waveguides are computed. For example, it defines the paths for line integrals, which are used to
@@ -38,3 +40,21 @@ def _using_auto_current_spec(self) -> bool:
3840
def num_impedance_specs(self) -> int:
3941
"""The number of impedance specifications to be used."""
4042
return len(self.impedance_specs)
43+
44+
@pd.validator("impedance_specs", always=True)
45+
def check_impedance_specs_consistent_with_num_modes(cls, val, values):
46+
"""Check that the number of impedance specifications is equal to the number of modes."""
47+
if val is None:
48+
return val
49+
50+
num_modes = values.get("num_modes", 1)
51+
valid_number_impedance_specs = len(val) == num_modes
52+
53+
if not valid_number_impedance_specs:
54+
raise SetupError(
55+
f"Given {len(val)} impedance specifications in the 'MicrowaveModeSpec', "
56+
f"but the number of modes requested is {num_modes}. Please ensure that the "
57+
"number of impedance specifications is equal to the number of modes."
58+
)
59+
60+
return val

tidy3d/components/mode/mode_solver.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@
3535
LossyMetalMedium,
3636
)
3737
from tidy3d.components.microwave.data.dataset import MicrowaveModeDataset
38+
from tidy3d.components.microwave.microwave_mode_spec import MicrowaveModeSpec
3839
from tidy3d.components.microwave.path_integrals.path_integral_factory import make_path_integrals
3940
from tidy3d.components.mode_spec import ModeSpec
40-
from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor
41+
from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor, ModeSpecTypes
4142
from tidy3d.components.scene import Scene
4243
from tidy3d.components.simulation import Simulation
4344
from tidy3d.components.source.field import ModeSource
@@ -156,7 +157,7 @@ class ModeSolver(Tidy3dBaseModel):
156157
discriminator=TYPE_TAG_STR,
157158
)
158159

159-
mode_spec: ModeSpec = pydantic.Field(
160+
mode_spec: ModeSpecTypes = pydantic.Field(
160161
...,
161162
title="Mode specification",
162163
description="Container with specifications about the modes to be solved for.",
@@ -437,6 +438,11 @@ def _num_cells_freqs_modes(self) -> tuple[int, int, int]:
437438
num_freqs = len(self.freqs)
438439
return num_cells, num_freqs, num_modes
439440

441+
@property
442+
def _is_microwave_mode_spec(self) -> bool:
443+
"""Check if the mode_spec is a MicrowaveModeSpec."""
444+
return isinstance(self.mode_spec, MicrowaveModeSpec)
445+
440446
def solve(self) -> ModeSolverData:
441447
""":class:`.ModeSolverData` containing the field and effective index data.
442448
@@ -544,7 +550,7 @@ def data_raw(self) -> ModeSolverData:
544550

545551
mode_solver_data = self._filter_components(mode_solver_data)
546552
# Calculate and add the characteristic impedance
547-
if self.mode_spec.microwave_mode_spec is not None:
553+
if self._is_microwave_mode_spec:
548554
mode_solver_data = self._add_microwave_data(mode_solver_data)
549555
return mode_solver_data
550556

@@ -1375,8 +1381,10 @@ def _make_path_integrals(
13751381
) -> tuple[tuple[Optional[VoltageIntegralTypes]], tuple[Optional[CurrentIntegralTypes]]]:
13761382
"""Wrapper for making path integrals from the MicrowaveModeSpec. Note: overriden in the backend to support
13771383
auto creation of path integrals."""
1384+
if not self._is_microwave_mode_spec:
1385+
raise ValueError("Cannot make path integrals for non-MicrowaveModeSpec")
13781386
return make_path_integrals(
1379-
self.mode_spec.microwave_mode_spec,
1387+
self.mode_spec,
13801388
self.to_monitor(name=MODE_MONITOR_NAME),
13811389
)
13821390

tidy3d/components/mode_spec.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from math import isclose
6-
from typing import Literal, Optional, Union
6+
from typing import Literal, Union
77

88
import numpy as np
99
import pydantic.v1 as pd
@@ -13,7 +13,6 @@
1313
from tidy3d.log import log
1414

1515
from .base import Tidy3dBaseModel, skip_if_fields_missing
16-
from .microwave.microwave_mode_spec import MicrowaveModeSpec
1716
from .types import Axis2D, TrackFreq
1817

1918
GROUP_INDEX_STEP = 0.005
@@ -164,14 +163,6 @@ class ModeSpec(Tidy3dBaseModel):
164163
f"default of {GROUP_INDEX_STEP} is used.",
165164
)
166165

167-
microwave_mode_spec: Optional[MicrowaveModeSpec] = pd.Field(
168-
None,
169-
title="Microwave Mode Specification",
170-
description="Additional specification for microwave specific mode properties. For example, "
171-
"it is used for setting up the computation for the characteristic impedance of a transmission "
172-
"line mode.",
173-
)
174-
175166
@pd.validator("bend_axis", always=True)
176167
@skip_if_fields_missing(["bend_radius"])
177168
def bend_axis_given(cls, val, values):
@@ -244,22 +235,3 @@ def angle_rotation_with_phi(cls, val, values):
244235
"enabled."
245236
)
246237
return val
247-
248-
@pd.validator("microwave_mode_spec")
249-
def check_microwave_mode_spec_consistent(cls, val, values):
250-
"""Check that the number of impedance specifications is equal to the number of modes."""
251-
if val is None:
252-
return val
253-
254-
num_modes = values["num_modes"]
255-
valid_number_impedance_specs = val.num_impedance_specs == num_modes
256-
257-
if not valid_number_impedance_specs:
258-
raise SetupError(
259-
f"Given {val.num_impedance_specs} impedance specifications in the 'MicrowaveModeSpec', "
260-
f"but the number of modes requested is {num_modes}. Please either ensure that the "
261-
"number of impedance specifications is equal to the number of modes or leave the "
262-
"'MicrowaveModeSpec' field as 'None', if impedances are not needed."
263-
)
264-
265-
return val

tidy3d/components/monitor.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing
1717
from .base_sim.monitor import AbstractMonitor
1818
from .medium import MediumType
19+
from .microwave.microwave_mode_spec import MicrowaveModeSpec
1920
from .mode_spec import ModeSpec
2021
from .types import (
2122
ArrayFloat1D,
@@ -46,6 +47,9 @@
4647
# for windowing the monitor.
4748
WINDOW_FACTOR = 15
4849

50+
# Union type for mode specifications
51+
ModeSpecTypes = Union[ModeSpec, MicrowaveModeSpec]
52+
4953

5054
class Monitor(AbstractMonitor):
5155
"""Abstract base class for monitors."""
@@ -332,7 +336,7 @@ def normal_axis(self) -> Axis:
332336
class AbstractModeMonitor(PlanarMonitor, FreqMonitor):
333337
""":class:`Monitor` that records mode-related data."""
334338

335-
mode_spec: ModeSpec = pydantic.Field(
339+
mode_spec: ModeSpecTypes = pydantic.Field(
336340
ModeSpec(),
337341
title="Mode Specification",
338342
description="Parameters to feed to mode solver which determine modes measured by monitor.",

tidy3d/components/source/field.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing
1212
from tidy3d.components.data.dataset import FieldDataset
1313
from tidy3d.components.data.validators import validate_can_interpolate, validate_no_nans
14+
from tidy3d.components.microwave.microwave_mode_spec import MicrowaveModeSpec
1415
from tidy3d.components.mode_spec import ModeSpec
1516
from tidy3d.components.source.frame import PECFrame
1617
from tidy3d.components.types import TYPE_TAG_STR, Ax, Axis, Coordinate, Direction
@@ -33,6 +34,9 @@
3334
# (oblique propagation).
3435
CRITICAL_FREQUENCY_FACTOR = 1.15
3536

37+
# Union type for mode specifications
38+
ModeSpecTypes = Union[ModeSpec, MicrowaveModeSpec]
39+
3640

3741
class FieldSource(Source, ABC):
3842
"""A Source defined by the desired E and/or H fields."""
@@ -389,7 +393,7 @@ class ModeSource(DirectionalSource, PlanarSource, BroadbandSource):
389393
* `Prelude to Integrated Photonics Simulation: Mode Injection <https://www.flexcompute.com/fdtd101/Lecture-4-Prelude-to-Integrated-Photonics-Simulation-Mode-Injection/>`_
390394
"""
391395

392-
mode_spec: ModeSpec = pydantic.Field(
396+
mode_spec: ModeSpecTypes = pydantic.Field(
393397
ModeSpec(),
394398
title="Mode Specification",
395399
description="Parameters to feed to mode solver which determine modes measured by monitor.",

0 commit comments

Comments
 (0)