Source code for tidy3d.plugins.smatrix.ports.base_lumped

"""Class and custom data array for representing a scattering matrix port based on lumped circuit elements."""

from abc import ABC, abstractmethod
from typing import Optional

import pydantic.v1 as pd

from ....components.base import Tidy3dBaseModel, cached_property
from ....components.data.data_array import DataArray, FreqDataArray
from ....components.data.sim_data import SimulationData
from ....components.geometry.utils_2d import snap_coordinate_to_grid
from ....components.grid.grid import Grid, YeeGrid
from ....components.lumped_element import AbstractLumpedResistor
from ....components.monitor import FieldMonitor
from ....components.source import GaussianPulse, UniformCurrentSource
from ....components.types import Complex, Coordinate, FreqArray
from ....constants import OHM

DEFAULT_PORT_NUM_CELLS = 3
DEFAULT_REFERENCE_IMPEDANCE = 50


[docs] class LumpedPortDataArray(DataArray): """Port parameter matrix elements for lumped ports. Example ------- >>> import numpy as np >>> ports_in = ['port1', 'port2'] >>> ports_out = ['port1', 'port2'] >>> f = [2e14] >>> coords = dict( ... port_in=ports_in, ... port_out=ports_out, ... f=f ... ) >>> fd = LumpedPortDataArray((1 + 1j) * np.random.random((2, 2, 1)), coords=coords) """ __slots__ = () _dims = ("port_out", "port_in", "f") _data_attrs = {"long_name": "lumped port matrix element"}
class AbstractLumpedPort(Tidy3dBaseModel, ABC): """Class representing a single lumped port""" name: str = pd.Field( ..., title="Name", description="Unique name for the port.", min_length=1, ) impedance: Complex = pd.Field( DEFAULT_REFERENCE_IMPEDANCE, title="Reference impedance", description="Reference port impedance for scattering parameter computation.", units=OHM, ) num_grid_cells: Optional[pd.PositiveInt] = pd.Field( DEFAULT_PORT_NUM_CELLS, title="Port grid cells", description="Number of mesh grid cells associated with the port along each direction, " "which are added through automatic mesh refinement. " "A value of ``None`` will turn off automatic mesh refinement.", ) @cached_property def _voltage_monitor_name(self) -> str: return f"{self.name}_voltage" @cached_property def _current_monitor_name(self) -> str: return f"{self.name}_current" def snapped_center(self, grid: Grid) -> Coordinate: """Get the exact center of this port after snapping along the injection axis. Ports are snapped to the nearest Yee cell boundary to match the exact position of the ``AbstractLumpedResistor". """ center = list(self.center) normal_axis = self.injection_axis normal_port_center = center[normal_axis] center[normal_axis] = snap_coordinate_to_grid(grid, normal_port_center, normal_axis) return tuple(center) @cached_property @abstractmethod def injection_axis(self): """Injection axis of the port.""" @abstractmethod def to_source( self, source_time: GaussianPulse, snap_center: float, grid=Grid ) -> UniformCurrentSource: """Create a current source from the lumped port.""" @abstractmethod def to_load(self, snap_center: float) -> AbstractLumpedResistor: """Create a load resistor from the lumped port.""" @abstractmethod def to_voltage_monitor(self, freqs: FreqArray, snap_center: float) -> FieldMonitor: """Field monitor to compute port voltage.""" @abstractmethod def to_current_monitor(self, freqs: FreqArray, snap_center: float) -> FieldMonitor: """Field monitor to compute port current.""" @abstractmethod def compute_voltage(self, sim_data: SimulationData) -> FreqDataArray: """Helper to compute voltage across the port.""" @abstractmethod def compute_current(self, sim_data: SimulationData) -> FreqDataArray: """Helper to compute current flowing through the port.""" @abstractmethod def _check_grid_size(yee_grid: YeeGrid): """Raises :class:``SetupError`` if the grid is too coarse at port locations"""