from __future__ import annotations import importlib import inspect import re import sys from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) import nazca as nd import time import mxpic as mx RUNS_DIR = ROOT / "runs" OUTPUT_GDS = RUNS_DIR / "build_all_primitives.gds" PRIMITIVE_EXPORT_PACKAGES = ( "mxpic.components.primitives.active", "mxpic.components.primitives.passive", "mxpic.components.primitives.pic", ) SKIP_CLASSES = {"Route"} def bootstrap_technology() -> None: """Register broad layer and xsection defaults used by primitive examples.""" mx.technologies.foundry["AMF"]["AMF_Si220_Active"]() def discover_primitive_classes() -> list[type[Any]]: classes: list[type[Any]] = [] seen_class_paths: set[str] = set() for package_name in PRIMITIVE_EXPORT_PACKAGES: package = importlib.import_module(package_name) for _, cls in package.__dict__.items(): if not inspect.isclass(cls): continue if cls.__name__ in SKIP_CLASSES: continue if "__init__" not in cls.__dict__: continue if not ( cls.__module__ == package_name or cls.__module__.startswith(package_name + ".") ): continue class_path = f"{cls.__module__}.{cls.__name__}" if class_path in seen_class_paths: continue seen_class_paths.add(class_path) classes.append(cls) return classes def safe_name(prefix: str, index: int, class_name: str) -> str: cleaned = re.sub(r"[^A-Za-z0-9_]", "_", class_name) return f"{prefix}{index:03d}_{cleaned}"[:32] def get_cell(device: Any) -> nd.Cell: if isinstance(device, nd.Cell): return device cell = getattr(device, "cell", None) if isinstance(cell, nd.Cell): return cell raise TypeError(f"{type(device).__name__} did not expose a nazca Cell through .cell") def build_fiber_coupler_seed() -> nd.Cell: with nd.Cell(name="_seed_fiber_coupler", instantiate=False) as cell: straight = nd.strt(length=10, width=0.45, xs="strip").put(0, 0, 0) nd.Pin(name="g1", pin=straight.pin["a0"]).put() nd.Pin(name="a0", pin=straight.pin["a0"]).put() nd.Pin(name="b0", pin=straight.pin["b0"]).put() return cell class BuildContext(dict[str, Any]): def __missing__(self, key: str) -> Any: try: builder = CONTEXT_BUILDERS[key] except KeyError: raise KeyError(key) from None value = builder(self) self[key] = value return value def build_context() -> BuildContext: return BuildContext() def build_via_i2m(_: BuildContext) -> Any: from mxpic.components.electronics import Vias return Vias( xs="via_s2m", area=[1.0, 1.0], sz=[0.25, 0.25], spacing=[0.35, 0.35], xs_l1="p", xs_l2="metal", ) def build_via_h2m(_: BuildContext) -> Any: from mxpic.components.electronics import Vias return Vias( xs="via_h2m", area=[1.0, 1.0], sz=[0.25, 0.25], spacing=[0.35, 0.35], xs_l1="heater", xs_l2="metal", ) def build_grating_unit(_: BuildContext) -> Any: from mxpic.components.primitives.pic.gratings import Grating_2D_Hole return Grating_2D_Hole() def build_psr(_: BuildContext) -> Any: from mxpic.components.primitives.pic.taper import PSR return PSR(name="_seed_psr") def build_mdm(_: BuildContext) -> Any: from mxpic.components.primitives.pic.couplers import MDM return MDM(name="_seed_mdm") def build_bragg(_: BuildContext) -> Any: from mxpic.components.primitives.pic.bragg import Bragg return Bragg() def build_crow_ring_device(_: BuildContext) -> Any: from mxpic.components.primitives.pic.rings import AED_ring return AED_ring(name="_seed_aed_ring") def build_crow_bus_device(_: BuildContext) -> Any: from mxpic.components.primitives.pic.couplers import ring_bus_wg return ring_bus_wg() CONTEXT_BUILDERS = { "fiber_coupler": lambda context: build_fiber_coupler_seed(), "grating_unit": build_grating_unit, "psr": build_psr, "mdm": build_mdm, "bragg": build_bragg, "_crow_ring_device": build_crow_ring_device, "crow_ring": lambda context: context["_crow_ring_device"].cell, "crow_w_ring": lambda context: [0.45, 0.65], "crow_sz_ring": lambda context: [20, 20], "_crow_bus_device": build_crow_bus_device, "crow_bus": lambda context: context["_crow_bus_device"].cell, "crow_w_bus": lambda context: context["_crow_bus_device"].w, "crow_sz_bus": lambda context: context["_crow_bus_device"].sz, "via_h2m": build_via_h2m, "via_i2m": build_via_i2m, } REQUIRED_VALUES: dict[str, Any] = { "A_cp": 10, "Brag": lambda context: context["bragg"], "MDM": lambda context: context["mdm"], "PSR": lambda context: context["psr"], "R0": 10, "R1": 6, "bus": lambda context: context["crow_bus"], "dLx": 0, "dLy": 10, "fiber_coupler": lambda context: context["fiber_coupler"], "gap": 0.2, "grating_unit": lambda context: context["grating_unit"], "number": 4, "pitch": 127, "r0_rck": 6, "r1_rck": 10, "r_ring": 10, "r_rck": 10, "ring": lambda context: context["crow_ring"], "sz_bus": lambda context: context["crow_sz_bus"], "sz_ring": lambda context: context["crow_sz_ring"], "w0": 0.45, "w0_ring": 0.35, "w0_rck": 0.45, "w1": 0.45, "w1_ring": 0.55, "w1_rck": 0.45, "w_bus": 0.45, "w_ring": 0.45, "w_rck": 0.45, } def class_overrides( class_path: str, _context: dict[str, Any], ) -> dict[str, Any]: overrides = { "mxpic.components.primitives.pic.couplers.ADC_STD_2x2": {"Rd1": 20}, } return dict(overrides.get(class_path, {})) def required_value(parameter: str, context: dict[str, Any]) -> Any: value = REQUIRED_VALUES[parameter] if callable(value): return value(context) return value def build_kwargs(cls: type[Any], device_name: str, context: dict[str, Any]) -> dict[str, Any]: signature = inspect.signature(cls) kwargs: dict[str, Any] = {} class_path = f"{cls.__module__}.{cls.__name__}" for parameter_name, parameter in signature.parameters.items(): if parameter_name == "self": continue if parameter_name == "name": kwargs[parameter_name] = device_name continue if parameter_name == "cell_name": kwargs[parameter_name] = device_name continue if parameter_name == "via_i2m": kwargs[parameter_name] = context["via_i2m"] continue if parameter.default is inspect.Parameter.empty: kwargs[parameter_name] = required_value(parameter_name, context) kwargs.update(class_overrides(class_path, context)) return kwargs def build_top_cell(cell: nd.Cell, top_name: str) -> nd.Cell: with nd.Cell(name=top_name, instantiate=False) as top_cell: cell.put(0, 0, 0) return top_cell def main() -> None: bootstrap_technology() context = build_context() topcells = [] failures = [] for index, cls in enumerate(discover_primitive_classes(), start=1): device_name = safe_name("DEV", index, cls.__name__) top_name = safe_name("TOP", index, cls.__name__) class_path = f"{cls.__module__}.{cls.__name__}" try: kwargs = build_kwargs(cls, device_name, context) device = cls(**kwargs) topcells.append(build_top_cell(get_cell(device), top_name)) print(f"built {top_name}: {class_path}") except Exception as exc: failures.append((class_path, exc)) print(f"failed {class_path}: {exc}") if failures: print("\nPrimitive build failures:") for class_path, exc in failures: print(f"- {class_path}: {exc}") raise RuntimeError(f"{len(failures)} primitive(s) failed to build") nd.export_gds(topcells=topcells, filename=str(OUTPUT_GDS)) print(f"\nWrote {len(topcells)} top cells to {OUTPUT_GDS}") if __name__ == "__main__": main()