diff --git a/mkdocs.yml b/mkdocs.yml index d741b0a..0bd1e58 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,7 +21,8 @@ nav: - Directional Coupler: nbs/meep_dc.md - Crossing: nbs/meep_crossing.md - FEM for RF: - - CPW: nbs/palace_cpw.md + - CPW (Lumped Ports): nbs/palace_cpw_lumped.md + - CPW (Wave Ports): nbs/palace_cpw_waveport.md - Microstrip: nbs/palace_microstrip.md - Branch Line Coupler: nbs/palace_branch_line_coupler.md - "Parallel Simulations: Width Sweep": nbs/palace_width_sweep.md diff --git a/nbs/_palace_cpw.ipynb b/nbs/_palace_cpw.ipynb new file mode 100644 index 0000000..8584374 --- /dev/null +++ b/nbs/_palace_cpw.ipynb @@ -0,0 +1,519 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": { + "papermill": { + "duration": 0.00345, + "end_time": "2026-04-04T05:08:46.583945", + "exception": false, + "start_time": "2026-04-04T05:08:46.580495", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "# Running Palace Simulations\n", + "\n", + "[Palace](https://awslabs.github.io/palace/) is an open-source 3D electromagnetic simulator supporting eigenmode, driven (S-parameter), and electrostatic simulations. This notebook demonstrates using the `gsim.palace` API to run a driven simulation on a CPW (coplanar waveguide) structure.\n", + "\n", + "**Requirements:**\n", + "\n", + "- IHP PDK: `uv pip install ihp-gdsfactory`\n", + "- [GDSFactory+](https://gdsfactory.com) account for cloud simulation" + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": { + "papermill": { + "duration": 0.001823, + "end_time": "2026-04-04T05:08:46.589529", + "exception": false, + "start_time": "2026-04-04T05:08:46.587706", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "### Load a pcell from IHP PDK" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:08:46.594146Z", + "iopub.status.busy": "2026-04-04T05:08:46.593957Z", + "iopub.status.idle": "2026-04-04T05:08:48.217508Z", + "shell.execute_reply": "2026-04-04T05:08:48.217147Z" + }, + "papermill": { + "duration": 1.626697, + "end_time": "2026-04-04T05:08:48.218023", + "exception": false, + "start_time": "2026-04-04T05:08:46.591326", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import gdsfactory as gf\n", + "from ihp import LAYER, PDK\n", + "\n", + "PDK.activate()\n", + "\n", + "\n", + "@gf.cell\n", + "def gsg_electrode(\n", + " length: float = 800,\n", + " s_width: float = 20,\n", + " g_width: float = 40,\n", + " gap_width: float = 15,\n", + " layer=LAYER.TopMetal2drawing,\n", + ") -> gf.Component:\n", + " \"\"\"\n", + " Create a GSG (Ground-Signal-Ground) electrode.\n", + "\n", + " Args:\n", + " length: horizontal length of the electrodes\n", + " s_width: width of the signal (center) electrode\n", + " g_width: width of the ground electrodes\n", + " gap_width: gap between signal and ground electrodes\n", + " layer: layer for the metal\n", + " \"\"\"\n", + " c = gf.Component()\n", + "\n", + " # Top ground electrode\n", + " r1 = c << gf.c.rectangle((length, g_width), centered=True, layer=layer)\n", + " r1.move((0, (g_width + s_width) / 2 + gap_width))\n", + "\n", + " # Center signal electrode\n", + " _r2 = c << gf.c.rectangle((length, s_width), centered=True, layer=layer)\n", + "\n", + " # Bottom ground electrode\n", + " r3 = c << gf.c.rectangle((length, g_width), centered=True, layer=layer)\n", + " r3.move((0, -(g_width + s_width) / 2 - gap_width))\n", + "\n", + " # Add ports at the signal center (one per side)\n", + " # The CPW port API computes the gap element surfaces from s_width and gap_width\n", + " c.add_port(\n", + " name=\"o1\",\n", + " center=(-length / 2, 0),\n", + " width=s_width,\n", + " orientation=180,\n", + " port_type=\"electrical\",\n", + " layer=layer,\n", + " )\n", + "\n", + " c.add_port(\n", + " name=\"o2\",\n", + " center=(length / 2, 0),\n", + " width=s_width,\n", + " orientation=0,\n", + " port_type=\"electrical\",\n", + " layer=layer,\n", + " )\n", + "\n", + " return c\n", + "\n", + "\n", + "c = gsg_electrode()\n", + "cc = c.copy()\n", + "cc.draw_ports()\n", + "cc" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": { + "papermill": { + "duration": 0.000656, + "end_time": "2026-04-04T05:08:48.219611", + "exception": false, + "start_time": "2026-04-04T05:08:48.218955", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "### Configure and run simulation with DrivenSim" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:08:48.221390Z", + "iopub.status.busy": "2026-04-04T05:08:48.221229Z", + "iopub.status.idle": "2026-04-04T05:08:48.687534Z", + "shell.execute_reply": "2026-04-04T05:08:48.687184Z" + }, + "papermill": { + "duration": 0.467892, + "end_time": "2026-04-04T05:08:48.688108", + "exception": false, + "start_time": "2026-04-04T05:08:48.220216", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "from gsim.palace import DrivenSim\n", + "\n", + "# Create simulation object\n", + "sim_lumped = DrivenSim()\n", + "\n", + "# Set output directory\n", + "sim_lumped.set_output_dir(\"./palace-sim-cpw\")\n", + "\n", + "# Set the component geometry\n", + "sim_lumped.set_geometry(c)\n", + "\n", + "# Configure layer stack from active PDK\n", + "sim_lumped.set_stack(substrate_thickness=2.0, air_above=100.0, air_below=100.0)\n", + "\n", + "# Configure left CPW port (single port at signal center)\n", + "sim_lumped.add_cpw_port(\n", + " \"o1\",\n", + " layer=\"topmetal2\",\n", + " s_width=20,\n", + " gap_width=15,\n", + " length=1.0,\n", + " # offset=2.5,\n", + " excited=True,\n", + ")\n", + "\n", + "# Configure right CPW port (single port at signal center)\n", + "sim_lumped.add_cpw_port(\n", + " \"o2\",\n", + " layer=\"topmetal2\",\n", + " s_width=20,\n", + " gap_width=15,\n", + " length=1.0,\n", + " # offset=2.5,\n", + " excited=False,\n", + ")\n", + "\n", + "# Configure driven simulation (frequency sweep for S-parameters)\n", + "sim_lumped.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n", + "\n", + "# Validate configuration\n", + "print(sim_lumped.validate_config())" + ] + }, + { + "cell_type": "markdown", + "id": "5df9d4ab", + "metadata": {}, + "source": [ + "### Configure simulation with DrivenSim for WavePorts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f107f324", + "metadata": {}, + "outputs": [], + "source": [ + "# Create simulation object\n", + "sim_waveport = DrivenSim()\n", + "\n", + "# Set output directory\n", + "sim_waveport.set_output_dir(\"./palace-sim-cpw-waveport\")\n", + "\n", + "# Set the component geometry\n", + "sim_waveport.set_geometry(c)\n", + "\n", + "# Configure layer stack from active PDK\n", + "sim_waveport.set_stack(substrate_thickness=2.0, air_above=100.0, air_below=100.0)\n", + "\n", + "# Configure left CPW port (single port at signal center)\n", + "sim_waveport.add_wave_port(\"o1\", layer=\"topmetal2\", max_size=True, mode=1, excited=True)\n", + "\n", + "# Configure right CPW port (single port at signal center)\n", + "sim_waveport.add_wave_port(\n", + " \"o2\", layer=\"topmetal2\", max_size=True, mode=1, excited=False\n", + ")\n", + "\n", + "# Configure driven simulation (frequency sweep for S-parameters)\n", + "sim_waveport.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n", + "\n", + "# Validate configuration\n", + "print(sim_waveport.validate_config())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:08:48.690170Z", + "iopub.status.busy": "2026-04-04T05:08:48.690094Z", + "iopub.status.idle": "2026-04-04T05:08:50.291490Z", + "shell.execute_reply": "2026-04-04T05:08:50.291103Z" + }, + "papermill": { + "duration": 1.602879, + "end_time": "2026-04-04T05:08:50.291850", + "exception": false, + "start_time": "2026-04-04T05:08:48.688971", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# Generate mesh with planar conductors (presets: \"coarse\", \"default\", \"fine\")\n", + "sim_lumped.mesh(\n", + " preset=\"graded\",\n", + " refined_mesh_size=2.0,\n", + " max_mesh_size=40.0,\n", + " fmax=150e9,\n", + " margin_x=50.0,\n", + " margin_y=0,\n", + ")\n", + "\n", + "# Use graded refinement with much finer custom sizing for waveports\n", + "sim_waveport.mesh(\n", + " preset=\"graded\",\n", + " refined_mesh_size=2.0,\n", + " max_mesh_size=40.0,\n", + " fmax=150e9,\n", + " margin_x=0,\n", + " margin_y=50.0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dda6217b", + "metadata": {}, + "outputs": [], + "source": [ + "# Solid view — coloured surfaces per physical group, boundary transparent\n", + "sim_lumped.plot_mesh(\n", + " style=\"solid\",\n", + " transparent_groups=[\"air__None\", \"SiO2__None\", \"SiO2__passive\", \"air__passive\"],\n", + " interactive=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:08:50.293928Z", + "iopub.status.busy": "2026-04-04T05:08:50.293860Z", + "iopub.status.idle": "2026-04-04T05:08:51.192364Z", + "shell.execute_reply": "2026-04-04T05:08:51.192023Z" + }, + "papermill": { + "duration": 0.900347, + "end_time": "2026-04-04T05:08:51.193094", + "exception": false, + "start_time": "2026-04-04T05:08:50.292747", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# Solid view — coloured surfaces per physical group, boundary transparent\n", + "sim_waveport.plot_mesh(\n", + " style=\"solid\",\n", + " transparent_groups=[\"air__None\", \"SiO2__passive\", \"air__passive\"],\n", + " interactive=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": { + "papermill": { + "duration": 0.00199, + "end_time": "2026-04-04T05:08:51.198503", + "exception": false, + "start_time": "2026-04-04T05:08:51.196513", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "### Run simulation on cloud" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:08:51.202941Z", + "iopub.status.busy": "2026-04-04T05:08:51.202838Z", + "iopub.status.idle": "2026-04-04T05:17:13.575280Z", + "shell.execute_reply": "2026-04-04T05:17:13.574753Z" + }, + "papermill": { + "duration": 502.375746, + "end_time": "2026-04-04T05:17:13.575895", + "exception": false, + "start_time": "2026-04-04T05:08:51.200149", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "sim_lumped.write_config()\n", + "results_lumped = sim_lumped.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-04T05:17:13.579923Z", + "iopub.status.busy": "2026-04-04T05:17:13.579830Z", + "iopub.status.idle": "2026-04-04T05:17:13.735717Z", + "shell.execute_reply": "2026-04-04T05:17:13.735352Z" + }, + "papermill": { + "duration": 0.158415, + "end_time": "2026-04-04T05:17:13.736142", + "exception": false, + "start_time": "2026-04-04T05:17:13.577727", + "status": "completed" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "sim_waveport.write_config()\n", + "results_waveport = sim_waveport.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97231d61", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from gsim.palace import load_sparams\n", + "\n", + "sp_lumped = load_sparams(results_lumped.files)\n", + "sp_waveport = load_sparams(results_waveport.files)\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(5, 5))\n", + "\n", + "ax1.plot(sp_lumped.freq, sp_lumped.s21.db, label=\"S21 (lumped)\")\n", + "ax1.plot(sp_waveport.freq, sp_waveport.s21.db, \"--\", label=\"S21 (waveport)\")\n", + "\n", + "ax2.plot(sp_lumped.freq, sp_lumped.s21.deg, label=\"S21 (lumped)\")\n", + "ax2.plot(sp_waveport.freq, sp_waveport.s21.deg, \"--\", label=\"S21 (waveport)\")\n", + "\n", + "ax1.set_ylabel(\"Magnitude (dB)\")\n", + "ax1.set_title(\"S21 — Lumped vs Waveport\")\n", + "ax1.legend()\n", + "ax1.grid(True)\n", + "\n", + "ax2.set_xlabel(\"Frequency (GHz)\")\n", + "ax2.set_ylabel(\"Phase (deg)\")\n", + "ax2.legend()\n", + "ax2.grid(True)\n", + "\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3af1d107", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(5, 5))\n", + "\n", + "ax1.plot(sp_lumped.freq, sp_lumped.s11.db, label=\"S11 (lumped)\")\n", + "ax1.plot(sp_waveport.freq, sp_waveport.s11.db, \"--\", label=\"S11 (waveport)\")\n", + "\n", + "ax2.plot(sp_lumped.freq, sp_lumped.s11.deg, label=\"S11 (lumped)\")\n", + "ax2.plot(sp_waveport.freq, sp_waveport.s11.deg, \"--\", label=\"S11 (waveport)\")\n", + "\n", + "ax1.set_ylabel(\"Magnitude (dB)\")\n", + "ax1.set_title(\"S11 — Lumped vs Waveport\")\n", + "ax1.legend()\n", + "ax1.grid(True)\n", + "\n", + "ax2.set_xlabel(\"Frequency (GHz)\")\n", + "ax2.set_ylabel(\"Phase (deg)\")\n", + "ax2.legend()\n", + "ax2.grid(True)\n", + "\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c086f613", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "gsim", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.10" + }, + "papermill": { + "default_parameters": {}, + "duration": 510.589712, + "end_time": "2026-04-04T05:17:16.368920", + "environment_variables": {}, + "exception": null, + "input_path": "nbs/palace_cpw.ipynb", + "output_path": "nbs/palace_cpw.ipynb", + "parameters": {}, + "start_time": "2026-04-04T05:08:45.779208", + "version": "2.6.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/nbs/palace_cpw.ipynb b/nbs/palace_cpw.ipynb deleted file mode 100644 index 40aa156..0000000 --- a/nbs/palace_cpw.ipynb +++ /dev/null @@ -1,564 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "0", - "metadata": { - "papermill": { - "duration": 0.00345, - "end_time": "2026-04-04T05:08:46.583945", - "exception": false, - "start_time": "2026-04-04T05:08:46.580495", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "# Running Palace Simulations\n", - "\n", - "[Palace](https://awslabs.github.io/palace/) is an open-source 3D electromagnetic simulator supporting eigenmode, driven (S-parameter), and electrostatic simulations. This notebook demonstrates using the `gsim.palace` API to run a driven simulation on a CPW (coplanar waveguide) structure.\n", - "\n", - "**Requirements:**\n", - "\n", - "- IHP PDK: `uv pip install ihp-gdsfactory`\n", - "- [GDSFactory+](https://gdsfactory.com) account for cloud simulation" - ] - }, - { - "cell_type": "markdown", - "id": "1", - "metadata": { - "papermill": { - "duration": 0.001823, - "end_time": "2026-04-04T05:08:46.589529", - "exception": false, - "start_time": "2026-04-04T05:08:46.587706", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Load a pcell from IHP PDK" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "2", - "metadata": { - "execution": { - "iopub.execute_input": "2026-04-04T05:08:46.594146Z", - "iopub.status.busy": "2026-04-04T05:08:46.593957Z", - "iopub.status.idle": "2026-04-04T05:08:48.217508Z", - "shell.execute_reply": "2026-04-04T05:08:48.217147Z" - }, - "papermill": { - "duration": 1.626697, - "end_time": "2026-04-04T05:08:48.218023", - "exception": false, - "start_time": "2026-04-04T05:08:46.591326", - "status": "completed" - }, - "tags": [] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAzAAAAJoCAYAAAC5ogQ1AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAMTgAADE4Bf3eMIwAAJqpJREFUeJzt3d1uG1uWZtEvG/ngfHP3RbWRbpWUFHXs0J7hMQCizpIdyVn6AbjA2Na/fvz48WMAAAAB/+e7AwAAAD7LAgMAAGRYYAAAgAwLDAAAkGGBAQAAMiwwAABAhgUGAADI+Pezv/Cvf/3rig4AAIA9+zWV3oEBAAAyjltgHo/Hdyd8WbW92r1126vdW7e92r1123Vfr9pe7d667dXurdte7d7Oa//Xjyfv0biFDAAAuIpbyAAAgNuwwAAAABnHLTCn3WP3imp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4MDAAAcAxnYAAAgNuwwAAAABkWGAAAIOO4Bea0Q0KvqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57Q7xAwAAx3CIHwAAuA0LDAAAkGGBAQAAMo5bYE47JPSKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGU8XmPfuefvMx1x3ZtPV153YVLnuxKbKdSc2XX3diU2V605suvq6E5sq153YVLnuxKarrzux6Tuue8YZGAAA4BjOwAAAALdhgQEAADIsMAAAQMZxC8xXDvKcotpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTvEDwAAHMMhfgAA4DYsMAAAQIYFBgAAyDhugTntkNArqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93Zeu0P8AADAMRziBwAAbsMCAwAAZBy3wJx2j90rqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93ZeuzMwAADAMZyBAQAAbsMCAwAAZFhgAACAjOMWmNMOCb2i2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1O8QPAAAcwyF+AADgNiwwAABAxnELzGn32L2i2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1OwMDAAAcwxkYAADgNiwwAABAhgUGAADIOG6BOe2Q0Cuq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67Q/wAAMAxHOIHAABuwwIDAABkWGAAAICM4xaY0w4JvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7xA8AABzDIX4AAOA2LDAAAEDGcQvMaffYvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7AwMAABzDGRgAAOA2LDAAAECGBQYAAMg4boE57ZDQK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrtD/AAAwDEc4gcAAG7DAgMAAGRYYAAAgIynC8x7h3Y+8zHXndl09XUnNlWuO7Gpct2JTVdfd2JT5boTm66+7sSmynUnNlWuO7Hp6utObPqO655xiB8AADiGQ/wAAMBtWGAAAICM4xaYr9wHd4pqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuDAwAAHAMZ2AAAIDbsMAAAAAZFhgAACDjuAXmtENCr6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee0O8QMAAMdwiB8AALgNCwwAAJBhgQEAADKOW2BOOyT0imp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4QPwAAcAyH+AEAgNuwwAAAABnHLTCn3WP3imp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4MDAAAcAxnYAAAgNuwwAAAABkWGAAAIOO4Bea0Q0KvqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57Q7xAwAAx3CIHwAAuA0LDAAAkGGBAQAAMo5bYE47JPSKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGcctMKfdY/eKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7gwMAABwDGdgAACA27DAAAAAGRYYAAAg47gF5rRDQq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntDvEDAADHcIgfAAC4DQsMAACQYYEBAAAyjltgTjsk9Ipqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuED8AAHAMh/gBAIDbsMAAAAAZTxeY9+55+8zHXHdm09XXndhUue7Epsp1JzZdfd2JTZXrTmy6+roTmyrXndhUue7EpquvO7HpO657xhkYAADgGM7AAAAAt2GBAQAAMiwwAABAxnELzFcO8pyi2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1O8QPAAAcwyF+AADgNiwwAABAxnELzGn32L2i2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1OwMDAAAcwxkYAADgNiwwAABAhgUGAADIOG6BOe2Q0Cuq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67Q/wAAMAxHOIHAABuwwIDAABkWGAAAICM4xaY0w4JvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7xA8AABzDIX4AAOA2LDAAAEDGcQvMaffYvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7AwMAABzDGRgAAOA2LDAAAECGBQYAAMg4boE57ZDQK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrtD/AAAwDEc4gcAAG7DAgMAAGRYYAAAgIzjFpjTDgm9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTvEDwAAHMMhfgAA4DYsMAAAQMZxC8xp99i9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTsDAwAAHMMZGAAA4DYsMAAAQIYFBgAAyDhugTntkNArqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93Zeu0P8AADAMRziBwAAbsMCAwAAZFhgAACAjKcLzHuHdj7zMded2XT1dSc2Va47saly3YlNV193YlPluhObrr7uxKbKdSc2Va47senq605s+o7rnnGIHwAAOIZD/AAAwG1YYAAAgIzjFpiv3Ad3imp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4MDAAAcAxnYAAAgNuwwAAAABkWGAAAIOO4Bea0Q0KvqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57Q7xAwAAx3CIHwAAuA0LDAAAkGGBAQAAMo5bYE47JPSKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGcctMKfdY/eKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7gwMAABwDGdgAACA27DAAAAAGRYYAAAg47gF5rRDQq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntDvEDAADHcIgfAAC4DQsMAACQYYEBAAAyjltgTjsk9Ipqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuED8AAHAMh/gBAIDbsMAAAAAZxy0wp91j94pqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuDAwAAHAMZ2AAAIDbsMAAAAAZFhgAACDjuAXmtENCr6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee0O8QMAAMdwiB8AALgNCwwAAJBx3AJz2j12r6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee3OwAAAAMdwBgYAALgNCwwAAJBhgQEAADKeLjDvHdr5zMdcd2bT1ded2FS57sSmynUnNl193YlNletObLr6uhObKted2FS57sSmq687sek7rnvGIX4AAOAYDvEDAAC3YYEBAAAyLDAAAEDGcQvMVw7ynKLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7xA8AABzDIX4AAOA2LDAAAEDGcQvMaffYvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7AwMAABzDGRgAAOA2LDAAAECGBQYAAMg4boE57ZDQK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrtD/AAAwDEc4gcAAG7DAgMAAGRYYAAAgIzjFpjTDgm9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTvEDwAAHMMhfgAA4DYsMAAAQMZxC8xp99i9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTsDAwAAHMMZGAAA4DYsMAAAQIYFBgAAyDhugTntkNArqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93Zeu0P8AADAMRziBwAAbsMCAwAAZFhgAACAjH9/d8BbPx7fXQAAAPzqX4/v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371pfmV+7zeeFuav/obXE+b3foOs2ffLnX4+y7Ofz+tnP5/mv+Hns/r9Uv35PJF3YAAAgA9d/fo8+w7MT9+9aZrNZrPZbDabzX/zfBrvwAAAAB+6+vV59h2Y7940vzK7J/P6uXwPb3Wufr9Ufz7Ls5/P62c/n+a/4eez+v1S/fk80ZHvwAAAAOc46R2Y4xYYAADg75W9hQwAAOAtCwwAAJBx3ALz68Gsmmp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4MDAAAcAxnYAAAgNuwwAAAABkWGAAAIOO4Bea0Q0KvqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57Q7xAwAAx3CIHwAAuA0LDAAAkHHcAnPaPXavqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57c7AAAAAx3AGBgAAuA0LDAAAkGGBAQAAMo5bYE47JPSKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGRYYAAAg47gF5rRDQq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntDvEDAADHcIgfAAC4DQsMAACQcdwCc9o9dq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntzsAAAADHcAYGAAC4DQsMAACQYYEBAAAyni4w7x3a+czHXHdm09XXndhUue7Epsp1JzZdfd2JTZXrTmy6+roTmyrXndhUue7EpquvO7HpO657xiF+AADgGA7xAwAAt2GBAQAAMiwwAABAxnELzFcO8pyi2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1O8QPAAAcwyF+AADgNiwwAABAxnELzGn32L2i2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1OwMDAAAcwxkYAADgNiwwAABAhgUGAADIOG6BOe2Q0Cuq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67Q/wAAMAxHOIHAABuwwIDAABkHLfAnHaP3Suq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67MzAAAMAxnIEBAABuwwIDAABkWGAAAICM4xaY0w4JvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7xA8AABzDIX4AAOA2LDAAAECGBQYAAMg4boE57ZDQK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrtD/AAAwDEc4gcAAG7DAgMAAGQct8Ccdo/dK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrszMAAAwDGcgQEAAG7DAgMAAGRYYAAAgIzjFpjTDgm9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTvEDwAAHMMhfgAA4DYsMAAAQIYFBgAAyDhugTntkNArqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93Zeu0P8AADAMRziBwAAbsMCAwAAZDxdYN675+0zH3PdmU1XX3diU+W6E5sq153YdPV1JzZVrjux6errTmyqXHdiU+W6E5uuvu7Epu+47hlnYAAAgGM4AwMAANyGBQYAAMiwwAAAABnHLTBfOchzimp7tXvrtle7t257tXvrtuu+XrW92r1126vdW7e92r2d1+4QPwAAcAyH+AEAgNuwwAAAABkWGAAAIOO4Bea0Q0KvqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57Q7xAwAAx3CIHwAAuA0LDAAAkHHcAnPaPXavqLZXu7due7V767ZXu7duu+7rVdur3Vu3vdq9ddur3dt57c7AAAAAx3AGBgAAuA0LDAAAkGGBAQAAMo5bYE47JPSKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGRYYAAAg47gF5rRDQq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntDvEDAADHcIgfAAC4DQsMAACQcdwCc9o9dq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntzsAAAADHcAYGAAC4DQsMAACQYYEBAAAyjltgTjsk9Ipqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuED8AAHAMh/gBAIDbsMAAAAAZFhgAACDjuAXmtENCr6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee0O8QMAAMdwiB8AALgNCwwAAJBx3AJz2j12r6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee3OwAAAAMdwBgYAALgNCwwAAJBhgQEAADKeLjDvHdr5zMdcd2bT1ded2FS57sSmynUnNl193YlNletObLr6uhObKted2FS57sSmq687sek7rnvGIX4AAOAYDvEDAAC3YYEBAAAyjltgvnIf3Cmq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67MzAAAMAxnIEBAABuwwIDAABkWGAAAICM4xaY0w4JvaLaXu3euu3V7q3bXu3euu26r1dtr3Zv3fZq99Ztr3Zv57U7xA8AABzDIX4AAOA2LDAAAECGBQYAAMg4boE57ZDQK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrtD/AAAwDEc4gcAAG7DAgMAAGQct8Ccdo/dK6rt1e6t217t3rrt1e6t2677etX2avfWba92b932avd2XrszMAAAwDGcgQEAAG7DAgMAAGRYYAAAgIzjFpjTDgm9otpe7d667dXurdte7d667bqvV22vdm/d9mr31m2vdm/ntTvEDwAAHMMhfgAA4DYsMAAAQIYFBgAAyDhugTntkNArqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93Zeu0P8AADAMRziBwAAbsMCAwAAZBy3wJx2j90rqu3V7q3bXu3euu3V7q3brvt61fZq99Ztr3Zv3fZq93ZeuzMwAADAMZyBAQAAbsMCAwAAZFhgAACAjOMWmNMOCb2i2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1O8QPAAAcwyF+AADgNiwwAABAhgUGAADIOG6BOe2Q0Cuq7dXurdte7d667dXurduu+3rV9mr31m2vdm/d9mr3dl67Q/wAAMAxHOIHAABuwwIDAABkPF1g3rvn7TMfc92ZTVdfd2JT5boTmyrXndh09XUnNlWuO7Hp6utObKpcd2JT5boTm66+7sSm77juGWdgAACAYzgDAwAA3IYFBgAAyLDAAAAAGcctMF85yHOKanu1e+u2V7u3bnu1e+u2675etb3avXXbq91bt73avZ3X7hA/AABwDIf4AQCA27DAAAAAGRYYAAAg47gF5rRDQq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntDvEDAADHcIgfAAC4DQsMAACQcdwCc9o9dq+otle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntzsAAAADHcAYGAAC4DQsMAACQYYEBAAAyjltgTjsk9Ipqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuED8AAHAMh/gBAIDbsMAAAAAZFhgAACDjuAXmtENCr6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee0O8QMAAMdwiB8AALgNCwwAAJBx3AJz2j12r6i2V7u3bnu1e+u2V7u3brvu61Xbq91bt73avXXbq93bee3OwAAAAMdwBgYAALgNC8wX/Le30R6Pxz/6cwAA4GP//u6AkmeLx6/LyXuLyrM/BwAAnvjxxLZLH4/H4/Ln/B2Nj8fjf3381/mja/7pc759/p8fe6+n/Dm/W3u1u9xe7S6369Z+9+5ye7W73F7t/o72p/vJaQtM4fHZZeTqBeazz+vh4eHh4eHh4eFx6uMZZ2B+s8/cZgYAAHyNBeY3s8AAAMCfc9wCU36BX22vdm/d9mr31m2vdm/ddt3Xq7ZXu7due7V767ZXu7cD252Bef3x0bmSV868vHo25b1/IMAZGA8PDw8PDw8Pj7s9nvHPKL/g1+3z138O+dePvffxz/75q89/3DYMAAB/2L/+37ssH/+Ff/3rqhb+CwsLAAB/gyfryXlnYAAAAD5y3AJTfpeh2l7t3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1u4UMAAA4hlvIAACA27DAAAAAGZf/M8qn3UP3t/B5BwDgDp6+A/PR7zN59rHPXlfy858y/vV3ufy3j33m71xx3Xv/f/y3+bMf+53fB65rNFWuO7Hp6utObKpcd2LT1ded2FS57sSmynUnNl193YlN33HdM5cf4v9K5Cmq7Y/HI9sOAMDfxSF+AADgNiwwAABAhgXmN6replXt3rrt1e6t217t3rrtuq9Xba92b932avfWba92b+e1OwPzl/B5BwCg4NkZmMsXGAAAgI84xA8AANyGBQYAAMg4boEpn9Wotle7t257tXvrtle7t2677utV26vdW7e92r1126vd23ntzsAAAADHcAYGAAC4DQsMAACQYYEBAAAyjltgTjsk9Ipqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuED8AAHAMh/gBAIDbsMAAAAAZxy0wp91j94pqe7V767ZXu7due7V767brvl61vdq9ddur3Vu3vdq9ndfuDAwAAHAMZ2AAAIDbsMAAAAAZ/372F569hQMAAHAV78AAAAAZFhgAACDDAgMAAGRYYAAAgAwLDAAAkGGBAQAAMiwwAABAxv8FcWORNT8o6nkAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import gdsfactory as gf\n", - "from ihp import LAYER, PDK\n", - "\n", - "PDK.activate()\n", - "\n", - "\n", - "@gf.cell\n", - "def gsg_electrode(\n", - " length: float = 800,\n", - " s_width: float = 20,\n", - " g_width: float = 40,\n", - " gap_width: float = 15,\n", - " layer=LAYER.TopMetal2drawing,\n", - ") -> gf.Component:\n", - " \"\"\"\n", - " Create a GSG (Ground-Signal-Ground) electrode.\n", - "\n", - " Args:\n", - " length: horizontal length of the electrodes\n", - " s_width: width of the signal (center) electrode\n", - " g_width: width of the ground electrodes\n", - " gap_width: gap between signal and ground electrodes\n", - " layer: layer for the metal\n", - " \"\"\"\n", - " c = gf.Component()\n", - "\n", - " # Top ground electrode\n", - " r1 = c << gf.c.rectangle((length, g_width), centered=True, layer=layer)\n", - " r1.move((0, (g_width + s_width) / 2 + gap_width))\n", - "\n", - " # Center signal electrode\n", - " _r2 = c << gf.c.rectangle((length, s_width), centered=True, layer=layer)\n", - "\n", - " # Bottom ground electrode\n", - " r3 = c << gf.c.rectangle((length, g_width), centered=True, layer=layer)\n", - " r3.move((0, -(g_width + s_width) / 2 - gap_width))\n", - "\n", - " # Add ports at the signal center (one per side)\n", - " # The CPW port API computes the gap element surfaces from s_width and gap_width\n", - " c.add_port(\n", - " name=\"o1\",\n", - " center=(-length / 2, 0),\n", - " width=s_width,\n", - " orientation=180,\n", - " port_type=\"electrical\",\n", - " layer=layer,\n", - " )\n", - "\n", - " c.add_port(\n", - " name=\"o2\",\n", - " center=(length / 2, 0),\n", - " width=s_width,\n", - " orientation=0,\n", - " port_type=\"electrical\",\n", - " layer=layer,\n", - " )\n", - "\n", - " return c\n", - "\n", - "\n", - "c = gsg_electrode()\n", - "cc = c.copy()\n", - "cc.draw_ports()\n", - "cc" - ] - }, - { - "cell_type": "markdown", - "id": "3", - "metadata": { - "papermill": { - "duration": 0.000656, - "end_time": "2026-04-04T05:08:48.219611", - "exception": false, - "start_time": "2026-04-04T05:08:48.218955", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Configure and run simulation with DrivenSim" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "4", - "metadata": { - "execution": { - "iopub.execute_input": "2026-04-04T05:08:48.221390Z", - "iopub.status.busy": "2026-04-04T05:08:48.221229Z", - "iopub.status.idle": "2026-04-04T05:08:48.687534Z", - "shell.execute_reply": "2026-04-04T05:08:48.687184Z" - }, - "papermill": { - "duration": 0.467892, - "end_time": "2026-04-04T05:08:48.688108", - "exception": false, - "start_time": "2026-04-04T05:08:48.220216", - "status": "completed" - }, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Validation: PASSED\n" - ] - } - ], - "source": [ - "from gsim.palace import DrivenSim\n", - "\n", - "# Create simulation object\n", - "sim_lumped = DrivenSim()\n", - "\n", - "# Set output directory\n", - "sim_lumped.set_output_dir(\"./palace-sim-cpw\")\n", - "\n", - "# Set the component geometry\n", - "sim_lumped.set_geometry(c)\n", - "\n", - "# Configure layer stack from active PDK\n", - "sim_lumped.set_stack(substrate_thickness=2.0, air_above=100.0, air_below=100.0)\n", - "\n", - "# Configure left CPW port (single port at signal center)\n", - "sim_lumped.add_cpw_port(\n", - " \"o1\",\n", - " layer=\"topmetal2\",\n", - " s_width=20,\n", - " gap_width=15,\n", - " length=5.0,\n", - " offset=2.5,\n", - " excited=True,\n", - ")\n", - "\n", - "# Configure right CPW port (single port at signal center)\n", - "sim_lumped.add_cpw_port(\n", - " \"o2\",\n", - " layer=\"topmetal2\",\n", - " s_width=20,\n", - " gap_width=15,\n", - " length=5.0,\n", - " offset=2.5,\n", - " excited=False,\n", - ")\n", - "\n", - "# Configure driven simulation (frequency sweep for S-parameters)\n", - "sim_lumped.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n", - "\n", - "# Validate configuration\n", - "print(sim_lumped.validate_config())" - ] - }, - { - "cell_type": "markdown", - "id": "5df9d4ab", - "metadata": {}, - "source": [ - "### Configure simulation with DrivenSim for WavePorts" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "f107f324", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Validation: PASSED\n" - ] - } - ], - "source": [ - "# Create simulation object\n", - "sim_waveport = DrivenSim()\n", - "\n", - "# Set output directory\n", - "sim_waveport.set_output_dir(\"./palace-sim-cpw-waveport\")\n", - "\n", - "# Set the component geometry\n", - "sim_waveport.set_geometry(c)\n", - "\n", - "# Configure layer stack from active PDK\n", - "sim_waveport.set_stack(substrate_thickness=2.0, air_above=100.0, air_below=100.0)\n", - "\n", - "# Configure left CPW port (single port at signal center)\n", - "sim_waveport.add_wave_port(\"o1\", layer=\"topmetal2\", max_size=True, mode=1, excited=True)\n", - "\n", - "# Configure right CPW port (single port at signal center)\n", - "sim_waveport.add_wave_port(\n", - " \"o2\", layer=\"topmetal2\", max_size=True, mode=1, excited=False\n", - ")\n", - "\n", - "# Configure driven simulation (frequency sweep for S-parameters)\n", - "sim_waveport.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n", - "\n", - "# Validate configuration\n", - "print(sim_waveport.validate_config())" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "5", - "metadata": { - "execution": { - "iopub.execute_input": "2026-04-04T05:08:48.690170Z", - "iopub.status.busy": "2026-04-04T05:08:48.690094Z", - "iopub.status.idle": "2026-04-04T05:08:50.291490Z", - "shell.execute_reply": "2026-04-04T05:08:50.291103Z" - }, - "papermill": { - "duration": 1.602879, - "end_time": "2026-04-04T05:08:50.291850", - "exception": false, - "start_time": "2026-04-04T05:08:48.688971", - "status": "completed" - }, - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Mesh Summary\n", - "========================================\n", - "Dimensions: 800.0 x 230.0 x 218.3 µm\n", - "Nodes: 26,231\n", - "Elements: 197,834\n", - "Tetrahedra: 147,868\n", - "Edge length: 0.40 - 81.61 µm\n", - "Quality: 0.555 (min: 0.001)\n", - "SICN: 0.607 (all valid)\n", - "----------------------------------------\n", - "Volumes (3):\n", - " - SiO2 [1]\n", - " - passive [2]\n", - " - air [3]\n", - "Surfaces (10):\n", - " - topmetal2_xy [4]\n", - " - topmetal2_z [5]\n", - " - P1 [6]\n", - " - P2 [7]\n", - " - SiO2__None [8]\n", - " - SiO2__passive [9]\n", - " - SiO2__air [10]\n", - " - passive__None [11]\n", - " - air__passive [12]\n", - " - air__None [13]\n", - "----------------------------------------\n", - "Mesh: palace-sim-cpw-waveport/palace.msh" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Generate mesh with planar conductors (presets: \"coarse\", \"default\", \"fine\")\n", - "sim_lumped.mesh(\n", - " preset=\"graded\",\n", - " refined_mesh_size=2.0,\n", - " max_mesh_size=40.0,\n", - " fmax=150e9,\n", - " margin_x=50.0,\n", - " margin_y=0,\n", - ")\n", - "\n", - "# Use graded refinement with much finer custom sizing for waveports\n", - "sim_waveport.mesh(\n", - " preset=\"graded\",\n", - " refined_mesh_size=2.0,\n", - " max_mesh_size=40.0,\n", - " fmax=150e9,\n", - " margin_x=0,\n", - " margin_y=50.0,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "6", - "metadata": { - "execution": { - "iopub.execute_input": "2026-04-04T05:08:50.293928Z", - "iopub.status.busy": "2026-04-04T05:08:50.293860Z", - "iopub.status.idle": "2026-04-04T05:08:51.192364Z", - "shell.execute_reply": "2026-04-04T05:08:51.192023Z" - }, - "papermill": { - "duration": 0.900347, - "end_time": "2026-04-04T05:08:51.193094", - "exception": false, - "start_time": "2026-04-04T05:08:50.292747", - "status": "completed" - }, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6b677a8f13104dbf8f99acb866325c6c", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Widget(value='