# Components¶

gdsfactory provides a generic customizable components library in gf.components

## Basic shapes¶

### Rectangle¶

To create a simple rectangle, there are two functions:

gf.components.rectangle() can create a basic rectangle:

[1]:

import gdsfactory as gf

gf.components.rectangle(size=(4.5, 2), layer=(1, 0))

2021-09-25 16:19:19.544 | INFO     | gdsfactory.config:<module>:51 - 3.2.9

[1]:

rectangle_layer1_0_size4p5_2: uid 1, ports [], aliases [], 1 polygons, 0 references

gf.components.bbox() can also create a rectangle based on a bounding box. This is useful if you want to create a rectangle which exactly surrounds a piece of existing geometry. For example, if we have an arc geometry and we want to define a box around it, we can use gf.components.bbox():

[2]:

D = gf.Component()
arc = D << gf.components.bend_circular(radius=10, width=0.5, angle=90, layer=(1, 0))
arc.rotate(90)
# Draw a rectangle around the arc we created by using the arc's bounding box
rect = D << gf.components.bbox(bbox=arc.bbox, layer=(0, 0))
D

[2]:

Unnamed_06001b97: uid 2, ports [], aliases [], 0 polygons, 2 references

### Cross¶

The gf.components.cross() function creates a cross structure:

[3]:

gf.components.cross(length=10, width=0.5, layer=(1, 0))

[3]:

cross_layer1_0_length10_91787232: uid 5, ports ['o3', 'o1', 'o2', 'o4'], aliases [], 2 polygons, 0 references

### Ellipse¶

The gf.components.ellipse() function creates an ellipse by defining the major and minor radii:

[4]:

gf.components.ellipse(radii=(10, 5), angle_resolution=2.5, layer=(1, 0))

[4]:

ellipse_angle_resolutio_44057b02: uid 7, ports [], aliases [], 1 polygons, 0 references

### Circle¶

The gf.components.circle() function creates a circle:

[5]:

gf.components.circle(radius=10, angle_resolution=2.5, layer=(1, 0))

[5]:

circle_angle_resolution_dac0666b: uid 8, ports [], aliases [], 1 polygons, 0 references

### Ring¶

The gf.components.ring() function creates a ring. The radius refers to the center radius of the ring structure (halfway between the inner and outer radius).

[6]:

gf.components.ring(radius=5, width=0.5, angle_resolution=2.5, layer=(1, 0))

[6]:

ring_angle_resolution2p_845f9d9a: uid 9, ports [], aliases [], 1 polygons, 0 references
[7]:

gf.components.ring_single(
width=0.5, gap=0.2, radius=10, length_x=4, length_y=2, layer=(1, 0)
)

[7]:

ring_single_gap200n_lay_eddc165f: uid 10, ports ['o2', 'o1'], aliases [], 0 polygons, 6 references
[8]:

import gdsfactory as gf

gf.components.ring_double(
width=0.5, gap=0.2, radius=10, length_x=4, length_y=2, layer=(1, 0)
)

[8]:

ring_double_gap200n_lay_1cb49fce: uid 25, ports ['o1', 'o2', 'o3', 'o4'], aliases [], 0 polygons, 4 references
[9]:

gf.components.ring_double(
width=0.5,
gap=0.2,
length_x=4,
length_y=2,
layer=(1, 0),
bend=gf.components.bend_circular,
)

[9]:

ring_double_bendbend_ci_4127b690: uid 33, ports ['o1', 'o2', 'o3', 'o4'], aliases [], 0 polygons, 4 references

### Bend circular¶

The gf.components.bend_circular() function creates an arc. The radius refers to the center radius of the arc (halfway between the inner and outer radius).

[10]:

gf.components.bend_circular(radius=2.0, width=0.5, angle=90, npoints=720, layer=(1, 0))

[10]:

bend_circular_angle90_l_5ebc659d: uid 34, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

### Bend euler¶

The gf.components.bend_euler() function creates an adiabatic bend in which the bend radius changes gradually. Euler bends have lower loss than circular bends.

[11]:

gf.components.bend_euler(radius=2.0, width=0.5, angle=90, npoints=720, layer=(1, 0))

[11]:

bend_euler_angle90_laye_c1b4eebf: uid 35, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

### Tapers¶

gf.components.taper()is defined by setting its length and its start and end length. It has two ports, 1 and 2, on either end, allowing you to easily connect it to other structures.

[12]:

gf.components.taper(length=10, width1=6, width2=4, port=None, layer=(1, 0))

[12]:

taper_layer1_0_length10_8f785b8b: uid 36, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

gf.components.ramp() is a structure is similar to taper() except it is asymmetric. It also has two ports, 1 and 2, on either end.

[13]:

gf.components.ramp(length=10, width1=4, width2=8, layer=(1, 0))

[13]:

ramp_layer1_0_length10__4acf6857: uid 37, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

### Common compound shapes¶

The gf.components.L() function creates a “L” shape with ports on either end named 1 and 2.

[14]:

gf.components.L(width=7, size=(10, 20), layer=(1, 0))

[14]:

L_layer1_0_size10_20_width7: uid 38, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

The gf.components.C() function creates a “C” shape with ports on either end named 1 and 2.

[15]:

gf.components.C(width=7, size=(10, 20), layer=(1, 0))

[15]:

C_layer1_0_size10_20_width7: uid 39, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

## Text¶

Gdsfactory has an implementation of the DEPLOF font with the majority of english ASCII characters represented (thanks to phidl)

[16]:

gf.components.text(
text="Hello world!\nMultiline text\nLeft-justified",
size=10,
justify="left",
layer=(1, 0),
)
# justify should be either 'left', 'center', or 'right'

[16]:

Hello_world Multiline_text Leftmjustified_0_0: uid 40, ports [], aliases [], 0 polygons, 3 references

## Grid / packer / align / distribute¶

### Grid¶

The gf.components.grid() function can take a list (or 2D array) of objects and arrange them along a grid. This is often useful for making parameter sweeps. If the separation argument is true, grid is arranged such that the elements are guaranteed not to touch, with a spacing distance between them. If separation is false, elements are spaced evenly along a grid. The align_x/align_y arguments specify intra-row/intra-column alignment. Theedge_x/edge_y arguments specify inter-row/inter-column alignment (unused if separation = True).

[17]:

import gdsfactory as gf

components_list = []
for width1 in [1, 6, 9]:
for width2 in [1, 2, 4, 8]:
D = gf.components.taper(length=10, width1=width1, width2=width2, layer=(1, 0))
components_list.append(D)

c = gf.grid(
components_list,
spacing=(5, 1),
separation=True,
shape=(3, 4),
align_x="x",
align_y="y",
edge_x="x",
edge_y="ymax",
)
c

[17]:

grid: uid 56, ports [], aliases [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)], 0 polygons, 12 references

### Packer¶

The gf.pack() function packs geometries together into rectangular bins. If a max_size is specified, the function will create as many bins as is necessary to pack all the geometries and then return a list of the filled-bin Devices.

Here we generate several random shapes then pack them together automatically. We allow the bin to be as large as needed to fit all the Devices by specifying max_size = (None, None). By setting aspect_ratio = (2,1), we specify the rectangular bin it tries to pack them into should be twice as wide as it is tall:

[18]:

import numpy as np
import gdsfactory as gf

np.random.seed(5)
D_list = [
gf.components.ellipse(radii=tuple(np.random.rand(2) * n + 2)) for n in range(50)
]
D_list += [
gf.components.rectangle(size=tuple(np.random.rand(2) * n + 2)) for n in range(50)
]

D_packed_list = gf.pack(
D_list,  # Must be a list or tuple of Devices
spacing=1.25,  # Minimum distance between adjacent shapes
aspect_ratio=(2, 1),  # (width, height) ratio of the rectangular bin
max_size=(None, None),  # Limits the size into which the shapes will be packed
density=1.05,  # Values closer to 1 pack tighter but require more computation
sort_by_area=True,  # Pre-sorts the shapes by area
)
D = D_packed_list[0]  # Only one bin was created, so we plot that
D

[18]:

Unnamed_c6a50e1d: uid 158, ports [], aliases [], 0 polygons, 100 references

Say we need to pack many shapes into multiple 500x500 unit die. If we set max_size = (500,500) the shapes will be packed into as many 500x500 unit die as required to fit them all:

[19]:

np.random.seed(1)
D_list = [
gf.components.ellipse(radii=tuple(np.random.rand(2) * n + 2)) for n in range(120)
]
D_list += [
gf.components.rectangle(size=tuple(np.random.rand(2) * n + 2)) for n in range(120)
]

D_packed_list = gf.pack(
D_list,  # Must be a list or tuple of Devices
spacing=4,  # Minimum distance between adjacent shapes
aspect_ratio=(1, 1),  # Shape of the box
max_size=(500, 500),  # Limits the size into which the shapes will be packed
density=1.05,  # Values closer to 1 pack tighter but require more computation
sort_by_area=True,  # Pre-sorts the shapes by area
)

# Put all packed bins into a single device and spread them out with distribute()
F = gf.Component()
F.distribute(elements="all", direction="x", spacing=100, separation=True)
F

/home/docs/checkouts/readthedocs.org/user_builds/gdsfactory/checkouts/latest/gdsfactory/pack.py:168: UserWarning: created 3 groups of components
warnings.warn(f"created {len(components_packed_list)-1} groups of components")

[19]:

Unnamed_3ecd2a40: uid 743, ports [], aliases [], 0 polygons, 4 references

Note that the packing problem is an NP-complete problem, so gf.components.packer() may be slow if there are more than a few hundred Devices to pack (in that case, try pre-packing a few dozen at a time then packing the resulting bins). Requires the rectpack python package.

### Distribute¶

The distribute() function allows you to space out elements within a Device evenly in the x or y direction. It is meant to duplicate the distribute functionality present in Inkscape / Adobe Illustrator:

Say we start out with a few random-sized rectangles we want to space out:

[20]:

c = gf.Component()
# Create different-sized rectangles and add them to D
[
gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20], layer=(0, 0))
).move([n, n * 4])
for n in [0, 2, 3, 1, 2]
]
c

[20]:

Unnamed_6b0222e6: uid 744, ports [], aliases [], 0 polygons, 5 references

Oftentimes, we want to guarantee some distance between the objects. By setting separation = True we move each object such that there is spacing distance between them:

[21]:

D = gf.Component()
# Create different-sized rectangles and add them to D
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move((n, n * 4))
for n in [0, 2, 3, 1, 2]
]
# Distribute all the rectangles in D along the x-direction with a separation of 5
D.distribute(
elements="all",  # either 'all' or a list of objects
direction="x",  # 'x' or 'y'
spacing=5,
separation=True,
)
D

[21]:

Unnamed_32515d53: uid 749, ports [], aliases [], 0 polygons, 5 references

Alternatively, we can spread them out on a fixed grid by setting separation = False. Here we align the left edge (edge = 'min') of each object along a grid spacing of 100:

[22]:

D = gf.Component()
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move((n, n * 4))
for n in [0, 2, 3, 1, 2]
]
D.distribute(
elements="all", direction="x", spacing=100, separation=False, edge="xmin"
)  # edge must be either 'xmin' (left), 'xmax' (right), or 'x' (center)
D

[22]:

Unnamed_cc63e5c9: uid 754, ports [], aliases [], 0 polygons, 5 references

The alignment can be done along the right edge as well by setting edge = 'max', or along the center by setting edge = 'center' like in the following:

[23]:

D = gf.Component()
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move(
(n - 10, n * 4)
)
for n in [0, 2, 3, 1, 2]
]
D.distribute(
elements="all", direction="x", spacing=100, separation=False, edge="x"
)  # edge must be either 'xmin' (left), 'xmax' (right), or 'x' (center)
D

[23]:

