def tree(): p1 = gdstk.Polygon(((0, 0), (0, 1), (1, 0)), 0, 0) p2 = gdstk.Polygon(((2, 0), (2, 1), (1, 0)), 1, 1) l1 = gdstk.Label("label1", (0, 0), layer=11) l2 = gdstk.Label("label2", (2, 1), layer=12) c1 = gdstk.Cell("tree1") c1.add(p1) c1.add(l1) c2 = gdstk.Cell("tree2") c2.add(l2) c2.add(p2) c2.add(gdstk.Reference(c1)) c3 = gdstk.Cell("tree3") c3.add(gdstk.Reference(c2, (0, 0), columns=3, rows=2, spacing=(3, 3))) return c3, c2, c1
def test_properties(): for obj in [ gdstk.Polygon([-1 + 0j, -2j, 3 + 0j, 4j]), gdstk.FlexPath((0j, 1j), 0.1), gdstk.RobustPath(0j, 0.1), gdstk.Label("Label", 0j), gdstk.Reference("EMPTY"), gdstk.Cell("CELL"), gdstk.Library("Name"), ]: assert len(obj.properties) == 0 assert obj.get_property("None") is None obj.set_property("FIRST", 1) obj.set_property("SECOND", 2.0) obj.set_property("THIRD", -3) obj.set_property("FOURTH", [1, 2.0, -3, "FO", b"UR\x00TH\x00"]) obj.set_property("FIRST", -1) assert obj.get_property("FIRST") == [-1] obj.delete_property("THIRD") assert obj.properties == [ ["FIRST", -1], ["FOURTH", 1, 2.0, -3, b"FO", b"UR\x00TH\x00"], ["SECOND", 2.0], ["FIRST", 1], ] obj.properties = ( ("ONE", -1), ("TWO", -2.3e-4, "two"), ("Three", b"\xFF\xEE", 0), ) assert obj.properties == [ ["ONE", -1], ["TWO", -2.3e-4, b"two"], ["Three", b"\xFF\xEE", 0], ]
def test_copy_transform(proof_cells): ref_cell1 = gdstk.Cell("Reference 1") ref_cell1.add(*gdstk.text("F.", 10, (0, 0))) ref_cell1.add(gdstk.Label("LaBeL", (2.4, 8.7), "s")) ref_cell1.add( gdstk.FlexPath(8 + 4j, 1, simple_path=True, layer=3).arc(2, 0, numpy.pi / 2)) ref_cell1.add( gdstk.RobustPath(7.5 + 7j, 1, simple_path=True, layer=4).bezier([-2 + 1j, -2 + 3j, 4j, 6j, -3 + 6j], relative=True)) ref_cell2 = gdstk.Cell("Reference 2") ref_cell2.add(*gdstk.text("^", 10, (0, 5), layer=1)) ref_cell2.add(gdstk.Reference(ref_cell1)) cell = gdstk.Cell("Original cell") cell.add(gdstk.rectangle((-1, -0.5), (1, 0.5), layer=2)) cell.add(gdstk.Reference(ref_cell2)) cell.add(gdstk.Reference(ref_cell1, (10, 7), numpy.pi / 4, 0.5, True)) cell.add( gdstk.Reference(ref_cell1, (-7, 15), -numpy.pi / 3, 0.5, True, 3, 2, (5, 4))) cell.add( gdstk.Reference(ref_cell2, (-7, 23), numpy.pi / 3, 0.5, True, 3, 2, (5, 8))) cell_copy = cell.copy("Cell.copy", (-10, -10), numpy.pi / 2, 2, True).flatten() for path in cell_copy.paths: cell_copy.add(*path.to_polygons()) assert_same_shape(proof_cells["Cell.copy"].polygons, cell_copy.polygons)
def test_filter(): polys = [ gdstk.rectangle((0, 0), (1, 1), layer=l, datatype=t) for t in range(3) for l in range(3) ] labels = [ gdstk.Label("FILTER", (1, 1), layer=l, texttype=t) for t in range(3) for l in range(3) ] paths = [ gdstk.FlexPath([0j, 1j], [0.1, 0.1, 0.1], 0.5, layer=[0, 1, 2], datatype=t) for t in range(3) ] + [ gdstk.RobustPath(0j, [0.1, 0.1], 0.5, layer=[1, 2], datatype=t) for t in range(3) ] layers = [1, 2] types = [0] for op, test in [ ("and", lambda a, b: a and b), ("or", lambda a, b: a or b), ("xor", lambda a, b: (a and not b) or (b and not a)), ("nand", lambda a, b: not (a and b)), ("nor", lambda a, b: not (a or b)), ("nxor", lambda a, b: not ((a and not b) or (b and not a))), ]: path_results = [ [test(a in layers, b in types) for a, b in zip(path.layers, path.datatypes)] for path in paths ] cell = gdstk.Cell(op) cell.add(*polys, *labels, *paths) cell.filter(layers, types, op) cell_polys = cell.polygons for poly in polys: if test(poly.layer in layers, poly.datatype in types): assert poly not in cell_polys else: assert poly in cell_polys cell_labels = cell.labels for label in labels: if test(label.layer in layers, label.texttype in types): assert label not in cell_labels else: assert label in cell_labels cell_paths = cell.paths for path, results in zip(paths, path_results): if all(results): assert path not in cell_paths else: assert path in cell_paths assert len(path.layers) == len(results) - sum(results) assert all( not test(a in layers, b in types) for a, b in zip(path.layers, path.datatypes) )
def test_add_element(): p = gdstk.Polygon(((0, 0), (1, 0), (0, 1))) l = gdstk.Label("label", (0, 0)) c = gdstk.Cell("c_add_element") assert c.add(p) is c assert c.add(p, l) is c polygons = c.polygons assert len(polygons) == 2 assert polygons[0] is p assert polygons[1] is p assert len(c.labels) == 1 assert c.labels[0] is l
def bench_gdstk(output=None): c1 = gdstk.Cell("REF") c1.add(gdstk.rectangle((0, 0), (10, 10))) c1.add( gdstk.FlexPath([(0, 0), (10, 0), (10, 10), (0, 10)], [0.1, 0.1], 0.3, layer=1)) c1.add(gdstk.Label("Label", (5, 5), anchor='o')) c2 = gdstk.Cell("MAIN") c2.add(gdstk.Reference(c1, columns=3, rows=2, spacing=(20, 20))) c2.flatten() c1.remove(*c1.polygons, *c1.paths, *c1.labels) if output: c2.write_svg(output, 10)
def test_bb_label_repetition(): lbl = gdstk.Label("label", (1, 2)) lbl.repetition = gdstk.Repetition(x_offsets=(1, 3, -2)) c_lbl = gdstk.Cell("A") c_lbl.add(lbl) assert_close(c_lbl.bounding_box(), ((-1, 2), (4, 2))) ref = gdstk.Reference(c_lbl) ref.repetition = gdstk.Repetition(y_offsets=(-1, 2, -4)) c_ref = gdstk.Cell("B") c_ref.add(ref) assert_close(c_ref.bounding_box(), ((-1, -2), (4, 4))) ref.rotation = numpy.pi / 4 a = (-1 + 2j) * numpy.exp(0.25j * numpy.pi) b = (4 + 2j) * numpy.exp(0.25j * numpy.pi) assert_close(c_ref.bounding_box(), ((a.real, a.imag - 4), (b.real, b.imag + 2)))
def test_label_bounding_box(): c = gdstk.Cell("CELL") l = gdstk.Label("Label", (2, 3)) c.add(l) bb = c.bounding_box(); assert bb[0][0] == 2 and bb[0][1] == 3 assert bb[1][0] == 2 and bb[1][1] == 3 ref = gdstk.Reference(c, (-1, 1)) bb = ref.bounding_box() assert bb[0][0] == 1 and bb[0][1] == 4 assert bb[1][0] == 1 and bb[1][1] == 4 ang = numpy.pi / 4 x = ref.origin[0] + l.origin[0] * numpy.cos(ang) - l.origin[1] * numpy.sin(ang) y = ref.origin[1] + l.origin[0] * numpy.sin(ang) + l.origin[1] * numpy.cos(ang) ref.rotation = ang bb = ref.bounding_box() assert_close(bb, ((x, y), (x, y)))
def init_image(): frame = gdstk.rectangle((-2, -1), (2, 1), datatype=1) label_o = gdstk.Label("Center", (0, 0), rotation=numpy.pi / 6) label_n = gdstk.Label("North", (0, 1), "n") label_s = gdstk.Label("South", (0, -1), "s") label_e = gdstk.Label("East", (2, 0), "e") label_w = gdstk.Label("West", (-2, 0), "w") label_ne = gdstk.Label("Northeast", (2, 1), "ne") label_se = gdstk.Label("Southeast", (2, -1), "se") label_nw = gdstk.Label("Northwest", (-2, 1), "nw") label_sw = gdstk.Label("Southwest", (-2, -1), "sw") return gdstk.Cell("init").add( frame, label_o, label_n, label_s, label_e, label_w, label_ne, label_se, label_nw, label_sw, )
def test_properties(): for obj in [ gdstk.Polygon([-1 + 0j, -2j, 3 + 0j, 4j]), gdstk.FlexPath((0j, 1j), 0.1), gdstk.RobustPath(0j, 0.1), gdstk.Label("Label", 0j), gdstk.Reference("EMPTY"), ]: assert obj.get_property(12) is None assert obj.delete_property(12) is obj obj.set_property(13, "Property text") assert obj.get_property(12) is None assert obj.get_property(13) == "Property text" obj.delete_property(13) assert obj.get_property(13) is None obj.set_property(13, "Second text") obj.set_property(13, "Third text") assert obj.get_property(13) == "Third text"
def write_svg_image(): # (layer, datatype) = (0, 1) poly1 = gdstk.ellipse((0, 0), (13, 10), datatype=1) # (layer, datatype) = (1, 0) poly2 = gdstk.ellipse((0, 0), (10, 7), layer=1) (layer, texttype) = (3, 2) label = gdstk.Label("Example", (0, 0), layer=3, texttype=2) cell = gdstk.Cell("SVG") cell.add(poly1, poly2, label) # cell.write_svg( # "example.svg", # background="none", # style={(0, 1): {"fill": "none", "stroke": "black", "stroke-dasharray": "8,8"}}, # fontstyle={(3, 2): {"fill": "none", "stroke": "red", "font-size": "32px"}}, # pad="5%", # sort_function=lambda p1, p2: p1.layer < p2.layer, # ) cell.name = "write_svg" return cell
def test_copy(): p = gdstk.Polygon(((0, 0), (1, 0), (0, 1))) lbl = gdstk.Label("label", (0, 0)) cref = gdstk.Cell("ref").add(gdstk.rectangle((-1, -1), (-2, -2))) ref = gdstk.Reference(cref) cell = gdstk.Cell("original") cell.add(p, lbl, ref) shallow_copy = cell.copy("copy_0", deep_copy=False) assert len(shallow_copy.polygons) == len(cell.polygons) assert p in shallow_copy.polygons assert len(shallow_copy.labels) == len(cell.labels) assert lbl in shallow_copy.labels assert len(shallow_copy.references) == len(cell.references) assert ref in shallow_copy.references deep_copy = cell.copy("copy_1") assert len(deep_copy.polygons) == len(cell.polygons) assert p not in deep_copy.polygons assert len(deep_copy.labels) == len(cell.labels) assert lbl not in deep_copy.labels assert len(deep_copy.references) == len(cell.references) assert ref not in deep_copy.references assert deep_copy.references[0].cell is ref.cell
def sample_library(): lib = gdstk.Library("lib", unit=2e-3, precision=1e-5) c1 = gdstk.Cell("gl_rw_gds_1") c1.add(gdstk.rectangle((0, -1), (1, 2), 2, 4)) c1.add(gdstk.Label("label", (1, -1), "w", 10, 1.5, True, 5, 6)) c2 = gdstk.Cell("gl_rw_gds_2") c2.add(gdstk.ellipse((0, 0), 1)) c3 = gdstk.Cell("gl_rw_gds_3") c3.add(gdstk.Reference(c1, (0, 1), -90, 2, True)) c4 = gdstk.Cell("gl_rw_gds_4") c4.add( gdstk.Reference( c2, (-1, -2), columns=2, rows=3, spacing=(1, 4), rotation=numpy.pi, magnification=0.5, x_reflection=True, )) lib.add(c1, c2, c3, c4) return lib
def test_gds_properties(): for obj in [ gdstk.Polygon([-1 + 0j, -2j, 3 + 0j, 4j]), gdstk.FlexPath((0j, 1j), 0.1), gdstk.RobustPath(0j, 0.1), gdstk.Label("Label", 0j), gdstk.Reference("EMPTY"), ]: assert obj.get_gds_property(12) is None assert obj.delete_gds_property(12) is obj obj.set_gds_property(13, "Property text") assert obj.get_gds_property(12) is None assert obj.get_gds_property(13) == "Property text" obj.delete_gds_property(13) assert obj.get_gds_property(13) is None obj.set_gds_property(13, "Second text") obj.set_gds_property(13, "Third text") obj.set_gds_property(14, "Fourth text") assert obj.get_gds_property(13) == "Third text" assert obj.properties == [ ["S_GDS_PROPERTY", 14, b"Fourth text\x00"], ["S_GDS_PROPERTY", 13, b"Third text\x00"], ]
def make_proof_lib(): lib = gdstk.Library("Test Library", unit=1e-6, precision=1e-12) cell = lib.new_cell("Polygon.fillet") p1 = gdstk.Polygon([(0, 0), (1.2, 0), (1.2, 0.3), (1, 0.3), (1.5, 1), (0, 1.5)]) p2 = p1.copy().translate(2, 0) cell.add(p1.fillet(0.3, tolerance=1e-3)) cell.add(p2.fillet([0.3, 0, 0.1, 0, 0.5, 10], tolerance=1e-3)) for scale_width in [True, False]: cell = lib.new_cell(f"FlexPath: scale_width {scale_width}") path0 = gdstk.FlexPath( (0j, 1j, 0.5 + 1j), [0.1, 0.2], 0.3, tolerance=1e-4, scale_width=scale_width, ) path0.turn(0.4, -numpy.pi, [0.2, 0.1]).segment((-0.2, 0), relative=True) path1 = path0.copy().mirror((1.5, 0)) path1.set_layers(1, 1) path2 = path0.copy().mirror((1.5, 0), (1.5, 1)) path2.set_layers(2, 2) path3 = path0.copy().scale(2, (3, 0)) path3.set_layers(3, 3) path4 = path0.copy().scale(-2, (-1, 0)) path4.set_layers(4, 4) path5 = path0.copy().rotate(numpy.pi / 2, (2, 1)).translate(0.2, -0.3) path5.set_layers(5, 5) cell.add(path0, path1, path2, path3, path4, path5) for scale_width in [True, False]: cell = lib.new_cell(f"RobustPath: scale_width {scale_width}") path0 = gdstk.RobustPath( 0j, [0.1, 0.2], 0.3, tolerance=1e-4, scale_width=scale_width, ) path0.vertical(1).horizontal(0.5).turn(0.4, -numpy.pi, [0.2, 0.1]).segment( (-0.2, 0), relative=True) path1 = path0.copy().mirror((1.5, 0)) path1.set_layers(1, 1) path2 = path0.copy().mirror((1.5, 0), (1.5, 1)) path2.set_layers(2, 2) path3 = path0.copy().scale(2, (3, 0)) path3.set_layers(3, 3) path4 = path0.copy().scale(-2, (-1, 0)) path4.set_layers(4, 4) path5 = path0.copy().rotate(numpy.pi / 2, (2, 1)).translate(0.2, -0.3) path5.set_layers(5, 5) cell.add(path0, path1, path2, path3, path4, path5) ref_cell1 = gdstk.Cell("Reference 1") ref_cell1.add(*gdstk.text("F.", 10, (0, 0))) ref_cell1.add(gdstk.Label("LaBeL", (2.4, 8.7), "s")) ref_cell1.add(gdstk.FlexPath(8 + 4j, 1, layer=3).arc(2, 0, numpy.pi / 2)) ref_cell1.add( gdstk.RobustPath(7.5 + 7j, 1, layer=4).bezier([-2 + 1j, -2 + 3j, 4j, 6j, -3 + 6j], relative=True)) ref_cell2 = gdstk.Cell("Reference 2") ref_cell2.add(*gdstk.text("^", 10, (0, 5), layer=1)) ref_cell2.add(gdstk.Reference(ref_cell1)) cell = gdstk.Cell("Original cell") cell.add(gdstk.rectangle((-1, -0.5), (1, 0.5), layer=2)) cell.add(gdstk.Reference(ref_cell2)) cell.add(gdstk.Reference(ref_cell1, (10, 7), numpy.pi / 4, 0.5, True)) cell.add( gdstk.Reference(ref_cell1, (-7, 15), -numpy.pi / 3, 0.5, True, 3, 2, (5, 4))) cell.add( gdstk.Reference(ref_cell2, (-7, 23), numpy.pi / 3, 0.5, True, 3, 2, (5, 8))) cell_copy = cell.copy("Cell.copy", (-10, -10), numpy.pi / 2, 2, True).flatten() lib.add(cell_copy) gds_outfile = pathlib.Path(__file__).parent / "proof_lib.gds" if gds_outfile.exists(): print(f"Test library {str(gds_outfile)} already exists.") else: lib.write_gds(gds_outfile) print(f"Test library saved as {str(gds_outfile)}.") oas_outfile = pathlib.Path(__file__).parent / "proof_lib.oas" if oas_outfile.exists(): print(f"Test library {str(oas_outfile)} already exists.") else: lib.write_oas(oas_outfile) print(f"Test library saved as {str(oas_outfile)}.")
def memory_benchmark(): proc = psutil.Process() total = 100000 print(f"\nMemory usage per object for {total} objects:\n") def print_row(*vals, hsep=False): columns = [20, 16, 16, 9] print( "|", vals[0].ljust(columns[0]), "|", " | ".join(v.center(c) for v, c in zip(vals[1:], columns[1:])), "|", ) if hsep: print( "|", ":" + "-" * (columns[0] - 1), "|", " | ".join(":" + "-" * (c - 2) + ":" for c in columns[1:]), "|", ) print_row( "Object", "Gdspy " + gdspy.__version__, "Gdstk " + gdstk.__version__, "Reduction", hsep=True, ) def mem_test(func): start_mem = proc.memory_info() r = [func(i) for i in range(total)] end_mem = proc.memory_info() return (end_mem.vms - start_mem.vms) / total, r data = [] gdspy_cell = gdspy.Cell("TEMP", exclude_from_current=True) gdstk_cell = gdstk.Cell("TEMP") for obj, gdspy_func, gdstk_func in [ ( "Rectangle", lambda i: gdspy.Rectangle((i, i), (i + 1, i + 1)), lambda i: gdstk.rectangle((i, i), (i + 1, i + 1)), ), ( "Circle (r = 10)", lambda i: gdspy.Round((0, 10 * i), 10), lambda i: gdstk.ellipse((0, 10 * i), 10), ), ( "FlexPath segment", lambda i: gdspy.FlexPath([(i, i + 1), (i + 1, i)], 0.1), lambda i: gdstk.FlexPath([(i, i + 1), (i + 1, i)], 0.1), ), ( "FlexPath arc", lambda i: gdspy.FlexPath([(10 * i, 0)], 0.1).arc(10, 0, numpy.pi), lambda i: gdstk.FlexPath([(10 * i, 0)], 0.1).arc(10, 0, numpy.pi), ), ( "RobustPath segment", lambda i: gdspy.RobustPath((i, i + 1), 0.1).segment((i + 1, i)), lambda i: gdstk.RobustPath((i, i + 1), 0.1).segment((i + 1, i)), ), ( "RobustPath arc", lambda i: gdspy.RobustPath((10 * i, 0), 0.1).arc(10, 0, numpy.pi), lambda i: gdstk.RobustPath((10 * i, 0), 0.1).arc(10, 0, numpy.pi), ), ( "Label", lambda i: gdspy.Label(str(i), (i, i)), lambda i: gdstk.Label(str(i), (i, i)), ), ( "Reference", lambda i: gdspy.CellReference(gdspy_cell, (0, 0)), lambda i: gdstk.Reference(gdstk_cell, (0, 0)), ), ( "Reference (array)", lambda i: gdspy.CellArray(gdspy_cell, (0, 0), 1, 1, (0, 0)), lambda i: gdstk.Reference(gdstk_cell, (0, 0), rows=1, columns=1), ), ( "Cell", lambda i: gdspy.Cell(str(i), exclude_from_current=True), lambda i: gdstk.Cell(str(i)), ), ]: gdspy_mem, gdspy_data = mem_test(gdspy_func) data.append(gdspy_data) gdstk_mem, gdstk_data = mem_test(gdstk_func) data.append(gdstk_data) print_row( obj, prefix_format(gdspy_mem, unit="B", base="bin"), prefix_format(gdstk_mem, unit="B", base="bin"), f"{100 - 100 * gdstk_mem / gdspy_mem:.0f}%", )
offset=[-0.25, 0.25, -0.75, 0.75], ) rp.parametric( lambda u: numpy.array((4 * numpy.sin(6 * numpy.pi * u), 45 * u)), offset=[ lambda u: -0.25 * numpy.cos(24 * numpy.pi * u), lambda u: 0.25 * numpy.cos(24 * numpy.pi * u), -0.75, 0.75, ], ) draw(gdstk.Cell("robust_paths").add(rp), path) # Text # Label centered at (1, 3) label = gdstk.Label("Sample label", (5, 3), texttype=2) # Horizontal text with height 2.25 htext = gdstk.text("12345", 2.25, (0.25, 6)) # Vertical text with height 1.5 vtext = gdstk.text("ABC", 1.5, (10.5, 4), vertical=True) rect = gdstk.rectangle((0, 0), (10, 6), layer=10) draw(gdstk.Cell("text").add(*htext, *vtext, label, rect), path) # Boolean Operations # Create some text text = gdstk.text("GDSTK", 4, (0, 0)) # Create a rectangle extending the text's bounding box by 1 rect = gdstk.rectangle((-1, -1), (5 * 4 * 9 / 16 + 1, 4 + 1))