how to use ruby script to flatten a cell with hierachy ?

edited March 2015 in Ruby Scripting
Hi, Matthias,
When using layout.cell.flatten, the instances in the cell will be removed. But when using Klayout GUI to flatten the cell, there is no such problem. The instances of sub-cells are flattened. Could you have any ruby example to do the flatten operation like GUI did ?

Thanks,
covalent

Comments

  • edited November -1

    Hi covalent,

    I'm afraid, I can't confirm that.

    The cell#flatten function is basically identical with the "flatten" menu function from the cell list.

    • "cell.flatten(true)" is equal to the UI function with "all levels" and "prune" checked
    • "cell.flatten(false)" is equal to the UI function with "all levels" and "prune" unchecked

    With "prune" checked or set to true, the function will remove the subcells. Otherwise it will keep them. But in every case the instances are removed since they shapes of the child cells have now been moved into the target cell.

    Matthias

  • edited March 2015
    Hi Matthias,

    Below is my exampe code. I create 6 hierchical levels. Only the bottom cell (SUB5) has a box shape. Other parent cells are to make complex array using this box as an instance. Then I use layout.cell.flatten to flatten my main cell (called "MAIN" in below code) and use layout.write to save result as an oas. When opening the .oas file, all instances are removed but no shapes are evelated to "MAIN" cell. Nothing is seen. However, if i use GUI to flatten the cell, it is ok. That is why i ask this question. Now i am struggling to generate my own cell flatten script.

    My Klayout version is 0.23.4 on windows platform.
    Finally thanks for your response.
    covalent

    my example code
    ---------------------------------
    tc = layout.create_cell("TOP")
    mc = layout.create_cell("MAIN")

    seginfo = [segpitch, orthopitch, nseg, north] #for generate cellinstarray
    gtinfo = [pitch, 0, nt, 0] #for generate cellinstarray
    cidx = garray("SUB3", garray("SUB4", gbox("SUB5", num, type, cdx, cdy), *seginfo), *gtinfo)
    mc.insert(RBA::CellInstArray::new(cidx, RBA::Trans::new(0, false, 0, 0)))
    tc.insert(RBA::CellInstArray::new(mc.cell_index, RBA::Trans::new(0, false, 0, 0)))

    def garray(name, idx, px, py, nx, ny)
    cell = gcell(name)
    p1 = RBA::Point::new(px, 0)
    p2 = RBA::Point::new(0, py)
    dup1 = nx
    dup2 = ny
    disx = -(nx-1)*px/2
    disy = -(ny-1)*py/2
    trans = RBA::Trans::new(0, false, disx, disy)
    cell.insert(RBA::CellInstArray::new(idx, trans, p1, p2, dup1, dup2))
    return cell.cell_index
    end

    def gbox(name, num, type, x, y)
    x1, x2 = -x/2, x/2
    y1, y2 = -y/2, y/2
    cell = gcell(name)
    layer_idx = layout.insert_layer(RBA::LayerInfo::new(num, type))
    cell.shapes(layer_idx).insert(RBA::Box::new(x1, y1, x2, y2))
    return cell.cell_index
    end

    def gcell(name)
    if layout.has_cell?(name)
    return layout.cell(name)
    else
    return layout.create_cell(name)
    end
    end
  • edited March 2015

    covalent,

    Can you please post the entire working code? It will then be easier to help reproduce the problem. For example in the code you posted there are several undefined variables including: segpitch,orthopitch,nseg,north,pitch, ...

    Also, minor point: if you indent each line by four spaces when you type in this forum then you will get this:

    Indented by four space characters
      Indented by six spaces (four spaces make it 'code', two more spaces are additional indent)
    

    (You can indent the entire code all at once using a text editor program or the KL Macro Editor, and then just copy and paste into here)

    David

  • edited March 2015

    Hi davidenhutch,

    Below is my simplied code which can point out the probelm i told. The generated .oas file has nothing. but if you delete the code of flattening (i mark it using pond mark in Unit_Mark" class), result is normal but i want it to be flatten. Please you help what problem is in my code. Thanks.

    covalent

    class MenuHandler < RBA::Action
    def initialize( t, k, &action ) 
        self.title = t
        self.shortcut = k
        @action = action    
    end
    def triggered
        @action.call( self ) 
    end
    private
    @action
    end
    
    class Unit_Mark
    def initialize
        $layout = RBA::Layout::new
        layout.dbu = 0.00025    
        dbu = layout.dbu
        num = 999
        type = 1
        pitch = 500/dbu/1000
    
        segpitch = 100/dbu/1000
        orthopitch = 120/dbu/1000
        nseg = 3
        north = 10
    
        cdx = 40/dbu/1000
        cdy = 50/dbu/1000
    
        nt = 30
    
        tc = layout.create_cell("TOP")
        mc = layout.create_cell("MAIN")
    
        seginfo = [segpitch, orthopitch, nseg, north]
        gtinfo = [pitch, 0, nt, 0]
        cidx = garray("SUB3", garray("SUB4", gbox("SUB5", num, type, cdx, cdy), *seginfo), *gtinfo)
        mc.insert(RBA::CellInstArray::new(cidx, RBA::Trans::new(0, false, 0, 0)))
        tc.insert(RBA::CellInstArray::new(mc.cell_index, RBA::Trans::new(0, false, 0, 0)))
    
        # this piece of code is to flatten cell using cell.flatten(true)    
        tc.each_child_cell do |c1|
            ccl = layout.cell(c1)
            ccl.flatten(true)
        end 
        ######################
    
        layout.write("x.gds")
    
    end
    
    def garray(name, idx, px, py, nx, ny)
        cell = gcell(name) 
        p1 = RBA::Point::new(px, 0)
        p2 = RBA::Point::new(0, py)
        dup1 = nx
        dup2 = ny
        disx = -(nx-1)*px/2
        disy = -(ny-1)*py/2
        trans = RBA::Trans::new(0, false, disx, disy)
        cell.insert(RBA::CellInstArray::new(idx, trans, p1, p2, dup1, dup2))
        return cell.cell_index
    end
    
    def gbox(name, num, type, x, y)
        x1, x2 = -x/2, x/2
        y1, y2 = -y/2, y/2
        cell = gcell(name)
        layer_idx = layout.insert_layer(RBA::LayerInfo::new(num, type))
        cell.shapes(layer_idx).insert(RBA::Box::new(x1, y1, x2, y2)) 
        return cell.cell_index
    end
    
    def gcell(name)
        if layout.has_cell?(name)
            return layout.cell(name)
        else
            return layout.create_cell(name)
        end
    end 
    
    def layout
        return $layout
    end
    end
    
    app = RBA::Application.instance
    mw = app.main_window
    @menu_handler = MenuHandler.new("RBA test", ""){Unit_Mark.new}
    mw.menu.insert_item("@toolbar.end", "rba_test", @menu_handler)  
    
    app.exec
    
  • edited November -1

    covalent,

    I took a quick look and actually I cannot detect why it is not working. I also tried layout.flatten(tc.cell_index,x,false) and observe what I think is funny behavior when you change x from 0 (nothing, no funny behavior) to 1 (flattens 1 level down, no funny behavior) to 2 (ditto) to 3 (here SUB5 is orphaned, which is I think funny behavior). I also tried true instead of false as the last argument and of course SUB5 disappears in the x=3 case here because it has just been orphaned (so my point is, to observe what is going on with the 'funny behavior' you should set it to false). Perhaps I'm missing something and this 'funny behavior' is actually the desired behavior.

    Anyway, to solve your problem, look at flatten.rb here:
    http://www.klayout.de/rba_examples.html

    I tried it with your already-generated x.gds (from your script, with flatten lines commented out) and it works.

    Since it works as a separate script, you can combine the two scripts to get your desired functionality.

    Note, you will have to deselect F3 > Top level objects only, then view "TOP" as top cell, then select all using your mouse, then run the "Flatten" script from your toolbar. Note also that that procedure is not required when you merge that code with yours -- it is just written in such a way as to require the user to select whatever instances they want to raise to TOP. Presumably you would refer to the child cells programmatically rather than require the user to select them.

    Hope this is enough to solve your problem. Let us know what you find.

    David

  • edited November -1

    I have done my own script to get what i want before. but i still thank for your reponse very much.

  • edited November -1

    Great! Glad to hear.

    Do post your solution here if you get a chance -- that kind of thing is useful for others in the future.

  • edited November -1

    Hi all,

    sorry for that late reply, but I have little time left for support currently.

    I was able to reproduce the issue with a modified version of the code. It took a little debugging but I found the root cause: the flatten function will treat the zero count of the "b" dimension of the "gtinfo" array as REALLY zero - the effect is that no instances of the SUB3 array are traversed.

    If you set the dimension to 1, the problem is solved (you can leave the pitch at 0):

     gtinfo = [pitch, 0, nt, 1]
    

    I admit that is a little bit inconsistent. When you write the file, the stream writer will replace the zero by 1 hence normalizing the layout to a proper one. I'll fix that on occasion.

    Thanks for mentioning that.

    Best regards,

    Matthias

  • edited March 2015

    Hi Matthias,

    Oh..... i had seen my code many times and didn't find this mistake. Thank you very much. But i have a question. Because i have used below code to load all shapes of the cell i want it to be flatten originally. I am wondering if i use cell.flatten and cell.shapes to get the shapes of the cell, could this way is better or faster than my own code ?

    # objs is an array to store the shape objects of the cell
    # cell is the i want it to be flatten for getting the shapes
    # idx is the layer index. One cell has only one index.
    
    objs = Array.new
    inst_flatten(objs, cell, idx, RBA::Trans::new(0, false, 0, 0))
    
    def inst_flatten(objs, cell, idx, trans)
        cell.shapes(idx).each do |shape|
            box = shape.box.transformed(trans)
            objs = objs.push(box)
        end
    
        cell.each_inst do |inst|
            if inst.is_regular_array?
                na = inst.na
                nb = inst.nb
                a = inst.a
                b = inst.b
                if (na - 1) < 0
                    na = 1
                end
                if (nb - 1) < 0
                    nb = 1
                end             
                (0..(na - 1)).each do |ia|
                    (0..(nb - 1)).each do |ib|
                        disp = RBA::Point.new(a.x * ia + b.x * ib, a.y * ia + b.y * ib)
                        disp_trans = RBA::Trans.new(disp)
                        inst_flatten(objs, inst.cell, idx, trans * disp_trans * inst.trans)
                    end
                end
            else
                inst_flatten(objs, inst.cell, idx, trans * inst.trans)          
            end         
        end     
    end
    
  • edited November -1

    Hi covalent,

    A more efficient way to traverse the shapes of a hierarchy of cells is to use the RecursiveShapeIterator object:

    # print the polygon-like objects as seen from the initial cell "cell"
    iter = cell.begin_shapes_rec(layer)
    while !iter.at_end?
      if iter.shape.renders_polygon?
        polygon = iter.shape.polygon.transformed(iter.itrans)
        puts "In cell #{iter.cell.name}: " + polyon.to_s
      end
      iter.next
    end
    

    Matthias

Sign In or Register to comment.