Пример #1
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')
a.bbox.tolist() == [[0.0, 0.0], [216.0, 104.0]]
qp(D)

#==============================================================================
# Adding premade geometry with phidl.geometry
#==============================================================================
# Usually at the beginning of a phidl file we import the phidl.geometry module
# as ``pg``, like this:
import phidl.geometry as pg

# The ``pg`` module contains dozens of premade shapes and structures, ranging
# from simple ones like ellipses to complex photonic structures.  Let's create
# a few simple structures and plot them
D = Device()
G1 = pg.ellipse(radii=(10, 5), angle_resolution=2.5, layer=1)
G2 = pg.snspd(wire_width=0.2, wire_pitch=0.6, size=(10, 8), layer=2)
G3 = pg.rectangle(size=(10, 5), layer=3)
g1 = D.add_ref(G1)
g2 = D.add_ref(G2)
g3 = D.add_ref(G3)
g1.xmin = g2.xmax + 5
g3.xmin = g1.xmax + 5
qp(D)

# There are dozens of these types of structures.  See the /phidl/geometry.py
# file for a full geometry list.  Note some of the more complex shapes are
# experimental and may change with time.

# Let's save this file so we can practice importing it in the next step
D.write_gds('MyNewGDS.gds')
Пример #3
0
def do_something_interesting():
    x_section = Device()

    def insert_wx(layname, width, x):
        # insert a rectangle with a given width and center x. Height doesn't matter.
        shape = x_section << pg.rectangle((width, 2), layer=lys[layname])
        shape.x = x
        shape.y = 50
        return shape

    def insert(layname, xmin, xmax):
        # insert a rectangle spanning these x coordinates
        shape = x_section << pg.rectangle((xmax - xmin, 2), layer=lys[layname])
        shape.xmin = xmin
        shape.y = 50
        return shape

    # LED
    ppdopant_x = .65
    outer_wgx = ppdopant_x + .17
    insert_wx('wg_deep', 2 * outer_wgx, 0)
    insert('wg_shallow', .15, outer_wgx)
    insert('wg_shallow', -outer_wgx, -.15)
    insert_wx('dp_e', .1, 0)
    insert('dp_n', .05, outer_wgx)
    insert('dp_p', -outer_wgx, -.05)
    insert_wx('dp_n+', .3, ppdopant_x)
    insert_wx('dp_p+', .3, -ppdopant_x)
    for side in [-1, 1]:
        insert_wx('m4_ledpad', .28, side * ppdopant_x)
        insert_wx('v3', .25, side * ppdopant_x)
        insert_wx('m5_wiring', .3, side * ppdopant_x)
        insert_wx('m5_wiring', .6, side * (ppdopant_x + .3))
        insert_wx('v5', side * .4, side * (ppdopant_x + .4))

    # WG
    wg = insert_wx('wg_deep', .2, 2)

    # SNSPD
    nw = insert_wx('m2_nw', .3, wg.xmax + 1)
    pad = insert('m1_nwpad', nw.xmax - .1, nw.xmax + .4)
    via = insert('v3', pad.xmax - .3, pad.xmax - .1)
    wire = insert('m5_wiring', pad.x, pad.x + 1)
    insert_wx('v5', .3, wire.xmax - .2)

    # htron
    snspd = x_section << pg.snspd(
        wire_width=0.05, wire_pitch=0.3, size=(2, 2), layer=lys['m2_nw'])
    snspd.rotate(90)
    snspd.y = wire.y
    snspd.xmin = wire.xmax + 1
    heater = x_section << pg.rectangle((2.4, 2), layer=lys['m3_res'])
    heater.xmin = snspd.xmin
    heater.y = snspd.y
    pad = insert('m1_nwpad', snspd.xmin - .5, snspd.xmin + .02)
    via = insert('v5', pad.xmin, pad.xmax - .2)
    wire = insert_wx('m5_wiring', .4, via.x)
    insert_wx('v3', .3, wire.x - .05)
    # pad = insert('m1_nwpad', heater.xmax - .2, heater.xmax-.05)
    via = insert('v5', heater.xmax - .2, heater.xmax - .05)
    wire = insert_wx('m5_wiring', .4, via.x)
    insert_wx('v3', .3, wire.x - .05)

    # resistor
    res = insert_wx('m3_res', 2, wire.xmax + 1.5)
    via1 = insert('v5', res.xmin + .1, res.xmin + .5)
    wire1 = insert_wx('m5_wiring', .5, via1.x)
    insert_wx('v3', .4, wire1.x)
    via2 = insert('v5', res.xmax - .5, res.xmax - .1)
    wire2 = insert_wx('m5_wiring', .5, via2.x)
    insert_wx('v3', .4, wire2.x)
    insert('wg_deep', wire1.xmin - .1, wire2.xmax + .1)

    return x_section
Пример #4
0
create_image(D, 'optimal_step')

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

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

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

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)
qp(D) # quickplot the geometry
create_image(D, 'snspd')

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

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)
qp(D) # quickplot the geometry
create_image(D, 'snspd_expanded')

Пример #5
0
            port=Port(
                name=p.name,
                midpoint=p.midpoint,
                width=p.width,
                orientation=p.orientation,
                parent=p.parent,
            )
        )
    for poly in device.polygons:
        component.add_polygon(poly)
    for label in device.labels:
        component.add_label(
            text=label.text,
            position=label.position,
            layer=(label.layer, label.texttype),
        )
    return component


if __name__ == "__main__":
    import phidl.geometry as pg

    import gdsfactory as gf

    c = pg.rectangle()
    c = pg.snspd()

    c2 = from_phidl(component=c)
    print(c2.ports)
    gf.show(c2)
Пример #6
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