From 07a17629b4e4554a4a0f80b63dd975df3126a721 Mon Sep 17 00:00:00 2001 From: mdmaas Date: Tue, 9 Jun 2026 18:44:27 -0300 Subject: [PATCH] Add notebook for IHP RF components meshing --- nbs/_palace_ihp_rf_devices_mesh.ipynb | 881 ++++++++++++++++++++++++++ nbs/_palace_ihp_rf_devices_mesh.py | 187 ++++++ 2 files changed, 1068 insertions(+) create mode 100644 nbs/_palace_ihp_rf_devices_mesh.ipynb create mode 100644 nbs/_palace_ihp_rf_devices_mesh.py diff --git a/nbs/_palace_ihp_rf_devices_mesh.ipynb b/nbs/_palace_ihp_rf_devices_mesh.ipynb new file mode 100644 index 0000000..2e037b6 --- /dev/null +++ b/nbs/_palace_ihp_rf_devices_mesh.ipynb @@ -0,0 +1,881 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "49ac428f", + "metadata": {}, + "source": [ + "# Palace Mesh Generation: IHP RF Devices\n", + "\n", + "This notebook discovers RF components from `ihp.cells.rf_devices`, prints their ports, and generates Palace meshes for each component.\n", + "\n", + "**Requirements:**\n", + "- IHP PDK from GitHub (`pip install git+https://github.com/gdsfactory/IHP.git`)\n", + "- gsim environment with Palace meshing dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e270eea1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:2026-06-09 18:31:05,866:jax._src.xla_bridge:852: An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + } + ], + "source": [ + "from __future__ import annotations\n", + "\n", + "from pathlib import Path\n", + "\n", + "import ihp.cells.rf_devices as rf_devices\n", + "import pandas as pd\n", + "from ihp import PDK\n", + "\n", + "from gsim.common.stack import get_stack\n", + "from gsim.palace import DrivenSim\n", + "\n", + "PDK.activate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f79956b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Discovered RF components:\n", + "- branch_line_coupler\n", + "- coupled_line_bandpass_filter\n", + "- coupler_tline\n", + "- directional_coupler\n", + "- hairpin_coupled_line_bandpass_filter\n", + "- quarter_wave_transformer\n", + "- wilkinson_power_divider\n" + ] + } + ], + "source": [ + "# Discover RF component factories defined in ihp.cells.rf_devices and registered in the active PDK.\n", + "rf_module_factories = {\n", + " name\n", + " for name, obj in vars(rf_devices).items()\n", + " if callable(obj) and not name.startswith(\"_\")\n", + "}\n", + "\n", + "rf_keywords = (\n", + " \"wilkinson\",\n", + " \"filter\",\n", + " \"coupler\",\n", + " \"divider\",\n", + " \"directional\",\n", + " \"hybrid\",\n", + " \"branch\",\n", + " \"transformer\",\n", + ")\n", + "\n", + "component_names = sorted(\n", + " name\n", + " for name in PDK.cells\n", + " if name in rf_module_factories and any(k in name.lower() for k in rf_keywords)\n", + ")\n", + "\n", + "print(\"Discovered RF components:\")\n", + "for name in component_names:\n", + " print(f\"- {name}\")\n", + "\n", + "if not component_names:\n", + " raise RuntimeError(\n", + " \"No RF device components were discovered in ihp.cells.rf_devices\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d585d09", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
componentportorientation_degwidth_umcenter_umlayer
0branch_line_couplere1180.01.68(-100.0, 0.84)TopMetal2drawing
1branch_line_couplere20.01.68(3838.657, 0.84)TopMetal2drawing
2branch_line_couplere30.01.68(3838.657, -3733.505)TopMetal2drawing
3branch_line_couplere4180.01.68(-100.0, -3733.505)TopMetal2drawing
4coupled_line_bandpass_filtere1180.01.68(0.0, 0.0)TopMetal2drawing
5coupled_line_bandpass_filtere20.01.68(15037.564, 25.204)TopMetal2drawing
6coupler_tlinee1180.01.68(0.0, 13.442)TopMetal2drawing
7coupler_tlinee20.01.68(10.0, 13.442)TopMetal2drawing
8coupler_tlinee30.01.68(10.0, -13.442)TopMetal2drawing
9coupler_tlinee4180.01.68(0.0, -13.442)TopMetal2drawing
10directional_couplere1180.01.68(-100.0, 1.108)TopMetal2drawing
11directional_couplere20.01.68(3834.391, 1.108)TopMetal2drawing
12directional_couplere3270.01.68(3735.231, -101.94800000000001)TopMetal2drawing
13directional_couplere4270.01.68(-0.84, -101.94800000000001)TopMetal2drawing
14hairpin_coupled_line_bandpass_filtere1180.01.68(0.0, 0.0)TopMetal2drawing
15hairpin_coupled_line_bandpass_filtere20.01.68(148.196, 0.0)TopMetal2drawing
16quarter_wave_transformere1180.01.68(-100.0, 0.0)TopMetal2drawing
17quarter_wave_transformere20.00.20(846.878, 0.0)TopMetal2drawing
18wilkinson_power_dividere1180.01.68(0.0, 0.0)TopMetal2drawing
19wilkinson_power_dividere20.01.68(731.163, 17.506)TopMetal2drawing
20wilkinson_power_dividere30.01.68(731.163, -17.506)TopMetal2drawing
\n", + "
" + ], + "text/plain": [ + " component port orientation_deg width_um \\\n", + "0 branch_line_coupler e1 180.0 1.68 \n", + "1 branch_line_coupler e2 0.0 1.68 \n", + "2 branch_line_coupler e3 0.0 1.68 \n", + "3 branch_line_coupler e4 180.0 1.68 \n", + "4 coupled_line_bandpass_filter e1 180.0 1.68 \n", + "5 coupled_line_bandpass_filter e2 0.0 1.68 \n", + "6 coupler_tline e1 180.0 1.68 \n", + "7 coupler_tline e2 0.0 1.68 \n", + "8 coupler_tline e3 0.0 1.68 \n", + "9 coupler_tline e4 180.0 1.68 \n", + "10 directional_coupler e1 180.0 1.68 \n", + "11 directional_coupler e2 0.0 1.68 \n", + "12 directional_coupler e3 270.0 1.68 \n", + "13 directional_coupler e4 270.0 1.68 \n", + "14 hairpin_coupled_line_bandpass_filter e1 180.0 1.68 \n", + "15 hairpin_coupled_line_bandpass_filter e2 0.0 1.68 \n", + "16 quarter_wave_transformer e1 180.0 1.68 \n", + "17 quarter_wave_transformer e2 0.0 0.20 \n", + "18 wilkinson_power_divider e1 180.0 1.68 \n", + "19 wilkinson_power_divider e2 0.0 1.68 \n", + "20 wilkinson_power_divider e3 0.0 1.68 \n", + "\n", + " center_um layer \n", + "0 (-100.0, 0.84) TopMetal2drawing \n", + "1 (3838.657, 0.84) TopMetal2drawing \n", + "2 (3838.657, -3733.505) TopMetal2drawing \n", + "3 (-100.0, -3733.505) TopMetal2drawing \n", + "4 (0.0, 0.0) TopMetal2drawing \n", + "5 (15037.564, 25.204) TopMetal2drawing \n", + "6 (0.0, 13.442) TopMetal2drawing \n", + "7 (10.0, 13.442) TopMetal2drawing \n", + "8 (10.0, -13.442) TopMetal2drawing \n", + "9 (0.0, -13.442) TopMetal2drawing \n", + "10 (-100.0, 1.108) TopMetal2drawing \n", + "11 (3834.391, 1.108) TopMetal2drawing \n", + "12 (3735.231, -101.94800000000001) TopMetal2drawing \n", + "13 (-0.84, -101.94800000000001) TopMetal2drawing \n", + "14 (0.0, 0.0) TopMetal2drawing \n", + "15 (148.196, 0.0) TopMetal2drawing \n", + "16 (-100.0, 0.0) TopMetal2drawing \n", + "17 (846.878, 0.0) TopMetal2drawing \n", + "18 (0.0, 0.0) TopMetal2drawing \n", + "19 (731.163, 17.506) TopMetal2drawing \n", + "20 (731.163, -17.506) TopMetal2drawing " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Build each component and tabulate ports.\n", + "port_rows = []\n", + "components = {}\n", + "\n", + "for name in component_names:\n", + " c = PDK.cells[name]()\n", + " components[name] = c\n", + " port_rows.extend(\n", + " {\n", + " \"component\": name,\n", + " \"port\": p.name,\n", + " \"orientation_deg\": p.orientation,\n", + " \"width_um\": p.width,\n", + " \"center_um\": tuple(float(x) for x in p.center),\n", + " \"layer\": str(p.layer),\n", + " }\n", + " for p in c.ports\n", + " )\n", + "\n", + "ports_df = (\n", + " pd.DataFrame(port_rows).sort_values([\"component\", \"port\"]).reset_index(drop=True)\n", + ")\n", + "ports_df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5ac0ae94", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Small conductor feature detected (1.680 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (1.634 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (1.680 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (0.536 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (1.078 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (0.200 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n", + "Small conductor feature detected (0.200 um) may be under-resolved by refined_mesh_size=5.000 um. Pass auto_size=True to scale the mesh down.\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
componentstatusmesh_path
0branch_line_couplerokpalace-sim-ihp-rf/branch_line_coupler/palace.msh
1coupled_line_bandpass_filterokpalace-sim-ihp-rf/coupled_line_bandpass_filter...
2coupler_tlineokpalace-sim-ihp-rf/coupler_tline/palace.msh
3directional_couplerokpalace-sim-ihp-rf/directional_coupler/palace.msh
4hairpin_coupled_line_bandpass_filterokpalace-sim-ihp-rf/hairpin_coupled_line_bandpas...
5quarter_wave_transformerokpalace-sim-ihp-rf/quarter_wave_transformer/pal...
6wilkinson_power_dividerokpalace-sim-ihp-rf/wilkinson_power_divider/pala...
\n", + "
" + ], + "text/plain": [ + " component status \\\n", + "0 branch_line_coupler ok \n", + "1 coupled_line_bandpass_filter ok \n", + "2 coupler_tline ok \n", + "3 directional_coupler ok \n", + "4 hairpin_coupled_line_bandpass_filter ok \n", + "5 quarter_wave_transformer ok \n", + "6 wilkinson_power_divider ok \n", + "\n", + " mesh_path \n", + "0 palace-sim-ihp-rf/branch_line_coupler/palace.msh \n", + "1 palace-sim-ihp-rf/coupled_line_bandpass_filter... \n", + "2 palace-sim-ihp-rf/coupler_tline/palace.msh \n", + "3 palace-sim-ihp-rf/directional_coupler/palace.msh \n", + "4 palace-sim-ihp-rf/hairpin_coupled_line_bandpas... \n", + "5 palace-sim-ihp-rf/quarter_wave_transformer/pal... \n", + "6 palace-sim-ihp-rf/wilkinson_power_divider/pala... " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Generate a mesh per component under ./palace-sim-ihp-rf/.\n", + "stack = get_stack()\n", + "base_dir = Path(\"./palace-sim-ihp-rf\")\n", + "base_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + "mesh_rows = []\n", + "\n", + "for name, c in components.items():\n", + " out_dir = base_dir / name\n", + " out_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " try:\n", + " sim = DrivenSim()\n", + " sim.set_output_dir(out_dir)\n", + " sim.set_geometry(c)\n", + " sim.set_stack(stack)\n", + "\n", + " # Add all component ports as via ports so port geometries are meshed.\n", + " for port in c.ports:\n", + " sim.add_port(\n", + " port.name,\n", + " from_layer=\"metal3\",\n", + " to_layer=\"topmetal2\",\n", + " geometry=\"via\",\n", + " )\n", + "\n", + " sim.set_driven(fmin=1e9, fmax=110e9, num_points=21)\n", + " result = sim.mesh(preset=\"default\")\n", + "\n", + " mesh_rows.append(\n", + " {\n", + " \"component\": name,\n", + " \"status\": \"ok\",\n", + " \"mesh_path\": str(result.mesh_path),\n", + " }\n", + " )\n", + " except Exception as e:\n", + " mesh_rows.append(\n", + " {\n", + " \"component\": name,\n", + " \"status\": \"error\",\n", + " \"mesh_path\": \"\",\n", + " \"error\": str(e),\n", + " }\n", + " )\n", + "\n", + "mesh_df = (\n", + " pd.DataFrame(mesh_rows).sort_values([\"status\", \"component\"]).reset_index(drop=True)\n", + ")\n", + "mesh_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b6f6027", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "### branch_line_coupler" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "71f860ee590848b8a628c671f1e69a39", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Widget(value='