88
99import pydantic .v1 as pd
1010import xarray as xr
11+ from typing_extensions import Self
1112
1213from tidy3d .components .data .data_array import FieldProjectionAngleDataArray , FreqDataArray
1314from 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.
0 commit comments