Home Forums Nazca export cells into an existing gds

  • This topic has 4 replies, 2 voices, and was last updated 3 years ago by paul.
Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #5856
    paul
    Member

    Hello Nazca users,

    Has anybody come up with a nice way of exporting gds cells created with Nazca into an existing gds file? The nd.export_gds(filename='foo.gds') method works nicely but overwrites foo.gds.
    After having generated a whole mask set with Nazca I often need to make small changes and while I could just amend my code and run the script again, I tend to think that this is overkill and error-prone.

    So far what I have been doing is instantiating only the cells/hierarchy which I need to modify, export them in a temporary gds file and copying and pasting the cells in foo.gds (as deep copy) with Klayout. I can then reinstantiate the cells in the hierarchy manually. This works well and is super flexible but has limited efficiency. The same issue arises with Nazca created Klayout libraries, having to regenerate the whole list of cells when only one has been modified.

    Not a showstopper, but I’d be interested to know if there was a workaround which I am not aware of.

    Thanks

    #5858
    Ronald
    Keymaster

    Dear Paul,

    As an example on how to add a cell to a gds I take a small detour. First load the gds as a “library” in Nazca:

    LIB = nd.load_gds(asdict=True)

    Due to asdict=True the load_gds() returns a dictionary where the keys are the cell names and the values are the Cells. By default only top cells are expressed as the keys in dict LIB, but this can be changed to include all cells as keys:

    LIB = nd.load_gds(filename=, asdict=True, topcellsonly=False

    Hence, if you have a gds “test.gds” with top cells named “A” and “B”, you can load and place them like this:

    LIB = nd.load_gds(filename="test.gds", asdict=True)
    LIB['A'].put()
    LIB['B'].put()

    The default pin of the library cells (here LIB[‘A’], LIB[‘B’]) is set to the ‘org’ pin.

    You can load and export the original gds in the following way:

    LIB = nd.load_gds(filename=, asdict=True)
    cell_list = list(LIB.values())
    nd.export_gds(cell_list)

    You can add extra cells to cell_list before calling nd.export_gds.
    Does that cover your use case?

    Ronald

    #5859
    paul
    Member

    Hello Ronald,

    Yes I think that it does cover it, because in a normal use case I would instantiate the new cells as top cells and then instantiate them in the hierarchy manually in Klayout (usually by replacing old cells).

    import nazca as nd
    
    # Level 1 Cells
    with nd.Cell(name='B') as cellB:
        nd.strt().put()
    with nd.Cell(name='C') as cellC: 
        nd.bend(angle=90).put()
    with nd.Cell(name='D') as cellD: 
        nd.taper(layer=2).put()
        
    # Level 0 Cell (top cell)
    with nd.Cell(name='A') as cellA: 
        cellB.put()
        cellC.put(10)
        
    nd.export_gds(filename='example.gds', topcells=cellA)
    
    # Load example.gds, and add cellD as a top cell
    cell_dict = nd.load_gds(filename='example.gds', 
                            asdict=True, 
                            topcellsonly=True)
    
    cell_list=list(cell_dict.values())
    cell_list.append(cellD)
    nd.export_gds(filename='example.gds', topcells=cell_list)

    In the example above, I could either manually instantiate cell D as a new cell in cell A, or replace of the existing cells by cell D after the second export.

    To push things further how could I automatically replace the cells in Nazca? In the example below I tried to replace cell C with a new version in the cell dictionary. It does not replace the old cell but instantiate it as a new top cell.

    import nazca as nd
    
    # A new version of cellC 
    with nd.Cell(name='C$1') as newC:
        nd.bend(angle=30, layer=3).put()
    
    # topcellsonlly flag set to False to import old cell C 
    cell_dict = nd.load_gds(filename='example.gds', 
                            asdict=True, 
                            topcellsonly=False)
        
    # replace cell C in cell_dict   
    cell_dict['C'] = newC
    # get new list of cells 
    cell_list=list(cell_dict.values())
    
    nd.export_gds(filename='example_v2.gds', topcells=cell_list)

    The obvious answer would be to recreate the whole hierarchy, i.e in this case:

    newCellA
        newCellC
        oldCellB
    oldCellD

    But this can get tedious if you need to replace a cell in the lowest level of the hierarchy, or even worse if the cell is instantiated in different ‘tree branches’.

    Thanks,

    Paul

    nazca version: 0.5.7

    #5861
    Ronald
    Keymaster

    Dear Paul,

    There is a special mechanism in Nazca to replace parametric and/or static cells.
    In case of static cells the example below shows how you can use on or more GDS library files as a source to replace cells in your original gds by name. It doesn’t matter how many or how deep in the tree those cells are:

    import nazca as nd
    
    # File name of gds input.
    gdsin = 'example.gds'
    
    # a list of scell (static cell) libraries:
    # and a cellmap for each library file: { : }
    # where resides in gdsin and in the lib.
    scell_libs = {
        'scell_lib1.gds': {
            'C': 'newC',
             # other cell name mappings
        },
        # other libs and mappings as needed
    }
    
    # Replace cells and write output to a new gds file (gdsin will not be changed).
    nd.replaceCells(
        gdsin=gdsin,
        ScellMapping=scell_libs
    )

    Starting with the following cell structure

    A
      B
      C
    D

    the replacement C -> newC gives

    A
      B
      newC
    D

    Although A has different content now, effectively only its references to C have been changed. So, I kept A’s original name.

    In contrast, if you replace A -> newA you get

    newA
      # branches in newA
    D

    If you replace A by newA the substructure (the tree) of A is irrelevant as it is replaced as a whole; You remove the whole branch behind the cut. Cell newA can be a cell or tree of cells.

    If newA would look like

    newA
      C

    then the replacement result A -> newA is

    newA
      C
    D

    If newA would look like

    newA
      newC

    then the replacement result is

    newA
      newC
    D

    If you have two libraries like

    # lib1.gds:
    NewA
      C
    
    # lib2.gds:
    newC

    then you would use

    gdsin = 'example.gds'
    
    scell_libs = {
        'lib1.gds': {'A': 'newA'},
        'lib2.gds': {'C': 'newC'}
    }
    
    nd.replaceCells(
        gdsin=gdsin,
        ScellMapping=scell_libs
    )

    to obtain

    newA
      newC
    D

    Note: Since Python 3.7 dictionaries are ordered as a language feature, which is important as replacement is not commutative in the order of the libraries (in ‘scell_libs’ above). In earlier Python versions you would make consecutive calls of nd.replaceCells() with one library at a time to ensure the library order.

    Ronald

    #5862
    paul
    Member

    Thanks Ronald, I came across this function yesterday whilst browsing the manual but hadn’t had time to try it out. Looks very powerful.

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.