Unnamed_0bab2d93: uid 759, ports [], aliases [], 0 polygons, 5 references

### Align¶

The align() function allows you to elements within a Device horizontally or vertically. It is meant to duplicate the alignment functionality present in Inkscape / Adobe Illustrator:

Say we distribute() a few objects, but they’re all misaligned:

[24]:

D = gf.Component()
# Create different-sized rectangles and add them to D then distribute them
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move((n, n * 4))
for n in [0, 2, 3, 1, 2]
]
D.distribute(elements="all", direction="x", spacing=5, separation=True)
D

[24]:

Unnamed_8177db20: uid 764, ports [], aliases [], 0 polygons, 5 references

we can use the align() function to align their top edges (alignment = ‘ymax’):

[25]:

D = gf.Component()
# Create different-sized rectangles and add them to D then distribute them
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move((n, n * 4))
for n in [0, 2, 3, 1, 2]
]
D.distribute(elements="all", direction="x", spacing=5, separation=True)

# Align top edges
D.align(elements="all", alignment="ymax")
D

[25]:

Unnamed_643b8374: uid 769, ports [], aliases [], 0 polygons, 5 references

or align their centers (alignment = ‘y’):

[26]:

D = gf.Component()
# Create different-sized rectangles and add them to D then distribute them
[
D.add_ref(gf.components.rectangle(size=[n * 15 + 20, n * 15 + 20])).move((n, n * 4))
for n in [0, 2, 3, 1, 2]
]
D.distribute(elements="all", direction="x", spacing=5, separation=True)

# Align top edges
D.align(elements="all", alignment="y")
D

[26]:

Unnamed_7e69e759: uid 774, ports [], aliases [], 0 polygons, 5 references

other valid alignment options include 'xmin', 'x', 'xmax', 'ymin', 'y', and 'ymax'

## Boolean / outline / offset / invert¶

There are several common boolean-type operations available in the geometry library. These include typical boolean operations (and/or/not/xor), offsetting (expanding/shrinking polygons), outlining, and inverting.

### Boolean¶

The gf.boolean() function can perform AND/OR/NOT/XOR operations, and will return a new geometry with the result of that operation.

Speedup note: The num_divisions argument can be used to divide up the geometry into multiple rectangular regions and process each region sequentially (which is more computationally efficient). If you have a large geometry that takes a long time to process, try using num_divisions = [10,10] to optimize the operation.

[27]:

E = gf.components.ellipse(radii=(10, 5), layer=(1, 0))
R = gf.components.rectangle(size=[15, 5], layer=(2, 0))
C = gf.boolean(A=E, B=R, operation="not", precision=1e-6, num_divisions=[1, 1], layer=0)
# Other operations include 'and', 'or', 'xor', or equivalently 'A-B', 'B-A', 'A+B'

# Plot the originals and the result
D = gf.Component()
D

[27]:

Unnamed_b69c32f6: uid 783, ports [], aliases [], 0 polygons, 3 references

### Offset¶

The gf.offset() function takes the polygons of the input geometry, combines them together, and expands/contracts them. The function returns polygons on a single layer – it does not respect layers.

Speedup note: The num_divisions argument can be used to divide up the geometry into multiple rectangular regions and process each region sequentially (which is more computationally efficient). If you have a large geometry that takes a long time to process, try using num_divisions = [10,10] to optimize the operation.

[28]:

import gdsfactory as gf

# Create T, an ellipse and rectangle which will be offset (expanded / contracted)
T = gf.Component("ellipse_and_rectangle")
e = T << gf.components.ellipse(radii=(10, 5), layer=(1, 0))
r = T << gf.components.rectangle(size=[15, 5], layer=(2, 0))
r.move([3, -2.5])

Texpanded = gf.offset(
T, distance=2, join_first=True, precision=1e-6, num_divisions=[1, 1], layer=(0, 0)
)
Texpanded.name = "expanded"
Tshrink = gf.offset(
T,
distance=-1.5,
join_first=True,
precision=1e-6,
num_divisions=[1, 1],
layer=(0, 0),
)
Tshrink.name = "shrink"

# Plot the original geometry, the expanded, and the shrunk versions
D = gf.Component("top")
D.distribute([t1, t2, t3], direction="x", spacing=5)
D

[28]:

top: uid 789, ports [], aliases [], 0 polygons, 3 references

### Outline¶

The gf.components.outline() function takes the polygons of the input geometry then performs an offset and “not” boolean operation to create an outline. The function returns polygons on a single layer – it does not respect layers.

Speedup note: The num_divisions argument can be used to divide up the geometry into multiple rectangular regions and process each region sequentially (which is more computationally efficient). If you have a large geometry that takes a long time to process, try using num_divisions = [10,10] to optimize the operation.

[29]:

import phidl.geometry as pg

# Create a blank device and add two shapes
X = gf.Component()

O = pg.outline(X, distance=1.5, precision=1e-6, layer=(0, 0))

# Plot the original geometry and the result
D = gf.Component()
D

[29]:

Unnamed_0c45b6a9: uid 798, ports [], aliases [], 0 polygons, 2 references

The open_ports argument opens holes in the outlined geometry at each Port location.

• If not False, holes will be cut in the outline such that the Ports are not covered.

• If True, the holes will have the same width as the Ports.

• If a float, the holes will be widened by that value.

• If a float equal to the outline distance, the outline will be flush with the port (useful positive-tone processes).

[30]:

D = gf.components.L(width=7, size=(10, 20), layer=(1, 0))
D

[30]:

L_layer1_0_size10_20_width7: uid 799, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references
[31]:

# Outline the geometry and open a hole at each port
N = pg.outline(D, distance=5, open_ports=False)  # No holes
gf.plot(N)

[32]:

O = pg.outline(D, distance=5, open_ports=True)  # Hole is the same width as the port
gf.plot(O)

[33]:

P = pg.outline(
D, distance=5, open_ports=2.9
)  # Change the hole size by entering a float
gf.plot(P)

[34]:

Q = pg.outline(
D, distance=5, open_ports=5
)  # Creates flush opening (open_ports > distance)
gf.plot(Q)


### Invert¶

The pg.invert() function creates an inverted version of the input geometry. The function creates a rectangle around the geometry (with extra padding of distance border), then subtract all polygons from all layers from that rectangle, resulting in an inverted version of the geometry.

Speedup note: The num_divisions argument can be used to divide up the geometry into multiple rectangular regions and process each region sequentially (which is more computationally efficient). If you have a large geometry that takes a long time to process, try using num_divisions = [10,10] to optimize the operation.

[35]:

import phidl.geometry as pg

D = pg.invert(E, border=0.5, precision=1e-6, layer=(0, 0))
gf.plot(D)


### Union¶

The pg.union() function is a “join” function, and is functionally identical to the “OR” operation of gf.boolean(). The one difference is it’s able to perform this function layer-wise, so each layer can be individually combined.

[36]:

import gdsfactory as gf
import phidl.geometry as pg

D = gf.Component()
e0 = D << gf.components.ellipse(layer=(0, 0))
e1 = D << gf.components.ellipse(layer=(0, 0))
e2 = D << gf.components.ellipse(layer=(0, 0))
e3 = D << gf.components.ellipse(layer=(0, 0))
e4 = D << gf.components.ellipse(layer=(0, 0))
e5 = D << gf.components.ellipse(layer=(0, 0))

e1.rotate(15 * 1)
e2.rotate(15 * 2)
e3.rotate(15 * 3)
e4.rotate(15 * 4)
e5.rotate(15 * 5)

D

[36]:

Unnamed_b74b9086: uid 832, ports [], aliases [], 0 polygons, 6 references
[37]:

# We have two options to unioning - take all polygons, regardless of
# layer, and join them together (in this case on layer (0,0) like so:
D_joined = pg.union(D, by_layer=False, layer=(0, 0))
gf.plot(D_joined)

[38]:

