Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pya.Library.library_by_name #879

Closed
lukasc-ubc opened this issue Jul 26, 2021 · 6 comments
Closed

pya.Library.library_by_name #879

lukasc-ubc opened this issue Jul 26, 2021 · 6 comments
Assignees
Labels
Milestone

Comments

@lukasc-ubc
Copy link

Hi @klayoutmatthias

I have the following problem in 0.27.2 and 0.27.3 (version klayout-HW-klayout-0.27.3-macOS-BigSur-1-qt5Brew-RsysPhb38). Namely, the library_by_name() function doesn't work for my libraries.

> pya.Library.library_names()
['Basic', 'EBeam', 'EBeam_Beta', 'GSiP', 'SiEPIC General']
> pya.Library.library_by_name('EBeam')
> pya.Library.library_by_name('GSiP')
> pya.Library.library_by_name('Basic')
<pya.Library object at 0x152980940>

In 0.26.12, it works correctly:

> pya.Library.library_by_name('EBeam')
<__main__.SiEPIC_EBeam_Library object at 0x1655ebc40>
> pya.Library.library_by_name('Basic')
<pya.Library object at 0x160382d40>
> pya.Library.library_by_name('GSiP')
<__main__.GSiP object at 0x166b6e140>

I also note that the following does work correctly in 0.27 (but not 0.26), so there is a work-around available:

  libs = pya.Library.library_ids()
  for lib in libs:
    l = pya.Library.library_by_id(lib)
    print("%s: %s" % (lib,l))

thank you

lukasc-ubc added a commit to SiEPIC/SiEPIC-Tools that referenced this issue Jul 26, 2021
@klayoutmatthias
Copy link
Collaborator

Hi Lukas,

you can check if the "library_ids" method is available with this:

if "library_ids" in pya.Library.__dict__:
  ... version 0.27 ...

so a solution is possible which is both 0.26 and 0.27 compatible.

Let me explain the behaviour of 0.27 - maybe it makes more sense then. I'm willing to discuss a change with the goal of better backward compatibility, but there are some use cases I want to maintain:

In the course of making libraries bound more strictly to a technology, the "library_by_name" function got a technology filter. The technology handling follows these rules:

  • A library can either be technology independent or be bound to one or multiple technologies
  • Multiple libraries bound to different technologies can be registered under the same name

"library_by_name" with only a library name will only find libraries not bound to a technology. "library_by_name" with a technology name given will find the libraries bound to that technology.

Here is an example:

lib1 = pya.Library()
lib1.layout().read("/home/matthias/lib1.gds")
lib1.description = "LIB1 for no tech"
lib1.register("LIB1")

lib2 = pya.Library()
lib2.layout().read("/home/matthias/lib2.gds")
lib2.add_technology("A")
lib2.add_technology("B")
lib2.description = "LIB2 for tech A,B"
lib2.register("LIB2")

lib3a = pya.Library()
lib3a.layout().read("/home/matthias/lib3a.gds")
lib3a.add_technology("A")
lib3a.description = "LIB3 for tech A"
lib3a.register("LIB3")

lib3b = pya.Library()
lib3b.layout().read("/home/matthias/lib3b.gds")
lib3b.add_technology("B")
lib3b.description = "LIB3 for tech B"
lib3b.register("LIB3")

Enumerating these libraries with "library_ids" gives this:

for id in pya.Library.library_ids():
  lib = pya.Library.library_by_id(id)
  print("Library: " + lib.name() + " - techs: " + ",".join(lib.technologies()))

Output:
Library: LIB1 - techs: 
Library: LIB2 - techs: A,B
Library: LIB3 - techs: B
Library: LIB3 - techs: A

Various "library_by_name" calls give this:

library_by_name('LIB1') = LIB1 for no tech
library_by_name('LIB1', 'A') = LIB1 for no tech
library_by_name('LIB1', 'B') = LIB1 for no tech
library_by_name('LIB2') = (none)
library_by_name('LIB2', 'A') = LIB2 for tech A,B
library_by_name('LIB2', 'B') = LIB2 for tech A,B
library_by_name('LIB3') = (none)
library_by_name('LIB3', 'A') = LIB3 for tech A
library_by_name('LIB3', 'B') = LIB3 for tech B

