Skip to content

Circuits

circuits

Photonic circuit simulation: an S-matrix netlist solver and compact models.

Solve a :class:~lightsmith.problems.CircuitProblem with lightsmith.solve(problem) (backend lightsmith-circuit, method circuit), or call :func:circuit_sparameters directly to get the S-matrix as an array (a PyTorch tensor with gradients on device="torch-cpu"/CUDA)::

from lightsmith.circuits import circuit_sparameters
sol = circuit_sparameters(problem, device="torch-cpu", params={"ring": {"neff": neff_tensor}})
power = abs(sol["out", "in"]) ** 2

:func:list_models documents every compact model and its settings. Files from field solvers (Touchstone .sNp or SParameterResult JSON) enter a circuit as "component": "sparams:<path>"; :func:waveguide_from_modes turns an FDE ModeResult into a dispersive waveguide instance.

MODELS module-attribute

MODELS: dict[str, CompactModel] = {}

CircuitSolution dataclass

CircuitSolution(ports: list[str], wavelengths_nm: ndarray, s: Any, device: Device, info: dict[str, Any] = dict(), warnings: list[str] = list())

ports instance-attribute

ports: list[str]

wavelengths_nm instance-attribute

wavelengths_nm: ndarray

s instance-attribute

s: Any

device instance-attribute

device: Device

info class-attribute instance-attribute

info: dict[str, Any] = field(default_factory=dict)

warnings class-attribute instance-attribute

warnings: list[str] = field(default_factory=list)

numpy

numpy() -> ndarray

NetlistError

Bases: ValueError

The netlist is inconsistent (unknown/duplicate/unconnected ports, unknown models, bad settings).

Ctx dataclass

Ctx(wl_np: ndarray, device: Device, single: bool = False)

Wavelength grid and array namespace a model is evaluated on.

wl_np instance-attribute

wl_np: ndarray

device instance-attribute

device: Device

single class-attribute instance-attribute

single: bool = False

n property

n: int

p

p(v)

A setting as a (possibly differentiable) real array; tensors pass through.

zeros

zeros()

c

c(v)

Broadcast a real/complex scalar or (W,) array to a complex (W,) array.

expi

expi(phi)

exp(i phi) for real phi.

table

table(x_nm, y)

Interpolate tabulated data (not differentiable) onto the wavelength grid.

smatrix

smatrix(ports: list[str], entries: dict[tuple[str, str], Any], reciprocal: bool = True)

Assemble S[w, out, in] from {(out, in): (W,) array}; reciprocal fills (in, out) too.

check_netlist

check_netlist(problem: CircuitProblem, ports_of: dict[str, list[str]], unconnected: str = 'error') -> tuple[list[tuple[str, str]], dict[str, str], list[str], list[str]]

Validate references; return (connections, external map, ignored ports, warnings).

Raises :class:NetlistError naming every unknown, duplicate or unconnected port.

circuit_sparameters

circuit_sparameters(problem: CircuitProblem | dict | str, *, params: dict[str, dict[str, Any]] | None = None, device: str | Device = 'cpu', wavelengths_nm=None, algorithm: Literal['auto', 'dense', 'reduce'] = 'auto', precision: Literal['double', 'single'] = 'double', unconnected: Literal['error', 'ignore'] = 'error', base_dir: str | Path | None = None) -> CircuitSolution

Solve a circuit and return its external S-matrix as an array on device.

params overrides instance settings, e.g. {"ring": {"neff": t}}; with device="torch-cpu" (or a CUDA device) and t a tensor with requires_grad=True, gradients flow from the result back to t. wavelengths_nm overrides the problem's wavelengths.

interconnect

interconnect(blocks: dict[str, Block], conns: list[tuple[str, str]], ext_refs: list[str], ctx: Ctx, algorithm: Literal['auto', 'dense', 'reduce'] = 'auto') -> tuple[Any, str]

External S-matrix of the connected blocks; returns (S_ext, algorithm used).

compact_model

compact_model(name: str, settings: type[ModelSettings], ports: tuple[str, ...] | None, aliases: tuple[str, ...] = ())

Register a compact model fn(ctx, values) -> (ports, S[w, out, in]) under name.

get_model

get_model(component: str) -> CompactModel

Look up a model by name or alias; sparams:<path> loads S-parameters from a file.

list_models

list_models() -> list[dict[str, Any]]

Every registered model: name, aliases, ports, documentation and settings JSON schema.

model_names

model_names() -> list[str]

waveguide_from_modes

waveguide_from_modes(result, length_nm: float, mode: int = 0, wl0_nm: float | None = None, extra_loss_db_per_cm: float = 0.0)

Build a waveguide :class:~lightsmith.problems.Instance from an FDE ModeResult.

With one wavelength the model uses neff, ng (from the mode, or neff if absent) and the mode loss at that wavelength. With several wavelengths neff and loss are tabulated (and interpolated, no extrapolation), so the circuit sees the full dispersion that the mode solver computed. mode indexes modes sorted by decreasing neff, as in ModeResult.modes[wavelength][mode].

read_sparameters

read_sparameters(path: str | Path, time_convention: TimeConvention = '+iwt') -> tuple[ndarray, list[str], ndarray]

Read S-parameters from a Touchstone (.sNp/.ts) or SParameterResult JSON file.

read_touchstone

read_touchstone(path: str | Path, time_convention: TimeConvention = '+iwt') -> tuple[ndarray, list[str], ndarray]

Read a Touchstone file. Returns (wavelengths_nm ascending, port names, S[wl, out, in]).

S is returned in lightsmith's exp(-i omega t) convention (conjugated when the file uses time_convention="+iwt", the Touchstone standard).

write_touchstone

write_touchstone(path: str | Path, wavelengths_nm, s, ports: list[str] | None = None, time_convention: TimeConvention = '+iwt') -> Path

Write S[wl, out, in] (exp(-i omega t) convention) as a Touchstone 1.1 RI file in Hz.

The extension should be .sNp with N the port count. Port names go into ! Port[n] = name comments so :func:read_touchstone restores them.