Deleting Specific Objects within a Cell (Python Script/Macro)

I'm quite new and still learning the ropes, so I appreciate any patience and guidance you can offer!
I'm trying to figure out how to delete specific objects within a cell, and I'm hoping to get some help with a script.

If I delete an object from the red circle, the entire cell #1 is removed. I don't want to do that.

I found that when I double-click on cell #1, the pillar shapes appear as black boxes within the red circle. When I selected those objects and pressed the 'Delete' key, they were successfully deleted.

I'd really like to automate this deletion process. So, my question is: How can I delete or remove the objects from the selected cell's pillars using a Python script (macro)?

My Script:
Here's the Python script I've tried so far, but it's leading to the whole cell being removed:

 import pya
import math

# Enter your Python code here ..
x = 583.6628
y = 348.6938
center_x = 0
center_y = 0
r = math.sqrt(x*x + y*y)

layout_view = pya.LayoutView.current()

cv = layout_view.active_cellview()
layout = cv.layout()
cell = cv.cell
dbu = layout.dbu
print("dbu unit: ", dbu)

object_selection = layout_view.each_object_selected()
i = 1
for instance in object_selection:
  print(f"--- the {i} pillars --")
  i = i+1;
  path_list = instance.path
  shape_list = instance.shape
  if path_list is not None:
    for path in path_list:
      instance = path.cell_inst()

      cplx_trans = instance.cplx_trans
      #reference_call = instance.cell_index
      instance_cell_index = instance.cell_index
      inst_cell = layout.cell(instance_cell_index)
      inst_cell_bbox = inst_cell.bbox()
      dimension = inst_cell_bbox.transformed(cplx_trans)
      dimension_height = (abs(dimension.bottom) - abs(dimension.top)) * dbu
      dimension_width = (abs(dimension.right) - abs(dimension.left)) * dbu
      print(f"instance of cell dimension: width {dimension_width}, height {dimension_height}")
      disp_x = cplx_trans.disp.x * dbu
      disp_y = cplx_trans.disp.y * dbu
      angle = cplx_trans.angle
      rot = cplx_trans.rot
      mag = cplx_trans.mag
      print(f"instance of Position: {disp_x} , {disp_y}")
      print("instance of the angle in units of 90 degree: ", angle)
      print("instance of the angle code:", rot())
      print("instance of scaling:", mag)

      test_r = math.sqrt(disp_x*disp_x + disp_y*disp_y)
      if test_r > r:
        layout.delete_cells(instance_cell_index)
        print("Delete!!")

