Source code for tidy3d.components.microwave.data.dataset

"""Dataset for microwave and RF transmission line mode data, including impedance, voltage, and current coefficients."""

from __future__ import annotations

from abc import abstractmethod
from typing import TYPE_CHECKING

import numpy as np
import xarray as xr
from pydantic import Field

from tidy3d.components.base import cached_property
from tidy3d.components.data.data_array import (
    CurrentFreqModeDataArray,
    CurrentFreqTerminalModeDataArray,
    ImpedanceFreqModeDataArray,
    ImpedanceFreqModeModeDataArray,
    ImpedanceFreqTerminalTerminalDataArray,
    ScalarTerminalFieldDataArray,
    VoltageFreqModeDataArray,
    VoltageFreqTerminalModeDataArray,
)
from tidy3d.components.data.dataset import (
    ElectromagneticFieldDataset,
    FreqDataset,
    ModeFreqDataset,
)

if TYPE_CHECKING:
    from tidy3d.components.data.data_array import VoltageFreqModeTerminalDataArray


class AbstractTransmissionLineDataset(ModeFreqDataset):
    """Base class for transmission line datasets."""

    @property
    @abstractmethod
    def Z0_matrix(
        self,
    ) -> ImpedanceFreqModeModeDataArray | ImpedanceFreqTerminalTerminalDataArray:
        """The characteristic impedance matrix."""


[docs] class TransmissionLineDataset(AbstractTransmissionLineDataset): """Holds mode data that is specific to transmission lines in microwave and RF applications, like characteristic impedance. Notes ----- The data in this class is only calculated when a :class:`~tidy3d.rf.MicrowaveModeSpec` is provided to the :class:`ModeMonitor`, :class:`ModeSolverMonitor`, :class:`ModeSolver`, or :class:`ModeSimulation`. """ Z0: ImpedanceFreqModeDataArray = Field( title="Characteristic Impedance", description="The characteristic impedance of the transmission line.", ) voltage_coeffs: VoltageFreqModeDataArray = Field( title="Mode Voltage Coefficients", description="Quantity calculated for transmission lines, which associates " "a voltage-like quantity with each mode profile that scales linearly with the " "complex-valued mode amplitude.", ) current_coeffs: CurrentFreqModeDataArray = Field( title="Mode Current Coefficients", description="Quantity calculated for transmission lines, which associates " "a current-like quantity with each mode profile that scales linearly with the " "complex-valued mode amplitude.", ) @cached_property def Z0_matrix(self) -> ImpedanceFreqModeModeDataArray: """The characteristic impedance matrix (diagonal matrix here).""" # Convert to full matrix with dimensions (f, mode_index_out, mode_index_in) mode_indices = self.Z0.coords["mode_index"].values num_modes = len(mode_indices) # Create identity matrix as xarray DataArray eye = xr.DataArray( np.eye(num_modes), coords={"mode_index_out": mode_indices, "mode_index_in": mode_indices}, ) # Rename dimension and multiply - xarray broadcasts correctly # Z0[f, mode_index_out] * eye[mode_index_out, mode_index_in] -> Z0_diag[f, mode_index_out, mode_index_in] Z0_diag = self.Z0.rename({"mode_index": "mode_index_out"}) * eye return ImpedanceFreqModeModeDataArray(Z0_diag)
[docs] class TransmissionLineTerminalDataset(AbstractTransmissionLineDataset): """Holds terminal data that is specific to transmission lines in microwave and RF applications, like characteristic impedance, and voltage and current mode to terminal transformation matrices. Notes ----- The data in this class is only calculated when a :class:`MicrowaveTerminalModeSpec` is provided to the :class:`ModeMonitor`, :class:`ModeSolverMonitor`, :class:`ModeSolver`, or :class:`ModeSimulation`. """ Z0: ImpedanceFreqTerminalTerminalDataArray = Field( ..., title="Terminal Characteristic Impedance Matrix", description="The terminal characteristic impedance matrix of the transmission line.", ) voltage_transform: VoltageFreqTerminalModeDataArray = Field( ..., title="Voltage Transformation Matrix", description="The voltage transformation matrix from modes to terminals.", ) current_transform: CurrentFreqTerminalModeDataArray = Field( ..., title="Current Transformation Matrix", description="The current transformation matrix from modes to terminals.", ) @cached_property def Z0_matrix(self) -> ImpedanceFreqTerminalTerminalDataArray: """The characteristic impedance matrix (diagonal matrix here).""" return self.Z0 @cached_property def voltage_transform_inv(self) -> VoltageFreqModeTerminalDataArray: """Inverse of the voltage transformation matrix. Returns ------- VoltageFreqModeTerminalDataArray Inverse of the voltage transform matrix that maps terminals to modes. """ return xr.apply_ufunc( np.linalg.inv, self.voltage_transform, input_core_dims=[["terminal_label", "mode_index"]], output_core_dims=[["mode_index", "terminal_label"]], vectorize=True, )
class TerminalFieldDataset(ElectromagneticFieldDataset, FreqDataset): """Dataset storing scalar components of E and H fields as a function of freq. and terminal_label. This dataset is similar to ModeSolverDataset but uses terminal_label instead of mode_index. Inherits from FreqDataset to support frequency interpolation via _interp_in_freq_update_dict. Example ------- >>> x = [-1,1] >>> y = [0] >>> z = [-3,-1,1,3] >>> f = [2e14, 3e14] >>> terminal_label = ["t0", "t1", "t2"] >>> field_coords = dict(x=x, y=y, z=z, f=f, terminal_label=terminal_label) >>> field = ScalarTerminalFieldDataArray((1+1j)*np.random.random((2,1,4,2,3)), coords=field_coords) >>> data = TerminalFieldDataset( ... Ex=field, ... Ey=field, ... Ez=field, ... Hx=field, ... Hy=field, ... Hz=field, ... ) """ Ex: ScalarTerminalFieldDataArray | None = Field( None, title="Ex", description="Spatial distribution of the x-component of the electric field for each terminal.", ) Ey: ScalarTerminalFieldDataArray | None = Field( None, title="Ey", description="Spatial distribution of the y-component of the electric field for each terminal.", ) Ez: ScalarTerminalFieldDataArray | None = Field( None, title="Ez", description="Spatial distribution of the z-component of the electric field for each terminal.", ) Hx: ScalarTerminalFieldDataArray | None = Field( None, title="Hx", description="Spatial distribution of the x-component of the magnetic field for each terminal.", ) Hy: ScalarTerminalFieldDataArray | None = Field( None, title="Hy", description="Spatial distribution of the y-component of the magnetic field for each terminal.", ) Hz: ScalarTerminalFieldDataArray | None = Field( None, title="Hz", description="Spatial distribution of the z-component of the magnetic field for each terminal.", )