It looks like you're new here. If you want to get involved, click one of these buttons!
I wrote a script to do the following:
Given an already-open layout, choose a GDS file and instance it (the whole GDS file, assuming one top cell) as a cell in the current layout. In other words, the point is to pull in another layout as a cell within the current layout.
But there are a few strange behaviours.
First, here is the code. Here is a helper script first, that I call 'Misc tools.rb'
class MiscTools
# To use this, add this line to your file: load File.expand_path('Misc/Misc tools.rb', $PHTOOLS)
# Originally from: http://klayout.de/forum/comments.php?DiscussionID=103
def self.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
end
And here is the actual code. Note you will need to replace the "load" line to refer to the script above.
# Instances a gds file as a new cell in the current layout.
# The name of the new cell is the name of the gds file, minus the ".gds"
include RBA
load File.expand_path('Misc/Misc tools.rb', $PHTOOLS) # Contains the helper method "copy_cells"
layout_view = RBA::Application.instance.main_window.current_view
if layout_view == nil
raise "No view selected"
end
layout_view.transaction("Bring in external file")
begin
layout = Application.instance.main_window.current_view.active_cellview.layout
file = MiscTools.choose_file()
unless file.nil?
load File.expand_path(file)
layout_to_grab = Layout.new
layout_to_grab.read(file) unless file.nil?
lmap = {}
linfo_to_index = {}
layout_to_grab.layer_indices.each { |l|
linfo = layout_to_grab.get_info(l)
layer = layout.insert_layer(linfo)
lmap[l] = layer;
linfo_to_index[linfo.to_s] = layer
}
layout_to_grab_top = MiscTools.copy_cells(layout_to_grab, layout, lmap)
#layout.cell(top).insert(CellInstArray.new(layout_to_grab_top, Trans.new)) #Do this line if you want to instantiate the cell in the "top" cell
end
ensure
layout_view.commit
end
Now, here are the issues.
1) If cell "A" already exists in the open layout, and the layout we're bringing in also has cell "A", I'd like them to merge (ie assume cell "A" is identical in both cases and just use the original "A". Instead, it names the new one "A$1" to differentiate it from the old one.
2) The cell I've just brought in doesn't show up in the window (it appears blank when you press "*", although the cell is truly there when you press "-" to see the black outline). However if I then save the whole thing as GDS and re-open it, it shows up just fine now.
3) In the layout I'm bringing in, I have some PCells with guiding shapes. These are converted to non-PCells (polygons) with obviously no guiding shapes. Is there a way to do this and preserve the PCells and guiding shapes?
Note, if this is not the best way to do this, let me know!! I tried playing around with KLayout's functions to get multiple layouts into one tab ("@1", @2", ...) but couldn't for instance figure out how to "flatten" @1 and @2 so that I could instance @2 within @1. So I gave up on that.
Thanks,
David
Comments
Ah, so now I found File > Import > Other file into current.
This solves #2, but anyway #1 and #3 are still the same problem. (Well, #1 isn't a problem, it's a preference...)
Note, to solve #1, I guess I should use File > Import > Other file into current, and then choose:
However this doesn't work as I imagine it...
Here's a simple use case. Create a top cell "TOP". Create a child cell "A". Instance "A" inside of "TOP". Put a box in child cell "A". Save the whole thing as TOP.gds. Also save the child cell by right-clicking in the cell tree and selecting "Save Child Cell As" > "A.gds".
Now, when I go through the File > Import > Other file into current > Merge hierarchy, I expect nothing to happen -- it should identify that "A" already exists in the current cell tree and ignore it. However it instances the shape on cell "TOP". So, now you get two boxes in "TOP" -- one is the child cell "A" with a box in, the other is the box itself which has just been imported and plonked down, i.e. not in its own cell.
I think I'm understanding it wrong though, or maybe the Import function is still early stages. But I imagine it should just see that it has a cell A, and it's importing a cell A with identical contents, and either just ignore it or say "I found this cell with the same name and the same contents. Ignoring."
Also if you go in and modify A.gds manually (so now [A.gds] > [cell "A"] has different contents to [TOP.gds] > [cell TOP] > [cell "A"]) then try the above procedure, it would be nice to have it say "I found this cell by the same name with different contents. What do you want me to do? Use old cell / Use new cell / Rename old cell / Rename new cell."
Anyway just some thoughts - let me know if I'm understanding that correctly.
Hi David,
you love to write text do you ... :-)
I'll try to answer your points, but first of all, the solution you look for may be as simple as this:
The second read will basically continue the first read. If it encounters a cell the second time, it will continue to fill this cell. This will also preserve and merge PCell instances of both files. If you don't want to merge all cells, you can rename certain cells between the two read's so there is no name conflict.
Your code is basically correct, but regarding the guiding shapes, you can add an enhancement: guiding shapes are stored on special layout layers which will appear in the layer list too. You can identify that layer using Layout#guiding_shape_layer and skip that.
However, preserving PCell instances across layouts is possible, but is a awful lot of code. You can use Cell#is_pcell_instance to identify PCell instances. You can then obtain the PCell parameters and the PCell declaration, observing that a PCell typically lives in a library, obtain a new PCell variant from that library, create a library reference etc ...
Since version 0.23.x there is better support for copying shapes, instances and even cell trees across layouts. Have a look at the Cell#copy... method family. There are even hierarchical copy functions which allow specification of a cell mapping table. That may also provide a solution for your problem. However, I have not built in support for PCell translation, so that will not solve the PCell preservation issue currently. But I'll file that as a request.
The display problem may be related to the layers - you are using "insert_layer" which will always create a new layer, even if the requested one already exists. The layout database allows two layers to have the same specification but different identity. In that case, only the first one is shown in the layer view and the new cell appears empty, because it has the shapes on the second layer. I realized that is a problem, so there is a method called Layout#layer since 0.23.x which only creates a layout if it does not exist yet (you see - I try to be one step ahead :-) ).
The "import layout" functionality is probably too sophisticated. It is designed to preserve the flat layout appearance of the imported layout. Hence, I cannot simply merge cell A of the imported layout into cell A. There are various solutions: merge, if both A's provide the same instances as seen from the top cell or create new cells which represent the original hierarchy of the imported layout. None of the options will admit to modifying the gometrical relations of the cell. I guess that is what caused the confusion in your case.
Is something missing? I think not, but I'm sure you will follow up :-)
Best regards,
Matthias
Heh.. just call me an overachiever.
I should have known you already had some simple way of doing this! :-)
However it's almost right but not quite. Instead of just using the first- or last-read cell "A", it reads ALL cell "A"s and puts them all on top of each other in a new cell "A".
In other words, if "A" has a box on, and you're reading 100 files, each with an identical "A" somewhere in its tree, your resultant cell "A" will look the same but have 100 boxes on top of each other. This is fine for simple layouts but increases the filesize dramatically if "A" is complex.
Any simple way to not read in any existing cells?
(And if "A" is not identical between the 100 files, again it is instanced on top of each other, leading to sometimes undesired results. I suggest it might be worth having a LoadLayoutOptions option, where you choose the mode, e.g.: "Ignore cells with identical name to existing layout" / "Overwrite cells with identical name on existing layout" / "Merge cells with identical name" / "Rename new cells found to have same name" / "Rename old cells found to have the same name")
Hi David,
I'm a overachiever too :-)
If the "read again" approach is too simplistic, I can offer Cell#copy_tree_shapes. There is a version of that method which takes a CellMapping object which allows to be very specific about what target cell is to be used for which source cell. Once you have two layouts you can basically decide which cell you want to copy where. The CellMapping object allows setting up a mapping using various ways and you can even modify that later or generate a mapping yourself. But there is no option to drop shapes currently - the intention is to provide a lossless transfer (however, that's an interesting extension).
Alternatively you can code the transfer using Cell#copy_shapes or Cell#copy_shapes_tree for subcells and decide on a per-cell basis how to handle the transfer. I assume you can identify some common cells by their name (i.e som library prefix).
Matthias
I'm a little bit confused. I also want to import some cells from another gds file to my current layout.
Is there a simple way to achieve this with the layout.read method like Matthias wrote before?
My first idea was to merge different gds files with this code:
http://klayout.de/forum/comments.php?DiscussionID=146
But what I'm looking for is a File->Import->OtherFileIntoCurrent->Instantiate in ruby code.
Daniel
Try this:
Hi all,
thanks for the code pasted. Basically the method will work. There is a little issue here: if the layout read contains cells with the same name than any cell in the present layout (here: "master_layout"), then the read method will merge the content of both cells rather than creating two different cells. Another issue arises if the database unit of the imported layout is different from the master layout.
That effect is intended, but it's pretty dangerous. A more elaborate method which avoids these issues is the following:
Matthias