Source code for reasitic.info
"""Geometry-information commands: metal area, segment listing,
partial-inductance matrix dump.
These mirror ``cmd_metalarea_print`` (``asitic_repl.c:0x0804ee74``),
``cmd_listsegs`` (case 210), and ``cmd_lrmat_dump`` (case 531). The
binary's outputs are textual; we return Python objects and format
them as text in :func:`format_*` helpers.
"""
from __future__ import annotations
from io import StringIO
from typing import Any
import numpy as np
from reasitic.geometry import Shape
from reasitic.inductance.filament import build_inductance_matrix, filament_grid
from reasitic.substrate.shunt import _polygon_signed_area
[docs]
def metal_area(shape: Shape) -> float:
"""Total xy-projected metal area of ``shape`` in μm².
Sum of absolute polygon areas (shoelace formula) across every
polygon in the shape. Polygons with fewer than 3 vertices
(e.g. a wire) are treated as zero-area.
"""
return float(
sum(abs(_polygon_signed_area(p.vertices)) for p in shape.polygons)
)
[docs]
def list_segments(shape: Shape) -> list[dict[str, Any]]:
"""Return one dict per segment with position, length, and width."""
out: list[dict[str, Any]] = []
for i, s in enumerate(shape.segments()):
out.append(
{
"index": i,
"x_a": s.a.x,
"y_a": s.a.y,
"z_a": s.a.z,
"x_b": s.b.x,
"y_b": s.b.y,
"z_b": s.b.z,
"length": s.length,
"width": s.width,
"thickness": s.thickness,
"metal": s.metal,
}
)
return out
[docs]
def format_segments(shape: Shape) -> str:
"""Render :func:`list_segments` as the binary's text format."""
out = StringIO()
out.write(f"Shape <{shape.name}> has {len(shape.segments())} segments:\n")
out.write(
f"{'#':>3} {'metal':>5} {'L_um':>10} {'a':>30} {'b':>30}\n"
)
for s in list_segments(shape):
a = f"({s['x_a']:.2f},{s['y_a']:.2f},{s['z_a']:.2f})"
b = f"({s['x_b']:.2f},{s['y_b']:.2f},{s['z_b']:.2f})"
out.write(
f"{s['index']:>3} {s['metal']:>5} {s['length']:>10.3f} {a:>30} {b:>30}\n"
)
return out.getvalue()
[docs]
def lr_matrix(shape: Shape) -> np.ndarray:
"""Per-segment partial inductance matrix in nH.
Diagonal = self-L of each segment; off-diagonal = signed Grover
parallel-segment mutual. Mirrors the binary's ``LRMAT`` dump
(case 531).
"""
fils = []
for idx, s in enumerate(shape.segments()):
for f in filament_grid(s, n_w=1, n_t=1):
f.parent_segment = idx
fils.append(f)
return build_inductance_matrix(fils)
[docs]
def format_lr_matrix(shape: Shape) -> str:
"""Render the partial-L matrix as a text table."""
M = lr_matrix(shape)
n = M.shape[0]
out = StringIO()
out.write(f"# Partial-inductance matrix (nH) for shape <{shape.name}>: {n}x{n}\n")
for i in range(n):
row = " ".join(f"{M[i, j]:10.6f}" for j in range(n))
out.write(row + "\n")
return out.getvalue()