# Or we can perform the union operate by-layer
D_joined_by_layer = pg.union(D, by_layer=True)
gf.plot(D_joined_by_layer)


### XOR / diff¶

The pg.xor_diff() function can be used to compare two geometries and identify where they are different. Specifically, it performs a layer-wise XOR operation. If two geometries are identical, the result will be an empty Device. If they are not identical, any areas not shared by the two geometries will remain.

[39]:

import phidl.geometry as pg

A = gf.Component()

B = gf.Component()
X = pg.xor_diff(A=A, B=B, precision=1e-6)

# Plot the original geometry and the result
# Upper left: A / Upper right: B
# Lower left: A and B / Lower right: A xor B "diff" comparison
D = gf.Component()
D

[39]:

Unnamed_402e7977: uid 845, ports [], aliases [], 0 polygons, 5 references

## Lithography structures¶

### Step-resolution¶

The gf.components.litho_steps() function creates lithographic test structure that is useful for measuring resolution of photoresist or electron-beam resists. It provides both positive-tone and negative-tone resolution tests.

[40]:

D = gf.components.litho_steps(
line_widths=[1, 2, 4, 8, 16], line_spacing=10, height=100, layer=(1, 0)
)
D

[40]:

litho_steps_height100_l_4f03783f: uid 846, ports [], aliases [], 0 polygons, 12 references

### Calipers (inter-layer alignment)¶

The gf.components.litho_calipers() function is used to detect offsets in multilayer fabrication. It creates a two sets of notches on different layers. When an fabrication error/offset occurs, it is easy to detect how much the offset is because both center-notches are no longer aligned.

[41]:

D = gf.components.litho_calipers(
notch_size=[1, 5],
notch_spacing=2,
num_notches=7,
offset_per_notch=0.1,
row_spacing=0,
layer1=(1, 0),
layer2=(2, 0),
)
D

[41]:

litho_calipers_layer11__460508bd: uid 855, ports [], aliases [], 0 polygons, 32 references

## Paths / straights¶

See the Path tutorial for more details – this is just an enumeration of the available built-in Path functions

### Circular arc¶

[42]:

P = gf.path.arc(radius=10, angle=135, npoints=720)
gf.plot(P)


### Straight¶

[43]:

import gdsfactory as gf

P = gf.path.straight(length=5, npoints=100)
gf.plot(P)


### Euler curve¶

Also known as a straight-to-bend, clothoid, racetrack, or track transition, this Path tapers adiabatically from straight to curved. Often used to minimize losses in photonic straights. If p < 1.0, will create a “partial euler” curve as described in Vogelbacher et. al. https://dx.doi.org/10.1364/oe.27.031394. If the use_eff argument is false, radius corresponds to minimum radius of curvature of the bend. If use_eff is true, radius corresponds to the “effective” radius of the bend– The curve will be scaled such that the endpoints match an arc with parameters radius and angle.

[44]:

P = gf.path.euler(radius=3, angle=90, p=1.0, use_eff=False, npoints=720)
gf.plot(P)

[45]:

P

[45]:

<phidl.device_layout.Path at 0x7fefd18c5190>


### Smooth path from waypoints¶

[46]:

import numpy as np
import gdsfactory as gf

points = np.array([(20, 10), (40, 10), (20, 40), (50, 40), (50, 20), (70, 20)])

P = gf.path.smooth(
points=points,
bend_path_function=gf.path.euler,
use_eff=False,
)
gf.plot(P)


### Delay spiral¶

[47]:

gf.components.spiral()

[47]:

spiral: uid 859, ports ['o2', 'o1'], aliases [], 242 polygons, 0 references

## Importing GDS files¶

gf.import_gds() allows you to easily import external GDSII files. It imports a single cell from the external GDS file and converts it into a gdsfactory component.

[48]:

D = gf.components.ellipse()
D.write_gds("myoutput.gds")
D = gf.import_gds(gdspath="myoutput.gds", cellname=None, flatten=False)
D

[48]:

ellipse: uid 861, ports [], aliases [], 1 polygons, 0 references

## LayerSet¶

