Saving visible layers as flat GDS

JayJay
edited December 2009 in KLayout Support
I was trying to get to the coordinates of certain shapes in the hierarchy.

I generally do this by transforming shapes, for every level of hierarchy as I come back up to top. It works.

An alternate approach, I have been using is to flatten the GDS by writing a on-the-fly flatten rule deck for DRC tool, specifying layers of interest. Then process the flattened data back with scripts.

Here I was hoping to be able to write flattened data in text format and then process with perl or something to fit my requirement.

Suggestions are welcome.

Comments

  • edited December 2009

    Hi Jay,

    the following is a piece of ruby code that adds a new "Tools" menu entry (Dump flat shapes).
    It asks for a file name and prints the shapes as they appear in the current top cell for all
    visible layers. The format is XML like that:

    <shape_dump cell="TOP" dbu="0.001">
      <layer source="1/0">
        <polygon>(-116,-16;-116,62;-9,62;-9,51;-108,51;-108,-3;-21,-3;-21,51;-9,51;-9,-16)</polygon>
        <path>(-338,317;-338,362;-336,360;-336,392) w=10 bx=0 ex=0 r=false</path>
        <box>(12,-25;17,-21)</box>
        <text>('ABC',r0 -1250,400)</text>
      </layer>
      <layer source="100/0">
        <polygon>(-2,-24;-2,-12;5,-12;8,-15;13,-15;13,-24)</polygon>
        <box>(-1205,-291;-1195,-281)</box>
      </layer>
    </shape_dump>
    

    Please note that the coordinates are given in database units. The script can be easily adjusted to
    produce micrometer units if required.

    BTW: a better solution would be to use the RecursiveShapeIterator object, but I just discovered some
    issues with array instances ...

    Best regards,

    Matthias

    Here is the script:

    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
    
    def dump_shapes(file, layout, cell, layer, trans)
    
      itrans = RBA::ICplxTrans.from_trans(trans)
    
      cell.shapes(layer).each do |shape|
    
        if shape.is_box?
          box = shape.box.transformed_cplx(itrans)
          file.puts("    <box>#{box.to_s}</box>")
        elsif shape.is_path?
          path = shape.path.transformed_cplx(itrans)
          file.puts("    <path>#{path.to_s}</path>")
        elsif shape.is_polygon?
          polygon = shape.polygon.transformed_cplx(itrans)
          file.puts("    <polygon>#{polygon.to_s}</polygon>")
        elsif shape.is_text?
          text = shape.text.transformed_cplx(itrans)
          file.puts("    <text>#{text.to_s}</text>")
        end
    
      end
    
      cell.each_inst do |inst|
    
        if inst.is_regular_array?
    
          na = inst.na
          nb = inst.nb
          a = inst.a
          b = inst.b
    
          (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::CplxTrans.new(RBA::Trans.new(disp))
              dump_shapes(file, layout, layout.cell(inst.cell_index), layer, trans * disp_trans * inst.cplx_trans)
            end
          end
    
        else
          dump_shapes(file, layout, layout.cell(inst.cell_index), layer, trans * inst.cplx_trans)
        end
    
      end
    
    end
    
    $dump_flat_shapes = MenuAction.new( "Dump Flat Shapes", "" ) do 
    
      app = RBA::Application.instance
      mw = app.main_window
    
      lv = mw.current_view
      if lv == nil
        raise "No view selected"
      end
    
      cv = lv.active_cellview
      if !cv.is_valid?
        raise "No cell or no layout found"
      end
    
      layers = []
    
      lnode = lv.begin_layers
      while !lnode.at_end?
        if !lnode.current.has_children? && lnode.current.layer_index >=0 && lnode.current.visible?(true)
          layers.push(lnode.current.layer_index)
        end
        lnode.next
      end
    
      # Ask for the file name 
      filename = RBA::FileDialog.get_save_file_name("Flat Dump", ".", "All files (*)")
      if filename.has_value?
    
        File.open(filename.value, "w") do |file|
    
          file.puts("<shape_dump cell=\"#{cv.layout.cell_name(cv.cell_index)}\" dbu=\"#{cv.layout.dbu}\">")
    
          layers.each do |l|
    
            file.puts("  <layer source=\"#{cv.layout.get_info(l).to_s}\">")
            dump_shapes(file, cv.layout, cv.cell, l, RBA::CplxTrans.new)
            file.puts("  </layer>")
    
          end
    
          file.puts("</shape_dump>")
    
        end
    
      end
    
    end
    
    app = RBA::Application.instance
    mw = app.main_window
    
    menu = mw.menu
    menu.insert_separator("tools_menu.end", "name")
    menu.insert_item("tools_menu.end", "dump_flat_shapes", $dump_flat_shapes)
    
  • JayJay
    edited December 2009

    Matthias,

    First of all, thanks for all the great effort. It's very helpful.

    In the code above, I have tried to debug, why the following crashes the tool:

    layers.each do |l|
    file.puts(" ")
    dump_shapes(file, cv.layout, cv.cell, l, RBA::CplxTrans.new)
    file.puts(" ")
    end

    Value of 'l' seems to show up as -1 in all cases. There is no other message besides segfault.

    Couple questions:
    1. Iterating over lnodes, I am also getting non existing layers in layers[]
    2. UI seems to freeze, 'strace' shows following messages with no other activity.
    rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
    rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0

    Thanks
    ~J

  • JayJay
    edited December 2009

    Changing from
    if !lnode.current.has_children? && lnode.current.visible?(true)
    to
    if !lnode.current.has_children? && lnode.current.layer_index >=0 && lnode.current.visible?(true)

    seems to solve the problem. I no longer have -1 in layers[].

    For a layout with 50 shapes, it seems to take a long time between file open dialog and writing the text file.

    Never-the-less it does solve the problem =)

    Thanks
    ~J

  • edited 10:59PM

    Hi Jay,

    you're right. The -1 layer index may appear if a layer is specified in the layer list but is not in the layout (i.e. when the layer list is loaded from a file). I did not take into account that case correctly. Some of the ruby methods are mapped to low-level C++ methods which do not do much consistency checking which makes the application crash. I admit that is not user-friendly. I'll try to provide more checks.

    I changed the code above accordingly.

    Thanks for the hint.

    Best regards,

    Matthias

  • JayJay
    edited 10:59PM
    Matthias,

    Code you put up there is a good example of traversing layers and shapes in layout.

    Thanks for your help.

    ~J
Sign In or Register to comment.