{ "cells": [ { "cell_type": "markdown", "id": "c6f135d3", "metadata": {}, "source": [ "# 08 · Any EDA in, any engine out\n", "\n", "`07_choosing_an_engine` showed one job running on three *engines*. This is the\n", "mirror image — and then the two axes together. **However your geometry is\n", "authored** — programmatically in gdsfactory, in a KLayout/SiEPIC foundry PDK,\n", "or as a plain GDS from any tool — gds_fdtd ingests it, **auto-detects the\n", "ports**, and hands you the same engine-agnostic `Component`. From there the\n", "identical `validate → build → run` drives beamz, tidy3d, or Lumerical.\n", "\n", "| Frontend | How you get geometry | Entry point |\n", "|----------|----------------------|-------------|\n", "| **gdsfactory** | parametric Python components (PDK) | `layout.gdsfactory.from_gdsfactory` |\n", "| **KLayout / SiEPIC** | a foundry PDK cell | `lyprocessor.load_cell` → `load_component_from_tech` |\n", "| **raw GDS** | any `.gds` from any tool | `lyprocessor.load_cell` → `load_component_from_tech` |\n", "| **PreFab** | a lithography-predicted GDS | `lyprocessor.load_device(prefab_model=…)` |\n", "\n", "The last section is the full **frontend × engine matrix**: three devices — one\n", "from each frontend — each simulated on all three engines, with recorded results\n", "so this notebook reproduces for free." ] }, { "cell_type": "code", "execution_count": 1, "id": "b46ceffc", "metadata": { "execution": { "iopub.execute_input": "2026-07-20T01:55:02.789680Z", "iopub.status.busy": "2026-07-20T01:55:02.789517Z", "iopub.status.idle": "2026-07-20T01:55:03.268643Z", "shell.execute_reply": "2026-07-20T01:55:03.267930Z" } }, "outputs": [], "source": [ "import json\n", "import os\n", "from pathlib import Path\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from gds_fdtd.lyprocessor import load_cell\n", "from gds_fdtd.plotting import plot_component, plot_permittivity\n", "from gds_fdtd.simprocessor import load_component_from_tech\n", "from gds_fdtd.smatrix import SMatrix\n", "from gds_fdtd.spec import SimulationSpec\n", "from gds_fdtd.technology import Technology\n", "\n", "\n", "def _find(rel: str) -> Path:\n", " for base in (Path.cwd(), *Path.cwd().parents):\n", " if (base / rel).exists():\n", " return base / rel\n", " raise FileNotFoundError(rel)\n", "\n", "\n", "REC = _find(\"examples/08_frontends/recorded\")\n", "tech = Technology.from_yaml(_find(\"examples/tech.yaml\"))\n", "components = {} # frontend label -> Component" ] }, { "cell_type": "markdown", "id": "69cded6a", "metadata": {}, "source": [ "## 1 · gdsfactory — parametric, programmatic\n", "\n", "[gdsfactory](https://gdsfactory.github.io/gdsfactory/) builds components in\n", "Python. `from_gdsfactory` reads the polygons on each technology layer and\n", "lifts the gdsfactory ports into gds_fdtd ports. The device: a gentle\n", "**S-bend** (`bend_s`, 5×1 µm), used again in the matrix at the end." ] }, { "cell_type": "code", "execution_count": 2, "id": "473ee544", "metadata": { "execution": { "iopub.execute_input": "2026-07-20T01:55:03.270215Z", "iopub.status.busy": "2026-07-20T01:55:03.270094Z", "iopub.status.idle": "2026-07-20T01:55:05.226252Z", "shell.execute_reply": "2026-07-20T01:55:05.225543Z" } }, "outputs": [ { "data": { "text/html": [ "
18:55:04 PDT WARNING: Using canonical configuration directory at \n", " '/home/mustafa/.config/tidy3d'. Found legacy directory at \n", " '~/.tidy3d', which will be ignored. Remove it manually or run \n", " 'tidy3d config migrate --delete-legacy' to clean up. \n", "\n" ], "text/plain": [ "\u001b[2;36m18:55:04 PDT\u001b[0m\u001b[2;36m \u001b[0m\u001b[31mWARNING: Using canonical configuration directory at \u001b[0m\n", "\u001b[2;36m \u001b[0m\u001b[32m'/home/mustafa/.config/tidy3d'\u001b[0m\u001b[31m. Found legacy directory at \u001b[0m\n", "\u001b[2;36m \u001b[0m\u001b[32m'~/.tidy3d'\u001b[0m\u001b[31m, which will be ignored. Remove it manually or run \u001b[0m\n", "\u001b[2;36m \u001b[0m\u001b[32m'tidy3d config migrate --delete-legacy'\u001b[0m\u001b[31m to clean up. \u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import gdsfactory as gf # noqa: E402\n", "\n", "from gds_fdtd.layout.gdsfactory import from_gdsfactory # noqa: E402\n", "\n", "gf.gpdk.PDK.activate()\n", "gf_bend = from_gdsfactory(gf.components.bend_s(size=(5.0, 1.0)), tech)\n", "gf_bend.name = \"gf_bend_s\"\n", "components[\"gdsfactory\\nbend_s\"] = gf_bend" ] }, { "cell_type": "markdown", "id": "b7fb469f", "metadata": {}, "source": [ "## 2 · KLayout / SiEPIC — a foundry PDK\n", "\n", "The same reader consumes a cell straight from the SiEPIC EBeam PDK (the\n", "`ebeam_y_1550` y-branch) — KLayout pin + DevRec conventions become ports and\n", "bounds automatically. This is the path most silicon-photonics tapeouts use,\n", "and it feeds *every* engine (beamz reads the extruded polygons through a\n", "component shim)." ] }, { "cell_type": "code", "execution_count": 3, "id": "68d06b27", "metadata": { "execution": { "iopub.execute_input": "2026-07-20T01:55:05.228336Z", "iopub.status.busy": "2026-07-20T01:55:05.228126Z", "iopub.status.idle": "2026-07-20T01:55:05.583994Z", "shell.execute_reply": "2026-07-20T01:55:05.583342Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SiEPIC-EBeam-PDK Python module: siepic_ebeam_pdk, KLayout technology: EBeam\n", "KLayout SiEPIC-Tools version 0.5.31\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "SiEPIC-Tools is up to date (0.5.31 vs 0.5.31).\n", "Version check, time: 0.28484654426574707 seconds\n", "SiEPIC-EBeam-PDK Python module: pymacros, v0.4.53\n", "Libraries associated with Technology EBeam: ['EBeam', 'EBeam-ANT', 'EBeam-Dream', 'EBeam-SiN', 'EBeam_Beta']\n" ] } ], "source": [ "try:\n", " import siepic_ebeam_pdk as pdk\n", "\n", " gds = os.path.join(os.path.dirname(pdk.__file__), \"gds\", \"EBeam\", \"ebeam_y_1550.gds\")\n", " cell, _ = load_cell(gds, top_cell=\"ebeam_y_1550\")\n", " ybranch = load_component_from_tech(cell=cell, tech=tech)\n", " ybranch.name = \"ebeam_y_1550\"\n", " components[\"SiEPIC\\nebeam_y_1550\"] = ybranch\n", "except ImportError:\n", " print(\"(install siepic_ebeam_pdk to load the SiEPIC PDK cell)\")" ] }, { "cell_type": "markdown", "id": "fdf39665", "metadata": {}, "source": [ "## 3 · A raw GDS file — from any tool\n", "\n", "No PDK, no framework: point `load_cell` at any `.gds` whose polygons land on\n", "the technology's device/pin/DevRec layers. Here it is `sbend_dontfabme` from\n", "`examples/devices.gds`, the *sharp* S-bend that `06_convergence_and_caching`\n", "uses as its stress test." ] }, { "cell_type": "code", "execution_count": 4, "id": "a3e26261", "metadata": { "execution": { "iopub.execute_input": "2026-07-20T01:55:05.585299Z", "iopub.status.busy": "2026-07-20T01:55:05.585161Z", "iopub.status.idle": "2026-07-20T01:55:05.595318Z", "shell.execute_reply": "2026-07-20T01:55:05.594850Z" } }, "outputs": [], "source": [ "cell, _ = load_cell(str(_find(\"examples/devices.gds\")), top_cell=\"sbend_dontfabme\")\n", "sbend = load_component_from_tech(cell=cell, tech=tech)\n", "sbend.name = \"sbend_dontfabme\"\n", "components[\"raw GDS\\nsbend_dontfabme\"] = sbend" ] }, { "cell_type": "markdown", "id": "39756837", "metadata": {}, "source": [ "## 4 · PreFab — lithography-aware geometry\n", "\n", "[PreFab](https://www.prefabphotonics.com/) predicts how a nanofabrication\n", "process will *actually* print your design (corner rounding, proximity\n", "effects). `load_device` runs the model and writes a `