Internal error: dbLayout.cc:1182

edited December 2013 in KLayout Support

Hi Matthias,

using Ruby scripting, I came across the following internal error:

RuntimeError: Internal error: dbLayout.cc:1182 topological_sort () was not true in Cell::each_touching_inst in Action::triggered
  gdsext.rb:106:in `each_touching_inst'
  gdsext.rb:106:in `kinstance'
  gdsext.rb:198:in `move_pin_to'
  clkpause_ch.rb:92:in `create'
  clkpause_ch.rb:12:in `block in create'
  clkpause_ch.rb:5:in `each'
  clkpause_ch.rb:5:in `create'
  script_reader.lym:75:in `block in triggered'
  script_reader.lym:72:in `each'
  script_reader.lym:72:in `triggered'

Here is part of the gdsext.rb code which I think is relevant:

def kinstance
  raise "ERROR: Trying to access an Instance which has been deleted." if @parent == nil
  @parent.kcell.each_touching_inst(RBA::Box::new(@infolabel.text_pos, @infolabel.text_pos)) do |inst|  # gdsext.rb:106
    if inst.cell_inst.trans == @infolabel.text.trans
      if get_cell.kcell.cell_index == inst.cell_index
        return inst 
      end
    end
  end
end

There, @parent is an object which has a Cell instance kcell and @infolabel is a Shape instance of type Text.

Please let me know if you need further information.

Oh, forgot to mention that I am using version 0.23.1.

