예제 #1
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
예제 #2
0
def phidl_port_translation():
    # Conversion between object and geometric representation of ports
    try:
        pg.with_geometric_ports
    except AttributeError:
        pass  # skipping

    def geom_equal(A, B):
        h1 = A.hash_geometry(precision=1e-4)
        h2 = B.hash_geometry(precision=1e-4)
        return h1 == h2

    init_D = pg.compass(layer=1)
    geom_D = pg.with_geometric_ports(init_D, layer=2)
    end_D = pg.with_object_ports(geom_D, layer=2)
    assert geom_equal(init_D, end_D)

    assert len(geom_D.ports) == 0
    geom_D.remove_layers([2], include_labels=True)
    assert geom_equal(init_D, geom_D)

    assert geom_equal(init_D, end_D)
    for pnam, port in init_D.ports.items():
        assert np.all(end_D.ports[pnam].midpoint == port.midpoint)

    # now through the filesystem
    end2_D = anyCell_to_anyCell(init_D, Device())
    for pnam, port in init_D.ports.items():
        assert np.all(end_D.ports[pnam].midpoint == port.midpoint)
    assert geom_equal(init_D, end2_D)
    assert init_D.name == end2.name
예제 #3
0
        def draw(self):

            oldprobe=probe.draw(self)

            cell=pg.deepcopy(oldprobe)

            groundpad=pg.compass(
                layer=self.ground_layer,
                size=(self.ground_size,self.ground_size))

            r=st.get_corners(groundpad)

            for alias in cell.aliases:

                if 'GroundLX' in alias:

                    dest=cell[alias].ports['N'].endpoints[1]

                    for portname in cell.ports:

                        if alias in portname:

                            cell.remove(cell.ports[portname])

                    cell.remove(cell[alias])

                    groundref=cell.add_ref(groundpad,alias=alias)

                    groundref.move(origin=r.ur.coord,
                    destination=dest)

                    ppt.copy_ports(groundref,cell,prefix="GroundLX")

                if 'GroundRX' in alias:

                    dest=cell[alias].ports['N'].endpoints[0]

                    for portname in cell.ports:

                        if alias in portname:

                            cell.remove(cell.ports[portname])

                    cell.remove(cell[alias])

                    groundref=cell.add_ref(groundpad,alias=alias)

                    groundref.move(
                        origin=r.ul.coord,
                        destination=dest)

                    for portname in cell[alias].ports:

                        cell.remove(cell[alias].ports[portname])

                    ppt.copy_ports(groundref,cell,prefix="GroundRX")

            return cell
예제 #4
0
def htron(nanowire_width = 0.15, nanowire_spacing = 0.1,
          meander_num_squares = 5000, heater_num_squares = 1):

    # Create blank device
    D = Device(name = 'htron')

    # Basic calculations
    extra_meander_width = 2
    extra_meander_height = 1
    area_per_meander_sq = (nanowire_width+nanowire_spacing)*nanowire_width
    meander_area = area_per_meander_sq*meander_num_squares
    meander_total_width = np.sqrt(meander_area/heater_num_squares)
    meander_total_height = heater_num_squares*meander_total_width
    meander_size = np.array([meander_total_width, meander_total_height])
    heater_size = meander_size

    meander_size = meander_size + [extra_meander_width,extra_meander_height]

    # meander_size = heater_size + np.array([meander_extra_width,0])
    meander_pitch = nanowire_width + nanowire_spacing
    # heater_standoff_y = 1

    # Create components
    Meander = pg.snspd_expanded(wire_width = nanowire_width, wire_pitch = meander_pitch, size = meander_size,
               terminals_same_side = False, connector_width = nanowire_width*4, layer = lys['m2_nw'])
    # heater_size_actual = heater_size + np.array([0, heater_standoff_y])
    Heater = pg.compass(size = heater_size, layer = lys['m3_res'])

    # Add references to components
    m = D.add_ref(Meander)
    h = D.add_ref(Heater)
    h.center = m.center


    # Record meta-information
    heater_area = heater_size[0]*heater_size[1]
    D.info['nanowire_width'] = nanowire_width
    D.info['nanowire_pitch'] = nanowire_width + nanowire_spacing
    D.info['meander_num_squares'] = np.round(m.info['num_squares'],2)
    D.info['meander_size'] = np.round((m.xsize, m.ysize),2).tolist()
    D.info['heater_size'] = np.round(heater_size,2).tolist()
    D.info['heater_area'] = np.round(heater_size[0]*heater_size[1],2)
    D.info['heater_num_squares'] = np.round(heater_num_squares,2)
    D.info['overlap_area'] = np.round(m.ysize*heater_size[0],1)
    D.info['overlap_num_squares'] = np.round(heater_area/area_per_meander_sq,1)

    D.add_port(name = 1, port = h.ports['N'])
    D.add_port(name = 2, port = h.ports['S'])
    D.add_port(name = 3, port = m.ports[1])
    D.add_port(name = 4, port = m.ports[2])

    return D