The LayerSet class allows you to predefine a collection of layers and specify their properties including: gds layer/datatype, name, and color. It also comes with a handy preview function called gf.layers.preview_layerset()

[49]:

import gdsfactory as gf

lys = gf.layers.LayerSet()
D = gf.layers.preview_layerset(lys, size=100, spacing=100)
D

[49]:

layerset: uid 862, ports [], aliases [], 0 polygons, 12 references

## Useful contact pads / connectors¶

These functions are common shapes with ports, often used to make contact pads

[50]:

D = gf.components.compass(size=(4, 2), layer=(1, 0))
D

[50]:

compass_layer1_0_size4_2: uid 887, ports ['e1', 'e2', 'e3', 'e4'], aliases [], 0 polygons, 1 references
[51]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.compass_multi(size=(4, 2), ports={"N": 3, "S": 4}, layer=(1, 0))
plot(D)  # quickplot the geometry

[52]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.flagpole(
size=(50, 25), stub_size=(4, 8), shape="p", taper_type="fillet", layer=(1, 0)
)
# taper_type should be None, 'fillet', or 'straight'

plot(D)  # quickplot the geometry

[53]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.straight(size=(4, 2), layer=(1, 0))
plot(D)  # quickplot the geometry

[54]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.connector(midpoint=(0, 0), width=1, orientation=0)
plot(D)  # quickplot the geometry

[55]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.tee(size=(8, 4), stub_size=(1, 2), taper_type="fillet", layer=(1, 0))
# taper_type should be None, 'fillet', or 'straight'
plot(D)


## Chip / die template¶

[56]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.basic_die(
size=(10000, 5000),  # Size of die
street_width=100,  # Width of corner marks for die-sawing
street_length=1000,  # Length of corner marks for die-sawing
die_name="chip99",  # Label text
text_size=500,  # Label text size
text_location="SW",  # Label text compass location e.g. 'S', 'SE', 'SW'
layer=0,
draw_bbox=False,
bbox_layer=99,
)
plot(D)  # quickplot the geometry


## Optimal superconducting curves¶

The following structures are meant to reduce “current crowding” in superconducting thin-film structures (such as superconducting nanowires). They are the result of conformal mapping equations derived in Clem, J. & Berggren, K. “Geometry-dependent critical currents in superconducting nanocircuits.” Phys. Rev. B 84, 1–27 (2011).

[57]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.optimal_hairpin(
width=0.2, pitch=0.6, length=10, turn_ratio=4, num_pts=50, layer=0
)
plot(D)  # quickplot the geometry

[58]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.optimal_step(
start_width=10,
end_width=22,
num_pts=50,
width_tol=1e-3,
anticrowding_factor=1.2,
symmetric=False,
layer=0,
)
plot(D)  # quickplot the geometry

[59]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.optimal_90deg(width=100.0, num_pts=15, length_adjust=1, layer=0)
plot(D)  # quickplot the geometry

[60]:

import phidl.geometry as pg
from phidl import quickplot as plot

D = pg.snspd(
wire_width=0.2,
wire_pitch=0.6,
size=(10, 8),
num_squares=None,
turn_ratio=4,
terminals_same_side=False,
layer=0,
)
plot(D)  # quickplot the geometry

[61]:

D = pg.snspd_expanded(
wire_width=0.3,
wire_pitch=0.6,
size=(10, 8),
num_squares=None,
connector_width=1,
connector_symmetric=False,
turn_ratio=4,
terminals_same_side=False,
layer=0,
)
plot(D)  # quickplot the geometry


## Copying and extracting geometry¶

[62]:

E = gf.Component()
# X = gf.components.ellipse(layer = {0,1})
D = pg.extract(E, layers=[(1, 0)])
plot(D)  # quickplot the geometry

[63]:

import gdsfactory as gf

X = gf.components.ellipse(layer=(2, 0))
c = X.copy()
c

[63]:

ellipse_layer2_0: uid 919, ports [], aliases [], 1 polygons, 0 references
[ ]:



[ ]: