GDSII format reader/writer
Project description
klamath README
klamath is a Python module for reading and writing to the GDSII file format.
The goal is to keep this library simple:
- Map data types directly wherever possible.
- Presents an accurate representation of what is saved to the file.
- Avoids excess copies / allocations for speed.
- No "automatic" error checking, except when casting datatypes. If data integrity checks are provided at all, they must be explicitly run by the caller.
- Low-level functionality is first-class.
- Meant for use-cases where the caller wants to read or write individual GDS records.
- Offers complete control over the written file.
- Opinionated and limited high-level functionality.
- Discards or ignores rarely-encountered data types.
- Keeps functions simple and reusable.
- Only de/encodes the file format, doesn't provide tools to modify the data itself.
- Still requires explicit values for most fields.
- No compilation
- Uses
numpyfor speed, since it's commonly available / pre-built. - Building this library should not require a compiler.
- Uses
klamath was built to provide a fast and versatile GDS interface for
masque, which provides higher-level
tools for working with hierarchical design data and supports multiple
file formats.
Alternatives
- gdspy
- Provides abstractions and methods for working with design data outside of the I/O process (e.g. polygon clipping).
- Requires compilation (C++) to build from source.
- Focused on high-level API
- python-gdsii
- Pure-python implementation. Can easily be altered to use
numpyfor speed, but is limited by object allocation overhead. - Focused on high-level API
- Pure-python implementation. Can easily be altered to use
Links
Installation
Requirements:
- python >= 3.11
- numpy
Install with pip:
pip3 install klamath
Alternatively, install from git
pip3 install git+https://mpxd.net/code/jan/klamath.git@release
Examples
Low-level
Filter which polygons are read based on layer:
import io
import klamath
from klamath import records
from klamath.record import Record
def read_polygons(stream, filter_layer_tuple=(4, 5)):
"""
Given a stream positioned at the start of a record,
return the vertices of all BOUNDARY records which match
the provided `filter_layer_tuple`, up to the next
ENDSTR record.
"""
polys = []
while True:
size, tag = Record.read_header(stream)
stream.seek(size, io.SEEK_CUR) # skip to next header
if tag == records.ENDEL.tag:
break # If ENDEL, we are done
if tag != records.BOUNDARY.tag:
continue # Skip until we find a BOUNDARY
layer = records.LAYER.skip_and_read(stream)[0] # skip to LAYER
dtype = records.DATATYPE.read(stream)[0]
if (layer, dtype) != filter_layer_tuple:
continue # Skip reading XY unless layer matches
xy = XY.read(stream).reshape(-1, 2)
polys.append(xy)
return polys
High-level
Write an example GDS file:
import klamath
from klamath.elements import Boundary, Text, Path, Reference
stream = open('example.gds', 'wb')
header = klamath.library.FileHeader(
name=b'example',
meters_per_db_unit=1e-9, # 1 nm DB unit
user_units_per_db_unit=1e-3) # 1 um (1000nm) display unit
header.write(stream)
elements_A = [
Boundary(layer=(4, 18),
xy=[[0, 0], [10, 0], [10, 20], [0, 20], [0, 0]],
properties={1: b'prop1string', 2: b'some other string'}),
Text(layer=(5, 5),
xy=[[5, 10]],
string=b'center position',
properties={}, # Remaining args are set to default values
presentation=0, # and will be omitted when writing
angle_deg=0,
invert_y=False,
width=0,
path_type=0,
mag=1),
Path(layer=(4, 20),
xy=[[0, 0], [10, 10], [0, 20]],
path_type=0,
width=0,
extension=(0, 0), # ignored since path_type=0
properties={}),
]
klamath.library.write_struct(stream, name=b'my_struct', elements=elements_A)
elements_top = [
Reference(struct_name=b'my_struct',
xy=[[30, 30]],
colrow=None, # not an array
angle_deg=0,
invert_y=True,
mag=1.5,
properties={}),
Reference(struct_name=b'my_struct',
colrow=(3, 2), # 3x2 array at (0, 50)
xy=[[0, 50], [60, 50], [30, 50]], # with basis vectors
angle_deg=30, # [20, 0] and [0, 30]
invert_y=False,
mag=1,
properties={}),
]
klamath.library.write_struct(stream, name=b'top', elements=elements_top)
klamath.records.ENDLIB.write(stream, None)
stream.close()
Read back the file:
import klamath
stream = open('example.gds', 'rb')
header = klamath.library.FileHeader.read(stream)
structs = {}
struct = klamath.library.try_read_struct(stream)
while struct is not None:
name, elements = struct
structs[name] = elements
struct = klamath.library.try_read_struct(stream)
stream.close()
print(structs)
Read back a single struct by name:
import klamath
stream = open('example.gds', 'rb')
header = klamath.library.FileHeader.read(stream)
struct_positions = klamath.library.scan_structs(stream)
stream.seek(struct_positions[b'my_struct'])
elements_A = klamath.library.try_read_struct(stream)
stream.close()
print(elements_A)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file klamath-1.5.tar.gz.
File metadata
- Download URL: klamath-1.5.tar.gz
- Upload date:
- Size: 40.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f08126056a03dd003040ebbe8b7657819c787840dec68f6b4166ae4a11932b33
|
|
| MD5 |
f2e96b1cdfbfd5dbbaa88bc1dd0c9a4c
|
|
| BLAKE2b-256 |
038568126d83dca63cf8377ed21e274e9f739d0edc0d922d11b43d93447ae7d6
|
File details
Details for the file klamath-1.5-py3-none-any.whl.
File metadata
- Download URL: klamath-1.5-py3-none-any.whl
- Upload date:
- Size: 56.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a3a3df4c0b9c81753b21130658b686715148f0573170e4baa8228163b6d4c9d
|
|
| MD5 |
5f19f00da11a5f02e194035a78586875
|
|
| BLAKE2b-256 |
005cebedc0f9cd19085f6587746b4d1a459ac1900ed5c1ca73a928c83800f8c3
|