Hi,
I've two gds files and I want to merge them together. For this I created one blank layout and instantiating the top cells of these two gds files under that top cell in new layout. All this I want to do through ruby script, non-interactively.
Im running klayout -e -z -rm merge_gds.rb
Now I'm unable to copy cell from gds1 file and paste in the same cellview of new layout. Also how do I instantiate the cell at a particular location ?
Regards,
Acku
Comments
Hi Acku,
merging of layouts is not the strength of RBA but it's possible (although probably slower than the native functionality).
Here is a sample script that takes two layouts (a.gds and b.gds) and merges them. It illustrates how to solve the problem of merging the layer sets and the hierarchies. It can be extended to merge properties as well, but I omitted that for simplicity. In addition it assumes that the database units of the layouts is identical. If that is not the case, the second will be magnified or shrinked.
In particular, copying the instances is somewhat tedious currently.
Best regards,
Matthias
Here is the script:
Thanks a lot!
The script is working fine for me and solved my purpose. I modified it to merge several hundreds of gds files in one file.
Actually I was trying to follow the most intuitive approach of loading gds files in same layout, but this doesn't seem to work as some "m_layer_states not free" error was coming. Maybe this can be made to work by making the manual work automatic just like it happens (I'm not sure) while doing the same with GUI.
Thank you so much again, as this example helped to learn a lot. It would be really beneficiary for users of RBA if some more such examples are added in the RBA Examples section.
Regards,
Acku
Hi Acku,
Being able to load a file into an existing layout is actually a nice suggestion! Right now that use case is not supported and seeing those error message would not surprise me.
I admit such a feature would be quite useful. I'll try to consider that for the next release.
Best regards,
Matthias
The above code is really useful, but I need to copy layer properties as well. I tried to modify it to map the layer properties but somehow I couldn't make it work. However I able to handle gds files with different database units.
Can you please guide me on how to update the copy_cells function above to copy the layer properties as well ?
Regards
Acku
Hi Acku,
there is nothing special with the properties. All you need to do is to create a mapping for the property id's and apply the new id's.
Below is the new script.
Best regards,
Matthias
Thanks again. I couldn't figure out that this needs to be done for every instance as well. The code is working fine now!
Thanks and Regards,
Acku
You're welcome :-)
I admit it's more tedious than it should be. I'll try to provide a better solution in the next release, like the one you already mentioned.
BTW: if you need performance, the script can be set up somewhat more efficient by not merging both layouts into a new one but rather the second into the first.
Best regards,
Matthias
I want to merge 2 gds into 1 and flatten them.
I use your first script of this discussion and add the flatten script in the end of file.
But I get the error message as following (mergecell.rb is the file name of my script)
./mergecell.rb:112: [BUG] Segmentation fault
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
/usr/local/klayout/bin64/klayout.sh: line 66: 18798 Aborted ${KLAYOUT_HOME}/bin64/current/klayout ${ARGUMENTS} ${FILES}
Could you give me some hints?
The following is the RBA code.
----------------------------------------------------------------------------------
# Merge two layouts
# This script merges two layouts (a.gds and b.gds) into another one (c.gds)
# and creates a new top cell referencing both source layouts.
# TODO:
# * Consider case of different DBU's (requires scaling)
# * Copy properties as well (requires property mapping)
# Open the input layouts
l1 = RBA::Layout.new
l1.read("a.gds")
l2 = RBA::Layout.new
l2.read("b.gds")
# Open the target layout
l3 = RBA::Layout.new
top = l3.add_cell("TOP")
# Take the output DBU from l1
l3.dbu = l1.dbu
# Create a map of layer indices of layout 1 to 3 and 2 to 3.
# lmap_1to3 will map a layer index from 1 to 3 and lmap_2to3 a layer index from 2 to 3.
# Add the required layers to l3.
lmap_1to3 = {}
lmap_2to3 = {}
linfo_to_index = {}
l1.layer_indices.each do |layer|
linfo = l1.get_info(layer)
l3layer = l3.insert_layer(linfo)
lmap_1to3[layer] = l3layer;
linfo_to_index[linfo.to_s] = l3layer
end
l2.layer_indices.each do |layer|
linfo = l2.get_info(layer)
l3layer = linfo_to_index[linfo.to_s]
if !l3layer
l3layer = l3.insert_layer(linfo)
end
lmap_2to3[layer] = l3layer;
end
# A utility function which copies one layout into another
def copy_cells(lsrc, ltarget, lmap)
citarget = nil
# a map for the cell indices
cmap = {}
lsrc.each_cell_bottom_up do |cisrc|
# 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|
newshape = shtarget.insert(shape)
shtarget.replace_prop_id(newshape, 0) # clear properties
end
end
# translate and copy the instances
csrc.each_inst do |inst|
# 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?
ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb))
else
ctarget.insert(RBA::CellInstArray.new(cinew, trans))
end
end
end
# Return the last cell's index which (because we iterated bottom up) is a
# top cell
return citarget
end
# Actually copy the layouts
new_l1top = copy_cells(l1, l3, lmap_1to3)
new_l2top = copy_cells(l2, l3, lmap_2to3)
# Create the top level instances
# no off-set
l3.cell(top).insert(RBA::CellInstArray.new(new_l1top, RBA::Trans.new(RBA::Point.new(0, 0))))
l3.cell(top).insert(RBA::CellInstArray.new(new_l2top, RBA::Trans.new(RBA::Point.new(0, 0))))
(0..(l3.cells-1)).each do |ci|
if l3.cell_name(ci) == "TOP"
l3.flatten(ci, 32, true)
end
end
# write the output file
l3.write("c.gds")
---------------------------------------------------------
Regards,
Canny
Hi Canny,
I think the problem is caused because not every integer between 0 and l3.cells might be a valid cell index. The program should not segmentation fault, but I can't exclude that in every case.
To find the cell called "TOP" better use
that method gives you the index of the TOP cell, so you could simply write:
Best regards,
Matthias