def mzi(length=1000, sep=50):
    with nd.Cell(hashme=True) as mziBB:
        eopm = eopm_dc(length=length, pads=True, sep=40)
        mmi_left  = mmi2x2_dp().put('lc')
        deep.sbend(offset=sep).put(mmi_left.pin['b0'])
        eopm_top = eopm.put()
        deep.sbend(offset=-sep).put()
        mmi_right = mmi2x2_dp().put()

        deep.sbend(offset=-sep).put(mmi_left.pin['b1'])
        eopm_bot = eopm.put(flip=True)
        deep.sbend(offset=sep).put()

        nd.Pin('a0', pin=mmi_left.pin['a0']).put()
        nd.Pin('a1', pin=mmi_left.pin['a1']).put()
        nd.Pin('b0', pin=mmi_right.pin['b0']).put()
        nd.Pin('b1', pin=mmi_right.pin['b1']).put()
        nd.Pin('c0', pin=eopm_top.pin['c0']).put()
        nd.Pin('c1', pin=eopm_top.pin['c1']).put()
        nd.Pin('d0', pin=eopm_bot.pin['c0']).put()
        nd.Pin('d1', pin=eopm_bot.pin['c1']).put()
        pdk.put_stub()

        bb_length, y, a = nd.diff(mziBB.pin['a0'], mziBB.pin['b0'])
        pdk.put_boundingbox('org', length=abs(bb_length), width=2*sep+428)
    return mziBB
def abb_eopm_dc(length=750, contacts=2):
    """Create an electro-optic phase modulator cell.

    Args:
        length (float): length of the modulator section in um

    Returns:
        Cell: eopm element
    """
    width = 60
    with nd.Cell(hashme=True) as C:
        nd.Pin(name='a0', xs='Deep', width=wdeep).put(0, 0, 180)
        nd.Pin(name='b0', xs='Deep', width=wdeep).put(length, 0, 0)

        # x-positions of pads:
        L = 0.5*(length - wmetdc)
        xpos = []
        if contacts > 1:
            for n in range(contacts):
                xpos.append(0.5*wmetdc + L*2*n/(contacts-1))
        elif contacts == 1:
            xpos = [0.5*length]
        elif contacts == 0:
            pass
        for n, x in enumerate(xpos):
            pinname = 'c'+str(n)
            p1 = nd.Pin(name=pinname, xs='MetalDC', width=wmetdc).put(x, 0, 90)
            nd.put_stub(pinname)

        #nd.Pin(name='c0', xs='MetalDC', width=wmetdc).put(0.5*length, 5.0, 90)
        pdk.put_stub(['a0', 'b0', 'c0'])
        pdk.put_boundingbox('org', length, width, align='lc')
        icons.icon_strt(length, width, bufx=0, bufy=10, layer='MetalDCIcon').put('cc', 0, 'cc')
        icons.icon_strt(length, width, bufx=10, bufy=-8, layer='DeepIcon').put('cc', 0, 'cc')
    return C
def dbr_laser(Ldbr1=50, Ldbr2=500, Lsoa=750, Lpm=70):
    """Create a parametrized dbr laser building block."""
    Liso = 20
    with nd.Cell(hashme=True) as laser:
        #create an isolation cell for reuse
        iso = isolation_act(length=Liso)

        #draw the laser
        s2a1 = s2a().put(0)
        iso.put()
        dbr1 = dbr(length=Ldbr1).put()
        iso.put()
        soa1 = soa(length=Lsoa).put()
        iso.put()
        phase1 = phase_shifter(length=Lpm).put()
        iso.put()
        dbr2 = dbr(length=Ldbr2).put()
        iso.put()
        a2s1 = a2s().put()

        # add pins to the laser building block
        nd.Pin('a0', pin=s2a1.pin['a0']).put()
        nd.Pin('b0', pin=a2s1.pin['b0']).put()
        nd.Pin('c0', pin=dbr1.pin['c0']).put()
        nd.Pin('c1', pin=soa1.pin['c0']).put()
        nd.Pin('c2', pin=phase1.pin['c0']).put()
        nd.Pin('c3', pin=dbr2.pin['c0']).put()
        pdk.put_stub()

        length, y, a = nd.diff(laser.pin['a0'], laser.pin['b0'])
        pdk.put_boundingbox('org', length=abs(length), width=200, align='lb',
            move=(0, -30, 0))
    return laser
    def isolation(length=length):
        """Create a p-isolation cell.

        Args:
            length (float): length of the isolation section in um

        Returns:
            Cell: isolation element
        """
        bb_width = 20
        with nd.Cell(hashme=True) as C:
            nd.Pin(name='a0', xs=xs, width=width).put(0, 0, 180)
            nd.Pin(name='b0', xs=xs, width=width).put(length, 0, 0)
            pdk.put_stub()
            pdk.put_boundingbox('org', length, bb_width)
            icons.icon_strt(length, bb_width, bufx=4, bufy=-8, layer=layer).put('cc', 0, 'cc')
        return C
def phase_shifter(length=100):
    """Create a current injection phase shifting cell.

    Args:
        length (float): length of phase section in um

    Returns:
        Cell: phase-shifter element
    """
    width = 200
    h = -70
    with nd.Cell(hashme=True) as C:
        nd.Pin(name='a0', xs='Active', width=wact).put(0, h, 180)
        nd.Pin(name='b0', xs='Active', width=wact).put(length, h, 0)
        nd.Pin(name='c0', xs='MetalDC', width=wmetdc).put(0.5*length, 5.0, 90)
        pdk.put_stub(['a0', 'b0', 'c0'])
        pdk.put_boundingbox('org', length, width, align='lc')
        icons.icon_strt(length, width, bufx=0, bufy=10, layer='MetalDCIcon').put('cc', 0, 'cc')
        icons.icon_strt(length, width, bufx=10, bufy=-8, layer='ActiveIcon').put('cc', 0, h, 'cc')
    return C
def dbr(length=100, pitch=0.250, duty_cycle=0.5):
    """Create a DBR cell.

    Args:
        length (float): length of DBR section in um
        pitch (float): pitch (full period) of dbr in um
        duty_cycle (float): duty cycle of grating (default = 0.5)

    Returns:
        Cell: dbr element
    """
    width = 200
    h = -70
    icon = icons.Tp_icon_grating('ActiveIcon')
    with nd.Cell(hashme=True) as C:
        nd.Pin(name='a0', xs='Active', width=wact).put(0, h, 180)
        nd.Pin(name='b0', xs='Active', width=wact).put(length, h, 0)
        nd.Pin(name='c0', xs='MetalDC', width=wmetdc).put(0.5*length, 5.0, 90)
        pdk.put_stub(['a0', 'b0', 'c0'])
        pdk.put_boundingbox('org', length, width, align='lc')
        icons.icon_strt(length, width, bufx=0, bufy=10, layer='MetalDCIcon').put('cc', 0, 'cc')
        icons.icon_strt(length, width, bufx=10, bufy=-8, layer='ActiveIcon').put('cc', 0, h, 'cc')
        icon(length, width, bufx=5, bufy=-40).put('cc', 0, h, 'cc')
    return C
def soa(length=100, pad=True):
    """Create a SOA cell.

    Args:
        length (float): length of gain section in um

    Returns:
        Cell: SOA element
    """
    if pad:
        width = 200
    else:
        width = 50

    h = -70
    with nd.Cell(hashme=True) as C:
        nd.Pin(name='a0', xs='Active', width=wact).put(0, h, 180)
        nd.Pin(name='b0', xs='Active', width=wact).put(length, h, 0)
        nd.Pin(name='c0', xs='MetalDC', width=wmetdc).put(0.5*length, 5.0, 90)
        pdk.put_stub(['a0', 'b0', 'c0'])
        pdk.put_boundingbox('org', length, width, align='lc')
        icons.icon_strt(length, width, bufx=0, bufy=10, layer='MetalDCIcon').put('cc', 0, 'cc')
        icons.icon_strt(length, width, bufx=10, bufy=-8, layer='ActiveIcon').put('cc', 0, h, 'cc')
    return C
#==============================================================================
with nd.Cell('awg1x4') as awg1x4:

    awg = nd.load_gds(
        filename= os.path.join(dir_path, 'gdsBB', 'AWG_1x4.gds'),
        cellname='awg',
        newcellname='demo_awg',
        layermap={1:3})
    awg.put()

    nd.Pin('a0', xs='Deep', width=wdeep).put((9.184851e-016, -5, -90))
    nd.Pin('b0', xs='Deep', width=wdeep).put((273.63575, -4.5798919, -85.569401))
    nd.Pin('b1', xs='Deep', width=wdeep).put((269.89849, -4.9532407, -88.523134))
    nd.Pin('b2', xs='Deep', width=wdeep).put((266.1423, -4.9532407, -91.476866))
    nd.Pin('b3', xs='Deep', width=wdeep).put((262.40504, -4.5798919, -94.430599))
    pdk.put_stub(['a0', 'b0', 'b1', 'b2', 'b3'])

#BBfunctioncalls.append('awg1x4')

BBcells = [eval(F) for F in BBfunctioncalls]


#==============================================================================
# Create groups to provide a structure to put building blocks (BB) under.
# This is optional, though useful in navigation BBs.
#==============================================================================
bb_connectors     = pdk.Functional_group() #: inter-connectors
bb_transitions    = pdk.Functional_group() #: xsection transistions
bb_splitters      = pdk.Functional_group() #: power splitter and combiners
bb_combiners      = pdk.Functional_group() #: power splitter and combiners
bb_amplifiers     = pdk.Functional_group() #: SOAs