Comments

  • edited November -1

    Hi friendx,

    That error typically happens if you have a recursive hierarchy, i.e. cell "A" calls "B" and "B" itself calls "A". The recursion in your case may be more subtle, but it's quite likely that this is the reason.

    Please check, whether you happened to build such a hierarchy or your input file contains a hierarchy of that kind. The editor will prevent you from creating a recursive hierarchy, but if you create your layout through a script, such things can happen.

    Regards,

    Matthias

  • edited November -1

    Thanks for pointing that out. After re-arranging generating script I got it to work. Since I'm working on a convenience API layer for layout generation which will be called from user scripts, this layer should probably check for recursive hierarchy on every instantiation call to make sure this doesn't happen and to properly warn the user about it.

  • edited May 2015

    Sorry for bumping this old thread, but I think I have the same error again with KLayout v0.24-python-eval - but this time, I can't see the circular reference!

    To debug the instantiation tree, I added the following debug code on top of my script to track the RBA::Cell.insert calls:

    module RBA
      class Cell
        alias_method :old_insert, :insert
        def insert(obj)
          if obj.class == CellInstArray
            puts "Layout #{layout}, Cell #{self} ('#{layout.cell_name(self.cell_index)}', index #{self.cell_index}): inserting instance #{obj.object_id} of '#{layout.cell_name(obj.cell_index)}' (index #{obj.cell_index})"
          end
          old_insert(obj)
        end
      end
    end
    

    With the test layout which is generated by a script, this leads to the following output:

    Layout #<RBA::Layout:0x0000000bfbf710>, Cell #<RBA::Cell:0x0000000bfa8740> ('pcell_test', index 0): inserting instance 100463520 of 'TEXT' (index 1)
    Layout #<RBA::Layout:0x0000000bfbf710>, Cell #<RBA::Cell:0x0000000bfa8740> ('pcell_test', index 0): inserting instance 100462700 of 'TEXT' (index 1)
    Layout #<RBA::Layout:0x0000000bfbf710>, Cell #<RBA::Cell:0x0000000bfa8740> ('pcell_test', index 0): inserting instance 100438580 of 'NCUT_NSEL_vv' (index 4)
    Layout #<RBA::Layout:0x0000000bf4a190>, Cell #<RBA::Cell:0x0000000bf91d88> ('SBPP', index 1): inserting instance 100396720 of 'POLCUT$1' (index 3)
    Layout #<RBA::Layout:0x0000000bfbf710>, Cell #<RBA::Cell:0x0000000bfa8740> ('pcell_test', index 0): inserting instance 100395560 of 'SBPP' (index 5)
    

    All instances are variants of PCells. The top-level cell is pcell_test, the two TEXT instances are from the library "Basic" (the "TEXT" PCell provided by you) and NCUT_NSEL_vv is another PCell I created myself.

    The interesting part (which causes the error) is what follows: SBPP is a PCell which instantiates another PCell, POLCUT. If I leave out the instantiation of POLCUT, everything is fine. If I leave it in, I can't save the GDS (or in text format, it simply does nothing) and when I exit KLayout, before the main window closes, an error message pops up saying

    Internal error: dbLayout.cc:1220 topological_sort () was not true

    Interestingly, while I am looking at the layout (I can go into all the different PCells and see their layout), everything looks totally fine.

    The next thing to debug this would probably be to write a sample script to try and reproduce this behaviour, unfortunately there is some PCell code I cannot share (it is also quite large and complicated) so I'd need to try and replicate this otherwise.

    Before I do that however, I was just wondering if you still think this could be a circular reference, as I can't see anything suspicious in the cell indices (other than maybe a $ sign I would've expected in the name of the SBPP variant and potentially that the layout is different for the instantiation of the POLCUT$1)?

    This should be the final hierarchy:

    'pcell_test' (index 0)
      |
      +-- 'TEXT' (index 1)
      |
      +-- 'TEXT' (index 1)
      |
      +-- 'NCUT_NSEL_vv' (index 4)
      |
      +-- 'SBPP' (index 5)
            |
            +-- 'POLCUT$1' (index 3?)
    

    I think I can understand that POLCUT$1 might get instantiated in a different Layout object (probably the one belonging to the Library containing the PCell), but would that cause any issues?

    Thanks, friendfx

  • edited May 2015

    Hi again,

    in the meanwhile I created a minimal example of what I would like to do and which causes a similar error. Here is the code of the hierarchical PCells:

    class ParentPCell < RBA::PCellDeclarationHelper
      def initialize
        super
        param(:width, TypeInt, "Width", default: 1200)
        param(:height, TypeInt, "Height", default: 800)
      end
      def produce_impl
        begin
          li = layout.layer(RBA::LayerInfo.new(6, 0))
          x1, y1, x2, y2 = -width/2, -height/2, width/2, height/2
          cell.shapes(li).insert(RBA::Box.new(x1, y1, x2, y2))
    
          lib = RBA::Library.library_by_name("Discussion404_5_Lib")
          lib || raise("Lib not found.")
          pcell_decl = lib.layout.pcell_declaration("ChildPCell")
          pcell_decl || raise("PCell declaration not found.")
          param = {size: 150}
          params = pcell_decl.get_parameters.collect do |p|
              param[p.name.to_sym] || p.default
          end
          pcell_var = layout.add_pcell_variant(lib, pcell_decl.id, params)
          cia = RBA::CellInstArray.new(pcell_var, RBA::Trans.new(0, x1, y1))
          cell.insert(cia)
        rescue
          abort("#{$!}\n#{$!.backtrace.join("\n")}")
        end
      end
    end
    
    class ChildPCell < RBA::PCellDeclarationHelper
      def initialize
        super
        param(:size, TypeInt, "Size", default: 100)
      end
      def produce_impl
        begin
          li = layout.layer(RBA::LayerInfo.new(5, 0))
          cell.shapes(li).insert(RBA::Box.new(-size, -size, size, size))
        rescue
          abort("#{$!}\n#{$!.backtrace.join("\n")}")
        end
      end
    end
    
    class Discussion404_5_Lib < RBA::Library
      def initialize(pcell_classes)
        pcell_classes.each do |pcell_class|
          pcell_obj = pcell_class.new
          layout.register_pcell(pcell_class.name.to_str.split(':')[-1], pcell_obj)
        end
        register(self.class.name.split(':')[-1])
      end
    end
    
    Discussion404_5_Lib.new([ChildPCell, ParentPCell])
    

    Maybe there is something fundamentally wrong with it, such as the way I am trying to instantiate one PCell inside the other?

    Any help would be appreciated.

  • edited May 2015

    Hi friendfx,

    thank you very much for providing that perfect test case. That makes debugging far easier.

    I can reproduce the issue, although I am able to save the file. But on closing the application crashes.

    I am debugging it right now, but the matter is somewhat complicated. So I'd ask you to be a little patient.

    Thanks,

    Matthias

  • edited May 2015

    Hi friendfx,

    I was able to debug that issue somewhat. Apparently the problem arises due to the recursive library reference in the parent PCell.

    That needs a little explanation: a PCell imported from a library is actually a twofold indirection: first, a cell is referenced from a library and inside that library, a PCell variant (basically a "shadow cell" containing the generated layout) is linked to.

    If you create a PCell instance that way, the PCell variant will contain a library proxy which points to the library itself and within that library a PCell variant is linked against. The problem is now caused by the library containing library proxies linking into itself.

    Confused? I admit that is not easy to understand.

    But luckily there is a very simple solution: you simply don't need the library reference, since when the PCell is instantiated, we are already inside that library. The code for the parent PCell simplifies to:

    class ParentPCell < RBA::PCellDeclarationHelper
      def initialize
        super
        param(:width, TypeInt, "Width", default: 1200)
        param(:height, TypeInt, "Height", default: 800)
      end
      def produce_impl
        begin
          li = layout.layer(RBA::LayerInfo.new(6, 0))
          x1, y1, x2, y2 = -width/2, -height/2, width/2, height/2
          cell.shapes(li).insert(RBA::Box.new(x1, y1, x2, y2))
    
          pcell_decl = layout.pcell_declaration("ChildPCell")
          pcell_decl || raise("PCell declaration not found.")
          param = {size: 150}
          params = pcell_decl.get_parameters.collect do |p|
              param[p.name.to_sym] || p.default
          end
          pcell_var = layout.add_pcell_variant(pcell_decl.id, params)
          cia = RBA::CellInstArray.new(pcell_var, RBA::Trans.new(0, x1, y1))
          cell.insert(cia)
        rescue
          abort("#{$!}\n#{$!.backtrace.join("\n")}")
        end
      end
    end
    

    Note that the "lib" references are gone. Taking the layout is sufficient, since that layout is actually already located inside the library and that is where the "shadow" cell is being created when produce_impl is called.

    With that change, the code works in my case.

    I'll debug the issue further. Maybe it's possible to give a nice error instead of a plain crash.

    Best regards,

    Matthias

  • edited November -1

    Hi Matthias,

    Thank you so much for looking into this issue and providing a very simple solution at the same time! I will test it immediately.

    You are right, I still am a bit confused about how a PCell is actually created. Through debugging (my above post with the RBA::Cell::insert logging code), I realised that the layout "seen" by the PCell's produce_impl method is not necessarily the layout where the final instance ends up, but I wasn't aware that one could cause a circular reference through the libraries - good to know!

    That of course raises the question for the case where one PCell tries to instantiate a PCell from a different library, would I need to (am I allowed to) get the lib reference then?

  • edited May 2015

    Hi,

    It's perfectly valid to reference cells from other libraries from within PCells. Your code wasn't wrong. The problem is only that the reference was a library reference and the source library was the library the PCell lived in.

    Regarding your doubts about the internals, here is a more elaborate explanation and I hope this will be of use for others as well:

    First of all, PCells and Libraries are not necessarily connected. PCells do not need to live in a library and both concepts share some features but are independent.

    1.) A PCell first of all is an object which is registered within a layout. It provides the recipe how to generate the layout and some metadata and this object is what you provide when you create a PCell in your code. Initially, that objects is just an attachment to a layout. It comes to life when a PCell is instantiated. Then, a "real" cell is created in the layout using the PCell object to generate the layout. This cell is a perfectly normal cell and acts as a cache for the layout. When working with the layout, that cell behaves like any other cell. Hence, the PCell concept blends well into the static layout world.

    However, these PCell instance cells (called "variants") know where they originate from, so it's possible to change the parameters which will effectively make the system recompute the layout and eventually create new variants. If you save a layout, KLayout will write additional information which allows to restore that connection on loading. If the connection cannot be restored, the variant will turn into a normal cell and the layout becomes static.

    2.) A library is a layout object which is separate from the working layout and registered globally in the system. A library is basically not more than a normal layout object which can be located through it's name.

    When a library cell is referenced from the working layout, a proxy cell is created. That again is a perfectly normal cell, which holds a copy of the library cell but knows the library it's connected to. So, if the library gets updated, the system is able to update the proxy cell as well, keeping them in sync. Library references are not plain pointers to cells inside libraries, but mirror cells which are synchronized with the library. That concept avoids problems arising from sharing resources (for example, layer translation) and the layout object using a library cell behaves like a usual layout object.

    If you take a PCell from a library, it will first be instantiated in the layout that the library is made up of. Hence, the layout object is not your working layout. In a second step, the library reference is formed by copying the generated layout. This happens outside the PCell instantiation code, so you won't notice that.

    So when you want to instantiate a PCell from the same library, it's sufficient to take the PCell from the library's layout and a library proxy is not required. In fact, library proxies pointing into the library itself make the application crash on cleaning up the layout (this of course is a bug, but one that happens in a somewhat redundant case). Library proxies pointing to other libraries are perfectly valid.

    A final note: be careful not a create cyclic references, for which the application will also crash (i.e. a cell of library A using a cell from library B and the cell from B using cells from A). So if you have a library A using cells from library B which itself uses cells from C, there is no issue and apart from that, I'd consider that a better design anyway.

    Matthias

Sign In or Register to comment.