Coding to manipulate individual objects of an array

edited June 2015 in Ruby Scripting
Hello
I have used the instance tool to make an array of an object, but I now need to write a script to select some of the objects randomly and delete them.
I am unsure of how to approach this problem, does the array behave like a matrix with indexes?
Thank you!

Comments

  • edited November -1

    Not really. An array is a fixed array (as stored in GDS/OAS databases), individual elements cannot be addressed and changed directly. However there is a workaround - Matthias has invented something called cell variants: http://www.klayout.de/doc/manual/create_variants.html. Well maybe someone else invented it, but at least I've never seen it in other tools. I think this is what you want. Let us know how you get on.

    The second option is just to go Edit > Selection > Resolve arrays, to make each element an individual instance again, and therefore be able to edit each one. Not exactly what you asked for, but I mention it in case you weren't aware.

    David

  • edited November -1
    Thank you David,
    Now that I have each object in an individual cell how can I call upon them in a script? Do I call upon them by their cell name like I would with a variable?
    Sorry, if my questions sound strange, I'm more of a matlab/matrix kind of person.
  • edited June 2015

    Oh. Hah. I see your title says "Coding..." -- sorry I should have offered a coding solution earlier but I just read the post content.

    I too came to KL with mostly just Matlab experience. So I got a book out and learned Ruby, which is something I recommend as it will speed your coding up significantly later. Now I love Ruby (aside from a couple small niggles) and I despise Matlab (nothing but niggles). Of course they are not used equivalently, but just speaking to the languages themselves rather than what they are used for.

    Anyhoo, try this. It's not the only way to do it, for example a more coding-efficient approach may be to instance an array and then resolve it. But at least with this approach here you have some more insight and flexibility I think.

    1. File > New layout > cell called "TOP"
    2. Right click on cell tree > New cell > cell called "CHILD"
    3. Center-click on CHILD so it's bolded, then draw some shapes.
    4. Center-click on TOP so it's bolded.
    5. Run this script which will place a 3x4 array of CHILD, and then erase the one at 2,3

    =

    include RBA
    app = Application.instance
    mw = app.main_window
    lv = mw.current_view
    ly = lv.active_cellview.layout
    dbu = ly.dbu # The conversion factor between microns and database units (which are integers that the coords are stored in)
    
    # Inputs:
    px = 100 # x pitch, in um
    py = 200
    nx = 3   # Number of elements in x direction
    ny = 4
    top_cell_name = "TOP" # You don't have to name it here. You could get the cell reference another way, e.g. top = layout_view.active_cellview.cell
    child_cell_name = "CHILD"
    
    top   = ly.cell(top_cell_name)
    child = ly.cell(child_cell_name)
    
    # Place nx-by-ny instances
    inst = [] # The 2d array that will hold the references to each instance
    nx.times { |i|
      curr_col = [] # The 1d array that will hold references to instances in just the current column
      ny.times { |j|
    
        # The current transformation, or just location in this case, of the cell
        # Divide by dbu to convert from microns into database units
        trans = Trans.new((i*px)/dbu, (j*py)/dbu)
    
        child_cia = CellInstArray.new(child.cell_index,trans)
    
        curr_inst = top.insert(child_cia)
    
        curr_col << curr_inst
    
      }
      inst << curr_col
    }
    inst = inst.transpose # Because I stored the rows and columns backwards..
    
    # Delete the one at 3nd row (from the bottom), 2nd column (from the left) for example.
    # Note that indexing starts at 0, so we subtract 1 from the above numbers.
    row = 3
    col = 2
    inst[row-1][col-1].delete
    
  • edited November -1
    Beautiful!
    That's exactly what I needed to understand, I will look more into the example you gave me to try to make the grating i need.
    Thanks lots!
  • edited June 2015
    Another question though, when you do inst[row-1][col-1].delete (last line) it deletes the shape, but what becomes of that position (row, col) after you delete it? Is it a nil or a 0?
    For example, I am trying to delete 500 random shapes out of 2025 (45X45) shapes in an instance but because they are random some indexes will occur more than once.

    counter = 1
    while counter <= 500
    row = rand(1..nx)-1 #here nx=45
    col = rand(1..ny)-1 #here ny=45
    if inst[row][col].nil? == true then
    redo
    else
    inst[row][col].delete
    counter +=1
    end
    end

    I have tried to add an if-loop that will redo the iteration if the inst[row][col] is empty (because it has already been deleted) but I don't think the line if inst[row][col].nil? == 0 is not being understood and I keep getting this error

    inst->instances() != 0 was not true in Instance::delete

    is there a way to tell it not to delete twice if there is no shape in the instance at that index?
  • edited June 2015

    Hi,

    the inst array will hold RBA::Instance objects which you can think of as pointers into the database. By calling their "delete" method the original instance in the database is deleted.

    The pointers still exists, hence the inst members are still RBA::Instance objects. But after calling RBA::Instance#delete they point to "nothing". Or in other words, they become invalid.

    They won't become nil, but their "is_valid?" method will return false. Any attempt to access their attributes will fail with an exception too.

    So you can easily avoid a duplicate deletes by doing this:

    inst[row][col].is_valid? && inst[row][col].delete
    

    Matthias

  • edited November -1
    Hi,
    I have tried the method ".is_valid" but even that gives me an error. It seems like it won't let me use any method on a deleted object.


    > inst[0][0].is_valid?
    true
    > inst[0][0].delete
    > inst[0][0].is_valid?
    RuntimeError: Internal error: /Users/mhe/src/klayout-0.23.2/src/gsiDeclDbCell.cc:2109 inst->instances () != 0 was not true in Instance::is_valid?
    (console eval):1:in `is_valid?'
    (console eval):1:in `<main>'
  • edited November -1
    Update: I tried the method ".is_null?" that one gave me false prior to deleting and true after the object was deleted.

    Thanks everyone!!! This has been super informative.
  • edited June 2015

    Hi Ines,

    Sorry for the confusion: "is_valid?" is actually giving that internal error in 0.23. This is already fixed in the upcoming 0.24 version.

    "is_null?" is not a bad choice in your case.

    But be aware that there is a subtle difference between "is_valid?" and "is_null?": "is_valid?" may be able to detect if the instance was deleted through another way, while "is_null?" only checks whether the instance was deleted by using this Instance object's delete method.

    Deleting instances while keeping the pointer is somewhat risky: if you keep instances and delete the database instances behind it some other way, the pointer might become invalid without you noticing it. The technical reason is that the database, being an optimized system, does not keep track of the pointers referring to objects within it.

    Here is an example demonstrating that effect:

    a = ... Some Instance ...
    b = a.dup  # new Instance pointing to the same database object than a
    
    a.delete
    a.is_null?    # true
    
    # b now points to a database object that is gone, BUT:
    b.is_null?    # false !!!
    

    So accessing b will probably result in a crash. "is_valid?" was meant to mitigate this problem somewhat, but that is only halfway true: if you delete the whole cell containing the instances, "is_valid?" won't be able to figure out what happened as well and a crash might happen. So better not keep Instance objects for a longer time except in simple cases like yours.

    Thanks for mentioning this.

    Matthias

Sign In or Register to comment.