예제 #5
0
    def draw(self):

        r1=pg.compass(size=(self.port.width,self.distance),\
            layer=self.layer)

        north_port = r1.ports['N']
        south_port = r1.ports['S']

        r2=pg.compass(size=(self.size,self.size),\
            layer=self.layer)

        sq_ref = r1 << r2

        sq_ref.connect(r2.ports['S'], destination=north_port)

        r1.absorb(sq_ref)
        r1 = join(r1)
        r1.add_port(port=south_port, name='conn')

        del r2

        return r1
예제 #6
0
def test_port_geometry():
    # Conversion between object and geometric representation of ports
    def geom_equal(A, B):
        h1 = A.hash_geometry(precision = 1e-4)
        h2 = B.hash_geometry(precision = 1e-4)
        return h1 == h2
    init_D = pg.compass(layer = 1)
    geom_D = pg.with_geometric_ports(init_D, layer = 2)
    end_D = pg.with_object_ports(geom_D, layer = 2)
    assert geom_equal(init_D, end_D)

    assert len(geom_D.ports) == 0
    geom_D.remove_layers([2], include_labels = True)
    assert geom_equal(init_D, geom_D)

    for pnam, port in init_D.ports.items():
        assert np.all(end_D.ports[pnam].midpoint == port.midpoint)
예제 #7
0
        def draw(self):

            cell=Device(name=self.name)

            super_ref=cell.add_ref(cls.draw(self))

            nvias_x,nvias_y=self.n_vias

            unit_cell=self._draw_padded_via()

            viacell=join(CellArray(unit_cell,\
                columns=nvias_x,rows=nvias_y,\
                spacing=(unit_cell.xsize,unit_cell.ysize)))

            viacell.add_port(Port(name='conn',\
                midpoint=(viacell.x,viacell.ymax),\
                width=viacell.xsize,\
                orientation=90))

            for sides in side:

                for p_name in super_ref.ports.keys():

                    if re.search(sides,p_name):

                        p=super_ref.ports[p_name]

                        pad=pg.compass(size=(p.width,self.via_distance),layer=self.pad_layers[0])

                        if sides=='top':

                            self._attach_instance(cell, pad, pad.ports['S'], viacell,p)

                        if sides=='bottom':

                            self._attach_instance(cell, pad, pad.ports['N'], viacell,p)

            for p_name,p_value in super_ref.ports.items():

                cell.add_port(p_value)

            return cell
예제 #8
0
def add_compass(device: Device) -> Device:
    ''' add four ports at the bbox of a cell.

    Parameters
    ----------
    device : phidl.Device

    Returns
    -------
    device : phidl.Device.
    '''

    bound_cell=pg.compass(size=device.size).move(\
    origin=(0,0),destination=device.center)

    ports = port = bound_cell.get_ports()

    device.add_port(port=ports[0], name='N')
    device.add_port(port=ports[1], name='S')
    device.add_port(port=ports[2], name='E')
    device.add_port(port=ports[3], name='W')

    return device
예제 #9
0
        def draw(self):

            cell=pt.Device(name=self.name)

            oldprobe=cell<<probe.draw(self)

            cell.absorb(oldprobe)

            groundpad=pg.compass(size=(self.ground_size,self.ground_size),\
            layer=self.layer)

            [_,_,ul,ur]=get_corners(groundpad)

            for name,p in oldprobe.ports.items():

                name=p.name

                if 'gnd' in name:

                    groundref=cell<<groundpad

                    if 'left' in name:

                        groundref.move(origin=ur.coord,\
                        destination=p.endpoints[1])

                        left_port=groundref.ports['N']

                    elif 'right' in name:

                        groundref.move(origin=ul.coord,\
                        destination=p.endpoints[0])

                        right_port=groundref.ports['N']

                    cell.absorb(groundref)

                else :

                    cell.add_port(p)

            for name,port in oldprobe.ports.items():

                if 'gnd' in name:

                    if 'left' in name:

                        if self.pad_position=='side':

                            left_port=Port(name=name,\
                                midpoint=(left_port.midpoint[0]+self.ground_size/2,\
                                left_port.midpoint[1]-self.ground_size/2),\
                                orientation=180,\
                                width=self.ground_size)

                        elif self.pad_position=='top':

                            left_port=Port(name=name,\
                                midpoint=(left_port.midpoint[0],\
                                left_port.midpoint[1]),\
                                orientation=90,\
                                width=self.ground_size)

                        else :

                            raise ValueError(f"New pad position is {self.pad_position} : not acceptable")

                        cell.add_port(left_port)

                    elif 'right' in name:

                        if self.pad_position=='side':

                            right_port=Port(name=name,\
                            midpoint=(right_port.midpoint[0]-self.ground_size/2,\
                                right_port.midpoint[1]-self.ground_size/2),\
                            orientation=0,\
                            width=self.ground_size)

                        elif self.pad_position=='top':

                            right_port=Port(name=name,\
                            midpoint=(right_port.midpoint[0],\
                                right_port.midpoint[1]),\
                            orientation=90,\
                            width=self.ground_size)

                        else :

                            raise ValueError(f"New pad position is {self.pad_position} : not acceptable")

                        cell.add_port(right_port)

            return cell
예제 #10
0
create_image(D, 'preview_layerset')
phidl.reset()

# example-connector
import phidl.geometry as pg
from phidl import quickplot as qp

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

# example-compass
import phidl.geometry as pg
from phidl import quickplot as qp

D = pg.compass(size = (4,2), layer = 0)
qp(D) # quickplot the geometry
create_image(D, 'compass')

# example-compass_multi
import phidl.geometry as pg
from phidl import quickplot as qp

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

# example-flagpole
import phidl.geometry as pg
from phidl import quickplot as qp
예제 #11
0
def wg_to_snspd(wgnw_width=0.1,
                wgnw_length=100,
                wgnw_gap=0.15,
                num_squares=5000.0,
                meander_width=0.4,
                meander_fill_factor=0.5,
                wg_width=0.75):
    ''' Waveguide coupled to SNSPD with inductor (meander).
        The length and width of the meander are chosen so that it is approximately square

        Args:
            meander_width (float): nanowire width within meander inductor
            num_squares (float): total squares in meander and out-and-back
            wgnw_width (float): width of out-and-back nanowire
            wgnw_length (float): length of out-and-back
            wgnw_gap (float): spacing between the out-and-back wires
            wg_width (float): waveguide width

        Ports:
            el_1: wiring port
            el_gnd: wiring port
            wg_in: input optical port
            de_edge: edge of explicit waveguide on the SNSPD side
    '''

    D = Device('wg_to_snspd')

    # Calculations and checks
    numsquares_wgnw = 2 * wgnw_length / wgnw_width
    numsquares_meander = num_squares - numsquares_wgnw
    if numsquares_meander < 1000:
        print(
            'Warning: Not enough squares in SNSPD meander. Clipped to 1000 from {:.1f}'
            .format(numsquares_meander))
        numsquares_meander = 1000
    meander_pitch = meander_width / meander_fill_factor
    meander_length = np.sqrt(numsquares_meander * meander_width *
                             meander_pitch)
    wgnw_pitch = wgnw_width + wgnw_gap
    wgnw_distance_to_edge = wg_width / 2 - wgnw_width - wgnw_gap / 2
    if wgnw_distance_to_edge < 0:
        print('Warning: nanowire will overhang side of waveguide by {:.3f} um'.
              format(-wgnw_distance_to_edge))

    numsquares_per_taper = 3  # approximate
    D.info[
        'num_squares'] = numsquares_meander + numsquares_wgnw - meander_length / meander_width + 3 * numsquares_per_taper
    # D.info['expected_resistance'] = D.info['num_squares']*EXPECTED_RSQ_WSI
    D.info['wire_width'] = wgnw_width
    D.info['length'] = wgnw_length

    # Geometry
    meander = D << pg.snspd(wire_width=meander_width,
                            wire_pitch=meander_pitch,
                            terminals_same_side=False,
                            size=(meander_length, None),
                            num_squares=numsquares_meander,
                            layer=lys['m2_nw'])
    meander.reflect(p1=(0, 0), p2=(1, 0))

    Taper = pg.optimal_step(start_width=wgnw_width,
                            end_width=meander_width,
                            num_pts=50,
                            width_tol=1e-3,
                            anticrowding_factor=1.2,
                            layer=lys['m2_nw'])
    taper1 = D << Taper
    taper1.connect(2, meander.ports[1])

    wgnw = D << pg.optimal_hairpin(width=wgnw_width,
                                   pitch=wgnw_pitch,
                                   length=wgnw_length,
                                   layer=lys['m2_nw'])
    wgnw.connect(2, taper1.ports[1])

    taper2 = D << Taper
    taper2.reflect()
    taper2.connect(1, wgnw.ports[1])

    # Electrical ports
    exit_bend = D << pg.optimal_90deg(
        width=meander_width, num_pts=15, length_adjust=1, layer=lys['m2_nw'])
    exit_bend.connect(port=2, destination=taper2.ports[2])
    D.add_port('el_gnd', port=exit_bend.ports[1])

    exit_taper = D << pg.optimal_step(start_width=meander_width,
                                      end_width=meander_width * 4,
                                      num_pts=50,
                                      width_tol=1e-3,
                                      anticrowding_factor=1.2,
                                      layer=lys['m2_nw'])
    exit_taper.connect(1, meander.ports[2])
    D.add_port('el_1', port=exit_taper.ports[2])

    # Waveguide and optical ports
    wg = D << pg.compass(size=[wgnw_length + wgnw_distance_to_edge, wg_width],
                         layer=lys['wg_deep'])
    wg.xmax = wgnw.xmax
    wg.y = wgnw.y

    D.add_port('de_edge', port=wg.ports['E'])
    D.add_port('wg_in', port=wg.ports['W'])
    D.ports['de_edge'].info['is_waveguide_edge'] = True

    pos = D.ports['wg_in'].midpoint
    D.move(-1 * pos)

    return D
예제 #12
0
def connect_ports(
    cell : Device,
    tag : str ='top',
    layer : int= ld.layerTop,
    distance : float = 10.0,
    metal_width: float = None):
    ''' connects all the ports in the cell with name matching a tag.

    Parameters:
    -----------
        cell : Device

        tag: str

        conn_dist: pt.Point
            offset from port location

        layer : tuple.


    Returns:
    ----------

        cell : Device
            contains routings and connection port

    '''

    import pirel.pcells as pc

    ports=ppt.find_ports(cell,tag,depth=0)

    ports.sort(key=lambda x: x.midpoint[0])

    ports_centroid=st.get_centroid_ports(*ports)

    if len(ports)==1:

        raise ValueError("pm.connect_ports() : len(ports) must be >1 ")

    if metal_width is None:

        metal_width=ports_centroid.width

    port_mid_norm=pt.Point(ports_centroid.normal[1])-pt.Point(ports_centroid.normal[0])

    midpoint_projected=Point(ports_centroid.midpoint)+port_mid_norm*(distance+metal_width)

    pad_side=ports_centroid.width

    new_port=Port(
        name=tag,
        orientation=ports_centroid.orientation,
        width=ports_centroid.width,
        midpoint=midpoint_projected.coord)

    output_cell=Device()

    for p in ports:

        straight_conn=output_cell<<pg.compass(
            layer=layer,size=(p.width,abs(midpoint_projected.y-p.midpoint[1])))

        straight_conn.connect("S",p)

    cross_conn=output_cell<<pg.compass(
        layer=layer,size=(output_cell.xsize,metal_width))

    cross_conn.connect('S',new_port,overlap=metal_width)

    output=st.join(output_cell)

    output.add_port(new_port)

    return output