Really easy question

edited December 2017 in Ruby Scripting
I have a script that when I have a technology library charged in Klayout, it finds in the active cell all same cells that they appear in technology library and replace all of them. The problem is that I want to generate a file specifying in what position and how much cells it replaces. I put some like that to see the names of and the position of each cell, but it reports a lot of cells with the same name and the same position and for some of cells no. I think that the problem is that I call only parent cells and not all children cells :| if anyone could help me, I am sure that it will be easy but i can't fix it.

cell_inst_object.cell_index = cv.layout.cell_by_name(names[instan.child_inst.cell_index])
n = cell_inst_object
x = n.trans.disp.x
y = n.trans.disp.y
name = n.cell.name
puts "#{name} at #{'%.3f'%(x*layout.dbu)}, #{'%.3f'%(y*layout.dbu)} #{instan.child_inst.cell_inst.na} #{instan.child_inst.b}"

Thank you

Comments

  • edited November -1

    Hi,

    Could you show the full code? This is just a small part and I can't read much from that.

    Matthias

  • edited November -1
    Sorry for the delay,

    The full code to replace cells from a library is as follow. And my problem is in line 190 :
    # This file read technology library of Ligentec and check if BB are in
    # A utility function which copies one layout into another
    def copy_cells(lsrc, ltarget, lmap, pmap, names)

    citarget = nil

    # a map for the cell indices
    cmap = {}

    lsrc.each_cell_bottom_up do |cisrc|
    #print tn
    names.each do |names_value|
    puts names_value[1].to_s
    puts lsrc.cell_name(cisrc).to_s
    puts names_value[1].to_s.eql?lsrc.cell_name(cisrc).to_s
    if names_value[1].to_s.eql?lsrc.cell_name(cisrc).to_s

    # create a new cell in the target layout and add to the cell index map
    csrc = lsrc.cell(cisrc)
    citarget = ltarget.add_cell(lsrc.cell_name(cisrc))
    ctarget = ltarget.cell(citarget)
    cmap[cisrc] = citarget

    # copy the shapes
    lsrc.layer_indices.each do |lisrc|
    shtarget = ctarget.shapes(lmap[lisrc])
    csrc.shapes(lisrc).each do |shape|

    # property mapping
    newpid = 0 # =no properties
    if shape.has_prop_id?
    newpid = pmap[shape.prop_id]
    if !newpid
    newpid = ltarget.properties_id(lsrc.properties(shape.prop_id))
    pmap[shape.prop_id] = newpid
    end
    end

    newshape = shtarget.insert(shape)
    shtarget.replace_prop_id(newshape, newpid)
    end
    end

    # translate and copy the instances
    csrc.each_inst do |inst|

    # property mapping
    newpid = 0 # =no properties
    if inst.has_prop_id?
    newpid = pmap[inst.prop_id]
    if !newpid
    newpid = ltarget.properties_id(lsrc.properties(inst.prop_id))
    pmap[inst.prop_id] = newpid
    end
    end

    # get the instance object and create a new one with the new cell index
    i = inst.cell_inst
    trans = i.is_complex? ? i.cplx_trans : i.trans
    cinew = cmap[i.cell_index]
    if i.is_regular_array?
    newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
    else
    newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans))
    end

    # apply the new property id
    ctarget.replace_prop_id(newinst, newpid)

    end
    end
    end
    end

    return cmap

    end



    app = RBA::Application.instance

    mw = app.main_window
    # get the current layout view
    lv = mw.current_view
    if lv == nil
    raise "No view selected"
    end

    # get the current cell view (the one selected in the hierarchy browser)
    cv = lv.cellview(lv.active_cellview_index)
    if !cv.is_valid?
    raise "No layout selected"
    end

    layout = cv.layout

    # fetch the name of the layout with the replacement cells
    fn = ENV['HOME']+"\\klayout_library_MPW.gds"


    library =RBA::Library.library_by_name("Lib_klayout")
    library || raise("Please charge Library of Klayout Tools->klayout Library")
    lib=library.layout
    #lib = RBA::Layout::new
    #puts lib
    #lmap = lib.read(fn)

    if ((lib.dbu - cv.layout.dbu).abs > 1e-6)
    raise "Database units of the layouts must be identical"
    end
    org_layers = {}
    new_layers = {}
    =begin
    cv.layout.layer_indices.each do |l|
    info = cv.layout.get_info(l)
    if lmap.is_mapped?(info)
    puts info
    ll = lmap.logical(info)
    puts ll
    org_layers[l] = ll
    new_layers[ll] = l
    end
    end
    =end
    cv.layout.layer_indices.each do |l|
    info = cv.layout.get_info(l)

    lib.layer_indices.each do |l_auxi|
    info_auxi = lib.get_info(l_auxi)
    puts info.to_s.eql?info_auxi.to_s
    if info.to_s.eql?info_auxi.to_s
    puts info
    ll = l_auxi
    org_layers[l] = ll
    new_layers[ll] = l
    end
    end
    end
    has_new_layers = false

    lib.layer_indices.each do |l|
    if ! new_layers[l]
    # puts l
    ll = cv.layout.insert_layer(lib.get_info(l))
    new_layers[l] = ll
    org_layers[ll] = l
    has_new_layers = true
    end
    end
    puts has_new_layers
    tmap = {}
    names = {}
    dummy = 0
    lib.each_cell do |t|
    tn = lib.cell_name(t.cell_index)
    #print tn
    if cv.layout.has_cell?(tn)
    tt = cv.layout.cell_by_name(tn)
    tmap[tt] = t
    names[tt] = tn
    cv.layout.rename_cell(tt, "dummy")
    cv.layout.prune_subcells(tt, -1)
    end
    end

    pmap = {}
    cmap = copy_cells(lib, cv.layout, new_layers, pmap, names)
    namebf=""
    ss=0
    tr = RBA::CplxTrans::new
    #puts cmap[1]
    layout.each_cell do |cell_prob|
    i=0
    cell_prob.each_parent_inst do |instan|
    if tmap[instan.child_inst.cell_index]
    i=i+1
    end
    end
    x=0
    while x<i
    cell_prob.each_parent_inst do |instan|
    if tmap[instan.child_inst.cell_index]
    n = instan.child_inst
    cell_inst_object = n.dup
    #puts cv.layout.cell_name(tmap[instan.child_inst.cell_index].cell_index)
    cell_inst_object.cell_index = cv.layout.cell_by_name(names[instan.child_inst.cell_index])
    n = cell_inst_object
    =begin
    x = n.trans.disp.x
    y = n.trans.disp.y

    name = n.cell.name
    =end puts "#{name} at #{'%.3f'%(x*layout.dbu)}, #{'%.3f'%(y*layout.dbu)} #{instan.child_inst.cell_inst.na} #{instan.child_inst.b}"

    end
    end
    x = x+1
    end
    end
    tmap.each do |k,v|
    layout.prune_cell(k, -1)
    end
    if has_new_layers
    mw.cm_lv_add_missing
    end
    =begin
    topcell = "Edge_Coupler"
    ly = layout
    parent_cell_p = ly.cell(ly.cell_by_name(topcell))
    parent_cell_p.each_parent_cell{ |parent_cell_index|
    parent_cell = layout.cell(parent_cell_index)
    parent_cell.each_inst { |inst| # Iterate over all the child instances
    x = inst.bbox.center.x
    y = inst.bbox.center.y
    if inst.cell.name.to_s.eql?topcell
    puts "#{inst.cell.name} at #{'%.3f'%(x*ly.dbu)}, #{'%.3f'%(y*ly.dbu)}"
    end
    }
    }

    def search_cell(from_cell, name_re, dbu, tr = RBA::CplxTrans::new)
    from_cell.each_inst do |inst|
    child_cell = inst.cell
    path_tr = tr * inst.cplx_trans
    if child_cell.name =~ name_re
    name=child_cell.name
    coords=path_tr.disp
    x=coords.x*dbu
    y=coords.y*dbu
    puts "#{name} ( #{'%.3f'%x} , #{'%.3f'%y} )"
    else
    search_cell(child_cell, name_re, dbu, path_tr)
    end
    end
    end
    dbu = layout.dbu

    search_cell(layout.top_cell, Edge_Coupler, dbu)

    layout.top_cell.each_inst { |inst| # Iterate over all the child instances

    if inst.is_regular_array?

    a,b,na,nb = inst.a, inst.b, inst.na, inst.nb
    x0,y0 = inst.bbox.center.x, inst.bbox.center.y # The xy position of the primary (bottom-left in this case) element

    na.times { |i|
    nb.times { |j|

    x = x0 + a.x*j + a.y*j
    y = y0 + b.x*i + b.y*i
    puts "#{inst.cell.name} at #{'%.3f'%(x*layout.dbu)}, #{'%.3f'%(y*layout.dbu)}"

    }
    }

    else
    x = inst.bbox.center.x
    y = inst.bbox.center.y
    puts "#{inst.cell.name} at #{'%.3f'%(x*layout.dbu)}, #{'%.3f'%(y*layout.dbu)}"
    end

    }
    =end

    Could you recommend something for this code to try to extract the number of cells and the name to put in one file?

    Thank you
  • edited March 2018

    Hi,

    first think I see is that there is an apparent lack of support for copying multiple cells of one layout to another ... the copy_cells function looks fairly complex.

    Nevertheless, the real issue is probably that you're iterating over the parent instances. That does not allow to modify the respective child instance. In addition, if you would modify it while iterating, that would change the parent-child relationship while you traverse it. Bad idea.

    So the solution I'd suggest is this (not tested)

    ...
    
    new_layers = {}
    has_new_layers = false
    lib.layer_indexes do |l_lib|
      li_lib = lib.get_info(l_lib)
      l_ly = layout.find_layer(li_lib)
      if !l_ly
        has_new_layers = true
        l_ly = layout.layer(li_lib)
      end
      new_layers[l_lib] = l_ly
    end
    
    names = {}
    lib.each_cell do |t|
      tn = lib.cell_name(t.cell_index)
      tt = layout.cell(tn)
      if tt
        names[tt.cell_index] = tn
        tt.name = "__dummy__"
        tt.prune_subcells
      end
    end
    
    pmap = {}
    # there should be a built-in method for this:
    copy_cells(lib, layout, new_layers, pmap, names)
    
    layout.each_cell do |cell|
      cell.each_instance do |inst|
        if names[inst.cell_index]
          inst.cell = cv.layout.cell(names[inst.cell_index])
        end 
      end
    end
    
    names.each do |k,v|
      layout.prune_cell(k, -1)
    end
    

    Regards,

    Matthias

  • Dear Matthias,

    Sorry for my late answer but I tried different things and how I didn't find a solution I left this issue.

    I bring this back. I try your code but I found that I need a little modify in the first loop to have this ruby file woking

    ...
    new_layers = {}
    has_new_layers = false

    This loop try to find the new layers of the library that it is necessary to introduce. This is important when copy cells because produce errors if both layout don't have the same layers invoked.

    The array of new layers has in each index the new layer to introduce.

    lib.layer_indices.each do |l_lib|
    li_lib = lib.get_info(l_lib)
    l_ly = layout.find_layer(li_lib)
    if !l_ly
    has_new_layers = true
    l_ly = layout.layer(li_lib)
    end
    new_layers[l_lib] = l_ly
    end
    names = {}

    This loop renames the old cells by dummy to don't have problems to import the cell with the same name. We store the index of these cells.

    lib.each_cell do |t|
    tn = lib.cell_name(t.cell_index)
    tt = layout.cell(tn)
    if tt
    names[tt.cell_index] = tn
    tt.name = "dummy"
    tt.prune_subcells
    end
    end
    pmap = {}
    names_file ={}
    names_file[0]=0;
    xx = 0
    yy = 0
    number_cells ={}
    positions_file =[]

    This function copy the new cells of the library that they have the same name in the hierarchy of the cell

    copy_cells(lib, cv.layout, new_layers, pmap, names)

    This loop iterates along the layout and replace the old cell instantiation (named dummy) by the new instantiation to replace them and update the cell block with the same name

    layout.each_cell do |cell|
    cell.each_inst do |inst|
    if names[inst.cell_index]

        inst.cell = cv.layout.cell(names[inst.cell_index])
        n = inst.dup
        x = n.trans.disp.x
        y = n.trans.disp.y
        name = n.cell.name
        if names_file[xx].to_s.eql?name
            yy = yy+1
            number_cells[xx]=yy
            #puts yy
        else
            number_cells[xx]=yy
            xx = xx+1;
            names_file[xx] = name
            yy = 1
        end
        positions_file.push(['%.3f'%(x*layout.dbu),'%.3f'%(y*layout.dbu)])
        #puts "#{name} at #{'%.3f'%(x*layout.dbu)}, #{'%.3f'%(y*layout.dbu)}"
    end 
    

    end
    end

    positions_file.each_with_index do |nn,index|
    puts index
    end

    With loop it is possible to write a file with the positions replaced by the new cells

    summaryfile = 'Summary_replacement.txt'
    File.open(summaryfile, 'w') do |out|
    out << "Cells modified by the PDK \n \n"
    acumul = 0
    names_file.each_with_index do |nn,index|
    if index>0
    out << "Cell replaced with name: #{names_file[index]} was modified the next number of iterations: #{'%i'%(number_cells[index])}\n"
    out << "At the positions: \n"
    positions_file.each_with_index do |rr,index_rr|
    if (index_rr)<indexnumber_cells[index]
    out << "[X,Y]: #{rr}\n"
    end
    end
    acumul=acumul+index
    number_cells[index]
    out << "\n"
    end
    end
    end

    This loop prune the old cells that they don't have instantiations now in the top cell due to in the las loop were modified by the new cell

    names.each do |k,v|
    layout.prune_cell(k, -1)
    end
    if has_new_layers
    mw.cm_lv_add_missing
    end

    At the end I reach my goal to have a ruby file that "read" a library with propietary cells and replace in the hierarchy the black box cells and write a file with the specific replacement summary.
    Thank you Matthias :)

Sign In or Register to comment.