Skip to content

Commit 2477d96

Browse files
dmarek-flexdbochkov-flexcompute
authored andcommitted
fix(rf): change inheritance structure of Microwave monitors
1 parent 0418b53 commit 2477d96

File tree

2 files changed

+111
-73
lines changed

2 files changed

+111
-73
lines changed

tidy3d/components/microwave/data/monitor_data.py

Lines changed: 89 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pydantic.v1 as pd
1010
import xarray as xr
11+
from typing_extensions import Self
1112

1213
from tidy3d.components.data.data_array import FieldProjectionAngleDataArray, FreqDataArray
1314
from tidy3d.components.data.monitor_data import DirectivityData, ModeData, ModeSolverData
@@ -201,69 +202,27 @@ def realized_gain(self) -> FieldProjectionAngleDataArray:
201202
return partial_G.Gtheta + partial_G.Gphi
202203

203204

204-
class MicrowaveModeData(ModeData, MicrowaveBaseModel):
205-
"""
206-
Data associated with a :class:`.ModeMonitor` for microwave and RF applications: modal amplitudes,
207-
propagation indices, mode profiles, and transmission line data.
205+
class MicrowaveModeDataBase(MicrowaveBaseModel):
206+
"""Base class for microwave mode data that extends standard mode data with RF/microwave features.
208207
209-
Notes
210-
-----
208+
This base class adds microwave-specific functionality to mode data classes, including:
211209
212-
This class extends :class:`.ModeData` with additional microwave-specific data including
213-
characteristic impedance, voltage coefficients, and current coefficients. The data is
214-
stored as `DataArray <https://docs.xarray.dev/en/stable/generated/xarray.DataArray.html>`_
215-
objects using the `xarray <https://docs.xarray.dev/en/stable/index.html>`_ package.
210+
- **Transmission line data**: Characteristic impedance (Z0), voltage coefficients, and
211+
current coefficients for transmission line analysis
212+
- **Enhanced modes_info**: Includes impedance data in the mode properties dataset
213+
- **Group index handling**: Properly filters transmission line data when computing group indices
214+
- **Mode reordering**: Ensures transmission line data tracks with reordered modes
216215
217-
The microwave mode data contains all the information from :class:`.ModeData` plus additional
218-
microwave dataset with impedance calculations performed using voltage and current line integrals
219-
as specified in the :class:`.MicrowaveModeSpec`.
216+
Notes
217+
-----
218+
This is a mixin class that must be combined with mode data classes (:class:`.ModeData` or
219+
:class:`.ModeSolverData`). It uses ``super()`` to call methods on the mixed-in class, extending
220+
their functionality rather than replacing it.
220221
221-
Example
222-
-------
223-
>>> import tidy3d as td
224-
>>> import numpy as np
225-
>>> from tidy3d.components.data.data_array import (
226-
... CurrentFreqModeDataArray,
227-
... ImpedanceFreqModeDataArray,
228-
... ModeAmpsDataArray,
229-
... ModeIndexDataArray,
230-
... VoltageFreqModeDataArray,
231-
... )
232-
>>> from tidy3d.components.microwave.data.dataset import TransmissionLineDataset
233-
>>> direction = ["+", "-"]
234-
>>> f = [1e14, 2e14, 3e14]
235-
>>> mode_index = np.arange(3)
236-
>>> index_coords = dict(f=f, mode_index=mode_index)
237-
>>> index_data = ModeIndexDataArray((1+1j) * np.random.random((3, 3)), coords=index_coords)
238-
>>> amp_coords = dict(direction=direction, f=f, mode_index=mode_index)
239-
>>> amp_data = ModeAmpsDataArray((1+1j) * np.random.random((2, 3, 3)), coords=amp_coords)
240-
>>> impedance_data = ImpedanceFreqModeDataArray(50 * np.ones((3, 3)), coords=index_coords)
241-
>>> voltage_data = VoltageFreqModeDataArray((1+1j) * np.random.random((3, 3)), coords=index_coords)
242-
>>> current_data = CurrentFreqModeDataArray((0.02+0.01j) * np.random.random((3, 3)), coords=index_coords)
243-
>>> tl_data = TransmissionLineDataset(
244-
... Z0=impedance_data,
245-
... voltage_coeffs=voltage_data,
246-
... current_coeffs=current_data
247-
... )
248-
>>> monitor = td.MicrowaveModeMonitor(
249-
... center=(0, 0, 0),
250-
... size=(2, 0, 6),
251-
... freqs=[2e14, 3e14],
252-
... mode_spec=td.MicrowaveModeSpec(num_modes=3, impedance_specs=td.AutoImpedanceSpec()),
253-
... name='microwave_mode',
254-
... )
255-
>>> data = MicrowaveModeData(
256-
... monitor=monitor,
257-
... amps=amp_data,
258-
... n_complex=index_data,
259-
... transmission_line_data=tl_data
260-
... )
222+
The mixin should be placed first in the inheritance list to ensure its method overrides
223+
are used.
261224
"""
262225

263-
monitor: MicrowaveModeMonitor = pd.Field(
264-
..., title="Monitor", description="Mode monitor associated with the data."
265-
)
266-
267226
transmission_line_data: Optional[TransmissionLineDataset] = pd.Field(
268227
None,
269228
title="Transmission Line Data",
@@ -276,12 +235,14 @@ class MicrowaveModeData(ModeData, MicrowaveBaseModel):
276235
def modes_info(self) -> xr.Dataset:
277236
"""Dataset collecting various properties of the stored modes."""
278237
super_info = super().modes_info
238+
239+
# Add transmission line data if present
279240
if self.transmission_line_data is not None:
280241
super_info["Re(Z0)"] = self.transmission_line_data.Z0.real
281242
super_info["Im(Z0)"] = self.transmission_line_data.Z0.imag
282243
return super_info
283244

284-
def _group_index_post_process(self, frequency_step: float) -> ModeData:
245+
def _group_index_post_process(self, frequency_step: float) -> Self:
285246
"""Calculate group index and remove added frequencies used only for this calculation.
286247
287248
Parameters
@@ -291,10 +252,12 @@ def _group_index_post_process(self, frequency_step: float) -> ModeData:
291252
292253
Returns
293254
-------
294-
:class:`.ModeData`
255+
Self
295256
Filtered data with calculated group index.
296257
"""
297258
super_data = super()._group_index_post_process(frequency_step)
259+
260+
# Add transmission line data handling if present
298261
if self.transmission_line_data is not None:
299262
_, center_inds, _ = self._group_index_freq_slices()
300263
update_dict = {
@@ -315,6 +278,8 @@ def _apply_mode_reorder(self, sort_inds_2d):
315278
permutation to apply to the mode_index for that frequency.
316279
"""
317280
main_data_reordered = super()._apply_mode_reorder(sort_inds_2d)
281+
282+
# Add transmission line data handling if present
318283
if self.transmission_line_data is not None:
319284
transmission_line_data_reordered = self.transmission_line_data._apply_mode_reorder(
320285
sort_inds_2d
@@ -325,7 +290,71 @@ def _apply_mode_reorder(self, sort_inds_2d):
325290
return main_data_reordered
326291

327292

328-
class MicrowaveModeSolverData(ModeSolverData, MicrowaveModeData):
293+
class MicrowaveModeData(MicrowaveModeDataBase, ModeData):
294+
"""
295+
Data associated with a :class:`.ModeMonitor` for microwave and RF applications: modal amplitudes,
296+
propagation indices, mode profiles, and transmission line data.
297+
298+
Notes
299+
-----
300+
301+
This class extends :class:`.ModeData` with additional microwave-specific data including
302+
characteristic impedance, voltage coefficients, and current coefficients. The data is
303+
stored as `DataArray <https://docs.xarray.dev/en/stable/generated/xarray.DataArray.html>`_
304+
objects using the `xarray <https://docs.xarray.dev/en/stable/index.html>`_ package.
305+
306+
The microwave mode data contains all the information from :class:`.ModeData` plus additional
307+
microwave dataset with impedance calculations performed using voltage and current line integrals
308+
as specified in the :class:`.MicrowaveModeSpec`.
309+
310+
Example
311+
-------
312+
>>> import tidy3d as td
313+
>>> import numpy as np
314+
>>> from tidy3d.components.data.data_array import (
315+
... CurrentFreqModeDataArray,
316+
... ImpedanceFreqModeDataArray,
317+
... ModeAmpsDataArray,
318+
... ModeIndexDataArray,
319+
... VoltageFreqModeDataArray,
320+
... )
321+
>>> from tidy3d.components.microwave.data.dataset import TransmissionLineDataset
322+
>>> direction = ["+", "-"]
323+
>>> f = [1e14, 2e14, 3e14]
324+
>>> mode_index = np.arange(3)
325+
>>> index_coords = dict(f=f, mode_index=mode_index)
326+
>>> index_data = ModeIndexDataArray((1+1j) * np.random.random((3, 3)), coords=index_coords)
327+
>>> amp_coords = dict(direction=direction, f=f, mode_index=mode_index)
328+
>>> amp_data = ModeAmpsDataArray((1+1j) * np.random.random((2, 3, 3)), coords=amp_coords)
329+
>>> impedance_data = ImpedanceFreqModeDataArray(50 * np.ones((3, 3)), coords=index_coords)
330+
>>> voltage_data = VoltageFreqModeDataArray((1+1j) * np.random.random((3, 3)), coords=index_coords)
331+
>>> current_data = CurrentFreqModeDataArray((0.02+0.01j) * np.random.random((3, 3)), coords=index_coords)
332+
>>> tl_data = TransmissionLineDataset(
333+
... Z0=impedance_data,
334+
... voltage_coeffs=voltage_data,
335+
... current_coeffs=current_data
336+
... )
337+
>>> monitor = td.MicrowaveModeMonitor(
338+
... center=(0, 0, 0),
339+
... size=(2, 0, 6),
340+
... freqs=[2e14, 3e14],
341+
... mode_spec=td.MicrowaveModeSpec(num_modes=3, impedance_specs=td.AutoImpedanceSpec()),
342+
... name='microwave_mode',
343+
... )
344+
>>> data = MicrowaveModeData(
345+
... monitor=monitor,
346+
... amps=amp_data,
347+
... n_complex=index_data,
348+
... transmission_line_data=tl_data
349+
... )
350+
"""
351+
352+
monitor: MicrowaveModeMonitor = pd.Field(
353+
..., title="Monitor", description="Mode monitor associated with the data."
354+
)
355+
356+
357+
class MicrowaveModeSolverData(MicrowaveModeDataBase, ModeSolverData):
329358
"""
330359
Data associated with a :class:`.ModeSolverMonitor` for microwave and RF applications: scalar components
331360
of E and H fields plus characteristic impedance data.

tidy3d/components/microwave/monitor.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,27 @@
99
from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor
1010

1111

12-
class MicrowaveModeMonitor(MicrowaveBaseModel, ModeMonitor):
12+
class MicrowaveModeMonitorBase(MicrowaveBaseModel):
13+
"""Base class for microwave mode monitors that use :class:`.MicrowaveModeSpec`.
14+
15+
This mixin provides the ``mode_spec`` field configured for RF and microwave applications,
16+
including characteristic impedance calculations and transmission line analysis.
17+
18+
Notes
19+
-----
20+
This is a mixin class that provides the :class:`.MicrowaveModeSpec` field for mode monitors.
21+
It must be placed first in the inheritance list to ensure its ``mode_spec`` field takes
22+
precedence over the base :class:`.ModeSpec` field from :class:`.AbstractModeMonitor`.
23+
"""
24+
25+
mode_spec: MicrowaveModeSpec = pydantic.Field(
26+
default_factory=MicrowaveModeSpec._default_without_license_warning,
27+
title="Mode Specification",
28+
description="Parameters to feed to mode solver which determine modes measured by monitor.",
29+
)
30+
31+
32+
class MicrowaveModeMonitor(MicrowaveModeMonitorBase, ModeMonitor):
1333
""":class:`Monitor` that records amplitudes from modal decomposition of fields on plane.
1434
1535
Notes
@@ -47,14 +67,8 @@ class MicrowaveModeMonitor(MicrowaveBaseModel, ModeMonitor):
4767
* `ModalSourcesMonitors <../../notebooks/ModalSourcesMonitors.html>`_
4868
"""
4969

50-
mode_spec: MicrowaveModeSpec = pydantic.Field(
51-
default_factory=MicrowaveModeSpec._default_without_license_warning,
52-
title="Mode Specification",
53-
description="Parameters to feed to mode solver which determine modes measured by monitor.",
54-
)
5570

56-
57-
class MicrowaveModeSolverMonitor(MicrowaveModeMonitor, ModeSolverMonitor):
71+
class MicrowaveModeSolverMonitor(MicrowaveModeMonitorBase, ModeSolverMonitor):
5872
""":class:`Monitor` that stores the mode field profiles returned by the mode solver in the
5973
monitor plane.
6074
@@ -68,8 +82,3 @@ class MicrowaveModeSolverMonitor(MicrowaveModeMonitor, ModeSolverMonitor):
6882
... mode_spec=mode_spec,
6983
... name='mode_monitor')
7084
"""
71-
72-
@property
73-
def _stored_freqs(self) -> list[float]:
74-
"""Return actually stored frequencies of the data."""
75-
return self.mode_spec._sampling_freqs_mode_solver_data(freqs=self.freqs)

0 commit comments

Comments
 (0)