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
Hi,
Could you show the full code? This is just a small part and I can't read much from that.
Matthias
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
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)
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]
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+indexnumber_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