So bottom line is that "library_by_name" is only backward compatible for libraries without technology. This reflects the behaviour of the technology filter applied when KLayout looks up a library for integrating into a specific layout.

Because of the (useful) ability to bind multiple libraries to the same name, it's not strictly possible to emulate the original behaviour. Suppose, I'd change "library_by_name" back to being unspecific with respect to the technology, what should this function return for "LIB3"? In the example above, there are two of them. So formally, that would be some "libraries_by_name" then, which is still not backward compatible.

Any suggestion?

Best regards,

Matthias

@lukasc-ubc
Copy link
Author

lukasc-ubc commented Jul 28, 2021

Hi Matthias,

Thank you for the explanation. Some of the above could be added to the documentation, particularly the part
"library_by_name" with only a library name will only find libraries not bound to a technology. "library_by_name" with a technology name given will find the libraries bound to that technology.

I don't see a big problem with library_by_name returning multiple libraries. Then one has do a selection of the technology one is looking for; or this is already available via the 2nd parameter in the call.

Another related question is about technology support within individual PCells (as opposed to Libraries). We have many PCells that we use in different technologies. We selectively copy and paste the relevant ones (but not the entire library). Inside the PCells, we need to hard code which technology the cell is associated with to support some of the code (which uses additional layer definition information, and waveguide parameter definitions read from XML configuration files).

It would be nice if the PCell could recognize which Library/Technology it is associated with.

In https://www.klayout.de/doc-qt5/code/class_PCellDeclaration.html, it would be great to have a self.technology. This variable would then change depending on which Library the PCell is attached to.

Or the PCell could have a variable that points to which Library it is attached to. Presumably one can create this list by iterating through all the libraries and cells, but a reverse lookup would be useful.

Thank you
Lukas

@klayoutmatthias
Copy link
Collaborator

Hi Lukas,

in 0.27.5, there will be two methods which reflect the ownership: PCellDeclaration will have "layout" which tells which Layout object it lives in and "Layout" will have "library" which tells if the layout lives inside a library.

So with the enhancement, the technology can be derived by:

pcell = PCellDeclaration ...
technology = pcell.layout.library.technology

For completeness you should add a check for layout or library being nil.

Matthias

@klayoutmatthias klayoutmatthias added this to the 0.27.5 milestone Nov 14, 2021
klayoutmatthias added a commit that referenced this issue Nov 15, 2021
Solved #879: PCellDeclaration now knows the layout and layout knows t…
@lukasc-ubc
Copy link
Author

Hi @klayoutmatthias

In product_impl(), this works correctly:

self.layout.library().technology

But it does not work in init. Namely self.layout does not exist.

The error occurs during the Library class register_pcell step, even though the name of the technology has been assigned using self.technology = 'techname'

Knowing the technology name during the initialization of the PCell would be very useful so that the parameter choices can be technology specific, such as using a drop-down TypeList where the values are loaded from a technology file.

I tested this in both 0.27.5 and 0.27.8

thank you
Lukas

@lukasc-ubc
Copy link
Author

Hi @klayoutmatthias

In 0.28.4, self.layout == None, during the cell def init(self) method. It does work however in def produce_impl(self).

thank you

@klayoutmatthias
Copy link
Collaborator

Sorry I did not notice the comment before. I kind of vanished from my view.

The thing is a bit of a chicken-and-egg problem. Namely because of that registration idiom:

class PCell(pya.PCellDeclarationHelper):
  def __init__(self):
    super(PCell, self).__init__()
    ...

class PCellLib(pya.Library):
  def __init__(self):
    ...
    self.layout().register_pcell("PCell", PCell())

So PCell needs to be created before it can be registered at the library. Only after this registration, the layout attribute will become valid.

But there is nothing wrong with passing the layout reference to the PCell constructor:

class PCell(pya.PCellDeclarationHelper):
  def __init__(self, layout):
    super(PCell, self).__init__()
    ... 
    use "layout" instead of "self.layout" ...

class PCellLib(pya.Library):
  def __init__(self):
    ...
    self.layout().register_pcell("PCell", PCell(self.layout()))

Best regards,

Matthias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants