Merge multi db with similar cell name hierarchy

edited May 2017 in Ruby Scripting
Hi Matthias,

We tried to merge multiple gds/oasis files which have similar cell name hierarchy,
with the following two ways the result is not what we want, could you please help to
give some hints to merge files with skip/overwrite cell when the same cell name is encountered ?

1. Declare one layout object and layout.read() more than two files, however the layout pattern and
instance in the same cell name would be repeat counted. If merge more than 10 files the display speed
of result file would be horrible slow.

2. Decalre three layout object, layout.read() two files into two objects, use copy_tree to copy topcell
of two objects to new_top objects, but this function would rename the same cell name to xxx$.

Best Regards,
--
chhung

Comments

  • edited November -1

    Hi chhung,

    What exactly do you want to achieve?

    Method 1 is useful if you want to merge layouts by "adding information" to an existing layout. You can use this approach for example, if you have split a layout into several layouts containing the same hierarchy but different layers each. This approach is fast but dumb.

    Method 2 will build separate hierarchy trees. Since cell names need to be unique, they have to be made unique by adding a suffix.

    I guess your requirement is somewhat between both approaches. There a manifold ways to merge layouts, so you need to be specific about the actual requirement you have.

    Regards,

    Matthias

  • edited May 2017

    Hi Matthias,

    We are trying the fast and dumb way for our approach. XD

    For example:

    We have two files(file1 / file2) and want to merge it to a new file(file3)
    The cell hierarchy like

    file1 => cellA => cellA1
          => cellB => cellB1
          => cellC
    
    file2 => cellA => cellA1
          => cellB => cellB1
          => cellC
    

    All the subcells are the same and only the topcell of file1 and file2 are different,

    we hope to merge these files to new file3

    file3 => file1 => cellA => cellA1
                   => cellB => cellB1
                   => cellC
          => file2 => cellA => cellA1
                   => cellB => cellB1
                   => cellC
    

    If we use method 1, the new file3 would contain file1 and file2 ok,

    however the file1 => cellA and file2 => cellA would have cellA1 * 2,

    the new file3 would show cellA1 for four times, Once we merge more than

    30~50 these kind of files, although the result file is still small but the

    display speed would become too slow.

    Best Regards,

    chhung

  • edited November -1

    Hi chhung,

    I understand you basically want a smart way to detect that cells are identical and not copy over the contents. Right?

    That's a feature not provided by the copy_... methods. But if you know that only the top cells differ, you can basically create an empty file2 cell in the target layout, copy over the shapes and the instances one by one, mapping the child cells to the corresponding ones in the target layout.

    Matthias

  • edited June 2017
    Hi Matthias,

    It would be a wonderful world if the copy_tree() could support
    an option to choose rename/overwrite/skip the same cell name. :P

    I tried to do the steps(create target layout with file1/file2 topcell name),
    however jammed on (copy source file1/file2 shapes and mapping instance to target).
    May I ask help for some sample codes about this? @_@a

    Best Regards,
    --
    chhung
  • edited November -1

    Hi chhung,

    I'm sorry, but I still don't get your problem. And I don't see any code I could help with.

    In you sample, the hierarchies of file1 and file2 are identical. Will it be a solution then to copy over the objects of file2's top cell only? I mean, reproducing the instances within file2's top cell with the cells from file1?

    Matthias

  • edited November -1

    Hi Matthias,

    Sorry to reply so late, I've learned about how to merge two db with the same hierarchy and only have different shapes in topcell. However I have no idea if the following line should be executed, is it used to refresh the prop id in the same db?

    shtarget.replace_prop_id(newshape, 0)
    

    The codes:

    newdb = RBA::Layout.new
    newtop = newdb.add_cell("0_TOP")
    
    layout1 = RBA::Layout.new
    layout1.read("db1.gds")
    
    newdb.dbu = layout1.dbu
    
    new_layout1 = newdb.create_cell(layout1.top_cell.name)
    new_layout1.copy_tree(layout1.top_cell)
    
    trans=RBA::Trans.new(RBA::Point.new(0, 0))
    newdb.cell(newtop).insert(RBA::CellInstArray.new(newdb.cell_by_name("db1"), trans) )
    
    
    layout2 = RBA::Layout.new
    layout2.read("db2.gds")
    
    new_layout2 = newdb.add_cell(layout2.top_cell.name)
    
    trans=RBA::Trans.new(RBA::Point.new(0, 40000))
    newdb.cell(newtop).insert(RBA::CellInstArray.new(newdb.cell_by_name("db2"), trans) )
    
    newdb.cell(newdb.cell_by_name("db1")).each_inst do |inst|
      i = inst.cell_inst
      trans = i.is_complex? ? i.cplx_trans : i.trans
    
      if i.is_regular_array?
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans, i.a, i.b, i.na, i.nb))
      else
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans))
      end
    end
    
    lmap = {}
    
    layout2.layer_indices.each do |layer|
      linfo = layout2.get_info(layer)
      TargetLayer = newdb.insert_layer(linfo)
      lmap[layer] = TargetLayer;
    end
    
    layout2.layer_indices.each do |layer|
      shtarget = newdb.cell(newdb.cell_by_name("db2")).shapes(lmap[layer])
      layout2.cell(layout2.cell_by_name("db2")).shapes(layer).each do |shape|
        newshape = shtarget.insert(shape)
        #shtarget.replace_prop_id(newshape, 0)
      end
    end
    
    newdb.write("db1_db2_merged.oas")
    

    Best Regards,

    chhung

  • edited June 2017

    Hi chhung,

    this script looks quite good already. I admit it could be easier, but lacking the right functions currently, it's the best way to emulate it.

    The function you are looking for is: Layout#properties_id and the reverse Layout#properties:

    if shape.has_prop_id?
      shtarget.insert(shape, newdb.properties_id(layout2.properties(shape.prop_id)))
    else
      shtarget.insert(shape)
    end
    

    Basically instances can have properties too, so you might need to apply the same to instances.

    BTW: I assume that "db1" is the top cell of layout1. In that case you can write new_layout1.cell_index instead of newdb.cell_by_name("db1") and the same for the second layout. That makes the script work even if the top cell name of layout1 or layout2 changes.

    Kind regards,

    Matthias

  • edited June 2017

    Hi Matthias,

    About the instance properties, the code is modified from

    if i.is_regular_array?
      newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans, i.a, i.b, i.na, i.nb))
    else
      newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans))
    end
    

    to

    if i.is_regular_array?
      if inst.has_prop_id?
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans, i.a, i.b, i.na, i.nb),   newdb.properties_id(layout2.properties(inst.prop_id) ) )
      else
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans, i.a, i.b, i.na, i.nb))
      end
    else
      if inst.has_prop_id?
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans),   newdb.properties_id(layout2.properties(inst.prop_id) ) )
      else
        newdb.cell(new_layout2).insert(RBA::CellInstArray.new(inst.cell_index, trans))
      end
    end
    

    Is it correct ?

    To write new_layout1.cell_index instead of newdb.cell_by_name("db1") is ok, however write new_layout2.cell_index instead of newdb.cell_by_name("db2") would get error, it said "undefined method `cell_index' for 13:Fixnum, is it because the new_layout1 was made by newdb.create_cell, and new_layout2 was made by newdb.add_cell ?

    Best Regards,

    chhung

  • edited November -1

    Hi chhung,

    the code looks correct. It's a bit bloated - you can probably simplify it a little exploiting the fact that a property id of "0" means "no property" and using the RBA::CellInstArray taken from the RBA::Instance object (not tested):

    new_prop_id = inst.has_prop_id? newdb.properties_id(layout2.properties(inst.prop_id)) : 0
    cell_inst_array = inst.cell_inst
    cell_inst_array.cell_index = inst.cell_index
    newdb.cell(new_layout2).insert(cell_inst_array, new_prop_id)
    

    Regarding your second question: if you consistently use create_cell, new_layout2 will also be a RBA::Cell' object and the suggested code works. The olderadd_cell` will basically do the same but already return a cell index which is less convenient to work with.

    Regards,

    Matthias

Sign In or Register to comment.