Comments

  • Hi @Sharon,

    there is some confusion.

    First, you probably have not enabled "Select Top Level Objects" from the "View" menu. So in your first scenario, if you select things, you actually select shapes inside the pillar cell "1". When you delete them, the cell becomes empty in all places. From your perspective, that looks like the cell vanished. Instead it is still there, but empty.

    When you double-click the "1" cell, it becomes hidden. When you select the remaining boxes, you actually select "instances" (cell placements). If you delete those, the "1" cell becomes unplaced, hence vanished in those places.

    The code is not clearly saying what you intend to do. I think you don't really need to automate something. Just enable "Select Top Level Objects".

    Matthias

  • Dear Matthias,

    Thank you for your reply.
    The cell '1' is instantiated multiple times across the layout.

    However, I would like to delete only the instances of cell '#1' that are located in an "inactive region" and keeping all instances of cell '#1' that are within an "active region". My method is,
    1. Collect #1 cell location in active region
    2. Create #1-1 cell
    layer_index = layout.layer(pya.LayerInfo(1, 0))
    circle_cell = layout.create_cell("1-1")
    3. Draw shape #1 on circle_cell
    4. the instances circle_cell refer onto pillars
    circle_inst = pya.DCellInstArray(circle_cell.cell_index(), pya.DCplxTrans(1.0, 0, False, dx, dy))
    5. Delete #1 cell

    How can I copy_instances and copy_shapes the '#1' shape and instance located within the active region into a new cell named '#1-1', rather than creating a new '#1-1' cell and drawing shape '#1' on circle_cell ? Do you have a example for me? Thank you.

    Best Regard,
    Sharon

  • Hello Sharon.

    I would suggest the following flow:

    1) Create the active region shapes and add them to a new region (the active region).
    2) Check for each instance if its bbox (instance.bbox) is inside the active region, if so, keep it (do nothing), else delete it (instance.delete).

    If you have instance arrays you should resolve them first...

    Cheers,

    Tomas

  • edited July 30

    Hi @Sharon,

    If the instances you want to delete are made from array instances, the code becomes quite tricky. In the user interface, you can select the instances you want to delete. But if you select a part of an array, you first have to resolve arrays (Edit/Selection/Resolve Arrays) before you can delete individual instances. An array is a single object and you can only delete it as a whole.

    If that is the case here, automating this job is not a simple task of a few lines of code.

    Matthias

  • Hi Tomas,
    Thank you for your comment.
    My GDS is generated from Lumerical. I've confirmed that the instance is already resolved so that I can directly select and delete them.
    I use a similar method to yous.
    1. create a new layout "circle_cell" to draw a new circle shape (geometrically identical to shape of pillars cell #1) within it.
    2. traced (dx, dy) positions of all instances of cell #1 that are located within active region
    3. then to create new instance using circle_inst = pya.DCellInstArray(circle_cell.cell_index(), pya.DCplxTrans(1.0, 0, False, dx, dy)), and insert the new instance into pillars pillars.insert(circle_inst)
    4. do delete_cells("1") from pillars layout

    Hi Matthias,
    For this case, I know I can only delete it as a whole, I proceed by creating a new layout.
    This is my simple of layout where the instance of cell #1 are located both the active region (the region are also part of other cells) and inactive region. I don't know why cell #1 is generated in inactive region, but it need to delete it.

  • edited July 31

    Hello Sharon,

    My proposal is to just delete existing instances which are not inside an "active region" layer (10/0 in the example below), not to create new cells/layouts. To do this you can work with Regions, but they only work with shapes, so I use the instance bbox, which is a Box shape, for the Region operations.

    Original layout:

    Result after running the script:

    1) As mentioned before, instance arrays must be resolved prior to running the script as they will be checked and deleted as a whole. If preferred, this can also be done by script using the instance method .explode
    2) I used the bbox of the instance, but this can be refined to, for example, the shapes on a specific layer of the cell the instance refers to
    3) the script is in Ruby (I'm one of the few still using Ruby I guess, lol)
    4) the script is quite slow when the number of instances is huge

    The script:

    module MyMacro
    
      include RBA
    
    
    #---INPUT-------------------------------------------------------------------------------------------------------------------------------
    
          active_region_layer_number = 10
          active_region_datatype_number = 0
    
    #------------------------------------------------------------------------------------------------------------------------------------------
    
          layout_view = Application.instance.main_window.current_view      
          cell_view = layout_view.active_cellview      
          layout = cell_view.layout      
          viewed_cell = cell_view.cell
    
          # create a Region for the "active region" layer
    
          active_region = Region.new(viewed_cell.begin_shapes_rec(layout.layer(active_region_layer_number, active_region_datatype_number)))
    
    
          # collect instances to delete
    
          instances_to_delete = []
    
          viewed_cell.each_inst do |inst|
    
              # add the instance bbox to a new Region
    
              inst_bbox = Region.new(inst.bbox)
    
              selection = inst_bbox.not_inside(active_region)
    
              unless selection.is_empty?
    
                  instances_to_delete << inst
    
              end # unless
    
          end # each_inst
    
    
          # delete the instances outside the active region
    
          instances_to_delete.each do |inst|
    
              inst.delete
    
          end # each
    
    
    end # MyMacro
    

    Cheers,

    Tomas

  • Hi Thomas,

    thanks a lot for sharing the script. I recall there has been a discussion with exactly the same issue, but I can't find it. Maybe that was also a discussion on GitHub.

    Unfortunately the Forum system I am using is our of maintenance (project became a company, it got bought by investor, and he shut it down) and there is no chance of getting better search function :(

    Matthias

  • Dear @tomas2004 ,

    Your instructions were a huge help—thank you very much! I finally got them working in Python, even though you were in Ruby, lol.

Sign In or Register to comment.