def compass(size=200, layer=1): """Show compass image to identify the sample direction. Args: size (double): size (wxh) of the bounding box. layer (int | str | tuple): layer (or list of layers) to draw in. Returns: cell containing the compass. """ s = size/182 quart = [(0,0), (s,0), (s,s), (16*s,16*s), (s/2,70*s), (-s/2,70*s), (-16*s,16*s), (-15*s,15*s), (-s,65*s), (0,65*s)] p = 75 * s h = 20 * s with nd.Cell("compass_"+nd.md5(layer)) as C: for lay in nd.make_iter(layer): nd.Polygon(layer=lay, points=quart).put(0,0,0) nd.Polygon(layer=lay, points=quart).put(0,0,90) nd.Polygon(layer=lay, points=quart).put(0,0,180) nd.Polygon(layer=lay, points=quart).put(0,0,270) nd.text('E', layer=lay, height=h, align='lc').put(p, 0) nd.text('N', layer=lay, height=h, align='cb').put(0, 71*s) nd.text('W', layer=lay, height=h, align='rc').put(-p, 0) nd.text('S', layer=lay, height=h, align='ct').put(0, -p) return C
def soa(length=100): """Parametrized SOA whitebox generation.""" angle = 70.0 width_active = 30.0 width = 2.0 name = 'wb_shallow.soa_{}'.format(length) with nd.Cell(name=name, instantiate=False) as C: bb = bbbb.soa(length=length).put(0, 0, 0) bb.raise_pins(namesin=['a0']) #active paral = geom.parallelogram2( length=length, height=width_active, angle=angle, position=2, shift=(0 + 0.5 * width_active / tan(radians(angle)), 0)) active = nd.Polygon(layer=50, points=paral).put(0, 0, 0) #pad rect = geom.rectangle(length=length, height=200, position=2, shift=(0, 30)) metal = nd.Polygon(layer=10, points=rect).put(0, 0, 0) #waveguide nd.strt(width=3, length=length, xs='wb_soa').put(0, 0, 0) return C
def xsection_transition(length, width, layer1, layer2): with nd.Cell('icon', instantiate=False) as icon: rect = geom.box(0.25 * length, 0.50 * width) nd.Polygon(points=rect, layer=layer1).put(0.25 * length) nd.Polygon(points=rect, layer=layer2).put(0.50 * length) nd.Pin('cc').put(0.5 * length) return icon
def getcell(self): with nd.Cell(name=self.name) as dha_cell: inpin = nd.Pin(name='a0').put(self.start[0], self.start[1], self.start[2]) nd.Pin(name='b0').put(self.end[0], self.end[1], self.end[2]) a, b = self.outline() if self.return_path == True: nd.Polygon(nd.util.polyline2polygon(xy=self.points, width=self.ww), layer=self.layer).put() nd.Polyline(width=self.owidth, points=a, layer=self.olayer).put(inpin.rotate(180)) nd.Polyline(width=self.owidth, points=b, layer=self.olayer).put(inpin.rotate(180)) else: nd.Polygon(nd.util.polyline2polygon(xy=self.points, width=self.ww), layer=self.layer).put() nd.Polygon(nd.util.polyline2polygon(xy=a, width=self.owidth), layer=self.olayer).put(inpin.rotate(180)) nd.Polygon(nd.util.polyline2polygon(xy=b, width=self.owidth), layer=self.olayer).put(inpin.rotate(180)) return dha_cell
def icon_gsg(pitch=100, height=None): """Create an icon with a gsg diode symbol. The icon scales with the pitch and the height. Args: pitch (float): pitch beteween ground and signal height (float): height of the icon Returns: Cell: diode gsg icon """ if height is None: height = 2 * pitch ratio = 0.3 w_line = 0.1 * ratio * height radius = 0.15 * ratio * height height = height - 2 * radius - 2 * w_line with nd.Cell('icon_gsg', instantiate=False) as icon: # define shapes outline = [(-0.5 * ratio * height, 0.5 * ratio * height), (0.5 * ratio * height, 0.5 * ratio * height), (0, -0.5 * ratio * height)] diode_triangle = nd.Polygon(points=outline, layer=layer) outline = geom.rectangle(ratio * height, w_line, position=5) diode_base = nd.Polygon(points=outline, layer=layer) outline = geom.ring(radius=radius, width=w_line, N=20) ring = nd.Polygon(points=outline, layer=layer) outline = geom.rectangle(w_line, height, position=5) pole = nd.Polygon(points=outline, layer=layer) outline = geom.rectangle(2 * pitch, w_line, position=5) gnd = nd.Polygon(points=outline, layer=layer) # put shapes gnd.put(0, -0.5 * (height - w_line)) diode_triangle.put(0) diode_base.put(0, -0.5 * ratio * (height - w_line)) pole.put(0) pole.put(pitch - 0.5 * w_line) pole.put(-pitch + 0.5 * w_line) ringpos = 0.5 * (height + radius + w_line) ring.put(0, ringpos) ring.put(pitch - 0.5 * w_line, ringpos) ring.put(-pitch + 0.5 * w_line, ringpos) # add pins nd.Pin('cc').put(0) nd.Pin('top').put(0, ringpos + radius + w_line, -90) return icon
def marker2(layera=1, layerb=None, layerc=None): """TU/e-Smart alignment marker 2. This is the second (marker2) of two matching markers. Args: layera (int | str | tuple): layer (or list of layers) in which marker pattern is written. Default 1. layerb (int | str | tuple): layer (or list of layers) in which the background is defined. Default None. layerc (int | str | tuple): layer (or list of layers) in which an extra box around the marker is drawn for visibility in dark field masks. Default None. Returns: function: function generating a cell with this specific marker. Example: Place marker centered at (0,0) in layer 5 with darkfield box:: import nazca as nd m2 = nd.marker2(layera=5, layerc=5) m2.put() nd.export_plt() """ with nd.Cell(name='marker2_'+nd.md5((layera,layerb,layerc))) as C: poly = (((-55,-75), (-55,-55), (-75,-55), (-75,55), (-55,55), (-55,75), (-5,75), (-5,55), (-40,55), (-40,40), (-55,40), (-55,30), (-40,30), (-40,15), (-30,15), (-30,30), (-15,30), (-15,40), (-30,40), (-30,55), (-5,55), (-5,-16), (-39,-16), (-39,-31), (-54,-31), (-54,-39), (-39,-39), (-39,-54), (-31,-54), (-31,-39), (-16,-39), (-16,-31), (-31,-31), (-31,-16), (-5,-16), (-5,-75),), ((30,15), (30,30), (15,30), (15,40), (30,40), (30,55), (40,55), (40,40), (55,40), (55,30), (40,30), (40,15),), ((31,-54), (31,-39), (16,-39), (16,-31), (31,-31), (31,-16), (39,-16), (39,-31), (54,-31), (54,-39), (39,-39), (39,-54),), ((55,-75), (55,-55), (75,-55), (75,-75),), ((55,55), (55,75), (75,75), (75,55),)) nd.Pin(name='a0', xs=None).put(0,0,180) nd.Pin(name='b0', xs=None).put(0,0,0) for p in poly: for lay in nd.make_iter(layera): nd.Polygon(layer=lay, points=p).put() for lay in nd.make_iter(layerb): nd.Polygon(layer=lay, points=geom.rectangle(180, 180, position=5)).put() for lay in nd.make_iter(layerc): nd.Polygon(layer=lay, points=geom.frame(60, 240,240)).put(-90,-90) return C
def marker1(layera=1, layerb=None): """TU/e-Smart alignment marker 1. This is the first (marker1) of two matching markers. Args: layera (int | str | tuple): layer (or list of layers) in which marker pattern is written. layerb (int | str | tuple): layer (or list of layers) in which the background is defined. Returns: function: marker cell. Example: Place marker centered at (0,0) in layer 1 with background layer 12:: import nazca as nd m1 = nd.marker1(layera=1, layerb=12) m1.put() nd.export_plt() """ with nd.Cell(name='marker1_'+nd.md5((layera,layerb))) as C: poly = (((-75,55), (-75,75), (75,75), (75,55), (65,55), (65,65), (-65,65), (-65,55),), ((-37.5,17.5), (-37.5,32.5), (-52.5,32.5), (-52.5,37.5), (-37.5,37.5), (-37.5,52.5), (-32.5,52.5), (-32.5,37.5), (-17.5,37.5), (-17.5,32.5), (-32.5,32.5), (-32.5,17.5),), ((32.5,17.5), (32.5,32.5), (17.5,32.5), (17.5,37.5), (32.5,37.5), (32.5,52.5), (37.5,52.5), (37.5,37.5), (52.5,37.5), (52.5,32.5), (37.5,32.5), (37.5,17.5),), ((-38.5,-53.5), (-38.5,-38.5), (-53.5,-38.5), (-53.5,-31.5), (-38.5,-31.5), (-38.5,-16.5), (-31.5,-16.5), (-31.5,-31.5), (-16.5,-31.5), (-16.5,-38.5), (-31.5,-38.5), (-31.5,-53.5),), ((31.5,-53.5), (31.5,-38.5), (16.5,-38.5), (16.5,-31.5), (31.5,-31.5), (31.5,-16.5), (38.5,-16.5), (38.5,-31.5), (53.5,-31.5), (53.5,-38.5), (38.5,-38.5), (38.5,-53.5),), ((-75,-75), (-75,-55), (-65,-55), (-65,-65), (65,-65), (65,-55), (75,-55), (75,-75),)) nd.Pin(name='a0', xs=None).put(0,0,180) nd.Pin(name='b0', xs=None).put(0,0,0) for p in poly: for lay in nd.make_iter(layera): nd.Polygon(layer=lay, points=p).put() for lay in nd.make_iter(layerb): nd.Polygon(layer=lay, points=geom.rectangle(180, 180, position=5)).put() return C
def nonius(layer=1): """Nonius structure""" with nd.Cell(name='nonius_'+nd.md5(layer)) as C: for lay in nd.make_iter(layer): l = [20, 20, 30, 20, 20, 20, 20, 30, 20, 20] for i in range(10): nd.Polygon(layer=lay, points= nd.geometries.rectangle(l[i], 5.9-0.2*i, position=2)).put( 0, -45.05+10*i) l = [30, 20, 20, 20, 20, 30, 20, 20, 20, 20, 30] for i in range(11): nd.Polygon(layer=lay, points= nd.geometries.rectangle(l[i], 6-0.2*i, position=8)).put( 0, -50+10*i) return C
def icon_pad(length, width, bufx=bufx, bufy=bufy): length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) with nd.Cell('icon', instantiate=False) as icon: pad = geom.rounded_rect(length=length, height=width, position=5) nd.Polygon(layer=layer, points=pad).put(0) nd.Pin('cc').put(0) return icon
def icon_strt(length, width, layer, bufx=None, bufy=None): length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) with nd.Cell('icon', instantiate=False) as icon: rect = geom.box(length, width) nd.Polygon(points=rect, layer=layer).put(0) nd.Pin('cc').put(0.5 * length) return icon
def cell(length=length, angle=angle): anglerad = radians(angle) """Create a trapezoidal IO cell. Returns: Cell """ with nd.Cell(hashme=True, instantiate=False) as C: #When instantiate is True, cell put in (0,0,0) nd.Pin(name='a0', xs=xs['a0'], width=pinwidth['a0']).put(0, 0, 180) nd.Pin(name='b0', xs=xs['b0'], width=pinwidth['b0']).\ put(length/cos(anglerad)-0.5*width*tan(abs(anglerad))) pdk.put_stub(['b0']) pdk.cellname(length=0.5 * length).put(-0.1 * length, 0, 180, 'a0') for lay, grow, acc in nd.layeriter(xs['a0']): outline = nd.geom.trapezoid(length=length / cos(anglerad) + grow * tan(abs(anglerad)), height=width + 2 * grow, angle1=90 + angle, angle2=90, position=2) nd.Polygon(layer=lay, points=outline).put(0) cfg.cp = C.pin['b0'] C.groupname = groupname return C
def cell(length=length, angle=angle): anglerad = radians(angle) """Create a trapezoidal IO cell. Returns: Cell """ with nd.Cell(hashme=True, instantiate=False) as C: """When instantiate is True, cell put in (0, 0, 0)""" nd.Pin(name='a0', xs=xs['a0'], width=pinwidth['a0']).put(0, 0, 180) nd.Pin(name='b0', xs=xs['b0'], width=pinwidth['b0']).\ put(0.5*length*(1.0+1.0/cos(anglerad))) pdk.put_stub(['a0', 'b0']) pdk.cellname(length=0.5 * length).put(C.pin['a0'].rot(180)) temp_a = tan(anglerad) + 0.5 * width * tan(anglerad) temp_b = length / cos(anglerad) + length for lay, grow, acc in nd.layeriter(xs['a0']): outline = [(0, 0.5 * width + grow), (0.5 * temp_b - (width + grow) * temp_a, 0.5 * width + grow), (0.5 * temp_b + grow * temp_a, -0.5 * width - grow), (0, -0.5 * width - grow)] nd.Polygon(layer=lay, points=outline).put(0) cfg.cp = C.pin['b0'] C.groupname = groupname return C
def icon_grating(length=100, width=20, bufx=None, bufy=None): """Create an icon for a grating. Args: length (float): length of the grating icon width (float): width of the grating icon Returns: Cell: grating icon """ length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) Nmin = 3 h = width w = 0.4 * width if length < 2 * Nmin * w: w = length / 6 N = 3 else: N = int(length / (2 * w)) with nd.Cell('icon', instantiate=False) as icon: t, u, v = w / 4, w / 2, h / 2 cross = [(u, t), (u, v), (-u, v), (-u, t), (-w, t), (-w, -t), (-u, -t), (-u, -v), (u, -v), (u, -t), (w, -t), (w, t)] for i in range(N): nd.Polygon(points=cross, layer=layer).put(0 + i * w * 2) nd.Pin('cc').put((N - 1) * w) return icon
def icon_ssc(length=100, width=20, bufx=None, bufy=None): """Create an icon for a grating. Args: length (float): length of the grating icon width (float): width of the grating icon Returns: Cell: grating icon """ length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) N = 20 dx = length / N wout = width win = 0.1 * wout wi = 0.5 * win wo = 0.5 * (wout - win) x, y1, y2 = [], [], [] for i in range(N): x.append(i * dx) dy = wi + (wo / (N - 1)) * i * i / (N - 1) y1.append(dy) y2.append(-dy) X = x + x[::-1] Y = y1 + y2[::-1] outline = list(zip(X, Y)) with nd.Cell('icon', instantiate=False) as icon: nd.Polygon(points=outline, layer=layer).put(0) nd.Pin('cc').put(0.5 * length) nd.Pin('a0').put(0, 0, 180) nd.Pin('b0').put(length, 0, 0) return icon
def cell(diameter=diameter): """Create a DCpad cell. Args: diameter (float): diameter of circular debt Returns: Cell """ with nd.Cell(hashme=True) as C: C.groupname = groupname pdk.addBBmap(name) bb_width = diameter + 2*buf_width bb_length = diameter + 2*buf_length C.default_pins('c0', 'c0') nd.Pin(name='c0', xs=xs['c0'], width=pinwidth['c0'], remark='electrical').\ put(0.5*bb_length, 0, 180) pdk.put_stub('c0', length=pinwidth['c0'], shape='circle') pdk.put_boundingbox('org', bb_length, bb_width) for lay, grow, acc in nd.layeriter(xs['c0']): pad = nd.geom.circle(radius=0.5*diameter, N=100) nd.Polygon(layer=lay, points=pad).\ put('cc') return C
def cell(length=length, width=width): """Create a DCpad_lw cell. Args: length (float): length of the pad in um width (float): width of the pad in um Returns: Cell: dcpad element """ with nd.Cell(hashme=True) as C: C.groupname = groupname C.default_pins('c0','c0') buf = 10 bb_width = width + buf bb_length = length + buf nd.Pin(name='c0', xs=xs['c0'], width=pinwidth['c0'], remark='electrical').\ put(0.5*bb_length, 0, 180) pdk.put_stub('c0', length=pinwidth['c0'], shape='circle') pdk.put_boundingbox('org', bb_length, bb_width) for lay, grow, acc in nd.layeriter(xs['c0']): pad = nd.geom.rounded_rect( length=length+grow, height=width, position=5) nd.Polygon(layer=lay, points=pad).\ put(C.pin['c0']) return C
def icon_mmi(length=None, width=None, bufx=None, bufy=None): length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) Nin0 = 0.5 * (Nin - 1) Nout0 = 0.5 * (Nout - 1) w_mmi = scale_width * width w_in = w_mmi / (2.0 * max(Nin + 0.5, Nout + 0.5)) w_pitch = 2 * w_in l_in = w_in p = [] # list of points (x, y) p.append((bufx + l_in, -0.5 * w_mmi)) #bottom left for i in range(Nin): p.append((bufx + l_in, (-Nin0 + i) * w_pitch - 0.5 * w_in)) p.append((bufx, (-Nin0 + i) * w_pitch - 0.5 * w_in)) p.append((bufx, (-Nin0 + i) * w_pitch + 0.5 * w_in)) p.append((bufx + l_in, (-Nin0 + i) * w_pitch + 0.5 * w_in)) p.append((bufx + l_in, +0.5 * w_mmi)) p.append((bufx + length - l_in, +0.5 * w_mmi)) for i in range(Nout - 1, -1, -1): p.append( (bufx + length - l_in, (-Nout0 + i) * w_pitch + 0.5 * w_in)) p.append((bufx + length, (-Nout0 + i) * w_pitch + 0.5 * w_in)) p.append((bufx + length, (-Nout0 + i) * w_pitch - 0.5 * w_in)) p.append( (bufx + length - l_in, (-Nout0 + i) * w_pitch - 0.5 * w_in)) p.append((bufx + length - l_in, -0.5 * w_mmi)) with nd.Cell('icon', instantiate=False) as icon: nd.Polygon(points=p, layer=layer).put(0) nd.Pin('cc').put(0.5 * length) return icon
def place_rects(rect_name, rect_length, rect_width, rect_angles, rect_x_coords, rect_y_coords): try: rect_width[0] except TypeError: rect_width = num.array([rect_width]) with nd.Cell(rect_name) as rect_array: for u in num.arange(rect_y_coords.size): for v in num.arange(rect_angles.size): # (c, s) = (num.cos(rect_angles[v]*num.pi/180), # num.sin(rect_angles[v]*num.pi/180)) # rotation = num.array(((c, -s), (s, c))) rect_pts = num.array([[0, 0, rect_width[u], rect_width[u]], [0, rect_length, rect_length, 0]]) rect_pts = num.transpose( num.dot(rotation_mat(rect_angles[v]), rect_pts)) rect_pts = geom.transform(points=rect_pts, move=(rect_x_coords[v], rect_y_coords[u], 0)) nd.Polygon(points=rect_pts, layer='layer3').put(0) message = 'Angle = ' + num.array2string(rect_angles[0]) + \ ' to ' + num.array2string(rect_angles[-1]) + ', width = ' if rect_width.size == 1: message += rect_width else: message += num.array2string(rect_width[u]) nd.text(text=message, height=20, layer='layer3', align='rb') \ .put(int(rect_x_coords[-2] + 250 ), int(rect_y_coords[u]) + 100) rect_array.put(0) return rect_array
def cell(length=length, width1=width1, width2=width2, xs=xs, layer=layer, name=name): """ Create a taper element. Args: length (float): length of taper width1 (float): start width of taper width2 (float): end width of taper xs (str): xsection of taper layer (int | str): layer number or layername Returns: Cell: taper element """ #nonlocal name if name is None: name = 'taper' # Cellname with md5 hash #h = md5('{}{}{}{}'.format(length, width1, width2, xs)) #fullname = name="{}_{}".format(name, h) #if fullname in cfg.cellnames.keys(): # return cfg.cellnames[fullname] with Cell(name=name, cnt=True) as taper: taper.instantiate = False if abs(length) < gridsize / 2: return taper # Empty taper if width1 > width2: pin = ['b0', 'a0'] width1, width2 = width2, width1 else: pin = ['a0', 'b0'] nd.Pin(name=pin[0], width=width1, xs=xs, show=True).put(0, 0, 180) nd.Pin(name=pin[1], width=width2, xs=xs, show=True).put(length, 0, 0) taper.length_geo = length for lay, growx, growy, acc in layeriter(xs, layer, dogrowy=True): # Set widths for this layer twidth1 = width1 + 2 * growx twidth2 = width2 + 2 * growx outline = [(0 - growy, twidth1 / 2), (length + growy, twidth2 / 2), (length + growy, -twidth2 / 2), (0 - growy, -twidth1 / 2)] nd.Polygon(layer=lay, points=outline).put() return taper
def cornerUL(layera=1, layerb=None): """Fiducial marker ┌ with upper left corner for machine vision. This marker is not symmetric and can be used to specify the orientation of the chip. Args: layer1 (int | str | tuple): layer (or list of layers) in which the shape is written. layer2 (int | str | tuple): layer (or list of layers) in which the etch background is defined. Returns: Cell: cell with this marker. Example: Place marker centered at (0,0) in layer 1 with background layer 12. import nazca as nd f1 = nd.cornerUL(layera=1, layer2=12) f1.put() nd.export_plt() """ with nd.Cell(name='Fiducial_cornerUL_'+nd.md5((layera,layerb))) as C: for lay in nd.make_iter(layera): nd.Polygon(layer=lay, points=geom.rectangle(10, 125, position=5)).\ put(-67.5,0) nd.Polygon(layer=lay, points=geom.rectangle(125, 10, position=5)).\ put(0,67.5) for lay in nd.make_iter(layerb): nd.Polygon(layer=lay, points=geom.rectangle(200, 200, position=5)).put() nd.Pin(name='a0', xs=None).put(0,0,180) nd.Pin(name='b0', xs=None).put(0,0,0) return C
def icon_diode(length=0, width=None, bufx=None, bufy=None): """Create an icon with a diode symbol. Returns: Cell: diode icon """ length, width, bufx, bufy = calc_buf(length, width, bufx, bufy) ratio = 0.3 w_line = 0.1 * ratio * width with nd.Cell('icon', instantiate=False) as icon: dio1 = [(-0.5 * ratio * width, 0.5 * ratio * width), (0.5 * ratio * width, 0.5 * ratio * width), (0, -0.5 * ratio * width)] dio2 = geom.rectangle(ratio * width, w_line, position=5) dio3 = geom.rectangle(w_line, width, position=5) nd.Polygon(points=dio1, layer=layer).put(0.5 * length) nd.Polygon(points=dio2, layer=layer).put(0.5 * length, -0.5 * ratio * (width - w_line)) nd.Polygon(points=dio3, layer=layer).put(0.5 * length) nd.Pin('cc').put(0.5 * length) return icon
def cell(length=length, width=width, xs=xs, layer=layer, edge1=edge1, edge2=edge2, name=name): """Create a straight waveguide element. Args: length (float): length of waveguide width (float): width of waveguide xs (str): xsection of waveguide layer (int | str): layer number or layername edge1 (function): optional function F(t) describing edge1 of the waveguide edge2 (function): optional function G(t) describing edge2 of the waveguide Returns: Cell: straight element """ if name is None: name = 'straight' #assert width is not None if width is None: width = 0.0 with Cell(name=name, cnt=True) as guide: guide.instantiate = False nd.Pin(name='a0', width=width, xs=xs, show=True).put(0, 0, 180) nd.Pin(name='b0', width=width, xs=xs, show=True).put(length, 0, 0) guide.length_geo = length for lay, growx, growy, acc in layeriter(xs, layer, dogrowy=True): if edge1 is None: outline = [(0 - growy, 0.5 * width + growx), (length + growy, 0.5 * width + growx), (length + growy, -0.5 * width - growx), (0 - growy, -0.5 * width - growx)] else: if edge2 is None: edge2 = edge1 Fp1 = [] Fp2 = [] for t in np.linspace(0, 1, 20): Fp1.append((length * t, edge1(t) + growx)) Fp2.append((length * t, -edge2(t) - growx)) outline = Fp1 + list(reversed(Fp2)) if abs(length) > min_length: nd.Polygon(layer=lay, points=outline).put(0) return guide
def target(layera=1, layerb=None): """Fiducial marker 'target' for machine vision. Args: layera (layer): layer in which the target is written. layerb (layer): layer in which etch background is defined (trench). name (string): cell name. Returns: Cell: cell with this marker. Example: Place marker centered at (0,0) in layer 1 with background layer 12. import nazca as nd f1 = nd.target(layera=1, layerb=12) f1.put() nd.export_plt() """ with nd.Cell(name='Fiducial_target_'+nd.md5((layera,layerb))) as C: nd.Polygon(layer=layera, points=geom.rectangle(200, 10, position=5)).put() nd.Polygon(layer=layera, points=geom.rectangle(10, 200, position=5)).put() nd.Polygon(layer=layera, points=geom.ring(radius=35, width=10, N=41)).put() nd.Polygon(layer=layera, points=geom.ring(radius=70, width=10, N=81)).put() nd.Polygon(layer=layerb, points=geom.rectangle(225, 225, position=5)).put() nd.Pin(name='a0', xs=None).put(0,0,180) nd.Pin(name='b0', xs=None).put(0,0,0) return C
def cell(length=length, height=height, cleave=cleave, pitch=pitch): """Create a cell boundary. Returns: Cell """ with nd.Cell(hashme=True) as C: pdk.parameters('hashme').put(0) #TODO: No foundry specific stuff here: remove. for lay, grow, acc in nd.layeriter(xs): frame = geom.frame(sizew=cleave, sizel=length, sizeh=height, grow=grow) nd.Polygon(layer=lay, points=frame).put(0) #Placing IOs amount_ios = round((height - cleave - pitch) / pitch) #IOs positions lay = 'AnnotationIO' for no in range(0, amount_ios): pinID = 'ioL{:03d}'.format(no) angle = 0 p = nd.Pin(name=pinID).put(-cleave, pitch + no * pitch, angle) p = nd.Pin(name='ioL' + str(no)).put(-cleave, pitch + no * pitch, angle) pdk.arrow.put(p) nd.text(pinID, layer=lay, height=0.15, align='rc').put(p.move(-0.1)) for no in range(0, amount_ios): mo = amount_ios + no pinID = 'ioR{:03d}'.format(no) angle = 0 p = nd.Pin(name=pinID).put(length, pitch + no * pitch, 180 + angle) p = nd.Pin(name='ioR' + str(no)).put(length, pitch + no * pitch, 180 + angle) pdk.arrow.put(p) nd.text(pinID, layer=lay, height=0.15, align='lc').\ put(p.move(-0.1, 0, 180)) C.groupname = groupname return C
def place_cross(cross_name, x, y, cross_w, cross_l): try: cross_w[0] except TypeError: cross_w = num.array([cross_w]) with nd.Cell(name=cross_name) as xs: for u in num.arange(num.size(cross_w)): box_pts = num.array([[0, 0, cross_l, cross_l], [cross_w[u], 0, 0, cross_w[u]]]) xs_box_h = geom.transform( points=num.transpose(box_pts), move=(+x, y + (cross_l - cross_w[u]) / 2 + u * (cross_l + 50), 0)) xs_box_v = geom.transform(points=num.transpose( num.dot(rotation_mat(90), box_pts)), move=(+x + (cross_l + cross_w[u]) / 2, +y + u * (cross_l + 50), 0)) xs_box_30 = geom.transform( points=num.transpose(num.dot(rotation_mat(30), box_pts)), move=(+x + (cross_l - cross_l * num.cos(num.pi / 6) + cross_w[u] * num.sin(num.pi / 6)) / 2, +y + (cross_l - cross_l * num.sin(num.pi / 6) - cross_w[u] * num.cos(num.pi / 6)) / 2 + u * (cross_l + 50), 0)) xs_box_60 = geom.transform( points=num.transpose(num.dot(rotation_mat(60), box_pts)), move=(+x + (cross_l - cross_l * num.cos(num.pi / 3) + cross_w[u] * num.sin(num.pi / 3)) / 2, +y + (cross_l - cross_l * num.sin(num.pi / 3) - cross_w[u] * num.cos(num.pi / 3)) / 2 + u * (cross_l + 50), 0)) xs_box_120 = geom.transform(xs_box_60, flipy=True, move=(0, +2 * y + cross_l + 2 * u * (cross_l + 50), 0)) xs_box_150 = geom.transform(xs_box_30, flipx=True, move=(+2 * x + cross_l, 0, 0)) nd.Polygon(points=xs_box_h, layer='layer3').put(0) nd.Polygon(points=xs_box_v, layer='layer3').put(0) nd.Polygon(points=xs_box_30, layer='layer3').put(0) nd.Polygon(points=xs_box_60, layer='layer3').put(0) nd.Polygon(points=xs_box_120, layer='layer3').put(0) nd.Polygon(points=xs_box_150, layer='layer3').put(0) message_txt = 'Height = ' + str(cross_l) + ', Width = ' + str( cross_w[u]) nd.text(text=message_txt, height=20, layer='layer3') \ .put(int(x - cross_l / 2 - 150), int(y + u * (cross_l + 50))) xs.put(0) return
def north(size=100, layer=1): """Show north pointer to identify the sample direction. Args: size (double): size (wxh) of the bounding box. layer (int | str | tuple): layer (or list of layers) to draw in. Returns: cell containing the pointer. """ s = size/148 pointer = [(-69*s,-74*s), (-70*s,-73*s), (-s,74*s), (s,74*s), (70*s,-73*s), (69*s,-74*s), (0,-33*s), (0,57*s), (-s,57*s), (-52*s,-52*s), (-51*s,-53*s), (0,-23*s), (0,-33*s)] with nd.Cell("north_"+nd.md5(layer)) as C: for lay in nd.make_iter(layer): nd.Polygon(layer=lay, points=pointer).put(0,0,0) return C
def make_pincell(layer=None, shape=None, size=None): """Create a cell to indicate a pin position. The cell contains a shape, e.g. an arrow, to point out a location in the layout. Available pin shapes are in a dictionary in cfg.pinshapes: {name: polygon}. The predefined shapes have been normalized to unit size. Args: layer (float): layer number to place the pin symbol/shape shape (str): name (dict key) of the pin symbol/shape. size (float): scaling factor of the pin symbol/shape Returns: Cell: cell with pin symbol """ pinshape = cfg.pin_settings['bb_pin_shape'] if layer is None: layer = cfg.pin_settings['bb_pin_layer'] layer = nd.get_layer(layer) if shape is None: shape = pinshape if size is None: size = cfg.pin_settings['bb_pin_size'] if shape not in cfg.pinshapes.keys(): print("Warning: arrowtype '{}' not recognized.".format(shape)) print("Available options are: {}.".format(cfg.pinshapes.keys())) print("Fall back type '{}' will be used.".format(pinshape)) shape = pinshape name = "{}_{}_{}_{}".format('arrow', layer, shape, size) name = cfg.gds_cellname_cleanup(name) if name in cfg.cellnames.keys(): return cfg.cellnames[name] with nd.Cell(name, instantiate=cfg.pin_instantiate, store_pins=False) as arrow: outline = [(x * size, y * size) for x, y in cfg.pinshapes[shape]] nd.Polygon(layer=layer, points=outline).put(0) return arrow
def place_blks(block_name, block_height, block_width, block_angles, block_x_coords, block_y_coords): with nd.Cell(block_name) as blk_arr: for u in num.arange(block_width.size): for v in num.arange(block_angles.size): block_pts = geom.parallelogram(length=block_width[u], height=block_height, angle=block_angles[v], shift=(block_x_coords[v], block_y_coords[u], 0)) nd.Polygon(points=block_pts, layer='layer3').put(0) message = 'Angle = ' + num.array2string(block_angles[0]) + \ ' to ' + num.array2string(block_angles[-1]) + \ ', Width = ' + num.array2string(block_width[0] * num.sin(num.pi/180 *block_angles[0])) nd.text(text=message, height=20, layer='layer3') \ .put(int(block_x_coords[-1] + 0.5 * block_x_coords[0]), int(block_y_coords[u])) blk_arr.put(0) return blk_arr
def cell(width=width, distance=distance, offset=offset, xs=xs, layer=layer, name=name): """Create a cosine bend waveguide element. Args: width (float): width of the interconnect in um pin (Node): optional Node for modeling info xs (str): xsection of cbend offset (float): lateral offset of the cbend in um distance (float): total forward length of the cbend in um xs (str): xsection of waveguide layer (int | str): layer number or layername Returns: Cell: ccurve element """ if name is None: name = 'ccurve' xya = (distance, offset, 0) # End point # ccurve waveguide, cwg with Cell(name=name, cnt=True) as cwg: cwg.instantiate = False nd.Pin(name='a0', width=width, xs=xs, show=True).put(0, 0, 180) nd.Pin(name='b0', width=width, xs=xs, show=True).put(*xya) for lay, growx, growy, acc in layeriter(xs, layer, dogrowy=True): # sampled curve xy = curve2polyline(cbend_point, xya, acc, (distance, offset)) # polygon of proper width xy = nd.util.polyline2polygon(xy, width + growx * 2) nd.Polygon(layer=lay, points=xy).put(0) return cwg
def whereami(text='here', size=100, pin=None): """Show current pointer position as arrow in the layout. Args: text (str): annotation text size (float): size of the annotation Returns: None """ layer = 500 nd.cp.push() if pin is None: pin = nd.cp.here() points = [(0, 0), (-0.5, 0.5), (-0.4, 0.25), (-1, 0.3), (-1, -0.3), (-0.4, -0.25), (-0.5, -0.5)] points = [(x * size, y * size) for x, y in points] with Cell('I am'.format(wherecnt)) as crisis: nd.Polygon(layer=layer, points=points).put(0) nd.text(text + ' ', height=size / 4, align='rc', layer=layer).put(0) crisis.put(pin) nd.cp.pop()