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 __future__ import annotations
from abc import abstractmethod
from typing import TYPE_CHECKING, Any, Optional
from pydantic import Field, PositiveInt
from tidy3d.components.base import cached_property
from tidy3d.components.geometry.utils_2d import snap_coordinate_to_grid
from tidy3d.components.types import Complex
from tidy3d.constants import OHM
from .base_terminal import AbstractTerminalPort
if TYPE_CHECKING:
from tidy3d.components.grid.grid import Grid, YeeGrid
from tidy3d.components.lumped_element import LumpedElementType
from tidy3d.components.microwave.path_integrals.integrals.voltage import (
AxisAlignedVoltageIntegral,
)
from tidy3d.components.monitor import FieldMonitor
from tidy3d.components.types import Coordinate, FreqArray
DEFAULT_PORT_NUM_CELLS = 3
DEFAULT_REFERENCE_IMPEDANCE = 50
[docs]
class AbstractLumpedPort(AbstractTerminalPort):
"""Class representing a single lumped port."""
impedance: Complex = Field(
DEFAULT_REFERENCE_IMPEDANCE,
title="Reference impedance",
description="Reference port impedance for scattering parameter computation.",
json_schema_extra={"units": OHM},
)
num_grid_cells: Optional[PositiveInt] = 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.",
)
enable_snapping_points: bool = Field(
True,
title="Snap Grid To Lumped Port",
description="When enabled, snapping points are automatically generated to snap grids to key "
"geometric features of the lumped port for more accurate modelling.",
)
@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"
[docs]
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 load.
"""
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 to_load(self, snap_center: Optional[float] = None) -> LumpedElementType:
"""Create a load from the lumped port."""
[docs]
@abstractmethod
def to_voltage_monitor(
self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Optional[Grid] = None
) -> FieldMonitor:
"""Field monitor to compute port voltage."""
[docs]
@abstractmethod
def to_current_monitor(
self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Optional[Grid] = None
) -> FieldMonitor:
"""Field monitor to compute port current."""
[docs]
def to_monitors(
self,
freqs: FreqArray,
snap_center: Optional[float] = None,
grid: Optional[Grid] = None,
**kwargs: Any,
) -> list[FieldMonitor]:
"""Field monitors to compute port voltage and current."""
return [
self.to_voltage_monitor(freqs, snap_center, grid),
self.to_current_monitor(freqs, snap_center, grid),
]
@abstractmethod
def _make_plot_voltage_integral(self) -> AxisAlignedVoltageIntegral:
"""Create a voltage path integral for plotting (no grid needed)."""
@abstractmethod
def _check_grid_size(self, yee_grid: YeeGrid) -> None:
"""Raises :class:`SetupError` if the grid is too coarse at port locations."""
@property
def _is_using_mesh_refinement(self) -> bool:
"""Check if this lumped port is using any mesh refinement options.
Returns ``True`` if snapping points are enabled or custom grid cell count is specified.
"""
return self.enable_snapping_points or self.num_grid_cells is not None