def chip(size=(13000, 18000),
         keepout=2000,
         name='chip01',
         text_size=250,
         layer_text=10,
         layer=99):
    k = keepout
    DX = size[0]
    DY = size[1]
    OUT = pg.rectangle(size=size, layer=layer)
    IN = pg.rectangle(size=(DX - 2 * k, DY - 2 * k), layer=layer)
    IN.move((k, k))

    CHIP = pg.boolean(A=OUT, B=IN, operation='A-B', layer=layer)

    #Add name
    L = pg.text(text=name, size=text_size, layer=1, justify='center')
    CHIP.add_ref(L).move((DX / 2, k - text_size - 200))

    #Add markers
    M = global_markers()
    offset = 110
    CHIP.add_ref(M).move([k - offset, k - offset])
    CHIP.add_ref(M).move([DX - k + offset - 3000, k - offset])
    CHIP.add_ref(M).move([k - offset, DY - k + offset])
    CHIP.add_ref(M).move([DX - k + offset - 3000, DY - k + offset])

    return CHIP
def eom_sym(wg_width, length, middle_e_width, e_e_gap, chip_width, offset,
            radius):
    euler_y = mod_euler(radius=radius, angle=-45)[1][1]
    euler_x = mod_euler(radius=radius, angle=-45)[1][0]
    wg_wg_sep = (middle_e_width + e_e_gap) / 2 - 2 * euler_y
    straight = wg_wg_sep * np.sqrt(2)
    if wg_wg_sep < 0:
        raise Exception(
            "middle_e_width is set too small with respect to Euler radius")

    left = chip_width / 2 - length / 2 - 2 * euler_x - wg_wg_sep + offset
    right = left

    P1 = Path()
    P1.append(pp.straight(length=left))
    P1.append(mod_euler(radius=radius, angle=-45)[0])
    P1.append(pp.straight(length=straight))
    P1.append(mod_euler(radius=radius, angle=45)[0])
    P1.append(pp.straight(length=length))
    P1.append(mod_euler(radius=radius, angle=45)[0])
    P1.append(pp.straight(length=straight))
    P1.append(mod_euler(radius=radius, angle=-45)[0])
    P1.append(pp.straight(length=right))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=1)
    waveguide_device1 = P1.extrude(X)

    E = Device('EOM_GHz')
    b1 = E.add_ref(waveguide_device1)
    b2 = E.add_ref(waveguide_device1)
    b2.mirror((0, 0), (1, 0))

    square = middle_e_width * 0.6
    square_rec_offset = (middle_e_width - square) / 2
    e_left = left + 2 * euler_x + wg_wg_sep
    e_right = left + 2 * euler_x + wg_wg_sep + length - square

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=10)
    S = pg.rectangle(size=(square, square), layer=2)

    #top electrode
    h_top = middle_e_width / 2 + e_e_gap
    E.add_ref(R).move([e_left, h_top])
    E.add_ref(S).move([e_left, h_top + square_rec_offset])
    E.add_ref(S).move([e_right, h_top + square_rec_offset])

    #middle electrode
    E.add_ref(R).move([e_left, -middle_e_width / 2])
    E.add_ref(S).move([e_left, -square / 2])
    E.add_ref(S).move([e_right, -square / 2])

    #bottom electrode
    h_bot = -3 * middle_e_width / 2 - e_e_gap
    E.add_ref(R).move([e_left, h_bot])
    E.add_ref(S).move([e_left, h_bot + square_rec_offset])
    E.add_ref(S).move([e_right, h_bot + square_rec_offset])
    #E << R
    return E
