Can you search for specific sized feature. i.e can I search to find in particular layer
all areas that are 0.7um x 0.7um or smaller? It would be nice to input the x and y size and
have Klayout highlight those features.
There is no built-in functionality of this kind (yet). However, Here is a script that searches the current layout for shapes with a size smaller than a given threshold. It will install itself in the layer list's context menu (right mouse button) as a menu item "Find Small Shapes On Selected Layers".
When this menu item is selected, it will ask for a size and scan all selected layers for shapes with a bounding box which is smaller than the given size in both directions. When finished, it will open a marker browser containing all the found shapes.
This version of the script will report shapes per cell. That means, if a cell is placed twice, a shape inside that cell will be reported only once. That reduces the number of reported items but since a cell can be placed in different orientations, the distinction of x and y size does not make sense then.
Please also note that this script will report small areas on a per-shape basis. If an area is actually larger, because it is formed by two small adjacent or overlapping shapes, the smaller parts are still reported. The solution to that problem is to merge all shapes before using this function. That is currently not quite efficient for larger layouts and a efficient implementation for that case is the domain of real (expensive) DRC tools.
Anyway, I hope that script is useful.
Best regards,
Matthias
Here is the script:
def find_small_shapes
sz = RBA::InputDialog::get_double("Find Objects Smaller Than", "Enter the desired threshold size.\nObjects with a bounding box smaller than the given size (in both directions) are put into a marker DB.", 1.0, 6)
if ! sz.has_value?
return
end
app = RBA::Application.instance
mw = app.main_window
view = mw.current_view
return unless view
layers = view.selected_layers
return unless layers.size > 0
cv_index = -1
view.selected_layers.each do |l|
if cv_index >= 0
if l.current.source_cellview(true) >= 0 && cv_index != l.current.source_cellview(true)
raise "Selected layers must originate from the same layout"
end
else
cv_index = l.current.source_cellview(true)
end
end
cv = view.cellview(cv_index)
return unless cv.is_valid?
layout = cv.layout
sz_dbu = (sz.value / layout.dbu + 0.5).floor.to_i
dbu_trans = RBA::CplxTrans::new(layout.dbu)
# remove a RDB called "find_small_shapes"
(0..(view.num_rdbs-1)).each do |rdb_index|
if view.rdb(rdb_index).name == "find_small_shapes"
view.remove_rdb(rdb_index)
break
end
end
rdb_index = view.create_rdb("find_small_shapes")
rdb = view.rdb(rdb_index)
rdb.top_cell_name = layout.cell_name(cv.cell_index)
view.selected_layers.each do |l|
if cv_index == l.current.source_cellview(true)
layer_index = l.current.layer_index
if layout.is_valid_layer?(layer_index)
cat_name = l.current.source(true)
rdb_cat = rdb.create_category(cat_name)
rdb_cat_id = rdb_cat.rdb_id
cells = layout.cell(cv.cell_index).called_cells
cells.push(cv.cell_index)
cells.each do |ci|
rdb_cell = rdb.create_cell(layout.cell_name(ci))
rdb_cell_id = rdb_cell.rdb_id
cell = layout.cell(ci)
cell.shapes(layer_index).each do |shape|
bbox = shape.bbox
if (shape.is_box? || shape.is_polygon? || shape.is_path?) && bbox.width <= sz_dbu && bbox.height <= sz_dbu
rdb_item = rdb.create_item(rdb_cell_id, rdb_cat_id)
if shape.is_box?
dbox = shape.box.transformed_cplx(dbu_trans)
rdb_item.add_value(RBA::RdbItemValue::new(dbox))
elsif shape.is_path?
# in 0.21 there are no path markers -> convert to polygon
dpath = shape.path.polygon.transformed_cplx(dbu_trans)
rdb_item.add_value(RBA::RdbItemValue::new(dpath))
elsif shape.is_polygon?
dpolygon = shape.polygon.transformed_cplx(dbu_trans)
rdb_item.add_value(RBA::RdbItemValue::new(dpolygon))
end
end
end
end
end
end
end
# Hint a corresponding cm_... method is missing
action_path = "tools_menu.browse_markers"
if mw.menu.is_valid(action_path)
mw.menu.action(action_path).trigger
end
end
# A helper class for a menu bound action
class MenuAction < RBA::Action
def initialize( title, shortcut, &action )
self.title = title
self.shortcut = shortcut
@action = action
end
def triggered
@action.call( self )
end
private
@action
end
# register the function in the toolbar
# TODO: add shortcut, correct title etc.
app = RBA::Application.instance
mw = app.main_window
menu = mw.menu
menu.insert_separator("@lcp_context_menu.end", "tb_separator")
menu.insert_item("@lcp_context_menu.end", "find_small_shapes", MenuAction.new("Find Small Shapes On Selected Layers", "") { find_small_shapes })
Comments
Hi Scott,
There is no built-in functionality of this kind (yet). However, Here is a script that searches the current layout for shapes with a size smaller than a given threshold. It will install itself in the layer list's context menu (right mouse button) as a menu item "Find Small Shapes On Selected Layers".
When this menu item is selected, it will ask for a size and scan all selected layers for shapes with a bounding box which is smaller than the given size in both directions. When finished, it will open a marker browser containing all the found shapes.
This version of the script will report shapes per cell. That means, if a cell is placed twice, a shape inside that cell will be reported only once. That reduces the number of reported items but since a cell can be placed in different orientations, the distinction of x and y size does not make sense then.
Please also note that this script will report small areas on a per-shape basis. If an area is actually larger, because it is formed by two small adjacent or overlapping shapes, the smaller parts are still reported. The solution to that problem is to merge all shapes before using this function. That is currently not quite efficient for larger layouts and a efficient implementation for that case is the domain of real (expensive) DRC tools.
Anyway, I hope that script is useful.
Best regards,
Matthias
Here is the script: