Make and put a Cell

By 3 November 2019Nazca Layout, Nazca Foundry

Make and Put a Cell

How make cells and put them in a layout

(For using polygons in a cell see also Create a building block using Polygons)

The Nazca cell

Layout structures in Nazca are grouped in “cells”, very much alike a gds cell hierarchy. A cell can contain the following Nazca mask objects:

  • – Cells
  • – Polygons
  • – Polylines
  • – Annotations
  • – Pins

Each Nazca mask object has a “put” method to place them in a Nazca cell. Note that as soon as nazca is imported with import nazca as nd  it a creates and activates a “nazca” top cell for you so you do not have to create the first Cell. Below is a code example that shows how to place a straight and bent waveguide and export it to gds. The result is show in the figure. The structures in gds are placed in the cell named “nazca”. Note that an empty put() positions the element at the “current pin” or “cp”. For the first element in a new cell this is position (0, 0, 0). If an element has been placed, the cp is set to be the default output pin of that element.

# example created by Bright Photonics

import nazca as nd

nd.strt(length=5.0, layer=1).put()
nd.bend(angle=45.0, layer=1).put()

nd.export_gds()

Make a custom cell

All that has to be done to place these structures in a custom cell is to create new cell and place layout structures in that cell. The new cell is initialized using the Python “with” context in combination with a call to make Nazca Cell object as demonstrated below. The new cell object is assigned to variable C (which can have any valid variable name). The creation of the new cell does not put that cell in the layout. After cell creation we can to put it with C.put(). The cell named “myCell” now resides in the cell named “nazca”, and the gds structure is a follows:

  • – Nazca
    • – myCell
# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    nd.strt(length=5, layer=1).put()
    nd.bend(angle=45, layer=2).put()

C.put()

nd.export_gds()

The pin dictionary

Each cell contains a dictionary with pins named ‘pin’. Those pins can be used to connect the cell to a position in the mask or to connect it to other cells. By default a cell automatically creates an input and output pin named ‘a0’ and ‘b0’, respectively. Pin ‘a0’ is the default pin that the cell uses when it is put, whereas pin ‘b0’ is used as default pin if something else is connected to the cell (or more precise to an instance of the cell as will become clear later).

If pins ‘a0’ and ‘b0’ have not been defined inside the cell by the user they will be placed at (x, y, a) for ‘a0’ is (0, 0, 180) and for ‘b0’ is (0, 0, 0). Note these are “outward pointing” in line with the Nazca “chain connectivity” concept when connecting cells. This concept avoids a lot of confusion with respect to having inward pointing inputs and outward pointing outputs when defining a circuit. Each cell also always has a zero pin located at (0, 0, 0). This is not a chain connectivity pin as it serves another purpose, i.e. as cell origin, rather than a circuit pin.

In the code below the cell pins are accessed by printing the keys of the pin dictionary, and by looping over the pins and using Nazca’s formatted coordinate method fxya().

# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    nd.strt(length=5, layer=1).put()
    nd.bend(angle=45, layer=2).put()

print(C.pin.keys())
# dict_keys(['org', 'a0', 'b0'])

for name, node in C.pin.item():
    print(f"{name} @ {node.fxya()}")
# org @ (0.000, 0.000, 0.000)
# a0 @ (0.000, 0.000, 180.000)
# b0 @ (0.000, 0.000, 0.000)

Define custom pin positions

The new cell “myCell” has all connectivity it needs and can be put like any other Nazca cell, e.g. like

C.put()
C.put()

The result in gds will be two instances of ‘”myCell” in parent cell “Nazca”, but on top of each other, because ‘a0’ of the second C.put connects to ‘b0’ of the first put and these point towards each other in (x, y) = (0, 0). Hence, it makes sense to reposition ‘a0’ and ‘b0’ when creating the cell. This is done by creating a Nazca “Pin” object and putting it in the cell. The Pin object can be placed anyware in the cell, but here a logical place of ‘a0’ is at the input of the straight guide and for ‘b0’ at the output of the bent guide. Nazca allows for placing those pins by reference using the “pin” keyword in the Pin object. The cell’s designer should make sure pins are always outward pointing from a mask element’s structure to keep making connections intuitive and uniform:

# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    C.autobbox = True
    e1 = nd.strt(length=5, layer=1).put()
    e2 = nd.bend(angle=45, layer=2).put()
    nd.Pin(name='a0', pin=e1.pin['a0']).put()
    nd.Pin(name='b0', pin=e2.pin['b0']).put()

C.put()
C.put()

for name, node in C.pin.items():
    print(f"{name} @ {node.fxya()}")
# org @ (0.000, 0.000, 0.000)
# a0 @ (0.000, 0.000, 180.000)
# b0 @ (12.071, 2.929, 45.000)

nd.export_gds()

Stubs (visualize pins)

It is possible to visualize the pins in the cell in gds export via Nazca stubs, as shown in the next example. The pins are by default indicated by an arrow shape, where the pin is located at the tip of the arrow and points in the direction of the arrow. The name of the pin is added to the gds as an gds annotation. Note that the ‘org’ pin is not visualized.

# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    e1 = nd.strt(length=5).put()
    e2 = nd.bend(angle=45).put()
    nd.Pin(name='a0', pin=e1.pin['a0']).put()
    nd.Pin(name='b0', pin=e2.pin['b0']).put()
    nd.put_stub()

C.put()

nd.export_gds()

Add a bounding box

A bounding box is added to the cell by setting the cell attribute autobbox = True. The bbox adds pins lb, lc, lt, tl, tc, tr, rt, rc, rb, br, bc, bl and cc. The letters indicate left, right, top and center. The first letter indicates the direction of the pin. The cc pin sits in the geometrical center of the bbox, but is not visualized:

# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    C.autobbox = True
    e1 = nd.strt(length=5).put()
    e2 = nd.bend(angle=45).put()
    nd.Pin(name='a0', pin=e1.pin['a0']).put()
    nd.Pin(name='b0', pin=e2.pin['b0']).put()
    nd.put_stub()

C.put()

nd.export_gds()

Changing default pins and show some put options

A cell can have as many pins as needed and have any string name.  The default pin names can be customized as demonstrated in the next code example. Note that the default input and output pin can be chosen to be the same pin. To show some options of the put function, a series of put statements have been added:

# example created by Bright Photonics

import nazca as nd

with nd.Cell('myCell') as C:
    C.default_pins('bert', 'ernie')
    C.autobbox = True
    e1 = nd.strt(length=5).put()
    e2 = nd.bend(angle=45).put()
    nd.Pin(name='bert', pin=e1.pin['a0']).put()
    nd.Pin(name='ernie', pin=e2.pin['b0']).put()
    nd.put_stub()

C.put()
C.put()
C.put(25)
C.put('bert', 25, 10)
C.put('bert', 25, 20, flip=True)
C.put('ernie', 25, 30)

nd.export_gds()

Related Tutorials

Nazca LayoutNazca Foundry
11 November 2019

Log your layout

In this example we show how to log your layout.
Nazca LayoutNazca Foundry
2 November 2019

xsections and layers

In this example we show how to create xsections and layers
Nazca LayoutNazca FoundryPhotonic BBs
28 October 2019

Reuse parametric building blocks

Avoid "duplicate cellname" warnings using introspection via the @hasme decorator.
Nazca LayoutNazca Foundry
28 March 2019

Parametric curve

In this example we show how to create parametric curves between two points.