Beispiel #3
0
def test_align():
    D = Device()
    # Create different-sized rectangles and add them to D then distribute them
    [
        D.add_ref(
            pg.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')
    h = D.hash_geometry(precision=1e-4)
    assert (h == '38025959a80e46e47eabcf3f096c6273427dabc3')

    D = Device()
    # Create different-sized rectangles and add them to D then distribute them
    [
        D.add_ref(
            pg.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')
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'ed32ee1ce1f3da8f6216020877d6c1b64097c600')
Beispiel #4
0
def test_distribute():
    D = Device()
    # Create different-sized rectangles and add them to D
    [
        D.add_ref(
            pg.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)

    h = D.hash_geometry(precision=1e-4)
    assert (h == '1aa688d7dfb59e94d28dd0d9b8f324ff30281d70')

    D = Device()
    [
        D.add_ref(
            pg.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')
    h = D.hash_geometry(precision=1e-4)
    assert (h == '18be0ef1db78095233d2f3ae5f065d9f453a6c07')
def poling_region(length=4000,
                  period=5,
                  dutycycle=0.4,
                  gap=25,
                  Lfinger=50,
                  layer=10,
                  pad_width=50):

    #Calculations
    Wfinger = period * dutycycle
    Nfinger = int(length / period) + 1
    length = Nfinger * period - (1 - dutycycle) * period

    P = Device('Poling Electrodes')

    #Positive side
    R = pg.rectangle([length, pad_width], layer=layer)
    F = pg.rectangle([Wfinger, Lfinger], layer=layer)
    P << R
    a = P.add_array(F, columns=Nfinger, rows=1, spacing=(period, 0))
    a.move([0, pad_width])

    #Negative side
    R2 = pg.rectangle([length, pad_width], layer=layer)
    r2 = P.add_ref(R2)
    r2.move([0, pad_width + Lfinger + gap])

    return P
Beispiel #6
0
def give_loopmirror(gap=.5):
    # just an example of augmenting a normal phidl device (loop_mirror_terminator)
    # giving it as a phidl Device as well as port, bounding box, and source things used by MEEP
    D = Device('loopmirror')

    cell = D << pg.rectangle([31, 15], layer=lys['FLOORPLAN'])
    cell.center = (0, 0)

    access = D << pg.compass([8, .35], layer=lys['wg_deep'])
    access.y = cell.y
    access.xmin = cell.xmin

    mmi = mmi1x2(gap_mmi=.5)
    loop = D << loop_mirror_terminator(y_splitter=mmi)
    loop.connect('wg_in_1', access.ports['E'])

    medium_map = get_layer_mapping(lys)

    port = D << pg.rectangle([.1, 1], layer=1)
    source = D << pg.rectangle([.1, 1], layer=2)
    port.y = 0
    source.y = 0
    port.x = loop.xmin - 6
    source.x = loop.xmin - 7

    D.flatten()
    return D
def dcpm(L, elec_w, e_e_gap, via, wg_width):
    P = Path()
    P.append(pp.straight(length=L))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)
    DCPM = Device()
    DCPM << P.extrude(X)
    R1 = pg.rectangle(size=(L, elec_w), layer=40)
    R2 = pg.rectangle(size=(L, elec_w), layer=40)
    DCPM << R1.move([0, e_e_gap / 2])
    DCPM << R2.move([0, -elec_w - e_e_gap / 2])
    return DCPM
def dcimthin(wg_width, off_chip, W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi, length,
             radius, x_pos, y_pos, middle_e_width, e_e_gap):

    if e_e_gap == 9:
        angle = 12.5196846104787
    elif e_e_gap == 7:
        angle = 11.83919343835311
    elif e_e_gap == 11:
        angle = 13.165741242693

    # Parameters
    mmi_length = L_tp * 2 + L_mmi
    side_electrode_width = middle_e_width * 2

    eulerX = mod_euler(radius=radius, angle=angle)[1][0]
    racetrack_length = eulerX * 4 + length
    #mzi_length = racetrack_length + mmi_length*2
    side = x_pos
    #side = (chip_width - mzi_length)/2

    # Devices
    M = mzi(length, radius, angle, wg_width, Y_mmi)

    mmiL = mmi(W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi)
    mmiR = mmi(W, L_tp, W_tp, L_mmi, W_mmi, Y_mmi)
    mmiR.mirror().move([mmi_length, 0])

    E = Device('EOM')
    #E << pg.rectangle(size=(side+off_chip,wg_width), layer=1).move([-off_chip,y_pos-wg_width/2])
    E << mmiL.move([side, y_pos])
    E << M.move([side + mmi_length, y_pos])
    E << mmiR.move([side + mmi_length + racetrack_length, y_pos])
    #E << pg.rectangle(size=(side+off_chip,wg_width), layer=1).move([side+mzi_length,y_pos-wg_width/2])

    e_left = side + mmi_length + 2 * eulerX

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=40)
    R2 = pg.rectangle(size=(length, side_electrode_width), layer=40)

    #top electrode
    h_top = middle_e_width / 2 + e_e_gap + y_pos
    E.add_ref(R2).move([e_left, h_top])

    #middle electrode
    E.add_ref(R).move([e_left, y_pos - middle_e_width / 2])

    #bottom electrode
    h_bot = -middle_e_width / 2 - side_electrode_width - e_e_gap + y_pos
    E.add_ref(R2).move([e_left, h_bot])
    return E, e_left
def global_markers(layer_marker=10, layer_mask=20):
    D = Device('Global Markers')
    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    #Add marker cover
    cover = pg.bbox(bbox=a.bbox, layer=layer_mask)
    D << pg.offset(cover, distance=100, layer=layer_mask)
    return D
def dcim(im_gap, im_length, coupler_l, im_r, im_angle, elec_w, e_e_gap, via,
         wg_width, V_Groove_Spacing):
    P = Path()
    euler_y = mod_euler(radius=im_r, angle=im_angle)[1][1]
    euler_x = mod_euler(radius=im_r, angle=im_angle)[1][0]
    l_bend = ((V_Groove_Spacing - im_gap - 4 * euler_y - wg_width) /
              2) / np.sin(np.pi * im_angle / 180)
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.straight(length=l_bend))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=coupler_l))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.straight(length=im_length))
    P.append(pp.euler(radius=im_r, angle=-im_angle))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=coupler_l))
    P.append(pp.euler(radius=im_r, angle=im_angle))
    P.append(pp.straight(length=l_bend))
    P.append(pp.euler(radius=im_r, angle=-im_angle))

    P.movey(V_Groove_Spacing)
    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)

    IM = Device('IM')
    IM << P.extrude(X)
    IM << P.extrude(X).mirror(p1=[1, V_Groove_Spacing / 2],
                              p2=[2, V_Groove_Spacing / 2])
    R1 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R2 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R3 = pg.rectangle(size=(im_length, elec_w), layer=40)
    R4 = pg.rectangle(size=(im_length, elec_w), layer=40)

    movex = euler_x * 4 + coupler_l + l_bend * np.cos(np.pi * im_angle / 180)
    movey = euler_y * 2 + im_gap / 2 + wg_width
    IM << R1.move(
        [movex, V_Groove_Spacing / 2 + movey + e_e_gap / 2 - wg_width / 2])
    IM << R2.move([
        movex,
        V_Groove_Spacing / 2 + movey - e_e_gap / 2 - elec_w - wg_width / 2
    ])
    IM << R3.move(
        [movex, V_Groove_Spacing / 2 - movey + e_e_gap / 2 + wg_width / 2])
    IM << R4.move([
        movex,
        V_Groove_Spacing / 2 - movey - e_e_gap / 2 - elec_w + wg_width / 2
    ])
    return IM, movex
Beispiel #11
0
    def _draw_unit_cell(self):

        o = self.origin

        rect=pg.rectangle(size=(self.coverage*self.pitch,self.length),\
            layer=self.layer)

        rect.move(origin=(0, 0), destination=o.coord)

        unitcell = Device()

        r1 = unitcell << rect

        unitcell.absorb(r1)

        rect_partialetch=pg.rectangle(\
            size=(\
                (1-self.coverage)*self.pitch,self.length-self.y_offset),\
            layer=LayoutDefault.layerPartialEtch)

        rect_partialetch.move(origin=o.coord,\
            destination=(self.pitch*self.coverage,self.y_offset))

        rp1 = unitcell << rect_partialetch

        rp2 = unitcell << rect_partialetch

        rp2.move(destination=(self.pitch, 0))

        r2 = unitcell << rect

        r2.move(origin=o.coord,\
        destination=(o+Point(self.pitch,self.y_offset)).coord)

        r3 = unitcell << rect

        r3.move(origin=o.coord,\
            destination=(o+Point(2*self.pitch,0)).coord)

        unitcell.absorb(r2)

        unitcell.absorb(r3)

        unitcell.name = "UnitCell"

        del rect, rect_partialetch

        return unitcell
Beispiel #12
0
    def __init__(self, params):

        SividdleDevice.__init__(self, name=params['name'])

        # Generate binary bitmap out of image
        bitmap = image_to_binary_bitmap(params['image'], params['threshold'],
                                        params['dither'])
        x_image = bitmap.shape[0]
        y_image = bitmap.shape[1]

        if params['image_device'] is None:
            # Define pixel polygon
            pixel = pg.rectangle(size=(params['pixel_size'],
                                       params['pixel_size']),
                                 layer=params['layer'])
        else:
            pixel = params['image_device']

        for x in range(x_image):
            for y in range(y_image):
                if bitmap[x, y] == 1:
                    reference = self.add_ref(pixel)
                    reference.move([x * pixel.xsize, y * pixel.ysize])

        # Shift center of bounding box to origin.
        self.center = [0, 0]
Beispiel #13
0
def test_packer():
    np.random.seed(5)
    D_list = [
        pg.ellipse(radii=np.random.rand(2) * n +
                   2).move(np.random.rand(2) * 100 + 2) for n in range(50)
    ]
    D_list += [
        pg.rectangle(size=np.random.rand(2) * n +
                     2).move(np.random.rand(2) * 1000 + 2) for n in range(50)
    ]

    D_packed_list = pg.packer(
        D_list,  # Must be a list or tuple of Devices
        spacing=1.25,  # Minimum distance between adjacent shapes
        aspect_ratio=(1, 2),  # Shape of the box
        max_size=(
            None,
            None),  # Limits the size into which the shapes will be packed
        density=1.5,
        sort_by_area=True,  # Pre-sorts the shapes by area
        verbose=False,
    )
    # The function will return a list of packed Devices.  If not all the Devices
    # in D_list can fit in the area `max_size`, it will fill up the first box to
    # capacity then create another, repeating until all the shapes are packed
    # into boxes of max_size.  (`max_size` can be (None, None))
    # of `max_size` as is necessary
    D = D_packed_list[0]
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'd90e43693a5840bdc21eae85f56fdaa57fdb88b2')
Beispiel #14
0
    def _draw_unit_cell(self):

        o = self.origin

        rect=pg.rectangle(size=(self.coverage*self.pitch,self.length),\
            layer=self.layer)

        rect.move(origin=(0, 0), destination=o.coord)

        unitcell = Device()

        r1 = unitcell << rect

        unitcell.absorb(r1)

        r2 = unitcell << rect

        r2.move(origin=o.coord,\
        destination=(o+Point(self.pitch,self.y_offset)).coord)

        r3 = unitcell << rect

        r3.move(origin=o.coord,\
            destination=(o+Point(2*self.pitch,0)).coord)

        unitcell.absorb(r2)

        unitcell.absorb(r3)

        unitcell.name = "UnitCell"

        del rect

        return unitcell
Beispiel #15
0
def add_passivation(cell, margin, scale, layer):

    rect = pg.rectangle(size=(cell.xsize * scale.x, cell.ysize * scale.y))

    margin_rect = pg.rectangle(size=(margin.x * cell.xsize,
                                     margin.y * cell.ysize))

    rect.move(origin=rect.center, destination=cell.center)

    margin_rect.move(origin=margin_rect.center, destination=cell.center)

    pa = pg.boolean(rect, margin_rect, operation='xor')

    for l in layer:

        cell.add_polygon(pa.get_polygons(), layer=(l, 0))
Beispiel #16
0
    def __init__(self, params):

        SividdleDevice.__init__(self, name='etchslab')

        # retrieve parameters
        self.id_string = params['id_string']
        self.expose_layer = params['expose_layer']
        self.label_layer = params['label_layer']
        self.length_slab = params['length_slab']
        self.width_slit = params['width_slit']
        self.width_slab = params['width_slab']

        slit = pg.rectangle(size=(self.width_slit, self.length_slab),
                            layer=self.expose_layer).rotate(90)

        self << pg.copy(slit).movey((self.width_slit + self.width_slab) * 0.5)
        self << pg.copy(slit).movey(-(self.width_slit + self.width_slab) * 0.5)
        self.add_label(text='{} \n slab_width = {:.2f} \
                \n slit_width = {:.2f} \
                \n slab_length = {:.2f}'.format(self.id_string,
                                                self.width_slab,
                                                self.width_slit,
                                                self.length_slab),
                       position=(self.xmin, self.ymax),
                       layer=self.label_layer)

        # Shift center of bounding box to origin.
        self.center = [0, 0]
Beispiel #17
0
    def draw(self):

        if self.shape == 'square':

            cell=pg.rectangle(size=(self.size,self.size),\
                layer=self.layer)

        elif self.shape == 'circle':

            cell=pg.circle(radius=self.size/2,\
            layer=self.layer)

        else:

            raise ValueError("Via shape can be \'square\' or \'circle\'")

        cell.move(origin=(0,0),\
            destination=self.origin.coord)

        cell.add_port(Port(name='conn',\
        midpoint=cell.center,\
        width=cell.xmax-cell.xmin,\
        orientation=90))

        return cell
Beispiel #18
0
    def draw(self):
        ''' Generates layout cell based on current parameters.

        'conn' port is included in the cell.

        Returns
        -------
        cell : phidl.Device.
        '''
        o = self.origin

        pad=pg.rectangle(size=self.size.coord,\
        layer=self.layer).move(origin=(0,0),\
        destination=o.coord)

        cell = Device(self.name)

        r1 = cell << pad
        cell.absorb(r1)
        r2 = cell << pad

        r2.move(origin=o.coord,\
        destination=(o+self.distance).coord)

        cell.absorb(r2)

        cell.add_port(name='conn',\
        midpoint=(o+Point(self.size.x/2,self.size.y)).coord,\
        width=self.size.x,\
        orientation=90)

        del pad

        return cell
Beispiel #19
0
        def _draw_padded_via(self):

            viaref=DeviceReference(self.via.draw())

            size=float(self.via.size*self.over_via)

            port=viaref.ports['conn']

            trace=pg.rectangle(size=(size,size),layer=self.pad_layers[0])

            trace.move(origin=trace.center,\
                destination=viaref.center)

            trace2=pg.copy_layer(trace,layer=self.pad_layers[0],new_layer=self.pad_layers[1])

            cell=Device(self.name)

            cell.absorb(cell<<trace)

            cell.absorb(cell<<trace2)

            cell.add(viaref)

            port.midpoint=(port.midpoint[0],cell.ymax)

            port.width=size

            cell.add_port(port)

            if bottom_conn==False:

                cell.remove_layers(layers=[self.pad_layers[1]])

            return cell
def via_test(x_pos, l_testpad, h_testpad, via, chip_width, chip_height):
    offset = 10
    D = Device('via test')
    D << pg.rectangle(size=(l_testpad, h_testpad), layer=10).move(
        [x_pos - l_testpad / 2, chip_height / 2 - h_testpad / 2])
    D << pg.rectangle(size=(via, via), layer=2).move(
        [x_pos - l_testpad / 2, chip_height / 2 - via / 2])
    D << pg.rectangle(size=(via, via), layer=2).move(
        [x_pos + l_testpad / 2 - via, chip_height / 2 - via / 2])
    D << pg.rectangle(size=(l_testpad, h_testpad), layer=3).move([
        x_pos - l_testpad / 2 + via - l_testpad + offset,
        chip_height / 2 - h_testpad / 2
    ])
    D << pg.rectangle(size=(l_testpad, h_testpad), layer=3).move([
        x_pos + l_testpad / 2 - via - offset, chip_height / 2 - h_testpad / 2
    ])
    return D
def bonding_pads(margin, pad, chip_width, chip_height):
    num = 18
    sep = (chip_width - 2 * margin) / num
    P = pg.rectangle(size=(pad, pad), layer=3).move([margin, margin])
    P << pg.rectangle(size=(pad, pad), layer=3).move(
        [margin, chip_height - margin - pad])
    for i in range(1, int(num / 2)):
        P << pg.rectangle(size=(pad, pad), layer=3).move(
            [margin + i * sep, margin])
        P << pg.rectangle(size=(pad, pad), layer=3).move(
            [margin + i * sep, chip_height - margin - pad])

    E = Device('bonding_pads')
    b1 = E.add_ref(P)
    b2 = E.add_ref(P)
    b2.mirror((chip_width / 2, chip_height), (chip_width / 2, 0))

    return E, sep
def contact_pads(size=(150, 150), label='', label_size=50, layer=10):
    # P = Device('Pad')
    R = pg.rectangle(size, layer)
    if label != '':
        L = pg.text(label, label_size, layer=layer)
        L.move([10, 10])
        P = pg.boolean(A=R, B=L, operation='A-B', layer=layer)
    else:
        P = R
    return P
def triplet_pad(x, y, pad, pad_g, elec_m, elec, elec_s, e_e_gap, pos):
    R = pg.rectangle(size=(pad, pad), layer=70)

    D = Device()
    rect1 = D << R
    rect2 = D << R
    rect3 = D << R
    rect1.move([x, y])
    rect2.move([x - pad_g, y])
    rect3.move([x + pad_g, y])

    #middle connector pad
    xm1 = x - elec_m / 2
    xm2 = x - pad / 2
    xm3 = x + pad / 2
    xm4 = x + elec_m / 2
    xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2)
    ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec)
    if pos == 'u':
        ypts = (y - elec, y, y, y - elec)
    D.add_polygon([xpts, ypts], layer=70)

    text_size = 20
    L = pg.text(text='S', size=text_size, layer=97, justify='center')
    D.add_ref(L).move((x + pad / 3, y))

    #left connector pad
    xm1 = x - elec_m / 2 - e_e_gap - elec_s
    xm2 = x - pad / 2 - pad_g
    xm3 = x + pad / 2 - pad_g
    xm4 = x - elec_m / 2 - e_e_gap
    xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2)
    ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec)
    if pos == 'u':
        ypts = (y - elec, y, y, y - elec)
    D.add_polygon([xpts, ypts], layer=70)

    L = pg.text(text='G', size=text_size, layer=97, justify='center')
    D.add_ref(L).move((x - pad_g + +pad / 3, y))

    #left connector pad
    xm1 = x + elec_m / 2 + e_e_gap
    xm2 = x + pad / 2 + pad_g - pad
    xm3 = x + pad / 2 + pad_g
    xm4 = x + elec_m / 2 + e_e_gap + elec_s
    xpts = (xm1 + pad / 2, xm2 + pad / 2, xm3 + pad / 2, xm4 + pad / 2)
    ypts = (y + pad + elec, y + elec, y + elec, y + pad + elec)
    if pos == 'u':
        ypts = (y - elec, y, y, y - elec)
    D.add_polygon([xpts, ypts], layer=70)

    L = pg.text(text='G', size=text_size, layer=97, justify='center')
    D.add_ref(L).move((x + pad_g + +pad / 3, y))

    return D
def wb_pad(x, y, pad, name):
    R = pg.rectangle(size=(pad, pad - 0.5), layer=70)

    D = Device()
    rect1 = D << R
    rect1.move([x, y])

    text_size = 20
    L = pg.text(text=name, size=text_size, layer=97, justify='center')
    D.add_ref(L).move((x + pad / 3, y))

    return D
Beispiel #25
0
def test_write_and_import_gds():
    D = Device()
    D.add_ref(pg.rectangle(size=[1.5, 2.7], layer=[3, 2]))
    D.add_ref(pg.rectangle(size=[0.8, 2.5], layer=[9, 7]))
    D.add_array(pg.rectangle(size=[1, 2], layer=[4, 66]),
                rows=3,
                columns=2,
                spacing=[14, 7.5])
    D.add_array(pg.rectangle(size=[1.5, 2.5], layer=[4, 67]),
                rows=1,
                columns=2,
                spacing=[14, 7.5])
    D.add_polygon([[3, 4, 5], [6.7, 8.9, 10.15]], layer=[7, 8])
    D.add_polygon([[3, 4, 5], [1.7, 8.9, 10.15]], layer=[7, 9])
    precision = 1e-4
    unit = 1e-6
    h1 = D.hash_geometry(precision=precision)
    D.write_gds('temp.gds', precision=unit * precision, unit=1e-6)
    Dimport = pg.import_gds('temp.gds', flatten=False)
    h2 = Dimport.hash_geometry(precision=precision)
    assert (h1 == h2)
