Forum Replies Created

Viewing 20 posts - 141 through 160 (of 194 total)
  • Author
    Posts
  • in reply to: Interconnect: pcurve_p2p #5526
    Ronald
    Keymaster

    Dear Chenhui,

    Your post got stuck in a dark moderation corner it seems, but here it is…

    The pcurve_p2p() calculates a particular spine, zero-width curve in (x, y), and adds a width to it via polyline2polygon() method in util.py. It is a parametric curve with position (x, y) as function of t and it needs to be defined how the width changes along the curve as w(t). The width could for example change with respect of t or with the geometrical distance along the spine, depending on your use case.

    The pcurve has no width added to its call at the moment, and therefor you probably will find the viper() method in util.py useful. See this viper example. It allows full freedom in x, y and w as function of t. In a similar way a w(t) may be added to the pcurve.

    Ronald

    in reply to: viper() method #5524
    Ronald
    Keymaster

    Dear Marek,

    The viper can be found in util.py and can be accessed follows

    import nazca as nd
    nd.util.viper()

    The viper() is a “lower level” function on top of polyline2polygon(). The latter has been upgraded to handle variable widths better. The viper returns an array of points, which can be fed into a Polygon. Below is an example where x, y are the coordinates that the viper follows and w the width.

    import nazca as nd
    import math as m
    
    def x(t):
    return (2+15*t)*m.exp(t)
    
    def y(t):
    return (2+20*t)*m.cos(t*5)
    
    def w(t):
    return 2+3*(m.sin(t*15))**2
    
    # N is the number of points, x, y, w functions of one parameter.
    xygon = nd.util.viper(x, y, w, N=200)
    nd.Polygon(points=xygon).put(0, 5)
    
    # draw the same viper spine again, but with constant width
    xygon = nd.util.viper(x, y, lambda t: 0.1, N=200)
    nd.Polygon(points=xygon, layer=2).put(0, 5)
    
    nd.export_gds()

    For the viper to also become an interconnect it would need some extra checks on how many polygon points are needed for grid snapping at the right resolution. In the present case just give a sufficiently large N.

    Ronald

    in reply to: GDS Datatype / Texttpe for annotations #5520
    Ronald
    Keymaster

    Dear Prasanna,

    Yes, only for datatype = 0 annotations seem to show up in layout viewers.  (This possibly depends on the specific viewer as well.) And as you mentioned already, annotations formally do not have a datatype but a texttype.

    Ronald

     

    in reply to: Import GDS with cell name already in layout #5496
    Ronald
    Keymaster

    Dear Emmanuel,

    You can basically design any layout you want in Nazca and export it to foundry compatible GDS layout.  Foundry rules need to be known and correctly implemented. Designs created with Nazca are utilized in e.g. SiPh transceivers, InP lasers, PLC multiplexers, SiN based spectrometers, Polymer interposers and many more applications.

    Ronald

    in reply to: Polygon clipping with interconnects #5473
    Ronald
    Keymaster

    Dear Weiming,

    Your question needs a slightly more elaborate answer in case of reading polygons from interconnects. Take the following example based on your code:

    import nazca as nd
    
    ic1 = nd.interconnects.Interconnect(width=2.0, radius=20)
    bend_instance = ic1.bend(angle=45).put()
    print(bend_instance.cnode.cell.polygons)
    
    # prints an empty list: []

    The polygons you are after seem at first sight to be located in the ‘polygons’ attribute of the cell that the bend instance (here named ‘bend_instance’) is based on. To get to the cell object we have to look it up via the cnode (the “cell master node”) that is stored in the instance: bend_instance.cnode.cell. However, there are no Polygon objects there (capital P to denote it is a class), i.e. the polygon attribute is an empty list of Polygons: [].

    The catch is that the polygon that describes the bend geometry actually resides in a cell two levels deeper in the Nazca tree, but this is simplified in the gds export.

    Your easy way out is the ‘cell_iter’ method. The following example prints all the polygon points [(x1, y1), (x2, y2), …] in instance ‘bend_instance’ regardless of the level.

    cell_iter = nd.cell_iter(bend_instance)
    for params in cell_iter:
        if params.cell_start:
            for pgon, points, bbox in params.iters['polygon']:
                print(points)

    Actually, the Polygon object ‘pgon’ by itself already contains all polygon information, including the points, bounding box and layer information. Try replacing ‘print(points)’ by the line below to see how that works

    print(f"layer: '{pgon.layer}'\npoints: {pgon.points}\n")

    Ronald

    in reply to: Polygon clipping with interconnects #5470
    Ronald
    Keymaster

    Dear Weiming,

    That should work, taking into account the remarks as described in the post

    Polygon subtraction function

    To access the polygons note that e.g. an interconnect is a Nazca Cell object that stores Polygon objects in it under self.polygons. In the Polygon object you find the attributes self.points and self.layer.

    Ronald

    in reply to: Interconnect: pcurve_p2p #5469
    Ronald
    Keymaster

    Dear Chenhui,

    The pcurve_p2p (point to point) is a specific implementation of a parametric curve (for photonics) without width change at the moment. The width can be added to the function. More generic, a parametric curve can be described by functions x(t), y(t), w(t), with t = [0, 1] for the position and width of a curve as a function of t. It may by useful to add a function to take care of this as this question pops up more often.

    Ronald

    in reply to: No show_pin attibute in nazca.netlist #5468
    Ronald
    Keymaster

    Dear Wanshu,

    An alternative way to show the current position or a specific pin p you may use

    nd.whereami()  # current pin
    nd.whereami(p) # pin p

    The nd.show_pin is there in netlist.py, though I see its scope to find the current pointer needs an upgrade.
    Effectively, what show_pin does is drawing a polygon (e.g. a circle) on the pin:

    nd.Polygon(points=<polygon_points_here>, layer=<layer_here>).put(p)

    Ronald

    in reply to: define pins in a loop #5458
    Ronald
    Keymaster

    Hi Chenhui,

    You are correct.
    Just typed it as a concept directly in the edit box rather than in Python.

    Ronald

    in reply to: define pins in a loop #5455
    Ronald
    Keymaster

    Dear Chenhui,

    Thank you, good catch, I edited it in the original post.

    Your example raises pins for multiple instances. If the instances are added to a list you can iterate over them.

    padN = [] 
    with ...
        ...
        padN.append(bump(pad=pad).put(293.14, 114.02, 0))
        padN.append(bump(pad=pad).put(368.14, 113.31, 0))
    for i, pad in enumerate(padN):
        pad.raise_pins(['out0'], ['out'+str(i)])
    in reply to: Mask layer management #5444
    Ronald
    Keymaster

    Dear Chenhui,

    For using a csv file to define mask layers:

    # csv file content example 'my_layers.csv'
    # (no spaces after the comma's)
    # remove these comment lines
    layer_name,layer,datatype,accuracy,origin,remark
    name1,2,10,0.001,,
    name2,5,0,0.001,,
    name3,100,0,0.001,,
    import nazca as nd
    nd.load_layers(filename='my_layers.csv')
    nd.show_layers()

    Ronald

    in reply to: define pins in a loop #5443
    Ronald
    Keymaster

    Dear Chenhui,

    Check out the raise_pins() method.
    https://nazca-design.org/manual/code.html?highlight=raise_pins#nazca.Instance.raise_pins

    In your example ‘padN1’ is an instance of cell ‘bump’ in parent cell ‘C’. The raise_pins raises the pins of padN1 to the parent level.

    padN1.raise_pins()

    Ronald

    in reply to: Mask layer management #5438
    Ronald
    Keymaster

    Dear Chenhui,

    Yes there is a mask layer system in Nazca. You can either load layers from a csv file or add them in your script via add_layer(). A layer can be given a layer_name too, e.g.

    import nazca as nd
    nd.add_layer(name='my_layer', layer= (2, 5))
    nd.Polygon(points=[(0, 0), (10, 0), (0, 10)], layer='my_layer')
    nd.export_gds()

    As of Nazca-0.5, released Feb 20 ’19, there are some useful updates:
    The layers are no longer primarily organized in layers and datatypes, but by an ID. You can still call a layer as previously, however, you can now also have multiple names for the same (layer, datatype) combination without ambiguity. If you refer to a layer by number and it has multiple layer_names Nazca will issue a warning and ask you to use the unique layer_name instead.

    import nazca as nd
    nd.add_layer(name='my_layer1', layer= (2, 5))
    nd.add_layer(name='my_layer2', layer= (2, 5))
    nd.Polygon(points=[(0, 0), (10, 0), (0, 10)], layer='my_layer1')
    nd.Polygon(points=[(0, 0), (10, 0), (0, 10)], layer=(2, 5)) # This will trigger a warning
    
    # warning message:
    WARNING: Non-unique layer identifier used: (2, 5).
    Matching layer_names for (2, 5) are ['my_layer1', 'my_layer2'].
    Continuing here with layer_name = 'my_layer1'.
    
    nd.export_gds()

    Ronald

    in reply to: Import GDS with cell name already in layout #5417
    Ronald
    Keymaster

    Dear Douglas,

    In GDS a cellname must be unique. It’s the ID.

    Nazca always avoids two different cells having the same name. When you load a GDS file it may have any cellname in there, possibly conflicting with an existing cellname in your design. For more info on what happens see

    import nazca as nd
    print(help(nd.load_gds))

    Which shows this and more (v0.5):

    ————————
    load_gds(filename, cellname=None, newcellname=None, asdict=False, select=’top’, layermap=None, cellmap=None, scale=1.0, prefix=”, instantiate=True, native=True, bbox=False, bboxbuf=0, connect=None, flat=False)

    Load GDS cell ‘cellname’ (and its instances) from ‘filename’ into a Nazca cell.

    By default, load_gds returns a single cell in the specified gds file.
    However, when using a gds file as a library, i.e. accessing multiple cells
    in the file individually, it is more efficient to call, load (and internally)
    store the gds file only once by setting asdict=True. This makes makes load_gds
    return a dictionary with a references to each Cell by name:

    {‘topcells’: {cellname: Cell}, ‘subcells’: {cellname: Cell}}

    This method checks for cellname clashes, i.e. a cell(tree)
    loaded into the layout can not contain a cell name that already exists
    in the layout. There are three ways to avoid name clashes in case they occur:

    1. Set a ‘newcellname’: changes only the name of the top cell;
    Note ‘newcellname’ is ignored if a is provided,
    i.e. add any a topcell renaming to the cellmap in this case.

    2. Provide a ‘cellmap’: maps original cell names one-by-one to new cell
    names. Cells names omitted will not be renamed.

    3. Provide a cell name : applies to all cells in a branch,
    except those in ‘newcellname’ or ‘cellmap’.

    Note, if you need to create a building block from GDS with pins and stubs,
    and you have the pin and xsection info available already (for example in a
    file) then you may prefer to use method ‘load_gdsBB’ instead.

    Ronald

    in reply to: Need to define periodic holes next to the waveguide #5412
    Ronald
    Keymaster

    Dear Hitesh,

    It seems to me that the center path of the waveguide has to be defined like a polyline and a function is needed similar to the nazca internal function ‘polyline2polygon’ to add a width to the line. A width for the edge of the waveguide and a width for the path on which the circles/squares are to be placed. In curves some care needs to be taken for the distance of the circles on their path on the in and outside, I guess. No magic bullet, but no show-stoppers either.

    Ronald

    in reply to: MMI cell #5410
    Ronald
    Keymaster

    Dear Joaquin,

    This touches upon the core idea behind Nazca: “Make a cell, put a cell”.

    Creating a cell and putting it zero or more times in a layout (in other words: instantiating it zero or more times in a parent cell) are two distinct activities.

    As soon as you finish creating a cell, you can by definition not add anything new to it anymore; The cell is closed. It may feel like a restriction, but actually it is not and it guarantees a consistent cell hierarchy. Hence, anything you put in a cell just has to be done before it is closed.

    Your example attempts to instantiate cell ‘mmb’ to a pin inside the already closed cell ‘mmi1x2’, i.e. it tries to add ‘mmb’ into ‘mmi1x2’:

    mmb.put(mmi1x2.pin['a0'])

    However, you don’t want to connect ‘mmb’ to the cell ‘mmi1x2’ but to the ‘copy’ of mmi1x2, i.e. its instance. More precise ‘mmi1x2().put()’ instantiates cell ‘mmi1x2’ in the “active cell”, i.e the open cell you are constructing. Note that you are always in an active layout cell one way or another, e.g. Nazca automatically creates a cell named ‘nazca’ for you at the start.

    Solution to connect mmb to mmi1x2:

    A = mmi1x2.put()
    mmb.put(A.pin['a0'])

    The put() method returns a reference to the instance, here assigned to ‘A’, of the cell it puts, here ‘mmi1x2’. It’s like using a stamp to make prints: ‘mmi1x2’ is the stamp and ‘A’ is its print in the layout. You can reuse stamp ‘mmi1x2’ as much as you like, and each print it creates is an instance (a reference to the stamp).

    In order to connect to the print/instance, or any number of prints/instances in scope in the active cell, just keep a reference of it when putting it. It looks something like this:

    
    A = mmi1x2.put(0)    # place mmi1x2 at x=0 and call the resulting instance A
    B = mmi1x2.put(100)  # place a 2nd mmi1x2 at x=100 and call the resulting instance B
    mmb.put(A.pin['a0']) # place mmb connected pin 'a0' of A
    mmb.put(A.pin['b0']) # place a 2nd mmb connected pin 'b0' of A
    mmb.put(B.pin['a0']) # place a 3rd mmb connected to pin 'a0' of B

    Nazca gives the following message when connecting to closed cell
    (which is a compressed version of the story above):

    Exception: You are trying to connect to a closed Cell object:
    The construction found is similar to
    $ foo.put(cell.pin[‘a0’])
    Connect not to the Cell but to an instance of the cell instead
    $ instance = cell.put()
    $ foo.put(instance.pin[‘a0’])

    Ronald

    in reply to: How to draw a triangle #5400
    Ronald
    Keymaster

    Dear Wanshu,

    A straight forward way to define these kind of structures is to create a function that returns your custom polygon (list of points) and create a Polygon mask element from the list of points:

    from math import tan, radians
    import nazca as nd
    
    def triangle(length=10, angle=45):
        base = 2*length*tan(radians(0.5*angle))
        return [(0, 0.5*base), (0, -0.5*base), (length, 0)]
    
    tri = nd.Polygon(points=triangle(length=50, angle=30))
    tri.put(0)
    tri.put(0, 10, 45)
    
    nd.export_gds()

    Ronald

    Ronald
    Keymaster

    Dear Pervaiz,

    Note that Nazca Design is at version 0.4.3. Hence, the version number you mention (0.9.1) is very helpful in identifying that you have another unrelated nazca package alltogether.

    If you follow the installation on https://nazca-design.org/installation/ you should be fine.

    Ronald

    in reply to: Warning: Duplicated cell name #5350
    Ronald
    Keymaster

    Dear Douglas,

    Below an example of @hashme. Its first parameter is the cell’s basename. The optional parameters following the basename are variable names whose value you like to have included in the cell name as a “visual aid”. To ensure a unique cellname in all cases, a hash based on all parameters of the decorated function (var1, var2, var3, var4 in the example) is generated and added as a suffix to the cellname.

    import nazca as nd
    #from nazca.pdk_template_core import hashme # before nazca-0.5
    from nazca.bb_util import hashme # from nazca-0.5
    
    @hashme('cellname', 'var1', 'var3')
    def func(var1=10, var2=3, var3=20, var4=5):
    with nd.Cell(hashme=True) as C:
    nd.strt(length=var1, width=var2).put(0)
    nd.strt(length=var3, width=var4).put(0, 20)
    return C
    
    func(var1=20).put(0)
    func(var3=15, var4=1).put(0, 50)
    
    nd.export_gds()

    Resulting cellnames:
    cellname_10_15_$d269
    cellname_20_20_$9d42

    Ronald

    in reply to: quasi-curved polygon! #5347
    Ronald
    Keymaster

    Dear sara,

    The pins are more useful in the context of connecting building blocks, rather than defining polygon structures.

    To answer the polygon part if for some reason you want to use pins:

    1.
    The point keyword in Polygon accepts a list of (x, y) describing the polygon points in order as drawn.

    Note that curve.pin[‘a0’] does not describe the curve. It is a point (pin) to reference a position with respect to the curve. If you want to use a pin position in a polygon (unlikely), use the pin’s xya method:

    import nazca as nd
    
    p1 = nd.Pin('a0').put(10, 20, 30)
    x1, y1, a1 = p1.xya()
    
    x2, y2, a2 = nd.Pin('b0').put(10, -20, -30).xya()
    
    nd.Polygon(points=[(0,0), (x1, y1), (x2, y2)], layer=1)

    2.
    You need to create a polygon that “carves-out” the desired shape along the outline of the blue structure in your picture. See the next example, and note that the “filled” structure is on the “left side” of the line that defines the polygon. Orientation of the outline matters.

    import nazca as nd
    
    points = [(-1, 1), (1, 1), (1, -1), (-1, -1), (-1, 1), (-2, -2), (2, -2), (2, 2), (-2, 2), (-2, -2)]
    nd.Polygon(points=points).put(0)
    nd.export_plt()

    Ronald

Viewing 20 posts - 141 through 160 (of 194 total)