Skip to main content

Prepare IHP SG13G2 GDSII layout for EM simulation


Version 1.2: all-new, geometry-based algorithms across every tool, replacing the earlier hardcoded heuristics — for significantly cleaner and more general simplification output.


This is a collection of tools to simplify GDSII layout for EM simulation.

Layouts are usually simple and clean in the initial design phase, but simulating a „final“ layout that was already prepared for tape-out with density rules etc. can be a challenge. The picture below shows some typical challenges:

  1. To fulfill metal density rules, larger areas have been created as an array of squares with hole inside. This hole does not really matter for EM results, but it will lead to additional mesh cells and slow down mesh generation and simulation. For openEMS, the value of refined_cellsize can efficiently be used to skip small detail, but still those edges will slow down the meshing processing. For Palace, such small detail will all be included in mesh and it is absolutely required to remove this.
  2. On layer TopMetal2 shown as orange boxes on the top right side, and many other layers hidden here, the layout includes unconnected (floating) metal boxes that are used to fulfill density rules. Unlike auto-generated dummy metal fill, this man-made dummy metal fill is on purpose „drawing“ and can’t be skipped by the purpose (data type).
  3. Especially for pads, there is a massive amount of vias located in via arrays at rather large spacing. A large distance for via array merging could merge adjacent via stacks that connect different metal shapes, and short them. gds_prepare_for_EM, gds2palace (0.8.1 and newer) and gds2openEMS only merge vias that connect the same metal shapes above and below.
  4. In the case shown here, the pads for copper pillar are round, which is represented in GDSII as a polygon with many vertices, resulting in over-meshing at these polygons, wasting simulation time.

To solve these issues and create a more simulation-friendly layout, a collection of tools is provided here.

gds_removefill

Removes unconnected (floating) man-made dummy metal fill. A shape only counts as removable fill once that same size repeats often enough on a layer, so genuinely isolated design content is left alone.

Optional commandline parameters, and their default value if not given:

  • output filename (second positional argument) - <input>_cleaned.gds
  • --cell - the top-level cell with the largest bounding box (KLayout's $$$CONTEXT_INFO$$$ never counts); the log names the cell and the other top-level cells. Before, the first top-level cell was taken, which in a file with several of them could be another cell than the design
  • --minsize - 1 (micron)
  • --maxsize - no upper limit
  • --mincount - 20 (how many repeats of the same size count as fill)
python gds_removefill.py layout.gds cleaned_layout.gds --minsize 1 --maxsize 40 --mincount 20

gds_simplify

Replaces density-fill cutouts (squares/shapes with a hole punched in them) with solid outlines, replaces circle-like pads with octagons for faster meshing, and detects and removes thin ring/frame structures on the layout periphery such as seal rings. Always processes the full built-in default set of layers.

Optional commandline parameters, and their default value if not given:

  • --exclude-layers - none (the full built-in default layer set is processed)
  • --cell - as for gds_removefill; used for the seal ring detection, all cells are simplified
python gds_simplify.py layout.gds --exclude-layers 126,134

gds_prepare_for_EM

The all-in-one tool: runs all of the above plus via-array simplification (replacing dense via arrays with a handful of clean shapes) and round-pad-to-octagon conversion, producing a single simulation-ready output file in one pass.

It also fills holes that only appear once neighbouring polygons are merged, e.g. a meshed ground plane drawn as several polygons whose seams cut through rows of openings. Such a hole is filled only if holes of the same size repeat at least --fill-mincount times on a layer, so a one-off opening enclosed by merged metal (e.g. the aperture around an antenna) stays open.

Optional commandline parameters, and their default value if not given:

  • output filename (second positional argument) - <input>_cleaned.gds
  • --cell - the top-level cell with the largest bounding box (KLayout's $$$CONTEXT_INFO$$$ never counts); the log names the cell and the other top-level cells. Before, the first top-level cell was taken, which in a file with several of them could be another cell than the design
  • --fill-minsize - 1 (micron)
  • --fill-maxsize - no upper limit
  • --fill-mincount - 20 (how many repeats of the same size count as fill, or as a hole pattern to fill)
  • --max-hole-area - no upper limit (every real cutout found is filled); set this to leave larger cutouts untouched
  • --via-merge-size - 2 (micron): vias closer than this are merged into one shape, but only if they connect the same metal shapes above and below, so via merging never shorts different metal shapes. The merged shape is clipped to the overlap of these metal shapes. 0 = no via merging.
python gds_prepare_for_EM.py layout.gds cleaned_layout.gds --fill-minsize 1 --fill-maxsize 40 --fill-mincount 20 --max-hole-area 1

Starting from the example above, the resulting cleaned and simplified GDSII then looks like this:

Installation

There are two ways to use these tools - pick whichever fits your workflow.

Requires Python 3.9+ and these libraries: gdspy, rtree, numpy, shapely (>=2.0).

Run the Python files directly, no installation needed beyond the dependencies:

pip install -r requirements.txt
python gds_prepare_for_EM.py layout.gds

Install as a package, which adds gds_prepare_for_EM, gds_simplify, and gds_removefill as commands on your PATH while the virtual environment is active:

pip install gds_prepare_for_EM
gds_prepare_for_EM layout.gds

(For a local/development install from a clone of this repository, use pip install -e . instead.)

Usage

To run a tool, specify the *.gds filename as commandline parameter; the cleaned file is saved with an appropriate file suffix (or pass a second argument to choose the output filename). Every tool always prints its full list of options and the values used for that particular run, so you can see exactly what a run did after the fact - run with --help to see the options without processing a file, or --version to print the version.

example, either as a direct script or as an installed command:

python gds_prepare_for_EM.py layout.gds
python gds_prepare_for_EM.py layout.gds cleaned_layout.gds

gds_prepare_for_EM layout.gds
gds_prepare_for_EM layout.gds cleaned_layout.gds

Use from Python (stackup-driven simplification)

gds_simplify_for_em runs the same steps from Python, with the layers taken from a gds2palace XML stackup instead of the IHP SG13G2 layer names. setupEM's Tools > Simplify GDS and the gds2palace MCP server use it.

from gds2palace import stackup_reader, utilities
from gds_simplify_for_em import layers_from_stackup, run_simplify, estimate_polygon_count_by_layer

_, _, metals_list = stackup_reader.read_substrate(utilities.get_stackup_path("SG13G2_FEM_200um.xml"))
metal_layers, via_layers = layers_from_stackup(metals_list)    # port layers 201-299 are left out

print(estimate_polygon_count_by_layer("layout.gds", "", purposelist=[0]))   # {layer: count}, no flattening
run_simplify("layout.gds", metal_layers, "layout_simplified.gds",
             do_floating=True, do_cutouts=True, via_layers=via_layers, via_merge_size=1.0)
  • run_simplify(): fills small cutouts, removes floating fill, merges each layer and merges via arrays (vias closer than via_merge_size that connect the same metal shapes above and below), in this order, then checks and repairs polygon validity.
  • estimate_polygon_count() / estimate_polygon_count_by_layer(): the polygon count of a cell, from the cell hierarchy without flattening it, so it is fast even for dense fill and via arrays.
  • ground_plane_holes() / run_simplify(..., fill_ground_holes=True): openings in ground planes, measured in the layout. Each metal layer is merged first, so holes drawn inside tiles and gaps left between side-by-side tiles are the same kind of opening. A merged shape is a ground plane if, with its holes filled, it is large (at least 10 % of the layout's bounding box) and solid (at least 60 % of its own bounding box). Openings of one size that occur at least 20 times on a layer (cheesing, a tiled mesh) are filled; other openings, which belong to the circuit, and holes in shapes that are not ground planes stay. There is no size threshold: only the repeated sizes found in the layout are filled.

License

This project is licensed under the Apache License, Version 2.0 - see LICENSE for the full text.

Technology-specific (IHP SG13G2) hardcoded values

These tools are written against the IHP SG13G2 GDSII layer/purpose numbering. To adapt them to a different PDK, edit the tables below - there is no config file, everything else in each script derives from these tables.

Each of the three tools keeps its own independent copy of the layer/purpose tables - they are not shared or synced. Editing one script's table has no effect on the others; if a layer/purpose number needs to change, it must be changed in each script that defines it.

gds_prepare_for_EM.py

Item Values Purpose
LAYER_NAMES (layer number <-> name) 1=Activ, 6=Cont, 8=Metal1, 9=Passiv, 10=Metal2, 19=Via1, 29=Via2, 30=Metal3, 36=MIM, 41=Pillar, 49=Via3, 50=Metal4, 66=Via4, 67=Metal5, 125=TopVia1, 126=TopMetal1, 129=Vmim, 133=TopVia2, 134=TopMetal2, 157=LBE Defines which GDSII layer numbers are metals/vias and their names; everything else (metal lists, via lists) derives from this
VIA_ABOVE_BELOW Cont: Metal1/Activ, Via1: Metal2/Metal1, Via2: Metal3/Metal2, Via3: Metal4/Metal3, Via4: Metal5/Metal4, Vmim: TopMetal1/MIM, TopVia1: TopMetal1/Metal5, TopVia2: TopMetal2/TopMetal1 SG13G2's specific via stack topology - which metal sits above/below each via layer, used for via-array merging
EXTRA_VIA_LIKE_NAMES Passiv, Pillar Layers that aren't real vias but should still be excluded from floating-fill removal
exclude_purpose_list (excluded from output entirely) 28=noqrc, 22=filler, 23=nofill, 21=block SG13G2 GDSII purpose/datatype numbers
Layers above 200 layers_list extended with every layer above 200 found in the design Not an IHP PDK layer range - a pipeline-wide convention (shared with gds2palace_ihp_sg13g2/openems_ihp_sg13g2) for layers drawn by the user above the PDK's own layer numbers: EM ports (201-299), substrate/backside ground sheets (250, 251), thermal heat sources and boundaries (300 and up, e.g. 401-499). They are kept unchanged, regardless of LAYER_NAMES above. Before 1.7.1 only 201-249 were kept

gds_simplify.py

Item Values Purpose
LAYER_NAMES (layer number <-> name) Same full 18-layer table as gds_prepare_for_EM.py above - an independent copy, not shared Defines which GDSII layer numbers are metals/vias and their names; metal_layers_list derives from this
required_purpose_list (only these purposes are processed) 0=drawing, 35=pillar, 70=copper SG13G2 GDSII purpose/datatype numbers
delete_layers_list (deleted outright, no replacement) 148, 160 SG13G2-specific GDSII layer numbers dropped to reduce file size
delete_purpose_list (deleted outright, no replacement) 22=filler, 23=nofill, 29, 2=pin SG13G2 GDSII purpose/datatype numbers
Port-layer convention poly_layer > 200 check Not an IHP PDK layer range - same pipeline-wide port-layer convention as gds_prepare_for_EM.py above, so those are always kept regardless of LAYER_NAMES above

gds_removefill.py

Item Values Purpose
LAYER_NAMES (layer number <-> name) 10-layer subset (via/via-like layers only): 6=Cont, 9=Passiv, 19=Via1, 29=Via2, 41=Pillar, 49=Via3, 66=Via4, 125=TopVia1, 129=Vmim, 133=TopVia2 An independent, smaller copy of the same table - defines via_layers_list, the layers excluded from floating-fill removal
VIA_LAYER_NAMES Cont, Via1, Via2, Via3, Via4, Vmim, TopVia1, TopVia2, Pillar, Passiv Names from LAYER_NAMES above treated as via/via-like for fill-removal purposes

gds_geometry_utils.py / tools/gds_diff.py

Neither file contains any PDK-specific values - both work purely on generic polygon geometry (hole/cutout decomposition, circle detection, periphery ring detection, design cell selection, structural diffing) and apply to any GDSII layout.

python tools/gds_diff.py [--flat] a.gds b.gds compares the polygons and paths per cell and (layer, datatype): count, area and vertex counts, and ends with a summary line (also "no differences"). Cells are compared by name; --flat compares the two design cells flattened instead, whatever their names, e.g. a layout against gds_prepare_for_EM's output, whose cell is flattened and renamed.

Tests

python -m pytest from the repo root (pip install pytest, or .[test]). Small layouts generated by the tests check that layers above 200 are kept, the choice of the design cell, fill removal and tools/gds_diff.py, in a few seconds. The golden checks (marker golden, about 30 s) run gds_prepare_for_EM and gds_removefill on the layouts in testcases/ and compare the per-layer polygon count and area with tests/golden/; testcases/ is not in git, so they are skipped without it (or set GDS_TESTCASES to its folder). A change that alters a result on purpose updates the golden files with UPDATE_GOLDEN=1 python -m pytest tests/test_golden.py; python -m pytest -m "not golden" skips them.

Metadata

Release files for gds-prepare-for-EM 1.7.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gds-prepare-for-EM 1.7.1
File Size Uploaded Provenance Actions
gds_prepare_for_em-1.7.1.tar.gz 51.3 kB Without provenance Details for gds_prepare_for_em-1.7.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for gds-prepare-for-EM 1.7.1
File Interpreter ABI Platform Actions
gds_prepare_for_em-1.7.1-py3-none-any.whl Python 3 none any Details for gds_prepare_for_em-1.7.1-py3-none-any.whl

Total release size: 100.1 kB

Release files / gds_prepare_for_em-1.7.1.tar.gz

Download URL gds_prepare_for_em-1.7.1.tar.gz
Size 51.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5b276ed8d64b0a9667afbcb1ee9fe3977eaec4670f3f37902f46a455d757f17f
BLAKE2b-256 checksum
How to use checksums
fe256b51aaa5c274252bdcd511a1091e72fa6b581ec2e0c4edad988132d3b285
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / gds_prepare_for_em-1.7.1-py3-none-any.whl

Download URL gds_prepare_for_em-1.7.1-py3-none-any.whl
Size 48.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
532b8abd148b7416f94581bff280b54516daf327d9a8f0a347186de3bef7ff16
BLAKE2b-256 checksum
How to use checksums
33049082e95a9c7fc543d9c356551cf0b82e1642551c6ac264629a12bea0199c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for gds-prepare-for-EM 1.7.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page