Beispiel #26
0
    def __init__(self, params):
        SividdleDevice.__init__(self, name='aligment_mark')

        interim_alignment_mark = SividdleDevice('interim_alignment_mark')

        # Add four squares defining the alignment mark
        interim_alignment_mark << pg.rectangle(
            size=(params['d_large'], params['d_large']), layer=params['layer'])

        interim_alignment_mark << pg.rectangle(
            size=(params['d_small'], params['d_small']),
            layer=params['layer']).movex(params['d_large'] + params['sep'])

        interim_alignment_mark << pg.rectangle(
            size=(params['d_small'], params['d_small']),
            layer=params['layer']).movey(params['d_large'] + params['sep'])

        interim_alignment_mark << pg.rectangle(
            size=(params['d_large'], params['d_large']),
            layer=params['layer']).move([
                params['d_small'] + params['sep'],
                params['d_small'] + params['sep']
            ])

        # Add interim device to self, invert if choosen.
        if params['invert']:
            self << interim_alignment_mark.invert(params['layer'])
        else:
            self << interim_alignment_mark

        # Add bounding box

        # Make exposure box.
        if params['exposure_box']:
            exposure_box_width = self.xsize \
                + 2 * params['exposure_box_dx']
            exposure_box = pg.rectangle(size=(exposure_box_width,
                                              exposure_box_width),
                                        layer=params['exposure_box_layer'])
            self << exposure_box.move((
                self.xsize * 0.5 - exposure_box.xsize * 0.5,
                self.ysize * 0.5 - exposure_box.ysize * 0.5,
            ))

            # Center device
            # Shift center of bounding box to origin
            self.center = [0, 0]

            # Add dot at alignment point
            if params['make_dot']:
                dot = pg.rectangle(size=(params['dot_size'],
                                         params['dot_size']),
                                   layer=params['dot_layer'])
                dot.move(
                    (-params['dot_size'] * 0.5, -params['dot_size'] * 0.5))

                self << dot
Beispiel #27
0
    def draw(self):

        name = self.name

        o = self.origin

        pad_x = self.size.x

        if pad_x > self.pitch * 9 / 10:

            pad_x = self.pitch * 9 / 10

            warnings.warn("Pad size too large, capped to pitch*9/10")

        pad_cell=pg.rectangle(size=(pad_x,self.size.y),\
        layer=self.layer)

        pad_cell.move(origin=(0,0),\
        destination=o.coord)

        cell = Device(self.name)

        dp = Point(self.pitch, 0)
        pad_gnd_sx = cell << pad_cell
        pad_sig = cell << pad_cell
        pad_sig.move(origin=o.coord,\
        destination=(o+dp).coord)

        pad_gnd_dx = cell << pad_cell
        pad_gnd_dx.move(origin=o.coord,\
        destination=(o+dp*2).coord)

        cell.add_port(Port(name='sig',\
        midpoint=(o+Point(pad_x/2+self.pitch,self.size.y)).coord,\
        width=pad_x,\
        orientation=90))

        cell.add_port(Port(name='gnd_left',\
        midpoint=(o+Point(pad_x/2,self.size.y)).coord,\
        width=pad_x,\
        orientation=90))

        cell.add_port(Port(name='gnd_right',\
        midpoint=(o+Point(pad_x/2+2*self.pitch,self.size.y)).coord,\
        width=pad_x,\
        orientation=90))

        return cell
def rfpm(wg_width, length, middle_e_width, e_e_gap):

    side_electrode_width = middle_e_width * 2

    P = Path()
    P.append(pp.straight(length=length))

    X = CrossSection()
    X.add(width=wg_width, offset=0, layer=30)
    RFPM = Device()
    RFPM << P.extrude(X)
    Rt = pg.rectangle(size=(length, side_electrode_width), layer=40)
    Rm = pg.rectangle(size=(length, middle_e_width), layer=40)
    Rb = pg.rectangle(size=(length, side_electrode_width), layer=40)
    RFPM << Rt.move([0, e_e_gap / 2])
    RFPM << Rm.move([0, -middle_e_width - e_e_gap / 2])
    RFPM << Rb.move(
        [0, -middle_e_width - side_electrode_width - e_e_gap - e_e_gap / 2])

    square = middle_e_width * 0.9
    side_height = side_electrode_width * 0.9
    square_rec_offset = (side_electrode_width - side_height) / 2
    square_rec_offset_m = (middle_e_width - square) / 2
    e_left = 0
    e_right = e_left + length - square

    #side_e_width
    R = pg.rectangle(size=(length, middle_e_width), layer=40)
    R2 = pg.rectangle(size=(length, side_electrode_width), layer=40)
    S = pg.rectangle(size=(square, square), layer=50)
    S2 = pg.rectangle(size=(square, side_height), layer=50)

    #top electrode
    h_top = e_e_gap / 2
    RFPM.add_ref(S2).move([e_left, h_top + square_rec_offset])
    RFPM.add_ref(S2).move([e_right, h_top + square_rec_offset])

    #middle electrode
    h_mid = -middle_e_width - e_e_gap / 2
    RFPM.add_ref(S).move([e_left, h_mid + square_rec_offset_m])
    RFPM.add_ref(S).move([e_right, h_mid + square_rec_offset_m])

    #bottom electrode
    h_bot = -middle_e_width - side_electrode_width - e_e_gap - e_e_gap / 2
    RFPM.add_ref(S2).move([e_left, h_bot + square_rec_offset])
    RFPM.add_ref(S2).move([e_right, h_bot + square_rec_offset])

    return RFPM
Beispiel #29
0
def test_group():
    # Test all types
    D = Device()
    E1 = pg.ellipse(radii=(10, 5), angle_resolution=2.5, layer=0)
    E2 = pg.rectangle(size=(4, 2), layer=0).movex(15)
    e1 = D << E1
    e2 = D << E2
    e3 = D << E2
    e4 = D.add_label('hello', position=(1.5, -1.5))
    e5 = pg.snspd()
    e6 = D.add_polygon([(8, 6, 7, 9, 7, 0), (6, 8, 9, 5, 7, 0)])
    e7 = D.add_array(pg.cross())
    e2verify = D << E2

    # Test creation and addition
    G = Group()
    G.add(e1)
    G.add(e2)
    G.add([e3, e4, e5])
    G += (e6, e7)
    assert np.allclose(G.bbox.flatten(), np.array([-10., -8.5, 105., 105.]))

    # Test movement
    G.move((2, 7))
    e2verify.move((2, 7))
    assert np.allclose(G.bbox.flatten(), np.array([-8., -1.5, 107., 112.]))
    assert all(e2.center == e2verify.center)
    assert e2.rotation == e2verify.rotation

    # Test rotation
    G.rotate(90, center=(5, 5))
    e2verify.rotate(90, center=(5, 5))
    assert np.allclose(G.bbox.flatten(), np.array([-102., -8., 11.5, 107.]))
    assert all(e2.center == e2verify.center)
    assert e2.rotation == e2verify.rotation

    # Test mirroring
    G.mirror(p1=(1, 1), p2=(-1, 1))
    e2verify.mirror(p1=(1, 1), p2=(-1, 1))
    assert np.allclose(G.bbox.flatten(), np.array([-102., -105., 11.5, 10.]))
    assert all(e2.center == e2verify.center)
    assert e2.rotation == e2verify.rotation
    h = D.hash_geometry(precision=1e-4)
    assert (h == '3964acb3971771c6e70ceb587c2ae8b37f2ed112')
Beispiel #30
0
def test_pack():
    import phidl.geometry as pg

    D_list = [pg.ellipse(radii=np.random.rand(2) * n + 2) for n in range(2)]
    D_list += [pg.rectangle(size=np.random.rand(2) * n + 2) for n in range(2)]

    D_packed_list = pack(
        D_list,  # Must be a list or tuple of Components
        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
    )
    c = D_packed_list[0]  # Only one bin was created, so we plot that
    # print(len(c.get_dependencies()))
    assert len(c.get_dependencies()) == 4