docs: use explicit get_stack() from PDK in Palace notebooks#134
Conversation
Replace implicit set_stack(kwargs...) with explicit stack = get_stack(...) in all IHP Palace notebooks, making the PDK layer stack extraction visible and inspectable. Fixes #133
There was a problem hiding this comment.
Code Review
This pull request updates several Jupyter notebooks to utilize the get_stack utility for automated PDK layer stack configuration and clears cell outputs and execution counts. The review feedback consistently identifies a regression in the notebook file structure where the source field for code cells was converted from the standard array-of-strings format to a single string. This change is discouraged as it negatively impacts the maintainability of the raw JSON files and the readability of version control diffs.
| "# Validate configuration\n", | ||
| "print(sim_lumped.validate_config())" | ||
| ] | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\n# Create simulation object\nsim_lumped = DrivenSim()\n\n# Set output directory\nsim_lumped.set_output_dir(\"./palace-sim-cpw\")\n\n# Set the component geometry\nsim_lumped.set_geometry(c)\n\n# Configure layer stack from active PDK\nstack = get_stack(air_above=100.0, air_below=100.0) # auto-detects active PDK\nsim_lumped.set_stack(stack)\n\n# Configure left CPW port (single port at signal center)\nsim_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)\nsim_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)\nsim_lumped.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\n# Validate configuration\nprint(sim_lumped.validate_config())" |
There was a problem hiding this comment.
The source field in Jupyter notebooks is typically represented as an array of strings (one per line). Changing it to a single string with embedded newlines makes the raw JSON file significantly harder to maintain and results in less useful git diffs, as any change to the cell will be shown as a single massive line change. It is recommended to stick to the standard array-of-strings format.
| "print(sim.validate_config())" | ||
| ] | ||
| "outputs": [], | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\n# Create simulation object\nsim = DrivenSim()\n\n# Set output directory\nsim.set_output_dir(\"./palace-sim-branch-coupler\")\n\n# Set the component geometry\nsim.set_geometry(c)\n\n# Configure layer stack from active PDK\nstack = get_stack(air_above=300.0) # auto-detects active PDK\nsim.set_stack(stack)\n\n# Configure via ports (Metal3 ground plane to TopMetal2 signal)\nfor port in c.ports:\n sim.add_port(port.name, from_layer=\"metal3\", to_layer=\"topmetal2\", geometry=\"via\")\n\n# Configure driven simulation (frequency sweep for S-parameters)\nsim.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\n# Validate configuration\nprint(sim.validate_config())" |
| "print(sim.validate_config())" | ||
| ] | ||
| "outputs": [], | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\nsim = DrivenSim()\nsim.set_output_dir(\"./palace-sim-cpw-lumped\")\nsim.set_geometry(c)\n\nstack = get_stack(air_above=100.0, air_below=100.0) # auto-detects active PDK\nsim.set_stack(stack)\n\n# CPW lumped ports — offset defaults to length/2 (flush with conductor edge)\nsim.add_cpw_port(\"o1\", layer=\"topmetal2\", s_width=20, gap_width=15, excited=True)\nsim.add_cpw_port(\"o2\", layer=\"topmetal2\", s_width=20, gap_width=15, excited=False)\n\nsim.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\nprint(sim.validate_config())" |
| "print(sim.validate_config())" | ||
| ] | ||
| "outputs": [], | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\n# Create simulation object\nsim = DrivenSim()\n\n# Set output directory\nsim.set_output_dir(\"./palace-sim-cpw\")\n\n# Set the component geometry\nsim.set_geometry(c)\n\n# Configure layer stack from active PDK\nstack = get_stack(air_above=300.0) # auto-detects active PDK\nsim.set_stack(stack)\n\n# Configure left CPW port (single port at signal center)\nsim.add_cpw_port(\"o1\", layer=\"topmetal2\", s_width=20, gap_width=15)\n\n# Configure right CPW port (single port at signal center)\nsim.add_cpw_port(\"o2\", layer=\"topmetal2\", s_width=20, gap_width=15)\n\n# Configure driven simulation (frequency sweep for S-parameters)\nsim.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\n# Validate configuration\nprint(sim.validate_config())" |
| "print(sim.validate_config())" | ||
| ] | ||
| "outputs": [], | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\nsim = DrivenSim()\nsim.set_output_dir(\"./palace-sim-cpw-waveport\")\nsim.set_geometry(c)\n\nstack = get_stack(air_above=100.0, air_below=100.0) # auto-detects active PDK\nsim.set_stack(stack)\n\n# Wave ports — max_size fills the full domain boundary\nsim.add_wave_port(\"o1\", layer=\"topmetal2\", max_size=True, mode=1, excited=True)\nsim.add_wave_port(\"o2\", layer=\"topmetal2\", max_size=True, mode=1, excited=False)\n\nsim.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\nprint(sim.validate_config())" |
| "print(sim.validate_config())" | ||
| ] | ||
| "outputs": [], | ||
| "source": "from gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\n# Create simulation object\nsim = DrivenSim()\n\n# Set output directory\nsim.set_output_dir(\"./palace-sim-microstrip\")\n\n# Set the component geometry\nsim.set_geometry(c)\n\n# Configure layer stack from active PDK\nstack = get_stack(air_above=300.0) # auto-detects active PDK\nsim.set_stack(stack)\n\n# Configure via ports (Metal1 ground plane to TopMetal2 signal)\nfor port in c.ports:\n sim.add_port(port.name, from_layer=\"metal1\", to_layer=\"topmetal2\", geometry=\"via\")\n\n# Configure driven simulation (frequency sweep for S-parameters)\nsim.set_driven(fmin=1e9, fmax=100e9, num_points=300)\n\n# Validate configuration\nprint(sim.validate_config())" |
| "print(f\"Configured {len(sims)} simulations\")" | ||
| ] | ||
| "outputs": [], | ||
| "source": "import gdsfactory as gf\nfrom ihp import LAYER, PDK, cells\n\nfrom gsim.common.stack import get_stack\nfrom gsim.palace import DrivenSim\n\nPDK.activate()\n\nstack = get_stack(air_above=300.0) # auto-detects active PDK\n\nsims = []\n\nfor w in widths:\n # Build component\n c = gf.Component()\n r1 = c << cells.straight_metal(length=1000, width=w)\n\n r = c.get_region(layer=LAYER.TopMetal2drawing)\n r_sized = r.sized(+20000)\n c.add_polygon(r_sized, layer=LAYER.Metal1drawing)\n c.add_ports(r1.ports)\n\n # Configure simulation\n sim = DrivenSim()\n sim.set_output_dir(f\"./palace-sim-w{w:.1f}\")\n sim.set_geometry(c)\n sim.set_stack(stack)\n\n for port in c.ports:\n sim.add_port(\n port.name, from_layer=\"metal1\", to_layer=\"topmetal2\", geometry=\"via\"\n )\n\n sim.set_driven(fmin=1e9, fmax=100e9, num_points=80)\n sim.mesh(preset=\"default\")\n\n sims.append(sim)\n\nprint(f\"Configured {len(sims)} simulations\")" |
Replace implicit stack auto-detection with explicit stack = get_stack() in all 6 MEEP notebooks, eliminating the "No stack configured" validation warning and making PDK layer stack extraction visible.
Summary
stack = get_stack()across all Palace and MEEP notebooks, making PDK layer stack extraction visible and inspectablepalace_width_sweep, the stack is extracted once outside the loop and reusedNotebooks updated
Palace (8):
palace_cpw_waveport,palace_cpw_lumped,palace_cpw_fields,palace_cpw_via,palace_microstrip,palace_branch_line_coupler,palace_width_sweep,_palace_cpwMEEP (6):
meep_ybranch,meep_crossing,meep_dc,meep_ring_coupler,meep_2d,meep_2d_xz_gcNot changed
_palace_mach_zehnder— non-standard TFLN-on-quartz stackFixes #133
Test plan
get_stack()resolves correctly